From 794b5a232fc98edd38071401008fa6af5ca3d231 Mon Sep 17 00:00:00 2001 From: gnosygnu Date: Sun, 12 Jul 2015 21:10:02 -0400 Subject: [PATCH] v2.7.2.1 --- .directory | 4 + 100_core/.classpath | 30 + 100_core/.project | 17 + 100_core/lib/commons-compress-1.5.jar | Bin 0 -> 256241 bytes 100_core/src/gplx/Exc.java | 70 + 100_core/src/gplx/Exc_.java | 67 + 100_core/src/gplx/Exc_msg.java | 44 + 100_core/src/gplx/core/brys/Bry_rdr.java | 155 ++ .../src/gplx/core/btries/Btrie_bwd_mgr.java | 88 + .../gplx/core/btries/Btrie_bwd_mgr_tst.java | 87 + .../src/gplx/core/btries/Btrie_fast_mgr.java | 156 ++ .../gplx/core/btries/Btrie_fast_mgr_tst.java | 85 + .../src/gplx/core/btries/Btrie_itm_stub.java | 23 + 100_core/src/gplx/core/btries/Btrie_mgr.java | 24 + .../src/gplx/core/btries/Btrie_slim_itm.java | 130 ++ .../gplx/core/btries/Btrie_slim_itm_tst.java | 49 + .../src/gplx/core/btries/Btrie_slim_mgr.java | 128 ++ .../gplx/core/btries/Btrie_slim_mgr_tst.java | 92 + .../src/gplx/core/btries/Btrie_utf8_itm.java | 68 + .../src/gplx/core/btries/Btrie_utf8_mgr.java | 68 + .../src/gplx/core/criterias/Criteria.java | 24 + .../src/gplx/core/criterias/Criteria_.java | 53 + .../gplx/core/criterias/Criteria_between.java | 40 + .../core/criterias/Criteria_bool_base.java | 57 + .../gplx/core/criterias/Criteria_comp.java | 37 + .../src/gplx/core/criterias/Criteria_eq.java | 34 + .../src/gplx/core/criterias/Criteria_fld.java | 67 + .../src/gplx/core/criterias/Criteria_in.java | 46 + .../core/criterias/Criteria_ioItm_tst.java | 50 + .../gplx/core/criterias/Criteria_ioMatch.java | 37 + .../gplx/core/criterias/Criteria_like.java | 36 + .../src/gplx/core/criterias/Criteria_tst.java | 92 + 100_core/src/gplx/core/js/Js_wtr.java | 107 ++ 100_core/src/gplx/core/js/Js_wtr_tst.java | 41 + .../gplx/core/primitives/Bool_obj_ref.java | 36 + .../gplx/core/primitives/Bool_obj_val.java | 34 + .../src/gplx/core/primitives/Bry_obj_ref.java | 35 + .../gplx/core/primitives/Byte_obj_ref.java | 31 + .../gplx/core/primitives/Byte_obj_val.java | 29 + .../gplx/core/primitives/Double_obj_val.java | 32 + .../src/gplx/core/primitives/Int_obj_ref.java | 45 + .../src/gplx/core/primitives/Int_obj_val.java | 32 + .../gplx/core/primitives/String_obj_ref.java | 30 + .../gplx/core/primitives/String_obj_val.java | 27 + .../src/gplx/core/strings/String_bldr.java | 115 ++ .../src/gplx/core/strings/String_bldr_.java | 22 + .../src/gplx/core/strings/String_ring.java | 61 + .../gplx/core/strings/String_ring_tst.java | 46 + 100_core/src/gplx/core/threads/Gfo_lock.java | 28 + .../src/gplx/core/threads/Thread_adp.java | 45 + .../src/gplx/core/threads/Thread_adp_.java | 36 + 100_core/src_000_err/gplx/Err.java | 63 + 100_core/src_000_err/gplx/ErrMsgWtr.java | 112 ++ 100_core/src_000_err/gplx/ErrProcData.java | 67 + .../src_000_err/gplx/ErrProcData_tst.java | 48 + 100_core/src_000_err/gplx/Err_.java | 36 + 100_core/src_000_err/gplx/Err_arg.java | 53 + 100_core/src_000_err/gplx/Gfo_msg_data.java | 34 + 100_core/src_000_err/gplx/Gfo_msg_grp.java | 46 + 100_core/src_000_err/gplx/Gfo_msg_grp_.java | 30 + 100_core/src_000_err/gplx/Gfo_msg_itm.java | 57 + 100_core/src_000_err/gplx/Gfo_msg_itm_.java | 27 + 100_core/src_000_err/gplx/Gfo_msg_log.java | 54 + 100_core/src_000_err/gplx/Gfo_msg_obj.java | 22 + 100_core/src_000_err/gplx/Gfo_msg_root.java | 80 + .../src_000_err/gplx/Gfo_msg_root_tst.java | 62 + .../src_100_interface/gplx/Cancelable.java | 23 + .../src_100_interface/gplx/Cancelable_.java | 26 + .../src_100_interface/gplx/CompareAble.java | 20 + .../src_100_interface/gplx/CompareAble_.java | 78 + .../gplx/CompareAble_tst.java | 38 + 100_core/src_100_interface/gplx/EqAble.java | 21 + .../src_100_interface/gplx/InjectAble.java | 21 + 100_core/src_100_interface/gplx/NewAble.java | 21 + .../src_100_interface/gplx/ParseAble.java | 21 + .../src_100_interface/gplx/ParseAble_.java | 21 + 100_core/src_100_interface/gplx/RlsAble.java | 21 + 100_core/src_100_interface/gplx/RlsAble_.java | 22 + 100_core/src_100_interface/gplx/SrlAble.java | 21 + 100_core/src_100_interface/gplx/SrlAble_.java | 65 + .../src_100_interface/gplx/SrlAble__tst.java | 66 + .../src_100_interface/gplx/XtoStrAble.java | 21 + .../src_100_interface/gplx/XtoStrAble_.java | 21 + 100_core/src_110_primitive/gplx/Array_.java | 99 ++ .../src_110_primitive/gplx/Array__tst.java | 41 + 100_core/src_110_primitive/gplx/Bool_.java | 59 + 100_core/src_110_primitive/gplx/Bry_.java | 1037 +++++++++++ 100_core/src_110_primitive/gplx/Bry__tst.java | 280 +++ 100_core/src_110_primitive/gplx/Bry_bfr.java | 567 ++++++ 100_core/src_110_primitive/gplx/Bry_bfr_.java | 38 + .../src_110_primitive/gplx/Bry_bfr_mkr.java | 158 ++ .../gplx/Bry_bfr_mkr_tst.java | 74 + .../src_110_primitive/gplx/Bry_bfr_tst.java | 227 +++ .../src_110_primitive/gplx/Bry_finder.java | 296 ++++ .../gplx/Bry_finder_tst.java | 78 + 100_core/src_110_primitive/gplx/Bry_fmtr.java | 267 +++ .../src_110_primitive/gplx/Bry_fmtr_arg.java | 21 + .../src_110_primitive/gplx/Bry_fmtr_arg_.java | 33 + .../gplx/Bry_fmtr_arg_fmtr_objs.java | 25 + .../gplx/Bry_fmtr_eval_mgr.java | 22 + .../gplx/Bry_fmtr_eval_mgr_.java | 27 + .../gplx/Bry_fmtr_eval_mgr_gfs.java | 25 + .../src_110_primitive/gplx/Bry_fmtr_itm.java | 33 + .../src_110_primitive/gplx/Bry_fmtr_tst.java | 78 + .../src_110_primitive/gplx/Bry_fmtr_vals.java | 31 + 100_core/src_110_primitive/gplx/Byte_.java | 56 + .../src_110_primitive/gplx/Byte__tst.java | 35 + .../src_110_primitive/gplx/Byte_ascii.java | 111 ++ 100_core/src_110_primitive/gplx/Char_.java | 76 + 100_core/src_110_primitive/gplx/Double_.java | 54 + .../src_110_primitive/gplx/Double__tst.java | 29 + 100_core/src_110_primitive/gplx/Float_.java | 36 + 100_core/src_110_primitive/gplx/Int_.java | 260 +++ 100_core/src_110_primitive/gplx/Int__tst.java | 115 ++ 100_core/src_110_primitive/gplx/Int_ary_.java | 95 + .../src_110_primitive/gplx/Int_ary__tst.java | 44 + 100_core/src_110_primitive/gplx/Long_.java | 113 ++ .../src_110_primitive/gplx/Long__tst.java | 49 + 100_core/src_110_primitive/gplx/Object_.java | 46 + .../src_110_primitive/gplx/Object__tst.java | 36 + 100_core/src_110_primitive/gplx/Short_.java | 22 + 100_core/src_110_primitive/gplx/String_.java | 535 ++++++ .../src_110_primitive/gplx/String__tst.java | 184 ++ .../gplx/brys/Bry_fmtr_arg_ary_dim2.java | 27 + .../gplx/brys/Bry_fmtr_arg_bfr.java | 23 + .../gplx/brys/Bry_fmtr_arg_bfr_preserve.java | 23 + .../gplx/brys/Bry_fmtr_arg_bry.java | 23 + .../gplx/brys/Bry_fmtr_arg_byt.java | 23 + .../gplx/brys/Bry_fmtr_arg_decimal_int.java | 25 + .../gplx/brys/Bry_fmtr_arg_fmtr.java | 25 + .../gplx/brys/Bry_fmtr_arg_int.java | 23 + .../gplx/brys/Bry_fmtr_arg_time.java | 55 + .../gplx/brys/Bry_fmtr_arg_time_tst.java | 42 + .../src_120_basicDataType/gplx/DateAdp.java | 152 ++ .../src_120_basicDataType/gplx/DateAdp_.java | 119 ++ .../gplx/DateAdp__tst.java | 68 + .../gplx/DateAdp_parser.java | 120 ++ .../gplx/DateAdp_parser_tst.java | 34 + .../gplx/DecimalAdp.java | 67 + .../gplx/DecimalAdp_.java | 57 + .../gplx/DecimalAdp__tst.java | 62 + .../src_120_basicDataType/gplx/EnmMgr.java | 72 + 100_core/src_120_basicDataType/gplx/Enm_.java | 30 + .../src_120_basicDataType/gplx/Guid_adp.java | 22 + .../src_120_basicDataType/gplx/Guid_adp_.java | 24 + .../gplx/Guid_adp__tst.java | 28 + .../src_120_basicDataType/gplx/Io_url.java | 98 ++ .../src_120_basicDataType/gplx/Io_url_.java | 96 + .../src_120_basicDataType/gplx/KeyVal.java | 31 + .../gplx/KeyValHash.java | 60 + .../gplx/KeyValHash_tst.java | 36 + .../gplx/KeyValList.java | 36 + .../src_120_basicDataType/gplx/KeyVal_.java | 104 ++ .../src_120_basicDataType/gplx/Math_.java | 72 + .../src_120_basicDataType/gplx/Math__tst.java | 61 + .../src_120_basicDataType/gplx/ObjAry.java | 36 + .../src_120_basicDataType/gplx/RandomAdp.java | 24 + .../gplx/RandomAdp_.java | 30 + .../gplx/TimeSpanAdp.java | 85 + .../gplx/TimeSpanAdp_.java | 162 ++ .../gplx/TimeSpanAdp__parse_tst.java | 54 + .../gplx/TimeSpanAdp_basic_tst.java | 87 + .../gplx/TimeSpanAdp_xtoStr_tst.java | 59 + .../gplx/Url_encoder_interface.java | 27 + 100_core/src_120_basicDataType/gplx/Yn.java | 78 + 100_core/src_140_list/gplx/Hash_adp.java | 31 + 100_core/src_140_list/gplx/Hash_adp_.java | 38 + 100_core/src_140_list/gplx/Hash_adp_bry.java | 184 ++ .../src_140_list/gplx/Hash_adp_bry_tst.java | 68 + 100_core/src_140_list/gplx/List_adp.java | 73 + 100_core/src_140_list/gplx/List_adp_.java | 66 + 100_core/src_140_list/gplx/List_adp_base.java | 166 ++ .../src_140_list/gplx/List_adp_sorter.java | 73 + .../gplx/List_adp_sorter_tst.java | 37 + 100_core/src_140_list/gplx/List_adp_tst.java | 222 +++ 100_core/src_140_list/gplx/Ordered_hash.java | 31 + 100_core/src_140_list/gplx/Ordered_hash_.java | 30 + .../src_140_list/gplx/Ordered_hash_base.java | 94 + .../src_140_list/gplx/Ordered_hash_tst.java | 39 + .../src_140_list/gplx/lists/ComparerAble.java | 20 + .../gplx/lists/ComparerAble_.java | 21 + .../src_140_list/gplx/lists/EnumerAble.java | 19 + .../gplx/lists/Hash_adp_base.java | 57 + .../gplx/lists/Hash_adp_list.java | 40 + .../gplx/lists/Iterator_null.java | 24 + .../src_140_list/gplx/lists/StackAdp.java | 26 + .../src_140_list/gplx/lists/StackAdp_.java | 41 + .../src_140_list/gplx/lists/StackAdp_tst.java | 33 + .../src_150_text/gplx/intl/Gfo_case_itm.java | 24 + .../src_150_text/gplx/intl/Gfo_case_mgr.java | 22 + .../src_150_text/gplx/intl/Gfo_case_mgr_.java | 21 + 100_core/src_150_text/gplx/intl/Utf16_.java | 137 ++ .../src_150_text/gplx/intl/Utf16__tst.java | 59 + 100_core/src_150_text/gplx/intl/Utf8_.java | 117 ++ .../src_150_text/gplx/intl/Utf8__tst.java | 69 + .../gplx/texts/Base32Converter.java | 99 ++ .../gplx/texts/Base64Converter.java | 79 + .../gplx/texts/BaseXXConverter_tst.java | 58 + .../src_150_text/gplx/texts/CharStream.java | 67 + .../gplx/texts/CharStream_tst.java | 61 + .../src_150_text/gplx/texts/HexDecUtl.java | 96 + .../gplx/texts/HexDecUtl_tst.java | 63 + 100_core/src_150_text/gplx/texts/RegxAdp.java | 64 + .../src_150_text/gplx/texts/RegxAdp_.java | 28 + .../src_150_text/gplx/texts/RegxAdp__tst.java | 93 + .../gplx/texts/RegxAdp_mpo_find.java | 36 + .../gplx/texts/RegxAdp_mpo_replace.java | 27 + .../src_150_text/gplx/texts/RegxBldr.java | 62 + .../src_150_text/gplx/texts/RegxGroup.java | 26 + .../src_150_text/gplx/texts/RegxMatch.java | 28 + .../gplx/texts/RegxPatn_cls_ioMatch.java | 34 + .../gplx/texts/RegxPatn_cls_ioMatch_.java | 53 + .../gplx/texts/RegxPatn_cls_ioMatch_tst.java | 58 + .../gplx/texts/RegxPatn_cls_like.java | 31 + .../gplx/texts/RegxPatn_cls_like_.java | 63 + .../gplx/texts/RegxPatn_cls_like_tst.java | 86 + .../gplx/texts/StringTableBldr.java | 57 + .../gplx/texts/StringTableBldr_tst.java | 59 + .../gplx/texts/StringTableCol.java | 39 + .../gplx/texts/StringTableColAlign.java | 29 + .../src_160_hash/gplx/security/HashAlgo.java | 24 + .../src_160_hash/gplx/security/HashAlgo_.java | 93 + .../gplx/security/HashAlgo_md5_tst.java | 81 + .../gplx/security/HashAlgo_sha1_tst.java | 81 + .../gplx/security/HashAlgo_tth192.java | 1005 +++++++++++ .../security/HashAlgo_tth192_tree_tst.java | 65 + .../gplx/security/HashAlgo_tth192_tst.java | 58 + .../gplx/security/HashDlgWtr_tst.java | 41 + 100_core/src_200_io/gplx/Io_mgr.java | 162 ++ 100_core/src_200_io/gplx/Io_mgr__tst.java | 100 ++ 100_core/src_200_io/gplx/ios/IoEngine.java | 154 ++ .../src_200_io/gplx/ios/IoEnginePool.java | 34 + 100_core/src_200_io/gplx/ios/IoEngine_.java | 30 + .../src_200_io/gplx/ios/IoEngine_base.java | 57 + .../src_200_io/gplx/ios/IoEngine_memory.java | 200 +++ .../src_200_io/gplx/ios/IoEngine_system.java | 636 +++++++ .../gplx/ios/IoEngine_xrg_deleteDir.java | 34 + .../gplx/ios/IoEngine_xrg_deleteFil.java | 30 + .../gplx/ios/IoEngine_xrg_downloadFil.java | 69 + .../ios/IoEngine_xrg_fil_affects1_base.java | 25 + .../gplx/ios/IoEngine_xrg_loadFilStr.java | 44 + .../gplx/ios/IoEngine_xrg_openRead.java | 35 + .../gplx/ios/IoEngine_xrg_openWrite.java | 31 + .../gplx/ios/IoEngine_xrg_queryDir.java | 55 + .../gplx/ios/IoEngine_xrg_recycleFil.java | 59 + .../gplx/ios/IoEngine_xrg_saveFilStr.java | 33 + .../gplx/ios/IoEngine_xrg_xferDir.java | 37 + .../gplx/ios/IoEngine_xrg_xferFil.java | 34 + 100_core/src_200_io/gplx/ios/IoErr.java | 30 + 100_core/src_200_io/gplx/ios/IoItmAttrib.java | 25 + .../src_200_io/gplx/ios/IoItmClassXtn.java | 32 + 100_core/src_200_io/gplx/ios/IoItmDir.java | 71 + 100_core/src_200_io/gplx/ios/IoItmDir_.java | 55 + 100_core/src_200_io/gplx/ios/IoItmFil.java | 42 + 100_core/src_200_io/gplx/ios/IoItmFil_.java | 31 + .../src_200_io/gplx/ios/IoItmFil_mem.java | 39 + 100_core/src_200_io/gplx/ios/IoItmHash.java | 43 + 100_core/src_200_io/gplx/ios/IoItmList.java | 76 + 100_core/src_200_io/gplx/ios/IoItm_base.java | 53 + 100_core/src_200_io/gplx/ios/IoItm_base_.java | 26 + .../src_200_io/gplx/ios/IoRecycleBin.java | 60 + 100_core/src_200_io/gplx/ios/IoStream.java | 33 + 100_core/src_200_io/gplx/ios/IoStream_.java | 180 ++ .../src_200_io/gplx/ios/IoStream_mem.java | 70 + .../src_200_io/gplx/ios/IoStream_mem_tst.java | 30 + .../src_200_io/gplx/ios/IoStream_mock.java | 45 + .../gplx/ios/IoStream_mock_tst.java | 48 + .../gplx/ios/IoStream_stream_rdr.java | 39 + 100_core/src_200_io/gplx/ios/IoUrlInfo.java | 244 +++ .../src_200_io/gplx/ios/IoUrlInfoRegy.java | 52 + 100_core/src_200_io/gplx/ios/IoUrlInfo_.java | 34 + .../src_200_io/gplx/ios/IoUrlTypeRegy.java | 76 + 100_core/src_200_io/gplx/ios/IoZipWkr.java | 40 + .../src_200_io/gplx/ios/IoZipWkr_tst.java | 28 + .../src_200_io/gplx/ios/Io_download_fmt.java | 94 + .../gplx/ios/Io_download_fmt_tst.java | 73 + 100_core/src_200_io/gplx/ios/Io_fil.java | 38 + 100_core/src_200_io/gplx/ios/Io_fil_mkr.java | 24 + 100_core/src_200_io/gplx/ios/Io_size_.java | 116 ++ .../src_200_io/gplx/ios/Io_size__tst.java | 69 + 100_core/src_200_io/gplx/ios/Io_stream_.java | 55 + .../src_200_io/gplx/ios/Io_stream_rdr.java | 30 + .../src_200_io/gplx/ios/Io_stream_rdr_.java | 266 +++ .../gplx/ios/Io_stream_rdr_tst.java | 56 + .../src_200_io/gplx/ios/Io_stream_wtr.java | 28 + .../src_200_io/gplx/ios/Io_stream_wtr_.java | 213 +++ .../src_200_io/gplx/ios/Io_url_obj_ref.java | 30 + 100_core/src_210_env/gplx/ClassAdp_.java | 45 + 100_core/src_210_env/gplx/Env_.java | 98 ++ 100_core/src_210_env/gplx/JarAdp_.java | 33 + 100_core/src_210_env/gplx/Op_sys.java | 85 + 100_core/src_210_env/gplx/Op_sys_.java | 34 + 100_core/src_210_env/gplx/ProcessAdp.java | 354 ++++ 100_core/src_210_env/gplx/ProcessAdp_tst.java | 32 + 100_core/src_220_console/gplx/ConsoleAdp.java | 68 + 100_core/src_220_console/gplx/ConsoleDlg.java | 28 + .../src_220_console/gplx/ConsoleDlg_.java | 32 + .../src_220_console/gplx/ConsoleDlg_dev.java | 49 + .../src_300_classXtn/gplx/BoolClassXtn.java | 41 + .../src_300_classXtn/gplx/ByteClassXtn.java | 28 + 100_core/src_300_classXtn/gplx/ClassXtn.java | 29 + .../src_300_classXtn/gplx/ClassXtnPool.java | 39 + .../src_300_classXtn/gplx/ClassXtn_base.java | 28 + .../gplx/DateAdpClassXtn.java | 28 + .../gplx/DateAdpClassXtn_tst.java | 28 + .../gplx/DecimalAdpClassXtn.java | 27 + .../src_300_classXtn/gplx/DoubleClassXtn.java | 26 + .../src_300_classXtn/gplx/FloatClassXtn.java | 26 + .../src_300_classXtn/gplx/IntClassXtn.java | 28 + .../src_300_classXtn/gplx/IoUrlClassXtn.java | 29 + .../src_300_classXtn/gplx/LongClassXtn.java | 27 + .../src_300_classXtn/gplx/ObjectClassXtn.java | 27 + .../src_300_classXtn/gplx/StringClassXtn.java | 28 + .../gplx/TimeSpanAdpClassXtn.java | 28 + 100_core/src_310_gfoNde/gplx/GfoFld.java | 28 + 100_core/src_310_gfoNde/gplx/GfoFldList.java | 27 + 100_core/src_310_gfoNde/gplx/GfoFldList_.java | 63 + 100_core/src_310_gfoNde/gplx/GfoNde.java | 72 + 100_core/src_310_gfoNde/gplx/GfoNdeFxt.java | 35 + 100_core/src_310_gfoNde/gplx/GfoNdeList.java | 27 + 100_core/src_310_gfoNde/gplx/GfoNdeList_.java | 40 + 100_core/src_310_gfoNde/gplx/GfoNde_.java | 46 + 100_core/src_311_gfoObj/gplx/GfoEvMgr.java | 131 ++ .../src_311_gfoObj/gplx/GfoEvMgrOwner.java | 21 + 100_core/src_311_gfoObj/gplx/GfoEvMgr_.java | 45 + .../src_311_gfoObj/gplx/GfoEvMgr_tst.java | 69 + 100_core/src_311_gfoObj/gplx/GfoEvObj.java | 19 + 100_core/src_311_gfoObj/gplx/GfoInvkAble.java | 28 + .../src_311_gfoObj/gplx/GfoInvkAbleCmd.java | 35 + .../src_311_gfoObj/gplx/GfoInvkAble_.java | 37 + .../src_311_gfoObj/gplx/GfoInvkCmdMgr.java | 68 + .../gplx/GfoInvkCmdMgrOwner.java | 21 + .../src_311_gfoObj/gplx/GfoInvkRootWkr.java | 21 + .../src_311_gfoObj/gplx/GfoInvkXtoStr.java | 43 + 100_core/src_311_gfoObj/gplx/GfoMsg.java | 71 + 100_core/src_311_gfoObj/gplx/GfoMsgUtl.java | 25 + 100_core/src_311_gfoObj/gplx/GfoMsg_.java | 270 +++ 100_core/src_311_gfoObj/gplx/GfoMsg_tst.java | 51 + 100_core/src_311_gfoObj/gplx/GfoTemplate.java | 21 + .../gplx/GfoTemplateFactory.java | 32 + 100_core/src_330_store/gplx/DataRdr.java | 51 + 100_core/src_330_store/gplx/DataRdr_.java | 68 + 100_core/src_330_store/gplx/DataWtr.java | 32 + 100_core/src_330_store/gplx/DataWtr_.java | 48 + 100_core/src_330_store/gplx/DataWtr_base.java | 52 + 100_core/src_330_store/gplx/SrlMgr.java | 35 + 100_core/src_330_store/gplx/SrlObj.java | 22 + .../gplx/stores/DataRdr_base.java | 214 +++ .../gplx/stores/DataRdr_mem.java | 78 + .../src_330_store/gplx/stores/GfoNdeRdr.java | 21 + .../src_330_store/gplx/stores/GfoNdeRdr_.java | 48 + .../gplx/stores/xmls/XmlDataRdr.java | 77 + .../gplx/stores/xmls/XmlDataRdr_.java | 25 + .../gplx/stores/xmls/XmlDataWtr_.java | 113 ++ .../gplx/stores/dsvs/DsvDataRdrOpts.java | 25 + .../gplx/stores/dsvs/DsvDataRdr_.java | 248 +++ .../stores/dsvs/DsvDataRdr_csv_dat_tst.java | 216 +++ .../stores/dsvs/DsvDataRdr_dsv_dat_tst.java | 70 + .../stores/dsvs/DsvDataRdr_dsv_hdr_tst.java | 82 + .../stores/dsvs/DsvDataRdr_dsv_misc_tst.java | 76 + .../stores/dsvs/DsvDataRdr_layout_tst.java | 131 ++ .../gplx/stores/dsvs/DsvDataWtr.java | 115 ++ .../gplx/stores/dsvs/DsvDataWtr_.java | 31 + .../gplx/stores/dsvs/DsvDataWtr_csv_tst.java | 100 ++ .../gplx/stores/dsvs/DsvDataWtr_tbls_tst.java | 73 + .../gplx/stores/dsvs/DsvHeaderList.java | 44 + .../gplx/stores/dsvs/DsvStoreLayout.java | 51 + .../gplx/stores/dsvs/DsvSymbols.java | 52 + 100_core/src_400_gfs/gplx/GfsCore.java | 167 ++ 100_core/src_400_gfs/gplx/GfsCoreHelp.java | 73 + 100_core/src_400_gfs/gplx/GfsCore_tst.java | 113 ++ 100_core/src_400_gfs/gplx/GfsCtx.java | 65 + 100_core/src_400_gfs/gplx/GfsLibIni.java | 21 + 100_core/src_400_gfs/gplx/GfsLibIni_core.java | 35 + 100_core/src_400_gfs/gplx/GfsRegy.java | 54 + 100_core/src_400_gfs/gplx/GfsTypeNames.java | 28 + 100_core/src_400_gfs/gplx/Gfs_Date_tst.java | 42 + .../src_410_gfoCfg/gplx/GfoMsgParser.java | 21 + 100_core/src_410_gfoCfg/gplx/GfoRegy.java | 94 + 100_core/src_410_gfoCfg/gplx/GfoRegyItm.java | 31 + .../gplx/GfoRegy_RegDir_tst.java | 61 + .../gplx/GfoRegy_basic_tst.java | 31 + 100_core/src_420_usrMsg/gplx/Gfo_log_bfr.java | 29 + 100_core/src_420_usrMsg/gplx/Gfo_usr_dlg.java | 35 + .../src_420_usrMsg/gplx/Gfo_usr_dlg_.java | 48 + .../src_420_usrMsg/gplx/Gfo_usr_dlg__gui.java | 27 + .../gplx/Gfo_usr_dlg__gui_.java | 41 + .../gplx/Gfo_usr_dlg__gui_test.java | 29 + .../src_420_usrMsg/gplx/Gfo_usr_dlg__log.java | 31 + .../gplx/Gfo_usr_dlg__log_.java | 35 + .../gplx/Gfo_usr_dlg__log_base.java | 123 ++ .../src_420_usrMsg/gplx/Gfo_usr_dlg_base.java | 55 + 100_core/src_420_usrMsg/gplx/UsrDlg.java | 51 + 100_core/src_420_usrMsg/gplx/UsrDlg_.java | 21 + 100_core/src_420_usrMsg/gplx/UsrMsg.java | 68 + 100_core/src_420_usrMsg/gplx/UsrMsgWkr.java | 50 + 100_core/src_420_usrMsg/gplx/UsrMsgWkr_.java | 27 + .../gplx/UsrMsgWkr_console.java | 34 + .../src_420_usrMsg/gplx/UsrMsgWkr_test.java | 38 + 100_core/src_800_tst/gplx/PerfLogMgr_fxt.java | 66 + 100_core/src_800_tst/gplx/Tfds.java | 245 +++ .../src_800_tst/gplx/TfdsEqListItmStr.java | 21 + 100_core/src_800_tst/gplx/Tfds_tst.java | 29 + 100_core/src_900_xml/gplx/Base64_utl.java | 24 + 100_core/src_900_xml/gplx/Base85_utl.java | 66 + 100_core/src_900_xml/gplx/Base85_utl_tst.java | 56 + 100_core/src_900_xml/gplx/HierStrBldr.java | 56 + .../src_900_xml/gplx/HierStrBldr_tst.java | 47 + 100_core/src_900_xml/gplx/xmls/XmlAtr.java | 24 + .../src_900_xml/gplx/xmls/XmlAtrList.java | 37 + 100_core/src_900_xml/gplx/xmls/XmlDoc.java | 24 + 100_core/src_900_xml/gplx/xmls/XmlDoc_.java | 53 + .../src_900_xml/gplx/xmls/XmlDoc_tst.java | 71 + .../gplx/xmls/XmlFileSplitter.java | 140 ++ .../gplx/xmls/XmlFileSplitterOpts.java | 27 + .../gplx/xmls/XmlFileSplitter_tst.java | 88 + 100_core/src_900_xml/gplx/xmls/XmlNde.java | 51 + .../src_900_xml/gplx/xmls/XmlNdeList.java | 35 + .../src_900_xml/gplx/xmls/XmlSplitRdr.java | 51 + .../src_900_xml/gplx/xmls/XmlSplitWtr.java | 40 + 100_core/src_900_xml/gplx/xmls/Xpath_.java | 106 ++ .../src_900_xml/gplx/xmls/Xpath__tst.java | 44 + 100_core/tst/gplx/EnmParser_tst.java | 60 + 100_core/tst/gplx/GfoMsg_rdr_tst.java | 57 + 100_core/tst/gplx/GfoTreeBldr_fxt.java | 32 + 100_core/tst/gplx/TfdsTstr_fxt.java | 99 ++ 100_core/tst/gplx/ios/IoEngineFxt.java | 54 + .../tst/gplx/ios/IoEngine_dir_basic_base.java | 79 + .../ios/IoEngine_dir_basic_memory_tst.java | 24 + .../ios/IoEngine_dir_basic_system_tst.java | 28 + .../tst/gplx/ios/IoEngine_dir_deep_base.java | 126 ++ .../ios/IoEngine_dir_deep_memory_tst.java | 36 + .../ios/IoEngine_dir_deep_system_tst.java | 25 + .../tst/gplx/ios/IoEngine_fil_basic_base.java | 176 ++ .../ios/IoEngine_fil_basic_memory_tst.java | 57 + .../ios/IoEngine_fil_basic_system_tst.java | 58 + .../tst/gplx/ios/IoEngine_fil_xfer_base.java | 106 ++ .../ios/IoEngine_fil_xfer_memory_tst.java | 28 + .../ios/IoEngine_fil_xfer_system_tst.java | 28 + .../gplx/ios/IoEngine_stream_xfer_tst.java | 49 + .../gplx/ios/IoEngine_xrg_queryDir_tst.java | 65 + .../gplx/ios/IoEngine_xrg_recycleFil_tst.java | 32 + .../ios/IoItmDir_FetchDeepOrNull_tst.java | 40 + 100_core/tst/gplx/ios/IoItm_fxt.java | 34 + .../tst/gplx/ios/IoUrlInfo_alias_tst.java | 58 + 100_core/tst/gplx/ios/IoUrl_lnx_tst.java | 55 + 100_core/tst/gplx/ios/IoUrl_map_tst.java | 31 + 100_core/tst/gplx/ios/IoUrl_wnt_tst.java | 98 ++ .../tst/gplx/stores/GfoNdeRdr_read_tst.java | 48 + 100_core/tst/gplx/stores/GfoNdeRdr_tst.java | 189 ++ .../tst/gplx/stores/xmls/XmlDataRdr_tst.java | 102 ++ .../tst/gplx/stores/xmls/XmlDataWtr_tst.java | 95 + 100_core/xtn/gplx/Internal.java | 20 + 100_core/xtn/gplx/MainClass.java | 22 + 100_core/xtn/gplx/New.java | 20 + 100_core/xtn/gplx/Virtual.java | 20 + 110_gfml/.classpath | 14 + 110_gfml/.project | 17 + 110_gfml/src_100_tkn/gplx/gfml/GfmlLxr.java | 34 + 110_gfml/src_100_tkn/gplx/gfml/GfmlLxr_.java | 217 +++ 110_gfml/src_100_tkn/gplx/gfml/GfmlObj.java | 29 + .../src_100_tkn/gplx/gfml/GfmlObjList.java | 25 + 110_gfml/src_100_tkn/gplx/gfml/GfmlTkn.java | 46 + 110_gfml/src_100_tkn/gplx/gfml/GfmlTkn_.java | 65 + 110_gfml/src_100_tkn/gplx/gfml/GfmlTrie.java | 114 ++ .../src_100_tkn/gplx/gfml/IntObjHash.java | 77 + 110_gfml/src_200_type/gplx/gfml/GfmlFld.java | 40 + .../src_200_type/gplx/gfml/GfmlFldList.java | 34 + 110_gfml/src_200_type/gplx/gfml/GfmlType.java | 53 + .../gplx/gfml/GfmlTypeCompiler.java | 105 ++ .../src_200_type/gplx/gfml/GfmlTypeHash.java | 49 + .../src_200_type/gplx/gfml/GfmlTypeMakr.java | 67 + .../src_200_type/gplx/gfml/GfmlTypeMgr.java | 140 ++ 110_gfml/src_300_gdoc/gplx/gfml/GfmlAtr.java | 76 + 110_gfml/src_300_gdoc/gplx/gfml/GfmlDoc.java | 45 + .../src_300_gdoc/gplx/gfml/GfmlDocLxrs.java | 130 ++ .../src_300_gdoc/gplx/gfml/GfmlDocPos.java | 71 + .../src_300_gdoc/gplx/gfml/GfmlDocWtr_.java | 40 + 110_gfml/src_300_gdoc/gplx/gfml/GfmlDoc_.java | 46 + 110_gfml/src_300_gdoc/gplx/gfml/GfmlItm.java | 29 + .../src_300_gdoc/gplx/gfml/GfmlItmHnds.java | 24 + .../src_300_gdoc/gplx/gfml/GfmlItmKeys.java | 61 + 110_gfml/src_300_gdoc/gplx/gfml/GfmlNde.java | 113 ++ .../src_300_gdoc/gplx/gfml/GfmlScopeItm.java | 73 + .../src_400_pragma/gplx/gfml/GfmlPragma.java | 50 + .../gplx/gfml/GfmlPragmaDefault.java | 133 ++ .../gplx/gfml/GfmlPragmaLxrFrm.java | 64 + .../gplx/gfml/GfmlPragmaLxrSym.java | 56 + .../gplx/gfml/GfmlPragmaType.java | 79 + .../gplx/gfml/GfmlPragmaVar.java | 78 + .../src_400_pragma/gplx/gfml/GfmlVarCtx.java | 62 + .../src_400_pragma/gplx/gfml/GfmlVarItm.java | 32 + .../src_400_pragma/gplx/gfml/GfmlVarTkn.java | 39 + .../src_500_build/gplx/gfml/GfmlBldr.java | 74 + .../src_500_build/gplx/gfml/GfmlBldrCmd.java | 40 + .../src_500_build/gplx/gfml/GfmlBldrCmds.java | 128 ++ .../src_500_build/gplx/gfml/GfmlBldr_.java | 44 + .../src_500_build/gplx/gfml/GfmlFrame.java | 35 + .../src_500_build/gplx/gfml/GfmlFrame_.java | 87 + .../gplx/gfml/GfmlFrame_nde.java | 250 +++ .../gplx/gfml/GfmlFrame_ndeTknMgr.java | 90 + .../gplx/gfml/GfmlStringHighlighter.java | 103 ++ .../src_600_rdrWtr/gplx/gfml/GfmlDataNde.java | 102 ++ .../src_600_rdrWtr/gplx/gfml/GfmlDataRdr.java | 47 + .../gplx/gfml/GfmlDataRdr_base.java | 60 + .../src_600_rdrWtr/gplx/gfml/GfmlDataWtr.java | 99 ++ .../gplx/gfml/GfmlDataWtrOpts.java | 27 + .../gplx/gfml/GfoMsgParser_gfml.java | 22 + .../src_600_rdrWtr/gplx/gfml/SqlConsts.java | 42 + 110_gfml/src_600_rdrWtr/gplx/gfml/SqlDoc.java | 144 ++ 110_gfml/tst/gplx/gfml/GfmlDataRdr_tst.java | 120 ++ .../tst/gplx/gfml/yfxts_GfmlParse_fxt.java | 79 + .../gplx/gfml/yfxts_GfmlTypeCompiler_fxt.java | 102 ++ .../gplx/gfml/ymoks_GfmlAtr_GfmlNde_mok.java | 182 ++ 110_gfml/tst/gplx/gfml/ymoks_GfmlTkn_mok.java | 77 + .../gplx/gfml/ymoks_GfmlTyp_GfmlFld_mok.java | 83 + 110_gfml/tst/gplx/gfml/ymoks_UsrMsg_mok.java | 36 + .../tst/gplx/gfml/z011_IntObjHash_tst.java | 63 + 110_gfml/tst/gplx/gfml/z012_GfmlTrie_tst.java | 73 + .../tst/gplx/gfml/z015_GfmlDocPos_tst.java | 52 + .../tst/gplx/gfml/z016_GfmlScopeList_tst.java | 55 + .../gfml/z017_GfmlStringHighlighter_tst.java | 53 + .../gplx/gfml/z051_GfmlFldPool_keyed_tst.java | 77 + .../tst/gplx/gfml/z081_GfmlDataWtr_tst.java | 71 + .../gplx/gfml/z082_GfmlDataWtrOpts_tst.java | 54 + .../tst/gplx/gfml/z091_GfmlLxr_basic_tst.java | 68 + .../gplx/gfml/z101_core_ndeInline_tst.java | 50 + .../gplx/gfml/z102_core_whitespace_tst.java | 79 + .../tst/gplx/gfml/z103_core_elmKey_tst.java | 52 + .../tst/gplx/gfml/z111_core_comment0_tst.java | 51 + .../tst/gplx/gfml/z112_core_comment1_tst.java | 69 + .../tst/gplx/gfml/z120_quotes_eval0_tst.java | 41 + .../gplx/gfml/z121_quotes_quotes0_tst.java | 52 + .../gfml/z122_quotes_quote0_eval0_tst.java | 64 + .../gplx/gfml/z123_quotes_quoteBlock_tst.java | 40 + .../gplx/gfml/z124_quotes_quoteFold_tst.java | 61 + .../tst/gplx/gfml/z151_ndeSubs_basic_tst.java | 65 + .../tst/gplx/gfml/z152_ndeSubs_data_tst.java | 68 + .../gplx/gfml/z161_ndeHdrs_inline_tst.java | 46 + .../tst/gplx/gfml/z162_ndeHdrs_err_tst.java | 33 + .../tst/gplx/gfml/z163_ndeHdrs_body_tst.java | 52 + .../tst/gplx/gfml/z164_hdeHdrs_data_tst.java | 53 + .../tst/gplx/gfml/z181_ndeDots_basic_tst.java | 65 + .../tst/gplx/gfml/z182_ndeDots_subs_tst.java | 73 + .../gplx/gfml/z183_ndeDots_parens_tst.java | 140 ++ .../gplx/gfml/z184_ndeDots_atrSpr_tst.java | 47 + .../gplx/gfml/z191_ndeProps_basic_tst.java | 120 ++ .../tst/gplx/gfml/z192_ndeProps_dots_tst.java | 39 + .../tst/gplx/gfml/z400_GfmlTypeMakr_tst.java | 66 + .../gfml/z401_types_compile_basic_tst.java | 65 + .../gfml/z402_types_compile_implicit_tst.java | 63 + .../gfml/z403_types_compile_default_tst.java | 64 + .../gfml/z411_types_apply_atrs_basic_tst.java | 66 + .../gfml/z421_types_apply_ndes_basic_tst.java | 52 + .../gfml/z422_types_apply_ndes_multi_tst.java | 74 + .../gfml/z423_types_apply_ndes_misc_tst.java | 49 + .../gfml/z424_types_apply_ndes_nest_tst.java | 67 + .../gplx/gfml/z441_types_parse_basic_tst.java | 53 + .../gfml/z442_types_parse_default_tst.java | 101 ++ .../gplx/gfml/z443_types_parse_keyd_tst.java | 50 + .../gfml/z450_fx_GfmlDefaultItem_fxt.java | 41 + .../tst/gplx/gfml/z451_dflts_compile_tst.java | 46 + .../tst/gplx/gfml/z452_dflts_exec_tst.java | 96 + .../tst/gplx/gfml/z455_dflts_scope_tst.java | 49 + .../tst/gplx/gfml/z456_dflts_parse_tst.java | 35 + .../tst/gplx/gfml/z481_vars_compile_tst.java | 35 + .../tst/gplx/gfml/z482_vars_parse_tst.java | 85 + .../tst/gplx/gfml/z501_lxr_parse_tst.java | 88 + 110_gfml/tst/gplx/gfml/z601_edit_atr_tst.java | 130 ++ 110_gfml/tst/gplx/gfml/z602_edit_nde_tst.java | 24 + .../gplx/gfml/z801_useCase_DataRdr_tst.java | 81 + .../gfml/z803_useCase_KbdKeyboard_tst.java | 87 + .../gplx/gfml/z811_useCase_GfmlIoSql_tst.java | 50 + 110_gfml/tst/gplx/gfml/z901_perf_tst.java | 117 ++ 140_dbs/.classpath | 14 + 140_dbs/.project | 17 + .../lib/mysql-connector-java-5.1.12-bin.jar | Bin 0 -> 732695 bytes 140_dbs/lib/postgresql-8.4-701.jdbc4.jar | Bin 0 -> 510170 bytes 140_dbs/lib/sqlite-jdbc-3.7.15-M1.jar | Bin 0 -> 3677896 bytes 140_dbs/src/gplx/dbs/Db_cmd_mode.java | 42 + 140_dbs/src/gplx/dbs/Db_conn.java | 80 + 140_dbs/src/gplx/dbs/Db_conn_.java | 38 + 140_dbs/src/gplx/dbs/Db_conn_bldr.java | 36 + 140_dbs/src/gplx/dbs/Db_conn_bldr_data.java | 24 + 140_dbs/src/gplx/dbs/Db_conn_bldr_wkr.java | 62 + 140_dbs/src/gplx/dbs/Db_conn_info.java | 25 + 140_dbs/src/gplx/dbs/Db_conn_info_.java | 56 + 140_dbs/src/gplx/dbs/Db_conn_info__base.java | 52 + 140_dbs/src/gplx/dbs/Db_conn_info_tst.java | 46 + 140_dbs/src/gplx/dbs/Db_conn_pool.java | 46 + 140_dbs/src/gplx/dbs/Db_crt_.java | 64 + 140_dbs/src/gplx/dbs/Db_crt_tst.java | 53 + 140_dbs/src/gplx/dbs/Db_idx_itm.java | 34 + 140_dbs/src/gplx/dbs/Db_meta_fld.java | 47 + 140_dbs/src/gplx/dbs/Db_meta_fld_list.java | 80 + 140_dbs/src/gplx/dbs/Db_meta_idx.java | 35 + 140_dbs/src/gplx/dbs/Db_meta_tbl.java | 43 + 140_dbs/src/gplx/dbs/Db_qry.java | 24 + 140_dbs/src/gplx/dbs/Db_qry_.java | 51 + 140_dbs/src/gplx/dbs/Db_rdr.java | 34 + 140_dbs/src/gplx/dbs/Db_rdr_.java | 37 + 140_dbs/src/gplx/dbs/Db_rdr__basic.java | 46 + 140_dbs/src/gplx/dbs/Db_sql_select.java | 78 + 140_dbs/src/gplx/dbs/Db_stmt.java | 62 + 140_dbs/src/gplx/dbs/Db_stmt_.java | 58 + 140_dbs/src/gplx/dbs/Db_stmt_bldr.java | 48 + 140_dbs/src/gplx/dbs/engines/Db_engine.java | 43 + .../gplx/dbs/engines/Db_engine_sql_base.java | 109 ++ .../dbs/engines/mems/Db_conn_info__mem.java | 33 + .../gplx/dbs/engines/mems/Db_engine__mem.java | 56 + .../gplx/dbs/engines/mems/Db_rdr__mem.java | 44 + .../gplx/dbs/engines/mems/Db_stmt__mem.java | 140 ++ .../gplx/dbs/engines/mems/Mem_qry_set.java | 24 + .../src/gplx/dbs/engines/mems/Mem_row.java | 30 + .../src/gplx/dbs/engines/mems/Mem_tbl.java | 95 + .../dbs/engines/mysql/Mysql_conn_info.java | 41 + .../gplx/dbs/engines/mysql/Mysql_engine.java | 48 + .../dbs/engines/nulls/Noop_conn_info.java | 23 + .../gplx/dbs/engines/nulls/Noop_engine.java | 44 + .../engines/postgres/Postgres_conn_info.java | 42 + .../dbs/engines/postgres/Postgres_engine.java | 35 + .../dbs/engines/sqlite/Sqlite_conn_info.java | 47 + .../dbs/engines/sqlite/Sqlite_engine.java | 130 ++ .../dbs/engines/sqlite/Sqlite_engine_.java | 92 + .../dbs/engines/sqlite/Sqlite_schema_mgr.java | 66 + .../dbs/engines/sqlite/Sqlite_txn_mgr.java | 70 + .../dbs/engines/tdbs/TdbConnectInfo_tst.java | 32 + .../gplx/dbs/engines/tdbs/TdbDatabase.java | 47 + .../gplx/dbs/engines/tdbs/TdbDbLoadMgr.java | 49 + .../dbs/engines/tdbs/TdbDbLoadMgr_tst.java | 101 ++ .../gplx/dbs/engines/tdbs/TdbDbSaveMgr.java | 63 + .../dbs/engines/tdbs/TdbDbSaveMgr_tst.java | 77 + .../src/gplx/dbs/engines/tdbs/TdbDelete.java | 47 + .../src/gplx/dbs/engines/tdbs/TdbEngine.java | 90 + .../src/gplx/dbs/engines/tdbs/TdbFile.java | 31 + .../gplx/dbs/engines/tdbs/TdbFileList.java | 63 + .../src/gplx/dbs/engines/tdbs/TdbFlush.java | 34 + .../gplx/dbs/engines/tdbs/TdbFlush_tst.java | 119 ++ .../src/gplx/dbs/engines/tdbs/TdbInsert.java | 59 + .../src/gplx/dbs/engines/tdbs/TdbSelect.java | 99 ++ .../src/gplx/dbs/engines/tdbs/TdbStores.java | 32 + .../src/gplx/dbs/engines/tdbs/TdbTable.java | 65 + .../gplx/dbs/engines/tdbs/TdbTableList.java | 63 + .../src/gplx/dbs/engines/tdbs/TdbUpdate.java | 46 + .../gplx/dbs/engines/tdbs/Tdb_conn_info.java | 37 + 140_dbs/src/gplx/dbs/metas/Meta_fld_itm.java | 31 + 140_dbs/src/gplx/dbs/metas/Meta_fld_mgr.java | 26 + 140_dbs/src/gplx/dbs/metas/Meta_idx_itm.java | 23 + 140_dbs/src/gplx/dbs/metas/Meta_idx_mgr.java | 24 + 140_dbs/src/gplx/dbs/metas/Meta_itm_tid.java | 28 + 140_dbs/src/gplx/dbs/metas/Meta_tbl_itm.java | 24 + 140_dbs/src/gplx/dbs/metas/Meta_tbl_mgr.java | 24 + 140_dbs/src/gplx/dbs/metas/Meta_type_itm.java | 28 + .../dbs/metas/parsers/Meta_fld_wkr__base.java | 117 ++ .../dbs/metas/parsers/Meta_parser__fld.java | 118 ++ .../metas/parsers/Meta_parser__fld_tst.java | 71 + .../dbs/metas/parsers/Meta_parser__tbl.java | 57 + .../metas/parsers/Meta_parser__tbl_tst.java | 66 + .../gplx/dbs/metas/parsers/Sql_bry_rdr.java | 57 + .../dbs/metas/parsers/Sql_bry_rdr_tst.java | 52 + 140_dbs/src/gplx/dbs/qrys/Db_arg.java | 24 + .../src/gplx/dbs/qrys/Db_qry__select_cmd.java | 131 ++ .../gplx/dbs/qrys/Db_qry__select_in_tbl.java | 87 + .../src/gplx/dbs/qrys/Db_qry_arg_owner.java | 33 + 140_dbs/src/gplx/dbs/qrys/Db_qry_delete.java | 31 + 140_dbs/src/gplx/dbs/qrys/Db_qry_dml_tst.java | 44 + 140_dbs/src/gplx/dbs/qrys/Db_qry_flush.java | 37 + 140_dbs/src/gplx/dbs/qrys/Db_qry_insert.java | 67 + .../src/gplx/dbs/qrys/Db_qry_select_tst.java | 89 + 140_dbs/src/gplx/dbs/qrys/Db_qry_sql.java | 82 + 140_dbs/src/gplx/dbs/qrys/Db_qry_sql_tst.java | 47 + 140_dbs/src/gplx/dbs/qrys/Db_qry_update.java | 61 + 140_dbs/src/gplx/dbs/qrys/Db_stmt_cmd.java | 163 ++ 140_dbs/src/gplx/dbs/qrys/Db_stmt_sql.java | 177 ++ .../src/gplx/dbs/qrys/Db_stmt_sql_tst.java | 29 + 140_dbs/src/gplx/dbs/qrys/Db_val_type.java | 35 + 140_dbs/src/gplx/dbs/sqls/Db_fld.java | 23 + 140_dbs/src/gplx/dbs/sqls/Db_obj_ary_crt.java | 36 + 140_dbs/src/gplx/dbs/sqls/Db_obj_ary_tst.java | 42 + .../src/gplx/dbs/sqls/Db_sqlbldr__sqlite.java | 99 ++ 140_dbs/src/gplx/dbs/sqls/Db_sqlbldr_tst.java | 68 + 140_dbs/src/gplx/dbs/sqls/Sql_from.java | 27 + 140_dbs/src/gplx/dbs/sqls/Sql_group_by.java | 28 + 140_dbs/src/gplx/dbs/sqls/Sql_join_itm.java | 35 + .../src/gplx/dbs/sqls/Sql_join_itmType.java | 31 + 140_dbs/src/gplx/dbs/sqls/Sql_order_by.java | 28 + .../src/gplx/dbs/sqls/Sql_order_by_itm.java | 31 + .../gplx/dbs/sqls/Sql_order_by_sorter.java | 40 + 140_dbs/src/gplx/dbs/sqls/Sql_qry_wtr.java | 22 + 140_dbs/src/gplx/dbs/sqls/Sql_qry_wtr_.java | 24 + .../src/gplx/dbs/sqls/Sql_qry_wtr_ansi.java | 300 ++++ .../gplx/dbs/sqls/Sql_qry_wtr_ansi_tst.java | 99 ++ .../gplx/dbs/sqls/Sql_qry_wtr_iosql_tst.java | 60 + .../src/gplx/dbs/sqls/Sql_qry_wtr_tst.java | 60 + 140_dbs/src/gplx/dbs/sqls/Sql_select.java | 30 + .../src/gplx/dbs/sqls/Sql_select_fld_.java | 69 + .../gplx/dbs/sqls/Sql_select_fld_base.java | 45 + .../gplx/dbs/sqls/Sql_select_fld_list.java | 57 + 140_dbs/src/gplx/dbs/sqls/Sql_tbl_src.java | 29 + 140_dbs/src/gplx/dbs/utls/Db_cmd_backup.java | 66 + .../src/gplx/dbs/utls/Db_cmd_backup_tst.java | 31 + .../src/gplx/dbs/utls/Db_in_wkr__base.java | 49 + 140_dbs/src/gplx/dbs/utls/PoolIds.java | 51 + 140_dbs/src/gplx/dbs/utls/PoolIds_tst.java | 56 + 140_dbs/src/gplx/stores/DbMaprArg.java | 27 + 140_dbs/src/gplx/stores/DbMaprItm.java | 52 + 140_dbs/src/gplx/stores/DbMaprMgr.java | 48 + 140_dbs/src/gplx/stores/DbMaprMgr_tst.java | 140 ++ 140_dbs/src/gplx/stores/DbMaprRdr.java | 122 ++ 140_dbs/src/gplx/stores/DbMaprWtr.java | 115 ++ 140_dbs/src/gplx/stores/Db_data_rdr.java | 81 + 140_dbs/src/gplx/stores/Db_data_rdr_.java | 22 + 140_dbs/src/gplx/stores/MockDiscObj.java | 130 ++ 140_dbs/tst/gplx/dbs/DbTstDat.java | 24 + 140_dbs/tst/gplx/dbs/DbTstRow.java | 31 + 140_dbs/tst/gplx/dbs/Db_conn_fxt.java | 54 + 140_dbs/tst/gplx/dbs/Db_qry_fxt.java | 55 + 140_dbs/tst/gplx/dbs/GfoNdeTstr.java | 32 + .../tst/gplx/dbs/engines/db_CrudOps_tst.java | 129 ++ .../gplx/dbs/engines/db_DataTypes_tst.java | 79 + .../gplx/dbs/groupBys/GroupBys_base_tst.java | 95 + .../gplx/dbs/groupBys/GroupBys_mysql_tst.java | 28 + .../gplx/dbs/groupBys/GroupBys_tdb_tst.java | 29 + .../dbs/insertIntos/InsertIntos_base_tst.java | 60 + .../insertIntos/InsertIntos_mysql_tst.java | 24 + .../dbs/insertIntos/InsertIntos_tdb_tst.java | 24 + .../tst/gplx/dbs/joins/Joins_base_tst.java | 44 + 140_dbs/tst/gplx/dbs/joins/Joins_tdb_tst.java | 31 + .../gplx/dbs/orderBys/OrderBys_base_tst.java | 52 + .../gplx/dbs/orderBys/OrderBys_tdb_tst.java | 38 + 140_dbs/xtn/gplx/dbs/Bug_Utf8.java | 157 ++ 140_dbs/xtn/gplx/dbs/SqliteDbMain.java | 245 +++ 150_gfui/.classpath | 24 + 150_gfui/.project | 17 + 150_gfui/lib/swt.jar | Bin 0 -> 1918393 bytes 150_gfui/src_100_basic/gplx/gfui/DirInt.java | 35 + .../src_100_basic/gplx/gfui/GfuiAlign.java | 23 + .../src_100_basic/gplx/gfui/GfuiAlign_.java | 62 + .../src_100_basic/gplx/gfui/GfuiAxisType.java | 25 + .../gplx/gfui/GfuiBorderEdge.java | 57 + .../src_100_basic/gplx/gfui/PointAdp.java | 35 + .../src_100_basic/gplx/gfui/PointAdp_.java | 32 + 150_gfui/src_100_basic/gplx/gfui/RectAdp.java | 44 + .../src_100_basic/gplx/gfui/RectAdpF.java | 33 + .../src_100_basic/gplx/gfui/RectAdp_.java | 34 + 150_gfui/src_100_basic/gplx/gfui/SizeAdp.java | 36 + .../src_100_basic/gplx/gfui/SizeAdpF.java | 25 + .../src_100_basic/gplx/gfui/SizeAdpF_.java | 34 + .../src_100_basic/gplx/gfui/SizeAdp_.java | 42 + .../src_110_draw_core/gplx/gfui/ColorAdp.java | 56 + .../gplx/gfui/ColorAdp_.java | 118 ++ .../gplx/gfui/ColorAdp__tst.java | 58 + .../src_110_draw_core/gplx/gfui/FontAdp.java | 81 + .../gplx/gfui/FontStyleAdp.java | 23 + .../gplx/gfui/FontStyleAdp_.java | 68 + .../src_110_draw_core/gplx/gfui/PenAdp.java | 53 + .../src_110_draw_core/gplx/gfui/PenAdp_.java | 25 + .../gplx/gfui/SolidBrushAdp.java | 31 + .../gplx/gfui/SolidBrushAdp_.java | 38 + .../gplx/gfui/GfuiBorderMgr.java | 69 + .../src_120_draw_objs/gplx/gfui/GfxAdp.java | 29 + .../gplx/gfui/GfxAdpBase.java | 107 ++ .../src_120_draw_objs/gplx/gfui/GfxAdp_.java | 26 + .../gplx/gfui/GfxStringData.java | 115 ++ .../gplx/gfui/PaintArgs.java | 29 + 150_gfui/src_200_ipt/gplx/gfui/IptArg.java | 44 + .../gplx/gfui/IptArgChainMgr_tst.java | 62 + 150_gfui/src_200_ipt/gplx/gfui/IptArg_.java | 118 ++ 150_gfui/src_200_ipt/gplx/gfui/IptBnd.java | 24 + 150_gfui/src_200_ipt/gplx/gfui/IptBndMgr.java | 293 ++++ .../src_200_ipt/gplx/gfui/IptBndMgr_tst.java | 72 + 150_gfui/src_200_ipt/gplx/gfui/IptBnd_.java | 62 + .../src_200_ipt/gplx/gfui/IptBnd_chkBox.java | 42 + .../src_200_ipt/gplx/gfui/IptBnd_txt_cmd.java | 43 + .../gplx/gfui/IptBnd_txt_range.java | 96 + .../gplx/gfui/IptBnd_upDownRange.java | 58 + .../src_200_ipt/gplx/gfui/IptBndsOwner.java | 21 + 150_gfui/src_200_ipt/gplx/gfui/IptCfg.java | 92 + 150_gfui/src_200_ipt/gplx/gfui/IptCfgItm.java | 24 + .../src_200_ipt/gplx/gfui/IptCfgRegy.java | 33 + 150_gfui/src_200_ipt/gplx/gfui/IptCfg_.java | 31 + .../src_200_ipt/gplx/gfui/IptCfg_tst.java | 84 + .../src_200_ipt/gplx/gfui/IptEventData.java | 49 + .../src_200_ipt/gplx/gfui/IptEventMgr.java | 98 ++ .../src_200_ipt/gplx/gfui/IptEventType.java | 35 + .../src_200_ipt/gplx/gfui/IptEventType_.java | 57 + .../src_200_ipt/gplx/gfui/IptEvtDataKey.java | 36 + .../gplx/gfui/IptEvtDataKeyHeld.java | 31 + .../gplx/gfui/IptEvtDataMouse.java | 34 + 150_gfui/src_200_ipt/gplx/gfui/IptKey.java | 29 + .../src_200_ipt/gplx/gfui/IptKeyStrMgr.java | 75 + .../gplx/gfui/IptKeyStrMgr_tst.java | 59 + 150_gfui/src_200_ipt/gplx/gfui/IptKey_.java | 153 ++ .../src_200_ipt/gplx/gfui/IptKey__tst.java | 39 + .../src_200_ipt/gplx/gfui/IptMouseBtn.java | 24 + .../src_200_ipt/gplx/gfui/IptMouseBtn_.java | 54 + .../src_200_ipt/gplx/gfui/IptMouseMove.java | 23 + .../src_200_ipt/gplx/gfui/IptMouseWheel.java | 23 + .../src_200_ipt/gplx/gfui/IptMouseWheel_.java | 36 + 150_gfui/src_210_lyt/gplx/gfui/GftBand.java | 90 + .../src_210_lyt/gplx/gfui/GftBand_tst.java | 112 ++ 150_gfui/src_210_lyt/gplx/gfui/GftCell.java | 26 + 150_gfui/src_210_lyt/gplx/gfui/GftGrid.java | 138 ++ .../src_210_lyt/gplx/gfui/GftGrid_fx.java | 93 + 150_gfui/src_210_lyt/gplx/gfui/GftItem.java | 34 + .../src_210_lyt/gplx/gfui/GftSizeCalc.java | 60 + .../src_300_gxw/gplx/gfui/GxwBoxListener.java | 31 + .../src_300_gxw/gplx/gfui/GxwCbkHost.java | 35 + .../src_300_gxw/gplx/gfui/GxwCbkHost_.java | 86 + .../gplx/gfui/GxwCheckListBox.java | 31 + .../gplx/gfui/GxwCheckListBox_lang.java | 201 +++ .../src_300_gxw/gplx/gfui/GxwComboBox.java | 22 + .../gplx/gfui/GxwComboBox_lang.java | 108 ++ .../src_300_gxw/gplx/gfui/GxwCore_base.java | 43 + .../src_300_gxw/gplx/gfui/GxwCore_lang.java | 159 ++ .../src_300_gxw/gplx/gfui/GxwCore_mock.java | 45 + 150_gfui/src_300_gxw/gplx/gfui/GxwElem.java | 26 + .../gplx/gfui/GxwElemFactory_base.java | 74 + .../src_300_gxw/gplx/gfui/GxwElem_lang.java | 67 + .../gplx/gfui/GxwElem_mock_base.java | 74 + .../src_300_gxw/gplx/gfui/GxwListBox.java | 25 + .../gplx/gfui/GxwListBox_lang.java | 82 + .../gplx/gfui/GxwTextBox_lang.java | 216 +++ .../src_300_gxw/gplx/gfui/GxwTextFld.java | 43 + .../src_300_gxw/gplx/gfui/GxwTextHtml.java | 24 + .../gplx/gfui/GxwTextHtml_lang.java | 253 +++ .../gplx/gfui/GxwTextMemo_lang.java | 335 ++++ 150_gfui/src_300_gxw/gplx/gfui/GxwWin.java | 32 + .../src_300_gxw/gplx/gfui/GxwWin_lang.java | 271 +++ 150_gfui/src_300_gxw/gplx/gfui/Gxw_html.java | 30 + .../gplx/gfui/Gxw_html_load_tid_.java | 35 + .../src_300_gxw/gplx/gfui/Gxw_tab_itm.java | 24 + .../src_300_gxw/gplx/gfui/Gxw_tab_mgr.java | 31 + 150_gfui/src_300_gxw/gplx/gfui/MockForm.java | 31 + .../src_400_win/gplx/gfui/GfoConsoleWin.java | 253 +++ .../gplx/gfui/GfuiBnd_win_host.java | 39 + .../src_400_win/gplx/gfui/GfuiCmdForm.java | 52 + .../gplx/gfui/GfuiFocusOrderer.java | 58 + .../gplx/gfui/GfuiFocusXferBnd.java | 52 + .../src_400_win/gplx/gfui/GfuiForm_menu.java | 75 + .../src_400_win/gplx/gfui/GfuiMenuBar.java | 272 +++ .../gplx/gfui/GfuiMenuFormUtl.java | 39 + .../src_400_win/gplx/gfui/GfuiQuitMode.java | 36 + .../src_400_win/gplx/gfui/GfuiTipTextMgr.java | 33 + 150_gfui/src_400_win/gplx/gfui/GfuiWin.java | 123 ++ .../gplx/gfui/GfuiWinFocusMgr.java | 136 ++ .../gplx/gfui/GfuiWinKeyCmdMgr.java | 61 + 150_gfui/src_400_win/gplx/gfui/GfuiWin_.java | 72 + .../gplx/gfui/GfuiWin_toaster.java | 180 ++ 150_gfui/src_400_win/gplx/gfui/GxwWinNpi.java | 20 + .../src_410_box_core/gplx/gfui/GfuiElem.java | 75 + .../gplx/gfui/GfuiElemBase.java | 304 ++++ .../gplx/gfui/GfuiElemBase_.java | 22 + .../gplx/gfui/GfuiElemKeys.java | 46 + .../gplx/gfui/GfuiElemList.java | 53 + .../src_410_box_core/gplx/gfui/GfuiElem_.java | 44 + .../src_420_box_basic/gplx/gfui/GfuiBtn.java | 72 + .../gplx/gfui/GfuiBtnClickBnd.java | 40 + .../src_420_box_basic/gplx/gfui/GfuiBtn_.java | 47 + .../gplx/gfui/GfuiChkBox.java | 61 + .../gplx/gfui/GfuiChkBox_.java | 73 + .../gplx/gfui/GfuiComboBox.java | 34 + .../src_420_box_basic/gplx/gfui/GfuiLbl.java | 39 + .../src_420_box_basic/gplx/gfui/GfuiLbl_.java | 51 + .../gplx/gfui/GfuiListBox.java | 43 + .../gplx/gfui/GfuiTextBox.java | 67 + .../gplx/gfui/GfuiTextBox_.java | 46 + .../gplx/gfui/GfuiTextMemo.java | 41 + .../gplx/gfui/Gfui_html.java | 62 + .../gplx/gfui/Gfui_tab_itm.java | 30 + .../gplx/gfui/Gfui_tab_itm_data.java | 38 + .../gplx/gfui/Gfui_tab_itm_data_tst.java | 32 + .../gplx/gfui/Gfui_tab_mgr.java | 46 + .../gplx/gfui/DataBndr_whenEvt_execCmd.java | 51 + .../gplx/gfui/GfuiBnd_box_status.java | 55 + .../gplx/gfui/GfuiCheckListBox.java | 41 + .../gplx/gfui/GfuiCheckListPanel.java | 60 + .../gplx/gfui/GfuiFormPanel.java | 38 + .../gplx/gfui/GfuiIoDialogUtl.java | 52 + .../gplx/gfui/GfuiIoUrlSelectBox.java | 70 + .../gplx/gfui/GfuiIoUrlSelectBox_.java | 22 + .../gplx/gfui/GfuiMoveElemBnd.java | 80 + .../gplx/gfui/GfuiMoveElemBtn.java | 87 + .../gplx/gfui/GfuiStatusBar.java | 48 + .../gplx/gfui/GfuiStatusBarBnd.java | 28 + .../gplx/gfui/GfuiStatusBox.java | 106 ++ .../gplx/gfui/GfuiStatusBoxBnd.java | 39 + 150_gfui/src_500_tab/gplx/gfui/TabBnd.java | 89 + 150_gfui/src_500_tab/gplx/gfui/TabBox.java | 154 ++ .../gplx/gfui/TabBoxEvt_orderChanged.java | 33 + .../gplx/gfui/TabBoxEvt_tabSelect.java | 37 + 150_gfui/src_500_tab/gplx/gfui/TabBoxMgr.java | 57 + 150_gfui/src_500_tab/gplx/gfui/TabBox_.java | 33 + 150_gfui/src_500_tab/gplx/gfui/TabPnlItm.java | 38 + .../src_600_adp/gplx/gfui/ClipboardAdp_.java | 59 + 150_gfui/src_600_adp/gplx/gfui/CursorAdp.java | 38 + 150_gfui/src_600_adp/gplx/gfui/IconAdp.java | 45 + 150_gfui/src_600_adp/gplx/gfui/ImageAdp.java | 50 + 150_gfui/src_600_adp/gplx/gfui/ImageAdp_.java | 126 ++ .../src_600_adp/gplx/gfui/ImageAdp_base.java | 69 + .../src_600_adp/gplx/gfui/ImageAdp_null.java | 34 + 150_gfui/src_600_adp/gplx/gfui/ScreenAdp.java | 32 + .../src_600_adp/gplx/gfui/ScreenAdp_.java | 58 + 150_gfui/src_600_adp/gplx/gfui/TimerAdp.java | 53 + .../gplx/gfui/GfoFactory_gfui.java | 39 + .../src_700_env/gplx/gfui/GfsLibIni_gfui.java | 24 + 150_gfui/src_700_env/gplx/gfui/GfuiEnv_.java | 109 ++ .../src_700_env/gplx/gfui/GfuiInvkCmd.java | 23 + .../src_700_env/gplx/gfui/Gfui_clipboard.java | 27 + .../gplx/gfui/Gfui_clipboard_.java | 21 + .../src_700_env/gplx/gfui/Gfui_dlg_file.java | 33 + .../src_700_env/gplx/gfui/Gfui_dlg_msg.java | 33 + .../src_700_env/gplx/gfui/Gfui_dlg_msg_.java | 22 + 150_gfui/src_700_env/gplx/gfui/Gfui_kit.java | 50 + 150_gfui/src_700_env/gplx/gfui/Gfui_kit_.java | 32 + .../src_700_env/gplx/gfui/Gfui_kit_base.java | 109 ++ .../src_700_env/gplx/gfui/Gfui_mnu_grp.java | 48 + .../src_700_env/gplx/gfui/Gfui_mnu_itm.java | 37 + .../src_700_env/gplx/gfui/Gfui_mnu_itm_.java | 22 + 150_gfui/src_700_env/gplx/gfui/Mem_html.java | 66 + 150_gfui/src_700_env/gplx/gfui/Mem_kit.java | 38 + 150_gfui/src_700_env/gplx/gfui/Swing_kit.java | 33 + 150_gfui/src_700_env/gplx/gfui/Swt_kit.java | 342 ++++ .../src_700_env/gplx/gfui/TxtFindMgr.java | 48 + 150_gfui/tst/gplx/gfui/ClipboardAdp__tst.java | 26 + 150_gfui/tst/gplx/gfui/GfuiBorderMgr_tst.java | 53 + .../tst/gplx/gfui/GfuiClickKeyMgr_tst.java | 31 + .../tst/gplx/gfui/GfuiFocusOrderer_tst.java | 87 + .../tst/gplx/gfui/GfuiMoveElemBtn_tst.java | 35 + 150_gfui/tst/gplx/gfui/GfxAdpMok.java | 49 + 150_gfui/tst/gplx/gfui/GfxItm.java | 19 + 150_gfui/tst/gplx/gfui/GfxItmList.java | 30 + 150_gfui/tst/gplx/gfui/GfxItm_base.java | 34 + 150_gfui/tst/gplx/gfui/GfxLineItm.java | 40 + 150_gfui/tst/gplx/gfui/GfxRectItm.java | 37 + 150_gfui/tst/gplx/gfui/GfxStringItm.java | 38 + 150_gfui/tst/gplx/gfui/ImageAdp_tst.java | 45 + 150_gfui/tst/gplx/gfui/IptArg_parser_tst.java | 63 + 150_gfui/tst/gplx/gfui/IptEventType_tst.java | 34 + 150_gfui/tst/gplx/gfui/ScreenAdp_tst.java | 29 + 150_gfui/tst/gplx/gfui/TabBox_tst.java | 131 ++ 150_gfui/xtn/gplx/gfui/Swt_app_browser.java | 85 + 150_gfui/xtn/gplx/gfui/Swt_app_main.java | 200 +++ 150_gfui/xtn/gplx/gfui/Swt_btn.java | 100 ++ 150_gfui/xtn/gplx/gfui/Swt_clipboard.java | 58 + 150_gfui/xtn/gplx/gfui/Swt_control.java | 44 + 150_gfui/xtn/gplx/gfui/Swt_core_cmds.java | 243 +++ 150_gfui/xtn/gplx/gfui/Swt_core_lnrs.java | 150 ++ 150_gfui/xtn/gplx/gfui/Swt_dlg_msg.java | 96 + 150_gfui/xtn/gplx/gfui/Swt_html.java | 271 +++ 150_gfui/xtn/gplx/gfui/Swt_img.java | 47 + 150_gfui/xtn/gplx/gfui/Swt_lbl.java | 44 + 150_gfui/xtn/gplx/gfui/Swt_popup_grp.java | 224 +++ 150_gfui/xtn/gplx/gfui/Swt_tab_itm.java | 55 + 150_gfui/xtn/gplx/gfui/Swt_tab_mgr.java | 272 +++ 150_gfui/xtn/gplx/gfui/Swt_text.java | 59 + 150_gfui/xtn/gplx/gfui/Swt_text_w_border.java | 89 + 150_gfui/xtn/gplx/gfui/Swt_win.java | 114 ++ 400_xowa/.classpath | 32 + 400_xowa/.project | 17 + 400_xowa/lib/jtidy_xowa.jar | Bin 0 -> 186977 bytes 400_xowa/lib/luaj_xowa.jar | Bin 0 -> 336772 bytes .../src/gplx/cache/Gfo_cache_mgr_base.java | 48 + .../src/gplx/cache/Gfo_cache_mgr_bry.java | 53 + 400_xowa/src/gplx/core/brys/Bit_.java | 123 ++ 400_xowa/src/gplx/core/brys/Bit__tst.java | 109 ++ 400_xowa/src/gplx/core/brys/Bry_bldr.java | 40 + 400_xowa/src/gplx/core/brys/Bry_comparer.java | 26 + 400_xowa/src/gplx/core/brys/Bry_rdr_tst.java | 56 + .../gplx/core/btries/Btrie_utf8_mgr_tst.java | 96 + .../src/gplx/core/enums/Gfo_enum_grp.java | 54 + 400_xowa/src/gplx/core/flds/Gfo_fld_base.java | 48 + 400_xowa/src/gplx/core/flds/Gfo_fld_rdr.java | 124 ++ .../src/gplx/core/flds/Gfo_fld_rdr_tst.java | 56 + 400_xowa/src/gplx/core/flds/Gfo_fld_wtr.java | 59 + .../gplx/core/html/parsers/Gfo_html_node.java | 24 + .../core/html/parsers/Gfo_html_parser.java | 68 + .../gplx/core/html/parsers/Gfo_html_wkr.java | 22 + .../gplx/core/html/parsers/Xob_html_tkn.java | 33 + 400_xowa/src/gplx/core/ints/Int_ary_bldr.java | 23 + .../src/gplx/core/lists/Binary_search_.java | 52 + .../gplx/core/lists/Binary_search__tst.java | 47 + .../src/gplx/core/net/Http_client_rdr.java | 24 + .../src/gplx/core/net/Http_client_rdr_.java | 35 + .../core/net/Http_client_rdr__stream.java | 34 + .../src/gplx/core/net/Http_client_wtr.java | 27 + .../src/gplx/core/net/Http_client_wtr_.java | 21 + .../core/net/Http_client_wtr__stream.java | 53 + .../gplx/core/net/Http_post_data_hash.java | 27 + .../src/gplx/core/net/Http_post_data_itm.java | 23 + .../src/gplx/core/net/Http_request_itm.java | 81 + .../gplx/core/net/Http_request_parser.java | 168 ++ .../core/net/Http_request_parser_tst.java | 82 + .../src/gplx/core/net/Http_server_wtr.java | 24 + .../src/gplx/core/net/Http_server_wtr_.java | 22 + .../core/net/Http_server_wtr__console.java | 21 + 400_xowa/src/gplx/core/net/Socket_adp.java | 23 + .../src/gplx/core/net/Socket_adp__base.java | 36 + 400_xowa/src/gplx/core/regxs/Gfo_pattern.java | 50 + .../src/gplx/core/regxs/Gfo_pattern_ctx.java | 31 + .../src/gplx/core/regxs/Gfo_pattern_itm.java | 64 + .../src/gplx/core/regxs/Gfo_pattern_itm_.java | 51 + .../src/gplx/core/regxs/Gfo_pattern_tst.java | 93 + .../gplx/core/threads/Gfo_async_cmd_itm.java | 42 + .../gplx/core/threads/Gfo_async_cmd_mkr.java | 34 + .../src/gplx/core/threads/Gfo_async_mgr.java | 58 + .../src/gplx/core/threads/Gfo_thread_cmd.java | 30 + .../gplx/core/threads/Gfo_thread_cmd_.java | 22 + .../core/threads/Gfo_thread_cmd_base.java | 41 + .../core/threads/Gfo_thread_cmd_download.java | 73 + .../core/threads/Gfo_thread_cmd_replace.java | 61 + .../core/threads/Gfo_thread_cmd_unzip.java | 115 ++ .../gplx/core/threads/Gfo_thread_pool.java | 62 + .../src/gplx/core/threads/Gfo_thread_wkr.java | 23 + 400_xowa/src/gplx/core/xmls/Gfo_xml_wtr.java | 151 ++ .../src/gplx/core/xmls/Gfo_xml_wtr_tst.java | 81 + 400_xowa/src/gplx/dbs/Db_attach_cmd.java | 54 + 400_xowa/src/gplx/dbs/Db_attach_rdr.java | 40 + 400_xowa/src/gplx/dbs/cfgs/Db_cfg_hash.java | 34 + 400_xowa/src/gplx/dbs/cfgs/Db_cfg_itm.java | 59 + 400_xowa/src/gplx/dbs/cfgs/Db_cfg_tbl.java | 123 ++ .../src/gplx/dbs/metas/Schema_db_mgr.java | 28 + .../src/gplx/dbs/metas/Schema_loader_mgr.java | 21 + .../gplx/dbs/metas/Schema_loader_mgr_.java | 51 + .../dbs/metas/updates/Schema_update_cmd.java | 23 + .../dbs/metas/updates/Schema_update_cmd_.java | 37 + .../dbs/metas/updates/Schema_update_mgr.java | 32 + .../metas/updates/Schema_update_mgr_tst.java | 55 + 400_xowa/src/gplx/fsdb/Fsdb_db_file.java | 28 + 400_xowa/src/gplx/fsdb/Fsdb_db_mgr.java | 30 + 400_xowa/src/gplx/fsdb/Fsdb_db_mgr_.java | 53 + 400_xowa/src/gplx/fsdb/Fsdb_db_mgr__v1.java | 113 ++ 400_xowa/src/gplx/fsdb/Fsdb_db_mgr__v2.java | 67 + .../src/gplx/fsdb/Fsdb_db_mgr__v2_bldr.java | 113 ++ 400_xowa/src/gplx/fsdb/data/Fsd_bin_tbl.java | 100 ++ 400_xowa/src/gplx/fsdb/data/Fsd_dir_itm.java | 27 + 400_xowa/src/gplx/fsdb/data/Fsd_dir_tbl.java | 68 + 400_xowa/src/gplx/fsdb/data/Fsd_fil_itm.java | 34 + 400_xowa/src/gplx/fsdb/data/Fsd_fil_tbl.java | 105 ++ 400_xowa/src/gplx/fsdb/data/Fsd_img_itm.java | 27 + 400_xowa/src/gplx/fsdb/data/Fsd_thm_itm.java | 61 + 400_xowa/src/gplx/fsdb/data/Fsd_thm_tbl.java | 155 ++ .../src/gplx/fsdb/data/Fsd_thm_tbl_tst.java | 58 + 400_xowa/src/gplx/fsdb/meta/Fsm_atr_fil.java | 111 ++ 400_xowa/src/gplx/fsdb/meta/Fsm_atr_mgr.java | 34 + 400_xowa/src/gplx/fsdb/meta/Fsm_atr_tbl.java | 55 + 400_xowa/src/gplx/fsdb/meta/Fsm_bin_fil.java | 40 + 400_xowa/src/gplx/fsdb/meta/Fsm_bin_mgr.java | 60 + 400_xowa/src/gplx/fsdb/meta/Fsm_bin_tbl.java | 58 + 400_xowa/src/gplx/fsdb/meta/Fsm_cfg_mgr.java | 54 + 400_xowa/src/gplx/fsdb/meta/Fsm_id_itm.java | 24 + 400_xowa/src/gplx/fsdb/meta/Fsm_mnt_itm.java | 73 + 400_xowa/src/gplx/fsdb/meta/Fsm_mnt_mgr.java | 58 + 400_xowa/src/gplx/fsdb/meta/Fsm_mnt_tbl.java | 59 + 400_xowa/src/gplx/gfs/Gfs_lxr.java | 214 +++ 400_xowa/src/gplx/gfs/Gfs_lxr_.java | 39 + 400_xowa/src/gplx/gfs/Gfs_msg_bldr.java | 49 + 400_xowa/src/gplx/gfs/Gfs_msg_bldr_tst.java | 76 + 400_xowa/src/gplx/gfs/Gfs_nde.java | 85 + 400_xowa/src/gplx/gfs/Gfs_parser.java | 104 ++ 400_xowa/src/gplx/gfs/Gfs_parser_ctx.java | 126 ++ 400_xowa/src/gplx/gfs/Gfs_parser_tst.java | 196 +++ 400_xowa/src/gplx/gfs/Gfs_wtr.java | 46 + 400_xowa/src/gplx/gfui/Gfui_bnd_parser.java | 316 ++++ .../src/gplx/gfui/Gfui_bnd_parser_tst.java | 60 + 400_xowa/src/gplx/html/Html_atr_.java | 29 + 400_xowa/src/gplx/html/Html_entity_.java | 35 + 400_xowa/src/gplx/html/Html_nde.java | 94 + 400_xowa/src/gplx/html/Html_parser.java | 165 ++ 400_xowa/src/gplx/html/Html_parser_tst.java | 53 + 400_xowa/src/gplx/html/Html_selecter.java | 40 + 400_xowa/src/gplx/html/Html_tag_.java | 59 + 400_xowa/src/gplx/html/Html_utl.java | 180 ++ 400_xowa/src/gplx/html/Html_utl_tst.java | 62 + 400_xowa/src/gplx/html/Html_wtr.java | 107 ++ 400_xowa/src/gplx/intl/Gfo_app.java | 21 + 400_xowa/src/gplx/intl/Gfo_i18n_itm.java | 42 + 400_xowa/src/gplx/intl/Gfo_i18n_mgr.java | 41 + 400_xowa/src/gplx/intl/Gfo_i18n_val_cmd.java | 21 + .../src/gplx/intl/String_surrogate_utl.java | 36 + .../gplx/intl/String_surrogate_utl_tst.java | 57 + .../src/gplx/ios/Io_stream_rdr_process.java | 67 + 400_xowa/src/gplx/ios/Io_stream_zip_mgr.java | 54 + 400_xowa/src/gplx/json/Json_doc.java | 67 + 400_xowa/src/gplx/json/Json_doc_bldr.java | 42 + 400_xowa/src/gplx/json/Json_doc_srl.java | 89 + 400_xowa/src/gplx/json/Json_doc_tst.java | 45 + 400_xowa/src/gplx/json/Json_doc_wtr.java | 98 ++ 400_xowa/src/gplx/json/Json_factory.java | 29 + 400_xowa/src/gplx/json/Json_grp.java | 34 + 400_xowa/src/gplx/json/Json_itm.java | 116 ++ 400_xowa/src/gplx/json/Json_itm_.java | 24 + 400_xowa/src/gplx/json/Json_itm_ary.java | 71 + 400_xowa/src/gplx/json/Json_itm_base.java | 29 + 400_xowa/src/gplx/json/Json_itm_int.java | 33 + 400_xowa/src/gplx/json/Json_itm_kv.java | 35 + 400_xowa/src/gplx/json/Json_itm_nde.java | 81 + 400_xowa/src/gplx/json/Json_itm_tmp.java | 31 + 400_xowa/src/gplx/json/Json_kv_ary_srl.java | 61 + .../src/gplx/json/Json_kv_ary_srl_tst.java | 50 + 400_xowa/src/gplx/json/Json_parser.java | 167 ++ 400_xowa/src/gplx/json/Json_parser_tst.java | 99 ++ 400_xowa/src/gplx/json/Json_wtr.java | 129 ++ 400_xowa/src/gplx/json/Json_wtr_tst.java | 100 ++ 400_xowa/src/gplx/php/Php_ctx.java | 21 + 400_xowa/src/gplx/php/Php_evaluator.java | 262 +++ 400_xowa/src/gplx/php/Php_itm.java | 44 + 400_xowa/src/gplx/php/Php_itm_.java | 44 + 400_xowa/src/gplx/php/Php_itm_ary.java | 37 + 400_xowa/src/gplx/php/Php_itm_int.java | 24 + 400_xowa/src/gplx/php/Php_itm_kv.java | 24 + 400_xowa/src/gplx/php/Php_itm_quote.java | 23 + 400_xowa/src/gplx/php/Php_itm_sub.java | 23 + 400_xowa/src/gplx/php/Php_key.java | 23 + 400_xowa/src/gplx/php/Php_line.java | 19 + 400_xowa/src/gplx/php/Php_line_assign.java | 23 + 400_xowa/src/gplx/php/Php_lxr.java | 283 +++ 400_xowa/src/gplx/php/Php_parser.java | 121 ++ 400_xowa/src/gplx/php/Php_parser_tst.java | 399 +++++ 400_xowa/src/gplx/php/Php_srl_itm.java | 138 ++ 400_xowa/src/gplx/php/Php_srl_parser.java | 208 +++ 400_xowa/src/gplx/php/Php_srl_parser_tst.java | 112 ++ 400_xowa/src/gplx/php/Php_text_itm.java | 62 + .../src/gplx/php/Php_text_itm_parser.java | 145 ++ 400_xowa/src/gplx/php/Php_text_itm_tst.java | 53 + 400_xowa/src/gplx/php/Php_tkn.java | 74 + 400_xowa/src/gplx/php/Php_tkn_factory.java | 28 + 400_xowa/src/gplx/php/Php_tkn_wkr.java | 35 + .../src/gplx/srls/dsvs/Dsv_fld_parser.java | 22 + .../src/gplx/srls/dsvs/Dsv_fld_parser_.java | 114 ++ .../src/gplx/srls/dsvs/Dsv_tbl_parser.java | 79 + .../srls/dsvs/Dsv_tbl_parser_int_tst.java | 64 + .../srls/dsvs/Dsv_tbl_parser_str_tst.java | 102 ++ 400_xowa/src/gplx/srls/dsvs/Dsv_wkr_base.java | 42 + 400_xowa/src/gplx/xowa/Xoa_app.java | 46 + 400_xowa/src/gplx/xowa/Xoa_app_.java | 208 +++ 400_xowa/src/gplx/xowa/Xoa_app_fxt.java | 72 + 400_xowa/src/gplx/xowa/Xoa_consts.java | 30 + 400_xowa/src/gplx/xowa/Xoa_test_.java | 37 + 400_xowa/src/gplx/xowa/Xoae_app.java | 227 +++ 400_xowa/src/gplx/xowa/apis/Xoapi_doc.java | 178 ++ 400_xowa/src/gplx/xowa/apis/Xoapi_root.java | 77 + .../src/gplx/xowa/apis/xowa/Xoapi_app.java | 42 + .../src/gplx/xowa/apis/xowa/Xoapi_bldr.java | 28 + .../src/gplx/xowa/apis/xowa/Xoapi_gui.java | 36 + .../src/gplx/xowa/apis/xowa/Xoapi_html.java | 37 + .../src/gplx/xowa/apis/xowa/Xoapi_nav.java | 40 + .../src/gplx/xowa/apis/xowa/Xoapi_net.java | 42 + .../gplx/xowa/apis/xowa/Xoapi_special.java | 31 + .../src/gplx/xowa/apis/xowa/Xoapi_usr.java | 45 + .../src/gplx/xowa/apis/xowa/Xoapi_xtns.java | 35 + .../gplx/xowa/apis/xowa/apps/Xoapi_fsys.java | 32 + .../xowa/apis/xowa/bldrs/Xoapi_bldr_wiki.java | 31 + .../apis/xowa/bldrs/filters/Xoapi_filter.java | 28 + .../dansguardians/Xoapi_dansguardian.java | 76 + .../bldrs/filters/titles/Xoapi_title.java | 49 + .../apis/xowa/bldrs/imports/Xoapi_import.java | 91 + .../gplx/xowa/apis/xowa/envs/Xoapi_env.java | 29 + .../xowa/apis/xowa/gui/Xoapi_browser.java | 53 + .../gplx/xowa/apis/xowa/gui/Xoapi_font.java | 55 + .../gplx/xowa/apis/xowa/gui/Xoapi_page.java | 36 + .../apis/xowa/gui/browsers/Xoapi_find.java | 89 + .../xowa/gui/browsers/Xoapi_html_box.java | 53 + .../apis/xowa/gui/browsers/Xoapi_info.java | 46 + .../apis/xowa/gui/browsers/Xoapi_prog.java | 34 + .../xowa/gui/browsers/Xoapi_prog_log.java | 29 + .../apis/xowa/gui/browsers/Xoapi_search.java | 34 + .../apis/xowa/gui/browsers/Xoapi_tabs.java | 90 + .../apis/xowa/gui/browsers/Xoapi_url.java | 62 + .../xowa/apis/xowa/gui/pages/Xoapi_edit.java | 57 + .../apis/xowa/gui/pages/Xoapi_selection.java | 52 + .../xowa/apis/xowa/gui/pages/Xoapi_view.java | 61 + .../xowa/apis/xowa/html/Xoapi_modules.java | 36 + .../gplx/xowa/apis/xowa/html/Xoapi_page.java | 27 + .../gplx/xowa/apis/xowa/html/Xoapi_skins.java | 35 + .../gplx/xowa/apis/xowa/html/Xoapi_tidy.java | 40 + .../xowa/apis/xowa/html/Xoapi_toggle_itm.java | 90 + .../xowa/apis/xowa/html/Xoapi_toggle_mgr.java | 50 + .../xowa/html/modules/Xoapi_collapsible.java | 32 + .../xowa/html/modules/Xoapi_navframe.java | 32 + .../apis/xowa/html/modules/Xoapi_popups.java | 242 +++ .../apis/xowa/html/modules/Xoapi_toc.java | 32 + .../xowa/html/skins/Xoapi_skin_app_base.java | 29 + .../gplx/xowa/apis/xowa/navs/Xoapi_wiki.java | 40 + .../xowa/apis/xowa/specials/Xoapi_search.java | 73 + .../apis/xowa/startups/Xoapi_startups.java | 29 + .../startups/tabs/Xoapi_startup_tabs.java | 87 + .../tabs/Xoapi_startup_tabs_tid_.java | 39 + .../xowa/apis/xowa/usrs/Xoapi_bookmarks.java | 65 + .../gplx/xowa/apis/xowa/usrs/Xoapi_cache.java | 51 + .../xowa/apis/xowa/usrs/Xoapi_history.java | 37 + .../gplx/xowa/apis/xowa/usrs/Xoapi_logs.java | 37 + .../xowa/apis/xowa/xtns/Xoapi_scribunto.java | 38 + .../xowa/apis/xowa/xtns/Xoapi_wikibase.java | 48 + 400_xowa/src/gplx/xowa/apps/Xoa_app_type.java | 35 + 400_xowa/src/gplx/xowa/apps/Xoa_gfs_mgr.java | 126 ++ .../src/gplx/xowa/apps/Xoa_gfs_php_mgr.java | 117 ++ .../gplx/xowa/apps/Xoa_gfs_php_mgr_tst.java | 50 + 400_xowa/src/gplx/xowa/apps/Xoa_shell.java | 38 + .../src/gplx/xowa/apps/Xoa_shell_tst.java | 30 + 400_xowa/src/gplx/xowa/apps/Xoa_stage_.java | 21 + 400_xowa/src/gplx/xowa/apps/Xoa_thread_.java | 30 + .../src/gplx/xowa/apps/Xoa_thread_mgr.java | 27 + .../xowa/apps/caches/Wdata_doc_cache.java | 26 + .../gplx/xowa/apps/caches/Xoa_cache_mgr.java | 24 + .../gplx/xowa/apps/fsys/Xoa_fsys_eval.java | 42 + .../src/gplx/xowa/apps/fsys/Xoa_fsys_mgr.java | 52 + .../gplx/xowa/apps/progs/Xoa_prog_mgr.java | 128 ++ .../gplx/xowa/apps/setups/Xoa_setup_mgr.java | 37 + .../xowa/apps/setups/Xoa_setup_mgr_tst.java | 36 + .../gplx/xowa/apps/versions/Xoa_version_.java | 38 + .../xowa/apps/versions/Xoa_version_tst.java | 37 + 400_xowa/src/gplx/xowa/bldrs/Db_idx_mode.java | 38 + 400_xowa/src/gplx/xowa/bldrs/Db_mgr_fxt.java | 138 ++ .../src/gplx/xowa/bldrs/Xob_base_fxt.java | 78 + 400_xowa/src/gplx/xowa/bldrs/Xob_cmd.java | 26 + .../src/gplx/xowa/bldrs/Xob_cmd_keys.java | 77 + 400_xowa/src/gplx/xowa/bldrs/Xob_cmd_mgr.java | 149 ++ 400_xowa/src/gplx/xowa/bldrs/Xob_db_file.java | 49 + 400_xowa/src/gplx/xowa/bldrs/Xob_fxt.java | 161 ++ .../src/gplx/xowa/bldrs/Xob_ns_to_db_mgr.java | 88 + .../src/gplx/xowa/bldrs/Xob_ns_to_db_wkr.java | 24 + .../gplx/xowa/bldrs/aria2/Aria2_lib_mgr.java | 50 + .../xowa/bldrs/aria2/Gfui_process_win.java | 40 + .../xowa/bldrs/cfgs/Xob_wiki_cfg_bldr.java | 56 + .../bldrs/cfgs/Xob_wiki_cfg_bldr_tst.java | 179 ++ .../xowa/bldrs/cmds/Xob_dump_mgr_base.java | 315 ++++ .../gplx/xowa/bldrs/cmds/Xob_ns_file_itm.java | 63 + .../bldrs/cmds/Xob_ns_file_itm_parser.java | 79 + .../bldrs/cmds/Xob_parse_all_src_sql.java | 92 + .../gplx/xowa/bldrs/cmds/ctgs/Uca_trie.java | 1074 ++++++++++++ .../xowa/bldrs/cmds/ctgs/Uca_trie_tst.java | 45 + .../cmds/ctgs/Xob_category_registry_sql.java | 54 + .../ctgs/Xob_category_registry_sql_tst.java | 66 + .../cmds/ctgs/Xob_categorylinks_base.java | 89 + .../cmds/ctgs/Xob_categorylinks_base_tst.java | 70 + .../cmds/ctgs/Xob_categorylinks_sql.java | 43 + .../cmds/ctgs/Xob_categorylinks_sql_make.java | 153 ++ .../cmds/ctgs/Xob_categorylinks_sql_tst.java | 140 ++ .../cmds/ctgs/Xob_categorylinks_txt.java | 24 + .../xowa/bldrs/cmds/ctgs/Xob_ctg_v1_base.java | 141 ++ .../bldrs/cmds/ctgs/Xob_ctg_v1_base_tst.java | 61 + .../xowa/bldrs/cmds/ctgs/Xob_ctg_v1_sql.java | 77 + .../bldrs/cmds/ctgs/Xob_ctg_v1_sql_tst.java | 84 + .../xowa/bldrs/cmds/ctgs/Xob_ctg_v1_txt.java | 23 + .../bldrs/cmds/ctgs/Xob_sql_join_mgr.java | 36 + .../ctgs/Xoctg_hiddencat_parser_base.java | 43 + .../cmds/ctgs/Xoctg_hiddencat_parser_sql.java | 47 + .../ctgs/Xoctg_hiddencat_parser_sql_tst.java | 61 + .../cmds/ctgs/Xoctg_hiddencat_parser_txt.java | 33 + .../cmds/ctgs/Xoctg_hiddencat_ttl_wkr.java | 68 + .../ctgs/Xoctg_hiddencat_ttl_wkr_tst.java | 45 + .../bldrs/cmds/ctgs/Xoctg_link_idx_wkr.java | 185 ++ .../cmds/ctgs/Xoctg_link_idx_wkr_tst.java | 63 + .../xowa/bldrs/cmds/files/Xob_bin_db_itm.java | 57 + .../xowa/bldrs/cmds/files/Xob_bin_db_mgr.java | 71 + .../cmds/files/Xob_diff_regy_exec_cmd.java | 101 ++ .../files/Xob_diff_regy_exec_cmd_tst.java | 45 + .../cmds/files/Xob_diff_regy_make_cmd.java | 137 ++ .../bldrs/cmds/files/Xob_fsdb_make_cmd.java | 378 ++++ .../bldrs/cmds/files/Xob_fsdb_reduce_cmd.java | 62 + .../bldrs/cmds/files/Xob_lnki_regy_cmd.java | 32 + .../bldrs/cmds/files/Xob_lnki_regy_tbl.java | 115 ++ .../bldrs/cmds/files/Xob_lnki_src_tid.java | 21 + .../bldrs/cmds/files/Xob_lnki_temp_tbl.java | 62 + .../bldrs/cmds/files/Xob_lnki_temp_wkr.java | 218 +++ .../cmds/files/Xob_lnki_temp_wkr_tst.java | 45 + .../bldrs/cmds/files/Xob_orig_regy_cmd.java | 46 + .../bldrs/cmds/files/Xob_orig_regy_tbl.java | 221 +++ .../files/Xob_orig_regy_update_bmk_mgr.java | 100 ++ .../cmds/files/Xob_orig_regy_update_cmd.java | 64 + .../bldrs/cmds/files/Xob_page_regy_cmd.java | 50 + .../bldrs/cmds/files/Xob_page_regy_tbl.java | 86 + .../bldrs/cmds/files/Xob_xfer_regy_cmd.java | 36 + .../bldrs/cmds/files/Xob_xfer_regy_tbl.java | 157 ++ .../cmds/files/Xob_xfer_regy_update_cmd.java | 172 ++ .../cmds/files/Xob_xfer_temp_cmd_orig.java | 103 ++ .../cmds/files/Xob_xfer_temp_cmd_thumb.java | 81 + .../bldrs/cmds/files/Xob_xfer_temp_itm.java | 131 ++ .../cmds/files/Xob_xfer_temp_itm_tst.java | 192 ++ .../bldrs/cmds/files/Xob_xfer_temp_tbl.java | 79 + .../bldrs/cmds/files/Xob_xfer_update_cmd.java | 83 + .../xowa/bldrs/cmds/files/Xobu_poll_mgr.java | 38 + .../xowa/bldrs/cmds/texts/Xob_init_base.java | 59 + .../bldrs/cmds/texts/Xob_search_base.java | 109 ++ .../xowa/bldrs/cmds/texts/Xob_term_base.java | 41 + .../bldrs/cmds/texts/sqls/Xob_css_cmd.java | 52 + .../bldrs/cmds/texts/sqls/Xob_init_cmd.java | 33 + .../texts/sqls/Xob_ns_to_db_wkr__text.java | 30 + .../bldrs/cmds/texts/sqls/Xob_page_cmd.java | 103 ++ .../cmds/texts/sqls/Xob_page_cmd_tst.java | 37 + .../cmds/texts/sqls/Xob_search_sql_cmd.java | 86 + .../texts/sqls/Xob_search_sql_cmd_tst.java | 52 + .../cmds/texts/sqls/Xob_search_sql_wkr.java | 93 + .../bldrs/cmds/texts/sqls/Xob_term_cmd.java | 33 + .../cmds/texts/tdbs/Xob_calc_stats_cmd.java | 112 ++ .../cmds/texts/tdbs/Xob_init_base_tst.java | 43 + .../bldrs/cmds/texts/tdbs/Xob_init_tdb.java | 28 + .../cmds/texts/tdbs/Xob_make_id_wkr.java | 38 + .../bldrs/cmds/texts/tdbs/Xob_page_txt.java | 90 + .../tdbs/Xob_parse_dump_templates_cmd.java | 36 + .../cmds/texts/tdbs/Xob_search_base_tst.java | 56 + .../bldrs/cmds/texts/tdbs/Xob_search_tdb.java | 25 + .../bldrs/cmds/texts/tdbs/Xob_term_txt.java | 26 + .../xowa/bldrs/cmds/texts/tdbs/Xob_tst.java | 204 +++ .../bldrs/cmds/utils/Xob_cleanup_cmd.java | 132 ++ .../bldrs/cmds/utils/Xob_core_batch_utl.java | 42 + .../cmds/utils/Xob_decompress_bz2_cmd.java | 54 + .../bldrs/cmds/utils/Xob_deploy_copy_cmd.java | 70 + .../bldrs/cmds/utils/Xob_deploy_zip_cmd.java | 83 + .../bldrs/cmds/utils/Xob_download_wkr.java | 69 + .../bldrs/cmds/utils/Xob_exec_sql_cmd.java | 43 + .../xowa/bldrs/cmds/utils/Xob_unzip_wkr.java | 41 + .../bldrs/cmds/utils/Xob_xml_dumper_cmd.java | 65 + .../xowa/bldrs/cmds/wikis/Xob_image_cmd.java | 118 ++ .../bldrs/cmds/wikis/Xob_image_cmd_tst.java | 51 + .../xowa/bldrs/cmds/wikis/Xob_image_tbl.java | 58 + .../cmds/wikis/Xob_page_dump_cmd_drop.java | 42 + .../cmds/wikis/Xob_page_dump_cmd_make.java | 44 + .../bldrs/cmds/wikis/Xob_page_dump_tbl.java | 47 + .../bldrs/cmds/wikis/Xob_redirect_cmd.java | 56 + .../bldrs/cmds/wikis/Xob_redirect_tbl.java | 164 ++ .../xowa/bldrs/css/Xoa_css_extractor.java | 265 +++ .../css/Xoa_css_extractor_basic_tst.java | 130 ++ .../bldrs/css/Xoa_css_extractor_wiki_tst.java | 46 + .../bldrs/css/Xoa_css_img_downloader.java | 191 ++ .../bldrs/css/Xoa_css_img_downloader_tst.java | 183 ++ .../gplx/xowa/bldrs/css/Xob_css_parser.java | 56 + .../bldrs/css/Xob_css_parser__import.java | 43 + .../bldrs/css/Xob_css_parser__import_tst.java | 38 + .../xowa/bldrs/css/Xob_css_parser__url.java | 58 + .../bldrs/css/Xob_css_parser__url_tst.java | 60 + .../xowa/bldrs/css/Xob_css_tkn__base.java | 117 ++ .../gplx/xowa/bldrs/css/Xob_mirror_mgr.java | 59 + .../xowa/bldrs/css/Xob_mirror_mgr_tst.java | 63 + .../gplx/xowa/bldrs/css/Xob_url_fixer.java | 99 ++ .../xowa/bldrs/css/Xob_url_fixer_tst.java | 42 + .../xowa/bldrs/css/Xobc_download_itm.java | 25 + .../filters/core/Xob_ttl_filter_mgr.java | 43 + .../filters/core/Xob_ttl_filter_mgr_srl.java | 39 + .../core/Xob_ttl_filter_mgr_srl_tst.java | 54 + .../filters/core/Xob_ttl_filter_mgr_tst.java | 51 + .../dansguardians/Crt__match_base.java | 47 + .../bldrs/filters/dansguardians/Dg_file.java | 85 + .../filters/dansguardians/Dg_log_mgr.java | 175 ++ .../filters/dansguardians/Dg_match_mgr.java | 164 ++ .../dansguardians/Dg_match_mgr_tst.java | 58 + .../filters/dansguardians/Dg_parser.java | 95 + .../filters/dansguardians/Dg_parser_tst.java | 57 + .../gplx/xowa/bldrs/infos/Xob_info_file.java | 70 + .../xowa/bldrs/infos/Xob_info_session.java | 61 + .../xowa/bldrs/langs/Json_itm_wkr__base.java | 81 + .../xowa/bldrs/langs/Xob_i18n_parser.java | 31 + .../xowa/bldrs/langs/Xob_i18n_parser_tst.java | 64 + .../xowa/bldrs/langs/Xobc_utl_make_lang.java | 54 + .../bldrs/langs/Xobc_utl_make_lang_kwds.java | 160 ++ .../bldrs/langs/Xobc_utl_make_lang_tst.java | 179 ++ .../xowa/bldrs/langs/Xol_lang_transform.java | 25 + .../xowa/bldrs/langs/Xol_mw_lang_parser.java | 367 ++++ .../bldrs/langs/Xol_mw_lang_parser_tst.java | 315 ++++ .../xowa/bldrs/servers/Xob_core_server.java | 48 + .../gplx/xowa/bldrs/servers/Xob_wmf_mgr.java | 35 + .../xowa/bldrs/servers/jobs/Xob_job_itm.java | 24 + .../xowa/bldrs/servers/jobs/Xob_job_mgr.java | 27 + .../bldrs/wiki_cfgs/Xob_subpage_parser.java | 88 + .../bldrs/wiki_cfgs/Xoi_wiki_props_alias.java | 27 + .../bldrs/wiki_cfgs/Xoi_wiki_props_api.java | 86 + .../wiki_cfgs/Xoi_wiki_props_api_tst.java | 142 ++ .../bldrs/wiki_cfgs/Xoi_wiki_props_ns.java | 27 + .../bldrs/wiki_cfgs/Xoi_wiki_props_wiki.java | 23 + .../gplx/xowa/bldrs/xmls/Xob_import_cfg.java | 62 + .../xowa/bldrs/xmls/Xob_import_marker.java | 49 + .../xowa/bldrs/xmls/Xob_siteinfo_parser.java | 88 + .../gplx/xowa/bldrs/xmls/Xob_xml_dumper.java | 97 ++ .../xowa/bldrs/xmls/Xob_xml_dumper_tst.java | 102 ++ .../xowa/bldrs/xmls/Xob_xml_page_bldr.java | 80 + .../gplx/xowa/bldrs/xmls/Xob_xml_parser.java | 128 ++ .../gplx/xowa/bldrs/xmls/Xob_xml_parser_.java | 73 + .../xowa/bldrs/xmls/Xob_xml_parser_tst.java | 136 ++ 400_xowa/src/gplx/xowa/cfgs/Xoa_cfg_db.java | 25 + .../src/gplx/xowa/cfgs/Xoa_cfg_db_txt.java | 44 + 400_xowa/src/gplx/xowa/cfgs/Xoa_cfg_grp.java | 80 + .../src/gplx/xowa/cfgs/Xoa_cfg_grp_tid.java | 47 + 400_xowa/src/gplx/xowa/cfgs/Xoa_cfg_itm.java | 43 + 400_xowa/src/gplx/xowa/cfgs/Xoa_cfg_mgr.java | 140 ++ .../src/gplx/xowa/cfgs/Xoa_cfg_mgr_tst.java | 87 + .../src/gplx/xowa/cfgs/gui/Xocfg_gui_mgr.java | 31 + .../src/gplx/xowa/cfgs/gui/Xocfg_html.java | 31 + .../gplx/xowa/cfgs/gui/Xocfg_pref_mgr.java | 106 ++ .../src/gplx/xowa/cfgs/gui/Xocfg_win.java | 31 + .../src/gplx/xowa/cfgs2/Xocfg_bnd_itm.java | 59 + .../gplx/xowa/cfgs2/Xocfg_bnd_itm_srl.java | 51 + .../src/gplx/xowa/cfgs2/Xocfg_bnd_mgr.java | 69 + .../src/gplx/xowa/cfgs2/Xocfg_gui_mgr.java | 29 + 400_xowa/src/gplx/xowa/cfgs2/Xocfg_regy.java | 34 + 400_xowa/src/gplx/xowa/cfgs2/Xocfg_root.java | 31 + 400_xowa/src/gplx/xowa/cfgs2/Xocfg_root_.java | 21 + .../gplx/xowa/cfgs2/Xocfg_tab_btn_mgr.java | 69 + .../src/gplx/xowa/cfgs2/Xocfg_tab_mgr.java | 27 + .../gplx/xowa/cfgs2/Xocfg_tab_new_mgr.java | 50 + 400_xowa/src/gplx/xowa/ctgs/Xoa_ctg_mgr.java | 65 + .../src/gplx/xowa/ctgs/Xoctg_data_cache.java | 30 + .../src/gplx/xowa/ctgs/Xoctg_data_ctg.java | 38 + .../gplx/xowa/ctgs/Xoctg_data_ctg_tst.java | 24 + .../src/gplx/xowa/ctgs/Xoctg_fmtr_all.java | 160 ++ .../src/gplx/xowa/ctgs/Xoctg_fmtr_grp.java | 82 + .../src/gplx/xowa/ctgs/Xoctg_fmtr_itm.java | 121 ++ .../src/gplx/xowa/ctgs/Xoctg_html_mgr.java | 133 ++ .../gplx/xowa/ctgs/Xoctg_html_mgr_tst.java | 270 +++ .../src/gplx/xowa/ctgs/Xoctg_idx_itm.java | 50 + .../src/gplx/xowa/ctgs/Xoctg_idx_mgr.java | 157 ++ .../src/gplx/xowa/ctgs/Xoctg_idx_mgr_tst.java | 136 ++ .../src/gplx/xowa/ctgs/Xoctg_page_xtn.java | 24 + .../gplx/xowa/ctgs/Xoctg_pagelist_grp.java | 40 + .../gplx/xowa/ctgs/Xoctg_pagelist_itms.java | 42 + .../gplx/xowa/ctgs/Xoctg_pagelist_mgr.java | 35 + .../gplx/xowa/ctgs/Xoctg_pagelist_wtr.java | 69 + .../xowa/ctgs/Xoctg_pagelist_wtr_tst.java | 87 + 400_xowa/src/gplx/xowa/ctgs/Xoctg_url.java | 72 + .../src/gplx/xowa/ctgs/Xoctg_url_tst.java | 71 + .../src/gplx/xowa/ctgs/Xoctg_view_ctg.java | 57 + .../gplx/xowa/ctgs/Xoctg_view_ctg_tst.java | 24 + .../src/gplx/xowa/ctgs/Xoctg_view_grp.java | 41 + .../src/gplx/xowa/ctgs/Xoctg_view_itm.java | 54 + 400_xowa/src/gplx/xowa/dbs/Xodb_load_mgr.java | 40 + .../src/gplx/xowa/dbs/Xodb_load_mgr_sql.java | 204 +++ .../gplx/xowa/dbs/Xodb_load_mgr_sql_tst.java | 173 ++ .../src/gplx/xowa/dbs/Xodb_load_mgr_txt.java | 567 ++++++ 400_xowa/src/gplx/xowa/dbs/Xodb_mgr.java | 28 + 400_xowa/src/gplx/xowa/dbs/Xodb_mgr_sql.java | 63 + 400_xowa/src/gplx/xowa/dbs/Xodb_mgr_txt.java | 61 + 400_xowa/src/gplx/xowa/dbs/Xodb_page_rdr.java | 24 + .../src/gplx/xowa/dbs/Xodb_page_rdr__sql.java | 40 + .../src/gplx/xowa/dbs/Xodb_page_rdr__tdb.java | 86 + 400_xowa/src/gplx/xowa/dbs/Xodb_save_mgr.java | 27 + .../src/gplx/xowa/dbs/Xodb_save_mgr_sql.java | 81 + .../src/gplx/xowa/dbs/Xodb_save_mgr_txt.java | 110 ++ .../src/gplx/xowa/dbs/Xodb_upgrade_mgr.java | 68 + .../src/gplx/xowa/files/Xof_bin_updater.java | 43 + .../src/gplx/xowa/files/Xof_exec_tid.java | 21 + 400_xowa/src/gplx/xowa/files/Xof_ext.java | 47 + 400_xowa/src/gplx/xowa/files/Xof_ext_.java | 192 ++ .../src/gplx/xowa/files/Xof_file_fxt.java | 49 + .../src/gplx/xowa/files/Xof_file_itm.java | 64 + .../src/gplx/xowa/files/Xof_file_wkr.java | 135 ++ .../src/gplx/xowa/files/Xof_file_wkr_.java | 37 + .../src/gplx/xowa/files/Xof_fsdb_itm.java | 147 ++ .../src/gplx/xowa/files/Xof_fsdb_mode.java | 33 + .../src/gplx/xowa/files/Xof_html_elem.java | 27 + .../src/gplx/xowa/files/Xof_img_size.java | 166 ++ .../src/gplx/xowa/files/Xof_img_size_tst.java | 102 ++ .../src/gplx/xowa/files/Xof_lnki_page.java | 27 + .../src/gplx/xowa/files/Xof_lnki_time.java | 43 + .../src/gplx/xowa/files/Xof_media_type.java | 30 + .../src/gplx/xowa/files/Xof_mime_minor_.java | 55 + .../xowa/files/Xof_patch_upright_tid_.java | 30 + .../src/gplx/xowa/files/Xof_redlink_wkr.java | 35 + .../src/gplx/xowa/files/Xof_url_bldr.java | 202 +++ .../src/gplx/xowa/files/Xof_url_bldr_tst.java | 53 + 400_xowa/src/gplx/xowa/files/Xof_wkr_mgr.java | 37 + .../src/gplx/xowa/files/Xof_xfer_itm.java | 305 ++++ .../src/gplx/xowa/files/Xof_xfer_itm_.java | 94 + .../src/gplx/xowa/files/Xof_xfer_itm_tst.java | 66 + .../gplx/xowa/files/Xog_redlink_thread.java | 31 + .../src/gplx/xowa/files/Xow_file_mgr.java | 138 ++ .../src/gplx/xowa/files/bins/Bin_fetcher.java | 65 + .../src/gplx/xowa/files/bins/Xof_bin_mgr.java | 192 ++ .../xowa/files/bins/Xof_bin_skip_mgr.java | 89 + .../src/gplx/xowa/files/bins/Xof_bin_wkr.java | 27 + .../gplx/xowa/files/bins/Xof_bin_wkr_.java | 36 + .../files/bins/Xof_bin_wkr__fsdb_sql.java | 130 ++ .../files/bins/Xof_bin_wkr__fsys_base.java | 68 + .../files/bins/Xof_bin_wkr__http_wmf.java | 63 + .../gplx/xowa/files/caches/Xof_cache_mgr.java | 80 + .../xowa/files/caches/Xof_cache_mgr_tst.java | 72 + .../gplx/xowa/files/caches/Xofc_cfg_mgr.java | 50 + .../gplx/xowa/files/caches/Xofc_dir_itm.java | 30 + .../gplx/xowa/files/caches/Xofc_dir_mgr.java | 92 + .../gplx/xowa/files/caches/Xofc_dir_tbl.java | 87 + .../gplx/xowa/files/caches/Xofc_fil_itm.java | 73 + .../gplx/xowa/files/caches/Xofc_fil_mgr.java | 149 ++ .../gplx/xowa/files/caches/Xofc_fil_tbl.java | 155 ++ .../gplx/xowa/files/caches/Xou_cache_itm.java | 89 + .../gplx/xowa/files/caches/Xou_cache_mgr.java | 215 +++ .../xowa/files/caches/Xou_cache_mgr_tst.java | 113 ++ .../gplx/xowa/files/caches/Xou_cache_tbl.java | 197 +++ .../xowa/files/caches/Xou_cache_tbl_tst.java | 61 + .../files/caches/Xou_file_itm_finder.java | 62 + .../gplx/xowa/files/cnvs/Xof_cnv_wkr_.java | 21 + .../files/cnvs/Xof_img_wkr_resize_img.java | 22 + .../Xof_img_wkr_resize_img_imageMagick.java | 43 + .../cnvs/Xof_img_wkr_resize_img_mok.java | 30 + .../files/downloads/Xof_download_wkr.java | 23 + .../files/downloads/Xof_download_wkr_io.java | 40 + .../downloads/Xof_download_wkr_test.java | 30 + .../gplx/xowa/files/exts/Xof_rule_grp.java | 42 + .../gplx/xowa/files/exts/Xof_rule_itm.java | 33 + .../gplx/xowa/files/exts/Xof_rule_mgr.java | 45 + .../xowa/files/fsdb/Fsdb_regy_fil_tbl.java | 77 + .../gplx/xowa/files/fsdb/Xof_fsdb_mgr.java | 26 + .../xowa/files/fsdb/Xof_fsdb_mgr__sql.java | 69 + .../xowa/files/fsdb/Xof_fsdb_mgr_cfg.java | 27 + .../xowa/files/fsdb/fs_roots/Fs_root_dir.java | 110 ++ .../files/fsdb/fs_roots/Fs_root_dir_tst.java | 95 + .../files/fsdb/fs_roots/Fs_root_fsdb_mgr.java | 49 + .../files/fsdb/fs_roots/Fs_root_wkr_fsdb.java | 72 + .../files/fsdb/fs_roots/Orig_fil_itm.java | 46 + .../files/fsdb/fs_roots/Orig_fil_mgr.java | 24 + .../files/fsdb/fs_roots/Orig_fil_tbl.java | 81 + .../fsdb/tsts/Xof_file_ext__bmp_tst.java | 33 + .../fsdb/tsts/Xof_file_ext__flac_tst.java | 35 + .../fsdb/tsts/Xof_file_ext__oga_tst.java | 35 + .../fsdb/tsts/Xof_file_ext__ogg_tst.java | 37 + .../fsdb/tsts/Xof_file_ext__ogv_tst.java | 36 + .../fsdb/tsts/Xof_file_ext__pdf_tst.java | 29 + .../fsdb/tsts/Xof_file_ext__png_tst.java | 63 + .../fsdb/tsts/Xof_file_ext__svg_tst.java | 40 + .../fsdb/tsts/Xof_file_ext__unknown_tst.java | 35 + .../fsdb/tsts/Xof_file_ext__wav_tst.java | 36 + .../fsdb/tsts/Xof_file_ext__xcf_tst.java | 35 + .../xowa/files/fsdb/tsts/Xof_file_fxt.java | 189 ++ .../fsdb/tsts/Xof_file_redirect_tst.java | 66 + .../src/gplx/xowa/files/gui/Js_img_mgr.java | 56 + .../src/gplx/xowa/files/gui/Js_img_wkr.java | 22 + .../src/gplx/xowa/files/gui/Xog_js_wkr.java | 26 + .../src/gplx/xowa/files/gui/Xog_js_wkr_.java | 28 + .../gplx/xowa/files/gui/Xog_js_wkr__log.java | 34 + .../src/gplx/xowa/files/imgs/Xof_img_mgr.java | 29 + .../Xof_img_wkr_convert_djvu_to_tiff.java | 21 + .../Xof_img_wkr_convert_djvu_to_tiff_.java | 36 + .../imgs/Xof_img_wkr_query_img_size.java | 37 + .../imgs/Xof_img_wkr_query_img_size_test.java | 25 + .../xowa/files/origs/Xob_orig_tbl_bldr.java | 120 ++ .../gplx/xowa/files/origs/Xof_orig_itm.java | 56 + .../gplx/xowa/files/origs/Xof_orig_mgr.java | 94 + .../gplx/xowa/files/origs/Xof_orig_tbl.java | 115 ++ .../xowa/files/origs/Xof_orig_tbl_tst.java | 75 + .../gplx/xowa/files/origs/Xof_orig_wkr.java | 27 + .../gplx/xowa/files/origs/Xof_orig_wkr_.java | 39 + .../files/origs/Xof_orig_wkr__orig_db.java | 37 + .../files/origs/Xof_orig_wkr__wmf_api.java | 55 + .../files/origs/Xof_orig_wkr__xo_meta.java | 50 + .../xowa/files/origs/Xof_wiki_finder.java | 70 + .../xowa/files/origs/Xof_wiki_finder_itm.java | 28 + .../gplx/xowa/files/repos/Xof_repo_itm.java | 87 + .../gplx/xowa/files/repos/Xof_repo_itm_.java | 56 + .../gplx/xowa/files/repos/Xof_repo_pair.java | 32 + .../gplx/xowa/files/repos/Xow_repo_mgr.java | 25 + .../gplx/xowa/files/repos/Xow_repo_mgr_.java | 42 + .../gplx/xowa/files/repos/Xowe_repo_mgr.java | 260 +++ .../gplx/xowa/files/xfers/Xof_xfer_mgr.java | 376 ++++ .../gplx/xowa/files/xfers/Xof_xfer_queue.java | 87 + .../files/xfers/Xof_xfer_queue_base_fxt.java | 113 ++ .../xfers/Xof_xfer_queue_html_basic_tst.java | 134 ++ .../xfers/Xof_xfer_queue_html_cases_tst.java | 290 ++++ .../files/xfers/Xof_xfer_queue_html_fxt.java | 61 + .../Xof_xfer_queue_html_offline_tst.java | 31 + .../Xof_xfer_queue_html_wmf_api_tst.java | 170 ++ .../gplx/xowa/files/xfers/Xof_xfer_rslt.java | 31 + .../src/gplx/xowa/fmtrs/Gfo_sort_able.java | 21 + .../src/gplx/xowa/fmtrs/Xoa_fmtr_itm.java | 65 + .../src/gplx/xowa/fmtrs/Xoa_fmtr_itm_tst.java | 42 + .../src/gplx/xowa/fmtrs/Xoa_fmtr_mgr.java | 26 + .../gplx/xowa/fmtrs/Xoa_fmtr_sort_mgr.java | 66 + 400_xowa/src/gplx/xowa/gui/Xoa_gui_mgr.java | 136 ++ 400_xowa/src/gplx/xowa/gui/Xog_html_mgr.java | 40 + 400_xowa/src/gplx/xowa/gui/Xog_resizer.java | 114 ++ .../src/gplx/xowa/gui/bnds/Xog_bnd_box.java | 29 + .../src/gplx/xowa/gui/bnds/Xog_bnd_box_.java | 126 ++ .../src/gplx/xowa/gui/bnds/Xog_bnd_itm.java | 33 + .../xowa/gui/bnds/Xog_bnd_itm_srl_tst.java | 45 + .../src/gplx/xowa/gui/bnds/Xog_bnd_mgr.java | 248 +++ .../gplx/xowa/gui/bnds/Xog_bnd_mgr_srl.java | 69 + .../src/gplx/xowa/gui/bnds/Xog_bnd_win.java | 90 + .../src/gplx/xowa/gui/cmds/Xog_cmd_ctg.java | 71 + .../src/gplx/xowa/gui/cmds/Xog_cmd_itm.java | 35 + .../src/gplx/xowa/gui/cmds/Xog_cmd_itm_.java | 171 ++ .../src/gplx/xowa/gui/cmds/Xog_cmd_mgr.java | 57 + .../gplx/xowa/gui/cmds/Xog_cmd_mgr_invk.java | 27 + .../xowa/gui/history/Xog_history_itm.java | 52 + .../xowa/gui/history/Xog_history_mgr.java | 77 + .../xowa/gui/history/Xog_history_stack.java | 70 + .../gui/history/Xog_history_stack_tst.java | 86 + .../src/gplx/xowa/gui/menus/Xog_menu_mgr.java | 56 + .../gplx/xowa/gui/menus/Xog_menu_mnu_src.java | 247 +++ .../xowa/gui/menus/Xog_popup_mnu_mgr.java | 68 + .../xowa/gui/menus/Xog_window_mnu_mgr.java | 46 + .../gplx/xowa/gui/menus/dom/Xog_mnu_base.java | 117 ++ .../gplx/xowa/gui/menus/dom/Xog_mnu_bldr.java | 84 + .../xowa/gui/menus/dom/Xog_mnu_evt_mgr.java | 38 + .../gplx/xowa/gui/menus/dom/Xog_mnu_grp.java | 112 ++ .../gplx/xowa/gui/menus/dom/Xog_mnu_itm.java | 87 + .../gplx/xowa/gui/menus/dom/Xog_mnu_regy.java | 103 ++ .../gui/urls/Xof_orig_file_downloader.java | 33 + .../src/gplx/xowa/gui/urls/Xog_url_wkr.java | 159 ++ .../gplx/xowa/gui/urls/Xog_url_wkr_tst.java | 100 ++ .../urls/url_macros/Xog_url_macro_grp.java | 44 + .../urls/url_macros/Xog_url_macro_mgr.java | 92 + .../url_macros/Xog_url_macro_mgr_tst.java | 56 + .../gplx/xowa/gui/views/Load_page_wkr.java | 81 + .../src/gplx/xowa/gui/views/Rect_ref.java | 38 + .../src/gplx/xowa/gui/views/Xog_html_itm.java | 261 +++ .../gplx/xowa/gui/views/Xog_html_itm_tst.java | 60 + .../src/gplx/xowa/gui/views/Xog_js_procs.java | 46 + .../xowa/gui/views/Xog_launcher_tabs.java | 103 ++ .../src/gplx/xowa/gui/views/Xog_layout.java | 109 ++ .../gplx/xowa/gui/views/Xog_layout_box.java | 83 + .../xowa/gui/views/Xog_tab_close_lnr.java | 21 + .../xowa/gui/views/Xog_tab_close_mgr.java | 33 + .../src/gplx/xowa/gui/views/Xog_tab_itm.java | 277 +++ .../src/gplx/xowa/gui/views/Xog_tab_itm_.java | 30 + .../xowa/gui/views/Xog_tab_itm_edit_mgr.java | 127 ++ .../xowa/gui/views/Xog_tab_itm_read_mgr.java | 89 + .../src/gplx/xowa/gui/views/Xog_tab_mgr.java | 269 +++ .../src/gplx/xowa/gui/views/Xog_win_itm.java | 308 ++++ .../src/gplx/xowa/gui/views/Xog_win_itm_.java | 58 + .../gui/views/Xog_win_itm__prog_href_mgr.java | 40 + 400_xowa/src/gplx/xowa/html/Xoh_cfg_file.java | 29 + 400_xowa/src/gplx/xowa/html/Xoh_cmd_itm.java | 23 + 400_xowa/src/gplx/xowa/html/Xoh_cmd_mgr.java | 40 + 400_xowa/src/gplx/xowa/html/Xoh_consts.java | 58 + 400_xowa/src/gplx/xowa/html/Xoh_html_mgr.java | 39 + 400_xowa/src/gplx/xowa/html/Xoh_html_wtr.java | 666 +++++++ .../src/gplx/xowa/html/Xoh_html_wtr_cfg.java | 25 + .../gplx/xowa/html/Xoh_html_wtr_escaper.java | 123 ++ .../src/gplx/xowa/html/Xoh_html_wtr_tst.java | 357 ++++ 400_xowa/src/gplx/xowa/html/Xoh_imgs_mgr.java | 36 + 400_xowa/src/gplx/xowa/html/Xoh_page_mgr.java | 62 + .../gplx/xowa/html/Xoh_page_wtr_mgr_base.java | 26 + .../gplx/xowa/html/Xoh_page_wtr_mgr_tst.java | 33 + .../src/gplx/xowa/html/Xoh_page_wtr_wkr.java | 169 ++ .../src/gplx/xowa/html/Xoh_page_wtr_wkr_.java | 56 + .../gplx/xowa/html/Xoh_page_wtr_wkr_tst.java | 75 + 400_xowa/src/gplx/xowa/html/Xoh_wtr_ctx.java | 33 + .../src/gplx/xowa/html/Xohe_page_wtr_mgr.java | 114 ++ .../src/gplx/xowa/html/Xohp_ctg_grp_mgr.java | 62 + .../gplx/xowa/html/Xohp_ctg_grp_mgr_tst.java | 56 + .../src/gplx/xowa/html/Xohv_page_wtr_mgr.java | 20 + 400_xowa/src/gplx/xowa/html/Xow_html_mgr.java | 75 + .../gplx/xowa/html/css/Xob_css_status.java | 79 + .../src/gplx/xowa/html/css/Xow_css_mgr.java | 53 + .../gplx/xowa/html/css/Xowd_css_core_mgr.java | 60 + .../xowa/html/css/Xowd_css_core_mgr_tst.java | 120 ++ .../gplx/xowa/html/hdumps/Xohd_hdump_rdr.java | 88 + .../gplx/xowa/html/hdumps/Xohd_hdump_wtr.java | 57 + .../xowa/html/hdumps/Xohd_hdump_wtr_tst.java | 158 ++ .../xowa/html/hdumps/abrvs/Xohd_abrv_.java | 74 + .../xowa/html/hdumps/abrvs/Xohd_abrv_mgr.java | 162 ++ .../html/hdumps/abrvs/Xohd_abrv_mgr_tst.java | 153 ++ .../html/hdumps/bldrs/Xob_hdump_bldr.java | 96 + .../html/hdumps/bldrs/Xob_hdump_img_cmd.java | 116 ++ .../html/hdumps/bldrs/Xob_link_dump_cmd.java | 56 + .../html/hdumps/bldrs/Xob_link_dump_tbl.java | 69 + .../hdumps/bldrs/Xob_redlink_mkr_cmd.java | 88 + .../xowa/html/hdumps/core/Xohd_data_itm.java | 23 + .../html/hdumps/core/Xohd_data_itm__base.java | 101 ++ .../core/Xohd_data_itm__gallery_itm.java | 44 + .../core/Xohd_data_itm__gallery_mgr.java | 35 + .../html/hdumps/core/Xohd_data_itm__img.java | 23 + .../xowa/html/hdumps/core/Xohd_data_tid.java | 26 + .../hdumps/data/Xohd_page_html_mgr__load.java | 87 + .../hdumps/data/Xohd_page_html_mgr__save.java | 52 + .../hdumps/data/srl/Xohd_page_srl_itm.java | 46 + .../hdumps/data/srl/Xohd_page_srl_itm_.java | 34 + .../data/srl/Xohd_page_srl_itm_tst.java | 98 ++ .../hdumps/data/srl/Xohd_page_srl_itms.java | 75 + .../hdumps/data/srl/Xohd_page_srl_mgr.java | 44 + .../html/hdumps/pages/Xopg_hdump_data.java | 39 + .../html/hdumps/pages/Xopg_module_mgr.java | 33 + .../src/gplx/xowa/html/hrefs/Xoh_href.java | 75 + .../gplx/xowa/html/hrefs/Xoh_href_parser.java | 243 +++ .../xowa/html/hrefs/Xoh_href_parser_tst.java | 249 +++ .../gplx/xowa/html/hzips/Hzip_bfr_mgr.java | 54 + .../xowa/html/hzips/Xodump_stats_itm.java | 49 + .../xowa/html/hzips/Xodump_stats_tbl.java | 75 + .../gplx/xowa/html/hzips/Xow_hzip_dict.java | 44 + .../gplx/xowa/html/hzips/Xow_hzip_int_.java | 64 + .../xowa/html/hzips/Xow_hzip_int__tst.java | 52 + .../xowa/html/hzips/Xow_hzip_itm__anchor.java | 236 +++ .../html/hzips/Xow_hzip_itm__anchor_tst.java | 120 ++ .../html/hzips/Xow_hzip_itm__file_tst.java | 27 + .../xowa/html/hzips/Xow_hzip_itm__header.java | 55 + .../html/hzips/Xow_hzip_itm__header_tst.java | 38 + .../xowa/html/hzips/Xow_hzip_itm__href.java | 98 ++ .../gplx/xowa/html/hzips/Xow_hzip_mgr.java | 109 ++ .../xowa/html/hzips/Xow_hzip_mgr_fxt.java | 59 + .../gplx/xowa/html/hzips/Xow_hzip_xtid.java | 52 + .../src/gplx/xowa/html/js/Xoh_js_cbk.java | 197 +++ .../src/gplx/xowa/html/js/Xoh_js_cbk_tst.java | 46 + .../html/js/Xoh_js_cbk_wdata_labels_tst.java | 63 + .../src/gplx/xowa/html/js/Xoh_json_exec.java | 53 + .../xowa/html/lnkis/Xoh_arg_img_core.java | 21 + .../html/lnkis/Xoh_arg_img_core__basic.java | 26 + .../html/lnkis/Xoh_arg_img_core__hdump.java | 31 + .../html/lnkis/Xoh_file_html_fmtr__base.java | 146 ++ .../html/lnkis/Xoh_file_html_fmtr__hdump.java | 55 + .../xowa/html/lnkis/Xoh_file_img_wkr.java | 25 + .../gplx/xowa/html/lnkis/Xoh_file_mgr.java | 76 + .../xowa/html/lnkis/Xoh_file_wtr__basic.java | 235 +++ .../lnkis/Xoh_file_wtr_audio_video_tst.java | 249 +++ .../html/lnkis/Xoh_file_wtr_basic_tst.java | 297 ++++ .../html/lnkis/Xoh_file_wtr_media_tst.java | 63 + .../gplx/xowa/html/lnkis/Xoh_lnki_consts.java | 50 + .../xowa/html/lnkis/Xoh_lnki_consts_tst.java | 34 + .../xowa/html/lnkis/Xoh_lnki_text_fmtr.java | 39 + .../xowa/html/lnkis/Xoh_lnki_title_fmtr.java | 76 + .../html/lnkis/Xoh_lnki_title_fmtr_tst.java | 42 + .../gplx/xowa/html/lnkis/Xoh_lnki_wtr.java | 201 +++ .../gplx/xowa/html/lnkis/Xoh_redlink_utl.java | 22 + .../xowa/html/modules/Xoh_module_itm.java | 34 + .../xowa/html/modules/Xoh_module_itm_.java | 36 + .../modules/Xoh_module_itm__collapsible.java | 41 + .../html/modules/Xoh_module_itm__css.java | 38 + .../html/modules/Xoh_module_itm__gallery.java | 36 + .../html/modules/Xoh_module_itm__globals.java | 105 ++ .../html/modules/Xoh_module_itm__hiero.java | 35 + .../html/modules/Xoh_module_itm__mathjax.java | 35 + .../modules/Xoh_module_itm__navframe.java | 41 + .../html/modules/Xoh_module_itm__popups.java | 60 + .../Xoh_module_itm__search_suggest.java | 39 + .../modules/Xoh_module_itm__timeline.java | 35 + .../Xoh_module_itm__title_rewrite.java | 34 + .../html/modules/Xoh_module_itm__toc.java | 51 + .../modules/Xoh_module_itm__top_icon.java | 39 + .../html/modules/Xoh_module_itm__xoui.java | 47 + .../xowa/html/modules/Xoh_module_mgr.java | 112 ++ .../xowa/html/modules/Xoh_module_mgr_tst.java | 130 ++ .../xowa/html/modules/Xoh_module_wtr.java | 182 ++ .../xowa/html/modules/Xoh_module_wtr_tst.java | 63 + .../html/modules/popups/Xopg_popup_mgr.java | 24 + .../popups/Xow_popup_anchor_finder.java | 69 + .../Xow_popup_anchor_finder__hdr_tst.java | 85 + .../Xow_popup_anchor_finder__id_tst.java | 50 + .../html/modules/popups/Xow_popup_cfg.java | 34 + .../modules/popups/Xow_popup_html_mkr.java | 69 + .../html/modules/popups/Xow_popup_itm.java | 51 + .../html/modules/popups/Xow_popup_mgr.java | 303 ++++ .../html/modules/popups/Xow_popup_parser.java | 247 +++ .../modules/popups/Xow_popup_parser_data.java | 64 + .../modules/popups/Xow_popup_parser_tst.java | 513 ++++++ .../html/modules/popups/Xow_popup_word.java | 29 + .../modules/popups/Xow_popup_wrdx_mkr.java | 202 +++ .../popups/keeplists/Xop_keeplist_rule.java | 47 + .../popups/keeplists/Xop_keeplist_wiki.java | 49 + .../keeplists/Xop_keeplist_wiki_srl.java | 66 + .../keeplists/Xop_keeplist_wiki_tst.java | 61 + .../Xoh_file_page__other_resolutions.java | 39 + .../xowa/html/ns_files/Xoh_file_page_wtr.java | 111 ++ .../html/ns_files/Xoh_ns_file_page_mgr.java | 87 + .../ns_files/Xoh_ns_file_page_mgr_tst.java | 139 ++ .../html/portal/Xoa_available_wikis_mgr.java | 52 + .../gplx/xowa/html/portal/Xoa_portal_mgr.java | 26 + .../xowa/html/portal/Xoh_page_body_cls.java | 131 ++ .../html/portal/Xoh_page_body_cls_tst.java | 54 + .../gplx/xowa/html/portal/Xoh_rtl_utl.java | 73 + .../xowa/html/portal/Xoh_rtl_utl_tst.java | 64 + .../xowa/html/portal/Xoh_subpages_bldr.java | 66 + .../html/portal/Xoh_subpages_bldr_tst.java | 50 + .../gplx/xowa/html/portal/Xow_portal_mgr.java | 141 ++ .../xowa/html/portal/Xow_portal_mgr_tst.java | 51 + .../xowa/html/sidebar/Xowh_sidebar_itm.java | 50 + .../xowa/html/sidebar/Xowh_sidebar_mgr.java | 136 ++ .../html/sidebar/Xowh_sidebar_mgr_tst.java | 259 +++ .../gplx/xowa/html/skins/Xoh_skin_itm.java | 33 + .../gplx/xowa/html/skins/Xoh_skin_mgr.java | 51 + .../gplx/xowa/html/skins/Xoh_skin_regy.java | 34 + .../src/gplx/xowa/html/tidy/Xoh_tidy_mgr.java | 85 + .../gplx/xowa/html/tidy/Xoh_tidy_mgr_tst.java | 92 + .../src/gplx/xowa/html/tidy/Xoh_tidy_wkr.java | 22 + .../gplx/xowa/html/tidy/Xoh_tidy_wkr_.java | 42 + .../xowa/html/tidy/Xoh_tidy_wkr_jtidy.java | 77 + .../html/tidy/Xoh_tidy_wkr_jtidy_tst.java | 54 + .../xowa/html/tidy/Xoh_tidy_wkr_tidy.java | 58 + .../src/gplx/xowa/html/tocs/Xow_hdr_mgr.java | 129 ++ .../src/gplx/xowa/html/tocs/Xow_toc_mgr.java | 220 +++ .../gplx/xowa/html/tocs/Xow_toc_mgr_tst.java | 545 ++++++ .../gplx/xowa/html/utils/Xoh_js_cleaner.java | 203 +++ .../xowa/html/utils/Xoh_js_cleaner_tst.java | 42 + .../xowa/html/wtrs/Xoh_anchor_kv_bldr.java | 49 + .../src/gplx/xowa/html/wtrs/Xoh_img_path.java | 27 + .../gplx/xowa/html/wtrs/Xoh_lnki_bldr.java | 82 + .../gplx/xowa/html/wtrs/Xoh_lnki_wtr_utl.java | 34 + .../html/xouis/fmtrs/Xoui_cells_fmtr.java | 77 + .../xowa/html/xouis/fmtrs/Xoui_tbl_fmtr.java | 71 + .../html/xouis/fmtrs/Xoui_tbl_fmtr_tst.java | 41 + .../xowa/html/xouis/fmtrs/Xoui_val_fmtr.java | 43 + .../xowa/html/xouis/fmtrs/Xoui_val_fmtr_.java | 22 + .../xowa/html/xouis/tbls/Xoui_btn_itm.java | 25 + .../xowa/html/xouis/tbls/Xoui_col_itm.java | 26 + .../xowa/html/xouis/tbls/Xoui_row_itm.java | 26 + .../xowa/html/xouis/tbls/Xoui_tbl_itm.java | 29 + .../xowa/html/xouis/tbls/Xoui_tbl_mgr.java | 82 + .../xowa/html/xouis/tbls/Xoui_val_hash.java | 26 + .../xowa/html/xouis/tbls/Xoui_val_itm.java | 24 + .../src/gplx/xowa/langs/Xoa_lang_mgr.java | 118 ++ .../gplx/xowa/langs/Xol_func_name_itm.java | 36 + .../gplx/xowa/langs/Xol_func_name_regy.java | 117 ++ .../src/gplx/xowa/langs/Xol_lang_itm.java | 28 + .../src/gplx/xowa/langs/Xol_lang_itm_.java | 948 ++++++++++ .../gplx/xowa/langs/cases/Xol_case_itm.java | 93 + .../gplx/xowa/langs/cases/Xol_case_itm_.java | 148 ++ .../gplx/xowa/langs/cases/Xol_case_mgr.java | 136 ++ .../gplx/xowa/langs/cases/Xol_case_mgr_.java | 1123 ++++++++++++ .../xowa/langs/cases/Xol_case_mgr_tst.java | 151 ++ .../src/gplx/xowa/langs/cnvs/Xol_cnv_grp.java | 64 + .../src/gplx/xowa/langs/cnvs/Xol_cnv_itm.java | 23 + .../src/gplx/xowa/langs/cnvs/Xol_cnv_mgr.java | 38 + .../gplx/xowa/langs/cnvs/Xol_cnv_mgr_tst.java | 89 + .../xowa/langs/cnvs/Xol_mw_parse_tst.java | 141 ++ .../langs/durations/Xol_duration_itm.java | 28 + .../langs/durations/Xol_duration_itm_.java | 80 + .../langs/durations/Xol_duration_mgr.java | 90 + .../langs/durations/Xol_interval_itm.java | 32 + .../gplx/xowa/langs/genders/Xol_gender.java | 21 + .../gplx/xowa/langs/genders/Xol_gender_.java | 34 + .../gplx/xowa/langs/grammars/Xol_grammar.java | 21 + .../xowa/langs/grammars/Xol_grammar_.java | 55 + .../xowa/langs/grammars/Xol_grammar_fi.java | 80 + .../grammars/Xol_grammar_manual_regy.java | 34 + .../xowa/langs/grammars/Xol_grammar_ru.java | 73 + .../gplx/xowa/langs/msgs/Xol_msg_mgr_.java | 134 ++ .../xowa/langs/numbers/Xol_num_fmtr_base.java | 204 +++ .../langs/numbers/Xol_num_fmtr_base_tst.java | 118 ++ .../gplx/xowa/langs/numbers/Xol_num_grp.java | 26 + .../xowa/langs/numbers/Xol_num_grp_fmtr.java | 81 + .../langs/numbers/Xol_num_grp_fmtr_tst.java | 54 + .../gplx/xowa/langs/numbers/Xol_num_mgr.java | 73 + .../gplx/xowa/langs/numbers/Xol_num_mgr_.java | 40 + .../langs/numbers/Xol_num_mgr__commafy_5.java | 44 + .../xowa/langs/numbers/Xol_transform_mgr.java | 54 + .../gplx/xowa/langs/plurals/Xol_plural.java | 21 + .../gplx/xowa/langs/plurals/Xol_plural_.java | 44 + .../xowa/langs/plurals/Xol_plural_ru.java | 40 + .../xowa/langs/plurals/Xol_plural_ru_tst.java | 35 + .../xowa/langs/vnts/Xol_vnt_converter.java | 74 + .../src/gplx/xowa/langs/vnts/Xol_vnt_itm.java | 40 + .../src/gplx/xowa/langs/vnts/Xol_vnt_mgr.java | 105 ++ .../gplx/xowa/langs/vnts/Xolg_vnt_grp.java | 25 + .../xowa/langs/vnts/Xolg_vnt_grp_fmtr.java | 58 + .../langs/vnts/Xolg_vnt_grp_fmtr_tst.java | 68 + .../gplx/xowa/langs/vnts/Xolg_vnt_itm.java | 23 + .../xowa/langs/vnts/Xop_vnt_eqgt_tkn.java | 22 + .../gplx/xowa/langs/vnts/Xop_vnt_flag.java | 124 ++ .../langs/vnts/Xop_vnt_flag_lang_bldr.java | 64 + .../xowa/langs/vnts/Xop_vnt_flag_parser.java | 111 ++ .../xowa/langs/vnts/Xop_vnt_html_wtr.java | 82 + .../gplx/xowa/langs/vnts/Xop_vnt_lxr_.java | 95 + .../gplx/xowa/langs/vnts/Xop_vnt_lxr_tst.java | 163 ++ .../xowa/langs/vnts/Xop_vnt_parser_tst.java | 88 + .../gplx/xowa/langs/vnts/Xop_vnt_rule.java | 26 + .../xowa/langs/vnts/Xop_vnt_rules_parser.java | 229 +++ .../src/gplx/xowa/langs/vnts/Xop_vnt_tkn.java | 70 + .../src/gplx/xowa/net/Xoo_protocol_itm.java | 129 ++ .../src/gplx/xowa/pages/Xopg_html_data.java | 93 + .../gplx/xowa/pages/Xopg_revision_data.java | 26 + .../src/gplx/xowa/pages/Xopg_tab_data.java | 29 + .../xowa/pages/Xopg_tmpl_prepend_mgr.java | 61 + .../src/gplx/xowa/pages/Xopg_view_mode.java | 21 + .../pages/skins/Xopg_xtn_skin_fmtr_arg.java | 33 + .../xowa/pages/skins/Xopg_xtn_skin_itm.java | 23 + .../pages/skins/Xopg_xtn_skin_itm_stub.java | 25 + .../pages/skins/Xopg_xtn_skin_itm_tid.java | 21 + .../xowa/pages/skins/Xopg_xtn_skin_mgr.java | 26 + .../gplx/xowa/parsers/amps/Xop_amp_lxr.java | 28 + .../gplx/xowa/parsers/amps/Xop_amp_mgr.java | 121 ++ .../parsers/amps/Xop_amp_mgr_decode_tst.java | 44 + .../xowa/parsers/amps/Xop_amp_tkn_num.java | 27 + .../xowa/parsers/amps/Xop_amp_tkn_txt.java | 31 + .../gplx/xowa/parsers/amps/Xop_amp_trie.java | 318 ++++ .../xowa/parsers/amps/Xop_amp_trie_itm.java | 58 + .../gplx/xowa/parsers/amps/Xop_amp_wkr.java | 32 + .../xowa/parsers/amps/Xop_amp_wkr_tst.java | 41 + .../gplx/xowa/parsers/apos/Xop_apos_dat.java | 83 + .../gplx/xowa/parsers/apos/Xop_apos_log.java | 26 + .../gplx/xowa/parsers/apos/Xop_apos_lxr.java | 26 + .../gplx/xowa/parsers/apos/Xop_apos_tkn.java | 29 + .../gplx/xowa/parsers/apos/Xop_apos_tkn_.java | 36 + .../xowa/parsers/apos/Xop_apos_tkn_chkr.java | 30 + .../gplx/xowa/parsers/apos/Xop_apos_wkr.java | 161 ++ .../xowa/parsers/apos/Xop_apos_wkr_tst.java | 159 ++ .../gplx/xowa/parsers/hdrs/Xop_hdr_log.java | 27 + .../gplx/xowa/parsers/hdrs/Xop_hdr_lxr.java | 27 + .../gplx/xowa/parsers/hdrs/Xop_hdr_tkn.java | 33 + .../xowa/parsers/hdrs/Xop_hdr_tkn_chkr.java | 33 + .../gplx/xowa/parsers/hdrs/Xop_hdr_wkr.java | 123 ++ .../parsers/hdrs/Xop_hdr_wkr__basic_tst.java | 127 ++ .../hdrs/Xop_hdr_wkr__div_wrapper_tst.java | 56 + .../parsers/hdrs/Xop_hdr_wkr__para_tst.java | 26 + .../gplx/xowa/parsers/lists/Xop_list_lxr.java | 27 + .../gplx/xowa/parsers/lists/Xop_list_tkn.java | 32 + .../xowa/parsers/lists/Xop_list_tkn_.java | 54 + .../xowa/parsers/lists/Xop_list_tkn_chkr.java | 36 + .../gplx/xowa/parsers/lists/Xop_list_wkr.java | 185 ++ .../xowa/parsers/lists/Xop_list_wkr_.java | 54 + .../parsers/lists/Xop_list_wkr_basic_tst.java | 337 ++++ .../parsers/lists/Xop_list_wkr_para_tst.java | 88 + .../lists/Xop_list_wkr_uncommon_tst.java | 409 +++++ .../gplx/xowa/parsers/lnkes/Xoh_lnke_wtr.java | 96 + .../xowa/parsers/lnkes/Xoh_lnke_wtr_tst.java | 36 + .../xowa/parsers/lnkes/Xop_lnke_end_lxr.java | 26 + .../gplx/xowa/parsers/lnkes/Xop_lnke_log.java | 22 + .../gplx/xowa/parsers/lnkes/Xop_lnke_lxr.java | 44 + .../gplx/xowa/parsers/lnkes/Xop_lnke_tkn.java | 40 + .../gplx/xowa/parsers/lnkes/Xop_lnke_wkr.java | 306 ++++ .../parsers/lnkes/Xop_lnke_wkr_brack_tst.java | 94 + .../lnkes/Xop_lnke_wkr_dangling_tst.java | 39 + .../lnkes/Xop_lnke_wkr_relative_tst.java | 42 + .../parsers/lnkes/Xop_lnke_wkr_text_tst.java | 99 ++ .../lnkes/Xop_lnke_wkr_uncommon_tst.java | 49 + .../parsers/lnkes/Xop_lnke_wkr_xwiki_tst.java | 43 + .../xowa/parsers/lnkis/cfgs/Xoc_lnki_cfg.java | 27 + .../lnkis/cfgs/Xoc_xwiki_repo_mgr.java | 45 + .../lnkis/redlinks/Xog_redlink_mgr.java | 121 ++ .../lnkis/redlinks/Xopg_redlink_idx_list.java | 32 + .../redlinks/Xopg_redlink_lnki_list.java | 50 + .../lnkis/redlinks/Xopg_redlink_logger.java | 21 + .../xowa/parsers/logs/Xop_log_basic_tbl.java | 63 + .../xowa/parsers/logs/Xop_log_basic_wkr.java | 72 + .../xowa/parsers/logs/Xop_log_invoke_wkr.java | 82 + .../gplx/xowa/parsers/logs/Xop_log_mgr.java | 68 + .../parsers/logs/Xop_log_property_wkr.java | 77 + .../gplx/xowa/parsers/paras/Xop_nl_lxr.java | 115 ++ .../xowa/parsers/paras/Xop_nl_tab_lxr.java | 51 + .../parsers/paras/Xop_nl_tab_lxr_tst.java | 65 + .../gplx/xowa/parsers/paras/Xop_nl_tkn.java | 27 + .../gplx/xowa/parsers/paras/Xop_para_tkn.java | 31 + .../gplx/xowa/parsers/paras/Xop_para_wkr.java | 344 ++++ .../parsers/paras/Xop_para_wkr_basic_tst.java | 1074 ++++++++++++ .../parsers/paras/Xop_para_wkr_para_tst.java | 109 ++ .../parsers/paras/Xop_para_wkr_pre_tst.java | 258 +++ .../gplx/xowa/parsers/paras/Xop_pre_lxr.java | 92 + .../gplx/xowa/parsers/paras/Xop_pre_tkn.java | 27 + .../gplx/xowa/parsers/tblws/Xop_tblw_lxr.java | 135 ++ .../xowa/parsers/tblws/Xop_tblw_lxr_ws.java | 66 + .../xowa/parsers/tblws/Xop_tblw_tb_tkn.java | 37 + .../xowa/parsers/tblws/Xop_tblw_tc_tkn.java | 30 + .../xowa/parsers/tblws/Xop_tblw_td_tkn.java | 30 + .../xowa/parsers/tblws/Xop_tblw_th_tkn.java | 30 + .../gplx/xowa/parsers/tblws/Xop_tblw_tkn.java | 27 + .../xowa/parsers/tblws/Xop_tblw_tr_tkn.java | 34 + .../gplx/xowa/parsers/tblws/Xop_tblw_wkr.java | 551 ++++++ .../parsers/tblws/Xop_tblw_wkr__atrs_tst.java | 212 +++ .../tblws/Xop_tblw_wkr__basic_tst.java | 823 +++++++++ .../tblws/Xop_tblw_wkr__dangling_tst.java | 57 + .../tblws/Xop_tblw_wkr__double_pipe_tst.java | 108 ++ .../parsers/tblws/Xop_tblw_wkr__errs_tst.java | 94 + .../tblws/Xop_tblw_wkr__nested_tst.java | 200 +++ .../parsers/tblws/Xop_tblw_wkr__para_tst.java | 156 ++ .../parsers/tblws/Xop_tblw_wkr__tblx_tst.java | 71 + .../tblws/Xop_tblw_wkr__uncommon_tst.java | 104 ++ .../xowa/parsers/tblws/Xop_tblw_ws_itm.java | 63 + .../xowa/parsers/tmpls/Nowiki_escape_itm.java | 68 + .../gplx/xowa/servers/Gxw_html_server.java | 74 + .../xowa/servers/http/File_retrieve_mode.java | 36 + .../xowa/servers/http/Http_server_mgr.java | 377 ++++ .../xowa/servers/http/Http_server_wkr_.java | 39 + .../servers/http/Http_server_wkr__tst.java | 42 + .../xowa/servers/http/Http_server_wkr_v2.java | 183 ++ .../src/gplx/xowa/servers/tcp/Socket_rdr.java | 53 + .../src/gplx/xowa/servers/tcp/Socket_wtr.java | 51 + .../xowa/servers/tcp/Xosrv_cmd_types.java | 25 + .../src/gplx/xowa/servers/tcp/Xosrv_msg.java | 121 ++ .../gplx/xowa/servers/tcp/Xosrv_msg_rdr.java | 64 + .../xowa/servers/tcp/Xosrv_msg_rdr_tst.java | 65 + .../gplx/xowa/servers/tcp/Xosrv_server.java | 128 ++ .../xowa/servers/tcp/Xosrv_server_tst.java | 40 + .../xowa/servers/tcp/Xosrv_socket_rdr.java | 48 + .../xowa/servers/tcp/Xosrv_socket_wtr.java | 34 + .../gplx/xowa/setup/addons/Xoi_addon_mgr.java | 28 + .../setup/addons/Xoi_firefox_installer.java | 64 + .../addons/Xoi_firefox_installer_tst.java | 43 + .../gplx/xowa/setup/maints/Wmf_dump_itm.java | 37 + .../setup/maints/Wmf_dump_list_parser.java | 72 + .../maints/Wmf_dump_list_parser_tst.java | 137 ++ .../xowa/setup/maints/Wmf_latest_itm.java | 26 + .../xowa/setup/maints/Wmf_latest_parser.java | 67 + .../setup/maints/Wmf_latest_parser_tst.java | 53 + .../gplx/xowa/setup/maints/Xoa_maint_mgr.java | 78 + .../setup/maints/Xoa_maint_wikis_mgr.java | 47 + .../gplx/xowa/setup/maints/Xow_maint_mgr.java | 57 + .../gplx/xowa/specials/Xoa_special_mgr.java | 30 + 400_xowa/src/gplx/xowa/specials/Xows_mgr.java | 95 + .../src/gplx/xowa/specials/Xows_page.java | 22 + .../gplx/xowa/specials/Xows_special_meta.java | 35 + .../xowa/specials/Xows_special_meta_.java | 75 + .../specials/allPages/Xows_page_allpages.java | 196 +++ .../allPages/Xows_page_allpages_tst.java | 205 +++ .../xowa/specials/movePage/Move_page.java | 181 ++ .../gplx/xowa/specials/nearby/Nearby_mgr.java | 196 +++ .../xowa/specials/nearby/Nearby_mgr_tst.java | 77 + .../randoms/Xop_randomRootPage_page.java | 27 + .../randoms/Xop_randomRootPage_page_tst.java | 55 + .../specials/randoms/Xows_page_random.java | 27 + .../search/Xog_search_suggest_cmd.java | 111 ++ .../search/Xog_search_suggest_mgr.java | 146 ++ .../xowa/specials/search/Xosrh_core_tst.java | 219 +++ .../xowa/specials/search/Xosrh_page_mgr.java | 98 ++ .../search/Xosrh_page_mgr_searcher.java | 21 + .../specials/search/Xosrh_page_mgr_tst.java | 86 + .../xowa/specials/search/Xosrh_parser.java | 88 + .../specials/search/Xosrh_parser_tst.java | 168 ++ .../xowa/specials/search/Xosrh_qry_itm.java | 219 +++ .../xowa/specials/search/Xosrh_rslt_grp.java | 44 + .../search/Xosrh_rslt_itm_sorter.java | 52 + .../xowa/specials/search/Xosrh_scanner.java | 153 ++ .../search/Xow_domain_sorter__manual_tid.java | 121 ++ .../xowa/specials/search/Xows_arg_mgr.java | 74 + .../gplx/xowa/specials/search/Xows_core.java | 86 + .../xowa/specials/search/Xows_db_cache.java | 42 + .../xowa/specials/search/Xows_db_matcher.java | 68 + .../specials/search/Xows_db_matcher_bldr.java | 95 + .../xowa/specials/search/Xows_db_row.java | 41 + .../xowa/specials/search/Xows_db_wkr.java | 109 ++ .../xowa/specials/search/Xows_db_word.java | 36 + .../xowa/specials/search/Xows_html_wkr.java | 123 ++ .../specials/search/Xows_html_wkr_tst.java | 76 + .../xowa/specials/search/Xows_ns_mgr.java | 81 + .../specials/search/Xows_page__search.java | 102 ++ .../specials/search/Xows_paging_parser.java | 40 + .../xowa/specials/search/Xows_ui_async.java | 70 + .../specials/search/Xows_ui_async_tst.java | 62 + .../xowa/specials/search/Xows_ui_cmd.java | 116 ++ .../xowa/specials/search/Xows_ui_qry.java | 45 + .../xowa/specials/search/Xows_ui_rslt.java | 24 + .../search/parsers/Xows_text_parser__v1.java | 68 + .../search/parsers/Xows_text_parser__v2.java | 107 ++ .../parsers/Xows_text_parser__v2_tst.java | 156 ++ .../search/parsers/Xows_text_tkn.java | 146 ++ .../search/parsers_old/Xow_search_parser.java | 94 + .../parsers_old/Xow_search_scanner.java | 144 ++ .../search/parsers_old/Xow_search_tkn.java | 40 + .../statistics/Xop_statistics_page.java | 132 ++ .../statistics/Xop_statistics_page_tst.java | 55 + .../xowa/bookmarks/Xoui_tbl_itm__bmk.java | 107 ++ .../xowa/bookmarks/Xows_bmk_page.java | 33 + .../xowa/default_tab/Default_tab_page.java | 27 + .../xowa/specials/xowa/diags/Db_rdr_utl.java | 73 + .../xowa/diags/Xows_cmd__file_check.java | 137 ++ .../xowa/diags/Xows_cmd__fs_check.java | 59 + .../xowa/diags/Xows_cmd__sql_dump.java | 51 + .../specials/xowa/diags/Xows_diag_page.java | 44 + .../xowa/file_browsers/Xoa_url_arg_mgr.java | 72 + .../file_browsers/Xosp_fbrow_cmd__base.java | 216 +++ .../file_browsers/Xosp_fbrow_data_dir.java | 61 + .../xowa/file_browsers/Xosp_fbrow_rslt.java | 24 + .../file_browsers/Xosp_fbrow_special.java | 40 + .../file_browsers/Xosp_fbrow_special_tst.java | 145 ++ .../popup_history/Popup_history_page.java | 40 + .../xowa/system_data/System_data_page.java | 63 + .../src/gplx/xowa/tdbs/Xotdb_dir_info.java | 55 + .../src/gplx/xowa/tdbs/Xotdb_dir_info_.java | 62 + .../src/gplx/xowa/tdbs/Xotdb_fsys_mgr.java | 92 + .../gplx/xowa/tdbs/Xotdb_fsys_mgr_tst.java | 37 + .../src/gplx/xowa/tdbs/Xotdb_page_itm_.java | 88 + .../gplx/xowa/tdbs/Xotdb_page_raw_parser.java | 58 + .../xowa/urls/encoders/Url_encoder_mgr.java | 29 + .../src/gplx/xowa/users/Xoc_layout_mgr.java | 75 + 400_xowa/src/gplx/xowa/users/Xou_cfg.java | 45 + .../src/gplx/xowa/users/Xou_fsys_mgr.java | 48 + 400_xowa/src/gplx/xowa/users/Xou_log_mgr.java | 29 + .../src/gplx/xowa/users/Xou_security_mgr.java | 30 + 400_xowa/src/gplx/xowa/users/Xou_session.java | 27 + 400_xowa/src/gplx/xowa/users/Xou_user.java | 26 + 400_xowa/src/gplx/xowa/users/Xou_user_.java | 66 + .../src/gplx/xowa/users/Xou_user_mgr.java | 38 + .../src/gplx/xowa/users/Xou_user_tst.java | 56 + .../src/gplx/xowa/users/Xouc_pages_mgr.java | 28 + .../src/gplx/xowa/users/Xouc_setup_mgr.java | 60 + .../src/gplx/xowa/users/Xouc_startup_mgr.java | 66 + .../src/gplx/xowa/users/Xouc_window_mgr.java | 103 ++ 400_xowa/src/gplx/xowa/users/Xoue_user.java | 133 ++ .../src/gplx/xowa/users/Xous_window_mgr.java | 64 + 400_xowa/src/gplx/xowa/users/Xouv_user.java | 36 + .../xowa/users/bmks/Xoud_bmk_dir_row.java | 27 + .../xowa/users/bmks/Xoud_bmk_dir_tbl.java | 60 + .../xowa/users/bmks/Xoud_bmk_itm_row.java | 30 + .../xowa/users/bmks/Xoud_bmk_itm_tbl.java | 92 + .../gplx/xowa/users/bmks/Xoud_bmk_mgr.java | 34 + .../src/gplx/xowa/users/data/Xou_db_file.java | 46 + .../src/gplx/xowa/users/data/Xou_db_mgr.java | 50 + .../gplx/xowa/users/data/Xoud_cfg_mgr.java | 64 + .../xowa/users/data/Xoud_history_mgr.java | 57 + .../xowa/users/data/Xoud_history_row.java | 33 + .../xowa/users/data/Xoud_history_special.java | 59 + .../xowa/users/data/Xoud_history_tbl.java | 94 + .../src/gplx/xowa/users/data/Xoud_id_mgr.java | 30 + .../gplx/xowa/users/data/Xoud_opt_scope.java | 84 + .../xowa/users/data/Xoud_opt_scope_tst.java | 51 + .../gplx/xowa/users/data/Xoud_regy_row.java | 24 + .../gplx/xowa/users/data/Xoud_regy_tbl.java | 89 + .../gplx/xowa/users/data/Xoud_site_mgr.java | 45 + .../gplx/xowa/users/data/Xoud_site_row.java | 29 + .../gplx/xowa/users/data/Xoud_site_tbl.java | 82 + .../gplx/xowa/users/data/Xoud_user_tbl.java | 71 + .../xowa/users/history/Xou_history_cfg.java | 29 + .../xowa/users/history/Xou_history_html.java | 55 + .../xowa/users/history/Xou_history_itm.java | 72 + .../xowa/users/history/Xou_history_mgr.java | 143 ++ .../users/history/Xou_history_mgr_tst.java | 97 ++ .../users/history/Xou_history_sorter.java | 28 + .../xowa/users/prefs/Prefs_converter.java | 113 ++ .../xowa/users/prefs/Prefs_converter_tst.java | 62 + .../gplx/xowa/users/prefs/Prefs_html_wtr.java | 124 ++ .../src/gplx/xowa/users/prefs/Prefs_mgr.java | 155 ++ .../gplx/xowa/users/prefs/Prefs_mgr_tst.java | 184 ++ .../xowa/users/prefs/Prefs_rename_mgr.java | 47 + .../xowa/users/wikis/Xofs_url_itm_parser.java | 79 + .../users/wikis/Xofs_url_itm_parser_tst.java | 53 + .../gplx/xowa/users/wikis/Xou_wiki_mgr.java | 104 ++ .../utls/upgrades/Upgrader_v00_02_01.java | 56 + .../utls/upgrades/Upgrader_v00_02_01_tst.java | 71 + .../xowa/utls/upgrades/Xoa_upgrade_mgr.java | 47 + .../utls/upgrades/Xoa_upgrade_mgr_tst.java | 33 + .../src/gplx/xowa/wikis/Xoa_wiki_mgr.java | 22 + .../src/gplx/xowa/wikis/Xoa_wiki_regy.java | 46 + .../src/gplx/xowa/wikis/Xoae_wiki_mgr.java | 108 ++ .../src/gplx/xowa/wikis/Xow_cfg_consts.java | 29 + 400_xowa/src/gplx/xowa/wikis/Xow_domain.java | 50 + 400_xowa/src/gplx/xowa/wikis/Xow_domain_.java | 104 ++ .../src/gplx/xowa/wikis/Xow_domain_tst.java | 39 + .../src/gplx/xowa/wikis/Xow_domain_type.java | 31 + .../src/gplx/xowa/wikis/Xow_domain_type_.java | 131 ++ .../src/gplx/xowa/wikis/Xow_fsys_mgr.java | 66 + .../src/gplx/xowa/wikis/Xow_page_mgr.java | 25 + .../src/gplx/xowa/wikis/Xow_page_tid.java | 41 + .../src/gplx/xowa/wikis/Xow_wiki_abrv.java | 30 + .../src/gplx/xowa/wikis/Xow_wiki_abrv_.java | 73 + .../gplx/xowa/wikis/Xow_wiki_abrv_tst.java | 52 + .../src/gplx/xowa/wikis/Xow_wiki_alias.java | 244 +++ .../gplx/xowa/wikis/Xow_wiki_alias_tst.java | 97 ++ .../gplx/xowa/wikis/caches/Xow_cache_mgr.java | 64 + .../xowa/wikis/caches/Xow_defn_cache.java | 37 + .../xowa/wikis/caches/Xow_page_cache.java | 40 + .../xowa/wikis/caches/Xow_page_cache_itm.java | 27 + .../xowa/wikis/data/Xow_page_fetcher.java | 24 + .../wikis/data/Xow_page_fetcher_test.java | 32 + .../wikis/data/Xow_page_fetcher_wiki.java | 27 + .../xowa/wikis/data/Xowd_core_db_props.java | 70 + .../gplx/xowa/wikis/data/Xowd_db_file.java | 94 + .../gplx/xowa/wikis/data/Xowd_db_file_.java | 55 + .../xowa/wikis/data/Xowd_db_file_hash.java | 44 + .../wikis/data/Xowd_db_file_schema_props.java | 38 + .../gplx/xowa/wikis/data/Xowd_db_layout.java | 46 + .../src/gplx/xowa/wikis/data/Xowd_db_mgr.java | 147 ++ .../wikis/data/tbls/Xowd_cat_core_tbl.java | 79 + .../data/tbls/Xowd_cat_core_tbl__in_wkr.java | 45 + .../wikis/data/tbls/Xowd_cat_link_tbl.java | 89 + .../wikis/data/tbls/Xowd_category_itm.java | 44 + .../wikis/data/tbls/Xowd_css_core_itm.java | 26 + .../wikis/data/tbls/Xowd_css_core_tbl.java | 73 + .../wikis/data/tbls/Xowd_css_file_itm.java | 24 + .../wikis/data/tbls/Xowd_css_file_tbl.java | 63 + .../xowa/wikis/data/tbls/Xowd_html_row.java | 29 + .../xowa/wikis/data/tbls/Xowd_html_tbl.java | 71 + .../xowa/wikis/data/tbls/Xowd_page_itm.java | 126 ++ .../wikis/data/tbls/Xowd_page_itm_sorter.java | 53 + .../wikis/data/tbls/Xowd_page_itm_tst.java | 42 + .../xowa/wikis/data/tbls/Xowd_page_tbl.java | 323 ++++ .../data/tbls/Xowd_page_tbl__in_wkrs.java | 116 ++ .../wikis/data/tbls/Xowd_page_tbl_tst.java | 35 + .../wikis/data/tbls/Xowd_search_link_tbl.java | 75 + .../wikis/data/tbls/Xowd_search_temp_tbl.java | 93 + .../wikis/data/tbls/Xowd_search_word_row.java | 25 + .../wikis/data/tbls/Xowd_search_word_tbl.java | 129 ++ .../wikis/data/tbls/Xowd_site_ns_tbl.java | 83 + .../wikis/data/tbls/Xowd_site_stats_tbl.java | 52 + .../xowa/wikis/data/tbls/Xowd_text_tbl.java | 59 + .../wikis/data/tbls/Xowd_wbase_pid_tbl.java | 58 + .../wikis/data/tbls/Xowd_wbase_qid_tbl.java | 59 + .../data/tbls/Xowd_wbase_qid_tbl_tst.java | 47 + .../wikis/data/tbls/Xowd_xowa_db_tbl.java | 89 + .../wikis/domains/Xow_domain_abrv_xo_.java | 51 + .../domains/Xow_domain_abrv_xo__tst.java | 42 + .../xowa/wikis/domains/Xow_domain_uid_.java | 105 ++ .../wikis/domains/Xow_domain_uid__tst.java | 37 + .../domains/crts/Xow_domain_crt_itm.java | 22 + .../domains/crts/Xow_domain_crt_itm_.java | 84 + .../crts/Xow_domain_crt_itm_parser.java | 91 + .../crts/Xow_domain_crt_kv_itm_mgr.java | 67 + .../xowa/wikis/modules/Xow_module_base.java | 30 + .../xowa/wikis/modules/Xow_module_mgr.java | 40 + .../xowa/wikis/ttls/Xow_ttl__anchor_tst.java | 42 + .../xowa/wikis/ttls/Xow_ttl__basic_tst.java | 61 + .../xowa/wikis/ttls/Xow_ttl__err_tst.java | 39 + .../wikis/ttls/Xow_ttl__html_entity_tst.java | 28 + .../xowa/wikis/ttls/Xow_ttl__i18n_tst.java | 43 + .../xowa/wikis/ttls/Xow_ttl__qarg_tst.java | 31 + .../gplx/xowa/wikis/ttls/Xow_ttl__ws_tst.java | 29 + .../xowa/wikis/ttls/Xow_ttl__xwik_tst.java | 42 + .../src/gplx/xowa/wikis/ttls/Xow_ttl_fxt.java | 86 + .../gplx/xowa/wikis/ttls/Xow_ttl_parser.java | 23 + .../gplx/xowa/wikis/xwikis/Xow_lang_grp.java | 85 + .../gplx/xowa/wikis/xwikis/Xow_lang_itm.java | 38 + .../gplx/xowa/wikis/xwikis/Xow_lang_mgr.java | 193 +++ .../xowa/wikis/xwikis/Xow_lang_mgr_fxt.java | 65 + .../xowa/wikis/xwikis/Xow_lang_mgr_tst.java | 93 + .../gplx/xowa/wikis/xwikis/Xow_xwiki_itm.java | 57 + .../xowa/wikis/xwikis/Xow_xwiki_itm_tst.java | 44 + .../gplx/xowa/wikis/xwikis/Xow_xwiki_mgr.java | 215 +++ .../xowa/wikis/xwikis/Xow_xwiki_mgr_srl.java | 40 + .../xowa/wikis/xwikis/Xow_xwiki_mgr_tst.java | 140 ++ 400_xowa/src/gplx/xowa/wmfs/Xoa_wmf_mgr.java | 40 + .../src/gplx/xowa/wmfs/Xow_wmf_api_mgr.java | 892 ++++++++++ .../src/gplx/xowa/wmfs/Xow_wmf_api_wkr.java | 26 + .../gplx/xowa/wmfs/Xow_wmf_api_wkr__ns.java | 78 + 400_xowa/src/gplx/xowa/wmfs/Xowmf_mgr.java | 29 + .../gplx/xowa/wmfs/apis/Xoapi_orig_base.java | 34 + .../xowa/wmfs/apis/Xoapi_orig_base_tst.java | 61 + .../gplx/xowa/wmfs/apis/Xoapi_orig_mok.java | 36 + .../gplx/xowa/wmfs/apis/Xoapi_orig_rslts.java | 31 + .../gplx/xowa/wmfs/apis/Xoapi_orig_wmf.java | 95 + .../gplx/xowa/wmfs/apis/Xowmf_api_mgr.java | 21 + .../xowa/wmfs/data/Xowmf_extensions_tbl.java | 69 + .../xowa/wmfs/data/Xowmf_general_tbl.java | 233 +++ .../wmfs/data/Xowmf_interwikimap_tbl.java | 53 + .../gplx/xowa/wmfs/data/Xowmf_json_tbl.java | 51 + .../src/gplx/xowa/wmfs/data/Xowmf_ns_tbl.java | 64 + .../gplx/xowa/wmfs/data/Xowmf_site_tbl.java | 60 + .../data/Xowmf_specialpagealiases_tbl.java | 45 + .../xowa/wmfs/data/Xowmf_statistics_tbl.java | 57 + .../Xowmf_wiki_dump_dirs_parser.java | 35 + .../Xowmf_wiki_dump_dirs_parser_tst.java | 67 + 400_xowa/src/gplx/xowa/xtns/Xow_xtn_mgr.java | 113 ++ 400_xowa/src/gplx/xowa/xtns/Xox_mgr.java | 26 + 400_xowa/src/gplx/xowa/xtns/Xox_mgr_base.java | 68 + 400_xowa/src/gplx/xowa/xtns/Xox_xnde.java | 23 + .../Xtn_categoryList_nde_tst.java | 24 + .../categoryList/Xtn_categorylist_nde.java | 24 + .../src/gplx/xowa/xtns/cite/Cite_xtn_mgr.java | 31 + .../src/gplx/xowa/xtns/cite/Ref_html_wtr.java | 149 ++ .../gplx/xowa/xtns/cite/Ref_html_wtr_cfg.java | 121 ++ .../src/gplx/xowa/xtns/cite/Ref_itm_grp.java | 50 + .../src/gplx/xowa/xtns/cite/Ref_itm_lst.java | 63 + .../src/gplx/xowa/xtns/cite/Ref_itm_mgr.java | 53 + .../xowa/xtns/cite/Ref_itm_mgr_cfg_tst.java | 35 + .../gplx/xowa/xtns/cite/Ref_itm_mgr_tst.java | 83 + 400_xowa/src/gplx/xowa/xtns/cite/Ref_nde.java | 81 + .../gplx/xowa/xtns/cite/References_nde.java | 58 + .../xtns/cite/References_nde_basic_tst.java | 202 +++ .../xtns/cite/References_nde_group_tst.java | 122 ++ .../xtns/cite/References_nde_pre_tst.java | 67 + .../xtns/cite/References_nde_rare_tst.java | 94 + .../xtns/dynamicPageList/Dpl_html_data.java | 55 + .../xowa/xtns/dynamicPageList/Dpl_itm.java | 183 ++ .../xtns/dynamicPageList/Dpl_itm_keys.java | 125 ++ .../xowa/xtns/dynamicPageList/Dpl_page.java | 35 + .../xtns/dynamicPageList/Dpl_redirect.java | 30 + .../xowa/xtns/dynamicPageList/Dpl_sort.java | 43 + .../xowa/xtns/dynamicPageList/Dpl_xnde.java | 158 ++ .../xtns/dynamicPageList/Dpl_xnde_tst.java | 243 +++ .../Pages_using_pending_changes_func.java | 27 + .../Pages_using_pending_changes_func_tst.java | 25 + .../Pending_change_level_func.java | 25 + .../Pending_change_level_func_tst.java | 25 + .../xtns/gallery/Gallery_box_w_fmtr_arg.java | 63 + .../xowa/xtns/gallery/Gallery_html_wtr.java | 173 ++ .../xtns/gallery/Gallery_html_wtr_utl.java | 27 + .../gplx/xowa/xtns/gallery/Gallery_itm.java | 62 + .../xowa/xtns/gallery/Gallery_itm_parser.java | 251 +++ .../xtns/gallery/Gallery_itm_parser_tst.java | 112 ++ .../xowa/xtns/gallery/Gallery_mgr_base.java | 226 +++ .../xowa/xtns/gallery/Gallery_mgr_base_.java | 64 + .../gallery/Gallery_mgr_base_basic_tst.java | 170 ++ .../Gallery_mgr_base_xnde_atrs_tst.java | 66 + .../xtns/gallery/Gallery_mgr_packed_base.java | 84 + .../gplx/xowa/xtns/gallery/Gallery_xnde.java | 129 ++ .../xowa/xtns/gallery/Gallery_xnde_tst.java | 182 ++ .../xowa/xtns/gallery/Gallery_xtn_mgr.java | 30 + .../xowa/xtns/geoCrumbs/Geoc_isin_func.java | 33 + .../xtns/geoCrumbs/Geoc_isin_func_tst.java | 35 + .../xowa/xtns/geoCrumbs/Geoc_isin_mgr.java | 33 + .../xtns/geodata/Geo_coordinates_func.java | 25 + .../geodata/Geo_coordinates_func_tst.java | 24 + .../gplx/xowa/xtns/hieros/Hiero_file_mgr.java | 66 + .../gplx/xowa/xtns/hieros/Hiero_html_mgr.java | 239 +++ .../xowa/xtns/hieros/Hiero_html_mgr_fxt.java | 56 + .../xowa/xtns/hieros/Hiero_html_mgr_tst.java | 389 +++++ .../gplx/xowa/xtns/hieros/Hiero_html_wtr.java | 172 ++ .../xtns/hieros/Hiero_mw_tables_parser.java | 118 ++ .../hieros/Hiero_mw_tables_parser_tst.java | 75 + .../gplx/xowa/xtns/hieros/Hiero_parser.java | 132 ++ .../xowa/xtns/hieros/Hiero_parser_tst.java | 59 + .../xowa/xtns/hieros/Hiero_phoneme_mgr.java | 59 + .../xowa/xtns/hieros/Hiero_prefab_mgr.java | 53 + .../src/gplx/xowa/xtns/hieros/Hiero_xnde.java | 44 + .../gplx/xowa/xtns/hieros/Hiero_xtn_mgr.java | 57 + .../gplx/xowa/xtns/imaps/Imap_desc_tid.java | 71 + .../gplx/xowa/xtns/imaps/Imap_html_fmtrs.java | 65 + .../xowa/xtns/imaps/Imap_img_fmtr_arg.java | 52 + .../src/gplx/xowa/xtns/imaps/Imap_itm.java | 59 + .../gplx/xowa/xtns/imaps/Imap_itm_shape.java | 67 + .../src/gplx/xowa/xtns/imaps/Imap_map.java | 73 + .../gplx/xowa/xtns/imaps/Imap_map_fmtr.java | 50 + .../src/gplx/xowa/xtns/imaps/Imap_parser.java | 234 +++ .../gplx/xowa/xtns/imaps/Imap_parser_tst.java | 101 ++ .../xowa/xtns/imaps/Imap_pts_fmtr_arg.java | 34 + .../src/gplx/xowa/xtns/imaps/Imap_xnde.java | 38 + .../xtns/imaps/Imap_xnde_html_all_tst.java | 228 +++ .../xtns/imaps/Imap_xnde_html_itm_tst.java | 33 + .../gplx/xowa/xtns/imaps/Imap_xtn_mgr.java | 48 + .../xtns/indicators/Indicator_html_bldr.java | 62 + .../indicators/Indicator_html_bldr_tst.java | 66 + .../xowa/xtns/indicators/Indicator_xnde.java | 42 + .../xtns/indicators/Indicator_xnde_tst.java | 25 + .../xtns/indicators/Indicator_xtn_mgr.java | 26 + .../xowa/xtns/inputBox/Xtn_inputbox_nde.java | 23 + .../xtns/inputBox/Xtn_inputbox_nde_tst.java | 25 + .../gplx/xowa/xtns/insiders/Insider_func.java | 34 + .../xowa/xtns/insiders/Insider_func_tst.java | 38 + .../xowa/xtns/insiders/Insider_html_bldr.java | 74 + .../xtns/insiders/Insider_html_bldr_tst.java | 62 + .../xowa/xtns/insiders/Insider_xtn_mgr.java | 40 + .../gplx/xowa/xtns/listings/Listing_xnde.java | 265 +++ .../xtns/listings/Listing_xnde_basic_tst.java | 108 ++ .../listings/Listing_xnde_template_tst.java | 143 ++ .../xowa/xtns/listings/Listing_xtn_mgr.java | 80 + .../src/gplx/xowa/xtns/lst/Lst_pfunc_lst.java | 31 + .../gplx/xowa/xtns/lst/Lst_pfunc_lst_tst.java | 101 ++ .../gplx/xowa/xtns/lst/Lst_pfunc_lstx.java | 31 + .../xowa/xtns/lst/Lst_pfunc_lstx_tst.java | 35 + .../src/gplx/xowa/xtns/lst/Lst_pfunc_wkr.java | 139 ++ .../gplx/xowa/xtns/lst/Lst_section_nde.java | 57 + .../xowa/xtns/lst/Lst_section_nde_mgr.java | 24 + .../xowa/xtns/lst/Lst_section_nde_tst.java | 31 + .../xowa/xtns/mapSources/Map_dd2dms_func.java | 65 + .../xtns/mapSources/Map_dd2dms_func_tst.java | 25 + .../xowa/xtns/mapSources/Map_deg2dd_func.java | 34 + .../xtns/mapSources/Map_deg2dd_func_tst.java | 26 + .../xtns/mapSources/Map_geolink_func.java | 102 ++ .../xtns/mapSources/Map_geolink_func_tst.java | 35 + .../gplx/xowa/xtns/mapSources/Map_math.java | 318 ++++ .../xtns/massMessage/Message_target_func.java | 28 + .../massMessage/Message_target_func_tst.java | 25 + .../src/gplx/xowa/xtns/math/Math_nde.java | 31 + .../xowa/xtns/math/Xof_math_html_wtr.java | 84 + .../src/gplx/xowa/xtns/math/Xof_math_itm.java | 28 + .../src/gplx/xowa/xtns/math/Xof_math_mgr.java | 106 ++ .../xowa/xtns/math/Xof_math_mgr_html_tst.java | 36 + .../gplx/xowa/xtns/math/Xof_math_mgr_tst.java | 27 + .../xowa/xtns/math/Xof_math_subst_regy.java | 176 ++ .../src/gplx/xowa/xtns/pfuncs/Pf_func.java | 24 + .../src/gplx/xowa/xtns/pfuncs/Pf_func_.java | 423 +++++ .../gplx/xowa/xtns/pfuncs/Pf_func_base.java | 71 + .../xowa/xtns/pfuncs/exprs/Pfunc_expr.java | 44 + .../xtns/pfuncs/exprs/Pfunc_expr_ops.java | 545 ++++++ .../xtns/pfuncs/exprs/Pfunc_expr_shunter.java | 220 +++ .../xtns/pfuncs/exprs/Pfunc_expr_tst.java | 116 ++ .../gplx/xowa/xtns/pfuncs/ifs/Pfunc_if.java | 37 + .../xowa/xtns/pfuncs/ifs/Pfunc_if_tst.java | 45 + .../gplx/xowa/xtns/pfuncs/ifs/Pfunc_ifeq.java | 32 + .../xowa/xtns/pfuncs/ifs/Pfunc_ifeq_tst.java | 48 + .../xowa/xtns/pfuncs/ifs/Pfunc_iferror.java | 123 ++ .../xtns/pfuncs/ifs/Pfunc_iferror_tst.java | 30 + .../xowa/xtns/pfuncs/ifs/Pfunc_ifexist.java | 35 + .../xtns/pfuncs/ifs/Pfunc_ifexist_mgr.java | 78 + .../xtns/pfuncs/ifs/Pfunc_ifexist_tst.java | 50 + .../xowa/xtns/pfuncs/ifs/Pfunc_ifexpr.java | 42 + .../xtns/pfuncs/ifs/Pfunc_ifexpr_tst.java | 31 + .../xowa/xtns/pfuncs/ifs/Pfunc_switch.java | 89 + .../xtns/pfuncs/ifs/Pfunc_switch_tst.java | 91 + .../xowa/xtns/pfuncs/ifs/Xop_xowa_dbg.java | 28 + .../xowa/xtns/pfuncs/langs/Pfunc_gender.java | 59 + .../xtns/pfuncs/langs/Pfunc_gender_tst.java | 31 + .../xowa/xtns/pfuncs/langs/Pfunc_grammar.java | 32 + .../xtns/pfuncs/langs/Pfunc_grammar_tst.java | 57 + .../xtns/pfuncs/langs/Pfunc_i18n_tst.java | 56 + .../xowa/xtns/pfuncs/langs/Pfunc_int.java | 38 + .../xowa/xtns/pfuncs/langs/Pfunc_int_tst.java | 116 ++ .../xtns/pfuncs/langs/Pfunc_language.java | 35 + .../xtns/pfuncs/langs/Pfunc_language_tst.java | 30 + .../xowa/xtns/pfuncs/langs/Pfunc_plural.java | 31 + .../xtns/pfuncs/langs/Pfunc_plural_tst.java | 27 + .../xtns/pfuncs/numbers/Pf_formatnum.java | 43 + .../pfuncs/numbers/Pf_formatnum_de_tst.java | 38 + .../pfuncs/numbers/Pf_formatnum_en_tst.java | 47 + .../pfuncs/numbers/Pf_formatnum_es_tst.java | 38 + .../pfuncs/numbers/Pf_formatnum_fa_tst.java | 53 + .../xtns/pfuncs/pages/Pfunc_defaultsort.java | 24 + .../xtns/pfuncs/pages/Pfunc_displaytitle.java | 51 + .../pfuncs/pages/Pfunc_displaytitle_tst.java | 49 + .../xtns/pfuncs/pages/Pfunc_misc_tst.java | 24 + .../pfuncs/pages/Pfunc_noeditsection.java | 24 + .../xtns/pfuncs/pages/Pfunc_rev_props.java | 51 + .../pfuncs/pages/Pfunc_rev_props_tst.java | 33 + .../pfuncs/scribunto/Pfunc_scrib_lib.java | 52 + .../pfuncs/scribunto/Pfunc_scrib_lib_tst.java | 31 + .../xtns/pfuncs/scribunto/Pfunc_xtn_mgr.java | 27 + .../xowa/xtns/pfuncs/strings/Pfunc_case.java | 39 + .../xtns/pfuncs/strings/Pfunc_case_tst.java | 40 + .../xowa/xtns/pfuncs/strings/Pfunc_pad.java | 61 + .../xtns/pfuncs/strings/Pfunc_pad_tst.java | 34 + .../xowa/xtns/pfuncs/strings/Pfunc_tag.java | 128 ++ .../xtns/pfuncs/strings/Pfunc_tag_tst.java | 40 + .../xtns/pfuncs/stringutils/Pfunc_count.java | 41 + .../pfuncs/stringutils/Pfunc_count_tst.java | 25 + .../pfuncs/stringutils/Pfunc_explode.java | 59 + .../pfuncs/stringutils/Pfunc_explode_tst.java | 28 + .../xtns/pfuncs/stringutils/Pfunc_len.java | 28 + .../pfuncs/stringutils/Pfunc_len_tst.java | 26 + .../xtns/pfuncs/stringutils/Pfunc_pos.java | 33 + .../pfuncs/stringutils/Pfunc_pos_tst.java | 26 + .../pfuncs/stringutils/Pfunc_replace.java | 36 + .../pfuncs/stringutils/Pfunc_replace_tst.java | 27 + .../xtns/pfuncs/stringutils/Pfunc_rpos.java | 33 + .../pfuncs/stringutils/Pfunc_rpos_tst.java | 26 + .../xtns/pfuncs/stringutils/Pfunc_sub.java | 43 + .../pfuncs/stringutils/Pfunc_sub_tst.java | 29 + .../pfuncs/stringutils/Pfunc_urldecode.java | 28 + .../stringutils/Pfunc_urldecode_tst.java | 23 + .../xowa/xtns/pfuncs/times/Pft_fmt_itm.java | 22 + .../xowa/xtns/pfuncs/times/Pft_fmt_itm_.java | 189 ++ .../pfuncs/times/Pft_fmt_itm_foreign.java | 334 ++++ .../pfuncs/times/Pft_fmt_itm_seg_int.java | 130 ++ .../xtns/pfuncs/times/Pft_func_date_int.java | 92 + .../pfuncs/times/Pft_func_date_lcl_tst.java | 37 + .../xtns/pfuncs/times/Pft_func_date_name.java | 35 + .../pfuncs/times/Pft_func_date_rev_tst.java | 30 + .../pfuncs/times/Pft_func_date_utc_tst.java | 38 + .../pfuncs/times/Pft_func_formatdate.java | 49 + .../times/Pft_func_formatdate_bldr.java | 53 + .../pfuncs/times/Pft_func_formatdate_tst.java | 38 + .../xowa/xtns/pfuncs/times/Pft_func_time.java | 95 + .../pfuncs/times/Pft_func_time_basic_tst.java | 101 ++ .../times/Pft_func_time_foreign_tst.java | 77 + .../pfuncs/times/Pft_func_time_int_tst.java | 24 + .../times/Pft_func_time_uncommon_tst.java | 25 + .../xowa/xtns/pfuncs/times/Pxd_eval_seg.java | 209 +++ .../gplx/xowa/xtns/pfuncs/times/Pxd_itm_.java | 122 ++ .../xowa/xtns/pfuncs/times/Pxd_itm_int.java | 299 ++++ .../xowa/xtns/pfuncs/times/Pxd_itm_misc.java | 134 ++ .../xtns/pfuncs/times/Pxd_itm_month_name.java | 364 ++++ .../xowa/xtns/pfuncs/times/Pxd_parser.java | 262 +++ .../xtns/pfuncs/times/Pxd_parser_tst.java | 95 + .../xtns/pfuncs/ttls/Pfunc_anchorencode.java | 104 ++ .../pfuncs/ttls/Pfunc_anchorencode_tst.java | 35 + .../xowa/xtns/pfuncs/ttls/Pfunc_filepath.java | 58 + .../xtns/pfuncs/ttls/Pfunc_filepath_tst.java | 67 + .../gplx/xowa/xtns/pfuncs/ttls/Pfunc_ns.java | 57 + .../xowa/xtns/pfuncs/ttls/Pfunc_ns_tst.java | 37 + .../xowa/xtns/pfuncs/ttls/Pfunc_rel2abs.java | 183 ++ .../xtns/pfuncs/ttls/Pfunc_rel2abs_tst.java | 68 + .../xtns/pfuncs/ttls/Pfunc_titleparts.java | 80 + .../pfuncs/ttls/Pfunc_titleparts_tst.java | 81 + .../gplx/xowa/xtns/pfuncs/ttls/Pfunc_ttl.java | 51 + .../xowa/xtns/pfuncs/ttls/Pfunc_ttl_tst.java | 49 + .../xtns/pfuncs/ttls/Pfunc_urlencode.java | 29 + .../xtns/pfuncs/ttls/Pfunc_urlencode_tst.java | 30 + .../xowa/xtns/pfuncs/ttls/Pfunc_urlfunc.java | 65 + .../xtns/pfuncs/ttls/Pfunc_urlfunc_tst.java | 42 + .../pfuncs/wikis/Pfunc_pagesincategory.java | 45 + .../xtns/pfuncs/wikis/Pfunc_wiki_props.java | 39 + .../pfuncs/wikis/Pfunc_wiki_props_tst.java | 39 + .../xtns/pfuncs/wikis/Pfunc_wiki_stats.java | 49 + .../pfuncs/wikis/Pfunc_wiki_stats_tst.java | 32 + .../src/gplx/xowa/xtns/poems/Poem_nde.java | 85 + .../gplx/xowa/xtns/poems/Poem_nde_tst.java | 285 +++ .../gplx/xowa/xtns/poems/Poem_xtn_mgr.java | 28 + .../xtns/proofreadPage/Pp_index_parser.java | 120 ++ .../xtns/proofreadPage/Pp_pagelist_nde.java | 27 + .../proofreadPage/Pp_pagelist_nde_tst.java | 25 + .../proofreadPage/Pp_pagequality_nde.java | 23 + .../proofreadPage/Pp_pagequality_nde_tst.java | 25 + .../xowa/xtns/proofreadPage/Pp_pages_nde.java | 442 +++++ .../proofreadPage/Pp_pages_nde_basic_tst.java | 128 ++ .../proofreadPage/Pp_pages_nde_hdr_tst.java | 157 ++ .../proofreadPage/Pp_pages_nde_index_tst.java | 236 +++ .../Pp_pages_nde_recursion_tst.java | 42 + .../xowa/xtns/proofreadPage/Pp_xtn_mgr.java | 28 + .../src/gplx/xowa/xtns/quiz/Quiz_xnde.java | 26 + .../gplx/xowa/xtns/quiz/Quiz_xnde_tst.java | 25 + .../xtns/relatedArticles/Articles_func.java | 87 + .../relatedArticles/Articles_func_tst.java | 50 + .../xtns/relatedSites/Sites_html_bldr.java | 77 + .../relatedSites/Sites_html_bldr_tst.java | 69 + .../xtns/relatedSites/Sites_regy_itm.java | 28 + .../xtns/relatedSites/Sites_regy_mgr.java | 52 + .../xowa/xtns/relatedSites/Sites_xtn_mgr.java | 44 + 400_xowa/src/gplx/xowa/xtns/rss/Rss_xnde.java | 26 + .../src/gplx/xowa/xtns/rss/Rss_xnde_tst.java | 27 + .../src/gplx/xowa/xtns/scores/Score_xnde.java | 203 +++ .../gplx/xowa/xtns/scores/Score_xnde_tst.java | 25 + .../gplx/xowa/xtns/scores/Score_xtn_mgr.java | 69 + .../gplx/xowa/xtns/scribunto/Scrib_core.java | 222 +++ .../xowa/xtns/scribunto/Scrib_core_fxt.java | 147 ++ .../xowa/xtns/scribunto/Scrib_core_tst.java | 117 ++ .../xtns/scribunto/Scrib_err_filter_mgr.java | 94 + .../scribunto/Scrib_err_filter_mgr_tst.java | 50 + .../xowa/xtns/scribunto/Scrib_frame_.java | 43 + .../xowa/xtns/scribunto/Scrib_fsys_mgr.java | 62 + .../xtns/scribunto/Scrib_fsys_mgr_tst.java | 62 + .../xtns/scribunto/Scrib_invoke_func.java | 81 + .../xtns/scribunto/Scrib_invoke_func_fxt.java | 207 +++ .../xowa/xtns/scribunto/Scrib_kv_utl_.java | 64 + .../gplx/xowa/xtns/scribunto/Scrib_lib.java | 24 + .../xowa/xtns/scribunto/Scrib_lib_mgr.java | 31 + .../xowa/xtns/scribunto/Scrib_lua_mod.java | 62 + .../xowa/xtns/scribunto/Scrib_lua_proc.java | 27 + .../gplx/xowa/xtns/scribunto/Scrib_proc.java | 32 + .../xowa/xtns/scribunto/Scrib_proc_args.java | 146 ++ .../xowa/xtns/scribunto/Scrib_proc_mgr.java | 42 + .../xowa/xtns/scribunto/Scrib_proc_rslt.java | 62 + .../xowa/xtns/scribunto/Scrib_xtn_mgr.java | 80 + .../xtns/scribunto/engines/Scrib_engine.java | 27 + .../scribunto/engines/Scrib_engine_type.java | 34 + .../xtns/scribunto/engines/Scrib_server.java | 28 + .../scribunto/engines/luaj/Luaj_engine.java | 122 ++ .../scribunto/engines/luaj/Luaj_server.java | 83 + .../engines/luaj/Luaj_server_func_dbg.java | 40 + .../engines/luaj/Luaj_server_func_recv.java | 32 + .../scribunto/engines/luaj/Luaj_value.java | 117 ++ .../engines/process/Process_engine.java | 108 ++ .../engines/process/Process_recv_msg.java | 59 + .../engines/process/Process_send_wtr.java | 98 ++ .../engines/process/Process_send_wtr_tst.java | 42 + .../engines/process/Process_server.java | 127 ++ .../engines/process/Process_server_mock.java | 94 + .../engines/process/Process_stream_rdr.java | 88 + .../process/Process_stream_rdr_tst.java | 79 + .../xtns/scribunto/errs/Gfo_comp_op_1.java | 130 ++ .../xtns/scribunto/errs/Gfo_fld_owner.java | 68 + .../xowa/xtns/scribunto/errs/Gfo_val.java | 31 + .../xtns/scribunto/errs/Scrib_err_mgr.java | 89 + .../xtns/scribunto/libs/Scrib_lib_html.java | 32 + .../scribunto/libs/Scrib_lib_language.java | 245 +++ .../libs/Scrib_lib_language_tst.java | 156 ++ .../scribunto/libs/Scrib_lib_message.java | 179 ++ .../scribunto/libs/Scrib_lib_message_tst.java | 76 + .../xtns/scribunto/libs/Scrib_lib_mw.java | 390 +++++ .../libs/Scrib_lib_mw__invoke_tst.java | 126 ++ .../scribunto/libs/Scrib_lib_mw__lib_tst.java | 89 + .../xtns/scribunto/libs/Scrib_lib_site.java | 181 ++ .../scribunto/libs/Scrib_lib_site_tst.java | 159 ++ .../xtns/scribunto/libs/Scrib_lib_text.java | 112 ++ .../libs/Scrib_lib_text_html_entities.java | 1539 +++++++++++++++++ .../scribunto/libs/Scrib_lib_text_tst.java | 32 + .../xtns/scribunto/libs/Scrib_lib_title.java | 230 +++ .../scribunto/libs/Scrib_lib_title_tst.java | 168 ++ .../xtns/scribunto/libs/Scrib_lib_uri.java | 76 + .../scribunto/libs/Scrib_lib_uri_tst.java | 43 + .../scribunto/libs/Scrib_lib_ustring.java | 323 ++++ .../libs/Scrib_lib_ustring__invoke_tst.java | 71 + .../libs/Scrib_lib_ustring__lib_tst.java | 134 ++ .../scribunto/libs/Scrib_lib_wikibase.java | 64 + .../libs/Scrib_lib_wikibase_entity.java | 57 + .../libs/Scrib_lib_wikibase_entity_tst.java | 38 + .../libs/Scrib_lib_wikibase_srl.java | 164 ++ .../libs/Scrib_lib_wikibase_srl_tst.java | 417 +++++ .../libs/Scrib_lib_wikibase_srl_visitor.java | 94 + .../libs/Scrib_lib_wikibase_tst.java | 63 + .../scribunto/libs/Scrib_regx_converter.java | 264 +++ .../libs/Scrib_regx_converter_tst.java | 67 + .../xtns/syntaxHighlight/Int_rng_mgr.java | 87 + .../xtns/syntaxHighlight/Int_rng_mgr_tst.java | 44 + .../Xtn_syntaxHighlight_nde.java | 100 ++ .../Xtn_syntaxHighlight_nde_tst.java | 174 ++ .../templateData/Xtn_templateData_nde.java | 31 + .../Xtn_templateData_nde_tst.java | 25 + .../titleBlacklists/Blacklist_scrib_lib.java | 41 + .../Blacklist_scrib_lib_tst.java | 29 + .../titleBlacklists/Blacklist_xtn_mgr.java | 27 + .../xtns/translates/Xop_languages_xnde.java | 129 ++ .../translates/Xop_languages_xnde_tst.java | 74 + .../xtns/translates/Xop_mylanguage_page.java | 34 + .../translates/Xop_mylanguage_page_tst.java | 58 + .../xtns/translates/Xop_translate_xnde.java | 32 + .../translates/Xop_translate_xnde_tst.java | 28 + .../xowa/xtns/translates/Xop_tvar_lxr.java | 37 + .../xtns/translates/Xop_tvar_lxr_tst.java | 32 + .../xowa/xtns/translates/Xop_tvar_tkn.java | 32 + .../src/gplx/xowa/xtns/wdatas/Wdata_doc.java | 46 + .../gplx/xowa/xtns/wdatas/Wdata_doc_bldr.java | 47 + .../gplx/xowa/xtns/wdatas/Wdata_doc_wtr.java | 171 ++ .../xtns/wdatas/Wdata_prop_val_visitor.java | 52 + .../gplx/xowa/xtns/wdatas/Wdata_wiki_mgr.java | 230 +++ .../xowa/xtns/wdatas/Wdata_wiki_mgr_fxt.java | 185 ++ .../xowa/xtns/wdatas/Wdata_wiki_mgr_tst.java | 62 + .../gplx/xowa/xtns/wdatas/Wdata_xtn_mgr.java | 38 + .../xtns/wdatas/Wdata_xwiki_link_wtr.java | 80 + .../xtns/wdatas/Wdata_xwiki_link_wtr_tst.java | 139 ++ .../xtns/wdatas/core/Wdata_alias_itm.java | 29 + .../xtns/wdatas/core/Wdata_claim_grp.java | 38 + .../wdatas/core/Wdata_claim_grp_list.java | 24 + .../wdatas/core/Wdata_claim_itm_base.java | 35 + .../wdatas/core/Wdata_claim_itm_core.java | 26 + .../wdatas/core/Wdata_claim_itm_entity.java | 49 + .../core/Wdata_claim_itm_globecoordinate.java | 41 + .../core/Wdata_claim_itm_monolingualtext.java | 31 + .../wdatas/core/Wdata_claim_itm_quantity.java | 46 + .../xtns/wdatas/core/Wdata_claim_itm_str.java | 30 + .../wdatas/core/Wdata_claim_itm_system.java | 31 + .../wdatas/core/Wdata_claim_itm_time.java | 71 + .../xtns/wdatas/core/Wdata_claim_visitor.java | 27 + .../xowa/xtns/wdatas/core/Wdata_date.java | 188 ++ .../xowa/xtns/wdatas/core/Wdata_date_tst.java | 91 + .../xtns/wdatas/core/Wdata_dict_claim.java | 56 + .../xtns/wdatas/core/Wdata_dict_claim_v1.java | 34 + .../wdatas/core/Wdata_dict_datavalue.java | 40 + .../xtns/wdatas/core/Wdata_dict_langtext.java | 36 + .../xtns/wdatas/core/Wdata_dict_mainsnak.java | 44 + .../xtns/wdatas/core/Wdata_dict_rank.java | 54 + .../wdatas/core/Wdata_dict_reference.java | 56 + .../xtns/wdatas/core/Wdata_dict_sitelink.java | 40 + .../xtns/wdatas/core/Wdata_dict_snak_tid.java | 61 + .../xowa/xtns/wdatas/core/Wdata_dict_utl.java | 30 + .../xtns/wdatas/core/Wdata_dict_val_tid.java | 79 + .../wdatas/core/Wdata_dict_value_entity.java | 36 + .../core/Wdata_dict_value_entity_tid.java | 55 + .../Wdata_dict_value_globecoordinate.java | 54 + .../Wdata_dict_value_monolingualtext.java | 36 + .../core/Wdata_dict_value_quantity.java | 44 + .../wdatas/core/Wdata_dict_value_string.java | 32 + .../wdatas/core/Wdata_dict_value_time.java | 93 + .../xtns/wdatas/core/Wdata_lang_sortable.java | 22 + .../xtns/wdatas/core/Wdata_lang_sorter.java | 83 + .../xtns/wdatas/core/Wdata_langtext_itm.java | 42 + .../wdatas/core/Wdata_references_grp.java | 23 + .../xtns/wdatas/core/Wdata_sitelink_itm.java | 33 + .../xtns/wdatas/hwtrs/Wdata_fmtr__claim.java | 285 +++ .../xtns/wdatas/hwtrs/Wdata_fmtr__json.java | 48 + .../wdatas/hwtrs/Wdata_fmtr__langtext.java | 128 ++ .../xtns/wdatas/hwtrs/Wdata_fmtr__oview.java | 92 + .../xtns/wdatas/hwtrs/Wdata_fmtr__slink.java | 164 ++ .../xtns/wdatas/hwtrs/Wdata_fmtr__toc.java | 77 + .../xtns/wdatas/hwtrs/Wdata_hwtr_mgr.java | 93 + .../xtns/wdatas/hwtrs/Wdata_hwtr_mgr_tst.java | 324 ++++ .../xtns/wdatas/hwtrs/Wdata_hwtr_msgs.java | 227 +++ .../xowa/xtns/wdatas/hwtrs/Wdata_lbl_itm.java | 47 + .../xowa/xtns/wdatas/hwtrs/Wdata_lbl_mgr.java | 139 ++ .../xowa/xtns/wdatas/hwtrs/Wdata_lbl_wkr.java | 22 + .../xtns/wdatas/hwtrs/Wdata_lbl_wkr_wiki.java | 49 + .../xtns/wdatas/hwtrs/Wdata_slink_grp.java | 82 + .../wdatas/hwtrs/Wdata_visitor__html_wtr.java | 112 ++ .../hwtrs/Wdata_visitor__html_wtr_tst.java | 89 + .../hwtrs/Wdata_visitor__lbl_gatherer.java | 43 + .../wdatas/imports/Io_stream_rdr_mgr.java | 74 + .../wdatas/imports/Wdata_idx_mgr_base.java | 40 + .../xtns/wdatas/imports/Wdata_idx_wtr.java | 53 + .../xtns/wdatas/imports/Xob_site_ns_cmd.java | 37 + .../imports/Xob_wbase_json_dump_cmd.java | 37 + .../imports/Xob_wbase_json_dump_db.java | 95 + .../imports/Xob_wbase_json_dump_parser.java | 89 + .../wdatas/imports/Xob_wbase_ns_parser.java | 52 + .../xtns/wdatas/imports/Xob_wdata_db_cmd.java | 420 +++++ .../wdatas/imports/Xob_wdata_pid_base.java | 55 + .../imports/Xob_wdata_pid_base_tst.java | 74 + .../wdatas/imports/Xob_wdata_pid_sql.java | 36 + .../wdatas/imports/Xob_wdata_pid_txt.java | 48 + .../wdatas/imports/Xob_wdata_qid_base.java | 63 + .../imports/Xob_wdata_qid_base_tst.java | 177 ++ .../wdatas/imports/Xob_wdata_qid_sql.java | 42 + .../wdatas/imports/Xob_wdata_qid_txt.java | 47 + .../parsers/Wdata_claims_parser_v2.java | 247 +++ .../xtns/wdatas/parsers/Wdata_doc_parser.java | 30 + .../parsers/Wdata_doc_parser_fxt_base.java | 99 ++ .../wdatas/parsers/Wdata_doc_parser_v1.java | 265 +++ .../parsers/Wdata_doc_parser_v1_tst.java | 187 ++ .../wdatas/parsers/Wdata_doc_parser_v2.java | 147 ++ .../parsers/Wdata_doc_parser_v2_tst.java | 393 +++++ .../Wdata_external_lang_links_data.java | 53 + .../pfuncs/Wdata_pf_noExternalLangLinks.java | 32 + .../Wdata_pf_noExternalLangLinks_tst.java | 64 + .../xtns/wdatas/pfuncs/Wdata_pf_property.java | 66 + .../wdatas/pfuncs/Wdata_pf_property_data.java | 59 + .../wdatas/pfuncs/Wdata_pf_property_fmt.java | 51 + .../wdatas/pfuncs/Wdata_pf_property_tst.java | 149 ++ .../wdatas/pfuncs/Wdata_pf_wbreponame.java | 27 + .../pfuncs/Wdata_pf_wbreponame_tst.java | 36 + .../specials/Wdata_itemByTitle_cfg.java | 28 + .../specials/Wdata_itemByTitle_page.java | 84 + .../specials/Wdata_itemByTitle_page_tst.java | 77 + .../xowa/xtns/xowa_cmds/Xop_xowa_cmd.java | 43 + .../xowa/xtns/xowa_cmds/Xop_xowa_cmd_tst.java | 94 + .../xowa/xtns/xowa_cmds/Xop_xowa_func.java | 34 + .../xtns/xowa_cmds/Xop_xowa_func_tst.java | 31 + .../xtns/xowa_cmds/Xox_xowa_html_cmd.java | 65 + .../xtns/xowa_cmds/Xox_xowa_html_cmd_tst.java | 55 + 400_xowa/src/gplx/xowa2/apps/Xoav_app.java | 72 + .../src/gplx/xowa2/apps/Xoav_wiki_mgr.java | 72 + .../src/gplx/xowa2/apps/urls/Xoav_url.java | 25 + .../gplx/xowa2/apps/urls/Xoav_url_parser.java | 43 + .../xowa2/apps/urls/Xoav_url_parser_tst.java | 43 + .../gplx/xowa2/files/Xofv_file_mgr_tst.java | 186 ++ .../src/gplx/xowa2/files/Xofv_repo_itm.java | 35 + .../src/gplx/xowa2/files/Xofv_repo_mgr.java | 34 + .../files/commons/Xof_commons_image_itm.java | 32 + .../files/commons/Xof_commons_image_tbl.java | 72 + 400_xowa/src/gplx/xowa2/gui/Xog_page.java | 78 + .../gplx/xowa2/gui/Xogv_page_load_wkr.java | 49 + .../src/gplx/xowa2/gui/Xogv_tab_base.java | 62 + .../src/gplx/xowa2/users/Xouv_cfg_keys.java | 24 + .../src/gplx/xowa2/wikis/Xowv_repo_mgr.java | 72 + 400_xowa/src/gplx/xowa2/wikis/Xowv_wiki.java | 102 ++ .../wikis/specials/Xosp_special_mgr.java | 52 + .../gplx/ios/BinaryHeap_Io_line_rdr.java | 84 + .../gplx/ios/BinaryHeap_Io_line_rdr_tst.java | 50 + .../src_040_io/gplx/ios/Io_buffer_rdr.java | 73 + .../gplx/ios/Io_buffer_rdr_tst.java | 64 + 400_xowa/src_040_io/gplx/ios/Io_fil_chkr.java | 31 + 400_xowa/src_040_io/gplx/ios/Io_line_rdr.java | 165 ++ .../gplx/ios/Io_line_rdr_key_gen.java | 21 + .../gplx/ios/Io_line_rdr_key_gen_.java | 56 + .../src_040_io/gplx/ios/Io_line_rdr_tst.java | 96 + 400_xowa/src_040_io/gplx/ios/Io_make_cmd.java | 21 + 400_xowa/src_040_io/gplx/ios/Io_sort.java | 98 ++ 400_xowa/src_040_io/gplx/ios/Io_sort_cmd.java | 23 + .../src_040_io/gplx/ios/Io_sort_filCmd.java | 29 + .../gplx/ios/Io_sort_fil_basic.java | 38 + .../src_040_io/gplx/ios/Io_sort_misc_tst.java | 58 + .../gplx/ios/Io_sort_split_itm.java | 35 + .../gplx/ios/Io_sort_split_itm_sorter.java | 26 + 400_xowa/src_040_io/gplx/ios/Io_sort_tst.java | 66 + 400_xowa/src_040_io/gplx/ios/Io_url_gen.java | 24 + 400_xowa/src_040_io/gplx/ios/Io_url_gen_.java | 45 + 400_xowa/src_060_utl/gplx/App_cmd_arg.java | 113 ++ 400_xowa/src_060_utl/gplx/App_cmd_mgr.java | 162 ++ .../src_060_utl/gplx/App_cmd_mgr_tst.java | 142 ++ 400_xowa/src_060_utl/gplx/Bry_cache.java | 35 + .../src_060_utl/gplx/ByteAryAry_chkr.java | 34 + .../src_060_utl/gplx/GfoCacheMgr_tst.java | 66 + 400_xowa/src_060_utl/gplx/Gfo_cache_mgr.java | 122 ++ 400_xowa/src_060_utl/gplx/Gfo_url.java | 46 + 400_xowa/src_060_utl/gplx/Gfo_url_arg.java | 41 + 400_xowa/src_060_utl/gplx/Gfo_url_parser.java | 312 ++++ .../src_060_utl/gplx/Gfo_url_parser_tst.java | 153 ++ .../src_060_utl/gplx/Gfo_url_site_data.java | 24 + .../gplx/Gfo_usr_dlg__gui__opt.java | 22 + .../gplx/Gfo_usr_dlg__gui__swt.java | 50 + .../src_060_utl/gplx/Gfo_usr_dlg_fmt.java | 34 + 400_xowa/src_060_utl/gplx/HierPosAryBldr.java | 61 + .../src_060_utl/gplx/HierPosAryBldr_tst.java | 65 + 400_xowa/src_060_utl/gplx/Int_2_ref.java | 58 + 400_xowa/src_060_utl/gplx/Int_2_val.java | 33 + 400_xowa/src_060_utl/gplx/Int_ary_parser.java | 39 + .../src_060_utl/gplx/Int_ary_parser_tst.java | 28 + 400_xowa/src_060_utl/gplx/Int_list.java | 44 + 400_xowa/src_060_utl/gplx/Io_zip_mgr.java | 25 + .../src_060_utl/gplx/Io_zip_mgr_base.java | 119 ++ 400_xowa/src_060_utl/gplx/Io_zip_mgr_mok.java | 36 + 400_xowa/src_060_utl/gplx/Io_zip_mgr_tst.java | 31 + 400_xowa/src_060_utl/gplx/Number_parser.java | 181 ++ .../src_060_utl/gplx/Number_parser_tst.java | 103 ++ .../src_060_utl/gplx/Obj_ary_parser_base.java | 58 + 400_xowa/src_060_utl/gplx/StatRng.java | 142 ++ 400_xowa/src_060_utl/gplx/StatRng_tst.java | 39 + 400_xowa/src_060_utl/gplx/Tst_chkr.java | 30 + 400_xowa/src_060_utl/gplx/Tst_mgr.java | 134 ++ 400_xowa/src_060_utl/gplx/Url_encoder.java | 309 ++++ .../src_060_utl/gplx/Url_encoder_tst.java | 72 + 400_xowa/src_100_app/gplx/xowa/Xoa_cur.java | 31 + .../src_100_app/gplx/xowa/Xoa_hive_mgr.java | 39 + .../src_100_app/gplx/xowa/Xoa_sys_cfg.java | 85 + .../src_100_app/gplx/xowa/Xoac_lang_grp.java | 75 + .../gplx/xowa/Xoac_lang_grp_tst.java | 145 ++ .../src_100_app/gplx/xowa/Xoac_lang_itm.java | 37 + .../gplx/xowa/Xoac_wiki_cfg_bldr_cmd.java | 38 + .../gplx/xowa/Xoac_wiki_cfg_bldr_fil.java | 35 + .../src_100_app/gplx/xowa/Xoac_wiki_grp.java | 47 + .../gplx/xowa/Xoac_wiki_grp_tst.java | 99 ++ .../src_100_app/gplx/xowa/Xoac_wiki_itm.java | 35 + .../src_100_app/gplx/xowa/Xoad_wtr_dump.java | 102 ++ .../gplx/xowa/Bfmtr_eval_wiki.java | 31 + .../gplx/xowa/Xow_fragment_mgr.java | 65 + .../gplx/xowa/Xow_fragment_mgr_tst.java | 57 + .../src_120_wiki/gplx/xowa/Xow_gui_mgr.java | 26 + .../src_120_wiki/gplx/xowa/Xow_html_util.java | 36 + .../gplx/xowa/Xow_mainpage_finder.java | 32 + .../gplx/xowa/Xow_mainpage_finder_tst.java | 73 + .../src_120_wiki/gplx/xowa/Xow_msg_mgr.java | 113 ++ 400_xowa/src_120_wiki/gplx/xowa/Xow_ns.java | 105 ++ 400_xowa/src_120_wiki/gplx/xowa/Xow_ns_.java | 89 + .../src_120_wiki/gplx/xowa/Xow_ns_case_.java | 34 + .../src_120_wiki/gplx/xowa/Xow_ns_mgr.java | 262 +++ .../src_120_wiki/gplx/xowa/Xow_ns_mgr_.java | 51 + .../gplx/xowa/Xow_ns_mgr_tst.java | 79 + .../src_120_wiki/gplx/xowa/Xow_ns_tst.java | 63 + .../gplx/xowa/Xow_script_mgr.java | 58 + .../src_120_wiki/gplx/xowa/Xow_sys_cfg.java | 29 + 400_xowa/src_120_wiki/gplx/xowa/Xow_user.java | 26 + .../src_120_wiki/gplx/xowa/Xow_utl_mgr.java | 40 + 400_xowa/src_120_wiki/gplx/xowa/Xow_wiki.java | 49 + .../gplx/xowa/Xow_wiki_props.java | 74 + .../gplx/xowa/Xow_wiki_stats.java | 44 + .../src_120_wiki/gplx/xowa/Xow_wiki_tst.java | 41 + .../src_120_wiki/gplx/xowa/Xowc_parser.java | 36 + .../gplx/xowa/Xowc_xtn_pages.java | 80 + .../gplx/xowa/Xowc_xtn_pages_tst.java | 65 + .../src_120_wiki/gplx/xowa/Xowc_xtns.java | 28 + .../src_120_wiki/gplx/xowa/Xowe_wiki.java | 336 ++++ .../gplx/xowa/Xowe_wiki_bldr.java | 28 + .../gplx/xowa/Bry_comparer_fld_last.java | 27 + .../gplx/xowa/ByteAry_fil.java | 39 + .../gplx/xowa/Io_txn_itm_save.java | 67 + .../gplx/xowa/Xob_hive_mgr.java | 194 +++ .../gplx/xowa/Xob_hive_mgr_tst.java | 43 + .../gplx/xowa/Xobl_data_itm.java | 21 + .../gplx/xowa/Xow_data_mgr.java | 96 + .../gplx/xowa/Xow_data_mgr_tst.java | 163 ++ .../gplx/xowa/Xow_hive_mgr_fxt.java | 98 ++ .../gplx/xowa/Xowd_hive_mgr.java | 95 + .../gplx/xowa/Xowd_hive_mgr_tst.java | 98 ++ .../gplx/xowa/Xowd_hive_regy_itm.java | 62 + .../gplx/xowa/Xowd_regy_mgr.java | 76 + .../gplx/xowa/Xowd_regy_mgr_tst.java | 88 + .../src_140_lang/gplx/xowa/Xobcl_kwd_row.java | 28 + .../gplx/xowa/Xol_csv_parser.java | 82 + .../gplx/xowa/Xol_csv_parser_tst.java | 41 + .../src_140_lang/gplx/xowa/Xol_font_info.java | 41 + .../src_140_lang/gplx/xowa/Xol_kwd_grp.java | 34 + .../src_140_lang/gplx/xowa/Xol_kwd_grp_.java | 465 +++++ .../src_140_lang/gplx/xowa/Xol_kwd_itm.java | 24 + .../src_140_lang/gplx/xowa/Xol_kwd_mgr.java | 95 + .../gplx/xowa/Xol_kwd_parse_data.java | 80 + .../gplx/xowa/Xol_kwd_parse_data_tst.java | 38 + 400_xowa/src_140_lang/gplx/xowa/Xol_lang.java | 168 ++ .../src_140_lang/gplx/xowa/Xol_lang_.java | 260 +++ .../src_140_lang/gplx/xowa/Xol_lang_srl.java | 271 +++ .../gplx/xowa/Xol_lang_srl_tst.java | 345 ++++ .../gplx/xowa/Xol_lnki_trail_mgr.java | 73 + .../gplx/xowa/Xol_lnki_trail_mgr_tst.java | 43 + .../src_140_lang/gplx/xowa/Xol_msg_itm.java | 48 + .../src_140_lang/gplx/xowa/Xol_msg_itm_.java | 516 ++++++ .../gplx/xowa/Xol_msg_itm_tst.java | 39 + .../src_140_lang/gplx/xowa/Xol_msg_mgr.java | 106 ++ .../gplx/xowa/Xol_msg_mgr_tst.java | 64 + .../src_140_lang/gplx/xowa/Xol_ns_grp.java | 44 + .../gplx/xowa/Xol_specials_itm.java | 23 + .../gplx/xowa/Xol_specials_mgr.java | 45 + .../src_160_file/gplx/xowa/Xoa_repo_mgr.java | 67 + .../gplx/xowa/Xof_cfg_download.java | 50 + .../src_160_file/gplx/xowa/Xof_file_mgr.java | 45 + .../src_160_file/gplx/xowa/Xofo_file.java | 109 ++ .../src_160_file/gplx/xowa/Xofo_lnki.java | 61 + .../gplx/xowa/Xofo_lnki_parser.java | 75 + .../gplx/xowa/Xofo_lnki_parser_tst.java | 68 + .../gplx/xowa/Xofw_file_finder_rslt.java | 30 + .../gplx/xowa/Xofw_wiki_finder.java | 23 + .../gplx/xowa/Xofw_wiki_wkr_base.java | 72 + .../gplx/xowa/Xofw_wiki_wkr_mock.java | 43 + 400_xowa/src_160_file/gplx/xowa/Xoo_mgr.java | 54 + .../src_161_meta/gplx/xowa/Xof_meta_fil.java | 61 + .../gplx/xowa/Xof_meta_fil_tst.java | 29 + .../src_161_meta/gplx/xowa/Xof_meta_itm.java | 183 ++ .../src_161_meta/gplx/xowa/Xof_meta_mgr.java | 118 ++ .../gplx/xowa/Xof_meta_mgr_tst.java | 94 + .../gplx/xowa/Xof_meta_thumb.java | 51 + .../gplx/xowa/Xof_meta_thumb_parser.java | 72 + .../gplx/xowa/Xof_meta_thumb_parser_tst.java | 50 + .../gplx/xowa/Bry_comparer_bgn_eos.java | 25 + .../gplx/xowa/Io_line_rdr_key_gen_all.java | 25 + .../gplx/xowa/Io_sort_cmd_img.java | 63 + .../gplx/xowa/Io_sort_cmd_img_tst.java | 46 + .../gplx/xowa/Io_sort_cmd_ns.java | 60 + 400_xowa/src_200_bldr/gplx/xowa/Xob_bldr.java | 113 ++ .../gplx/xowa/Xob_make_cmd_site.java | 137 ++ .../src_200_bldr/gplx/xowa/Xob_page_cmd.java | 25 + .../src_200_bldr/gplx/xowa/Xob_stat_itm.java | 43 + .../src_200_bldr/gplx/xowa/Xob_stat_mgr.java | 68 + .../src_200_bldr/gplx/xowa/Xob_stat_type.java | 36 + .../src_200_bldr/gplx/xowa/Xob_xdat_file.java | 272 +++ .../gplx/xowa/Xob_xdat_file_tst.java | 118 ++ .../gplx/xowa/Xob_xdat_file_wtr.java | 148 ++ .../gplx/xowa/Xob_xdat_file_wtr_tst.java | 54 + .../src_200_bldr/gplx/xowa/Xob_xdat_itm.java | 29 + .../src_200_bldr/gplx/xowa/Xobd_parser.java | 63 + .../gplx/xowa/Xobd_parser_wkr.java | 25 + 400_xowa/src_200_bldr/gplx/xowa/Xobd_rdr.java | 101 ++ 400_xowa/src_200_bldr/gplx/xowa/Xobd_wkr.java | 27 + .../src_200_bldr/gplx/xowa/Xobdc_merger.java | 41 + .../src_200_bldr/gplx/xowa/Xobdc_utl.java | 53 + .../gplx/xowa/Cfg_nde_obj.java | 29 + .../gplx/xowa/Cfg_nde_obj_.java | 31 + .../gplx/xowa/Cfg_nde_root.java | 137 ++ .../src_210_bldr_core/gplx/xowa/Gfs_bldr.java | 89 + .../gplx/xowa/Sql_file_parser.java | 162 ++ .../gplx/xowa/Sql_file_parser_cmd.java | 43 + .../gplx/xowa/Sql_file_parser_data.java | 23 + .../gplx/xowa/Sql_file_parser_tst.java | 74 + .../gplx/xowa/Sql_fld_mgr.java | 60 + .../gplx/xowa/Sql_fld_mgr_tst.java | 47 + .../gplx/xowa/Xob_idx_base.java | 39 + .../gplx/xowa/Xob_itm_basic_base.java | 28 + .../gplx/xowa/Xob_itm_dump_base.java | 55 + .../gplx/xowa/Xob_sql_dump_base.java | 59 + .../gplx/xowa/Xob_tmp_wtr.java | 42 + .../gplx/xowa/Xob_tmp_wtr_mgr.java | 44 + .../gplx/xowa/Xob_tmp_wtr_wkr.java | 22 + .../gplx/xowa/Xob_tmp_wtr_wkr__ttl.java | 25 + .../gplx/xowa/Xos_url_gen.java | 48 + .../gplx/xowa/Xos_url_gen_tst.java | 32 + .../gplx/xowa/Xob_dump_file.java | 89 + .../gplx/xowa/Xob_dump_file_.java | 72 + .../gplx/xowa/Xoi_cmd_base.java | 111 ++ .../gplx/xowa/Xoi_cmd_dumpfile.java | 60 + .../gplx/xowa/Xoi_cmd_dumpfile_tst.java | 76 + .../gplx/xowa/Xoi_cmd_mgr.java | 144 ++ .../gplx/xowa/Xoi_cmd_wiki.java | 199 +++ .../gplx/xowa/Xoi_cmd_wiki_import.java | 117 ++ .../gplx/xowa/Xoi_cmd_wiki_tst.java | 127 ++ .../gplx/xowa/Xoi_dump_mgr.java | 97 ++ .../gplx/xowa/Xoi_mirror_parser.java | 47 + .../gplx/xowa/Xoi_mirror_parser_tst.java | 60 + .../gplx/xowa/Xoi_setup_mgr.java | 44 + .../gplx/xowa/Xow_cfg_wiki_core.java | 86 + .../gplx/xowa/Xow_cfg_wiki_core_tst.java | 111 ++ .../src_300_html/gplx/xowa/Xoa_app_eval.java | 25 + .../gplx/xowa/Xoa_app_eval_tst.java | 41 + 400_xowa/src_300_html/gplx/xowa/Xoa_page.java | 27 + .../src_300_html/gplx/xowa/Xoa_page_.java | 24 + .../gplx/xowa/Xoa_page__commons_mgr.java | 27 + .../src_300_html/gplx/xowa/Xoae_page.java | 110 ++ .../gplx/xowa/Xoh_cfg_gallery.java | 26 + 400_xowa/src_300_html/gplx/xowa/Xoh_dom_.java | 71 + .../src_300_html/gplx/xowa/Xoh_dom_tst.java | 45 + 400_xowa/src_300_html/gplx/xowa/Xoh_find.java | 29 + .../gplx/xowa/Xop_link_parser.java | 90 + 400_xowa/src_310_url/gplx/xowa/Xoa_url.java | 95 + .../gplx/xowa/Xoa_url_arg_hash.java | 76 + .../src_310_url/gplx/xowa/Xoa_url_parser.java | 307 ++++ .../gplx/xowa/Xoa_url_parser_basic_tst.java | 172 ++ .../xowa/Xoa_url_parser_mw_links_tst.java | 25 + .../gplx/xowa/Xoa_url_parser_url_bar_tst.java | 69 + .../src_310_url/gplx/xowa/Xoa_url_tst.java | 32 + .../gplx/xowa/Pfunc_titleparts_log.java | 25 + .../src_400_parser/gplx/xowa/TstObj_tst.java | 233 +++ .../src_400_parser/gplx/xowa/Xoa_ttl.java | 420 +++++ .../gplx/xowa/Xoa_ttl_chkr.java | 29 + .../gplx/xowa/Xop_arg_itm_tkn_chkr.java | 26 + .../src_400_parser/gplx/xowa/Xop_ctx.java | 322 ++++ .../src_400_parser/gplx/xowa/Xop_ctx_.java | 29 + .../gplx/xowa/Xop_ctx__tst.java | 33 + .../src_400_parser/gplx/xowa/Xop_ctx_wkr.java | 29 + .../src_400_parser/gplx/xowa/Xop_fxt.java | 416 +++++ .../gplx/xowa/Xop_lnki_tkn_chkr.java | 59 + .../src_400_parser/gplx/xowa/Xop_lxr.java | 25 + .../src_400_parser/gplx/xowa/Xop_lxr_.java | 27 + .../src_400_parser/gplx/xowa/Xop_lxr_mgr.java | 79 + .../gplx/xowa/Xop_lxr_misc.java | 40 + .../src_400_parser/gplx/xowa/Xop_parser.java | 214 +++ .../src_400_parser/gplx/xowa/Xop_parser_.java | 36 + .../gplx/xowa/Xop_parser__tst.java | 58 + .../gplx/xowa/Xop_redirect_mgr.java | 125 ++ .../gplx/xowa/Xop_redirect_mgr_tst.java | 69 + .../gplx/xowa/Xop_sanitizer.java | 110 ++ .../gplx/xowa/Xop_sanitizer_tst.java | 44 + .../gplx/xowa/Xop_tblw_log.java | 31 + .../gplx/xowa/Xop_tblw_tb_tkn_chkr.java | 32 + .../gplx/xowa/Xop_tblw_tc_tkn_chkr.java | 27 + .../gplx/xowa/Xop_tblw_td_tkn_chkr.java | 30 + .../gplx/xowa/Xop_tblw_th_tkn_chkr.java | 30 + .../gplx/xowa/Xop_tblw_tr_tkn_chkr.java | 30 + .../gplx/xowa/Xop_tkn_chkr_base.java | 64 + .../gplx/xowa/Xop_tkn_chkr_hr.java | 29 + .../gplx/xowa/Xop_tkn_chkr_lnke.java | 33 + .../src_400_parser/gplx/xowa/Xop_ttl_log.java | 109 ++ .../gplx/xowa/Xop_xnde_log.java | 36 + .../gplx/xowa/Xop_xnde_tkn_chkr.java | 124 ++ .../gplx/xowa/Xot_prm_chkr.java | 29 + .../src_405_tkn/gplx/xowa/Xop_bry_tkn.java | 27 + .../src_405_tkn/gplx/xowa/Xop_tkn_grp.java | 34 + .../src_405_tkn/gplx/xowa/Xop_tkn_itm.java | 48 + .../src_405_tkn/gplx/xowa/Xop_tkn_itm_.java | 128 ++ .../gplx/xowa/Xop_tkn_itm_base.java | 166 ++ .../src_405_tkn/gplx/xowa/Xop_tkn_mkr.java | 171 ++ .../src_405_tkn/gplx/xowa/Xop_tkn_null.java | 52 + .../src_405_tkn/gplx/xowa/Xop_txt_tkn.java | 34 + .../gplx/xowa/Xop_comm_lxr.java | 96 + .../gplx/xowa/Xop_comm_lxr_tst.java | 102 ++ .../gplx/xowa/Xop_cr_lxr.java | 30 + .../gplx/xowa/Xop_cr_tkn.java | 35 + .../gplx/xowa/Xop_eq_lxr.java | 81 + .../gplx/xowa/Xop_eq_tkn.java | 24 + .../gplx/xowa/Xop_hr_lxr.java | 44 + .../gplx/xowa/Xop_hr_lxr_basic_tst.java | 31 + .../gplx/xowa/Xop_hr_lxr_para_tst.java | 54 + .../gplx/xowa/Xop_hr_tkn.java | 23 + .../gplx/xowa/Xop_ignore_tkn.java | 26 + .../gplx/xowa/Xop_pipe_lxr.java | 83 + .../gplx/xowa/Xop_pipe_tkn.java | 22 + .../gplx/xowa/Xop_root_tkn.java | 28 + .../gplx/xowa/Xop_space_lxr_tst.java | 32 + .../gplx/xowa/Xop_space_tkn.java | 46 + .../gplx/xowa/Xop_tab_tkn.java | 54 + .../gplx/xowa/Xop_under_lxr.java | 146 ++ .../gplx/xowa/Xop_under_lxr_tst.java | 187 ++ .../gplx/xowa/Xop_under_tkn.java | 23 + .../gplx/xowa/Xop_lnki_align_h.java | 31 + .../gplx/xowa/Xop_lnki_arg_parser.java | 168 ++ .../gplx/xowa/Xop_lnki_lxr_bgn.java | 56 + .../gplx/xowa/Xop_lnki_lxr_end.java | 26 + .../src_440_lnki/gplx/xowa/Xop_lnki_tkn.java | 64 + .../src_440_lnki/gplx/xowa/Xop_lnki_type.java | 65 + .../src_440_lnki/gplx/xowa/Xop_lnki_wkr.java | 177 ++ .../src_440_lnki/gplx/xowa/Xop_lnki_wkr_.java | 138 ++ .../gplx/xowa/Xop_lnki_wkr__basic_tst.java | 351 ++++ .../gplx/xowa/Xop_lnki_wkr__ctg_tst.java | 132 ++ .../gplx/xowa/Xop_lnki_wkr__invalid_tst.java | 94 + .../gplx/xowa/Xop_lnki_wkr__link_tst.java | 144 ++ .../gplx/xowa/Xop_lnki_wkr__pre_tst.java | 109 ++ .../gplx/xowa/Xop_lnki_wkr__subpage_tst.java | 68 + .../gplx/xowa/Xop_lnki_wkr__uncommon_tst.java | 60 + .../gplx/xowa/Xop_lnki_wkr__xwiki_tst.java | 115 ++ .../src_490_xnde/gplx/xowa/Xop_xatr_hash.java | 47 + .../src_490_xnde/gplx/xowa/Xop_xatr_itm.java | 65 + .../gplx/xowa/Xop_xatr_parser.java | 408 +++++ .../gplx/xowa/Xop_xatr_parser_tst.java | 113 ++ .../gplx/xowa/Xop_xatr_whitelist_mgr.java | 263 +++ .../gplx/xowa/Xop_xatr_whitelist_mgr_tst.java | 71 + .../gplx/xowa/Xop_xnde_atr_parser.java | 21 + .../src_490_xnde/gplx/xowa/Xop_xnde_lxr.java | 26 + .../src_490_xnde/gplx/xowa/Xop_xnde_tag.java | 81 + .../src_490_xnde/gplx/xowa/Xop_xnde_tag_.java | 264 +++ .../gplx/xowa/Xop_xnde_tag_lang.java | 32 + .../gplx/xowa/Xop_xnde_tag_regy.java | 61 + .../gplx/xowa/Xop_xnde_tag_stack.java | 35 + .../src_490_xnde/gplx/xowa/Xop_xnde_tkn.java | 119 ++ .../src_490_xnde/gplx/xowa/Xop_xnde_wkr.java | 757 ++++++++ .../gplx/xowa/Xop_xnde_wkr__basic_tst.java | 158 ++ .../xowa/Xop_xnde_wkr__blockquote_tst.java | 60 + .../xowa/Xop_xnde_wkr__err_dangling_tst.java | 198 +++ .../xowa/Xop_xnde_wkr__err_malformed_tst.java | 74 + .../gplx/xowa/Xop_xnde_wkr__err_misc_tst.java | 190 ++ .../xowa/Xop_xnde_wkr__include_basic_tst.java | 83 + .../Xop_xnde_wkr__include_uncommon_tst.java | 194 +++ .../gplx/xowa/Xop_xnde_wkr__li_tst.java | 104 ++ .../gplx/xowa/Xop_xnde_wkr__nowiki_tst.java | 144 ++ .../gplx/xowa/Xop_xnde_wkr__tblx_tst.java | 80 + .../xowa/Xop_xnde_wkr__text_block_tst.java | 79 + .../gplx/xowa/Xop_xnde_wkr__tidy_tst.java | 46 + .../gplx/xowa/Xop_xnde_wkr__xatrs_tst.java | 57 + 400_xowa/src_500_tmpl/gplx/xowa/Arg_bldr.java | 205 +++ .../src_500_tmpl/gplx/xowa/Arg_itm_tkn.java | 77 + .../src_500_tmpl/gplx/xowa/Arg_nde_tkn.java | 43 + .../gplx/xowa/Arg_nde_tkn_mock.java | 41 + .../gplx/xowa/Xop_brack_bgn_lxr.java | 30 + .../gplx/xowa/Xop_brack_end_lxr.java | 33 + .../gplx/xowa/Xop_curly_bgn_lxr.java | 36 + .../gplx/xowa/Xop_curly_bgn_tkn.java | 23 + .../gplx/xowa/Xop_curly_end_lxr.java | 26 + .../src_500_tmpl/gplx/xowa/Xop_curly_wkr.java | 158 ++ .../src_500_tmpl/gplx/xowa/Xop_subst_tst.java | 80 + 400_xowa/src_500_tmpl/gplx/xowa/Xop_tkn_.java | 26 + .../gplx/xowa/Xop_tkn_print_tst.java | 40 + .../gplx/xowa/Xot_compile_data.java | 23 + 400_xowa/src_500_tmpl/gplx/xowa/Xot_defn.java | 34 + .../src_500_tmpl/gplx/xowa/Xot_defn_.java | 37 + .../gplx/xowa/Xot_defn_subst.java | 27 + .../src_500_tmpl/gplx/xowa/Xot_defn_tmpl.java | 93 + .../gplx/xowa/Xot_defn_tmpl_.java | 69 + .../gplx/xowa/Xot_defn_trace.java | 63 + .../gplx/xowa/Xot_defn_trace_brief_tst.java | 58 + .../gplx/xowa/Xot_defn_trace_dbg.java | 141 ++ .../gplx/xowa/Xot_defn_trace_dbg_tst.java | 49 + .../gplx/xowa/Xot_examples_tst.java | 131 ++ 400_xowa/src_500_tmpl/gplx/xowa/Xot_fmtr.java | 75 + 400_xowa/src_500_tmpl/gplx/xowa/Xot_invk.java | 33 + .../src_500_tmpl/gplx/xowa/Xot_invk_mock.java | 97 ++ .../gplx/xowa/Xot_invk_sandbox_tst.java | 48 + .../src_500_tmpl/gplx/xowa/Xot_invk_temp.java | 86 + .../src_500_tmpl/gplx/xowa/Xot_invk_tkn.java | 475 +++++ .../src_500_tmpl/gplx/xowa/Xot_invk_wkr.java | 118 ++ .../gplx/xowa/Xot_invk_wkr_basic_tst.java | 453 +++++ .../xowa/Xot_invk_wkr_prepend_nl_tst.java | 121 ++ .../gplx/xowa/Xot_invk_wkr_raw_msg_tst.java | 49 + .../xowa/Xot_invk_wkr_transclude_tst.java | 40 + .../src_500_tmpl/gplx/xowa/Xot_prm_tkn.java | 89 + .../gplx/xowa/Xot_prm_tkn_tst.java | 57 + .../src_500_tmpl/gplx/xowa/Xot_prm_wkr.java | 46 + .../src_500_tmpl/gplx/xowa/Xot_tmpl_wtr.java | 112 ++ .../app/data/cfg/user_system_cfg.gfs | 6 + .../anonymous/app/data/cfg/xowa_user_cfg.gfs | 4 + .../anonymous/app/tmp/log/current/err.txt | 16 + .../anonymous/app/tmp/log/current/session.txt | 46 + 400_xowa/xtn/gplx/xowa/Xowa_main.java | 23 + 400_xowa/xtn/gplx/xowa/Xowa_tcp_console.java | 247 +++ LICENSE.txt | 624 +++++++ README.md | 105 ++ README.txt | 82 + build.xml | 52 + lib/junit.jar | Bin 0 -> 220482 bytes .../file/en.wikipedia.org/img_regy.sqlite3 | Bin 0 -> 4096 bytes .../file/en.wikipedia.org/main/core.sqlite3 | Bin 0 -> 14336 bytes .../file/en.wikipedia.org/mnt_regy.sqlite3 | Bin 0 -> 3072 bytes tst/400_xowa/root/bin/any/sql/xowa/xowa.sql | 91 + .../root/bin/any/sql/xowa/xowa.sqlite3 | Bin 0 -> 57344 bytes .../fsdb.main/fsdb.abc.sqlite3 | Bin 0 -> 28672 bytes .../fsdb.main/fsdb.atr.00.sqlite3 | Bin 0 -> 40960 bytes .../fsdb.main/fsdb.bin.0000.sqlite3 | Bin 0 -> 12288 bytes .../fsdb.user/fsdb.abc.sqlite3 | Bin 0 -> 28672 bytes .../fsdb.user/fsdb.atr.00.sqlite3 | Bin 0 -> 40960 bytes .../fsdb.user/fsdb.bin.0000.sqlite3 | Bin 0 -> 12288 bytes .../file/en.wikipedia.org/wiki.mnt.sqlite3 | Bin 0 -> 20480 bytes .../en.wikipedia.org/wiki.orig#00.sqlite3 | Bin 0 -> 12288 bytes .../test_user/app/data/cfg/xowa_user_cfg.gfs | 1 + tst/400_xowa/root/wiki/en.wikipedia.org/a.xml | 1 + .../en.wikipedia.org-text.xowa | Bin 0 -> 36864 bytes .../tmp/text.cat.core/0000000000.csv | 3 + .../tmp/text.cat.hidden/dump/0000000000.csv | 2 + .../tmp/text.cat.link/dump/0000000000.csv | 3 + .../tmp/text.cat.link/sort/0000000000.csv | 3 + 3099 files changed, 238212 insertions(+) create mode 100644 .directory create mode 100644 100_core/.classpath create mode 100644 100_core/.project create mode 100644 100_core/lib/commons-compress-1.5.jar create mode 100644 100_core/src/gplx/Exc.java create mode 100644 100_core/src/gplx/Exc_.java create mode 100644 100_core/src/gplx/Exc_msg.java create mode 100644 100_core/src/gplx/core/brys/Bry_rdr.java create mode 100644 100_core/src/gplx/core/btries/Btrie_bwd_mgr.java create mode 100644 100_core/src/gplx/core/btries/Btrie_bwd_mgr_tst.java create mode 100644 100_core/src/gplx/core/btries/Btrie_fast_mgr.java create mode 100644 100_core/src/gplx/core/btries/Btrie_fast_mgr_tst.java create mode 100644 100_core/src/gplx/core/btries/Btrie_itm_stub.java create mode 100644 100_core/src/gplx/core/btries/Btrie_mgr.java create mode 100644 100_core/src/gplx/core/btries/Btrie_slim_itm.java create mode 100644 100_core/src/gplx/core/btries/Btrie_slim_itm_tst.java create mode 100644 100_core/src/gplx/core/btries/Btrie_slim_mgr.java create mode 100644 100_core/src/gplx/core/btries/Btrie_slim_mgr_tst.java create mode 100644 100_core/src/gplx/core/btries/Btrie_utf8_itm.java create mode 100644 100_core/src/gplx/core/btries/Btrie_utf8_mgr.java create mode 100644 100_core/src/gplx/core/criterias/Criteria.java create mode 100644 100_core/src/gplx/core/criterias/Criteria_.java create mode 100644 100_core/src/gplx/core/criterias/Criteria_between.java create mode 100644 100_core/src/gplx/core/criterias/Criteria_bool_base.java create mode 100644 100_core/src/gplx/core/criterias/Criteria_comp.java create mode 100644 100_core/src/gplx/core/criterias/Criteria_eq.java create mode 100644 100_core/src/gplx/core/criterias/Criteria_fld.java create mode 100644 100_core/src/gplx/core/criterias/Criteria_in.java create mode 100644 100_core/src/gplx/core/criterias/Criteria_ioItm_tst.java create mode 100644 100_core/src/gplx/core/criterias/Criteria_ioMatch.java create mode 100644 100_core/src/gplx/core/criterias/Criteria_like.java create mode 100644 100_core/src/gplx/core/criterias/Criteria_tst.java create mode 100644 100_core/src/gplx/core/js/Js_wtr.java create mode 100644 100_core/src/gplx/core/js/Js_wtr_tst.java create mode 100644 100_core/src/gplx/core/primitives/Bool_obj_ref.java create mode 100644 100_core/src/gplx/core/primitives/Bool_obj_val.java create mode 100644 100_core/src/gplx/core/primitives/Bry_obj_ref.java create mode 100644 100_core/src/gplx/core/primitives/Byte_obj_ref.java create mode 100644 100_core/src/gplx/core/primitives/Byte_obj_val.java create mode 100644 100_core/src/gplx/core/primitives/Double_obj_val.java create mode 100644 100_core/src/gplx/core/primitives/Int_obj_ref.java create mode 100644 100_core/src/gplx/core/primitives/Int_obj_val.java create mode 100644 100_core/src/gplx/core/primitives/String_obj_ref.java create mode 100644 100_core/src/gplx/core/primitives/String_obj_val.java create mode 100644 100_core/src/gplx/core/strings/String_bldr.java create mode 100644 100_core/src/gplx/core/strings/String_bldr_.java create mode 100644 100_core/src/gplx/core/strings/String_ring.java create mode 100644 100_core/src/gplx/core/strings/String_ring_tst.java create mode 100644 100_core/src/gplx/core/threads/Gfo_lock.java create mode 100644 100_core/src/gplx/core/threads/Thread_adp.java create mode 100644 100_core/src/gplx/core/threads/Thread_adp_.java create mode 100644 100_core/src_000_err/gplx/Err.java create mode 100644 100_core/src_000_err/gplx/ErrMsgWtr.java create mode 100644 100_core/src_000_err/gplx/ErrProcData.java create mode 100644 100_core/src_000_err/gplx/ErrProcData_tst.java create mode 100644 100_core/src_000_err/gplx/Err_.java create mode 100644 100_core/src_000_err/gplx/Err_arg.java create mode 100644 100_core/src_000_err/gplx/Gfo_msg_data.java create mode 100644 100_core/src_000_err/gplx/Gfo_msg_grp.java create mode 100644 100_core/src_000_err/gplx/Gfo_msg_grp_.java create mode 100644 100_core/src_000_err/gplx/Gfo_msg_itm.java create mode 100644 100_core/src_000_err/gplx/Gfo_msg_itm_.java create mode 100644 100_core/src_000_err/gplx/Gfo_msg_log.java create mode 100644 100_core/src_000_err/gplx/Gfo_msg_obj.java create mode 100644 100_core/src_000_err/gplx/Gfo_msg_root.java create mode 100644 100_core/src_000_err/gplx/Gfo_msg_root_tst.java create mode 100644 100_core/src_100_interface/gplx/Cancelable.java create mode 100644 100_core/src_100_interface/gplx/Cancelable_.java create mode 100644 100_core/src_100_interface/gplx/CompareAble.java create mode 100644 100_core/src_100_interface/gplx/CompareAble_.java create mode 100644 100_core/src_100_interface/gplx/CompareAble_tst.java create mode 100644 100_core/src_100_interface/gplx/EqAble.java create mode 100644 100_core/src_100_interface/gplx/InjectAble.java create mode 100644 100_core/src_100_interface/gplx/NewAble.java create mode 100644 100_core/src_100_interface/gplx/ParseAble.java create mode 100644 100_core/src_100_interface/gplx/ParseAble_.java create mode 100644 100_core/src_100_interface/gplx/RlsAble.java create mode 100644 100_core/src_100_interface/gplx/RlsAble_.java create mode 100644 100_core/src_100_interface/gplx/SrlAble.java create mode 100644 100_core/src_100_interface/gplx/SrlAble_.java create mode 100644 100_core/src_100_interface/gplx/SrlAble__tst.java create mode 100644 100_core/src_100_interface/gplx/XtoStrAble.java create mode 100644 100_core/src_100_interface/gplx/XtoStrAble_.java create mode 100644 100_core/src_110_primitive/gplx/Array_.java create mode 100644 100_core/src_110_primitive/gplx/Array__tst.java create mode 100644 100_core/src_110_primitive/gplx/Bool_.java create mode 100644 100_core/src_110_primitive/gplx/Bry_.java create mode 100644 100_core/src_110_primitive/gplx/Bry__tst.java create mode 100644 100_core/src_110_primitive/gplx/Bry_bfr.java create mode 100644 100_core/src_110_primitive/gplx/Bry_bfr_.java create mode 100644 100_core/src_110_primitive/gplx/Bry_bfr_mkr.java create mode 100644 100_core/src_110_primitive/gplx/Bry_bfr_mkr_tst.java create mode 100644 100_core/src_110_primitive/gplx/Bry_bfr_tst.java create mode 100644 100_core/src_110_primitive/gplx/Bry_finder.java create mode 100644 100_core/src_110_primitive/gplx/Bry_finder_tst.java create mode 100644 100_core/src_110_primitive/gplx/Bry_fmtr.java create mode 100644 100_core/src_110_primitive/gplx/Bry_fmtr_arg.java create mode 100644 100_core/src_110_primitive/gplx/Bry_fmtr_arg_.java create mode 100644 100_core/src_110_primitive/gplx/Bry_fmtr_arg_fmtr_objs.java create mode 100644 100_core/src_110_primitive/gplx/Bry_fmtr_eval_mgr.java create mode 100644 100_core/src_110_primitive/gplx/Bry_fmtr_eval_mgr_.java create mode 100644 100_core/src_110_primitive/gplx/Bry_fmtr_eval_mgr_gfs.java create mode 100644 100_core/src_110_primitive/gplx/Bry_fmtr_itm.java create mode 100644 100_core/src_110_primitive/gplx/Bry_fmtr_tst.java create mode 100644 100_core/src_110_primitive/gplx/Bry_fmtr_vals.java create mode 100644 100_core/src_110_primitive/gplx/Byte_.java create mode 100644 100_core/src_110_primitive/gplx/Byte__tst.java create mode 100644 100_core/src_110_primitive/gplx/Byte_ascii.java create mode 100644 100_core/src_110_primitive/gplx/Char_.java create mode 100644 100_core/src_110_primitive/gplx/Double_.java create mode 100644 100_core/src_110_primitive/gplx/Double__tst.java create mode 100644 100_core/src_110_primitive/gplx/Float_.java create mode 100644 100_core/src_110_primitive/gplx/Int_.java create mode 100644 100_core/src_110_primitive/gplx/Int__tst.java create mode 100644 100_core/src_110_primitive/gplx/Int_ary_.java create mode 100644 100_core/src_110_primitive/gplx/Int_ary__tst.java create mode 100644 100_core/src_110_primitive/gplx/Long_.java create mode 100644 100_core/src_110_primitive/gplx/Long__tst.java create mode 100644 100_core/src_110_primitive/gplx/Object_.java create mode 100644 100_core/src_110_primitive/gplx/Object__tst.java create mode 100644 100_core/src_110_primitive/gplx/Short_.java create mode 100644 100_core/src_110_primitive/gplx/String_.java create mode 100644 100_core/src_110_primitive/gplx/String__tst.java create mode 100644 100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_ary_dim2.java create mode 100644 100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_bfr.java create mode 100644 100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_bfr_preserve.java create mode 100644 100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_bry.java create mode 100644 100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_byt.java create mode 100644 100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_decimal_int.java create mode 100644 100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_fmtr.java create mode 100644 100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_int.java create mode 100644 100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_time.java create mode 100644 100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_time_tst.java create mode 100644 100_core/src_120_basicDataType/gplx/DateAdp.java create mode 100644 100_core/src_120_basicDataType/gplx/DateAdp_.java create mode 100644 100_core/src_120_basicDataType/gplx/DateAdp__tst.java create mode 100644 100_core/src_120_basicDataType/gplx/DateAdp_parser.java create mode 100644 100_core/src_120_basicDataType/gplx/DateAdp_parser_tst.java create mode 100644 100_core/src_120_basicDataType/gplx/DecimalAdp.java create mode 100644 100_core/src_120_basicDataType/gplx/DecimalAdp_.java create mode 100644 100_core/src_120_basicDataType/gplx/DecimalAdp__tst.java create mode 100644 100_core/src_120_basicDataType/gplx/EnmMgr.java create mode 100644 100_core/src_120_basicDataType/gplx/Enm_.java create mode 100644 100_core/src_120_basicDataType/gplx/Guid_adp.java create mode 100644 100_core/src_120_basicDataType/gplx/Guid_adp_.java create mode 100644 100_core/src_120_basicDataType/gplx/Guid_adp__tst.java create mode 100644 100_core/src_120_basicDataType/gplx/Io_url.java create mode 100644 100_core/src_120_basicDataType/gplx/Io_url_.java create mode 100644 100_core/src_120_basicDataType/gplx/KeyVal.java create mode 100644 100_core/src_120_basicDataType/gplx/KeyValHash.java create mode 100644 100_core/src_120_basicDataType/gplx/KeyValHash_tst.java create mode 100644 100_core/src_120_basicDataType/gplx/KeyValList.java create mode 100644 100_core/src_120_basicDataType/gplx/KeyVal_.java create mode 100644 100_core/src_120_basicDataType/gplx/Math_.java create mode 100644 100_core/src_120_basicDataType/gplx/Math__tst.java create mode 100644 100_core/src_120_basicDataType/gplx/ObjAry.java create mode 100644 100_core/src_120_basicDataType/gplx/RandomAdp.java create mode 100644 100_core/src_120_basicDataType/gplx/RandomAdp_.java create mode 100644 100_core/src_120_basicDataType/gplx/TimeSpanAdp.java create mode 100644 100_core/src_120_basicDataType/gplx/TimeSpanAdp_.java create mode 100644 100_core/src_120_basicDataType/gplx/TimeSpanAdp__parse_tst.java create mode 100644 100_core/src_120_basicDataType/gplx/TimeSpanAdp_basic_tst.java create mode 100644 100_core/src_120_basicDataType/gplx/TimeSpanAdp_xtoStr_tst.java create mode 100644 100_core/src_120_basicDataType/gplx/Url_encoder_interface.java create mode 100644 100_core/src_120_basicDataType/gplx/Yn.java create mode 100644 100_core/src_140_list/gplx/Hash_adp.java create mode 100644 100_core/src_140_list/gplx/Hash_adp_.java create mode 100644 100_core/src_140_list/gplx/Hash_adp_bry.java create mode 100644 100_core/src_140_list/gplx/Hash_adp_bry_tst.java create mode 100644 100_core/src_140_list/gplx/List_adp.java create mode 100644 100_core/src_140_list/gplx/List_adp_.java create mode 100644 100_core/src_140_list/gplx/List_adp_base.java create mode 100644 100_core/src_140_list/gplx/List_adp_sorter.java create mode 100644 100_core/src_140_list/gplx/List_adp_sorter_tst.java create mode 100644 100_core/src_140_list/gplx/List_adp_tst.java create mode 100644 100_core/src_140_list/gplx/Ordered_hash.java create mode 100644 100_core/src_140_list/gplx/Ordered_hash_.java create mode 100644 100_core/src_140_list/gplx/Ordered_hash_base.java create mode 100644 100_core/src_140_list/gplx/Ordered_hash_tst.java create mode 100644 100_core/src_140_list/gplx/lists/ComparerAble.java create mode 100644 100_core/src_140_list/gplx/lists/ComparerAble_.java create mode 100644 100_core/src_140_list/gplx/lists/EnumerAble.java create mode 100644 100_core/src_140_list/gplx/lists/Hash_adp_base.java create mode 100644 100_core/src_140_list/gplx/lists/Hash_adp_list.java create mode 100644 100_core/src_140_list/gplx/lists/Iterator_null.java create mode 100644 100_core/src_140_list/gplx/lists/StackAdp.java create mode 100644 100_core/src_140_list/gplx/lists/StackAdp_.java create mode 100644 100_core/src_140_list/gplx/lists/StackAdp_tst.java create mode 100644 100_core/src_150_text/gplx/intl/Gfo_case_itm.java create mode 100644 100_core/src_150_text/gplx/intl/Gfo_case_mgr.java create mode 100644 100_core/src_150_text/gplx/intl/Gfo_case_mgr_.java create mode 100644 100_core/src_150_text/gplx/intl/Utf16_.java create mode 100644 100_core/src_150_text/gplx/intl/Utf16__tst.java create mode 100644 100_core/src_150_text/gplx/intl/Utf8_.java create mode 100644 100_core/src_150_text/gplx/intl/Utf8__tst.java create mode 100644 100_core/src_150_text/gplx/texts/Base32Converter.java create mode 100644 100_core/src_150_text/gplx/texts/Base64Converter.java create mode 100644 100_core/src_150_text/gplx/texts/BaseXXConverter_tst.java create mode 100644 100_core/src_150_text/gplx/texts/CharStream.java create mode 100644 100_core/src_150_text/gplx/texts/CharStream_tst.java create mode 100644 100_core/src_150_text/gplx/texts/HexDecUtl.java create mode 100644 100_core/src_150_text/gplx/texts/HexDecUtl_tst.java create mode 100644 100_core/src_150_text/gplx/texts/RegxAdp.java create mode 100644 100_core/src_150_text/gplx/texts/RegxAdp_.java create mode 100644 100_core/src_150_text/gplx/texts/RegxAdp__tst.java create mode 100644 100_core/src_150_text/gplx/texts/RegxAdp_mpo_find.java create mode 100644 100_core/src_150_text/gplx/texts/RegxAdp_mpo_replace.java create mode 100644 100_core/src_150_text/gplx/texts/RegxBldr.java create mode 100644 100_core/src_150_text/gplx/texts/RegxGroup.java create mode 100644 100_core/src_150_text/gplx/texts/RegxMatch.java create mode 100644 100_core/src_150_text/gplx/texts/RegxPatn_cls_ioMatch.java create mode 100644 100_core/src_150_text/gplx/texts/RegxPatn_cls_ioMatch_.java create mode 100644 100_core/src_150_text/gplx/texts/RegxPatn_cls_ioMatch_tst.java create mode 100644 100_core/src_150_text/gplx/texts/RegxPatn_cls_like.java create mode 100644 100_core/src_150_text/gplx/texts/RegxPatn_cls_like_.java create mode 100644 100_core/src_150_text/gplx/texts/RegxPatn_cls_like_tst.java create mode 100644 100_core/src_150_text/gplx/texts/StringTableBldr.java create mode 100644 100_core/src_150_text/gplx/texts/StringTableBldr_tst.java create mode 100644 100_core/src_150_text/gplx/texts/StringTableCol.java create mode 100644 100_core/src_150_text/gplx/texts/StringTableColAlign.java create mode 100644 100_core/src_160_hash/gplx/security/HashAlgo.java create mode 100644 100_core/src_160_hash/gplx/security/HashAlgo_.java create mode 100644 100_core/src_160_hash/gplx/security/HashAlgo_md5_tst.java create mode 100644 100_core/src_160_hash/gplx/security/HashAlgo_sha1_tst.java create mode 100644 100_core/src_160_hash/gplx/security/HashAlgo_tth192.java create mode 100644 100_core/src_160_hash/gplx/security/HashAlgo_tth192_tree_tst.java create mode 100644 100_core/src_160_hash/gplx/security/HashAlgo_tth192_tst.java create mode 100644 100_core/src_160_hash/gplx/security/HashDlgWtr_tst.java create mode 100644 100_core/src_200_io/gplx/Io_mgr.java create mode 100644 100_core/src_200_io/gplx/Io_mgr__tst.java create mode 100644 100_core/src_200_io/gplx/ios/IoEngine.java create mode 100644 100_core/src_200_io/gplx/ios/IoEnginePool.java create mode 100644 100_core/src_200_io/gplx/ios/IoEngine_.java create mode 100644 100_core/src_200_io/gplx/ios/IoEngine_base.java create mode 100644 100_core/src_200_io/gplx/ios/IoEngine_memory.java create mode 100644 100_core/src_200_io/gplx/ios/IoEngine_system.java create mode 100644 100_core/src_200_io/gplx/ios/IoEngine_xrg_deleteDir.java create mode 100644 100_core/src_200_io/gplx/ios/IoEngine_xrg_deleteFil.java create mode 100644 100_core/src_200_io/gplx/ios/IoEngine_xrg_downloadFil.java create mode 100644 100_core/src_200_io/gplx/ios/IoEngine_xrg_fil_affects1_base.java create mode 100644 100_core/src_200_io/gplx/ios/IoEngine_xrg_loadFilStr.java create mode 100644 100_core/src_200_io/gplx/ios/IoEngine_xrg_openRead.java create mode 100644 100_core/src_200_io/gplx/ios/IoEngine_xrg_openWrite.java create mode 100644 100_core/src_200_io/gplx/ios/IoEngine_xrg_queryDir.java create mode 100644 100_core/src_200_io/gplx/ios/IoEngine_xrg_recycleFil.java create mode 100644 100_core/src_200_io/gplx/ios/IoEngine_xrg_saveFilStr.java create mode 100644 100_core/src_200_io/gplx/ios/IoEngine_xrg_xferDir.java create mode 100644 100_core/src_200_io/gplx/ios/IoEngine_xrg_xferFil.java create mode 100644 100_core/src_200_io/gplx/ios/IoErr.java create mode 100644 100_core/src_200_io/gplx/ios/IoItmAttrib.java create mode 100644 100_core/src_200_io/gplx/ios/IoItmClassXtn.java create mode 100644 100_core/src_200_io/gplx/ios/IoItmDir.java create mode 100644 100_core/src_200_io/gplx/ios/IoItmDir_.java create mode 100644 100_core/src_200_io/gplx/ios/IoItmFil.java create mode 100644 100_core/src_200_io/gplx/ios/IoItmFil_.java create mode 100644 100_core/src_200_io/gplx/ios/IoItmFil_mem.java create mode 100644 100_core/src_200_io/gplx/ios/IoItmHash.java create mode 100644 100_core/src_200_io/gplx/ios/IoItmList.java create mode 100644 100_core/src_200_io/gplx/ios/IoItm_base.java create mode 100644 100_core/src_200_io/gplx/ios/IoItm_base_.java create mode 100644 100_core/src_200_io/gplx/ios/IoRecycleBin.java create mode 100644 100_core/src_200_io/gplx/ios/IoStream.java create mode 100644 100_core/src_200_io/gplx/ios/IoStream_.java create mode 100644 100_core/src_200_io/gplx/ios/IoStream_mem.java create mode 100644 100_core/src_200_io/gplx/ios/IoStream_mem_tst.java create mode 100644 100_core/src_200_io/gplx/ios/IoStream_mock.java create mode 100644 100_core/src_200_io/gplx/ios/IoStream_mock_tst.java create mode 100644 100_core/src_200_io/gplx/ios/IoStream_stream_rdr.java create mode 100644 100_core/src_200_io/gplx/ios/IoUrlInfo.java create mode 100644 100_core/src_200_io/gplx/ios/IoUrlInfoRegy.java create mode 100644 100_core/src_200_io/gplx/ios/IoUrlInfo_.java create mode 100644 100_core/src_200_io/gplx/ios/IoUrlTypeRegy.java create mode 100644 100_core/src_200_io/gplx/ios/IoZipWkr.java create mode 100644 100_core/src_200_io/gplx/ios/IoZipWkr_tst.java create mode 100644 100_core/src_200_io/gplx/ios/Io_download_fmt.java create mode 100644 100_core/src_200_io/gplx/ios/Io_download_fmt_tst.java create mode 100644 100_core/src_200_io/gplx/ios/Io_fil.java create mode 100644 100_core/src_200_io/gplx/ios/Io_fil_mkr.java create mode 100644 100_core/src_200_io/gplx/ios/Io_size_.java create mode 100644 100_core/src_200_io/gplx/ios/Io_size__tst.java create mode 100644 100_core/src_200_io/gplx/ios/Io_stream_.java create mode 100644 100_core/src_200_io/gplx/ios/Io_stream_rdr.java create mode 100644 100_core/src_200_io/gplx/ios/Io_stream_rdr_.java create mode 100644 100_core/src_200_io/gplx/ios/Io_stream_rdr_tst.java create mode 100644 100_core/src_200_io/gplx/ios/Io_stream_wtr.java create mode 100644 100_core/src_200_io/gplx/ios/Io_stream_wtr_.java create mode 100644 100_core/src_200_io/gplx/ios/Io_url_obj_ref.java create mode 100644 100_core/src_210_env/gplx/ClassAdp_.java create mode 100644 100_core/src_210_env/gplx/Env_.java create mode 100644 100_core/src_210_env/gplx/JarAdp_.java create mode 100644 100_core/src_210_env/gplx/Op_sys.java create mode 100644 100_core/src_210_env/gplx/Op_sys_.java create mode 100644 100_core/src_210_env/gplx/ProcessAdp.java create mode 100644 100_core/src_210_env/gplx/ProcessAdp_tst.java create mode 100644 100_core/src_220_console/gplx/ConsoleAdp.java create mode 100644 100_core/src_220_console/gplx/ConsoleDlg.java create mode 100644 100_core/src_220_console/gplx/ConsoleDlg_.java create mode 100644 100_core/src_220_console/gplx/ConsoleDlg_dev.java create mode 100644 100_core/src_300_classXtn/gplx/BoolClassXtn.java create mode 100644 100_core/src_300_classXtn/gplx/ByteClassXtn.java create mode 100644 100_core/src_300_classXtn/gplx/ClassXtn.java create mode 100644 100_core/src_300_classXtn/gplx/ClassXtnPool.java create mode 100644 100_core/src_300_classXtn/gplx/ClassXtn_base.java create mode 100644 100_core/src_300_classXtn/gplx/DateAdpClassXtn.java create mode 100644 100_core/src_300_classXtn/gplx/DateAdpClassXtn_tst.java create mode 100644 100_core/src_300_classXtn/gplx/DecimalAdpClassXtn.java create mode 100644 100_core/src_300_classXtn/gplx/DoubleClassXtn.java create mode 100644 100_core/src_300_classXtn/gplx/FloatClassXtn.java create mode 100644 100_core/src_300_classXtn/gplx/IntClassXtn.java create mode 100644 100_core/src_300_classXtn/gplx/IoUrlClassXtn.java create mode 100644 100_core/src_300_classXtn/gplx/LongClassXtn.java create mode 100644 100_core/src_300_classXtn/gplx/ObjectClassXtn.java create mode 100644 100_core/src_300_classXtn/gplx/StringClassXtn.java create mode 100644 100_core/src_300_classXtn/gplx/TimeSpanAdpClassXtn.java create mode 100644 100_core/src_310_gfoNde/gplx/GfoFld.java create mode 100644 100_core/src_310_gfoNde/gplx/GfoFldList.java create mode 100644 100_core/src_310_gfoNde/gplx/GfoFldList_.java create mode 100644 100_core/src_310_gfoNde/gplx/GfoNde.java create mode 100644 100_core/src_310_gfoNde/gplx/GfoNdeFxt.java create mode 100644 100_core/src_310_gfoNde/gplx/GfoNdeList.java create mode 100644 100_core/src_310_gfoNde/gplx/GfoNdeList_.java create mode 100644 100_core/src_310_gfoNde/gplx/GfoNde_.java create mode 100644 100_core/src_311_gfoObj/gplx/GfoEvMgr.java create mode 100644 100_core/src_311_gfoObj/gplx/GfoEvMgrOwner.java create mode 100644 100_core/src_311_gfoObj/gplx/GfoEvMgr_.java create mode 100644 100_core/src_311_gfoObj/gplx/GfoEvMgr_tst.java create mode 100644 100_core/src_311_gfoObj/gplx/GfoEvObj.java create mode 100644 100_core/src_311_gfoObj/gplx/GfoInvkAble.java create mode 100644 100_core/src_311_gfoObj/gplx/GfoInvkAbleCmd.java create mode 100644 100_core/src_311_gfoObj/gplx/GfoInvkAble_.java create mode 100644 100_core/src_311_gfoObj/gplx/GfoInvkCmdMgr.java create mode 100644 100_core/src_311_gfoObj/gplx/GfoInvkCmdMgrOwner.java create mode 100644 100_core/src_311_gfoObj/gplx/GfoInvkRootWkr.java create mode 100644 100_core/src_311_gfoObj/gplx/GfoInvkXtoStr.java create mode 100644 100_core/src_311_gfoObj/gplx/GfoMsg.java create mode 100644 100_core/src_311_gfoObj/gplx/GfoMsgUtl.java create mode 100644 100_core/src_311_gfoObj/gplx/GfoMsg_.java create mode 100644 100_core/src_311_gfoObj/gplx/GfoMsg_tst.java create mode 100644 100_core/src_311_gfoObj/gplx/GfoTemplate.java create mode 100644 100_core/src_311_gfoObj/gplx/GfoTemplateFactory.java create mode 100644 100_core/src_330_store/gplx/DataRdr.java create mode 100644 100_core/src_330_store/gplx/DataRdr_.java create mode 100644 100_core/src_330_store/gplx/DataWtr.java create mode 100644 100_core/src_330_store/gplx/DataWtr_.java create mode 100644 100_core/src_330_store/gplx/DataWtr_base.java create mode 100644 100_core/src_330_store/gplx/SrlMgr.java create mode 100644 100_core/src_330_store/gplx/SrlObj.java create mode 100644 100_core/src_330_store/gplx/stores/DataRdr_base.java create mode 100644 100_core/src_330_store/gplx/stores/DataRdr_mem.java create mode 100644 100_core/src_330_store/gplx/stores/GfoNdeRdr.java create mode 100644 100_core/src_330_store/gplx/stores/GfoNdeRdr_.java create mode 100644 100_core/src_330_store/gplx/stores/xmls/XmlDataRdr.java create mode 100644 100_core/src_330_store/gplx/stores/xmls/XmlDataRdr_.java create mode 100644 100_core/src_330_store/gplx/stores/xmls/XmlDataWtr_.java create mode 100644 100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdrOpts.java create mode 100644 100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_.java create mode 100644 100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_csv_dat_tst.java create mode 100644 100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_dsv_dat_tst.java create mode 100644 100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_dsv_hdr_tst.java create mode 100644 100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_dsv_misc_tst.java create mode 100644 100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_layout_tst.java create mode 100644 100_core/src_340_dsv/gplx/stores/dsvs/DsvDataWtr.java create mode 100644 100_core/src_340_dsv/gplx/stores/dsvs/DsvDataWtr_.java create mode 100644 100_core/src_340_dsv/gplx/stores/dsvs/DsvDataWtr_csv_tst.java create mode 100644 100_core/src_340_dsv/gplx/stores/dsvs/DsvDataWtr_tbls_tst.java create mode 100644 100_core/src_340_dsv/gplx/stores/dsvs/DsvHeaderList.java create mode 100644 100_core/src_340_dsv/gplx/stores/dsvs/DsvStoreLayout.java create mode 100644 100_core/src_340_dsv/gplx/stores/dsvs/DsvSymbols.java create mode 100644 100_core/src_400_gfs/gplx/GfsCore.java create mode 100644 100_core/src_400_gfs/gplx/GfsCoreHelp.java create mode 100644 100_core/src_400_gfs/gplx/GfsCore_tst.java create mode 100644 100_core/src_400_gfs/gplx/GfsCtx.java create mode 100644 100_core/src_400_gfs/gplx/GfsLibIni.java create mode 100644 100_core/src_400_gfs/gplx/GfsLibIni_core.java create mode 100644 100_core/src_400_gfs/gplx/GfsRegy.java create mode 100644 100_core/src_400_gfs/gplx/GfsTypeNames.java create mode 100644 100_core/src_400_gfs/gplx/Gfs_Date_tst.java create mode 100644 100_core/src_410_gfoCfg/gplx/GfoMsgParser.java create mode 100644 100_core/src_410_gfoCfg/gplx/GfoRegy.java create mode 100644 100_core/src_410_gfoCfg/gplx/GfoRegyItm.java create mode 100644 100_core/src_410_gfoCfg/gplx/GfoRegy_RegDir_tst.java create mode 100644 100_core/src_410_gfoCfg/gplx/GfoRegy_basic_tst.java create mode 100644 100_core/src_420_usrMsg/gplx/Gfo_log_bfr.java create mode 100644 100_core/src_420_usrMsg/gplx/Gfo_usr_dlg.java create mode 100644 100_core/src_420_usrMsg/gplx/Gfo_usr_dlg_.java create mode 100644 100_core/src_420_usrMsg/gplx/Gfo_usr_dlg__gui.java create mode 100644 100_core/src_420_usrMsg/gplx/Gfo_usr_dlg__gui_.java create mode 100644 100_core/src_420_usrMsg/gplx/Gfo_usr_dlg__gui_test.java create mode 100644 100_core/src_420_usrMsg/gplx/Gfo_usr_dlg__log.java create mode 100644 100_core/src_420_usrMsg/gplx/Gfo_usr_dlg__log_.java create mode 100644 100_core/src_420_usrMsg/gplx/Gfo_usr_dlg__log_base.java create mode 100644 100_core/src_420_usrMsg/gplx/Gfo_usr_dlg_base.java create mode 100644 100_core/src_420_usrMsg/gplx/UsrDlg.java create mode 100644 100_core/src_420_usrMsg/gplx/UsrDlg_.java create mode 100644 100_core/src_420_usrMsg/gplx/UsrMsg.java create mode 100644 100_core/src_420_usrMsg/gplx/UsrMsgWkr.java create mode 100644 100_core/src_420_usrMsg/gplx/UsrMsgWkr_.java create mode 100644 100_core/src_420_usrMsg/gplx/UsrMsgWkr_console.java create mode 100644 100_core/src_420_usrMsg/gplx/UsrMsgWkr_test.java create mode 100644 100_core/src_800_tst/gplx/PerfLogMgr_fxt.java create mode 100644 100_core/src_800_tst/gplx/Tfds.java create mode 100644 100_core/src_800_tst/gplx/TfdsEqListItmStr.java create mode 100644 100_core/src_800_tst/gplx/Tfds_tst.java create mode 100644 100_core/src_900_xml/gplx/Base64_utl.java create mode 100644 100_core/src_900_xml/gplx/Base85_utl.java create mode 100644 100_core/src_900_xml/gplx/Base85_utl_tst.java create mode 100644 100_core/src_900_xml/gplx/HierStrBldr.java create mode 100644 100_core/src_900_xml/gplx/HierStrBldr_tst.java create mode 100644 100_core/src_900_xml/gplx/xmls/XmlAtr.java create mode 100644 100_core/src_900_xml/gplx/xmls/XmlAtrList.java create mode 100644 100_core/src_900_xml/gplx/xmls/XmlDoc.java create mode 100644 100_core/src_900_xml/gplx/xmls/XmlDoc_.java create mode 100644 100_core/src_900_xml/gplx/xmls/XmlDoc_tst.java create mode 100644 100_core/src_900_xml/gplx/xmls/XmlFileSplitter.java create mode 100644 100_core/src_900_xml/gplx/xmls/XmlFileSplitterOpts.java create mode 100644 100_core/src_900_xml/gplx/xmls/XmlFileSplitter_tst.java create mode 100644 100_core/src_900_xml/gplx/xmls/XmlNde.java create mode 100644 100_core/src_900_xml/gplx/xmls/XmlNdeList.java create mode 100644 100_core/src_900_xml/gplx/xmls/XmlSplitRdr.java create mode 100644 100_core/src_900_xml/gplx/xmls/XmlSplitWtr.java create mode 100644 100_core/src_900_xml/gplx/xmls/Xpath_.java create mode 100644 100_core/src_900_xml/gplx/xmls/Xpath__tst.java create mode 100644 100_core/tst/gplx/EnmParser_tst.java create mode 100644 100_core/tst/gplx/GfoMsg_rdr_tst.java create mode 100644 100_core/tst/gplx/GfoTreeBldr_fxt.java create mode 100644 100_core/tst/gplx/TfdsTstr_fxt.java create mode 100644 100_core/tst/gplx/ios/IoEngineFxt.java create mode 100644 100_core/tst/gplx/ios/IoEngine_dir_basic_base.java create mode 100644 100_core/tst/gplx/ios/IoEngine_dir_basic_memory_tst.java create mode 100644 100_core/tst/gplx/ios/IoEngine_dir_basic_system_tst.java create mode 100644 100_core/tst/gplx/ios/IoEngine_dir_deep_base.java create mode 100644 100_core/tst/gplx/ios/IoEngine_dir_deep_memory_tst.java create mode 100644 100_core/tst/gplx/ios/IoEngine_dir_deep_system_tst.java create mode 100644 100_core/tst/gplx/ios/IoEngine_fil_basic_base.java create mode 100644 100_core/tst/gplx/ios/IoEngine_fil_basic_memory_tst.java create mode 100644 100_core/tst/gplx/ios/IoEngine_fil_basic_system_tst.java create mode 100644 100_core/tst/gplx/ios/IoEngine_fil_xfer_base.java create mode 100644 100_core/tst/gplx/ios/IoEngine_fil_xfer_memory_tst.java create mode 100644 100_core/tst/gplx/ios/IoEngine_fil_xfer_system_tst.java create mode 100644 100_core/tst/gplx/ios/IoEngine_stream_xfer_tst.java create mode 100644 100_core/tst/gplx/ios/IoEngine_xrg_queryDir_tst.java create mode 100644 100_core/tst/gplx/ios/IoEngine_xrg_recycleFil_tst.java create mode 100644 100_core/tst/gplx/ios/IoItmDir_FetchDeepOrNull_tst.java create mode 100644 100_core/tst/gplx/ios/IoItm_fxt.java create mode 100644 100_core/tst/gplx/ios/IoUrlInfo_alias_tst.java create mode 100644 100_core/tst/gplx/ios/IoUrl_lnx_tst.java create mode 100644 100_core/tst/gplx/ios/IoUrl_map_tst.java create mode 100644 100_core/tst/gplx/ios/IoUrl_wnt_tst.java create mode 100644 100_core/tst/gplx/stores/GfoNdeRdr_read_tst.java create mode 100644 100_core/tst/gplx/stores/GfoNdeRdr_tst.java create mode 100644 100_core/tst/gplx/stores/xmls/XmlDataRdr_tst.java create mode 100644 100_core/tst/gplx/stores/xmls/XmlDataWtr_tst.java create mode 100644 100_core/xtn/gplx/Internal.java create mode 100644 100_core/xtn/gplx/MainClass.java create mode 100644 100_core/xtn/gplx/New.java create mode 100644 100_core/xtn/gplx/Virtual.java create mode 100644 110_gfml/.classpath create mode 100644 110_gfml/.project create mode 100644 110_gfml/src_100_tkn/gplx/gfml/GfmlLxr.java create mode 100644 110_gfml/src_100_tkn/gplx/gfml/GfmlLxr_.java create mode 100644 110_gfml/src_100_tkn/gplx/gfml/GfmlObj.java create mode 100644 110_gfml/src_100_tkn/gplx/gfml/GfmlObjList.java create mode 100644 110_gfml/src_100_tkn/gplx/gfml/GfmlTkn.java create mode 100644 110_gfml/src_100_tkn/gplx/gfml/GfmlTkn_.java create mode 100644 110_gfml/src_100_tkn/gplx/gfml/GfmlTrie.java create mode 100644 110_gfml/src_100_tkn/gplx/gfml/IntObjHash.java create mode 100644 110_gfml/src_200_type/gplx/gfml/GfmlFld.java create mode 100644 110_gfml/src_200_type/gplx/gfml/GfmlFldList.java create mode 100644 110_gfml/src_200_type/gplx/gfml/GfmlType.java create mode 100644 110_gfml/src_200_type/gplx/gfml/GfmlTypeCompiler.java create mode 100644 110_gfml/src_200_type/gplx/gfml/GfmlTypeHash.java create mode 100644 110_gfml/src_200_type/gplx/gfml/GfmlTypeMakr.java create mode 100644 110_gfml/src_200_type/gplx/gfml/GfmlTypeMgr.java create mode 100644 110_gfml/src_300_gdoc/gplx/gfml/GfmlAtr.java create mode 100644 110_gfml/src_300_gdoc/gplx/gfml/GfmlDoc.java create mode 100644 110_gfml/src_300_gdoc/gplx/gfml/GfmlDocLxrs.java create mode 100644 110_gfml/src_300_gdoc/gplx/gfml/GfmlDocPos.java create mode 100644 110_gfml/src_300_gdoc/gplx/gfml/GfmlDocWtr_.java create mode 100644 110_gfml/src_300_gdoc/gplx/gfml/GfmlDoc_.java create mode 100644 110_gfml/src_300_gdoc/gplx/gfml/GfmlItm.java create mode 100644 110_gfml/src_300_gdoc/gplx/gfml/GfmlItmHnds.java create mode 100644 110_gfml/src_300_gdoc/gplx/gfml/GfmlItmKeys.java create mode 100644 110_gfml/src_300_gdoc/gplx/gfml/GfmlNde.java create mode 100644 110_gfml/src_300_gdoc/gplx/gfml/GfmlScopeItm.java create mode 100644 110_gfml/src_400_pragma/gplx/gfml/GfmlPragma.java create mode 100644 110_gfml/src_400_pragma/gplx/gfml/GfmlPragmaDefault.java create mode 100644 110_gfml/src_400_pragma/gplx/gfml/GfmlPragmaLxrFrm.java create mode 100644 110_gfml/src_400_pragma/gplx/gfml/GfmlPragmaLxrSym.java create mode 100644 110_gfml/src_400_pragma/gplx/gfml/GfmlPragmaType.java create mode 100644 110_gfml/src_400_pragma/gplx/gfml/GfmlPragmaVar.java create mode 100644 110_gfml/src_400_pragma/gplx/gfml/GfmlVarCtx.java create mode 100644 110_gfml/src_400_pragma/gplx/gfml/GfmlVarItm.java create mode 100644 110_gfml/src_400_pragma/gplx/gfml/GfmlVarTkn.java create mode 100644 110_gfml/src_500_build/gplx/gfml/GfmlBldr.java create mode 100644 110_gfml/src_500_build/gplx/gfml/GfmlBldrCmd.java create mode 100644 110_gfml/src_500_build/gplx/gfml/GfmlBldrCmds.java create mode 100644 110_gfml/src_500_build/gplx/gfml/GfmlBldr_.java create mode 100644 110_gfml/src_500_build/gplx/gfml/GfmlFrame.java create mode 100644 110_gfml/src_500_build/gplx/gfml/GfmlFrame_.java create mode 100644 110_gfml/src_500_build/gplx/gfml/GfmlFrame_nde.java create mode 100644 110_gfml/src_500_build/gplx/gfml/GfmlFrame_ndeTknMgr.java create mode 100644 110_gfml/src_500_build/gplx/gfml/GfmlStringHighlighter.java create mode 100644 110_gfml/src_600_rdrWtr/gplx/gfml/GfmlDataNde.java create mode 100644 110_gfml/src_600_rdrWtr/gplx/gfml/GfmlDataRdr.java create mode 100644 110_gfml/src_600_rdrWtr/gplx/gfml/GfmlDataRdr_base.java create mode 100644 110_gfml/src_600_rdrWtr/gplx/gfml/GfmlDataWtr.java create mode 100644 110_gfml/src_600_rdrWtr/gplx/gfml/GfmlDataWtrOpts.java create mode 100644 110_gfml/src_600_rdrWtr/gplx/gfml/GfoMsgParser_gfml.java create mode 100644 110_gfml/src_600_rdrWtr/gplx/gfml/SqlConsts.java create mode 100644 110_gfml/src_600_rdrWtr/gplx/gfml/SqlDoc.java create mode 100644 110_gfml/tst/gplx/gfml/GfmlDataRdr_tst.java create mode 100644 110_gfml/tst/gplx/gfml/yfxts_GfmlParse_fxt.java create mode 100644 110_gfml/tst/gplx/gfml/yfxts_GfmlTypeCompiler_fxt.java create mode 100644 110_gfml/tst/gplx/gfml/ymoks_GfmlAtr_GfmlNde_mok.java create mode 100644 110_gfml/tst/gplx/gfml/ymoks_GfmlTkn_mok.java create mode 100644 110_gfml/tst/gplx/gfml/ymoks_GfmlTyp_GfmlFld_mok.java create mode 100644 110_gfml/tst/gplx/gfml/ymoks_UsrMsg_mok.java create mode 100644 110_gfml/tst/gplx/gfml/z011_IntObjHash_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z012_GfmlTrie_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z015_GfmlDocPos_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z016_GfmlScopeList_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z017_GfmlStringHighlighter_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z051_GfmlFldPool_keyed_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z081_GfmlDataWtr_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z082_GfmlDataWtrOpts_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z091_GfmlLxr_basic_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z101_core_ndeInline_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z102_core_whitespace_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z103_core_elmKey_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z111_core_comment0_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z112_core_comment1_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z120_quotes_eval0_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z121_quotes_quotes0_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z122_quotes_quote0_eval0_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z123_quotes_quoteBlock_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z124_quotes_quoteFold_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z151_ndeSubs_basic_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z152_ndeSubs_data_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z161_ndeHdrs_inline_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z162_ndeHdrs_err_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z163_ndeHdrs_body_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z164_hdeHdrs_data_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z181_ndeDots_basic_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z182_ndeDots_subs_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z183_ndeDots_parens_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z184_ndeDots_atrSpr_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z191_ndeProps_basic_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z192_ndeProps_dots_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z400_GfmlTypeMakr_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z401_types_compile_basic_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z402_types_compile_implicit_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z403_types_compile_default_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z411_types_apply_atrs_basic_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z421_types_apply_ndes_basic_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z422_types_apply_ndes_multi_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z423_types_apply_ndes_misc_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z424_types_apply_ndes_nest_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z441_types_parse_basic_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z442_types_parse_default_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z443_types_parse_keyd_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z450_fx_GfmlDefaultItem_fxt.java create mode 100644 110_gfml/tst/gplx/gfml/z451_dflts_compile_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z452_dflts_exec_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z455_dflts_scope_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z456_dflts_parse_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z481_vars_compile_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z482_vars_parse_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z501_lxr_parse_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z601_edit_atr_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z602_edit_nde_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z801_useCase_DataRdr_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z803_useCase_KbdKeyboard_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z811_useCase_GfmlIoSql_tst.java create mode 100644 110_gfml/tst/gplx/gfml/z901_perf_tst.java create mode 100644 140_dbs/.classpath create mode 100644 140_dbs/.project create mode 100644 140_dbs/lib/mysql-connector-java-5.1.12-bin.jar create mode 100644 140_dbs/lib/postgresql-8.4-701.jdbc4.jar create mode 100644 140_dbs/lib/sqlite-jdbc-3.7.15-M1.jar create mode 100644 140_dbs/src/gplx/dbs/Db_cmd_mode.java create mode 100644 140_dbs/src/gplx/dbs/Db_conn.java create mode 100644 140_dbs/src/gplx/dbs/Db_conn_.java create mode 100644 140_dbs/src/gplx/dbs/Db_conn_bldr.java create mode 100644 140_dbs/src/gplx/dbs/Db_conn_bldr_data.java create mode 100644 140_dbs/src/gplx/dbs/Db_conn_bldr_wkr.java create mode 100644 140_dbs/src/gplx/dbs/Db_conn_info.java create mode 100644 140_dbs/src/gplx/dbs/Db_conn_info_.java create mode 100644 140_dbs/src/gplx/dbs/Db_conn_info__base.java create mode 100644 140_dbs/src/gplx/dbs/Db_conn_info_tst.java create mode 100644 140_dbs/src/gplx/dbs/Db_conn_pool.java create mode 100644 140_dbs/src/gplx/dbs/Db_crt_.java create mode 100644 140_dbs/src/gplx/dbs/Db_crt_tst.java create mode 100644 140_dbs/src/gplx/dbs/Db_idx_itm.java create mode 100644 140_dbs/src/gplx/dbs/Db_meta_fld.java create mode 100644 140_dbs/src/gplx/dbs/Db_meta_fld_list.java create mode 100644 140_dbs/src/gplx/dbs/Db_meta_idx.java create mode 100644 140_dbs/src/gplx/dbs/Db_meta_tbl.java create mode 100644 140_dbs/src/gplx/dbs/Db_qry.java create mode 100644 140_dbs/src/gplx/dbs/Db_qry_.java create mode 100644 140_dbs/src/gplx/dbs/Db_rdr.java create mode 100644 140_dbs/src/gplx/dbs/Db_rdr_.java create mode 100644 140_dbs/src/gplx/dbs/Db_rdr__basic.java create mode 100644 140_dbs/src/gplx/dbs/Db_sql_select.java create mode 100644 140_dbs/src/gplx/dbs/Db_stmt.java create mode 100644 140_dbs/src/gplx/dbs/Db_stmt_.java create mode 100644 140_dbs/src/gplx/dbs/Db_stmt_bldr.java create mode 100644 140_dbs/src/gplx/dbs/engines/Db_engine.java create mode 100644 140_dbs/src/gplx/dbs/engines/Db_engine_sql_base.java create mode 100644 140_dbs/src/gplx/dbs/engines/mems/Db_conn_info__mem.java create mode 100644 140_dbs/src/gplx/dbs/engines/mems/Db_engine__mem.java create mode 100644 140_dbs/src/gplx/dbs/engines/mems/Db_rdr__mem.java create mode 100644 140_dbs/src/gplx/dbs/engines/mems/Db_stmt__mem.java create mode 100644 140_dbs/src/gplx/dbs/engines/mems/Mem_qry_set.java create mode 100644 140_dbs/src/gplx/dbs/engines/mems/Mem_row.java create mode 100644 140_dbs/src/gplx/dbs/engines/mems/Mem_tbl.java create mode 100644 140_dbs/src/gplx/dbs/engines/mysql/Mysql_conn_info.java create mode 100644 140_dbs/src/gplx/dbs/engines/mysql/Mysql_engine.java create mode 100644 140_dbs/src/gplx/dbs/engines/nulls/Noop_conn_info.java create mode 100644 140_dbs/src/gplx/dbs/engines/nulls/Noop_engine.java create mode 100644 140_dbs/src/gplx/dbs/engines/postgres/Postgres_conn_info.java create mode 100644 140_dbs/src/gplx/dbs/engines/postgres/Postgres_engine.java create mode 100644 140_dbs/src/gplx/dbs/engines/sqlite/Sqlite_conn_info.java create mode 100644 140_dbs/src/gplx/dbs/engines/sqlite/Sqlite_engine.java create mode 100644 140_dbs/src/gplx/dbs/engines/sqlite/Sqlite_engine_.java create mode 100644 140_dbs/src/gplx/dbs/engines/sqlite/Sqlite_schema_mgr.java create mode 100644 140_dbs/src/gplx/dbs/engines/sqlite/Sqlite_txn_mgr.java create mode 100644 140_dbs/src/gplx/dbs/engines/tdbs/TdbConnectInfo_tst.java create mode 100644 140_dbs/src/gplx/dbs/engines/tdbs/TdbDatabase.java create mode 100644 140_dbs/src/gplx/dbs/engines/tdbs/TdbDbLoadMgr.java create mode 100644 140_dbs/src/gplx/dbs/engines/tdbs/TdbDbLoadMgr_tst.java create mode 100644 140_dbs/src/gplx/dbs/engines/tdbs/TdbDbSaveMgr.java create mode 100644 140_dbs/src/gplx/dbs/engines/tdbs/TdbDbSaveMgr_tst.java create mode 100644 140_dbs/src/gplx/dbs/engines/tdbs/TdbDelete.java create mode 100644 140_dbs/src/gplx/dbs/engines/tdbs/TdbEngine.java create mode 100644 140_dbs/src/gplx/dbs/engines/tdbs/TdbFile.java create mode 100644 140_dbs/src/gplx/dbs/engines/tdbs/TdbFileList.java create mode 100644 140_dbs/src/gplx/dbs/engines/tdbs/TdbFlush.java create mode 100644 140_dbs/src/gplx/dbs/engines/tdbs/TdbFlush_tst.java create mode 100644 140_dbs/src/gplx/dbs/engines/tdbs/TdbInsert.java create mode 100644 140_dbs/src/gplx/dbs/engines/tdbs/TdbSelect.java create mode 100644 140_dbs/src/gplx/dbs/engines/tdbs/TdbStores.java create mode 100644 140_dbs/src/gplx/dbs/engines/tdbs/TdbTable.java create mode 100644 140_dbs/src/gplx/dbs/engines/tdbs/TdbTableList.java create mode 100644 140_dbs/src/gplx/dbs/engines/tdbs/TdbUpdate.java create mode 100644 140_dbs/src/gplx/dbs/engines/tdbs/Tdb_conn_info.java create mode 100644 140_dbs/src/gplx/dbs/metas/Meta_fld_itm.java create mode 100644 140_dbs/src/gplx/dbs/metas/Meta_fld_mgr.java create mode 100644 140_dbs/src/gplx/dbs/metas/Meta_idx_itm.java create mode 100644 140_dbs/src/gplx/dbs/metas/Meta_idx_mgr.java create mode 100644 140_dbs/src/gplx/dbs/metas/Meta_itm_tid.java create mode 100644 140_dbs/src/gplx/dbs/metas/Meta_tbl_itm.java create mode 100644 140_dbs/src/gplx/dbs/metas/Meta_tbl_mgr.java create mode 100644 140_dbs/src/gplx/dbs/metas/Meta_type_itm.java create mode 100644 140_dbs/src/gplx/dbs/metas/parsers/Meta_fld_wkr__base.java create mode 100644 140_dbs/src/gplx/dbs/metas/parsers/Meta_parser__fld.java create mode 100644 140_dbs/src/gplx/dbs/metas/parsers/Meta_parser__fld_tst.java create mode 100644 140_dbs/src/gplx/dbs/metas/parsers/Meta_parser__tbl.java create mode 100644 140_dbs/src/gplx/dbs/metas/parsers/Meta_parser__tbl_tst.java create mode 100644 140_dbs/src/gplx/dbs/metas/parsers/Sql_bry_rdr.java create mode 100644 140_dbs/src/gplx/dbs/metas/parsers/Sql_bry_rdr_tst.java create mode 100644 140_dbs/src/gplx/dbs/qrys/Db_arg.java create mode 100644 140_dbs/src/gplx/dbs/qrys/Db_qry__select_cmd.java create mode 100644 140_dbs/src/gplx/dbs/qrys/Db_qry__select_in_tbl.java create mode 100644 140_dbs/src/gplx/dbs/qrys/Db_qry_arg_owner.java create mode 100644 140_dbs/src/gplx/dbs/qrys/Db_qry_delete.java create mode 100644 140_dbs/src/gplx/dbs/qrys/Db_qry_dml_tst.java create mode 100644 140_dbs/src/gplx/dbs/qrys/Db_qry_flush.java create mode 100644 140_dbs/src/gplx/dbs/qrys/Db_qry_insert.java create mode 100644 140_dbs/src/gplx/dbs/qrys/Db_qry_select_tst.java create mode 100644 140_dbs/src/gplx/dbs/qrys/Db_qry_sql.java create mode 100644 140_dbs/src/gplx/dbs/qrys/Db_qry_sql_tst.java create mode 100644 140_dbs/src/gplx/dbs/qrys/Db_qry_update.java create mode 100644 140_dbs/src/gplx/dbs/qrys/Db_stmt_cmd.java create mode 100644 140_dbs/src/gplx/dbs/qrys/Db_stmt_sql.java create mode 100644 140_dbs/src/gplx/dbs/qrys/Db_stmt_sql_tst.java create mode 100644 140_dbs/src/gplx/dbs/qrys/Db_val_type.java create mode 100644 140_dbs/src/gplx/dbs/sqls/Db_fld.java create mode 100644 140_dbs/src/gplx/dbs/sqls/Db_obj_ary_crt.java create mode 100644 140_dbs/src/gplx/dbs/sqls/Db_obj_ary_tst.java create mode 100644 140_dbs/src/gplx/dbs/sqls/Db_sqlbldr__sqlite.java create mode 100644 140_dbs/src/gplx/dbs/sqls/Db_sqlbldr_tst.java create mode 100644 140_dbs/src/gplx/dbs/sqls/Sql_from.java create mode 100644 140_dbs/src/gplx/dbs/sqls/Sql_group_by.java create mode 100644 140_dbs/src/gplx/dbs/sqls/Sql_join_itm.java create mode 100644 140_dbs/src/gplx/dbs/sqls/Sql_join_itmType.java create mode 100644 140_dbs/src/gplx/dbs/sqls/Sql_order_by.java create mode 100644 140_dbs/src/gplx/dbs/sqls/Sql_order_by_itm.java create mode 100644 140_dbs/src/gplx/dbs/sqls/Sql_order_by_sorter.java create mode 100644 140_dbs/src/gplx/dbs/sqls/Sql_qry_wtr.java create mode 100644 140_dbs/src/gplx/dbs/sqls/Sql_qry_wtr_.java create mode 100644 140_dbs/src/gplx/dbs/sqls/Sql_qry_wtr_ansi.java create mode 100644 140_dbs/src/gplx/dbs/sqls/Sql_qry_wtr_ansi_tst.java create mode 100644 140_dbs/src/gplx/dbs/sqls/Sql_qry_wtr_iosql_tst.java create mode 100644 140_dbs/src/gplx/dbs/sqls/Sql_qry_wtr_tst.java create mode 100644 140_dbs/src/gplx/dbs/sqls/Sql_select.java create mode 100644 140_dbs/src/gplx/dbs/sqls/Sql_select_fld_.java create mode 100644 140_dbs/src/gplx/dbs/sqls/Sql_select_fld_base.java create mode 100644 140_dbs/src/gplx/dbs/sqls/Sql_select_fld_list.java create mode 100644 140_dbs/src/gplx/dbs/sqls/Sql_tbl_src.java create mode 100644 140_dbs/src/gplx/dbs/utls/Db_cmd_backup.java create mode 100644 140_dbs/src/gplx/dbs/utls/Db_cmd_backup_tst.java create mode 100644 140_dbs/src/gplx/dbs/utls/Db_in_wkr__base.java create mode 100644 140_dbs/src/gplx/dbs/utls/PoolIds.java create mode 100644 140_dbs/src/gplx/dbs/utls/PoolIds_tst.java create mode 100644 140_dbs/src/gplx/stores/DbMaprArg.java create mode 100644 140_dbs/src/gplx/stores/DbMaprItm.java create mode 100644 140_dbs/src/gplx/stores/DbMaprMgr.java create mode 100644 140_dbs/src/gplx/stores/DbMaprMgr_tst.java create mode 100644 140_dbs/src/gplx/stores/DbMaprRdr.java create mode 100644 140_dbs/src/gplx/stores/DbMaprWtr.java create mode 100644 140_dbs/src/gplx/stores/Db_data_rdr.java create mode 100644 140_dbs/src/gplx/stores/Db_data_rdr_.java create mode 100644 140_dbs/src/gplx/stores/MockDiscObj.java create mode 100644 140_dbs/tst/gplx/dbs/DbTstDat.java create mode 100644 140_dbs/tst/gplx/dbs/DbTstRow.java create mode 100644 140_dbs/tst/gplx/dbs/Db_conn_fxt.java create mode 100644 140_dbs/tst/gplx/dbs/Db_qry_fxt.java create mode 100644 140_dbs/tst/gplx/dbs/GfoNdeTstr.java create mode 100644 140_dbs/tst/gplx/dbs/engines/db_CrudOps_tst.java create mode 100644 140_dbs/tst/gplx/dbs/engines/db_DataTypes_tst.java create mode 100644 140_dbs/tst/gplx/dbs/groupBys/GroupBys_base_tst.java create mode 100644 140_dbs/tst/gplx/dbs/groupBys/GroupBys_mysql_tst.java create mode 100644 140_dbs/tst/gplx/dbs/groupBys/GroupBys_tdb_tst.java create mode 100644 140_dbs/tst/gplx/dbs/insertIntos/InsertIntos_base_tst.java create mode 100644 140_dbs/tst/gplx/dbs/insertIntos/InsertIntos_mysql_tst.java create mode 100644 140_dbs/tst/gplx/dbs/insertIntos/InsertIntos_tdb_tst.java create mode 100644 140_dbs/tst/gplx/dbs/joins/Joins_base_tst.java create mode 100644 140_dbs/tst/gplx/dbs/joins/Joins_tdb_tst.java create mode 100644 140_dbs/tst/gplx/dbs/orderBys/OrderBys_base_tst.java create mode 100644 140_dbs/tst/gplx/dbs/orderBys/OrderBys_tdb_tst.java create mode 100644 140_dbs/xtn/gplx/dbs/Bug_Utf8.java create mode 100644 140_dbs/xtn/gplx/dbs/SqliteDbMain.java create mode 100644 150_gfui/.classpath create mode 100644 150_gfui/.project create mode 100644 150_gfui/lib/swt.jar create mode 100644 150_gfui/src_100_basic/gplx/gfui/DirInt.java create mode 100644 150_gfui/src_100_basic/gplx/gfui/GfuiAlign.java create mode 100644 150_gfui/src_100_basic/gplx/gfui/GfuiAlign_.java create mode 100644 150_gfui/src_100_basic/gplx/gfui/GfuiAxisType.java create mode 100644 150_gfui/src_100_basic/gplx/gfui/GfuiBorderEdge.java create mode 100644 150_gfui/src_100_basic/gplx/gfui/PointAdp.java create mode 100644 150_gfui/src_100_basic/gplx/gfui/PointAdp_.java create mode 100644 150_gfui/src_100_basic/gplx/gfui/RectAdp.java create mode 100644 150_gfui/src_100_basic/gplx/gfui/RectAdpF.java create mode 100644 150_gfui/src_100_basic/gplx/gfui/RectAdp_.java create mode 100644 150_gfui/src_100_basic/gplx/gfui/SizeAdp.java create mode 100644 150_gfui/src_100_basic/gplx/gfui/SizeAdpF.java create mode 100644 150_gfui/src_100_basic/gplx/gfui/SizeAdpF_.java create mode 100644 150_gfui/src_100_basic/gplx/gfui/SizeAdp_.java create mode 100644 150_gfui/src_110_draw_core/gplx/gfui/ColorAdp.java create mode 100644 150_gfui/src_110_draw_core/gplx/gfui/ColorAdp_.java create mode 100644 150_gfui/src_110_draw_core/gplx/gfui/ColorAdp__tst.java create mode 100644 150_gfui/src_110_draw_core/gplx/gfui/FontAdp.java create mode 100644 150_gfui/src_110_draw_core/gplx/gfui/FontStyleAdp.java create mode 100644 150_gfui/src_110_draw_core/gplx/gfui/FontStyleAdp_.java create mode 100644 150_gfui/src_110_draw_core/gplx/gfui/PenAdp.java create mode 100644 150_gfui/src_110_draw_core/gplx/gfui/PenAdp_.java create mode 100644 150_gfui/src_110_draw_core/gplx/gfui/SolidBrushAdp.java create mode 100644 150_gfui/src_110_draw_core/gplx/gfui/SolidBrushAdp_.java create mode 100644 150_gfui/src_120_draw_objs/gplx/gfui/GfuiBorderMgr.java create mode 100644 150_gfui/src_120_draw_objs/gplx/gfui/GfxAdp.java create mode 100644 150_gfui/src_120_draw_objs/gplx/gfui/GfxAdpBase.java create mode 100644 150_gfui/src_120_draw_objs/gplx/gfui/GfxAdp_.java create mode 100644 150_gfui/src_120_draw_objs/gplx/gfui/GfxStringData.java create mode 100644 150_gfui/src_120_draw_objs/gplx/gfui/PaintArgs.java create mode 100644 150_gfui/src_200_ipt/gplx/gfui/IptArg.java create mode 100644 150_gfui/src_200_ipt/gplx/gfui/IptArgChainMgr_tst.java create mode 100644 150_gfui/src_200_ipt/gplx/gfui/IptArg_.java create mode 100644 150_gfui/src_200_ipt/gplx/gfui/IptBnd.java create mode 100644 150_gfui/src_200_ipt/gplx/gfui/IptBndMgr.java create mode 100644 150_gfui/src_200_ipt/gplx/gfui/IptBndMgr_tst.java create mode 100644 150_gfui/src_200_ipt/gplx/gfui/IptBnd_.java create mode 100644 150_gfui/src_200_ipt/gplx/gfui/IptBnd_chkBox.java create mode 100644 150_gfui/src_200_ipt/gplx/gfui/IptBnd_txt_cmd.java create mode 100644 150_gfui/src_200_ipt/gplx/gfui/IptBnd_txt_range.java create mode 100644 150_gfui/src_200_ipt/gplx/gfui/IptBnd_upDownRange.java create mode 100644 150_gfui/src_200_ipt/gplx/gfui/IptBndsOwner.java create mode 100644 150_gfui/src_200_ipt/gplx/gfui/IptCfg.java create mode 100644 150_gfui/src_200_ipt/gplx/gfui/IptCfgItm.java create mode 100644 150_gfui/src_200_ipt/gplx/gfui/IptCfgRegy.java create mode 100644 150_gfui/src_200_ipt/gplx/gfui/IptCfg_.java create mode 100644 150_gfui/src_200_ipt/gplx/gfui/IptCfg_tst.java create mode 100644 150_gfui/src_200_ipt/gplx/gfui/IptEventData.java create mode 100644 150_gfui/src_200_ipt/gplx/gfui/IptEventMgr.java create mode 100644 150_gfui/src_200_ipt/gplx/gfui/IptEventType.java create mode 100644 150_gfui/src_200_ipt/gplx/gfui/IptEventType_.java create mode 100644 150_gfui/src_200_ipt/gplx/gfui/IptEvtDataKey.java create mode 100644 150_gfui/src_200_ipt/gplx/gfui/IptEvtDataKeyHeld.java create mode 100644 150_gfui/src_200_ipt/gplx/gfui/IptEvtDataMouse.java create mode 100644 150_gfui/src_200_ipt/gplx/gfui/IptKey.java create mode 100644 150_gfui/src_200_ipt/gplx/gfui/IptKeyStrMgr.java create mode 100644 150_gfui/src_200_ipt/gplx/gfui/IptKeyStrMgr_tst.java create mode 100644 150_gfui/src_200_ipt/gplx/gfui/IptKey_.java create mode 100644 150_gfui/src_200_ipt/gplx/gfui/IptKey__tst.java create mode 100644 150_gfui/src_200_ipt/gplx/gfui/IptMouseBtn.java create mode 100644 150_gfui/src_200_ipt/gplx/gfui/IptMouseBtn_.java create mode 100644 150_gfui/src_200_ipt/gplx/gfui/IptMouseMove.java create mode 100644 150_gfui/src_200_ipt/gplx/gfui/IptMouseWheel.java create mode 100644 150_gfui/src_200_ipt/gplx/gfui/IptMouseWheel_.java create mode 100644 150_gfui/src_210_lyt/gplx/gfui/GftBand.java create mode 100644 150_gfui/src_210_lyt/gplx/gfui/GftBand_tst.java create mode 100644 150_gfui/src_210_lyt/gplx/gfui/GftCell.java create mode 100644 150_gfui/src_210_lyt/gplx/gfui/GftGrid.java create mode 100644 150_gfui/src_210_lyt/gplx/gfui/GftGrid_fx.java create mode 100644 150_gfui/src_210_lyt/gplx/gfui/GftItem.java create mode 100644 150_gfui/src_210_lyt/gplx/gfui/GftSizeCalc.java create mode 100644 150_gfui/src_300_gxw/gplx/gfui/GxwBoxListener.java create mode 100644 150_gfui/src_300_gxw/gplx/gfui/GxwCbkHost.java create mode 100644 150_gfui/src_300_gxw/gplx/gfui/GxwCbkHost_.java create mode 100644 150_gfui/src_300_gxw/gplx/gfui/GxwCheckListBox.java create mode 100644 150_gfui/src_300_gxw/gplx/gfui/GxwCheckListBox_lang.java create mode 100644 150_gfui/src_300_gxw/gplx/gfui/GxwComboBox.java create mode 100644 150_gfui/src_300_gxw/gplx/gfui/GxwComboBox_lang.java create mode 100644 150_gfui/src_300_gxw/gplx/gfui/GxwCore_base.java create mode 100644 150_gfui/src_300_gxw/gplx/gfui/GxwCore_lang.java create mode 100644 150_gfui/src_300_gxw/gplx/gfui/GxwCore_mock.java create mode 100644 150_gfui/src_300_gxw/gplx/gfui/GxwElem.java create mode 100644 150_gfui/src_300_gxw/gplx/gfui/GxwElemFactory_base.java create mode 100644 150_gfui/src_300_gxw/gplx/gfui/GxwElem_lang.java create mode 100644 150_gfui/src_300_gxw/gplx/gfui/GxwElem_mock_base.java create mode 100644 150_gfui/src_300_gxw/gplx/gfui/GxwListBox.java create mode 100644 150_gfui/src_300_gxw/gplx/gfui/GxwListBox_lang.java create mode 100644 150_gfui/src_300_gxw/gplx/gfui/GxwTextBox_lang.java create mode 100644 150_gfui/src_300_gxw/gplx/gfui/GxwTextFld.java create mode 100644 150_gfui/src_300_gxw/gplx/gfui/GxwTextHtml.java create mode 100644 150_gfui/src_300_gxw/gplx/gfui/GxwTextHtml_lang.java create mode 100644 150_gfui/src_300_gxw/gplx/gfui/GxwTextMemo_lang.java create mode 100644 150_gfui/src_300_gxw/gplx/gfui/GxwWin.java create mode 100644 150_gfui/src_300_gxw/gplx/gfui/GxwWin_lang.java create mode 100644 150_gfui/src_300_gxw/gplx/gfui/Gxw_html.java create mode 100644 150_gfui/src_300_gxw/gplx/gfui/Gxw_html_load_tid_.java create mode 100644 150_gfui/src_300_gxw/gplx/gfui/Gxw_tab_itm.java create mode 100644 150_gfui/src_300_gxw/gplx/gfui/Gxw_tab_mgr.java create mode 100644 150_gfui/src_300_gxw/gplx/gfui/MockForm.java create mode 100644 150_gfui/src_400_win/gplx/gfui/GfoConsoleWin.java create mode 100644 150_gfui/src_400_win/gplx/gfui/GfuiBnd_win_host.java create mode 100644 150_gfui/src_400_win/gplx/gfui/GfuiCmdForm.java create mode 100644 150_gfui/src_400_win/gplx/gfui/GfuiFocusOrderer.java create mode 100644 150_gfui/src_400_win/gplx/gfui/GfuiFocusXferBnd.java create mode 100644 150_gfui/src_400_win/gplx/gfui/GfuiForm_menu.java create mode 100644 150_gfui/src_400_win/gplx/gfui/GfuiMenuBar.java create mode 100644 150_gfui/src_400_win/gplx/gfui/GfuiMenuFormUtl.java create mode 100644 150_gfui/src_400_win/gplx/gfui/GfuiQuitMode.java create mode 100644 150_gfui/src_400_win/gplx/gfui/GfuiTipTextMgr.java create mode 100644 150_gfui/src_400_win/gplx/gfui/GfuiWin.java create mode 100644 150_gfui/src_400_win/gplx/gfui/GfuiWinFocusMgr.java create mode 100644 150_gfui/src_400_win/gplx/gfui/GfuiWinKeyCmdMgr.java create mode 100644 150_gfui/src_400_win/gplx/gfui/GfuiWin_.java create mode 100644 150_gfui/src_400_win/gplx/gfui/GfuiWin_toaster.java create mode 100644 150_gfui/src_400_win/gplx/gfui/GxwWinNpi.java create mode 100644 150_gfui/src_410_box_core/gplx/gfui/GfuiElem.java create mode 100644 150_gfui/src_410_box_core/gplx/gfui/GfuiElemBase.java create mode 100644 150_gfui/src_410_box_core/gplx/gfui/GfuiElemBase_.java create mode 100644 150_gfui/src_410_box_core/gplx/gfui/GfuiElemKeys.java create mode 100644 150_gfui/src_410_box_core/gplx/gfui/GfuiElemList.java create mode 100644 150_gfui/src_410_box_core/gplx/gfui/GfuiElem_.java create mode 100644 150_gfui/src_420_box_basic/gplx/gfui/GfuiBtn.java create mode 100644 150_gfui/src_420_box_basic/gplx/gfui/GfuiBtnClickBnd.java create mode 100644 150_gfui/src_420_box_basic/gplx/gfui/GfuiBtn_.java create mode 100644 150_gfui/src_420_box_basic/gplx/gfui/GfuiChkBox.java create mode 100644 150_gfui/src_420_box_basic/gplx/gfui/GfuiChkBox_.java create mode 100644 150_gfui/src_420_box_basic/gplx/gfui/GfuiComboBox.java create mode 100644 150_gfui/src_420_box_basic/gplx/gfui/GfuiLbl.java create mode 100644 150_gfui/src_420_box_basic/gplx/gfui/GfuiLbl_.java create mode 100644 150_gfui/src_420_box_basic/gplx/gfui/GfuiListBox.java create mode 100644 150_gfui/src_420_box_basic/gplx/gfui/GfuiTextBox.java create mode 100644 150_gfui/src_420_box_basic/gplx/gfui/GfuiTextBox_.java create mode 100644 150_gfui/src_420_box_basic/gplx/gfui/GfuiTextMemo.java create mode 100644 150_gfui/src_420_box_basic/gplx/gfui/Gfui_html.java create mode 100644 150_gfui/src_420_box_basic/gplx/gfui/Gfui_tab_itm.java create mode 100644 150_gfui/src_420_box_basic/gplx/gfui/Gfui_tab_itm_data.java create mode 100644 150_gfui/src_420_box_basic/gplx/gfui/Gfui_tab_itm_data_tst.java create mode 100644 150_gfui/src_420_box_basic/gplx/gfui/Gfui_tab_mgr.java create mode 100644 150_gfui/src_430_box_custom/gplx/gfui/DataBndr_whenEvt_execCmd.java create mode 100644 150_gfui/src_430_box_custom/gplx/gfui/GfuiBnd_box_status.java create mode 100644 150_gfui/src_430_box_custom/gplx/gfui/GfuiCheckListBox.java create mode 100644 150_gfui/src_430_box_custom/gplx/gfui/GfuiCheckListPanel.java create mode 100644 150_gfui/src_430_box_custom/gplx/gfui/GfuiFormPanel.java create mode 100644 150_gfui/src_430_box_custom/gplx/gfui/GfuiIoDialogUtl.java create mode 100644 150_gfui/src_430_box_custom/gplx/gfui/GfuiIoUrlSelectBox.java create mode 100644 150_gfui/src_430_box_custom/gplx/gfui/GfuiIoUrlSelectBox_.java create mode 100644 150_gfui/src_430_box_custom/gplx/gfui/GfuiMoveElemBnd.java create mode 100644 150_gfui/src_430_box_custom/gplx/gfui/GfuiMoveElemBtn.java create mode 100644 150_gfui/src_430_box_custom/gplx/gfui/GfuiStatusBar.java create mode 100644 150_gfui/src_430_box_custom/gplx/gfui/GfuiStatusBarBnd.java create mode 100644 150_gfui/src_430_box_custom/gplx/gfui/GfuiStatusBox.java create mode 100644 150_gfui/src_430_box_custom/gplx/gfui/GfuiStatusBoxBnd.java create mode 100644 150_gfui/src_500_tab/gplx/gfui/TabBnd.java create mode 100644 150_gfui/src_500_tab/gplx/gfui/TabBox.java create mode 100644 150_gfui/src_500_tab/gplx/gfui/TabBoxEvt_orderChanged.java create mode 100644 150_gfui/src_500_tab/gplx/gfui/TabBoxEvt_tabSelect.java create mode 100644 150_gfui/src_500_tab/gplx/gfui/TabBoxMgr.java create mode 100644 150_gfui/src_500_tab/gplx/gfui/TabBox_.java create mode 100644 150_gfui/src_500_tab/gplx/gfui/TabPnlItm.java create mode 100644 150_gfui/src_600_adp/gplx/gfui/ClipboardAdp_.java create mode 100644 150_gfui/src_600_adp/gplx/gfui/CursorAdp.java create mode 100644 150_gfui/src_600_adp/gplx/gfui/IconAdp.java create mode 100644 150_gfui/src_600_adp/gplx/gfui/ImageAdp.java create mode 100644 150_gfui/src_600_adp/gplx/gfui/ImageAdp_.java create mode 100644 150_gfui/src_600_adp/gplx/gfui/ImageAdp_base.java create mode 100644 150_gfui/src_600_adp/gplx/gfui/ImageAdp_null.java create mode 100644 150_gfui/src_600_adp/gplx/gfui/ScreenAdp.java create mode 100644 150_gfui/src_600_adp/gplx/gfui/ScreenAdp_.java create mode 100644 150_gfui/src_600_adp/gplx/gfui/TimerAdp.java create mode 100644 150_gfui/src_700_env/gplx/gfui/GfoFactory_gfui.java create mode 100644 150_gfui/src_700_env/gplx/gfui/GfsLibIni_gfui.java create mode 100644 150_gfui/src_700_env/gplx/gfui/GfuiEnv_.java create mode 100644 150_gfui/src_700_env/gplx/gfui/GfuiInvkCmd.java create mode 100644 150_gfui/src_700_env/gplx/gfui/Gfui_clipboard.java create mode 100644 150_gfui/src_700_env/gplx/gfui/Gfui_clipboard_.java create mode 100644 150_gfui/src_700_env/gplx/gfui/Gfui_dlg_file.java create mode 100644 150_gfui/src_700_env/gplx/gfui/Gfui_dlg_msg.java create mode 100644 150_gfui/src_700_env/gplx/gfui/Gfui_dlg_msg_.java create mode 100644 150_gfui/src_700_env/gplx/gfui/Gfui_kit.java create mode 100644 150_gfui/src_700_env/gplx/gfui/Gfui_kit_.java create mode 100644 150_gfui/src_700_env/gplx/gfui/Gfui_kit_base.java create mode 100644 150_gfui/src_700_env/gplx/gfui/Gfui_mnu_grp.java create mode 100644 150_gfui/src_700_env/gplx/gfui/Gfui_mnu_itm.java create mode 100644 150_gfui/src_700_env/gplx/gfui/Gfui_mnu_itm_.java create mode 100644 150_gfui/src_700_env/gplx/gfui/Mem_html.java create mode 100644 150_gfui/src_700_env/gplx/gfui/Mem_kit.java create mode 100644 150_gfui/src_700_env/gplx/gfui/Swing_kit.java create mode 100644 150_gfui/src_700_env/gplx/gfui/Swt_kit.java create mode 100644 150_gfui/src_700_env/gplx/gfui/TxtFindMgr.java create mode 100644 150_gfui/tst/gplx/gfui/ClipboardAdp__tst.java create mode 100644 150_gfui/tst/gplx/gfui/GfuiBorderMgr_tst.java create mode 100644 150_gfui/tst/gplx/gfui/GfuiClickKeyMgr_tst.java create mode 100644 150_gfui/tst/gplx/gfui/GfuiFocusOrderer_tst.java create mode 100644 150_gfui/tst/gplx/gfui/GfuiMoveElemBtn_tst.java create mode 100644 150_gfui/tst/gplx/gfui/GfxAdpMok.java create mode 100644 150_gfui/tst/gplx/gfui/GfxItm.java create mode 100644 150_gfui/tst/gplx/gfui/GfxItmList.java create mode 100644 150_gfui/tst/gplx/gfui/GfxItm_base.java create mode 100644 150_gfui/tst/gplx/gfui/GfxLineItm.java create mode 100644 150_gfui/tst/gplx/gfui/GfxRectItm.java create mode 100644 150_gfui/tst/gplx/gfui/GfxStringItm.java create mode 100644 150_gfui/tst/gplx/gfui/ImageAdp_tst.java create mode 100644 150_gfui/tst/gplx/gfui/IptArg_parser_tst.java create mode 100644 150_gfui/tst/gplx/gfui/IptEventType_tst.java create mode 100644 150_gfui/tst/gplx/gfui/ScreenAdp_tst.java create mode 100644 150_gfui/tst/gplx/gfui/TabBox_tst.java create mode 100644 150_gfui/xtn/gplx/gfui/Swt_app_browser.java create mode 100644 150_gfui/xtn/gplx/gfui/Swt_app_main.java create mode 100644 150_gfui/xtn/gplx/gfui/Swt_btn.java create mode 100644 150_gfui/xtn/gplx/gfui/Swt_clipboard.java create mode 100644 150_gfui/xtn/gplx/gfui/Swt_control.java create mode 100644 150_gfui/xtn/gplx/gfui/Swt_core_cmds.java create mode 100644 150_gfui/xtn/gplx/gfui/Swt_core_lnrs.java create mode 100644 150_gfui/xtn/gplx/gfui/Swt_dlg_msg.java create mode 100644 150_gfui/xtn/gplx/gfui/Swt_html.java create mode 100644 150_gfui/xtn/gplx/gfui/Swt_img.java create mode 100644 150_gfui/xtn/gplx/gfui/Swt_lbl.java create mode 100644 150_gfui/xtn/gplx/gfui/Swt_popup_grp.java create mode 100644 150_gfui/xtn/gplx/gfui/Swt_tab_itm.java create mode 100644 150_gfui/xtn/gplx/gfui/Swt_tab_mgr.java create mode 100644 150_gfui/xtn/gplx/gfui/Swt_text.java create mode 100644 150_gfui/xtn/gplx/gfui/Swt_text_w_border.java create mode 100644 150_gfui/xtn/gplx/gfui/Swt_win.java create mode 100644 400_xowa/.classpath create mode 100644 400_xowa/.project create mode 100644 400_xowa/lib/jtidy_xowa.jar create mode 100644 400_xowa/lib/luaj_xowa.jar create mode 100644 400_xowa/src/gplx/cache/Gfo_cache_mgr_base.java create mode 100644 400_xowa/src/gplx/cache/Gfo_cache_mgr_bry.java create mode 100644 400_xowa/src/gplx/core/brys/Bit_.java create mode 100644 400_xowa/src/gplx/core/brys/Bit__tst.java create mode 100644 400_xowa/src/gplx/core/brys/Bry_bldr.java create mode 100644 400_xowa/src/gplx/core/brys/Bry_comparer.java create mode 100644 400_xowa/src/gplx/core/brys/Bry_rdr_tst.java create mode 100644 400_xowa/src/gplx/core/btries/Btrie_utf8_mgr_tst.java create mode 100644 400_xowa/src/gplx/core/enums/Gfo_enum_grp.java create mode 100644 400_xowa/src/gplx/core/flds/Gfo_fld_base.java create mode 100644 400_xowa/src/gplx/core/flds/Gfo_fld_rdr.java create mode 100644 400_xowa/src/gplx/core/flds/Gfo_fld_rdr_tst.java create mode 100644 400_xowa/src/gplx/core/flds/Gfo_fld_wtr.java create mode 100644 400_xowa/src/gplx/core/html/parsers/Gfo_html_node.java create mode 100644 400_xowa/src/gplx/core/html/parsers/Gfo_html_parser.java create mode 100644 400_xowa/src/gplx/core/html/parsers/Gfo_html_wkr.java create mode 100644 400_xowa/src/gplx/core/html/parsers/Xob_html_tkn.java create mode 100644 400_xowa/src/gplx/core/ints/Int_ary_bldr.java create mode 100644 400_xowa/src/gplx/core/lists/Binary_search_.java create mode 100644 400_xowa/src/gplx/core/lists/Binary_search__tst.java create mode 100644 400_xowa/src/gplx/core/net/Http_client_rdr.java create mode 100644 400_xowa/src/gplx/core/net/Http_client_rdr_.java create mode 100644 400_xowa/src/gplx/core/net/Http_client_rdr__stream.java create mode 100644 400_xowa/src/gplx/core/net/Http_client_wtr.java create mode 100644 400_xowa/src/gplx/core/net/Http_client_wtr_.java create mode 100644 400_xowa/src/gplx/core/net/Http_client_wtr__stream.java create mode 100644 400_xowa/src/gplx/core/net/Http_post_data_hash.java create mode 100644 400_xowa/src/gplx/core/net/Http_post_data_itm.java create mode 100644 400_xowa/src/gplx/core/net/Http_request_itm.java create mode 100644 400_xowa/src/gplx/core/net/Http_request_parser.java create mode 100644 400_xowa/src/gplx/core/net/Http_request_parser_tst.java create mode 100644 400_xowa/src/gplx/core/net/Http_server_wtr.java create mode 100644 400_xowa/src/gplx/core/net/Http_server_wtr_.java create mode 100644 400_xowa/src/gplx/core/net/Http_server_wtr__console.java create mode 100644 400_xowa/src/gplx/core/net/Socket_adp.java create mode 100644 400_xowa/src/gplx/core/net/Socket_adp__base.java create mode 100644 400_xowa/src/gplx/core/regxs/Gfo_pattern.java create mode 100644 400_xowa/src/gplx/core/regxs/Gfo_pattern_ctx.java create mode 100644 400_xowa/src/gplx/core/regxs/Gfo_pattern_itm.java create mode 100644 400_xowa/src/gplx/core/regxs/Gfo_pattern_itm_.java create mode 100644 400_xowa/src/gplx/core/regxs/Gfo_pattern_tst.java create mode 100644 400_xowa/src/gplx/core/threads/Gfo_async_cmd_itm.java create mode 100644 400_xowa/src/gplx/core/threads/Gfo_async_cmd_mkr.java create mode 100644 400_xowa/src/gplx/core/threads/Gfo_async_mgr.java create mode 100644 400_xowa/src/gplx/core/threads/Gfo_thread_cmd.java create mode 100644 400_xowa/src/gplx/core/threads/Gfo_thread_cmd_.java create mode 100644 400_xowa/src/gplx/core/threads/Gfo_thread_cmd_base.java create mode 100644 400_xowa/src/gplx/core/threads/Gfo_thread_cmd_download.java create mode 100644 400_xowa/src/gplx/core/threads/Gfo_thread_cmd_replace.java create mode 100644 400_xowa/src/gplx/core/threads/Gfo_thread_cmd_unzip.java create mode 100644 400_xowa/src/gplx/core/threads/Gfo_thread_pool.java create mode 100644 400_xowa/src/gplx/core/threads/Gfo_thread_wkr.java create mode 100644 400_xowa/src/gplx/core/xmls/Gfo_xml_wtr.java create mode 100644 400_xowa/src/gplx/core/xmls/Gfo_xml_wtr_tst.java create mode 100644 400_xowa/src/gplx/dbs/Db_attach_cmd.java create mode 100644 400_xowa/src/gplx/dbs/Db_attach_rdr.java create mode 100644 400_xowa/src/gplx/dbs/cfgs/Db_cfg_hash.java create mode 100644 400_xowa/src/gplx/dbs/cfgs/Db_cfg_itm.java create mode 100644 400_xowa/src/gplx/dbs/cfgs/Db_cfg_tbl.java create mode 100644 400_xowa/src/gplx/dbs/metas/Schema_db_mgr.java create mode 100644 400_xowa/src/gplx/dbs/metas/Schema_loader_mgr.java create mode 100644 400_xowa/src/gplx/dbs/metas/Schema_loader_mgr_.java create mode 100644 400_xowa/src/gplx/dbs/metas/updates/Schema_update_cmd.java create mode 100644 400_xowa/src/gplx/dbs/metas/updates/Schema_update_cmd_.java create mode 100644 400_xowa/src/gplx/dbs/metas/updates/Schema_update_mgr.java create mode 100644 400_xowa/src/gplx/dbs/metas/updates/Schema_update_mgr_tst.java create mode 100644 400_xowa/src/gplx/fsdb/Fsdb_db_file.java create mode 100644 400_xowa/src/gplx/fsdb/Fsdb_db_mgr.java create mode 100644 400_xowa/src/gplx/fsdb/Fsdb_db_mgr_.java create mode 100644 400_xowa/src/gplx/fsdb/Fsdb_db_mgr__v1.java create mode 100644 400_xowa/src/gplx/fsdb/Fsdb_db_mgr__v2.java create mode 100644 400_xowa/src/gplx/fsdb/Fsdb_db_mgr__v2_bldr.java create mode 100644 400_xowa/src/gplx/fsdb/data/Fsd_bin_tbl.java create mode 100644 400_xowa/src/gplx/fsdb/data/Fsd_dir_itm.java create mode 100644 400_xowa/src/gplx/fsdb/data/Fsd_dir_tbl.java create mode 100644 400_xowa/src/gplx/fsdb/data/Fsd_fil_itm.java create mode 100644 400_xowa/src/gplx/fsdb/data/Fsd_fil_tbl.java create mode 100644 400_xowa/src/gplx/fsdb/data/Fsd_img_itm.java create mode 100644 400_xowa/src/gplx/fsdb/data/Fsd_thm_itm.java create mode 100644 400_xowa/src/gplx/fsdb/data/Fsd_thm_tbl.java create mode 100644 400_xowa/src/gplx/fsdb/data/Fsd_thm_tbl_tst.java create mode 100644 400_xowa/src/gplx/fsdb/meta/Fsm_atr_fil.java create mode 100644 400_xowa/src/gplx/fsdb/meta/Fsm_atr_mgr.java create mode 100644 400_xowa/src/gplx/fsdb/meta/Fsm_atr_tbl.java create mode 100644 400_xowa/src/gplx/fsdb/meta/Fsm_bin_fil.java create mode 100644 400_xowa/src/gplx/fsdb/meta/Fsm_bin_mgr.java create mode 100644 400_xowa/src/gplx/fsdb/meta/Fsm_bin_tbl.java create mode 100644 400_xowa/src/gplx/fsdb/meta/Fsm_cfg_mgr.java create mode 100644 400_xowa/src/gplx/fsdb/meta/Fsm_id_itm.java create mode 100644 400_xowa/src/gplx/fsdb/meta/Fsm_mnt_itm.java create mode 100644 400_xowa/src/gplx/fsdb/meta/Fsm_mnt_mgr.java create mode 100644 400_xowa/src/gplx/fsdb/meta/Fsm_mnt_tbl.java create mode 100644 400_xowa/src/gplx/gfs/Gfs_lxr.java create mode 100644 400_xowa/src/gplx/gfs/Gfs_lxr_.java create mode 100644 400_xowa/src/gplx/gfs/Gfs_msg_bldr.java create mode 100644 400_xowa/src/gplx/gfs/Gfs_msg_bldr_tst.java create mode 100644 400_xowa/src/gplx/gfs/Gfs_nde.java create mode 100644 400_xowa/src/gplx/gfs/Gfs_parser.java create mode 100644 400_xowa/src/gplx/gfs/Gfs_parser_ctx.java create mode 100644 400_xowa/src/gplx/gfs/Gfs_parser_tst.java create mode 100644 400_xowa/src/gplx/gfs/Gfs_wtr.java create mode 100644 400_xowa/src/gplx/gfui/Gfui_bnd_parser.java create mode 100644 400_xowa/src/gplx/gfui/Gfui_bnd_parser_tst.java create mode 100644 400_xowa/src/gplx/html/Html_atr_.java create mode 100644 400_xowa/src/gplx/html/Html_entity_.java create mode 100644 400_xowa/src/gplx/html/Html_nde.java create mode 100644 400_xowa/src/gplx/html/Html_parser.java create mode 100644 400_xowa/src/gplx/html/Html_parser_tst.java create mode 100644 400_xowa/src/gplx/html/Html_selecter.java create mode 100644 400_xowa/src/gplx/html/Html_tag_.java create mode 100644 400_xowa/src/gplx/html/Html_utl.java create mode 100644 400_xowa/src/gplx/html/Html_utl_tst.java create mode 100644 400_xowa/src/gplx/html/Html_wtr.java create mode 100644 400_xowa/src/gplx/intl/Gfo_app.java create mode 100644 400_xowa/src/gplx/intl/Gfo_i18n_itm.java create mode 100644 400_xowa/src/gplx/intl/Gfo_i18n_mgr.java create mode 100644 400_xowa/src/gplx/intl/Gfo_i18n_val_cmd.java create mode 100644 400_xowa/src/gplx/intl/String_surrogate_utl.java create mode 100644 400_xowa/src/gplx/intl/String_surrogate_utl_tst.java create mode 100644 400_xowa/src/gplx/ios/Io_stream_rdr_process.java create mode 100644 400_xowa/src/gplx/ios/Io_stream_zip_mgr.java create mode 100644 400_xowa/src/gplx/json/Json_doc.java create mode 100644 400_xowa/src/gplx/json/Json_doc_bldr.java create mode 100644 400_xowa/src/gplx/json/Json_doc_srl.java create mode 100644 400_xowa/src/gplx/json/Json_doc_tst.java create mode 100644 400_xowa/src/gplx/json/Json_doc_wtr.java create mode 100644 400_xowa/src/gplx/json/Json_factory.java create mode 100644 400_xowa/src/gplx/json/Json_grp.java create mode 100644 400_xowa/src/gplx/json/Json_itm.java create mode 100644 400_xowa/src/gplx/json/Json_itm_.java create mode 100644 400_xowa/src/gplx/json/Json_itm_ary.java create mode 100644 400_xowa/src/gplx/json/Json_itm_base.java create mode 100644 400_xowa/src/gplx/json/Json_itm_int.java create mode 100644 400_xowa/src/gplx/json/Json_itm_kv.java create mode 100644 400_xowa/src/gplx/json/Json_itm_nde.java create mode 100644 400_xowa/src/gplx/json/Json_itm_tmp.java create mode 100644 400_xowa/src/gplx/json/Json_kv_ary_srl.java create mode 100644 400_xowa/src/gplx/json/Json_kv_ary_srl_tst.java create mode 100644 400_xowa/src/gplx/json/Json_parser.java create mode 100644 400_xowa/src/gplx/json/Json_parser_tst.java create mode 100644 400_xowa/src/gplx/json/Json_wtr.java create mode 100644 400_xowa/src/gplx/json/Json_wtr_tst.java create mode 100644 400_xowa/src/gplx/php/Php_ctx.java create mode 100644 400_xowa/src/gplx/php/Php_evaluator.java create mode 100644 400_xowa/src/gplx/php/Php_itm.java create mode 100644 400_xowa/src/gplx/php/Php_itm_.java create mode 100644 400_xowa/src/gplx/php/Php_itm_ary.java create mode 100644 400_xowa/src/gplx/php/Php_itm_int.java create mode 100644 400_xowa/src/gplx/php/Php_itm_kv.java create mode 100644 400_xowa/src/gplx/php/Php_itm_quote.java create mode 100644 400_xowa/src/gplx/php/Php_itm_sub.java create mode 100644 400_xowa/src/gplx/php/Php_key.java create mode 100644 400_xowa/src/gplx/php/Php_line.java create mode 100644 400_xowa/src/gplx/php/Php_line_assign.java create mode 100644 400_xowa/src/gplx/php/Php_lxr.java create mode 100644 400_xowa/src/gplx/php/Php_parser.java create mode 100644 400_xowa/src/gplx/php/Php_parser_tst.java create mode 100644 400_xowa/src/gplx/php/Php_srl_itm.java create mode 100644 400_xowa/src/gplx/php/Php_srl_parser.java create mode 100644 400_xowa/src/gplx/php/Php_srl_parser_tst.java create mode 100644 400_xowa/src/gplx/php/Php_text_itm.java create mode 100644 400_xowa/src/gplx/php/Php_text_itm_parser.java create mode 100644 400_xowa/src/gplx/php/Php_text_itm_tst.java create mode 100644 400_xowa/src/gplx/php/Php_tkn.java create mode 100644 400_xowa/src/gplx/php/Php_tkn_factory.java create mode 100644 400_xowa/src/gplx/php/Php_tkn_wkr.java create mode 100644 400_xowa/src/gplx/srls/dsvs/Dsv_fld_parser.java create mode 100644 400_xowa/src/gplx/srls/dsvs/Dsv_fld_parser_.java create mode 100644 400_xowa/src/gplx/srls/dsvs/Dsv_tbl_parser.java create mode 100644 400_xowa/src/gplx/srls/dsvs/Dsv_tbl_parser_int_tst.java create mode 100644 400_xowa/src/gplx/srls/dsvs/Dsv_tbl_parser_str_tst.java create mode 100644 400_xowa/src/gplx/srls/dsvs/Dsv_wkr_base.java create mode 100644 400_xowa/src/gplx/xowa/Xoa_app.java create mode 100644 400_xowa/src/gplx/xowa/Xoa_app_.java create mode 100644 400_xowa/src/gplx/xowa/Xoa_app_fxt.java create mode 100644 400_xowa/src/gplx/xowa/Xoa_consts.java create mode 100644 400_xowa/src/gplx/xowa/Xoa_test_.java create mode 100644 400_xowa/src/gplx/xowa/Xoae_app.java create mode 100644 400_xowa/src/gplx/xowa/apis/Xoapi_doc.java create mode 100644 400_xowa/src/gplx/xowa/apis/Xoapi_root.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/Xoapi_app.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/Xoapi_bldr.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/Xoapi_gui.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/Xoapi_html.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/Xoapi_nav.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/Xoapi_net.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/Xoapi_special.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/Xoapi_usr.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/Xoapi_xtns.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/apps/Xoapi_fsys.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/bldrs/Xoapi_bldr_wiki.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/bldrs/filters/Xoapi_filter.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/bldrs/filters/dansguardians/Xoapi_dansguardian.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/bldrs/filters/titles/Xoapi_title.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/bldrs/imports/Xoapi_import.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/envs/Xoapi_env.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/gui/Xoapi_browser.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/gui/Xoapi_font.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/gui/Xoapi_page.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/gui/browsers/Xoapi_find.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/gui/browsers/Xoapi_html_box.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/gui/browsers/Xoapi_info.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/gui/browsers/Xoapi_prog.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/gui/browsers/Xoapi_prog_log.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/gui/browsers/Xoapi_search.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/gui/browsers/Xoapi_tabs.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/gui/browsers/Xoapi_url.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/gui/pages/Xoapi_edit.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/gui/pages/Xoapi_selection.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/gui/pages/Xoapi_view.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/html/Xoapi_modules.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/html/Xoapi_page.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/html/Xoapi_skins.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/html/Xoapi_tidy.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/html/Xoapi_toggle_itm.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/html/Xoapi_toggle_mgr.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/html/modules/Xoapi_collapsible.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/html/modules/Xoapi_navframe.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/html/modules/Xoapi_popups.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/html/modules/Xoapi_toc.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/html/skins/Xoapi_skin_app_base.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/navs/Xoapi_wiki.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/specials/Xoapi_search.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/startups/Xoapi_startups.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/startups/tabs/Xoapi_startup_tabs.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/startups/tabs/Xoapi_startup_tabs_tid_.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/usrs/Xoapi_bookmarks.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/usrs/Xoapi_cache.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/usrs/Xoapi_history.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/usrs/Xoapi_logs.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/xtns/Xoapi_scribunto.java create mode 100644 400_xowa/src/gplx/xowa/apis/xowa/xtns/Xoapi_wikibase.java create mode 100644 400_xowa/src/gplx/xowa/apps/Xoa_app_type.java create mode 100644 400_xowa/src/gplx/xowa/apps/Xoa_gfs_mgr.java create mode 100644 400_xowa/src/gplx/xowa/apps/Xoa_gfs_php_mgr.java create mode 100644 400_xowa/src/gplx/xowa/apps/Xoa_gfs_php_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa/apps/Xoa_shell.java create mode 100644 400_xowa/src/gplx/xowa/apps/Xoa_shell_tst.java create mode 100644 400_xowa/src/gplx/xowa/apps/Xoa_stage_.java create mode 100644 400_xowa/src/gplx/xowa/apps/Xoa_thread_.java create mode 100644 400_xowa/src/gplx/xowa/apps/Xoa_thread_mgr.java create mode 100644 400_xowa/src/gplx/xowa/apps/caches/Wdata_doc_cache.java create mode 100644 400_xowa/src/gplx/xowa/apps/caches/Xoa_cache_mgr.java create mode 100644 400_xowa/src/gplx/xowa/apps/fsys/Xoa_fsys_eval.java create mode 100644 400_xowa/src/gplx/xowa/apps/fsys/Xoa_fsys_mgr.java create mode 100644 400_xowa/src/gplx/xowa/apps/progs/Xoa_prog_mgr.java create mode 100644 400_xowa/src/gplx/xowa/apps/setups/Xoa_setup_mgr.java create mode 100644 400_xowa/src/gplx/xowa/apps/setups/Xoa_setup_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa/apps/versions/Xoa_version_.java create mode 100644 400_xowa/src/gplx/xowa/apps/versions/Xoa_version_tst.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/Db_idx_mode.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/Db_mgr_fxt.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/Xob_base_fxt.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/Xob_cmd.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/Xob_cmd_keys.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/Xob_cmd_mgr.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/Xob_db_file.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/Xob_fxt.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/Xob_ns_to_db_mgr.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/Xob_ns_to_db_wkr.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/aria2/Aria2_lib_mgr.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/aria2/Gfui_process_win.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cfgs/Xob_wiki_cfg_bldr.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cfgs/Xob_wiki_cfg_bldr_tst.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/Xob_dump_mgr_base.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/Xob_ns_file_itm.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/Xob_ns_file_itm_parser.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/Xob_parse_all_src_sql.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/ctgs/Uca_trie.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/ctgs/Uca_trie_tst.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/ctgs/Xob_category_registry_sql.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/ctgs/Xob_category_registry_sql_tst.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/ctgs/Xob_categorylinks_base.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/ctgs/Xob_categorylinks_base_tst.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/ctgs/Xob_categorylinks_sql.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/ctgs/Xob_categorylinks_sql_make.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/ctgs/Xob_categorylinks_sql_tst.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/ctgs/Xob_categorylinks_txt.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/ctgs/Xob_ctg_v1_base.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/ctgs/Xob_ctg_v1_base_tst.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/ctgs/Xob_ctg_v1_sql.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/ctgs/Xob_ctg_v1_sql_tst.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/ctgs/Xob_ctg_v1_txt.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/ctgs/Xob_sql_join_mgr.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/ctgs/Xoctg_hiddencat_parser_base.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/ctgs/Xoctg_hiddencat_parser_sql.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/ctgs/Xoctg_hiddencat_parser_sql_tst.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/ctgs/Xoctg_hiddencat_parser_txt.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/ctgs/Xoctg_hiddencat_ttl_wkr.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/ctgs/Xoctg_hiddencat_ttl_wkr_tst.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/ctgs/Xoctg_link_idx_wkr.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/ctgs/Xoctg_link_idx_wkr_tst.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/files/Xob_bin_db_itm.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/files/Xob_bin_db_mgr.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/files/Xob_diff_regy_exec_cmd.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/files/Xob_diff_regy_exec_cmd_tst.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/files/Xob_diff_regy_make_cmd.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/files/Xob_fsdb_make_cmd.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/files/Xob_fsdb_reduce_cmd.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/files/Xob_lnki_regy_cmd.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/files/Xob_lnki_regy_tbl.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/files/Xob_lnki_src_tid.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/files/Xob_lnki_temp_tbl.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/files/Xob_lnki_temp_wkr.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/files/Xob_lnki_temp_wkr_tst.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/files/Xob_orig_regy_cmd.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/files/Xob_orig_regy_tbl.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/files/Xob_orig_regy_update_bmk_mgr.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/files/Xob_orig_regy_update_cmd.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/files/Xob_page_regy_cmd.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/files/Xob_page_regy_tbl.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/files/Xob_xfer_regy_cmd.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/files/Xob_xfer_regy_tbl.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/files/Xob_xfer_regy_update_cmd.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/files/Xob_xfer_temp_cmd_orig.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/files/Xob_xfer_temp_cmd_thumb.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/files/Xob_xfer_temp_itm.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/files/Xob_xfer_temp_itm_tst.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/files/Xob_xfer_temp_tbl.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/files/Xob_xfer_update_cmd.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/files/Xobu_poll_mgr.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/texts/Xob_init_base.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/texts/Xob_search_base.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/texts/Xob_term_base.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/texts/sqls/Xob_css_cmd.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/texts/sqls/Xob_init_cmd.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/texts/sqls/Xob_ns_to_db_wkr__text.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/texts/sqls/Xob_page_cmd.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/texts/sqls/Xob_page_cmd_tst.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/texts/sqls/Xob_search_sql_cmd.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/texts/sqls/Xob_search_sql_cmd_tst.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/texts/sqls/Xob_search_sql_wkr.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/texts/sqls/Xob_term_cmd.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/texts/tdbs/Xob_calc_stats_cmd.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/texts/tdbs/Xob_init_base_tst.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/texts/tdbs/Xob_init_tdb.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/texts/tdbs/Xob_make_id_wkr.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/texts/tdbs/Xob_page_txt.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/texts/tdbs/Xob_parse_dump_templates_cmd.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/texts/tdbs/Xob_search_base_tst.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/texts/tdbs/Xob_search_tdb.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/texts/tdbs/Xob_term_txt.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/texts/tdbs/Xob_tst.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/utils/Xob_cleanup_cmd.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/utils/Xob_core_batch_utl.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/utils/Xob_decompress_bz2_cmd.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/utils/Xob_deploy_copy_cmd.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/utils/Xob_deploy_zip_cmd.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/utils/Xob_download_wkr.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/utils/Xob_exec_sql_cmd.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/utils/Xob_unzip_wkr.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/utils/Xob_xml_dumper_cmd.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/wikis/Xob_image_cmd.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/wikis/Xob_image_cmd_tst.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/wikis/Xob_image_tbl.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/wikis/Xob_page_dump_cmd_drop.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/wikis/Xob_page_dump_cmd_make.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/wikis/Xob_page_dump_tbl.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/wikis/Xob_redirect_cmd.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/cmds/wikis/Xob_redirect_tbl.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/css/Xoa_css_extractor.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/css/Xoa_css_extractor_basic_tst.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/css/Xoa_css_extractor_wiki_tst.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/css/Xoa_css_img_downloader.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/css/Xoa_css_img_downloader_tst.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/css/Xob_css_parser.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/css/Xob_css_parser__import.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/css/Xob_css_parser__import_tst.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/css/Xob_css_parser__url.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/css/Xob_css_parser__url_tst.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/css/Xob_css_tkn__base.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/css/Xob_mirror_mgr.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/css/Xob_mirror_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/css/Xob_url_fixer.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/css/Xob_url_fixer_tst.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/css/Xobc_download_itm.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/filters/core/Xob_ttl_filter_mgr.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/filters/core/Xob_ttl_filter_mgr_srl.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/filters/core/Xob_ttl_filter_mgr_srl_tst.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/filters/core/Xob_ttl_filter_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/filters/dansguardians/Crt__match_base.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/filters/dansguardians/Dg_file.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/filters/dansguardians/Dg_log_mgr.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/filters/dansguardians/Dg_match_mgr.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/filters/dansguardians/Dg_match_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/filters/dansguardians/Dg_parser.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/filters/dansguardians/Dg_parser_tst.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/infos/Xob_info_file.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/infos/Xob_info_session.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/langs/Json_itm_wkr__base.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/langs/Xob_i18n_parser.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/langs/Xob_i18n_parser_tst.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/langs/Xobc_utl_make_lang.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/langs/Xobc_utl_make_lang_kwds.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/langs/Xobc_utl_make_lang_tst.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/langs/Xol_lang_transform.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/langs/Xol_mw_lang_parser.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/langs/Xol_mw_lang_parser_tst.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/servers/Xob_core_server.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/servers/Xob_wmf_mgr.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/servers/jobs/Xob_job_itm.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/servers/jobs/Xob_job_mgr.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/wiki_cfgs/Xob_subpage_parser.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/wiki_cfgs/Xoi_wiki_props_alias.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/wiki_cfgs/Xoi_wiki_props_api.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/wiki_cfgs/Xoi_wiki_props_api_tst.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/wiki_cfgs/Xoi_wiki_props_ns.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/wiki_cfgs/Xoi_wiki_props_wiki.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/xmls/Xob_import_cfg.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/xmls/Xob_import_marker.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/xmls/Xob_siteinfo_parser.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/xmls/Xob_xml_dumper.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/xmls/Xob_xml_dumper_tst.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/xmls/Xob_xml_page_bldr.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/xmls/Xob_xml_parser.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/xmls/Xob_xml_parser_.java create mode 100644 400_xowa/src/gplx/xowa/bldrs/xmls/Xob_xml_parser_tst.java create mode 100644 400_xowa/src/gplx/xowa/cfgs/Xoa_cfg_db.java create mode 100644 400_xowa/src/gplx/xowa/cfgs/Xoa_cfg_db_txt.java create mode 100644 400_xowa/src/gplx/xowa/cfgs/Xoa_cfg_grp.java create mode 100644 400_xowa/src/gplx/xowa/cfgs/Xoa_cfg_grp_tid.java create mode 100644 400_xowa/src/gplx/xowa/cfgs/Xoa_cfg_itm.java create mode 100644 400_xowa/src/gplx/xowa/cfgs/Xoa_cfg_mgr.java create mode 100644 400_xowa/src/gplx/xowa/cfgs/Xoa_cfg_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa/cfgs/gui/Xocfg_gui_mgr.java create mode 100644 400_xowa/src/gplx/xowa/cfgs/gui/Xocfg_html.java create mode 100644 400_xowa/src/gplx/xowa/cfgs/gui/Xocfg_pref_mgr.java create mode 100644 400_xowa/src/gplx/xowa/cfgs/gui/Xocfg_win.java create mode 100644 400_xowa/src/gplx/xowa/cfgs2/Xocfg_bnd_itm.java create mode 100644 400_xowa/src/gplx/xowa/cfgs2/Xocfg_bnd_itm_srl.java create mode 100644 400_xowa/src/gplx/xowa/cfgs2/Xocfg_bnd_mgr.java create mode 100644 400_xowa/src/gplx/xowa/cfgs2/Xocfg_gui_mgr.java create mode 100644 400_xowa/src/gplx/xowa/cfgs2/Xocfg_regy.java create mode 100644 400_xowa/src/gplx/xowa/cfgs2/Xocfg_root.java create mode 100644 400_xowa/src/gplx/xowa/cfgs2/Xocfg_root_.java create mode 100644 400_xowa/src/gplx/xowa/cfgs2/Xocfg_tab_btn_mgr.java create mode 100644 400_xowa/src/gplx/xowa/cfgs2/Xocfg_tab_mgr.java create mode 100644 400_xowa/src/gplx/xowa/cfgs2/Xocfg_tab_new_mgr.java create mode 100644 400_xowa/src/gplx/xowa/ctgs/Xoa_ctg_mgr.java create mode 100644 400_xowa/src/gplx/xowa/ctgs/Xoctg_data_cache.java create mode 100644 400_xowa/src/gplx/xowa/ctgs/Xoctg_data_ctg.java create mode 100644 400_xowa/src/gplx/xowa/ctgs/Xoctg_data_ctg_tst.java create mode 100644 400_xowa/src/gplx/xowa/ctgs/Xoctg_fmtr_all.java create mode 100644 400_xowa/src/gplx/xowa/ctgs/Xoctg_fmtr_grp.java create mode 100644 400_xowa/src/gplx/xowa/ctgs/Xoctg_fmtr_itm.java create mode 100644 400_xowa/src/gplx/xowa/ctgs/Xoctg_html_mgr.java create mode 100644 400_xowa/src/gplx/xowa/ctgs/Xoctg_html_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa/ctgs/Xoctg_idx_itm.java create mode 100644 400_xowa/src/gplx/xowa/ctgs/Xoctg_idx_mgr.java create mode 100644 400_xowa/src/gplx/xowa/ctgs/Xoctg_idx_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa/ctgs/Xoctg_page_xtn.java create mode 100644 400_xowa/src/gplx/xowa/ctgs/Xoctg_pagelist_grp.java create mode 100644 400_xowa/src/gplx/xowa/ctgs/Xoctg_pagelist_itms.java create mode 100644 400_xowa/src/gplx/xowa/ctgs/Xoctg_pagelist_mgr.java create mode 100644 400_xowa/src/gplx/xowa/ctgs/Xoctg_pagelist_wtr.java create mode 100644 400_xowa/src/gplx/xowa/ctgs/Xoctg_pagelist_wtr_tst.java create mode 100644 400_xowa/src/gplx/xowa/ctgs/Xoctg_url.java create mode 100644 400_xowa/src/gplx/xowa/ctgs/Xoctg_url_tst.java create mode 100644 400_xowa/src/gplx/xowa/ctgs/Xoctg_view_ctg.java create mode 100644 400_xowa/src/gplx/xowa/ctgs/Xoctg_view_ctg_tst.java create mode 100644 400_xowa/src/gplx/xowa/ctgs/Xoctg_view_grp.java create mode 100644 400_xowa/src/gplx/xowa/ctgs/Xoctg_view_itm.java create mode 100644 400_xowa/src/gplx/xowa/dbs/Xodb_load_mgr.java create mode 100644 400_xowa/src/gplx/xowa/dbs/Xodb_load_mgr_sql.java create mode 100644 400_xowa/src/gplx/xowa/dbs/Xodb_load_mgr_sql_tst.java create mode 100644 400_xowa/src/gplx/xowa/dbs/Xodb_load_mgr_txt.java create mode 100644 400_xowa/src/gplx/xowa/dbs/Xodb_mgr.java create mode 100644 400_xowa/src/gplx/xowa/dbs/Xodb_mgr_sql.java create mode 100644 400_xowa/src/gplx/xowa/dbs/Xodb_mgr_txt.java create mode 100644 400_xowa/src/gplx/xowa/dbs/Xodb_page_rdr.java create mode 100644 400_xowa/src/gplx/xowa/dbs/Xodb_page_rdr__sql.java create mode 100644 400_xowa/src/gplx/xowa/dbs/Xodb_page_rdr__tdb.java create mode 100644 400_xowa/src/gplx/xowa/dbs/Xodb_save_mgr.java create mode 100644 400_xowa/src/gplx/xowa/dbs/Xodb_save_mgr_sql.java create mode 100644 400_xowa/src/gplx/xowa/dbs/Xodb_save_mgr_txt.java create mode 100644 400_xowa/src/gplx/xowa/dbs/Xodb_upgrade_mgr.java create mode 100644 400_xowa/src/gplx/xowa/files/Xof_bin_updater.java create mode 100644 400_xowa/src/gplx/xowa/files/Xof_exec_tid.java create mode 100644 400_xowa/src/gplx/xowa/files/Xof_ext.java create mode 100644 400_xowa/src/gplx/xowa/files/Xof_ext_.java create mode 100644 400_xowa/src/gplx/xowa/files/Xof_file_fxt.java create mode 100644 400_xowa/src/gplx/xowa/files/Xof_file_itm.java create mode 100644 400_xowa/src/gplx/xowa/files/Xof_file_wkr.java create mode 100644 400_xowa/src/gplx/xowa/files/Xof_file_wkr_.java create mode 100644 400_xowa/src/gplx/xowa/files/Xof_fsdb_itm.java create mode 100644 400_xowa/src/gplx/xowa/files/Xof_fsdb_mode.java create mode 100644 400_xowa/src/gplx/xowa/files/Xof_html_elem.java create mode 100644 400_xowa/src/gplx/xowa/files/Xof_img_size.java create mode 100644 400_xowa/src/gplx/xowa/files/Xof_img_size_tst.java create mode 100644 400_xowa/src/gplx/xowa/files/Xof_lnki_page.java create mode 100644 400_xowa/src/gplx/xowa/files/Xof_lnki_time.java create mode 100644 400_xowa/src/gplx/xowa/files/Xof_media_type.java create mode 100644 400_xowa/src/gplx/xowa/files/Xof_mime_minor_.java create mode 100644 400_xowa/src/gplx/xowa/files/Xof_patch_upright_tid_.java create mode 100644 400_xowa/src/gplx/xowa/files/Xof_redlink_wkr.java create mode 100644 400_xowa/src/gplx/xowa/files/Xof_url_bldr.java create mode 100644 400_xowa/src/gplx/xowa/files/Xof_url_bldr_tst.java create mode 100644 400_xowa/src/gplx/xowa/files/Xof_wkr_mgr.java create mode 100644 400_xowa/src/gplx/xowa/files/Xof_xfer_itm.java create mode 100644 400_xowa/src/gplx/xowa/files/Xof_xfer_itm_.java create mode 100644 400_xowa/src/gplx/xowa/files/Xof_xfer_itm_tst.java create mode 100644 400_xowa/src/gplx/xowa/files/Xog_redlink_thread.java create mode 100644 400_xowa/src/gplx/xowa/files/Xow_file_mgr.java create mode 100644 400_xowa/src/gplx/xowa/files/bins/Bin_fetcher.java create mode 100644 400_xowa/src/gplx/xowa/files/bins/Xof_bin_mgr.java create mode 100644 400_xowa/src/gplx/xowa/files/bins/Xof_bin_skip_mgr.java create mode 100644 400_xowa/src/gplx/xowa/files/bins/Xof_bin_wkr.java create mode 100644 400_xowa/src/gplx/xowa/files/bins/Xof_bin_wkr_.java create mode 100644 400_xowa/src/gplx/xowa/files/bins/Xof_bin_wkr__fsdb_sql.java create mode 100644 400_xowa/src/gplx/xowa/files/bins/Xof_bin_wkr__fsys_base.java create mode 100644 400_xowa/src/gplx/xowa/files/bins/Xof_bin_wkr__http_wmf.java create mode 100644 400_xowa/src/gplx/xowa/files/caches/Xof_cache_mgr.java create mode 100644 400_xowa/src/gplx/xowa/files/caches/Xof_cache_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa/files/caches/Xofc_cfg_mgr.java create mode 100644 400_xowa/src/gplx/xowa/files/caches/Xofc_dir_itm.java create mode 100644 400_xowa/src/gplx/xowa/files/caches/Xofc_dir_mgr.java create mode 100644 400_xowa/src/gplx/xowa/files/caches/Xofc_dir_tbl.java create mode 100644 400_xowa/src/gplx/xowa/files/caches/Xofc_fil_itm.java create mode 100644 400_xowa/src/gplx/xowa/files/caches/Xofc_fil_mgr.java create mode 100644 400_xowa/src/gplx/xowa/files/caches/Xofc_fil_tbl.java create mode 100644 400_xowa/src/gplx/xowa/files/caches/Xou_cache_itm.java create mode 100644 400_xowa/src/gplx/xowa/files/caches/Xou_cache_mgr.java create mode 100644 400_xowa/src/gplx/xowa/files/caches/Xou_cache_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa/files/caches/Xou_cache_tbl.java create mode 100644 400_xowa/src/gplx/xowa/files/caches/Xou_cache_tbl_tst.java create mode 100644 400_xowa/src/gplx/xowa/files/caches/Xou_file_itm_finder.java create mode 100644 400_xowa/src/gplx/xowa/files/cnvs/Xof_cnv_wkr_.java create mode 100644 400_xowa/src/gplx/xowa/files/cnvs/Xof_img_wkr_resize_img.java create mode 100644 400_xowa/src/gplx/xowa/files/cnvs/Xof_img_wkr_resize_img_imageMagick.java create mode 100644 400_xowa/src/gplx/xowa/files/cnvs/Xof_img_wkr_resize_img_mok.java create mode 100644 400_xowa/src/gplx/xowa/files/downloads/Xof_download_wkr.java create mode 100644 400_xowa/src/gplx/xowa/files/downloads/Xof_download_wkr_io.java create mode 100644 400_xowa/src/gplx/xowa/files/downloads/Xof_download_wkr_test.java create mode 100644 400_xowa/src/gplx/xowa/files/exts/Xof_rule_grp.java create mode 100644 400_xowa/src/gplx/xowa/files/exts/Xof_rule_itm.java create mode 100644 400_xowa/src/gplx/xowa/files/exts/Xof_rule_mgr.java create mode 100644 400_xowa/src/gplx/xowa/files/fsdb/Fsdb_regy_fil_tbl.java create mode 100644 400_xowa/src/gplx/xowa/files/fsdb/Xof_fsdb_mgr.java create mode 100644 400_xowa/src/gplx/xowa/files/fsdb/Xof_fsdb_mgr__sql.java create mode 100644 400_xowa/src/gplx/xowa/files/fsdb/Xof_fsdb_mgr_cfg.java create mode 100644 400_xowa/src/gplx/xowa/files/fsdb/fs_roots/Fs_root_dir.java create mode 100644 400_xowa/src/gplx/xowa/files/fsdb/fs_roots/Fs_root_dir_tst.java create mode 100644 400_xowa/src/gplx/xowa/files/fsdb/fs_roots/Fs_root_fsdb_mgr.java create mode 100644 400_xowa/src/gplx/xowa/files/fsdb/fs_roots/Fs_root_wkr_fsdb.java create mode 100644 400_xowa/src/gplx/xowa/files/fsdb/fs_roots/Orig_fil_itm.java create mode 100644 400_xowa/src/gplx/xowa/files/fsdb/fs_roots/Orig_fil_mgr.java create mode 100644 400_xowa/src/gplx/xowa/files/fsdb/fs_roots/Orig_fil_tbl.java create mode 100644 400_xowa/src/gplx/xowa/files/fsdb/tsts/Xof_file_ext__bmp_tst.java create mode 100644 400_xowa/src/gplx/xowa/files/fsdb/tsts/Xof_file_ext__flac_tst.java create mode 100644 400_xowa/src/gplx/xowa/files/fsdb/tsts/Xof_file_ext__oga_tst.java create mode 100644 400_xowa/src/gplx/xowa/files/fsdb/tsts/Xof_file_ext__ogg_tst.java create mode 100644 400_xowa/src/gplx/xowa/files/fsdb/tsts/Xof_file_ext__ogv_tst.java create mode 100644 400_xowa/src/gplx/xowa/files/fsdb/tsts/Xof_file_ext__pdf_tst.java create mode 100644 400_xowa/src/gplx/xowa/files/fsdb/tsts/Xof_file_ext__png_tst.java create mode 100644 400_xowa/src/gplx/xowa/files/fsdb/tsts/Xof_file_ext__svg_tst.java create mode 100644 400_xowa/src/gplx/xowa/files/fsdb/tsts/Xof_file_ext__unknown_tst.java create mode 100644 400_xowa/src/gplx/xowa/files/fsdb/tsts/Xof_file_ext__wav_tst.java create mode 100644 400_xowa/src/gplx/xowa/files/fsdb/tsts/Xof_file_ext__xcf_tst.java create mode 100644 400_xowa/src/gplx/xowa/files/fsdb/tsts/Xof_file_fxt.java create mode 100644 400_xowa/src/gplx/xowa/files/fsdb/tsts/Xof_file_redirect_tst.java create mode 100644 400_xowa/src/gplx/xowa/files/gui/Js_img_mgr.java create mode 100644 400_xowa/src/gplx/xowa/files/gui/Js_img_wkr.java create mode 100644 400_xowa/src/gplx/xowa/files/gui/Xog_js_wkr.java create mode 100644 400_xowa/src/gplx/xowa/files/gui/Xog_js_wkr_.java create mode 100644 400_xowa/src/gplx/xowa/files/gui/Xog_js_wkr__log.java create mode 100644 400_xowa/src/gplx/xowa/files/imgs/Xof_img_mgr.java create mode 100644 400_xowa/src/gplx/xowa/files/imgs/Xof_img_wkr_convert_djvu_to_tiff.java create mode 100644 400_xowa/src/gplx/xowa/files/imgs/Xof_img_wkr_convert_djvu_to_tiff_.java create mode 100644 400_xowa/src/gplx/xowa/files/imgs/Xof_img_wkr_query_img_size.java create mode 100644 400_xowa/src/gplx/xowa/files/imgs/Xof_img_wkr_query_img_size_test.java create mode 100644 400_xowa/src/gplx/xowa/files/origs/Xob_orig_tbl_bldr.java create mode 100644 400_xowa/src/gplx/xowa/files/origs/Xof_orig_itm.java create mode 100644 400_xowa/src/gplx/xowa/files/origs/Xof_orig_mgr.java create mode 100644 400_xowa/src/gplx/xowa/files/origs/Xof_orig_tbl.java create mode 100644 400_xowa/src/gplx/xowa/files/origs/Xof_orig_tbl_tst.java create mode 100644 400_xowa/src/gplx/xowa/files/origs/Xof_orig_wkr.java create mode 100644 400_xowa/src/gplx/xowa/files/origs/Xof_orig_wkr_.java create mode 100644 400_xowa/src/gplx/xowa/files/origs/Xof_orig_wkr__orig_db.java create mode 100644 400_xowa/src/gplx/xowa/files/origs/Xof_orig_wkr__wmf_api.java create mode 100644 400_xowa/src/gplx/xowa/files/origs/Xof_orig_wkr__xo_meta.java create mode 100644 400_xowa/src/gplx/xowa/files/origs/Xof_wiki_finder.java create mode 100644 400_xowa/src/gplx/xowa/files/origs/Xof_wiki_finder_itm.java create mode 100644 400_xowa/src/gplx/xowa/files/repos/Xof_repo_itm.java create mode 100644 400_xowa/src/gplx/xowa/files/repos/Xof_repo_itm_.java create mode 100644 400_xowa/src/gplx/xowa/files/repos/Xof_repo_pair.java create mode 100644 400_xowa/src/gplx/xowa/files/repos/Xow_repo_mgr.java create mode 100644 400_xowa/src/gplx/xowa/files/repos/Xow_repo_mgr_.java create mode 100644 400_xowa/src/gplx/xowa/files/repos/Xowe_repo_mgr.java create mode 100644 400_xowa/src/gplx/xowa/files/xfers/Xof_xfer_mgr.java create mode 100644 400_xowa/src/gplx/xowa/files/xfers/Xof_xfer_queue.java create mode 100644 400_xowa/src/gplx/xowa/files/xfers/Xof_xfer_queue_base_fxt.java create mode 100644 400_xowa/src/gplx/xowa/files/xfers/Xof_xfer_queue_html_basic_tst.java create mode 100644 400_xowa/src/gplx/xowa/files/xfers/Xof_xfer_queue_html_cases_tst.java create mode 100644 400_xowa/src/gplx/xowa/files/xfers/Xof_xfer_queue_html_fxt.java create mode 100644 400_xowa/src/gplx/xowa/files/xfers/Xof_xfer_queue_html_offline_tst.java create mode 100644 400_xowa/src/gplx/xowa/files/xfers/Xof_xfer_queue_html_wmf_api_tst.java create mode 100644 400_xowa/src/gplx/xowa/files/xfers/Xof_xfer_rslt.java create mode 100644 400_xowa/src/gplx/xowa/fmtrs/Gfo_sort_able.java create mode 100644 400_xowa/src/gplx/xowa/fmtrs/Xoa_fmtr_itm.java create mode 100644 400_xowa/src/gplx/xowa/fmtrs/Xoa_fmtr_itm_tst.java create mode 100644 400_xowa/src/gplx/xowa/fmtrs/Xoa_fmtr_mgr.java create mode 100644 400_xowa/src/gplx/xowa/fmtrs/Xoa_fmtr_sort_mgr.java create mode 100644 400_xowa/src/gplx/xowa/gui/Xoa_gui_mgr.java create mode 100644 400_xowa/src/gplx/xowa/gui/Xog_html_mgr.java create mode 100644 400_xowa/src/gplx/xowa/gui/Xog_resizer.java create mode 100644 400_xowa/src/gplx/xowa/gui/bnds/Xog_bnd_box.java create mode 100644 400_xowa/src/gplx/xowa/gui/bnds/Xog_bnd_box_.java create mode 100644 400_xowa/src/gplx/xowa/gui/bnds/Xog_bnd_itm.java create mode 100644 400_xowa/src/gplx/xowa/gui/bnds/Xog_bnd_itm_srl_tst.java create mode 100644 400_xowa/src/gplx/xowa/gui/bnds/Xog_bnd_mgr.java create mode 100644 400_xowa/src/gplx/xowa/gui/bnds/Xog_bnd_mgr_srl.java create mode 100644 400_xowa/src/gplx/xowa/gui/bnds/Xog_bnd_win.java create mode 100644 400_xowa/src/gplx/xowa/gui/cmds/Xog_cmd_ctg.java create mode 100644 400_xowa/src/gplx/xowa/gui/cmds/Xog_cmd_itm.java create mode 100644 400_xowa/src/gplx/xowa/gui/cmds/Xog_cmd_itm_.java create mode 100644 400_xowa/src/gplx/xowa/gui/cmds/Xog_cmd_mgr.java create mode 100644 400_xowa/src/gplx/xowa/gui/cmds/Xog_cmd_mgr_invk.java create mode 100644 400_xowa/src/gplx/xowa/gui/history/Xog_history_itm.java create mode 100644 400_xowa/src/gplx/xowa/gui/history/Xog_history_mgr.java create mode 100644 400_xowa/src/gplx/xowa/gui/history/Xog_history_stack.java create mode 100644 400_xowa/src/gplx/xowa/gui/history/Xog_history_stack_tst.java create mode 100644 400_xowa/src/gplx/xowa/gui/menus/Xog_menu_mgr.java create mode 100644 400_xowa/src/gplx/xowa/gui/menus/Xog_menu_mnu_src.java create mode 100644 400_xowa/src/gplx/xowa/gui/menus/Xog_popup_mnu_mgr.java create mode 100644 400_xowa/src/gplx/xowa/gui/menus/Xog_window_mnu_mgr.java create mode 100644 400_xowa/src/gplx/xowa/gui/menus/dom/Xog_mnu_base.java create mode 100644 400_xowa/src/gplx/xowa/gui/menus/dom/Xog_mnu_bldr.java create mode 100644 400_xowa/src/gplx/xowa/gui/menus/dom/Xog_mnu_evt_mgr.java create mode 100644 400_xowa/src/gplx/xowa/gui/menus/dom/Xog_mnu_grp.java create mode 100644 400_xowa/src/gplx/xowa/gui/menus/dom/Xog_mnu_itm.java create mode 100644 400_xowa/src/gplx/xowa/gui/menus/dom/Xog_mnu_regy.java create mode 100644 400_xowa/src/gplx/xowa/gui/urls/Xof_orig_file_downloader.java create mode 100644 400_xowa/src/gplx/xowa/gui/urls/Xog_url_wkr.java create mode 100644 400_xowa/src/gplx/xowa/gui/urls/Xog_url_wkr_tst.java create mode 100644 400_xowa/src/gplx/xowa/gui/urls/url_macros/Xog_url_macro_grp.java create mode 100644 400_xowa/src/gplx/xowa/gui/urls/url_macros/Xog_url_macro_mgr.java create mode 100644 400_xowa/src/gplx/xowa/gui/urls/url_macros/Xog_url_macro_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa/gui/views/Load_page_wkr.java create mode 100644 400_xowa/src/gplx/xowa/gui/views/Rect_ref.java create mode 100644 400_xowa/src/gplx/xowa/gui/views/Xog_html_itm.java create mode 100644 400_xowa/src/gplx/xowa/gui/views/Xog_html_itm_tst.java create mode 100644 400_xowa/src/gplx/xowa/gui/views/Xog_js_procs.java create mode 100644 400_xowa/src/gplx/xowa/gui/views/Xog_launcher_tabs.java create mode 100644 400_xowa/src/gplx/xowa/gui/views/Xog_layout.java create mode 100644 400_xowa/src/gplx/xowa/gui/views/Xog_layout_box.java create mode 100644 400_xowa/src/gplx/xowa/gui/views/Xog_tab_close_lnr.java create mode 100644 400_xowa/src/gplx/xowa/gui/views/Xog_tab_close_mgr.java create mode 100644 400_xowa/src/gplx/xowa/gui/views/Xog_tab_itm.java create mode 100644 400_xowa/src/gplx/xowa/gui/views/Xog_tab_itm_.java create mode 100644 400_xowa/src/gplx/xowa/gui/views/Xog_tab_itm_edit_mgr.java create mode 100644 400_xowa/src/gplx/xowa/gui/views/Xog_tab_itm_read_mgr.java create mode 100644 400_xowa/src/gplx/xowa/gui/views/Xog_tab_mgr.java create mode 100644 400_xowa/src/gplx/xowa/gui/views/Xog_win_itm.java create mode 100644 400_xowa/src/gplx/xowa/gui/views/Xog_win_itm_.java create mode 100644 400_xowa/src/gplx/xowa/gui/views/Xog_win_itm__prog_href_mgr.java create mode 100644 400_xowa/src/gplx/xowa/html/Xoh_cfg_file.java create mode 100644 400_xowa/src/gplx/xowa/html/Xoh_cmd_itm.java create mode 100644 400_xowa/src/gplx/xowa/html/Xoh_cmd_mgr.java create mode 100644 400_xowa/src/gplx/xowa/html/Xoh_consts.java create mode 100644 400_xowa/src/gplx/xowa/html/Xoh_html_mgr.java create mode 100644 400_xowa/src/gplx/xowa/html/Xoh_html_wtr.java create mode 100644 400_xowa/src/gplx/xowa/html/Xoh_html_wtr_cfg.java create mode 100644 400_xowa/src/gplx/xowa/html/Xoh_html_wtr_escaper.java create mode 100644 400_xowa/src/gplx/xowa/html/Xoh_html_wtr_tst.java create mode 100644 400_xowa/src/gplx/xowa/html/Xoh_imgs_mgr.java create mode 100644 400_xowa/src/gplx/xowa/html/Xoh_page_mgr.java create mode 100644 400_xowa/src/gplx/xowa/html/Xoh_page_wtr_mgr_base.java create mode 100644 400_xowa/src/gplx/xowa/html/Xoh_page_wtr_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa/html/Xoh_page_wtr_wkr.java create mode 100644 400_xowa/src/gplx/xowa/html/Xoh_page_wtr_wkr_.java create mode 100644 400_xowa/src/gplx/xowa/html/Xoh_page_wtr_wkr_tst.java create mode 100644 400_xowa/src/gplx/xowa/html/Xoh_wtr_ctx.java create mode 100644 400_xowa/src/gplx/xowa/html/Xohe_page_wtr_mgr.java create mode 100644 400_xowa/src/gplx/xowa/html/Xohp_ctg_grp_mgr.java create mode 100644 400_xowa/src/gplx/xowa/html/Xohp_ctg_grp_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa/html/Xohv_page_wtr_mgr.java create mode 100644 400_xowa/src/gplx/xowa/html/Xow_html_mgr.java create mode 100644 400_xowa/src/gplx/xowa/html/css/Xob_css_status.java create mode 100644 400_xowa/src/gplx/xowa/html/css/Xow_css_mgr.java create mode 100644 400_xowa/src/gplx/xowa/html/css/Xowd_css_core_mgr.java create mode 100644 400_xowa/src/gplx/xowa/html/css/Xowd_css_core_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa/html/hdumps/Xohd_hdump_rdr.java create mode 100644 400_xowa/src/gplx/xowa/html/hdumps/Xohd_hdump_wtr.java create mode 100644 400_xowa/src/gplx/xowa/html/hdumps/Xohd_hdump_wtr_tst.java create mode 100644 400_xowa/src/gplx/xowa/html/hdumps/abrvs/Xohd_abrv_.java create mode 100644 400_xowa/src/gplx/xowa/html/hdumps/abrvs/Xohd_abrv_mgr.java create mode 100644 400_xowa/src/gplx/xowa/html/hdumps/abrvs/Xohd_abrv_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa/html/hdumps/bldrs/Xob_hdump_bldr.java create mode 100644 400_xowa/src/gplx/xowa/html/hdumps/bldrs/Xob_hdump_img_cmd.java create mode 100644 400_xowa/src/gplx/xowa/html/hdumps/bldrs/Xob_link_dump_cmd.java create mode 100644 400_xowa/src/gplx/xowa/html/hdumps/bldrs/Xob_link_dump_tbl.java create mode 100644 400_xowa/src/gplx/xowa/html/hdumps/bldrs/Xob_redlink_mkr_cmd.java create mode 100644 400_xowa/src/gplx/xowa/html/hdumps/core/Xohd_data_itm.java create mode 100644 400_xowa/src/gplx/xowa/html/hdumps/core/Xohd_data_itm__base.java create mode 100644 400_xowa/src/gplx/xowa/html/hdumps/core/Xohd_data_itm__gallery_itm.java create mode 100644 400_xowa/src/gplx/xowa/html/hdumps/core/Xohd_data_itm__gallery_mgr.java create mode 100644 400_xowa/src/gplx/xowa/html/hdumps/core/Xohd_data_itm__img.java create mode 100644 400_xowa/src/gplx/xowa/html/hdumps/core/Xohd_data_tid.java create mode 100644 400_xowa/src/gplx/xowa/html/hdumps/data/Xohd_page_html_mgr__load.java create mode 100644 400_xowa/src/gplx/xowa/html/hdumps/data/Xohd_page_html_mgr__save.java create mode 100644 400_xowa/src/gplx/xowa/html/hdumps/data/srl/Xohd_page_srl_itm.java create mode 100644 400_xowa/src/gplx/xowa/html/hdumps/data/srl/Xohd_page_srl_itm_.java create mode 100644 400_xowa/src/gplx/xowa/html/hdumps/data/srl/Xohd_page_srl_itm_tst.java create mode 100644 400_xowa/src/gplx/xowa/html/hdumps/data/srl/Xohd_page_srl_itms.java create mode 100644 400_xowa/src/gplx/xowa/html/hdumps/data/srl/Xohd_page_srl_mgr.java create mode 100644 400_xowa/src/gplx/xowa/html/hdumps/pages/Xopg_hdump_data.java create mode 100644 400_xowa/src/gplx/xowa/html/hdumps/pages/Xopg_module_mgr.java create mode 100644 400_xowa/src/gplx/xowa/html/hrefs/Xoh_href.java create mode 100644 400_xowa/src/gplx/xowa/html/hrefs/Xoh_href_parser.java create mode 100644 400_xowa/src/gplx/xowa/html/hrefs/Xoh_href_parser_tst.java create mode 100644 400_xowa/src/gplx/xowa/html/hzips/Hzip_bfr_mgr.java create mode 100644 400_xowa/src/gplx/xowa/html/hzips/Xodump_stats_itm.java create mode 100644 400_xowa/src/gplx/xowa/html/hzips/Xodump_stats_tbl.java create mode 100644 400_xowa/src/gplx/xowa/html/hzips/Xow_hzip_dict.java create mode 100644 400_xowa/src/gplx/xowa/html/hzips/Xow_hzip_int_.java create mode 100644 400_xowa/src/gplx/xowa/html/hzips/Xow_hzip_int__tst.java create mode 100644 400_xowa/src/gplx/xowa/html/hzips/Xow_hzip_itm__anchor.java create mode 100644 400_xowa/src/gplx/xowa/html/hzips/Xow_hzip_itm__anchor_tst.java create mode 100644 400_xowa/src/gplx/xowa/html/hzips/Xow_hzip_itm__file_tst.java create mode 100644 400_xowa/src/gplx/xowa/html/hzips/Xow_hzip_itm__header.java create mode 100644 400_xowa/src/gplx/xowa/html/hzips/Xow_hzip_itm__header_tst.java create mode 100644 400_xowa/src/gplx/xowa/html/hzips/Xow_hzip_itm__href.java create mode 100644 400_xowa/src/gplx/xowa/html/hzips/Xow_hzip_mgr.java create mode 100644 400_xowa/src/gplx/xowa/html/hzips/Xow_hzip_mgr_fxt.java create mode 100644 400_xowa/src/gplx/xowa/html/hzips/Xow_hzip_xtid.java create mode 100644 400_xowa/src/gplx/xowa/html/js/Xoh_js_cbk.java create mode 100644 400_xowa/src/gplx/xowa/html/js/Xoh_js_cbk_tst.java create mode 100644 400_xowa/src/gplx/xowa/html/js/Xoh_js_cbk_wdata_labels_tst.java create mode 100644 400_xowa/src/gplx/xowa/html/js/Xoh_json_exec.java create mode 100644 400_xowa/src/gplx/xowa/html/lnkis/Xoh_arg_img_core.java create mode 100644 400_xowa/src/gplx/xowa/html/lnkis/Xoh_arg_img_core__basic.java create mode 100644 400_xowa/src/gplx/xowa/html/lnkis/Xoh_arg_img_core__hdump.java create mode 100644 400_xowa/src/gplx/xowa/html/lnkis/Xoh_file_html_fmtr__base.java create mode 100644 400_xowa/src/gplx/xowa/html/lnkis/Xoh_file_html_fmtr__hdump.java create mode 100644 400_xowa/src/gplx/xowa/html/lnkis/Xoh_file_img_wkr.java create mode 100644 400_xowa/src/gplx/xowa/html/lnkis/Xoh_file_mgr.java create mode 100644 400_xowa/src/gplx/xowa/html/lnkis/Xoh_file_wtr__basic.java create mode 100644 400_xowa/src/gplx/xowa/html/lnkis/Xoh_file_wtr_audio_video_tst.java create mode 100644 400_xowa/src/gplx/xowa/html/lnkis/Xoh_file_wtr_basic_tst.java create mode 100644 400_xowa/src/gplx/xowa/html/lnkis/Xoh_file_wtr_media_tst.java create mode 100644 400_xowa/src/gplx/xowa/html/lnkis/Xoh_lnki_consts.java create mode 100644 400_xowa/src/gplx/xowa/html/lnkis/Xoh_lnki_consts_tst.java create mode 100644 400_xowa/src/gplx/xowa/html/lnkis/Xoh_lnki_text_fmtr.java create mode 100644 400_xowa/src/gplx/xowa/html/lnkis/Xoh_lnki_title_fmtr.java create mode 100644 400_xowa/src/gplx/xowa/html/lnkis/Xoh_lnki_title_fmtr_tst.java create mode 100644 400_xowa/src/gplx/xowa/html/lnkis/Xoh_lnki_wtr.java create mode 100644 400_xowa/src/gplx/xowa/html/lnkis/Xoh_redlink_utl.java create mode 100644 400_xowa/src/gplx/xowa/html/modules/Xoh_module_itm.java create mode 100644 400_xowa/src/gplx/xowa/html/modules/Xoh_module_itm_.java create mode 100644 400_xowa/src/gplx/xowa/html/modules/Xoh_module_itm__collapsible.java create mode 100644 400_xowa/src/gplx/xowa/html/modules/Xoh_module_itm__css.java create mode 100644 400_xowa/src/gplx/xowa/html/modules/Xoh_module_itm__gallery.java create mode 100644 400_xowa/src/gplx/xowa/html/modules/Xoh_module_itm__globals.java create mode 100644 400_xowa/src/gplx/xowa/html/modules/Xoh_module_itm__hiero.java create mode 100644 400_xowa/src/gplx/xowa/html/modules/Xoh_module_itm__mathjax.java create mode 100644 400_xowa/src/gplx/xowa/html/modules/Xoh_module_itm__navframe.java create mode 100644 400_xowa/src/gplx/xowa/html/modules/Xoh_module_itm__popups.java create mode 100644 400_xowa/src/gplx/xowa/html/modules/Xoh_module_itm__search_suggest.java create mode 100644 400_xowa/src/gplx/xowa/html/modules/Xoh_module_itm__timeline.java create mode 100644 400_xowa/src/gplx/xowa/html/modules/Xoh_module_itm__title_rewrite.java create mode 100644 400_xowa/src/gplx/xowa/html/modules/Xoh_module_itm__toc.java create mode 100644 400_xowa/src/gplx/xowa/html/modules/Xoh_module_itm__top_icon.java create mode 100644 400_xowa/src/gplx/xowa/html/modules/Xoh_module_itm__xoui.java create mode 100644 400_xowa/src/gplx/xowa/html/modules/Xoh_module_mgr.java create mode 100644 400_xowa/src/gplx/xowa/html/modules/Xoh_module_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa/html/modules/Xoh_module_wtr.java create mode 100644 400_xowa/src/gplx/xowa/html/modules/Xoh_module_wtr_tst.java create mode 100644 400_xowa/src/gplx/xowa/html/modules/popups/Xopg_popup_mgr.java create mode 100644 400_xowa/src/gplx/xowa/html/modules/popups/Xow_popup_anchor_finder.java create mode 100644 400_xowa/src/gplx/xowa/html/modules/popups/Xow_popup_anchor_finder__hdr_tst.java create mode 100644 400_xowa/src/gplx/xowa/html/modules/popups/Xow_popup_anchor_finder__id_tst.java create mode 100644 400_xowa/src/gplx/xowa/html/modules/popups/Xow_popup_cfg.java create mode 100644 400_xowa/src/gplx/xowa/html/modules/popups/Xow_popup_html_mkr.java create mode 100644 400_xowa/src/gplx/xowa/html/modules/popups/Xow_popup_itm.java create mode 100644 400_xowa/src/gplx/xowa/html/modules/popups/Xow_popup_mgr.java create mode 100644 400_xowa/src/gplx/xowa/html/modules/popups/Xow_popup_parser.java create mode 100644 400_xowa/src/gplx/xowa/html/modules/popups/Xow_popup_parser_data.java create mode 100644 400_xowa/src/gplx/xowa/html/modules/popups/Xow_popup_parser_tst.java create mode 100644 400_xowa/src/gplx/xowa/html/modules/popups/Xow_popup_word.java create mode 100644 400_xowa/src/gplx/xowa/html/modules/popups/Xow_popup_wrdx_mkr.java create mode 100644 400_xowa/src/gplx/xowa/html/modules/popups/keeplists/Xop_keeplist_rule.java create mode 100644 400_xowa/src/gplx/xowa/html/modules/popups/keeplists/Xop_keeplist_wiki.java create mode 100644 400_xowa/src/gplx/xowa/html/modules/popups/keeplists/Xop_keeplist_wiki_srl.java create mode 100644 400_xowa/src/gplx/xowa/html/modules/popups/keeplists/Xop_keeplist_wiki_tst.java create mode 100644 400_xowa/src/gplx/xowa/html/ns_files/Xoh_file_page__other_resolutions.java create mode 100644 400_xowa/src/gplx/xowa/html/ns_files/Xoh_file_page_wtr.java create mode 100644 400_xowa/src/gplx/xowa/html/ns_files/Xoh_ns_file_page_mgr.java create mode 100644 400_xowa/src/gplx/xowa/html/ns_files/Xoh_ns_file_page_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa/html/portal/Xoa_available_wikis_mgr.java create mode 100644 400_xowa/src/gplx/xowa/html/portal/Xoa_portal_mgr.java create mode 100644 400_xowa/src/gplx/xowa/html/portal/Xoh_page_body_cls.java create mode 100644 400_xowa/src/gplx/xowa/html/portal/Xoh_page_body_cls_tst.java create mode 100644 400_xowa/src/gplx/xowa/html/portal/Xoh_rtl_utl.java create mode 100644 400_xowa/src/gplx/xowa/html/portal/Xoh_rtl_utl_tst.java create mode 100644 400_xowa/src/gplx/xowa/html/portal/Xoh_subpages_bldr.java create mode 100644 400_xowa/src/gplx/xowa/html/portal/Xoh_subpages_bldr_tst.java create mode 100644 400_xowa/src/gplx/xowa/html/portal/Xow_portal_mgr.java create mode 100644 400_xowa/src/gplx/xowa/html/portal/Xow_portal_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa/html/sidebar/Xowh_sidebar_itm.java create mode 100644 400_xowa/src/gplx/xowa/html/sidebar/Xowh_sidebar_mgr.java create mode 100644 400_xowa/src/gplx/xowa/html/sidebar/Xowh_sidebar_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa/html/skins/Xoh_skin_itm.java create mode 100644 400_xowa/src/gplx/xowa/html/skins/Xoh_skin_mgr.java create mode 100644 400_xowa/src/gplx/xowa/html/skins/Xoh_skin_regy.java create mode 100644 400_xowa/src/gplx/xowa/html/tidy/Xoh_tidy_mgr.java create mode 100644 400_xowa/src/gplx/xowa/html/tidy/Xoh_tidy_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa/html/tidy/Xoh_tidy_wkr.java create mode 100644 400_xowa/src/gplx/xowa/html/tidy/Xoh_tidy_wkr_.java create mode 100644 400_xowa/src/gplx/xowa/html/tidy/Xoh_tidy_wkr_jtidy.java create mode 100644 400_xowa/src/gplx/xowa/html/tidy/Xoh_tidy_wkr_jtidy_tst.java create mode 100644 400_xowa/src/gplx/xowa/html/tidy/Xoh_tidy_wkr_tidy.java create mode 100644 400_xowa/src/gplx/xowa/html/tocs/Xow_hdr_mgr.java create mode 100644 400_xowa/src/gplx/xowa/html/tocs/Xow_toc_mgr.java create mode 100644 400_xowa/src/gplx/xowa/html/tocs/Xow_toc_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa/html/utils/Xoh_js_cleaner.java create mode 100644 400_xowa/src/gplx/xowa/html/utils/Xoh_js_cleaner_tst.java create mode 100644 400_xowa/src/gplx/xowa/html/wtrs/Xoh_anchor_kv_bldr.java create mode 100644 400_xowa/src/gplx/xowa/html/wtrs/Xoh_img_path.java create mode 100644 400_xowa/src/gplx/xowa/html/wtrs/Xoh_lnki_bldr.java create mode 100644 400_xowa/src/gplx/xowa/html/wtrs/Xoh_lnki_wtr_utl.java create mode 100644 400_xowa/src/gplx/xowa/html/xouis/fmtrs/Xoui_cells_fmtr.java create mode 100644 400_xowa/src/gplx/xowa/html/xouis/fmtrs/Xoui_tbl_fmtr.java create mode 100644 400_xowa/src/gplx/xowa/html/xouis/fmtrs/Xoui_tbl_fmtr_tst.java create mode 100644 400_xowa/src/gplx/xowa/html/xouis/fmtrs/Xoui_val_fmtr.java create mode 100644 400_xowa/src/gplx/xowa/html/xouis/fmtrs/Xoui_val_fmtr_.java create mode 100644 400_xowa/src/gplx/xowa/html/xouis/tbls/Xoui_btn_itm.java create mode 100644 400_xowa/src/gplx/xowa/html/xouis/tbls/Xoui_col_itm.java create mode 100644 400_xowa/src/gplx/xowa/html/xouis/tbls/Xoui_row_itm.java create mode 100644 400_xowa/src/gplx/xowa/html/xouis/tbls/Xoui_tbl_itm.java create mode 100644 400_xowa/src/gplx/xowa/html/xouis/tbls/Xoui_tbl_mgr.java create mode 100644 400_xowa/src/gplx/xowa/html/xouis/tbls/Xoui_val_hash.java create mode 100644 400_xowa/src/gplx/xowa/html/xouis/tbls/Xoui_val_itm.java create mode 100644 400_xowa/src/gplx/xowa/langs/Xoa_lang_mgr.java create mode 100644 400_xowa/src/gplx/xowa/langs/Xol_func_name_itm.java create mode 100644 400_xowa/src/gplx/xowa/langs/Xol_func_name_regy.java create mode 100644 400_xowa/src/gplx/xowa/langs/Xol_lang_itm.java create mode 100644 400_xowa/src/gplx/xowa/langs/Xol_lang_itm_.java create mode 100644 400_xowa/src/gplx/xowa/langs/cases/Xol_case_itm.java create mode 100644 400_xowa/src/gplx/xowa/langs/cases/Xol_case_itm_.java create mode 100644 400_xowa/src/gplx/xowa/langs/cases/Xol_case_mgr.java create mode 100644 400_xowa/src/gplx/xowa/langs/cases/Xol_case_mgr_.java create mode 100644 400_xowa/src/gplx/xowa/langs/cases/Xol_case_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa/langs/cnvs/Xol_cnv_grp.java create mode 100644 400_xowa/src/gplx/xowa/langs/cnvs/Xol_cnv_itm.java create mode 100644 400_xowa/src/gplx/xowa/langs/cnvs/Xol_cnv_mgr.java create mode 100644 400_xowa/src/gplx/xowa/langs/cnvs/Xol_cnv_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa/langs/cnvs/Xol_mw_parse_tst.java create mode 100644 400_xowa/src/gplx/xowa/langs/durations/Xol_duration_itm.java create mode 100644 400_xowa/src/gplx/xowa/langs/durations/Xol_duration_itm_.java create mode 100644 400_xowa/src/gplx/xowa/langs/durations/Xol_duration_mgr.java create mode 100644 400_xowa/src/gplx/xowa/langs/durations/Xol_interval_itm.java create mode 100644 400_xowa/src/gplx/xowa/langs/genders/Xol_gender.java create mode 100644 400_xowa/src/gplx/xowa/langs/genders/Xol_gender_.java create mode 100644 400_xowa/src/gplx/xowa/langs/grammars/Xol_grammar.java create mode 100644 400_xowa/src/gplx/xowa/langs/grammars/Xol_grammar_.java create mode 100644 400_xowa/src/gplx/xowa/langs/grammars/Xol_grammar_fi.java create mode 100644 400_xowa/src/gplx/xowa/langs/grammars/Xol_grammar_manual_regy.java create mode 100644 400_xowa/src/gplx/xowa/langs/grammars/Xol_grammar_ru.java create mode 100644 400_xowa/src/gplx/xowa/langs/msgs/Xol_msg_mgr_.java create mode 100644 400_xowa/src/gplx/xowa/langs/numbers/Xol_num_fmtr_base.java create mode 100644 400_xowa/src/gplx/xowa/langs/numbers/Xol_num_fmtr_base_tst.java create mode 100644 400_xowa/src/gplx/xowa/langs/numbers/Xol_num_grp.java create mode 100644 400_xowa/src/gplx/xowa/langs/numbers/Xol_num_grp_fmtr.java create mode 100644 400_xowa/src/gplx/xowa/langs/numbers/Xol_num_grp_fmtr_tst.java create mode 100644 400_xowa/src/gplx/xowa/langs/numbers/Xol_num_mgr.java create mode 100644 400_xowa/src/gplx/xowa/langs/numbers/Xol_num_mgr_.java create mode 100644 400_xowa/src/gplx/xowa/langs/numbers/Xol_num_mgr__commafy_5.java create mode 100644 400_xowa/src/gplx/xowa/langs/numbers/Xol_transform_mgr.java create mode 100644 400_xowa/src/gplx/xowa/langs/plurals/Xol_plural.java create mode 100644 400_xowa/src/gplx/xowa/langs/plurals/Xol_plural_.java create mode 100644 400_xowa/src/gplx/xowa/langs/plurals/Xol_plural_ru.java create mode 100644 400_xowa/src/gplx/xowa/langs/plurals/Xol_plural_ru_tst.java create mode 100644 400_xowa/src/gplx/xowa/langs/vnts/Xol_vnt_converter.java create mode 100644 400_xowa/src/gplx/xowa/langs/vnts/Xol_vnt_itm.java create mode 100644 400_xowa/src/gplx/xowa/langs/vnts/Xol_vnt_mgr.java create mode 100644 400_xowa/src/gplx/xowa/langs/vnts/Xolg_vnt_grp.java create mode 100644 400_xowa/src/gplx/xowa/langs/vnts/Xolg_vnt_grp_fmtr.java create mode 100644 400_xowa/src/gplx/xowa/langs/vnts/Xolg_vnt_grp_fmtr_tst.java create mode 100644 400_xowa/src/gplx/xowa/langs/vnts/Xolg_vnt_itm.java create mode 100644 400_xowa/src/gplx/xowa/langs/vnts/Xop_vnt_eqgt_tkn.java create mode 100644 400_xowa/src/gplx/xowa/langs/vnts/Xop_vnt_flag.java create mode 100644 400_xowa/src/gplx/xowa/langs/vnts/Xop_vnt_flag_lang_bldr.java create mode 100644 400_xowa/src/gplx/xowa/langs/vnts/Xop_vnt_flag_parser.java create mode 100644 400_xowa/src/gplx/xowa/langs/vnts/Xop_vnt_html_wtr.java create mode 100644 400_xowa/src/gplx/xowa/langs/vnts/Xop_vnt_lxr_.java create mode 100644 400_xowa/src/gplx/xowa/langs/vnts/Xop_vnt_lxr_tst.java create mode 100644 400_xowa/src/gplx/xowa/langs/vnts/Xop_vnt_parser_tst.java create mode 100644 400_xowa/src/gplx/xowa/langs/vnts/Xop_vnt_rule.java create mode 100644 400_xowa/src/gplx/xowa/langs/vnts/Xop_vnt_rules_parser.java create mode 100644 400_xowa/src/gplx/xowa/langs/vnts/Xop_vnt_tkn.java create mode 100644 400_xowa/src/gplx/xowa/net/Xoo_protocol_itm.java create mode 100644 400_xowa/src/gplx/xowa/pages/Xopg_html_data.java create mode 100644 400_xowa/src/gplx/xowa/pages/Xopg_revision_data.java create mode 100644 400_xowa/src/gplx/xowa/pages/Xopg_tab_data.java create mode 100644 400_xowa/src/gplx/xowa/pages/Xopg_tmpl_prepend_mgr.java create mode 100644 400_xowa/src/gplx/xowa/pages/Xopg_view_mode.java create mode 100644 400_xowa/src/gplx/xowa/pages/skins/Xopg_xtn_skin_fmtr_arg.java create mode 100644 400_xowa/src/gplx/xowa/pages/skins/Xopg_xtn_skin_itm.java create mode 100644 400_xowa/src/gplx/xowa/pages/skins/Xopg_xtn_skin_itm_stub.java create mode 100644 400_xowa/src/gplx/xowa/pages/skins/Xopg_xtn_skin_itm_tid.java create mode 100644 400_xowa/src/gplx/xowa/pages/skins/Xopg_xtn_skin_mgr.java create mode 100644 400_xowa/src/gplx/xowa/parsers/amps/Xop_amp_lxr.java create mode 100644 400_xowa/src/gplx/xowa/parsers/amps/Xop_amp_mgr.java create mode 100644 400_xowa/src/gplx/xowa/parsers/amps/Xop_amp_mgr_decode_tst.java create mode 100644 400_xowa/src/gplx/xowa/parsers/amps/Xop_amp_tkn_num.java create mode 100644 400_xowa/src/gplx/xowa/parsers/amps/Xop_amp_tkn_txt.java create mode 100644 400_xowa/src/gplx/xowa/parsers/amps/Xop_amp_trie.java create mode 100644 400_xowa/src/gplx/xowa/parsers/amps/Xop_amp_trie_itm.java create mode 100644 400_xowa/src/gplx/xowa/parsers/amps/Xop_amp_wkr.java create mode 100644 400_xowa/src/gplx/xowa/parsers/amps/Xop_amp_wkr_tst.java create mode 100644 400_xowa/src/gplx/xowa/parsers/apos/Xop_apos_dat.java create mode 100644 400_xowa/src/gplx/xowa/parsers/apos/Xop_apos_log.java create mode 100644 400_xowa/src/gplx/xowa/parsers/apos/Xop_apos_lxr.java create mode 100644 400_xowa/src/gplx/xowa/parsers/apos/Xop_apos_tkn.java create mode 100644 400_xowa/src/gplx/xowa/parsers/apos/Xop_apos_tkn_.java create mode 100644 400_xowa/src/gplx/xowa/parsers/apos/Xop_apos_tkn_chkr.java create mode 100644 400_xowa/src/gplx/xowa/parsers/apos/Xop_apos_wkr.java create mode 100644 400_xowa/src/gplx/xowa/parsers/apos/Xop_apos_wkr_tst.java create mode 100644 400_xowa/src/gplx/xowa/parsers/hdrs/Xop_hdr_log.java create mode 100644 400_xowa/src/gplx/xowa/parsers/hdrs/Xop_hdr_lxr.java create mode 100644 400_xowa/src/gplx/xowa/parsers/hdrs/Xop_hdr_tkn.java create mode 100644 400_xowa/src/gplx/xowa/parsers/hdrs/Xop_hdr_tkn_chkr.java create mode 100644 400_xowa/src/gplx/xowa/parsers/hdrs/Xop_hdr_wkr.java create mode 100644 400_xowa/src/gplx/xowa/parsers/hdrs/Xop_hdr_wkr__basic_tst.java create mode 100644 400_xowa/src/gplx/xowa/parsers/hdrs/Xop_hdr_wkr__div_wrapper_tst.java create mode 100644 400_xowa/src/gplx/xowa/parsers/hdrs/Xop_hdr_wkr__para_tst.java create mode 100644 400_xowa/src/gplx/xowa/parsers/lists/Xop_list_lxr.java create mode 100644 400_xowa/src/gplx/xowa/parsers/lists/Xop_list_tkn.java create mode 100644 400_xowa/src/gplx/xowa/parsers/lists/Xop_list_tkn_.java create mode 100644 400_xowa/src/gplx/xowa/parsers/lists/Xop_list_tkn_chkr.java create mode 100644 400_xowa/src/gplx/xowa/parsers/lists/Xop_list_wkr.java create mode 100644 400_xowa/src/gplx/xowa/parsers/lists/Xop_list_wkr_.java create mode 100644 400_xowa/src/gplx/xowa/parsers/lists/Xop_list_wkr_basic_tst.java create mode 100644 400_xowa/src/gplx/xowa/parsers/lists/Xop_list_wkr_para_tst.java create mode 100644 400_xowa/src/gplx/xowa/parsers/lists/Xop_list_wkr_uncommon_tst.java create mode 100644 400_xowa/src/gplx/xowa/parsers/lnkes/Xoh_lnke_wtr.java create mode 100644 400_xowa/src/gplx/xowa/parsers/lnkes/Xoh_lnke_wtr_tst.java create mode 100644 400_xowa/src/gplx/xowa/parsers/lnkes/Xop_lnke_end_lxr.java create mode 100644 400_xowa/src/gplx/xowa/parsers/lnkes/Xop_lnke_log.java create mode 100644 400_xowa/src/gplx/xowa/parsers/lnkes/Xop_lnke_lxr.java create mode 100644 400_xowa/src/gplx/xowa/parsers/lnkes/Xop_lnke_tkn.java create mode 100644 400_xowa/src/gplx/xowa/parsers/lnkes/Xop_lnke_wkr.java create mode 100644 400_xowa/src/gplx/xowa/parsers/lnkes/Xop_lnke_wkr_brack_tst.java create mode 100644 400_xowa/src/gplx/xowa/parsers/lnkes/Xop_lnke_wkr_dangling_tst.java create mode 100644 400_xowa/src/gplx/xowa/parsers/lnkes/Xop_lnke_wkr_relative_tst.java create mode 100644 400_xowa/src/gplx/xowa/parsers/lnkes/Xop_lnke_wkr_text_tst.java create mode 100644 400_xowa/src/gplx/xowa/parsers/lnkes/Xop_lnke_wkr_uncommon_tst.java create mode 100644 400_xowa/src/gplx/xowa/parsers/lnkes/Xop_lnke_wkr_xwiki_tst.java create mode 100644 400_xowa/src/gplx/xowa/parsers/lnkis/cfgs/Xoc_lnki_cfg.java create mode 100644 400_xowa/src/gplx/xowa/parsers/lnkis/cfgs/Xoc_xwiki_repo_mgr.java create mode 100644 400_xowa/src/gplx/xowa/parsers/lnkis/redlinks/Xog_redlink_mgr.java create mode 100644 400_xowa/src/gplx/xowa/parsers/lnkis/redlinks/Xopg_redlink_idx_list.java create mode 100644 400_xowa/src/gplx/xowa/parsers/lnkis/redlinks/Xopg_redlink_lnki_list.java create mode 100644 400_xowa/src/gplx/xowa/parsers/lnkis/redlinks/Xopg_redlink_logger.java create mode 100644 400_xowa/src/gplx/xowa/parsers/logs/Xop_log_basic_tbl.java create mode 100644 400_xowa/src/gplx/xowa/parsers/logs/Xop_log_basic_wkr.java create mode 100644 400_xowa/src/gplx/xowa/parsers/logs/Xop_log_invoke_wkr.java create mode 100644 400_xowa/src/gplx/xowa/parsers/logs/Xop_log_mgr.java create mode 100644 400_xowa/src/gplx/xowa/parsers/logs/Xop_log_property_wkr.java create mode 100644 400_xowa/src/gplx/xowa/parsers/paras/Xop_nl_lxr.java create mode 100644 400_xowa/src/gplx/xowa/parsers/paras/Xop_nl_tab_lxr.java create mode 100644 400_xowa/src/gplx/xowa/parsers/paras/Xop_nl_tab_lxr_tst.java create mode 100644 400_xowa/src/gplx/xowa/parsers/paras/Xop_nl_tkn.java create mode 100644 400_xowa/src/gplx/xowa/parsers/paras/Xop_para_tkn.java create mode 100644 400_xowa/src/gplx/xowa/parsers/paras/Xop_para_wkr.java create mode 100644 400_xowa/src/gplx/xowa/parsers/paras/Xop_para_wkr_basic_tst.java create mode 100644 400_xowa/src/gplx/xowa/parsers/paras/Xop_para_wkr_para_tst.java create mode 100644 400_xowa/src/gplx/xowa/parsers/paras/Xop_para_wkr_pre_tst.java create mode 100644 400_xowa/src/gplx/xowa/parsers/paras/Xop_pre_lxr.java create mode 100644 400_xowa/src/gplx/xowa/parsers/paras/Xop_pre_tkn.java create mode 100644 400_xowa/src/gplx/xowa/parsers/tblws/Xop_tblw_lxr.java create mode 100644 400_xowa/src/gplx/xowa/parsers/tblws/Xop_tblw_lxr_ws.java create mode 100644 400_xowa/src/gplx/xowa/parsers/tblws/Xop_tblw_tb_tkn.java create mode 100644 400_xowa/src/gplx/xowa/parsers/tblws/Xop_tblw_tc_tkn.java create mode 100644 400_xowa/src/gplx/xowa/parsers/tblws/Xop_tblw_td_tkn.java create mode 100644 400_xowa/src/gplx/xowa/parsers/tblws/Xop_tblw_th_tkn.java create mode 100644 400_xowa/src/gplx/xowa/parsers/tblws/Xop_tblw_tkn.java create mode 100644 400_xowa/src/gplx/xowa/parsers/tblws/Xop_tblw_tr_tkn.java create mode 100644 400_xowa/src/gplx/xowa/parsers/tblws/Xop_tblw_wkr.java create mode 100644 400_xowa/src/gplx/xowa/parsers/tblws/Xop_tblw_wkr__atrs_tst.java create mode 100644 400_xowa/src/gplx/xowa/parsers/tblws/Xop_tblw_wkr__basic_tst.java create mode 100644 400_xowa/src/gplx/xowa/parsers/tblws/Xop_tblw_wkr__dangling_tst.java create mode 100644 400_xowa/src/gplx/xowa/parsers/tblws/Xop_tblw_wkr__double_pipe_tst.java create mode 100644 400_xowa/src/gplx/xowa/parsers/tblws/Xop_tblw_wkr__errs_tst.java create mode 100644 400_xowa/src/gplx/xowa/parsers/tblws/Xop_tblw_wkr__nested_tst.java create mode 100644 400_xowa/src/gplx/xowa/parsers/tblws/Xop_tblw_wkr__para_tst.java create mode 100644 400_xowa/src/gplx/xowa/parsers/tblws/Xop_tblw_wkr__tblx_tst.java create mode 100644 400_xowa/src/gplx/xowa/parsers/tblws/Xop_tblw_wkr__uncommon_tst.java create mode 100644 400_xowa/src/gplx/xowa/parsers/tblws/Xop_tblw_ws_itm.java create mode 100644 400_xowa/src/gplx/xowa/parsers/tmpls/Nowiki_escape_itm.java create mode 100644 400_xowa/src/gplx/xowa/servers/Gxw_html_server.java create mode 100644 400_xowa/src/gplx/xowa/servers/http/File_retrieve_mode.java create mode 100644 400_xowa/src/gplx/xowa/servers/http/Http_server_mgr.java create mode 100644 400_xowa/src/gplx/xowa/servers/http/Http_server_wkr_.java create mode 100644 400_xowa/src/gplx/xowa/servers/http/Http_server_wkr__tst.java create mode 100644 400_xowa/src/gplx/xowa/servers/http/Http_server_wkr_v2.java create mode 100644 400_xowa/src/gplx/xowa/servers/tcp/Socket_rdr.java create mode 100644 400_xowa/src/gplx/xowa/servers/tcp/Socket_wtr.java create mode 100644 400_xowa/src/gplx/xowa/servers/tcp/Xosrv_cmd_types.java create mode 100644 400_xowa/src/gplx/xowa/servers/tcp/Xosrv_msg.java create mode 100644 400_xowa/src/gplx/xowa/servers/tcp/Xosrv_msg_rdr.java create mode 100644 400_xowa/src/gplx/xowa/servers/tcp/Xosrv_msg_rdr_tst.java create mode 100644 400_xowa/src/gplx/xowa/servers/tcp/Xosrv_server.java create mode 100644 400_xowa/src/gplx/xowa/servers/tcp/Xosrv_server_tst.java create mode 100644 400_xowa/src/gplx/xowa/servers/tcp/Xosrv_socket_rdr.java create mode 100644 400_xowa/src/gplx/xowa/servers/tcp/Xosrv_socket_wtr.java create mode 100644 400_xowa/src/gplx/xowa/setup/addons/Xoi_addon_mgr.java create mode 100644 400_xowa/src/gplx/xowa/setup/addons/Xoi_firefox_installer.java create mode 100644 400_xowa/src/gplx/xowa/setup/addons/Xoi_firefox_installer_tst.java create mode 100644 400_xowa/src/gplx/xowa/setup/maints/Wmf_dump_itm.java create mode 100644 400_xowa/src/gplx/xowa/setup/maints/Wmf_dump_list_parser.java create mode 100644 400_xowa/src/gplx/xowa/setup/maints/Wmf_dump_list_parser_tst.java create mode 100644 400_xowa/src/gplx/xowa/setup/maints/Wmf_latest_itm.java create mode 100644 400_xowa/src/gplx/xowa/setup/maints/Wmf_latest_parser.java create mode 100644 400_xowa/src/gplx/xowa/setup/maints/Wmf_latest_parser_tst.java create mode 100644 400_xowa/src/gplx/xowa/setup/maints/Xoa_maint_mgr.java create mode 100644 400_xowa/src/gplx/xowa/setup/maints/Xoa_maint_wikis_mgr.java create mode 100644 400_xowa/src/gplx/xowa/setup/maints/Xow_maint_mgr.java create mode 100644 400_xowa/src/gplx/xowa/specials/Xoa_special_mgr.java create mode 100644 400_xowa/src/gplx/xowa/specials/Xows_mgr.java create mode 100644 400_xowa/src/gplx/xowa/specials/Xows_page.java create mode 100644 400_xowa/src/gplx/xowa/specials/Xows_special_meta.java create mode 100644 400_xowa/src/gplx/xowa/specials/Xows_special_meta_.java create mode 100644 400_xowa/src/gplx/xowa/specials/allPages/Xows_page_allpages.java create mode 100644 400_xowa/src/gplx/xowa/specials/allPages/Xows_page_allpages_tst.java create mode 100644 400_xowa/src/gplx/xowa/specials/movePage/Move_page.java create mode 100644 400_xowa/src/gplx/xowa/specials/nearby/Nearby_mgr.java create mode 100644 400_xowa/src/gplx/xowa/specials/nearby/Nearby_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa/specials/randoms/Xop_randomRootPage_page.java create mode 100644 400_xowa/src/gplx/xowa/specials/randoms/Xop_randomRootPage_page_tst.java create mode 100644 400_xowa/src/gplx/xowa/specials/randoms/Xows_page_random.java create mode 100644 400_xowa/src/gplx/xowa/specials/search/Xog_search_suggest_cmd.java create mode 100644 400_xowa/src/gplx/xowa/specials/search/Xog_search_suggest_mgr.java create mode 100644 400_xowa/src/gplx/xowa/specials/search/Xosrh_core_tst.java create mode 100644 400_xowa/src/gplx/xowa/specials/search/Xosrh_page_mgr.java create mode 100644 400_xowa/src/gplx/xowa/specials/search/Xosrh_page_mgr_searcher.java create mode 100644 400_xowa/src/gplx/xowa/specials/search/Xosrh_page_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa/specials/search/Xosrh_parser.java create mode 100644 400_xowa/src/gplx/xowa/specials/search/Xosrh_parser_tst.java create mode 100644 400_xowa/src/gplx/xowa/specials/search/Xosrh_qry_itm.java create mode 100644 400_xowa/src/gplx/xowa/specials/search/Xosrh_rslt_grp.java create mode 100644 400_xowa/src/gplx/xowa/specials/search/Xosrh_rslt_itm_sorter.java create mode 100644 400_xowa/src/gplx/xowa/specials/search/Xosrh_scanner.java create mode 100644 400_xowa/src/gplx/xowa/specials/search/Xow_domain_sorter__manual_tid.java create mode 100644 400_xowa/src/gplx/xowa/specials/search/Xows_arg_mgr.java create mode 100644 400_xowa/src/gplx/xowa/specials/search/Xows_core.java create mode 100644 400_xowa/src/gplx/xowa/specials/search/Xows_db_cache.java create mode 100644 400_xowa/src/gplx/xowa/specials/search/Xows_db_matcher.java create mode 100644 400_xowa/src/gplx/xowa/specials/search/Xows_db_matcher_bldr.java create mode 100644 400_xowa/src/gplx/xowa/specials/search/Xows_db_row.java create mode 100644 400_xowa/src/gplx/xowa/specials/search/Xows_db_wkr.java create mode 100644 400_xowa/src/gplx/xowa/specials/search/Xows_db_word.java create mode 100644 400_xowa/src/gplx/xowa/specials/search/Xows_html_wkr.java create mode 100644 400_xowa/src/gplx/xowa/specials/search/Xows_html_wkr_tst.java create mode 100644 400_xowa/src/gplx/xowa/specials/search/Xows_ns_mgr.java create mode 100644 400_xowa/src/gplx/xowa/specials/search/Xows_page__search.java create mode 100644 400_xowa/src/gplx/xowa/specials/search/Xows_paging_parser.java create mode 100644 400_xowa/src/gplx/xowa/specials/search/Xows_ui_async.java create mode 100644 400_xowa/src/gplx/xowa/specials/search/Xows_ui_async_tst.java create mode 100644 400_xowa/src/gplx/xowa/specials/search/Xows_ui_cmd.java create mode 100644 400_xowa/src/gplx/xowa/specials/search/Xows_ui_qry.java create mode 100644 400_xowa/src/gplx/xowa/specials/search/Xows_ui_rslt.java create mode 100644 400_xowa/src/gplx/xowa/specials/search/parsers/Xows_text_parser__v1.java create mode 100644 400_xowa/src/gplx/xowa/specials/search/parsers/Xows_text_parser__v2.java create mode 100644 400_xowa/src/gplx/xowa/specials/search/parsers/Xows_text_parser__v2_tst.java create mode 100644 400_xowa/src/gplx/xowa/specials/search/parsers/Xows_text_tkn.java create mode 100644 400_xowa/src/gplx/xowa/specials/search/parsers_old/Xow_search_parser.java create mode 100644 400_xowa/src/gplx/xowa/specials/search/parsers_old/Xow_search_scanner.java create mode 100644 400_xowa/src/gplx/xowa/specials/search/parsers_old/Xow_search_tkn.java create mode 100644 400_xowa/src/gplx/xowa/specials/statistics/Xop_statistics_page.java create mode 100644 400_xowa/src/gplx/xowa/specials/statistics/Xop_statistics_page_tst.java create mode 100644 400_xowa/src/gplx/xowa/specials/xowa/bookmarks/Xoui_tbl_itm__bmk.java create mode 100644 400_xowa/src/gplx/xowa/specials/xowa/bookmarks/Xows_bmk_page.java create mode 100644 400_xowa/src/gplx/xowa/specials/xowa/default_tab/Default_tab_page.java create mode 100644 400_xowa/src/gplx/xowa/specials/xowa/diags/Db_rdr_utl.java create mode 100644 400_xowa/src/gplx/xowa/specials/xowa/diags/Xows_cmd__file_check.java create mode 100644 400_xowa/src/gplx/xowa/specials/xowa/diags/Xows_cmd__fs_check.java create mode 100644 400_xowa/src/gplx/xowa/specials/xowa/diags/Xows_cmd__sql_dump.java create mode 100644 400_xowa/src/gplx/xowa/specials/xowa/diags/Xows_diag_page.java create mode 100644 400_xowa/src/gplx/xowa/specials/xowa/file_browsers/Xoa_url_arg_mgr.java create mode 100644 400_xowa/src/gplx/xowa/specials/xowa/file_browsers/Xosp_fbrow_cmd__base.java create mode 100644 400_xowa/src/gplx/xowa/specials/xowa/file_browsers/Xosp_fbrow_data_dir.java create mode 100644 400_xowa/src/gplx/xowa/specials/xowa/file_browsers/Xosp_fbrow_rslt.java create mode 100644 400_xowa/src/gplx/xowa/specials/xowa/file_browsers/Xosp_fbrow_special.java create mode 100644 400_xowa/src/gplx/xowa/specials/xowa/file_browsers/Xosp_fbrow_special_tst.java create mode 100644 400_xowa/src/gplx/xowa/specials/xowa/popup_history/Popup_history_page.java create mode 100644 400_xowa/src/gplx/xowa/specials/xowa/system_data/System_data_page.java create mode 100644 400_xowa/src/gplx/xowa/tdbs/Xotdb_dir_info.java create mode 100644 400_xowa/src/gplx/xowa/tdbs/Xotdb_dir_info_.java create mode 100644 400_xowa/src/gplx/xowa/tdbs/Xotdb_fsys_mgr.java create mode 100644 400_xowa/src/gplx/xowa/tdbs/Xotdb_fsys_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa/tdbs/Xotdb_page_itm_.java create mode 100644 400_xowa/src/gplx/xowa/tdbs/Xotdb_page_raw_parser.java create mode 100644 400_xowa/src/gplx/xowa/urls/encoders/Url_encoder_mgr.java create mode 100644 400_xowa/src/gplx/xowa/users/Xoc_layout_mgr.java create mode 100644 400_xowa/src/gplx/xowa/users/Xou_cfg.java create mode 100644 400_xowa/src/gplx/xowa/users/Xou_fsys_mgr.java create mode 100644 400_xowa/src/gplx/xowa/users/Xou_log_mgr.java create mode 100644 400_xowa/src/gplx/xowa/users/Xou_security_mgr.java create mode 100644 400_xowa/src/gplx/xowa/users/Xou_session.java create mode 100644 400_xowa/src/gplx/xowa/users/Xou_user.java create mode 100644 400_xowa/src/gplx/xowa/users/Xou_user_.java create mode 100644 400_xowa/src/gplx/xowa/users/Xou_user_mgr.java create mode 100644 400_xowa/src/gplx/xowa/users/Xou_user_tst.java create mode 100644 400_xowa/src/gplx/xowa/users/Xouc_pages_mgr.java create mode 100644 400_xowa/src/gplx/xowa/users/Xouc_setup_mgr.java create mode 100644 400_xowa/src/gplx/xowa/users/Xouc_startup_mgr.java create mode 100644 400_xowa/src/gplx/xowa/users/Xouc_window_mgr.java create mode 100644 400_xowa/src/gplx/xowa/users/Xoue_user.java create mode 100644 400_xowa/src/gplx/xowa/users/Xous_window_mgr.java create mode 100644 400_xowa/src/gplx/xowa/users/Xouv_user.java create mode 100644 400_xowa/src/gplx/xowa/users/bmks/Xoud_bmk_dir_row.java create mode 100644 400_xowa/src/gplx/xowa/users/bmks/Xoud_bmk_dir_tbl.java create mode 100644 400_xowa/src/gplx/xowa/users/bmks/Xoud_bmk_itm_row.java create mode 100644 400_xowa/src/gplx/xowa/users/bmks/Xoud_bmk_itm_tbl.java create mode 100644 400_xowa/src/gplx/xowa/users/bmks/Xoud_bmk_mgr.java create mode 100644 400_xowa/src/gplx/xowa/users/data/Xou_db_file.java create mode 100644 400_xowa/src/gplx/xowa/users/data/Xou_db_mgr.java create mode 100644 400_xowa/src/gplx/xowa/users/data/Xoud_cfg_mgr.java create mode 100644 400_xowa/src/gplx/xowa/users/data/Xoud_history_mgr.java create mode 100644 400_xowa/src/gplx/xowa/users/data/Xoud_history_row.java create mode 100644 400_xowa/src/gplx/xowa/users/data/Xoud_history_special.java create mode 100644 400_xowa/src/gplx/xowa/users/data/Xoud_history_tbl.java create mode 100644 400_xowa/src/gplx/xowa/users/data/Xoud_id_mgr.java create mode 100644 400_xowa/src/gplx/xowa/users/data/Xoud_opt_scope.java create mode 100644 400_xowa/src/gplx/xowa/users/data/Xoud_opt_scope_tst.java create mode 100644 400_xowa/src/gplx/xowa/users/data/Xoud_regy_row.java create mode 100644 400_xowa/src/gplx/xowa/users/data/Xoud_regy_tbl.java create mode 100644 400_xowa/src/gplx/xowa/users/data/Xoud_site_mgr.java create mode 100644 400_xowa/src/gplx/xowa/users/data/Xoud_site_row.java create mode 100644 400_xowa/src/gplx/xowa/users/data/Xoud_site_tbl.java create mode 100644 400_xowa/src/gplx/xowa/users/data/Xoud_user_tbl.java create mode 100644 400_xowa/src/gplx/xowa/users/history/Xou_history_cfg.java create mode 100644 400_xowa/src/gplx/xowa/users/history/Xou_history_html.java create mode 100644 400_xowa/src/gplx/xowa/users/history/Xou_history_itm.java create mode 100644 400_xowa/src/gplx/xowa/users/history/Xou_history_mgr.java create mode 100644 400_xowa/src/gplx/xowa/users/history/Xou_history_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa/users/history/Xou_history_sorter.java create mode 100644 400_xowa/src/gplx/xowa/users/prefs/Prefs_converter.java create mode 100644 400_xowa/src/gplx/xowa/users/prefs/Prefs_converter_tst.java create mode 100644 400_xowa/src/gplx/xowa/users/prefs/Prefs_html_wtr.java create mode 100644 400_xowa/src/gplx/xowa/users/prefs/Prefs_mgr.java create mode 100644 400_xowa/src/gplx/xowa/users/prefs/Prefs_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa/users/prefs/Prefs_rename_mgr.java create mode 100644 400_xowa/src/gplx/xowa/users/wikis/Xofs_url_itm_parser.java create mode 100644 400_xowa/src/gplx/xowa/users/wikis/Xofs_url_itm_parser_tst.java create mode 100644 400_xowa/src/gplx/xowa/users/wikis/Xou_wiki_mgr.java create mode 100644 400_xowa/src/gplx/xowa/utls/upgrades/Upgrader_v00_02_01.java create mode 100644 400_xowa/src/gplx/xowa/utls/upgrades/Upgrader_v00_02_01_tst.java create mode 100644 400_xowa/src/gplx/xowa/utls/upgrades/Xoa_upgrade_mgr.java create mode 100644 400_xowa/src/gplx/xowa/utls/upgrades/Xoa_upgrade_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa/wikis/Xoa_wiki_mgr.java create mode 100644 400_xowa/src/gplx/xowa/wikis/Xoa_wiki_regy.java create mode 100644 400_xowa/src/gplx/xowa/wikis/Xoae_wiki_mgr.java create mode 100644 400_xowa/src/gplx/xowa/wikis/Xow_cfg_consts.java create mode 100644 400_xowa/src/gplx/xowa/wikis/Xow_domain.java create mode 100644 400_xowa/src/gplx/xowa/wikis/Xow_domain_.java create mode 100644 400_xowa/src/gplx/xowa/wikis/Xow_domain_tst.java create mode 100644 400_xowa/src/gplx/xowa/wikis/Xow_domain_type.java create mode 100644 400_xowa/src/gplx/xowa/wikis/Xow_domain_type_.java create mode 100644 400_xowa/src/gplx/xowa/wikis/Xow_fsys_mgr.java create mode 100644 400_xowa/src/gplx/xowa/wikis/Xow_page_mgr.java create mode 100644 400_xowa/src/gplx/xowa/wikis/Xow_page_tid.java create mode 100644 400_xowa/src/gplx/xowa/wikis/Xow_wiki_abrv.java create mode 100644 400_xowa/src/gplx/xowa/wikis/Xow_wiki_abrv_.java create mode 100644 400_xowa/src/gplx/xowa/wikis/Xow_wiki_abrv_tst.java create mode 100644 400_xowa/src/gplx/xowa/wikis/Xow_wiki_alias.java create mode 100644 400_xowa/src/gplx/xowa/wikis/Xow_wiki_alias_tst.java create mode 100644 400_xowa/src/gplx/xowa/wikis/caches/Xow_cache_mgr.java create mode 100644 400_xowa/src/gplx/xowa/wikis/caches/Xow_defn_cache.java create mode 100644 400_xowa/src/gplx/xowa/wikis/caches/Xow_page_cache.java create mode 100644 400_xowa/src/gplx/xowa/wikis/caches/Xow_page_cache_itm.java create mode 100644 400_xowa/src/gplx/xowa/wikis/data/Xow_page_fetcher.java create mode 100644 400_xowa/src/gplx/xowa/wikis/data/Xow_page_fetcher_test.java create mode 100644 400_xowa/src/gplx/xowa/wikis/data/Xow_page_fetcher_wiki.java create mode 100644 400_xowa/src/gplx/xowa/wikis/data/Xowd_core_db_props.java create mode 100644 400_xowa/src/gplx/xowa/wikis/data/Xowd_db_file.java create mode 100644 400_xowa/src/gplx/xowa/wikis/data/Xowd_db_file_.java create mode 100644 400_xowa/src/gplx/xowa/wikis/data/Xowd_db_file_hash.java create mode 100644 400_xowa/src/gplx/xowa/wikis/data/Xowd_db_file_schema_props.java create mode 100644 400_xowa/src/gplx/xowa/wikis/data/Xowd_db_layout.java create mode 100644 400_xowa/src/gplx/xowa/wikis/data/Xowd_db_mgr.java create mode 100644 400_xowa/src/gplx/xowa/wikis/data/tbls/Xowd_cat_core_tbl.java create mode 100644 400_xowa/src/gplx/xowa/wikis/data/tbls/Xowd_cat_core_tbl__in_wkr.java create mode 100644 400_xowa/src/gplx/xowa/wikis/data/tbls/Xowd_cat_link_tbl.java create mode 100644 400_xowa/src/gplx/xowa/wikis/data/tbls/Xowd_category_itm.java create mode 100644 400_xowa/src/gplx/xowa/wikis/data/tbls/Xowd_css_core_itm.java create mode 100644 400_xowa/src/gplx/xowa/wikis/data/tbls/Xowd_css_core_tbl.java create mode 100644 400_xowa/src/gplx/xowa/wikis/data/tbls/Xowd_css_file_itm.java create mode 100644 400_xowa/src/gplx/xowa/wikis/data/tbls/Xowd_css_file_tbl.java create mode 100644 400_xowa/src/gplx/xowa/wikis/data/tbls/Xowd_html_row.java create mode 100644 400_xowa/src/gplx/xowa/wikis/data/tbls/Xowd_html_tbl.java create mode 100644 400_xowa/src/gplx/xowa/wikis/data/tbls/Xowd_page_itm.java create mode 100644 400_xowa/src/gplx/xowa/wikis/data/tbls/Xowd_page_itm_sorter.java create mode 100644 400_xowa/src/gplx/xowa/wikis/data/tbls/Xowd_page_itm_tst.java create mode 100644 400_xowa/src/gplx/xowa/wikis/data/tbls/Xowd_page_tbl.java create mode 100644 400_xowa/src/gplx/xowa/wikis/data/tbls/Xowd_page_tbl__in_wkrs.java create mode 100644 400_xowa/src/gplx/xowa/wikis/data/tbls/Xowd_page_tbl_tst.java create mode 100644 400_xowa/src/gplx/xowa/wikis/data/tbls/Xowd_search_link_tbl.java create mode 100644 400_xowa/src/gplx/xowa/wikis/data/tbls/Xowd_search_temp_tbl.java create mode 100644 400_xowa/src/gplx/xowa/wikis/data/tbls/Xowd_search_word_row.java create mode 100644 400_xowa/src/gplx/xowa/wikis/data/tbls/Xowd_search_word_tbl.java create mode 100644 400_xowa/src/gplx/xowa/wikis/data/tbls/Xowd_site_ns_tbl.java create mode 100644 400_xowa/src/gplx/xowa/wikis/data/tbls/Xowd_site_stats_tbl.java create mode 100644 400_xowa/src/gplx/xowa/wikis/data/tbls/Xowd_text_tbl.java create mode 100644 400_xowa/src/gplx/xowa/wikis/data/tbls/Xowd_wbase_pid_tbl.java create mode 100644 400_xowa/src/gplx/xowa/wikis/data/tbls/Xowd_wbase_qid_tbl.java create mode 100644 400_xowa/src/gplx/xowa/wikis/data/tbls/Xowd_wbase_qid_tbl_tst.java create mode 100644 400_xowa/src/gplx/xowa/wikis/data/tbls/Xowd_xowa_db_tbl.java create mode 100644 400_xowa/src/gplx/xowa/wikis/domains/Xow_domain_abrv_xo_.java create mode 100644 400_xowa/src/gplx/xowa/wikis/domains/Xow_domain_abrv_xo__tst.java create mode 100644 400_xowa/src/gplx/xowa/wikis/domains/Xow_domain_uid_.java create mode 100644 400_xowa/src/gplx/xowa/wikis/domains/Xow_domain_uid__tst.java create mode 100644 400_xowa/src/gplx/xowa/wikis/domains/crts/Xow_domain_crt_itm.java create mode 100644 400_xowa/src/gplx/xowa/wikis/domains/crts/Xow_domain_crt_itm_.java create mode 100644 400_xowa/src/gplx/xowa/wikis/domains/crts/Xow_domain_crt_itm_parser.java create mode 100644 400_xowa/src/gplx/xowa/wikis/domains/crts/Xow_domain_crt_kv_itm_mgr.java create mode 100644 400_xowa/src/gplx/xowa/wikis/modules/Xow_module_base.java create mode 100644 400_xowa/src/gplx/xowa/wikis/modules/Xow_module_mgr.java create mode 100644 400_xowa/src/gplx/xowa/wikis/ttls/Xow_ttl__anchor_tst.java create mode 100644 400_xowa/src/gplx/xowa/wikis/ttls/Xow_ttl__basic_tst.java create mode 100644 400_xowa/src/gplx/xowa/wikis/ttls/Xow_ttl__err_tst.java create mode 100644 400_xowa/src/gplx/xowa/wikis/ttls/Xow_ttl__html_entity_tst.java create mode 100644 400_xowa/src/gplx/xowa/wikis/ttls/Xow_ttl__i18n_tst.java create mode 100644 400_xowa/src/gplx/xowa/wikis/ttls/Xow_ttl__qarg_tst.java create mode 100644 400_xowa/src/gplx/xowa/wikis/ttls/Xow_ttl__ws_tst.java create mode 100644 400_xowa/src/gplx/xowa/wikis/ttls/Xow_ttl__xwik_tst.java create mode 100644 400_xowa/src/gplx/xowa/wikis/ttls/Xow_ttl_fxt.java create mode 100644 400_xowa/src/gplx/xowa/wikis/ttls/Xow_ttl_parser.java create mode 100644 400_xowa/src/gplx/xowa/wikis/xwikis/Xow_lang_grp.java create mode 100644 400_xowa/src/gplx/xowa/wikis/xwikis/Xow_lang_itm.java create mode 100644 400_xowa/src/gplx/xowa/wikis/xwikis/Xow_lang_mgr.java create mode 100644 400_xowa/src/gplx/xowa/wikis/xwikis/Xow_lang_mgr_fxt.java create mode 100644 400_xowa/src/gplx/xowa/wikis/xwikis/Xow_lang_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa/wikis/xwikis/Xow_xwiki_itm.java create mode 100644 400_xowa/src/gplx/xowa/wikis/xwikis/Xow_xwiki_itm_tst.java create mode 100644 400_xowa/src/gplx/xowa/wikis/xwikis/Xow_xwiki_mgr.java create mode 100644 400_xowa/src/gplx/xowa/wikis/xwikis/Xow_xwiki_mgr_srl.java create mode 100644 400_xowa/src/gplx/xowa/wikis/xwikis/Xow_xwiki_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa/wmfs/Xoa_wmf_mgr.java create mode 100644 400_xowa/src/gplx/xowa/wmfs/Xow_wmf_api_mgr.java create mode 100644 400_xowa/src/gplx/xowa/wmfs/Xow_wmf_api_wkr.java create mode 100644 400_xowa/src/gplx/xowa/wmfs/Xow_wmf_api_wkr__ns.java create mode 100644 400_xowa/src/gplx/xowa/wmfs/Xowmf_mgr.java create mode 100644 400_xowa/src/gplx/xowa/wmfs/apis/Xoapi_orig_base.java create mode 100644 400_xowa/src/gplx/xowa/wmfs/apis/Xoapi_orig_base_tst.java create mode 100644 400_xowa/src/gplx/xowa/wmfs/apis/Xoapi_orig_mok.java create mode 100644 400_xowa/src/gplx/xowa/wmfs/apis/Xoapi_orig_rslts.java create mode 100644 400_xowa/src/gplx/xowa/wmfs/apis/Xoapi_orig_wmf.java create mode 100644 400_xowa/src/gplx/xowa/wmfs/apis/Xowmf_api_mgr.java create mode 100644 400_xowa/src/gplx/xowa/wmfs/data/Xowmf_extensions_tbl.java create mode 100644 400_xowa/src/gplx/xowa/wmfs/data/Xowmf_general_tbl.java create mode 100644 400_xowa/src/gplx/xowa/wmfs/data/Xowmf_interwikimap_tbl.java create mode 100644 400_xowa/src/gplx/xowa/wmfs/data/Xowmf_json_tbl.java create mode 100644 400_xowa/src/gplx/xowa/wmfs/data/Xowmf_ns_tbl.java create mode 100644 400_xowa/src/gplx/xowa/wmfs/data/Xowmf_site_tbl.java create mode 100644 400_xowa/src/gplx/xowa/wmfs/data/Xowmf_specialpagealiases_tbl.java create mode 100644 400_xowa/src/gplx/xowa/wmfs/data/Xowmf_statistics_tbl.java create mode 100644 400_xowa/src/gplx/xowa/wmfs/dump_pages/Xowmf_wiki_dump_dirs_parser.java create mode 100644 400_xowa/src/gplx/xowa/wmfs/dump_pages/Xowmf_wiki_dump_dirs_parser_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/Xow_xtn_mgr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/Xox_mgr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/Xox_mgr_base.java create mode 100644 400_xowa/src/gplx/xowa/xtns/Xox_xnde.java create mode 100644 400_xowa/src/gplx/xowa/xtns/categoryList/Xtn_categoryList_nde_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/categoryList/Xtn_categorylist_nde.java create mode 100644 400_xowa/src/gplx/xowa/xtns/cite/Cite_xtn_mgr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/cite/Ref_html_wtr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/cite/Ref_html_wtr_cfg.java create mode 100644 400_xowa/src/gplx/xowa/xtns/cite/Ref_itm_grp.java create mode 100644 400_xowa/src/gplx/xowa/xtns/cite/Ref_itm_lst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/cite/Ref_itm_mgr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/cite/Ref_itm_mgr_cfg_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/cite/Ref_itm_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/cite/Ref_nde.java create mode 100644 400_xowa/src/gplx/xowa/xtns/cite/References_nde.java create mode 100644 400_xowa/src/gplx/xowa/xtns/cite/References_nde_basic_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/cite/References_nde_group_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/cite/References_nde_pre_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/cite/References_nde_rare_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/dynamicPageList/Dpl_html_data.java create mode 100644 400_xowa/src/gplx/xowa/xtns/dynamicPageList/Dpl_itm.java create mode 100644 400_xowa/src/gplx/xowa/xtns/dynamicPageList/Dpl_itm_keys.java create mode 100644 400_xowa/src/gplx/xowa/xtns/dynamicPageList/Dpl_page.java create mode 100644 400_xowa/src/gplx/xowa/xtns/dynamicPageList/Dpl_redirect.java create mode 100644 400_xowa/src/gplx/xowa/xtns/dynamicPageList/Dpl_sort.java create mode 100644 400_xowa/src/gplx/xowa/xtns/dynamicPageList/Dpl_xnde.java create mode 100644 400_xowa/src/gplx/xowa/xtns/dynamicPageList/Dpl_xnde_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/flaggedRevs/Pages_using_pending_changes_func.java create mode 100644 400_xowa/src/gplx/xowa/xtns/flaggedRevs/Pages_using_pending_changes_func_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/flaggedRevs/Pending_change_level_func.java create mode 100644 400_xowa/src/gplx/xowa/xtns/flaggedRevs/Pending_change_level_func_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/gallery/Gallery_box_w_fmtr_arg.java create mode 100644 400_xowa/src/gplx/xowa/xtns/gallery/Gallery_html_wtr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/gallery/Gallery_html_wtr_utl.java create mode 100644 400_xowa/src/gplx/xowa/xtns/gallery/Gallery_itm.java create mode 100644 400_xowa/src/gplx/xowa/xtns/gallery/Gallery_itm_parser.java create mode 100644 400_xowa/src/gplx/xowa/xtns/gallery/Gallery_itm_parser_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/gallery/Gallery_mgr_base.java create mode 100644 400_xowa/src/gplx/xowa/xtns/gallery/Gallery_mgr_base_.java create mode 100644 400_xowa/src/gplx/xowa/xtns/gallery/Gallery_mgr_base_basic_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/gallery/Gallery_mgr_base_xnde_atrs_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/gallery/Gallery_mgr_packed_base.java create mode 100644 400_xowa/src/gplx/xowa/xtns/gallery/Gallery_xnde.java create mode 100644 400_xowa/src/gplx/xowa/xtns/gallery/Gallery_xnde_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/gallery/Gallery_xtn_mgr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/geoCrumbs/Geoc_isin_func.java create mode 100644 400_xowa/src/gplx/xowa/xtns/geoCrumbs/Geoc_isin_func_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/geoCrumbs/Geoc_isin_mgr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/geodata/Geo_coordinates_func.java create mode 100644 400_xowa/src/gplx/xowa/xtns/geodata/Geo_coordinates_func_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/hieros/Hiero_file_mgr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/hieros/Hiero_html_mgr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/hieros/Hiero_html_mgr_fxt.java create mode 100644 400_xowa/src/gplx/xowa/xtns/hieros/Hiero_html_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/hieros/Hiero_html_wtr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/hieros/Hiero_mw_tables_parser.java create mode 100644 400_xowa/src/gplx/xowa/xtns/hieros/Hiero_mw_tables_parser_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/hieros/Hiero_parser.java create mode 100644 400_xowa/src/gplx/xowa/xtns/hieros/Hiero_parser_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/hieros/Hiero_phoneme_mgr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/hieros/Hiero_prefab_mgr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/hieros/Hiero_xnde.java create mode 100644 400_xowa/src/gplx/xowa/xtns/hieros/Hiero_xtn_mgr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/imaps/Imap_desc_tid.java create mode 100644 400_xowa/src/gplx/xowa/xtns/imaps/Imap_html_fmtrs.java create mode 100644 400_xowa/src/gplx/xowa/xtns/imaps/Imap_img_fmtr_arg.java create mode 100644 400_xowa/src/gplx/xowa/xtns/imaps/Imap_itm.java create mode 100644 400_xowa/src/gplx/xowa/xtns/imaps/Imap_itm_shape.java create mode 100644 400_xowa/src/gplx/xowa/xtns/imaps/Imap_map.java create mode 100644 400_xowa/src/gplx/xowa/xtns/imaps/Imap_map_fmtr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/imaps/Imap_parser.java create mode 100644 400_xowa/src/gplx/xowa/xtns/imaps/Imap_parser_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/imaps/Imap_pts_fmtr_arg.java create mode 100644 400_xowa/src/gplx/xowa/xtns/imaps/Imap_xnde.java create mode 100644 400_xowa/src/gplx/xowa/xtns/imaps/Imap_xnde_html_all_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/imaps/Imap_xnde_html_itm_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/imaps/Imap_xtn_mgr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/indicators/Indicator_html_bldr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/indicators/Indicator_html_bldr_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/indicators/Indicator_xnde.java create mode 100644 400_xowa/src/gplx/xowa/xtns/indicators/Indicator_xnde_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/indicators/Indicator_xtn_mgr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/inputBox/Xtn_inputbox_nde.java create mode 100644 400_xowa/src/gplx/xowa/xtns/inputBox/Xtn_inputbox_nde_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/insiders/Insider_func.java create mode 100644 400_xowa/src/gplx/xowa/xtns/insiders/Insider_func_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/insiders/Insider_html_bldr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/insiders/Insider_html_bldr_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/insiders/Insider_xtn_mgr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/listings/Listing_xnde.java create mode 100644 400_xowa/src/gplx/xowa/xtns/listings/Listing_xnde_basic_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/listings/Listing_xnde_template_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/listings/Listing_xtn_mgr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/lst/Lst_pfunc_lst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/lst/Lst_pfunc_lst_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/lst/Lst_pfunc_lstx.java create mode 100644 400_xowa/src/gplx/xowa/xtns/lst/Lst_pfunc_lstx_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/lst/Lst_pfunc_wkr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/lst/Lst_section_nde.java create mode 100644 400_xowa/src/gplx/xowa/xtns/lst/Lst_section_nde_mgr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/lst/Lst_section_nde_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/mapSources/Map_dd2dms_func.java create mode 100644 400_xowa/src/gplx/xowa/xtns/mapSources/Map_dd2dms_func_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/mapSources/Map_deg2dd_func.java create mode 100644 400_xowa/src/gplx/xowa/xtns/mapSources/Map_deg2dd_func_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/mapSources/Map_geolink_func.java create mode 100644 400_xowa/src/gplx/xowa/xtns/mapSources/Map_geolink_func_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/mapSources/Map_math.java create mode 100644 400_xowa/src/gplx/xowa/xtns/massMessage/Message_target_func.java create mode 100644 400_xowa/src/gplx/xowa/xtns/massMessage/Message_target_func_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/math/Math_nde.java create mode 100644 400_xowa/src/gplx/xowa/xtns/math/Xof_math_html_wtr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/math/Xof_math_itm.java create mode 100644 400_xowa/src/gplx/xowa/xtns/math/Xof_math_mgr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/math/Xof_math_mgr_html_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/math/Xof_math_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/math/Xof_math_subst_regy.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/Pf_func.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/Pf_func_.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/Pf_func_base.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/exprs/Pfunc_expr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/exprs/Pfunc_expr_ops.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/exprs/Pfunc_expr_shunter.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/exprs/Pfunc_expr_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/ifs/Pfunc_if.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/ifs/Pfunc_if_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/ifs/Pfunc_ifeq.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/ifs/Pfunc_ifeq_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/ifs/Pfunc_iferror.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/ifs/Pfunc_iferror_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/ifs/Pfunc_ifexist.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/ifs/Pfunc_ifexist_mgr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/ifs/Pfunc_ifexist_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/ifs/Pfunc_ifexpr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/ifs/Pfunc_ifexpr_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/ifs/Pfunc_switch.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/ifs/Pfunc_switch_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/ifs/Xop_xowa_dbg.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/langs/Pfunc_gender.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/langs/Pfunc_gender_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/langs/Pfunc_grammar.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/langs/Pfunc_grammar_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/langs/Pfunc_i18n_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/langs/Pfunc_int.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/langs/Pfunc_int_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/langs/Pfunc_language.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/langs/Pfunc_language_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/langs/Pfunc_plural.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/langs/Pfunc_plural_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/numbers/Pf_formatnum.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/numbers/Pf_formatnum_de_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/numbers/Pf_formatnum_en_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/numbers/Pf_formatnum_es_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/numbers/Pf_formatnum_fa_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/pages/Pfunc_defaultsort.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/pages/Pfunc_displaytitle.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/pages/Pfunc_displaytitle_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/pages/Pfunc_misc_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/pages/Pfunc_noeditsection.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/pages/Pfunc_rev_props.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/pages/Pfunc_rev_props_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/scribunto/Pfunc_scrib_lib.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/scribunto/Pfunc_scrib_lib_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/scribunto/Pfunc_xtn_mgr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/strings/Pfunc_case.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/strings/Pfunc_case_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/strings/Pfunc_pad.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/strings/Pfunc_pad_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/strings/Pfunc_tag.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/strings/Pfunc_tag_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/stringutils/Pfunc_count.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/stringutils/Pfunc_count_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/stringutils/Pfunc_explode.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/stringutils/Pfunc_explode_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/stringutils/Pfunc_len.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/stringutils/Pfunc_len_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/stringutils/Pfunc_pos.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/stringutils/Pfunc_pos_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/stringutils/Pfunc_replace.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/stringutils/Pfunc_replace_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/stringutils/Pfunc_rpos.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/stringutils/Pfunc_rpos_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/stringutils/Pfunc_sub.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/stringutils/Pfunc_sub_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/stringutils/Pfunc_urldecode.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/stringutils/Pfunc_urldecode_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pft_fmt_itm.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pft_fmt_itm_.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pft_fmt_itm_foreign.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pft_fmt_itm_seg_int.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pft_func_date_int.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pft_func_date_lcl_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pft_func_date_name.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pft_func_date_rev_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pft_func_date_utc_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pft_func_formatdate.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pft_func_formatdate_bldr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pft_func_formatdate_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pft_func_time.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pft_func_time_basic_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pft_func_time_foreign_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pft_func_time_int_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pft_func_time_uncommon_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pxd_eval_seg.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pxd_itm_.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pxd_itm_int.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pxd_itm_misc.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pxd_itm_month_name.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pxd_parser.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pxd_parser_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/ttls/Pfunc_anchorencode.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/ttls/Pfunc_anchorencode_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/ttls/Pfunc_filepath.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/ttls/Pfunc_filepath_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/ttls/Pfunc_ns.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/ttls/Pfunc_ns_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/ttls/Pfunc_rel2abs.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/ttls/Pfunc_rel2abs_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/ttls/Pfunc_titleparts.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/ttls/Pfunc_titleparts_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/ttls/Pfunc_ttl.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/ttls/Pfunc_ttl_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/ttls/Pfunc_urlencode.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/ttls/Pfunc_urlencode_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/ttls/Pfunc_urlfunc.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/ttls/Pfunc_urlfunc_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/wikis/Pfunc_pagesincategory.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/wikis/Pfunc_wiki_props.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/wikis/Pfunc_wiki_props_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/wikis/Pfunc_wiki_stats.java create mode 100644 400_xowa/src/gplx/xowa/xtns/pfuncs/wikis/Pfunc_wiki_stats_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/poems/Poem_nde.java create mode 100644 400_xowa/src/gplx/xowa/xtns/poems/Poem_nde_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/poems/Poem_xtn_mgr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/proofreadPage/Pp_index_parser.java create mode 100644 400_xowa/src/gplx/xowa/xtns/proofreadPage/Pp_pagelist_nde.java create mode 100644 400_xowa/src/gplx/xowa/xtns/proofreadPage/Pp_pagelist_nde_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/proofreadPage/Pp_pagequality_nde.java create mode 100644 400_xowa/src/gplx/xowa/xtns/proofreadPage/Pp_pagequality_nde_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/proofreadPage/Pp_pages_nde.java create mode 100644 400_xowa/src/gplx/xowa/xtns/proofreadPage/Pp_pages_nde_basic_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/proofreadPage/Pp_pages_nde_hdr_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/proofreadPage/Pp_pages_nde_index_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/proofreadPage/Pp_pages_nde_recursion_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/proofreadPage/Pp_xtn_mgr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/quiz/Quiz_xnde.java create mode 100644 400_xowa/src/gplx/xowa/xtns/quiz/Quiz_xnde_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/relatedArticles/Articles_func.java create mode 100644 400_xowa/src/gplx/xowa/xtns/relatedArticles/Articles_func_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/relatedSites/Sites_html_bldr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/relatedSites/Sites_html_bldr_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/relatedSites/Sites_regy_itm.java create mode 100644 400_xowa/src/gplx/xowa/xtns/relatedSites/Sites_regy_mgr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/relatedSites/Sites_xtn_mgr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/rss/Rss_xnde.java create mode 100644 400_xowa/src/gplx/xowa/xtns/rss/Rss_xnde_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scores/Score_xnde.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scores/Score_xnde_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scores/Score_xtn_mgr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_core.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_core_fxt.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_core_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_err_filter_mgr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_err_filter_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_frame_.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_fsys_mgr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_fsys_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_invoke_func.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_invoke_func_fxt.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_kv_utl_.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_lib.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_lib_mgr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_lua_mod.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_lua_proc.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_proc.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_proc_args.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_proc_mgr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_proc_rslt.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/Scrib_xtn_mgr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/engines/Scrib_engine.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/engines/Scrib_engine_type.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/engines/Scrib_server.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/engines/luaj/Luaj_engine.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/engines/luaj/Luaj_server.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/engines/luaj/Luaj_server_func_dbg.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/engines/luaj/Luaj_server_func_recv.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/engines/luaj/Luaj_value.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/engines/process/Process_engine.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/engines/process/Process_recv_msg.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/engines/process/Process_send_wtr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/engines/process/Process_send_wtr_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/engines/process/Process_server.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/engines/process/Process_server_mock.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/engines/process/Process_stream_rdr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/engines/process/Process_stream_rdr_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/errs/Gfo_comp_op_1.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/errs/Gfo_fld_owner.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/errs/Gfo_val.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/errs/Scrib_err_mgr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/libs/Scrib_lib_html.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/libs/Scrib_lib_language.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/libs/Scrib_lib_language_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/libs/Scrib_lib_message.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/libs/Scrib_lib_message_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/libs/Scrib_lib_mw.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/libs/Scrib_lib_mw__invoke_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/libs/Scrib_lib_mw__lib_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/libs/Scrib_lib_site.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/libs/Scrib_lib_site_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/libs/Scrib_lib_text.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/libs/Scrib_lib_text_html_entities.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/libs/Scrib_lib_text_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/libs/Scrib_lib_title.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/libs/Scrib_lib_title_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/libs/Scrib_lib_uri.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/libs/Scrib_lib_uri_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/libs/Scrib_lib_ustring.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/libs/Scrib_lib_ustring__invoke_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/libs/Scrib_lib_ustring__lib_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/libs/Scrib_lib_wikibase.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/libs/Scrib_lib_wikibase_entity.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/libs/Scrib_lib_wikibase_entity_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/libs/Scrib_lib_wikibase_srl.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/libs/Scrib_lib_wikibase_srl_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/libs/Scrib_lib_wikibase_srl_visitor.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/libs/Scrib_lib_wikibase_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/libs/Scrib_regx_converter.java create mode 100644 400_xowa/src/gplx/xowa/xtns/scribunto/libs/Scrib_regx_converter_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/syntaxHighlight/Int_rng_mgr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/syntaxHighlight/Int_rng_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/syntaxHighlight/Xtn_syntaxHighlight_nde.java create mode 100644 400_xowa/src/gplx/xowa/xtns/syntaxHighlight/Xtn_syntaxHighlight_nde_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/templateData/Xtn_templateData_nde.java create mode 100644 400_xowa/src/gplx/xowa/xtns/templateData/Xtn_templateData_nde_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/titleBlacklists/Blacklist_scrib_lib.java create mode 100644 400_xowa/src/gplx/xowa/xtns/titleBlacklists/Blacklist_scrib_lib_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/titleBlacklists/Blacklist_xtn_mgr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/translates/Xop_languages_xnde.java create mode 100644 400_xowa/src/gplx/xowa/xtns/translates/Xop_languages_xnde_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/translates/Xop_mylanguage_page.java create mode 100644 400_xowa/src/gplx/xowa/xtns/translates/Xop_mylanguage_page_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/translates/Xop_translate_xnde.java create mode 100644 400_xowa/src/gplx/xowa/xtns/translates/Xop_translate_xnde_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/translates/Xop_tvar_lxr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/translates/Xop_tvar_lxr_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/translates/Xop_tvar_tkn.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/Wdata_doc.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/Wdata_doc_bldr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/Wdata_doc_wtr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/Wdata_prop_val_visitor.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/Wdata_wiki_mgr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/Wdata_wiki_mgr_fxt.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/Wdata_wiki_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/Wdata_xtn_mgr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/Wdata_xwiki_link_wtr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/Wdata_xwiki_link_wtr_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/core/Wdata_alias_itm.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/core/Wdata_claim_grp.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/core/Wdata_claim_grp_list.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/core/Wdata_claim_itm_base.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/core/Wdata_claim_itm_core.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/core/Wdata_claim_itm_entity.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/core/Wdata_claim_itm_globecoordinate.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/core/Wdata_claim_itm_monolingualtext.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/core/Wdata_claim_itm_quantity.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/core/Wdata_claim_itm_str.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/core/Wdata_claim_itm_system.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/core/Wdata_claim_itm_time.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/core/Wdata_claim_visitor.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/core/Wdata_date.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/core/Wdata_date_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/core/Wdata_dict_claim.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/core/Wdata_dict_claim_v1.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/core/Wdata_dict_datavalue.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/core/Wdata_dict_langtext.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/core/Wdata_dict_mainsnak.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/core/Wdata_dict_rank.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/core/Wdata_dict_reference.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/core/Wdata_dict_sitelink.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/core/Wdata_dict_snak_tid.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/core/Wdata_dict_utl.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/core/Wdata_dict_val_tid.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/core/Wdata_dict_value_entity.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/core/Wdata_dict_value_entity_tid.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/core/Wdata_dict_value_globecoordinate.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/core/Wdata_dict_value_monolingualtext.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/core/Wdata_dict_value_quantity.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/core/Wdata_dict_value_string.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/core/Wdata_dict_value_time.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/core/Wdata_lang_sortable.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/core/Wdata_lang_sorter.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/core/Wdata_langtext_itm.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/core/Wdata_references_grp.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/core/Wdata_sitelink_itm.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/hwtrs/Wdata_fmtr__claim.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/hwtrs/Wdata_fmtr__json.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/hwtrs/Wdata_fmtr__langtext.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/hwtrs/Wdata_fmtr__oview.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/hwtrs/Wdata_fmtr__slink.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/hwtrs/Wdata_fmtr__toc.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/hwtrs/Wdata_hwtr_mgr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/hwtrs/Wdata_hwtr_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/hwtrs/Wdata_hwtr_msgs.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/hwtrs/Wdata_lbl_itm.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/hwtrs/Wdata_lbl_mgr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/hwtrs/Wdata_lbl_wkr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/hwtrs/Wdata_lbl_wkr_wiki.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/hwtrs/Wdata_slink_grp.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/hwtrs/Wdata_visitor__html_wtr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/hwtrs/Wdata_visitor__html_wtr_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/hwtrs/Wdata_visitor__lbl_gatherer.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/imports/Io_stream_rdr_mgr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/imports/Wdata_idx_mgr_base.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/imports/Wdata_idx_wtr.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/imports/Xob_site_ns_cmd.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/imports/Xob_wbase_json_dump_cmd.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/imports/Xob_wbase_json_dump_db.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/imports/Xob_wbase_json_dump_parser.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/imports/Xob_wbase_ns_parser.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/imports/Xob_wdata_db_cmd.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/imports/Xob_wdata_pid_base.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/imports/Xob_wdata_pid_base_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/imports/Xob_wdata_pid_sql.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/imports/Xob_wdata_pid_txt.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/imports/Xob_wdata_qid_base.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/imports/Xob_wdata_qid_base_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/imports/Xob_wdata_qid_sql.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/imports/Xob_wdata_qid_txt.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/parsers/Wdata_claims_parser_v2.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/parsers/Wdata_doc_parser.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/parsers/Wdata_doc_parser_fxt_base.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/parsers/Wdata_doc_parser_v1.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/parsers/Wdata_doc_parser_v1_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/parsers/Wdata_doc_parser_v2.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/parsers/Wdata_doc_parser_v2_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/pfuncs/Wdata_external_lang_links_data.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/pfuncs/Wdata_pf_noExternalLangLinks.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/pfuncs/Wdata_pf_noExternalLangLinks_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/pfuncs/Wdata_pf_property.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/pfuncs/Wdata_pf_property_data.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/pfuncs/Wdata_pf_property_fmt.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/pfuncs/Wdata_pf_property_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/pfuncs/Wdata_pf_wbreponame.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/pfuncs/Wdata_pf_wbreponame_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/specials/Wdata_itemByTitle_cfg.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/specials/Wdata_itemByTitle_page.java create mode 100644 400_xowa/src/gplx/xowa/xtns/wdatas/specials/Wdata_itemByTitle_page_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/xowa_cmds/Xop_xowa_cmd.java create mode 100644 400_xowa/src/gplx/xowa/xtns/xowa_cmds/Xop_xowa_cmd_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/xowa_cmds/Xop_xowa_func.java create mode 100644 400_xowa/src/gplx/xowa/xtns/xowa_cmds/Xop_xowa_func_tst.java create mode 100644 400_xowa/src/gplx/xowa/xtns/xowa_cmds/Xox_xowa_html_cmd.java create mode 100644 400_xowa/src/gplx/xowa/xtns/xowa_cmds/Xox_xowa_html_cmd_tst.java create mode 100644 400_xowa/src/gplx/xowa2/apps/Xoav_app.java create mode 100644 400_xowa/src/gplx/xowa2/apps/Xoav_wiki_mgr.java create mode 100644 400_xowa/src/gplx/xowa2/apps/urls/Xoav_url.java create mode 100644 400_xowa/src/gplx/xowa2/apps/urls/Xoav_url_parser.java create mode 100644 400_xowa/src/gplx/xowa2/apps/urls/Xoav_url_parser_tst.java create mode 100644 400_xowa/src/gplx/xowa2/files/Xofv_file_mgr_tst.java create mode 100644 400_xowa/src/gplx/xowa2/files/Xofv_repo_itm.java create mode 100644 400_xowa/src/gplx/xowa2/files/Xofv_repo_mgr.java create mode 100644 400_xowa/src/gplx/xowa2/files/commons/Xof_commons_image_itm.java create mode 100644 400_xowa/src/gplx/xowa2/files/commons/Xof_commons_image_tbl.java create mode 100644 400_xowa/src/gplx/xowa2/gui/Xog_page.java create mode 100644 400_xowa/src/gplx/xowa2/gui/Xogv_page_load_wkr.java create mode 100644 400_xowa/src/gplx/xowa2/gui/Xogv_tab_base.java create mode 100644 400_xowa/src/gplx/xowa2/users/Xouv_cfg_keys.java create mode 100644 400_xowa/src/gplx/xowa2/wikis/Xowv_repo_mgr.java create mode 100644 400_xowa/src/gplx/xowa2/wikis/Xowv_wiki.java create mode 100644 400_xowa/src/gplx/xowa2/wikis/specials/Xosp_special_mgr.java create mode 100644 400_xowa/src_040_io/gplx/ios/BinaryHeap_Io_line_rdr.java create mode 100644 400_xowa/src_040_io/gplx/ios/BinaryHeap_Io_line_rdr_tst.java create mode 100644 400_xowa/src_040_io/gplx/ios/Io_buffer_rdr.java create mode 100644 400_xowa/src_040_io/gplx/ios/Io_buffer_rdr_tst.java create mode 100644 400_xowa/src_040_io/gplx/ios/Io_fil_chkr.java create mode 100644 400_xowa/src_040_io/gplx/ios/Io_line_rdr.java create mode 100644 400_xowa/src_040_io/gplx/ios/Io_line_rdr_key_gen.java create mode 100644 400_xowa/src_040_io/gplx/ios/Io_line_rdr_key_gen_.java create mode 100644 400_xowa/src_040_io/gplx/ios/Io_line_rdr_tst.java create mode 100644 400_xowa/src_040_io/gplx/ios/Io_make_cmd.java create mode 100644 400_xowa/src_040_io/gplx/ios/Io_sort.java create mode 100644 400_xowa/src_040_io/gplx/ios/Io_sort_cmd.java create mode 100644 400_xowa/src_040_io/gplx/ios/Io_sort_filCmd.java create mode 100644 400_xowa/src_040_io/gplx/ios/Io_sort_fil_basic.java create mode 100644 400_xowa/src_040_io/gplx/ios/Io_sort_misc_tst.java create mode 100644 400_xowa/src_040_io/gplx/ios/Io_sort_split_itm.java create mode 100644 400_xowa/src_040_io/gplx/ios/Io_sort_split_itm_sorter.java create mode 100644 400_xowa/src_040_io/gplx/ios/Io_sort_tst.java create mode 100644 400_xowa/src_040_io/gplx/ios/Io_url_gen.java create mode 100644 400_xowa/src_040_io/gplx/ios/Io_url_gen_.java create mode 100644 400_xowa/src_060_utl/gplx/App_cmd_arg.java create mode 100644 400_xowa/src_060_utl/gplx/App_cmd_mgr.java create mode 100644 400_xowa/src_060_utl/gplx/App_cmd_mgr_tst.java create mode 100644 400_xowa/src_060_utl/gplx/Bry_cache.java create mode 100644 400_xowa/src_060_utl/gplx/ByteAryAry_chkr.java create mode 100644 400_xowa/src_060_utl/gplx/GfoCacheMgr_tst.java create mode 100644 400_xowa/src_060_utl/gplx/Gfo_cache_mgr.java create mode 100644 400_xowa/src_060_utl/gplx/Gfo_url.java create mode 100644 400_xowa/src_060_utl/gplx/Gfo_url_arg.java create mode 100644 400_xowa/src_060_utl/gplx/Gfo_url_parser.java create mode 100644 400_xowa/src_060_utl/gplx/Gfo_url_parser_tst.java create mode 100644 400_xowa/src_060_utl/gplx/Gfo_url_site_data.java create mode 100644 400_xowa/src_060_utl/gplx/Gfo_usr_dlg__gui__opt.java create mode 100644 400_xowa/src_060_utl/gplx/Gfo_usr_dlg__gui__swt.java create mode 100644 400_xowa/src_060_utl/gplx/Gfo_usr_dlg_fmt.java create mode 100644 400_xowa/src_060_utl/gplx/HierPosAryBldr.java create mode 100644 400_xowa/src_060_utl/gplx/HierPosAryBldr_tst.java create mode 100644 400_xowa/src_060_utl/gplx/Int_2_ref.java create mode 100644 400_xowa/src_060_utl/gplx/Int_2_val.java create mode 100644 400_xowa/src_060_utl/gplx/Int_ary_parser.java create mode 100644 400_xowa/src_060_utl/gplx/Int_ary_parser_tst.java create mode 100644 400_xowa/src_060_utl/gplx/Int_list.java create mode 100644 400_xowa/src_060_utl/gplx/Io_zip_mgr.java create mode 100644 400_xowa/src_060_utl/gplx/Io_zip_mgr_base.java create mode 100644 400_xowa/src_060_utl/gplx/Io_zip_mgr_mok.java create mode 100644 400_xowa/src_060_utl/gplx/Io_zip_mgr_tst.java create mode 100644 400_xowa/src_060_utl/gplx/Number_parser.java create mode 100644 400_xowa/src_060_utl/gplx/Number_parser_tst.java create mode 100644 400_xowa/src_060_utl/gplx/Obj_ary_parser_base.java create mode 100644 400_xowa/src_060_utl/gplx/StatRng.java create mode 100644 400_xowa/src_060_utl/gplx/StatRng_tst.java create mode 100644 400_xowa/src_060_utl/gplx/Tst_chkr.java create mode 100644 400_xowa/src_060_utl/gplx/Tst_mgr.java create mode 100644 400_xowa/src_060_utl/gplx/Url_encoder.java create mode 100644 400_xowa/src_060_utl/gplx/Url_encoder_tst.java create mode 100644 400_xowa/src_100_app/gplx/xowa/Xoa_cur.java create mode 100644 400_xowa/src_100_app/gplx/xowa/Xoa_hive_mgr.java create mode 100644 400_xowa/src_100_app/gplx/xowa/Xoa_sys_cfg.java create mode 100644 400_xowa/src_100_app/gplx/xowa/Xoac_lang_grp.java create mode 100644 400_xowa/src_100_app/gplx/xowa/Xoac_lang_grp_tst.java create mode 100644 400_xowa/src_100_app/gplx/xowa/Xoac_lang_itm.java create mode 100644 400_xowa/src_100_app/gplx/xowa/Xoac_wiki_cfg_bldr_cmd.java create mode 100644 400_xowa/src_100_app/gplx/xowa/Xoac_wiki_cfg_bldr_fil.java create mode 100644 400_xowa/src_100_app/gplx/xowa/Xoac_wiki_grp.java create mode 100644 400_xowa/src_100_app/gplx/xowa/Xoac_wiki_grp_tst.java create mode 100644 400_xowa/src_100_app/gplx/xowa/Xoac_wiki_itm.java create mode 100644 400_xowa/src_100_app/gplx/xowa/Xoad_wtr_dump.java create mode 100644 400_xowa/src_120_wiki/gplx/xowa/Bfmtr_eval_wiki.java create mode 100644 400_xowa/src_120_wiki/gplx/xowa/Xow_fragment_mgr.java create mode 100644 400_xowa/src_120_wiki/gplx/xowa/Xow_fragment_mgr_tst.java create mode 100644 400_xowa/src_120_wiki/gplx/xowa/Xow_gui_mgr.java create mode 100644 400_xowa/src_120_wiki/gplx/xowa/Xow_html_util.java create mode 100644 400_xowa/src_120_wiki/gplx/xowa/Xow_mainpage_finder.java create mode 100644 400_xowa/src_120_wiki/gplx/xowa/Xow_mainpage_finder_tst.java create mode 100644 400_xowa/src_120_wiki/gplx/xowa/Xow_msg_mgr.java create mode 100644 400_xowa/src_120_wiki/gplx/xowa/Xow_ns.java create mode 100644 400_xowa/src_120_wiki/gplx/xowa/Xow_ns_.java create mode 100644 400_xowa/src_120_wiki/gplx/xowa/Xow_ns_case_.java create mode 100644 400_xowa/src_120_wiki/gplx/xowa/Xow_ns_mgr.java create mode 100644 400_xowa/src_120_wiki/gplx/xowa/Xow_ns_mgr_.java create mode 100644 400_xowa/src_120_wiki/gplx/xowa/Xow_ns_mgr_tst.java create mode 100644 400_xowa/src_120_wiki/gplx/xowa/Xow_ns_tst.java create mode 100644 400_xowa/src_120_wiki/gplx/xowa/Xow_script_mgr.java create mode 100644 400_xowa/src_120_wiki/gplx/xowa/Xow_sys_cfg.java create mode 100644 400_xowa/src_120_wiki/gplx/xowa/Xow_user.java create mode 100644 400_xowa/src_120_wiki/gplx/xowa/Xow_utl_mgr.java create mode 100644 400_xowa/src_120_wiki/gplx/xowa/Xow_wiki.java create mode 100644 400_xowa/src_120_wiki/gplx/xowa/Xow_wiki_props.java create mode 100644 400_xowa/src_120_wiki/gplx/xowa/Xow_wiki_stats.java create mode 100644 400_xowa/src_120_wiki/gplx/xowa/Xow_wiki_tst.java create mode 100644 400_xowa/src_120_wiki/gplx/xowa/Xowc_parser.java create mode 100644 400_xowa/src_120_wiki/gplx/xowa/Xowc_xtn_pages.java create mode 100644 400_xowa/src_120_wiki/gplx/xowa/Xowc_xtn_pages_tst.java create mode 100644 400_xowa/src_120_wiki/gplx/xowa/Xowc_xtns.java create mode 100644 400_xowa/src_120_wiki/gplx/xowa/Xowe_wiki.java create mode 100644 400_xowa/src_120_wiki/gplx/xowa/Xowe_wiki_bldr.java create mode 100644 400_xowa/src_121_wiki_data/gplx/xowa/Bry_comparer_fld_last.java create mode 100644 400_xowa/src_121_wiki_data/gplx/xowa/ByteAry_fil.java create mode 100644 400_xowa/src_121_wiki_data/gplx/xowa/Io_txn_itm_save.java create mode 100644 400_xowa/src_121_wiki_data/gplx/xowa/Xob_hive_mgr.java create mode 100644 400_xowa/src_121_wiki_data/gplx/xowa/Xob_hive_mgr_tst.java create mode 100644 400_xowa/src_121_wiki_data/gplx/xowa/Xobl_data_itm.java create mode 100644 400_xowa/src_121_wiki_data/gplx/xowa/Xow_data_mgr.java create mode 100644 400_xowa/src_121_wiki_data/gplx/xowa/Xow_data_mgr_tst.java create mode 100644 400_xowa/src_121_wiki_data/gplx/xowa/Xow_hive_mgr_fxt.java create mode 100644 400_xowa/src_121_wiki_data/gplx/xowa/Xowd_hive_mgr.java create mode 100644 400_xowa/src_121_wiki_data/gplx/xowa/Xowd_hive_mgr_tst.java create mode 100644 400_xowa/src_121_wiki_data/gplx/xowa/Xowd_hive_regy_itm.java create mode 100644 400_xowa/src_121_wiki_data/gplx/xowa/Xowd_regy_mgr.java create mode 100644 400_xowa/src_121_wiki_data/gplx/xowa/Xowd_regy_mgr_tst.java create mode 100644 400_xowa/src_140_lang/gplx/xowa/Xobcl_kwd_row.java create mode 100644 400_xowa/src_140_lang/gplx/xowa/Xol_csv_parser.java create mode 100644 400_xowa/src_140_lang/gplx/xowa/Xol_csv_parser_tst.java create mode 100644 400_xowa/src_140_lang/gplx/xowa/Xol_font_info.java create mode 100644 400_xowa/src_140_lang/gplx/xowa/Xol_kwd_grp.java create mode 100644 400_xowa/src_140_lang/gplx/xowa/Xol_kwd_grp_.java create mode 100644 400_xowa/src_140_lang/gplx/xowa/Xol_kwd_itm.java create mode 100644 400_xowa/src_140_lang/gplx/xowa/Xol_kwd_mgr.java create mode 100644 400_xowa/src_140_lang/gplx/xowa/Xol_kwd_parse_data.java create mode 100644 400_xowa/src_140_lang/gplx/xowa/Xol_kwd_parse_data_tst.java create mode 100644 400_xowa/src_140_lang/gplx/xowa/Xol_lang.java create mode 100644 400_xowa/src_140_lang/gplx/xowa/Xol_lang_.java create mode 100644 400_xowa/src_140_lang/gplx/xowa/Xol_lang_srl.java create mode 100644 400_xowa/src_140_lang/gplx/xowa/Xol_lang_srl_tst.java create mode 100644 400_xowa/src_140_lang/gplx/xowa/Xol_lnki_trail_mgr.java create mode 100644 400_xowa/src_140_lang/gplx/xowa/Xol_lnki_trail_mgr_tst.java create mode 100644 400_xowa/src_140_lang/gplx/xowa/Xol_msg_itm.java create mode 100644 400_xowa/src_140_lang/gplx/xowa/Xol_msg_itm_.java create mode 100644 400_xowa/src_140_lang/gplx/xowa/Xol_msg_itm_tst.java create mode 100644 400_xowa/src_140_lang/gplx/xowa/Xol_msg_mgr.java create mode 100644 400_xowa/src_140_lang/gplx/xowa/Xol_msg_mgr_tst.java create mode 100644 400_xowa/src_140_lang/gplx/xowa/Xol_ns_grp.java create mode 100644 400_xowa/src_140_lang/gplx/xowa/Xol_specials_itm.java create mode 100644 400_xowa/src_140_lang/gplx/xowa/Xol_specials_mgr.java create mode 100644 400_xowa/src_160_file/gplx/xowa/Xoa_repo_mgr.java create mode 100644 400_xowa/src_160_file/gplx/xowa/Xof_cfg_download.java create mode 100644 400_xowa/src_160_file/gplx/xowa/Xof_file_mgr.java create mode 100644 400_xowa/src_160_file/gplx/xowa/Xofo_file.java create mode 100644 400_xowa/src_160_file/gplx/xowa/Xofo_lnki.java create mode 100644 400_xowa/src_160_file/gplx/xowa/Xofo_lnki_parser.java create mode 100644 400_xowa/src_160_file/gplx/xowa/Xofo_lnki_parser_tst.java create mode 100644 400_xowa/src_160_file/gplx/xowa/Xofw_file_finder_rslt.java create mode 100644 400_xowa/src_160_file/gplx/xowa/Xofw_wiki_finder.java create mode 100644 400_xowa/src_160_file/gplx/xowa/Xofw_wiki_wkr_base.java create mode 100644 400_xowa/src_160_file/gplx/xowa/Xofw_wiki_wkr_mock.java create mode 100644 400_xowa/src_160_file/gplx/xowa/Xoo_mgr.java create mode 100644 400_xowa/src_161_meta/gplx/xowa/Xof_meta_fil.java create mode 100644 400_xowa/src_161_meta/gplx/xowa/Xof_meta_fil_tst.java create mode 100644 400_xowa/src_161_meta/gplx/xowa/Xof_meta_itm.java create mode 100644 400_xowa/src_161_meta/gplx/xowa/Xof_meta_mgr.java create mode 100644 400_xowa/src_161_meta/gplx/xowa/Xof_meta_mgr_tst.java create mode 100644 400_xowa/src_161_meta/gplx/xowa/Xof_meta_thumb.java create mode 100644 400_xowa/src_161_meta/gplx/xowa/Xof_meta_thumb_parser.java create mode 100644 400_xowa/src_161_meta/gplx/xowa/Xof_meta_thumb_parser_tst.java create mode 100644 400_xowa/src_200_bldr/gplx/xowa/Bry_comparer_bgn_eos.java create mode 100644 400_xowa/src_200_bldr/gplx/xowa/Io_line_rdr_key_gen_all.java create mode 100644 400_xowa/src_200_bldr/gplx/xowa/Io_sort_cmd_img.java create mode 100644 400_xowa/src_200_bldr/gplx/xowa/Io_sort_cmd_img_tst.java create mode 100644 400_xowa/src_200_bldr/gplx/xowa/Io_sort_cmd_ns.java create mode 100644 400_xowa/src_200_bldr/gplx/xowa/Xob_bldr.java create mode 100644 400_xowa/src_200_bldr/gplx/xowa/Xob_make_cmd_site.java create mode 100644 400_xowa/src_200_bldr/gplx/xowa/Xob_page_cmd.java create mode 100644 400_xowa/src_200_bldr/gplx/xowa/Xob_stat_itm.java create mode 100644 400_xowa/src_200_bldr/gplx/xowa/Xob_stat_mgr.java create mode 100644 400_xowa/src_200_bldr/gplx/xowa/Xob_stat_type.java create mode 100644 400_xowa/src_200_bldr/gplx/xowa/Xob_xdat_file.java create mode 100644 400_xowa/src_200_bldr/gplx/xowa/Xob_xdat_file_tst.java create mode 100644 400_xowa/src_200_bldr/gplx/xowa/Xob_xdat_file_wtr.java create mode 100644 400_xowa/src_200_bldr/gplx/xowa/Xob_xdat_file_wtr_tst.java create mode 100644 400_xowa/src_200_bldr/gplx/xowa/Xob_xdat_itm.java create mode 100644 400_xowa/src_200_bldr/gplx/xowa/Xobd_parser.java create mode 100644 400_xowa/src_200_bldr/gplx/xowa/Xobd_parser_wkr.java create mode 100644 400_xowa/src_200_bldr/gplx/xowa/Xobd_rdr.java create mode 100644 400_xowa/src_200_bldr/gplx/xowa/Xobd_wkr.java create mode 100644 400_xowa/src_200_bldr/gplx/xowa/Xobdc_merger.java create mode 100644 400_xowa/src_200_bldr/gplx/xowa/Xobdc_utl.java create mode 100644 400_xowa/src_210_bldr_core/gplx/xowa/Cfg_nde_obj.java create mode 100644 400_xowa/src_210_bldr_core/gplx/xowa/Cfg_nde_obj_.java create mode 100644 400_xowa/src_210_bldr_core/gplx/xowa/Cfg_nde_root.java create mode 100644 400_xowa/src_210_bldr_core/gplx/xowa/Gfs_bldr.java create mode 100644 400_xowa/src_210_bldr_core/gplx/xowa/Sql_file_parser.java create mode 100644 400_xowa/src_210_bldr_core/gplx/xowa/Sql_file_parser_cmd.java create mode 100644 400_xowa/src_210_bldr_core/gplx/xowa/Sql_file_parser_data.java create mode 100644 400_xowa/src_210_bldr_core/gplx/xowa/Sql_file_parser_tst.java create mode 100644 400_xowa/src_210_bldr_core/gplx/xowa/Sql_fld_mgr.java create mode 100644 400_xowa/src_210_bldr_core/gplx/xowa/Sql_fld_mgr_tst.java create mode 100644 400_xowa/src_210_bldr_core/gplx/xowa/Xob_idx_base.java create mode 100644 400_xowa/src_210_bldr_core/gplx/xowa/Xob_itm_basic_base.java create mode 100644 400_xowa/src_210_bldr_core/gplx/xowa/Xob_itm_dump_base.java create mode 100644 400_xowa/src_210_bldr_core/gplx/xowa/Xob_sql_dump_base.java create mode 100644 400_xowa/src_210_bldr_core/gplx/xowa/Xob_tmp_wtr.java create mode 100644 400_xowa/src_210_bldr_core/gplx/xowa/Xob_tmp_wtr_mgr.java create mode 100644 400_xowa/src_210_bldr_core/gplx/xowa/Xob_tmp_wtr_wkr.java create mode 100644 400_xowa/src_210_bldr_core/gplx/xowa/Xob_tmp_wtr_wkr__ttl.java create mode 100644 400_xowa/src_210_bldr_core/gplx/xowa/Xos_url_gen.java create mode 100644 400_xowa/src_210_bldr_core/gplx/xowa/Xos_url_gen_tst.java create mode 100644 400_xowa/src_240_install/gplx/xowa/Xob_dump_file.java create mode 100644 400_xowa/src_240_install/gplx/xowa/Xob_dump_file_.java create mode 100644 400_xowa/src_240_install/gplx/xowa/Xoi_cmd_base.java create mode 100644 400_xowa/src_240_install/gplx/xowa/Xoi_cmd_dumpfile.java create mode 100644 400_xowa/src_240_install/gplx/xowa/Xoi_cmd_dumpfile_tst.java create mode 100644 400_xowa/src_240_install/gplx/xowa/Xoi_cmd_mgr.java create mode 100644 400_xowa/src_240_install/gplx/xowa/Xoi_cmd_wiki.java create mode 100644 400_xowa/src_240_install/gplx/xowa/Xoi_cmd_wiki_import.java create mode 100644 400_xowa/src_240_install/gplx/xowa/Xoi_cmd_wiki_tst.java create mode 100644 400_xowa/src_240_install/gplx/xowa/Xoi_dump_mgr.java create mode 100644 400_xowa/src_240_install/gplx/xowa/Xoi_mirror_parser.java create mode 100644 400_xowa/src_240_install/gplx/xowa/Xoi_mirror_parser_tst.java create mode 100644 400_xowa/src_240_install/gplx/xowa/Xoi_setup_mgr.java create mode 100644 400_xowa/src_240_install/gplx/xowa/Xow_cfg_wiki_core.java create mode 100644 400_xowa/src_240_install/gplx/xowa/Xow_cfg_wiki_core_tst.java create mode 100644 400_xowa/src_300_html/gplx/xowa/Xoa_app_eval.java create mode 100644 400_xowa/src_300_html/gplx/xowa/Xoa_app_eval_tst.java create mode 100644 400_xowa/src_300_html/gplx/xowa/Xoa_page.java create mode 100644 400_xowa/src_300_html/gplx/xowa/Xoa_page_.java create mode 100644 400_xowa/src_300_html/gplx/xowa/Xoa_page__commons_mgr.java create mode 100644 400_xowa/src_300_html/gplx/xowa/Xoae_page.java create mode 100644 400_xowa/src_300_html/gplx/xowa/Xoh_cfg_gallery.java create mode 100644 400_xowa/src_300_html/gplx/xowa/Xoh_dom_.java create mode 100644 400_xowa/src_300_html/gplx/xowa/Xoh_dom_tst.java create mode 100644 400_xowa/src_300_html/gplx/xowa/Xoh_find.java create mode 100644 400_xowa/src_300_html/gplx/xowa/Xop_link_parser.java create mode 100644 400_xowa/src_310_url/gplx/xowa/Xoa_url.java create mode 100644 400_xowa/src_310_url/gplx/xowa/Xoa_url_arg_hash.java create mode 100644 400_xowa/src_310_url/gplx/xowa/Xoa_url_parser.java create mode 100644 400_xowa/src_310_url/gplx/xowa/Xoa_url_parser_basic_tst.java create mode 100644 400_xowa/src_310_url/gplx/xowa/Xoa_url_parser_mw_links_tst.java create mode 100644 400_xowa/src_310_url/gplx/xowa/Xoa_url_parser_url_bar_tst.java create mode 100644 400_xowa/src_310_url/gplx/xowa/Xoa_url_tst.java create mode 100644 400_xowa/src_400_parser/gplx/xowa/Pfunc_titleparts_log.java create mode 100644 400_xowa/src_400_parser/gplx/xowa/TstObj_tst.java create mode 100644 400_xowa/src_400_parser/gplx/xowa/Xoa_ttl.java create mode 100644 400_xowa/src_400_parser/gplx/xowa/Xoa_ttl_chkr.java create mode 100644 400_xowa/src_400_parser/gplx/xowa/Xop_arg_itm_tkn_chkr.java create mode 100644 400_xowa/src_400_parser/gplx/xowa/Xop_ctx.java create mode 100644 400_xowa/src_400_parser/gplx/xowa/Xop_ctx_.java create mode 100644 400_xowa/src_400_parser/gplx/xowa/Xop_ctx__tst.java create mode 100644 400_xowa/src_400_parser/gplx/xowa/Xop_ctx_wkr.java create mode 100644 400_xowa/src_400_parser/gplx/xowa/Xop_fxt.java create mode 100644 400_xowa/src_400_parser/gplx/xowa/Xop_lnki_tkn_chkr.java create mode 100644 400_xowa/src_400_parser/gplx/xowa/Xop_lxr.java create mode 100644 400_xowa/src_400_parser/gplx/xowa/Xop_lxr_.java create mode 100644 400_xowa/src_400_parser/gplx/xowa/Xop_lxr_mgr.java create mode 100644 400_xowa/src_400_parser/gplx/xowa/Xop_lxr_misc.java create mode 100644 400_xowa/src_400_parser/gplx/xowa/Xop_parser.java create mode 100644 400_xowa/src_400_parser/gplx/xowa/Xop_parser_.java create mode 100644 400_xowa/src_400_parser/gplx/xowa/Xop_parser__tst.java create mode 100644 400_xowa/src_400_parser/gplx/xowa/Xop_redirect_mgr.java create mode 100644 400_xowa/src_400_parser/gplx/xowa/Xop_redirect_mgr_tst.java create mode 100644 400_xowa/src_400_parser/gplx/xowa/Xop_sanitizer.java create mode 100644 400_xowa/src_400_parser/gplx/xowa/Xop_sanitizer_tst.java create mode 100644 400_xowa/src_400_parser/gplx/xowa/Xop_tblw_log.java create mode 100644 400_xowa/src_400_parser/gplx/xowa/Xop_tblw_tb_tkn_chkr.java create mode 100644 400_xowa/src_400_parser/gplx/xowa/Xop_tblw_tc_tkn_chkr.java create mode 100644 400_xowa/src_400_parser/gplx/xowa/Xop_tblw_td_tkn_chkr.java create mode 100644 400_xowa/src_400_parser/gplx/xowa/Xop_tblw_th_tkn_chkr.java create mode 100644 400_xowa/src_400_parser/gplx/xowa/Xop_tblw_tr_tkn_chkr.java create mode 100644 400_xowa/src_400_parser/gplx/xowa/Xop_tkn_chkr_base.java create mode 100644 400_xowa/src_400_parser/gplx/xowa/Xop_tkn_chkr_hr.java create mode 100644 400_xowa/src_400_parser/gplx/xowa/Xop_tkn_chkr_lnke.java create mode 100644 400_xowa/src_400_parser/gplx/xowa/Xop_ttl_log.java create mode 100644 400_xowa/src_400_parser/gplx/xowa/Xop_xnde_log.java create mode 100644 400_xowa/src_400_parser/gplx/xowa/Xop_xnde_tkn_chkr.java create mode 100644 400_xowa/src_400_parser/gplx/xowa/Xot_prm_chkr.java create mode 100644 400_xowa/src_405_tkn/gplx/xowa/Xop_bry_tkn.java create mode 100644 400_xowa/src_405_tkn/gplx/xowa/Xop_tkn_grp.java create mode 100644 400_xowa/src_405_tkn/gplx/xowa/Xop_tkn_itm.java create mode 100644 400_xowa/src_405_tkn/gplx/xowa/Xop_tkn_itm_.java create mode 100644 400_xowa/src_405_tkn/gplx/xowa/Xop_tkn_itm_base.java create mode 100644 400_xowa/src_405_tkn/gplx/xowa/Xop_tkn_mkr.java create mode 100644 400_xowa/src_405_tkn/gplx/xowa/Xop_tkn_null.java create mode 100644 400_xowa/src_405_tkn/gplx/xowa/Xop_txt_tkn.java create mode 100644 400_xowa/src_409_tkn_misc/gplx/xowa/Xop_comm_lxr.java create mode 100644 400_xowa/src_409_tkn_misc/gplx/xowa/Xop_comm_lxr_tst.java create mode 100644 400_xowa/src_409_tkn_misc/gplx/xowa/Xop_cr_lxr.java create mode 100644 400_xowa/src_409_tkn_misc/gplx/xowa/Xop_cr_tkn.java create mode 100644 400_xowa/src_409_tkn_misc/gplx/xowa/Xop_eq_lxr.java create mode 100644 400_xowa/src_409_tkn_misc/gplx/xowa/Xop_eq_tkn.java create mode 100644 400_xowa/src_409_tkn_misc/gplx/xowa/Xop_hr_lxr.java create mode 100644 400_xowa/src_409_tkn_misc/gplx/xowa/Xop_hr_lxr_basic_tst.java create mode 100644 400_xowa/src_409_tkn_misc/gplx/xowa/Xop_hr_lxr_para_tst.java create mode 100644 400_xowa/src_409_tkn_misc/gplx/xowa/Xop_hr_tkn.java create mode 100644 400_xowa/src_409_tkn_misc/gplx/xowa/Xop_ignore_tkn.java create mode 100644 400_xowa/src_409_tkn_misc/gplx/xowa/Xop_pipe_lxr.java create mode 100644 400_xowa/src_409_tkn_misc/gplx/xowa/Xop_pipe_tkn.java create mode 100644 400_xowa/src_409_tkn_misc/gplx/xowa/Xop_root_tkn.java create mode 100644 400_xowa/src_409_tkn_misc/gplx/xowa/Xop_space_lxr_tst.java create mode 100644 400_xowa/src_409_tkn_misc/gplx/xowa/Xop_space_tkn.java create mode 100644 400_xowa/src_409_tkn_misc/gplx/xowa/Xop_tab_tkn.java create mode 100644 400_xowa/src_409_tkn_misc/gplx/xowa/Xop_under_lxr.java create mode 100644 400_xowa/src_409_tkn_misc/gplx/xowa/Xop_under_lxr_tst.java create mode 100644 400_xowa/src_409_tkn_misc/gplx/xowa/Xop_under_tkn.java create mode 100644 400_xowa/src_440_lnki/gplx/xowa/Xop_lnki_align_h.java create mode 100644 400_xowa/src_440_lnki/gplx/xowa/Xop_lnki_arg_parser.java create mode 100644 400_xowa/src_440_lnki/gplx/xowa/Xop_lnki_lxr_bgn.java create mode 100644 400_xowa/src_440_lnki/gplx/xowa/Xop_lnki_lxr_end.java create mode 100644 400_xowa/src_440_lnki/gplx/xowa/Xop_lnki_tkn.java create mode 100644 400_xowa/src_440_lnki/gplx/xowa/Xop_lnki_type.java create mode 100644 400_xowa/src_440_lnki/gplx/xowa/Xop_lnki_wkr.java create mode 100644 400_xowa/src_440_lnki/gplx/xowa/Xop_lnki_wkr_.java create mode 100644 400_xowa/src_440_lnki/gplx/xowa/Xop_lnki_wkr__basic_tst.java create mode 100644 400_xowa/src_440_lnki/gplx/xowa/Xop_lnki_wkr__ctg_tst.java create mode 100644 400_xowa/src_440_lnki/gplx/xowa/Xop_lnki_wkr__invalid_tst.java create mode 100644 400_xowa/src_440_lnki/gplx/xowa/Xop_lnki_wkr__link_tst.java create mode 100644 400_xowa/src_440_lnki/gplx/xowa/Xop_lnki_wkr__pre_tst.java create mode 100644 400_xowa/src_440_lnki/gplx/xowa/Xop_lnki_wkr__subpage_tst.java create mode 100644 400_xowa/src_440_lnki/gplx/xowa/Xop_lnki_wkr__uncommon_tst.java create mode 100644 400_xowa/src_440_lnki/gplx/xowa/Xop_lnki_wkr__xwiki_tst.java create mode 100644 400_xowa/src_490_xnde/gplx/xowa/Xop_xatr_hash.java create mode 100644 400_xowa/src_490_xnde/gplx/xowa/Xop_xatr_itm.java create mode 100644 400_xowa/src_490_xnde/gplx/xowa/Xop_xatr_parser.java create mode 100644 400_xowa/src_490_xnde/gplx/xowa/Xop_xatr_parser_tst.java create mode 100644 400_xowa/src_490_xnde/gplx/xowa/Xop_xatr_whitelist_mgr.java create mode 100644 400_xowa/src_490_xnde/gplx/xowa/Xop_xatr_whitelist_mgr_tst.java create mode 100644 400_xowa/src_490_xnde/gplx/xowa/Xop_xnde_atr_parser.java create mode 100644 400_xowa/src_490_xnde/gplx/xowa/Xop_xnde_lxr.java create mode 100644 400_xowa/src_490_xnde/gplx/xowa/Xop_xnde_tag.java create mode 100644 400_xowa/src_490_xnde/gplx/xowa/Xop_xnde_tag_.java create mode 100644 400_xowa/src_490_xnde/gplx/xowa/Xop_xnde_tag_lang.java create mode 100644 400_xowa/src_490_xnde/gplx/xowa/Xop_xnde_tag_regy.java create mode 100644 400_xowa/src_490_xnde/gplx/xowa/Xop_xnde_tag_stack.java create mode 100644 400_xowa/src_490_xnde/gplx/xowa/Xop_xnde_tkn.java create mode 100644 400_xowa/src_490_xnde/gplx/xowa/Xop_xnde_wkr.java create mode 100644 400_xowa/src_490_xnde/gplx/xowa/Xop_xnde_wkr__basic_tst.java create mode 100644 400_xowa/src_490_xnde/gplx/xowa/Xop_xnde_wkr__blockquote_tst.java create mode 100644 400_xowa/src_490_xnde/gplx/xowa/Xop_xnde_wkr__err_dangling_tst.java create mode 100644 400_xowa/src_490_xnde/gplx/xowa/Xop_xnde_wkr__err_malformed_tst.java create mode 100644 400_xowa/src_490_xnde/gplx/xowa/Xop_xnde_wkr__err_misc_tst.java create mode 100644 400_xowa/src_490_xnde/gplx/xowa/Xop_xnde_wkr__include_basic_tst.java create mode 100644 400_xowa/src_490_xnde/gplx/xowa/Xop_xnde_wkr__include_uncommon_tst.java create mode 100644 400_xowa/src_490_xnde/gplx/xowa/Xop_xnde_wkr__li_tst.java create mode 100644 400_xowa/src_490_xnde/gplx/xowa/Xop_xnde_wkr__nowiki_tst.java create mode 100644 400_xowa/src_490_xnde/gplx/xowa/Xop_xnde_wkr__tblx_tst.java create mode 100644 400_xowa/src_490_xnde/gplx/xowa/Xop_xnde_wkr__text_block_tst.java create mode 100644 400_xowa/src_490_xnde/gplx/xowa/Xop_xnde_wkr__tidy_tst.java create mode 100644 400_xowa/src_490_xnde/gplx/xowa/Xop_xnde_wkr__xatrs_tst.java create mode 100644 400_xowa/src_500_tmpl/gplx/xowa/Arg_bldr.java create mode 100644 400_xowa/src_500_tmpl/gplx/xowa/Arg_itm_tkn.java create mode 100644 400_xowa/src_500_tmpl/gplx/xowa/Arg_nde_tkn.java create mode 100644 400_xowa/src_500_tmpl/gplx/xowa/Arg_nde_tkn_mock.java create mode 100644 400_xowa/src_500_tmpl/gplx/xowa/Xop_brack_bgn_lxr.java create mode 100644 400_xowa/src_500_tmpl/gplx/xowa/Xop_brack_end_lxr.java create mode 100644 400_xowa/src_500_tmpl/gplx/xowa/Xop_curly_bgn_lxr.java create mode 100644 400_xowa/src_500_tmpl/gplx/xowa/Xop_curly_bgn_tkn.java create mode 100644 400_xowa/src_500_tmpl/gplx/xowa/Xop_curly_end_lxr.java create mode 100644 400_xowa/src_500_tmpl/gplx/xowa/Xop_curly_wkr.java create mode 100644 400_xowa/src_500_tmpl/gplx/xowa/Xop_subst_tst.java create mode 100644 400_xowa/src_500_tmpl/gplx/xowa/Xop_tkn_.java create mode 100644 400_xowa/src_500_tmpl/gplx/xowa/Xop_tkn_print_tst.java create mode 100644 400_xowa/src_500_tmpl/gplx/xowa/Xot_compile_data.java create mode 100644 400_xowa/src_500_tmpl/gplx/xowa/Xot_defn.java create mode 100644 400_xowa/src_500_tmpl/gplx/xowa/Xot_defn_.java create mode 100644 400_xowa/src_500_tmpl/gplx/xowa/Xot_defn_subst.java create mode 100644 400_xowa/src_500_tmpl/gplx/xowa/Xot_defn_tmpl.java create mode 100644 400_xowa/src_500_tmpl/gplx/xowa/Xot_defn_tmpl_.java create mode 100644 400_xowa/src_500_tmpl/gplx/xowa/Xot_defn_trace.java create mode 100644 400_xowa/src_500_tmpl/gplx/xowa/Xot_defn_trace_brief_tst.java create mode 100644 400_xowa/src_500_tmpl/gplx/xowa/Xot_defn_trace_dbg.java create mode 100644 400_xowa/src_500_tmpl/gplx/xowa/Xot_defn_trace_dbg_tst.java create mode 100644 400_xowa/src_500_tmpl/gplx/xowa/Xot_examples_tst.java create mode 100644 400_xowa/src_500_tmpl/gplx/xowa/Xot_fmtr.java create mode 100644 400_xowa/src_500_tmpl/gplx/xowa/Xot_invk.java create mode 100644 400_xowa/src_500_tmpl/gplx/xowa/Xot_invk_mock.java create mode 100644 400_xowa/src_500_tmpl/gplx/xowa/Xot_invk_sandbox_tst.java create mode 100644 400_xowa/src_500_tmpl/gplx/xowa/Xot_invk_temp.java create mode 100644 400_xowa/src_500_tmpl/gplx/xowa/Xot_invk_tkn.java create mode 100644 400_xowa/src_500_tmpl/gplx/xowa/Xot_invk_wkr.java create mode 100644 400_xowa/src_500_tmpl/gplx/xowa/Xot_invk_wkr_basic_tst.java create mode 100644 400_xowa/src_500_tmpl/gplx/xowa/Xot_invk_wkr_prepend_nl_tst.java create mode 100644 400_xowa/src_500_tmpl/gplx/xowa/Xot_invk_wkr_raw_msg_tst.java create mode 100644 400_xowa/src_500_tmpl/gplx/xowa/Xot_invk_wkr_transclude_tst.java create mode 100644 400_xowa/src_500_tmpl/gplx/xowa/Xot_prm_tkn.java create mode 100644 400_xowa/src_500_tmpl/gplx/xowa/Xot_prm_tkn_tst.java create mode 100644 400_xowa/src_500_tmpl/gplx/xowa/Xot_prm_wkr.java create mode 100644 400_xowa/src_500_tmpl/gplx/xowa/Xot_tmpl_wtr.java create mode 100644 400_xowa/user/anonymous/app/data/cfg/user_system_cfg.gfs create mode 100644 400_xowa/user/anonymous/app/data/cfg/xowa_user_cfg.gfs create mode 100644 400_xowa/user/anonymous/app/tmp/log/current/err.txt create mode 100644 400_xowa/user/anonymous/app/tmp/log/current/session.txt create mode 100644 400_xowa/xtn/gplx/xowa/Xowa_main.java create mode 100644 400_xowa/xtn/gplx/xowa/Xowa_tcp_console.java create mode 100644 LICENSE.txt create mode 100644 README.md create mode 100644 README.txt create mode 100644 build.xml create mode 100644 lib/junit.jar create mode 100644 tst/400_xowa/file/en.wikipedia.org/img_regy.sqlite3 create mode 100644 tst/400_xowa/file/en.wikipedia.org/main/core.sqlite3 create mode 100644 tst/400_xowa/file/en.wikipedia.org/mnt_regy.sqlite3 create mode 100644 tst/400_xowa/root/bin/any/sql/xowa/xowa.sql create mode 100644 tst/400_xowa/root/bin/any/sql/xowa/xowa.sqlite3 create mode 100644 tst/400_xowa/root/file/en.wikipedia.org/file/en.wikipedia.org/fsdb.main/fsdb.abc.sqlite3 create mode 100644 tst/400_xowa/root/file/en.wikipedia.org/file/en.wikipedia.org/fsdb.main/fsdb.atr.00.sqlite3 create mode 100644 tst/400_xowa/root/file/en.wikipedia.org/file/en.wikipedia.org/fsdb.main/fsdb.bin.0000.sqlite3 create mode 100644 tst/400_xowa/root/file/en.wikipedia.org/file/en.wikipedia.org/fsdb.user/fsdb.abc.sqlite3 create mode 100644 tst/400_xowa/root/file/en.wikipedia.org/file/en.wikipedia.org/fsdb.user/fsdb.atr.00.sqlite3 create mode 100644 tst/400_xowa/root/file/en.wikipedia.org/file/en.wikipedia.org/fsdb.user/fsdb.bin.0000.sqlite3 create mode 100644 tst/400_xowa/root/file/en.wikipedia.org/file/en.wikipedia.org/wiki.mnt.sqlite3 create mode 100644 tst/400_xowa/root/file/en.wikipedia.org/file/en.wikipedia.org/wiki.orig#00.sqlite3 create mode 100644 tst/400_xowa/root/user/test_user/app/data/cfg/xowa_user_cfg.gfs create mode 100644 tst/400_xowa/root/wiki/en.wikipedia.org/a.xml create mode 100644 tst/400_xowa/root/wiki/en.wikipedia.org/en.wikipedia.org-text.xowa create mode 100644 tst/400_xowa/root/wiki/en.wikipedia.org/tmp/text.cat.core/0000000000.csv create mode 100644 tst/400_xowa/root/wiki/en.wikipedia.org/tmp/text.cat.hidden/dump/0000000000.csv create mode 100644 tst/400_xowa/root/wiki/en.wikipedia.org/tmp/text.cat.link/dump/0000000000.csv create mode 100644 tst/400_xowa/root/wiki/en.wikipedia.org/tmp/text.cat.link/sort/0000000000.csv diff --git a/.directory b/.directory new file mode 100644 index 000000000..9cdaf085c --- /dev/null +++ b/.directory @@ -0,0 +1,4 @@ +[Dolphin] +Timestamp=2015,7,12,21,9,46 +Version=3 +ViewMode=1 diff --git a/100_core/.classpath b/100_core/.classpath new file mode 100644 index 000000000..57d372839 --- /dev/null +++ b/100_core/.classpath @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/100_core/.project b/100_core/.project new file mode 100644 index 000000000..71ba1b5d0 --- /dev/null +++ b/100_core/.project @@ -0,0 +1,17 @@ + + + 100_core + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/100_core/lib/commons-compress-1.5.jar b/100_core/lib/commons-compress-1.5.jar new file mode 100644 index 0000000000000000000000000000000000000000..0239414e84904a81427539de5a0b0df01a7ec4ce GIT binary patch literal 256241 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

rLKlIgU%f4UTrlTt*{`K)C92 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

BB*U`*Mu(Y4U9*zJ7lSmKJDte%csUwR(Tk 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%0AOCKo3h5Wnca@CCB6s|su@L6o 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%0D$sp#}GGCfL`-zWn;Xf#NADSDipmNf{WX4$74V8 zW{2yY4nK3D;+^UfU|t5%I1o+Bs)*dOT%Pn-i5GCcuhp^~jlTMb<}IT)Uky%Z*YCeq zozr)8dE0b12O2scKL=sXuLKYdX8#>_7Ks&b~iHVqMNpBBED$Fo{TF}xYujl3h zE~4(Dc&LQmtzM-ZGVmM%zv$h83+uKh-d!eF{)-g%ro5(%xW=Z-)!_cq&>t5U1z4oF zL4gT2r>ggg;1^rkX~m*>q%H9T1}ZrobqekMk>6B0;XPYxB%8psIpUjJ=~cQA**tV1 z1N*jerd-S2S0XYEtNKvFf{6)3(XjR=JyVqrWzziXf}roF6TPnH0RwicAjP8Cf?Z38 zqH+9lC@D9Sk@&3n-$eUt>_UwS{hU;dPdr#=+;Us^ z=FgU)T|)|hO~{t^N0BJ)nOS}~yPQR|+q$FX4;SBz-dJELMlB18(cI3GeG6|?9&w=G z;%u?gh^2gOCPuSdnFWu_hR`@ll`e0K^|v51zWZ1;>A86bc29b{+g6l?_-$yp2SgvxigL2MY|T$flu z2r+IXbWosO3!a65gB}iN|H!!eH0&Z#EhnMY7+Tr zx=%&1Zh<+)9o5EAvgQGr+v%W+qe&NTey7S7o~BljCh)>$Qcihb&gy}c%oLyrhx^_N zhsc`y1V?i)UA!u|VY95O+IFk^F@L=)-qgNhbfFAy*ch=Hj+U8BZ@f&Wjfw7yiJqN~ zp02_`-HsN&OpCMKJ2FNKb8Se3qmP9{`a$ITN@X&QP(=e*MziPa3Hcqmhcy7(a*wqQ z#?!y)d9s=B=~@i2qeT(mp@jBa8vbg2ru*6*MAOFQ%6llb9r#@Kc2nby%UuGqFK~ti zQ!cZUf5zY{IH@Ph6-{_{?yA@sF}&dN>gSFuvdD&|QoXx>=ES*svln0h%v~sO#(F<5 z)L@_Xm)*<^;I!WVXN;ccdM6`%DNhAJD%HdCJpRHV_`7V#XdOvuAD5@ zMu2kWmUxP7mDJ6ysyc^12E9XGwxtX}cn z2flQ(=E;Q+<^YM(=SYGqVc%l89kU&m29LmF56i4)TcR&SO)C!DdJE!tk$L!p#i^c4 zPxC@bPmD{*IKPFTFU*f`F#N9Ils9!r?yZA`cur1yXXYAZvikAyCIT;7+7+6|9=F_> z1(R*;Kdmz_QBt4000TBwHGx!k{G+4+lg1&P7wTd&)NFo*a;O$%N(4=(YmKrx$rhPD zf`2|!DyHH8@azig77OJmC&3NEB55qJQ5+lDEH$-NAgsx2^0TyBMC(u5Hy6D0i@=w4 zZs$$TxBTr@UIuT$mI>8|-i6cJ%AJ3taujwB*bvbR*dX1p7dJn0-G#`zsrAZ?dS@%u zkv(KVvpBXRuHQ30sU+3RIE!&m8eTZvqYgD9q4}|PJPMo5+h*90({$snGVgtEgQ*PB=D@|vXXe0 z@;U&%0Yc~iU%PK(ed{Jk>(zXLMepCA+K3Afu8K@hO8$S;19QrRBGn^n!gdgpf*UJ9 z&KHSSa+c;OljkVUXG-%{axqR*NubJ%H*%PDv(3rFPCi~ryeT0bL#EicUmK{2z#vr; zXOH2(Q)Q?1hoL&CTXTi%N`k`R6hlQq9o3G(+9K1FPsF1WCW5B(#>*D1^txDIsP_c; z@n(_i;gP5=ust+3qxFqOknOkmW6b{8Uaq{VNcV{C*(GH2vCP{}J4iw81lFicLxC|x z*dq_iGx^1c>t>425tFDdk~NjlSt@|d6j~QbkTecmCMkosUi8U*yZ}glT`k?Hjum{A zBv2mtmRH&js#^E&hwtphf0?dCt($U8VQ!3$L;;+aatTb_AgBJKl~*2C$i&qaWPFA6w2A8_s22btJOc>pqP&Fr|&47m2jl5}}O*8=;9s?&F-Zay5)RBsd_S0?1o z@ZLSWEgz3%KT8lri4AR4QB(45+IEkw$3RAVxe|t;&2-W$w?OOi& zg}3zg04@vZ#}C2(Sg!QXZ$=p>M_VUH1xI@$J*$7{l~mn46&H~|t&KexI7R8>M1LLN zV+7+PC_*sdp(*?0m*UAaP}4BbjGh=8XAu8s6e@MhS6bf#YOEqN*D9BkMQT*9lt3+4 zvd~CwQr5I6xB5D}%Ve=3VW3r)c>Or)@|fm0-nh=V-*nJ%J=1x<2DK&ngzvG}JQX2r z8mUnVx*oMngxX%Vb^5Wqv-X{!_Q<`Fqo?uX=LQ*#&0Ni(29T$n#Sgys zp5S#L)1E{O>*Ql>`i;_EYPT(bIZwha4!ZS{t<4XPnB>7neJ-l;OpL2}+ipo0Ggsa$ z*s!6iy(*_VchUZS{kxDLTx1@e@%>*2RxnU+wIivu=oA@7D0}2>f)Z!*1 z!qcWNW^yw{yCw+R(?;z&BR3UPKIBW&X0F=()t;`s!KlbXj?OLst-0COm+!oEWyfk+ zS!{@WR1(D0iqw&(l-rC$gk%VJF^AqUAp!-6Dnsh>nH9GtHp8Z&xXR5|ONwNzR4I+4 z9jrh(WrB3=<;~^f+LEFq@)rd&3)5Oryc(a+H$?!A11>TR%ut0tb>fx9}TIi$;HlIaWH#y{;iTtT#0oEv(yeTtV({}e4qC3kM)1N>hON+ zoHT%7J8vpgXV8I9Avc#?)l!b35fDi`SI<2~z-jzuEEY$3s^V6GuQ43 zPIi39pn1EI3{h5$pdb978*t=2`#zyvlPqTSCBUPkXsN~8^ofoNk)cJ_#P3c0QHae;}{D`G(nz>2O3D`+7$U{571t4i7VTpQ~4! zC*@!^Ol>v}7yH^EI_ED#x+t|lp~2xbcg*DZ-}zC^GX780i`(65gq~nWik*`c3I$g% z+}owmfhkP*JI)MbIN5Z^cj$#yNuX}QAch;4zn z<2HVWz@uS$0llrSxKg6~Y9NvQDKLz_Z9Hf#)6G19^n8jeiTF8H3o%fK5x1I9tmJMm7CV#}dA_u03c| zaec;LYm0KhwN8#)HjWR@QAzDP^DH~#vV$yJpE532yz9i)WSouPMvp9cWSW=Rt)_cY zv8MOVEL&bcSy?%uke{x3rB)h&zm0|Tu6^^)Js!9WrWb5K1M&SpL$&15T4SeU2M6r@lykaE;Ir7mas^wZ=(iw zzzmkKMbnnsSFYmWXR+llz1k6-vMj<5l-yQe&|<$S6i&)8>#-A#RIfk8IL6dH+I7Iu z8jucaH27{3HX61y`p|#^#Jio!!19ozzv4rz=Od9eVJSQaDB{Xr`v7bZYkW(P(_d>XvY|&;26W zby^{lDJEuTdNsdQOK<#eFRGdOTlaQ0Cx3#!=&zY*FoB6z3O1VCXM;) z^A_AWQKAJkzD3c}sB>bPnL}MT?>RRbLBN7LiSCDMCeCKC-$SZHnOmB56Ed4GZQGgCIP5eva>(&ufP}y&$%qg16^X=-{QJTw$Tck2W)|G%)h z5wGNu_qCl!gBHD3N^u51&d@n?vsV^cHkemaq3q$MV8|7g`6FnsqJbX752wD zC75nXTx{Xr!Z7nqTVpq#cTgG=N|xhyZOCy6HDPh(xO!Qa1qhR%U)W8&2~15k&Ra#? zXbw%v9SGtd4v!o}>9#gSXC}D{9Pk+-qPezrc_p%>kU32 zE2SD(NH4uvze;g`{d0?&xLVL$SP;slwZ+9{^~<_)pYv?z#i~W>@{g&^UZLuU2fbQ!dVwj% zYNo-pdcBdUImvJrc&c|GDas18i63bwUgE;g>t190Xv$Ln>0n4$igc)NNS;EyDoP8w z&4@bjcjwZc0%HOcWrrEClrKeLLaY@#@W|nIs@ynAHvr^ERs!4$wz53Av0=p*yOmIz z@)sB!mpyRu?1X58yIZZ)gAz#-#UdVxdh|rMh%rkMWGt20?~sMNhA>1|;ij(Qoi~Uq zr#-gR*?Z}ZoE;$$G2ghQNuaAMJ*(s+ShHBZFO>P;!k{V;iVY%!b_(GsUg~7IkSl8} z&QJ0colgD2zH`)UHIC(v8%tsmfjD%Lu~DLU>^(n#qLg|?XEZ0T*4nt)IN5v15;uE8 zw&H(ZFGN5;?XRVeaXLtf{AJP?q z{#q)Dt2S7Vw4(U-6|4;oBb*n+ zE&IdO2FAesH`lTWU+T6A1C!X<61lOid5}-JF_KgP{gfmlgWk!eyWtGh-aw|L4IX?{ zZE(TL7K!Z8Z-F-E98Ak&&=@3*JaEFCYRED1d!+JAV*8)emP070%()V}y`+?9P=OD8 zfCY0Xl0K@}4Iq#sBYt#vgn3Nq0Vx|Ib9a}sEl~m_b%Om(YT5YaxbV!BHe)i@(>{q8 zU*7SB90K`Dp+9j9T~xO7hcQEWKA_CPP+_QKaZ+@MB0#n0SuaL6|AFJT`0L_(J$k zq(ZrZ6l=Lco3tp{%tW+z_O>iy%M9qt^)DR0afIWx-Wa?O1ZIyxA3Js6%VutBuL~c9 z8krIzLfmCQ9^V%EWw+j-Otskl)c93|x|&eG)OV?x)5Mkb8(MXgXs<1~d{L?z1^p(- zC~Y>y+H|Sa>{7!9a^YF9Q;ndgbhvnzDcI45v-7C~(DZtD4fu}ki?g|&(&N%aNtqku zi}#k{haBXnL@d<`KabZ`Q^j;3VS{i>FQwU1dOzEr(Wm3;o3E~25kyU;2btI(GZU^i z^DrlERi^cBb%Gq%?(vLwMVYp8k2SiHr_eb{qFSzKC%df?qZG0#c48=`Y`dP+&m%pSsGVr7$xz2=A|K8xQ9GGjre^6UsIXK1n zbiaEzUGTVn5I@7bf3W{_%hp}z!>mU2v@UGQaONvrD#kk-Bu~g_c(+OXb|FMS!#~s> zihJxSv_#71;I7lly(iR7Yk$#;$F=@|8E@gRso`RA<*=TH(w4Gei_PCsG5qU=RlglZ zOL>_Xil>oY0Rpk%i+y20RqH>RRClel?WP!!->_{Z(d*rWU(Qx=r0i*6i{op7W%L0} zULxk=wzik}nk}%%s`&w3m&q?QCokVZa9WjdqLlcUmei1dv?2EVp!tA4N6&DYl~_NK zl*A_1Olp!!2~e?jb^2m8|ErL4oW%o5^VWG){({!;hg8L#E>H-|@X9&h#2rC-^LxWJ z0XIqHHS!HD>4x%Am{VFXd&h!DSTG7Py_oh-u^ntyFAk>!Rra@l_fNlTY!>Nj=3j(3 zRwMiiDTCzi$)V>rQK{)FUjstYV=`! zv(ig3V2v%ZL$ouDa9-`~z>VbZ55Ty?w@FAMevNr6EHpd&VRHn=?TWN^1NxI&=Fj$l zJq_GWGx!b7?;8$P0p6wkUlKq%ey z&|N_c1}$65v_VGYr*;AYlawvBF}q!!L2pF;h4Xh%PF`_sb2S7Ct`JWoH{&cRM%EisqaT=JJD@*qz zKdGnGDoLzg9M$#3mK9%IfGa+Ug0?O*7tPo$nOD`D?xS$e5+&tHHH0wF`Z9Y`Rl#eS zqNWRGpG=={ysWheHWNG1QT07+<6kAPht5(WJgkSTQ>{kl5C_)|$9dTG#DTq%6CI*` z>W@C(x=48AC5e$ILH5thGk&7F{M@N7nB5lLhi$QV2fn|Rp)!==;ub{wj6A=ESKc)^ zg0Ms)K0#$R?Tgae{ezEmfh>K2YQ#!LVJoWXOPGfs6GnlBI)Bq)Yalt%XQ9umjp|^_ z=Xw*B622Wud7D)-^rnx)pz#NGa8XbOG|xQYoYF*Ah_4(Lpo;GtYJB_0w07*0Pcg(Op}z%F zx|VxhUXVotKVWq&t6qo!kf=JKHXxS;kjjImyGkomhR1AJcTMF6i3hZ=4Dv(S36@d~ zTjJLfyNLM)>cfHmMMk-!wg_*1{wF{3f9dm`m3O2MzL66X-=1W(|F|PFbh5Ig`6q&a zfQ^-{y^({1nT<7{rHPHbnWL%Izq175*RAJy;ex)b=2lXW!cKh!BsLKX_!ju{Sbq76 zLm-gtkq{vyYk1h9tZG|WsdS*QRQ^JM?GeB?HpnNKgXHa-o4S~q@_zFe`h5DhSNQ=u z+gN+l)7uuv0fVtpvy0wsW-$I@1<8TpjE>@vOB_ASe=J{^uOb3^;AJG+X>!1zXi1f>E-k8Cq`pnB5$&RP`0A^TI0t=CKoEPYV$2rA!q zE_Rv$M=}7ngebQ?V!C0(A^TjHKt?ngH%aU$dah%Fz7P`r=^P2c9Zf`hTtBYk1udi^ zM>JZmmEomFrUmz&@h&(p$!vjv0FyH+A}>`6)TBflJ0y8-#N(#eBcd%Zv0AJ}nFKRO2Y)-cQf?o+gsBp?sA2z*3P>0K_v?XxdG+rlX z5vyuOx2VBTD-26=`Ol)$D*6$(RD4yu(+Du8X>UKmv{!vDwu|rp>yc#*AL>L)=0$Zpk%H(;4;6<&#mo;1x zslqyE*Qmd1NO8{(Y$q44zDbF|w)$pp;^HOS=1c4CxcZvs2WP)Eq|-+It~VqTr>TB@ zD4B{_e`Y&~W96T$njz`7RK98z;mf*7oN3O{lJ(Zl zv@;ZCE2CHBs%3`0p?|Wg{?~<6$~fI4@m)0>-!AO`JlOaj7m~e^fsKi^nY)ppu#LTy zp5wpWL6ve+62Npw84u}eYwDF@U|Ken!PGdMN=Rk^ityyM&f@hIVdwZbsqmL-PH>$6 zigvxdRGx{)L+eX_4jMHS-Qv;S{()uC956|5ze16xHoz>vg(7@6gG!R59$EDUbrF=i zHc!!{sg@lK89QuF7t~j(IG06ds9}|jzdVoFD|=sn&>U_`HGz#AJiy3_9RnbBNb4TS z$Q(`C9h)~kyJLej?t^wjn$-fIiVQJGPS+(#P8iOl%4_A27yjj5b`YNe)ezd!=?OKk zA-_f~;8uc40tcMB!qIKY0qZ#`7Dr@jN@<0CWx(}=`;58m&ZsxuWA9gKZ4T(wQ9aP{!sv{uqvl{4XR<5 zf?T3`D%?tOKA388Rb5~LpVMKsZb;%_d^BPhmsUb7Jya<_r*wc4@2i92$eIrm${&f5M!C2wX(~SD5LTo)xCbd8`N*z`#JqfJn?LmOL%9?Pr zw~{uJ)mhT7vCtV$e63yTi%o-y+25m*5}T(_8h@4Q*Is0HXxKxESI~gc*gdFfsuprc zYs6NPXfm@JCTP?(lR|L>B+pvL6DqP9N{nN2KBEGcG8n5HoB8G5V+;rq#N|HCMTy-l zmL4?~CXO+0(`k-crYa{vrk9NBsfG%hHf;(}o2VXOk)ThfWR>$v=taeLeh2U*-Wz=3 z8vEIHnCDua4|R+(J?bp8^sphlyozAR()zbx)h zwfn(XdzzYcTDzaN5wgpIo2e_r)yw7lQ-T7-6fy=Hy{J%=_iuI0qBmpdLY;&;RS=ufc7ul@Li zH{Xp3D=N{}S8|V^%laEX#q76c6*?90rG=}H{F*nhn8Cf(= zBd%df z0)l{4QT{(6F@ht&zYl(<^8PY+619$lj8A2C0S&xr+pJt_Qh%FS5?@}tY+I{b3uYFe z&{}Rp);zCkQfl86T5oJRSFgO}UUSkI&${1CA3ZplviXR$^zP2McIvwS=)V6um1*Mh z^@8|gY39xUq&Hk>B{(^(<`>WJJ=|M?(~tNVpQn9GIBz{wzhr+&?bxm8f@g!%kMJ0k zz(dkGkICq4@wa+B@tbOX?d08Va5sUG>A*)Rd>ioBz?f!`KAOPyv1lLIJ)RrN*spAU zZK%EOn{&LYUYmf&?!XSh10TcPX1<{hj$IFxpzh?YR{oN1zhyT;IDURkeh61ew?HI_ zTku;*@L#1Nesk%Av|@<#8qO2oGaGow3ZdEJ{-#L0k%}aS+JDB3jJje#>UM#Y36*}g z%8u~khX+uh)CsCmL+H~00GuXYqYH!lN#L!5BlbL6XT`|g>Z3a@jm|C&LIhS?nZGIl zILq;qwIya}McEYKTUlQ1>fpp&v+!JburTMh3(j0?)ue9ZIM_?zg_ps3B6*9ork*wI zapD-ay;2=X?CgCOQkS6zx=xNnYb*sS&%{B&h;|BVu?5y?i?fE?F?ND7X^S7HyRl~| zBpMZ^ORf}dj;&aLx*)_4s_?bn^}-JaHF{~FOFu7Y-iaj ztz&>J>1jA+Hrb5#2n|;OM23JPlJCc5NRD<=o>E%W1khn?vOWv_bm+_H=&_20?Ta{qf zdB#QVWT+!&B1bJ3{QRo_F`BUIsqfEG{w!cA zDy?K3l0~q}L2Imo~F{8PaluOWW z1z|;~X=vP+B_`Yy z^2N`|{7>JG4~#Z1qhi_`DOMk$DlB@N4QA)Nu-q1U(q!O$hV!Lp&dHc?#pUs`{Xplo zz$RwqpsVz5hpXu2MXNNl%G7-mt$~U{s7dki_yQA&W6&0|3@MS=Ct?vc3_%)YtIUa{ zH!^Y;9*6|Xy-$;xc#QG;RYKgfzwz+efDa6;A>@irf(1O@ihqs9Q*?}qVKbic4)?HV za1Dg1tv9QtxV1Om*~qP|Esw2EBb}J9tuA+E?w_twR9+!0Ew;-zChM9cyDQd;Q|we_ z7?bSiQ~rPkai@XCay9;H(E=z-+2&t#fFI=gEU&re?TIMoHEIdj#HoLUt!P#{BUyAP zD>xFhdR<<%o;zZ_{3Q3xYF;ON`gnXwtH82Zrbnq>O8Wwc%_rNzu@gT5B6}d?Dj)-k z?&FN;hl}n<Ke3b;#bxM%<0+=?jg+742M>8^QS-AkMAsRN?#x#wxD|cD zYjN1XT_4%(A3?VBT>bXeBFo~ZQyL(qC^prG@j<7&g($xv1lB8a4uj_NFu+vc z{+l04j5UzE@<)cQcikrXXh9GhLLW5hUP9Uls9%mcLwmjV&e5t zTG1@eU}Wa4zNaIh;{<%SoLfS7AcLe1l0ser-S*yi{{y+510Cu{bEO8Rn4dqAG2Qd- zn3|ai%#ZR>m?vX1*E8PW_(&l&5{@TCvqZ~imn<`lXe+LdHBz zmNPuT8>;vLXdEk|sEFOIkt%2X7F=@}r8zaLu+x2uOd>l@g@7-aJuad?E`rU6w+zpF zT$%MyX0y^|ajIm~S@8;}KF3)xRg`sky}b>l7eqoF&?5le-_0_52683U@(GF}sONQwS4q|LNtcM%xC-Z&!0oM{ zEta<$!;s*smbrKvCEKsv1NsJ5ZoC& z%+9{<@|Oiu9w)lSnWb7`Qj0;n6!{~yQTID)_>+mcV_d38sSOo$>XPZK9Tucae!Stegp63G zv4tau=Gs7!G&pCauio!!!WZcVupbAk90bmSZqt)tZljv1B(PZzyNQ&SlO z>v5g3F&YW*?NQC2$YbgRF70aJx&2iGgM!Zx)cdah(Yi-~XQ%7cOu`a2%3~uQ_Vv55 zwl(Ex*88#599fy3imaY#(h}<2tbuBWoKaF!Q66@2Rd(M*+39I7hnV(p_XJ+UVh$(& z`4wCzZ>ik9tev|u`5iK6u9jLwA0pW@!fh^xn-*=|N0(!28&}{vr{<%xM#=lR+5UvK zV;d}CPqSS#j+X*kzy&OE!<-qrBrg==oDK)SWE217@@p>u2Z$2)De%hKvOG^MKXqOh zt^r5iRBG#UYsX{_cwHvgY}o!81XuPmt(i}D1X4fla}6Td)sMJ}obG)cqH70?3wf3m zLw6_^J=C$8!%r*==ZJR@z?_kLFBtTvJ3fqh z{LjD&Nf%D-yQqrtT-R@?6Bj`Dc;!z89A(^k?VFBjJ^~p$Q*D2*8EmmZ@B>n)gC;IM z7)m@GFWpOb09F1iOxh;{a1T~hJ=~V}wns-#zwJCvGvqHT$Dw~_1pODpSa<&`Fz$y? zCl2?YIA8yLdZg%VZLR-5!jPg=O)DhhA6A|2^O8-;rHdvXwZfH+tE6h%Xi-rSDg<>A z9&4L=noY@OUsvy>O`adJJlwAMKIEW~bkv_+egrbI@ZIn~vOH%6wl8Oi;o-Mg=`|he zrx%ed>DLa^uG7!&)9l-mPshGKFYvvVt?+{iW;|-XImi4_hWQYY@dqNuM@qkJLFL1d zSj|(6TE`q5Gcp-B&^FRG4qC@R>ClCKPdhkH|JDM`lpTwnom|g3J`(ta8fbJ2b546> z#^L7*OfhnII`3^Eg9sN0m^UB7Qf7K@qRW4gJ6U{Zz61;QqHtE4f&d1atw6fyCNU*7 z_g(!a5<@-=4cDU6CYuxN$6Md^mZmGQAJ!^T zWX3rG&!Mv9FwU=ql~aVoSuQ2*{$zX+lVtBXBM;({`ml*L61PEy%pIhOi~*qeTt9GS>@1E1aSN-+y8pei0(f zs?}AX$yiWeTZ0@VR?A)#`@6AyTCjdq6MgbH4|P2Au$UePkQJ+!9m-SYa`lN_*RsMP%EFzC~ zjBu-vg*InPa?S@D^qqHv9e-!(PNaM$-31?favhg0Xepi88; zp$8G*a``^YoT6dv3@9JlJp$AB6x{ zLbw7#nDX$DTmjD!U%z-PQOc7PeVI@c%szhkpBO6PgfFUkAwzHrEkXsr%3&A1dP`PK zmg5FDPnBDm82cg{Hz^#gDkUw(W6rQoNQZ@@R_SxY(y9;KaGw)dmU&|{FEsZ{9z)Kr zru;24aH^)^SjMYD>*GLEi>+Aki#2~VT?t!X5m3;}^ER2YsqHp)73+y7AgBe;yc~@i zlqBSHj|w6D`+mbMwC@_c`I%C^epkG5UdUQb(-SPs(Tn-q9zZ4oH-KC?gDqqqAQeCL%76zC zUXT4rgSR++q2&U+%I~}b6#lo!AwY{X6VsUQrKlGZwl!dZji1LJ7~Ki9%sya)C{xpz z&qX{AUo}pHbTqXZuVa(nA{%czZmPwYFCW2Z1-Wn<++haUD3((!8}R^s)k_zIh=l*C z9mR4~y;4?-f6I<`DGu=fef2{Lq)-{ym-T|k+`cXoLx&y~um<3a(f^P~*Ip|EA0W*%QPe75bjLwwYxm!l? zWxB=58%=YJfy6C^t*a=kiLLG`7u0t(MZNr$p|Vzdd{+ID28OfO%p3U|GF-L!mCYW|5=wb0{?3B%DG5{=ikqU;qR~+h6VG_Y1s}?jtKx*0YI$Xr-LB`xX1L>lOQT_xn@N zvhAiyo_RlCjf82^TF6InJOLp51U`IVA_xF^pxTPDMiNDGugv}c zzWO7Vjh!q%7R5GvxSk#BA7Q%cMvPGj@;a=1EJ(Vx$*UaM`*4ItL})_^?ZlG4OP7 zvElal<2qn?`r@I4Hec%pJ<0NWbjZ&!u98|txviI=y*ccnlR4Fs%GF#?~5t1vPQKU&MjJG2E5eXSWQ1?t)dh*(eWNIJ-4&lmNQk`{pkY~l-+%~ z-PV{sMgT>5(&QF+9MJUZ+X%>MwSKLhBXbdV>6*jEkHK}PwtXDQKmigE(TJoVPSv(E z=p_;_gdi7PWXExkJ{&=wh04Gr!Cpus3gbb2psTl0WgbPc08sW;{jXSZMh%>11$TJ3 zX~*|bV}4$0+RBO>PaK-!1hceCA1R$(SX~&RMD=8f{Tp`xxv>$3=xve5J*7_xnRYL| zi6Errq$K1InNcQQgC6x85&Y7qZod~yFNaGIu&S_NHKAj8EL77)32ijf0A^T%KZiHAi@f@Gk z^=?%B#XxUu2jUm&n2kM41=rzB+K{zZEawY+k6!dP4b=yT=XNEI5NP5_P=<08vZ$TH zRKx@}whO5ShN7mD&EqY#PU1t^xn|qPwPnKJqMWU9Y>0IB2<`9?$LyU!KbZ6p;4_6C z)#{*`NU$e$2GEpA|DratItU@p6pZ+ygeUqnc4t-Cu`jKJA+LK%Q1 zN~rhT|N2|5=tRle{H&c(|LZRL|9M67PZSm+`hWbNRZ3H`i2O+3(wZGE+J6w_kp7mF zee$JH_z(#rDBzoy+WFbxri{6ax-?JQgyTeg!=b_&?De_L4f0BOHB^cK(57rocCy-T zy?525zkdD1`Tla|qTC_4S|`&R7Qs2Z=qM;4#6(u2Ua(rrY`W>~&jL=x$8|Mg;+~nc z3SDz`kM+df_0Vs@EFYcCL6JXjxO6_~o{jHVzkb?4WunH7)F@w$Wi_OBYvH$xR2Xv$ z*KhKIaZ9!i(PG>{h9a~s8}#VuAbddC1{Y&kgW<-pa-^Q(Kt7ViXeVmy4p**>=EO}@7I5q{Cy zWTl|RrZ3+YUz9ve%4Fx&l6w#Bcaz6_(@y$O{ccHLh#Se%!6Ne~cCfY$@xBaKHecg) zcR4JJDWfyvn+7c}(S!P4qeZdWwi_ZZ=Zzr`iY_>Xr*B!*vcvHC5%XTfhF+3c{#U}kt;qcQ( zV~w38<{%r98KP2UF_ksQ{$eWsp|lD_jx1(3pRNMhYI5p2tzs^ zVJ6ng0YHoWyKpBYv$tt*7pWRCm7FGVU~FL*!<u>glhjh{x(B3KHL|k<9SK0H1Aat5D0@!eVU^&cg?(P z4!8Zn!)2%Yg!ME%+G01IPQUo?EEu%`6BLpwlei&no~!#?zt|yq zs&uvK{2&Ju78NNjBry*kJUlIbDbbMeSgq>l6G2h=8{-52K;`MVT7!!hUY|g}Eqx>E=VGCCs8%h@VA0q9sis49GB63!5a} zZ4!_7vmat_Du4VN?#hLIl8^qUE-`=VQuIHoOK}?)eJk_-cZpAtf~Kq@KipT!);WOq zVSbnkd4P2?j{8lSP@ph^SRkw!qOMemW6D#S<3x`2qwK3*KJni{+?`m4=^PfZAhhUr zIz~>;`>7Vj`_GY7+h5If+CoiGkez-_3=E~nbv6&&ge(y&Om9Bm%W|}T7j zsN)6tb_9!(_IrsXbJ1A+s7k?Cil!>Cok4l?(MsDWb#@?gF8O$W@;N-1rJBPXOcR-oqf)$ z(7;2Aam0vUIpgi%9m!qJz1T+ zRx2I3`|BTH1HAGKVJ3FBZ*7^x@HZ46R3d;`@n1iJ~& zqR%xQsT%3z;%kmY$JfNjmm-a!6$tfCotY;2=FJqLpQ{al$ZtteQWYUv&O;2B7vlbj zE@~C0_LN{<{s_7Yb!_!Iv(m!L;3V}Rjc$KO{MT-oN-oPW3IFRC3(0?6mH(uY_@^tt zKe}g=I=ENTVfr_(vB51CefmzY)o#)T~(- za22Y`UzASxXwX(Y>0fmxOXZqPmMtz7&X&$)&Mj*i6`PkD)DPcY+o@93Poz6{?}wjT z`|i2#9-*o+T#jJ9LhcNHk@jrAF>ft@UxV&AqxAgU{r&qJ+0XxbX~@?3MJ^Q=_=fXi zt9JyzXt&m%7ibnX_v9AW`Kb&hmwYGJ>Dm_%>q|A17xRVpcP=O$kS{nM>ye*{Gud7x1(j3Ct5yd~+Y{`WmUekjEO-6n2zL!z@wgbtUo ztmuhd##QvfDj7Fg)dW39R<*)`A{lzc1Ryqqvu##BM$Lt^UAVu)r%Z$s+dy16097KR zb6OHj;^QzYLy_9_cv6FL1PpPA)YPCwdhvkMp-%{mDftO|#Iu&5#P3r1!-Y{P?D3@7 zdFQmEiN27eb61yN=Z9R_M<;M|`qkqMw0QT%{CpHfc?4Pqz&uuTMs@g-KqC2Vb@W)a z@L7z!C^eK2ticuMRrzOXhK5ubv$l#G5=0UGw`XsoB9u8~<>oe46d6N#3#;W$a8k&H z!4-)ca8kT7N{4?7qsh1v$SlK%D>3{lk&G5X5giG}?t&ZGTabzw9LUE;wc1m=bksC6 zYZH=4Y=SKXm{V`44ysL9mLa$*Oc0!`1uH$cmzz|y^oFa>)H;jrO{@$1EFy@3w%lF} z`Wg-4_03zyAcQkB5|hOftO|j?%v%2v)cf2o2eXDmW+cXkO8-ET|TJi7b?vSgV`%BnK=p zTN62XRj_T;aAHKAE^SPf<`pYnCQ}MArVRi32aqp7PSBP$XC%a{B@KFyy@BbE$0$Zz z+3d+H_3;Gb6}eG~%w#!X(cpnO-AO^5I;+%EEnyL}*nX*ri0GvZoiFYdhNx{J?C?I?AECif`ikB$8P>Q|BF7H9`&lVx{D~6aRq~b&)bi(A7@plbH_<7)6?H zi7^##tprwoynUUXMx*f6U_H~Qpzs#HjYR4iLUl-K=^rjV^P272tL zYha)24H6jr%WW%rE^QNned&US{#s!YB7jkVpn8!y=U~|s>7WrFlN*Rw2Wz{E_^-P*e+u!f@)=!qP>^nyc~Ji-rG?p$@r2 zS}RmqNlW66eOHKkvu{wkb#)MBgNls(3$Q}yis_bm!)y;i%SNJzirFZge8M3C)i*@Mb`}yRk>VFXj%0~`EEogu|%3E zoW?yDL6WXh)+7YSE0p`}Fr0Ad@z#jd9fg+7OW;0lU!x?xXmLg4}ZAL4AYPv&P zy<@P0L(z0K0YGEk=HMdNP%?xAGY+FYw|gI@+hUSskd}4{E6bRPVs%N|A;{)?%7)pv zv_k`V3)u|s5N7cPg{D-SbaSoFlN4w9nQf*+2OSzWB1xJc=^6j!m^nL+q92z^tx-^m~;`4vLF97Pp*`;6X)?-`Aj_%EoEv+V5x@x zHLuQ_>32Y-4UR~7seVQgr6S~VwP7rC)ARJomS!d3$U4%4mv~kZ?wLZr^0|IV$($fB zs)o1Zq7dmqFq(iWj|`M?kYvbeWmGv8uPwj(&|GAS3N=MZs*~43Gr!h_&a|VL&yWwJ^$jwETVV0-6 zZyDdQ7$OR5!(xF|n|!aL1{3Pj@!l-8Ko|9`y9jkJHW7sEs-AlfGTBcaeL4)v3lh#1 zQM~W$YgFQU@`jAM3gF&y0GI ztD*>$5}S!>EQkVSIzQ0}E~8mohNGb%5vquV6vfr0biAu6kA36MwdAoVdeLf+V28|8 zOTwn%dWd*z>kPsasNuU$^}*8?@#&kLfUfDATODr(e5$35y^=ZP3G{O5xc?l z^~8}-m*F2_eQPJID%PQl2h$3Y&n6){s-8+$3n}Nj{da~vUO!pc;jF5wrWWG(Ml}|O z{#&=!B95hnIl||57VyV9V@qz*qI3n}yx4{{F~LAXnhv=v$AG_~@GD`F01ttpm}=8p zYrLzvCf6J-%>mixoN-g^nZDE4fJWF*ZtizpeLQ0PzPLHkwt*!(c%91cJC=dG%+mV{r4$>W z0!Bz~>u_Xl80eRyT68wNlb54hVN?PpyrQi>%KK0FCD5P9LB5~s@#kJ3jfQ&s-&mP4 zaYCTCwsw?nv}|FW<@T3s;i#cJu5bh8A3lVxFFaYDeyE>cpKQh(09j{45I+*NWJI>G z`Eobc1D+_0fs?Kz3x-E`~Yq|VGFb61k*~IwZvW;B-__RoZ$^B^osR4r|eQ?!@ zIzVN!USP9f;l@Rby)u$wI_mlqjH;o{(t&-o*kiC;ZG&tm-s@BYOzHxciGG)UH>KEC z(C4)t1K!woJKnZ-%!1orI0vUN>lR)Ych~qAg&0~*WBN2o5XB0SoL7mmPMsEv6yHvUPws~}#Xf`eSblD$B94~AROz9zIc)1hi zQFK#z8?X*+PHnOy5}dPz^IT_qvN)ka+b5OG}Cm2F8{jF~%aAZh2?yh=;vXPbSEsJcShipa1o(itZhCvK0Li1y~x5~&!vc`a` zWn1*yEn^~XxhLtn2e25m9JvCLH>Y;IrpsPEk6tW*G-9{Dk)|&T;mPzupjHS_rjJ!l zS)v-PJ75_h8P?>A2P$cnY=+=Ww^u2a=V9QvL)Yj!{8VQ&>8^|^Y<$k+O(D`TkC7}W zh@8S!Z+;zll~6+`3@hy z2+Z9S8SRA`g^N|Y5zBfp2tc6|o+^-`GYB&nhom782n8RELI_l)_#>qJQJT;zJB)sG zK-k_Be7(T2;nV|Q?*{CtL#$NIt|VL@{drYPoP_bTfo~gPxwQ{bZ-2&kdayRsKJEuw zDch9Qte`$vi=u4yH>Y}4Pe?5fQ?{2i^$XJS9FkKxQDGkFXLzceDB-;&{P1-%2m?a{ zzOaRmA2^Ap$ldsDXSZX7`M*EOkMB@Q+#{p^z&{)pE?>mC^Bc~W{jOVC^N7tVPz@ON zQ9>!{p;y`C5%zI^%ZI>{2aTPg>M(l-irJAVV8^3 zg&q{22xI#&p7tHR8U(%6uznI!o)SsE0*PT0Qi04*-;l72mKus?_}wzv<|brfP?NM9 zm$Z+}4vQ-W<{R(+QgOabXjGI%TEV7CjXE0qa20u=^7j7u@QkfMN-NgYNnGThhH*d` zK5mMTNK14DFYe}*@Bmb}nn;X!DYg>)RS)QBr8`4Xb)SBp%a6jo;TPzJQry{_VvB1? zAn8&tyGrOY#ov=4`w3N?IDqD1Ogcd(;-Gh-#rV4q3V2McB@x3uZz&&W&M znRV+!J$FE;l8uV)A2KX2YB-RN={W{kuk1;hkRBz#Iw%nUB(7Qce&WS*3@LUZC?^$zi%B|uGweH{Y?N{ zI+Dpj`P78N-5Yt{tZ#RHlFSWSr=vL)a$IMHiy`UtBQO)Z_hJ{m467c!ZwtK)`#Zli zbKg{8E?aV}r1y)sHABY{+Swi3!3a@g)Fdk9Jf4;{KPbH{%Dr5`X2>9?CW-T8Lo+_E zW0q>YPW-BG%7M0d++&0<$%lVP|u|@AXw@-e~Cczp=RtUsG!ytW#~4FC^Nb zm(lNWRl1wCHfi)9Je`ai)lyg{%NLCmogHSuwyoLVrl6me7nh+I1m}ON`t|vnuWtXu zniA<8^3`=h!@gOX+}KSy?R5)q27ci{9HQ(@CNy?7;smR*Hr{a<*Sp^P39vqUbh4mI z^$eN!F?ntgL$<7$Z|`r$1{q{*dN?%_P(Z%11g}3NTJ+HljV-J_?8sJs8B9iKsq zwcXQphs+(PRb$;Ysrn$cJmj2{-7=Ksn)G<-j!J^Hs!zdYI{i^CRU+$ z{p!H3XfzKkv3qjtIGd(ANvqt<7BBNh3%< zlXSccxi&<*13k)?rQ_qdoTGucSfnx8;k}W3R)@z&T`P*g$#6V_dFkp1sgK|pRfVYP zq-<%!GX;y>{!QoQL~1(@6ljItqsQ=;U>OrqhF@OH?(I@o34vgAa#8r`hMwnz^ zzkZ4QXJgEN8W{a|6bjM*b-Gn4Z~s>w%9l&Sm`y*13PfX}A21*hKCy!JVgM2tzrkE# zJwDob4Y3t|w$XqULRL5DzV9wu_sd$b1t*8gTlsfrk1uyAV+_X`d#YO59f&*I_UClh zbJlg1=krkmFK_z~C#>c@Z>Q~-O1uiZYCO0eoH|RYJIM$ME}oBcNw-%Eao`0$T-CnA-|471`?fTBky?hlfLssh48u*lrS2jt6L#gK9bK84qJ-cNjqt3oMdsZ?VM=%KGY^`?3EP8F z`D)u$ghD3vfuW%bkMX3qP7f-;=Sqvn32EW{5d=ALh^o!i2*YEICh2u*wM^x^QUb-V zj35Id&&{<41m%fUnKbE^J*yd!SVC9XW}W78;fX4{aT%SVIt!MWPg+uCUR8UFDR*#E z*!UzF(O0?*PGpPN?Mf?7m4-uy!O^eDrig~2Xi3~iw=!{j>Sbs|CF@YW>YG+~!&CLbnt5FT49Iur_Xhq8~qv-4dE_xU%upVd@}Yk;N$u6a!s% zBB8y1JuU^J@n-~oAbQ=+oFw?d*S(p?5b{t%?7^oV^f4MN3nQ>aw#D?ejO`O<*$7T- z1%EqyY;_(7%#}cOMb6*y9Bv5Pn)SZ(EV%Aq-k5AF6+VBxd7W)z2y|+GAxC^*3fx_z zC4Tn;Meh?uHcifZg&}cCYIOeb#kd_E5v?)Hv}K^ zu1ZKHxVfH>%}eqC#36J8)o#gyd=1Ue8K?Whvvt9M9=uc9grgjo%^RN;K{sP z?=v8q$xDY{7Mw$`G~y3Fzbt0PU+Pwq7he3>66j4Ta%-Tegcj%ls@Js>dPxh+E)#Lf zf^91F0}f%nZa4sT=6jYxP1q|LC;*H7)RUB+{@M@b>G5qnnJ*OdSI(q^>pH@3Kh^`> zTNLe7Ul<2;a(_y>Ii2T!ZT6JdU+ve(zdKyEk z`QX(2I_n@x8q67ml0w7_;jEBe>24Lh(0i1?HVC@ZH_UtIz}@^_4ZSU4i-6lC?TR}c zNXZ97aXfg($mE1oSH1x6onosg12PbeC#WlZf)Qt^;%-4Bky%Ry+kF`3iTMy!7Mj5V z?OQ6o|F(t8`TI@6{-Z*og8Yx&_WzILOHNopTKvB~+y5x0DiuxDA63#nxbyunN~d4C>8FPix~yL^~uJbkiqc&s?!1q9GX`wRbVGuvv?QXd8sQ*V5VO zUy!o!BAh11w5M_0PmF8bUoA!(h zi?#9f%fx&tlq?8G*W3d*LZh^rDYf!U2Qr&Ux>YvBc)FOK%t|bnv5qI)SZ=YCmqQrT zYuX)>&YjH_!x3LCY(!llGlDJ14Q1K1nnoM`a(6bwFn;t!p1a}VmcGdK4^9*PF$BUr z7264kLA^}~x|uJ}X&9$eQh%C0N9&)UusLfDj&=45kX7DTx<%(vy$z0`y+sa{J~0zb zjj>_jwlc8tSbeBFHFZpwB4_z+1+tnYk{a|@C7iM|VFc+;F`i@gUJRM0(P?Aa`ndO9 z0D=I*(t~*`9b^04-*Pkv-LvVrPqNxngkR=dN$g=5e{x^eqMJ_}sVH+0k<9$pV31H& zH5R#E9m4U1YaxfqNm}J zaLOz4mwrnqH_kBE#bfQvfDf#!huio704yjs*HjpX4Ri0xjJEVf=&u%3A}B;l;)5PN z=((CwPpDTIdhnXK#|BvyG9RDC-qFvX^?O3MRxdpLh3?T8w%2XBp&Zg$U!GeSUpteDPG9!Z{8`>lzD4$GM&ccAj>Jq z=$PhOBiJsr=B3+#D#tiK_sb|XSu*}Cy~eH(nPg#+I?hMS_*t$O2afz|?K zi{jN|5(VbLHyaqT%|_rBxf2StNC(7A^#U)*$kZ1Lv1I|I#2*X3W&-3LfP?w~Ojro! z(LekB2fQt$HeJPH#k$y=S!lAcC#1_nqbhGz%90t2ZXQIs32t^nAMnS-3|G2~2GDe4 zA0P)!I_VjA#dEsPf00jl-xv4EMo@8*%p5feAT`0Sl`Kd$%3(9!aTBc-dwl@%L4^5| zz2;WXhhitMhmrlEAg0`hd4gvC1^cfDy;1uXH1Us6!tUplA@HBQFqHJ|jQ?pD{XcTF zCdG4$A1%+9j7{d?;;<50&F5}1FMjwLv={V)5k8`HlWH-ft_cAUiI-tM{hn>V3zD4a1C zY1ViCWS)WgD_})CpU#UCPQ)`VpS`#3$nZ}eF(Jm#s?L=JHH6WK91v>r_Rz~e&gbdk z{SXSx5sU#6auXRO##kiAo}Uk7#$AXIp(r=M(+8m3c5ha7c&Ahk3l2?I=x8)?K{yOi9&Y{|OUK7ji3pO0rk>^AjD=$j{ zl%^+3DA?}=`UWw}wEQNc^sIJMiu|aU!~FeIQNR26VE||rsXhh z^Z}s07y1P-lHnWZrV=_yNo-M=2{rtl2+dY$o&a==EV=zv1O_Bp1?QL#bEC0pnF7vv zvIs^aLZ(})SG4K)E&)s;z~6g5$z<1}}V zqi^i>Gv_utYwq`Pf$T4;0i|D*_J2Sq?c`WOjqagWxkxfcj2+qhNNbUr;$SI4DPC3Y-nC2KR+DVlBo@n_0i+0PQJ^yZ1Ia&Xux}o4qOHtdX7pdQLb!ilsAZlB#rfE&E5v` z#KJE2O_j9`9VzJaw(Q}!sr0uiss375Om<10R1)rB`N+Jg^XUT-j;P9bG-ghObft*t zaUJ)0{R4!8B|;OL?Rcu=2xlpEXmSkE};?_b;aw#neJur4aB(IRllt#Bex}B z*G2FJWslkAQ6W<{?MKHMT*&Dip|oZvFPFnuF@Xyx6D84uC4#h04><{)7DY!yAqwiN z!@SX<S9U3dl)JjmkZJ0ZZiI zNeR*HZqx$0YKsA5ZCE{#QZ~PVMIWo;%$dWEvxoJ1^Hc{h$wIYL|HB0nx-I@3@v zGSCXCYsW!f`{~^(nPA)ltJP|A0})B|RrCY51u{axGv+GTr6|^We8Q*Ls!yQ-FTtf~ z`9-R1y_eBXLQ@y#4>MxOvzfQGp~p3n3wa-d2mYk1ZuTqntesYdzL}}bO4YLS(gUXU zdjii~o$yl4Jn-bzJ)kT}B`sOZVw(JqOk)>4c+Yy$m5`~J>*D0}U#%l~_lz=(*1jpN zTTFeORFyl8!aid448l|*i^Uqn&nmSU9lgMej!@s{lmjEX#l*qYb1lJo(|2SZZV*=D z-h8unAfX2mSe_@{0Lrs=pcb!opxAl$f-A`zVM`i*&YH%}5f^}uv;LDI?6m0MR&>|7 zSeC|{rzW_|5A7H>)k$Y7J<8^?iA@4`ui2jr?vp$zk30M(w-wt+7I8tQH8zSW-5^WP zq$*MN<`rtvjU=5AU6~HHBn6i-@P&(bn-s2R8P0Y%W-HctAyn+>`M)+y^TA};D}Fix z_sSeCg6x>i8>MU=(GK91SmI>bUhg#3J(;tYevU(sx3Q%9_}N$uD7>&5N>V3L{;_Zi#tsS-l{@Y>3Oewv9-k#36Io@ax1_(-X2FFh<(5^r!h1r4b`GMEIM?=*uFppyY@Vppne_<6N zZW#Eik=ZcPIv`nn@|>d-w~%ztm^LpQ&zCm3C{%ZLcW}@f2AmN}t=Douz2AbGeK*f^ zv3Ku#V#Fv_n30ec2l<%d==qM zle}Ll%qI5*_nK1dT;u=W83%6|Bwr$(CZQHhO8@FuRxMkb6r`|NC`^|jx zo3H%Nl`C>Z#5u8#$21dYoR&d3Oa8a@v}MS?0xd%}i(OGFTouGYHe|F|yCjgCbM1|Aqw971DiBg)uveWw57)H9cPpVy|xO%ViMJlqUYWfb*~L#Q`KP3D4ZAo(>huaSpPea*dP_-GU~QxCzL8D6@9;5+HWGK zPcqeic^J=nrudbjp2z>hn(>5C_?}Zf%^jsX3Kv${k8=gDh;7gE`noD8JD(!ezDFwG zxJG~Q6}}rMOqIq<<7OkQtUC^`R{oxO=CY2P5FTjI-F-@<>Xi3>FGDcPIt;v!TCTP0 zl-2Xk7ad9oDmCh=#+F)6;)lgW)Dta}6Iov~NpAa-Qm7Np@C4mc?*;7Ja0-!q)1*eEaBpQh z_lz*fCHhO6M zrMX6c3#a+?zC@&O$fK+<_;Wf<_)K&gC2L!$pk6$mw0Q?dfrxzoHt8Gd%`RnHuVIfV zb*ZeTfWf!vzU4PGUctQS&ZkR!|+TpwHqj3JT!NnM&X%5*oMfe7C`=c1@g=}H9Crw`V zR0?WTQT{##uB#+3uaB3Ae?VO6Zi^jgMR7)a74#9$2M-l=WoyZtwm}2AWH;wrH7PF}5XS`>C|0a0+u#N6G%9~?lB7{%-Blos zRL2{U?}(RNrwaA%M50Ib^dv-Q^{E*0L5&OXI6MfC53LhQJR+9;VpFeY%3##~SeNF> zy|pLpk{@Nb(mWmtXMSpfFmsgk?UFzx+cqza!I=<;MlBGh&bVZ3Bg)B;r#1*(wwpL( z%5w_UEFB_5C_qUn>L08JLZbOd{ zNsswY)HxJEu|C@04Rzb^?4a~t`#}G%{o;QN5=tg!HorG1;wA>hCXWAo&8TuA`ybQn z%z~?wPC{ULxSPU;r$xIbpg;{iakwxh;%yl122%O&S;`hofZKf-DI$`QH^9!Y8vTs* z%K9WL`Whe83FD5NX%C0j^Jrb&4q&uF1)2l5A=98~>a-E7ll3vu=`a$?tnwiU;kAHD zr8@lFGMa9ewmMB0jdksv^BQwW4&6m85l+Ao%H;O=xysgRipF52GWDW?UUSKTvCGCP z&6UK)II2~OmWXz(p11ysRe0l&YeR}ehmB9 zsp0e*b5)Ky*UH6bv=ZIqHUVls8mob4>tIDV!O9sOL|Z@=l=Z2SVKiEF33jg&35dly z(W{DN%I6Bf*ASZJ>qkQyoWCg3_M zCVZo&mvzua)PtU@jP9O49ERC(uS^-{xza7y^0sw@GsPSUd5XGmYzUg-tH~cSzK#s z8#g6;mF@)a=PXF+9HI+A52MncYNvNMC3wQnkWmsuAt_JZ3opPuc#od|Zb95}5+2~$ zMf22GQ1?C=bn;9RAUpeE@Oj*u^lN`S$Q^`}d9%yfRpUm$X%o@ff+u;EQn_zLnDP)l zR`J8{3KOk?#ISa$+AslPea(U4KmzMP0*S76_W1JHlhDeUF~88>}rX>?PByort}#a7vkjFQVQ54=Mzqo zJdP&xUx6yb$vJyn)HlZ6p%!w%6m~k3q@U)hiBipjBe*;^aVhW=X`>a!e&dQTFNc&D z@rfbCxDlM6E-45jrGKVdVtK$Ff^8BA7 z60wqqn2d<5^8dnYtx?ud!ZbtYfr9GX7mXoShi{5#0kjs9VUhV){)fJRB))A3qZI8b z5^D>ZdIsp*U)JuOj>M}XdG zI-2_YEq{RKEFU!m{nSD?Sc&CVm8Z}`!^OI8fr(3}tC~Rb!X2#B^4}%y2B&G+&Mk*d zpg5k+jcEct^cM&o=qrS3{5msztEdKbC2?9&qiyGI+rXqX?mregx~joE;X;Wq<_fy zbTsU>$=WIPPjTE&98KZ2zQkg$vzl^-)h=Cl5gK{2KMXm*1s5D8uoXV0Z{K%`2u`{} z0EP+dn74TM_cz7gK2a=@wC-%9*Tl<6Mx^KTtTee{@0omd@vMY^0;>&cb?WCwW`>4A zic${qW5z*yN9zFJ97G0)c;lbC05gfBr=t*12ucQXARH&i(>pBV_asiMj+*=ihh``p zFFoh2PvdTEz2{Y;ROj|c-Y+)zZZGjwMWq;>==4u*KQs0kF!&NaUA3K};Lp6LKQbI0 zWXC-Kz0FbTQxeRCQU^2aVIg~qyQYxmjsZ;2fp>}AVq^qbMH_IW9lbL%e!r{yIXrbo zwtPkrv@3{&31Gr%h#s-WNWD$SKA~WUM1DaqX3|d3k?av>&w9sLe{kakib_@N^<;%aHu`A5uIY$;4Fi3ru~* z-D`Wl+{nK_(DNhziHsY!X+;>u#L+49YCT&>MXn!cC!eg9_n+87iPX{;h|%34hLRUV z%#%={=5fa6v}G8TU*+yhTX5c|p)+4+JI!MH@6mNh^lnEY4l#ygbStjlzUu!Cr zLQT0$qa1xtVc`eeVa( z+(jVq;Mc&Nr^)ORGQvyxGP=dwf^Q3GYopk#F~qvD8U6WRRN27sKga`4|6`k+qdckjd)&;EGery!hBubqvQi!m zKeg=~8U}-Es@RlNy~F-!ol>X6d2l4ec202;?iTM8xL2TSE21Eo`k&;Jk?qdn$)?xG z@kLym9sslvK?pLaVq0i*HmFiPL-LS4BxmiUg|KXqL^Mf)jA1qb!;z;g^B{cdf)%u8 z{|-F#XsV9fX00unNc}{VNkbFe2P|FPU0=$MOA%_yW;`JDNa9IEzWlKP`BuqMae$Jen=t%30^Fqv?q*8Vvo6j-&6y)DGIUT0@@8QnjjbCNn^_Q9HpMFJ^B zbwy2$7A39$zE3=>T+H4JDZsM%zzu(;otOJHG>s68y5E2~isN&d7daKL zW%rs0F9qGcVo!+0%a$-#g{(VXoF=c_RhgQ%S5C*$*ZnK52)+%UGDciqdd+zGy*BjE zNon3(NkETZj;d<~dan(1O8H)d`dB@o~l^`qaoSKp?x|$gZ;@ zvK&spdS(2Ac>mgd5obQsA+{mX*!rhO@E3~7=$x$n=kW+P@g;fPE`z5DyZnj_R^Dxh z0cs71^uD;7-}<50Fu{>0jDecsh-qkDNRw_ZLiY4q6uMm$nnRng`|*~1UlSS>)FH$B z;IXsNou*i&ziz=hG1MEV26F5EKOGZ>Y6|#~qXGaF(*9SxVgJ3x{(Jnv|3^NrCd6+( z?-JjM3FCw5eS-`tH~}ZMAZlW`pnPgF@gML|egc2MYH89WV|_*>Gg9gnmp95~+vV;+ zNJ%XvtqVvbdYVF==5;mcQ=_!KTcnRW-2v&6=Lx}9 zI?2e14)#@<(QE#-Pxn`0 zcdd&oy0=7?-itN5!_>JraMdN5cF$lnylP+1c@$CGC7L$obIPUik^W+Iwg_X?GG)O& zus4qi+qt#OdLOqqU&ME+ocP~sXfp?;OdeP*0v&^R39u0#4J_VE+WAky<>Mx5)A>Pz zudW*W!ld0M%+sQ2ljlcWzJq7-{=E?vIR2eUJN2%Z`6+uSbMBEo*`n>q{)HIV&b=`O zJ~q-q-kub{b{q>IQun0RB^`T$?Zk`le3F3ekbmLkyqtR{ z&9Gf~M`3T1k-bPYs?_hC?`~)#9|1Q!n_&2eWY*ArQ|{1eq9ZT&mOkKQ)Fbl7`Z-=+ zaQX?MUL%vwSB%D8e98cB9_@F&;UY<5&|P@f@!u@I`JTa@dyBuf%?K^vp=yf-KLT^Y zU3}8y^wvBmdbYnLi@{^IPfPF`BT@S!%Jikg|Gso3>i6)*Kw7kzSM8 zlV?7L8D91Z0{(_Bm`cuDUF$K`(NYrfYNV!5N>Eo{Zjsg3q+DOBT5iey-E^03j-Xm= ztgUvL25ZV9HnembOqbJ~6DM6`g$pl((mn>YqAWK}Z-iBJx>UJ!wz8hWJpHSU5dkX5 z1(BB3u-im=5Mzja_1P0wJK$$aYNz*&~ty{vw#Hb|kI^lO~HgN#Ypa7ZjPK#wj}x`(M$og<@8m-5tZ`@<4un4q&;!Ug|}12K^jb;lo3w%(?Ouhn6J zzrYLMbM>{uBR~6&r`rt4Vx0bnpVCD?t=mFBwQGR|lE`SSvTAlaaqMk{!b%M#ve}at z`iBM{u1?T071}IALl68RSdUU=MoA$zD>v*(s+H7XWNU?g$VRtyeFaT<73{OU>uE=f z?*wHY^#saaaQ8!Y3W`K8imHj8UMbtR?!E|bN|vMV7Ddg;6=bl(y0~DPV{YWxRYJC2 z3*RZt#LS?UXK&^CuU)~f+9lazZ31PPo0>V6l^Kp72CrI6>rIqnDyO~#*RPs_8$Phx zBw3ArrXp8YrmB)>e^gHkogEI&~@U%98105N=c zXxjf5e9Q);EhBOlxdJvF(`TafG*Etr$l^U>X%PAlRyr zj+&kPmGQcJy{%w9&4E#CZ`bRwxs)fL)|Qa?n-UFQt#fvj=3d&80Z1q1(c3$jjgsLd zR8O4XL5RsAsIJOTOCEp;$a4%6Tv*lpS9gAgd}VWqZ$H;bEJ=@jn|M^{T!2yU%)Y6G z-Jk2)9|xeW$XluC42rdGpPGnyE^HhY#Se!|)x~YlnE=XvV-RafsQvu*9QjO|jt@Zy zA^;*L+QxToc9S*^%~XKE9Ey-P;@tZ$pdCE-V>mu~uXL1N5eaf&e&9W=Fwz2!0Jo2@ zjix@QlEH+b)D+&`$bjU1H&OPwpri=K*LO~S0})GMmUk7`1cp``+c8R%w9vKC0nXZ9O&V^c>F48BTIm9Mx9y++- zBGPD%ilg4aW3i7B&xXh#q*BKIb*@Wd)QlU81I86x2#$am6%oEd&FI59g(4u%LY z-1sUPGeQJGNy?E?^u1p=YhkeYo5b0TUoj`cQ)C63bf&<4;K5j(IsyA-sZby8dl%PA z*7vGsVk-w=#HXztKD#L36W((H`~23!2%$-4{K%sWEMq6|H~y5e-YJwOM3R+_JO2Jd z)`(IjZ%_q-GboQVU+OW0MJ^k;><0{H;xRoA!zrLeXbFd?So%5dsV3o^d5!0MzcwXB z{})bBkI0Ve?F-B|;Llus(Ift123f)lrgJM$=`Yp&u(idqbPe8YZIGYstePa?X< z1kV$$1|UpWnbLhLWRTxv9F{kwkpXEM)+0QR`7P9EVSld?{TrBt?*6F3GyS`bqd?FN zeCdzG594dxXG6c=z8Z8#);061%4MnD*eQ$WOupTMjyV0s0B*%nzFf(o&hDtuQ6MZ5 zJyJvF+26-o<*cnM&`0rZ__;V@`Cmz>M&Du&6Ypm z(SRDW2~V5NGLu@GT$UZ58y{U-g9t*CI8d;`f3nNC%i%og3XY;aDcct2HZ=hUsw@1< zE72Zv#ohCFko?Wih$5mq?EjSRDv3mir3dK12p34KDdvZJ@{{fcIjIZu@XupIEeQ|5 zL8J+|)NzZVQl_K+)RkO@#R^-@(y~|70Ze}N`?hPsM%E(JFLGEgbtQc*$S1>QA^TGn zStWaN4FiknO#v=X36|A!+r)Cb6t@W~8mcNtqma#*j-sf5SoG1~>*v$?TdUr{i2<8p z&)^>ADgupxBhbc#c^`|e|uaOHn=NmIhnP|0Vgu4?V+|XvIj*Zq* zv*1wFTcI`HON%G#pn~kr-;e;Oq8mP7tFNBy&r6DeLhzAWsNe09r$0hSNd_d>FLOkv#9Q=et!do%fW&jIWHoQY5Onk)IEkDJNOjzfWae zVB`DaD#G@sxO71US({372Ja5p#1DW5-6Y;J4!0gswLiCmrzGAbE=Ps}=i6e8UbI2VTwgiO`%7P!}d<1zw66Zxc!#06;QdE)_nXm}RM3m?|5z}=brf5B(37HxAYz?*n zT5L`mrKgrG(tE(ah9O-_+F1fPsRB4B1!;&3_=FJN{)!mqhzvmxnq-F#p%gEgDT=cr z5obdn&isKO`}#waG=zj2fi^CCFIF?1B9yF<;Sg@UU@U2rHbM|X8`J2Ru8pH2ls<(|&3eQtPJmmZB)3BG$5> zq@3nU&FHVSyN-HTXLRDhbr(;XLB}gFQKvmA{d#ucU;;bpf_Jy$=TBQGwKm`H-T0nk z?C=wSJxm_J%A&nm{}YraXe+9A8I=}_wgY9y{>&fR&OlrxcW9@ukdrjXmAY!4UeY(N zgT}|~;SFslz0}h;^!9z_&uIqn-n2mHp&1QcF#WXrHsuVQdG7qV7x`y;nNxc??7~Da zK>KI_Qi?wKl*%1}iMYi>Nvumcia3mVtUy@ocpctrZiLoc$Qd*L3&~qr#K~y(C2PtYexG>ZBE%TNW5oayfS~_!nC<>1TlJtr-Ll2gS&B!q;({N-HdYg_&;^|SVPuwBb(`+AKnXeUXSYYMB)=;Lbx`5~ zJqeUcz%eV?bFQXxr){3c|ZrSj2PmH=ykcuxrmM@YmHB*q3od^f654|1@y<-t4H@(#{01sPzv;s8x+1Y;Po#Ds z5IxMCkiTz1t($T?_fS3zmS8T6dhty;PGu$=rjzXUj4R{1c=n65BOef-u5rx{5V@Z< z{Z&x=y5mqKTjdGG`{#it%poP2*6ECJxxYI~T7VR^Mg=qpwA{Q3_#XBc32Iihq@My^ zhGf+SNdfJUq`t~IbP>u}uA7hBR7S3dT%lMQsa>*awdLB|M8W=bBb;wbBfW8FPMj!# z*cEtOhS;~vAzl}%z%O`g3gvXA2zJF>@A`H`(TV^0#%%Iakpl}(Ag%5ay3r*3fD#TZ zODuybGU@C-m;EsR1=KDF>@YgCJyE2s#yieCDbW@mzFVA4w1h9=b;qz)=<@5hAZkJ~ z{=xs{cDX3av|x|w1S=O1Eoo8zMZ;Bb%+ogBXeh59TUM!KrWaTGHxDENMMjopqd_dj zk3Nae2Bc)fAB)`)Py4eepg1G zMptCw4byzr+>}vQq}vnVdKcpia#LdUX3E*uI){H##O1-aHQBl#&=Z3jD&?KmD=Bw- z^+>!UBlp1b$h|PV@`m3%>fo6dXAcV37}YyH?42z2Ch&aAkUIiL@wGh2;#mO#=*PDP zj~aPq$B2kSnr+MZg~P#HHUDAS5j4-I+>z7-oG908O8E=lOO4T)6ie=rc#I;pZLHW} z4Q_iNzBW@aJAB)J{M%yr^5(GK5VpC5(O`OkxVw9&Mslfka+O?eheb*k?=mx+?Go$_ zttVQ*vZHIrCsp?q1p|2 zj9UZs53<&f>MtIP9!r+z(rv29A%;}wtu6Pd zJz|HSpA{*BDuMiFMC!@zk4jGM$S1p~EH_bJFvF!9$b_b8Uqd`>OFd}1K0U$! zn)-Ireu4ynnj%5S0ZkvGYq**8HK8Y(<0ub=T~1|gacke&M)IH^$grC^ zX0O!IC+?CVZ`zKW`!X|Q8$6r^Y2wHkWvFC3Ghc$}tlEod_3W?`Rc?w<UcM55`C?tTi7m{afz+JOM zFW#uLlf=bYqxX=6iVw-D9`l)6$&OM+Xd9p-a}wp!lm(1+im}JiIZGSNoVw|JUK`Vi zFTse95asUyOXFi^J5pgBMGQzSQ67-qim}$I4_#OcaTa=u$cK)sF_sc`Bsm+~rD}?> zGfSol>3h=&4^$JYCFR1UQsw3(L~m)yTLy@|FWQt3>A=aIir1W>GK1udfsJB?uIWBI z(ljktH}ny@6ECW*73G-n{YuG~W)%n-eOH|&bP)ho9~D8kbRCV9WapBP(8^#%`VU1F zK{7QGndN^27;R@6%9Yavnl`vJ3p0gIO^p>oTKqigg~^dEYz`l~Bwiyll=0)4t*_kI zR0c)`ViK!L){*4+@ElugzrEIn#c!~8GLS7Wtzr$b(qP6!Qif-||HkFa z55WJf^ookqggX4{J+Hq?FZX{{@A;ns?|*Y#xct*_T2w^_yLCE%r;3>oR*T{&S27z}zS(q| z)k*37`Ffxu)GSg+$yKeOE4TIVRe~a#Wx%x6imyjl6dSxF#+7y5A3V?n!7=@_bU&1e zwu*yM1zy>qx#%pdb`P=o7#$dy-`--w?{0nwSC*+c%1S@>r9{l9CMWx6`a)|%pfiK? zU*pMGV|5?2NzRS}YyC@P0}Dswasq;eV0QKxVsq(o{S#YvFnn?G->!}9{6(%(yw%*v zhRQ(HdvnfrpkuuCv&gyLY1CF|Hb*0#(Do$WsaEgB1}={Uy!7zYm$-%L>NC5)xiCCW z8lz5&l>)elDyASbEzCwazfruNa|@q+#{FV}Giw2B5Hc(DF&5KIJrx{pp(Y7Xb}liD z<3~S4r}uu8hgYl6qlsw)!xaa8tVi*|C`6P(nMA-<>@a_@H?~r>Cp|$rrwJQkrv-&~ z?n`V<*PRzyv@)Q%Y&vsN8muRiHpfC2c-We-812R8JpRxR+P9jB4$q8}f^qd{mO>Tt z&mm%JYLZc^V%TJ48oVbIO$P6L^A+TfI{(obN5YJ4t>8G~&IoQbXXx}l>m)eEIl=cu zs0zEQuLDgoroY@#F~{7?gr+0Z$n46-s8q<<&7fv)p ztEe8mTvnysm-Q6ZmcL}r*WW;g&fb<5#&zK~38Q3&97gd9IoYRZ1e|1`?TQ>@YSXc&90(mO=+yL^74A#IU1+u*Yg8#iw*~@Y){t5 zeZ4F{5*X*jd;Q_g53an;+sG(oESN7O_>?k{>?2cNjnj+?7JT0#OKi|l#rS5+eJRmM z=1D=tq=OUn$d9gacw)E)t1P>EZs~*_kq{2X82Myh-q;mRMD)OoNQzsoWN|+RiF5_g z$b#T1HgMRGqw(-fQotHdm{7`cjU*{X(^C5JrLFnAW^i!Ts2*EwSRW@6_`BnJ>974I z^7g2Nq`mni;^l-ZAryv^;7t;!)?*HgBJWN6X_Eefa!!uCWM4na8B4FR)rRbt-cU78 zwX~N2jTh({?tuSG=hH=KtzHU(m(W^nY0Fa@4lelvhxGax(fcLZKid1u&fFlnqEZ(GS#y z%JEf^`vEe`ZH&=r?OoC{HrtB~EtxH(>n$?h6G|6`m@7g@(uHIERe~gvER$HTq|`c9 z)jHS1z5&mK@ZRTEyJx$nwDraL)T4Z!In45Wd_NvG-!3OFhyYS|*>tP>2uS7V-%yhV zrE?z*Nn#HX-IB+Zq;pO0ZAfS7IYtgONN4XNc-dmTZgJ>J_dIg_R)WyDUvtsu_CIv9 z`^K|7m-Eod?AL?RxL*UX=)4p{iEuyTN13GGd0rF1>gYcxsW>nCt#ChAgI2oTf%yy^ zV^y+GrrDe%egKm4?nktybapSc4ewc#qNrbBliWPsbFtDk+o|G}=0SZ201P|&Q+H;F^FVsK{JB$D5(XY1m_Uf3^q zS0^+{pR59LJSaj6$gs#LO=b`+=fRA-w3>&l0MgZo8G3?sDx4#3mszrM*Ta{aSSse^ zQqk%A+Zj4UM3K|-vgC%{L^^FLEL*B<#W3wIo?lEz)iQwtRJ;BQGhk{Kh^mOG$aPh* zgJ~7BC@Ckvg%EQKc8NJzE}T4FP6V37-1k%?&juIkSdu5+UKD~oU?`{>HzuzZ>uCO} z%!S4<;Q5ESEYoIuRDH>QjxlyA@qAc%wTnI)!^LhYhfAGft#qww()&;qORiI?kQ9;9 zSeVEZikf93Fu9oMB7-%J5|ACa#gfuV-pU-Qeh)t^((2kZ?xSg_9Ic$-Yq!-Oo=MMq zUp^IVKYH3zRhT#^6P8p_EP3A!8QmI=oXEIzgi1V)lIOrXZ|J#AMA>6_hr+=omAKi0 zVQgIBw0pV)QxcA}W`?!dLa9E@GKG2^CP=fpd_O3ui!|&01tcqj+N?1dF3H29#a!}p zFF%NvdX&o>)w7iW-)QB+PQ|F#=UzG=t8ge^C6AAFGEgJnaEHh9Rf-H#7YT^ zdD!i{jI+@)FC20$*gN~7Z^oZQsd74m^kE5Y&@#h-~&&b zUio|`H!L^g&qRsDvOLE=KB2Ney}cF4bp(Zas7@5`nYPq#JRB)~&5;P1E3YMR67#=H zOxC$6He;mg3t7y{lzE%=wP9Yr5YsyTKHsT-%^kdxiPY6+8Xbr%0J8XiY-xHttvC-8 z$ps=p7jLAMUTS5iF^XjIjHb<@NDwTdC#WXCyawYFh?dJek?(cu&*%xwOHB+w7E`I z%unZ=O1oulek48@?hH^>xA@)bRsC_EEYmBi$8hs}E->Rt2l;=)y~42B)Qxgj6p<1f zvko`=Yl24%7n(7&!dd66d9s^;4?zP%P?Q(<8<4js3vNd=-A_A2_f0bc%?DWd9ifHA zUEs9NF?R_=oLS)?Q8>l(jJkScoNIN@AF>iHd~~JooU9XtENxqu?ZjZuQu#ybtkGxg zBC{aOqm;4fLC641W|XI}y(TH@%rl12YVXv3Z;4&y_Mu=y&!U#cy%U&p^@3+yr1zne zcGUH(^LC*Srp}{qfiSa%(263--Us^al3j*x%yS2IVW5p9@!7%Mc6$WeflPv&t^QiY zS3_!(JX3bf3mlG*%go{<8*a8T@a&=s^VS{16zcn{pX5tGGODK$<(VhKV+Iq109}qc zW9LWng@c@mpyckx`BVlBCXb7OuP8`1m6hngrJpXivXmKZQqwRq6{@ZeV{4rjeu>?d zn;3|PLX8=mqAli^jtw8&BMu|i(;|FAn{iy?_`M1*5B@u@83dJZQudx<2_TU68B==( zg$(K`F^fOwdW{x>-uxO!ndeZ_e1|;qO0j&WHihTQ@)e2}T?s(+77|^M+5RXs`Ac_& zfrm?U!?4L?PE-M!fhQY5J2c-B^of<;(pYYfF4AgV;9vC2IqZzS_)!54#APwP#7gSi zIIg@4r1QoKc}IJEz_S@er5^oaGZID(Z}4t*B3I<+c~1?m49_U-B@ORnej9C=(XURd z#*La{SU7=@w)()v1H(+d+|tT*dbo#aYDy1AS0Vsb&dIL_W9!Y|&MN5p0snBzaI`>{ z9OYI%>nqv4>vX?oXCu-x%4i5P?kX;4I^}SCl58@Q)-;l^aK+0q@3hWU#WB15I%9|g zMSrQd1Aon-s>BOSQud*sxITNAhE>wTdcrb=>tFY%?$K7a?pCdRrKL238JoikeA2gd zVQs*xm2NkgGM!A&cQZb~C$Ii3j`|r<{mJwt`~@{}r&d``cbf9XrSgyOl;jOQY*5O0C+JZ%pvvg;uD#{p`tc6;+}l+6`}fKyFGIuWGJrycEIqD$7o2Rys(il$ zi+qD4nnT1XY!@yTx}eJ(*MYk4(|bS6{${nwSxM7Z##E0KgRI!F)Ekv3E?;$k28bM9 zAURwlovacbS?W~kcMoDf(lKO-jcRq5UC-C+bJlU)c)ou9f;&XB@gvdVG$i|Fw&4Ta zM8oa~TXnfiC$7~S&yL6R+pA!C|72ldj=^Y+!^9kh+8ldRuKg~NVtwqoB`YXdK@ZA8xo-WUvFcW)9X-+O}tYBXn1CLylC zPvz%{#ZiChl0JGVkbBD08kWOD2>!6Eg5y|;ETraNkUk31mMJ*Lsl&8WV|4^JmKrgs zO|l6*E-Zzeo(~?jk?kRg*{r0PSagp+x_qe`IJ`V=l4^z7<29<)pK_~aZ0KD{vO_`OJM7ghpwh=@HMKkZmRkJmYtJvsz{$TE4WEj{o5v4UCz(E^m@NL!twq-Asn9=7M zA7|cAg2``+OMx^Q@9FlOE}JNFMFFTKom*PoEgeL&gN5O94QD0i0jHDD;^Wiq``*D; zT2vSPRnTrYGD$M|b0I!|5{*ye@+i^hryayiZsPg#p9pFA4d@0}C;$M2i~s<9|J5$^ zzq{c6*Foji{+7Jd%x8AZX4ONS6o79`Kwxcv7?Gb}2&6&4EoCqyzx{v_@ zU%6ztX+>3oWgZ2Ys%jMVPr6XKz9;p%re>?j$Mx^^wZ?V3-hHzlw-5GjFA4!iJa;l+VXGdx*iL?A2#RLrz_1w7*hcGQz_Eg& zt?bB<6-9}r>SYhR>~2pxb708pMz?EN5EiLP>#a@gSdd5d55gY~cOT+OJNs&A7`Ob8 zBV|<|>`m@7Gi+whL`u8uU&x7PKJcuOCq`>3Q_(|?djQyH*FqecYw!u@AkOVHDZTp(n=UziTmCw>+Dkbx5s@f2SkVJoC|la0y!;#KX0G zw1eAEPYnH|1aM>Qt-#RK91xBS!@&$UBb^wg4js{Y;#?B#jS!Wnx5A;^9J?n&I@@uN z4CAu$yYsZvylyc+{gLWi_FZH@@dFWmm+1)J0XY3R{h{XctaEcolEQ|-X!EP`U2!Az zIQ`!Fe75zJic8aOve$c=Ef4*_8P(_g52q}cyv~-c!P@@CH4gr z5~>;@cJ#A2x1=Ajq)GzmZ__&`$_$}2H}5{&GBXmp%x^^|XyC-1Dh*;(5z~Jvo<4%Pg$ljw>6SG#;u?$c(-xWF-!Q1k>FwT(mroDMccxVdEVQUeauK zo{TVEf4V~rmhQv;mkApj?4!Ju3{x656e5-<(K>>-T8;H?qOls3cs6l;@u|pz}_04Mf}~QFHY7~Rc-q-I_Vz;(0|_1-~n8N@`yv#Heh!@zw`vZqs*r z9B52iQlHg`7N&&t*taKZx`BJHmlQ#iYYeN9UpK}$t!QbQB1 zF4cWmV#)2#`-P|N5-Y zTvo?Fg2ecbeb!AlG1Ffp!Fcv`?%ACg5mNl20HH=YGb>xVU znu)pT;`VY0PHlfKgUG-F7@CcTngR;ZLUqz1_hO5Bdt}gRw6MkNzFTX8n;K!_Litoc z#O-wnG63{bs~d(xDC+7!r^U;wxFy%P;eJk2uzh#=zAmk`eR`CbO8RfiOaPhkC%G^5-hkUB z@YGQwrFX1JZ`80CYHY5Ha$mug?*$fj&IycBEoT~E2z_4#7jjR+=z-h&bOq%=)jxG zCfotIiN;>1n4!0piCN#4dv7EhKF%87E{$!%6Lue%iZ?i(>K#5>SX+I+o{IM$zHyL> zN2ON_6ujY4W$FP#l+il}6uzK5(x_OnlAMMF-{lA~WpALk%2y8W#1U5!L!UbxiIz18 zLZiKZwfcdjr4ETu4cTRLMf;2HQxSP;cNpBVcQe^N_|!jsYqF#%W#qk&S2R=2EsFq; z(WFXy1Xl}MdEszjNEDg&{Totv)q!ybe#8<1?@;>+PYqKUOiLYBS`1mg2*}cRG8*PVq^HAkAhoe>cnjO<=H3mgQq^ zZ!P7KAvalV%c>YKN+W_&+#FeFppp&@&f}AfGFfJ2(Rk2(tDPGTiPlfKBVb6H*E3*5 z3ZI^B&1PunMr}bm>0=Q0fl7$?LswGB0p({RqH4sQKjC(l4oNJpoU&|PHI#0OF0Wi% z*v(xqboVIK*)3dTx%jr8KGksMZ4m3>ktr(A26CBW?+rR$5()2Q2;Gpp7jZaa%;QZK z+yts9D}sviyeQ5>;fI5+9_Rge{IEvC|1< zfF{yom}e8Yo$O*key55P7|6L-Bbk))c0sD2iASdYj^z08QEnZCNSOx|68s#mKTLe+ z%vq@Mr#^CbmaNUC9xk;HxE>p}Pvn-FdGLe)V3wbbL?vq%sy^ku(r3sd6cp!q@JpFZ z2&86BB9Nd=q{F|;88GLYlL4Yc10Q$o%f-Hr%`u(B#dH&sA>BvNEESXs5bU&gF;hW} z0mKaC+?#2U-ijoO@-yY5PiNtE-Jt$sf;2zdBFzmWVcUr`f4~o#l1*mdl37_M?7RS? zJb{dZCdvY^t-?Fu`ITYs0|IAhGWeqG-w#v6c-|o9D~NL+6=I#9km2stzdOeZ0G!Gg zRXrd$MJaI%+yxVLv5VKmf=N9!0W!uFZ^B-palIriWvhp19PJTUT8j-Ewp)DU51)tPt0}UL@oQC4GPqkd${l~8SFQpdq?tnJxf4|p84=lj*q&=mrBH6(u*GiF=Vi( zo_XGAx&x?;Iq<&;AuPU(h%In8jGV=uj#(+j6vIy`l6sh^9$2vaBx{j*)+Mo^7i$CM zyjiY1(w0?eE+KkM4ATwaH-@79M$*iO4E5;AN$iU|Jue0n)gz7iFf+lj*&yBOuvzv0 z7iaGnq)Xprc~_mXZQHhO+qP|;vTfV8ZQG}8+nRGvcfZdQ^G-y^bi|G;uE@J27dB zVL&$LK2uIjOJ_w|M7`Cwih)B$mxgjK`Qr&aVsUh^q*_**>3a%M7N}PpsP<){F1eOk zviHZqhz!iBuLgUqqCOB(tSmTT6N$4mnzOZ`Bhgsgf<2Z!=LLLixUKhELp>$r=zx@> zg`c4ZOw!(J2G?W+*Q9Awp&hJS?TIHvGUFgX*sBNQD(|r9{4bb8FpXWwFh%vi!9QJ$ zGIq#9$Ivr6*Z)`o-lFX`EPRnA#XN^`z&8>1nFslq;#Ztj8d0B&F+1A{LzeWRA7;$i zr|S6v$LGWRiAlG*K;H1H=<5-oyhtIYmYiY3ci^jxr6oD2hR4{TW#-zZ2BRO2k zL5DUObT!+l`el#^L!}irSlAZ8ebrMwxhXy}CPOyZSeY-mULCL@8xV&r#36?jzAIB4 z9a3EFAz*_T*gam#M!IQ!_6be%gNW6YG?S4>d|g)(*kp8vYmafbNORvkloT~tb$yvB zbuS5Z?_}T+Db8f-9u;TpqWseJ-GL#W$g!04B}BoN=nX+84crIT(`O!kf!VWO=^t7oxJ$>L(cJNF=~4qKfL57l zB)A?4H4;hRorSk%M7|uAG5d%5EZB-_=1`OT{)RYpU#$jj+@8Wl?R*N9t}N1o0jn@8 zV?@=AB-_dq_It3dQ0=*+eYjdXfQCc2MF z7A2Qfh?=smmE_|Smg}Pu`PEq1Ex2h$n*dPOSWZpdb92vvZ^FiRzSb1B`5J$0Qo{TU zhdS$W4rb`s_H0PH4s&cUx{zU^rrq6s8+JlgSTm%VMV{GjEBbYnn{0N}Uf>R*Rib{Z%LZ;`6VhbzlCPSD~`z?xe=Xowc{5`iHol zhxXDd@A5w$xxSnyS+M#)7=knSQ~;Y)zx zW-k}q)+vWZ4C8FCH5-a^q!Uq*(ic)t*_${MPE( z0LpNMa_QWFqrHQs<|>Hy=ihQD;2fHm=s18I%zB?Ns*BoJ0@LeXyr4{#6+9t!eu{$N z{#=o}Xl&JlG111a$QPdS$1ud5LVYmEQ3ro2K-DbMB|DEgx%rg__EXL02gJFsUWe`r z_amf!B0%#A_)Q+{yXF49Ep~za#qGDHpe|>ZHwi1G0fxkbsj%h&?a8L_=a2n91P1(; zGwN27=2YH^_lpJjELf{LNJSd}%&b zv!Hd4TeL5MFV0UDFZqMYL%$}Vl*l8<(b5jZ;Y~F@5UlXS$WPI0dllJ%Bh665>$*%X zZ0Smk4$@Fsm6Xk4N3rt33r}=!X8Mx6)(*ERfesHDqIF}>H-qHJLkWAPv$OyzVio=* z9wF(2d`qK}45|AgYf$y1O@)fOWn>Gl$n8P9uY6lb*6f=!0mHTK8j3YMt|3=<{>T18Lg>T-JlP0= z*Pb=NQeot8!u?w~hA7+kAwz}$6T?zvQ?_zqNy<+?Mh-A4vO+;i3(CWk=eGbYzeK!w z;F%yc^Wa|y?2vw?DL9eiMcYMxhT|X72S<7nm!ltL75PB)%jjG#LoFwAufgn+M-?p9 z-a*B}$(?g`Dv}ly>@aEKFUTw!REWZdsFh)fe$5p#g_L#S8F5yNq$@~Iw&?oRRJ%WZK2UNa2ut!gKi z1uzVoR#nf`RIjYaVkuSp4A)Hza-2fREFepGBDT=Arf%RRo?yjg%=u27iHX`FQa$8? zU@FxZ(<;Gd{BFkfeMCCV{Oy|IjGpjmlFBKy>lWq~%N_r>r_otQTs zTLj*2@_r~fBHuupI|9-^2{r=Vf$kk7E@JP{!9H>ha_xTYkX`XrEeP3luQh4xB};dHyf70SMRUxF3N8R7!h_>0^4w*jhhG(3k;zOhTL| zGK0MBRw5X*%fRKLO2iL>wbN21&8CG~`SHD-&V7NjzYrK+;A_d793gq_GaK))$!W0u ztJc!J3Mn`x)xF4t^$pm54d0sx<{?$p4OsaOjdJaAq)#z|Ya8*w+v1~-{H0mW?%#`Y zA~n7jEPkvPalO1qwMxkENbbWsIGs8`b39e)hJ=n<+I>b zwBr;Z_kbecY}HEobtKCXEGhH^*gVDGhw1U4%8KW_+Tc}qwA#gd)4!y6SrL?l_m>PqGYkIH>!J?ju6&g4`;*S( zG$Rd)E;z$K77UR`JV-*BW`39gV2MxKiI^9#l4UHL;NNa+Mhe-ii9!u-LqXN4wWKJr z>Fj2*Y6(^EUa8Zn^RlsWWog$@Q?sS2wL00Nck!A@Z@Smsm-a!{`>o3REzA3@%lj?B`>im_ z7pxF^gZ^6Men#l7c@j79xejaVtB!y)IpNBg+ZfKg)Mo{_>kFTNgFG6)p#$ zfb+EUCNi{I`V|n0={PmfBcYnrJsurAiurQX!;!yP69Nt6io;ASyvp zOB>4fB?0|>22BBNWN0m*q%Xuxu4eY6YqM`!JQuAgZpNN8&Zbp)NqVNh9sC`%SV1|Z-x-U7Ck)tVN5d49FDJU@p#{W9?xeCx`lX}O|wgqjzP>K^?1 za@Fl?mGM1#|A2Ch7u=YEMFyj=&)s9z0xtcyvR1_BCw;J{doXK4%F#>@rFMhRdVbXR=9eO$*@_v<#rodH7m272wqp3D9 zq?_BVlqWUKD+ZP2tTZo`V&ewRa4T4CM1VKAA7IF%wHSXCt;|_l-0}p*>u9=$%InAR4qZy`j0WxDd zzd)XwaIo1M+#lm^%03_crujgXL6)!7TS53WC|3)TCLq&63Rq$d0hs~2Ultn4+=}5^ zxP{%vMnSt~LF#+IJK`?`L&PY@SsN6ROC#*TUNL=7`i}vAjw&D(x>`taB)>3la19g@ zp&+63U^+Ff1h)wS0)i5uVMQ7$f&v2%;lyxMSQ$L&^r3X~Q4snaj}MjHS;>qH4x8AJ zG(+T4i&?t^<(d95g~T$C&#yaW)}G&|sBtlu5#TL`TELz4v46MvZ3x>?H_?Aa+_k~`9H5L5~@e-HU#h7zt3#IJ^F>P&_2(!L>}xgap8Nj?mHhOx&Y&YpUY zWTSMb!y`Nu2;?#N64|ilOrsopl@|Bx$OdQ=Q6X;GI?ORas>5rb_SVyrxK9*iOJ4y&sBR;s)vlFI-iJH#u@PyCw z#!0o9HM;uBY)~Q>)#^NU);ex5xINjnei$p(hlD7T>TpYdf9d19ZTUOYb@(P6GH%-- zI~AL&EAUwe(vxk*F<6|tU#O%=e|+cviDp!-(%Gzgc2?R_A>UwRRe$ShuB2ldQcq56 zt0+7)xk_Z_=+_v*>v1`f()nUMsIp_%5`EEUnkRQCz2 zqMckaOVu(|^%~_ZXON?pDAmqVoXSqQogP1?N<5<(qgkyCXiZCmY~p06vCHlPI!_@UcpQo5jh|jc3te&dDcHrqv zxu3?5=HDkCQd>&Gb)kE_TZe$rslyL!!wk}Wyu(SrSkU0l3YxLoeUjHwagkHXtDsQF zVGr>r-R(R^{#?xpQpIKW*MEXIJpv6z0?!tHEf2!b_GJ5&e_%Ry`0DtE6TK5Umy?H% z;l*SC+H|-;y0sLGZ+$K+r*93+bTklNVYzO1UP$hQ>LdnMY!A(XR3dZIr1&$oHaX); z+#X^!iz(ikSj%!@$Jpu5zxnA$wlSbbjHVM1>ii+KCz+d8_3Iy$HNRl*Q%$RXU6 zr&KFLgPKaGCEsg5z6?^$6=qE3fS2|FZ6mgPUfU+~aLVdZ#fJwg<&NejhN5iZ4E1hgew`n^dYNNs5CBw zaEtOZpJAG9rZ7%zxQ4e_sj2+j+DqHJnp$U+$`S$hh>s-)CQg!P`TQR=f04AzkP(%T zYH0G8mrzm+dqyNA=z9cC5=dA-zHJb_hh1ri!F?}q1(X=CE~+?Ev*#p2M12ST}$+tedyHYlhS zLKa?=Ht>ZhQS+nB%i31kks&<8ijQ2IFK z;{Pc%1PFV)9mHKEZGnw}h;!2Er5HofY^4i>F5ZA$@WLKeR>o(hbp;zs<_G?Q3dUVF zmW|i_i9VyYzR=J~I&3pFkD{5yBk@o8 zCgp?8^+whOgRG>a(hvgbxDVN z7R0vvIJy7|DS~eMaO(?_3pa+Dz8n7cjAx{O_Z{QCaG0A*03^y_aC)#7(U#Nh3&}hM zUclciGc~mT1iq`&JHLXT8vA(!wBmXp}j;e?|!G&!>W z?J|LCB9v<+bKu^my9zYJ)Xd*NAy4HHYuG%Pb{am?nN0e9jp_N(M#E0(7u9kLP!d5` zpy&7N3tZ*Vw;i#XU2mQs9Ue}n6RPAoYo8cNgZ@%K~Hg{&b5RZwPLVcmKyg(CMmYK@49WN2CNY%cqV)+7TLsP zj1wgTrnZNe%_8iU3?UXuf9B+L6P6dF6~abp)D5v4D3R#Q3?Z+HQ+7Taw=7g?lA&B8 z;_W`>JJQBYI(Z`BaH^rrQ}`SGMEBI9u28@`D(FbP1JgUK%lt0At{ag;Y&dPvLdNnU zv30=M1|VD$FztyV;_!qJ2d>3nYOvD!g7#debc6N`XTkL7SP$k2thA!~#4Z)C{`NwV z+NE4;#-fpucxy zp7x(wfCrN8U2J)-R~nTni0bFsDhX~6XcQ-R;P8y%E{m$|1F}84DGpyy^b)Tf#2}w& z`nQ^UouaJf9;7 zOMj6+n%9NDoR!FDJGa0$TSS5!<{kf@IL*ye8g)j^9@H19JQ$saTiUacZgqB`>_o}1 z!*bqnQGPEhyVZ$Z@4+SZM&0o4UOT-Q6!VtQzPJ#JwS(XEp*ZBQEv36!9&hv*>_{X< zC^);kh4dGCbxJJ=bQf1Bs-NJv-VS+ru+30t-Rthkw^e}nGPp^NBRS8)cp4`6{ZSy6 z-Ln)eh>kU^cZO%!GmH0}u`W7fpCNk1TPAXsO7$E00sPnQ-#-gOiC(@(XMclRU@89R z3q$`FBlMp`6ipBP|LwzTu`|6FNbna3g-1tbzye131qx1D6%QO&hpruZNQ99#HKd_l zRV^jpFsu_uXj!dl-NUbFsBYyU-sn&Z?myGM zbkQlr^W1{Bqht0}BY;8Q;{4jgbL9RJ-P{?YhYoS06DtSC?7FI>5Y7So2f@8a zCgkz?%JwFVNmkl>#gubL5Zv?A$%6I?(xR5$38|)YXtulhZ)>C!=>Z$l@2<%G>7YqQw|T>9E`Km55ct{wly#JXI=87Ft)Zy zH-v0-DL060xdc1Kwzl{8jJmXmD7Lz1M@;SOE*mY2!u`Z+Dz>~*J!YM6*l#&hgC3Z< zH^r{7jX zLX>P2CeVCXs>^`CIo%H{r(_x+VL*s%Qu-qhhyd^GnV0a}LOwb6HF6?aX_&nWy{%qO z`Yeytu2+wF9*9a&Z(A-@zjkD|LvU#k)&s|^OCcAxV`)Xr7^7Q?2sdGj7i%QdgE;I1 zCfg4+NE+(2A>}44O6_ggY9m`HqSIuYt3%$5xbjaLlCD5dg&&**-Vz!aA)+>TyP8Uz z^&U27&@Wi*@_MnGLet;uM~SbEs$-=VhrNprnL~+K9@vz_4juolMi5617uiG&=Crqz z4l&#+DN?|S4P~W~C27ij>Lrsb?_RUBL*&dbgK`0Y7#N*@rNaSa~|=CDn#I z5YaNT-q4o>{OBusZb274@f^?QZy6$#&#ea8s1u^G%yb93XGAn@qrsFc*Ra z7aq=^nHekb4Nn<1C8CQkkYRgBhE5Rn-iFnn4{(WEgJP(<^7LW095NFV3=f*mWqOB= zy>Q~ya>ri0tr~tWLVzPNN=Pd`;dC0hm!{&N6bVxn65e}2qp?#I4UrC^Se!SJPn68< z>pM81lYRa;Quv_T=JfW6 zYYL`aJ%hx^DP?o%$f%h=^OX!-{)Si2h#(!r5haaf0$I(|#Hj8!rY2`0Tr;HP1xF2_ zB*q6Sb>5KrNR#EUqykTVk{IFa$rpV=vhjl1rtCl-+Nj-S~%zBzs5?9P7}Zjw8Ya_&i@TYT;0v^%EZ)Pvo7 zgM1e+{hDL8Lpf#fuPO53)Eid2@QzN~h36?;jC@pLp8KM(5FnqAX)3yFHca}6GfAP# zWHZQ^S-oQ|F#;_u=}=~0ptQNZdteleXGReoVHL?j&+4pSOwv2Kcmu_-6=sC02?+{^ zbZU+3g)rbv>ss42jkcSAQ|*xf?$tS=-LARA;oKSLV(yVT$&QP?Ire(5qNiuL@TL=b zyczE(WJHS!T-#|%94 z3Q}j~Y*L+*3y<>}#xVVg^w4Q)l`GYGq>s>`w0v9#lpt;+$g+kbOp#^+R#K=R9NOJS z6-H_aO0dkwOj)O!@!;XBet-)$pa~{Z`J5xc#G8A=#}lN?W`;Nu%NLl(<#vV`kznM6 z)gjC+Odz5X$+!Gg^6>1NKNEY}*U%T{9Ig%}TsF&3M@>02?}&X@IhqxLDfaNe~U~Vlgf!S!pl-F)3lC*6l{!=Gd)Y3RO%h#ZKnjO{+Ga zInv-1Oq+S?T9ntAMibCwk3VBxrmoz)m;C+6@~$oj|1_P%Den=Phy7T(3;mQ25jnq7 zr8DT*G(09Wo;EJ-SIIlq>_~qpC}%A!;5dMgUFXOQ8$((CQ*yLN!chxFesS!&L;$2n zn+00%#MZv9%8jk$$u8-MWn$C%#uWJ&6il*i2bNa?*QR>q5L*4MJ*Az|Y4?H?lf0@y zPT)gF8&fgMk7K;%NI;D`Q8)mjAN)q_h=Eol7(bLpevJhC9S1gQ$)C=UT}fXVA4VF@ z>cG(ISmWuDe<%$S#y}S~6+5b!{Y2lk&Bh?%Nw1Sbzu%B#)_*)P=c|d>xmIDzxR<4t zZ3`NJ@p1pD$AIs9@)sd)l2Lm4IPIvIVZ^wFZl!~&st`PmZRAs^-2I)7%w;W%ZzDaB z9^J#PX}~K=97#NN?1!B823qUVGNf407rv8(KXjS?UZ+hOC;K$h9G+s|HuGLj8z+RD zyrDX;z9F6&Mjk7=5d27E*a6Oj<%9KbV?0eqn(I9K+h>8F3foivNu;;3M@@aF+R~@Z zdD1clR6ScLGs+Htxpn>t-LB6XmZL6EoQ{f)I$sd$37)S+cB{ zP^;DuR$tBKOG0g=2{+9owE&w?^noI70N4(lfe1%Sag41dJSKyqq2|u`Uv)~$e~iLaO?6F%HqOT{ zO?5%wrC|`4<9b6Nra?f}r_qwDJ>Aw7+Qf56d%&|h+ynLw&7M=x#Z&a+rX>E_?l^soz;ZwCL5$B8=MGPnmGNzm?b-D&q*_Q#vG~SFH8elbU&=3bQ>O8<^nhMs~uj~=zPSJ zzt@wRoD0?(uq;zP1KX%om1EM_^o6U_!aaHNreRB_hWX6stA<8Yr{iUv!6-VEX(}pI z3ETq9MW_uIxL-Ge|3iP^Oa1}Q0u(1t!9gIzyECx^#ZJhe3Y200L!;+4U$W&?JXP8DI0+ZPCGNsrh%zO~K7&slzmnvtVJj zXo`XV-874vyg;z@VEhLZlu+!IIF7n&(Cp8O?dY`w#)g7u7I9Vu9F@#wiJ*5K zSeQDppv_A4#UDOl@&#(UdbI-tzCb(PI3PzdX&*FgW1GqXH+?wU#g^}O84`YZobO1} zrF=wWe*7|ze0k3dr(byF-@yZqYLatgVc)&|JiHeH*zOLHo5#){#Jva!?;??V$l537ktILe6hY+) zjkD7Y1bfw;!{ar6+VK{7K(fy`nr4318HpUzyh?7DPd`f(B_v`_zx1^oj`ztCz{wQ~)`a-UmKxHl3@};zTAeelnXYK~8!R2n zOaa#T!8G1DY}ir<9mC$<|2T4wn?V?Fu9o_d^yoA`{6HRiq6A1c)=@UsF&3Qg#H>2 zYO?Z|kvP>!fnfh8dsT97Iel}>rG_rRh`pJeOr@C&CZq{<5IWRV}SVzf0MZpLtyDwfcbr zvi(g~~&bBKewlF|y1XhK+;{J4@Luv~Oy+L!Pq$(n?&8zFm znsohI(UMSllg=2QW{#aL81`nZK6D}#Ox?{Iuonw!Gf89d}q+!06M{y+=tz>=9e(?Yg)Ufic;asi1` zqFQ(iu^ZRF#IW$3XIWyFI*uAP;Kz`0< zasOD~a+b|Vd7WuSjXBd|w`0%lwbf#)mR%h0Nx^PyDxuhA0^Ke^T`B5)A2bTYwqT0h zqp{DJw1CtTXmqEdIi#}S&;v1R&se!*aVF4{%6#MO$eI7Re|iMi;g`FOc8;?vIC(Sm zOt#D4xvzd?>w%e`xyqW=!QQ>{{-JRXs8nj@@3v$5P1~3}^gAF@tTKBlg6+^<$j{ zFM1JoRU{BEdUVV+X0fT#C2~v<+!h(~%ofS=>Yh{FJbce%kC#NCryOSJ>;`akRQPG1 z%GjHM(>A)4LIwjff!!{R$yX#QbL?xz-}s@kriaRpR+~WFpvKU${Cnn&Y2L$G0|m+_ zM~sQke|&3RjnOB*}`}FrX!YeuH-kLORm1=5y2h= z`xotShoAwCOt7yE?1ZUIki)A^1Wjt)5vQMN2b=Z^w9hM!mY~<+;*QWxSSrZf?AQ$5 z;A1bp$0rJig5Jd2sx#vcD8!SD=7ini`X_Aj{SEoVjbehITMN6HHeadRE0kw!Z&7S}YEKgb+Q#K&D~Cta^z?xZE^Vua zM*>Z(Ts_R5M$4x(V@$!1yA;caMA3Tdo--z*GZH7cMD@!-{Fm0UPnYZ@@=UM;!xwBE zscu4eCFi47Dy3ef&}#9v$Zy};gqCcxe5k~t>?^06dA#c9jXpKQ%Cb)k%5y@$Hv&pa z;YyA6Y-X^}v7X88T4|MQ8^8r?B8gTMg+A4+a4a0TcD{L*id!@jOF@M0*yC7&Z7}mG z5Ba7tSSS9bwUOhnl)Y1|pH)t6BNmdH21ntqyqByiVBpEuD%hc9gQ4J@Ys}%X&_@MW z(XK#Tr0z3@CU^ha@1qUrf{Gq_U&5dW=>MQFP0#ZP}3C7hu=e;--VYhp7iENEcLL24%@& zt3yWCkLTPsxiyWs0#nvf<~cVh&-s1N(a1w^zZFU3rJn}x<35z@$jpCuaE+1NXpI62ulI?)OJfB%)79Zd{uL=B9b?HoP+ zW0u&gX5)mUg6!K;Bm?fhf-GqzFyLjeQKHOmjbIHGEN&5>DjAu#X)J-3uvNF7q=*bG zK=BI_Qr$Zh?p5MKYfv6clpC+(S}Nk3omykwo^eEe~` zY5(~0Q>z73kCKw59*qfi2j;qRAMrQKP6JpEw*|%qhb#{prM&~^*b|J!sfg>$CP$9u z5o|yZ9SS$hpARZ35oUHKD0IDS9<;|l7RHbU+ZUXGedMg04d=Z?!&d-%2Vpz{1QdA7 z0-D`)mIQ&*Cfz$ERY>b%~lU6gvD+(>We`_ywB|T z#JV7E({h{aZlI&KBG@rqly8;~3>u&AKxHzSzKk1m5DBoMi6&WNV`Z(at*lOtYps?N zl#quwjW5d|GHikyD=E0cOTw>j)DNyGKbC|*qC|Cp&)0xMEUQylPHJ&4(qd>C+cFS| zss%f=54A2U$X48#!et@NuUBCc|wuCaWcq8dlBCkEVn%cxyG^mJXaSrx0%}zU+hX9wOp~pjE=x9#&2OipZ9v zDgu?xb2vTASITE&J@m}t14v?7(IFbktulE&6_A-0Qn>d_3Nh0}Reo9C=8=7~*kzr8 zZ2-+=YuwCZYdY8Qp$ce{v8^Jk0Wc-NW6P-LbdXp+?fD0soTg%|8{^1IF03HkVxJ_5lz}_med^J?m-<$tjcxwR?ST7NtG9MLK5WYYFn=t+haN_>6k$c<%xZ4l)%-^%aBB%L>u%}mt#i6bV&V4!uPhVe0tJjk^JG+&eUi)xkfi)-`xmJG|Zv0_VW z>%BH3EU$LG#FwZA2TQKd3hY*1jSL!|kRG|;>LVg-8H&Z1(UX4}IYnn73)G`Y4(cds zBpjG3%neG}le?rUmJju|9MV3{ZRIFzSggkJ={ibW^qDW4M_o6^4;ydf=lw=;)!b7C zULvAisGG4SO=xx9jDyf?^N_8*~0F z-cBSm^8w9C)b_Wf@~R7pYpBX8C;V%}3__@a5(|{U_}jwLU9x)+Rc3hg#OVj?Yi{Eo zIHa-qf~A`&{NFA&^pLbA$gcV1jy^|gyVV`6(4noC=tyb{0~#z3kfbmL=D;>kegok-^*XfKsFp>miihE{nf-r3Ls(_5e~Z@l%iB5nvyv zcEj4a|(~SLEn&qXbGB|PX(!1Z!b=mN%LW@ zyor1)66g$w?uf0bWY(s_TI8(?OQr~Yts-9EDE7g+b_R4=B)^3MtX`-SF6zlCE~_N< zpX0n_H4hLo+J&w?EM)5Ertlo;#H}QQNCU@$EeOTr=hOQL-HzzHm|r^DQ<9b`Jh#%M z45ctW6{Tnoih{I5Wu-{Zs>#axOxSM`cz8uQc=Jci%0^Be(M?lGP92h&qvEP+&pe_Z zbweZUs4=NH7G|LDK^G2T=wB|XyYTAFr$}!otUHPBErDTrr0*?*O&v%*Tm&ENNj;>3 zOwZ6gCa=Lf_~N?o&hC)LKhkk~T^86f zyRKFk?jC>sb!PUD*LY_2)bZf2$Jp&JXixaR@f!c%-*f+$%GieN#xeq73Ky92{k=JmSuSG}Ad+;>3VBxlwL&(moQ_mAy^Y3QlH?=-kw z*b{~g_Q<)&IkF(QjyYRt^VpiyAbraml>FRtL7tU2$#t^!jRq!h8PZlMi{{lG)7_O0 zLTN=Ky&!6n7F9wf58H@|pJJ6|I))a+MLgbG9gWW5M#?fl`OoEFG0-AH@R0@tMdB*(OYld5J-C6O68A%B!ibWrAalkFz(@!jKu#d`slbu3 zQ|(38)2rG;PLcz{A)F)!GUAQi9lH5$Wh#Gu>u!<|C^1sCT!YmR?5!LxZbfQIwNibN z?66!-)GQ|mY?wn`CdYJ8kJg~)@F9;!-xVWSs1JD7p11j4I=DIC$!{IruZI*{IfU9A zj0EATe{WOl)bT9VlQh-BstJ0wT4a9b1x>%9jH_37U)2G7jA5_|A4_kd!;p?bzvS_n zVhnUBtyB+oSVi~{ODE9?LXQC(Cxl!{iC;DQyc7YuthK3sBgpwF@^+Z=(G{auA+B@46rQox`E-WAwTgF9FoPq&Y?f zH7Si5h{57Co_Q69j19B(wH0=wdYnTMn$meyZT0m8q&5>FaN;T(>VBAktOzWJ0IE}%AA2k$Q%U+%vnlz+2IFwfnkg;aswS{f8{RXm-6CzMTj`FS$&TKr9rcEB%4U9~%?PsQQd+mHyo0~r*%J)07{ z;`Pp7iJG)g8JNs^kuG+Gptie7%YYc@`cM``UVCIwZq1coA5Mo({b)wgce$$NW7?zRhKy3X2xwzz26h8S@)tdZlXhTFlV}h<}Bw! zF{&d_BVG1HbI_yb#8d^KS_gF_!`tb2F|CO!RxE?KsdZmoFuqHtU2FSX#pEN$6C!R7 zG<>V8cWC?qooVLun%9VJIUk=9JYaF&o#?&xSCK1M^AiS#ln*n}pI73$ru^@C3Gx(Q z9rR%3_7LHPPU18Cw2!_4OVA5f6Z&3K3btwy6g6kt9>&B|L{tX+XR62XiT0>wz@?I} zSejs(9a_f@!Mm$d1=VTuj65fCD~y4fqKT#X=II60$}1t1K0u- z+#5*PpEJWc#6SZWEpL&(;9ax;Uc14M0@v5dj72I!nI`cVmt96&14w`Ai($T4@#-dV9l z!EE&5vAet6mTdrNPPg_DqjwmxyEjXp39(mv4v;?siLViMSFnHMV;*tyr?oVK{vM6X z8)GyywPUp^q!gN=an(c7MBTAS-ssnBz(eoL;vb?y(XcBF0JH8oUG8lW7ycmg;gdDW z96O-3BhOFGNda2?ndZt~(tE5+#YL^w(X-3+IlS)oRb&PF7U!a<@$&qMy4J8}pBvqP zZh*}e(MW7}^$w%S_`?(({io=|li9-?RV@UBD>BLZJBr$;>-OgGZLVePwPfx@s)+7k z^%14&K+FiK7ej<_OTrhvHdJFnp!Z^}ZIA#}R9>tX>;;jDEcpE;_*BcngIJhu4?whV z?MDd8qUODIsE01fN6zU|jbuPn+NHFoZ$#>J4?ue>Q=5C6J<_T}iMX-tSrGiM`#})r zk18s%du)F9Y#uNEZ;ODBIR6|Y1ipQ_C+5rxID$R_(ALC7Z$1L>G9s5UPn-(fP|qgV zCw-iAxC{9oECCo*!K;Wo%V_zd$&ijB0fMWl*csKnT%)#JdU;rKTEuUXflsPEKS_8r zh@Xd>-*`)VU@otTF0aerzQ6b&zrN9dv>TT!i@!D()9wC`uiy8A{Vj*TiXihZdRO3o zqze9jY4ek^zXaf`j+;S6lz|a=P6Z0h|Ll$f?*(M&v+62eA8`7!)CrlQJ+*SDyWavu zx$zD7(LYlIM>#&!Z7nBXS7cmnu1-?@hFn<`&oiH>2u=uQ84$#8ChMRn2a9Z1eSk0m~skhd_P#;edCRbgQz%~a}(?$=sVhu^fGV_*=wU0vhlFFyoE|IFW;IF z=fbV0`*-J5Q7=4`mPsncab3I)XO@T&!L{qRyi=0xW&z!wm?oX&i~7zpADTc2dCod4 zBk%Xq3E#2&O5n=TBy%xZKShKIrG{_)8ct1~H12tzgc@|M06w6%&-SNU~m%R_ml!9u$uG};6TN9v_X-Eat&Q4PQ5!`K zL1~EaM5u*VsdoM)Q2tSQmYQ<)0)P7n^tYda{}25%^t7;Nq!ZNq`}=>e(N*SkWC!@+ z!EQ17P!W(pL_XUBqPag7R*r~L{;nb^=w>W1g9A!x-u45z!_Mvng5AoGtYhxKFa6lL za&~5Zy??&~|JG_#-BS#v3W~_@oT_Vk+kGB^2J}*9I#B6=P|Z}RTNCx@Yjq16?D;;u zSjnsWC}4v7%@Nd4mhqYMhT2#T3KJB-)Z`Ms$A(2nBsl-f1&ar(Z2%&0c1bD#CD8np zGn!>x&u<1FsAI~oc%V^#g}-!ZuyaCme(revHj+5n@XaYW9^EQ|-fR{b_8xU-y|uAL z*qshW2RNXUCEcu#6Equ-IxbYcOm2Sa zei-gw4f;nxx^O@(f7BHTVRY^oz|D2)-S&CG9ryeCGR5P^jZJ(-4kj>m$lS9EAsoaBu|t=Hkp5q+ zol|foP>_Wu$;7s8+qP{^Y}>YzKelb#wr$&(cxP*0wss$PtM0uI_r0sTx=(+H(J!-4 z^5hmH1tSGh4MPoc1>=Tk%ZLJA;PVbz8#VL;<`R-eW-r0NDf^=bDcr^uf}}IH)|JXu z^V;56kzgL~LiDze782&YqS!Lv5)$Th`Z$j+-j+h#LoF|bdf26MS@nD6rbb{wedeW8 zL7Ed7By-FC^D9~%o<1LEo9V^3#+FwZ|F=~Q{++_{&zQBJ0$=O0gHHeqXi#haTebb` zXQ2OzikdjVx6XPD*>j8=O`Mcuj^$*vk38rz8@j}gzfmUW!pQU0h?amB1QwU?wCmL# zSh8HITrD!{0H;{0wRpAjrs}b3m1PvUwxgAr)%Jt+OJN=wiw%}SrwwR|zn-JSw9w>( zkLY|e>8jOHRjjI2h0e51tL~`Tjr)Y3SzAtSWltTqQ~NONz`*96CHt9kkmDX@CGRl0 z4k`xZE7c~wimz+R3-XhGqDkxJvda8P0NGFJ_>}Txda)4@HdpLkSuCV?$)OX@BIEdq zLnt!LAAPCORF3jP6thwXt+4SM%$c0y##0W)!FZ#zW09O{&MbL-W&PtrI(q%PzwIf< zERL1SrB85+UhLCxRZsJ_1*{EEeqaj>8bl2+YLv!ER7c}u{CM{f;gU`9lCAObqR&No zW2Pwl$jiAg@3~PIrbIKMJlM;}|GY;){Z1SL6z1%J&?D#*8bg8Jfj>@e5lp4@xt;P6+{!#pwG+#ZnO7VZ@n z8UD%zy<6yHGbz{4VO(M#ijOW#U!DZN3`y|sGlxw<#+u1+&Tj#DalT{N!uOf>!I=EB zg2-5-B_g7u57T7ywcv>80c}KK4&t$SMB?`vSZgViS7Q!W6D)cYFuqA)_kgJbGtM~m z2Vmc1Xm?ur19%Te^|GI%0Ijx2?EI3CHpvR8E~4pPB5JW+?R}Q0Ho2@K9W;1**mb}E zkulLQ&5+%RfBjPB`}Iry|1*I9D|Wj*A>CD%mtQ((cig6A9Rc=8bdqVP5(EPNl_DbP zkYIr_P-P?}Km~*WFfuMf=GmwDfgoUvmi_q?c@%1wDyJTnmv@>r%`IBhxII*FyUn-b zvcEQOZ(lz??~JdTU)KjWtn^NE%wGAM;QJ(+se=ts(d~o%iGAYzVs{b+{1r4}R7nl8 zN@Af3A)Sye?D#8lY zP!-DtIK=GcFcl?vmT(m*d0NEMt56!`rPb)~Y!a{Hz;db2W)K|8eVV{CX!f!GF~BpZ zbN}W=$o4({_|R6_wVO6&6Yo*_vEd<3kM(lB3hKx-6oC z$&S`a!amAQCO(gW6CEj7vdIce4g(Ro$R-R!{T5CoGHL84Gl>h5$4;l?`dso9nM`iB zuZ(y0Ijd7|(wA5ja+%tl`KCwVh^3T&Q`uy#HCv{LOq#7MQJhtck_XBfLPw4Vsnu20 zs>?9-mg^izAroCyjbxS47v|Pjyw5{7REG!2r_-HL*vsjwb9aYiWxl37lu?x`w6L(P zE;7lh%dAx(SX-7-mzU`6^zsp!ob8ikEH&DjT6#)0UYMvaFR)hB=&CEz*CZ)hD_gQM zzwnV*9T4}6j_f_8A1hK$+NWb!lc~WYX(Sw^0`XyErdf;Zulzg(P7QC0u(if^uNsu8 zS5@F@Z7_DeSomf%>YYuGEm#3q6;?<*d1vTwdOQve=kPw|3k!tMV@#Zqgx%3u*~<-% z7P5yt22_|jD+;Qbt$7XgYVSLF6{_}Z)_b%W>NP}K{E7Nsp8b)OZOyFBljHtgR4!CMBJCGu2@rZq>ipd$iB7=Nu&^eu&y#QNh_e-y<)@HQm1-<3EVy}0L1r-frj*Uk z#`2{r<(N9mH7z|Y9$iA#cdwHZj*%RgDRA?R8g zE{MAuBO9h(gdY;Lq?OlmS!j+T@F{}1+47{9rgl#1Dr)Ri$K{6H*|?=rZ33aCGOX^;S79!m3BDQk|w6zvDWZZg@1<-R`NF7&Id7c-=w9d*U2I~!E^S}1{Al@5M zrOE99$Ik$y3^cs1HkA}ocTy^4lk2`er{(^BCN|y6q}?T+uqzBewE*Oi@Q#I_VrL}2MvwJ=r-Or!46Eafrq!Tay#8rg=-|4i8JiS@^rbEH zK@%6*2K1CkSJ%&MiI<5`R@O(X5;nFubo=+<_ltHOqH_%_5q_qWRR;KS>zebDRI>he zdubo#=?f27CsBn25rx~Mq8f`lXvdXE5w@w8&d^h~CKk12nd)SPh1Xq=!`bWB-|=s{z?`-N*MFzQ;zFRbQ|r zR5kG~v=%LyW&_S1Q5qU_n&3=26oKC+REJ7wgxbYtN zrDH&*-bC;5>?m!EVlB(xJN~X-z@;Mbi{?e_8kMdTI{y|c;?K)GyQs8UNhoH6E-}OtSyRaR^0;U~XBx+@uU-7WrKY zy(Vk9hL<67(2+~4+t${5j6Qocx6m2_HdE>raB9HLvuOiik1HDU#+#B2(aa8&KM zOm*oP>T#~jzR7DjMkt)a$^1HD^zvkf2cC(IBs>KHhR>D2ymia1pwyhADpO}^eT{UT zq1f}J(qVJ+;v<!S=y_E49#5`$c2#_oR6skM3DcObH0J@e3Xc=+V0kUcPPmA4(yZ$7ye{a zmiyWN?qjJR$ZpjP3R$FK|+B$6}$v(B z8wzT3ercXwtByX;!p^-FroHl{wz7)X=(g?JR!L3Vn~Wk)hyok!!3{1K9^;nc$l{ht zBOTs;!JW-rt5Jo%&DgVC1;xWm67p9yqA1fs2YhoO_`S*|IqLn=ORSekpDcCjN9oTG ze=BQIaNMV~n{d?RxH)?<1)d2&4`o&#*|884mt%1nLBn88IP3|+PMBogMx26C$$>58 z=wHhRiE6cokLEQ`j*7M;x90`+MEd#FwUo@P6ru#J$SVH6vV=`A{}(zn=BULe&VB0JHB z+38QkS7*$t=2s6e%}!m~UzfW>Pmw!htwFLQBj%9tv@jcu zU{{rWxFx31Dx=8t;OnMU+@{{n_EX-rg!L)5&*;MIVD5VG&bl~*9}B}-rg_7KkkoX) z?g;UFE1r?)3kUB&^5me>WcXPs^x5(p_XL9}ys9#eu9kMyX0EmoDXUQps{El6;d@ z#FTYRwa6)J!da=>(kOV$aaxumM}4YO^pG{F+VhCKylJ8Alhvv6=M?A#UkM~jd`Un@ zG6$X{Oc!QI^@&^1(H5qLjBMNmv4$`u62Q32C)>~G!dTP127Tc?A$ihWwX%s?ek2ai zO(;2_ibB$fao)Kjns8t(=sIn03;4%j#|}xlv^3^g)@jyM;~+PrARYe70x)2(kNe7T z#!6*fHYp+_$=4n%{-#~bBC{N}3}zVA6y4U4o#mL}1lKMj7QByG0#v`ye(+gNuzAY# z+m@=k(5%d$ZWy{DFyC=|6-foem43=dp;{W0H0oZUdaffpn~4uxDnZ9w1?Y7PuWm)- zb$j(y!KlCZ`@sjIHw~i0+T1Rg-}E~zd+)P&6dR*HKj3}%zUXa@YBv1y1`=_FK|>J} z?nIQ*`h7d(&|yo%+JGF9~aoDrvv4j8k_$?M|}GCDxlC+E&F=%y$k7kFJjdiQ9kD4v&BLd{lb zyi$B8w$DaF2f7cs>C0x!cbw~d>iDz5YW)6cV$Y@IChRuGF13d%J&!qZU=1>E`34es zMepO#uUzj*Wbo)o(jxZHG}(>$-ymkNUcbVQ(>*-YM_@nB9qO!Wk7%GV-*uG`wIrVPJ_l>Z!@OJP#qkA6mAT7T(bOH4hI zpU7G~`%tU2_YAT9ctURGt%|+%xskF%lCepaR)Ig-LHs~Ph;m(}-eq`V_A1rRLH0_WexUUz*d1Cu!+n?R z4D&D7R?D2udD98tQ}$Stc`+^wGTqbR)xReV2KwTknv?0xG6{TUHQ+^)W00u{`*wV+ zEP~@t4v)ewfD?ywmIjDBh!|s1t%V3NnVF+IEr|485MvG5A*$fJJ)#iWJUeQ!6F5V;%_c@YM4fW!DXUDk$zd5A$El4aO1E#EIpbA;7soA?bFJcf6#slH}>&^wP2gr!n`_e~XV^G>Y79Yzj%eg}J(Syovv29!5(i60 z5fRr~k*%}O4++!eXtfeiyBSdg6}uhbsNw3kWJ5+I<%%8`Lwv~IH@0Am%vQuW#t9(K z8t2$Z50soyN#a^mxRDw4E=7sTW>R64Eq6K5FJ^AVp1kZ0JEkYQ_2kk{SJgq7t{-C6 z;uszvrp=;d08w{W84bDE#_+4d$`WDaNZ;ZQDW5=ka;BQwEFUtELk(qY$2wnfE-e3x zkim3^q`Vu91@p?2BvPOUeoQ}OvE6d-u_@v2GYst()Rx~ii0i>Fm18f%B+t>pET1-) zPA=ok@{`92_)GEc^>{-K`LGrK^m@(MYS)KK81M;{z1E^)`)WepES0oA)pG!xGR;Sz zp`0{xStg16#L{=VYYsUh!2twH5kay|VO+Hswl$;HXSlL1vtpyNnC)Yn*lZ0v+qXGa znT%NIy+K&tR5N)VF2<+y!S#$#6w$o47r$_2#7MWVYT)fi9s#3WpGU@$2skO6?MmA* z0KFSD95Sg~TPie0-O0Z1O?%_ixKxyy>=J5_Ppw_=#X4$6qC- zDz*29Q^O9?u^$fyzN@nhj?uB;TmIpN^7+^pCYRbjXd+M?XViAj0NI~-fS>#KUpyM7a9BB^L{12Np#6h z(Ua`slD*Web>?)%_Sf=w;2K2%+tj;K8^k!!z>{8ZKTK=@wlH&!#FW$)?M4*Xisy5% zMV#B)I~j!6{!AFUkxPMQ?Je<&RBh|TcF zme0`BtREs9lO&sD9QQP=fu}6;z3WEgXP|Mw;cLm6DG2^dI(B?K^GRt*tJkBzG9}=< zDbyb^WO2*?L>Zp9h8OV^%T>C6YDE`gZaf{m9~F2AORl+_M_B-*l2Qp52Z0Z85tsp`VMT*@RZDLr;2N z=IlvKJJ|^Ez)9P6`6y4q&r(0r(JSWajZJ$5Gg`=O znrp?7-WA+>gH_|kH>`eyoN?qEew#UM8+rp)=lHYld5XPt^oiTb^&_EW$8TzcuVHgG zU3K%?q%xQg@OP5PRL#it7*$& zswF%Di>f*_c#VtiwC0B`T`6!wdv*vmMH_zH5n$0!p+iX zfjfw|4ISrr4d9xUI%PU>6<470Yp6A%8$zHih1k5j3-L*3$zt)g_%n}ksPwtsQ^1LD zbdOq`7U=!HR$KjtY!`rbpOl=|pdl0~c-5G=yi}F_kcoYq8sv2svmB|n7Tc?pdow2Q zx)XJ8^p_-;J$FIVCRf1_LZ0Rxk&fmbnT`q)fsPIm2~Qm$I)0Hr?3YcyQ5nX{wB$xNXf&j&^==(#C64 zuDhLMOOvv)9Mj%yc&@vxSKS`nwmR~;;etN&IWkT5)Xo{~+e&WG7lR14tp~lqNZz{1 z`qgy;tOpqC_!Ku3Ptb64=HX_~S$m)6&g(??QHS zI$TdDck*=&%k0MV$japnC3$sr+K4}RIWlQDwDlVGOW3@T6fG&>L33u-d7bd6#*FN8 zi;`}T6o}0v{@qq@ofyx&A!j|kkC@xeYfh_q{W06*IA$Zv7coxNVu-9e9`&*oq^#AL zgpgdm@%rk>oVZ>`C5D;z(O3FGB>E~GdLs|O^7rON0C_TCDIc^@3Q9YK8Bz3vAUgw= zSqw=l4>PQx8vy17mVT1Rs)(wWiW|`4#ln8Z(5Z^+Gx4O6y`k7DA~y)j3H*3=zFH`D zSD5V^eCNo}!^B%Ees}jSINihMRmbF&H#vW+=+(;;yKr;~)+>u$iCQA* z)=0hpsI>EGPOp}h{oAm}E}&Me)~mpBiQy8aSFZMK@6f4LxW2lbt6c8xP~@%1TvG1P z?9S6(qV|mO6s}dayM(JNsV%(2EFR|qOqC!S6Yo;9nSIu z0fCuuC9AVe3feQuLh|p(oC{wZ(^Hem?X%J*-Fx;M%16gK;bkrLl^{3Gl4#uzRxk>D zi>VRT3!cm11`V&*XWJ$PpNh|i6zwgAQZM3@c6LL^*Au7MXFbMZ4pOSTz(ioqLe;UJ zs2PVy6^-J#?qlwt<3r$%Ngz4Dw*miH2Z&kZRg3|9a_wR#nkg0Hih`AXyyIY1uzCn) zk3y!1V#AD$+J^9AgOc~o3qcxOr)BktWVa`cyq-D(CXiU~_dU?j@uHXrd@Szl^F$;- z<`m}w$!UD6KTUbs33G(?Ak2MLjh)ICKC`C^PadgWM}T(xCYFjV0p39d!Dz9AFk24h zHQ3Rx5hy$KLY7ZcpRR6zb?BYqANk1-NLoAOhG)~KMfO60-9SZ8=#dL;Mmf7-5+Cf6 z3!AijyV3g&T=EOTXP%|G~oGTf$~)MGKmWB)i0RbrF8l2+=j6DX6aQ)INU-r@%i&NOCqMVOazvdHi>1$Ue?>F{<1E#a;}0{9|2vgh>}+ zjN1Hx9`A}-dAWU1GqtPor0X0xWB@B8FT&|JD(qV?Kyhz_VmrRm7q@j1{?ydhtD241 z+#3J$+FHD^k#J%R?D$wO&g~ol$wRIos_t6aYC1l5;&=$h4`60hHKN7Rl;whSY%uiX z(&KIZEV3;^3_!J6I7jM4CAK|xf13Xmdhx31HCpM(bJ|R(rXP9|*U|s2VEYHT*|Oor zEi6e%YeG}A&baLI^pkTzJ3-+&FIxU@>oA)1A9e|-_w7@xXciE)#R(qt);&)w| z)!qTAFDsVwSNl+3{OWg*&>VP&>Td}4i(SLaZ;Z`n@~Ic!+4x7woMpd0Xzy>V)84|~ zp^x|3zZ!lfq`OjPOlddwV$`DnW9n~gy)%Y0KFQPVr3>lgb(0Lk%z06a+cVJmuoYLz z<#v3MCwI3Vc3_3>%Fkpc3LrBNR71%cx2oZ?pMDY{6!>NyE{mi%$YIUheYsYZO;0=) zJcvrdRMvX@+uv78mes-A8=v$uKY5BE%gp46 zUqI}O+vG^akw!=p_FT>3*f&n&47%4uQv@Fa`a-T><)h|Md5|HSmg(DyWo!2GLlYM+8Jh+!RO#K9CImOZ45L0HiwQo$_L zs2VeXS(b5zxzN5HQx+662zwf_Z4xH}x8(P0X5oE2Cs zk05@}eti@^C6MZaW9HlsmV9?hiP8haN0hiUbhI+-h(Lyz0CAN$26`vn;mcv3GlgMp z8cY_jb##b6?E-g`5S8xq5Iu;JZ&WGCGwP&=IlD<-hch)wVKvG@Ej}9u5Sz9oSxFVU z0Fh_1U2ah1iDa%RS(AAV75xtHn+8;;WWP0JKaC-LTiA%dnh~PN+W!pX z)GX$SDiq2#rV((Vl&_hn(jdm%m^Y7wi`*lh*ezC5PMGevf&eDjjWd%Ds zG3hu#IZh+}6A5D&rxf(5Eaol|*rpt6Gy*ru(xPQ5D_Y16IyNFbm*CNsV3ua0W!bIl zDK(<0XFj*BTle{#h_4yV^yxW~y`(qZ2XlhUXU4d%G#!{Y;q9=TYNM`+y0+?9aBY>O zu`5s6ZK61_p&m+qjOa67ED?M_N|FLD`(?Zr&t9o1>?P$j(bkW&kV;w;d%L?Wk!eI# zJ^QJGx(IwmCed_KenU2o4G*%ZzRWXUH=H--=A7$g-hiE*yOsf8eu*hG^EF9fj8?1p z41kx(8$86=VZNf%r|BYGr`zi;N9-nA{%yU=+eMfTkzhq99MqAS`Ll2>o^&PrXK!M3 ze#h$Zeh2eG+B^Y=sMq;=;2~(oIb)J?k-Fm=>)F-iDDz-QZ%UtpOnBR+&X?&MwAz3_HO7!9@+L@;cm`%`_?`JhpTK+{&U|+rck7Kb0&= z%@|f+g@+f-@SMO-TSqG-2@Z22W`wz280=pnWVSg+Sg>`@$*hOWUr||(rDA_Jm9de% zwpX4`&x{wIj5>RJ$kr3sWCwci!5ft^oLXaKUv{HjfT%>?9po*(Hj6=IA5_svPNOhC zkQKtJAaw4Tx%HKh{d$0o_OPDtlKic&t2?hMcs#@{tB-pJs@mOQlQ%#Ndzz8U+kRG+wv8n8!z$0?AYl<~T)=jF4 zr^mfHcV@VtyA6u1+c4FI#f{!DTvX=5Xdd^a5&|!*NuYlj?k}6nVZJPurl# zeUMIS+?}*R1utBwL|o}#D#NraD*nbwu8gFeUaicrOmYc{#j=t0fSDv@bRYJ7Vp%FY z{qKOe|CCXRPK~$K;r;r>!1n8x-2YYN^S?-Q)t>+9_}c#JG~;15O#%aHH(-nek%vS^ z2>BZfCMvN`N+SMulIR!-=9oZQ1OW1P6+~LaFshDblE1XAqIUCd`*ylky6SG%dCThV z7MItSR;|kCmX?g$pDYgmOw?}eSI@V8&STcI&&w(2Z6khYowzs zIb+%tilFVkX_|5p=demC$0{XNmLXOy&$g)YFbo)TyH}2I)@=!+AqzfVlptvk6SLB+k1~yYB((de5ZE#d+I;~QShHMx+9tGzJEW0I^fLF55_?Wlv^bq%D7|T2 z)~OnU#yLu*&H)l*3VvgT_zH(82r|0i+*n=&J3BLklN+tkC5Dv&f&hO`qTAN)#+e)H(<@RuamjhX(UwG?KS*Zus-4&}^Vc2NXXA6ttAZdGKP% zDzt?31*Xfhq1oz+co8GXQbM%22cSme14CDqXSI}iOBy;_EcdbYo}Ju<^bNu+^peM}bhYt2n zq|{)3Ll`E4sMg2CBv5GKJvLNvA(c-yyobqYomt;%ETUY74Z10`^guIig_G zX-z#zuq3BYSi0__SD0)u@$^uwLYqQWf|fI4V`BE*eah-liPM+sOB5~}6nF-FtmY(| zLnTn>|(fK(n!hu?M1rY_8vVaOmnr(CTrlNwZeB@p_v0T38~% zT9Ti-J5m&!teMf6NKFU`@LE2{^(6}_br|8i7KyK&i0@saJShx~%yo;(tMJq3;_C8Y zM3DBp!&`>FL65)2ihPZk%;Ci|t5xMvT&&Wrajo~pTS`_i8uy|_J|a|OuBFqMXeqP{ zNVk@NT?x_UnW&y?A4v*T{Z`l4_~^6BjBB>AbhX-tJ>^t?u7F>{3}|Ci^_dZKV#XH# zfq%kT3+<1AziKUkoQII~;Ky5hlvU$-e$dIP3BQQ85vQmkw~M8WQ7CuhDUc-5Cwe zv*IkJbH4Qavk|YiSRs?p~%7+b(a}hZmHo~>$yD`sh4$f^)jCf|Z z@R$l?VGk`RT`-}RnHc(o(jPz5hqpG5w`LL_E`^x`ixiL?rN#dDebH2Pcx; zwEsKNp*a_-Hm5eCxQfF=`nViKwbZVH$EPe(6iKw^u)JX&u9E3!tI#Rkr8#g*W< z8c_^uYpL}#rVi+cet9x(!paH52V~g1P+Xhh){s8?Z?+nJPeIKH@he1ja@jTnG^U!o zGJ*)tQPe4#Jq7JV=RYvx4y1S&CBk@~(Ri;Ybcg6EZR{U)#lgot}gm?=HmYQ#Kel-OTv(9%H%=Xn4f`quXBD2 z()!(uOV&1)f}RjY52*@R*ZU^?#kn43K?u=kU($^{)bF0~KEns?$^AB;W7>Zc*c+q6 zNIU|{QG*ZfHMR(CU+3c1^VlAr?%;y`*+gpXoq!so1g)z{LF3wjo}Va#W-+?N=so@c ziVf($hK2o#>3N>qJST;Fi|Kiv*n-?Jx&(V46u9|+dOhj~^bGW~*TiojbR%bd4__AvrT(Vgw$Ype3OIiKdBaGL@78zqzdlu0~X~#)XA65bgo2q z&K)m?9kAuZD7mO{VJ$Mh{acWyL{8S0ixzrx;!xM5|tIi2G4?1(mCG?-u);6H0Z;qP!tPr z*P!o0pQ{ctGA?E7fY)$!#C)FXy>G_Ah*F(veFKhi4d;6ace$eFNU6<71{swE!y|A0 z^woJfm7SPlQ^LMAS++X<#FW`1l*ov47;#InWP~;}{-O zv{BN&-<|_j1J9yYRwy5smkP93en2bsm#;<&F)Tf zlFB>yrXrQpclJyo#ETO2ri#I5+;h64%=ZR8kqf>rh711)zCHOs>}#go`YCXJ`Ijuf zvjzd~6p+Eb%gE5E+|it0I7YhqraKxMZ z2Sidfk&+*zb$z(zX+BR5)uVPr|5m5eJu}v&HRfE{jvL3T8=(wr13^mra(q17>MOv0h7IP z))zol<|WGmbKS|?N7Ju0XJoAw?%HrlZ1{V-(lb*9cnv0KrCCFA``Pvo)HXX#xAl0e zdh~q~nojh|zg6gynJAd$lBY`NF3jc*eu$VqL4mGo!;$=gL_f0wDgK}<;8zRfW1#J6 zterdV7gUO1=~DAJ1IFeO)6I&xL@-`qBF{kty0D^OKb0zuPx6|h(4Lo*TnZR#5od1j*McA4%ANs!z zY$w>Rh0jZZjBn=?d=7Sc!th?a$n`aI+|<}(#$M@eOZL|s<=A0|Q@B#vw>v)xs-TdZ z%pFp!91K5-^fGYvR1jGZEMP=TtI`K--+)*6<&;xF=sD$1Ult^2Y6WIpqf5?pn9rgo z_w<6j0J293+DD5BjDa$YiJt}jViAl@0$H-l1>qMWjLT6>9WpZc*M?NrNT>|u7S3^L zqOVa>o-$L#{CR%-zJj^|)l{ z8onsMs9g&Ri#_y|GB8%4C*?Fbg3#fhtXOE0L|}^}peePNl=C&j0K>!1IU17ak<#YP z8r7JuB;#DPqmn(~T0?fAi(Qr-#gpk;!$AETz{4_Af|EfrjXG1!=&nHpL*26ruX*6d z4aZRkoT9|VQDhS+1{3I37FBEULi10|#@qPt;g7COIt)n-?CR*e@*$#eb8oMSg=ZMk zQb=HXSA@3({d)JxIG(y?qGAS@6yfGeGj(ogwi0BP?~gJv4{Xa1x^RA`1h ztLqjUEwfjNGdw@}J?xy!s$dVF;WEW<<}Fy?a)ln7c{)K!aA++7A=G<#-2cu#o^BF( z4e*<~a>APE@qrdphGeXQmUV5sFHDkF%dajs9OYHq)*Crv7I^4m>+Bg)M?)3NUszLC z_-Qqx&7H-mvfzcj8yo#s*Sb#htD8a`hhOu1a$MNz$A%8!QlP;!H=v!b7Hl8{ zCbBFL*mJu&(?}m5G}DPZ5ygMzF43fs=Nmk@K=jB5)^h|suXyNUi_+>IVdS1C1C0Mz zaW1cq1Nyv?)_uvYmPWnFj~Po>OKp7}5@1I%GZ! z9^%+_0W#w3RD_G`$0#M0Et4TqXWMk(d$Zk~g5s%#v(8(?qJ_fCU>HwNK1G3WI3XZY z1@|RJiSu<8L*`}6nZ9Ad^K2Lz-Iiio*ZPWV$2ZqpC1QjBhS5`(PxP!QUP$t zVIKU3MUNZ6$1D7G#}o}ZtgJ$r6H3n`+bA54ZN@f-T&DA1JbVqz}9 zuedDdfFTabUCYrL(w0DyCNeK+Xk$NNclq)L{KZP&c1w+_YJF1y?ni7EPk{HY?!SFN z`xvPiq1`9#CDWq%)&R(uZV(yED_s?9DWhBM=L@r^fEV8pzNO>lqg6dgCsl5SAZh=$ zoJLm{#EA>hUyWA3PE;`bov5v;%vVkKp9^}#D$>HYE&QiEbS)qUX-;M zts&9l<-yrxWotrP(KFz{o2sXi%tFcI2GL5-Eg3GFV|?>wy@8Y;1((gSWr*~{go5s7 z2)8;=q9IG1)5Oa4wH_eU)v?%oZW;}UU`=|lyZ>a)rw9< za_G>X>-$qUt}s)J0Q&Q&IfRUMPe0Y)O^@0$#}q|n1IjyT*%P-i+EqCF-XsuXdX+c0?cM^VjHp>=8>E*wVOxkYjj=68w3OaTkir36>N>)4_c{ z;1j`YjacbvFAB{-34gyO@oN?*a^m0Beh&)XzbsEFLo|`Og(+EjGQtq zl3O&&bcW%Wg3+)KI^(aDb(Y?$^KrZW#evC!`TNV2OfVhlj0 zkd-USZ^&{yBAG}9SVU(D4LedLk2{s)v{wkp6>>UqsZL_5kee-tK6r0gnkg1m71U+P zav$k*fO*-*Ke|MBgH)*(Vtimr-NIxDhG^NGE9?$))wJg~6?4@T3ns8?1>kL6Xg2}B z+4>y{_&61+1j;8+1Ay91S5K9`&RL9$Jtu)mHs0X@TT#_#sF>`Sp9kY z3o7XolNgix`j7rJ#L(P~Kp!^_P+lt9;4J-8GqshC;=Q7l5{QDj0g4k(Gf-?r9mtA0 zN2F%@jGgI%v}geKeKSoM^j2gv?OcDh3}q+Xf$tts{Z;L8-t&*;>w{JRW0D zL^0XgdDvIj_h|i^^KJ3-lG!O6h<8s4KN-y%;YWq?REcS2h+zCPaz;q6taUiZFSLYD>Z0QCTm3p>4_<* ze=CRYyzv9aQptk>-Eh|AMJ+jvuP{G<<;msk{be!!URQHqipeQKjZf^7(^$0!{ocv5 z=iSxu{m7tf!HPv5>fIY`YeqeX2VHf=omm=wDO0cZ)fQ`bGA~%Ch~#SgnX|+3V`@uM zIw8>>1lWWxtlvs*Zul&%r}&2-Ydl23>4Wr){R;%?$uC>XQIoh`i`aKNMC@};qGmKz=@)zZ{XDC9#rq;qmywKYdwx62z3Ox0^BSfQk_zYH0ILGZA{6wvtkK zMIoiCc;AuHa6TklRN6eNs!&N&9&oIbL6$mCQHK#qr=S4Jo4<2wax2pNWMwHKKI2e7B`N@OSXAxiYC@=S)61FaBh##OU*o& zU6;fkqkRHzPv%QipW8ihy#R2FbZk+Ej#DSFbq<-o$tu#+q7^%$FPy*@2<=eJq_RhF zI<}T2dkrCZFfW`|8^&~joIB;N(ZGk}KFAf#b`H^bC~T2*4p%?Kb5OuX4L;a9)OM+R ztNUv65XFVxPJ$21ACuinzs0+2^U-{h^pf|)ix=zSrJg?oPbI{S>%6t`Nb?a&A1OOV zdTY%9X2*sfz#oX-gx4wlB;h`gwkv)r1=sn2hsRSieO~0Q{5+k4r79 zK4oO%{nP+Qr3f8j{U|lrH5=OQt4^q=T#yx75`cT)J6t z5B{~@9tUL5lj2(4fOr2lhjTlDxlx*Ky5OF}lZDCxBzK(EpH_>8cnWyOV^TH21nNI6 za`%<}~3vjd>k5Ld6n`(P&_sD5SieZmHlc9+r)WHj&WM6eoY zSMR3-Al4XFAEXIzP%>+OABjLT*l4~e8GmcQU3~@L8E)S#6@>7oY2Q-T4r1&|#o5E@ zEd6Ppx+e!gT%}(wVN^_IfR-&3@dNBltmiYQD4Wr5VI{O&afPpe+J-?84daMx>5Tjb zW$zfAN!Yb(CllNDB$?Q@ZQHi(iEZ1wW81cE+s2-!-u=~nzMpSZS9kyK>#APe=UT^M zwzut1xWA3>?7|@j^;=e(@1M}6Lo&L{YtzZ9{_z6woKR)(5AM5*b{KpOqpceE@Cy@ zJ8jj(Yh4!NYAMxNh`(MzGbbP*X%662AQx*Y(IGn{ciPptcdL!n)9i}(mb2o{`i!a< zOr?IMVZ)A@8y6XyBV`ehT>5jzsWP~u9%mDk*GKou`aN@Ei+QsVO&}9az*brd@O^mS z4UO%MT{FM(w*RjxH6ZOs9(65=*M5aprP-Flw~ffXoJp#Dgc&i!r#>r|dYwA71h@L- zZcN9bZ#b@tJuE~79$nU%;W-*m;!!KAgOE$c5`#<0FUykCSrH^!rpPIltN`Szl0Sa- ziv_AmrsSx1rK}uP>11BEai#3c8RGMCTpOm)=mVaf&l)4+l}aA$ygmaW%N-jv%K6%T%=J0CbomxnBxvld>0iHksfUsqZ%XZH3>-{aF>HbPWTxI+O2rjP;4y zsMy#spC}CvGw6F*);AUw7Pe=3F>@1U{DUB;6ivQF1^iu2&T(b&><}Y#`B9?)py0ntiqHPtit~E|=YnO6t_ooi z2mHuwZ)IX;CMt(=Pzm!TXY#Gqzd|Ayp97K@+fEu0U!IIOh*r%j&-#1a@W13fS5MIaW08O1?Bfzk?wF4PgB*a`!5EF0bR<_D>h1x>InmNV^WGF77(# zY!}-C%4`eASL`?|Yv(wMwz|O*KENbn_o4Mo+E; zN8>5d8=2x^zA?s=dmnMGN-pN3%th9FIze+`E9-%HZ%uVv^a%s-+#dK92A^-tjv$>L z0Be>j?pW7wfiGzE$5PHoBA9PT(l4@ z@6@TZwcO_oM>*a^keE`P+^qB}^72@r(9e&Wx+7|Y&LR#-2}M)iV-1Yj9nNAJv1i-7 zDs{_6qYF<3HKBPIEJ~5)2R!{y%X& z+y6Qn7g7}ZAJ9eevX^$u3&F_U#kr50TL~|PB9a2?Z}db*bLhQ4=;6+4Es|o{xCuh$ znGbJCN|{VD;<6mJ)4wwf299e@jHZX1MSEt*0BbjQA15y}7alrlFHc{-*B9Lcu^kO| z@VKg|#o6b!)!3CXlPb~ci%|!Z7T{A1CtdUtPck7Y{u?c|OU7ILUno#e=4mT-7}#KN z^dXsN13u=S#}Yd3Q=N`rIejOO?lX*h;8)}K-J+>&7n5@mZl{Rv>)LW6HTQ|7vrcmW z(Np|;PZ-g4G+VLPqu*jdv|66HMEMPj4C{R-%n3CfvZBu2OQM7D4b6S-C$>*!ggA?J<~T{tsJQ#r9TX?`z&m?6JwVG^5(=#*{K^k2ij}SlHXWhito*ugt1>wpF zC&>)qM^V-=3l6UL5@Vtx*+vjebEMLriXM_bPT1i@Zx3kd4MV`AtDd?}eFHVyvA4ly z8dZ1b2Yy`e$;&%b^2MN{f*t4^@9B{{WG~@%TvO|Wr3dHere&Ts;4XAlbsQ9msnXRM zPK2GPnQOupbYVMpGWdF`s!J@9;{mBaSZ@!IC@?osLaanniO4plN}G~AWG_#@mM zd-QOzYrGqi#GG({VqtvEG!3*>PTNS?W9RMwvvCr5hFK+Fgb;1tFB6j_cfkuC zZeA!M7ILj2p-88C8qKF`FvamU*s~9VWAOOP8lgq(qAa%{rJXE5@%-gJF=$QTK@p0L zz8?r}+wvXk^+yVv-CT2n%h_2t?1vFWut&B$GX?jAtC2kxM< zrEl}L1)fahxeVsam-{z&+;A`&2AiJVu=EEtLTYze99Y(^XK0Y=Bxj+YHZ-0& zF|{{XffP0#Bzae7w0b9}41GubL&YMB08V2(m>)a`5A>RNOyeC0Pniu7`YiJ;Sk||` zo?csZb5LydB45x_D+wEe#^oCxb7E~rgS{#^u`QgKo`QpdXplMHLw&GM8&x-vlY0t+ z!nOK)4tpq?i>PH+gzJK%e-jW6hLIcYxRDQC{tr3RPY&I+0J624SSbi7u zCC{Oqap(X_%3Q0C zL9!9E*Gg#3MpzXz8GcFFo<`f9S7V`{$s%$g&8ewHHd4)8%nG^4)Q617jHuREXBCSb zHd2~psoaX#7$$d-QWDZ)lG4a>i;zb@c*Xhou7W>JQ|T5XHtNA~?Sej(9Te9c@G} z8Xi+B+AIyq*Ttn(n50xHGs+}8em($|5lz%5$z^gePxB(ttiopGw4YuklRd_wl0q7) zF~$hX$_mDMA}Ta*lWKc%(JT+Em1X#(5p&b$shSQK@^z-5|KJZnM>)2v(B=cW zaX+T7{xr3$RCaAu9%o}tT>bbs^>eY|tZZACuCHuf&UoRd$lbj1mB{U#DOIY~`h8UN zsO=WMf69BPGzna3Vto!CjDsnM5W z70DcNO3DZYZl{OCy6BIRsDxQa2&bJ4l6EmDF)o2=SWe(r38HQ-F&<+frmE&x+S8QR zsV3EM0*r=eg@$RRTDL7L$65)wYXA1Crdc{!E(F)+a@<{460-GiJY*##s|Mk4!cioy zCT2P2jE7lC&#=c)P_i|0JZhI`vPH3+wvn{eR&zXIEkxfuUQDu%{d&h5wU3ll;gF)c{p{I@wCvm>^2v^v~C{`*vR3v;gzAh@Ob842xYh7jiqjc zx7+WK@!6W)pS&xo*D_Zssgz;)wgS z3ZPD2iTJd2l@qieJe`0i#%!d5+kedQ+xkK8otq=N0l^)^7a_C}p^oDT3$+GXkiQ5) zAB4=)Un4@Fz!&dr(qs4Gi6U*v~P0Hk<+WszfOf-jOOP_D0NSc-@hP}odKP*u|XUiUT zWHQHPOB{A;F#qL7ZQ?XCC;SgNw74F!UXpuoXDVi?05M0hI zG+NAUfc=kwTpAmU^%x!}#uOZDo^s1Dh0dGL(J!4rHCf=%Z=FFmnGe>ltw}yvDAMn( zNll$c+ApX{NnK#lZ>UL2osZV9s7XOx=xx9OKvtc#G#~{a-CF=^BbK2m%lXxXa-prx zm<;d$7|`Z{w-h$0yoECTp6k@sc{Kf^>y*|7HvOjSwAT5822?(@)`fWeu9V2o7Nxfw zSIDljw)tTZ!P$*st0JWRw(C@=3%mvhR~V9~{v;Wt8$@1AkOOS;$lIHoRqi) zM*Rkyw7B_nL4}XS_EEBsBWFdoVA;ssMGO5aWQ;kO*hxw_!O@v1e_!LAsD~XKZ^|U8p$=RC{1ww4b7WkaTBqduS@q zJqvpM1dp1piQACL%A}trm6ZEdS}JHes}-V#$pGjrTM^z4V*g*)>52xn#{aiaU-9UaUBU;yefpq@Au{1Jw(XQ*W*0vf z#b!R+Pb!y{#2X1G#)VfzE%rcc5oiFXOiofPm@QKX1fLRlP@$Ykynd+ax+(o=``O}~ z{_yGA?pj&5dgZzBv0a!yA_|JhR~e8eW41yxG}onTEW^;$EZb$2jly3~{wgzp z>Fku<$hlfYsXQhC>;N2%=SoAqEdMO3s^Vz^hOtlUpNT1D%gs^GgWsbCx8x1;7k+jc zgQeXl@H7}a)h*WIkW`WngdpJM@!->fm)q%fM84~=eCPddB+KX8J80pX$Kb%z4b1}16ffyzfl)Hp`~_+DdpgdnuQ_R< zo@n3Noy!BhAJ>DH+Q%3FQ`3WYA8`L`mD_{J+P{Cui&;0?Del8j6wCR0udyc$ zf;-Yn^EWgzP1{}8L_OjnS?@$>qW+dJQb%G#P4u0h4T*vG}sVr-;Z1a ziyXhPk}y4_i6gtP*wGyWi;J)LeN+P_21h^BQWTimrg=r0Ko0NpsPeMDv>vw6c8g{} zkeBXqARqa~fU}yFe;J$wtPUEq(Rszp@aj_U`f=F0!SHUE8msIQ#PI2t;_rn=twe7> zEu~k_vB&H`nGSUm#}r-qH1pgVQtI!XRD;>ZR)cP&Lh2^N&40frT0$x-)>y-?NCVY{ z%r=Ud{cUm`frhDhrLO&7Yd4X6n>L{oOom-U^vK=Dh9jDXgcuTSY}CStTf>Xk~;>vcae+%}rZ3Q8w(RGnViPj^%;??JHsUchfjL{hpSelWBu z+%0dKtGzIh;T-QBzV#qU>~WHIRD9=ES;{}7T z#AQ5bM{gTOjecDaU1cmuZfVz79eY!xitRqYc{Y?s{W5jvt=$*Ww^%zNG>S&VTZ1?1 zHNbdM?@wxRE@YgH( zLNt)$r^0x;C25AZd&VN2_~`>QD=p?akHqyw+`ghU{B=w;=fjP42pjALy_r?#?l~NP(}4)o+}8`sSMS zxCDh<$@dlwvO1)kihj4Z>Yr}+Gy=qh?zcMgFEadgl0@Ic&tMga?+mdHhVuo<54=0| zH?g{0R-zKtV!aoK&_+WIycSS|blL#{gtMHVEoK@;hd%v6LTLABOL z#Xp}qPN24SJ-BX`{n*dsozUBT#W;n2Z0a9O-V(BDlb%i0^d%i3tX-N#8B zd&%~?Y1`rW$d>W_ep$u?N^FfAcFj5+VeOoupSlGekO)af6-_t8l7w}FEyX;>;+5V5 zdawwo4|=`FiJ7L)lF85L=LiTo(1C5@zZ^FSa4zGke8b@Ry`7GB3e!}1HHrY*Y#p?8 zTETC*rqzL6&Uun7G3>G~OF~$4OR1|?g>`e9CsS@SQfW?CMD6t@*<4`Q zg*+86z6$~j%(9MdAD=mmg+vsT6)@1Z)WdHp7RD%ie>j=;bt_St3^7!iX61pOtdOQt zI*8^Rx7M?{A3Ep53{3@ec!R!vNLTgMa2@n|SdI|2x{ZD-%qIHb+E4?!n=7N$*cF=2 z01)*1ENy-Euq}!#jIwTJI`h*_i#ZkDhF19=(Hm?y<{1#~uX<>MzuR9|j|bSoAyawe z1HPEk&+IEkjKlOEM($N3UY?yTZrwE_#>obb6ZYGu{#T6J^cR>u2nM*nLV=M2nYq}Y z`S?*oKy61l!qW3D@MdRqj&S(>Yr5(iwuZhtv3T}o(ej+28Y1n;Wwoq`@ zMG5DIdPUc%l2}JANOCC-Lqaui;r#48c?8*|W`4aPI(T4!+~bQL#$qPF#HaS?EAsX> zexjKj*}bZN$H*NK*dOLX9_qacen;0F5_{7S6pC{aU&u)^xi7prfY|MkzXAPo)GdGU z2Y$v4uJy}U17d!HzVEo&?8+}TuO7*kXq#jFTGm$R_ZL@CNDh@?$Ng%Rc$r*=m(f@+ zj2$KyC1wwIiZupLA955pVkq{Rvu%WezwI0Td(7}ZGJs`f5dA)EARv7jARwOq{qD84 zGqO^$b9DZn@3bZlFZbl3rWZ}7n{Lyc`b0M4lLAKtpWL|%ik($9yB%K)93<$!PaRZ%^;!OLF%5CH!nS#(`f=Ud6uoLuFBUt;vTdbcDhj9 zd4FEJN9bk}(^;&Rt2CGzmhDWtKH3Un`6PrBTW94KPT>f$1$yH5Whk~2_IrxmwIX&b z4Gr_R@8%>u)yiIq-1Q<5ie6`9_uUjfb%l8o_7N1lsXO^3@AwoyB_iaCUKd4B)ZaT$f8zFY6}@SPkSJmz77-8A`5C10i)IaZEI6Tt zW;2C^`Wu+%W)++l3FeH!eo83lzlCHDs@V?>QbV_-<6%-rFjfGXifm5Lohnk6sVn*r zmg#>RxVSt$akxBFS({&)_#?mlDO|TF-yY1uckcoT`6)1&6{BAgrmve$TwNRK--5Ds znyUe+6t(Suj#4*MJG+T?T4oOp5(cG*b(O0tX-g5C>aFz*VkLRo8Y}Ay_4&1}j*5<& z!a{(NOg-1qJe-o#=kauPw7Np|)?)J?rXI}zjjE-tXqnm8?iz-r=wv7_R;9DMNKOCe zigu1jtCY!jlehFunyIU39v*px4*O?h>OJ>#!P{wohBDj89>Woh6m3q+d1rdVMM9*= zKIosBgp77Drqsy+*U20`CMSmw*W9(`xn-}E&@OpDTO&JSx(j*jpap#Hjfp@_!@_6eN9Vcjhlp>o76$O z1LHu{ofN~$#+hQ- zSaxY@F;44_Kx?A1w2B7b>ZqP@pQjYM9kTCvmPG}~UukYRg_A!i9}cqFWEhW+oo+Q! zFu6a4M5V2SVR2X;3|C8}LnnA148t24;83c82_wox>74vYFRHA8AUdkHAFjxuWiU*{ ztdj_FadAyII3R@-T0_$zj7A#uYuX-S368a9V75EvExTT*tK|G5jrgOf zWJUQZTgrGtbEC)*w8~CK%1(y0fO68fz5uO(QL76*A~Tag&xuL(m@$;9juWQDjh#j` zjA6Hbqpr4r4dviEMg#DtS4SqDlk;bP7%qCrr_1JQsbSqSwJ{7M1eQIDz0gFjdtmhW zm))zP`WCAMG%lPSP@MpMeM4cJ2?OHf<)3LGKp@>KDQ8L}YY8VEu-f3@Mm;Qyc(Z&A z)X70&jL4M_PvYQ(sJ?|NdltwBHCd9#KJ~y6J2DJp#1Hu$J`4o6$fwc2eSA>2LH)xH z*>kC}4D-!*mD*Zg^{b?4@J?x;dYd{SQcN1%FVTOEkZUav!@p-ob-0xh`3 z!BG$6S;^jt=bEnS7yFHcrRMwwdHZJGI&1jEV`DSm8chsc4Hnl6pq{=l$mAU!#^pI< zZOi5lheI`J`I9i+eSMtrunzi1h@&?$@&?Qt?2D71#aY*XI@K@+wMlU@*${sUVfL52 zyAugWqkM!0Gci9?ahl8tcv-e4$YT|%mB=(5p4%M!*(!FP?m5gX+gSyWj?@a6Ii3sX zspPw-KkIx65KRh)Z7G*MDLw&IZPddr+_>N5B4Go-G4{Uxh2*E6bB)5oezEhwo_}*- zXZ^ya2OfP&%70>8_?P3Jhhtcl#!4c!GQ4=SdmC>jp2%O_8514=cjv}lFGs)%{ixf zC$6L$QGL*^8bljsL_e~O-jm%!^UXL|aKT)ZKPMMYxSnuJt6k39WZ_zvo_>|W^$6(* zMv6{40e@p;ek0$3D6K@F_8?vrkBp|y)+1f{33T`he=s+u#+u9ZcLv?6gUN!FZS7Jl zK2RbcsvTb-z`wmDjw5qQsVBcl3%1q=Z6GfD-YbiC_1~(f@(7kaJg0|aE2!=lOFL6( zEXoPAV`uupWs9#UfPH!+Z~23~va&v~TF+iB8p98z2~H(3-aL9N3RWID$XJyvF}xDE zTTF0ucQHB&YFzk2E1!R%Rs|8|GgcD)ERF)HtC++pvda|0A(eXv32K!isv!OZ2r#IC z>f3$yQ#R!ma2l+suGvP&Gy+~(p_SKWF=P^JcJ?1xlBA0mln=XOVxQ$gkIhW%d0p)ax@gGd7&8 zY)d2OD)TOkfr+ZPe%Bse4$$Qbh|-QwLN}tSeie4FiMfD}y;qkU#)UlM1f9difh9|46YZ3eBdJxFI z<=8J5?7PjJsJP=r)6pzJx6DKT4z)GW&H!B68dOQuGc<_o2Hw3-H?(ZEI!4#cw2mlV z2zB(ea+LdRIwo#PGAK9jf73qjaSy#KOU#;|CpUuQ3z!d_a@pw1P~`BtF~|gl>>2))p@G zK+PT>a%N4Hrx_t1GiikN!MKxH94;(R9FZr8EynS{-HLgq2jehPp?=LDtv1dHB{g z_Fxg{0GUtAkk~=apURndkm2&DXE2@HREw(&(m}`9|I&BJe$N+%?Ed2*It`q-M9JSw zp25#02&pdXKL^95>TnpQ&h;gKRJDCnZ}1JKLS)M0QF01gTq(1R>e}{ZqpiZwNm{w= zc-T?Nc;OUyX7GCm3Xr=hyQP|drXV-$qGGX$gmQbM_h55~FkUXqPendru31UhB~*INY24D+I;EoI${~ z3{zIb3#b&#Pr@~ka8X$tX%T~`f0rtdcjzXS+#9Wrh?m6rx~$^ufKQ^-kW66!KX;2N z*ybs0iW{|t?`IV-wFaBsSyt@PYW82;paH*(DW$O9g}l_a|-s2{*`4{r1q+JCexk1eS9-N(izNqq;=-h9gVg# zO}jnryB!kxob7&fy^Fj(cI3^b_CQGXik~z5;z+YIGU1L;v-jaa%-5^-&~rESNm%p} z@PJ5gDE2DWnX9)C@(Imny7|p!|JVeXi*u?4lw9e!IM76>N?niW*H zF7t>tDpEWAz)0*4*MInD6ipF~&zyfbcxk46Z z9@`#B?CdGQK2k8}jfC0<(a-%CGiUS)!Rtujz=CP!uk?TzfqU1rbNznR(IcU2d)^14 zA7>c58HR;{b?pHVP~6(Bf8d7;ISo^X$qfCD(!+(>WcMLvV^6-?A`D6Co-19f)OpFF z?C+QQ!V$BPKiqM*yI4uL&<0+Ky&xOeNIxovS@$8rr-ab}3}I|Go&u(KD17678yU63B4BL1$Ry%^&AUxb4yo~t3smA49ICx}D7odhvAVD;-z3>BN&JoMTgYWX zNU-Z`lH9AIN8PGzt8Em_FFj5qWvHI3mLg(9FM?udq>wM(jZiX}+5^MAiJ*gQ{4g_5 zbcrei_^)30jJy_XY~;Ri%2T#H<#Heh-nxnB8~k-F7@S=xP#~CqY}9c~&w4!ZLo6lT z2AyhE55(k~5^kyx-q&$@%yLH}YsbQVR;X12+rY z-~K6uw!1qAZ4XFKw*;q--)YtReDhDcTZ6f?fKQ66{h8atH>N8wpSaLdtk#>zh%>m^ z9u-(VH3^n`)|@Tv_sM;O=LSV+$d&lMo5oS-U1BwJw1G%S+b7&xyhUn^5BI`@uBOdQ4s$y+n0=*x zoih8v9A>$ID8sh0{e?yLxkqC$jUkO%#E2c*AOtE72Za7eZ!M)Ypze9Pd8BJ&-lDDm zC7aflpW3q?)!pvSdF>q`D4_kFa7Ebt`_OB~8=qv@u109oE|-vS=G&QqV;?La_M313 zrGO+2^2sa2dd8K9v+y?(ZNmWE?NQibxHngicZ=$^urlP6te^8}jICPDNT;hWw}L*# z>M`$x+$yI+5lZ1@0YLe$>;`_aFp}&NnKf5^rng1YmLzI=jy)xOp8{k3Dy{UOp>GE! z6lw)#g^p!8y*5^e6y`zj-ZZ`ZzvmddH%8Ch?=FD34Ld*;6_D1`vucA8xIo~v!B9(E zrxT9cVH_Iqoa*hnndPlIX@-#-^V^kE_K+RqlIJl@XaXzIC4+ z#Uft3l?mB4zU-W?`O=W<#`az+SrYXHy%PLv?QyQQ zAyq?zimHRm=TPZv;)(rJYhFy(X_{)|U@B%Uj`w~MqbfS3H1_iQugk2)8S#p5{FKqW z*s^bY^z~zWk;C|3V?W-~*rc@pfSBO^g;=NSC_Fs=9&-?{ABbJe7pgE_Ff1RAmj>qW zK?VL{@S%bfMOn(+m?eiw85*+)pvb}!EgOJcCdx9;y(ElLW~y1D=p1jEZ|cGTP_Zf( zYg#a=2&`7oaSqj#<5FSsk$alOe{%8Uw<&>GQfbtCS|D;^`BK*r;!{{zfH~iItZ0wl zR@}*VTcmk3d(v^Oq~Vs_8b>>4%_*@xc{_*iy;AL#w>j`raC6LTk7O&u^9HPsxs~a7 z=eB1OsDXTTu20oe3i!%x4fx4hd{?%o##Zn|EPahDdL;w!<%cYDGm7vPODn}xqB--9 z%K|GD@DwSY8qbwNmx|A^TpB!8Z4_q8JC+_S<-787ITMr_UiO);gHVQSeL!s?Q~-Is!aACHoL(t}!u=zk%#fV{b7I7f zK`aR*LdF!}EPj9w7CypVF(T&5@wEGY!zriHE_giN?HXUY&Zl@wU^dMT+khi(Baj!~|+h?3o>Hw;;zA?A0 zo;s(BS}4U8GUSI$&1roSg z#Zg+af!XBGzw`+{4keMRC!?`kEEDSdS^!3W-GX^kVKHQFXuYt(zBgAA8@AY zq{i7|JPDXcV2GuKpf~S*$@cdmL8xg=6RRMU2SLm0g)jOY{C6!s%rA}v z2G$>|UI)UwU)9$w7q4FgA`a9Le7{wx6qAu%T2Oo5*n&?KWlD?V?}%PE-XH*{mlP)n zXF2A&ghP~fCoCchPh!ursb!9RVE8Knnmwd~khWEKRxFxsq|e{(hU%WlKIacxu|27J^yA5VN7eO&-} zo0}`^at36WH=tCQ5X=Rv9C(s2n%P5U;}p)nQK|V0bEvK(n1VbCTf!o&sF4W=NHyMg zSLAo31Kg~^*#2KpaeQSFVz@e{kf1@tfsqN41tsHRQA~^Xh!}?LC)lFcvYot+ zSJSQ>yA__#+UtV>PmrE`x+A_*nNK&LbjLF)Wq!SK=*NF#)$OYBC$=SucS;q&hl-#c zpybSIiQ}EqrMp{~W|6H7<}tcL)^DWO6-xKKh8Xe(rBz;-PH~ekXbMdOKlR9+3O6U3 z+BbB-E6`JBT2~k+?&7l-=z*sb1FH+@!Nqh90#QcMNQO4YjMfR_RDgpY!BPr*hkq*r*i(MS7!hf42>f)5 z(!w{>QHg&kL$8z@Ri$C-MoE`aRgY!#tPo{U8RC@qKG6)kf*X^L;QCRvH_?g+`o;MT z`!xMp@GSG1Rs0C+t)K12qsL?8M5HU6-%o!O-ntY>n>7!~FW1~SH9&k1D0zh2{eZa@ zdv`d1u`*xExBV1hvH%!SsN>r@u7*oeJ9qV%IFbZzUkEE=+QHFE=x0B z81%UDN4lK}J%W9({vCI(-k4YE_bLHyec%QKw$qw`4jYm?;^4M-(##cOc~hcoW1y`N z$chkVPbO`)d1xGp!E@~r(2$|Kx+RHt{jWS{a-?i?u`9y*j9-uFhlkKnS$J4QO2T=B z7DfJNqs6WhYJcr*wLMS81VKy>hx}wb%SJ8((|R`y$Z4^&AvX++l%Uz*Tz{=;fHny4 zClraubufCa%Vxk?&L@YL-2y_`&C|#=G@awd9hmx{)z*MBtWRuMIE-h9lTEHr9Omjc z)(D0_H$qM*g(Q((m!rBcqOsCj`cRpIjGoDoG+LO6T~}jZXQla#F_-s99M*=sH$|E zexDmr>3yMn5~l#ZRO4w|L@(-=)pbmw7tGYjF4~qUJOfnn|DlSWM3zCjhBL}mv>dwT zDwZ<=3y)39Bt9^&Zl^Dg@KzOV%DR14cG&zqQ~dA0PFALYY)0>%fxrFCdwn2e=sO9& z7T>_wM|q85(zknNjYCtNeR<&OwW0YEV1jBOPDUJ$Zs9AKID|k~CIuf36nLw1+WxeJ z-J3WEW8v&KwZ@QmK~`AQ%2#KVapqP`CM)HME`U8|nJb`Sesr2E7(}7c7`R|9$LHr1 zOFW`1z~nl($L=}4l}9Z_NHTGE;S+yLF%vh0&B3(l!nlBB$Ja^b21Fj2iQ3Xyf45{F)#pc8?(!HZ41(^Rbq32|IqgRojf3T0ppC0yk9u$g=*kcaU@_y3aZ z|72rT)SrWi|19Pu|B~&0s$C#EM>9GDdjlhL6FMV18yh=Yr~h2-9Zj76-;JH46WxEA z%vGE%teyTR9LrYLl0y+d{Vt)ol1DF}khvQdF^6%^*A~_k=)**T;Z>%;ZPsZvsoSz~ zZ4rIr>;4zu#*>Hh^%9tHH#|zN495LoGVA6@wd;0j?)mxr1k*>-Qh+sV#$Y@y2s6;7 zrl=!Fq83IPrXKk%){Y>heyqNye&jw{H+)C_*JUp~oDiqa2)x`p=}D)l;HFJ9-GIex zjZ_3sv0hhgu3BuE9ONV7OFgJD9tcS3#^u>8uv%_Be=ycj!Dld#L69Edkg+N1K%{s3037{PR#2aD8 zoX9S^RVb=XB_z1n3{aaOhr)KQI>&eLV2Vn$cbHl7VwHX|z87Pbp!z1ct5U5DMJ#2I z-ZvS}xzmw6C@!69jK^pea}#GL_>{34Yn?eyxh9^9vXUDx+bvnkU__PaN)095rqKUY zfD*z?v4?OYjWQDKC;20usLFAEq4jkde2%MR;HfySa;3b-EYpQ*3W|fwdKZ*WcEq~d zU%uLjVlJz=-|3y~fP$LKSf%5lDgKf|TLVqje$4pjX8!L-8jIk{dZy1_#+fMc7UF>N zry`lpuqhw2tlk}A5TTKvQ@tl5A`Rgocy@}p*)N%#03RY^|I9{F3kYD8FOidTsQE*R>sK|M#Yv>+TWKxs5uVML{qnQ#yZo8deW&ib#Gi++vshw$t`sIKKo( z^TZ7QMg*KXPRbMPlW6_*m7q3C0e6qdVcQ`Yy@N%dmnlt$C%Jy2+vA~r!}$L%cXDh% z<_$Cu5DE$qko5mzxtn=f*wcyqI|=>Y&0y#FUu_)!v-kmO9?n@RXg^((_de;~L{eN9 z3nW*{>j~1<3nIVf!7`aCD0G<51oKf#nDi15{xBJ&tfLF3pvPCB(g;E~Hu(cndoj(G zG?V|8M-v7^L$xpbRRDQnA0uY-wZ)d`3@!3GkeK+g^|9S`vvuTlBbfM zIS%;qD?Rpx@U1L}TYBrpAe#?npfAYFt9)=araON(LWa9| z5Ppgc0n)hwgLN)uqns>OTyWGR+&ITh${rW^^9Q|-?6baj2ncw$)qb8i9&+%A@x9mY z4!N=$n5S0tW*K2${e37Dx$$uXm^)P4)T2^3+~+;9*SdgQa(B%c3tKx?c^l}VsXKK> zw1{HWkOGU1p)z!GcP*`Ht!-XC_LeZZ?4BYKOr<_+8{KAOiHZ56{!~iT=H?dX#>N_J z4MLO}N>p|Ru%CS?!3!Zc+0J~Lhc zXE?d$_N?p2R_nw&@Sxo$hDEte*=(d8JQs`P87;^Z;fd>dB|?@(Ot!d2!a2%4xI3PU zrWXOq_G}}>n|a1{C=ID4M|npD0Qqiqe0UMH5agKKHVL(Ux^iPkR2V~fam^zS<;=Z^ggq2X90S*w5LDF?g6n$f?76FYfaE4XOGFQQ!M{>X}@ zjHH$nDg>XeBd9EzhEt@&@%!XrrQo{7U~@4)YW1$TP#Z4+V1_Ts;fn(qSpQ=>d0xjRpK_w$HRkG8K|?9baP#glE|T{ zf8d0f5P47(rqPZ<6YgFP3o+DzdkCc}B8?AQh?_ASsD=AmYeH<1H{!YDp9nj+|2g=p z+?IwYnf_T**C&X5LDLzQO8qHX??HqvnZ~O53Mkq&>HJNNb9iddqM6bZ z6ExL-bL$1;*DD$vP7vpt&O?_+PmoAH1V=_MF0#T7DFRGGbWGUHOu{dk71N=XxSYSd9nytXlf zbAENyH4v98eFCDyfjE<5yY{@3GNsJTB_h1!D<6j(g1J!gktdJ0-cBH>2jnr&8cWeQy3BrcF`=CEDMPui=&)_R~h?QyGA!*Jgnxj znC7WiEjKBB+*Celm!Je4Y^56bX47pRKjw?D`+Ms?+R=^V2<^mPO5B$d&KE|aBoeVU zjkJRAO4Y+p&Zf^g>NEF8y$Rja4Bd=`Zn1sIVF^oO-I2}}$5tE?R~D@T07A8^pMf4~ zlp<`e_fFtC;j0A{bq2>mXgQ@e>4n=Picwqi9&3^gYdD9$xyBcP!Q|noptk+k0aT}% z0bK3CvlcG--N4+A;r}cIkYV}BE{6ZIiK{w?GBvpl9OivHWu(E*YrbJ5M4U^J!B*+o_}zC-BriA z*9KW(a&J{rn?s+~i`jU&4GKjNy}qps&g5m;$8C%fjQ(;OzDy-z6|Zc{LA8ys#Qgr5 zyYP@k3h@L#@(2QH><5O_y(h!7+DmBxLn=|5x_$MQX0U4YxnM0>qAZS1TAf7okx2Ja zj+nK|;5BAC88fRE@gI}DWf?W~-cQ4;=gvZsAgF+($WQZqi97ZfIs(o1@L)`g`J26Q zJTmu6*DLJN1?EULJ8p{FB;h;aLo-a1T@o*#HF{iD#=~X=(Pl;{SG?#@e{Eh z&cMDsT!1I!ohrd<=iyd@^`uZK2(cRhR)s3%|A?jYrDntS>@6 zV96mFHBh7Vf7$=~Lv}1$o0X~@Y^aJ8)2Ry8T>w{C7v35mv+iREyH_pWZy;24WFqW+ zjePFR+-B)g2D5@Jd(qFuPyVG1#+ZtVWx`+qO!E#(9mSHBbU>pPDj+>ml=(t3_b z#Fnasi*3g%v}3*O1FmOf-=AHN%g3GBbW%{oi3PQN+B}oOtzza6VI?Et7Zx=6o6s%M z!B=he!g@!YWbq8cJ?brgzQui6kR&D%*7n@3PQjzuJ=d!XUXLH5CZ-_t==zODjBVK; zFkV&|UY01k&L(HliMI=k(Qt|6&zziFoT(A6D{x!+hrFepi5_1Di(zI!+YW_xnH1Y+ zBSF>`DVm`#oQeKE%8_775U?c*i!vBls`)p0WjzSWVXX6P9pz<-no){8%sNr>Nb^F> zVZI3qO3cC&2hHjWrGpeDDrKOb;ptU*7Qt;&6G~?bRL)TrN}BU&KZ7z>syQJ(rCWZh zc}BQ({K|POos+99C0Kk(INwyz7G1_DK!@fbvNdM?;*wIi(|B~Uz$+lxwa|_kI1{7R zo${%dh?P0j&>k1CUTm}~rE~)mgTNN`#jol|6AN;dMm{#ED7`(8E5de~pvbI|RJ>F# z)MQRtS{^!MnT3oo5R{LQ%bOHV(+HPngjO!&u5Pnj{!}?Rt?EU4(5~M1PcJ{A>sCll z0D+UeeH;$~iF*Y<+=9_XJ(V8D9Ay&$w}6T1f-f#197WZF?b-Iyo_|3PDQ~?D5;QDun z_1{&b@`?hIJUllm#6Dv1puQq9vavXUc&s)ezYrk4A0i@@t`j&G6cA7?1rbVw&|ScP+Fx^UI* zkq00z?5!5XPxoPPPtsvC{YjM-CqMN+RE!ep6DtamNz-Tpf@ZwXtQxyxWCFb}$VxM< z;m}3^U5l@+rf&dwC}>KPJ~uy%u0tb@!D3P(#*vrOUKTEuY&7}bwXGw_eVW2_sTj@Ku zy-KxKCya(d{z{xHXDC9c(R5rjux_U0Qv*JkHmR`53sWNe)G3?zT)IqXb$(@I5BCDFf5x~qN{3WA7pG^*Yb~FSNK)wpb615o+2Ta%qdZ$cuCQF33*=H zGmhd`2rN6(E?G+2@`{2=4{6yI#oiE)l_wgL6JT~#Od^DtAhZiKQzK#&Sel!1y#sE@ zR`k`UnRmcF(KOF7%*la0{>50vz4tPaI-dvFK!xV<4rUv`r;ou<;gAi##uOyt!ZrA- zu?*vd#TOl{_&QJ!3lPP)0N{dBou$%?V0M2+WWJcXJZ7vce7-+ifce2xoK4${4%S5@ zt1y|-6>20EQAkUtw^Lk}su_w!kQtTCZ?RutQ$o70y$*O=J~e(A@Iro&ae@DsIp0_%;eeraJ7HQ)Y}G=mn&WW-qS+%V4W!;Q ztT`hv(}=!mp`LOOE+%Z_KKbZ5%Y;O@uQ1`lOv}`Fu#ymr9Dojr5H+68_Hp9o-Jh2T z8jO8`zm|(OTD`@o;2$q)aPOero4;WRknqR0rL_IQe{Z#R#?p_P)M`DGKWDCZc?w1V zsda^s;z}ip<0?IAvW;lNkofueS!XfEhZF37mYPyTCOz5{&(-yotrM$%rYoKR;OMKf zzKPpK4^ui*4SY;EA{jdtTf{k|`n$*s4w782$pc8`BYM7k6=GI5*Q>|~lF_I*mPE6t z4{}g4wXlSaO=y}OPes)(sRv{h^2M^@xHX_(FeC|~h6UKN z#Xrb#dslc{19!##n!}%!pcV{UXlZtPa%%mV)je5UNQLX!Eb zQUyi9tm*0un8fNvvDo5~Q9F;rUMCL!;9g4#eTk$;)U3^*sm*_1eW71`Ey@Q302umS ze-Zs(pz(W#XvsiFM=SS_?>7eZos3Q0i5UKY!$O5MnKeFm?u=BnKs)msWU^+kK*ZQn zqUur!31EeJyEwi$H?7}E_4Auii$y)Ujk02u17O$kDD|*Ffo}Y@Oq}(@jHc1Uj$dC_ z*nU43q0sv~B4j~~YPJn#1`!1>%as^jhUj!JwXSv7p;{q35(dOjm{yZ$0_JA9d+9df zB(QWuj{1Jz-o?f$h`w>1I}l!cAUMT$MPl^GSy2*8QSRGQftx!wKydMF`{=rLMH5sS zoPmi9O!>3aijwo5EtI)(-4_Ir611$8u!;pCsse-KT>M;tD$%dka%a7h1SOz8*M2jI z6)SVRNxLL{oqaaYU4={cB;Je2M1)vT^eHh+pY<1eZBrG3rG)0)q&!d(`mt6bOf2-M zkXEQ={LFK^j_x9|ua_#FB4| zS)2aH{A^J5%vDJh%PXvAwN#Vh~EE~#pJ@_6Gt?sVh4^2XbGhPx~t;(h<` z`m3&^&qrI{Np{aF@9Vj8fXhB&T&V)&^=KwI3>=voyYvu7$jcseT=8rLvyA{M?)|}j z$oJ=lU!vC~xL`LJygU(8?l-BwJh&#)N!{GyRk;hd&AIZo)wzcI*>SRtc0h1+?suWM zy7vdiA=9sgeV!5FbPun(`eqfa?#sEnCL*dmZ^HSk`AMpOV^m9g`NB-{R1%|%*Cw@6yT(Z3~GhA1|4VT72Wamiv$|>_md|w z1oJ_*kg}?aEp@M+H+ObAfuj32fX2+WK5zUtb3Y8hfQ7RCiu*$`Ph|X2s8QG(aS-hu zh@ufPgnx)=;f@VNpB|>VFiE5n{|JMi_7G!)@o7q`x-W=BL{DdZ3RqlE@Knaa3_&3M z>@+30H(JG`^S3h|`>ND`)sj4mt52SyKXF`=4uG(#5KyFGG$;J|b3T5ygwvcPo;=#= zhSNWIS1en4Qp8j9W)}90zHE?C3rd8mu3T$wG>P6qXjg;75OHWb3ciEi$i?s$^`KB- zVDdv&YNG#X&|TmyvV_KYw}nr;Rzt7AXy=#GMY_WDZRkaY<0u!`0_v(iq)~QDBg^5= zMQQ8fNF}uYQJ@LzU1n|DHt~tThk~w~KzJltHRSv{rm5FP!CL_>&eB9yNwUO=Q&k1I zf6at#>W3el&I|7|dkj-c=mb5WsU+ow_GNPa23JHrkWT#D>+@(Do6Oq;cihMTxdl%j zecqzFI_BJ;g#0uk2K^#ur~{rh)q6%^v|GE&@Rh+O0B-?B$!xCde33tRa;z`K#l!%P z5}8c#9Yx)Z*(3M$H)aIFpq=#8()4*Fo~byRNTBu-2U9w-N-?6d35ku-VI|%ul=)$i z?75C5Ad8dE)SIIfozKDHOErqZ;A`&a+qoGbA6)l$Ipxcts3=^H36 zn6gIM>cyn!in!D9k{x`y`O&tDc5AX_mjbZ7nn6)?jS9!Bq|f)XD@x%LX--R1(t;M^ z_KXgvkMeZ4M`|aeXCBm1I?YF1%b+Vrs01Yrr26hUZ&@jIG%b zkgR$y+aoJ?xWwI!Y?JH6XnkGPUU?iL-+EE$V_^=$Y%P+vfD)x(xTdf}#Ispf zLv6j_vz8F|3GTJu7NuSo;fK$n+I>*&J!{VhQFKR{SA5~i+FFzH(XFn*pZRr$-+a1U zkj6G~)ablfJR3%|IO|)=dAyYkCHag@XbzFB&s4qtL1DVu!9*L7Q`w0D`&ta{)GLm- z4b`OWm+Ehrj)S!+0CN%ulQ57@Lr-vYMb3c* z*-4MJ@)8)gu0FjzqT(`cy}jVUX3ZlI%V~n6Wz?l+`k8c;U-~DU2Go&VEOF5eRnATV z({E!Y52C0}WyE8es5_z=x-z1g6b8BUo)2RPWNQ?pX8^zqWkfSTRmp9C3yAx~p=*8t zw-N~;Q|om%ptpjD&pP1vfF#6ccZcg63J5A^J06IR5TE&9YD|F%W^UrVIKTZ_mt7#3 zd!^N%Y4}@#eA%8^5;00RH+cCkWMq3DXi&kpQshOOgU%RG*{46DD!|>Ua(J+;GICQc z$JKTR+~+~LF5YYA!~8fSjNOl#;JLRk^6shRyC5XXFiy0xojXO3PT(G*O$A@;cRP zbmxEfQ}D=;mXh_tthI!Q4J#|KMyxF-4u&i2pZxMD8^>Q-8KK$`Ep8B$2oZNcRd4r= zjs=#Gp3ovCn#Y@r_7=VP#1PkL-^Fr)`EMoq2HsRcr>FbkYCJ%>Al`omK9;AUIg4s4{;1f<6 z@|X^Lco4*BKQybh9=^eDX;$fuCf$9^V8fjXvxX_W(mcQB#)B3F^d4$t#h^Cc4Zyd+ z^-BJEvzYZtetEMvd0Q652Xy@Xeg{})Ro!#>(Q&T~O6`kdeUkj>QiPlZ7_(WYCwQo` zy7rMigzf99yY2R1i3%>fd*;~{=pD?N;7bVUGiZTmOUA|2@t8DSzI~OIfTSHcd6yxC zS&5}hx=`^FO)vAwlv&^Oqp`N8{4=1orv00(5Daz~!E1g`uybJW@5z^cS<+TSSmbu!`X~I`l9vBBn1+(EwVjB$m9gNr zi*0UW`VaLZ;9zcKYW$xXNXhaqmzsMHOfxx2R1LKElh7X(wRF zm@|3d!lu4`;gd=lIFjfSz&G(`vWe;d0V%<&MF%Wf!-s7l$}cu79{gxK_$c(_|*@t?94W6?eL@>8w<^yK^(B z=T?u}4wy5tFhgq(?zZQz-}#DTWuby|udYob!PWAS*Q~8Vcvv&ayR>b=rEfikcPpn! z&>>>b6G7ov*Ht(xR^Fld6E&h;5n9_%2xc0n3@CmE_g<@DmsH%oBuF}i3T-~Fb`1ta zR6Dl+*J1mY7q1qR~l%l8^`$zLl4$~-aJHuk%X1D&S*I&#C; z7w@eD-^AK3ia-IKez9$#d0N6^1b4$@(`D$u!Gr0){mRRfo*F!;K}mrfz2s$~@QzRr z@W~6%m%q>{HEe?c6e~-n@t|36S2%)&dr5BJtQ8D~c(C$&j)>REP$Ah1`s5@Gd^h$9 zZa8oQJn>*%?&GF~1M$EY!KY!NJdLX$Vy2KFiX}YbR%ifCY#=0Ruwuw~^}h#9eZ)S8 z7hI(;(ALMrcl6t_MNZ?(dKE7yrB!&O+DSI!5ls#+-&bx6-OtFgPfy=&5!rKIKfbAY zbh`uQ@dAHACv4Y95qtSrKf(mW!R;)9>+s2S>juhdA5o!&Jdsz@z{eT%GyFHBH=X%< zv>sv$(gTPDN@C>Z%<&u4KPP2>WeI4S!pPQt3o80=LG|yzTiiz4*xJ^?{r?W{cwNhH zcn?llH>uZaR~D^mH2&25vbx(02g9O!d~H(2t?zoMZ{eRq_0t(g2#f zs*+Y01D;f}Lg<$9Du;O3PLVKmch8rOw!585`A{V@U@wb)Fqx2N8Z#eTv$0Tw8{sb& zZS?z?X<=pB8%zY&mt+;%P(+7YO*f{w&N|J4adrROvAEJ86ker2t)XQF*VkRGw2EEJ zinj%ql&^nN=s>NVwU_4^#DLD~klyd1xID`5J<`t15aLn3w2$g$YCXCKr{p!_B&5W} zBoyInrN#^dr#ouOuv)dv&#v`=XIY?-A;lu*~rJN}|z%zo97c z6sZsdHii<7od)H7*Y#f!GQ|sHxBOiI@xJAj@V`+2|C{9gucBuyyDEq5LxZeY6aI_C z*k?wk>3)M?Wwwm#4&AU_vkyX>j-ssTqK!ln&j!X z=M?*td*{- zADsc90M_QF&U9_+4r+R;L+bX560owSV#;*oN)3~!xgVO<+VsiVied+X1gMIO84YU9 z3vD`|i9{Vy=clia5;WPy@WsujcNr@L{j=>fd{0VHQ%^*ZC(np+r4Ho{!i9;nbQlua7@ zwic`_2Aj_xVTh~>B}Q1qIeSm#thz;rtSFtqWW=uP(_Ck~iYm-6oW@(9C!cU(e|}+A z5z29OeGlYu=V9uQ;!FSneltpMOe)Q5M6s66(@e`qvSQ2LCTfY&cMV{uMKeMKOQGdp z6eOycqqMnEzgMi36mi(RaaC*1SS+V^8C(a$edN-QbC0F=aAOF*Gr*0j4IuUlgj5*^ z#@hRx#Jg&dVg!IY0g~Ypj`+XYqNd{?W1%OFgH{i(^kK;!FOOt6QzoA_=(YFh!rK`sq zaEI~vK88JA%O&Jquw`R5J7Aps0;Uh?BRmVrt;PQ=xRKKS3ff%H2$ zTj1Y+I)5`G3RTt=F_qE3GS^wuo6u%~q7(*_SM4Bj8!MUdG-}l-m>T5h8dXwi0t+)X zTG~&fF9zQ}7@Y3`y>CEpy-uV;BAhg`$0DyjIit5$q{V;$*W%J9*pE23p589EcB*|p zTi~_!wKz@P zbtpARVGTVOjx;_PpsjtQ@5*gip1v>vKMTW1X?e=rR}lp}Ig+y9VlnWhEPZmQ;%;h` zpl^8q65#eOp)tBbQHn%2I^7{M&wU^+?j<(KF82A`e4px4?*LoSyD&i2QJ54?weGP+ zRCC%047NwNEbf&f>agtn(>0*`1y-mMesN7R!`HX;0@Tsy?u?ao@MUAS;TQXeh%Wi! z0#L9s*5bnuE9oTM^K|RoGLoZ4C>xja^A#2e<+VS67!Zqc8LVgg*{NU>AzL4iA!UT zZRy-Wy5p^tV)ug;!{bwSEup@!hm_PLk!jFWbf(*X-@=xW$wtLlDJer0y+1h|F~?qj zh8`;lwu(8&le^HFJ8U(N3x+9m78yqqL%EJU#g6Qi%y_ZQB}+UZyl7cMf!8MpO;TIA z`?*1h2F=?xy6IC@Hr#8Uyr}XP)}~||mtIOU&FN?>n!+d@7`ek=@{DBA9dByK z+#?^e_v`)o8Ui4F)G2&!jIGfc@Eq2f%dBY2PjFqn`5zQQ=a}Dr5kssVG7|)-~nb%x)rmO=R9xIkN6ex1H@T;455?<1lda;;oF8$W0c1rn}`!YkRuDhfA5i+6bo znIg_cg+oQI9@^Fduq!vZh8Iii*Y=$BPXPr}}s7Tw7pGIr5sb0pEaIJ1CfEKcHKDdta&6mq0n5{O}hn+C8Yq9m#@g6q;?z zk!MuJXV{b*?vqw&EZ%L*cd_*tuVt*-(Kc*P=5>;2(cuw||MZav97x;BW4d_-$VOZ<4b9%P#nT5N|~E z|H)(&|HH!K&S;_kcBGo79mwJF{PvPp4{nu!74iv$rB4LQ@$mikIm(TCA2phOd{7hR zgo5$-#R&Ydk-+5JC5LP0WaM-_{4;qTlfBjTW7&^40`m7 z7+t6bKS`pG0h3ZMv|bITcwfB>@;*E1_$HG%3+pk2gy?-$BQFHwpTM|3VPY%t`;`~@ zvBg0-MkJTj#5!kJ9V)J2}RCSSHqLcGg-0@lnbZ zX)U&f*f`9dWrYk>vWv^&v-0$hdTQ_9b1R&ciTbADFQsumbdC$SdwJn8ik)8%k+hCa zjxv3Vhavl7Q`UepB@Wje7{#)bRtc6P=0=26nSl`&{3TrEEO6TP@bR= zpAw^;Q+HP74QRC-Ci9+`IWn(~McU36d5edwFo1>fOGdT#w~~?u%7nCvU_z01jgfcZ z_4f|C0b!(_g16*Y5kz+r5{qH3e^kR!M}4hwr?J6 zMB?%N6_#`M46QdZUx3_p>ac|tsB|W=Msj6ePAMhno)zzd?y2#-6*k)?p1Ag*Fxr77 zk{$%s=d-*@IftyUj)d3ZnwJ?Z4MQ2UyFA8=A~tVU*3~qShUCL%Q*dF^f@0xCL9P1I zkQ5BwR+hkzNC|zk*Hkqce4Xf1q5u*0@tY`7%b4x+E(<;Sv!r+Wa{~738cI-f5Nc4R zFcA2KzQe#NUM$XdHt_-pr#N+UQ{D7OO>rnahW&`@vLFAGRAMoGP?{KF#7gz+^7RIk z!3E%M4Bb$V}dh0;RRsbWUX>5CLzQH5DK+#V-~0zMrW5Hp^DPWsQsZ z!;Y&VU2kyDRHi})4XNHTj#;4d^sAcJampno19x8mzk~gJ2AYzFEBmwUYJAR zlayw?AncJ8->1G)XNB3d6wErQ3hCLk~R@qsS7SW5DAy*ItD+-NnfzB zgy@%WOK&hdTh(gz)37T9TuYri1?m(`&XhKDr)JD2WmsJQZH&7AyZNDyvbPQjqHUdH zaV1Sm^_(;-zPYl)hBH_PetAcjnnQ#pZuXWbWKLvp{&(Jl+HiR#_a;MenmU9<>dNIq zx{d*`XKMKzv+2Lh_g6`oeA_U zw)@_9lK-9FN<&eHkEDt&dwuH6T{J(Ne;AC~*WB`Y6}yMasHEqlbi41k9?(pbn@VV$g8^@|t@%V|&c7D-)XGn(RbEOK299nd&9 zeuEKYr;I6)Ste&sx?&W_x*0g70*3OH@-&>=_0}y`%ZewC;uZ1wI!%Ef1Csu{TEkhD znaN{Q7xH3hqr>j-nU9nZK=l8;E&96HrD`P$^;=Q%E zKXq`8j?Wo1%Zdl_O;)1Wk6jVc%=1>P3dd77cbn*yH#7^T&cmG^ zC_T4%%8m1DGwGmD+ObLSYzP}2)U2;Vb(9*?5fo`x{j7!vG^7b&9B}Z3fE)wnBq66??TBQO0z_9H*X@yW; z1;Ad>9K1)bY8?SBpN%cr;JIsq)(`JvEf2(6`EvLlpCTp_j`rMTk=TTSYh0vc!#W%6JUA78?EbD9zNMyaIX>FoB*be()#* z;pEFK=J$d`pX>U!p>mA77v(v@7#{~CHY9qCZXQV#lfRVrJ+!_Xvn5cTEd12$Wx;R& zSz`xLt=S`Qf=L>9zM5JmwB=*;&PY>mOiOU>VAqgdy*qDp*SI_9TRS+$R<#T>B#!V` zM%^WH#@9H+sJ?`7s0Fy1pIRp03(?J^{{*sy7#W0Odc{-t+^&lUVQy z)cyf}f9d<{F*?O;&wKq28LSORc4k&t^g_l$Sypoi#j4a$190XpM2_v5;^0TVPX|-D70EAVnrEP zK_1Hlqvw!jmY@E}$5Wmtt;)1l<9fp@wBo`i?K0*|5M0hSz>U|_c5V_Aw!=f_#!nth;eq9QqZdp_?MqB#8p+(Rj{m}WwJ zkVvXhTf!20=-SA5pegIE9`#(QuV za|dQI6~@flb4o#bMGwr8GKByFR34%GUL&JB8J)8DIHTi3TAvVr{?OZ}hnZ^~m@~=r zfpZIOqF2Q!$dh8uj}L&a1`d}2!P zf_YG%A-_T(uG~ExZ~n=e@>NE|1z#j57z|AG$S~=ZPX=nK2CG1;$~_O%X0mWeQpu8QQf`K&=@f zhzV08{Qw>3(&rjh=e0&kYo&^}B-m~J!2DMjrww|F=X`Th*l!ps{reNCf6|w~{WtSZ zMIju+C z()bBe5+>M4TN^ysUi5XhWsL`|7lZd{gyDoN#S;cc%=-!>q0Ir5PA#O1_E+0*zg+Br zQHcW-^QrJ|G6xr<99w_rS!paVhOoBKp_20tRV=Ye`w!YfX=%}e%eQpC*9k&|#`&Ny z6etoE>PWo8nV%o)J1PS;*UFG5kwV=m`Xv{JE#$E08FR&aR$r{7aW`U2R~}9qVjhnO zR|9)YylnQR{#@MoM4e>G<0m9Y64MOy68(uJ4Wh0AlUA*_z$%+=BD?gkW7AoAc-uJY ztEPK!^)+;`17sl(bu%LdWuhuGVfU}nH}HyT*^@Xy{wHh}!6p1ZkLY6P1u(+tc9Ea| zMri+%$fQ*;$BEyC?c|%(ivKSV;pRcBrtwc4{7)KNsc0=b_dVjjWKmgEhL_jtc+&}% z;|Bo|0D?M=Cl7;1e$LrAFKDZjT%x$qO(T;ex&eF6k33pmr2k3cb3M*})Ji+$sB`)8 za`pxX;HV})6Mz9y4+)K8|EDB$#|9FOZrCnshnwYTg-fr#$3(tY5F`e8H~I=f3K{Du zbLRzDs@?=MBs)sgGowrOsgruD@y}@;pTl6)%4Qj#2yF)|Z+h?rdU3SW1vrtzq^4v} zv))q0kx!#p>zYZe0A&iK%xJ}VYSjdrmXsTqi=dvMMTT>|lO6_fv4*n+%%k&?#c$x~ zHSpW9MpOa}3mHsQbT&?DK=T1+4Ow zREWg?l|8!8s;P*ic1~A&OjuOqk&L-01Ba}7qI*BxoeMT9ogr(EmT5#~!4p)9VF=VyO8=BjY6DUmigC0fTUKThe7 zyBN&nS=ok8aD`ZFY_{J0tr-3V{pCh;`si=rkQHVY`s*0n#Dte^j}B^NpCPiZ}Zer{@mAtfefu=uPssJ??{G`8rvi;&ieEifSCHyjb|Im zi#T;N?luGzqI(kPSKC6z*?qlmaaO-Xad6pV)1owC+3x>at+3@+f|qK@GivKooqZx` z&JOryA+g{EVEjAa;CeQ^tgj$NYr^kQ*ZqpL?1IGXcj0tjiO>tQsYGlJ(%1v{$QU#> z$)1>;Jwt)$J+=(b_*)FA9c~|Pe!Cy+(1wBX1-)4u}+ zM4zFh_tPDrOceN5O?x73NcgD|v-kp;c@@{6c!Ahadfux>QTc~B@h_t23}3;w6U#UX zvay>(c*@FUKa`%>>&0%~lWUvRcU||j2`@dgP;U%AXF_!)aCeyy+8B3WMbg$IA+cC+ z2|J;zSN{UJsEj@KBBi6D4WO5i4xC*vi^q`hCi-24T9kWV(Cdm?NRLFF zN;1dR1-18-%7HELxvZRls%W8=chj{>vdbeA7}1a8^!hw0gL@bNKX?2rl)542^^P#B zL_6F2nfaF1{&3AZ%>!XrqyzL%0`%9LmlqJ*c>Zp8LEmrwe{&$~Kib{jjJQmtHHGi) zrX7+@Ld}n-B`mBIsE~_524XFo>!(D)V>etZH;Y&#%^^O9$Gbgsy=^R_WbzKcJ7%9f zoh(pJ*!8=lMy;=`x-QWRsYf)nworLS|$8NdqP9e)iH2{oU!tdMM?5# zi+K9%{ES6#KRW>zn^KdLt6sX))5+74RNiAj+VD|s!SQH-$Rs3JzMg8%;8+&BB%~}} zF{+}@fW)E9ddf0QxZdoX+752_bozoJp=nr>sYEDvQcwA~%YEZc9LGO6d zVzMo+s-I0QruI89OnyFrXlSlgVO%pJ3AubwN`!Ye%C$6np5UNS123y;Jjz#-hP0^&|h@A%DgiP$Mev5$K_;- z+6CW2yzxmKy;6Lcox_E80kMW`hd9}6NFVlBq`ZyLr>TGIE>ZvU!&6L~ul#1l#t-TX zxBsB;AG#)+b%StOO-FP1tkU!rm0mrg^m!l8b&Rs2I$~A zD+wHut^E0MCn^1!>*J=v$#5`ULxK0xOTZgUfK0(My*%+Vei=@n$Dla95eSgL1&)8k zQ?z}w1au+t$8)`CBHeij_ZK}GtvK!i0euW{5p$%4`hg#05iv;sE23!dzN`y(OG-v4 z44MgJs~is&~n=XpS9XXf&T3AX{he93)(~oOqDqllhC0ua@@k z#D9mM*mr!!Q|E+`mHR|T2vc5R~mJ{~hT~zRY(Lw*o8~;Vdk82AOYo$JRqNd|$!X=Of{wzswQe)MNbcgq)`B_b05C!I%Y9olTg!6#$5pBior z+ULrdc+9YO3Vj*jdjr7$Gp8-s6%>5o|HyHM<$%;g19nx7Pp?A0`nLp&}EY) z+TgOTrfRg4aTRUZqMD#cDGnASL170XkrrwoC}W+D}otJP~1vEb)!aA>NBibDdCt6oEgzaP}aS&@rEuz|is+3S~w` z7Pd1e9!}NJFy6?<-??%OmG~Ezy?M~!yS93@Um#Jk4VHR3OJqQ*`i3x2i9v?MsP<`j z(p4$Y2YzH4XM-8GU43n#%Opsg%m&U>jNqBVY9yh-mFUY*b!PIB>Ekt9ox@&Oz9RXf zU$;$il9zI_p8E#Apg7Xo2%S9qC!nQJ<-u18BCb0Yhih<1S(>U>Q}-u7Cp9KCSkt3C zk~3ON{*VM8nQab3we(~BHnf9YvRsJb{nyeQy>`|{^Ie*`zLkjT{~MUh^leOy9ccys z_Eit@cpBui}BxpCGKSWz3yY{@Lz`A*7px-@Sl$kDV9@=mFAWe z-Hpl#?<&xQR`z0|UhTD1#dY5eSKlMt#w55((9juibzUb^%$>>}u4xcG&{SS{lC z-paw+*acWwMgFcR-b1to_jSZl-Gw^*c|!bbVg^Kqn{fevZzv$*K_1X_3b zrFpU!Oj#D&rY~On0Bs=7Budm^o&CR3PR`A&c`&WowcUE7!f&&1AqW*u_EB?Pi^dC4JR6B81I>7kq z95u3WaI8m1cghi_Y9JAeCkG}7EQ|$5gy3Jvh3b@|84Vi!V|N6bfoUTwUx8vRUKWH( zOk*}EAdu78)U;e?EzA3WC7UAq!7AZ9l}QW%fn~Cd#k=pF{nj=0$+NaU_oe*~--Goo zEsEamEHtATEHc0};QSmr{ZcC$kS{2x5Kx{E-OgO#lxS$n{;2QE4!fO01!wN2Cd!Nx zcOb8hlW-7QU7>|FbNxH|ByZG-OE)~ft{ZQO z7ny|?axy0HlGs1`#0{f56qWZ;DQ+tJm@S&e|CRY&slOajdF^~ag43e0J=w6$UbNRN zW{|3w+JYoOMM3}6fppgJs&UmYEU|slnW~;OqI`!rXf*8&g?@>hu1`4PKDE|HUv8mx zeBClwu?icex_Mm~()jG+GWDbgOHzMyd2JBezL?XB1uslUoWg#VUO{<3fAC14}Ar9#`o}sOX<#lDXOg zPRCu!fxdLj}y+ISFh7w1DFBEw%%sI|ZTUXb6M{Zj##Z*LvFO|^MY!KLB1SE^57dX0%O@rV#tYYL zlo$M76u}jv|0fUqHR*4ST7S#2D&9grMT$mX?12Ji!WXM`)LaiV4u znC9Ed(en!hN;4fN6X{tZPcfMHWLLyI{umWEZau6wORwfX(X)>m%~R6c+ARxEp6_!| zA}|v!{o$BCdQ#Y3e;+lcU_QQ2|57`1 zxab}_Kdoz1;ken9zdn62x2a zu{=%XQ^f3mSd&}qC$Go{x3|ktlL}YRKEqBDa&Ja0z`d}(D!);3Tr5z<=O(x5M}u)b zFJu{mXj#&ks*&izoeRu?>4lkwm<%%-98X==(A&$-3anK7yw6RsrzG(1n?AGSt5EkK zgsd)7Pnr6|6tCB#t&USebYGHhoh!eaAgt~g&pVEfuB-SoC(7^KxpAsak`;HHavG;T zu2Xpl4|sx;8F#&FmGxH4H;qM11?WiLNq8}*O5T2mIiyW~u`NRcHF{e%l`ZR9b7wMr z?7*qDySxsVQBg4wk5H!{pH#m{IUt)VA&+-^hfF&2p0g39(cpNK;kj#gjh(#85m%&U zFICtPPOdam%lBf_;@0PQ3|=-!N1a~y9CtqT{j13y;!2cY?Fk+m!#6JFmiJmMJGjd? z^y_d=M|?!tS=-nV7-SRY#&ln^x!|acA6+j3Jh>GbGAbM>bTN)i z|IDZ8O6D#(%f?M)K2aw&3Ixk0wl+k;`2Mequ9zVlq7QZ zE0zm&tllkV{Q^53(oGZUIA5*k9BE8tt+?^h-H}=S9p+A96u*DU)WaC;3wUttKBrEK z){ircm7J%WG!9o|gS*U7CUwIY*2DLGu&>2Ab2TwWg;ROe8aK$X(L*A~FDhQ{&KkNX zj7Md}JJ;KEQAlk@|H%UL^&5+DiE)j_F9&kcrq@k{P-M(-(xgSV$t2@YI&)+RX(F?$dU~R67<^4LV*~G@Mcl;w3K5}gHr1yn7>OI&E+o|NGAG2`Mul4q7LQ*H36#{13Apg~ z3SK=?qCDS1Y zA;dCtk19#Tk8Yqfc*FlvU9qTSkBRBndsr03Nti`8X~nyYopHIE56RGxPK_nahZ!|T zHK$v>N#nxL=F`8Y#1o1|f`{Mw8tFXByygq1rU%7Xm=+!c>Xp_c%)=rwlsG$kpYYNA zPG%%YncBWj38u^`peYN2N{M4S60*pQN zrfyZB%qX$c*)ao-6G|cksxa_aQCIS(VKZR2tWsT6jyn;XmTa_ld@$(EdioKQTS5uO|1caPS zn{i9fk_loBIZ@@VA$_sxE=s|jRfUOmb9$av-Y*^}etgs^PV(wOw}uiM!ea`P3Jwa@ zG3=gc-#b-sl4jd+9$w)ugL!f(bsk_yhRr-2yY?h|?FPQ+14@(Z8zStEGUAw}qF=%X zFnkv`m)SQQoD|VtQNdHt%(<&umEy%NV>D1a8i-n;Au_$%G5Z0T%W>}d#I3rR`^thb zcj@%t`r}2ysBhDIF}{r{dV#z7=eb*_p>T0}x7V%ejj-2sniZQk zaF+dDf)G?wmqcMcv%N4A%MU)^c>itL4C*wU=Ei7+miBnmDh6(r{f&^4?qs)9DUw?a z4)6R?E;$W$tU4NQabjOh&wZPMM__6dN@R$l#+#(G>4>Rdk4+@|?%Iu#)%?}&RMk4v zD@&~%TWcYmsj_vfn@U+~tEX=i%D!Bm5MiI2y+uqtplTfyd!-}DBukBiOT8iW0aLt6V;D{On%D>8mP@`3tT=r`mN7ZaLzNzodvh}xXJp!kU< z&Nl$L>H{1trcKf_DT@KYb|c^O`o5cyNDS5=bx*%c330sQpIAbiu1&AxgnN@)Wy?s` zh*R_P;QQ8=IgadumHXkKsx zMROXgG^6j3**n~1}g%denQ4?u`KfN3-;)e8)vWZvo`(6^~q;tEu6{6 z5}D6&C+nG)^vbL`;)sgOFNZd|q^<3ce*sk(MNlATJl2fxZ8`vj zaajxnOr1<=t`FXX*aGm4cx5M;YA^2CF%@)1U>3NN~1<5nothg z&LDk(rqn<(-#BX*zwujUSR6th-$mG3ycKES9W1}uQ-q3*TR*<}6vH=LrG;w{WrXpJ zHhZFCTVY5269R@<#|D-&!%QFBcO)kb;U#P7#&WliZ=NWheajI+=w=oDmUr2<+$8Qs zm#YlYD8cRN2Nm^QeY4%mMoxTDI$g^KxSajU{p=Qe)|fQaAukM(m)=L+l@@Iz^34h! zVSBF;VWR&wXJ)kLb(yfHo zGFiLC_?t^KF{m5*uHBMtqm@UyIy}&?_)$Sk`X!rWV?j)HtB+QwqukrDis!oaXzbXF z{JCB68KPYI6Wydr*kd`9S!f?I#1=L-zf^ATDwL8bmApLrxLW1e&G!B;`eU+9EUv4h zGj&1Yq!SK1C5zxot@Z%+9Meo)eZF&h-o49IFKSHnRVZKRV(EpbprQFa zqEacj70t~)f01lxT28Qzq(nb*P&TRz_Yt4eC;N)quIUAyS|5hQ<>AYz&dg6dw7T~} z_!?2RSxLq_{3fL5h}rMB2G>p*K4PO6zGMC#(=zK$5k+G}1~u;VEy*ZXQLLmW?~9Qx zUb`+-cTEKzvKV4ih^-s6F4Sq!)!8ccA*)`f+m4weKs1B%d&TbgQPcZUZ|MEHrI1NAy4v6*-z~HE2j2gJ zEH)Vo+?O5)w)7d;(jU)v{$;s{RMYh98{~(|n9AR_k13gz)6ra-mHH%zR!Y|%sEehg zU}0vF!%sQoRc?qoMzmzbQbjgt{ayg0?(OZh=a&qti|I;-&C=t$mO-R7H_kPe^gRC+ z@6A(;VHTL5{l(6S5C@VP4K1qjS?SB(L`HFrHoUsMY^FYFBPSF{L}=lA$D2gTSA!*& znVlAFg|JWyx!k5R!uU|-{I2$sW^)CWGLfZwS*xrSwlgY>vV4?DTMh_J zq1BF0vavu4!W3y^d-~)x^8JZ4=FE;~{fw_IX<^g3PR=Ta?mF*+ZL_CO8fG&pm58KrCe@7$JE8@1?>8r_ou?OJM|+<%-2g6s ze_2-9sVY4(i@EwKY)IX3fZlebbw@wKeL=g%jx>U6;6zRq_5EdPKEg*k(*c&$b(`4P zF4GKh;{wn51KeG!R6hnLz0N>~CEAubAKLdu-mMK^y*guO$;^d+Ayp~%yc&Fe*|o{G5c;xm_ZJ3J;fJmH=w;94E#TB;g_`D=xU{b>?w#vmd~GkE z!mn>>9H!N{7DP}u*6}$)x1`E7z3H=Nkkzvh((Y{~^LV|;oyUp@%Wsx8-lx!rH=EnV zD&@6BsXA9~=sn~YN=d+uvWkgUQ#ANWSVt%XrG2{GO>oF_Ro>QZfFu^0lWaafPS z@A-0-i8v9bkPZ210MkryvrQtg_0}4@ZC?*sav-*iR}E*#N1>?|=%TBNEic`9u*kFo zzW(@%`me3%`?`RLm4lrtv?(Pj)XBm!ox2HdfQF_Z{^{_;D-4k2C+eDnm`ZrP{MmGRf1a8sW|nmQqvaw#y7k!eMDv zJSUZ!ZZD)66PQ+*#C1D?o&`%v;OQsW`NFFIjXbFx)608_+fHwKK7CoA!Svefdrg=YfLTAP1G2Od*{np{lZTGy7+zo@~ zz6*3L(nBF-O;3|ZaL)VYslmQVcYC_b;X8Eo>cdFsOELm=Rmg2IjCUwBkpr+An5$KM zO-yb5h{~+W5fZX-V@BUO;?=vh;gO4!#813_bJiJo-mflhgh|_1?DClD!Y5C5E>@m7G}SkSR13ue57GS2m~&T<^s( zI>nR6adwXoPbI?l5iyC(c{B7Uf$mw4D#EB68ukaIo%FAo!5wlf_y&&m#Bt<&EU%5_wy8J=#tn=q-^U;X*EGFHQ{Sc_ zt`hV25VEidMhy*M;GKchKw&CUYwPZFU$5}yw!>67dBMmQ?R{+1!_|iZ?v z)R5rTJw73~wt~be)i>99s`6%NV8;hv1LJ1&84Q0c;&*$587=7g82({Ydu{iGMW1x` zC6d0YK~;?Kf3Tb7bLobgV3CVI;+G89z}XhT>4xw*W5K+TJEXouW5)cR3nf-w{O&3I z+w#fEa1X*!HYnyurVAV1>OJ6?V5czX_-NQMV?;Sd_snYQ(5)kx9)?*r z0k;FerdX~&aN7}by$FMlwWE~-IL+n2BIEby7i{VtkjL@pe!;AHhEo5=m2lK&WwO}_ zt#`yRQ`=gJ18~qARM?RQEtdKnMLj(CYVjJb^`5~<2*CaXj&#{cP%KB(t~8jdo?9B5 zTlg@Se<>5@e1X9v5)vn}`l-MQugVshMUX2s=WhdVb zfuZcBD=8E`5=tRwpJvobav-2uWKJog>Qr4AT=04o?M~uwU#1GnwKU@?TFIx@byPP* zc*P`!@TbZseGTeQA{nAh2wy*_TKjZ!$WoYqs^5h&dDeMkW)3TLDep}BbIQ90Qiz)$ zD~Gl1OjO$BIzMHUm=aXGP$Gj@eW09$Teb@tM6Eu{E09$f-?$Dt|QNo zTTRF07)i(BoKydje+7>G%Nu^g2)r-rv;%D>kE8gl%ejIyTJzy`2^CQv^A0O_ZBWaZ zFJ>ByP4qF8KmouH;}8el7- z_xf;plqcCutTYrat_FrP%9Efl)3!(Ab5mP3+YUjt#s-e>T@}7wQB|H5{Rn~>m#any zG)%MoxWazSvGVO^F`KhK9&vg9BZSnA;WL)}(T^xeL>%5Z zygk`o%b1oy#2?2tpB@mn;^9}b{W`b?Qxu=Cc4d_-`ewf@l59&Kx4}wI@kdVceEat^ zBe5$mMmA!;!RE}V;%(w2BqTvph#a`!e6n@vyNq;t;KZOj(|gOXLRaoy)jt=rNOxPW zz(TV*P%ZyLH%6`|i9x!>f~KX6z4Vuf6Y$O>;JDU~vf?x|6q#3-l_&B>EFZV&H!#J^ z4B3NCO>`Er>Q;mPqnhKz_F;PHBr`H#GK=Eg@suH^Z3hMF|R{4_lCrI;m1Q zPmnSr^@{V-bd5PJXQ(K~gQcfB@y@cRqy!osOsiS;^o975vtOMby*H z0ncuuRG;7tYsDn}>23^r6DFzceWK4j#;uI6i-%dw#d4KDA}2P7z^AFe#)hR$c+H=Z zA0^IIyx+v?dgVojwWh~x9DNtHf=2f1Yu%WxB5K@{>roC=F2F})Q+EwBx{4J_lzyR?W|nhCE^cEg!Ak7Gj4hdS0SYN z?^37wBxG!`)DUwTJ#feo+DT#zm>%3JZC(MQ&dWH@Gk%_)~ z2x;2y6(7cR=U3|tXr({scdX#1>C5w2z2+KtFJ_8LUHm2CVd&Chs_QC1pOF)lfY z(N?>TR1cPk47_oRCihl$T2ajT4)Ft)O|0qW6Fcqq7Kzd~EY3v8c~zfCg-asxo{N5V z#YirPghKFibnPt0CL?+sZXUr2XqKbedZ9}Jma7An|EXN@-FKVl+1VTZh(_WXNUV0z=?=TDR?dqjw;@ z7AXOet4v~iSB74W|hGcPTc%NKIx$m3NJR>LMo^se+w#ies9Y#&8 zE}Ly|3N5bcmTSu0}L9L+%rne*U^oA1F&7f zgAEO)U5NBgs^Bsda>mIf$x&R3PMLfZCwNs_p!xFhy29%qGTbw_m8L9LTGcPEJHC&t z=%I*W=n%IT`@Gl9-1#}z{F$TKy}^VJhBtNNc*K?$U*3I=t!hN_HB=0?*g$UN{R;=?I#YSNsZ zW^(fp28B7yc!|HAI<&IlW{fgu3o@3gfSjy<<$l3lCI~TQ^(+m)hst*&+9Vs~!Ctt> z_}49$Cb_j7Qv`!Gvam#Y`vr+cMM}o(@E9y5bN^ue|j~g(H(1VOZ?L)2X_T3!8%y-@!|3t?Hqxd6`R0li(mN$)|4rPY$O}kkvu2x}mR4i* zHs4mXgqyncc&Av5=DGNjpPb@*??v)jFsUh#;G<>RvpVT3MJIh(8rJO3oEfJpH7Y}@uZZu!UYB9kr|e<; z;5%64Mc_U&m9SY5H>2k&eI011EE<_m00&IEAVrx0ts0 z8n-P|6WR0~%-8@Ls=UaS*L@%86@-IuTa&79KW!rGSi8XN5`g6vBymEuP&B5GU!!#G ztKIQDl#_&vuwFpcJ_npQz88@qSTsRC;%pi$#UoqvhI&r29OniX z)Xauaf3!k2>fvUe%XxZ&v=0=RvZpO@O0Qsxp6m|F|EO|I_U}0#>>K zj&#Cv)|b@IEtY4Zz?Yg1F#AeXQl&9Ik~6F81gEyTt&2e!bD0?ruH&Vq7=XlSoVH1o@+=jn& zz19wC#Qntp_6Cg`^<%AKD(rx)z_y-b?{K0Un2Wm%tw_{?(w%SS5OyS4SVX;c>r%HP zq$O|>9XTf2IycU~YUqKSO^sagt zC+E5lZi|!GRZGq7$n|t>g_Xf5SD^%xS!T4D7Vgz9TU=WXz9HJP+Vt}pNRhJB_Ns4{ zCbDpDzw;fMZyB0haoVmbVT&)0(P0!l^W+}cmJQW?vU0(k_5{<1C_!~w7bCq{*l|JG z)H;{Kq~75T9Gnntq12sV+fGcGYtL%#ItO_Yj|P()rQT@BY87TgA@RoT6lFZE)YODf zHm&IMk((yQ9!FlGDy2xO=ol?Sh(-Qjh6+ZOI>SU z=CoR#g}%#~3U0+~(-%TA8|EG;GwD;mk!3O0ml)QRXLob&dYK-NSeeXPQPu_gPkGno z7&+An@&lcV#kfmC7R#BdXQnI9O=wu5j%@|A3w{#WdQm)I+izbMn^w;ht?u>yWC#-L zy4EKtnETZJswJ&L{fJtt)GgG@C2lZ$11zlyw>$&eu;BXJ8p9B%*KDCVN159a@ObXT@j|I}Hc<;w;F?3$LS=Sn7}KE=9a_Z>AAVqEdOmo2_zd`frGO{5jsDr9*T?usclSuA}_ZWbr5emCL2@=&Be z0_`!}BLl%CVYQiuk$mu3G&4#jaF_~+dv50m>9fH_TLew%nQWUdcoY)F-ZDM?J|kp( z4+|?JjWMonni4OVT+g}Do;JT}ViAaC`JB=;UJFiP@nr$wyVU^VoVo$w2R5@xFW5gd zXRrA;TBV7R(kkGIXeJg(s!S(3wB1G2Aet1FqAh_by)#01o-_H>SraC@4Ekh_zKa9& zi%b6SO*VKbwf!@9riNZ6zsy3W_#^t z;weoY$DVpbDN@M~lVJHqt^j$}dQZv?lh+2;`K>kdtP=Ry+R_#T1;HR<{nOnv(A9>c z?^q@(>R6+LyJ=$K%Ph)urE>ev7Y?JUzp%<~jw>-Gma!xhCNMLTesF%g%-oZ#L+3GH z?XAfmzWUQqfdQzW!E3jUMjGMNa#lqjyT|YG%ym}o&dhz3f+6GXXABX9y?}f*@WOCG zoZB7;JX@K;eVkCEul|1sCWz?>(-RdF*K5dUkF~PdSN$$BW|f2-oG@ zydm!5u8c9Oszibnou1_l>1&+1NtJUu`1203`HV=Ec?|I9$@NhnXG7KZ>J_6j+D}-vyJhzo)M3<6?^=K(`79+YOcpb zGKA~ANLg@~*}d0r+lajFm2Mwrr1*R4vC{$OKN$h!jGQMf&Nde(vjJV0?+0DsA=U7d(`8D2=n3>#c{L*~Wlj^mEq8>6k zN4*U3Z4p78)GLy^cD3OsxJmuEA1Q)U6{{CXzMR%RgJcd@!+ROG1~6E|F)wB27iVS%ejib306ww3rA{tlTtI{9LYldN7*Uwi+Tssw_Q= z6(@UGcGv?({pu(Dq{cE8;g<21ekRT>Z=}Mq1}da7-rpH-_sNZ_JN=EiL@f&{#7tkZ*&BZlZvTI5*R^N(NFl#h_mq6oJR zyj58lc&)QH_cFgBvF_T=XMDj{Dpd7H>f$AYZr!a4q9?a-g6>_FZ)@d>$Rrx74fhY1pON=}~92YH;RFL^Ky1%j%Z`bA8X>XF02m@NZY*hjx{buCd^`N%5TRxpGo#L%3 z0&xA<+C32wN%kV=1z(2a7NqL6DzJti%AE+u3=}`F5U_iq@_FLxK5dLbalH=vB-d6W zZ!X+tG>!`J*GRB7w?$q%;dO`R5;?W;Aq_;Fv_{qV?0JQ!>c#FFw%zGL#HS?Ly`*ZL zdR;LmI#{!i+{iRKO)oGS8{b7PXu<9fmc9&s!^}yru~URZd4-VdOIK<4*_*ct)m;YP zE+FD=&u)HFVtlu~l^(`P(w50;Bq215I!_wBvt9-mF`Oj(@p*zEv*|CzH3Axt6NUc&!SZ92< z(6h${MoTI!K{QwxR*|p?r!7vpLNJzEo>7>MNv?veF#W~ud#9b7tzpuE=I2ddpGQAZ z<5}?Zd08~*SU1~rZ?Au>ftDrCPpXN=!eM0kP94|i*x1KCS0~O>^*)=fk63+A%Tsw| zA+IXKiDuIIL^$G{>V0-|d-vsv`%A?;Pl*uU4s&QYDr%ycs$wmK&f zVVq`zz%8|TZU7O-Vlvhop8Rfnk4f?gU8WuQOs^GMtco&f6jTp_t@2QlXVFiKpT4E9 zi*v$Zlj*xVd2=Q6$?Irx3m5J1sF}cVPg|bYwcZymkZf~x+SgC>5)+?@R#Cbsm;u|y zqLfdlP@rz(U!shS8{3N~PAGGo$f`Bk6om;v!(We5qm#0cEu4RR`H1rG^&j^MHTv5K^{Vw7xTOJ#=dHqM)X?B#>{HEg|o)IRMxqRYy-yahOLvUBQrt1 zN&DTipO9;JPcv+O{8IC=NFZDV6Nj@`+?c!FuZBrL zc>4LNCLL87^34PkB3rMDt*ewX?4{4s2~>F#U&+V650Ru_VK=K-!Dq#^cr?YWmWTYD zE~u}HhD(#5tX8=tAbhen`r;h(;Nw8kbA;)R^0nKN3?{bRWoK;4h-hL_KV8pNEF!l} zJf+`dBtP|%pG0dlE4RKx+hkr>ElC)W?V+Uo;O&j_@!KVW12aRgQjckzxrZ$D0IusvlaDvsFlxr3)bj$g_EO7<9Vp%t`0umfN$eYU6l_?&EZ7JQ0)h z9Jv{LnBI?0dNEOX+<(JOkE*1RAjW8*;z5(t(el283^ysc6VCK(%o~2LS*p8?j6#E? zN;o_!j*ZMdvMqEObU`j73~}twgyxdL6%>yeEn*;od6$ zFkj1)La&ut>&fA}AK6X9Hcc(I`mEl@H5=2u=@_mn=`bANM$z9?&!55%=#+ssC2vN^ zV9DN%WelvxnIwpNI{TSHmlthL+<8mVpb37u*1C6aafr^0Che}=BTCV-Q&Y}4X6P+t ze$nav52a&75O)kNFjcn*$r_N0DAqGN%anR&INfGPx+JP5wjnq)_2fEzS)j$NAdOWq zY6sCw{@$b1Q8QDunlkc-GD+p@uc;O->LY1S*=sX%IGqy5X7`~Y4BJ?Jp80sd_)Br0 z%cuF*xH0*#+A|B*4K5*LG-09l@-nsHt%OZaSYvy^^3uv^ai6_$=IZSbr8Ut(^cR%y z`0X70r8mj4L@2JR`<+X6=?EOjWfL4}zI46EG_P7%JIEUDDq)7SS%Jqhgt}b8mD=65 zG3%Zg)G@3#I9NOfSmoXu5L+diBBO4u29}>P`>^Uik2-~t zZZQHsrZ&(=CrLMGkAthuk|D)tbK5lTj<&~!ZRUCH1Qy8zH;1w<%dzZUTWnpzHlnk9 zy;>InYp*_-k}qSjshxa&kUaBVkF+5QQm&lS$V{{ zsdEUsAGv2X)X2JJR0Y&8;p3|}NQPah!FjUzQ1y{Qsf>i~M7?*lzOZwwCJP=VpI;Fp zoIAhIBVNtiYa+BRbvb3(!*ao7zPpdgOXD&NqzOf?ZX`Szj9{J&fA&<_)pxn2yyfMG zFUccq178HPObyI#u}yoqrNQ&gEyIaj=vLbhF-k#2`|%d991@*)Es=b}74 z3Xxac2^I7id<8KLW@n_tPBxcROHa)yDwt)%vTHOK7updT8=jPwQS9CF%_mru z33aVizO?-5z`l}l5QM98jGeXu(Yz!068N{M9ukDx*jd{c+BujS+ABH9bxF}l(n`oE zh(A(Zm7$gDno->B>N&|Ago%uTh1{8o9Fi;DiJ71ygc*#C98%e?7!=5|zHWiCAzj%Y z^j_)=x01zrQ2z${8T2R?#f`{yd;9hEz)JKWN#+6cC@Ie(c_JM`9rufK)-?;Ok$M7I5uW&dLcFc2-IAmp3A2Q>i?@NOw40T7z zr~eWY839=dQ4u9&dKuCE7GPi?tGz!y0r?IJ3*R3IuoQSVA0$U08{6;d;ZJ}p=)fl| zzklLeI`-QSV*L2rR~ciVKe(UA{TlfqR0AzPZ{R=zx8D+^LjT`~!4KsB{R1NP37`as z)Zb!QVblU=^y8-AM{Cw zZ4cT;h`{YLf2$O5R?qJmCjHUtuVZNTr-r}pDE(cFkaE_y2cn3aKeYI*sJq`D0!$om zWz}#x?iQekrbByp3Rnc~{Wk?jO9+X`Dv8iLxHuecfte`F)B|**5Pa?XWf+)ruRw51 z>VGZB$|-|34mSYNKDlhzJ&2FH4rVUq?*c)-rF(JU{9gO}-c;Ju9-OxEZ8O}#4nk%e zUEPFd_`t)T0!-nBYQGyy1HT*H{r11FupZfXcMuCAOYr?fTT*~!0kHU>u*3+DiFLH> zei)4M4V~a=Fnv1$<%vRpwUYcT7-Y(j)U*38-=8rRp3{?I0Rig)JD>$*A^$hbuREiU zj@(yf%)l<=0s%3A!xMoL@FAEP{%+);1^n#*Ldb&FmjO$e5?4VDQn;0Yua;DD0Q3&f>+ z1N$VTFMW&Se;}oMod<+DCd{A5Z7*BxH3}FvM*t`G1MBO!v4ZQM{|)YslpHs5>5Bt& z><2>!S-Jc1qqPgfB+Ble6Tm4*{4U5ryNB}9}2>Ig-{uT)`d#hNPx+pp5 zIUGfSP$P+tL2MHE$IIX@1BoBPfbZ#ETZYF$5x8y-?o-!y0BHKw28JRo;9sJqh86}# zVIj^W-eAxJAE?j(FcRA4_$-eD`yEaQtQHwsIs6V4BCMKmd_NUXCpH2&d8FC4Z#z2sv-U1q&}`5I8Bp_PH5fwC#s_U52xY4dYXi5cecDUeqIemv=3i+RU{5wQZs0NxQe z3IrLiA=zCNR3J|QaLs@w|2^qmj0ML5+UMfeO=qMkRyL4bgnHL4ertyiSY@sUbdRr1&_XDpvN6Ha6CF z4u%E*U(`^~!O;##{N1aPe*eW$-9rSgA%YJb1%7V;_&p)0KKPX#rw9~3gz(MB!BjG}w6QR}B53LW8O-k%OS=DC$e!Gv_rRqiZ3G64=LrzQL6az| z?KnMvuot3fIU^&m`S%y0DulJ;yKXNk0T?H6z3fmTf9N&ZGbb z+zCK|!1f;#~V1Sjp3`0KMDp> zrO+Gy8Au^93IqYrBj>($9569MD{xw-g}kGkjkUcYFpQ&c5S@PDEbJ2pP~3nhAmaY- zN%u0|JPsV7KO5_h7(l`ba)zfKBre{U`6xa_+_l@t8Nr~+u?5mJ==Apz%!$8D0Ng-? z4Df%1U;LyD z1?+$uxB!wZ=-e?Cyd?d1nGZy8SyO8u`wt`ix!fb+9C)xmW)VERbw1uXu49Rg|_9=6~1CR8A?!)=sL%N z+_yt0Z~A*fglK!kDJ5c=00t%w3@NnCX}bT`fdh`<=m0}x=A~5=ya@bGBl?l_{MKa@lEJQHYrvMSHIG9qPeQxdD;{XC68AAsX>t9ss zc)J!HoPa9LL9z^OEWDsP`Sme0 z-^|Io4kQT!DBwVEP|JcIHIwXrf%>B(NE=)9kOgujfo&eb|B(a|N+y*53*bT5ca$d( zZJM38reFnjNQngl!w-chUH`X;-zSxCml%qIQm^%|LS-k_N!i!H`*Z>e)PO>J+3~k% zUsv}Jm_DdJeBHkf(gFbsV{1E82NTOb%-WBA+#&}+Hy(m+K(m&k`&iu&20IOYBnZC` z6tY=+YNY@q7jOd5bGUWyu^_ezc%ybb~tc;5?~Do z+HS7{_Whk#`bx6{A}cvsTI&6Z*T{qgQ5-NNM3;0e>CEk6s10(*Pb}LqvqK zqIb*xigv&?{VI&_A?d#=1YrGv^Mx)kJzF~-EC{Tveo;Aa;^^dO0w8z*L<~wcwGYPv zk+5>ovoJOID-(&OlH=?IOCxN6p3tC6o5un@z?TCG{kcs%VUtk90#Z^QDU1>z!u}&k zzuE-pukCO=AKqsMc%jTAjxQGFUorpl1wR)vsc(;*1DFLZD0M+Qz6r3x@o%>HO-y+a zMHz{&p6BPt22Wn1kO3;$03{1TQOOhQSjftHHU}?^`IUWSb$=G*0F(DMPcPk$#=d2 z{VEw6L)K}<4fTGRHnbKdih%6fL+R^xtA$MDq@xJ3yHr>XRZS4=n=j*0V=BF#}Y zL1YsZ$@PU?)3pV33%v%_EOJcD|5SPu2@-JP59d`j1KxfHyoHXvA|#H9^ds*4nu&d- z($68!I+r3c0M<@{s2VyKdII*@{GAK>K5)M(mOvyUEW*)S0%0^U^Wma1zv?kze#DeN zFBd`v%mNduVH$)tC18sS^x8Zk52DB9ZVb$P!y4Pmh zzd-&u>$)8gd&Lz9DGHKHXjj4&|M!Rxrwv(x{dJ_clR7;CIcDfSFg5`w$&ge29%o;f zznLN+iZs)dD--~5Cjp!w6x?{~-@|>|wJZn<0nC5!CC-SgUUI-|?E;Ssz0P|x{U7nZ z<&xHR2gi`~=XD*3ft<%R#&974n>4^;iyV~1yjlN`Jvi#uAnF$BY^x{$l}bjo!*w*0 z&i@how`K~#)+sAPQUW0z0q{Z4$pGKNaj}IIg?=ue;|_ z0^yF`0Sjw=bERJ{cIVK3YJ@B$WB^&A*9S8$9UBT_p}(0tC@>|c>}S^cmt8ZH6W!baIw(Q%raO>{N1#5a76z@{*8>>Mt3Yo z08$vpF=U|ZpM&WikoILf=zoq1385|1@J>b=aJJ2Wy3k2$3(Ma_|M#v1C@M2EGJ@Gs z4{TL(CH=`_ECe*=BxBPKBt``93_!==J(vF(bYJQ}j;sagMJgMh??Av`1!#SPZOnf= zvOk1YHnjY@^em(YE(NtR{uU|-+L;;{|6(Oh%NRwj80Z{~?ICy^f#btVSjiY#f?DZc z!}su^*o*?{3Bd@6KuOOjbbNSu=pp|(%XaYlJcxj@DS)pRgo1Pw{b$JE7}R4~ya+fT zVl*%)XlJ|$URC^m9N?d2@eqc;AXVLS0YfZy#H`F^kKchqI{p=Cio&^7KcHn|P$Pww zT3r60LHEt-&(7ra7b6j4pmyyewGw{S<9FcChIFsVT_PE1`7FSLj@(Xb93StymiGld z;75L@a>yJ(k%#g&8b~}3)DB%l#nt-z9(=v{eINJtiiW_BmYOn!0%~o7sR?=q2Ikd& zhCLweQ7eX^9=_N9harP4O4pBx`U~5In9kw*zV}g74gVfxUz>jv>+qe>`+#Z2e*paB zO%Mmbq3?q@yzS)ht-t%75Hi|PI8N)}%832@yg>{KNrQhsM2GJP*+;Ir_0Px$Yc#)yKYTmJK0LqIG2x-^ z$~er#!#5S|<6QLlJ&xn=?=3h81R>(#!{hgX-uwOy5Y$ofhZ{e9X7_&MqXB=@`1ga7 zzaNr(xb?#aFYmW*8+?q`4;;gM5CKB-!{-9;Bd`L;|GNn0+bDeJ)i3-k1mW-*k^2aN zV5j|`5q{iH@w?gT=&5?39{2q@2eY@Q5_@w0rQsh3`t2XTaQOT`;vb&{Z&mN@c^~~S z==IS9{(jva3sigcf7PD;w}S%@9{BeI;O9sF{lG}~!iYN}?N2&<1mODtfCm}!vr|p> hapKbc8E5~D6L~3k5L|%u1Mr`dFbs@gI*2!5{tv{HN>Bg* literal 0 HcmV?d00001 diff --git a/100_core/src/gplx/Exc.java b/100_core/src/gplx/Exc.java new file mode 100644 index 000000000..0ed977a27 --- /dev/null +++ b/100_core/src/gplx/Exc.java @@ -0,0 +1,70 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Exc extends RuntimeException { + private final String stack; + private Exc_msg[] msgs_ary = new Exc_msg[8]; private int msgs_len = 8, msgs_idx = 0; + public Exc(String stack, String type, String msg, Object... args) { + Msgs_add(type, msg, args); + this.stack = stack; + } + public int Stack_erase() {return stack_erase;} public Exc Stack_erase_1_() {stack_erase = 1; return this;} private int stack_erase = 0; + public Exc Args_add(Object... args) {msgs_ary[msgs_idx - 1].Args_add(args); return this;} // i - 1 to get current + @gplx.Internal protected boolean Type_match(String type) { + for (int i = 0; i < msgs_len; ++i) { + if (String_.Eq(type, msgs_ary[i].Type())) return true; + } + return false; + } + @gplx.Internal protected void Msgs_add(String type, String msg, Object[] args) { + if (msgs_idx == msgs_len) { + int new_len = msgs_len * 2; + Exc_msg[] new_ary = new Exc_msg[new_len]; + Array_.CopyTo(msgs_ary, new_ary, 0); + this.msgs_ary = new_ary; + this.msgs_len = new_len; + } + msgs_ary[msgs_idx] = new Exc_msg(type, msg, args); + ++msgs_idx; + } + public String To_str_all() { + String rv = ""; + for (int i = msgs_idx - 1; i > -1; --i) { + rv += "[err " + Int_.Xto_str(i) + "] " + msgs_ary[i].To_str() + "\n"; + } + rv += "[stack]\n " + Stack_to_str(this, stack); + return rv; + } + @Override public String getMessage() {return To_str_all();} + private static String Stack_to_str(Exception e, String stack) { + String rv = stack; + if (rv == Exc_.Stack_null) { // occurs for thrown gplx exceptions; EX: throw Exc_.new_unimplemented + rv = ""; // set to "" b/c String concat below; + String[] lines = String_.Split_lang(Exc_.Stack_lang(e), '\n'); + int len = lines.length; + for (int i = 0; i < len; ++i) { + String line = lines[i]; + if (String_.Has_at_bgn(line, "gplx.Exc_.new")) continue; // ignore stack frames with "gplx.Exc_.new"; EX: throw Exc_.new_unimplemented + if (String_.Len(rv) > 0) rv += "\n"; + rv += line; + } + } + rv = String_.Replace(rv, "\n", "\n "); // " " is to indent stack stack + return rv; + } +} diff --git a/100_core/src/gplx/Exc_.java b/100_core/src/gplx/Exc_.java new file mode 100644 index 000000000..710bba32b --- /dev/null +++ b/100_core/src/gplx/Exc_.java @@ -0,0 +1,67 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Exc_ { + private static String Type__none = ""; @gplx.Internal protected static String Stack_null = null; + public static final String Type__op_canceled = "gplx.op_canceled"; + public static void Noop(Exception e) {} + public static Exc as_(Object obj) {return obj instanceof Exc ? (Exc)obj : null;} + public static Exc new_(String msg, Object... args) {return new Exc(Stack_null, Type__none, msg, args);} + public static Exc new_w_type(String type, String msg, Object... args) {return new Exc(Stack_null, type, msg, args);} + public static Exc new_exc(Exception e, String type, String msg, Object... args) { + Exc rv = ClassAdp_.Eq_typeSafe(e, Exc.class) ? (Exc)e : new Exc(Exc_.Stack_lang(e), Type__none, Exc_.Message_lang(e)); + rv.Msgs_add(type, msg, args); + return rv; + } + public static Exc new_unhandled(Object val) {return new Exc(Stack_null, Type__none, "val is not in switch/if", "val", val);} + public static Exc new_unimplemented() {return new Exc(Stack_null, Type__none, "method not implemented");} + public static Exc new_unimplemented_w_msg(String msg, Object... args) {return new Exc(Stack_null, Type__none, msg, args);} + public static Exc new_deprecated(String s) {return new Exc(Stack_null, Type__none, "deprecated", "method", s);} + public static Exc new_parse_type(Class c, String raw) {return new_parse(ClassAdp_.FullNameOf_type(c), raw);} + public static Exc new_parse_exc(Exception e, Class c, String raw) {return new_parse(ClassAdp_.FullNameOf_type(c), raw).Args_add("e", Err_.Message_lang(e));} + public static Exc new_parse(String type, String raw) {return new Exc(Stack_null, Type__none, "parse failed", "type", type, "raw", raw);} + public static Exc new_null(String s) {return new Exc(Stack_null, Type__none, "null obj", "obj", s);} + public static Exc new_missing_idx(int idx, int len) {return new Exc(Stack_null, Type__none, "index is out of bounds", "idx", idx, "len", len);} + public static Exc new_missing_key(String key) {return new Exc(Stack_null, Type__none, "key not found", "key", key);} + public static Exc new_invalid_op(String msg) {return new Exc(Stack_null, Type__none, msg);} + public static Exc new_op_canceled() {return new Exc(Stack_null, Type__op_canceled, "canceled by usr");} + public static Exc new_type_mismatch_w_exc(Exception ignore, Class t, Object o) {return new_type_mismatch(t, o);} + public static Exc new_type_mismatch(Class t, Object o) {return new Exc(Stack_null, Type__none, "type mismatch", "expdType", ClassAdp_.FullNameOf_type(t), "actlType", ClassAdp_.NameOf_obj(o), "actlObj", Object_.Xto_str_strict_or_null_mark(o));} + public static Exc new_cast(Exception ignore, Class t, Object o) { + String o_str = ""; + try {o_str = Object_.Xto_str_strict_or_null_mark(o);} + catch (Exception e) {o_str = ""; Exc_.Noop(e);} + return new Exc(Stack_null, Type__none, "cast failed", "type", ClassAdp_.NameOf_type(t), "obj", o_str); + } + + public static String Message_lang(Exception e) {return e.getMessage();} + public static String Stack_lang(Exception e) { + String rv = ""; + StackTraceElement[] ary = e.getStackTrace(); + int len = ary.length; + for (int i = 0; i < len; i++) { + if (i != 0) rv += "\n"; + rv += ary[i].toString(); + } + return rv; + } + public static boolean Type_match(Exception e, String type) { + Exc exc = Exc_.as_(e); + return exc == null ? false : exc.Type_match(type); + } +} diff --git a/100_core/src/gplx/Exc_msg.java b/100_core/src/gplx/Exc_msg.java new file mode 100644 index 000000000..adb8e721a --- /dev/null +++ b/100_core/src/gplx/Exc_msg.java @@ -0,0 +1,44 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +class Exc_msg { + private final String msg; private Object[] args; + public Exc_msg(String type, String msg, Object[] args) { + this.type = type; + this.msg = msg; + this.args = args; + } + public String Type() {return type;} private final String type; + public void Args_add(Object[] add) { + this.args = (Object[])Array_.Resize_add(args, add); + } + public String To_str() { + String rv = String_.Len_eq_0(type) ? "" : "[" + type + "] "; + rv += msg; + int len = args.length; + if (len > 0) { + rv += ":"; + for (int i = 0; i < len; i += 2) { + Object key = args[i]; + Object val = i < len ? args[i + 1] : "MISSING_VAL"; + rv += " " + Object_.Xto_str_strict_or_null_mark(key) + "=" + Object_.Xto_str_strict_or_null_mark(val); + } + } + return rv; + } +} diff --git a/100_core/src/gplx/core/brys/Bry_rdr.java b/100_core/src/gplx/core/brys/Bry_rdr.java new file mode 100644 index 000000000..7aabed2fc --- /dev/null +++ b/100_core/src/gplx/core/brys/Bry_rdr.java @@ -0,0 +1,155 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.brys; import gplx.*; import gplx.core.*; +public class Bry_rdr { + public byte[] Src() {return src;} protected byte[] src; + public int Src_len() {return src_len;} protected int src_len; + public void Init(byte[] src) {this.Init(src, 0);} + public void Init(byte[] src, int pos) { + this.src = src; this.src_len = src.length; this.pos = pos; + } + public int Pos() {return pos;} public Bry_rdr Pos_(int v) {this.pos = v; return this;} protected int pos; + public void Pos_add(int v) {pos += v;} + public boolean Pos_is_eos() {return pos == src_len;} + public void Pos_add_one() {++pos;} + public int Or_int() {return or_int;} public void Or_int_(int v) {or_int = v;} private int or_int = Int_.MinValue; + public byte[] Or_bry() {return or_bry;} public void Or_bry_(byte[] v) {or_bry = v;} private byte[] or_bry; + public int Find_fwd(byte find) {return Bry_finder.Find_fwd(src, find, pos);} + public int Find_fwd_ws() {return Bry_finder.Find_fwd_until_ws(src, pos, src_len);} + public int Find_fwd__pos_at_lhs(byte[] find_bry) {return Find_fwd__pos_at(find_bry, Bool_.N);} + public int Find_fwd__pos_at_rhs(byte[] find_bry) {return Find_fwd__pos_at(find_bry, Bool_.Y);} + public int Find_fwd__pos_at(byte[] find_bry, boolean pos_at_rhs) { + int find_pos = Bry_finder.Find_fwd(src, find_bry, pos, src_len); + if (pos_at_rhs) find_pos += find_bry.length; + if (find_pos != Bry_finder.Not_found) pos = find_pos; + return find_pos; + } + public int Read_int_to_semic() {return Read_int_to(Byte_ascii.Semic);} + public int Read_int_to_comma() {return Read_int_to(Byte_ascii.Comma);} + public int Read_int_to_pipe() {return Read_int_to(Byte_ascii.Pipe);} + public int Read_int_to_nl() {return Read_int_to(Byte_ascii.Nl);} + public int Read_int_to_quote() {return Read_int_to(Byte_ascii.Quote);} + public int Read_int_to_non_num(){return Read_int_to(Byte_ascii.Nil);} + public int Read_int_to(byte to_char) { + int bgn = pos; + int rv = 0; + int negative = 1; + while (pos < src_len) { + byte b = src[pos++]; + switch (b) { + case Byte_ascii.Num_0: case Byte_ascii.Num_1: case Byte_ascii.Num_2: case Byte_ascii.Num_3: case Byte_ascii.Num_4: + case Byte_ascii.Num_5: case Byte_ascii.Num_6: case Byte_ascii.Num_7: case Byte_ascii.Num_8: case Byte_ascii.Num_9: + rv = (rv * 10) + (b - Byte_ascii.Num_0); + break; + case Byte_ascii.Dash: + if (negative == -1) // 2nd negative + return or_int; // return or_int + else // 1st negative + negative = -1; // flag negative + break; + default: { + boolean match = b == to_char; + if (to_char == Byte_ascii.Nil) {// hack for Read_int_to_non_num + --pos; + match = true; + } + return match ? rv * negative : or_int; + } + } + } + return bgn == pos ? or_int : rv * negative; + } + public byte[] Read_bry_to_nl() {return Read_bry_to(Byte_ascii.Nl);} + public byte[] Read_bry_to_semic() {return Read_bry_to(Byte_ascii.Semic);} + public byte[] Read_bry_to_pipe() {return Read_bry_to(Byte_ascii.Pipe);} + public byte[] Read_bry_to_quote() {return Read_bry_to(Byte_ascii.Quote);} + public byte[] Read_bry_to_apos() {return Read_bry_to(Byte_ascii.Apos);} + public byte[] Read_bry_to(byte to_char) { + int bgn = pos; + while (pos < src_len) { + byte b = src[pos]; + if (b == to_char) + return Bry_.Mid(src, bgn, pos++); + else + ++pos; + } + return bgn == pos ? or_bry : Bry_.Mid(src, bgn, src_len); + } + public boolean Read_yn_to_pipe() {return Read_byte_to_pipe() == Byte_ascii.Ltr_y;} + public byte Read_byte_to_pipe() { + byte rv = src[pos]; + pos += 2; // 1 for byte; 1 for pipe; + return rv; + } + public double Read_double_to_pipe() {return Read_double_to(Byte_ascii.Pipe);} + public double Read_double_to(byte to_char) { + byte[] double_bry = Read_bry_to(to_char); + return Double_.parse_(String_.new_a7(double_bry)); // double will never have utf8 + } + @gplx.Virtual public Bry_rdr Skip_ws() { + while (pos < src_len) { + switch (src[pos]) { + case Byte_ascii.Tab: case Byte_ascii.Nl: case Byte_ascii.Cr: case Byte_ascii.Space: + ++pos; + break; + default: + return this; + } + } + return this; + } + public Bry_rdr Skip_alpha_num_under() { + while (pos < src_len) { + switch (src[pos]) { + case Byte_ascii.Num_0: case Byte_ascii.Num_1: case Byte_ascii.Num_2: case Byte_ascii.Num_3: case Byte_ascii.Num_4: + case Byte_ascii.Num_5: case Byte_ascii.Num_6: case Byte_ascii.Num_7: case Byte_ascii.Num_8: case Byte_ascii.Num_9: + case Byte_ascii.Ltr_A: case Byte_ascii.Ltr_B: case Byte_ascii.Ltr_C: case Byte_ascii.Ltr_D: case Byte_ascii.Ltr_E: + case Byte_ascii.Ltr_F: case Byte_ascii.Ltr_G: case Byte_ascii.Ltr_H: case Byte_ascii.Ltr_I: case Byte_ascii.Ltr_J: + case Byte_ascii.Ltr_K: case Byte_ascii.Ltr_L: case Byte_ascii.Ltr_M: case Byte_ascii.Ltr_N: case Byte_ascii.Ltr_O: + case Byte_ascii.Ltr_P: case Byte_ascii.Ltr_Q: case Byte_ascii.Ltr_R: case Byte_ascii.Ltr_S: case Byte_ascii.Ltr_T: + case Byte_ascii.Ltr_U: case Byte_ascii.Ltr_V: case Byte_ascii.Ltr_W: case Byte_ascii.Ltr_X: case Byte_ascii.Ltr_Y: case Byte_ascii.Ltr_Z: + case Byte_ascii.Ltr_a: case Byte_ascii.Ltr_b: case Byte_ascii.Ltr_c: case Byte_ascii.Ltr_d: case Byte_ascii.Ltr_e: + case Byte_ascii.Ltr_f: case Byte_ascii.Ltr_g: case Byte_ascii.Ltr_h: case Byte_ascii.Ltr_i: case Byte_ascii.Ltr_j: + case Byte_ascii.Ltr_k: case Byte_ascii.Ltr_l: case Byte_ascii.Ltr_m: case Byte_ascii.Ltr_n: case Byte_ascii.Ltr_o: + case Byte_ascii.Ltr_p: case Byte_ascii.Ltr_q: case Byte_ascii.Ltr_r: case Byte_ascii.Ltr_s: case Byte_ascii.Ltr_t: + case Byte_ascii.Ltr_u: case Byte_ascii.Ltr_v: case Byte_ascii.Ltr_w: case Byte_ascii.Ltr_x: case Byte_ascii.Ltr_y: case Byte_ascii.Ltr_z: + case Byte_ascii.Underline: + ++pos; + break; + default: + return this; + } + } + return this; + } + public void Chk_bry_or_fail(byte[] bry) { + int bry_len = bry.length; + boolean match = Bry_.Match(src, pos, pos + bry_len, bry); + if (match) pos += bry_len; + else throw Exc_.new_("bry.rdr:chk failed", "bry", bry, "pos", pos); + } + public void Chk_byte_or_fail(byte b) { + boolean match = pos < src_len ? src[pos] == b : false; + if (match) ++pos; + else throw Exc_.new_("bry.rdr:chk failed", "byte", b, "pos", pos); + } + public byte[] Mid_by_len_safe(int len) { + int end = pos + len; if (end > src_len) end = src_len; + return Bry_.Mid(src, pos, end); + } +} \ No newline at end of file diff --git a/100_core/src/gplx/core/btries/Btrie_bwd_mgr.java b/100_core/src/gplx/core/btries/Btrie_bwd_mgr.java new file mode 100644 index 000000000..92b658c44 --- /dev/null +++ b/100_core/src/gplx/core/btries/Btrie_bwd_mgr.java @@ -0,0 +1,88 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.btries; import gplx.*; import gplx.core.*; +import gplx.core.primitives.*; +public class Btrie_bwd_mgr { + public int Match_pos() {return match_pos;} private int match_pos; + public Object Match_exact(byte[] src, int bgn_pos, int end_pos) { + Object rv = Match(src[bgn_pos], src, bgn_pos, end_pos); + return rv == null ? null : match_pos - bgn_pos == end_pos - bgn_pos ? rv : null; + } + public Object Match_bgn(byte[] src, int bgn_pos, int end_pos) {return Match(src[bgn_pos], src, bgn_pos, end_pos);} + public Object Match(byte b, byte[] src, int bgn_pos, int end_pos) { + // NOTE: bgn, end follows same semantics as fwd where bgn >= & end < except reversed: bgn <= & end >; EX: "abcde" should pass 5, -1 + Object rv = null; int cur_pos = match_pos = bgn_pos; + Btrie_slim_itm cur = root; + while (true) { + Btrie_slim_itm nxt = cur.Ary_find(b); if (nxt == null) return rv; // nxt does not hav b; return rv; + --cur_pos; + if (nxt.Ary_is_empty()) {match_pos = cur_pos; return nxt.Val();} // nxt is leaf; return nxt.Val() (which should be non-null) + Object nxt_val = nxt.Val(); + if (nxt_val != null) {match_pos = cur_pos; rv = nxt_val;} // nxt is node; cache rv (in case of false match) + if (cur_pos == end_pos) return rv; // increment cur_pos and exit if src_len + b = src[cur_pos]; + cur = nxt; + } + } + public Btrie_bwd_mgr Add_str_byte(String key, byte val) {return Add(Bry_.new_u8(key), Byte_obj_val.new_(val));} + public Btrie_bwd_mgr Add_byteVal_strAry(byte val, String... ary) { + int ary_len = ary.length; + Byte_obj_val byteVal = Byte_obj_val.new_(val); + for (int i = 0; i < ary_len; i++) { + String itm = ary[i]; + Add(Bry_.new_u8(itm), byteVal); + } + return this; + } + public Btrie_bwd_mgr Add(String key, Object val) {return Add(Bry_.new_u8(key), val);} + public Btrie_bwd_mgr Add(byte[] key, Object val) { + if (val == null) throw Exc_.new_("null objects cannot be registered", "key", String_.new_u8(key)); + int key_len = key.length; + Btrie_slim_itm cur = root; + for (int i = key_len - 1; i > -1; i--) { + byte b = key[i]; + if (root.Case_any() && (b > 64 && b < 91)) b += 32; + Btrie_slim_itm nxt = cur.Ary_find(b); + if (nxt == null) + nxt = cur.Ary_add(b, null); + if (i == 0) + nxt.Val_set(val); + cur = nxt; + } + count++; // FUTURE: do not increment if replacing value + return this; + } + public int Count() {return count;} private int count; + public void Del(byte[] key) { + int key_len = key.length; + Btrie_slim_itm cur = root; + for (int i = 0; i < key_len; i++) { + byte b = key[i]; + cur = cur.Ary_find(b); + if (cur == null) break; + cur.Ary_del(b); + } + count--; // FUTURE: do not decrement if not found + } + public void Clear() {root.Clear(); count = 0;} + public static Btrie_bwd_mgr cs_() {return new Btrie_bwd_mgr(false);} + public static Btrie_bwd_mgr ci_() {return new Btrie_bwd_mgr(true);} + public Btrie_bwd_mgr(boolean caseAny) { + root = new Btrie_slim_itm(Byte_.Zero, null, caseAny); + } private Btrie_slim_itm root; +} diff --git a/100_core/src/gplx/core/btries/Btrie_bwd_mgr_tst.java b/100_core/src/gplx/core/btries/Btrie_bwd_mgr_tst.java new file mode 100644 index 000000000..c017b4ff4 --- /dev/null +++ b/100_core/src/gplx/core/btries/Btrie_bwd_mgr_tst.java @@ -0,0 +1,87 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.btries; import gplx.*; import gplx.core.*; +import org.junit.*; +public class Btrie_bwd_mgr_tst { + @Before public void init() {} private Btrie_bwd_mgr trie; + private void ini_setup1() { + trie = new Btrie_bwd_mgr(false); + run_Add("c" , 1); + run_Add("abc" , 123); + } + @Test public void Get_by() { + ini_setup1(); + tst_MatchAtCur("c" , 1); + tst_MatchAtCur("abc" , 123); + tst_MatchAtCur("bc" , 1); + tst_MatchAtCur("yzabc" , 123); + tst_MatchAtCur("ab" , null); + } + @Test public void Fetch_intl() { + trie = new Btrie_bwd_mgr(false); + run_Add("a�", 1); + tst_MatchAtCur("a�" , 1); + tst_MatchAtCur("�" , null); + } + @Test public void Eos() { + ini_setup1(); + tst_Match("ab", Byte_ascii.Ltr_c, 2, 123); + } + @Test public void Match_exact() { + ini_setup1(); + tst_MatchAtCurExact("c", 1); + tst_MatchAtCurExact("bc", null); + tst_MatchAtCurExact("abc", 123); + } + private void ini_setup2() { + trie = new Btrie_bwd_mgr(false); + run_Add("a" , 1); + run_Add("b" , 2); + } + @Test public void Match_2() { + ini_setup2(); + tst_MatchAtCur("a", 1); + tst_MatchAtCur("b", 2); + } + private void ini_setup_caseAny() { + trie = Btrie_bwd_mgr.ci_(); + run_Add("a" , 1); + run_Add("b" , 2); + } + @Test public void CaseAny() { + ini_setup_caseAny(); + tst_MatchAtCur("a", 1); + tst_MatchAtCur("A", 1); + } + private void run_Add(String k, int val) {trie.Add(Bry_.new_u8(k), val);} + private void tst_Match(String srcStr, byte b, int bgn_pos, int expd) { + byte[] src = Bry_.new_u8(srcStr); + Object actl = trie.Match(b, src, bgn_pos, -1); + Tfds.Eq(expd, actl); + } + private void tst_MatchAtCur(String srcStr, Object expd) { + byte[] src = Bry_.new_u8(srcStr); + Object actl = trie.Match(src[src.length - 1], src, src.length - 1, -1); + Tfds.Eq(expd, actl); + } + private void tst_MatchAtCurExact(String srcStr, Object expd) { + byte[] src = Bry_.new_u8(srcStr); + Object actl = trie.Match_exact(src, src.length - 1, -1); + Tfds.Eq(expd, actl); + } +} diff --git a/100_core/src/gplx/core/btries/Btrie_fast_mgr.java b/100_core/src/gplx/core/btries/Btrie_fast_mgr.java new file mode 100644 index 000000000..f2675863f --- /dev/null +++ b/100_core/src/gplx/core/btries/Btrie_fast_mgr.java @@ -0,0 +1,156 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.btries; import gplx.*; import gplx.core.*; +import gplx.core.primitives.*; +public class Btrie_fast_mgr { + private ByteTrieItm_fast root; + public boolean CaseAny() {return root.CaseAny();} public Btrie_fast_mgr CaseAny_(boolean v) {root.CaseAny_(v); return this;} + public int Match_pos() {return match_pos;} private int match_pos; + public Object Match_exact(byte[] src, int bgn_pos, int end_pos) { + Object rv = Match_bgn_w_byte(src[bgn_pos], src, bgn_pos, end_pos); + return rv == null ? null : match_pos - bgn_pos == end_pos - bgn_pos ? rv : null; + } + public Object Match_bgn(byte[] src, int bgn_pos, int end_pos) {return Match_bgn_w_byte(src[bgn_pos], src, bgn_pos, end_pos);} + public Object Match_bgn_w_byte(byte b, byte[] src, int bgn_pos, int src_len) { + match_pos = bgn_pos; + ByteTrieItm_fast nxt = root.Ary_find(b); if (nxt == null) return null; // nxt does not have b; return rv; + Object rv = null; int cur_pos = bgn_pos + 1; + ByteTrieItm_fast cur = root; + while (true) { + if (nxt.Ary_is_empty()) {match_pos = cur_pos; return nxt.Val();} // nxt is leaf; return nxt.Val() (which should be non-null) + Object nxt_val = nxt.Val(); + if (nxt_val != null) {match_pos = cur_pos; rv = nxt_val;} // nxt is node; cache rv (in case of false match) + if (cur_pos == src_len) return rv; // eos; exit + b = src[cur_pos]; + cur = nxt; + nxt = cur.Ary_find(b); if (nxt == null) return rv; + ++cur_pos; + } + } + public Btrie_fast_mgr Add_bry_bval(byte key, byte val) {return Add(new byte[] {key}, Byte_obj_val.new_(val));} + public Btrie_fast_mgr Add_bry_bval(byte[] key, byte val) {return Add(key, Byte_obj_val.new_(val));} + public Btrie_fast_mgr Add_str_byte(String key, byte val) {return Add(Bry_.new_u8(key), Byte_obj_val.new_(val));} + public Btrie_fast_mgr Add(byte key, Object val) {return Add(new byte[] {key}, val);} + public Btrie_fast_mgr Add(String key, Object val) {return Add(Bry_.new_u8(key), val);} + public Btrie_fast_mgr Add(byte[] key, Object val) { + if (val == null) throw Exc_.new_("null objects cannot be registered", "key", String_.new_u8(key)); + int key_len = key.length; int key_end = key_len - 1; + ByteTrieItm_fast cur = root; + for (int i = 0; i < key_len; i++) { + byte b = key[i]; + ByteTrieItm_fast nxt = cur.Ary_find(b); + if (nxt == null) + nxt = cur.Ary_add(b, null); + if (i == key_end) + nxt.Val_set(val); + cur = nxt; + } + return this; + } + public Btrie_fast_mgr Add_stub(byte tid, String s) { + byte[] bry = Bry_.new_u8(s); + Btrie_itm_stub stub = new Btrie_itm_stub(tid, bry); + return Add(bry, stub); + } + public void Del(byte[] key) { + int key_len = key.length; + ByteTrieItm_fast cur = root; + for (int i = 0; i < key_len; i++) { + byte b = key[i]; + Object itm_obj = cur.Ary_find(b); + if (itm_obj == null) break; // b not found; no match; exit; + ByteTrieItm_fast itm = (ByteTrieItm_fast)itm_obj; + if (i == key_len - 1) { // last char + if (itm.Val() == null) break; // itm does not have val; EX: trie with "abc", and "ab" deleted + if (itm.Ary_is_empty()) + cur.Ary_del(b); + else + itm.Val_set(null); + } + else { // mid char; set itm as cur and continue + cur = itm; + } + } + } + public void Clear() {root.Clear();} + public byte[] Replace(Bry_bfr tmp_bfr, byte[] src, int bgn, int end) { + int pos = bgn; + boolean dirty = false; + while (pos < end) { + byte b = src[pos]; + Object o = this.Match_bgn_w_byte(b, src, pos, end); + if (o == null) { + if (dirty) + tmp_bfr.Add_byte(b); + pos++; + } + else { + if (!dirty) { + tmp_bfr.Add_mid(src, bgn, pos); + dirty = true; + } + tmp_bfr.Add((byte[])o); + pos = match_pos; + } + } + return dirty ? tmp_bfr.Xto_bry_and_clear() : src; + } + public static Btrie_fast_mgr cs_() {return new Btrie_fast_mgr(false);} + public static Btrie_fast_mgr ci_ascii_() {return new Btrie_fast_mgr(true);} + public static Btrie_fast_mgr new_(boolean case_any) {return new Btrie_fast_mgr(case_any);} + Btrie_fast_mgr(boolean caseAny) { + root = new ByteTrieItm_fast(Byte_.Zero, null, caseAny); + } +} +class ByteTrieItm_fast { + private ByteTrieItm_fast[] ary = new ByteTrieItm_fast[256]; + public byte Key_byte() {return key_byte;} private byte key_byte; + public Object Val() {return val;} public void Val_set(Object val) {this.val = val;} Object val; + public boolean Ary_is_empty() {return ary_is_empty;} private boolean ary_is_empty; + public boolean CaseAny() {return caseAny;} public ByteTrieItm_fast CaseAny_(boolean v) {caseAny = v; return this;} private boolean caseAny; + public void Clear() { + val = null; + for (int i = 0; i < 256; i++) { + if (ary[i] != null) { + ary[i].Clear(); + ary[i] = null; + } + } + ary_len = 0; + ary_is_empty = true; + } + public ByteTrieItm_fast Ary_find(byte b) { + int key_byte = (caseAny && (b > 64 && b < 91) ? b + 32 : b) & 0xff;// PATCH.JAVA:need to convert to unsigned byte + return ary[key_byte]; + } + public ByteTrieItm_fast Ary_add(byte b, Object val) { + int key_byte = (caseAny && (b > 64 && b < 91) ? b + 32 : b) & 0xff;// PATCH.JAVA:need to convert to unsigned byte + ByteTrieItm_fast rv = new ByteTrieItm_fast(b, val, caseAny); + ary[key_byte] = rv; + ++ary_len; + ary_is_empty = false; + return rv; + } + public void Ary_del(byte b) { + int key_byte = (caseAny && (b > 64 && b < 91) ? b + 32 : b) & 0xff;// PATCH.JAVA:need to convert to unsigned byte + ary[key_byte] = null; + --ary_len; + ary_is_empty = ary_len == 0; + } int ary_len = 0; + public ByteTrieItm_fast(byte key_byte, Object val, boolean caseAny) {this.key_byte = key_byte; this.val = val; this.caseAny = caseAny;} +} diff --git a/100_core/src/gplx/core/btries/Btrie_fast_mgr_tst.java b/100_core/src/gplx/core/btries/Btrie_fast_mgr_tst.java new file mode 100644 index 000000000..bbc521ae8 --- /dev/null +++ b/100_core/src/gplx/core/btries/Btrie_fast_mgr_tst.java @@ -0,0 +1,85 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.btries; import gplx.*; import gplx.core.*; +import org.junit.*; +public class Btrie_fast_mgr_tst { + private Btrie_fast_mgr_fxt fxt = new Btrie_fast_mgr_fxt(); + @Before public void init() {fxt.Clear();} + @Test public void Get_by() { + fxt.Test_matchAtCur("a" , 1); + fxt.Test_matchAtCur("abc" , 123); + fxt.Test_matchAtCur("ab" , 1); + fxt.Test_matchAtCur("abcde" , 123); + fxt.Test_matchAtCur(" a" , null); + } + @Test public void Bos() { + fxt.Test_match("bc", Byte_ascii.Ltr_a, -1, 123); + } + @Test public void Match_exact() { + fxt.Test_matchAtCurExact("a", 1); + fxt.Test_matchAtCurExact("ab", null); + fxt.Test_matchAtCurExact("abc", 123); + } + @Test public void Del_noop__no_match() { + fxt.Exec_del("d"); + fxt.Test_matchAtCurExact("a" , 1); + fxt.Test_matchAtCurExact("abc" , 123); + } + @Test public void Del_noop__partial_match() { + fxt.Exec_del("ab"); + fxt.Test_matchAtCurExact("a" , 1); + fxt.Test_matchAtCurExact("abc" , 123); + } + @Test public void Del_match__long() { + fxt.Exec_del("abc"); + fxt.Test_matchAtCurExact("a" , 1); + fxt.Test_matchAtCurExact("abc" , null); + } + @Test public void Del_match__short() { + fxt.Exec_del("a"); + fxt.Test_matchAtCurExact("a" , null); + fxt.Test_matchAtCurExact("abc" , 123); + } +} +class Btrie_fast_mgr_fxt { + private Btrie_fast_mgr trie; + public void Clear() { + trie = Btrie_fast_mgr.cs_(); + Init_add( 1 , Byte_ascii.Ltr_a); + Init_add(123 , Byte_ascii.Ltr_a, Byte_ascii.Ltr_b, Byte_ascii.Ltr_c); + } + public void Init_add(int val, byte... ary) {trie.Add(ary, val);} + public void Test_match(String src_str, byte b, int bgn_pos, int expd) { + byte[] src = Bry_.new_a7(src_str); + Object actl = trie.Match_bgn_w_byte(b, src, bgn_pos, src.length); + Tfds.Eq(expd, actl); + } + public void Test_matchAtCur(String src_str, Object expd) { + byte[] src = Bry_.new_a7(src_str); + Object actl = trie.Match_bgn(src, 0, src.length); + Tfds.Eq(expd, actl); + } + public void Test_matchAtCurExact(String src_str, Object expd) { + byte[] src = Bry_.new_a7(src_str); + Object actl = trie.Match_exact(src, 0, src.length); + Tfds.Eq(expd, actl); + } + public void Exec_del(String src_str) { + trie.Del(Bry_.new_u8(src_str)); + } +} diff --git a/100_core/src/gplx/core/btries/Btrie_itm_stub.java b/100_core/src/gplx/core/btries/Btrie_itm_stub.java new file mode 100644 index 000000000..54acfbda0 --- /dev/null +++ b/100_core/src/gplx/core/btries/Btrie_itm_stub.java @@ -0,0 +1,23 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.btries; import gplx.*; import gplx.core.*; +public class Btrie_itm_stub { + public Btrie_itm_stub(byte tid, byte[] val) {this.tid = tid; this.val = val;} + public byte Tid() {return tid;} private byte tid; + public byte[] Val() {return val;} private byte[] val; +} diff --git a/100_core/src/gplx/core/btries/Btrie_mgr.java b/100_core/src/gplx/core/btries/Btrie_mgr.java new file mode 100644 index 000000000..2fe6c6bf0 --- /dev/null +++ b/100_core/src/gplx/core/btries/Btrie_mgr.java @@ -0,0 +1,24 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.btries; import gplx.*; import gplx.core.*; +public interface Btrie_mgr { + int Match_pos(); + Object Match_bgn(byte[] src, int bgn_pos, int end_pos); + Btrie_mgr Add_obj(String key, Object val); + Btrie_mgr Add_obj(byte[] key, Object val); +} diff --git a/100_core/src/gplx/core/btries/Btrie_slim_itm.java b/100_core/src/gplx/core/btries/Btrie_slim_itm.java new file mode 100644 index 000000000..55559daa2 --- /dev/null +++ b/100_core/src/gplx/core/btries/Btrie_slim_itm.java @@ -0,0 +1,130 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.btries; import gplx.*; import gplx.core.*; +public class Btrie_slim_itm { + private Btrie_slim_itm[] ary = Btrie_slim_itm.Ary_empty; + public Btrie_slim_itm(byte key_byte, Object val, boolean case_any) {this.key_byte = key_byte; this.val = val; this.case_any = case_any;} + public byte Key_byte() {return key_byte;} private byte key_byte; + public Object Val() {return val;} public void Val_set(Object val) {this.val = val;} private Object val; + public boolean Case_any() {return case_any;} private boolean case_any; + public boolean Ary_is_empty() {return ary == Btrie_slim_itm.Ary_empty;} + public void Clear() { + val = null; + for (int i = 0; i < ary_len; i++) + ary[i].Clear(); + ary = Btrie_slim_itm.Ary_empty; + ary_len = ary_max = 0; + } + public Btrie_slim_itm Ary_find(byte b) { + int find_val = (case_any && (b > 64 && b < 91) ? b + 32 : b) & 0xff;// PATCH.JAVA:need to convert to unsigned byte + int key_val = 0; + switch (ary_len) { + case 0: return null; + case 1: + Btrie_slim_itm rv = ary[0]; + key_val = rv.Key_byte() & 0xff;// PATCH.JAVA:need to convert to unsigned byte; + key_val = (case_any && (key_val > 64 && key_val < 91) ? key_val + 32 : key_val); + return key_val == find_val ? rv : null; + default: + int adj = 1; + int prv_pos = 0; + int prv_len = ary_len; + int cur_len = 0; + int cur_idx = 0; + Btrie_slim_itm itm = null; + while (true) { + cur_len = prv_len / 2; + if (prv_len % 2 == 1) ++cur_len; + cur_idx = prv_pos + (cur_len * adj); + if (cur_idx < 0) cur_idx = 0; + else if (cur_idx >= ary_len) cur_idx = ary_len - 1; + itm = ary[cur_idx]; + key_val = itm.Key_byte() & 0xff; // PATCH.JAVA:need to convert to unsigned byte; + key_val = (case_any && (key_val > 64 && key_val < 91) ? key_val + 32 : key_val); + if (find_val < key_val) adj = -1; + else if (find_val > key_val) adj = 1; + else /*(find_val == cur_val)*/ return itm; + if (cur_len == 1) { + cur_idx += adj; + if (cur_idx < 0 || cur_idx >= ary_len) return null; + itm = ary[cur_idx]; + return (itm.Key_byte() & 0xff) == find_val ? itm : null; // PATCH.JAVA:need to convert to unsigned byte; + } + prv_len = cur_len; + prv_pos = cur_idx; + } + } + } + public Btrie_slim_itm Ary_add(byte b, Object val) { + int new_len = ary_len + 1; + if (new_len > ary_max) { + ary_max += 4; + ary = (Btrie_slim_itm[])Array_.Resize(ary, ary_max); + } + Btrie_slim_itm rv = new Btrie_slim_itm(b, val, case_any); + ary[ary_len] = rv; + ary_len = new_len; + ByteHashItm_sorter._.Sort(ary, ary_len); + return rv; + } + public void Ary_del(byte b) { + boolean found = false; + for (int i = 0; i < ary_len; i++) { + if (found) { + if (i < ary_len - 1) + ary[i] = ary[i + 1]; + } + else { + if (b == ary[i].Key_byte()) found = true; + } + } + if (found) --ary_len; + } + public static final Btrie_slim_itm[] Ary_empty = new Btrie_slim_itm[0]; int ary_len = 0, ary_max = 0; +} +class ByteHashItm_sorter {// quicksort + Btrie_slim_itm[] ary; int ary_len; + public void Sort(Btrie_slim_itm[] ary, int ary_len) { + if (ary == null || ary_len < 2) return; + this.ary = ary; + this.ary_len = ary_len; + Sort_recurse(0, ary_len - 1); + } + private void Sort_recurse(int lo, int hi) { + int i = lo, j = hi; + int mid = ary[lo + (hi-lo)/2].Key_byte()& 0xFF; // get mid itm + while (i <= j) { // divide into two lists + while ((ary[i].Key_byte() & 0xFF) < mid) // if lhs.cur < mid, then get next from lhs + i++; + while ((ary[j].Key_byte() & 0xFF) > mid) // if rhs.cur > mid, then get next from rhs + j--; + + // lhs.cur > mid && rhs.cur < mid; switch lhs.cur and rhs.cur; increase i and j + if (i <= j) { + Btrie_slim_itm tmp = ary[i]; + ary[i] = ary[j]; + ary[j] = tmp; + i++; + j--; + } + } + if (lo < j) Sort_recurse(lo, j); + if (i < hi) Sort_recurse(i, hi); + } + public static final ByteHashItm_sorter _ = new ByteHashItm_sorter(); ByteHashItm_sorter() {} +} diff --git a/100_core/src/gplx/core/btries/Btrie_slim_itm_tst.java b/100_core/src/gplx/core/btries/Btrie_slim_itm_tst.java new file mode 100644 index 000000000..472011704 --- /dev/null +++ b/100_core/src/gplx/core/btries/Btrie_slim_itm_tst.java @@ -0,0 +1,49 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.btries; import gplx.*; import gplx.core.*; +import org.junit.*; +public class Btrie_slim_itm_tst { + private Btrie_slim_itm itm = new Btrie_slim_itm(Byte_.Zero, null, false); + @Before public void init() {itm.Clear();} + @Test public void Find_nil() { + tst_Find(Byte_ascii.Ltr_a, null); + } + @Test public void Add_one() { + run_Add(Byte_ascii.Ltr_a); + tst_Find(Byte_ascii.Ltr_a, "a"); + } + @Test public void Add_many() { + run_Add(Byte_ascii.Bang, Byte_ascii.Num_0, Byte_ascii.Ltr_a, Byte_ascii.Ltr_B); + tst_Find(Byte_ascii.Ltr_a, "a"); + } + @Test public void Del() { + run_Add(Byte_ascii.Bang, Byte_ascii.Num_0, Byte_ascii.Ltr_a, Byte_ascii.Ltr_B); + tst_Find(Byte_ascii.Ltr_a, "a"); + run_Del(Byte_ascii.Ltr_a); + tst_Find(Byte_ascii.Ltr_a, null); + tst_Find(Byte_ascii.Num_0, "0"); + tst_Find(Byte_ascii.Ltr_B, "B"); + } + private void tst_Find(byte b, String expd) { + Btrie_slim_itm actl_itm = itm.Ary_find(b); + Object actl = actl_itm == null ? null : actl_itm.Val(); + Tfds.Eq(expd, actl); + } + private void run_Add(byte... ary) {for (byte b : ary) itm.Ary_add(b, Char_.XtoStr((char)b));} + private void run_Del(byte... ary) {for (byte b : ary) itm.Ary_del(b);} +} diff --git a/100_core/src/gplx/core/btries/Btrie_slim_mgr.java b/100_core/src/gplx/core/btries/Btrie_slim_mgr.java new file mode 100644 index 000000000..2840e58f3 --- /dev/null +++ b/100_core/src/gplx/core/btries/Btrie_slim_mgr.java @@ -0,0 +1,128 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.btries; import gplx.*; import gplx.core.*; +import gplx.core.primitives.*; +public class Btrie_slim_mgr implements Btrie_mgr { + Btrie_slim_mgr(boolean case_match) {root = new Btrie_slim_itm(Byte_.Zero, null, !case_match);} private Btrie_slim_itm root; + public int Count() {return count;} private int count; + public int Match_pos() {return match_pos;} private int match_pos; + public Object Match_exact(byte[] src, int bgn_pos, int end_pos) { + Object rv = Match_bgn_w_byte(src[bgn_pos], src, bgn_pos, end_pos); + return rv == null ? null : match_pos - bgn_pos == end_pos - bgn_pos ? rv : null; + } + public Object Match_bgn(byte[] src, int bgn_pos, int end_pos) {return Match_bgn_w_byte(src[bgn_pos], src, bgn_pos, end_pos);} + public Object Match_bgn_w_byte(byte b, byte[] src, int bgn_pos, int src_len) { + Object rv = null; int cur_pos = match_pos = bgn_pos; + Btrie_slim_itm cur = root; + while (true) { + Btrie_slim_itm nxt = cur.Ary_find(b); if (nxt == null) return rv; // nxt does not hav b; return rv; + ++cur_pos; + if (nxt.Ary_is_empty()) {match_pos = cur_pos; return nxt.Val();} // nxt is leaf; return nxt.Val() (which should be non-null) + Object nxt_val = nxt.Val(); + if (nxt_val != null) {match_pos = cur_pos; rv = nxt_val;} // nxt is node; cache rv (in case of false match) + if (cur_pos == src_len) return rv; // increment cur_pos and exit if src_len + b = src[cur_pos]; + cur = nxt; + } + } + public Btrie_slim_mgr Add_bry_tid(byte[] bry, byte tid) {return (Btrie_slim_mgr)Add_obj(bry, Byte_obj_val.new_(tid));} + public Btrie_slim_mgr Add_str_byte(String key, byte val) {return (Btrie_slim_mgr)Add_obj(Bry_.new_u8(key), Byte_obj_val.new_(val));} + public Btrie_slim_mgr Add_str_int(String key, int val) {return (Btrie_slim_mgr)Add_obj(Bry_.new_u8(key), Int_obj_val.new_(val));} + public Btrie_slim_mgr Add_bry(String key, String val) {return (Btrie_slim_mgr)Add_obj(Bry_.new_u8(key), Bry_.new_u8(val));} + public Btrie_slim_mgr Add_bry(String key, byte[] val) {return (Btrie_slim_mgr)Add_obj(Bry_.new_u8(key), val);} + public Btrie_slim_mgr Add_bry(byte[] v) {return (Btrie_slim_mgr)Add_obj(v, v);} + public Btrie_slim_mgr Add_bry_bval(byte b, byte val) {return (Btrie_slim_mgr)Add_obj(new byte[] {b}, Byte_obj_val.new_(val));} + public Btrie_slim_mgr Add_bry_bval(byte[] bry, byte val) {return (Btrie_slim_mgr)Add_obj(bry, Byte_obj_val.new_(val));} + public Btrie_slim_mgr Add_str_byte__many(byte val, String... ary) { + int ary_len = ary.length; + Byte_obj_val bval = Byte_obj_val.new_(val); + for (int i = 0; i < ary_len; i++) + Add_obj(Bry_.new_u8(ary[i]), bval); + return this; + } + public Btrie_slim_mgr Add_stub(String key, byte val) {byte[] bry = Bry_.new_u8(key); return (Btrie_slim_mgr)Add_obj(bry, new Btrie_itm_stub(val, bry));} + public Btrie_slim_mgr Add_stubs(byte[][] ary) {return Add_stubs(ary, ary.length);} + public Btrie_slim_mgr Add_stubs(byte[][] ary, int ary_len) { + for (byte i = 0; i < ary_len; i++) { + byte[] bry = ary[i]; + Add_obj(bry, new Btrie_itm_stub(i, bry)); + } + return this; + } + public Btrie_mgr Add_obj(String key, Object val) {return Add_obj(Bry_.new_u8(key), val);} + public Btrie_mgr Add_obj(byte[] key, Object val) { + if (val == null) throw Exc_.new_("null objects cannot be registered", "key", String_.new_u8(key)); + int key_len = key.length; int key_end = key_len - 1; + Btrie_slim_itm cur = root; + for (int i = 0; i < key_len; i++) { + byte b = key[i]; + if (root.Case_any() && (b > 64 && b < 91)) b += 32; + Btrie_slim_itm nxt = cur.Ary_find(b); + if (nxt == null) + nxt = cur.Ary_add(b, null); + if (i == key_end) + nxt.Val_set(val); + cur = nxt; + } + count++; // FUTURE: do not increment if replacing value + return this; + } + public void Del(byte[] key) { + int key_len = key.length; + Btrie_slim_itm cur = root; + for (int i = 0; i < key_len; i++) { + byte b = key[i]; + Btrie_slim_itm nxt = cur.Ary_find(b); + if (nxt == null) break; + Object nxt_val = nxt.Val(); + if (nxt_val == null) // cur is end of chain; remove entry; EX: Abc and at c + cur.Ary_del(b); + else // cur is mid of chain; null out entry + nxt.Val_set(null); + cur = nxt; + } + count--; // FUTURE: do not decrement if not found + } + public byte[] Replace(Bry_bfr tmp_bfr, byte[] src, int bgn, int end) { + int pos = bgn; + boolean dirty = false; + while (pos < end) { + byte b = src[pos]; + Object o = this.Match_bgn_w_byte(b, src, pos, end); + if (o == null) { + if (dirty) + tmp_bfr.Add_byte(b); + pos++; + } + else { + if (!dirty) { + tmp_bfr.Add_mid(src, bgn, pos); + dirty = true; + } + tmp_bfr.Add((byte[])o); + pos = match_pos; + } + } + return dirty ? tmp_bfr.Xto_bry_and_clear() : src; + } + public void Clear() {root.Clear(); count = 0;} + public static Btrie_slim_mgr cs_() {return new Btrie_slim_mgr(true);} + public static Btrie_slim_mgr ci_ascii_() {return new Btrie_slim_mgr(false);} + public static Btrie_slim_mgr ci_utf_8_() {return new Btrie_slim_mgr(false);} + public static Btrie_slim_mgr new_(boolean v) {return new Btrie_slim_mgr(v);} +} diff --git a/100_core/src/gplx/core/btries/Btrie_slim_mgr_tst.java b/100_core/src/gplx/core/btries/Btrie_slim_mgr_tst.java new file mode 100644 index 000000000..25261a052 --- /dev/null +++ b/100_core/src/gplx/core/btries/Btrie_slim_mgr_tst.java @@ -0,0 +1,92 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.btries; import gplx.*; import gplx.core.*; +import org.junit.*; +public class Btrie_slim_mgr_tst { + @Before public void init() { + } private Btrie_slim_mgr trie; + private void ini_setup1() { + trie = Btrie_slim_mgr.cs_(); + run_Add("a" , 1); + run_Add("abc" , 123); + } + @Test public void Get_by() { + ini_setup1(); + tst_MatchAtCur("a" , 1); + tst_MatchAtCur("abc" , 123); + tst_MatchAtCur("ab" , 1); + tst_MatchAtCur("abcde" , 123); + tst_MatchAtCur(" a" , null); + } + @Test public void Bos() { + ini_setup1(); + tst_Match("bc", Byte_ascii.Ltr_a, -1, 123); + } + @Test public void Match_exact() { + ini_setup1(); + tst_MatchAtCurExact("a", 1); + tst_MatchAtCurExact("ab", null); + tst_MatchAtCurExact("abc", 123); + } + private void ini_setup2() { + trie = Btrie_slim_mgr.cs_(); + run_Add("a" , 1); + run_Add("b" , 2); + } + @Test public void Match_2() { + ini_setup2(); + tst_MatchAtCur("a", 1); + tst_MatchAtCur("b", 2); + } + private void ini_setup_caseAny() { + trie = Btrie_slim_mgr.ci_ascii_(); // NOTE:ci.ascii:test + run_Add("a" , 1); + run_Add("b" , 2); + } + @Test public void CaseAny() { + ini_setup_caseAny(); + tst_MatchAtCur("a", 1); + tst_MatchAtCur("A", 1); + } + @Test public void Del() { + ini_setup1(); + trie.Del(Bry_.new_a7("a")); // delete "a"; "abc" still remains; + tst_MatchAtCur("a" , null); + tst_MatchAtCur("abc" , 123); + + trie.Del(Bry_.new_a7("abc")); + tst_MatchAtCur("abc" , null); + } + + private void run_Add(String k, int val) {trie.Add_obj(Bry_.new_a7(k), val);} + private void tst_Match(String srcStr, byte b, int bgn_pos, int expd) { + byte[] src = Bry_.new_a7(srcStr); + Object actl = trie.Match_bgn_w_byte(b, src, bgn_pos, src.length); + Tfds.Eq(expd, actl); + } + private void tst_MatchAtCur(String srcStr, Object expd) { + byte[] src = Bry_.new_a7(srcStr); + Object actl = trie.Match_bgn_w_byte(src[0], src, 0, src.length); + Tfds.Eq(expd, actl); + } + private void tst_MatchAtCurExact(String srcStr, Object expd) { + byte[] src = Bry_.new_a7(srcStr); + Object actl = trie.Match_exact(src, 0, src.length); + Tfds.Eq(expd, actl); + } +} diff --git a/100_core/src/gplx/core/btries/Btrie_utf8_itm.java b/100_core/src/gplx/core/btries/Btrie_utf8_itm.java new file mode 100644 index 000000000..882bd3bc2 --- /dev/null +++ b/100_core/src/gplx/core/btries/Btrie_utf8_itm.java @@ -0,0 +1,68 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.btries; import gplx.*; import gplx.core.*; +import gplx.intl.*; +class Btrie_utf8_itm { + private Hash_adp_bry nxts; + private byte[] asymmetric_bry; + public Btrie_utf8_itm(byte[] key, Object val) {this.key = key; this.val = val;} + public byte[] Key() {return key;} private byte[] key; + public Object Val() {return val;} public void Val_set(Object val) {this.val = val;} private Object val; + public boolean Nxts_is_empty() {return nxts == null;} + public void Clear() { + val = null; + nxts.Clear(); + nxts = null; + } + public Btrie_utf8_itm Nxts_find(byte[] src, int c_bgn, int c_end, boolean called_by_match) { + if (nxts == null) return null; + Object rv_obj = nxts.Get_by_mid(src, c_bgn, c_end); + if (rv_obj == null) return null; + Btrie_utf8_itm rv = (Btrie_utf8_itm)rv_obj; + byte[] asymmetric_bry = rv.asymmetric_bry; + if (asymmetric_bry == null) // itm doesn't have asymmetric_bry; note that this is the case for most items + return rv; + else { // itm has asymmetric_bry; EX: "İ" was added to trie, must match "İ" and "i"; + if (called_by_match) { // called by mgr.Match + return + ( Bry_.Eq(rv.key, src, c_bgn, c_end) // key matches src; EX: "aİ" + || Bry_.Eq(rv.asymmetric_bry, src, c_bgn, c_end) // asymmetric_bry matches src; EX: "ai"; note that "aI" won't match + ) + ? rv : null; + } + else { // called by mgr.Add; this means that an asymmetric_itm was already added; happens when "İ" added first and then "I" added next + rv.asymmetric_bry = null; // always null out asymmetric_bry; note that this noops non-asymmetric itms, while making an asymmetric_itm case-insenstivie (matches İ,i,I); see tests + return rv; + } + } + } + public Btrie_utf8_itm Nxts_add(Gfo_case_mgr case_mgr, byte[] key, Object val) { + Btrie_utf8_itm rv = new Btrie_utf8_itm(key, val); + if (nxts == null) nxts = Hash_adp_bry.ci_utf8_(case_mgr); + nxts.Add_bry_obj(key, rv); + Gfo_case_itm case_itm = case_mgr.Get_or_null(key[0], key, 0, key.length); // get case_item + if (case_itm != null) { // note that case_itm may be null; EX: "__TOC__" and "_" + byte[] asymmetric_bry = case_itm.Asymmetric_bry(); + if (asymmetric_bry != null) { // case_itm has asymmetry_bry; only itms in Xol_case_itm_ that are created with Tid_upper and Tid_lower will be non-null + rv.asymmetric_bry = asymmetric_bry; // set itm to asymmetric_bry; EX: for İ, asymmetric_bry = i + nxts.Add_bry_obj(asymmetric_bry, rv); // add the asymmetric_bry to the hash; in above example, this allows "i" to match "İ" + } + } + return rv; + } +} diff --git a/100_core/src/gplx/core/btries/Btrie_utf8_mgr.java b/100_core/src/gplx/core/btries/Btrie_utf8_mgr.java new file mode 100644 index 000000000..fb5e6fca3 --- /dev/null +++ b/100_core/src/gplx/core/btries/Btrie_utf8_mgr.java @@ -0,0 +1,68 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.btries; import gplx.*; import gplx.core.*; +import gplx.intl.*; +public class Btrie_utf8_mgr implements Btrie_mgr { + private Btrie_utf8_itm root; private Gfo_case_mgr case_mgr; + Btrie_utf8_mgr(Gfo_case_mgr case_mgr) { + this.case_mgr = case_mgr; + this.root = new Btrie_utf8_itm(Bry_.Empty, null); + } + public int Count() {return count;} private int count; + public int Match_pos() {return match_pos;} private int match_pos; + public Object Match_bgn(byte[] src, int bgn_pos, int end_pos) {return Match_bgn_w_byte(src[bgn_pos], src, bgn_pos, end_pos);} + public Object Match_bgn_w_byte(byte b, byte[] src, int bgn_pos, int end_pos) { + Object rv = null; int cur_pos = match_pos = bgn_pos; + Btrie_utf8_itm cur = root; + while (true) { + int c_len = Utf8_.Len_of_char_by_1st_byte(b); + int c_end = cur_pos + c_len; + Btrie_utf8_itm nxt = cur.Nxts_find(src, cur_pos, c_end, true); if (nxt == null) return rv; // nxts does not have key; return rv; + cur_pos = c_end; + if (nxt.Nxts_is_empty()) {match_pos = cur_pos; return nxt.Val();} // nxt is leaf; return nxt.Val() (which should be non-null) + Object nxt_val = nxt.Val(); + if (nxt_val != null) {match_pos = cur_pos; rv = nxt_val;} // nxt is node; cache rv (in case of false match) + if (cur_pos == end_pos) return rv; // increment cur_pos and exit if end + b = src[cur_pos]; + cur = nxt; + } + } + public void Clear() {root.Clear(); count = 0;} + public Btrie_mgr Add_obj(String key, Object val) {return Add_obj(Bry_.new_u8(key), val);} + public Btrie_mgr Add_obj(byte[] key, Object val) { + if (val == null) throw Exc_.new_("null objects cannot be registered", "key", String_.new_u8(key)); + int key_len = key.length; + Btrie_utf8_itm cur = root; + int c_bgn = 0; + while (c_bgn < key_len) { + byte c = key[c_bgn]; + int c_len = Utf8_.Len_of_char_by_1st_byte(c); + int c_end = c_bgn + c_len; + Btrie_utf8_itm nxt = cur.Nxts_find(key, c_bgn, c_end, false); + if (nxt == null) + nxt = cur.Nxts_add(case_mgr, Bry_.Mid(key, c_bgn, c_end), null); + c_bgn = c_end; + if (c_bgn == key_len) + nxt.Val_set(val); + cur = nxt; + } + ++count; + return this; + } + public static Btrie_utf8_mgr new_(Gfo_case_mgr case_mgr) {return new Btrie_utf8_mgr(case_mgr);} +} diff --git a/100_core/src/gplx/core/criterias/Criteria.java b/100_core/src/gplx/core/criterias/Criteria.java new file mode 100644 index 000000000..18f209c53 --- /dev/null +++ b/100_core/src/gplx/core/criterias/Criteria.java @@ -0,0 +1,24 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.criterias; import gplx.*; import gplx.core.*; +public interface Criteria extends XtoStrAble { + byte Tid(); + boolean Matches(Object obj); + void Val_from_args(Hash_adp args); + void Val_as_obj_(Object obj); +} diff --git a/100_core/src/gplx/core/criterias/Criteria_.java b/100_core/src/gplx/core/criterias/Criteria_.java new file mode 100644 index 000000000..1bdb5068d --- /dev/null +++ b/100_core/src/gplx/core/criterias/Criteria_.java @@ -0,0 +1,53 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.criterias; import gplx.*; import gplx.core.*; +import gplx.texts.*; /*RegxPatn_cls_like*/ +public class Criteria_ { + public static final Criteria All = new Criteria_const(true); + public static final Criteria None = new Criteria_const(false); + public static Criteria Not(Criteria arg) {return new Criteria_not(arg);} + public static Criteria And(Criteria lhs, Criteria rhs) {return new Criteria_and(lhs, rhs);} + public static Criteria And_many(Criteria... ary) { + int len = Array_.Len(ary); if (len == 0) throw Exc_.new_("cannot AND 0 criterias;"); + Criteria rv = ary[0]; + for (int i = 1; i < len; i++) + rv = And(rv, ary[i]); + return rv; + } + public static Criteria Or(Criteria lhs, Criteria rhs) {return new Criteria_or(lhs, rhs);} + public static Criteria Or_many(Criteria... ary) { + int len = Array_.Len(ary); if (len == 0) throw Exc_.new_("cannot OR 0 criterias;"); + Criteria rv = ary[0]; + for (int i = 1; i < len; i++) + rv = Or(rv, ary[i]); + return rv; + } + public static Criteria eq_(Object arg) {return new Criteria_eq(false, arg);} + public static Criteria eqn_(Object arg) {return new Criteria_eq(true, arg);} + public static Criteria in_(Object... array) {return new Criteria_in(false, array);} + public static Criteria inn_(Object... array) {return new Criteria_in(true, array);} + public static Criteria lt_(Comparable val) {return new Criteria_comp(CompareAble_.Less, val);} + public static Criteria lte_(Comparable val) {return new Criteria_comp(CompareAble_.LessOrSame, val);} + public static Criteria mt_(Comparable val) {return new Criteria_comp(CompareAble_.More, val);} + public static Criteria mte_(Comparable val) {return new Criteria_comp(CompareAble_.MoreOrSame, val);} + public static Criteria between_(Comparable lhs, Comparable rhs) {return new Criteria_between(false, lhs, rhs);} + public static Criteria between_(boolean negated, Comparable lhs, Comparable rhs) {return new Criteria_between(negated, lhs, rhs);} + public static Criteria like_(String pattern) {return new Criteria_like(false, RegxPatn_cls_like_.parse_(pattern, RegxPatn_cls_like.EscapeDefault));} + public static Criteria liken_(String pattern) {return new Criteria_like(true, RegxPatn_cls_like_.parse_(pattern, RegxPatn_cls_like.EscapeDefault));} + public static final byte Tid_custom = 0, Tid_const = 1, Tid_not = 2, Tid_and = 3, Tid_or = 4, Tid_eq = 5, Tid_between = 6, Tid_in = 7, Tid_like = 8, Tid_comp = 9, Tid_wrapper = 10, Tid_iomatch = 11, Tid_db_obj_ary = 12; +} diff --git a/100_core/src/gplx/core/criterias/Criteria_between.java b/100_core/src/gplx/core/criterias/Criteria_between.java new file mode 100644 index 000000000..2837b124d --- /dev/null +++ b/100_core/src/gplx/core/criterias/Criteria_between.java @@ -0,0 +1,40 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.criterias; import gplx.*; import gplx.core.*; +public class Criteria_between implements Criteria { + public Criteria_between(boolean negate, Comparable lhs, Comparable rhs) {this.negate = negate; this.lhs = lhs; this.rhs = rhs;} + public byte Tid() {return Criteria_.Tid_between;} + public boolean Negated() {return negate;} private final boolean negate; + public void Val_from_args(Hash_adp args) {throw Exc_.new_unimplemented();} + public void Val_as_obj_(Object v) { + Object[] ary = (Object[])v; + lhs = (Comparable)ary[0]; + rhs = (Comparable)ary[1]; + } + public Comparable Lhs() {return lhs;} private Comparable lhs; + public Comparable Rhs() {return rhs;} private Comparable rhs; + public String XtoStr() {return String_.Concat_any("BETWEEN ", lhs, " AND ", rhs);} + public boolean Matches(Object compObj) { + Comparable comp = CompareAble_.as_(compObj); + int lhsResult = CompareAble_.CompareComparables(lhs, comp); + int rhsResult = CompareAble_.CompareComparables(rhs, comp); + boolean rv = (lhsResult * rhsResult) != 1; + return negate ? !rv : rv; + } + public static Criteria_between as_(Object obj) {return obj instanceof Criteria_between ? (Criteria_between)obj : null;} +} diff --git a/100_core/src/gplx/core/criterias/Criteria_bool_base.java b/100_core/src/gplx/core/criterias/Criteria_bool_base.java new file mode 100644 index 000000000..c76997702 --- /dev/null +++ b/100_core/src/gplx/core/criterias/Criteria_bool_base.java @@ -0,0 +1,57 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.criterias; import gplx.*; import gplx.core.*; +public abstract class Criteria_bool_base implements Criteria { + @gplx.Internal protected void Ctor(String op_literal, Criteria lhs, Criteria rhs) {this.op_literal = op_literal; this.lhs = lhs; this.rhs = rhs;} + public abstract byte Tid(); + public abstract boolean Matches(Object curVal); + public void Val_from_args(Hash_adp args) {lhs.Val_from_args(args); rhs.Val_from_args(args);} + public void Val_as_obj_(Object v) {throw Exc_.new_unimplemented();} + public String XtoStr() {return String_.Concat(lhs.XtoStr(), " ", this.op_literal, " ", rhs.XtoStr());} + public String Op_literal() {return op_literal;} private String op_literal; + public Criteria Lhs() {return lhs;} private Criteria lhs; + public Criteria Rhs() {return rhs;} private Criteria rhs; + public static Criteria_bool_base as_(Object obj) {return obj instanceof Criteria_bool_base ? (Criteria_bool_base)obj : null;} +} +class Criteria_and extends Criteria_bool_base { + public Criteria_and(Criteria lhs, Criteria rhs) {this.Ctor("AND", lhs, rhs);} + @Override public byte Tid() {return Criteria_.Tid_not;} + @Override public boolean Matches(Object curVal) {return this.Lhs().Matches(curVal) && this.Rhs().Matches(curVal);} +} +class Criteria_or extends Criteria_bool_base { + public Criteria_or(Criteria lhs, Criteria rhs) {this.Ctor("OR", lhs, rhs);} + @Override public byte Tid() {return Criteria_.Tid_or;} + @Override public boolean Matches(Object curVal) {return this.Lhs().Matches(curVal) || this.Rhs().Matches(curVal);} +} +class Criteria_const implements Criteria { + public Criteria_const(boolean val) {this.val = val;} + public byte Tid() {return Criteria_.Tid_const;} + public boolean Matches(Object comp) {return val;} private final boolean val; + public void Val_from_args(Hash_adp args) {;} + public void Val_as_obj_(Object v) {throw Exc_.new_unimplemented();} + public String XtoStr() {return String_.Concat(" IS ", Bool_.Xto_str_lower(val));} +} +class Criteria_not implements Criteria { + private final Criteria criteria; + public Criteria_not(Criteria v) {this.criteria = v;} + public byte Tid() {return Criteria_.Tid_not;} + public boolean Matches(Object obj) {return !criteria.Matches(obj);} + public void Val_from_args(Hash_adp args) {criteria.Val_from_args(args);} + public void Val_as_obj_(Object v) {criteria.Val_as_obj_(v);} + public String XtoStr() {return String_.Concat_any(" NOT ", criteria.XtoStr());} +} diff --git a/100_core/src/gplx/core/criterias/Criteria_comp.java b/100_core/src/gplx/core/criterias/Criteria_comp.java new file mode 100644 index 000000000..2fd8bbb68 --- /dev/null +++ b/100_core/src/gplx/core/criterias/Criteria_comp.java @@ -0,0 +1,37 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.criterias; import gplx.*; import gplx.core.*; +public class Criteria_comp implements Criteria { + private final int comp_mode; + @gplx.Internal protected Criteria_comp(int comp_mode, Comparable val) {this.comp_mode = comp_mode; this.val = val;} + public byte Tid() {return Criteria_.Tid_comp;} + public Comparable Val() {return val;} private Comparable val; + public void Val_from_args(Hash_adp args) {throw Exc_.new_unimplemented();} + public void Val_as_obj_(Object v) {val = (Comparable)v;} + public boolean Matches(Object compObj) { + Comparable comp = CompareAble_.as_(compObj); + return CompareAble_.Is(comp_mode, comp, val); + } + public String XtoStr() {return String_.Concat_any(XtoSymbol(), " ", val);} + public String XtoSymbol() { + String comp_sym = comp_mode < CompareAble_.Same ? "<" : ">"; + String eq_sym = comp_mode % 2 == CompareAble_.Same ? "=" : ""; + return comp_sym + eq_sym; + } + public static Criteria_comp as_(Object obj) {return obj instanceof Criteria_comp ? (Criteria_comp)obj : null;} +} diff --git a/100_core/src/gplx/core/criterias/Criteria_eq.java b/100_core/src/gplx/core/criterias/Criteria_eq.java new file mode 100644 index 000000000..64cf73b74 --- /dev/null +++ b/100_core/src/gplx/core/criterias/Criteria_eq.java @@ -0,0 +1,34 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.criterias; import gplx.*; import gplx.core.*; +public class Criteria_eq implements Criteria { + @gplx.Internal protected Criteria_eq(boolean negated, Object val) {this.negated = negated; this.val = val;} + public byte Tid() {return Criteria_.Tid_eq;} + public boolean Negated() {return negated;} private final boolean negated; + public Object Val() {return val;} private Object val; + public void Val_as_obj_(Object v) {this.val = v;} + public void Val_from_args(Hash_adp args) {throw Exc_.new_unimplemented();} + public boolean Matches(Object comp) { + Class val_type = ClassAdp_.ClassOf_obj(val); + if (!ClassAdp_.Eq_typeSafe(comp, val_type)) throw Exc_.new_type_mismatch(val_type, comp); + boolean rv = Object_.Eq(val, comp); + return negated ? !rv : rv; + } + public String XtoStr() {return String_.Concat_any("= ", val);} + public static Criteria_eq as_(Object obj) {return obj instanceof Criteria_eq ? (Criteria_eq)obj : null;} +} diff --git a/100_core/src/gplx/core/criterias/Criteria_fld.java b/100_core/src/gplx/core/criterias/Criteria_fld.java new file mode 100644 index 000000000..ccd394e25 --- /dev/null +++ b/100_core/src/gplx/core/criterias/Criteria_fld.java @@ -0,0 +1,67 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.criterias; import gplx.*; import gplx.core.*; +public class Criteria_fld implements Criteria { + Criteria_fld(String key, Criteria crt) {this.key = key; this.crt = crt;} + public byte Tid() {return Criteria_.Tid_wrapper;} + public String Key() {return key;} private final String key; + public Criteria Crt() {return crt;} private final Criteria crt; + public void Val_as_obj_(Object v) {throw Exc_.new_unimplemented();} + public void Val_from_args(Hash_adp args) { + List_adp list = (List_adp)args.Get_by(key); if (list == null) throw Exc_.new_("criteria.fld key not found", "key", key); + Object o = Fill_val(key, crt.Tid(), list); + crt.Val_as_obj_(o); + } + public boolean Matches(Object invkObj) { + GfoInvkAble invk = (GfoInvkAble)invkObj; + if (key == Criteria_fld.Key_null) return crt.Matches(invkObj); + Object comp = GfoInvkAble_.InvkCmd(invk, key); + return crt.Matches(comp); + } + public String XtoStr() {return String_.Concat(key, " ", crt.XtoStr());} + public static final String Key_null = null; + public static Criteria_fld as_(Object obj) {return obj instanceof Criteria_fld ? (Criteria_fld)obj : null;} + public static Criteria_fld new_(String key, Criteria crt) {return new Criteria_fld(key, crt);} + public static Object Fill_val(String key, byte tid, List_adp list) { + int len = list.Count(); + switch (tid) { + case Criteria_.Tid_eq: + case Criteria_.Tid_comp: + case Criteria_.Tid_like: + case Criteria_.Tid_iomatch: + if (len != 1) throw Exc_.new_("list.len should be 1", "key", key, "tid", tid, "len", len); + return list.Get_at(0); + case Criteria_.Tid_between: + if (len != 2) throw Exc_.new_("list.len should be 2", "key", key, "tid", tid, "len", len); + return new Object[] {list.Get_at(0), list.Get_at(1)}; + case Criteria_.Tid_in: + if (len == 0) throw Exc_.new_("list.len should be > 0", "key", key, "tid", tid, "len", len); + return list.To_obj_ary(); + case Criteria_.Tid_const: + case Criteria_.Tid_not: + case Criteria_.Tid_and: + case Criteria_.Tid_or: + if (len != 0) throw Exc_.new_("list.len should be 0", "key", key, "tid", tid, "len", len); + return key; // no values to fill in; return back key + case Criteria_.Tid_wrapper: // not recursive + case Criteria_.Tid_db_obj_ary: // unsupported + case Criteria_.Tid_custom: + default: throw Exc_.new_unhandled(tid); + } + } +} diff --git a/100_core/src/gplx/core/criterias/Criteria_in.java b/100_core/src/gplx/core/criterias/Criteria_in.java new file mode 100644 index 000000000..94a165ca2 --- /dev/null +++ b/100_core/src/gplx/core/criterias/Criteria_in.java @@ -0,0 +1,46 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.criterias; import gplx.*; import gplx.core.*; +public class Criteria_in implements Criteria { + public Criteria_in(boolean negated, Object[] ary) {this.negated = negated; Val_as_obj_ary_(ary);} + public byte Tid() {return Criteria_.Tid_in;} + public boolean Negated() {return negated;} private final boolean negated; + public Object[] Val_as_obj_ary() {return ary;} private Object[] ary; private Class ary_type; private int ary_len; + private void Val_as_obj_ary_(Object[] v) { + this.ary = v; + ary_len = Array_.Len(ary); + ary_type = ary_len == 0 ? Object.class : ClassAdp_.ClassOf_obj(ary[0]); + } + public void Val_as_obj_(Object v) {Val_as_obj_ary_((Object[])v);} + public void Val_from_args(Hash_adp args) {throw Exc_.new_unimplemented();} + public boolean Matches(Object comp) { + if (ary_len == 0) return false; // empty array never matches + if (!ClassAdp_.Eq_typeSafe(comp, ary_type)) throw Exc_.new_type_mismatch(ary_type, comp); + boolean rv = false; + for (int i = 0; i < ary_len; i++) { + Object val = ary[i]; + if (Object_.Eq(val, comp)) { + rv = true; + break; + } + } + return negated ? !rv : rv; + } + public String XtoStr() {return String_.Concat_any("IN ", String_.Concat_any(ary));} + public static Criteria_in as_(Object obj) {return obj instanceof Criteria_in ? (Criteria_in)obj : null;} +} diff --git a/100_core/src/gplx/core/criterias/Criteria_ioItm_tst.java b/100_core/src/gplx/core/criterias/Criteria_ioItm_tst.java new file mode 100644 index 000000000..35c3dd69e --- /dev/null +++ b/100_core/src/gplx/core/criterias/Criteria_ioItm_tst.java @@ -0,0 +1,50 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.criterias; import gplx.*; import gplx.core.*; +import org.junit.*; +import gplx.ios.*; +public class Criteria_ioItm_tst { + IoItmFil fil; Criteria crt; IoItm_fxt fx = IoItm_fxt.new_(); + @Test public void IoType() { + crt = crt_(IoItm_base_.Prop_Type, Criteria_.eq_(IoItmFil.Type_Fil)); + tst_Match(true, crt, fx.fil_wnt_("C:\\fil.txt")); + tst_Match(false, crt, fx.dir_wnt_("C:\\dir")); + } + @Test public void Ext() { + crt = crt_(IoItm_base_.Prop_Ext, Criteria_.eq_(".txt")); + tst_Match(true, crt, fx.fil_wnt_("C:\\fil.txt")); + tst_Match(false, crt, fx.fil_wnt_("C:\\fil.xml"), fx.fil_wnt_("C:\\fil.txt1"), fx.fil_wnt_("C:\\fil1.txt.xml"), fx.dir_wnt_("C:\\.txt")); + } + @Test public void Modified() { + fil = fx.fil_wnt_("C:\\fil.txt"); + crt = crt_(IoItmFil_.Prop_Modified, Criteria_.mte_(DateAdp_.parse_gplx("2001-01-01"))); + tst_Match(true, crt, fil.ModifiedTime_(DateAdp_.parse_gplx("2001-01-02")), fil.ModifiedTime_(DateAdp_.parse_gplx("2001-01-01"))); + tst_Match(false, crt, fil.ModifiedTime_(DateAdp_.parse_gplx("2000-12-31"))); + } + @Test public void IoMatch() { + Criteria crt = Criteria_ioMatch.parse_(true, "*.txt", false); + CriteriaFxt fx_crt = new CriteriaFxt(); + fx_crt.tst_Matches(crt, Io_url_.new_any_("file.txt")); + fx_crt.tst_MatchesNot(crt, Io_url_.new_any_("file.xml")); + } + Criteria crt_(String fld, Criteria crt) {return Criteria_fld.new_(fld, crt);} + void tst_Match(boolean expt, Criteria fieldCrt, IoItm_base... ary) { + for (IoItm_base itm : ary) + Tfds.Eq(expt, fieldCrt.Matches(itm)); + } +} diff --git a/100_core/src/gplx/core/criterias/Criteria_ioMatch.java b/100_core/src/gplx/core/criterias/Criteria_ioMatch.java new file mode 100644 index 000000000..39be4aa6a --- /dev/null +++ b/100_core/src/gplx/core/criterias/Criteria_ioMatch.java @@ -0,0 +1,37 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.criterias; import gplx.*; import gplx.core.*; +import gplx.texts.*; +public class Criteria_ioMatch implements Criteria { // EX: url IOMATCH '*.xml|*.txt' + public Criteria_ioMatch(boolean match, RegxPatn_cls_ioMatch pattern) {this.match = match; this.pattern = pattern;} + public byte Tid() {return Criteria_.Tid_iomatch;} + public boolean Negated() {return !match;} private final boolean match; + public void Val_from_args(Hash_adp args) {throw Exc_.new_unimplemented();} + public void Val_as_obj_(Object v) {this.pattern = (RegxPatn_cls_ioMatch)v;} + public RegxPatn_cls_ioMatch Pattern() {return pattern;} private RegxPatn_cls_ioMatch pattern; + public boolean Matches(Object compObj) { + Io_url comp = (Io_url)compObj; + boolean rv = pattern.Matches(comp.XtoCaseNormalized()); + return match ? rv : !rv; + } + public String XtoStr() {return String_.Concat_any("IOMATCH ", pattern);} + + public static final String TokenName = "IOMATCH"; + public static Criteria_ioMatch as_(Object obj) {return obj instanceof Criteria_ioMatch ? (Criteria_ioMatch)obj : null;} + public static Criteria_ioMatch parse_(boolean match, String raw, boolean caseSensitive) {return new Criteria_ioMatch(match, RegxPatn_cls_ioMatch_.parse_(raw, caseSensitive));} +} diff --git a/100_core/src/gplx/core/criterias/Criteria_like.java b/100_core/src/gplx/core/criterias/Criteria_like.java new file mode 100644 index 000000000..382f49c60 --- /dev/null +++ b/100_core/src/gplx/core/criterias/Criteria_like.java @@ -0,0 +1,36 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.criterias; import gplx.*; import gplx.core.*; +import gplx.texts.*; /*RegxPatn_cls_like*/ +public class Criteria_like implements Criteria { + @gplx.Internal protected Criteria_like(boolean negated, RegxPatn_cls_like pattern) { + this.negated = negated; this.pattern = pattern; + } + public byte Tid() {return Criteria_.Tid_like;} + public boolean Negated() {return negated;} private final boolean negated; + public RegxPatn_cls_like Pattern() {return pattern;} private RegxPatn_cls_like pattern; + public void Val_from_args(Hash_adp args) {throw Exc_.new_unimplemented();} + public void Val_as_obj_(Object v) {this.pattern = (RegxPatn_cls_like)v;} + public boolean Matches(Object compObj) { + String comp = String_.as_(compObj); if (comp == null) throw Exc_.new_type_mismatch(String.class, compObj); + boolean rv = pattern.Matches(comp); + return negated ? !rv : rv; + } + public String XtoStr() {return String_.Concat_any("LIKE ", pattern);} + public static Criteria_like as_(Object obj) {return obj instanceof Criteria_like ? (Criteria_like)obj : null;} +} \ No newline at end of file diff --git a/100_core/src/gplx/core/criterias/Criteria_tst.java b/100_core/src/gplx/core/criterias/Criteria_tst.java new file mode 100644 index 000000000..f3876cffe --- /dev/null +++ b/100_core/src/gplx/core/criterias/Criteria_tst.java @@ -0,0 +1,92 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.criterias; import gplx.*; import gplx.core.*; +import org.junit.*; +public class Criteria_tst { + @Test public void Equal() { + Criteria crt = Criteria_.eq_(true); + fx.tst_Matches(crt, true); + fx.tst_MatchesNot(crt, false); + fx.tst_MatchesFail(crt, "true"); + + fx.tst_Matches(Criteria_.eq_(1), 1); + fx.tst_Matches(Criteria_.eq_("equal"), "equal"); + fx.tst_Matches(Criteria_.eq_(date), date); + } + @Test public void Not() { + Criteria crt = Criteria_.eqn_(true); + fx.tst_Matches(crt, false); + fx.tst_MatchesNot(crt, true); + fx.tst_MatchesFail(crt, "false"); + + fx.tst_Matches(Criteria_.eqn_(1), -1); + fx.tst_Matches(Criteria_.eqn_("equal"), "not equal"); + fx.tst_Matches(Criteria_.eqn_(date), date.Add_minute(1)); + } + @Test public void MoreThan() { + Criteria crt = Criteria_.mt_(0); + fx.tst_Matches(crt, 1, 2); + fx.tst_MatchesNot(crt, 0, -1); + fx.tst_MatchesFail(crt, "1"); + + fx.tst_Matches(Criteria_.mt_(0), 1); + fx.tst_Matches(Criteria_.mt_("a"), "b"); + fx.tst_Matches(Criteria_.mt_(date), date.Add_minute(1)); + fx.tst_Matches(Criteria_.mt_(false), true); // MISC: thus truth is greater than falsehood + } + @Test public void MoreThanEq() { + Criteria crt = Criteria_.mte_(0); + fx.tst_Matches(crt, 0); + } + @Test public void Less() { + Criteria crt = Criteria_.lt_(0); + fx.tst_Matches(crt, -1, -2); + fx.tst_MatchesNot(crt, 0, 1); + fx.tst_MatchesFail(crt, "-1"); + } + @Test public void LessEq() { + Criteria crt = Criteria_.lte_(0); + fx.tst_Matches(crt, 0); + } + @Test public void Between() { + Criteria crt = Criteria_.between_(-1, 1); + fx.tst_Matches(crt, 0, 1, -1); + fx.tst_MatchesNot(crt, -2, 2); + fx.tst_MatchesFail(crt, "0"); + + fx.tst_Matches(Criteria_.between_(1, -1), 0); // reverse range + fx.tst_Matches(Criteria_.between_("a", "c"), "b"); + } + @Test public void In() { + Criteria crt = Criteria_.in_(0, 1, 2); + fx.tst_Matches(crt, 0, 1, 2); + fx.tst_MatchesNot(crt, 3, -1); + fx.tst_MatchesFail(crt, "0"); + } + CriteriaFxt fx = new CriteriaFxt(); + DateAdp date = DateAdp_.parse_gplx("2001-01-01"); +} +class CriteriaFxt { + public void tst_Matches(Criteria crt, Object... ary) {for (Object val : ary) Tfds.Eq(true, crt.Matches(val));} + public void tst_MatchesNot(Criteria crt, Object... ary) {for (Object val : ary) Tfds.Eq(false, crt.Matches(val));} + public void tst_MatchesFail(Criteria crt, Object val) { + try {crt.Matches(val);} + catch(Exception exc) {Exc_.Noop(exc); return;} + Tfds.Fail_expdError(); + } +} diff --git a/100_core/src/gplx/core/js/Js_wtr.java b/100_core/src/gplx/core/js/Js_wtr.java new file mode 100644 index 000000000..647fec495 --- /dev/null +++ b/100_core/src/gplx/core/js/Js_wtr.java @@ -0,0 +1,107 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.js; import gplx.*; import gplx.core.*; +public class Js_wtr { + private final Bry_bfr bfr = Bry_bfr.reset_(255); + private int arg_idx = 0, ary_idx = 0; + public byte Quote_char() {return quote_char;} public Js_wtr Quote_char_(byte v) {quote_char = v; return this;} private byte quote_char = Byte_ascii.Quote; + public void Clear() {bfr.Clear();} + public String To_str() {return bfr.Xto_str();} + public String To_str_and_clear() {return bfr.Xto_str_and_clear();} + public Js_wtr Func_init(String name) {return Func_init(Bry_.new_u8(name));} + public Js_wtr Func_init(byte[] name) { + bfr.Add(name).Add_byte(Byte_ascii.Paren_bgn); + arg_idx = 0; + return this; + } + public Js_wtr Func_term() { + bfr.Add_byte(Byte_ascii.Paren_end).Add_byte_semic(); + return this; + } + public Js_wtr Prm_bry(byte[] bry) { + Prm_spr(); + Write_val(bry); + return this; + } + public Js_wtr Prm_obj_ary(Object[] ary) { + int ary_len = ary.length; + for (int i = 0; i < ary_len; ++i) { + Object itm = ary[i]; + if (i != 0) bfr.Add_byte(Byte_ascii.Comma); + boolean val_needs_quotes = true; + if ( ClassAdp_.Eq_typeSafe(itm, Bool_.Cls_ref_type) + || ClassAdp_.Eq_typeSafe(itm, Int_.Cls_ref_type) + || ClassAdp_.Eq_typeSafe(itm, Long_.Cls_ref_type) + ) { + val_needs_quotes = false; + } + if (val_needs_quotes) + Write_val(Bry_.new_u8(Object_.Xto_str_strict_or_null_mark(itm))); + else + bfr.Add_obj_strict(itm); + } + return this; + } + public Js_wtr Ary_init() { + ary_idx = 0; + bfr.Add_byte(Byte_ascii.Brack_bgn); + return this; + } + public Js_wtr Ary_term() { + bfr.Add_byte(Byte_ascii.Brack_end); + return this; + } + public void Prm_spr() { + if (arg_idx != 0) bfr.Add_byte(Byte_ascii.Comma); + ++arg_idx; + } + private void Ary_spr() { + if (ary_idx != 0) bfr.Add_byte(Byte_ascii.Comma); + ++ary_idx; + } + public Js_wtr Ary_bry(byte[] bry) { + Ary_spr(); + Write_val(bry); + return this; + } + private Js_wtr Write_keyword_return() {bfr.Add(Keyword_return); return this;} + public Js_wtr Write_statement_return_func(String func, Object... args) { + this.Write_keyword_return(); + this.Func_init(func); + this.Prm_obj_ary(args); + this.Func_term(); + return this; + } + public void Write_val(byte[] bry) { + bfr.Add_byte(quote_char); + int len = bry.length; + for (int i = 0; i < len; i++) { + byte b = bry[i]; + switch (b) { + case Byte_ascii.Backslash: // "\" -> "\\"; needed else js will usurp \ as escape; EX: "\&" -> "&"; DATE:2014-06-24 + case Byte_ascii.Quote: + case Byte_ascii.Apos: bfr.Add_byte(Byte_ascii.Backslash).Add_byte(b); break; + case Byte_ascii.Nl: bfr.Add_byte(Byte_ascii.Backslash).Add_byte(Byte_ascii.Ltr_n); break; // "\n" -> "\\n" + case Byte_ascii.Cr: break;// skip + default: bfr.Add_byte(b); break; + } + } + bfr.Add_byte(quote_char); + } + private static final byte[] Keyword_return = Bry_.new_a7("return "); +} diff --git a/100_core/src/gplx/core/js/Js_wtr_tst.java b/100_core/src/gplx/core/js/Js_wtr_tst.java new file mode 100644 index 000000000..46a98d32d --- /dev/null +++ b/100_core/src/gplx/core/js/Js_wtr_tst.java @@ -0,0 +1,41 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.js; import gplx.*; import gplx.core.*; +import org.junit.*; +public class Js_wtr_tst { + @Before public void Init() {fxt.Clear();} private Js_wtr_fxt fxt = new Js_wtr_fxt(); + @Test public void Basic() { + fxt.Test_write_val_html("abc" , "'abc'"); + fxt.Test_write_val_html("a'b" , "'a\\'b'"); + fxt.Test_write_val_html("a\"b" , "'a\\\"b'"); + fxt.Test_write_val_html("a\nb" , "'a\\nb'"); + fxt.Test_write_val_html("a\rb" , "'ab'"); + fxt.Test_write_val_html("a\\&b" , "'a\\\\&b'"); // PURPOSE: backslashes need to be escaped; need for MathJax and "\&"; PAGE:Electromagnetic_field_tensor; DATE:2014-06-24 + } +} +class Js_wtr_fxt { + private Js_wtr wtr = new Js_wtr(); + public void Clear() { + wtr.Clear(); + wtr.Quote_char_(Byte_ascii.Apos); + } + public void Test_write_val_html(String raw, String expd) { + wtr.Write_val(Bry_.new_u8(raw)); + Tfds.Eq(expd, wtr.To_str_and_clear()); + } +} diff --git a/100_core/src/gplx/core/primitives/Bool_obj_ref.java b/100_core/src/gplx/core/primitives/Bool_obj_ref.java new file mode 100644 index 000000000..353caba1b --- /dev/null +++ b/100_core/src/gplx/core/primitives/Bool_obj_ref.java @@ -0,0 +1,36 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.primitives; import gplx.*; import gplx.core.*; +public class Bool_obj_ref { + public boolean Val() {return val;} private boolean val; + public boolean Val_y() {return val;} + public boolean Val_n() {return !val;} + public String Val_as_str_yn() {return Yn.Xto_str(val);} + public Bool_obj_ref Val_y_() {val = true; return this;} + public Bool_obj_ref Val_n_() {val = false; return this;} + public Bool_obj_ref Val_(boolean v) {val = v; return this;} + public Bool_obj_ref Val_toggle_() {val = !val; return this;} + @Override public String toString() {return Bool_.Xto_str_lower(val);} + public static Bool_obj_ref n_() {return new_(false);} + public static Bool_obj_ref y_() {return new_(true);} + public static Bool_obj_ref new_(boolean val) { + Bool_obj_ref rv = new Bool_obj_ref(); + rv.val = val; + return rv; + } Bool_obj_ref() {} +} diff --git a/100_core/src/gplx/core/primitives/Bool_obj_val.java b/100_core/src/gplx/core/primitives/Bool_obj_val.java new file mode 100644 index 000000000..df1919d51 --- /dev/null +++ b/100_core/src/gplx/core/primitives/Bool_obj_val.java @@ -0,0 +1,34 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.primitives; import gplx.*; import gplx.core.*; +public class Bool_obj_val { + Bool_obj_val(int v) {val = v;} private final int val; + public boolean Val() {return val == 1;} + public static final Bool_obj_val + Null = new Bool_obj_val(-1) + , False = new Bool_obj_val(0) + , True = new Bool_obj_val(1) + ; + public static Bool_obj_val read_(Object o) {String s = String_.as_(o); return s == null ? (Bool_obj_val)o : parse_(s);} + public static Bool_obj_val parse_(String raw) { + if (String_.Eq(raw, "y")) return Bool_obj_val.True; + else if (String_.Eq(raw, "n")) return Bool_obj_val.False; + else if (String_.Eq(raw, "")) return Bool_obj_val.Null; + else throw Exc_.new_parse_type(Bool_obj_val.class, raw); + } +} diff --git a/100_core/src/gplx/core/primitives/Bry_obj_ref.java b/100_core/src/gplx/core/primitives/Bry_obj_ref.java new file mode 100644 index 000000000..7ada3a493 --- /dev/null +++ b/100_core/src/gplx/core/primitives/Bry_obj_ref.java @@ -0,0 +1,35 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.primitives; import gplx.*; import gplx.core.*; +public class Bry_obj_ref { + public byte[] Val() {return val;} public Bry_obj_ref Val_(byte[] v) {val = v; return this;} private byte[] val; + @Override public int hashCode() {return CalcHashCode(val, 0, val.length);} + @Override public boolean equals(Object obj) {return obj == null ? false : Bry_.Eq(val, ((Bry_obj_ref)obj).Val());} // NOTE: strange, but null check needed; throws null error; EX.WP: File:Eug�ne Delacroix - La libert� guidant le peuple.jpg + public static int CalcHashCode(byte[] ary, int bgn, int end) { + int rv = 0; + for (int i = bgn; i < end; i++) + rv = (31 * rv) + ary[i]; + return rv; + } + public static Bry_obj_ref null_() {return new_(null);} + public static Bry_obj_ref new_(byte[] val) { + Bry_obj_ref rv = new Bry_obj_ref(); + rv.val = val; + return rv; + } private Bry_obj_ref() {} +} diff --git a/100_core/src/gplx/core/primitives/Byte_obj_ref.java b/100_core/src/gplx/core/primitives/Byte_obj_ref.java new file mode 100644 index 000000000..c7fcbd630 --- /dev/null +++ b/100_core/src/gplx/core/primitives/Byte_obj_ref.java @@ -0,0 +1,31 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.primitives; import gplx.*; import gplx.core.*; +public class Byte_obj_ref { + public byte Val() {return val;} private byte val; + public Byte_obj_ref Val_(byte v) {val = v; return this;} + @Override public int hashCode() {return val;} + @Override public boolean equals(Object obj) {return obj == null ? false : val == ((Byte_obj_ref)obj).Val();} + @Override public String toString() {return Int_.Xto_str(val);} + public static Byte_obj_ref zero_() {return new_(Byte_.Zero);} + public static Byte_obj_ref new_(byte val) { + Byte_obj_ref rv = new Byte_obj_ref(); + rv.val = val; + return rv; + } private Byte_obj_ref() {} +} diff --git a/100_core/src/gplx/core/primitives/Byte_obj_val.java b/100_core/src/gplx/core/primitives/Byte_obj_val.java new file mode 100644 index 000000000..2f14d17e0 --- /dev/null +++ b/100_core/src/gplx/core/primitives/Byte_obj_val.java @@ -0,0 +1,29 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.primitives; import gplx.*; import gplx.core.*; +public class Byte_obj_val { + public byte Val() {return val;} private byte val; + @Override public String toString() {return Int_.Xto_str(val);} + @Override public int hashCode() {return val;} + @Override public boolean equals(Object obj) {return obj == null ? false : val == ((Byte_obj_val)obj).Val();} + public static Byte_obj_val new_(byte val) { + Byte_obj_val rv = new Byte_obj_val(); + rv.val = val; + return rv; + } private Byte_obj_val() {} +} diff --git a/100_core/src/gplx/core/primitives/Double_obj_val.java b/100_core/src/gplx/core/primitives/Double_obj_val.java new file mode 100644 index 000000000..979216375 --- /dev/null +++ b/100_core/src/gplx/core/primitives/Double_obj_val.java @@ -0,0 +1,32 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.primitives; import gplx.*; import gplx.core.*; +public class Double_obj_val implements CompareAble { + public double Val() {return val;} double val; + @Override public String toString() {return Double_.Xto_str(val);} + @Override public int hashCode() {return (int)val;} + @Override public boolean equals(Object obj) {return obj == null ? false : val == ((Double_obj_val)obj).Val();} + public int compareTo(Object obj) {Double_obj_val comp = (Double_obj_val)obj; return Double_.Compare(val, comp.val);} + public static Double_obj_val neg1_() {return new_(-1);} + public static Double_obj_val zero_() {return new_(0);} + public static Double_obj_val new_(double val) { + Double_obj_val rv = new Double_obj_val(); + rv.val = val; + return rv; + } Double_obj_val() {} +} diff --git a/100_core/src/gplx/core/primitives/Int_obj_ref.java b/100_core/src/gplx/core/primitives/Int_obj_ref.java new file mode 100644 index 000000000..883b71d03 --- /dev/null +++ b/100_core/src/gplx/core/primitives/Int_obj_ref.java @@ -0,0 +1,45 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.primitives; import gplx.*; import gplx.core.*; +public class Int_obj_ref { + public int Val() {return val;} public Int_obj_ref Val_(int v) {val = v; return this;} int val; + public int Val_add() {val++; return val;} + public int Val_add_post() {return val++;} + public int Val_add(int v) {val += v; return val;} + public Int_obj_ref Val_zero_() {val = 0; return this;} + public Int_obj_ref Val_neg1_() {val = -1; return this;} + public String Val_as_str() {return Int_.Xto_str(val);} + @Override public String toString() {return Int_.Xto_str(val);} + @Override public int hashCode() {return val;} + @Override public boolean equals(Object obj) {return val == ((Int_obj_ref)obj).Val();} + public static Int_obj_ref neg1_() {return new_(-1);} + public static Int_obj_ref zero_() {return new_(0);} + public static Int_obj_ref new_(int val) { + Int_obj_ref rv = new Int_obj_ref(); + rv.val = val; + return rv; + } Int_obj_ref() {} + + public static int[] Ary_xto_int_ary(Int_obj_ref[] ary) { + int len = ary.length; + int[] rv = new int[len]; + for (int i = 0; i < len; ++i) + rv[i] = ary[i].val; + return rv; + } +} diff --git a/100_core/src/gplx/core/primitives/Int_obj_val.java b/100_core/src/gplx/core/primitives/Int_obj_val.java new file mode 100644 index 000000000..0f85da27d --- /dev/null +++ b/100_core/src/gplx/core/primitives/Int_obj_val.java @@ -0,0 +1,32 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.primitives; import gplx.*; import gplx.core.*; +public class Int_obj_val implements CompareAble { + public int Val() {return val;} int val; + @Override public String toString() {return Int_.Xto_str(val);} + @Override public int hashCode() {return val;} + @Override public boolean equals(Object obj) {return obj == null ? false : val == ((Int_obj_val)obj).Val();} + public int compareTo(Object obj) {Int_obj_val comp = (Int_obj_val)obj; return Int_.Compare(val, comp.val);} + public static Int_obj_val neg1_() {return new_(-1);} + public static Int_obj_val zero_() {return new_(0);} + public static Int_obj_val new_(int val) { + Int_obj_val rv = new Int_obj_val(); + rv.val = val; + return rv; + } Int_obj_val() {} +} diff --git a/100_core/src/gplx/core/primitives/String_obj_ref.java b/100_core/src/gplx/core/primitives/String_obj_ref.java new file mode 100644 index 000000000..fd4dacf13 --- /dev/null +++ b/100_core/src/gplx/core/primitives/String_obj_ref.java @@ -0,0 +1,30 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.primitives; import gplx.*; import gplx.core.*; +public class String_obj_ref { + public String Val() {return val;} public String_obj_ref Val_(String v) {val = v; return this;} private String val; + public String_obj_ref Val_null_() {return Val_(null);} + @Override public String toString() {return val;} + public static String_obj_ref empty_() {return new_("");} + public static String_obj_ref null_() {return new_(null);} + public static String_obj_ref new_(String val) { + String_obj_ref rv = new String_obj_ref(); + rv.val = val; + return rv; + } String_obj_ref() {} +} diff --git a/100_core/src/gplx/core/primitives/String_obj_val.java b/100_core/src/gplx/core/primitives/String_obj_val.java new file mode 100644 index 000000000..b042bea43 --- /dev/null +++ b/100_core/src/gplx/core/primitives/String_obj_val.java @@ -0,0 +1,27 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.primitives; import gplx.*; import gplx.core.*; +public class String_obj_val implements CompareAble { + public String Val() {return val;} private final String val; + @Override public String toString() {return val;} + public int compareTo(Object obj) { + String_obj_val comp = (String_obj_val)obj; + return String_.Compare_strict(val, comp.val); + } + public static String_obj_val new_(String val) {return new String_obj_val(val);} String_obj_val(String val) {this.val = val;} +} diff --git a/100_core/src/gplx/core/strings/String_bldr.java b/100_core/src/gplx/core/strings/String_bldr.java new file mode 100644 index 000000000..0099a2506 --- /dev/null +++ b/100_core/src/gplx/core/strings/String_bldr.java @@ -0,0 +1,115 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.strings; import gplx.*; import gplx.core.*; +public interface String_bldr { + boolean Has_none(); + boolean Has_some(); + String_bldr Add_many(String... array); + String_bldr Add_fmt(String format, Object... args); + String_bldr Add_fmt_line(String format, Object... args); + String_bldr Add_kv(String hdr, String val); + String_bldr Add_kv_obj(String k, Object v); + String_bldr Add_char_pipe(); + String_bldr Add_char_nl(); + String_bldr Add_char_crlf(); + String_bldr Add_str_w_crlf(String v); + String_bldr Add_spr_unless_first(String s, String spr, int i); + String_bldr Clear(); + String Xto_str_and_clear(); + String XtoStr(); + int Count(); + String_bldr Add(byte[] v); + String_bldr Add(String s); + String_bldr Add(char c); + String_bldr Add(int i); + String_bldr Add_obj(Object o); + String_bldr Add_mid(char[] ary, int bgn, int count); + String_bldr Add_at(int idx, String s); + String_bldr Del(int bgn, int len); +} +abstract class String_bldr_base implements String_bldr { + public boolean Has_none() {return this.Count() == 0;} + public boolean Has_some() {return this.Count() > 0;} + public String_bldr Add_many(String... array) {for (String s : array) Add(s); return this;} + public String_bldr Add_fmt(String format, Object... args) {Add(String_.Format(format, args)); return this;} + public String_bldr Add_fmt_line(String format, Object... args) {Add_str_w_crlf(String_.Format(format, args)); return this;} + public String_bldr Add_kv_obj(String k, Object v) { + if (this.Count() != 0) this.Add(" "); + this.Add_fmt("{0}={1}", k, Object_.Xto_str_strict_or_null_mark(v)); + return this; + } + public String_bldr Add_char_pipe() {return Add("|");} + public String_bldr Add_char_nl() {Add(Op_sys.Lnx.Nl_str()); return this;} + public String_bldr Add_char_crlf() {Add(Op_sys.Wnt.Nl_str()); return this;} + public String_bldr Add_str_w_crlf(String line) {Add(line); Add(String_.CrLf); return this;} + public String_bldr Add_spr_unless_first(String s, String spr, int i) { + if (i != 0) Add(spr); + Add(s); + return this; + } + public String_bldr Add_kv(String hdr, String val) { + if (String_.Len_eq_0(val)) return this; + if (this.Count() != 0) this.Add(' '); + this.Add(hdr); + this.Add(val); + return this; + } + public String_bldr Clear() {Del(0, Count()); return this;} + public String Xto_str_and_clear() { + String rv = XtoStr(); + Clear(); + return rv; + } + @Override public String toString() {return XtoStr();} + public abstract String XtoStr(); + public abstract int Count(); + public abstract String_bldr Add_at(int idx, String s); + public abstract String_bldr Add(byte[] v); + public abstract String_bldr Add(String s); + public abstract String_bldr Add(char c); + public abstract String_bldr Add(int i); + public abstract String_bldr Add_mid(char[] ary, int bgn, int count); + public abstract String_bldr Add_obj(Object o); + public abstract String_bldr Del(int bgn, int len); +} +class String_bldr_thread_single extends String_bldr_base { + private java.lang.StringBuilder sb = new java.lang.StringBuilder(); + @Override public String XtoStr() {return sb.toString();} + @Override public int Count() {return sb.length();} + @Override public String_bldr Add_at(int idx, String s) {sb.insert(idx, s); return this;} + @Override public String_bldr Add(byte[] v) {sb.append(String_.new_u8(v)); return this;} + @Override public String_bldr Add(String s) {sb.append(s); return this;} + @Override public String_bldr Add(char c) {sb.append(c); return this;} + @Override public String_bldr Add(int i) {sb.append(i); return this;} + @Override public String_bldr Add_mid(char[] ary, int bgn, int count) {sb.append(ary, bgn, count); return this;} + @Override public String_bldr Add_obj(Object o) {sb.append(o); return this;} + @Override public String_bldr Del(int bgn, int len) {sb.delete(bgn, len); return this;} +} +class String_bldr_thread_multiple extends String_bldr_base { + private java.lang.StringBuffer sb = new java.lang.StringBuffer(); + @Override public String XtoStr() {return sb.toString();} + @Override public int Count() {return sb.length();} + @Override public String_bldr Add_at(int idx, String s) {sb.insert(idx, s); return this;} + @Override public String_bldr Add(byte[] v) {sb.append(String_.new_u8(v)); return this;} + @Override public String_bldr Add(String s) {sb.append(s); return this;} + @Override public String_bldr Add(char c) {sb.append(c); return this;} + @Override public String_bldr Add(int i) {sb.append(i); return this;} + @Override public String_bldr Add_mid(char[] ary, int bgn, int count) {sb.append(ary, bgn, count); return this;} + @Override public String_bldr Add_obj(Object o) {sb.append(o); return this;} + @Override public String_bldr Del(int bgn, int len) {sb.delete(bgn, len); return this;} +} diff --git a/100_core/src/gplx/core/strings/String_bldr_.java b/100_core/src/gplx/core/strings/String_bldr_.java new file mode 100644 index 000000000..545e11bae --- /dev/null +++ b/100_core/src/gplx/core/strings/String_bldr_.java @@ -0,0 +1,22 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.strings; import gplx.*; import gplx.core.*; +public class String_bldr_ { + public static String_bldr new_() {return new String_bldr_thread_single();} + public static String_bldr new_thread() {return new String_bldr_thread_multiple();} +} diff --git a/100_core/src/gplx/core/strings/String_ring.java b/100_core/src/gplx/core/strings/String_ring.java new file mode 100644 index 000000000..a34a616cd --- /dev/null +++ b/100_core/src/gplx/core/strings/String_ring.java @@ -0,0 +1,61 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.strings; import gplx.*; import gplx.core.*; +public class String_ring { + String[] ary = String_.Ary_empty; + public int Len() {return len;} int len; + public String_ring Max_(int v) { + if (v != max) { + ary = new String[v]; + max = v; + } + return this; + } int max; + public void Clear() { + for (int i = 0; i < max; i++) { + ary[i] = null; + } + len = nxt = 0; + } + int nxt; + public void Push(String v) { + int idx = nxt++; + if (idx == max) { + idx = 0; + } + if (nxt == max) { + nxt = 0; + } + ary[idx] = v; + if (len < max) + ++len; + } + public String[] Xto_str_ary() { + String[] rv = new String[len]; + int ary_i = nxt - 1; + for (int rv_i = len - 1; rv_i > -1; rv_i--) { + if (ary_i == -1) { + ary_i = max - 1; + } + rv[rv_i] = ary[ary_i]; + --ary_i; + } + return rv; + } +// public String Get_at(int i) {return } +} diff --git a/100_core/src/gplx/core/strings/String_ring_tst.java b/100_core/src/gplx/core/strings/String_ring_tst.java new file mode 100644 index 000000000..081a22170 --- /dev/null +++ b/100_core/src/gplx/core/strings/String_ring_tst.java @@ -0,0 +1,46 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.strings; import gplx.*; import gplx.core.*; +import org.junit.*; +public class String_ring_tst { + String_ring_fxt fxt = new String_ring_fxt(); + @Before public void init() {fxt.Clear();} + @Test public void Basic() { + fxt.Clear().Max_(3).Push_many("a") .Expd("a"); + fxt.Clear().Max_(3).Push_many("a", "b") .Expd("a", "b"); + fxt.Clear().Max_(3).Push_many("a", "b", "c") .Expd("a", "b", "c"); + fxt.Clear().Max_(3).Push_many("a", "b", "c", "d") .Expd("b", "c", "d"); + fxt.Clear().Max_(3).Push_many("a", "b", "c", "d", "e") .Expd("c", "d", "e"); + fxt.Clear().Max_(3).Push_many("a", "b", "c", "d", "e", "f") .Expd("d", "e", "f"); + } +} +class String_ring_fxt { + String_ring ring = new String_ring(); + public String_ring_fxt Clear() {ring.Clear(); return this;} + public String_ring_fxt Max_(int v) {ring.Max_(v); return this;} + public String_ring_fxt Push_many(String... ary) { + int ary_len = ary.length; + for (int i = 0; i < ary_len; i++) + ring.Push(ary[i]); + return this; + } + public String_ring_fxt Expd(String... expd) { + Tfds.Eq_ary_str(expd, ring.Xto_str_ary()); + return this; + } +} diff --git a/100_core/src/gplx/core/threads/Gfo_lock.java b/100_core/src/gplx/core/threads/Gfo_lock.java new file mode 100644 index 000000000..378156273 --- /dev/null +++ b/100_core/src/gplx/core/threads/Gfo_lock.java @@ -0,0 +1,28 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.threads; import gplx.*; import gplx.core.*; +import java.util.concurrent.locks.*; +public class Gfo_lock { + private final ReentrantLock lock = new ReentrantLock(true); + public void Lock() { + lock.lock(); + } + public void Unlock() { + lock.unlock(); + } +} diff --git a/100_core/src/gplx/core/threads/Thread_adp.java b/100_core/src/gplx/core/threads/Thread_adp.java new file mode 100644 index 000000000..d36487b07 --- /dev/null +++ b/100_core/src/gplx/core/threads/Thread_adp.java @@ -0,0 +1,45 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.threads; import gplx.*; import gplx.core.*; +import java.lang.*; +public class Thread_adp implements Runnable { + private String name; private GfoInvkAble invk; private String cmd; private GfoMsg msg; + @gplx.Internal protected Thread_adp(String name, GfoInvkAble invk, String cmd, GfoMsg msg) { + this.name = name; this.invk = invk; this.cmd = cmd; this.msg = msg; + this.ctor_ThreadAdp(); + } + void ctor_ThreadAdp() { + this.thread = name == null ? new Thread(this) : new Thread(this, name); + } + public Thread Under_thread() {return thread;} private Thread thread; + public Thread_adp Start() { + thread.start(); + return this; + } + public void Interrupt() {thread.interrupt();} + public void Join() { + try {thread.join();} + catch (Exception e) {Exc_.Noop(e);} + } +// public void Stop() {thread.stop();} + public boolean IsAlive() {return thread.isAlive();} + @Override public void run() { + invk.Invk(GfsCtx._, 0, cmd, msg); + } + public static final Thread_adp Null = new Thread_adp(Thread_adp_.Name_null, GfoInvkAble_.Null, "", GfoMsg_.Null); +} diff --git a/100_core/src/gplx/core/threads/Thread_adp_.java b/100_core/src/gplx/core/threads/Thread_adp_.java new file mode 100644 index 000000000..2e770c84d --- /dev/null +++ b/100_core/src/gplx/core/threads/Thread_adp_.java @@ -0,0 +1,36 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.core.threads; import gplx.*; import gplx.core.*; +public class Thread_adp_ { + public static void Sleep(int milliseconds) { + try {Thread.sleep(milliseconds);} catch (InterruptedException e) {throw Exc_.new_exc(e, "core", "thread interrupted", "milliseconds", milliseconds);} + } + public static void Notify_all(Object o) {o.notifyAll();} + public static void Wait(Object o) { + try {o.wait();} + catch (InterruptedException e) {throw Exc_.new_exc(e, "core", "thread wait");} + } + public static Thread_adp invk_(GfoInvkAble invk, String cmd) {return invk_(Name_null, invk, cmd);} + public static Thread_adp invk_(String name, GfoInvkAble invk, String cmd) {return new Thread_adp(name, invk, cmd, GfoMsg_.Null);} + public static Thread_adp invk_msg_(GfoInvkAble invk, GfoMsg msg) {return invk_msg_(Name_null, invk, msg);} + public static Thread_adp invk_msg_(String name, GfoInvkAble invk, GfoMsg msg) {return new Thread_adp(name, invk, msg.Key(), msg);} + public static void Run_invk_msg(String name, GfoInvkAble invk, GfoMsg m) { + Thread_adp_.invk_msg_(name, invk, m).Start(); + } + public static final String Name_null = null; +} diff --git a/100_core/src_000_err/gplx/Err.java b/100_core/src_000_err/gplx/Err.java new file mode 100644 index 000000000..60b174531 --- /dev/null +++ b/100_core/src_000_err/gplx/Err.java @@ -0,0 +1,63 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Err extends RuntimeException { + @Override public String getMessage() {return Message_gplx();} + public String Key() {return key;} public Err Key_(String v) {key = v; return this;} private String key = ""; + public String Hdr() {return hdr;} public Err Hdr_(String v) {hdr = v; return this;} private String hdr = ""; + public List_adp Args() {return args;} List_adp args = List_adp_.new_(); + public Err Add(String k, Object o) {args.Add(KeyVal_.new_(k, o)); return this;} + @gplx.Internal protected ErrProcData Proc() {return proc;} ErrProcData proc = ErrProcData.Null; + public Ordered_hash CallStack() {return callStack;} Ordered_hash callStack = Ordered_hash_.new_(); + public int CallLevel() {return callLevel;} public Err CallLevel_(int val) {callLevel = val; return this;} public Err CallLevel_1_() {return CallLevel_(1);} int callLevel; + public Err Inner() {return inner;} Err inner; + @gplx.Internal protected static Err hdr_(String hdr) { + Err rv = new Err(); + rv.hdr = hdr; + return rv; + } @gplx.Internal protected Err() {} + @gplx.Internal protected static Err exc_(Exception thrown, String hdr) { + Err rv = hdr_(hdr + ":" + Err_.Message_lang(thrown)); // add a better error description; DATE:2014-08-15 + rv.inner = convert_(thrown); + for (int i = 0; i < rv.inner.callStack.Count(); i++) { + ErrProcData itm = (ErrProcData)rv.inner.callStack.Get_at(i); + rv.callStack.Add(itm.Raw(), itm); + } + return rv; + } + @gplx.Internal protected static Err convert_(Exception thrown) { + Err rv = Err_.as_(thrown); + if (rv == null) + rv = Err_.new_key_1(ClassAdp_.NameOf_obj(thrown), Err_.Message_lang(thrown)); + CallStack_fill(rv, Err_.StackTrace_lang(rv)); + return rv; + } + static void CallStack_fill(Err err, String stackTrace) { + ErrProcData[] ary = ErrProcData.parse_ary_(stackTrace); if (Array_.Len(ary) == 0) return; // no callStack; shouldn't happen, but don't throw error + err.proc = ary[0]; + for (ErrProcData itm : ary) { + String key = itm.Raw(); + if (err.callStack.Has(key)) continue; + err.callStack.Add(key, itm); + } + } + String Message_gplx() { + try {return Err_.Message_gplx(this);} + catch (Exception exc) {Exc_.Noop(exc); return super.getMessage();} + } +} diff --git a/100_core/src_000_err/gplx/ErrMsgWtr.java b/100_core/src_000_err/gplx/ErrMsgWtr.java new file mode 100644 index 000000000..e43447a60 --- /dev/null +++ b/100_core/src_000_err/gplx/ErrMsgWtr.java @@ -0,0 +1,112 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.core.strings.*; +public class ErrMsgWtr { + public String Message_gplx(Exception thrown) { + Err err = Err.convert_(thrown); // convert thrown to Err to make rest of class easier + Err[] innerAry = InnerAsAry(err); + String_bldr sb = String_bldr_.new_(); + WriteError(innerAry, sb, 0); + WriteInner(innerAry, sb); + WriteStack(innerAry, sb); + return sb.XtoStr(); + } + public String Message_gplx_brief(Exception thrown) { + Err err = Err.convert_(thrown); // convert thrown to Err to make rest of proc easier + String_bldr sb = String_bldr_.new_(); + sb.Add(err.Hdr()); + if (err.Args().Count() > 0) sb.Add(" --"); + for (Object kvo : err.Args()) { + KeyVal kv = (KeyVal)kvo; + String key = kv.Key(), val = kv.Val_to_str_or_empty(); + sb.Add_fmt(" {0}='{1}'", key, val); + } + sb.Add_fmt(" [{0}]", err.Key()); + return sb.XtoStr(); + } + void WriteInner(Err[] errAry, String_bldr sb) { + int len = Array_.Len(errAry); if (len <= 1) return; // no inners; return; + for (int i = 1; i < len; i++) + WriteError(errAry, sb, i); + } + void WriteError(Err[] errAry, String_bldr sb, int i) { + Err err = errAry[i]; + String msg = err.Hdr(); + String typ = String_.Eq(err.Key(), "") ? "" : String_.Concat(" <", err.Key(), ">"); + boolean onlyOne = errAry.length == 1; + String idxStr = onlyOne ? "" : Int_.Xto_str(i); + sb.Add(idxStr).Add("\t").Add(msg).Add(typ).Add_char_crlf(); // ex: " @count must be > 0 " + WriteKeyValAry(sb, err.Args()); + sb.Add("\t").Add(err.Proc().SignatureRaw()).Add_char_crlf(); +// WriteKeyValAry(sb, err.ProcArgs()); + } + void WriteKeyValAry(String_bldr sb, List_adp ary) { + // calc keyMax for valIndentLen + int keyMax = 0; + for (Object o : ary) { + KeyVal kv = (KeyVal)o; + int keyLen = String_.Len(kv.Key()); + if (keyLen > keyMax) keyMax = keyLen + 1; // +1 to guarantee one space between key and val + } + if (keyMax < 8)keyMax = 8; // separate by at least 8 chars + for (Object o : ary) { + KeyVal kv = (KeyVal)o; + String key = kv.Key(); int keyLen = String_.Len(key); + String valIndent = String_.Repeat(" ", keyMax - keyLen); + sb.Add("\t\t@").Add(key).Add(valIndent).Add(kv.Val_to_str_or_empty()).Add_char_crlf(); + } + } + void WriteStack(Err[] errAry, String_bldr sb) { + if (Env_.Mode_testing()) return; // only write stack when not testing + int len = Array_.Len(errAry); if (len == 0) return; // shouldn't happen, but don't want to throw err + Err first = errAry[0]; + boolean onlyOne = len == 1; + sb.Add_str_w_crlf(String_.Repeat("-", 80)); + List_adp tmp = List_adp_.new_(); + Ordered_hash callStack = first.CallStack(); int callStackCount = callStack.Count(); + for (int i = 0; i < callStackCount ; i++) { + ErrProcData proc = (ErrProcData)callStack.Get_at(i); + // get procIndex + int idx = -1; + for (int j = 0; j < len; j++) { + ErrProcData comp = errAry[j].Proc(); + if (String_.Eq(proc.Raw(), comp.Raw())) {idx = j; break;} + } + String idxStr = onlyOne ? "" : Int_.Xto_str(idx); + String hdr = idx == -1 ? "\t" : idxStr + "\t"; + String ideAddressSpr = String_.CrLf + "\t\t"; + String ideAddress = String_.Eq(proc.IdeAddress(), "") ? "" : ideAddressSpr + proc.IdeAddress(); // NOTE: ideAddress will be blank in compiled mode + String msg = String_.Concat(hdr, proc.SignatureRaw(), ideAddress); + tmp.Add(msg); + } + tmp.Reverse(); + for (Object o : tmp) + sb.Add_str_w_crlf((String)o); + } + static Err[] InnerAsAry(Err err) { + List_adp errAry = List_adp_.new_(); + Err cur = Err_.as_(err); + while (cur != null) { + errAry.Add(cur); + cur = cur.Inner(); + } + return (Err[])errAry.To_ary(Err.class); + } + public static final ErrMsgWtr _ = new ErrMsgWtr(); ErrMsgWtr() {} +} diff --git a/100_core/src_000_err/gplx/ErrProcData.java b/100_core/src_000_err/gplx/ErrProcData.java new file mode 100644 index 000000000..be808aa52 --- /dev/null +++ b/100_core/src_000_err/gplx/ErrProcData.java @@ -0,0 +1,67 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +class ErrProcData { + public String Raw() {return raw;} public ErrProcData Raw_(String val) {raw = val; return this;} private String raw = String_.Empty; + public String SignatureRaw() {return signatureRaw;} public ErrProcData SignatureRaw_(String val) {signatureRaw = val; return this;} private String signatureRaw = String_.Empty; + public String SourceFileRaw() {return sourceFileRaw;} public ErrProcData SourceFileRaw_(String val) {sourceFileRaw = val; return this;} private String sourceFileRaw = String_.Empty; + public int SourceLine() {return sourceLine;} public ErrProcData SourceLine_(int val) {sourceLine = val; return this;} int sourceLine; + public String IdeAddress() {return ideAddress;} public ErrProcData IdeAddress_(String val) {ideAddress = val; return this;} private String ideAddress = String_.Empty; + + public static ErrProcData[] parse_ary_(String stackTrace) { + /* + .java + ' at gplx.Err.new_(Err.java:92) + at gplx.Err.exc_(Err.java:43) + at gplx.Err_.err_(Err_.java:4) + at gplx._tst.Err__tst.RdrLoad(Err__tst.java:77) + at gplx._tst.Err__tst.MgrInit(Err__tst.java:76)' + .cs + ' at gplx._tst.Err__tst.RdrLoad() in c:\000\200_dev\100.gplx\100.framework\100.core\gplx\tst\gplx\err__tst.cs:line 77 + at gplx._tst.Err__tst.MgrInit(String s) in c:\000\200_dev\100.gplx\100.framework\100.core\gplx\tst\gplx\err__tst.cs:line 76' + */ + if (stackTrace == null) return new ErrProcData[0]; + String[] lines = String_.SplitLines_any(stackTrace); + List_adp list = List_adp_.new_(); + int len = Array_.Len(lines); + for (int i = 0; i < len; i++) { + ErrProcData md = ErrProcData.parse_(lines[i]); + if (md.SourceLine() == 0) break; // ASSUME: java code; not interested + if (String_.Has_at_bgn(md.signatureRaw, "gplx.Err_") || String_.Has_at_bgn(md.signatureRaw, "gplx.Err.")) continue; // java includes entire stackTrace from point of creation; only care about point of throw + list.Add(md); + } + return (ErrProcData[])list.To_ary(ErrProcData.class); + } + public static ErrProcData parse_(String raw) { + ErrProcData rv = new ErrProcData().Raw_(raw); + // ex:'gplx.Err.new_(Err.java:92)' + int sigEnd = String_.FindFwd(raw, "("); if (sigEnd == String_.Find_none) return rv; + rv.signatureRaw = String_.Mid(raw, 0, sigEnd); + int filBgn = sigEnd + 1; // 1="(" + int filEnd = String_.FindFwd(raw, ":", filBgn); if (filEnd == String_.Find_none) return rv; + rv.sourceFileRaw = String_.Mid(raw, filBgn, filEnd); + int linBgn = filEnd + 1; // 1=":" + int linEnd = String_.FindFwd(raw, ")", linBgn); if (linEnd == String_.Find_none) return rv; + String linRaw = String_.Mid(raw, linBgn, linEnd); + rv.sourceLine = Int_.parse_(linRaw); + rv.ideAddress = String_.Concat("(", rv.sourceFileRaw, ":", Int_.Xto_str(rv.sourceLine), ")"); + return rv; + } + public static ErrProcData new_() {return new ErrProcData();} ErrProcData() {} + public static final ErrProcData Null = new ErrProcData(); +} diff --git a/100_core/src_000_err/gplx/ErrProcData_tst.java b/100_core/src_000_err/gplx/ErrProcData_tst.java new file mode 100644 index 000000000..574890cdc --- /dev/null +++ b/100_core/src_000_err/gplx/ErrProcData_tst.java @@ -0,0 +1,48 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class ErrProcData_tst { + @Test public void parse_() { + tst_parse_("gplx._tst.Err__tst.RdrLoad(MethodData_tst.java:1)" + , ErrProcData.new_() + .SignatureRaw_("gplx._tst.Err__tst.RdrLoad") + .SourceFileRaw_("MethodData_tst.java") + .SourceLine_(1) + .IdeAddress_("(MethodData_tst.java:1)") + ); + } + @Test public void parse_ary_() { + String stackTrace = ""; + try {ThrowException();} catch (Exception exc) {stackTrace = Err_.StackTrace_lang(exc);} + ErrProcData[] ary = ErrProcData.parse_ary_(stackTrace); + Tfds.Eq(2, Array_.Len(ary)); + Tfds.Eq("gplx.ErrProcData_tst.ThrowException", ary[0].SignatureRaw()); + Tfds.Eq("gplx.ErrProcData_tst.parse_ary_", ary[1].SignatureRaw()); + } + Exception ThrowException() { + throw new RuntimeException("msg"); + } + void tst_parse_(String raw, ErrProcData expd) { + ErrProcData actl = ErrProcData.parse_(raw); + Tfds.Eq(expd.SignatureRaw(), actl.SignatureRaw()); + Tfds.Eq(expd.SourceFileRaw(), actl.SourceFileRaw()); + Tfds.Eq(expd.SourceLine(), actl.SourceLine()); + Tfds.Eq(expd.IdeAddress(), actl.IdeAddress()); + } +} diff --git a/100_core/src_000_err/gplx/Err_.java b/100_core/src_000_err/gplx/Err_.java new file mode 100644 index 000000000..a1ce685d6 --- /dev/null +++ b/100_core/src_000_err/gplx/Err_.java @@ -0,0 +1,36 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.core.strings.*; +public class Err_ { //_20110415 + public static Err as_(Object obj) {return obj instanceof Err ? (Err)obj : null;} + @gplx.Internal protected static Err new_key_1(String key, String hdr) {return Err.hdr_(hdr).Key_(key);} + public static String Message_lang(Exception e) {return e.getMessage();} + public static String Message_gplx(Exception e) {return ErrMsgWtr._.Message_gplx(e);} + public static String Message_gplx_brief(Exception e) {return ErrMsgWtr._.Message_gplx_brief(e);} + @gplx.Internal protected static String StackTrace_lang(Exception e) { + String_bldr sb = String_bldr_.new_(); + StackTraceElement[] stackTraceAry = e.getStackTrace(); + int len = stackTraceAry.length; + for (int i = 0; i < len; i++) { + if (i != 0) sb.Add_char_crlf(); + sb.Add(stackTraceAry[i].toString()); + } + return sb.XtoStr(); + } +} diff --git a/100_core/src_000_err/gplx/Err_arg.java b/100_core/src_000_err/gplx/Err_arg.java new file mode 100644 index 000000000..fee3dd571 --- /dev/null +++ b/100_core/src_000_err/gplx/Err_arg.java @@ -0,0 +1,53 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Err_arg extends Err { + public String ArgName() {return argName;} private String argName; + public Object ArgValue() {return argValue;} Object argValue; + public static Err_arg null_(String argName) { + Err_arg rv = new Err_arg(); + rv.Key_("gplx.arg").Hdr_("@" + rv.argName + " cannot be null"); + rv.argName = argName; + return rv; + } + public static Err_arg cannotBe_(String msg, String argName, Object argValue) { + Err_arg rv = new Err_arg(); + rv.Key_("gplx.arg"); + rv.Hdr_("val cannot be " + msg); + rv.Add("key", argName); + rv.Add("val", argValue); + return rv; + } + public static Err_arg notFound_key_(String argName, Object argValue) { + Err_arg rv = new Err_arg(); + rv.Key_("gplx.arg").Hdr_("arg not found").Add(argName, argValue); + rv.argName = argName; + rv.argValue = argValue; + return rv; + } + public static Err_arg outOfBounds_(String argName, int i, int count) { + Err_arg rv = new Err_arg(); + rv.Key_("gplx.arg").Hdr_("arg out of bounds").Add("argName", argName).Add("argVal", i).Add("count", count); + rv.argName = argName; + rv.argValue = i; + return rv; + } + public static boolean ClassCheck(Exception e) { + return ClassAdp_.Eq_typeSafe(e, Err_arg.class); + } +} diff --git a/100_core/src_000_err/gplx/Gfo_msg_data.java b/100_core/src_000_err/gplx/Gfo_msg_data.java new file mode 100644 index 000000000..4d1456804 --- /dev/null +++ b/100_core/src_000_err/gplx/Gfo_msg_data.java @@ -0,0 +1,34 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Gfo_msg_data { + public int Uid() {return uid;} int uid = uid_next++; + public Gfo_msg_itm Item() {return item;} Gfo_msg_itm item; + public Object[] Vals() {return vals;} Object[] vals; + public byte[] Src_bry() {return src_bry;} private byte[] src_bry; + public int Src_bgn() {return src_bgn;} int src_bgn; + public int Src_end() {return src_end;} int src_end; + public Gfo_msg_data Ctor_val_many(Gfo_msg_itm item, Object[] vals) {this.item = item; this.vals = vals; return this;} + public Gfo_msg_data Ctor_src_many(Gfo_msg_itm item, byte[] src_bry, int src_bgn, int src_end, Object[] vals) {this.item = item; this.src_bry = src_bry; this.src_bgn = src_bgn; this.src_end = src_end; this.vals = vals; return this;} + public void Clear() { + item = null; vals = null; src_bry = null; + } + public String Gen_str_ary() {return item.Gen_str_ary(vals);} + static int uid_next = 0; + public static final Gfo_msg_data[] Ary_empty = new Gfo_msg_data[0]; +} diff --git a/100_core/src_000_err/gplx/Gfo_msg_grp.java b/100_core/src_000_err/gplx/Gfo_msg_grp.java new file mode 100644 index 000000000..1106ed587 --- /dev/null +++ b/100_core/src_000_err/gplx/Gfo_msg_grp.java @@ -0,0 +1,46 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Gfo_msg_grp implements Gfo_msg_obj { + public Gfo_msg_grp(Gfo_msg_grp owner, int uid, byte[] key) { + this.owner = owner; this.uid = uid; this.key = key; this.key_str = String_.new_a7(key); + if (owner != null) { + owner.subs.Add(this); + path = Gfo_msg_grp_.Path(owner.path, key); + } + else + path = Bry_.Empty; + } + public void Subs_clear() {subs.Clear();} + public Gfo_msg_grp Owner() {return owner;} Gfo_msg_grp owner; + public int Uid() {return uid;} int uid; + public byte[] Key() {return key;} private byte[] key; + public String Key_str() {return key_str;} private String key_str; + public byte[] Path() {return path;} private byte[] path; + public String Path_str() {return String_.new_a7(path);} + public Gfo_msg_obj Subs_get_by_key(String sub_key) { + int subs_len = subs.Count(); + for (int i = 0; i < subs_len; i++) { + Gfo_msg_obj sub = (Gfo_msg_obj)subs.Get_at(i); + if (String_.Eq(sub_key, sub.Key_str())) return sub; + } + return null; + } + public void Subs_add(Gfo_msg_itm item) {subs.Add(item);} + List_adp subs = List_adp_.new_(); +} diff --git a/100_core/src_000_err/gplx/Gfo_msg_grp_.java b/100_core/src_000_err/gplx/Gfo_msg_grp_.java new file mode 100644 index 000000000..cae3e8c9a --- /dev/null +++ b/100_core/src_000_err/gplx/Gfo_msg_grp_.java @@ -0,0 +1,30 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Gfo_msg_grp_ { + public static final Gfo_msg_grp Root_gplx = new Gfo_msg_grp(null, Gfo_msg_grp_.Uid_next(), Bry_.new_a7("gplx")); + public static final Gfo_msg_grp Root = new Gfo_msg_grp(null, Gfo_msg_grp_.Uid_next(), Bry_.Empty); + public static Gfo_msg_grp prj_(String key) {return new Gfo_msg_grp(Root , Gfo_msg_grp_.Uid_next(), Bry_.new_a7(key));} + public static Gfo_msg_grp new_(Gfo_msg_grp owner, String key) {return new Gfo_msg_grp(owner , Gfo_msg_grp_.Uid_next(), Bry_.new_a7(key));} + public static int Uid_next() {return uid_next++;} static int uid_next = 0; + public static byte[] Path(byte[] owner_path, byte[] key) { + if (owner_path != Bry_.Empty) tmp_bfr.Add(owner_path).Add_byte(Byte_ascii.Dot); // only add "." if owner_path is available; prevents creating ".gplx" + return tmp_bfr.Add(key).Xto_bry_and_clear(); + } + static Bry_bfr tmp_bfr = Bry_bfr.reset_(256); +} diff --git a/100_core/src_000_err/gplx/Gfo_msg_itm.java b/100_core/src_000_err/gplx/Gfo_msg_itm.java new file mode 100644 index 000000000..65c61278f --- /dev/null +++ b/100_core/src_000_err/gplx/Gfo_msg_itm.java @@ -0,0 +1,57 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Gfo_msg_itm implements Gfo_msg_obj { + public Gfo_msg_itm(Gfo_msg_grp owner, int uid, byte cmd, byte[] key_bry, byte[] fmt, boolean add_to_owner) { + this.owner = owner; this.uid = uid; this.cmd = cmd; this.key_bry = key_bry; this.fmt = fmt; + this.key_str = String_.new_a7(key_bry); + this.path_bry = Gfo_msg_grp_.Path(owner.Path(), key_bry); + if (add_to_owner) owner.Subs_add(this); + } + public Gfo_msg_grp Owner() {return owner;} Gfo_msg_grp owner; + public int Uid() {return uid;} int uid; + public byte[] Path_bry() {return path_bry;} private byte[] path_bry; + public String Path_str() {return String_.new_u8(path_bry);} + public byte[] Key_bry() {return key_bry;} private byte[] key_bry; + public String Key_str() {return key_str;} private String key_str; + public Gfo_msg_obj Subs_get_by_key(String sub_key) {return null;} + public byte Cmd() {return cmd;} private byte cmd; + public byte[] Fmt() {return fmt;} private byte[] fmt; + public Bry_fmtr Fmtr() {if (fmtr == null) fmtr = Bry_fmtr.new_bry_(fmt).Compile(); return fmtr;} Bry_fmtr fmtr; + public String Gen_str_many(Object... vals) {return Gen_str_ary(vals);} + public String Gen_str_ary(Object[] vals) { + if (fmtr == null) fmtr = Bry_fmtr.new_bry_(fmt).Compile(); + if (fmtr.Fmt_args_exist()) { + fmtr.Bld_bfr_many(tmp_bfr, vals); + return tmp_bfr.Xto_str_and_clear(); + } + else + return String_.new_u8(fmt); + } + public String Gen_str_one(Object val) { + if (fmtr == null) fmtr = Bry_fmtr.new_bry_(fmt).Compile(); + if (fmtr.Fmt_args_exist()) { + fmtr.Bld_bfr_one(tmp_bfr, val); + return tmp_bfr.Xto_str_and_clear(); + } + else + return String_.new_u8(fmt); + } + public String Gen_str_none() {return key_str;} + static Bry_bfr tmp_bfr = Bry_bfr.reset_(255); +} diff --git a/100_core/src_000_err/gplx/Gfo_msg_itm_.java b/100_core/src_000_err/gplx/Gfo_msg_itm_.java new file mode 100644 index 000000000..f3321d6b0 --- /dev/null +++ b/100_core/src_000_err/gplx/Gfo_msg_itm_.java @@ -0,0 +1,27 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Gfo_msg_itm_ { + public static final byte Cmd_null = 0, Cmd_log = 1, Cmd_note = 2, Cmd_warn = 3, Cmd_stop = 4, Cmd_fail = 5; + public static final byte[][] CmdBry = new byte[][] {Bry_.new_a7("null"), Bry_.new_a7("log"), Bry_.new_a7("note"), Bry_.new_a7("warn"), Bry_.new_a7("stop"), Bry_.new_a7("fail")}; + public static Gfo_msg_itm new_note_(Gfo_msg_grp owner, String key) {return new_(owner, Cmd_note, key, key);} + public static Gfo_msg_itm new_fail_(Gfo_msg_grp owner, String key, String fmt) {return new_(owner, Cmd_warn, key, fmt);} + public static Gfo_msg_itm new_warn_(Gfo_msg_grp owner, String key) {return new_(owner, Cmd_warn, key, key);} + public static Gfo_msg_itm new_warn_(Gfo_msg_grp owner, String key, String fmt) {return new_(owner, Cmd_warn, key, fmt);} + public static Gfo_msg_itm new_(Gfo_msg_grp owner, byte cmd, String key, String fmt) {return new Gfo_msg_itm(owner, Gfo_msg_grp_.Uid_next(), cmd, Bry_.new_a7(key), Bry_.new_a7(fmt), false);} +} diff --git a/100_core/src_000_err/gplx/Gfo_msg_log.java b/100_core/src_000_err/gplx/Gfo_msg_log.java new file mode 100644 index 000000000..112deb916 --- /dev/null +++ b/100_core/src_000_err/gplx/Gfo_msg_log.java @@ -0,0 +1,54 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Gfo_msg_log { + public Gfo_msg_log(String root_key) {root = new Gfo_msg_root(root_key);} Gfo_msg_root root; + public int Ary_len() {return ary_idx;} + public Gfo_msg_data Ary_get(int i) {return ary[i];} + public Gfo_msg_log Clear() { + for (int i = 0; i < ary_idx; i++) + ary[i].Clear(); + ary_idx = 0; + return this; + } + public Gfo_msg_log Add_str_warn_key_none(String grp, String itm, byte[] src, int pos) {return Add_str(Gfo_msg_itm_.Cmd_warn, grp, itm, null, src, pos, pos + 1, null);} + public Gfo_msg_log Add_str_warn_key_none(String grp, String itm, byte[] src, int bgn, int end) {return Add_str(Gfo_msg_itm_.Cmd_warn, grp, itm, null, src, bgn, end, null);} + public Gfo_msg_log Add_str_warn_fmt_none(String grp, String itm, String fmt) {return Add_str(Gfo_msg_itm_.Cmd_warn, grp, itm, fmt , Bry_.Empty, -1, -1, null);} + public Gfo_msg_log Add_str_warn_fmt_none(String grp, String itm, String fmt, byte[] src, int pos) {return Add_str(Gfo_msg_itm_.Cmd_warn, grp, itm, fmt , src, pos, pos + 1, null);} + public Gfo_msg_log Add_str_warn_fmt_none(String grp, String itm, String fmt, byte[] src, int bgn, int end) {return Add_str(Gfo_msg_itm_.Cmd_warn, grp, itm, fmt , src, bgn, end, null);} + public Gfo_msg_log Add_str_warn_fmt_many(String grp, String itm, String fmt, Object... vals) {return Add_str(Gfo_msg_itm_.Cmd_warn, grp, itm, fmt , Bry_.Empty, -1, -1, vals);} + Gfo_msg_log Add_str(byte cmd, String owner_key, String itm, String fmt, byte[] src, int bgn, int end, Object[] vals) { + if (ary_idx >= ary_max) ary_expand(); + ary[ary_idx++] = root.Data_new_many(cmd, src, bgn, end, owner_key, itm, fmt, vals); + return this; + } + public Gfo_msg_log Add_itm_none(Gfo_msg_itm itm, byte[] src, int bgn, int end) {return Add_itm(itm, src, bgn, end, null);} + public Gfo_msg_log Add_itm_many(Gfo_msg_itm itm, byte[] src, int bgn, int end, Object... val_ary) {return Add_itm(itm, src, bgn, end, val_ary);} + Gfo_msg_log Add_itm(Gfo_msg_itm itm, byte[] src, int bgn, int end, Object[] vals) { + if (ary_idx >= ary_max) ary_expand(); + ary[ary_idx++] = root.Data_new_many(itm, src, bgn, end, vals); + return this; + } + void ary_expand() { + int new_max = ary_max == 0 ? 2 : ary_max * 2; + ary = (Gfo_msg_data[])Array_.Expand(ary, new Gfo_msg_data[new_max], ary_max); + ary_max = new_max; + } + Gfo_msg_data[] ary = Gfo_msg_data.Ary_empty; int ary_idx, ary_max; + public static Gfo_msg_log Test() {return new Gfo_msg_log("test");} +} diff --git a/100_core/src_000_err/gplx/Gfo_msg_obj.java b/100_core/src_000_err/gplx/Gfo_msg_obj.java new file mode 100644 index 000000000..0e166b958 --- /dev/null +++ b/100_core/src_000_err/gplx/Gfo_msg_obj.java @@ -0,0 +1,22 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public interface Gfo_msg_obj { + String Key_str(); + Gfo_msg_obj Subs_get_by_key(String sub_key); +} diff --git a/100_core/src_000_err/gplx/Gfo_msg_root.java b/100_core/src_000_err/gplx/Gfo_msg_root.java new file mode 100644 index 000000000..015646e7f --- /dev/null +++ b/100_core/src_000_err/gplx/Gfo_msg_root.java @@ -0,0 +1,80 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Gfo_msg_root { + public Gfo_msg_root(String root_key) { + this.root_key = root_key; + this.root = Gfo_msg_grp_.new_(Gfo_msg_grp_.Root, root_key); + } String root_key; + public void Data_ary_clear() { + for (int i = 0; i < data_ary_idx; i++) + data_ary[i].Clear(); + data_ary_idx = 0; + } + public void Data_ary_len_(int v) { + data_ary_len = v; + data_ary = new Gfo_msg_data[data_ary_len]; + for (int i = 0; i < data_ary_len; i++) + data_ary[i] = new Gfo_msg_data(); + data_ary_idx = 0; + } int data_ary_len; int data_ary_idx; Gfo_msg_data[] data_ary; + public void Reset() { + root.Subs_clear(); + owners.Clear(); + uid_list_next = uid_item_next = 0; + Data_ary_clear(); + } + public Gfo_msg_data Data_new_note_many(String owner_key, String key, String fmt, Object... vals) {return Data_new_many(Gfo_msg_itm_.Cmd_note, Bry_.Empty, -1, -1, owner_key, key, fmt, vals);} + public Gfo_msg_data Data_new_many(byte cmd, String owner_key, String key, String fmt, Object[] vals) {return Data_new_many(cmd, Bry_.Empty, -1, -1, owner_key, key, fmt, vals);} + public Gfo_msg_data Data_new_many(byte cmd, byte[] src, int bgn, int end, String owner_key, String key, String fmt, Object[] vals) { + Object owner_obj = owners.Get_by(owner_key); + Gfo_msg_grp owner = null; + if (owner_obj == null) { + owner = New_list_by_key(owner_key); + owners.Add(owner_key, owner); + } + else + owner = (Gfo_msg_grp)owner_obj; + Gfo_msg_itm itm = (Gfo_msg_itm)owner.Subs_get_by_key(key); + if (itm == null) + itm = new Gfo_msg_itm(owner, uid_item_next++, cmd, Bry_.new_u8(key), fmt == null ? Bry_.Empty : Bry_.new_a7(fmt), false); + return Data_new_many(itm, src, bgn, end, vals); + } + public Gfo_msg_data Data_new_many(Gfo_msg_itm itm, byte[] src, int bgn, int end, Object... vals) {return Data_get().Ctor_src_many(itm, src, bgn, end, vals);} + public Gfo_msg_data Data_get() { + return data_ary_idx < data_ary_len ? data_ary[data_ary_idx++] : new Gfo_msg_data(); + } + Gfo_msg_grp New_list_by_key(String key) { + String[] segs = String_.Split(key, '.'); + int segs_len = segs.length; int segs_last = segs_len - 1; + Gfo_msg_grp cur_list = root; + for (int i = 0; i < segs_last; i++) { + String seg = segs[i]; + Gfo_msg_grp sub_list = (Gfo_msg_grp)cur_list.Subs_get_by_key(seg); + if (sub_list == null) + sub_list = new Gfo_msg_grp(cur_list, uid_list_next++, Bry_.new_a7(key)); + cur_list = sub_list; + } + return cur_list; + } + Gfo_msg_grp root; + Ordered_hash owners = Ordered_hash_.new_(); + int uid_list_next = 0; + int uid_item_next = 0; + public static final Gfo_msg_root _ = new Gfo_msg_root("gplx"); +} diff --git a/100_core/src_000_err/gplx/Gfo_msg_root_tst.java b/100_core/src_000_err/gplx/Gfo_msg_root_tst.java new file mode 100644 index 000000000..94fa66dba --- /dev/null +++ b/100_core/src_000_err/gplx/Gfo_msg_root_tst.java @@ -0,0 +1,62 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class Gfo_msg_root_tst { + Gfo_msg_root_fxt fxt = new Gfo_msg_root_fxt(); + @Before public void setup() {fxt.Reset();} + @Test public void Str() { + fxt.Clear().Expd_data_str_("failed a0 b0").Tst_data_new_many("proj.cls.proc", "err_0", "failed ~{0} ~{1}", "a0", "b0"); + fxt.Clear().Expd_data_str_("failed a1 b1").Tst_data_new_many("proj.cls.proc", "err_0", "failed ~{0} ~{1}", "a1", "b1"); + } +// @Test public void Item() { // DISABLED: no longer registering items with owner; +// fxt.Clear().Expd_item_uid_(0).Expd_item_fmtr_arg_exists_(Bool_.Y).Tst_data_new_many("proj.cls.proc", "err_0", "failed ~{0} ~{1}", "a0", "b0"); +// fxt.Clear().Expd_item_uid_(1).Expd_item_fmtr_arg_exists_(Bool_.N).Tst_data_new_many("proj.cls.proc", "err_1", "failed"); +// fxt.Clear().Expd_item_uid_(0).Tst_data_new_many("proj.cls.proc", "err_0", "failed ~{0} ~{1}", "a0", "b0"); // make sure item_uid stays the same +// } + @Test public void Cache() { + fxt.Mgr().Data_ary_len_(2); + fxt.Clear().Expd_data_uid_(0).Tst_data_new_many("x", "err_0", "a"); + fxt.Clear().Expd_data_uid_(1).Tst_data_new_many("x", "err_0", "b"); + fxt.Clear().Expd_data_uid_(2).Tst_data_new_many("x", "err_0", "a"); + fxt.Mgr().Data_ary_clear(); + fxt.Clear().Expd_data_uid_(0).Tst_data_new_many("x", "err_0", "a"); + } +} +class Gfo_msg_root_fxt { + Gfo_msg_root root = new Gfo_msg_root("tst"); + public Gfo_msg_root_fxt Reset() {root.Reset(); this.Clear(); return this;} + public Gfo_msg_root_fxt Clear() { + expd_item_uid = -1; + expd_item_fmtr_arg_exists = Bool_.__byte; + expd_data_uid = -1; + expd_data_str = null; + return this; + } + public Gfo_msg_root Mgr() {return root;} + public Gfo_msg_root_fxt Expd_data_uid_(int v) {this.expd_data_uid = v; return this;} int expd_data_uid; + public Gfo_msg_root_fxt Expd_data_str_(String v) {this.expd_data_str = v; return this;} private String expd_data_str; + public Gfo_msg_root_fxt Expd_item_uid_(int v) {this.expd_item_uid = v; return this;} int expd_item_uid; + public Gfo_msg_root_fxt Expd_item_fmtr_arg_exists_(boolean v) {this.expd_item_fmtr_arg_exists = v ? Bool_.Y_byte : Bool_.N_byte; return this;} private byte expd_item_fmtr_arg_exists; + public void Tst_data_new_many(String path, String key, String fmt, Object... vals) { + Gfo_msg_data data = root.Data_new_many(Gfo_msg_itm_.Cmd_note, path, key, fmt, vals); + if (expd_item_uid != -1) Tfds.Eq(expd_item_uid, data.Item().Uid());; + if (expd_item_fmtr_arg_exists != Bool_.__byte) Tfds.Eq(Bool_.By_int(expd_item_fmtr_arg_exists), data.Item().Fmtr().Fmt_args_exist()); + if (expd_data_str != null) Tfds.Eq(expd_data_str, data.Item().Gen_str_many(data.Vals())); + } +} diff --git a/100_core/src_100_interface/gplx/Cancelable.java b/100_core/src_100_interface/gplx/Cancelable.java new file mode 100644 index 000000000..6d32f5e09 --- /dev/null +++ b/100_core/src_100_interface/gplx/Cancelable.java @@ -0,0 +1,23 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public interface Cancelable { + boolean Canceled(); + void Cancel(); + void Cancel_reset(); +} diff --git a/100_core/src_100_interface/gplx/Cancelable_.java b/100_core/src_100_interface/gplx/Cancelable_.java new file mode 100644 index 000000000..dc1808aac --- /dev/null +++ b/100_core/src_100_interface/gplx/Cancelable_.java @@ -0,0 +1,26 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Cancelable_ { + public static final Cancelable Never = new Cancelable_never(); +} +class Cancelable_never implements Cancelable { + public boolean Canceled() {return false;} + public void Cancel() {} + public void Cancel_reset() {} +} diff --git a/100_core/src_100_interface/gplx/CompareAble.java b/100_core/src_100_interface/gplx/CompareAble.java new file mode 100644 index 000000000..5e8bcb7ef --- /dev/null +++ b/100_core/src_100_interface/gplx/CompareAble.java @@ -0,0 +1,20 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public interface CompareAble extends Comparable {} // URL:/doc/gplx/CompareAble_.txt +// public int compareTo(Object obj) {Type comp = (Type)obj; return prop.compareTo(comp.prop);} diff --git a/100_core/src_100_interface/gplx/CompareAble_.java b/100_core/src_100_interface/gplx/CompareAble_.java new file mode 100644 index 000000000..8622eafe6 --- /dev/null +++ b/100_core/src_100_interface/gplx/CompareAble_.java @@ -0,0 +1,78 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.lists.*; +public class CompareAble_ { + public static Comparable as_(Object obj) {return obj instanceof Comparable ? (Comparable)obj : null;} + public static int Compare_obj(Object lhs, Object rhs) {return CompareComparables(as_(lhs), as_(rhs));} + public static int CompareComparables(Comparable lhs, Comparable rhs) { + if (lhs == null && rhs == null) return CompareAble_.Same; + else if (lhs == null) return CompareAble_.More; + else if (rhs == null) return CompareAble_.Less; + else return Compare(lhs, rhs); + } + + public static boolean Is_more(Comparable lhs, Comparable rhs) {return Is(More, lhs, rhs);} + public static boolean Is_moreOrSame(Comparable lhs, Comparable rhs) {return Is(MoreOrSame, lhs, rhs);} + public static boolean Is_less(Comparable lhs, Comparable rhs) {return Is(Less, lhs, rhs);} + public static boolean Is_lessOrSame(Comparable lhs, Comparable rhs) {return Is(LessOrSame, lhs, rhs);} + public static boolean Is_same(Comparable lhs, Comparable rhs) {return Is(Same, lhs, rhs);} + public static boolean Is(int expt, Comparable lhs, Comparable rhs) { + int actl = CompareComparables(lhs, rhs); + if (actl == Same && expt % 2 == Same) // actl=Same and expt=(Same||MoreOrSame||LessOrSame) + return true; + else + return (actl * expt) > 0; // actl=More||Less; expd will match if on same side of 0 (ex: expt=Less; actl=Less; -1 * -1 = 1) + } +// public static int FindSlot(ComparerAble comparer, Object[] ary, Object itm) {return FindSlot(comparer, ary, itm, false);} + public static int FindSlot(ComparerAble comparer, Object[] ary, Object itm) {if (itm == null) throw Exc_.new_null("itm is null"); + int aryLen = ary.length; + switch (aryLen) { + case 0: throw Exc_.new_("ary cannot have 0 itms"); + case 1: return 0; + } + int lo = -1, hi = aryLen - 1; // NOTE: -1 is necessary; see test + int curPos = (hi - lo) / 2; + int delta = 1; + while (true) { + Object curSeg = ary[curPos]; + int comp = curSeg == null ? CompareAble_.More : comparer.compare(itm, curSeg); // nulls should only happen for lastAry +// if (dbg) { +// Tfds.Write(curPos, itm.toString(), comp, comp.toString(), curSeg.toString()); +// } + if (comp == CompareAble_.Same) return curPos; + else if (comp > CompareAble_.Same) {lo = curPos; delta = 1;} + else if (comp < CompareAble_.Same) {hi = curPos; delta = -1;} + int dif = hi - lo; + if (dif == 1 || dif == 0) return hi; // NOTE: can be 0 when ary.length == 1 || 2; also, sometimes 0 in some situations + else curPos += (dif / 2) * delta; + } + } + public static int Compare(Comparable lhs, Comparable rhs) {return lhs.compareTo(rhs);} + + public static final int + More = 1 + , Less = -1 + , Same = 0 + , MoreOrSame = 2 + , LessOrSame = -2 + , ReverseMult = -1 + , OffsetCompare = 1 // handle srcPos >= 1 -> srcPosChk > 0 + ; + public static int Multiplier(boolean v) {return v ? 1 : -1;} +} diff --git a/100_core/src_100_interface/gplx/CompareAble_tst.java b/100_core/src_100_interface/gplx/CompareAble_tst.java new file mode 100644 index 000000000..b167ca0a8 --- /dev/null +++ b/100_core/src_100_interface/gplx/CompareAble_tst.java @@ -0,0 +1,38 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +import gplx.lists.*; +public class CompareAble_tst implements ComparerAble { + @Test public void Basic() { + String[] slotAry = new String[] {"b", "e", "h"}; // 0=b 1=e 2=h + tst_FindSlot(slotAry, "f", "h"); // f -> 1 2 -> 2 + tst_FindSlot(slotAry, "c", "e"); // c -> -1 1 -> 0 -> 0 1 -> 1 + tst_FindSlot(slotAry, "a", "b"); // a -> -1 1 -> 0 -> -1 0 -> 0 + } + @Test public void Null() { + String[] slotAry = new String[] {"b", "g", "l", "q", "v", null}; + tst_FindSlot(slotAry, "a", "b"); + tst_FindSlot(slotAry, "b", "b"); + tst_FindSlot(slotAry, "c", "g"); + tst_FindSlot(slotAry, "v", "v"); + tst_FindSlot(slotAry, "w", null); + } + public int compare(Object lhsObj, Object rhsObj) {return CompareAble_.Compare_obj(lhsObj, rhsObj);} + void tst_FindSlot(String[] slotAry, String s, String expd) {Tfds.Eq(expd, slotAry[CompareAble_.FindSlot(this, slotAry, s)]);} +} diff --git a/100_core/src_100_interface/gplx/EqAble.java b/100_core/src_100_interface/gplx/EqAble.java new file mode 100644 index 000000000..c23db7e63 --- /dev/null +++ b/100_core/src_100_interface/gplx/EqAble.java @@ -0,0 +1,21 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public interface EqAble { + boolean Eq(Object comp); +} diff --git a/100_core/src_100_interface/gplx/InjectAble.java b/100_core/src_100_interface/gplx/InjectAble.java new file mode 100644 index 000000000..309fca2f9 --- /dev/null +++ b/100_core/src_100_interface/gplx/InjectAble.java @@ -0,0 +1,21 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public interface InjectAble { + void Inject(Object owner); +} diff --git a/100_core/src_100_interface/gplx/NewAble.java b/100_core/src_100_interface/gplx/NewAble.java new file mode 100644 index 000000000..24178b1b7 --- /dev/null +++ b/100_core/src_100_interface/gplx/NewAble.java @@ -0,0 +1,21 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public interface NewAble { + Object NewByKey(Object o); +} diff --git a/100_core/src_100_interface/gplx/ParseAble.java b/100_core/src_100_interface/gplx/ParseAble.java new file mode 100644 index 000000000..8ab6433da --- /dev/null +++ b/100_core/src_100_interface/gplx/ParseAble.java @@ -0,0 +1,21 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public interface ParseAble { + Object ParseAsObj(String raw); +} diff --git a/100_core/src_100_interface/gplx/ParseAble_.java b/100_core/src_100_interface/gplx/ParseAble_.java new file mode 100644 index 000000000..d997313e4 --- /dev/null +++ b/100_core/src_100_interface/gplx/ParseAble_.java @@ -0,0 +1,21 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class ParseAble_ { + public static final ParseAble Null = null; +} diff --git a/100_core/src_100_interface/gplx/RlsAble.java b/100_core/src_100_interface/gplx/RlsAble.java new file mode 100644 index 000000000..e876c2476 --- /dev/null +++ b/100_core/src_100_interface/gplx/RlsAble.java @@ -0,0 +1,21 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public interface RlsAble { + void Rls(); +} diff --git a/100_core/src_100_interface/gplx/RlsAble_.java b/100_core/src_100_interface/gplx/RlsAble_.java new file mode 100644 index 000000000..8b8bbd8ab --- /dev/null +++ b/100_core/src_100_interface/gplx/RlsAble_.java @@ -0,0 +1,22 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class RlsAble_ { + public static RlsAble as_(Object obj) {return obj instanceof RlsAble ? (RlsAble)obj : null;} + public static RlsAble cast_(Object obj) {try {return (RlsAble)obj;} catch(Exception exc) {throw Exc_.new_type_mismatch_w_exc(exc, RlsAble.class, obj);}} +} diff --git a/100_core/src_100_interface/gplx/SrlAble.java b/100_core/src_100_interface/gplx/SrlAble.java new file mode 100644 index 000000000..52709f302 --- /dev/null +++ b/100_core/src_100_interface/gplx/SrlAble.java @@ -0,0 +1,21 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public interface SrlAble { + Object Srl(GfoMsg owner); +} diff --git a/100_core/src_100_interface/gplx/SrlAble_.java b/100_core/src_100_interface/gplx/SrlAble_.java new file mode 100644 index 000000000..8f9e0c85f --- /dev/null +++ b/100_core/src_100_interface/gplx/SrlAble_.java @@ -0,0 +1,65 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.core.strings.*; +public class SrlAble_ { + public static SrlAble as_(Object obj) {return obj instanceof SrlAble ? (SrlAble)obj : null;} + public static String XtoStr(GfoMsg owner) { + String_bldr sb = String_bldr_.new_(); + XtoStr(owner, sb, 0, false); + return sb.XtoStr(); + } + public static String XtoStr(Object o) { + SrlAble s = SrlAble_.as_(o); if (s == null) return Object_.Xto_str_strict_or_null_mark(o); + GfoMsg m = GfoMsg_.new_parse_("root"); + s.Srl(m); + return XtoStr(m); + } + static void XtoStr(GfoMsg owner, String_bldr sb, int depth, boolean indentOn) { + String indent = String_.Repeat(" ", depth * 4); + if (indentOn) sb.Add(indent); + sb.Add(owner.Key()).Add(":"); + for (int i = 0; i < owner.Args_count(); i++) { + if (i != 0) sb.Add(" "); + KeyVal kv = owner.Args_getAt(i); + sb.Add(kv.Key()).Add("=").Add("'").Add(Object_.Xto_str_strict_or_null_mark(kv.Val())).Add("'"); + } + int subsCount = owner.Subs_count(); + if (subsCount == 0) { + sb.Add(";"); + return; + } + else if (subsCount == 1) { + sb.Add("{"); + XtoStr(owner.Subs_getAt(0), sb, depth + 1, false); + sb.Add("}"); + return; + } + else { + sb.Add("{"); + if (subsCount > 1) sb.Add_char_crlf(); + for (int i = 0; i < subsCount; i++) { + GfoMsg sub = owner.Subs_getAt(i); + XtoStr(sub, sb, depth + 1, true); + sb.Add_char_crlf(); + } + sb.Add(indent); + sb.Add("}"); + } + } +} diff --git a/100_core/src_100_interface/gplx/SrlAble__tst.java b/100_core/src_100_interface/gplx/SrlAble__tst.java new file mode 100644 index 000000000..8b7bbd7a2 --- /dev/null +++ b/100_core/src_100_interface/gplx/SrlAble__tst.java @@ -0,0 +1,66 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class SrlAble__tst { + @Test public void Basic() { + tst_Srl_ + ( GfoMsg_.new_cast_("itm").Add("key", "a").Add("val", 1) + , "itm:key='a' val='1';" + ); + + } + @Test public void Depth1_1() { + tst_Srl_ + ( GfoMsg_.new_cast_("itm").Add("key", "a").Add("val", 1).Subs_ + ( GfoMsg_.new_cast_("itm").Add("key", "aa").Add("val", 11) + ) + , String_.Concat_lines_crlf_skipLast + ( "itm:key='a' val='1'{itm:key='aa' val='11';}" + ) + ); + } + @Test public void Depth1_2() { + tst_Srl_ + ( GfoMsg_.new_cast_("itm").Add("key", "a").Add("val", 1).Subs_ + ( GfoMsg_.new_cast_("itm").Add("key", "aa").Add("val", 11) + , GfoMsg_.new_cast_("itm").Add("key", "ab").Add("val", 12) + ) + , String_.Concat_lines_crlf_skipLast + ( "itm:key='a' val='1'{" + , " itm:key='aa' val='11';" + , " itm:key='ab' val='12';" + , "}" + ) + ); + } + @Test public void Depth1_1_2() { + tst_Srl_ + ( GfoMsg_.new_cast_("itm").Add("key", "a").Add("val", 1).Subs_ + ( GfoMsg_.new_cast_("itm").Add("key", "aa").Add("val", 11).Subs_( + GfoMsg_.new_cast_("itm").Add("key", "aab").Add("val", 112) + ) + ) + , String_.Concat_lines_crlf_skipLast + ( "itm:key='a' val='1'{itm:key='aa' val='11'{itm:key='aab' val='112';}}" + ) + ); + } + void tst_Srl_(GfoMsg m, String expd) {Tfds.Eq(expd, SrlAble_.XtoStr(m));} +} +//class SrlAble__tst diff --git a/100_core/src_100_interface/gplx/XtoStrAble.java b/100_core/src_100_interface/gplx/XtoStrAble.java new file mode 100644 index 000000000..e65d978f1 --- /dev/null +++ b/100_core/src_100_interface/gplx/XtoStrAble.java @@ -0,0 +1,21 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public interface XtoStrAble { + String XtoStr(); +} diff --git a/100_core/src_100_interface/gplx/XtoStrAble_.java b/100_core/src_100_interface/gplx/XtoStrAble_.java new file mode 100644 index 000000000..755b274bf --- /dev/null +++ b/100_core/src_100_interface/gplx/XtoStrAble_.java @@ -0,0 +1,21 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class XtoStrAble_ { + public static XtoStrAble as_(Object obj) {return obj instanceof XtoStrAble ? (XtoStrAble)obj : null;} +} diff --git a/100_core/src_110_primitive/gplx/Array_.java b/100_core/src_110_primitive/gplx/Array_.java new file mode 100644 index 000000000..ec6eea1ec --- /dev/null +++ b/100_core/src_110_primitive/gplx/Array_.java @@ -0,0 +1,99 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import java.lang.reflect.Array; +import gplx.core.strings.*; +public class Array_ { + public static void Sort(Object[] obj) {List_adp_sorter.new_().Sort(obj, obj.length);} + public static void Sort(Object[] obj, gplx.lists.ComparerAble comparer) {List_adp_sorter.new_().Sort(obj, obj.length, true, comparer);} + public static List_adp XtoList(Object ary) { + int aryLen = Array_.Len(ary); + List_adp rv = List_adp_.new_(); + for (int i = 0; i < aryLen; i++) + rv.Add(Array_.Get(ary, i)); + return rv; + } + public static Object[] Insert(Object[] cur, Object[] add, int addPos) { + int curLen = cur.length, addLen = add.length; + Object[] rv = (Object[])Array_.Create(Array_.ComponentType(cur), curLen + addLen); + for (int i = 0; i < addPos; i++) // copy old up to addPos + rv[i] = cur[i]; + for (int i = 0; i < addLen; i++) // insert add + rv[i + addPos] = add[i]; + for (int i = addPos; i < curLen; i++) // copy old after addPos + rv[i + addLen] = cur[i]; + return rv; + } + public static Object[] ReplaceInsert(Object[] cur, Object[] add, int curReplacePos, int addInsertPos) { + int curLen = cur.length, addLen = add.length; int newLen = addLen - addInsertPos; + Object[] rv = (Object[])Array_.Create(Array_.ComponentType(cur), curLen + newLen); + for (int i = 0; i < curReplacePos; i++) // copy old up to curInsertPos; EX: curReplacePos=5, addInsertPos=2; copy up to element 3; 4, 5 are dropped + rv[i] = cur[i]; + for (int i = 0; i < addLen; i++) // insert add + rv[i + curReplacePos] = add[i]; + for (int i = curReplacePos + addInsertPos; i < curLen; i++) // copy old after curReplacePos + rv[i + newLen] = cur[i]; + return rv; + } + public static Object Resize_add_one(Object src, int src_len, Object new_obj) { + Object rv = Resize(src, src_len + 1); + Set(rv, src_len, new_obj); + return rv; + } + public static Object Resize(Object src, int trg_len) { + Object trg = Create(ComponentType(src), trg_len); + int src_len = Array.getLength(src); + int copy_len = src_len > trg_len ? trg_len : src_len; // trg_len can either expand or shrink + CopyTo(src, 0, trg, 0, copy_len); + return trg; + } + public static String XtoStr(Object ary) { + String_bldr sb = String_bldr_.new_(); + int ary_len = Len(ary); + for (int i = 0; i < ary_len; i++) + sb.Add_obj(Get(ary, i)).Add_char_nl(); + return sb.XtoStr(); + } + public static int Len(Object ary) {return Array.getLength(ary);} + public static final int LenAry(Object[] ary) {return ary == null ? 0 : ary.length;} + public static Object Get_at(Object ary, int i) {return Array.get(ary, i); } + public static Object Create(Class t, int count) {return Array.newInstance(t, count);} + public static Object Get(Object ary, int i) {return Array.get(ary, i);} + public static void Set(Object ary, int i, Object o) {Array.set(ary, i, o);} + public static Object Expand(Object src, Object trg, int src_len) { + try {System.arraycopy(src, 0, trg, 0, src_len);} + catch (Exception e) {throw Exc_.new_exc(e, "core", "Array_.Expand failed", "src_len", src_len);} + return trg; + } + public static void Copy(Object src, Object trg) {System.arraycopy(src, 0, trg, 0, Len(src));} + public static void CopyTo(Object src, Object trg, int trgPos) {System.arraycopy(src, 0, trg, trgPos, Len(src));} + public static void CopyTo(Object src, int srcBgn, Object trg, int trgBgn, int srcLen) {System.arraycopy(src, srcBgn, trg, trgBgn, srcLen);} + public static Class ComponentType(Object ary) { + if (ary == null) throw Exc_.new_null("ary"); + return ary.getClass().getComponentType(); + } + public static Object Resize_add(Object src, Object add) { + int srcLen = Len(src); + int trgLen = srcLen + Len(add); + Object trg = Create(ComponentType(src), trgLen); + Copy(src, trg); + for (int i = srcLen; i < trgLen; i++) + Set(trg, i, Get(add, i - srcLen)); + return trg; + } + } diff --git a/100_core/src_110_primitive/gplx/Array__tst.java b/100_core/src_110_primitive/gplx/Array__tst.java new file mode 100644 index 000000000..2b996b575 --- /dev/null +++ b/100_core/src_110_primitive/gplx/Array__tst.java @@ -0,0 +1,41 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class Array__tst { + @Test public void Resize_add() { + tst_Resize_add(ary_(), ary_(1), ary_(1)); // 0 + 1 = 1 + tst_Resize_add(ary_(0), ary_(), ary_(0)); // 1 + 0 = 1 + tst_Resize_add(ary_(0), ary_(1), ary_(0, 1)); // 1 + 1 = 2 + } void tst_Resize_add(int[] source, int[] added, int[] expd) {Tfds.Eq_ary(expd, (int[])Array_.Resize_add(source, added));} + @Test public void Resize() { + tst_Resize(ary_(0), 0, ary_()); // 1 -> 0 + tst_Resize(ary_(0, 1), 1, ary_(0)); // 2 -> 1 + } void tst_Resize(int[] source, int length, int[] expd) {Tfds.Eq_ary(expd, (int[])Array_.Resize(source, length));} + @Test public void Insert() { + tst_Insert(ary_obj(0, 1, 4, 5), ary_obj(2, 3), 2, ary_obj(0, 1, 2, 3, 4, 5)); + } void tst_Insert(Object[] cur, Object[] add, int addPos, Object[] expd) {Tfds.Eq_ary(expd, Array_.Insert(cur, add, addPos));} + @Test public void ReplaceInsert() { + tst_ReplaceInsert(ary_obj(0, 1, 4, 5) , ary_obj(1, 2, 3), 1, 1, ary_obj(0, 1, 2, 3, 4, 5)); + tst_ReplaceInsert(ary_obj(0, 1, 2, 4, 5) , ary_obj(1, 2, 3), 1, 2, ary_obj(0, 1, 2, 3, 4, 5)); + tst_ReplaceInsert(ary_obj(0, 1, 2, 3, 4, 5) , ary_obj(1, 2, 3), 1, 3, ary_obj(0, 1, 2, 3, 4, 5)); + tst_ReplaceInsert(ary_obj(0, 1, 9, 4, 5) , ary_obj(2, 3) , 2, 1, ary_obj(0, 1, 2, 3, 4, 5)); + } void tst_ReplaceInsert(Object[] cur, Object[] add, int curReplacePos, int addInsertPos, Object[] expd) {Tfds.Eq_ary(expd, Array_.ReplaceInsert(cur, add, curReplacePos, addInsertPos));} + Object[] ary_obj(Object... ary) {return ary;} + int[] ary_(int... ary) {return ary;} +} diff --git a/100_core/src_110_primitive/gplx/Bool_.java b/100_core/src_110_primitive/gplx/Bool_.java new file mode 100644 index 000000000..312c6e948 --- /dev/null +++ b/100_core/src_110_primitive/gplx/Bool_.java @@ -0,0 +1,59 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Bool_ implements GfoInvkAble { + public static final String Cls_val_name = "boolean"; + public static final Class Cls_ref_type = Boolean.class; + public static final boolean N = false , Y = true; + public static final byte N_byte = 0 , Y_byte = 1 , __byte = 127; + public static final int N_int = 0 , Y_int = 1 , __int = -1; + public static final String N_str = "n" , Y_str = "y"; + public static final byte[] Y_bry = new byte[] {Byte_ascii.Ltr_y}, N_bry = new byte[] {Byte_ascii.Ltr_n}; + public static final String True_str = "true", False_str = "false"; + public static final byte[] True_bry = Bry_.new_a7(True_str), False_bry = Bry_.new_a7(False_str); + public static boolean cast_(Object obj) {try {return (Boolean)obj;} catch (Exception e) {throw Exc_.new_type_mismatch_w_exc(e, boolean.class, obj);}} + public static boolean cast_or_(Object obj, boolean v) {try {return (Boolean)obj;} catch (Exception e) {Exc_.Noop(e); return v;}} + public static boolean By_int(int v) {return v != 0;} + public static boolean parse_(String raw) { + if ( String_.Eq(raw, "true") + || String_.Eq(raw, "True") // needed for Store_Wtr(){boolVal.toString();} + ) + return true; + else if ( String_.Eq(raw, "false") + || String_.Eq(raw, "False") + ) + return false; + throw Exc_.new_parse_type(boolean.class, raw); + } + public static byte Xto_byte(boolean v) {return v ? Y_byte : N_byte;} + public static int Xto_int(boolean v) {return v ? 1 : 0;} + public static String Xto_str_lower(boolean v) {return v ? "true" : "false";} + public static final boolean[] Ary_empty = new boolean[0]; + public static final Bool_ Gfs = new Bool_(); + public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) { + if (ctx.Match(k, Invk_to_str)) { + boolean v = m.ReadBool(GfsCore_.Arg_primitive); + String fmt = m.ReadStrOr("fmt", null); + if (fmt == null) return v ? "true" : "false"; + else if (String_.Eq(fmt, "yn")) return v ? "y" : "n"; + else if (String_.Eq(fmt, "yes_no")) return v ? "yes" : "no"; + else return v ? "true" : "false"; + } + else return GfoInvkAble_.Rv_unhandled; + } public static final String Invk_to_str = "to_str"; +} diff --git a/100_core/src_110_primitive/gplx/Bry_.java b/100_core/src_110_primitive/gplx/Bry_.java new file mode 100644 index 000000000..e00f47a3a --- /dev/null +++ b/100_core/src_110_primitive/gplx/Bry_.java @@ -0,0 +1,1037 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import java.lang.*; +import gplx.core.primitives.*; import gplx.ios.*; +public class Bry_ { + public static final String Cls_val_name = "byte[]"; + public static final int NotFound = -1; + public static final byte[] Empty = new byte[0]; + public static final byte[][] Ary_empty = new byte[0][]; + public static final Class Cls_ref_type = byte[].class; + public static byte[] bytes_(byte... ary) {return ary;} + public static byte[] ints_ (int... ary) { + int len = ary.length; + byte[] rv = new byte[len]; + for (int i = 0; i < len; i++) + rv[i] = (byte)ary[i]; + return rv; + } + public static byte[] new_a7(String str) { + try { + if (str == null) return null; + int str_len = str.length(); + if (str_len == 0) return Bry_.Empty; + byte[] rv = new byte[str_len]; + for (int i = 0; i < str_len; ++i) { + char c = str.charAt(i); + if (c > 128) c = '?'; + rv[i] = (byte)c; + } + return rv; + } + catch (Exception e) {throw Exc_.new_exc(e, "core", "invalid ASCII sequence", "str", str);} + } + public static byte[] new_u8_safe(String str) {return str == null ? null : new_u8(str);} + public static byte[] new_u8(String str) { + try { + int str_len = str.length(); + int bry_len = new_u8_by_len(str, str_len); + byte[] rv = new byte[bry_len]; + new_u8_write(str, str_len, rv, 0); + return rv; + } + catch (Exception e) {throw Exc_.new_exc(e, "core", "invalid UTF-8 sequence", "s", str);} + } + public static int new_u8_by_len(String s, int s_len) { + int rv = 0; + for (int i = 0; i < s_len; ++i) { + char c = s.charAt(i); + int c_len = 0; + if ( c < 128) c_len = 1; // 1 << 7 + else if ( c < 2048) c_len = 2; // 1 << 11 + else if ( (c > 55295) // 0xD800 + && (c < 56320)) c_len = 4; // 0xDFFF + else c_len = 3; // 1 << 16 + if (c_len == 4) ++i; // surrogate is 2 wide, not 1 + rv += c_len; + } + return rv; + } + public static void new_u8_write(String str, int str_len, byte[] bry, int bry_pos) { + for (int i = 0; i < str_len; ++i) { + char c = str.charAt(i); + if ( c < 128) { + bry[bry_pos++] = (byte)c; + } + else if ( c < 2048) { + bry[bry_pos++] = (byte)(0xC0 | (c >> 6)); + bry[bry_pos++] = (byte)(0x80 | (c & 0x3F)); + } + else if ( (c > 55295) // 0xD800 + && (c < 56320)) { // 0xDFFF + if (i >= str_len) throw Exc_.new_("incomplete surrogate pair at end of String", "char", c); + char nxt_char = str.charAt(i + 1); + int v = 0x10000 + (c - 0xD800) * 0x400 + (nxt_char - 0xDC00); + bry[bry_pos++] = (byte)(0xF0 | (v >> 18)); + bry[bry_pos++] = (byte)(0x80 | (v >> 12) & 0x3F); + bry[bry_pos++] = (byte)(0x80 | (v >> 6) & 0x3F); + bry[bry_pos++] = (byte)(0x80 | (v & 0x3F)); + ++i; + } + else { + bry[bry_pos++] = (byte)(0xE0 | (c >> 12)); + bry[bry_pos++] = (byte)(0x80 | (c >> 6) & 0x3F); + bry[bry_pos++] = (byte)(0x80 | (c & 0x3F)); + } + } + } + public static byte[] Coalesce(byte[] orig, byte[] val_if_not_blank) {return Bry_.Len_eq_0(orig) ? val_if_not_blank : orig;} + public static byte Get_at_end_or_fail(byte[] bry) { + if (bry == null) throw Exc_.new_("bry is null"); + int bry_len = bry.length; + if (bry_len == 0) throw Exc_.new_("bry has 0 len"); + return bry[bry_len - 1]; + } + public static int While_fwd(byte[] src, byte while_byte, int bgn, int end) { + for (int i = bgn; i < end; i++) + if (src[i] != while_byte) return i; + return end; + } + public static byte[][] Ary_add(byte[][] lhs, byte[][] rhs) { + int lhs_len = lhs.length, rhs_len = rhs.length; + if (lhs_len == 0) return rhs; + else if (rhs_len == 0) return lhs; + else { + byte[][] rv = new byte[lhs_len + rhs_len][]; + for (int i = 0; i < lhs_len; i++) + rv[i] = lhs[i]; + for (int i = 0; i < rhs_len; i++) + rv[i + lhs_len] = rhs[i]; + return rv; + } + } + public static byte[][] Ary(byte[]... ary) {return ary;} + public static byte[][] Ary(String... ary) { + int ary_len = ary.length; + byte[][] rv = new byte[ary_len][]; + for (int i = 0; i < ary_len; i++) { + String itm = ary[i]; + rv[i] = itm == null ? null : Bry_.new_u8(itm); + } + return rv; + } + public static byte[][] Ary_obj(Object... ary) { + if (ary == null) return Bry_.Ary_empty; + int ary_len = ary.length; + byte[][] rv = new byte[ary_len][]; + for (int i = 0; i < ary_len; i++) { + Object itm = ary[i]; + rv[i] = itm == null ? null : Bry_.new_u8(Object_.Xto_str_strict_or_empty(itm)); + } + return rv; + } + public static boolean Ary_eq(byte[][] lhs, byte[][] rhs) { + int lhs_len = lhs.length; + int rhs_len = rhs.length; + if (lhs_len != rhs_len) return false; + for (int i = 0; i < lhs_len; ++i) + if (!Bry_.Eq(lhs[i], rhs[i])) return false; + return true; + } + public static byte[] Repeat_space(int len) {return Repeat(Byte_ascii.Space, len);} + public static byte[] Repeat(byte b, int len) { + byte[] rv = new byte[len]; + for (int i = 0; i < len; i++) + rv[i] = b; + return rv; + } + public static byte[] Copy(byte[] src) { + int src_len = src.length; + byte[] trg = new byte[src_len]; + for (int i = 0; i < src_len; i++) + trg[i] = src[i]; + return trg; + } + public static void Copy_by_pos(byte[] src, int src_bgn, int src_end, byte[] trg, int trg_bgn) { + int trg_adj = trg_bgn - src_bgn; + for (int i = src_bgn; i < src_end; i++) + trg[i + trg_adj] = src[i]; + } + public static void Copy_by_len(byte[] src, int src_bgn, int src_len, byte[] trg, int trg_bgn) { + for (int i = 0; i < src_len; i++) + trg[i + trg_bgn] = src[i + src_bgn]; + } + public static byte[][] XtoByteAryAry(String... strAry) { + int strAryLen = strAry.length; + byte[][] rv = new byte[strAryLen][]; + for (int i = 0; i < strAryLen; i++) + rv[i] = Bry_.new_u8(strAry[i]); + return rv; + } + public static byte[] Xto_str_lower(byte[] src, int bgn, int end) { + int len = end - bgn; + byte[] rv = new byte[len]; + for (int i = bgn; i < end; i++) { + byte b = src[i]; + switch (b) { + case Byte_ascii.Ltr_A: case Byte_ascii.Ltr_B: case Byte_ascii.Ltr_C: case Byte_ascii.Ltr_D: case Byte_ascii.Ltr_E: + case Byte_ascii.Ltr_F: case Byte_ascii.Ltr_G: case Byte_ascii.Ltr_H: case Byte_ascii.Ltr_I: case Byte_ascii.Ltr_J: + case Byte_ascii.Ltr_K: case Byte_ascii.Ltr_L: case Byte_ascii.Ltr_M: case Byte_ascii.Ltr_N: case Byte_ascii.Ltr_O: + case Byte_ascii.Ltr_P: case Byte_ascii.Ltr_Q: case Byte_ascii.Ltr_R: case Byte_ascii.Ltr_S: case Byte_ascii.Ltr_T: + case Byte_ascii.Ltr_U: case Byte_ascii.Ltr_V: case Byte_ascii.Ltr_W: case Byte_ascii.Ltr_X: case Byte_ascii.Ltr_Y: case Byte_ascii.Ltr_Z: + b += 32; + break; + } + rv[i - bgn] = b; + } + return rv; + } + public static byte[] Replace_one(byte[] src, byte[] find, byte[] repl) { + int src_len = src.length; + int findPos = Bry_finder.Find(src, find, 0, src_len, true); if (findPos == Bry_.NotFound) return src; + int findLen = find.length, replLen = repl.length; + int rvLen = src_len + replLen - findLen; + byte[] rv = new byte[rvLen]; + Copy_by_len(src , 0 , findPos , rv, 0 ); + Copy_by_len(repl, 0 , replLen , rv, findPos ); + Copy_by_len(src , findPos + findLen , src_len - findPos - findLen , rv, findPos + replLen); + return rv; + } + public static void Replace_all_direct(byte[] src, byte find, byte repl) {Replace_all_direct(src, find, repl, 0, src.length);} + public static void Replace_all_direct(byte[] src, byte find, byte repl, int bgn, int end) { + for (int i = bgn; i < end; i++) { + byte b = src[i]; + if (b == find) src[i] = repl; + } + } + public static byte[] Add_w_dlm(byte[] dlm, byte[]... ary) { + int ary_len = ary.length; + if (ary_len == 0) return Bry_.Empty; + int dlm_len = dlm.length; + int rv_len = dlm_len * (ary_len - 1); // rv will have at least as many dlms as itms - 1 + for (int i = 0; i < ary_len; i++) { + byte[] itm = ary[i]; + if (itm != null) rv_len += itm.length; + } + int rv_pos = 0; + byte[] rv = new byte[rv_len]; + for (int i = 0; i < ary_len; i++) { + byte[] itm = ary[i]; + if (i != 0) { + for (int j = 0; j < dlm_len; j++) { + rv[rv_pos++] = dlm[j]; + } + } + if (itm == null) continue; + int itm_len = itm.length; + for (int j = 0; j < itm_len; j++) { + rv[rv_pos++] = itm[j]; + } + } + return rv; + } + public static byte[] Add_w_dlm(byte dlm, byte[]... ary) { + int ary_len = ary.length; + if (ary_len == 0) return Bry_.Empty; + int rv_len = ary_len - 1; // rv will have at least as many dlms as itms - 1 + for (int i = 0; i < ary_len; i++) { + byte[] itm = ary[i]; + if (itm != null) rv_len += itm.length; + } + int rv_pos = 0; + byte[] rv = new byte[rv_len]; + for (int i = 0; i < ary_len; i++) { + byte[] itm = ary[i]; + if (i != 0) rv[rv_pos++] = dlm; + if (itm == null) continue; + int itm_len = itm.length; + for (int j = 0; j < itm_len; j++) { + rv[rv_pos++] = itm[j]; + } + } + return rv; + } + public static byte[] Add(byte[] ary, byte b) { + int ary_len = ary.length; + byte[] rv = new byte[ary_len + 1]; + for (int i = 0; i < ary_len; i++) + rv[i] = ary[i]; + rv[ary_len] = b; + return rv; + } + public static byte[] Add(byte b, byte[] ary) { + int ary_len = ary.length + 1; + byte[] rv = new byte[ary_len]; + for (int i = 1; i < ary_len; i++) + rv[i] = ary[i - 1]; + rv[0] = b; + return rv; + } + public static byte[] Add(byte[]... all) { + int all_len = all.length, rv_len = 0; + for (int i = 0; i < all_len; i++) { + byte[] cur = all[i]; if (all[i] == null) continue; + rv_len += cur.length; + } + byte[] rv = new byte[rv_len]; + int rv_idx = 0; + for (int i = 0; i < all_len; i++) { + byte[] cur = all[i]; if (all[i] == null) continue; + int cur_len = cur.length; + for (int j = 0; j < cur_len; j++) + rv[rv_idx++] = cur[j]; + } + return rv; + } + public static int LastIdx(byte[] src) {return src.length - 1;} + public static byte[] Limit(byte[] src, int len) { + if (src == null) return null; + int src_len = src.length; + return len < src_len ? Bry_.Mid(src, 0, len) : src; + } + public static byte[] Mid_by_nearby(byte[] src, int pos, int around) { + int bgn = pos - around; if (bgn < 0) bgn = 0; + int src_len = src.length; + int end = pos + around; if (end > src_len) end = src_len; + return Mid(src, bgn, end); + } + public static byte[] Mid_by_len(byte[] src, int bgn, int len) {return Mid(src, bgn, bgn + len);} + public static byte[] Mid_by_len_safe(byte[] src, int bgn, int len) { + int src_len = src.length; + if (bgn < 0) bgn = 0; + if (len + bgn > src_len) len = (src_len - bgn); + return Mid(src, bgn, bgn + len); + } + public static String MidByLenToStr(byte[] src, int bgn, int len) { + int end = bgn + len; end = Int_.BoundEnd(end, src.length); + byte[] ary = Bry_.Mid(src, bgn, end); + return String_.new_u8(ary); + } + public static byte[] Mid_safe(byte[] src, int bgn, int end) { + try {return Mid(src, bgn, end);} + catch (Exception e) {Exc_.Noop(e); return Bry_.Add_w_dlm(Byte_ascii.Space, Bry_.XbyInt(bgn), Bry_.XbyInt(end));} + } + public static byte[] Mid(byte[] src, int bgn) {return Mid(src, bgn, src.length);} + public static byte[] Mid_or(byte[] src, int bgn, int end, byte[] or) { + int src_len = src.length; + if ( src == null + || (bgn < 0 || bgn > src_len) + || (end < 0 || end > src_len) + || (end < bgn) + ) + return or; + return Mid(src, bgn, src.length); + } + public static byte[] Mid(byte[] src, int bgn, int end) { + try { + int len = end - bgn; if (len == 0) return Bry_.Empty; + byte[] rv = new byte[len]; + for (int i = bgn; i < end; i++) + rv[i - bgn] = src[i]; + return rv; + } catch (Exception e) { + String msg = ""; + if (src == null) msg = "src is null"; + else if (bgn < 0 || bgn > src.length) msg = "invalid bgn"; + else if (end < 0 || end > src.length) msg = "invalid end"; + else if (end < bgn) msg = "end < bgn"; + throw Exc_.new_exc(e, "core", msg, "bgn", bgn, "end", end, "src", src == null ? "" : String_.new_u8_by_len(src, bgn, 32)); + } + } + public static byte[] mask_(int len, byte... itms) { + byte[] rv = new byte[len]; + int itms_len = itms.length; + for (int i = 0; i < itms_len; i++) { + byte itm = itms[i]; + rv[itm & 0xFF] = itm; // PATCH.JAVA:need to convert to unsigned byte + } + return rv; + } + public static final byte[] Trim_ary_ws = mask_(256, Byte_ascii.Tab, Byte_ascii.Nl, Byte_ascii.Cr, Byte_ascii.Space); + public static byte[] Trim(byte[] src) {return Trim(src, 0, src.length, true, true, Trim_ary_ws);} + public static byte[] Trim(byte[] src, int bgn, int end) {return Trim(src, bgn, end, true, true, Trim_ary_ws);} + public static byte[] Trim(byte[] src, int bgn, int end, boolean trim_bgn, boolean trim_end, byte[] trim_ary) { + int txt_bgn = bgn, txt_end = end; + boolean all_ws = true; + if (trim_bgn) { + for (int i = bgn; i < end; i++) { + byte b = src[i]; + if (trim_ary[b & 0xFF] == Byte_ascii.Nil) { + txt_bgn = i; + i = end; + all_ws = false; + } + } + if (all_ws) return Bry_.Empty; + } + if (trim_end) { + for (int i = end - 1; i > -1; i--) { + byte b = src[i]; + if (trim_ary[b & 0xFF] == Byte_ascii.Nil) { + txt_end = i + 1; + i = -1; + all_ws = false; + } + } + if (all_ws) return Bry_.Empty; + } + return Bry_.Mid(src, txt_bgn, txt_end); + } + public static byte[] Trim_end(byte[] v, byte trim, int end) { + boolean trimmed = false; + int pos = end - 1; // NOTE: -1 b/c callers will always be passing pos + 1; EX: src, src_len + for (; pos > -1; pos--) { + if (v[pos] == trim) { + trimmed = true; + } + else + break; + } + return trimmed ? Bry_.Mid(v, 0, pos + 1) : v; + } + public static boolean Has(byte[] src, byte[] lkp) {return Bry_finder.Find_fwd(src, lkp) != Bry_finder.Not_found;} + public static boolean Has(byte[] src, byte lkp) { + if (src == null) return false; + int len = src.length; + for (int i = 0; i < len; i++) + if (src[i] == lkp) return true; + return false; + } + public static boolean Has_at_end(byte[] src, byte[] lkp) {int src_len = src.length; return Has_at_end(src, lkp, src_len - lkp.length, src_len);} + public static boolean Has_at_end(byte[] src, byte[] lkp, int src_bgn, int src_end) { + int lkp_len = lkp.length; + if (src_bgn < 0) return false; + int pos = src_end - lkp_len; if (pos < src_bgn) return false; // lkp is longer than src + for (int i = 0; i < lkp_len; i++) { + if (lkp[i] != src[i + pos]) return false; + } + return true; + } + public static boolean Has_at_bgn(byte[] src, byte lkp, int src_bgn) { + return src_bgn < src.length ? src[src_bgn] == lkp : false; + } + public static boolean Has_at_bgn(byte[] src, byte[] lkp) {return Has_at_bgn(src, lkp, 0, src.length);} + public static boolean Has_at_bgn(byte[] src, byte[] lkp, int src_bgn, int src_end) { + int lkp_len = lkp.length; + if (lkp_len + src_bgn > src_end) return false; // lkp is longer than src + for (int i = 0; i < lkp_len; i++) { + if (lkp[i] != src[i + src_bgn]) return false; + } + return true; + } + public static int Skip_fwd(byte[] src, int src_bgn, byte skip) { + int src_len = src.length; + for (int i = src_bgn; i < src_len; i++) { + byte b = src[i]; + if (b != skip) return i; + } + return 0; + } + public static int Skip_bwd(byte[] src, int src_bgn, byte skip) { + for (int i = src_bgn; i > -1; i--) { + byte b = src[i]; + if (b != skip) return i; + } + return src.length; + } + public static int Skip_fwd_nl(byte[] src, int src_bgn) { + int src_len = src.length; + for (int i = src_bgn; i < src_len; i++) { + byte b = src[i]; + switch (b) { + case Byte_ascii.Nl: case Byte_ascii.Cr: + break; + default: + return i; + } + } + return 0; + } + public static int Skip_bwd_nl(byte[] src, int src_bgn) { + for (int i = src_bgn; i > -1; i--) { + byte b = src[i]; + switch (b) { + case Byte_ascii.Nl: case Byte_ascii.Cr: + break; + default: + return i; + } + } + return src.length; + } + public static byte[] Resize_manual(byte[] src, int rvLen) { + byte[] rv = new byte[rvLen]; + int src_len = src.length; + if (src_len > rvLen) src_len = rvLen; // resizing smaller; only copy as many elements as in rvLen + for (int i = 0; i < src_len; i++) + rv[i] = src[i]; + return rv; + } + public static byte[] Resize(byte[] src, int trgLen) {return Resize(src, 0, trgLen);} + public static byte[] Resize(byte[] src, int src_bgn, int trgLen) { + byte[] trg = new byte[trgLen]; + int src_len = src.length > trgLen ? trgLen : src.length; // trgLen can either expand or shrink + Copy_by_len(src, src_bgn, src_len, trg, 0); + return trg; + } + public static boolean Match(byte[] src, byte[] find) {return Match(src, 0, src.length, find, 0, find.length);} + public static boolean Match(byte[] src, int src_bgn, byte[] find) {return Match(src, src_bgn, src.length, find, 0, find.length);} + public static boolean Match(byte[] src, int src_bgn, int src_end, byte[] find) {return Match(src, src_bgn, src_end, find, 0, find.length);} + public static boolean Match(byte[] src, int src_bgn, int src_end, byte[] find, int find_bgn, int find_end) { + int src_len = src.length; + if (src_end > src_len) src_end = src_len; // must limit src_end to src_len, else ArrayIndexOutOfBounds below; DATE:2015-01-31 + int find_len = find_end - find_bgn; + if (find_len != src_end - src_bgn) return false; + if (find_len == 0) return src_end - src_bgn == 0; // "" only matches "" + for (int i = 0; i < find_len; i++) { + int pos = src_bgn + i; + if (pos >= src_end) return false; // ran out of src; exit; EX: src=ab; find=abc + if (src[pos] != find[i + find_bgn]) return false; + } + return true; + } + public static boolean Match_bwd_any(byte[] src, int src_end, int src_bgn, byte[] find) { // NOTE: utf8 doesn't matter (matching byte for byte) + int find_len = find.length; + for (int i = 0; i < find_len; i++) { + int src_pos = src_end - i; + int find_pos = find_len - i - 1; + if (src_pos < src_bgn) return false; // ran out of src; exit; EX: src=ab; find=abc + if (src[src_pos] != find[find_pos]) return false; + } + return true; + } + public static int Compare(byte[] lhs, byte[] rhs) { + if (lhs == null) return CompareAble_.More; + else if (rhs == null) return CompareAble_.Less; + else return Compare(lhs, 0, lhs.length, rhs, 0, rhs.length); + } + public static int Compare(byte[] lhs, int lhs_bgn, int lhs_end, byte[] rhs, int rhs_bgn, int rhs_end) { + int lhs_len = lhs_end - lhs_bgn, rhs_len = rhs_end - rhs_bgn; + int min = lhs_len < rhs_len ? lhs_len : rhs_len; + int rv = CompareAble_.Same; + for (int i = 0; i < min; i++) { + rv = (lhs[i + lhs_bgn] & 0xff) - (rhs[i + rhs_bgn] & 0xff); // PATCH.JAVA:need to convert to unsigned byte + if (rv != CompareAble_.Same) return rv > CompareAble_.Same ? CompareAble_.More : CompareAble_.Less; // NOTE: changed from if (rv != CompareAble_.Same) return rv; DATE:2013-04-25 + } + return Int_.Compare(lhs_len, rhs_len); // lhs and rhs share same beginning bytes; return len comparisons + } + public static int Len(byte[] v) {return v == null ? 0 : v.length;} + public static boolean Len_gt_0(byte[] v) {return v != null && v.length > 0;} + public static boolean Len_eq_0(byte[] v) {return v == null || v.length == 0;} + public static void Set(byte[] src, int bgn, int end, byte[] repl) { + int repl_len = repl.length; + for (int i = 0; i < repl_len; i++) + src[i + bgn] = repl[i]; + } + public static boolean Eq_itm(byte[] src, int src_len, int pos, byte chk) { + return pos < src_len + && src[pos] == chk; + } + public static boolean Eq(byte[] lhs, byte[] rhs) { + if (lhs == null && rhs == null) return true; + else if (lhs == null || rhs == null) return false; + int lhs_len = lhs.length; + if (lhs_len != rhs.length) return false; + for (int i = 0; i < lhs_len; i++) // NOTE: lhs_len == rhsLen + if (lhs[i] != rhs[i]) return false; + return true; + } + public static boolean Eq(byte[] lhs, byte[] rhs, int rhs_bgn, int rhs_end) { + if (lhs == null && rhs == null) return true; + else if (lhs == null || rhs == null) return false; + int lhs_len = lhs.length; + int rhs_len = rhs_end - rhs_bgn; + if (lhs_len != rhs_len) return false; + for (int i = 0; i < lhs_len; i++) + if (lhs[i] != rhs[i + rhs_bgn]) return false; + return true; + } + public static boolean Eq_ci_ascii(byte[] lhs, byte[] rhs, int rhs_bgn, int rhs_end) { + if (lhs == null && rhs == null) return true; + else if (lhs == null || rhs == null) return false; + int lhs_len = lhs.length; + int rhs_len = rhs_end - rhs_bgn; + if (lhs_len != rhs_len) return false; + for (int i = 0; i < lhs_len; i++) { + byte lhs_b = lhs[i]; if (lhs_b > 64 && lhs_b < 91) lhs_b += 32; // lowercase + byte rhs_b = rhs[i + rhs_bgn]; if (rhs_b > 64 && rhs_b < 91) rhs_b += 32; // lowercase + if (lhs_b != rhs_b) return false; + } + return true; + } + public static byte[] XtoStrBytesByInt(int val, int padLen) {return XtoStrBytesByInt(val, null, 0, padLen);} + public static byte[] XtoStrBytesByInt(int val, byte[] ary, int aryPos, int padLen) { + int neg = 0; + if (val < 0) { + val *= -1; + neg = 1; + } + int digits = val == 0 ? 0 : Math_.Log10(val); + digits += 1; // digits = log + 1; EX: Log(1-9) = 0, Log(10-99) = 1 + int aryLen = digits + neg, aryBgn = aryPos, pad = 0; + if (aryLen < padLen) { // padding specified + pad = padLen - aryLen; + aryLen = padLen; + } + if (ary == null) ary = new byte[aryLen]; + long factor = 1; // factor needs to be long to handle 1 billion (for which factor would be 10 billion) + for (int i = 0; i < digits; i++) // calc maxFactor + factor *= 10; + if (neg == 1) ary[0] = Byte_NegSign; + + for (int i = 0; i < pad; i++) // fill ary with pad + ary[i + aryBgn] = XtoStrByte(0); + aryBgn += pad; // advance aryBgn by pad + for (int i = neg; i < aryLen - pad; i++) { + int denominator = (int)(factor / 10); // cache denominator to check for divide by 0 + int digit = denominator == 0 ? 0 : (int)((val % factor) / denominator); + ary[aryBgn + i] = XtoStrByte(digit); + factor /= 10; + } + return ary; + } + public static byte Xto_byte_by_int(byte[] ary, int bgn, int end, byte or) {return (byte)Xto_int_or(ary, bgn, end, or);} + public static int Xto_int(byte[] ary) {return Xto_int_or(ary, null, 0, ary.length, -1);} + public static int Xto_int_or_fail(byte[] ary) { + int rv = Xto_int_or(ary, null, 0, ary.length, Int_.MinValue); + if (rv == Int_.MinValue) throw Exc_.new_("could not parse to int", "val", String_.new_u8(ary)); + return rv; + } + public static boolean Xto_bool_by_int_or_fail(byte[] ary) { + int rv = Xto_int_or(ary, null, 0, ary.length, Int_.MinValue); + switch (rv) { + case 0: return false; + case 1: return true; + default: throw Exc_.new_("could not parse to boolean int", "val", String_.new_u8(ary)); + } + } + public static int Xto_int_or(byte[] ary, int or) {return Xto_int_or(ary, null, 0, ary.length, or);} + public static int Xto_int_or(byte[] ary, int bgn, int end, int or) {return Xto_int_or(ary, null, bgn, end, or);} + public static int Xto_int_or(byte[] ary, byte[] ignore_ary, int or) {return Xto_int_or(ary, ignore_ary, 0, ary.length, or);} + public static int Xto_int_or(byte[] ary, byte[] ignore_ary, int bgn, int end, int or) { + if ( ary == null + || end == bgn // null-len + ) return or; + int rv = 0, multiple = 1; + for (int i = end - 1; i >= bgn; i--) { // -1 b/c end will always be next char; EX: {{{1}}}; bgn = 3, end = 4 + byte b = ary[i]; + switch (b) { + case Byte_ascii.Num_0: case Byte_ascii.Num_1: case Byte_ascii.Num_2: case Byte_ascii.Num_3: case Byte_ascii.Num_4: + case Byte_ascii.Num_5: case Byte_ascii.Num_6: case Byte_ascii.Num_7: case Byte_ascii.Num_8: case Byte_ascii.Num_9: + rv += multiple * (b - Byte_ascii.Num_0); + multiple *= 10; + break; + case Byte_ascii.Dash: + return i == bgn ? rv * -1 : or; + case Byte_ascii.Plus: + return i == bgn ? rv : or; + default: + boolean invalid = true; + if (ignore_ary != null) { + int ignore_ary_len = ignore_ary.length; + for (int j = 0; j < ignore_ary_len; j++) { + if (b == ignore_ary[j]) { + invalid = false; + break; + } + } + } + if (invalid) return or; + break; + } + } + return rv; + } + public static int Xto_int_or_trim(byte[] ary, int bgn, int end, int or) { // NOTE: same as Xto_int_or, except trims ws at bgn / end; DATE:2014-02-09 + if (end == bgn) return or; // null len + int rv = 0, multiple = 1; + boolean numbers_seen = false, ws_seen = false; + for (int i = end - 1; i >= bgn; i--) { // -1 b/c end will always be next char; EX: {{{1}}}; bgn = 3, end = 4 + byte b = ary[i]; + switch (b) { + case Byte_ascii.Num_0: case Byte_ascii.Num_1: case Byte_ascii.Num_2: case Byte_ascii.Num_3: case Byte_ascii.Num_4: + case Byte_ascii.Num_5: case Byte_ascii.Num_6: case Byte_ascii.Num_7: case Byte_ascii.Num_8: case Byte_ascii.Num_9: + rv += multiple * (b - Byte_ascii.Num_0); + multiple *= 10; + if (ws_seen) // "number ws number" pattern; invalid ws in middle; see tests + return or; + numbers_seen = true; + break; + case Byte_ascii.Dash: + return i == bgn ? rv * -1 : or; + case Byte_ascii.Space: case Byte_ascii.Tab: case Byte_ascii.Nl: case Byte_ascii.Cr: + if (numbers_seen) + ws_seen = true; + break; + default: return or; + } + } + return rv; + } + public static int Xto_int_or_lax(byte[] ary, int bgn, int end, int or) { + if (end == bgn) return or; // null-len + int end_num = end; + for (int i = bgn; i < end; i++) { + byte b = ary[i]; + switch (b) { + case Byte_ascii.Num_0: case Byte_ascii.Num_1: case Byte_ascii.Num_2: case Byte_ascii.Num_3: case Byte_ascii.Num_4: + case Byte_ascii.Num_5: case Byte_ascii.Num_6: case Byte_ascii.Num_7: case Byte_ascii.Num_8: case Byte_ascii.Num_9: + break; + case Byte_ascii.Dash: + if (i != bgn) { + end_num = i; + i = end; + } + break; + default: + end_num = i; + i = end; + break; + } + } + return Xto_int_or(ary, bgn, end_num, or); + } + public static float XtoFloatByPos(byte[] ary, int bgn, int end) {return Float_.parse_(String_.new_u8(ary, bgn, end));} + public static double Xto_double(byte[] bry) {return Double_.parse_(String_.new_u8(bry, 0, bry.length));} + public static double Xto_double_or(byte[] bry, double or) {return Double_.parse_or(String_.new_u8(bry, 0, bry.length), or);} + public static double XtoDoubleByPosOr(byte[] ary, int bgn, int end, double or) {return Double_.parse_or(String_.new_u8(ary, bgn, end), or);} + public static double XtoDoubleByPos(byte[] ary, int bgn, int end) {return Double_.parse_(String_.new_u8(ary, bgn, end));} + public static DecimalAdp XtoDecimalByPos(byte[] ary, int bgn, int end) {return DecimalAdp_.parse_(String_.new_u8(ary, bgn, end));} + public static final byte Dlm_fld = (byte)'|', Dlm_row = (byte)'\n', Dlm_quote = (byte)'"', Dlm_null = 0, Ascii_zero = 48; + public static final String Fmt_csvDte = "yyyyMMdd HHmmss.fff"; + public static DateAdp ReadCsvDte(byte[] ary, Int_obj_ref posRef, byte lkp) {// ASSUME: fmt = yyyyMMdd HHmmss.fff + int y = 0, M = 0, d = 0, H = 0, m = 0, s = 0, f = 0; + int bgn = posRef.Val(); + y += (ary[bgn + 0] - Ascii_zero) * 1000; + y += (ary[bgn + 1] - Ascii_zero) * 100; + y += (ary[bgn + 2] - Ascii_zero) * 10; + y += (ary[bgn + 3] - Ascii_zero); + M += (ary[bgn + 4] - Ascii_zero) * 10; + M += (ary[bgn + 5] - Ascii_zero); + d += (ary[bgn + 6] - Ascii_zero) * 10; + d += (ary[bgn + 7] - Ascii_zero); + H += (ary[bgn + 9] - Ascii_zero) * 10; + H += (ary[bgn + 10] - Ascii_zero); + m += (ary[bgn + 11] - Ascii_zero) * 10; + m += (ary[bgn + 12] - Ascii_zero); + s += (ary[bgn + 13] - Ascii_zero) * 10; + s += (ary[bgn + 14] - Ascii_zero); + f += (ary[bgn + 16] - Ascii_zero) * 100; + f += (ary[bgn + 17] - Ascii_zero) * 10; + f += (ary[bgn + 18] - Ascii_zero); + if (ary[bgn + 19] != lkp) throw Exc_.new_("csv date is invalid", "txt", String_.new_u8_by_len(ary, bgn, 20)); + posRef.Val_add(19 + 1); // +1=lkp.len + return DateAdp_.new_(y, M, d, H, m, s, f); + } + public static String ReadCsvStr(byte[] ary, Int_obj_ref posRef, byte lkp) {return String_.new_u8(ReadCsvBry(ary, posRef, lkp, true));} + public static byte[] ReadCsvBry(byte[] ary, Int_obj_ref posRef, byte lkp) {return ReadCsvBry(ary, posRef, lkp, true);} + public static byte[] ReadCsvBry(byte[] ary, Int_obj_ref posRef, byte lkp, boolean make) { + int bgn = posRef.Val(), aryLen = ary.length; + Bry_bfr bb = null; + if (aryLen > 0 && ary[0] == Dlm_quote) { + int pos = bgn + 1; // +1 to skip quote + if (make) bb = Bry_bfr.new_(16); + while (true) { + if (pos == aryLen) throw Exc_.new_("endOfAry reached, but no quote found", "txt", String_.new_u8_by_len(ary, bgn, pos)); + byte b = ary[pos]; + if (b == Dlm_quote) { + if (pos == aryLen - 1) throw Exc_.new_("endOfAry reached, quote found but lkp not", "txt", String_.new_u8_by_len(ary, bgn, pos)); + byte next = ary[pos + 1]; + if (next == Dlm_quote) { // byte followed by quote + if (make) bb.Add_byte(b); + pos += 2; + } + else if (next == lkp) { + posRef.Val_(pos + 2); // 1=endQuote;1=lkp; + return make ? bb.Xto_bry() : Bry_.Empty; + } + else throw Exc_.new_("quote found, but not doubled", "txt", String_.new_u8_by_len(ary, bgn, pos + 1)); + } + else { + if (make) bb.Add_byte(b); + pos++; + } + } + } + else { + for (int i = bgn; i < aryLen; i++) { + if (ary[i] == lkp) { + posRef.Val_(i + 1); // +1 = lkp.Len + return make ? Bry_.Mid(ary, bgn, i) : Bry_.Empty; + } + } + throw Exc_.new_("lkp failed", "lkp", (char)lkp, "txt", String_.new_u8_by_len(ary, bgn, aryLen)); + } + } + public static int ReadCsvInt(byte[] ary, Int_obj_ref posRef, byte lkp) { + int bgn = posRef.Val(); + int pos = Bry_finder.Find_fwd(ary, lkp, bgn, ary.length); + if (pos == Bry_.NotFound) throw Exc_.new_("lkp failed", "lkp", (char)lkp, "bgn", bgn); + int rv = Bry_.Xto_int_or(ary, posRef.Val(), pos, -1); + posRef.Val_(pos + 1); // +1 = lkp.Len + return rv; + } + public static double ReadCsvDouble(byte[] ary, Int_obj_ref posRef, byte lkp) { + int bgn = posRef.Val(); + int pos = Bry_finder.Find_fwd(ary, lkp, bgn, ary.length); + if (pos == Bry_.NotFound) throw Exc_.new_("lkp failed", "lkp", (char)lkp, "bgn", bgn); + double rv = Bry_.XtoDoubleByPos(ary, posRef.Val(), pos); + posRef.Val_(pos + 1); // +1 = lkp.Len + return rv; + } + public static void ReadCsvNext(byte[] ary, Int_obj_ref posRef, byte lkp) { + int bgn = posRef.Val(); + int pos = Bry_finder.Find_fwd(ary, lkp, bgn, ary.length); + posRef.Val_(pos + 1); // +1 = lkp.Len + } + public static byte Byte_NegSign = (byte)'-'; + public static int XtoIntBy4Bytes(byte[] v) { + int v_len = v.length; + int mod = 8 * (v_len - 1); + int rv = 0; + for (int i = 0; i < v_len; i++) { + rv |= v[i] << mod; + mod -= 8; + } + return rv; +// return ((0xFF & v[0]) << 24) +// | ((0xFF & v[1]) << 16) +// | ((0xFF & v[2]) << 8) +// | (0xFF & v[3]); + } + public static byte[] XbyInt(int v) { + byte b0 = (byte)(v >> 24); + byte b1 = (byte)(v >> 16); + byte b2 = (byte)(v >> 8); + byte b3 = (byte)(v); + if (b0 != 0) return new byte[] {b0, b1, b2, b3}; + else if (b1 != 0) return new byte[] {b1, b2, b3}; + else if (b2 != 0) return new byte[] {b2, b3}; + else return new byte[] {b3}; + } + public static byte XtoStrByte(int digit) { + switch (digit) { + case 0: return Byte_ascii.Num_0; case 1: return Byte_ascii.Num_1; case 2: return Byte_ascii.Num_2; case 3: return Byte_ascii.Num_3; case 4: return Byte_ascii.Num_4; + case 5: return Byte_ascii.Num_5; case 6: return Byte_ascii.Num_6; case 7: return Byte_ascii.Num_7; case 8: return Byte_ascii.Num_8; case 9: return Byte_ascii.Num_9; + default: throw Exc_.new_("unknown digit", "digit", digit); + } + } + public static byte[][] Split(byte[] src, byte dlm) {return Split(src, dlm, false);} + public static byte[][] Split(byte[] src, byte dlm, boolean trim) { + if (Bry_.Len_eq_0(src)) return Bry_.Ary_empty; + int src_len = src.length, src_pos = 0, fld_bgn = 0; + List_adp rv = List_adp_.new_(); + while (true) { + boolean last = src_pos == src_len; + byte b = last ? dlm : src[src_pos]; + if (b == dlm) { + if (last && (src_pos - fld_bgn == 0)) {} + else { + byte[] itm = Bry_.Mid(src, fld_bgn, src_pos); + if (trim) itm = Bry_.Trim(itm); + rv.Add(itm); + } + fld_bgn = src_pos + 1; + } + if (last) break; + ++src_pos; + } + return (byte[][])rv.To_ary(byte[].class); + } + public static byte[] Replace_create(byte[] src, byte find, byte replace) { + byte[] rv = Bry_.Copy(src); + Replace_reuse(rv, find, replace); + return rv; + } + public static void Replace_reuse(byte[] src, byte find, byte replace) { + int src_len = src.length; + for (int i = 0; i < src_len; i++) { + if (src[i] == find) src[i] = replace; + } + } + public static byte[] Replace(byte[] src, byte find, byte replace) { + int src_len = src.length; + byte[] rv = new byte[src_len]; + for (int i = 0; i < src_len; i++) { + byte b = src[i]; + rv[i] = b == find ? replace : b; + } + return rv; + } + public static byte[] Replace_safe(Bry_bfr bfr, byte[] src, byte[] find, byte[] repl) { + if (src == null || find == null || repl == null) return null; + return Replace(bfr, src, find, repl, 0, src.length); + } + public static byte[] Replace(Bry_bfr bfr, byte[] src, byte[] find, byte[] repl) {return Replace(bfr, src, find, repl, 0, src.length);} + public static byte[] Replace(Bry_bfr bfr, byte[] src, byte[] find, byte[] repl, int src_bgn, int src_end) {return Replace(bfr, src, find, repl, src_bgn, src_end, Int_.MaxValue);} + public static byte[] Replace(Bry_bfr bfr, byte[] src, byte[] find, byte[] repl, int src_bgn, int src_end, int limit) { + int pos = src_bgn; + boolean dirty = false; + int find_len = find.length; + int bfr_bgn = pos; + int replace_count = 0; + while (pos < src_end) { + int find_pos = Bry_finder.Find_fwd(src, find, pos); + if (find_pos == Bry_finder.Not_found) break; + dirty = true; + bfr.Add_mid(src, bfr_bgn, find_pos); + bfr.Add(repl); + pos = find_pos + find_len; + bfr_bgn = pos; + ++replace_count; + if (replace_count == limit) break; + } + if (dirty) + bfr.Add_mid(src, bfr_bgn, src_end); + return dirty ? bfr.Xto_bry_and_clear() : src; + } + public static byte[] Replace(byte[] src, byte[] find, byte[] replace) {return Replace_between(src, find, null, replace);} + public static byte[] Replace_between(byte[] src, byte[] bgn, byte[] end, byte[] replace) { + Bry_bfr bfr = Bry_bfr.new_(); + boolean replace_all = end == null; + int src_len = src.length, bgn_len = bgn.length, end_len = replace_all ? 0 : end.length; + int pos = 0; + while (true) { + if (pos >= src_len) break; + int bgn_pos = Bry_finder.Find_fwd(src, bgn, pos); + if (bgn_pos == Bry_.NotFound) { + bfr.Add_mid(src, pos, src_len); + break; + } + else { + int bgn_rhs = bgn_pos + bgn_len; + int end_pos = replace_all ? bgn_rhs : Bry_finder.Find_fwd(src, end, bgn_rhs); + if (end_pos == Bry_.NotFound) { + bfr.Add_mid(src, pos, src_len); + break; + } + else { + bfr.Add_mid(src, pos, bgn_pos); + bfr.Add(replace); + pos = end_pos + end_len; + } + } + } + return bfr.Xto_bry_and_clear(); + } + public static int Trim_end_pos(byte[] src, int end) { + for (int i = end - 1; i > -1; i--) { + switch (src[i]) { + case Byte_ascii.Tab: case Byte_ascii.Nl: case Byte_ascii.Cr: case Byte_ascii.Space: + break; + default: + return i + 1; + } + } + return 0; + } + public static byte[][] Split(byte[] src, byte[] dlm) { + if (Bry_.Len_eq_0(src)) return Bry_.Ary_empty; + int cur_pos = 0, src_len = src.length, dlm_len = dlm.length; + List_adp rv = List_adp_.new_(); + while (true) { + int find_pos = Bry_finder.Find_fwd(src, dlm, cur_pos); + if (find_pos == Bry_.NotFound) { + if (cur_pos == src_len) break; // dlm is last sequence in src; do not create empty itm + find_pos = src_len; + } + rv.Add(Bry_.Mid(src, cur_pos, find_pos)); + if (find_pos == src_len) break; + cur_pos = find_pos + dlm_len; + } + return (byte[][])rv.To_ary(byte[].class); + } + public static byte[][] Split_lines(byte[] src) { + if (Bry_.Len_eq_0(src)) return Bry_.Ary_empty; + int src_len = src.length, src_pos = 0, fld_bgn = 0; + List_adp rv = List_adp_.new_(); + while (true) { + boolean last = src_pos == src_len; + byte b = last ? Byte_ascii.Nl : src[src_pos]; + int nxt_bgn = src_pos + 1; + switch (b) { + case Byte_ascii.Cr: + case Byte_ascii.Nl: + if ( b == Byte_ascii.Cr // check for crlf + && nxt_bgn < src_len && src[nxt_bgn] == Byte_ascii.Nl) { + ++nxt_bgn; + } + if (last && (src_pos - fld_bgn == 0)) {} // ignore trailing itms + else + rv.Add(Bry_.Mid(src, fld_bgn, src_pos)); + fld_bgn = nxt_bgn; + break; + } + if (last) break; + src_pos = nxt_bgn; + } + return (byte[][])rv.To_ary(byte[].class); + } + public static byte[] Increment_last(byte[] ary) {return Increment_last(ary, ary.length - 1);} + public static byte[] Increment_last(byte[] ary, int end_idx) { + for (int i = end_idx; i > -1; i--) { + byte end_val_old = ary[i]; + byte end_val_new = (byte)(end_val_old + 1); + ary[i] = end_val_new; + if (end_val_new > (end_val_old & 0xff)) break; // PATCH.JAVA:need to convert to unsigned byte + } + return ary; + } + public static byte[] Upper_1st(byte[] ary) { + if (ary == null) return null; + int len = ary.length; + if (len == 0) return ary; + byte b = ary[0]; + if (b > 96 && b < 123) + ary[0] = (byte)(b - 32); + return ary; + } + public static byte[] Upper_ascii(byte[] ary) { + int len = ary.length; + for (int i = 0; i < len; i++) { + byte b = ary[i]; + if (b > 96 && b < 123) + ary[i] = (byte)(b - 32); + } + return ary; + } + public static byte[] Lower_1st(byte[] ary) { + if (ary == null) return null; + int len = ary.length; + if (len == 0) return ary; + byte b = ary[0]; + if (b > 64 && b < 91) + ary[0] = (byte)(b + 32); + return ary; + } + public static byte[] Lower_ascii(byte[] ary) { + int len = ary.length; + for (int i = 0; i < len; i++) { + byte b = ary[i]; + if (b > 64 && b < 91) + ary[i] = (byte)(b + 32); + } + return ary; + } + public static byte[] Null_if_empty(byte[] v) {return Len_eq_0(v) ? null : v;} + public static byte Get_at_end(byte[] v) { + int v_len = v.length; + return v_len == 0 ? Byte_ascii.Nil : v[v_len - 1]; + } +} diff --git a/100_core/src_110_primitive/gplx/Bry__tst.java b/100_core/src_110_primitive/gplx/Bry__tst.java new file mode 100644 index 000000000..7d7c071bf --- /dev/null +++ b/100_core/src_110_primitive/gplx/Bry__tst.java @@ -0,0 +1,280 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; import gplx.core.primitives.*; +import gplx.texts.*; +public class Bry__tst { + @Test public void MidByPos() { + tst_MidByPos("abcba", 0, 1, "a"); + tst_MidByPos("abcba", 0, 2, "ab"); + tst_MidByPos("abcba", 1, 4, "bcb"); + } void tst_MidByPos(String src, int bgn, int end, String expd) {Tfds.Eq(expd, String_.new_u8(Bry_.Mid(Bry_.new_u8(src), bgn, end)));} + @Test public void Replace_one() { + tst_ReplaceOne("a" , "b" , "c" , "a"); + tst_ReplaceOne("b" , "b" , "c" , "c"); + tst_ReplaceOne("bb" , "b" , "c" , "cb"); + tst_ReplaceOne("abcd" , "bc" , "" , "ad"); + tst_ReplaceOne("abcd" , "b" , "ee" , "aeecd"); + } void tst_ReplaceOne(String src, String find, String repl, String expd) {Tfds.Eq(expd, String_.new_u8(Bry_.Replace_one(Bry_.new_u8(src), Bry_.new_u8(find), Bry_.new_u8(repl))));} + @Test public void XtoStrBytesByInt() { + tst_XtoStrBytesByInt(0, 0); + tst_XtoStrBytesByInt(9, 9); + tst_XtoStrBytesByInt(10, 1, 0); + tst_XtoStrBytesByInt(321, 3, 2, 1); + tst_XtoStrBytesByInt(-321, Bry_.Byte_NegSign, 3, 2, 1); + tst_XtoStrBytesByInt(Int_.MaxValue, 2,1,4,7,4,8,3,6,4,7); + } + void tst_XtoStrBytesByInt(int val, int... expdAryAsInt) { + byte[] expd = new byte[expdAryAsInt.length]; + for (int i = 0; i < expd.length; i++) { + int expdInt = expdAryAsInt[i]; + expd[i] = expdInt == Bry_.Byte_NegSign ? Bry_.Byte_NegSign : Bry_.XtoStrByte(expdAryAsInt[i]); + } + Tfds.Eq_ary(expd, Bry_.XtoStrBytesByInt(val, Int_.DigitCount(val))); + } + @Test public void Has_at_end() { + tst_HasAtEnd("a|bcd|e", "d" , 2, 5, true); // y_basic + tst_HasAtEnd("a|bcd|e", "bcd" , 2, 5, true); // y_many + tst_HasAtEnd("a|bcd|e", "|bcd" , 2, 5, false); // n_long + tst_HasAtEnd("a|bcd|e", "|bc" , 2, 5, false); // n_pos + tst_HasAtEnd("abc", "bc", true); // y + tst_HasAtEnd("abc", "bd", false); // n + tst_HasAtEnd("a", "ab", false); // exceeds_len + } + void tst_HasAtEnd(String src, String find, int bgn, int end, boolean expd) {Tfds.Eq(expd, Bry_.Has_at_end(Bry_.new_u8(src), Bry_.new_u8(find), bgn, end));} + void tst_HasAtEnd(String src, String find, boolean expd) {Tfds.Eq(expd, Bry_.Has_at_end(Bry_.new_u8(src), Bry_.new_u8(find)));} + @Test public void Has_at_bgn() { + tst_HasAtBgn("y_basic" , "a|bcd|e", "b" , 2, 5, true); + tst_HasAtBgn("y_many" , "a|bcd|e", "bcd" , 2, 5, true); + tst_HasAtBgn("n_long" , "a|bcd|e", "bcde" , 2, 5, false); + tst_HasAtBgn("n_pos" , "a|bcd|e", "|bc" , 2, 5, false); + } void tst_HasAtBgn(String tst, String src, String find, int bgn, int end, boolean expd) {Tfds.Eq(expd, Bry_.Has_at_bgn(Bry_.new_u8(src), Bry_.new_u8(find), bgn, end), tst);} + @Test public void Match() { + tst_Match("abc", 0, "abc", true); + tst_Match("abc", 2, "c", true); + tst_Match("abc", 0, "cde", false); + tst_Match("abc", 2, "abc", false); // bounds check + tst_Match("abc", 0, "abcd", false); + tst_Match("a" , 0, "", false); + tst_Match("" , 0, "a", false); + tst_Match("" , 0, "", true); + tst_Match("ab", 0, "a", false); // FIX: "ab" should not match "a" b/c .length is different + } void tst_Match(String src, int srcPos, String find, boolean expd) {Tfds.Eq(expd, Bry_.Match(Bry_.new_u8(src), srcPos, Bry_.new_u8(find)));} + @Test public void ReadCsvStr() { + tst_ReadCsvStr("a|" , "a"); + tst_ReadCsvStr("|a|", 1 , "a"); + Int_obj_ref bgn = Int_obj_ref.zero_(); tst_ReadCsvStr("a|b|c|", bgn, "a"); tst_ReadCsvStr("a|b|c|", bgn, "b"); tst_ReadCsvStr("a|b|c|", bgn, "c"); + tst_ReadCsvStr("|", ""); + tst_ReadCsvStr_err("a"); + + tst_ReadCsvStr("'a'|" , "a"); + tst_ReadCsvStr("'a''b'|" , "a'b"); + tst_ReadCsvStr("'a|b'|" , "a|b"); + tst_ReadCsvStr("''|", ""); + tst_ReadCsvStr_err("''"); + tst_ReadCsvStr_err("'a'b'"); + tst_ReadCsvStr_err("'a"); + tst_ReadCsvStr_err("'a|"); + tst_ReadCsvStr_err("'a'"); + } + @Test public void XtoIntBy4Bytes() { // test len=1, 2, 3, 4 + tst_XtoIntBy4Bytes(32, (byte)32); // space + tst_XtoIntBy4Bytes(8707, (byte)34, (byte)3); // ∃ + tst_XtoIntBy4Bytes(6382179, Byte_ascii.Ltr_a, Byte_ascii.Ltr_b, Byte_ascii.Ltr_c); + tst_XtoIntBy4Bytes(1633837924, Byte_ascii.Ltr_a, Byte_ascii.Ltr_b, Byte_ascii.Ltr_c, Byte_ascii.Ltr_d); + } + @Test public void XtoInt() { + tst_XtoInt("1", 1); + tst_XtoInt("123", 123); + tst_XtoInt("a", Int_.MinValue, Int_.MinValue); + tst_XtoInt("-1", Int_.MinValue, -1); + tst_XtoInt("-123", Int_.MinValue, -123); + tst_XtoInt("123-1", Int_.MinValue, Int_.MinValue); + tst_XtoInt("+123", Int_.MinValue, 123); + tst_XtoInt("", -1); + } + void tst_XtoInt(String val, int expd) {tst_XtoInt(val, -1, expd);} + void tst_XtoInt(String val, int or, int expd) {Tfds.Eq(expd, Bry_.Xto_int_or(Bry_.new_u8(val), or));} + void tst_XtoIntBy4Bytes(int expd, byte... ary) {Tfds.Eq(expd, Bry_.XtoIntBy4Bytes(ary), "XtoInt"); Tfds.Eq_ary(ary, Bry_.XbyInt(expd), "XbyInt");} + void tst_ReadCsvStr(String raw, String expd) {tst_ReadCsvStr(raw, Int_obj_ref.zero_() , expd);} + void tst_ReadCsvStr(String raw, int bgn, String expd) {tst_ReadCsvStr(raw, Int_obj_ref.new_(bgn), expd);} + void tst_ReadCsvStr(String raw, Int_obj_ref bgnRef, String expd) { + int bgn = bgnRef.Val(); + boolean rawHasQuotes = String_.CharAt(raw, bgn) == '\''; + String actl = String_.Replace(Bry_.ReadCsvStr(Bry_.new_u8(String_.Replace(raw, "'", "\"")), bgnRef, (byte)'|'), "\"", "'"); + Tfds.Eq(expd, actl, "rv"); + if (rawHasQuotes) { + int quoteAdj = String_.Count(actl, "'"); + Tfds.Eq(bgn + 1 + String_.Len(actl) + 2 + quoteAdj, bgnRef.Val(), "pos_quote"); // +1=lkp.Len; +2=bgn/end quotes + } + else + Tfds.Eq(bgn + 1 + String_.Len(actl), bgnRef.Val(), "pos"); // +1=lkp.Len + } + void tst_ReadCsvStr_err(String raw) { + try {Bry_.ReadCsvStr(Bry_.new_u8(String_.Replace(raw, "'", "\"")), Int_obj_ref.zero_(), (byte)'|');} + catch (Exception e) {Exc_.Noop(e); return;} + Tfds.Fail_expdError(); + } + @Test public void ReadCsvDte() { + tst_ReadCsvDte("20110801 221435.987"); + } void tst_ReadCsvDte(String raw) {Tfds.Eq_date(DateAdp_.parse_fmt(raw, Bry_.Fmt_csvDte), Bry_.ReadCsvDte(Bry_.new_u8(raw + "|"), Int_obj_ref.zero_(), (byte)'|'));} + @Test public void ReadCsvInt() { + tst_ReadCsvInt("1234567890"); + } void tst_ReadCsvInt(String raw) {Tfds.Eq(Int_.parse_(raw), Bry_.ReadCsvInt(Bry_.new_u8(raw + "|"), Int_obj_ref.zero_(), (byte)'|'));} + @Test public void Trim() { + Trim_tst("a b c", 1, 4, "b"); + Trim_tst("a c", 1, 3, ""); + Trim_tst(" ", 0, 2, ""); + } void Trim_tst(String raw, int bgn, int end, String expd) {Tfds.Eq(expd, String_.new_u8(Bry_.Trim(Bry_.new_u8(raw), bgn, end)));} + @Test public void Xto_int_lax() { + tst_Xto_int_lax("12a", 12); + tst_Xto_int_lax("1", 1); + tst_Xto_int_lax("123", 123); + tst_Xto_int_lax("a", 0); + tst_Xto_int_lax("-1", -1); + } + private void tst_Xto_int_lax(String val, int expd) {Tfds.Eq(expd, Bry_.Xto_int_or_lax(Bry_.new_u8(val), 0, String_.Len(val), 0));} + @Test public void Xto_int_or_trim() { + tst_Xto_int_trim("123 " , 123); + tst_Xto_int_trim(" 123" , 123); + tst_Xto_int_trim(" 123 " , 123); + tst_Xto_int_trim(" 1 3 " , -1); + } + private void tst_Xto_int_trim(String val, int expd) {Tfds.Eq(expd, Bry_.Xto_int_or_trim(Bry_.new_u8(val), 0, String_.Len(val), -1));} + @Test public void Compare() { + tst_Compare("abcde", 0, 1, "abcde", 0, 1, CompareAble_.Same); + tst_Compare("abcde", 0, 1, "abcde", 1, 2, CompareAble_.Less); + tst_Compare("abcde", 1, 2, "abcde", 0, 1, CompareAble_.More); + tst_Compare("abcde", 0, 1, "abcde", 0, 2, CompareAble_.Less); + tst_Compare("abcde", 0, 2, "abcde", 0, 1, CompareAble_.More); + tst_Compare("abcde", 2, 3, "abçde", 2, 3, CompareAble_.Less); + } void tst_Compare(String lhs, int lhs_bgn, int lhs_end, String rhs, int rhs_bgn, int rhs_end, int expd) {Tfds.Eq(expd, Bry_.Compare(Bry_.new_u8(lhs), lhs_bgn, lhs_end, Bry_.new_u8(rhs), rhs_bgn, rhs_end));} + @Test public void Increment_last() { + tst_IncrementLast(ary_(0), ary_(1)); + tst_IncrementLast(ary_(0, 255), ary_(1, 0)); + tst_IncrementLast(ary_(104, 111, 112, 101), ary_(104, 111, 112, 102)); + } + byte[] ary_(int... ary) { + byte[] rv = new byte[ary.length]; + for (int i = 0; i < ary.length; i++) + rv[i] = Byte_.By_int(ary[i]); + return rv; + } + void tst_IncrementLast(byte[] ary, byte[] expd) {Tfds.Eq_ary(expd, Bry_.Increment_last(Bry_.Copy(ary)));} + @Test public void Split() { + tst_Split("a|b|c" , Byte_ascii.Pipe, "a", "b", "c"); + tst_Split("a|b|c|" , Byte_ascii.Pipe, "a", "b", "c"); + tst_Split("|" , Byte_ascii.Pipe, ""); + tst_Split("" , Byte_ascii.Pipe); + } + void tst_Split(String raw_str, byte dlm, String... expd) { + byte[][] actl_bry = Bry_.Split(Bry_.new_a7(raw_str), dlm); + Tfds.Eq_ary_str(expd, String_.Ary(actl_bry)); + } + @Test public void Replace_between() { + tst_Replace_between("a[0]b" , "[", "]", "0", "a0b"); + tst_Replace_between("a[0]b[1]c" , "[", "]", "0", "a0b0c"); + tst_Replace_between("a[0b" , "[", "]", "0", "a[0b"); + } public void tst_Replace_between(String src, String bgn, String end, String repl, String expd) {Tfds.Eq(expd, String_.new_a7(Bry_.Replace_between(Bry_.new_a7(src), Bry_.new_a7(bgn), Bry_.new_a7(end), Bry_.new_a7(repl))));} + @Test public void Replace() { + Bry_bfr tmp_bfr = Bry_bfr.new_(); + tst_Replace(tmp_bfr, "a0b" , "0", "00", "a00b"); // 1 -> 1 + tst_Replace(tmp_bfr, "a0b0c" , "0", "00", "a00b00c"); // 1 -> 2 + tst_Replace(tmp_bfr, "a00b00c" , "00", "0", "a0b0c"); // 2 -> 1 + tst_Replace(tmp_bfr, "a0b0" , "0", "00", "a00b00"); // 1 -> 2; EOS + tst_Replace(tmp_bfr, "a00b00" , "00", "0", "a0b0"); // 2 -> 1; EOS + tst_Replace(tmp_bfr, "a0b0" , "1", "2", "a0b0"); // no match + tst_Replace(tmp_bfr, "a0b0" , "b1", "b2", "a0b0"); // false match; EOS + } + public void tst_Replace(Bry_bfr tmp_bfr, String src, String bgn, String repl, String expd) { + Tfds.Eq(expd, String_.new_a7(Bry_.Replace(tmp_bfr, Bry_.new_a7(src), Bry_.new_a7(bgn), Bry_.new_a7(repl)))); + } + @Test public void Split_bry() { + Split_bry_tst("a|b|c|" , "|" , String_.Ary("a", "b", "c")); + Split_bry_tst("a|" , "|" , String_.Ary("a")); + } + void Split_bry_tst(String src, String dlm, String[] expd) { + String[] actl = String_.Ary(Bry_.Split(Bry_.new_a7(src), Bry_.new_a7(dlm))); + Tfds.Eq_ary_str(expd, actl); + } + @Test public void Split_lines() { + Tst_split_lines("a\nb" , "a", "b"); // basic + Tst_split_lines("a\nb\n" , "a", "b"); // do not create empty trailing lines + Tst_split_lines("a\r\nb" , "a", "b"); // crlf + Tst_split_lines("a\rb" , "a", "b"); // cr only + } + void Tst_split_lines(String src, String... expd) { + Tfds.Eq_ary(expd, New_ary(Bry_.Split_lines(Bry_.new_a7(src)))); + } + String[] New_ary(byte[][] lines) { + int len = lines.length; + String[] rv = new String[len]; + for (int i = 0; i < len; i++) + rv[i] = String_.new_u8(lines[i]); + return rv; + } + @Test public void Match_bwd_any() { + Tst_match_bwd_any("abc", 2, 0, "c", true); + Tst_match_bwd_any("abc", 2, 0, "b", false); + Tst_match_bwd_any("abc", 2, 0, "bc", true); + Tst_match_bwd_any("abc", 2, 0, "abc", true); + Tst_match_bwd_any("abc", 2, 0, "zabc", false); + Tst_match_bwd_any("abc", 1, 0, "ab", true); + } + void Tst_match_bwd_any(String src, int src_end, int src_bgn, String find, boolean expd) { + Tfds.Eq(expd, Bry_.Match_bwd_any(Bry_.new_a7(src), src_end, src_bgn, Bry_.new_a7(find))); + } + private Bry__fxt fxt = new Bry__fxt(); + @Test public void Trim_end() { + fxt.Test_trim_end("a " , Byte_ascii.Space, "a"); // trim.one + fxt.Test_trim_end("a " , Byte_ascii.Space, "a"); // trim.many + fxt.Test_trim_end("a" , Byte_ascii.Space, "a"); // trim.none + fxt.Test_trim_end("" , Byte_ascii.Space, ""); // empty + } + @Test public void new_ascii_() { + fxt.Test_new_a7("a" , Bry_.ints_(97)); // one + fxt.Test_new_a7("abc" , Bry_.ints_(97, 98, 99)); // many + fxt.Test_new_a7("" , Bry_.Empty); // none + fxt.Test_new_a7("¢€𤭢" , Bry_.ints_(63, 63, 63, 63)); // non-ascii -> ? + } + @Test public void new_u8() { + fxt.Test_new_u8("a" , Bry_.ints_(97)); // one + fxt.Test_new_u8("abc" , Bry_.ints_(97, 98, 99)); // many + fxt.Test_new_u8("¢" , Bry_.ints_(194, 162)); // bry_len=2; cent + fxt.Test_new_u8("€" , Bry_.ints_(226, 130, 172)); // bry_len=3; euro + fxt.Test_new_u8("𤭢" , Bry_.ints_(240, 164, 173, 162)); // bry_len=3; example from en.w:UTF-8 + } + @Test public void Add_w_dlm() { + fxt.Test_add_w_dlm(Byte_ascii.Pipe, String_.Ary("a", "b", "c") , "a|b|c"); // basic + fxt.Test_add_w_dlm(Byte_ascii.Pipe, String_.Ary("a") , "a"); // one item + fxt.Test_add_w_dlm(Byte_ascii.Pipe, String_.Ary("a", null, "c") , "a||c"); // null + } + @Test public void Add_w_dlm_bry() { + fxt.Test_add_w_dlm("<>", String_.Ary("a","b","c"), "a<>b<>c"); + } +} +class Bry__fxt { + public void Test_trim_end(String raw, byte trim, String expd) { + byte[] raw_bry = Bry_.new_a7(raw); + Tfds.Eq(expd, String_.new_u8(Bry_.Trim_end(raw_bry, trim, raw_bry.length))); + } + public void Test_new_u8(String raw, byte[] expd) {Tfds.Eq_ary(expd, Bry_.new_u8(raw));} + public void Test_new_a7(String raw, byte[] expd) {Tfds.Eq_ary(expd, Bry_.new_a7(raw));} + public void Test_add_w_dlm(String dlm, String[] itms, String expd) {Tfds.Eq(expd, String_.new_u8(Bry_.Add_w_dlm(Bry_.new_u8(dlm), Bry_.Ary(itms))));} + public void Test_add_w_dlm(byte dlm, String[] itms, String expd) {Tfds.Eq(expd, String_.new_u8(Bry_.Add_w_dlm(dlm, Bry_.Ary(itms))));} +} diff --git a/100_core/src_110_primitive/gplx/Bry_bfr.java b/100_core/src_110_primitive/gplx/Bry_bfr.java new file mode 100644 index 000000000..8bd4ef706 --- /dev/null +++ b/100_core/src_110_primitive/gplx/Bry_bfr.java @@ -0,0 +1,567 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.core.primitives.*; +public class Bry_bfr { + private Bry_bfr_mkr_mgr mkr_mgr; private int reset; + public byte[] Bfr() {return bfr;} private byte[] bfr; + public int Len() {return bfr_len;} private int bfr_len; + public boolean Len_eq_0() {return bfr_len == 0;} + public boolean Len_gt_0() {return bfr_len > 0;} + public void Bfr_init(byte[] bfr, int bfr_len) { + synchronized (this) { + this.bfr = bfr; + this.bfr_len = bfr_len; + this.bfr_max = bfr.length; // NOTE: must sync bfr_max, else will fail later during add; bfr will think bfr has .length of bfr_max, when it actually has .length of bfr_len; DATE:2014-03-09 + } + } + public Bry_bfr Mkr_rls() { + if (mkr_mgr != null) { + synchronized (mkr_mgr) { + mkr_mgr.Rls(mkr_idx); + } + synchronized (this) { + this.mkr_mgr = null; + this.mkr_idx = -1; + } + } + return this; + } + public void Clear_and_rls() { + this.Clear(); + this.Mkr_rls(); + } + public String To_str_and_rls() {return String_.new_u8(To_bry_and_rls());} + public byte[] To_bry_and_rls() { + byte[] rv = null; + synchronized (bfr) { + rv = Xto_bry(); + this.Clear(); + if (reset > 0) Reset_if_gt(reset); + synchronized (mkr_mgr) { + mkr_mgr.Rls(mkr_idx); + } + mkr_mgr = null; + mkr_idx = -1; + } + return rv; + } + private Bry_bfr Reset_(int v) {reset = v; return this;} + public Bry_bfr Reset_if_gt(int limit) { + if (bfr_max > limit) { + this.bfr_max = limit; + this.bfr = new byte[limit]; + } + bfr_len = 0; + return this; + } + public Bry_bfr Clear() { + synchronized (this) { + this.bfr_len = 0; + } + return this; + } + public Bry_bfr ClearAndReset() {bfr_len = 0; if (reset > 0) Reset_if_gt(reset); return this;} + public byte Get_at_last_or_nil_if_empty() {return bfr_len == 0 ? Byte_ascii.Nil : bfr[bfr_len - 1];} + public Bry_bfr Add_safe(byte[] val) {return val == null ? this : Add(val);} + public Bry_bfr Add(byte[] val) { + int val_len = val.length; + if (bfr_len + val_len > bfr_max) Resize((bfr_max + val_len) * 2); + Bry_.Copy_by_pos(val, 0, val_len, bfr, bfr_len); + // Array_.CopyTo(val, 0, bfr, bfr_len, val_len); + bfr_len += val_len; + return this; + } + public Bry_bfr Add_mid(byte[] val, int bgn, int end) { + int len = end - bgn; + if (len < 0) throw Exc_.new_("negative len", "bgn", bgn, "end", end, "excerpt", String_.new_u8_by_len(val, bgn, bgn + 16)); // NOTE: check for invalid end < bgn, else difficult to debug errors later; DATE:2014-05-11 + if (bfr_len + len > bfr_max) Resize((bfr_max + len) * 2); + Bry_.Copy_by_pos(val, bgn, end, bfr, bfr_len); + // Array_.CopyTo(val, bgn, bfr, bfr_len, len); + bfr_len += len; + return this; + } + public Bry_bfr Add_bfr_and_preserve(Bry_bfr src) { + int len = src.bfr_len; + if (bfr_len + len > bfr_max) Resize((bfr_max + len) * 2); + Bry_.Copy_by_pos(src.bfr, 0, len, bfr, bfr_len); + // Array_.CopyTo(src.bfr, 0, bfr, bfr_len, len); + bfr_len += len; + return this; + } + public Bry_bfr Add_bfr_and_clear(Bry_bfr src) { + Add_bfr_and_preserve(src); + src.ClearAndReset(); + return this; + } + public Bry_bfr Add_bfr_or_mid(boolean escaped, Bry_bfr tmp_bfr, byte[] src, int src_bgn, int src_end) { + return escaped + ? this.Add_bfr_and_clear(tmp_bfr) + : this.Add_mid(src, src_bgn, src_end); + } + public Bry_bfr Add_bfr_trim_and_clear(Bry_bfr src, boolean trim_bgn, boolean trim_end) {return Add_bfr_trim_and_clear(src, trim_bgn, trim_end, Bry_.Trim_ary_ws);} + public Bry_bfr Add_bfr_trim_and_clear(Bry_bfr src, boolean trim_bgn, boolean trim_end, byte[] trim_ary) { + int src_len = src.bfr_len; + if (bfr_len + src_len > bfr_max) Resize((bfr_max + src_len) * 2); + byte[] src_bry = src.Bfr(); + int src_bgn = 0, src_end = src_len; + boolean all_ws = true; + if (trim_bgn) { + for (int i = 0; i < src_len; i++) { + byte b = src_bry[i]; + if (trim_ary[b & 0xFF] == Byte_ascii.Nil) { + src_bgn = i; + i = src_len; + all_ws = false; + } + } + if (all_ws) return this; + } + if (trim_end) { + for (int i = src_len - 1; i > -1; i--) { + byte b = src_bry[i]; + if (trim_ary[b & 0xFF] == Byte_ascii.Nil) { + src_end = i + 1; + i = -1; + all_ws = false; + } + } + if (all_ws) return this; + } + src_len = src_end - src_bgn; + Bry_.Copy_by_pos(src.bfr, src_bgn, src_end, bfr, bfr_len); + // Array_.CopyTo(src.bfr, src_bgn, bfr, bfr_len, src_len); + bfr_len += src_len; + src.Clear(); + return this; + } + public Bry_bfr Add_byte_eq() {return Add_byte(Byte_ascii.Eq);} + public Bry_bfr Add_byte_pipe() {return Add_byte(Byte_ascii.Pipe);} + public Bry_bfr Add_byte_comma() {return Add_byte(Byte_ascii.Comma);} + public Bry_bfr Add_byte_semic() {return Add_byte(Byte_ascii.Semic);} + public Bry_bfr Add_byte_apos() {return Add_byte(Byte_ascii.Apos);} + public Bry_bfr Add_byte_slash() {return Add_byte(Byte_ascii.Slash);} + public Bry_bfr Add_byte_backslash() {return Add_byte(Byte_ascii.Backslash);} + public Bry_bfr Add_byte_quote() {return Add_byte(Byte_ascii.Quote);} + public Bry_bfr Add_byte_space() {return Add_byte(Byte_ascii.Space);} + public Bry_bfr Add_byte_nl() {return Add_byte(Byte_ascii.Nl);} + public Bry_bfr Add_byte_dot() {return Add_byte(Byte_ascii.Dot);} + public Bry_bfr Add_byte_colon() {return Add_byte(Byte_ascii.Colon);} + public Bry_bfr Add_byte(byte val) { + int new_pos = bfr_len + 1; + if (new_pos > bfr_max) Resize(bfr_len * 2); + bfr[bfr_len] = val; + bfr_len = new_pos; + return this; + } + public Bry_bfr Add_byte_repeat(byte b, int len) { + if (bfr_len + len > bfr_max) Resize((bfr_max + len) * 2); + for (int i = 0; i < len; i++) + bfr[i + bfr_len] = b; + bfr_len += len; + return this; + } + public Bry_bfr Add_byte_if_not_last(byte b) { + if (bfr_len == 0 || (bfr_len > 0 && bfr[bfr_len - 1] == b)) return this; + this.Add_byte(b); + return this; + } + public Bry_bfr Add_u8_int(int val) { + if (bfr_len + 4 > bfr_max) Resize((bfr_max + 4) * 2); + int utf8_len = gplx.intl.Utf16_.Encode_int(val, bfr, bfr_len); + bfr_len += utf8_len; + return this; + } + public Bry_bfr Add_bool(boolean v) {return Add(v ? Const_bool_true : Const_bool_false);} public static final byte[] Const_bool_true = Bry_.new_a7("true"), Const_bool_false = Bry_.new_a7("false"); + public Bry_bfr Add_int_bool(boolean v) {return Add_int_fixed(v ? 1 : 0, 1);} + public Bry_bfr Add_int_variable(int val) { + int log10 = Int_.Log10(val); + int slots = val > -1 ? log10 + 1 : log10 * -1 + 2; + return Add_int(val, log10, slots); + } + public Bry_bfr Add_int_pad_bgn(byte pad_byte, int str_len, int val) { + int digit_len = Int_.DigitCount(val); + int pad_len = str_len - digit_len; + if (pad_len > 0) // note that this skips pad_len == 0, as well as guarding against negative pad_len; EX: pad(" ", 3, 1234) -> "1234" + Add_byte_repeat(pad_byte, pad_len); + Add_int_fixed(val, digit_len); + return this; + } + public Bry_bfr Add_int_digits(int digits, int val) {return Add_int(val, Int_.Log10(val), digits);} + public Bry_bfr Add_int_fixed(int val, int digits) {return Add_int(val, Int_.Log10(val), digits);} + public Bry_bfr Add_int(int val, int valLog, int arySlots) { + int aryBgn = bfr_len, aryEnd = bfr_len + arySlots; + if (aryEnd > bfr_max) Resize((aryEnd) * 2); + if (val < 0) { + bfr[aryBgn++] = Byte_ascii.Dash; + val *= -1; // make positive + valLog *= -1; // valLog will be negative; make positive + arySlots -= 1; // reduce slot by 1 + } + if (valLog >= arySlots) { + val %= Int_.Log10Ary[arySlots]; + } + for (int i = 0; i < arySlots; i++) { + int logIdx = arySlots - i - 1; + int div = logIdx < Int_.Log10AryLen ? Int_.Log10Ary[logIdx] : Int_.MaxValue; + bfr[aryBgn + i] = (byte)((val / div) + 48); + val %= div; + } + bfr_len = aryEnd; + return this; + } + public Bry_bfr Add_long_variable(long v) {int digitCount = Long_.DigitCount(v); return Add_long(v, digitCount, digitCount);} + public Bry_bfr Add_long_fixed(long val, int digits) {return Add_long(val, Long_.DigitCount(val), digits);} + protected Bry_bfr Add_long(long val, int digitCount, int arySlots) { + int aryBgn = bfr_len, aryEnd = bfr_len + arySlots; + if (aryEnd > bfr_max) Resize((aryEnd) * 2); + if (val < 0) { + bfr[aryBgn++] = Byte_ascii.Dash; + val *= -1; // make positive + arySlots -= 1; // reduce slot by 1 + } + if (digitCount >= arySlots) { + val %= Long_.Log10Ary[arySlots]; + } + for (int i = 0; i < arySlots; i++) { + int logIdx = arySlots - i - 1; + long div = logIdx < Long_.Log10Ary_len ? Long_.Log10Ary[logIdx] : Long_.MaxValue; + bfr[aryBgn + i] = (byte)((val / div) + 48); + val %= div; + } + bfr_len = aryEnd; + return this; + } + public Bry_bfr Add_bry_comma(byte[] v) {return Add_bry(Byte_ascii.Comma, v);} + public Bry_bfr Add_bry(byte dlm, byte[] v) { + if (v == null) return this; + int v_len = v.length; + for (int i = 0; i < v_len; i++) { + if (i != 0) this.Add_byte(dlm); + this.Add_int_variable(v[i]); + } + return this; + } + public Bry_bfr Add_bry_escape(byte quote_byte, byte[] escape, byte[] val, int bgn, int end) { // used for xml_wtr; DATE:2015-04-09 + boolean clean = true; // add with chunks of bytes instead of one-by-one + for (int i = bgn; i < end; ++i) { + byte b = val[i]; + if (clean) { + if (b == quote_byte) { + clean = false; + this.Add_mid(val, bgn, i); + this.Add(escape); + } + else {} + } + else { + if (b == quote_byte) this.Add(escape); + else this.Add_byte(b); + } + } + if (clean) + Add(val); + return this; + } + public Bry_bfr Add_str(String v) {return Add_str_u8(v);} + public Bry_bfr Add_str_u8(String str) { + try { + int str_len = str.length(); + int bry_len = Bry_.new_u8_by_len(str, str_len); + if (bfr_len + bry_len > bfr_max) Resize((bfr_max + bry_len) * 2); + Bry_.new_u8_write(str, str_len, bfr, bfr_len); + bfr_len += bry_len; + return this; + } + catch (Exception e) {throw Exc_.new_exc(e, "core", "invalid UTF-8 sequence", "s", str);} + } + public Bry_bfr Add_str_a7(String str) { + try { + int bry_len = str.length(); + if (bfr_len + bry_len > bfr_max) Resize((bfr_max + bry_len) * 2); + for (int i = 0; i < bry_len; ++i) { + char c = str.charAt(i); + if (c > 128) c = '?'; + bfr[i + bfr_len] = (byte)c; + } + bfr_len += bry_len; + return this; + } + catch (Exception e) {throw Exc_.new_exc(e, "core", "invalid UTF-8 sequence", "s", str);} + } + public Bry_bfr Add_kv_line(String key, Object val) { + this.Add_str_a7(key).Add_byte_colon().Add_byte_space(); + this.Add(Bry_.new_u8(Object_.Xto_str_strict_or_null_mark(val))).Add_byte_nl(); + return this; + } + public Bry_bfr Add_float(float f) {Add_str(Float_.Xto_str(f)); return this;} + public Bry_bfr Add_double(double v) {Add_str(Double_.Xto_str(v)); return this;} + public Bry_bfr Add_dte(DateAdp val) {return Add_dte_segs(val.Year(), val.Month(),val.Day(), val.Hour(), val.Minute(), val.Second(), val.Frac());} + public Bry_bfr Add_dte_segs(int y, int M, int d, int H, int m, int s, int f) { // yyyyMMdd HHmmss.fff + if (bfr_len + 19 > bfr_max) Resize((bfr_len + 19) * 2); + bfr[bfr_len + 0] = (byte)((y / 1000) + Bry_.Ascii_zero); y %= 1000; + bfr[bfr_len + 1] = (byte)((y / 100) + Bry_.Ascii_zero); y %= 100; + bfr[bfr_len + 2] = (byte)((y / 10) + Bry_.Ascii_zero); y %= 10; + bfr[bfr_len + 3] = (byte)( y + Bry_.Ascii_zero); + bfr[bfr_len + 4] = (byte)((M / 10) + Bry_.Ascii_zero); M %= 10; + bfr[bfr_len + 5] = (byte)( M + Bry_.Ascii_zero); + bfr[bfr_len + 6] = (byte)((d / 10) + Bry_.Ascii_zero); d %= 10; + bfr[bfr_len + 7] = (byte)( d + Bry_.Ascii_zero); + bfr[bfr_len + 8] = Byte_ascii.Space; + bfr[bfr_len + 9] = (byte)((H / 10) + Bry_.Ascii_zero); H %= 10; + bfr[bfr_len + 10] = (byte)( H + Bry_.Ascii_zero); + bfr[bfr_len + 11] = (byte)((m / 10) + Bry_.Ascii_zero); m %= 10; + bfr[bfr_len + 12] = (byte)( m + Bry_.Ascii_zero); + bfr[bfr_len + 13] = (byte)((s / 10) + Bry_.Ascii_zero); s %= 10; + bfr[bfr_len + 14] = (byte)( s + Bry_.Ascii_zero); + bfr[bfr_len + 15] = Byte_ascii.Dot; + bfr[bfr_len + 16] = (byte)((f / 100) + Bry_.Ascii_zero); f %= 100; + bfr[bfr_len + 17] = (byte)((f / 10) + Bry_.Ascii_zero); f %= 10; + bfr[bfr_len + 18] = (byte)( f + Bry_.Ascii_zero); + bfr_len += 19; + return this; + } + public Bry_bfr Add_dte_utc(int y, int M, int d, int H, int m, int s, int f) { // yyyy-MM-ddTHH:mm:ssZ + if (bfr_len + 20 > bfr_max) Resize((bfr_len + 20) * 2); + bfr[bfr_len + 0] = (byte)((y / 1000) + Bry_.Ascii_zero); y %= 1000; + bfr[bfr_len + 1] = (byte)((y / 100) + Bry_.Ascii_zero); y %= 100; + bfr[bfr_len + 2] = (byte)((y / 10) + Bry_.Ascii_zero); y %= 10; + bfr[bfr_len + 3] = (byte)( y + Bry_.Ascii_zero); + bfr[bfr_len + 4] = Byte_ascii.Dash; + bfr[bfr_len + 5] = (byte)((M / 10) + Bry_.Ascii_zero); M %= 10; + bfr[bfr_len + 6] = (byte)( M + Bry_.Ascii_zero); + bfr[bfr_len + 7] = Byte_ascii.Dash; + bfr[bfr_len + 8] = (byte)((d / 10) + Bry_.Ascii_zero); d %= 10; + bfr[bfr_len + 9] = (byte)( d + Bry_.Ascii_zero); + bfr[bfr_len + 10] = Byte_ascii.Ltr_T; + bfr[bfr_len + 11] = (byte)((H / 10) + Bry_.Ascii_zero); H %= 10; + bfr[bfr_len + 12] = (byte)( H + Bry_.Ascii_zero); + bfr[bfr_len + 13] = Byte_ascii.Colon; + bfr[bfr_len + 14] = (byte)((m / 10) + Bry_.Ascii_zero); m %= 10; + bfr[bfr_len + 15] = (byte)( m + Bry_.Ascii_zero); + bfr[bfr_len + 16] = Byte_ascii.Colon; + bfr[bfr_len + 17] = (byte)((s / 10) + Bry_.Ascii_zero); s %= 10; + bfr[bfr_len + 18] = (byte)( s + Bry_.Ascii_zero); + bfr[bfr_len + 19] = Byte_ascii.Ltr_Z; + bfr_len += 20; + return this; + } + public Bry_bfr Add_swap_ws(byte[] src) {return Add_swap_ws(src, 0, src.length);} + public Bry_bfr Add_swap_ws(byte[] src, int bgn, int end) { + int len = end - bgn; + if (bfr_len + (len * 2) > bfr_max) Resize((bfr_max + (len * 2)) * 2); + for (int i = bgn; i < end; i++) { + byte b = src[i]; + switch (b) { + case Byte_ascii.Nl: bfr[bfr_len] = Byte_ascii.Backslash; bfr[bfr_len + 1] = Byte_ascii.Ltr_n; bfr_len += 2; break; + case Byte_ascii.Tab: bfr[bfr_len] = Byte_ascii.Backslash; bfr[bfr_len + 1] = Byte_ascii.Ltr_t; bfr_len += 2; break; + case Byte_ascii.Backslash: bfr[bfr_len] = Byte_ascii.Backslash; bfr[bfr_len + 1] = Byte_ascii.Backslash; bfr_len += 2; break; + default: bfr[bfr_len] = b; ++bfr_len; break; + } + } + return this; + } + public Bry_bfr Add_str_pad_space_bgn(String v, int pad_max) {return Add_str_pad_space(v, pad_max, Bool_.N);} + public Bry_bfr Add_str_pad_space_end(String v, int pad_max) {return Add_str_pad_space(v, pad_max, Bool_.Y);} + Bry_bfr Add_str_pad_space(String v, int pad_max, boolean pad_end) { + byte[] v_bry = Bry_.new_u8(v); + if (pad_end) Add(v_bry); + int pad_len = pad_max - v_bry.length; + if (pad_len > 0) + Add_byte_repeat(Byte_ascii.Space, pad_len); + if (!pad_end) Add(v_bry); + return this; + } + + public Bry_bfr Add_obj(Object o) { + if (o == null) return this; // treat null as empty String; + Class o_type = o.getClass(); + if (o_type == byte[].class) Add((byte[])o); + else if (o_type == Integer.class) Add_int_variable(Int_.cast_(o)); + else if (o_type == Byte.class) Add_byte(Byte_.cast_(o)); + else if (o_type == Long.class) Add_long_variable(Long_.cast_(o)); + else if (o_type == String.class) Add_str((String)o); + else if (o_type == Bry_bfr.class) Add_bfr_and_preserve((Bry_bfr)o); + else if (o_type == DateAdp.class) Add_dte((DateAdp)o); + else if (o_type == Io_url.class) Add(((Io_url)o).RawBry()); + else if (o_type == Boolean.class) Add_yn(Bool_.cast_(o)); + else if (o_type == Double.class) Add_double(Double_.cast_(o)); + else if (o_type == Float.class) Add_float(Float_.cast_(o)); + else ((Bry_fmtr_arg)o).XferAry(this, 0); + return this; + } + public Bry_bfr Add_obj_strict(Object o) { + if (o == null) return this; // treat null as empty String; + Class o_type = o.getClass(); + if (o_type == byte[].class) Add((byte[])o); + else if (o_type == Integer.class) Add_int_variable(Int_.cast_(o)); + else if (o_type == Byte.class) Add_byte(Byte_.cast_(o)); + else if (o_type == Long.class) Add_long_variable(Long_.cast_(o)); + else if (o_type == String.class) Add_str((String)o); + else if (o_type == Bry_bfr.class) Add_bfr_and_preserve((Bry_bfr)o); + else if (o_type == DateAdp.class) Add_dte((DateAdp)o); + else if (o_type == Io_url.class) Add(((Io_url)o).RawBry()); + else if (o_type == Boolean.class) Add_bool(Bool_.cast_(o)); + else if (o_type == Double.class) Add_double(Double_.cast_(o)); + else if (o_type == Float.class) Add_float(Float_.cast_(o)); + else ((Bry_fmtr_arg)o).XferAry(this, 0); + return this; + } + public Bry_bfr Add_yn(boolean v) {Add_byte(v ? Byte_ascii.Ltr_y : Byte_ascii.Ltr_n); return this;} + public Bry_bfr Add_base85_len_5(int v) {return Add_base85(v, 5);} + public Bry_bfr Add_base85(int v, int pad) { + int new_len = bfr_len + pad; + if (new_len > bfr_max) Resize((new_len) * 2); + Base85_utl.XtoStrByAry(v, bfr, bfr_len, pad); + bfr_len = new_len; + return this; + } + public boolean Match_end_byt(byte b) {return bfr_len == 0 ? false : bfr[bfr_len - 1] == b;} + public boolean Match_end_byt_nl_or_bos() {return bfr_len == 0 ? true : bfr[bfr_len - 1] == Byte_ascii.Nl;} + public boolean Match_end_ary(byte[] ary) {return Bry_.Match(bfr, bfr_len - ary.length, bfr_len, ary);} + public Bry_bfr Insert_at(int add_pos, byte[] add_bry) {return Insert_at(add_pos, add_bry, 0, add_bry.length);} + public Bry_bfr Insert_at(int add_pos, byte[] add_bry, int add_bgn, int add_end) { + int add_len = add_end - add_bgn; + int new_max = bfr_max + add_len; + byte[] new_bfr = new byte[new_max]; + if (add_pos > 0) + Bry_.Copy_by_pos (bfr , 0, add_pos, new_bfr, 0); + Bry_.Copy_by_pos (add_bry, add_bgn, add_end, new_bfr, add_pos); + Bry_.Copy_by_pos (bfr , add_pos, bfr_len, new_bfr, add_pos + add_len); + bfr = new_bfr; + bfr_len += add_len; + bfr_max = new_max; + return this; + } + public Bry_bfr Delete_rng_to_bgn(int pos) {return Delete_rng(0, pos);} + public Bry_bfr Delete_rng_to_end(int pos) {return Delete_rng(pos, bfr_len);} + public Bry_bfr Delete_rng(int rng_bgn, int rng_end) { + int rng_len = rng_end - rng_bgn; + Bry_.Copy_by_pos(bfr, rng_end, bfr_len, bfr, rng_bgn); + bfr_len -= rng_len; + return this; + } + public Bry_bfr Del_by_1() { + bfr_len -= 1; bfr[bfr_len] = 0; return this; + } + public Bry_bfr Del_by(int count) { + int new_len = bfr_len - count; + if (new_len > -1) bfr_len = new_len; + return this; + } + public Bry_bfr Trim_end(byte trim_byte) { + if (bfr_len == 0) return this; + int count = 0; + for (int i = bfr_len - 1; i > -1; --i) { + byte b = bfr[i]; + if (b == trim_byte) + ++count; + else + break; + } + if (count > 0) + this.Del_by(count); + return this; + } + public Bry_bfr Concat_skip_empty(byte[] dlm, byte[]... ary) { + int ary_len = ary.length; + for (int i = 0; i < ary_len; i++) { + byte[] itm = ary[i]; + boolean itm_has_bytes = Bry_.Len_gt_0(itm); + if ( i != 0 + && itm_has_bytes + && bfr_len > 0 + ) + this.Add(dlm); + if (itm_has_bytes) + this.Add(itm); + } + return this; + } + public boolean Eq(byte b) {return bfr_len == 1 && bfr[0] == b;} + public byte[] Xto_bry() {return bfr_len == 0 ? Bry_.Empty : Bry_.Mid(bfr, 0, bfr_len);} + public byte[] Xto_bry_and_reset(int v) { + byte[] rv = Xto_bry(); + this.Clear().Reset_if_gt(v); + return rv; + } + public byte[] Xto_bry_and_clear_and_trim() {return Xto_bry_and_clear_and_trim(true, true, Bry_.Trim_ary_ws);} + public byte[] Xto_bry_and_clear_and_trim(boolean trim_bgn, boolean trim_end, byte[] trim_bry) { + byte[] rv = Bry_.Trim(bfr, 0, bfr_len, trim_bgn, trim_end, trim_bry); + this.Clear(); + return rv; + } + public byte[] Xto_bry_and_clear() { + byte[] rv = Xto_bry(); + this.Clear(); + if (reset > 0) Reset_if_gt(reset); + return rv; + } + public String Xto_str() {return String_.new_u8(Xto_bry());} + public String Xto_str_by_pos(int bgn, int end) {return String_.new_u8(Xto_bry(), bgn, end);} + public String Xto_str_and_clear() {return String_.new_u8(Xto_bry_and_clear());} + public String Xto_str_and_clear_and_trim() {return String_.new_u8(Xto_bry_and_clear_and_trim());} + public int XtoIntAndClear(int or) {int rv = XtoInt(or); this.Clear(); return rv;} + public int XtoInt(int or) { + switch (bfr_len) { + case 0: return or; + case 1: { + byte b = bfr[0]; + return Byte_ascii.Is_num(b) ? b - Byte_ascii.Num_0 : or; + } + default: + long rv = 0, mult = 1; + for (int i = bfr_len - 1; i > -1; i--) { + byte b = bfr[i]; + if (!Byte_ascii.Is_num(b)) return or; + long dif = (b - Byte_ascii.Num_0 ) * mult; + long new_val = rv + dif; + if (new_val > Int_.MaxValue) return or; // if number is > 2^32 consider error (int overflow); return or; DATE:2014-06-10 + rv = new_val; + mult *= 10; + } + return (int)rv; + } + } + public void Rls() { + bfr = null; + this.Mkr_rls(); + } + @Override public int hashCode() {return Bry_obj_ref.CalcHashCode(bfr, 0, bfr_len);} + @Override public boolean equals(Object obj) {return obj == null ? false : Bry_.Match(bfr, 0, bfr_len, ((Bry_obj_ref)obj).Val());} // NOTE: strange, but null check needed; throws null error; PAGE:c:File:Eug�ne_Delacroix_-_La_libert�_guidant_le_peuple.jpg + public void Resize(int v) { + bfr_max = v; + bfr = Bry_.Resize(bfr, 0, v); + } + @gplx.Internal protected int Mkr_idx() {return mkr_idx;} private int mkr_idx = -1; + @gplx.Internal protected boolean Mkr_idx_is_null() {return mkr_idx == -1;} + @gplx.Internal protected int Bfr_max() {return bfr_max;} private int bfr_max; + @gplx.Internal protected Bry_bfr Mkr_init(Bry_bfr_mkr_mgr mkr_mgr, int itm) { + synchronized (this) { + this.mkr_mgr = mkr_mgr; this.mkr_idx = itm; + } + return this; + } + public static Bry_bfr new_() {return new Bry_bfr(16);} + public static Bry_bfr new_(int v) {return new Bry_bfr(v);} + public static Bry_bfr reset_(int v) {return new Bry_bfr(16).Reset_(v);} // PERF: set initial size to 16, not reset val; allows for faster "startup"; DATE:2014-06-14 + Bry_bfr(int bfr_max) { + this.bfr_max = bfr_max; + this.bfr = new byte[bfr_max]; + } +} diff --git a/100_core/src_110_primitive/gplx/Bry_bfr_.java b/100_core/src_110_primitive/gplx/Bry_bfr_.java new file mode 100644 index 000000000..613404d42 --- /dev/null +++ b/100_core/src_110_primitive/gplx/Bry_bfr_.java @@ -0,0 +1,38 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Bry_bfr_ { + public static Bry_bfr[] Ary_empty = new Bry_bfr[0]; + public static void Assert_at_end(Bry_bfr bfr, byte assert_byte) { + int len = bfr.Len(); if (len == 0) return; + int assert_count = 0; + byte[] bfr_bry = bfr.Bfr(); + for (int i = len - 1; i > -1; --i) { + byte b = bfr_bry[i]; + if (b == assert_byte) + ++assert_count; + else + break; + } + switch (assert_count) { + case 0: bfr.Add_byte(assert_byte); break; + case 1: break; + default: bfr.Del_by(assert_count - 1); break; + } + } +} diff --git a/100_core/src_110_primitive/gplx/Bry_bfr_mkr.java b/100_core/src_110_primitive/gplx/Bry_bfr_mkr.java new file mode 100644 index 000000000..971fd14e1 --- /dev/null +++ b/100_core/src_110_primitive/gplx/Bry_bfr_mkr.java @@ -0,0 +1,158 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Bry_bfr_mkr { + public static final byte Tid_b128 = 0, Tid_b512 = 1, Tid_k004 = 2, Tid_m001 = 3; + private Bry_bfr_mkr_mgr mkr_b128 = new Bry_bfr_mkr_mgr(Tid_b128, 128), mkr_b512 = new Bry_bfr_mkr_mgr(Tid_b512, 512), mkr_k004 = new Bry_bfr_mkr_mgr(Tid_k004, 4 * Io_mgr.Len_kb), mkr_m001 = new Bry_bfr_mkr_mgr(Tid_m001, 1 * Io_mgr.Len_mb); + public Bry_bfr Get_b128() {return mkr_b128.Get();} + public Bry_bfr Get_b512() {return mkr_b512.Get();} + public Bry_bfr Get_k004() {return mkr_k004.Get();} + public Bry_bfr Get_m001() {return mkr_m001.Get();} + public void Rls(Bry_bfr v) { + v.Mkr_rls(); +// v.Mkr_mgr().Rls(v); + } + public void Reset_if_gt(int v) { + for (byte i = Tid_b128; i <= Tid_m001; i++) + mkr(i).Reset_if_gt(v); + } + public void Clear_fail_check() { + for (byte i = Tid_b128; i <= Tid_m001; i++) + mkr(i).Clear_fail_check(); + } + + public void Clear() { + for (byte i = Tid_b128; i <= Tid_m001; i++) + mkr(i).Clear(); + } + Bry_bfr_mkr_mgr mkr(byte tid) { + switch (tid) { + case Tid_b128: return mkr_b128; + case Tid_b512: return mkr_b512; + case Tid_k004: return mkr_k004; + case Tid_m001: return mkr_m001; + default: throw Exc_.new_unhandled(tid); + } + } +} +class Bry_bfr_mkr_mgr { + private final Object thread_lock; + public Bry_bfr_mkr_mgr(byte mgr_id, int reset) {// NOTE: random IndexOutOfBounds errors in Get around free[--free_len] with free_len being -1; put member variable initialization within thread_lock to try to avoid; DATE:2014-09-21 + thread_lock = new Object(); + synchronized (thread_lock) { + this.mgr_id = mgr_id; + this.reset = reset; + this.free = Int_.Ary_empty; + this.free_len = 0; + } + } private int reset; + public byte Mgr_id() {return mgr_id;} private byte mgr_id; + private Bry_bfr[] ary = Ary_empty; private int nxt_idx = 0, ary_max = 0; + private int[] free; private int free_len; + public void Reset_if_gt(int v) { + this.Clear(); // TODO: for now, just call clear + } + public void Clear_fail_check() { + synchronized (thread_lock) { + for (int i = 0; i < ary_max; i++) { + Bry_bfr itm = ary[i]; + if (itm != null) { + if (!itm.Mkr_idx_is_null()) throw Exc_.new_("failed to clear bfr", "idx", Int_.Xto_str(i)); + itm.Clear(); + } + ary[i] = null; + } + ary = Ary_empty; + free = Int_.Ary_empty; + free_len = 0; + nxt_idx = ary_max = 0; + } + } + public void Clear() { + synchronized (thread_lock) { + for (int i = 0; i < ary_max; i++) { + Bry_bfr itm = ary[i]; + if (itm != null) itm.Clear(); + ary[i] = null; + } + ary = Ary_empty; + free = Int_.Ary_empty; + free_len = 0; + nxt_idx = ary_max = 0; + } + } + public Bry_bfr[] Ary() {return ary;} + public int Nxt_idx() {return nxt_idx;} + public Bry_bfr Get() { + synchronized (thread_lock) { + Bry_bfr rv = null; + int rv_idx = -1; + if (free_len > 0) { + try {rv_idx = free[--free_len];} + catch (Exception e) {throw Exc_.new_exc(e, "core", "failed to get free index", "free_len", free_len, "free.length", free.length);} + try {rv = ary[rv_idx];} + catch (Exception e) {throw Exc_.new_exc(e, "core", "failed to get bfr", "rv_idx", rv_idx, "ary.length", ary.length);} + } + else { + if (nxt_idx == ary_max) + Expand(); + rv_idx = nxt_idx++; + rv = ary[rv_idx]; + if (rv == null) { + rv = Bry_bfr.reset_(reset); + ary[rv_idx] = rv; + } + } + rv.Mkr_init(this, rv_idx); + return rv.Clear(); // NOTE: ALWAYS call Clear when doing Get. caller may forget to call Clear, and reused bfr may have leftover bytes. unit tests will not catch, and difficult to spot in app + } + } + private void Expand() { + int new_max = ary_max == 0 ? 2 : ary_max * 2; + Bry_bfr[] new_ary = new Bry_bfr[new_max]; + Array_.CopyTo(ary, 0, new_ary, 0, ary_max); + ary = new_ary; + ary_max = new_max; + int[] new_free = new int[ary_max]; + Array_.CopyTo(free, 0, new_free, 0, free_len); + free = new_free; + } +// public void Rls(Bry_bfr v) { +// synchronized (thread_lock) { +// int idx = v.Mkr_itm(); +// if (idx == -1) throw Err_mgr._.fmt_("gplx.Bry_bfr", "rls_failed", "rls called on bfr that was not created by factory"); +// int new_ary_len = nxt_idx - 1; +// if (idx == new_ary_len) +// nxt_idx = new_ary_len; +// else +// free[free_len++] = idx; +// v.Mkr_(null, -1); +// } +// } + public void Rls(int idx) { + synchronized (thread_lock) { + if (idx == -1) throw Exc_.new_("rls called on bfr that was not created by factory"); + int new_ary_len = nxt_idx - 1; + if (idx == new_ary_len) + nxt_idx = new_ary_len; + else + free[free_len++] = idx; + } + } + public static final Bry_bfr[] Ary_empty = new Bry_bfr[0]; +} diff --git a/100_core/src_110_primitive/gplx/Bry_bfr_mkr_tst.java b/100_core/src_110_primitive/gplx/Bry_bfr_mkr_tst.java new file mode 100644 index 000000000..2cb5e3ef0 --- /dev/null +++ b/100_core/src_110_primitive/gplx/Bry_bfr_mkr_tst.java @@ -0,0 +1,74 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class Bry_bfr_mkr_tst { + Bry_bfr_mkr_fxt fxt = new Bry_bfr_mkr_fxt(); + @Before public void setup() {fxt.Clear();} + @Test public void Get_1() {fxt.Clear().Get().Tst_idxs(0);} + @Test public void Get_2() {fxt.Clear().Get().Get().Tst_idxs(0, 1);} + @Test public void Get_3() {fxt.Clear().Get().Get().Get().Tst_idxs(0, 1, 2);} + @Test public void Rls() { + fxt.Clear().Get().Rls(0).Tst_idxs(); + } + @Test public void Rls_skip_1() { + fxt.Clear().Get().Get().Rls(0).Tst_idxs(-1, 1); + fxt.Get().Tst_idxs(0, 1); + } + @Test public void Rls_skip_2_1() { + fxt.Clear().Get().Get().Get().Rls(1).Rls(0).Tst_idxs(-1, -1, 2); + fxt.Get().Tst_idxs(0, -1, 2); + fxt.Get().Tst_idxs(0, 1, 2); + fxt.Get().Tst_idxs(0, 1, 2, 3); + } + @Test public void Get_rls_get() { // PURPOSE: defect in which last rls failed b/c was not doing ++ if rv existed + fxt.Clear().Get().Rls(0).Get().Get().Rls(1).Rls(0).Tst_idxs(); + } + public static final int Int_null = -2; +} +class Bry_bfr_mkr_fxt { + Bry_bfr_mkr_mgr mkr; + public Bry_bfr_mkr_fxt Clear() { + if (mkr == null) { + mkr = new Bry_bfr_mkr_mgr(Byte_.Zero, 32); + } + mkr.Clear(); + return this; + } + public Bry_bfr_mkr_fxt Get() { + mkr.Get(); + return this; + } + public Bry_bfr_mkr_fxt Rls(int i) { + Bry_bfr bfr = mkr.Ary()[i]; + bfr.Mkr_rls(); + return this; + } + public Bry_bfr_mkr_fxt Tst_idxs(int... expd) { + int actl_len = mkr.Nxt_idx(); + int[] actl = new int[actl_len]; + for (int i = 0; i < actl_len; i++) { + Bry_bfr bfr = mkr.Ary()[i]; + int actl_val = Bry_bfr_mkr_tst.Int_null; + if (bfr != null) actl_val = bfr.Mkr_idx(); + actl[i] = actl_val; + } + Tfds.Eq_ary(expd, actl); + return this; + } +} diff --git a/100_core/src_110_primitive/gplx/Bry_bfr_tst.java b/100_core/src_110_primitive/gplx/Bry_bfr_tst.java new file mode 100644 index 000000000..d10a364ed --- /dev/null +++ b/100_core/src_110_primitive/gplx/Bry_bfr_tst.java @@ -0,0 +1,227 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class Bry_bfr_tst { + private Bry_bfr bb = Bry_bfr.new_(16); + @Before public void setup() {bb.Clear();} private ByteAryBfr_fxt fxt = new ByteAryBfr_fxt(); + @Test public void AddByte() { + bb = Bry_bfr.new_(2); // NOTE: make sure auto-expands + tst_AddByte("a", "a", 2); + tst_AddByte("b", "ab", 2); + tst_AddByte("c", "abc", 4); + } + @Test public void AddAry() { // NOTE: make sure auto-expands + bb = Bry_bfr.new_(2); + tst_AddByte("abcd", "abcd", 12); + } + @Test public void Add_byte_repeat() { // NOTE: make sure auto-expands + bb = Bry_bfr.new_(2); + tst_Add_byte_repeat(Byte_ascii.Space, 12, String_.Repeat(" ", 12)); + } void tst_Add_byte_repeat(byte b, int len, String expd) {Tfds.Eq(expd, bb.Add_byte_repeat(b, len).Xto_str_and_clear());} + void tst_AddByte(String s, String expdStr, int expdLen) { + if (String_.Len(s) == 1) + bb.Add_byte((byte)String_.CharAt(s, 0)); + else + bb.Add(Bry_.new_u8(s)); + Tfds.Eq(expdStr, String_.new_u8(bb.Xto_bry())); + Tfds.Eq(expdLen, bb.Bfr_max()); + } + @Test public void Add_dte() { + tst_AddDte("20110801 221435.987"); + } + void tst_AddDte(String raw) { + bb.Add_dte(DateAdp_.parse_fmt(raw, Bry_.Fmt_csvDte)); + Tfds.Eq(raw, String_.new_u8(bb.Xto_bry())); + } + @Test public void Add_int_variable() { + Add_int_variable(-1); + Add_int_variable(-12); + Add_int_variable(-1234); + Add_int_variable(2); + Add_int_variable(12); + Add_int_variable(1234); + Add_int_variable(123456789); + } + @Test public void Add_float() { + tst_Add_float(1 / 3); + tst_Add_float(-1 / 3); + } + void tst_Add_float(float v) { + bb.Add_float(v); + Tfds.Eq(v, Float_.parse_(String_.new_u8(bb.Xto_bry()))); + } + void Add_int_variable(int val) { + bb.Clear(); + bb.Add_int_variable(val); + Tfds.Eq(val, Int_.parse_(String_.new_u8(bb.Xto_bry()))); + } + @Test public void Add_int_fixed_len3() {tst_Add_int_fixed(123, 3, "123");} + @Test public void Add_int_fixed_pad_1() {tst_Add_int_fixed(2, 1, "2");} + @Test public void Add_int_fixed_pad_2() {tst_Add_int_fixed(2, 2, "02");} + @Test public void Add_int_fixed_pad_16() {tst_Add_int_fixed(2, 16, "0000000000000002");} // test overflows int + @Test public void Add_int_fixed_neg() {tst_Add_int_fixed(-2, 2, "-2");} + @Test public void Add_int_fixed_neg_pad1() {tst_Add_int_fixed(-2, 1, "-");} + @Test public void Add_int_fixed_chop_1() {tst_Add_int_fixed(123, 1, "3");} + @Test public void Add_int_fixed_chop_neg() {tst_Add_int_fixed(-21, 2, "-1");} + void tst_Add_int_fixed(int val, int digits, String expd) {Tfds.Eq(expd, String_.new_u8(bb.Add_int_fixed(val, digits).Xto_bry()));} + @Test public void Add_long_fixed_len3() {tst_Add_long_fixed(123, 3, "123");} + @Test public void Add_long_fixed_pad_1() {tst_Add_long_fixed(2, 1, "2");} + @Test public void Add_long_fixed_pad_2() {tst_Add_long_fixed(2, 2, "02");} + @Test public void Add_long_fixed_pad_16() {tst_Add_long_fixed(2, 16, "0000000000000002");} // test overflows long + @Test public void Add_long_fixed_neg() {tst_Add_long_fixed(-2, 2, "-2");} + @Test public void Add_long_fixed_neg_pad1() {tst_Add_long_fixed(-2, 1, "-");} + @Test public void Add_long_fixed_chop_1() {tst_Add_long_fixed(123, 1, "3");} + @Test public void Add_long_fixed_chop_neg() {tst_Add_long_fixed(-21, 2, "-1");} + @Test public void Add_long_fixed_large() {tst_Add_long_fixed(123456789012345L, 15, "123456789012345");} + void tst_Add_long_fixed(long val, int digits, String expd) {Tfds.Eq(expd, String_.new_u8(bb.Add_long_fixed(val, digits).Xto_bry()));} + @Test public void AddDte_short() { + tst_AddDte_short("2010-08-26T22:38:36Z"); + } + void tst_AddDte_short(String raw) { +// byte[] ary = String_.XtoByteAryAscii(raw); +// Bry_fmtr_IntBldr ib = new Bry_fmtr_IntBldr(); +// int y = 0, m = 0, d = 0, h = 0, n = 0, s = 0, aryLen = ary.length; +// for (int i = 0; i < aryLen; i++) { +// byte b = ary[i]; +// switch (i) { +// case 4: y = ib.XtoIntAndClear(); break; +// case 7: m = ib.XtoIntAndClear(); break; +// case 10: d = ib.XtoIntAndClear(); break; +// case 13: h = ib.XtoIntAndClear(); break; +// case 16: n = ib.XtoIntAndClear(); break; +// case 19: s = ib.XtoIntAndClear(); break; +// default: ib.Add(b); break; +// } +// } +// long l = Pow38_to(y, m, d, h, n, s); +//// Base85_utl.XtoStrByAry(l, bb. +// bb.Add_int(l); + } +// @Test public void InsertAt_str() { +// tst_InsertAt_str("", 0, "c", "c"); +// tst_InsertAt_str("ab", 0, "c", "cab"); +// tst_InsertAt_str("ab", 0, "cdefghij", "cdefghijab"); +// } +// void tst_InsertAt_str(String orig, int insertAt, String insertStr, String expd) { +// bb = Bry_bfr.new_(16); +// bb.Add_str(orig); +// bb.InsertAt_str(insertAt, insertStr); +// String actl = bb.Xto_str_and_clear(); +// Tfds.Eq(expd, actl); +// } + @Test public void Xto_bry_and_clear_and_trim() { + tst_XtoAryAndClearAndTrim("a" , "a"); + tst_XtoAryAndClearAndTrim(" a " , "a"); + tst_XtoAryAndClearAndTrim(" a b " , "a b"); + tst_XtoAryAndClearAndTrim(" " , ""); + } + void tst_XtoAryAndClearAndTrim(String raw, String expd) { + bb.Add_str(raw); + Tfds.Eq(expd, String_.new_u8(bb.Xto_bry_and_clear_and_trim())); + } + @Test public void XtoInt() { + tst_XtoInt("123", 123); + tst_XtoInt("a", Int_.MinValue); + tst_XtoInt("9999999999", Int_.MinValue); + } + void tst_XtoInt(String raw, int expd) { + bb.Add_str(raw); + Tfds.Eq(expd, bb.XtoIntAndClear(Int_.MinValue)); + } + static long Pow38_to(int year, int month, int day, int hour, int minute, int second, int frac) { + return ((long)year) << 26 + | ((long)month & 0x0f) << 22 // 16 + | ((long)day & 0x1f) << 17 // 32 + | ((long)hour & 0x1f) << 12 // 32 + | ((long)minute & 0x3f) << 6 // 64 + | ((long)second & 0x3f) // 64 + ; + } + static DateAdp Pow38_by(long v) { + int year = (int) (v >> 26); + int month = (int)((v >> 22) & 0x0f); + int day = (int)((v >> 17) & 0x1f); + int hour = (int)((v >> 12) & 0x1f); + int minute = (int)((v >> 6) & 0x3f); + int second = (int)((v ) & 0x3f); + return DateAdp_.new_(year, month, day, hour, minute, second, 0); + } + @Test public void Add_bfr_trimEnd_and_clear() { + tst_Add_bfr_trimEnd_and_clear("a ", "a"); + } + void tst_Add_bfr_trimEnd_and_clear(String raw, String expd) { + Bry_bfr tmp = Bry_bfr.new_().Add_str(raw); + Tfds.Eq(expd, bb.Add_bfr_trim_and_clear(tmp, false, true).Xto_str_and_clear()); + } + @Test public void Add_bfr_trimAll_and_clear() { + tst_Add_bfr_trimAll_and_clear(" a ", "a"); + tst_Add_bfr_trimAll_and_clear(" a b ", "a b"); + tst_Add_bfr_trimAll_and_clear("a", "a"); + tst_Add_bfr_trimAll_and_clear("", ""); + } + void tst_Add_bfr_trimAll_and_clear(String raw, String expd) { + Bry_bfr tmp = Bry_bfr.new_().Add_str(raw); + Tfds.Eq(expd, bb.Add_bfr_trim_and_clear(tmp, true, true).Xto_str_and_clear()); + } + @Test public void Add_int_pad_bgn() { + fxt.Test_Add_int_pad_bgn(Byte_ascii.Num_0, 3, 0, "000"); + fxt.Test_Add_int_pad_bgn(Byte_ascii.Num_0, 3, 1, "001"); + fxt.Test_Add_int_pad_bgn(Byte_ascii.Num_0, 3, 10, "010"); + fxt.Test_Add_int_pad_bgn(Byte_ascii.Num_0, 3, 100, "100"); + fxt.Test_Add_int_pad_bgn(Byte_ascii.Num_0, 3, 1000, "1000"); + } + @Test public void Add_bry_escape() { + fxt.Test_Add_bry_escape("abc" , "abc"); // nothing to escape + fxt.Test_Add_bry_escape("a'bc" , "a''bc"); // single escape (code handles first quote differently) + fxt.Test_Add_bry_escape("a'b'c" , "a''b''c"); // double escape (code handles subsequent quotes different than first) + } + @Test public void Insert_at() { + fxt.Test_Insert_at("abcd", 0, "xyz" , "xyzabcd"); // bgn + fxt.Test_Insert_at("abcd", 4, "xyz" , "abcdxyz"); // end + fxt.Test_Insert_at("abcd", 2, "xyz" , "abxyzcd"); // mid + fxt.Test_Insert_at("abcd", 2, "xyz", 1, 2 , "abycd"); // mid + } + @Test public void Delete_rng() { + fxt.Test_Delete_rng("abcd", 0, 2 , "cd"); // bgn + fxt.Test_Delete_rng("abcd", 2, 4 , "ab"); // end + fxt.Test_Delete_rng("abcd", 1, 3 , "ad"); // mid + } + @Test public void Delete_rng_to_bgn() { + fxt.Test_Delete_rng_to_bgn("abcd", 2 , "cd"); + } + @Test public void Delete_rng_to_end() { + fxt.Test_Delete_rng_to_end("abcd", 2 , "ab"); + } +} +class ByteAryBfr_fxt { + private Bry_bfr bfr = Bry_bfr.reset_(16); + public void Clear() { + bfr.ClearAndReset(); + } + public void Test_Add_int_pad_bgn(byte pad_byte, int str_len, int val, String expd) {Tfds.Eq(expd, bfr.Add_int_pad_bgn(pad_byte, str_len, val).Xto_str_and_clear());} + public void Test_Add_bry_escape(String val, String expd) { + byte[] val_bry = Bry_.new_u8(val); + Tfds.Eq(expd, bfr.Add_bry_escape(Byte_ascii.Apos, Byte_.Ary(Byte_ascii.Apos, Byte_ascii.Apos), val_bry, 0, val_bry.length).Xto_str_and_clear()); + } + public void Test_Insert_at(String init, int pos, String val, String expd) {Tfds.Eq(expd, bfr.Add_str(init).Insert_at(pos, Bry_.new_u8(val)).Xto_str_and_clear());} + public void Test_Insert_at(String init, int pos, String val, int val_bgn, int val_end, String expd) {Tfds.Eq(expd, bfr.Add_str(init).Insert_at(pos, Bry_.new_u8(val), val_bgn, val_end).Xto_str_and_clear());} + public void Test_Delete_rng(String init, int bgn, int end, String expd) {Tfds.Eq(expd, bfr.Add_str(init).Delete_rng(bgn, end).Xto_str_and_clear());} + public void Test_Delete_rng_to_bgn(String init, int pos, String expd) {Tfds.Eq(expd, bfr.Add_str(init).Delete_rng_to_bgn(pos).Xto_str_and_clear());} + public void Test_Delete_rng_to_end(String init, int pos, String expd) {Tfds.Eq(expd, bfr.Add_str(init).Delete_rng_to_end(pos).Xto_str_and_clear());} +} diff --git a/100_core/src_110_primitive/gplx/Bry_finder.java b/100_core/src_110_primitive/gplx/Bry_finder.java new file mode 100644 index 000000000..414178c68 --- /dev/null +++ b/100_core/src_110_primitive/gplx/Bry_finder.java @@ -0,0 +1,296 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Bry_finder { + public static final int Not_found = -1; + public static int Find_fwd(byte[] src, byte lkp) {return Find_fwd(src, lkp, 0, src.length);} + public static int Find_fwd(byte[] src, byte lkp, int cur) {return Find_fwd(src, lkp, cur, src.length);} + public static int Find_fwd(byte[] src, byte lkp, int cur, int end) { + for (int i = cur; i < end; i++) + if (src[i] == lkp) return i; + return Bry_finder.Not_found; + } + public static int Find_bwd(byte[] src, byte lkp) {return Find_bwd(src, lkp, src.length, 0);} + public static int Find_bwd(byte[] src, byte lkp, int cur) {return Find_bwd(src, lkp, cur , 0);} + public static int Find_bwd(byte[] src, byte lkp, int cur, int end) { + --cur; // always subtract 1 from cur; allows passing in src_len or cur_pos without forcing caller to subtract - 1; DATE:2014-02-11 + --end; + for (int i = cur; i > end; i--) + if (src[i] == lkp) return i; + return Bry_finder.Not_found; + } + public static int Move_fwd(byte[] src, byte lkp, int cur, int end) { + int rv = Find_fwd(src, lkp, cur, src.length); + return rv == Bry_finder.Not_found ? rv : rv + 1; + } + public static int Move_fwd(byte[] src, byte[] lkp, int cur) {return Move_fwd(src, lkp, cur, src.length);} + public static int Move_fwd(byte[] src, byte[] lkp, int cur, int end) { + int rv = Find_fwd(src, lkp, cur, src.length); + return rv == Bry_finder.Not_found ? rv : rv + lkp.length; + } + public static int Find_fwd(byte[] src, byte[] lkp) {return Find(src, lkp, 0 , src.length, true);} + public static int Find_fwd(byte[] src, byte[] lkp, int cur) {return Find(src, lkp, cur , src.length, true);} + public static int Find_fwd(byte[] src, byte[] lkp, int cur, int end) {return Find(src, lkp, cur , end, true);} + public static int Find(byte[] src, byte[] lkp, int src_bgn, int src_end, boolean fwd) { + if (src_bgn < 0 || src.length == 0) return Bry_finder.Not_found; + int dif, lkp_len = lkp.length, lkp_bgn, lkp_end, src_end_chk; + if (fwd) { + if (src_bgn > src_end) return Bry_finder.Not_found; + dif = 1; lkp_bgn = 0; lkp_end = lkp_len; src_end_chk = src_end - CompareAble_.OffsetCompare; + } + else { + if (src_bgn < src_end) return Bry_finder.Not_found; + dif = -1; lkp_bgn = lkp_len - 1; lkp_end = -1; src_end_chk = src.length - CompareAble_.OffsetCompare; // src_end_chk needed when going bwd, b/c lkp_len may be > 1 + } + while (src_bgn != src_end) { // while src is not done; + int lkp_cur = lkp_bgn; + while (lkp_cur != lkp_end) { // while lkp is not done + int pos = src_bgn + lkp_cur; + if ( pos > src_end_chk // outside bounds; occurs when lkp_len > 1 + || src[pos] != lkp[lkp_cur]) // srcByte doesn't match lkpByte + break; + else + lkp_cur += dif; + } + if (lkp_cur == lkp_end) return src_bgn; // lkp matches src; exit + src_bgn += dif; + } + return Bry_finder.Not_found; + } + public static int Find_bwd(byte[] src, byte[] lkp, int cur) {return Find_bwd(src, lkp, cur , 0);} + public static int Find_bwd(byte[] src, byte[] lkp, int cur, int end) { + if (cur < 1) return Bry_finder.Not_found; + --cur; // always subtract 1 from cur; allows passing in src_len or cur_pos without forcing caller to subtract - 1; DATE:2014-02-11 + --end; + int src_len = src.length; + int lkp_len = lkp.length; + for (int i = cur; i > end; i--) { + if (i + lkp_len > src_len) continue; // lkp too small for pos; EX: src=abcde; lkp=bcd; pos=4 + boolean match = true; + for (int j = 0; j < lkp_len; j++) { + if (lkp[j] != src[i + j]) { + match = false; + break; + } + } + if (match) return i; + } + return Bry_finder.Not_found; + } + public static int Find_bwd_last_ws(byte[] src, int cur) { + if (cur < 1) return Bry_finder.Not_found; + --cur; + int rv = Bry_finder.Not_found; + for (int i = cur; i > -1; i--) { + byte b = src[i]; + switch (b) { + case Byte_ascii.Space: case Byte_ascii.Tab: case Byte_ascii.Nl: case Byte_ascii.Cr: + rv = i; + break; + default: + i = -1; + break; + } + } + return rv; + } + public static int Find_bwd_ws(byte[] src, int cur, int end) { + for (int i = cur; i > -1; --i) { + byte b = src[i]; + switch (b) { + case Byte_ascii.Space: case Byte_ascii.Tab: case Byte_ascii.Nl: case Byte_ascii.Cr: + return i; + } + } + return Bry_finder.Not_found; + } + public static int Find_fwd_last_ws(byte[] src, int cur) { + int end = src.length; + if (cur >= end) return Bry_finder.Not_found; + int rv = Bry_finder.Not_found; + for (int i = cur; i < end; i++) { + byte b = src[i]; + switch (b) { + case Byte_ascii.Space: case Byte_ascii.Tab: case Byte_ascii.Nl: case Byte_ascii.Cr: + rv = i; + break; + default: + i = -1; + break; + } + } + return rv; + } + public static int Find_bwd_non_ws_or_not_found(byte[] src, int cur, int end) { // get pos of 1st char that is not ws; + if (cur >= src.length) return Bry_finder.Not_found; + for (int i = cur; i >= end; i--) { + byte b = src[i]; + switch (b) { + case Byte_ascii.Space: case Byte_ascii.Tab: case Byte_ascii.Nl: case Byte_ascii.Cr: + break; + default: + return i; + } + } + return Bry_finder.Not_found; + } + public static int Find_bwd_non_ws_or_end(byte[] src, int cur, int end) { + if (cur >= src.length) return Bry_finder.Not_found; + for (int i = cur; i >= end; i--) { + byte b = src[i]; + switch (b) { + case Byte_ascii.Space: case Byte_ascii.Tab: case Byte_ascii.Nl: case Byte_ascii.Cr: + break; + default: + return i; + } + } + return end; + } + public static int Find_bwd_while(byte[] src, int cur, int end, byte while_byte) { + --cur; + while (true) { + if ( cur < end + || src[cur] != while_byte) return cur; + --cur; + } + } + public static int Find_fwd_while(byte[] src, int cur, int end, byte while_byte) { + while (true) { + if ( cur == end + || src[cur] != while_byte) return cur; + cur++; + } + } + public static int Find_fwd_until(byte[] src, int cur, int end, byte until_byte) { + while (true) { + if ( cur == end + || src[cur] == until_byte) return cur; + cur++; + } + } + public static int Find_fwd_until_space_or_tab(byte[] src, int cur, int end) { + while (true) { + if (cur == end) return Bry_finder.Not_found; + switch (src[cur]) { + case Byte_ascii.Space: case Byte_ascii.Tab: + return cur; + default: + ++cur; + break; + } + } + } + public static int Find_fwd_until_ws(byte[] src, int cur, int end) { + while (true) { + if (cur == end) return Bry_finder.Not_found; + switch (src[cur]) { + case Byte_ascii.Space: case Byte_ascii.Tab: case Byte_ascii.Nl: case Byte_ascii.Cr: + return cur; + default: + ++cur; + break; + } + } + } + public static int Find_fwd_while_space_or_tab(byte[] src, int cur, int end) { + while (true) { + if (cur == end) return cur; + switch (src[cur]) { + case Byte_ascii.Space: case Byte_ascii.Tab: ++cur; break; + default: return cur; + } + } + } + public static int Trim_fwd_space_tab(byte[] src, int cur, int end) { + while (true) { + if (cur == end) return cur; + switch (src[cur]) { + case Byte_ascii.Space: case Byte_ascii.Tab: ++cur; break; + default: return cur; + } + } + } + public static int Trim_bwd_space_tab(byte[] src, int cur, int bgn) { + while (true) { + int prv_cur = cur - 1; // check byte before cur; EX: "a b " will have len of 4, and pass cur=4; + if (prv_cur < bgn) return cur; // checking byte before prv; exit; + switch (src[prv_cur]) { + case Byte_ascii.Space: case Byte_ascii.Tab: --cur; break; + default: return cur; + } + } + } + public static int Find_fwd_while_ws(byte[] src, int cur, int end) { + while (true) { + if (cur == end) return cur; + try { + switch (src[cur]) { + case Byte_ascii.Nl: case Byte_ascii.Cr: + case Byte_ascii.Space: case Byte_ascii.Tab: ++cur; break; + default: return cur; + } + } catch (Exception e) {throw Exc_.new_exc(e, "core", "idx is invalid", "cur", cur, "src", src);} + } + } + public static int Find_fwd_while_letter(byte[] src, int cur, int end) { + while (cur < end) { + switch (src[cur]) { + case Byte_ascii.Ltr_A: case Byte_ascii.Ltr_B: case Byte_ascii.Ltr_C: case Byte_ascii.Ltr_D: case Byte_ascii.Ltr_E: + case Byte_ascii.Ltr_F: case Byte_ascii.Ltr_G: case Byte_ascii.Ltr_H: case Byte_ascii.Ltr_I: case Byte_ascii.Ltr_J: + case Byte_ascii.Ltr_K: case Byte_ascii.Ltr_L: case Byte_ascii.Ltr_M: case Byte_ascii.Ltr_N: case Byte_ascii.Ltr_O: + case Byte_ascii.Ltr_P: case Byte_ascii.Ltr_Q: case Byte_ascii.Ltr_R: case Byte_ascii.Ltr_S: case Byte_ascii.Ltr_T: + case Byte_ascii.Ltr_U: case Byte_ascii.Ltr_V: case Byte_ascii.Ltr_W: case Byte_ascii.Ltr_X: case Byte_ascii.Ltr_Y: case Byte_ascii.Ltr_Z: + case Byte_ascii.Ltr_a: case Byte_ascii.Ltr_b: case Byte_ascii.Ltr_c: case Byte_ascii.Ltr_d: case Byte_ascii.Ltr_e: + case Byte_ascii.Ltr_f: case Byte_ascii.Ltr_g: case Byte_ascii.Ltr_h: case Byte_ascii.Ltr_i: case Byte_ascii.Ltr_j: + case Byte_ascii.Ltr_k: case Byte_ascii.Ltr_l: case Byte_ascii.Ltr_m: case Byte_ascii.Ltr_n: case Byte_ascii.Ltr_o: + case Byte_ascii.Ltr_p: case Byte_ascii.Ltr_q: case Byte_ascii.Ltr_r: case Byte_ascii.Ltr_s: case Byte_ascii.Ltr_t: + case Byte_ascii.Ltr_u: case Byte_ascii.Ltr_v: case Byte_ascii.Ltr_w: case Byte_ascii.Ltr_x: case Byte_ascii.Ltr_y: case Byte_ascii.Ltr_z: + break; + default: + return cur; + } + ++cur; + } + return cur; + } + public static int Find_fwd_while_num(byte[] src) {return Find_fwd_while_num(src, 0, src.length);} + public static int Find_fwd_while_num(byte[] src, int cur, int end) { + while (cur < end) { + if (!Byte_ascii.Is_num(src[cur])) + return cur; + ++cur; + } + return cur; + } + public static int Find_fwd_while_not_ws(byte[] src, int cur, int end) { + while (true) { + if (cur == end) return cur; + switch (src[cur]) { + case Byte_ascii.Space: + case Byte_ascii.Nl: + case Byte_ascii.Tab: + case Byte_ascii.Cr: + ++cur; + break; + default: + return cur; + } + } + } +} diff --git a/100_core/src_110_primitive/gplx/Bry_finder_tst.java b/100_core/src_110_primitive/gplx/Bry_finder_tst.java new file mode 100644 index 000000000..4707ede16 --- /dev/null +++ b/100_core/src_110_primitive/gplx/Bry_finder_tst.java @@ -0,0 +1,78 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +import gplx.texts.*; +public class Bry_finder_tst { + private Bry_finder_fxt fxt = new Bry_finder_fxt(); + @Test public void Find_fwd() { + fxt.Test_Find_fwd("abcba", "b", 0, 1); + fxt.Test_Find_fwd("abcba", "z", 0, -1); + fxt.Test_Find_fwd("abcba", "b", 1, 1); + fxt.Test_Find_fwd("abcba", "b", 2, 3); + fxt.Test_Find_fwd("abcba", "b", 4, -1); + fxt.Test_Find_fwd("abcba", "zb", 4, -1); + fxt.Test_Find_fwd("abcba", "a", 6, -1); + } + @Test public void Find_bwd() { + fxt.Test_Find_bwd("abcba", "b", 4, 3); + fxt.Test_Find_bwd("abcba", "z", 4, -1); + fxt.Test_Find_bwd("abcba", "b", 3, 1); + fxt.Test_Find_bwd("abcba", "b", 2, 1); + fxt.Test_Find_bwd("abcba", "b", 0, -1); + fxt.Test_Find_bwd("abcba", "zb", 4, -1); + fxt.Test_Find_fwd("abcba", "a", -1, -1); + fxt.Test_Find_bwd("abcba", "ab", 4, 0); + } + @Test public void Find_bwd_last_ws() { + fxt.Test_Find_bwd_1st_ws_tst("a b" , 2, 1); // basic + fxt.Test_Find_bwd_1st_ws_tst("a b" , 3, 1); // multiple + fxt.Test_Find_bwd_1st_ws_tst("ab" , 1, Bry_.NotFound); // none + } + @Test public void Trim_fwd_space_tab() { + fxt.Test_Trim_fwd_space_tab(" a b" , 1); + fxt.Test_Trim_fwd_space_tab("\ta b" , 1); + fxt.Test_Trim_fwd_space_tab(" \ta b" , 2); + fxt.Test_Trim_fwd_space_tab("a bc" , 0); + fxt.Test_Trim_fwd_space_tab("" , 0); + fxt.Test_Trim_fwd_space_tab(" \t" , 2); + } + @Test public void Trim_bwd_space_tab() { + fxt.Test_Trim_bwd_space_tab("a b " , 3); + fxt.Test_Trim_bwd_space_tab("a b\t" , 3); + fxt.Test_Trim_bwd_space_tab("a b\t " , 3); + fxt.Test_Trim_bwd_space_tab("a bc" , 4); + fxt.Test_Trim_bwd_space_tab("" , 0); + fxt.Test_Trim_bwd_space_tab(" \t" , 0); + } +} +class Bry_finder_fxt { + public void Test_Find_fwd(String src, String lkp, int bgn, int expd) {Tfds.Eq(expd, Bry_finder.Find_fwd(Bry_.new_u8(src), Bry_.new_u8(lkp), bgn));} + public void Test_Find_bwd(String src, String lkp, int bgn, int expd) {Tfds.Eq(expd, Bry_finder.Find_bwd(Bry_.new_u8(src), Bry_.new_u8(lkp), bgn));} + public void Test_Find_bwd_1st_ws_tst(String src, int pos, int expd) {Tfds.Eq(expd, Bry_finder.Find_bwd_last_ws(Bry_.new_a7(src), pos));} + public void Test_Trim_bwd_space_tab(String raw_str, int expd) { + byte[] raw_bry = Bry_.new_u8(raw_str); + int actl = Bry_finder.Trim_bwd_space_tab(raw_bry, raw_bry.length, 0); + Tfds.Eq(expd, actl, raw_str); + } + public void Test_Trim_fwd_space_tab(String raw_str, int expd) { + byte[] raw_bry = Bry_.new_u8(raw_str); + int actl = Bry_finder.Trim_fwd_space_tab(raw_bry, 0, raw_bry.length); + Tfds.Eq(expd, actl, raw_str); + } +} diff --git a/100_core/src_110_primitive/gplx/Bry_fmtr.java b/100_core/src_110_primitive/gplx/Bry_fmtr.java new file mode 100644 index 000000000..5d2b48961 --- /dev/null +++ b/100_core/src_110_primitive/gplx/Bry_fmtr.java @@ -0,0 +1,267 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.core.primitives.*; import gplx.core.strings.*; +public class Bry_fmtr { + public byte[] Fmt() {return fmt;} private byte[] fmt = Bry_.Empty; + public boolean Fmt_null() {return fmt.length == 0;} + public Bry_fmtr_eval_mgr Eval_mgr() {return eval_mgr;} public Bry_fmtr Eval_mgr_(Bry_fmtr_eval_mgr v) {eval_mgr = v; return this;} Bry_fmtr_eval_mgr eval_mgr = Bry_fmtr_eval_mgr_gfs._; + public Bry_fmtr Fmt_(byte[] v) {fmt = v; dirty = true; return this;} public Bry_fmtr Fmt_(String v) {return Fmt_(Bry_.new_u8(v));} + public Bry_fmtr Keys_(String... ary) { + if (keys == null) keys = Hash_adp_.new_(); + else keys.Clear(); + int ary_len = ary.length; + for (int i = 0; i < ary_len; i++) + keys.Add(Bry_obj_ref.new_(Bry_.new_u8(ary[i])), Int_obj_val.new_(i)); + dirty = true; + return this; + } Hash_adp keys = null; + public void Bld_bfr(Bry_bfr bfr, byte[]... args) { + if (dirty) Compile(); + int args_len = args.length; + for (int i = 0; i < itms_len; i++) { + Bry_fmtr_itm itm = itms[i]; + if (itm.Arg) { + int arg_idx = itm.ArgIdx; + if (arg_idx < args_len) + bfr.Add(args[arg_idx]); + else + bfr.Add(missing_bgn).Add_int_variable(arg_idx + missing_adj).Add(missing_end); + } + else + bfr.Add(itm.Dat); + } + } + public void Bld_bfr_none(Bry_bfr bfr) { + if (dirty) Compile(); + for (int i = 0; i < itms_len; i++) { + Bry_fmtr_itm itm = itms[i]; + if (itm.Arg) + bfr.Add_byte(char_escape).Add_byte(char_arg_bgn).Add_int_variable(itm.ArgIdx).Add_byte(char_arg_end); + else + bfr.Add(itm.Dat); + } + } + public void Bld_bfr(Bry_bfr bfr, Bry_fmtr_arg... args) { + if (dirty) Compile(); + for (int i = 0; i < itms_len; i++) { + Bry_fmtr_itm itm = itms[i]; + if (itm.Arg) + args[itm.ArgIdx].XferAry(bfr, itm.ArgIdx); + else + bfr.Add(itm.Dat); + } + } + public void Bld_bfr_one(Bry_bfr bfr, Object val) { + Bld_bfr_one_ary[0] = val; + Bld_bfr_ary(bfr, Bld_bfr_one_ary); + } Object[] Bld_bfr_one_ary = new Object[1]; + public void Bld_bfr_many(Bry_bfr bfr, Object... args) {Bld_bfr_ary(bfr, args);} + public void Bld_bfr_ary(Bry_bfr bfr, Object[] args) { + if (dirty) Compile(); + int args_len = args.length; + for (int i = 0; i < itms_len; i++) { + Bry_fmtr_itm itm = itms[i]; + if (itm.Arg) { + int arg_idx = itm.ArgIdx; + if (arg_idx > -1 && arg_idx < args_len) + bfr.Add_obj(args[itm.ArgIdx]); + else + bfr.Add_byte(char_escape).Add_byte(char_arg_bgn).Add_int_variable(arg_idx).Add_byte(char_arg_end); + } + else + bfr.Add(itm.Dat); + } + } + public byte[] Bld_bry_none(Bry_bfr bfr) {Bld_bfr_ary(bfr, Object_.Ary_empty); return bfr.Xto_bry_and_clear();} + public byte[] Bld_bry_many(Bry_bfr bfr, Object... args) { + Bld_bfr_ary(bfr, args); + return bfr.Xto_bry_and_clear(); + } + public String Bld_str_many(Bry_bfr bfr, String fmt, Object... args) { + this.Fmt_(fmt).Bld_bfr_many(bfr, args); + return bfr.Xto_str_and_clear(); + } + + public String Bld_str_many(String... args) { + if (dirty) Compile(); + String_bldr rv = String_bldr_.new_(); + int args_len = args.length; + for (int i = 0; i < itms_len; i++) { + Bry_fmtr_itm itm = itms[i]; + if (itm.Arg) { + int arg_idx = itm.ArgIdx; + if (arg_idx < args_len) + rv.Add(args[arg_idx]); + else + rv.Add(missing_bgn).Add(arg_idx + missing_adj).Add(missing_end); + } + else + rv.Add(itm.DatStr()); + } + return rv.XtoStr(); + } private Bry_fmtr_itm[] itms; int itms_len; + public byte[] Missing_bgn() {return missing_bgn;} public Bry_fmtr Missing_bgn_(byte[] v) {missing_bgn = v; return this;} private byte[] missing_bgn = missing_bgn_static; static byte[] missing_bgn_static = Bry_.new_u8("~{"), missing_end_static = Bry_.new_u8("}"); + public byte[] Missing_end() {return missing_end;} public Bry_fmtr Missing_end_(byte[] v) {missing_end = v; return this;} private byte[] missing_end = missing_end_static; + public int Missing_adj() {return missing_adj;} public Bry_fmtr Missing_adj_(int v) {missing_adj = v; return this;} int missing_adj; + public boolean Fail_when_invalid_escapes() {return fail_when_invalid_escapes;} public Bry_fmtr Fail_when_invalid_escapes_(boolean v) {fail_when_invalid_escapes = v; return this;} private boolean fail_when_invalid_escapes = true; + public Bry_fmtr Compile() { + synchronized (this) { // THREAD: DATE:2015-04-29 + Bry_bfr lkp_bfr = Bry_bfr.new_(16); + int fmt_len = fmt.length; int fmt_end = fmt_len - 1; int fmt_pos = 0; + byte[] trg_bry = new byte[fmt_len]; int trg_pos = 0; + boolean lkp_is_active = false, lkp_is_numeric = true; + byte nxt_byte, tmp_byte; + List_adp list = List_adp_.new_(); + fmt_args_exist = false; + while (true) { + if (fmt_pos > fmt_end) break; + byte cur_byte = fmt[fmt_pos]; + if (lkp_is_active) { + if (cur_byte == char_arg_end) { + if (lkp_is_numeric) + list.Add(Bry_fmtr_itm.arg_(lkp_bfr.XtoInt(0) - baseInt)); + else { + byte[] key_fmt = lkp_bfr.Xto_bry(); + Object idx_ref = keys.Get_by(Bry_obj_ref.new_(key_fmt)); + if (idx_ref == null) { + int lkp_bfr_len = lkp_bfr.Len(); + byte[] lkp_bry = lkp_bfr.Bfr(); + trg_bry[trg_pos++] = char_escape; + trg_bry[trg_pos++] = char_arg_bgn; + for (int i = 0; i < lkp_bfr_len; i++) + trg_bry[trg_pos++] = lkp_bry[i]; + trg_bry[trg_pos++] = char_arg_end; + } + else { + list.Add(Bry_fmtr_itm.arg_(((Int_obj_val)idx_ref).Val() - baseInt)); + } + } + lkp_is_active = false; + lkp_bfr.Clear(); + fmt_args_exist = true; + } + else { + lkp_bfr.Add_byte(cur_byte); + switch (cur_byte) { + case Byte_ascii.Num_0: case Byte_ascii.Num_1: case Byte_ascii.Num_2: case Byte_ascii.Num_3: case Byte_ascii.Num_4: + case Byte_ascii.Num_5: case Byte_ascii.Num_6: case Byte_ascii.Num_7: case Byte_ascii.Num_8: case Byte_ascii.Num_9: + break; + default: + lkp_is_numeric = false; + break; + } + } + fmt_pos += 1; + } + else if (cur_byte == char_escape) { + if (fmt_pos == fmt_end) { + if (fail_when_invalid_escapes) + throw Exc_.new_("escape char encountered but no more chars left"); + else { + trg_bry[trg_pos] = cur_byte; + break; + } + } + nxt_byte = fmt[fmt_pos + 1]; + if (nxt_byte == char_arg_bgn) { + if (trg_pos > 0) {list.Add(Bry_fmtr_itm.dat_(trg_bry, trg_pos)); trg_pos = 0;} // something pending; add it to list + int eval_lhs_bgn = fmt_pos + 2; + if (eval_lhs_bgn < fmt_len && fmt[eval_lhs_bgn] == char_eval_bgn) { // eval found + fmt_pos = Compile_eval_cmd(fmt, fmt_len, eval_lhs_bgn, list); + continue; + } + else { + lkp_is_active = true; + lkp_is_numeric = true; + } + } + else { // ~{0}; ~~ -> ~; ~n -> newLine; ~t -> tab + if (nxt_byte == char_escape) tmp_byte = char_escape; + else if (nxt_byte == char_escape_nl) tmp_byte = Byte_ascii.Nl; + else if (nxt_byte == char_escape_tab) tmp_byte = Byte_ascii.Tab; + else { + if (fail_when_invalid_escapes) throw Exc_.new_("unknown escape code", "code", Char_.XbyInt(nxt_byte), "fmt_pos", fmt_pos + 1); + else + tmp_byte = cur_byte; + } + trg_bry[trg_pos++] = tmp_byte; + } + fmt_pos += 2; + } + else { + trg_bry[trg_pos++] = cur_byte; + fmt_pos += 1; + } + } + if (lkp_is_active) throw Exc_.new_("idx mode not closed"); + if (trg_pos > 0) {list.Add(Bry_fmtr_itm.dat_(trg_bry, trg_pos)); trg_pos = 0;} + itms = (Bry_fmtr_itm[])list.To_ary(Bry_fmtr_itm.class); + itms_len = itms.length; + return this; + } + } + int Compile_eval_cmd(byte[] fmt, int fmt_len, int eval_lhs_bgn, List_adp list) { + int eval_lhs_end = Bry_finder.Find_fwd(fmt, char_eval_end, eval_lhs_bgn + Int_.Const_dlm_len, fmt_len); if (eval_lhs_end == Bry_.NotFound) throw Exc_.new_("eval_lhs_end_invalid: could not find eval_lhs_end", "snip", String_.new_u8(fmt, eval_lhs_bgn, fmt_len)); + byte[] eval_dlm = Bry_.Mid(fmt, eval_lhs_bgn , eval_lhs_end + Int_.Const_dlm_len); + int eval_rhs_bgn = Bry_finder.Find_fwd(fmt, eval_dlm , eval_lhs_end + Int_.Const_dlm_len, fmt_len); if (eval_rhs_bgn == Bry_.NotFound) throw Exc_.new_("eval_rhs_bgn_invalid: could not find eval_rhs_bgn", "snip", String_.new_u8(fmt, eval_lhs_end, fmt_len)); + byte[] eval_cmd = Bry_.Mid(fmt, eval_lhs_end + Int_.Const_dlm_len, eval_rhs_bgn); + byte[] eval_rslt = eval_mgr.Eval(eval_cmd); + int eval_rhs_end = eval_rhs_bgn + Int_.Const_dlm_len + eval_dlm.length; + if (eval_rslt == null) eval_rslt = Bry_.Mid(fmt, eval_lhs_bgn - 2, eval_rhs_end); // not found; return original argument + list.Add(Bry_fmtr_itm.dat_bry_(eval_rslt)); + return eval_rhs_end; + } + static final String GRP_KEY = "gplx.Bry_fmtr"; + public boolean Fmt_args_exist() {return fmt_args_exist;} private boolean fmt_args_exist; + boolean dirty = true; + int baseInt = 0; + public static final byte char_escape = Byte_ascii.Tilde, char_arg_bgn = Byte_ascii.Curly_bgn, char_arg_end = Byte_ascii.Curly_end, char_escape_nl = Byte_ascii.Ltr_n, char_escape_tab = Byte_ascii.Ltr_t, char_eval_bgn = Byte_ascii.Lt, char_eval_end = Byte_ascii.Gt; + public static final Bry_fmtr Null = new Bry_fmtr().Fmt_(""); + public static Bry_fmtr tmp_() {return new Bry_fmtr().Fmt_("").Keys_();} + public static Bry_fmtr new_(String fmt, String... keys) {return new Bry_fmtr().Fmt_(fmt).Keys_(keys);} // NOTE: keys may seem redundant, but are needed to align ordinals with proc; EX: fmt may be "~{A} ~{B}" or "~{B} ~{A}"; call will always be Bld(a, b); passing in "A", "B" guarantees A is 0 and B is 1; + public static Bry_fmtr new_(byte[] fmt, String... keys) {return new Bry_fmtr().Fmt_(fmt).Keys_(keys);} // NOTE: keys may seem redundant, but are needed to align ordinals with proc; EX: fmt may be "~{A} ~{B}" or "~{B} ~{A}"; call will always be Bld(a, b); passing in "A", "B" guarantees A is 0 and B is 1; + public static Bry_fmtr new_() {return new Bry_fmtr();} + public static Bry_fmtr keys_(String... keys) {return new Bry_fmtr().Keys_(keys);} + public static Bry_fmtr new_bry_(byte[] fmt, String... keys) {return new Bry_fmtr().Fmt_(fmt).Keys_(keys);} + public static String New_fmt_str(String key, Object[] args) { + tmp_bfr.Clear(); + tmp_bfr.Add_str(key); + tmp_bfr.Add_byte(Byte_ascii.Colon); + int args_len = args.length; + for (int i = 0; i < args_len; i++) { // add " 0='~{0}'" + tmp_bfr.Add_byte(Byte_ascii.Space); + tmp_bfr.Add_int_variable(i); + tmp_bfr.Add_byte(Byte_ascii.Eq); + tmp_bfr.Add_byte(Byte_ascii.Apos); + tmp_bfr.Add_byte(Byte_ascii.Tilde); + tmp_bfr.Add_byte(Byte_ascii.Curly_bgn); + tmp_bfr.Add_int_variable(i); + tmp_bfr.Add_byte(Byte_ascii.Curly_end); + tmp_bfr.Add_byte(Byte_ascii.Apos); + } + return tmp_bfr.Xto_str_and_clear(); + } static Bry_bfr tmp_bfr = Bry_bfr.reset_(255); + public void Bld_bfr_many_and_set_fmt(Object... args) { + Bry_bfr bfr = Bry_bfr.new_(); + this.Bld_bfr_many(bfr, args); + byte[] bry = bfr.Xto_bry_and_clear(); + this.Fmt_(bry).Compile(); + } + public static String Escape_tilde(String v) {return String_.Replace(v, "~", "~~");} +} diff --git a/100_core/src_110_primitive/gplx/Bry_fmtr_arg.java b/100_core/src_110_primitive/gplx/Bry_fmtr_arg.java new file mode 100644 index 000000000..bd97503fa --- /dev/null +++ b/100_core/src_110_primitive/gplx/Bry_fmtr_arg.java @@ -0,0 +1,21 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public interface Bry_fmtr_arg { + void XferAry(Bry_bfr bfr, int idx); +} diff --git a/100_core/src_110_primitive/gplx/Bry_fmtr_arg_.java b/100_core/src_110_primitive/gplx/Bry_fmtr_arg_.java new file mode 100644 index 000000000..53f0121eb --- /dev/null +++ b/100_core/src_110_primitive/gplx/Bry_fmtr_arg_.java @@ -0,0 +1,33 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.brys.*; +public class Bry_fmtr_arg_ { + public static Bry_fmtr_arg_bry bry_(String v) {return new Bry_fmtr_arg_bry(Bry_.new_u8(v));} + public static Bry_fmtr_arg_bry bry_(byte[] v) {return new Bry_fmtr_arg_bry(v);} + public static Bry_fmtr_arg_byt byt_(byte v) {return new Bry_fmtr_arg_byt(v);} + public static Bry_fmtr_arg_int int_(int v) {return new Bry_fmtr_arg_int(v);} + public static Bry_fmtr_arg_bfr bfr_(Bry_bfr v) {return new Bry_fmtr_arg_bfr(v);} + public static Bry_fmtr_arg_bfr_preserve bfr_retain_(Bry_bfr v) {return new Bry_fmtr_arg_bfr_preserve(v);} + public static Bry_fmtr_arg fmtr_(Bry_fmtr v, Bry_fmtr_arg... arg_ary) {return new Bry_fmtr_arg_fmtr(v, arg_ary);} + public static Bry_fmtr_arg_fmtr_objs fmtr_null_() {return new Bry_fmtr_arg_fmtr_objs(null, null);} + public static final Bry_fmtr_arg Noop = new Bry_fmtr_arg__noop(); +} +class Bry_fmtr_arg__noop implements Bry_fmtr_arg { + public void XferAry(Bry_bfr trg, int idx) {} +} diff --git a/100_core/src_110_primitive/gplx/Bry_fmtr_arg_fmtr_objs.java b/100_core/src_110_primitive/gplx/Bry_fmtr_arg_fmtr_objs.java new file mode 100644 index 000000000..edf7179a4 --- /dev/null +++ b/100_core/src_110_primitive/gplx/Bry_fmtr_arg_fmtr_objs.java @@ -0,0 +1,25 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Bry_fmtr_arg_fmtr_objs implements Bry_fmtr_arg { + public Bry_fmtr_arg_fmtr_objs Atrs_(Bry_fmtr fmtr, Object... objs) {this.fmtr = fmtr; this.objs = objs; return this;} + public void XferAry(Bry_bfr trg, int idx) { + fmtr.Bld_bfr_many(trg, objs); + } + public Bry_fmtr_arg_fmtr_objs(Bry_fmtr fmtr, Object[] objs) {this.fmtr = fmtr; this.objs = objs;} Bry_fmtr fmtr; Object[] objs; +} diff --git a/100_core/src_110_primitive/gplx/Bry_fmtr_eval_mgr.java b/100_core/src_110_primitive/gplx/Bry_fmtr_eval_mgr.java new file mode 100644 index 000000000..83abe2873 --- /dev/null +++ b/100_core/src_110_primitive/gplx/Bry_fmtr_eval_mgr.java @@ -0,0 +1,22 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public interface Bry_fmtr_eval_mgr { + boolean Enabled(); void Enabled_(boolean v); + byte[] Eval(byte[] cmd); +} diff --git a/100_core/src_110_primitive/gplx/Bry_fmtr_eval_mgr_.java b/100_core/src_110_primitive/gplx/Bry_fmtr_eval_mgr_.java new file mode 100644 index 000000000..a013bd25c --- /dev/null +++ b/100_core/src_110_primitive/gplx/Bry_fmtr_eval_mgr_.java @@ -0,0 +1,27 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Bry_fmtr_eval_mgr_ { + public static Io_url Eval_url(Bry_fmtr_eval_mgr eval_mgr, byte[] fmt) { + if (eval_mgr == null) return Io_url_.new_any_(String_.new_u8(fmt)); + Bry_bfr bfr = Bry_bfr.reset_(255); + Bry_fmtr fmtr = Bry_fmtr.tmp_(); + fmtr.Eval_mgr_(eval_mgr).Fmt_(fmt).Bld_bfr_none(bfr); + return Io_url_.new_any_(bfr.Xto_str_and_clear()); + } +} diff --git a/100_core/src_110_primitive/gplx/Bry_fmtr_eval_mgr_gfs.java b/100_core/src_110_primitive/gplx/Bry_fmtr_eval_mgr_gfs.java new file mode 100644 index 000000000..c26068df2 --- /dev/null +++ b/100_core/src_110_primitive/gplx/Bry_fmtr_eval_mgr_gfs.java @@ -0,0 +1,25 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Bry_fmtr_eval_mgr_gfs implements Bry_fmtr_eval_mgr { + public boolean Enabled() {return enabled;} public void Enabled_(boolean v) {enabled = v;} private boolean enabled; + public byte[] Eval(byte[] cmd) { + return enabled ? Bry_.new_u8(Object_.Xto_str_strict_or_null_mark(GfsCore._.ExecText(String_.new_u8(cmd)))) : null; + } + public static final Bry_fmtr_eval_mgr_gfs _ = new Bry_fmtr_eval_mgr_gfs(); Bry_fmtr_eval_mgr_gfs() {} +} diff --git a/100_core/src_110_primitive/gplx/Bry_fmtr_itm.java b/100_core/src_110_primitive/gplx/Bry_fmtr_itm.java new file mode 100644 index 000000000..4cbeacdda --- /dev/null +++ b/100_core/src_110_primitive/gplx/Bry_fmtr_itm.java @@ -0,0 +1,33 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Bry_fmtr_itm { + public boolean Arg; + public int ArgIdx; + public byte[] Dat; + public String DatStr() { + if (datStr == null) datStr = String_.new_u8(Dat); + return datStr; + } String datStr; + public static Bry_fmtr_itm arg_(int idx) {return new Bry_fmtr_itm(true, idx, Bry_.Empty);} + public static Bry_fmtr_itm dat_(byte[] dat, int len) {return new Bry_fmtr_itm(false, -1, Bry_.Mid(dat, 0, len));} + public static Bry_fmtr_itm dat_bry_(byte[] bry) {return new Bry_fmtr_itm(false, -1, bry);} + Bry_fmtr_itm(boolean arg, int argIdx, byte[] dat) { + this.Arg = arg; this.ArgIdx = argIdx; this.Dat = dat; + } +} diff --git a/100_core/src_110_primitive/gplx/Bry_fmtr_tst.java b/100_core/src_110_primitive/gplx/Bry_fmtr_tst.java new file mode 100644 index 000000000..8367a5d22 --- /dev/null +++ b/100_core/src_110_primitive/gplx/Bry_fmtr_tst.java @@ -0,0 +1,78 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class Bry_fmtr_tst { + @Test public void Idx_text() {tst_Format("a", "a");} + @Test public void Idx_1() {tst_Format("a", "~{0}", "a");} + @Test public void Idx_3() {tst_Format("abc", "~{0}~{1}~{2}", "a", "b", "c");} + @Test public void Idx_mix() {tst_Format("abcde", "a~{0}c~{1}e", "b", "d");} + @Test public void Key_basic() {tst("~{key}" , String_.Ary("key") , ary_("a") , "a");} + @Test public void Key_mult() {tst("~{key1}~{key2}" , String_.Ary("key1", "key2") , ary_("a", "b") , "ab");} + @Test public void Key_mix() {tst("~{key1}~{1}" , String_.Ary("key1", "key2") , ary_("a", "b") , "ab");} + @Test public void Key_repeat() {tst("~{key1}~{key1}" , String_.Ary("key1") , ary_("a") , "aa");} + @Test public void Simple() { + Bry_fmtr fmtr = Bry_fmtr.new_("0~{key1}1~{key2}2", "key1", "key2"); + Tfds.Eq("0.1,2", fmtr.Bld_str_many(".", ",")); + } + @Test public void Cmd() { + Bry_fmtr_tst_mok mok = new Bry_fmtr_tst_mok(); + Bry_fmtr fmtr = Bry_fmtr.new_("0~{key1}2~{<>3<>}4", "key1").Eval_mgr_(mok); + Tfds.Eq("012~{<>3<>}4", fmtr.Bld_str_many("1")); + mok.Enabled_(true); + Tfds.Eq("01234", fmtr.Bld_str_many("1")); + } + @Test public void Err_missing_idx() {tst_Format("~{0}", "~{0}");} + String[] ary_(String... ary) {return ary;} + void tst(String fmt, String[] keys, String[] args, String expd) { + Bry_fmtr fmtr = new Bry_fmtr().Fmt_(Bry_.new_u8(fmt)); + fmtr.Keys_(keys); + String actl = fmtr.Bld_str_many(args); + Tfds.Eq(expd, actl); + } + void tst_Format(String expd, String fmt, String... args) { + Bry_fmtr fmtr = new Bry_fmtr().Fmt_(fmt); + Tfds.Eq(expd, fmtr.Bld_str_many(args)); + } + @Test public void Bld_bfr_many_and_set_fmt() { + Bry_fmtr_fxt fxt = new Bry_fmtr_fxt().Clear(); + fxt.Bld_bfr_many_and_set_fmt("a~{0}c", Object_.Ary("b"), "abc"); + } + @Test public void Escape_tilde() { + Tfds.Eq("~~~~~~", Bry_fmtr.Escape_tilde("~~~")); + } +} +class Bry_fmtr_tst_mok implements Bry_fmtr_eval_mgr { + public boolean Enabled() {return enabled;} public void Enabled_(boolean v) {enabled = v;} private boolean enabled; + public byte[] Eval(byte[] cmd) { + return enabled ? cmd : null; + } +} +class Bry_fmtr_fxt { + public Bry_fmtr_fxt Clear() { + if (fmtr == null) { + fmtr = Bry_fmtr.new_(); + } + return this; + } private Bry_fmtr fmtr; + public void Bld_bfr_many_and_set_fmt(String fmt, Object[] args, String expd) { + fmtr.Fmt_(fmt); + fmtr.Bld_bfr_many_and_set_fmt(args); + Tfds.Eq(expd, String_.new_a7(fmtr.Fmt())); + } +} diff --git a/100_core/src_110_primitive/gplx/Bry_fmtr_vals.java b/100_core/src_110_primitive/gplx/Bry_fmtr_vals.java new file mode 100644 index 000000000..58f8d516b --- /dev/null +++ b/100_core/src_110_primitive/gplx/Bry_fmtr_vals.java @@ -0,0 +1,31 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Bry_fmtr_vals implements Bry_fmtr_arg { + private final Bry_fmtr fmtr; private Object[] vals; + Bry_fmtr_vals(Bry_fmtr fmtr) {this.fmtr = fmtr;} + public Bry_fmtr_vals Vals_(Object... v) {this.vals = v; return this;} + public void XferAry(Bry_bfr bfr, int idx) { + fmtr.Bld_bfr_ary(bfr, vals); + } + public static Bry_fmtr_vals new_fmt(String fmt, String... keys) { + Bry_fmtr fmtr = Bry_fmtr.new_(fmt, keys); + return new Bry_fmtr_vals(fmtr); + } + public static Bry_fmtr_vals new_(Bry_fmtr fmtr) {return new Bry_fmtr_vals(fmtr);} +} diff --git a/100_core/src_110_primitive/gplx/Byte_.java b/100_core/src_110_primitive/gplx/Byte_.java new file mode 100644 index 000000000..aad93dcbb --- /dev/null +++ b/100_core/src_110_primitive/gplx/Byte_.java @@ -0,0 +1,56 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Byte_ { + public static final String Cls_val_name = "byte"; + public static final Class Cls_ref_type = Byte.class; + public static final byte + Zero = 0 + , Min_value = Byte.MIN_VALUE + , Max_value_127 = 127 + ; + public static byte cast_(Object o) {try {return (Byte)o;} catch (Exception e) {throw Exc_.new_type_mismatch_w_exc(e, byte.class, o);}} + public static byte parse_(String raw) {return Byte.parseByte(raw);} + public static byte parse_or_(String raw, byte or) { + if (raw == null) return or; + try { + return parse_(raw); + } catch (Exception e) {Exc_.Noop(e); return or;} + } + public static byte By_int(int v) {return v > 127 ? (byte)(v - 256) : (byte)v;} // PERF?: (byte)(v & 0xff) + public static int Xto_int(byte v) {return v < 0 ? (int)v + 256 : v;} + public static String Xto_str(byte v) {return new Byte(v).toString();} + public static boolean In(byte v, byte... ary) { + for (byte itm : ary) + if (v == itm) return true; + return false; + } + public static int Compare(byte lhs, byte rhs) { + if (lhs == rhs) return CompareAble_.Same; + else if (lhs < rhs) return CompareAble_.Less; + else return CompareAble_.More; + } + public static byte[] Ary(byte... ary) {return ary;} + public static byte[] Ary_by_ints(int... ary) { + int ary_len = ary.length; + byte[] rv = new byte[ary_len]; + for (int i = 0; i < ary_len; i++) + rv[i] = By_int(ary[i]); + return rv; + } +} diff --git a/100_core/src_110_primitive/gplx/Byte__tst.java b/100_core/src_110_primitive/gplx/Byte__tst.java new file mode 100644 index 000000000..4bb4b80cb --- /dev/null +++ b/100_core/src_110_primitive/gplx/Byte__tst.java @@ -0,0 +1,35 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class Byte__tst { + @Test public void int_() { + tst_int_( 0, 0); + tst_int_( 127, 127); + tst_int_( 128, 128); // NOTE: JAVA defines byte as -128 -> 127 + tst_int_( 255, 255); + tst_int_( 256, 0); // NOTE: 256 will cast to 1; (byte)256 works same in both JAVA/.NET + } void tst_int_(int v, int expd) {Tfds.Eq((byte)expd, Byte_.By_int(v));} // WORKAROUND/JAVA: expd is of type int b/c java promotes numbers to ints + @Test public void XtoInt() { + tst_XtoInt( 0, 0); + tst_XtoInt( 127, 127); + tst_XtoInt( 128, 128); + tst_XtoInt( 255, 255); + tst_XtoInt( 256, 0); + } void tst_XtoInt(int v, int expd) {Tfds.Eq(expd, Byte_.Xto_int((byte)v));} // WORKAROUND/JAVA: v is of type int b/c java promotes numbers to ints +} diff --git a/100_core/src_110_primitive/gplx/Byte_ascii.java b/100_core/src_110_primitive/gplx/Byte_ascii.java new file mode 100644 index 000000000..8739f50a6 --- /dev/null +++ b/100_core/src_110_primitive/gplx/Byte_ascii.java @@ -0,0 +1,111 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Byte_ascii { + public static final byte + Nil = 0 , Backfeed = 8, Tab = 9 + , Nl = 10, Formfeed = 12, Cr = 13 + , Space = 32, Bang = 33, Quote = 34 + , Hash = 35, Dollar = 36, Percent = 37, Amp = 38, Apos = 39 + , Paren_bgn = 40, Paren_end = 41, Star = 42, Plus = 43, Comma = 44 + , Dash = 45, Dot = 46, Slash = 47, Num_0 = 48, Num_1 = 49 + , Num_2 = 50, Num_3 = 51, Num_4 = 52, Num_5 = 53, Num_6 = 54 + , Num_7 = 55, Num_8 = 56, Num_9 = 57, Colon = 58, Semic = 59 + , Lt = 60, Eq = 61, Gt = 62, Question = 63, At = 64 + , Ltr_A = 65, Ltr_B = 66, Ltr_C = 67, Ltr_D = 68, Ltr_E = 69 + , Ltr_F = 70, Ltr_G = 71, Ltr_H = 72, Ltr_I = 73, Ltr_J = 74 + , Ltr_K = 75, Ltr_L = 76, Ltr_M = 77, Ltr_N = 78, Ltr_O = 79 + , Ltr_P = 80, Ltr_Q = 81, Ltr_R = 82, Ltr_S = 83, Ltr_T = 84 + , Ltr_U = 85, Ltr_V = 86, Ltr_W = 87, Ltr_X = 88, Ltr_Y = 89 + , Ltr_Z = 90, Brack_bgn = 91, Backslash = 92, Brack_end = 93, Pow = 94 // Circumflex + , Underline = 95, Tick = 96, Ltr_a = 97, Ltr_b = 98, Ltr_c = 99 + , Ltr_d = 100, Ltr_e = 101, Ltr_f = 102, Ltr_g = 103, Ltr_h = 104 + , Ltr_i = 105, Ltr_j = 106, Ltr_k = 107, Ltr_l = 108, Ltr_m = 109 + , Ltr_n = 110, Ltr_o = 111, Ltr_p = 112, Ltr_q = 113, Ltr_r = 114 + , Ltr_s = 115, Ltr_t = 116, Ltr_u = 117, Ltr_v = 118, Ltr_w = 119 + , Ltr_x = 120, Ltr_y = 121, Ltr_z = 122, Curly_bgn = 123, Pipe = 124 + , Curly_end = 125, Tilde = 126 + ; + public static final byte + Angle_bgn = Lt, Angle_end = Gt + ; + public static final byte Max_7_bit = (byte)127, Ascii_min = 0, Ascii_max = 127; + public static boolean Is_sym(byte b) { + switch (b) { + case Byte_ascii.Bang: case Byte_ascii.Quote: + case Byte_ascii.Hash: case Byte_ascii.Dollar: case Byte_ascii.Percent: case Byte_ascii.Amp: case Byte_ascii.Apos: + case Byte_ascii.Paren_bgn: case Byte_ascii.Paren_end: case Byte_ascii.Star: case Byte_ascii.Plus: case Byte_ascii.Comma: + case Byte_ascii.Dash: case Byte_ascii.Dot: case Byte_ascii.Slash: + case Byte_ascii.Colon: case Byte_ascii.Semic: + case Byte_ascii.Lt: case Byte_ascii.Eq: case Byte_ascii.Gt: case Byte_ascii.Question: case Byte_ascii.At: + case Byte_ascii.Brack_bgn: case Byte_ascii.Backslash: case Byte_ascii.Brack_end: case Byte_ascii.Pow: + case Byte_ascii.Underline: case Byte_ascii.Tick: + case Byte_ascii.Curly_bgn: case Byte_ascii.Pipe: + case Byte_ascii.Curly_end: case Byte_ascii.Tilde: + return true; + default: + return false; + } + } + public static boolean Is_ltr(byte b) { + return ( b >= Byte_ascii.Ltr_a && b <= Byte_ascii.Ltr_z + || b >= Byte_ascii.Ltr_A && b <= Byte_ascii.Ltr_Z); + } + public static boolean Is_ws(byte b) { + switch (b) { + case Byte_ascii.Tab: case Byte_ascii.Nl: case Byte_ascii.Cr: case Byte_ascii.Space: return true; + default: return false; + } + } + public static boolean Is_num(byte b) { + return b > Byte_ascii.Slash && b < Byte_ascii.Colon; + } + public static int Xto_digit(byte b) {return b - Byte_ascii.Num_0;} + public static byte Case_upper(byte b) { + return b > 96 && b < 123 + ? (byte)(b - 32) + : b; + } + public static byte Case_lower(byte b) { + return b > 64 && b < 91 + ? (byte)(b + 32) + : b; + } + public static final byte[] Space_len2 = new byte[] {Space, Space}, Space_len4 = new byte[] {Space, Space, Space, Space}; + public static final byte[] + Tab_bry = new byte[] {Byte_ascii.Tab} + , Nl_bry = new byte[] {Byte_ascii.Nl} + , Bang_bry = new byte[] {Byte_ascii.Bang} + , Dot_bry = new byte[] {Byte_ascii.Dot} + , Comma_bry = new byte[] {Byte_ascii.Comma} + , Colon_bry = new byte[] {Byte_ascii.Colon} + , Amp_bry = new byte[] {Byte_ascii.Amp} + , Lt_bry = new byte[] {Byte_ascii.Lt} + , Gt_bry = new byte[] {Byte_ascii.Gt} + , Brack_bgn_bry = new byte[] {Byte_ascii.Brack_bgn} + , Brack_end_bry = new byte[] {Byte_ascii.Brack_end} + , Apos_bry = new byte[] {Byte_ascii.Apos} + , Quote_bry = new byte[] {Byte_ascii.Quote} + , Pipe_bry = new byte[] {Byte_ascii.Pipe} + , Underline_bry = new byte[] {Byte_ascii.Underline} + , Slash_bry = new byte[] {Byte_ascii.Slash} + , Asterisk_bry = new byte[] {Byte_ascii.Star} + , Dash_bry = new byte[] {Byte_ascii.Dash} + , Space_bry = new byte[] {Byte_ascii.Space} + ; +} diff --git a/100_core/src_110_primitive/gplx/Char_.java b/100_core/src_110_primitive/gplx/Char_.java new file mode 100644 index 000000000..c26960213 --- /dev/null +++ b/100_core/src_110_primitive/gplx/Char_.java @@ -0,0 +1,76 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Char_ { + public static final char Null = '\0', NewLine = '\n'; + public static final int CharLen = 1; + public static final int AsciiZero = 48; + public static boolean IsNumber(char c) { + switch (c) { + case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': return true; + default: return false; + } + } + public static boolean IsCaseLower(char c) {return Character.isLowerCase(c);} + public static boolean IsLetterOrDigit(char c) {return Character.isLetterOrDigit(c);} + public static boolean IsLetterEnglish(char c) { + switch (c) { + 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': return true; + default: return false; + } + } + public static boolean IsLetterLowerEnglish(char c) { + switch (c) { + 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': return true; + default: return false; + } + } + public static boolean IsWhitespace(char c) { + switch (c) { + case ' ': case '\t': case '\n': case '\r': return true; + default: return false; + } + } + public static int To_int_or(char c, int or) { + switch (c) { + case '0': return 0; case '1': return 1; case '2': return 2; case '3': return 3; case '4': return 4; + case '5': return 5; case '6': return 6; case '7': return 7; case '8': return 8; case '9': return 9; + default: return or; + } + } + public static boolean In(char match, char... ary) { + for (char itm : ary) + if (itm == match) return true; + return false; + } + public static String XtoStr(char[] ary, int pos, int length) {return new String(ary, pos, length);} + public static byte[] XtoByteAry(int v) {return Bry_.new_u8(Char_.XtoStr((char)v));} + public static char XbyInt(int i) {return (char)i;} + public static String XtoStr(int b) {return XtoStr((char)b);} + public static String XtoStr(char c) {return String.valueOf(c);} + public static byte XtoByte(char c) {return (byte)c;} + public static char cast_(Object o) {try {return (Character)o;} catch(Exception e) {throw Exc_.new_type_mismatch_w_exc(e, char.class, o);}} + public static char parse_(String raw) {try {return raw.charAt(0);} catch(Exception exc) {throw Exc_.new_parse_exc(exc, char.class, raw);}} +} diff --git a/100_core/src_110_primitive/gplx/Double_.java b/100_core/src_110_primitive/gplx/Double_.java new file mode 100644 index 000000000..484c8c4a8 --- /dev/null +++ b/100_core/src_110_primitive/gplx/Double_.java @@ -0,0 +1,54 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Double_ { + public static final String Cls_val_name = "double"; + public static final Class Cls_ref_type = Double.class; + public static final double + MinValue = Double.MIN_VALUE + , NaN = Double.NaN + , Inf_pos = Double.POSITIVE_INFINITY + ; + public static final byte[] + NaN_bry = Bry_.new_a7("NaN") + , Inf_pos_bry = Bry_.new_a7("INF") + ; + public static boolean IsNaN(double v) {return Double.isNaN(v);} + public static double cast_(Object o) {try {return (Double)o;} catch(Exception e) {throw Exc_.new_type_mismatch_w_exc(e, double.class, o);}} + public static double parse_(String raw) {try {return Double.parseDouble(raw);} catch(Exception e) {throw Exc_.new_parse_exc(e, double.class, raw);}} + public static double parse_or(String raw, double v) {try {return Double.parseDouble(raw);} catch(Exception e) {Exc_.Noop(e); return v;}} + public static double coerce_(Object v) { + try {String s = String_.as_(v); return s == null ? Double_.cast_(v) : Double_.parse_(s);} + catch (Exception e) {throw Exc_.new_cast(e, double.class, v);} + } + public static String Xto_str(double v) { + int v_int = (int)v; + return v - v_int == 0 ? Int_.Xto_str(v_int) : Double.toString(v); + } + public static String Xto_str_loose(double v) { + int v_as_int = (int)v; + return v == v_as_int + ? Int_.Xto_str(v_as_int) // convert to int, and call print String to eliminate any trailing decimal places + : Float_.Xto_str((float)v); // calling ((float)v).toString is better at removing trailing 0s than String.format("%g", v). note that .net .toString() handles it better; EX:2449.600000000000d; DATE:2014-07-29 + } + public static int Compare(double lhs, double rhs) { + if (lhs == rhs) return CompareAble_.Same; + else if (lhs < rhs) return CompareAble_.Less; + else return CompareAble_.More; + } +} diff --git a/100_core/src_110_primitive/gplx/Double__tst.java b/100_core/src_110_primitive/gplx/Double__tst.java new file mode 100644 index 000000000..0d5b3ba91 --- /dev/null +++ b/100_core/src_110_primitive/gplx/Double__tst.java @@ -0,0 +1,29 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class Double__tst { + private Double__fxt fxt = new Double__fxt(); + @Test public void Xto_str_loose() { + fxt.Test_Xto_str_loose(2449.6000000d , "2449.6"); + fxt.Test_Xto_str_loose(623.700d , "623.7"); + } +} +class Double__fxt { + public void Test_Xto_str_loose(double v, String expd) {Tfds.Eq(expd, Double_.Xto_str_loose(v));} +} diff --git a/100_core/src_110_primitive/gplx/Float_.java b/100_core/src_110_primitive/gplx/Float_.java new file mode 100644 index 000000000..dff490e33 --- /dev/null +++ b/100_core/src_110_primitive/gplx/Float_.java @@ -0,0 +1,36 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Float_ { + public static final String Cls_val_name = "float"; + public static final Class Cls_ref_type = Float.class; + public static final float NaN = Float.NaN;; + public static boolean IsNaN(float v) {return Float.isNaN(v);} + public static float cast_(Object obj) {try {return (Float)obj;} catch(Exception exc) {throw Exc_.new_type_mismatch_w_exc(exc, float.class, obj);}} + public static float parse_(String raw) {try {return Float.parseFloat(raw);} catch(Exception exc) {throw Exc_.new_parse_exc(exc, float.class, raw);}} + public static String Xto_str(float v) { + int v_int = (int)v; + return v - v_int == 0 ? Int_.Xto_str(v_int) : Float.toString(v); + } + public static float Div(int val, int divisor) {return (float)val / (float)divisor;} + public static float Div(long val, long divisor) {return (float)val / (float)divisor;} + public static int RoundUp(float val) { + int rv = (int)val; + return (rv == val) ? rv : rv + 1; + } +} diff --git a/100_core/src_110_primitive/gplx/Int_.java b/100_core/src_110_primitive/gplx/Int_.java new file mode 100644 index 000000000..1f7bf5d7c --- /dev/null +++ b/100_core/src_110_primitive/gplx/Int_.java @@ -0,0 +1,260 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.core.strings.*; +public class Int_ implements GfoInvkAble { + public static final String Cls_val_name = "int"; + public static final Class Cls_ref_type = Integer.class; + public static final int Base1 = 1; + public static final int Const_dlm_len = 1; + public static final int Const_position_after_char = 1; + public static final int Null = Int_.MinValue; + public static int coerce_(Object v) { + try {String s = String_.as_(v); return s == null ? Int_.cast_(v) : Int_.parse_(s);} + catch (Exception e) {throw Exc_.new_cast(e, int.class, v);} + } + public static int[] Ary_empty = new int[0]; + public static int[] Ary(int... v) {return v;} + public static int[] Ary_copy(int[] ary) {return Ary_copy(ary, ary.length);} + public static int[] Ary_copy(int[] ary, int new_len) { + int old_len = ary.length; + int[] rv = new int[new_len]; + for (int i = 0; i < old_len; i++) + rv[i] = ary[i]; + return rv; + } + public static void Ary_copy_to(int[] src, int src_len, int[] trg) { + for (int i = 0; i < src_len; ++i) + trg[i] = src[i]; + } + public static int[] AryRng(int bgn, int end) { + int len = end - bgn + 1; + int[] rv = new int[len]; + for (int i = 0; i < len; i++) + rv[i] = bgn + i; + return rv; + } + public static boolean Bounds_chk(int bgn, int end, int len) {return bgn > -1 && end < len;} + public static final int + MinValue = Integer.MIN_VALUE + , MaxValue = Integer.MAX_VALUE + , Neg1 = -1 + , Neg1_count = -1 + ; + public static int parse_or_(String raw, int or) { + if (raw == null) return or; + int rawLen = String_.Len(raw); if (rawLen == 0) return or; + int rv = 0, tmp = 0, factor = 1; + for (int i = rawLen; i > 0; i--) { + char c = String_.CharAt(raw, i - 1); + switch (c) { + case '0': tmp = 0; break; case '1': tmp = 1; break; case '2': tmp = 2; break; case '3': tmp = 3; break; case '4': tmp = 4; break; + case '5': tmp = 5; break; case '6': tmp = 6; break; case '7': tmp = 7; break; case '8': tmp = 8; break; case '9': tmp = 9; break; + case '-': rv *= -1; continue; // NOTE: note continue + default: return or; + } + rv += (tmp * factor); + factor *= 10; + } + return rv; + } + public static int EnsureLessThan(int v, int max) {return v >= max ? max : v;} + public static boolean In(int v, int comp0, int comp1) {return v == comp0 || v == comp1;} + public static boolean In(int v, int... ary) { + for (int itm : ary) + if (v == itm) return true; + return false; + } + public static int BoundEnd(int v, int end) {return v >= end ? end - 1 : v;} + public static int Min(int lhs, int rhs) {return lhs < rhs ? lhs : rhs;} + public static int Max(int lhs, int rhs) {return lhs > rhs ? lhs : rhs;} + public static int ModIfNeg1(int v, int or) {return v == -1 ? or : v;} + public static boolean RangeCheck(int v, int max) {return v >= 0 && v < max;} + public static void RangeCheckOrFail_list(int v, int max, String s) {if (v < 0 || v >= max) throw Exc_.new_("bounds check failed", "msg", s, "v", v, "min", 0, "max", max - 1);} + public static void RangeCheckOrFail(int v, int min, int max, String s) {if (v < min || v >= max) throw Exc_.new_("bounds check failed", "msg", s, "v", v, "min", min, "max", max);} + public static boolean Between(int v, int lhs, int rhs) { + int lhsCompare = v == lhs ? 0 : (v < lhs ? -1 : 1); + int rhsCompare = v == rhs ? 0 : (v < rhs ? -1 : 1); + return (lhsCompare * rhsCompare) != 1; // 1 when v is (a) greater than both or (b) less than both + } + public static int Div(int v, float divisor) {return (int)((float)v / divisor);} + public static int DivAndRoundUp(int v, int divisor) { + int whole = v / divisor; + int partial = v % divisor == 0 ? 0 : 1; + return whole + partial; + } + public static int Mult(int v, float multiplier) { + float product = ((float)v * multiplier); // WORKAROUND (DotNet): (int)((float)v * multiplier) returns 0 for 100 and .01f + return (int)product; + } + public static int Compare(int lhs, int rhs) { + if (lhs == rhs) return CompareAble_.Same; + else if (lhs < rhs) return CompareAble_.Less; + else return CompareAble_.More; + } + public static int DigitCount(int v) { + int log10 = Log10(v); + return v > -1 ? log10 + 1 : log10 * -1 + 2; + } + public static int Log10(int v) { + if (v == 0) return 0; + int sign = 1; + if (v < 0) { + if (v == Int_.MinValue) return -9; // NOTE: Int_.MinValue * -1 = Int_.MinValue + v *= -1; + sign = -1; + } + int rv = Log10AryLen - 2; // rv will only happen when v == Int_.MaxValue + int bgn = 0; + if (v > 1000) { // optimization to reduce number of ops to < 5 + bgn = 3; + if (v > 1000000) bgn = 6; + } + for (int i = bgn; i < Log10AryLen; i++) { + if (v < Log10Ary[i]) {rv = i - 1; break;} + } + return rv * sign; + } public static int[] Log10Ary = new int[] {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, Int_.MaxValue}; public static int Log10AryLen = 11; + public Int_ FailIfNeg1(String key, int val) { + if (val < 0) throw Exc_.new_("key must be >= 0", "key", key, "val", val); + return this; + } + public static String Xto_str_pad_bgn_space(int v, int reqdPlaces) {return Xto_str_pad_bgn_zero(v, reqdPlaces, Byte_ascii.Space, true);} // EX: 1, 3 returns " 1" + public static String Xto_str_pad_bgn_zero(int v, int reqdPlaces) {return Xto_str_pad_bgn_zero(v, reqdPlaces, Byte_ascii.Num_0, true);} // EX: 1, 3 returns "001" + static String Xto_str_pad_bgn_zero(int val, int places, byte pad_chr, boolean bgn) { + int len = DigitCount(val); + int pad_len = places - len; if (pad_len < 0) return Int_.Xto_str(val); + Bry_bfr bfr = Bry_bfr.new_(); + boolean neg = val < 0; + if (bgn) { // special logic to handle negative numbers; EX: -1 -> "-001", not "00-1" + if (neg) { + bfr.Add_byte(Byte_ascii.Dash); + val *= -1; + --len; + } + } + else + bfr.Add_int_fixed(val, len); + bfr.Add_byte_repeat(pad_chr, pad_len); + if (bgn) bfr.Add_int_fixed(val, len); // NOTE: neg handled above + return bfr.Xto_str(); + } + public static int read_(Object o) {String s = String_.as_(o); return s != null ? Int_.parse_(s) : Int_.cast_(o);} + public static int parse_(String raw) {try {return Integer.parseInt(raw);} catch(Exception e) {throw Exc_.new_parse_exc(e, int.class, raw);}} + public static int cast_(Object obj) {try {return (Integer)obj;} catch(Exception exc) {throw Exc_.new_type_mismatch_w_exc(exc, int.class, obj);}} + public static int cast_or_(Object obj, int or) {try {return (Integer)obj;} catch(Exception e) {Exc_.Noop(e); return or;}} + public static int Xby_double_(double v) {return (int)v;} + public static String Xto_str(int v) {return new Integer(v).toString();} + public static String Xto_str_fmt(int v, String fmt) {return new java.text.DecimalFormat(fmt).format(v);} + public static boolean TypeMatch(Class type) {return type == int.class || type == Integer.class;} + public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) { + if (ctx.Match(k, Invk_XtoStr_PadBgn)) { + int v = m.ReadInt(GfsCore_.Arg_primitive), pad = m.ReadInt("pad"); + return ctx.Deny() ? (Object)this : Xto_str_pad_bgn_zero(v, pad); + } + else if (ctx.Match(k, "Add")) { + int v = m.ReadInt(GfsCore_.Arg_primitive), operand = m.ReadInt("operand"); + return ctx.Deny() ? (Object)this : v + operand; + } + else return GfoInvkAble_.Rv_unhandled; + } public static final String Invk_XtoStr_PadBgn = "XtoStr_PadBgn"; + public static final Int_ Gfs = new Int_(); +// public static int Xto_int_hex(String v) {return Integer.parseInt(v, 16);} + public static int Xto_int_hex(byte[] src) {return Xto_int_hex(src, 0, src.length);} + public static int Xto_int_hex(byte[] src, int bgn, int end) { + int rv = 0; int factor = 1; + for (int i = end - 1; i >= bgn; i--) { + int val = Xto_int_hex(src[i]); + rv += (val * factor); + factor *= 16; + } + return rv; + } + public static int Xto_int_hex(byte b) { + switch (b) { + case Byte_ascii.Num_0: case Byte_ascii.Num_1: case Byte_ascii.Num_2: case Byte_ascii.Num_3: case Byte_ascii.Num_4: + case Byte_ascii.Num_5: case Byte_ascii.Num_6: case Byte_ascii.Num_7: case Byte_ascii.Num_8: case Byte_ascii.Num_9: + return b - Byte_ascii.Num_0; + case Byte_ascii.Ltr_A: case Byte_ascii.Ltr_B: case Byte_ascii.Ltr_C: case Byte_ascii.Ltr_D: case Byte_ascii.Ltr_E: case Byte_ascii.Ltr_F: + return b - Byte_ascii.Ltr_A + 10; + case Byte_ascii.Ltr_a: case Byte_ascii.Ltr_b: case Byte_ascii.Ltr_c: case Byte_ascii.Ltr_d: case Byte_ascii.Ltr_e: case Byte_ascii.Ltr_f: + return b - Byte_ascii.Ltr_a + 10; + default: + return -1; + } + } + public static String Xto_str_hex(int v) { + String rv = Integer.toHexString(v); + int rvLen = String_.Len(rv); + if (rvLen < 8) rv = String_.Repeat("0", 8 - rvLen) + rv; + return String_.Upper(rv); + } + public static String Xto_str(int[] ary) {return Xto_str(ary, " ");} + public static String Xto_str(int[] ary, String dlm) { + String_bldr sb = String_bldr_.new_(); + for (int i = 0; i < ary.length; i++) + sb.Add_spr_unless_first(Int_.Xto_str(ary[i]), dlm, i); + return sb.XtoStr(); + } + public static int[] Ary_parse(String raw_str, int reqd_len, int[] or) { + byte[] raw_bry = Bry_.new_a7(raw_str); + int raw_bry_len = raw_bry.length; + int[] rv = new int[reqd_len]; + int cur_val = 0, cur_mult = 1, cur_idx = reqd_len - 1; boolean signed = false; + for (int i = raw_bry_len - 1; i > -2; i--) { + byte b = i == -1 ? Byte_ascii.Comma : raw_bry[i]; + switch (b) { + case Byte_ascii.Num_0: case Byte_ascii.Num_1: case Byte_ascii.Num_2: case Byte_ascii.Num_3: case Byte_ascii.Num_4: + case Byte_ascii.Num_5: case Byte_ascii.Num_6: case Byte_ascii.Num_7: case Byte_ascii.Num_8: case Byte_ascii.Num_9: + if (signed) return or; + cur_val += (b - Byte_ascii.Num_0) * cur_mult; + cur_mult *= 10; + break; + case Byte_ascii.Space: case Byte_ascii.Nl: case Byte_ascii.Cr: case Byte_ascii.Tab: + break; + case Byte_ascii.Comma: + if (cur_idx < 0) return or; + rv[cur_idx--] = cur_val; + cur_val = 0; cur_mult = 1; + signed = false; + break; + case Byte_ascii.Dash: + if (signed) return or; + cur_val *= -1; + signed = true; + break; + case Byte_ascii.Plus: // noop; all values positive by default + if (signed) return or; + signed = true; + break; + default: + return or; + } + } + return cur_idx == -1 ? rv : or; // cur_idx == -1 checks for unfilled; EX: Ary_parse("1,2", 3, null) is unfilled + } + public static int[] Ary_parse(String raw_str, String spr) { + String[] ary = String_.Split(raw_str, spr); + int len = ary.length; + int[] rv = new int[len]; + for (int i = 0; i < len; i++) + rv[i] = Int_.parse_(ary[i]); + return rv; + } + public static byte[] Xto_bry(int v) {return Bry_.new_a7(Xto_str(v));} +} diff --git a/100_core/src_110_primitive/gplx/Int__tst.java b/100_core/src_110_primitive/gplx/Int__tst.java new file mode 100644 index 000000000..478f8208a --- /dev/null +++ b/100_core/src_110_primitive/gplx/Int__tst.java @@ -0,0 +1,115 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class Int__tst { + @Test public void XtoStr_PadBgn() { +// tst_XtoStr_PadLeft_Zeroes(1 , 3, "001"); // pad +// tst_XtoStr_PadLeft_Zeroes(123 , 3, "123"); // no pad +// tst_XtoStr_PadLeft_Zeroes(1234 , 3, "1234"); // val exceeds pad; confirm noop + tst_XtoStr_PadLeft_Zeroes(-1 , 3, "-01"); // negative + tst_XtoStr_PadLeft_Zeroes(-12 , 3, "-12"); // negative + tst_XtoStr_PadLeft_Zeroes(-123 , 3, "-123"); // negative + tst_XtoStr_PadLeft_Zeroes(-1234 , 3, "-1234"); // negative + } void tst_XtoStr_PadLeft_Zeroes(int val, int zeros, String expd) {Tfds.Eq(expd, Int_.Xto_str_pad_bgn_zero(val, zeros));} + @Test public void parseOr_() { + tst_ParseOr("", -1); // empty + tst_ParseOr("123", 123); // single + tst_ParseOr("1a", -1); // fail + } void tst_ParseOr(String raw, int expd) {Tfds.Eq(expd, Int_.parse_or_(raw, -1));} + @Test public void Between() { + tst_Between(1, 0, 2, true); // simple true + tst_Between(3, 0, 2, false); // simple false + tst_Between(0, 0, 2, true); // bgn true + tst_Between(2, 0, 2, true); // end true + } void tst_Between(int val, int lhs, int rhs, boolean expd) {Tfds.Eq(expd, Int_.Between(val, lhs, rhs));} + @Test public void Xto_fmt() { + tst_XtoStr_fmt(1, "1"); + tst_XtoStr_fmt(1000, "1,000"); + } void tst_XtoStr_fmt(int v, String expd) {Tfds.Eq(expd, Int_.Xto_str_fmt(v, "#,###"));} + @Test public void AryRng() { + tst_AryRng(1, 3, Int_.Ary(1, 2, 3)); + } void tst_AryRng(int bgn, int end, int[] expd) {Tfds.Eq_ary(expd, Int_.AryRng(bgn, end));} + @Test public void Log10_pos() { + tst_Log10(0, 0); + tst_Log10(1, 0); + tst_Log10(9, 0); + tst_Log10(10, 1); + tst_Log10(100, 2); + tst_Log10(1000000, 6); + tst_Log10(1000000000, 9); + tst_Log10(Int_.MaxValue, 9); + } + @Test public void Log10_neg() { + tst_Log10(-1, 0); + tst_Log10(-10, -1); + tst_Log10(-100, -2); + tst_Log10(-1000000, -6); + tst_Log10(-1000000000, -9); + tst_Log10(Int_.MinValue, -9); + tst_Log10(Int_.MinValue + 1, -9); + } + void tst_Log10(int val, int expd) {Tfds.Eq(expd, Int_.Log10(val));} + @Test public void DigitCount() { + tst_DigitCount(0, 1); + tst_DigitCount(9, 1); + tst_DigitCount(100, 3); + tst_DigitCount(-1, 2); + tst_DigitCount(-100, 4); + } void tst_DigitCount(int val, int expd) {Tfds.Eq(expd, Int_.DigitCount(val), Int_.Xto_str(val));} + @Test public void Log10() { + tst_Log10( 0, 0); + tst_Log10( 1, 0); + tst_Log10( 2, 0); + tst_Log10( 10, 1); + tst_Log10( 12, 1); + tst_Log10( 100, 2); + tst_Log10( 123, 2); + tst_Log10( 1000, 3); + tst_Log10( 1234, 3); + tst_Log10( 10000, 4); + tst_Log10( 12345, 4); + tst_Log10( 100000, 5); + tst_Log10( 123456, 5); + tst_Log10( 1000000, 6); + tst_Log10( 1234567, 6); + tst_Log10( 10000000, 7); + tst_Log10( 12345678, 7); + tst_Log10( 100000000, 8); + tst_Log10( 123456789, 8); + tst_Log10( 1000000000, 9); + tst_Log10( 1234567890, 9); + tst_Log10(Int_.MaxValue, 9); + } + @Test public void Xto_int_hex_tst() { + Xto_int_hex("007C", 124); + } void Xto_int_hex(String raw, int expd) {Tfds.Eq(expd, Int_.Xto_int_hex(Bry_.new_a7(raw)));} + @Test public void Ary_parse() { + Ary_parse__tst("1,2,3" , 3, Int_.Ary_empty, 1, 2, 3); + Ary_parse__tst("123,321,213" , 3, Int_.Ary_empty, 123, 321, 213); + Ary_parse__tst(" 1, 2,3" , 3, Int_.Ary_empty, 1, 2, 3); + Ary_parse__tst("-1,+2,-3" , 3, Int_.Ary_empty, -1, 2, -3); + Ary_parse__tst(Int_.Xto_str(Int_.MinValue) , 1, Int_.Ary_empty, Int_.MinValue); + Ary_parse__tst(Int_.Xto_str(Int_.MaxValue) , 1, Int_.Ary_empty, Int_.MaxValue); + Ary_parse__tst("1,2" , 1, Int_.Ary_empty); + Ary_parse__tst("1" , 2, Int_.Ary_empty); + Ary_parse__tst("a" , 1, Int_.Ary_empty); + Ary_parse__tst("1-2," , 1, Int_.Ary_empty); + } + void Ary_parse__tst(String raw, int reqd_len, int[] or, int... expd) {Tfds.Eq_ary(expd, Int_.Ary_parse(raw, reqd_len, or));} +} diff --git a/100_core/src_110_primitive/gplx/Int_ary_.java b/100_core/src_110_primitive/gplx/Int_ary_.java new file mode 100644 index 000000000..fbfab423b --- /dev/null +++ b/100_core/src_110_primitive/gplx/Int_ary_.java @@ -0,0 +1,95 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Int_ary_ { + public static int[] Parse_list_or(byte[] src, int[] or) { + try { + if (Bry_.Len_eq_0(src)) return or; // null, "" should return [0] + int raw_len = src.length; + int[] rv = null; int rv_idx = 0, rv_len = 0; + int pos = 0; + int num_bgn = -1, num_end = -1; + boolean itm_done = false, itm_is_rng = false; + int rng_bgn = Int_.MinValue; + while (true) { + boolean pos_is_last = pos == raw_len; + if ( itm_done + || pos_is_last + ) { + if (num_bgn == -1) return or; // empty itm; EX: "1,"; "1,,2" + int num = Bry_.Xto_int_or(src, num_bgn, num_end, Int_.MinValue); + if (num == Int_.MinValue) return or; // not a number; parse failed + if (rv_len == 0) { // rv not init'd + rv_len = (raw_len / 2) + 1; // default rv_len to len of String / 2; + 1 to avoid fraction rounding down + rv = new int[rv_len]; + } + int add_len = 1; + if (itm_is_rng) { + add_len = num - rng_bgn + List_adp_.Base1; + if (add_len == 0) return or; // bgn >= end; + } + if (add_len + rv_idx > rv_len) { // ary out of space; resize + rv_len = (add_len + rv_idx) * 2; + rv = (int[])Array_.Resize(rv, rv_len); + } + if (itm_is_rng) { + for (int i = rng_bgn; i <= num; i++) + rv[rv_idx++] = i; + } + else { + rv[rv_idx++] = num; + } + num_bgn = num_end = -1; + itm_done = itm_is_rng = false; + rng_bgn = Int_.MinValue; + if (pos_is_last) break; + } + byte b = src[pos]; + switch (b) { + case Byte_ascii.Num_0: case Byte_ascii.Num_1: case Byte_ascii.Num_2: case Byte_ascii.Num_3: case Byte_ascii.Num_4: + case Byte_ascii.Num_5: case Byte_ascii.Num_6: case Byte_ascii.Num_7: case Byte_ascii.Num_8: case Byte_ascii.Num_9: + if (num_bgn == -1) // num_bgn not set + num_bgn = pos; + num_end = pos + 1; // num_end is always after pos; EX: "9": num_end = 1; "98,7": num_end=2 + break; + case Byte_ascii.Space: case Byte_ascii.Tab: case Byte_ascii.Nl: case Byte_ascii.Cr: // NOTE: parseNumList replaces ws with '', so "1 1" will become "11" + break; + case Byte_ascii.Comma: + if (pos == raw_len -1) return or; // eos; EX: "1," + if (num_bgn == -1) return or; // empty itm; EX: ","; "1,,2" + itm_done = true; + break; + case Byte_ascii.Dash: + if (pos == raw_len -1) return or; // eos; EX: "1-" + if (num_bgn == -1) return or; // no rng_bgn; EX: "-2" + rng_bgn = Bry_.Xto_int_or(src, num_bgn, pos, Int_.MinValue); + if (rng_bgn == Int_.MinValue) return or; + num_bgn = -1; + itm_is_rng = true; + break; + default: + return or; + } + ++pos; + } + return (rv_idx == rv_len) // on the off-chance that rv_len == rv_idx; EX: "1" + ? rv + : (int[])Array_.Resize(rv, rv_idx); + } catch (Exception e) {Exc_.Noop(e); return or;} + } +} diff --git a/100_core/src_110_primitive/gplx/Int_ary__tst.java b/100_core/src_110_primitive/gplx/Int_ary__tst.java new file mode 100644 index 000000000..d051ed2b6 --- /dev/null +++ b/100_core/src_110_primitive/gplx/Int_ary__tst.java @@ -0,0 +1,44 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class Int_ary__tst { + private Int_ary__fxt fxt = new Int_ary__fxt(); + @Test public void Parse_list_or_() { + fxt.Test_Parse_list_or("1", 1); + fxt.Test_Parse_list_or("123", 123); + fxt.Test_Parse_list_or("1,2,123", 1, 2, 123); + fxt.Test_Parse_list_or("1,2,12,123", 1, 2, 12, 123); + fxt.Test_Parse_list_or("1-5", 1, 2, 3, 4, 5); + fxt.Test_Parse_list_or("1-1", 1); + fxt.Test_Parse_list_or("1-3,7,11-13,21", 1, 2, 3, 7, 11, 12, 13, 21); + + fxt.Test_Parse_list_empty("1 2"); // NOTE: MW would gen 12; treat as invalid + fxt.Test_Parse_list_empty("1,"); // eos + fxt.Test_Parse_list_empty("1,,2"); // empty comma + fxt.Test_Parse_list_empty("1-"); // eos + fxt.Test_Parse_list_empty("3-1"); // bgn > end + fxt.Test_Parse_list_empty("1,a,2"); + fxt.Test_Parse_list_empty("a-1,2"); + fxt.Test_Parse_list_empty("-1"); // no rng bgn + } +} +class Int_ary__fxt { + public void Test_Parse_list_empty(String raw) {Tfds.Eq_ary(Int_.Ary_empty, Int_ary_.Parse_list_or(Bry_.new_a7(raw), Int_.Ary_empty));} + public void Test_Parse_list_or(String raw, int... expd) {Tfds.Eq_ary(expd, Int_ary_.Parse_list_or(Bry_.new_a7(raw), Int_.Ary_empty));} +} diff --git a/100_core/src_110_primitive/gplx/Long_.java b/100_core/src_110_primitive/gplx/Long_.java new file mode 100644 index 000000000..30cd77119 --- /dev/null +++ b/100_core/src_110_primitive/gplx/Long_.java @@ -0,0 +1,113 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Long_ { + public static final String Cls_val_name = "long"; + public static final Class Cls_ref_type = Long.class; + public static final long + MinValue = Long.MIN_VALUE + , MaxValue = Long.MAX_VALUE + ; + public static final int Log10Ary_len = 21; + public static long[] Log10Ary = new long[] + { 1, 10, 100, 1000, 10000 + , 100000, 1000000, 10000000, 100000000, 1000000000 + , Long_.Pow(10, 10), Long_.Pow(10, 11), Long_.Pow(10, 12), Long_.Pow(10, 13), Long_.Pow(10, 14) + , Long_.Pow(10, 15), Long_.Pow(10, 16), Long_.Pow(10, 17), Long_.Pow(10, 18), Long_.Pow(10, 19) + , Long_.MaxValue + }; + public static long parse_(String raw) {try {return Long.parseLong(raw);} catch(Exception e) {throw Exc_.new_parse_exc(e, long.class, raw);}} + public static long cast_(Object obj) {try {return (Long)obj;} catch(Exception e) {throw Exc_.new_type_mismatch_w_exc(e, long.class, obj);}} + public static long coerce_(Object v) { + try {String s = String_.as_(v); return s == null ? Long_.cast_(v) : Long_.parse_(s);} + catch (Exception e) {throw Exc_.new_cast(e, long.class, v);} + } + public static long Xby_int(int v) {return (long)v;} + public static String Xto_str(long v) {return Long.toString(v);} + public static String Xto_str_PadBgn(long v, int reqdPlaces) {return String_.Pad(Xto_str(v), reqdPlaces, "0", true);} // ex: 1, 3 returns 001 + public static long parse_or_(String raw, long or) { + if (raw == null) return or; + try { + int rawLen = String_.Len(raw); + if (raw == null || rawLen == 0) return or; + long rv = 0, factor = 1; int tmp = 0; + for (int i = rawLen; i > 0; i--) { + tmp = Char_.To_int_or(String_.CharAt(raw, i - 1), Int_.MinValue); + if (tmp == Int_.MinValue) return or; + rv += (tmp * factor); + factor *= 10; + } + return rv; + } catch (Exception e) {Exc_.Noop(e); return or;} + } + public static int Compare(long lhs, long rhs) { + if (lhs == rhs) return CompareAble_.Same; + else if (lhs < rhs) return CompareAble_.Less; + else return CompareAble_.More; + } + public static int FindIdx(long[] ary, long find_val) { + int ary_len = ary.length; + int adj = 1; + int prv_pos = 0; + int prv_len = ary_len; + int cur_len = 0; + int cur_idx = 0; + long cur_val = 0; + while (true) { + cur_len = prv_len / 2; + if (prv_len % 2 == 1) ++cur_len; + cur_idx = prv_pos + (cur_len * adj); + if (cur_idx < 0) cur_idx = 0; + else if (cur_idx >= ary_len) cur_idx = ary_len - 1; + cur_val = ary[cur_idx]; + if (find_val < cur_val) adj = -1; + else if (find_val > cur_val) adj = 1; + else if (find_val == cur_val) return cur_idx; + if (cur_len == 1) { + if (adj == -1 && cur_idx > 0) + return --cur_idx; + return cur_idx; + } + prv_len = cur_len; + prv_pos = cur_idx; + } + } + public static int DigitCount(long v) { + int adj = Int_.Base1; + if (v < 0) { + if (v == Long_.MinValue) return 19; // NOTE: Long_.MinValue * -1 = Long_.MinValue + v *= -1; + ++adj; + } + return FindIdx(Log10Ary, v) + adj; + } + public static long Pow(int val, int exp) { + long rv = val; + for (int i = 1; i < exp; i++) + rv *= val; + return rv; + } + public static long Int_merge(int hi, int lo) {return (long)hi << 32 | (lo & 0xFFFFFFFFL);} + public static int Int_split_lo(long v) {return (int)(v);} + public static int Int_split_hi(long v) {return (int)(v >> 32);} +} +/* alternate for Int_merge; does not work in java + public static long MergeInts(int lo, int hi) {return (uint)(hi << 32) | (lo & 0xffffffff);} + public static int SplitLo(long v) {return (int)(((ulong)v & 0x00000000ffffffff));} + public static int SplitHi(long v) {return (int)(((ulong)v & 0xffffffff00000000)) >> 32;} +*/ diff --git a/100_core/src_110_primitive/gplx/Long__tst.java b/100_core/src_110_primitive/gplx/Long__tst.java new file mode 100644 index 000000000..dc1c4aa99 --- /dev/null +++ b/100_core/src_110_primitive/gplx/Long__tst.java @@ -0,0 +1,49 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class Long__tst { + @Test public void DigitCount() { + tst_DigitCount(0, 1); + tst_DigitCount(1, 1); + tst_DigitCount(9, 1); + tst_DigitCount(10, 2); + tst_DigitCount(100, 3); + tst_DigitCount(10000, 5); + tst_DigitCount(100000, 6); + tst_DigitCount(1000000, 7); + tst_DigitCount(1000000000, 10); + tst_DigitCount(10000000000L, 11); + tst_DigitCount(100000000000L, 12); + tst_DigitCount(10000000000000000L, 17); + tst_DigitCount(-1, 2); + } void tst_DigitCount(long val, int expd) {Tfds.Eq(expd, Long_.DigitCount(val));} + @Test public void Int_merge() { + tst_Int_merge(123, 456, 528280977864L); + tst_Int_merge(123, 457, 528280977865L); + } + void tst_Int_merge(int hi, int lo, long expd) { + Tfds.Eq(expd, Long_.Int_merge(hi, lo)); + Tfds.Eq(hi, Long_.Int_split_hi(expd)); + Tfds.Eq(lo, Long_.Int_split_lo(expd)); + } + @Test public void parse_or_() { + parse_or_tst("10000000000", 10000000000L); + } + void parse_or_tst(String raw, long expd) {Tfds.Eq(expd, Long_.parse_or_(raw, -1));} +} diff --git a/100_core/src_110_primitive/gplx/Object_.java b/100_core/src_110_primitive/gplx/Object_.java new file mode 100644 index 000000000..8f42ba924 --- /dev/null +++ b/100_core/src_110_primitive/gplx/Object_.java @@ -0,0 +1,46 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Object_ { + public static final String Cls_val_name = "Object"; + public static final Object[] Ary_empty = new Object[0]; + public static Object[] Ary(Object... ary) {return ary;} + public static boolean Eq(Object lhs, Object rhs) { + if (lhs == null && rhs == null) return true; + else if (lhs == null || rhs == null) return false; + else return lhs.equals(rhs); + } + public static String Xto_str_strict_or_null(Object v) {return v == null ? null : ToString_lang(v);} + public static String Xto_str_strict_or_null_mark(Object v) {return v == null ? String_.Null_mark : ToString_lang(v);} + public static String Xto_str_strict_or_empty(Object v) {return v == null ? String_.Empty : ToString_lang(v);} + private static String ToString_lang(Object v) { + Class c = v.getClass(); + if (ClassAdp_.Eq(c, String_.Cls_ref_type)) return (String)v; + else if (ClassAdp_.Eq(c, Bry_.Cls_ref_type)) return String_.new_u8((byte[])v); + else return v.toString(); + } + public static String Xto_str_loose_or(Object v, String or) { // tries to pretty-print doubles; also standardizes true/false; DATE:2014-07-14 + if (v == null) return null; + Class c = ClassAdp_.ClassOf_obj(v); + if (ClassAdp_.Eq(c, String_.Cls_ref_type)) return (String)v; + else if (ClassAdp_.Eq(c, Bry_.Cls_ref_type)) return String_.new_u8((byte[])v); + else if (ClassAdp_.Eq(c, Bool_.Cls_ref_type)) return Bool_.cast_(v) ? Bool_.True_str : Bool_.False_str; // always return "true" / "false" + else if (ClassAdp_.Eq(c, Double_.Cls_ref_type)) return Double_.Xto_str_loose(Double_.cast_(v)); + else return v.toString(); + } +} \ No newline at end of file diff --git a/100_core/src_110_primitive/gplx/Object__tst.java b/100_core/src_110_primitive/gplx/Object__tst.java new file mode 100644 index 000000000..43aeabdb1 --- /dev/null +++ b/100_core/src_110_primitive/gplx/Object__tst.java @@ -0,0 +1,36 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class Object__tst { + @Before public void init() {} private Object__fxt fxt = new Object__fxt(); + @Test public void Eq() { + fxt.Test_eq(null, null, true); // both null + fxt.Test_eq(5, 5, true); // both non-null + fxt.Test_eq(5, null, false); // rhs non-null + fxt.Test_eq(null, 5, false); // lhs non-null + } + @Test public void Xto_str_loose_or_null() { + fxt.Test_xto_str_loose_or_null(null, null); + fxt.Test_xto_str_loose_or_null(2449.6000000000004d, "2449.6"); + } +} +class Object__fxt { + public void Test_eq(Object lhs, Object rhs, boolean expd) {Tfds.Eq(expd, Object_.Eq(lhs, rhs));} + public void Test_xto_str_loose_or_null(Object v, String expd) {Tfds.Eq(expd, Object_.Xto_str_loose_or(v, null));} +} diff --git a/100_core/src_110_primitive/gplx/Short_.java b/100_core/src_110_primitive/gplx/Short_.java new file mode 100644 index 000000000..6e69867ee --- /dev/null +++ b/100_core/src_110_primitive/gplx/Short_.java @@ -0,0 +1,22 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Short_ { + public static final Class Cls_ref_type = Short.class; + public static short cast_(Object obj) {try {return (Short)obj;} catch(Exception exc) {throw Exc_.new_type_mismatch_w_exc(exc, short.class, obj);}} +} diff --git a/100_core/src_110_primitive/gplx/String_.java b/100_core/src_110_primitive/gplx/String_.java new file mode 100644 index 000000000..e2f23cf65 --- /dev/null +++ b/100_core/src_110_primitive/gplx/String_.java @@ -0,0 +1,535 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import java.lang.*; +import gplx.core.strings.*; +public class String_ implements GfoInvkAble { + public static final Class Cls_ref_type = String.class; + public static final String Cls_val_name = "str" + "ing"; + public static final int Find_none = -1, Pos_neg1 = -1; + public static final String Null = null, Empty = "", Null_mark = "<>", Tab = "\t", Lf = "\n", CrLf = "\r\n"; + public static String cast_(Object v) {return (String)v;} + public static String as_(Object obj) {return obj instanceof String ? (String)obj : null;} + public static String new_a7(byte[] v) {return v == null ? null : new_a7(v, 0, v.length);} + public static String new_a7(byte[] v, int bgn, int end) { + try { + return v == null + ? null + : new String(v, bgn, end - bgn, "ASCII"); + } + catch (Exception e) {throw Exc_.new_exc(e, "core", "unsupported encoding");} + } + public static String new_u8(byte[] v) {return v == null ? null : new_u8(v, 0, v.length);} + public static String new_u8(byte[] v, int bgn, int end) { + try { + return v == null + ? null + : new String(v, bgn, end - bgn, "UTF-8"); + } + catch (Exception e) {throw Exc_.new_exc(e, "core", "unsupported encoding");} + } + public static String new_u8_by_len(byte[] v, int bgn, int len) { + int v_len = v.length; + if (bgn + len > v_len) len = v_len - bgn; + return new_u8(v, bgn, bgn + len); + } + public static String[] Ary_add(String[]... arys) { + if (arys == null) return String_.Ary_empty; + int arys_len = arys.length; + int rv_len = 0; + for (int i = 0; i < arys_len; i++) { + String[] ary = arys[i]; + rv_len += ary.length; + } + int rv_idx = 0; + String[] rv = new String[rv_len]; + for (int i = 0; i < arys_len; i++) { + String[] ary = arys[i]; + int ary_len = ary.length; + for (int j = 0; j < ary_len; j++) + rv[rv_idx++] = ary[j]; + } + return rv; + } + public static boolean Len_gt_0(String s) {return s != null && s.length() > 0;} + public static boolean Len_eq_0(String s) {return s == null || s.length() == 0;} + public static int Len(String s) {return s.length();} + public static String Lower(String s) {return s.toLowerCase();} + public static String Upper(String s) {return s.toUpperCase();} + public static String CaseNormalize(boolean caseSensitive, String s) {return caseSensitive ? s : String_.Lower(s);} + public static String Trim(String s) {return s.trim();} + public static String Mid(String s, int bgn) {return s.substring(bgn);} + public static String Replace(String s, String find, String replace) {return s.replace(find, replace);} + public static char[] XtoCharAry(String s) {return s.toCharArray();} + public static char CharAt(String s, int i) {return s.charAt(i);} + public static int CodePointAt(String s, int i) {return s.codePointAt(i);} + public static boolean Has(String s, String find) {return s.indexOf(find) != String_.Find_none;} + public static boolean Has_at_bgn(String s, String v) {return s.startsWith(v);} + public static boolean Has_at_end(String s, String v) {return s.endsWith(v);} + public static int FindFwd(String s, String find) {return s.indexOf(find);} + public static int FindFwd(String s, String find, int pos) {return s.indexOf(find, pos);} + public static int FindBwd(String s, String find) {return s.lastIndexOf(find);} + public static int FindBwd(String s, String find, int pos) { + return s.lastIndexOf(find, pos); + } + public static int FindBetween(String s, String find, int bgn, int end) { + int rv = FindFwd(s, find, bgn); + return (rv > end) ? String_.Find_none : rv; + } + public static int FindAfter(String s, String find, int bgn) { + int rv = FindFwd(s, find, bgn); + return rv == String_.Find_none ? String_.Find_none : rv + Len(find); + } + public static int FindAfterRev(String s, String find, int pos) { + int rv = FindBwd(s, find, pos); + return rv == String_.Find_none ? String_.Find_none : rv + Len(find); + } + public static int Count(String s, String part) { + int count = 0, pos = -1; // -1 b/c first pass must be 0 (see pos + 1 below) + do { + pos = FindFwd(s, part, pos + 1); + if (pos == String_.Find_none) break; + count++; + } while (true); + return count; + } + public static boolean Eq(String lhs, String rhs) {return lhs == null ? rhs == null : lhs.equals(rhs);} + public static boolean EqAny(String lhs, String... rhsAry) { + for (int i = 0; i < rhsAry.length; i++) + if (Eq(lhs, rhsAry[i])) return true; + return false; + } + public static boolean EqNot(String lhs, String rhs) {return !Object_.Eq(lhs, rhs);} + public static boolean EqEmpty(String lhs, String rhs) {return lhs.equals("");} + public static String IfNullOrEmpty(String s, String or) {return s == null || s.length() == 0 ? or : s;} + public static int Compare(String lhs, String rhs) {return lhs.compareTo(rhs);} // NOTE: Compare instead of compareTo b/c javafy lowercases compareTo + public static int Compare_ignoreCase(String lhs, String rhs) { + if (lhs == null && rhs != null) return CompareAble_.Less; + else if (lhs != null && rhs == null) return CompareAble_.More; + else if (lhs == null && rhs == null) return CompareAble_.Same; + else return lhs.compareToIgnoreCase(rhs); + //#- + /* + if (lhs == null && rhs != null) return CompareAble_.Less; + else if (lhs != null && rhs == null) return CompareAble_.More; + else if (lhs == null && rhs == null) return CompareAble_.Same; + else return lhs.compareToIgnoreCase(rhs); + */ + } + public static int Compare_strict(String lhs, String rhs) { + int compare = String_.Compare(lhs, rhs); + if (compare == CompareAble_.Same) return CompareAble_.Same; + else if (compare < CompareAble_.Same) return CompareAble_.Less; + else /* (compare > CompareAble_.Same) */ return CompareAble_.More; + } + public static int Compare_byteAry(String lhs, String rhs) { + int lhsLen = lhs.length(), rhsLen = rhs.length(); + int aryLen = lhsLen < rhsLen ? lhsLen : rhsLen; + int[] lhsAry = XtoIntAry(lhs, aryLen), rhsAry = XtoIntAry(rhs, aryLen); + for (int i = 0; i < aryLen; i++) { + int comp = Int_.Compare(lhsAry[i], rhsAry[i]); + if (comp != CompareAble_.Same) return comp; + } + return Int_.Compare(lhsLen, rhsLen); + } + public static int[] XtoIntAry(String s, int len) { + int[] rv = new int[len]; + for (int i = 0; i < len; i++) + rv[i] = (int)s.charAt(i); + return rv; + } + public static String Coalesce(String s, String alt) {return Len_eq_0(s) ? alt : s;} + public static boolean In(String s, String... ary) { + for (String itm : ary) + if (String_.Eq(s, itm)) return true; + return false; + } + + public static String new_charAry_(char[] ary, int bgn, int len) {return new String(ary, bgn, len);} + public static String Mid(String s, int bgn, int end) { + try {return Mid_lang(s, bgn, end - bgn);} + catch (Exception e) { + int len = s == null ? 0 : Len(s); + String msg = ""; + if (s == null) msg = "s is null"; + else if (bgn > end) msg = "@bgn > @end"; + else if (bgn < 0 || bgn >= len) msg = "@bgn is invalid"; + else if (end < 0 || end > len) msg = "@end is invalid"; + throw Exc_.new_exc(e, "core", msg, "s", s, "bgn", bgn, "end", end, "len", len); + } + } + public static String MidByLenSafe(String s, int bgn, int len) { + if (bgn + len >= Len(s)) len = Len(s) - bgn; + return Mid_lang(s, bgn, len); + } + public static String MidByLen(String s, int bgn, int len) {return Mid_lang(s, bgn, len);} + public static String GetStrBefore(String s, String spr) { + int sprPos = String_.FindFwd(s, spr); if (sprPos == String_.Find_none) throw Exc_.new_("could not find spr", "s", s, "spr", spr); + return Mid(s, 0, sprPos); + } + public static String GetStrAfter(String s, String spr) { + int sprPos = String_.FindFwd(s, spr); if (sprPos == String_.Find_none) throw Exc_.new_("could not find spr", "s", s, "spr", spr); + return Mid(s, sprPos + 1); + } + public static String LimitToFirst(String s, int len) { + if (len < 0) throw Err_arg.cannotBe_("< 0", "len", len); + int sLen = Len(s); if (len > sLen) return s; + return Mid_lang(s, 0, len); + } + public static String LimitToLast(String s, int len) { + if (len < 0) throw Err_arg.cannotBe_("< 0", "len", len); + int sLen = Len(s); if (len > sLen) return s; + return Mid_lang(s, sLen - len, len); + } + public static String DelBgn(String s, int count) { + if (count < 0) throw Err_arg.cannotBe_("< 0", "count", count); + if (s == null) throw Err_arg.null_("s"); + int len = Len(s); if (count > len) throw Err_arg.cannotBe_("> @len", "count", count).Add("len", len); + return String_.Mid(s, count); + } + public static String DelBgnIf(String s, String find) { + if (s == null) throw Err_arg.null_("s"); if (find == null) throw Err_arg.null_("find"); + return Has_at_bgn(s, find) ? String_.Mid(s, Len(find)) : s; + } + public static String DelEnd(String s, int count) { + if (count < 0) throw Err_arg.cannotBe_("< 0", "count", count); + if (s == null) throw Err_arg.null_("s"); + int len = Len(s); if (count > len) throw Err_arg.cannotBe_("> len", "count", count).Add("len", len); + return Mid_lang(s, 0, len + -count); + } + public static String DelEndIf(String s, String find) { + if (s == null) throw Err_arg.null_("s"); if (find == null) throw Err_arg.null_("find"); + return Has_at_end(s, find) ? Mid_lang(s, 0, Len(s) - Len(find)) : s; + } + public static String LowerFirst(String s) { + int len = Len(s); if (len == 0) return String_.Empty; + String char0 = Lower(Mid_lang(s, 0, 1)); + return len == 1 ? char0 : char0 + Mid(s, 1); + } + public static String UpperFirst(String s) { + int len = Len(s); if (len == 0) return String_.Empty; + String char0 = Upper(Mid_lang(s, 0, 1)); + return len == 1 ? char0 : char0 + Mid(s, 1); + } + public static String PadBgn(String s, int totalLen, String pad) {return Pad(s, totalLen, pad, true);} + public static String PadEnd(String s, int totalLen, String pad) {return Pad(s, totalLen, pad, false);} + @gplx.Internal protected static String Pad(String s, int totalLen, String pad, boolean bgn) { + int sLen = Len(s); + int padLen = totalLen - sLen; if (padLen < 0) return s; + String_bldr sb = String_bldr_.new_(); + if (!bgn) sb.Add(s); + for (int i = 0; i < padLen; i++) + sb.Add(pad); + if (bgn) sb.Add(s); + return sb.XtoStr(); + } + public static String TrimEnd(String s) {if (s == null) return null; + int len = String_.Len(s); + if (len == 0) return s; + int last = len; + for (int i = len; i > 0; i--) { + char c = s.charAt(i - 1); + last = i; + if (c != ' ' && c != '\t' && c != '\r' && c != '\n') { + break; + } + } + return (last == len) ? s : Mid_lang(s, 0, last); + } + public static String Repeat(String s, int count) { + if (count < 0) throw Exc_.new_("count cannot be negative", "count", count, "s", s); + String_bldr sb = String_bldr_.new_(); + for (int i = 0; i < count; i++) + sb.Add(s); + return sb.XtoStr(); + } + public static String Insert(String s, int pos, String toInsert) { + if (pos < 0 || pos >= String_.Len(s)) throw Exc_.new_("String_.Insert failed; pos invalid", "pos", pos, "s", s, "toInsert", toInsert); + return s.substring(0, pos) + toInsert + s.substring(pos); + } + public static String Format(String fmt, Object... args) {return Format_do(fmt, args);} + public static String FormatOrEmptyStrIfNull(String fmt, Object arg) {return arg == null ? "" : Format(fmt, arg);} + public static String Concat(char... ary) {return new String(ary);} + public static String Concat(String s1, String s2, String s3) {return s1 + s2 + s3;} + public static String Concat(String... ary) { + String_bldr sb = String_bldr_.new_(); + for (String val : ary) + sb.Add(val); + return sb.XtoStr(); + } + public static String Concat_any(Object... ary) { + String_bldr sb = String_bldr_.new_(); + for (Object val : ary) + sb.Add_obj(val); + return sb.XtoStr(); + } + public static String ConcatWith_any(String separator, Object... ary) { + String_bldr sb = String_bldr_.new_(); + int aryLen = Array_.Len(ary); + for (int i = 0; i < aryLen; i++) { + if (i != 0) sb.Add(separator); + Object val = ary[i]; + sb.Add_obj(Object_.Xto_str_strict_or_empty(val)); + } + return sb.XtoStr(); + } + public static String Concat_with_str(String spr, String... ary) { + String_bldr sb = String_bldr_.new_(); + int len = ary.length; + for (int i = 0; i < len; i++) { + if (i != 0) sb.Add(spr); + sb.Add_obj(ary[i]); + } + return sb.XtoStr(); + } + public static String Concat_lines_crlf(String... values) { + String_bldr sb = String_bldr_.new_(); + for (String val : values) + sb.Add(val).Add(String_.CrLf); + return sb.XtoStr(); + } + public static String Concat_lines_crlf_skipLast(String... values) { + String_bldr sb = String_bldr_.new_(); + for (String val : values) { + if (sb.Count() != 0) sb.Add(String_.CrLf); + sb.Add(val); + } + return sb.XtoStr(); + } + public static String Concat_lines_nl(String... values) { + String_bldr sb = String_bldr_.new_(); + for (String val : values) + sb.Add(val).Add("\n"); + return sb.XtoStr(); + } + public static String Concat_lines_nl_skip_last(String... ary) { + String_bldr sb = String_bldr_.new_(); + int ary_len = ary.length; int ary_end = ary_len - 1; + for (int i = 0; i < ary_len; i++) { + sb.Add(ary[i]); + if (i != ary_end) sb.Add("\n"); + } + return sb.XtoStr(); + } + + public static String[] Ary(String... ary) {return ary;} + public static String[] Ary_wo_null(String... ary) { + List_adp list = List_adp_.new_(); + int len = ary.length; + for (int i = 0; i < len; ++i) { + String itm = ary[i]; + if (itm == null) continue; + list.Add(itm); + } + return list.To_str_ary(); + } + public static String AryXtoStr(String... ary) { + String_bldr sb = String_bldr_.new_(); + for (String s : ary) + sb.Add(s).Add(";"); + return sb.XtoStr(); + } + public static final String[] Ary_empty = new String[0]; + public static String[] Split(String raw, char dlm) {return Split(raw, dlm, false);} + public static String[] Split(String raw, char dlm, boolean addEmptyIfDlmIsLast) { + List_adp list = List_adp_.new_(); String_bldr sb = String_bldr_.new_(); + int rawLen = String_.Len(raw); char c = '\0'; + for (int i = 0; i < rawLen; i++) { + c = String_.CharAt(raw, i); + if (c == dlm) { + if (!addEmptyIfDlmIsLast && sb.Count() == 0 && i == rawLen - 1) {} + else list.Add(sb.Xto_str_and_clear()); + } + else + sb.Add(c); + } + if (sb.Count() > 0) + list.Add(sb.Xto_str_and_clear()); + return list.To_str_ary(); + } + public static String[] Split(String s, String separator) {return Split_do(s, separator, false);} + public static String[] SplitLines_crlf(String s) {return Split(s, Op_sys.Wnt.Nl_str());} + public static String[] SplitLines_nl(String s) {return Split(s, Op_sys.Lnx.Nl_str());} + public static String[] SplitLines_any(String s) {return Split_do(s, Op_sys.Lnx.Nl_str(), true);} + public static String[] Split_lang(String s, char c) {return s.split(Character.toString(c));} + + static String Format_do(String s, Object[] ary) { + int aryLength = Array_.LenAry(ary); if (aryLength == 0) return s; // nothing to format + String_bldr sb = String_bldr_.new_(); + char bracketBgn = '{', bracketEnd = '}'; + String aryVal = null; char c, next; + int pos = 0; int textLength = Len(s); String numberStr = ""; boolean bracketsOn = false; + while (true) { + if (pos == textLength) break; + c = CharAt(s, pos); + if (bracketsOn) { // mode=bracketsOn + if (c == bracketBgn) { // first bracketBgn is fake; add bracketBgn and whatever is in numberStr + sb.Add(bracketBgn).Add(numberStr); + numberStr = ""; + } + else if (c == bracketEnd) { + int aryIdx = Int_.parse_or_(numberStr, Int_.MinValue); + if (aryIdx != Int_.MinValue && Int_.Between(aryIdx, 0, aryLength - 1)) // check (a) aryIdx is num; (b) aryIdx is in bounds + aryVal = Object_.Xto_str_strict_or_empty(ary[aryIdx]); + else + aryVal = String_.Concat_any(bracketBgn, numberStr, bracketEnd); // not valid, just add String + sb.Add(aryVal); + bracketsOn = false; + numberStr = ""; + } + else // char=anythingElse + numberStr += c; + } + else { // mode=bracketsOff + if (c == bracketBgn || c == bracketEnd) { + boolean isEnd = pos == textLength - 1; + if (isEnd) + sb.Add(c); + else { + next = CharAt(s, pos + 1); + if (next == c) { // "{{" or "}}": escape by doubling + sb.Add(c); + pos++; + } + else + bracketsOn = true; + } + } + else // char=anythingElse + sb.Add(c); + } + pos++; + } + if (Len(numberStr) > 0) // unclosed bracket; add bracketBgn and whatever is in numberStr; ex: "{0" + sb.Add(bracketBgn).Add(numberStr); + return sb.XtoStr(); + } + static String[] Split_do(String s, String spr, boolean skipChar13) { + if (String_.Eq(s, "") // "".Split('a') return array with one member: "" + || String_.Eq(spr, "")) // "a".Split('\0') returns array with one member: "a" + return new String[] {s}; + List_adp list = List_adp_.new_(); String_bldr sb = String_bldr_.new_(); + int i = 0, sprPos = 0; boolean sprMatched = false; char spr0 = CharAt(spr, 0); + int textLength = Len(s); int sprLength = Len(spr); + while (true) { + if (sprMatched + || i == textLength) { // last pass; add whatever's in sb to list + list.Add(sb.Xto_str_and_clear()); + if (sprMatched && i == textLength) list.Add(""); // if s ends with spr and last pass, add emptyString as last + sprMatched = false; + } + if (i == textLength) break; + char c = CharAt(s, i); + if (skipChar13 && c == (char)13) {i++; continue;} + if (c == spr0) { // matches first char of spr + sprPos = 1; + while (true) { + if (sprPos == sprLength) { // made it to end, must be match + sprMatched = true; + break; + } + if (i + sprPos == textLength) break; // ran out of s; handles partial match at end of String; ab+, +- + if (CharAt(s, i + sprPos) != CharAt(spr, sprPos)) break; // no match + sprPos++; + } + if (!sprMatched) // add partial match to sb + sb.Add(Mid_lang(s, i, sprPos)); + i += sprPos; + } + else { // no spr match; just add char, increment pos + sb.Add(c); + i++; + } + } + return (String[])list.To_ary(String.class); + } + static String Mid_lang(String s, int bgn, int len) {return s.substring(bgn, bgn + len);} + public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) { + if (ctx.Match(k, Invk_Replace)) { + String s = m.ReadStr(GfsCore_.Arg_primitive), find = m.ReadStr("find"), replace = m.ReadStr("replace"); + if (ctx.Deny()) return this; + return Replace(s, find, replace); + } + else if (ctx.Match(k, Invk_Len)) { + String s = m.ReadStr(GfsCore_.Arg_primitive); + if (ctx.Deny()) return this; + return Len(s); + } + else if (ctx.Match(k, Invk_PadBgn)) { + String s = m.ReadStr(GfsCore_.Arg_primitive); int totalLen = m.ReadInt("totalLen"); String pad = m.ReadStr("pad"); + if (ctx.Deny()) return this; + return PadBgn(s, totalLen, pad); + } + else return GfoInvkAble_.Rv_unhandled; + } public static final String Invk_Replace = "Replace", Invk_Len = "Len", Invk_PadBgn = "PadBgn"; + public static final String_ Gfs = new String_(); + public static String Extract_after_bwd(String src, String dlm) { + int dlm_pos = String_.FindBwd(src, dlm); if (dlm_pos == String_.Find_none) return String_.Empty; + int src_len = String_.Len(src); if (dlm_pos == src_len - 1) return String_.Empty; + return String_.Mid(src, dlm_pos + 1, src_len); + } + public static String Replace_by_pos(String v, int del_bgn, int del_end, String repl) { + return String_.Mid(v, 0, del_bgn) + repl + String_.Mid(v, del_end, String_.Len(v)); + } + public static String read_(Object obj) {// NOTE: same as cast_; for consistent readability only + String rv = as_(obj); + if (rv == null && obj != null) throw Exc_.new_type_mismatch(String.class, obj); // NOTE: obj != null needed; EX: cast_(null) --> null + return rv; + } + public static String[] Ary(byte[]... ary) { + if (ary == null) return String_.Ary_empty; + int ary_len = ary.length; + String[] rv = new String[ary_len]; + for (int i = 0; i < ary_len; i++) + rv[i] = String_.new_u8(ary[i]); + return rv; + } + public static String [] Ary_filter(String[] src, String[] filter) { + Hash_adp hash = Hash_adp_.new_(); + int len = filter.length; + for (int i = 0; i < len; i++) { + String itm = filter[i]; + hash.Add_if_dupe_use_nth(itm, itm); + } + List_adp rv = List_adp_.new_(); + len = src.length; + for (int i = 0; i < len; i++) { + String itm = src[i]; + if (hash.Has(itm)) rv.Add(itm); + } + return rv.To_str_ary(); + } + public static String[] Ary_flatten(String[][] src_ary) { + int trg_len = 0; + int src_len = Array_.Len(src_ary); + for (int i = 0; i < src_len; i++) { + String[] itm = src_ary[i]; + if (itm != null) trg_len += Array_.Len(itm); + } + String[] trg_ary = new String[trg_len]; + trg_len = 0; + for (int i = 0; i < src_len; i++) { + String[] itm = src_ary[i]; + if (itm == null) continue; + int itm_len = Array_.Len(itm); + for (int j = 0; j < itm_len; j++) + trg_ary[trg_len++] = itm[j]; + } + return trg_ary; + } +} diff --git a/100_core/src_110_primitive/gplx/String__tst.java b/100_core/src_110_primitive/gplx/String__tst.java new file mode 100644 index 000000000..6abf77d36 --- /dev/null +++ b/100_core/src_110_primitive/gplx/String__tst.java @@ -0,0 +1,184 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class String__tst { + @Test public void Len() { + tst_Len("", 0); + tst_Len("abc", 3); + } void tst_Len(String v, int expd) {Tfds.Eq(expd, String_.Len(v), "Len");} + + @Test public void LimitToFirst() { + tst_LimitToFirst("abc", 0, ""); + tst_LimitToFirst("abc", 1, "a"); + tst_LimitToFirst("abc", 2, "ab"); + tst_LimitToFirst("abc", 3, "abc"); + tst_LimitToFirst("abc", 4, "abc"); + err_LimitToFirst("abc", -1); + } + void tst_LimitToFirst(String s, int v, String expd) {Tfds.Eq(expd, String_.LimitToFirst(s, v));} + void err_LimitToFirst(String s, int v) {try {String_.LimitToFirst(s, v);} catch (Exception exc) {Tfds.Err_classMatch(exc, Err_arg.class); return;} Tfds.Fail_expdError();} + @Test public void LimitToLast() { + tst_LimitToLast("abc", 0, ""); + tst_LimitToLast("abc", 1, "c"); + tst_LimitToLast("abc", 2, "bc"); + tst_LimitToLast("abc", 3, "abc"); + tst_LimitToLast("abc", 4, "abc"); + err_LimitToLast("abc", -1); + } + void tst_LimitToLast(String s, int v, String expd) {Tfds.Eq(expd, String_.LimitToLast(s, v));} + void err_LimitToLast(String s, int v) {try {String_.LimitToLast(s, v);} catch (Exception exc) {Tfds.Err_classMatch(exc, Err_arg.class); return;} Tfds.Fail_expdError();} + @Test public void DelBgn() { + tst_DelBgn("abc", 0, "abc"); + tst_DelBgn("abc", 1, "bc"); + tst_DelBgn("abc", 2, "c"); + tst_DelBgn("abc", 3, ""); + err_DelBgn(null, 0); + err_DelBgn("abc", 4); + } + void tst_DelBgn(String s, int v, String expd) {Tfds.Eq(expd, String_.DelBgn(s, v));} + void err_DelBgn(String s, int v) {try {String_.DelBgn(s, v);} catch (Exception exc) {Tfds.Err_classMatch(exc, Err_arg.class); return;} Tfds.Fail_expdError();} + @Test public void DelBgnIf() { + tst_DelBgnIf("abc", "", "abc"); + tst_DelBgnIf("abc", "a", "bc"); + tst_DelBgnIf("abc", "ab", "c"); + tst_DelBgnIf("abc", "abc", ""); + tst_DelBgnIf("abc", "abcd", "abc"); + tst_DelBgnIf("abc", "bcd", "abc"); + err_DelBgnIf(null, "abc"); + err_DelBgnIf("abc", null); + } + void tst_DelBgnIf(String s, String v, String expd) {Tfds.Eq(expd, String_.DelBgnIf(s, v));} + void err_DelBgnIf(String s, String v) {try {String_.DelBgnIf(s, v);} catch (Exception exc) {Tfds.Err_classMatch(exc, Err_arg.class); return;} Tfds.Fail_expdError();} + @Test public void DelEnd() { + tst_DelEnd("abc", 0, "abc"); + tst_DelEnd("abc", 1, "ab"); + tst_DelEnd("abc", 2, "a"); + tst_DelEnd("abc", 3, ""); + err_DelEnd(null, 0); + err_DelEnd("abc", 4); + } + void tst_DelEnd(String s, int v, String expd) {Tfds.Eq(expd, String_.DelEnd(s, v));} + void err_DelEnd(String s, int v) {try {String_.DelEnd(s, v);} catch (Exception exc) {Tfds.Err_classMatch(exc, Err_arg.class); return;} Tfds.Fail_expdError();} + @Test public void DelEndIf() { + tst_DelEndIf("abc", "", "abc"); + tst_DelEndIf("abc", "c", "ab"); + tst_DelEndIf("abc", "bc", "a"); + tst_DelEndIf("abc", "abc", ""); + tst_DelEndIf("abc", "abcd", "abc"); + tst_DelEndIf("abc", "ab", "abc"); + err_DelEndIf(null, ""); + err_DelEndIf("", null); + } + void tst_DelEndIf(String s, String v, String expd) {Tfds.Eq(expd, String_.DelEndIf(s, v));} + void err_DelEndIf(String s, String v) {try {String_.DelEndIf(s, v);} catch (Exception exc) {Tfds.Err_classMatch(exc, Err_arg.class); return;} Tfds.Fail_expdError();} + @Test public void MidByPos() { + tst_MidByPos("abc", 0, 0, ""); + tst_MidByPos("abc", 0, 1, "a"); + tst_MidByPos("abc", 0, 2, "ab"); + tst_MidByPos("abc", 0, 3, "abc"); + tst_MidByPos("abc", 2, 3, "c"); + err_MidByPos("abc", 1, 5); +// err_MidByPos("abc", 0, 4); + } + void tst_MidByPos(String s, int bgn, int end, String expd) {Tfds.Eq(expd, String_.Mid(s, bgn, end));} + void err_MidByPos(String s, int bgn, int end) {try {String_.Mid(s, bgn, end);} catch (Exception e) {Tfds.Err_classMatch(e, Exc.class); return;} Tfds.Fail_expdError();} + @Test public void TrimEnd() { + tst_TrimEnd("a", "a"); + tst_TrimEnd("a ", "a"); + tst_TrimEnd("a\t", "a"); + tst_TrimEnd("a\n", "a"); + tst_TrimEnd("a\r", "a"); + tst_TrimEnd("a\r\n \t", "a"); + tst_TrimEnd(" a", " a"); + tst_TrimEnd(null, null); + } + void tst_TrimEnd(String s, String expd) {Tfds.Eq(expd, String_.TrimEnd(s));} + + @Test public void Count() { + String text = "0 0 0"; + Tfds.Eq(3, String_.Count(text, "0")); + } + @Test public void Has() { + String text = "find word"; + Tfds.Eq_true(String_.Has(text, "word")); + Tfds.Eq_false(String_.Has(text, "nothing")); + } + @Test public void Repeat() { + Tfds.Eq("333", String_.Repeat("3", 3)); + } + @Test public void Format() { + tst_Format("", ""); // empty + tst_Format("no args", "no args"); // no args + tst_Format("0", "{0}", 0); // one + tst_Format("0 and 1", "{0} and {1}", 0, 1); // many + tst_Format("{", "{{", 0); // escape bracketBgn + tst_Format("}", "}}", 0); // escape bracketEnd + tst_Format("{a0c}", "{a{0}c}", 0); // nested; + tst_Format("{a{b}c}", "{a{b}c}", 0); // invalid invalid + tst_Format("{1}", "{1}", 1); // invalid array index + tst_Format("{a} {b}", "{a} {b}", 0); // invalid many + tst_Format("{a}0{b}1", "{a}{0}{b}{1}", 0, 1); // invalid and valid + tst_Format("{0", "{0", 0); // invalid dangling + } void tst_Format(String expd, String fmt, Object... ary) {Tfds.Eq(expd, String_.Format(fmt, ary));} + @Test public void Split() { + tst_Split("ab", " ", "ab"); // no match -> return array with original input + tst_Split("ab cd", " ", "ab", "cd"); // separator.length = 1 + tst_Split("ab+!cd", "+!", "ab", "cd"); // separator.length = 2 + tst_Split("ab+!cd+!ef", "+!", "ab", "cd", "ef"); // terms = 3 + tst_Split("ab+!cd+!", "+!", "ab", "cd", ""); // closing separator + tst_Split("+!ab", "+!", "", "ab"); // opening separator + tst_Split("ab+cd+!ef", "+!", "ab+cd", "ef"); // ignore partial matches + tst_Split("ab+!cd+", "+!", "ab", "cd+"); // ignore partial matches; end of String + + // boundary + tst_Split("ab", "", "ab"); // separator.length = 0 -> return array with input as only member + tst_Split("", " ", ""); // empty input -> return array with empty input + + // acceptance + tst_Split("this\r\nis\na\rtest\r\n.", "\r\n", "this", "is\na\rtest", "."); + } void tst_Split(String text, String separator, String... expd) {Tfds.Eq_ary(expd, String_.Split(text, separator));} + @Test public void ConcatWith_any() { + tst_ConcatWith_any("a|b", "|", "a", "b"); // do not append final delimiter + tst_ConcatWith_any("a||c", "|", "a", null, "c"); // null + tst_ConcatWith_any("a|b", "|", Object_.Ary("a", "b")); // pass array as arg + } void tst_ConcatWith_any(String expd, String delimiter, Object... array) {Tfds.Eq(expd, String_.ConcatWith_any(delimiter, array));} + @Test public void Compare_byteAry() { + tst_Compare_byteAry("a", "a", CompareAble_.Same); + tst_Compare_byteAry("a", "b", CompareAble_.Less); + tst_Compare_byteAry("b", "a", CompareAble_.More); + tst_Compare_byteAry("ab", "ac", CompareAble_.Less); + tst_Compare_byteAry("ac", "ab", CompareAble_.More); + tst_Compare_byteAry("a", "ab", CompareAble_.Less); + tst_Compare_byteAry("ab", "a", CompareAble_.More); + tst_Compare_byteAry("101", "1-0-1", CompareAble_.More); // NOTE: regular String_.Compare returns Less in .NET, More in Java + tst_Compare_byteAry("1-0-1", "101 (album)", CompareAble_.Less); + } void tst_Compare_byteAry(String lhs, String rhs, int expd) {Tfds.Eq(expd, String_.Compare_byteAry(lhs, rhs));} + @Test public void FindBwd() { // WORKAROUND.CS:String.LastIndexOf returns -1 for multi-chars; + tst_FindRev("abc", "a", 0, 0); + tst_FindRev("abc", "ab", 0, 0); // 2 chars + tst_FindRev("abc", "abc", 0, 0); // 3 chars + tst_FindRev("ab", "abc", 0, -1); // out of index error + tst_FindRev("ababab", "ab", 2, 2); // make sure cs implementation doesn't pick up next + } void tst_FindRev(String s, String find, int pos, int expd) {Tfds.Eq(expd, String_.FindBwd(s, find, pos));} + @Test public void Extract_after_bwd() { + Extract_after_bwd_tst("a/b", "/", "b"); + Extract_after_bwd_tst("a/", "/", ""); + Extract_after_bwd_tst("a", "/", ""); + } void Extract_after_bwd_tst(String src, String dlm, String expd) {Tfds.Eq(expd, String_.Extract_after_bwd(src, dlm));} +} diff --git a/100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_ary_dim2.java b/100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_ary_dim2.java new file mode 100644 index 000000000..162684012 --- /dev/null +++ b/100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_ary_dim2.java @@ -0,0 +1,27 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.brys; import gplx.*; +public class Bry_fmtr_arg_ary_dim2 implements Bry_fmtr_arg { + public Bry_fmtr_arg_ary_dim2 Data_(byte[][] v) {ary_dim2 = v; return this;} + public Bry_fmtr_arg_ary_dim2 Ary_dim2_(byte[][] v) {this.ary_dim2 = v; return this;} + public void XferAry(Bry_bfr trg, int idx) { + for (byte[] ary : ary_dim2) + trg.Add(ary); + } + public Bry_fmtr_arg_ary_dim2() {} byte[][] ary_dim2 = new byte[0][]; +} diff --git a/100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_bfr.java b/100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_bfr.java new file mode 100644 index 000000000..1e5126984 --- /dev/null +++ b/100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_bfr.java @@ -0,0 +1,23 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.brys; import gplx.*; +public class Bry_fmtr_arg_bfr implements Bry_fmtr_arg { + public Bry_fmtr_arg_bfr Data_(Bry_bfr v) {bfr = v; return this;} + public void XferAry(Bry_bfr trg, int idx) {trg.Add_bfr_and_clear(bfr);} + public Bry_fmtr_arg_bfr(Bry_bfr bfr) {this.bfr = bfr;} Bry_bfr bfr; +} diff --git a/100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_bfr_preserve.java b/100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_bfr_preserve.java new file mode 100644 index 000000000..162036ba3 --- /dev/null +++ b/100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_bfr_preserve.java @@ -0,0 +1,23 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.brys; import gplx.*; +public class Bry_fmtr_arg_bfr_preserve implements Bry_fmtr_arg { + public Bry_fmtr_arg_bfr_preserve Data_(Bry_bfr v) {bfr = v; return this;} + public void XferAry(Bry_bfr trg, int idx) {trg.Add_bfr_and_preserve(bfr);} + public Bry_fmtr_arg_bfr_preserve(Bry_bfr bfr) {this.bfr = bfr;} Bry_bfr bfr; +} diff --git a/100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_bry.java b/100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_bry.java new file mode 100644 index 000000000..e3e6e077e --- /dev/null +++ b/100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_bry.java @@ -0,0 +1,23 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.brys; import gplx.*; +public class Bry_fmtr_arg_bry implements Bry_fmtr_arg { + public Bry_fmtr_arg_bry Data_(byte[] v) {ary = v; return this;} + public void XferAry(Bry_bfr trg, int idx) {trg.Add(ary);} + public Bry_fmtr_arg_bry(byte[] v) {this.ary = v;} byte[] ary; +} diff --git a/100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_byt.java b/100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_byt.java new file mode 100644 index 000000000..0b5124d70 --- /dev/null +++ b/100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_byt.java @@ -0,0 +1,23 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.brys; import gplx.*; +public class Bry_fmtr_arg_byt implements Bry_fmtr_arg { + public Bry_fmtr_arg_byt Data_(byte v) {byt = v; return this;} + public void XferAry(Bry_bfr trg, int idx) {trg.Add_byte(byt);} + public Bry_fmtr_arg_byt(byte byt) {this.byt = byt;} private byte byt; +} diff --git a/100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_decimal_int.java b/100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_decimal_int.java new file mode 100644 index 000000000..bf38773ce --- /dev/null +++ b/100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_decimal_int.java @@ -0,0 +1,25 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.brys; import gplx.*; +public class Bry_fmtr_arg_decimal_int implements Bry_fmtr_arg { + public int Val() {return val;} public Bry_fmtr_arg_decimal_int Val_(int v) {val = v; return this;} int val; + public Bry_fmtr_arg_decimal_int Places_(int v) {places = v; multiple = (int)Math_.Pow(10, v); return this;} int multiple = 1000, places = 3; + public void XferAry(Bry_bfr bfr, int idx) { + bfr.Add_int_variable(val / multiple).Add_byte(Byte_ascii.Dot).Add_int_fixed(val % multiple, places); + } +} diff --git a/100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_fmtr.java b/100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_fmtr.java new file mode 100644 index 000000000..d5ff31db0 --- /dev/null +++ b/100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_fmtr.java @@ -0,0 +1,25 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.brys; import gplx.*; +public class Bry_fmtr_arg_fmtr implements Bry_fmtr_arg { + public Bry_fmtr_arg_fmtr Data_(Bry_fmtr v) {fmtr = v; return this;} + public void XferAry(Bry_bfr trg, int idx) { + fmtr.Bld_bfr(trg, arg_ary); + } + public Bry_fmtr_arg_fmtr(Bry_fmtr fmtr, Bry_fmtr_arg... arg_ary) {this.fmtr = fmtr; this.arg_ary = arg_ary;} Bry_fmtr fmtr; Bry_fmtr_arg[] arg_ary; +} diff --git a/100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_int.java b/100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_int.java new file mode 100644 index 000000000..9c8bcc597 --- /dev/null +++ b/100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_int.java @@ -0,0 +1,23 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.brys; import gplx.*; +public class Bry_fmtr_arg_int implements Bry_fmtr_arg { + public Bry_fmtr_arg_int Data_(int v) {val = Int_.cast_(v); val_digits = Int_.DigitCount(val); return this;} + public void XferAry(Bry_bfr trg, int idx) {trg.Add_int_fixed(val, val_digits);} + public Bry_fmtr_arg_int(int v) {this.val = v; this.val_digits = Int_.DigitCount(v);} int val, val_digits; +} diff --git a/100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_time.java b/100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_time.java new file mode 100644 index 000000000..d32d51d10 --- /dev/null +++ b/100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_time.java @@ -0,0 +1,55 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.brys; import gplx.*; +public class Bry_fmtr_arg_time implements Bry_fmtr_arg { + public Bry_fmtr_arg_time() { + units_len = units.length; + } + public long Seconds() {return seconds;} public Bry_fmtr_arg_time Seconds_(long v) {seconds = v; return this;} long seconds; + byte[][] segs = new byte[][] + { Bry_.new_a7("d") + , Bry_.new_a7("h") + , Bry_.new_a7("m") + , Bry_.new_a7("s") + }; + int[] units = new int[] {86400, 3600, 60, 1}; + int units_len; + byte[] spr = new byte[] {Byte_ascii.Space}; + public void XferAry(Bry_bfr bfr, int idx) { + if (seconds == 0) { // handle 0 separately (since it will always be < than units[*] + bfr.Add_int_fixed(0, 2).Add(segs[units_len - 1]); + return; + } + long val = seconds; + boolean dirty = false; + for (int i = 0; i < units_len; i++) { + long unit = units[i]; + long seg = 0; + if (val >= unit) { // unit has value; EX: 87000 > 86400, so unit is 1 day + seg = val / unit; + val = val - (seg * unit); + } + if (seg > 0 || dirty) { // dirty check allows for 0 in middle units (EX: 1h 0m 1s) + if (dirty) bfr.Add(spr); + if (seg < 10) bfr.Add_byte(Byte_ascii.Num_0); // 0 pad + bfr.Add_long_variable(seg).Add(segs[i]); + dirty = true; + } + } + } +} diff --git a/100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_time_tst.java b/100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_time_tst.java new file mode 100644 index 000000000..78679709b --- /dev/null +++ b/100_core/src_110_primitive/gplx/brys/Bry_fmtr_arg_time_tst.java @@ -0,0 +1,42 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.brys; import gplx.*; +import org.junit.*; +public class Bry_fmtr_arg_time_tst { + @Test public void Basic() { + Time_fmtr_arg_fxt fxt = new Time_fmtr_arg_fxt().Clear(); + fxt.XferAry( 1, "01s"); // seconds + fxt.XferAry( 62, "01m 02s"); // minutes + fxt.XferAry( 3723, "01h 02m 03s"); // hours + fxt.XferAry( 93784, "01d 02h 03m 04s"); // days + fxt.XferAry( 0, "00s"); // handle 0 seconds + fxt.XferAry( 3601, "01h 00m 01s"); // handle 0 in middle unit + } +} +class Time_fmtr_arg_fxt { + public Time_fmtr_arg_fxt Clear() { + if (arg == null) arg = new Bry_fmtr_arg_time(); + return this; + } Bry_fmtr_arg_time arg; + public void XferAry(int seconds, String expd) { + Bry_bfr bfr = Bry_bfr.reset_(255); + arg.Seconds_(seconds); + arg.XferAry(bfr, 0); + Tfds.Eq(expd, bfr.Xto_str()); + } +} diff --git a/100_core/src_120_basicDataType/gplx/DateAdp.java b/100_core/src_120_basicDataType/gplx/DateAdp.java new file mode 100644 index 000000000..cce54ffb7 --- /dev/null +++ b/100_core/src_120_basicDataType/gplx/DateAdp.java @@ -0,0 +1,152 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.TimeZone; +import java.text.SimpleDateFormat; +public class DateAdp implements CompareAble, GfoInvkAble { + public int compareTo(Object obj) {DateAdp comp = (DateAdp)obj; return under.compareTo(comp.under);} + @Override public String toString() {return XtoStr_gplx_long();} + public String XtoStr_gplx() {return XtoStr_fmt("yyyyMMdd_HHmmss.fff");} + public String XtoStr_gplx_long() {return XtoStr_fmt("yyyy-MM-dd HH:mm:ss.fff");} + public String XtoStr_fmt_HHmmss() {return XtoStr_fmt("HH:mm:ss");} + public String XtoStr_fmt_HHmm() {return XtoStr_fmt("HH:mm");} + public String XtoStr_fmt_yyyy_MM_dd() {return XtoStr_fmt("yyyy-MM-dd");} + public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) { + if (ctx.Match(k, Invk_XtoStr_fmt)) return XtoStr_fmt("yyyy-MM-dd HH:mm:ss"); + else if (ctx.Match(k, Invk_AddDays)) { + int days = m.ReadInt("days"); + if (ctx.Deny()) return this; + return this.Add_day(days); + } + else return GfoInvkAble_.Rv_unhandled; + } public static final String Invk_XtoStr_fmt = "XtoStr_fmt", Invk_AddDays = "Add_day"; + public int Segment(int segmentIdx) { + switch (segmentIdx) { + case DateAdp_.SegIdx_year: return this.Year(); + case DateAdp_.SegIdx_month: return this.Month(); + case DateAdp_.SegIdx_day: return this.Day(); + case DateAdp_.SegIdx_hour: return this.Hour(); + case DateAdp_.SegIdx_minute: return this.Minute(); + case DateAdp_.SegIdx_second: return this.Second(); + case DateAdp_.SegIdx_frac: return this.Frac(); + case DateAdp_.SegIdx_dayOfWeek: return this.DayOfWeek(); + case DateAdp_.SegIdx_weekOfYear: return this.WeekOfYear(); + case DateAdp_.SegIdx_dayOfYear: return this.DayOfYear(); + default: throw Exc_.new_unhandled(segmentIdx); + } + } + public int[] XtoSegAry() { + int[] rv = new int[7]; + rv[DateAdp_.SegIdx_year] = this.Year(); + rv[DateAdp_.SegIdx_month] = this.Month(); + rv[DateAdp_.SegIdx_day] = this.Day(); + rv[DateAdp_.SegIdx_hour] = this.Hour(); + rv[DateAdp_.SegIdx_minute] = this.Minute(); + rv[DateAdp_.SegIdx_second] = this.Second(); + rv[DateAdp_.SegIdx_frac] = this.Frac(); + return rv; + } + public String XtoStr_fmt_yyyyMMdd_HHmmss() {return XtoStr_fmt("yyyyMMdd_HHmmss");} + public String XtoStr_fmt_yyyyMMdd_HHmmss_fff() {return XtoStr_fmt("yyyyMMdd_HHmmss.fff");} + public String XtoStr_fmt_yyyyMMdd_HHmm() {return XtoStr_fmt("yyyyMMdd_HHmm");} + public String XtoStr_fmt_yyyy_MM_dd_HH_mm() {return XtoStr_fmt("yyyy-MM-dd HH:mm");} + public String XtoStr_fmt_yyyy_MM_dd_HH_mm_ss() {return XtoStr_fmt("yyyy-MM-dd HH:mm:ss");} + public String XtoStr_fmt_iso_8561() {return XtoStr_fmt("yyyy-MM-dd HH:mm:ss");} + public static int Timezone_offset_test = Int_.MinValue; + public Calendar UnderDateTime() {return under;} Calendar under; + public int Year() {return under.get(Calendar.YEAR);} + public int Month() {return under.get(Calendar.MONTH) + Month_base0adj;} + public int Day() {return under.get(Calendar.DAY_OF_MONTH);} + public int Hour() {return under.get(Calendar.HOUR_OF_DAY);} + public int Minute() {return under.get(Calendar.MINUTE);} + public int Second() {return under.get(Calendar.SECOND);} + public int DayOfWeek() {return under.get(Calendar.DAY_OF_WEEK) - 1;} // -1 : Base0; NOTE: dotnet/php is also Sunday=0 + public int DayOfYear() {return under.get(Calendar.DAY_OF_YEAR);} + public int Timezone_offset() { + return Timezone_offset_test == Int_.MinValue // Timezone_offset_test not over-ridden + ? 0 + // ? under.getTimeZone().getOffset(this.Timestamp_unix()) / 1000 // divide by 1000 to convert from ms to seconds + : Timezone_offset_test + ; + } + public DateAdp XtoUtc() { + java.util.Date date = under.getTime(); + java.util.TimeZone tz = under.getTimeZone(); + long msFromEpochGmt = date.getTime(); + int offsetFromUTC = tz.getOffset(msFromEpochGmt); + Calendar gmtCal = Calendar.getInstance(); + gmtCal.setTimeInMillis(msFromEpochGmt + -offsetFromUTC); + return new DateAdp(gmtCal); + } + public DateAdp XtoLocal() { + java.util.Date date = under.getTime(); + java.util.TimeZone tz = under.getTimeZone(); + long msFromEpochGmt = date.getTime(); + int offsetFromUTC = tz.getOffset(msFromEpochGmt); + Calendar gmtCal = Calendar.getInstance(); + gmtCal.setTimeInMillis(msFromEpochGmt + offsetFromUTC); + return new DateAdp(gmtCal); + } + public long Timestamp_unix() { + long offsetFromUTC = (under.getTimeZone().getOffset(0)); + boolean dst = TimeZone.getDefault().inDaylightTime(under.getTime()); + long dst_adj = dst ? 3600000 : 0; + return (under.getTimeInMillis() + offsetFromUTC + dst_adj) / 1000; + } + public int WeekOfYear() {return under.get(Calendar.WEEK_OF_YEAR);} + public int Frac() {return under.get(Calendar.MILLISECOND);} + public DateAdp Add_frac(int val) {return CloneAndAdd(Calendar.MILLISECOND, val);} + public DateAdp Add_second(int val) {return CloneAndAdd(Calendar.SECOND, val);} + public DateAdp Add_minute(int val) {return CloneAndAdd(Calendar.MINUTE, val);} + public DateAdp Add_hour(int val) {return CloneAndAdd(Calendar.HOUR, val);} + public DateAdp Add_day(int val) {return CloneAndAdd(Calendar.DAY_OF_MONTH, val);} + public DateAdp Add_month(int val) {return CloneAndAdd(Calendar.MONTH, val);} + public DateAdp Add_year(int val) {return CloneAndAdd(Calendar.YEAR, val);} + DateAdp CloneAndAdd(int field, int val) { + Calendar clone = (Calendar)under.clone(); + clone.add(field, val); + return new DateAdp(clone); + } + public String XtoStr_fmt(String fmt) { + fmt = fmt.replace("f", "S"); + SimpleDateFormat sdf = new SimpleDateFormat(fmt); + return sdf.format(under.getTime()); + } + public String XtoStr_tz() { + SimpleDateFormat sdf = new SimpleDateFormat("Z"); + String time_zone = sdf.format(under.getTime()); + return String_.Mid(time_zone, 0, 3) + ":" + String_.Mid(time_zone, 3, String_.Len(time_zone)); + } + public boolean Eq(DateAdp v) {DateAdp comp = v; return Object_.Eq(under.getTimeInMillis(), comp.under.getTimeInMillis());} + public int Diff_days(DateAdp prev) { + long diff = this.under.getTimeInMillis() - prev.under.getTimeInMillis(); + return (int)(diff / (1000 * 60 * 60 * 24)); + } + public TimeSpanAdp Diff(DateAdp earlier) { + long diff = this.under.getTimeInMillis() - earlier.under.getTimeInMillis(); + return TimeSpanAdp_.fracs_(diff); + } + protected DateAdp(Calendar under) {this.under = under;} + protected DateAdp(int year, int month, int day, int hour, int minute, int second, int frac) { + this.under = new GregorianCalendar(year, month - Month_base0adj, day, hour, minute, second); + under.set(Calendar.MILLISECOND, frac); + } + public static final int Month_base0adj = 1; + } diff --git a/100_core/src_120_basicDataType/gplx/DateAdp_.java b/100_core/src_120_basicDataType/gplx/DateAdp_.java new file mode 100644 index 000000000..6f3ff6f94 --- /dev/null +++ b/100_core/src_120_basicDataType/gplx/DateAdp_.java @@ -0,0 +1,119 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import java.sql.Timestamp; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.Locale; +import java.util.TimeZone; +public class DateAdp_ implements GfoInvkAble { + public static final String Cls_ref_name = "Date"; + public static final Class Cls_ref_type = DateAdp.class; + public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) { + if (ctx.Match(k, Invk_Now)) return Now(); + else return GfoInvkAble_.Rv_unhandled; + } public static final String Invk_Now = "Now"; + public static final DateAdp MinValue = new DateAdp( 1, 1, 1, 0, 0, 0, 0); + public static final DateAdp MaxValue = new DateAdp(9999, 12, 31, 23, 59, 59, 999); + public static DateAdp Now() {return Tfds.Now_enabled() ? Tfds.Now() : new DateAdp(new GregorianCalendar());} + public static DateAdp new_(int year, int month, int day, int hour, int minute, int second, int frac) {return new DateAdp(year, month, day, hour, minute, second, frac);} + public static DateAdp seg_(int[] ary) { + int ary_len = ary.length; + int y = ary_len > 0 ? ary[0] : 1; + int M = ary_len > 1 ? ary[1] : 1; + int d = ary_len > 2 ? ary[2] : 1; + int h = ary_len > 3 ? ary[3] : 0; + int m = ary_len > 4 ? ary[4] : 0; + int s = ary_len > 5 ? ary[5] : 0; + int f = ary_len > 6 ? ary[6] : 0; + return new DateAdp(y, M, d, h, m, s, f); + } + public static DateAdp cast_(Object arg) {try {return (DateAdp)arg;} catch(Exception exc) {throw Exc_.new_type_mismatch_w_exc(exc, DateAdp.class, arg);}} + public static DateAdp parse_iso8561_or(String raw, DateAdp or) { + try {return parse_iso8561(raw);} + catch (Exception e) {Exc_.Noop(e); return or;} + } + public static DateAdp parse_iso8561(String raw) { // NOTE: for now, same as parse_gplx + int[] ary = date_parser.Parse_iso8651_like(raw); + if (ary[1] < 1 || ary[1] > 12) return DateAdp_.MinValue; // guard against invalid month + if (ary[2] < 1 || ary[2] > 31) return DateAdp_.MinValue; + return new DateAdp(ary[0], ary[1], ary[2], ary[3], ary[4], ary[5], ary[6]); + } + public static DateAdp parse_gplx(String raw) { + int[] ary = date_parser.Parse_iso8651_like(raw); + if (ary[1] < 1 || ary[1] > 12) return DateAdp_.MinValue; // guard against invalid month + if (ary[2] < 1 || ary[2] > 31) return DateAdp_.MinValue; + return new DateAdp(ary[0], ary[1], ary[2], ary[3], ary[4], ary[5], ary[6]); + } static DateAdp_parser date_parser = DateAdp_parser.new_(); + public static DateAdp dateTime_(GregorianCalendar v) {return new DateAdp(v);} + public static DateAdp dateTime_obj_(Object v) {return new DateAdp((GregorianCalendar)v);} + public static final DateAdp_ Gfs = new DateAdp_(); + + public static int DaysInMonth(DateAdp date) { + int rv = DaysInMonth_ary[date.Month() - Int_.Base1]; + if (rv == 28 && IsLeapYear(date.Year())) rv = 29; + return rv; + } static int [] DaysInMonth_ary = {31,28,31,30,31,30,31,31,30,31,30,31}; + public static boolean IsLeapYear(int year) { + if (year % 4 != 0) return false; + else if (year % 400 == 0) return true; + else if (year % 100 == 0) return false; + else return true; + } + public static DateAdp unixtime_utc_seconds_(long v) {return unixtime_utc_ms_(v * 1000);} + public static DateAdp db_(Object v) { + Timestamp ts = (Timestamp)v; + Calendar gc = Calendar.getInstance(); + gc.setTimeInMillis(ts.getTime()); + return new DateAdp(gc); + } + public static DateAdp parse_(String raw) { + SimpleDateFormat sdf = new SimpleDateFormat(); + Date d = null; + try {d = sdf.parse(raw);} + catch (ParseException e) {throw Exc_.new_w_type("parse", "failed to parse to DateAdp", "raw", raw);} + GregorianCalendar cal = (GregorianCalendar)Calendar.getInstance(); + cal.setTime(d); + return dateTime_(cal); + } + public static DateAdp parse_fmt(String raw, String fmt) { + fmt = fmt.replace('t', 'a'); // AM/PM + fmt = fmt.replace('f', 'S'); // milliseconds + SimpleDateFormat sdf = new SimpleDateFormat(fmt, Locale.US); + Date d = null; + try {d = sdf.parse(raw);} + catch (ParseException e) {throw Exc_.new_w_type("parse", "failed to parse to DateAdp", "raw", raw, "fmt", fmt);} + GregorianCalendar cal = (GregorianCalendar)Calendar.getInstance(); + cal.setTime(d); + return dateTime_(cal); + } + public static DateAdp unixtime_utc_ms_(long v) {return unixtime_lcl_ms_(v).XtoUtc();} + public static DateAdp unixtime_lcl_ms_(long v) { + GregorianCalendar c = new GregorianCalendar(); + c.setTimeInMillis(v); + return new DateAdp(c); + } + public static final int SegIdx_year = 0, SegIdx_month = 1, SegIdx_day = 2, SegIdx_hour = 3, SegIdx_minute = 4, SegIdx_second = 5, SegIdx_frac = 6, SegIdx_dayOfWeek = 7, SegIdx_weekOfYear = 8, SegIdx_dayOfYear = 9, SegIdx__max = 10; + public static final String Fmt_iso8561_date_time = "yyyy-MM-dd HH:mm:ss"; + public static String Xto_str_fmt_or(DateAdp v, String fmt, String or) { + return v == null ? or : v.XtoStr_fmt(fmt); + } +} diff --git a/100_core/src_120_basicDataType/gplx/DateAdp__tst.java b/100_core/src_120_basicDataType/gplx/DateAdp__tst.java new file mode 100644 index 000000000..450292045 --- /dev/null +++ b/100_core/src_120_basicDataType/gplx/DateAdp__tst.java @@ -0,0 +1,68 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class DateAdp__tst { + @Test public void Parse_gplx() { + tst_Parse_gplx("99991231_235959.999", "99991231_235959.999"); + tst_Parse_gplx("20090430_213200.123", "20090430_213200.123"); + tst_Parse_gplx("20090430_213200" , "20090430_213200.000"); + tst_Parse_gplx("20090430" , "20090430_000000.000"); + } + @Test public void Parse_separators() { + tst_Parse_gplx("2009-04-30 21:32:00.123", "20090430_213200.123"); + tst_Parse_gplx("2009-04-30 21:32:00" , "20090430_213200.000"); + tst_Parse_gplx("2009-04-30" , "20090430_000000.000"); + } + @Test public void DayOfWeek() { + tst_DayOfWeek("2012-01-18", 3); //3=Wed + } void tst_DayOfWeek(String raw, int expd) {Tfds.Eq(expd, DateAdp_.parse_gplx(raw).DayOfWeek());} + @Test public void WeekOfYear() { + tst_WeekOfYear("2006-02-01", 5); // 1-1:Sun;2-1:Wed + tst_WeekOfYear("2007-02-01", 5); // 1-1:Mon;2-1:Thu + tst_WeekOfYear("2008-02-01", 5); // 1-1:Tue;2-1:Fri + tst_WeekOfYear("2009-02-01", 6); // 1-1:Thu;2-1:Sun + tst_WeekOfYear("2010-02-01", 6); // 1-1:Fri;2-1:Mon + tst_WeekOfYear("2011-02-01", 6); // 1-1:Sat;2-1:Tue + } void tst_WeekOfYear(String raw, int expd) {Tfds.Eq(expd, DateAdp_.parse_gplx(raw).WeekOfYear());} + @Test public void DayOfYear() { + tst_DayOfYear("2012-01-01", 1); + tst_DayOfYear("2012-02-29", 60); + tst_DayOfYear("2012-12-31", 366); + } void tst_DayOfYear(String raw, int expd) {Tfds.Eq(expd, DateAdp_.parse_gplx(raw).DayOfYear());} + @Test public void Timestamp_unix() { + tst_Timestamp_unix("1970-01-01 00:00:00", 0); + tst_Timestamp_unix("2012-01-01 00:00:00", 1325376000); + } void tst_Timestamp_unix(String raw, long expd) {Tfds.Eq(expd, DateAdp_.parse_gplx(raw).Timestamp_unix());} + @Test public void DaysInMonth() { + tst_DaysInMonth("2012-01-01", 31); + tst_DaysInMonth("2012-02-01", 29); + tst_DaysInMonth("2012-04-01", 30); + tst_DaysInMonth("2011-02-01", 28); + } void tst_DaysInMonth(String raw, int expd) {Tfds.Eq(expd, DateAdp_.DaysInMonth(DateAdp_.parse_gplx(raw)));} + @Test public void XtoUtc() { + tst_XtoUtc("2012-01-01 00:00", "2012-01-01 05:00"); //4=Wed + } void tst_XtoUtc(String raw, String expd) {Tfds.Eq(expd, DateAdp_.parse_gplx(raw).XtoUtc().XtoStr_fmt_yyyy_MM_dd_HH_mm());} + + void tst_Parse_gplx(String raw, String expd) { + DateAdp date = DateAdp_.parse_gplx(raw); + String actl = date.XtoStr_gplx(); + Tfds.Eq(expd, actl); + } + DateAdp_parser bldr = DateAdp_parser.new_(); +} diff --git a/100_core/src_120_basicDataType/gplx/DateAdp_parser.java b/100_core/src_120_basicDataType/gplx/DateAdp_parser.java new file mode 100644 index 000000000..84c602b9e --- /dev/null +++ b/100_core/src_120_basicDataType/gplx/DateAdp_parser.java @@ -0,0 +1,120 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class DateAdp_parser { + public int[] Parse_iso8651_like(String raw_str) {Parse_iso8651_like(tmp_rv, raw_str); return tmp_rv;} int[] tmp_rv = new int[7]; + public void Parse_iso8651_like(int[] rv, String raw_str) { + byte[] raw_bry = Bry_.new_u8(raw_str); + Parse_iso8651_like(rv, raw_bry, 0, raw_bry.length); + } + public void Parse_iso8651_like(int[] rv, byte[] src, int bgn, int end) { + /* 1981-04-05T14:30:30.000-05:00 ISO 8601: http://en.wikipedia.org/wiki/ISO_8601 + 1981.04.05 14.30.30.000-05.00 ISO 8601 loose + 99991231_235959.999 gplx + yyyy-MM-ddTHH:mm:ss.fffzzzz Format String */ + int rv_len = rv.length; + for (int i = 0; i < rv_len; i++) + rv[i] = 0; // .Clear + int pos = bgn, rv_idx = 0, int_len = 0, max_len = max_lens[rv_idx]; + while (true) { + int int_val = -1; + byte b = pos < end ? src[pos] : Byte_ascii.Nil; + switch (b) { + case Byte_ascii.Num_0: case Byte_ascii.Num_1: case Byte_ascii.Num_2: case Byte_ascii.Num_3: case Byte_ascii.Num_4: + case Byte_ascii.Num_5: case Byte_ascii.Num_6: case Byte_ascii.Num_7: case Byte_ascii.Num_8: case Byte_ascii.Num_9: + int_val = b - Byte_ascii.Num_0; // convert ascii to val; EX: 49 -> 1 + int_len = int_bldr.Add(int_val); + break; + } + if ( (int_val == -1 && int_len > 0) // char is not number && number exists (ignore consecutive delimiters: EX: "1981 01") + || int_len == max_len) { // max_len reached; necessary for gplxFormat + rv[rv_idx++] = int_bldr.BldAndClear(); + if (rv_idx == 7) break; // past frac; break; + int_len = 0; + max_len = max_lens[rv_idx]; + } + if (pos == end) break; + ++pos; + } + } + int[] max_lens = new int[] {4/*y*/,2/*M*/,2/*d*/,2/*H*/,2/*m*/,2/*s*/,3/*S*/,0}; + IntBldr int_bldr = IntBldr.new_(4); + public static DateAdp_parser new_() {return new DateAdp_parser();} DateAdp_parser() {} +} +class IntBldr { + public int Add(char c) { + if (idx > digitsLen - 1) throw Exc_.new_missing_idx(idx, digitsLen); + digits[idx++] = XbyChar(c); + return idx; + } + public int Add(int i) { + if (idx > digitsLen - 1) throw Exc_.new_missing_idx(idx, digitsLen); + digits[idx++] = i; + return idx; + } + public int Parse(String raw) { + ParseStr(raw); + try {return Bld();} + catch (Exception exc) {throw Exc_.new_parse_exc(exc, int.class, raw);} + } + public boolean ParseTry(String raw) { + ParseStr(raw); + for (int i = 0; i < idx; i++) + if (digits[i] < 0) return false; + return true; + } + public int Bld() { + int rv = 0, exponent = 1; + for (int i = idx - 1; i > -1; i--) { + int digit = digits[i]; + if (digit < 0) throw Exc_.new_("invalid char", "char", (char)-digits[i], "ascii", -digits[i]); + rv += digit * exponent; + exponent *= 10; + } + return sign * rv; + } + public int BldAndClear() { + int rv = Bld(); + this.Clear(); + return rv; + } + public void Clear() {idx = 0; sign = 1;} + void ParseStr(String raw) { + this.Clear(); + int rawLength = String_.Len(raw); + for (int i = 0; i < rawLength; i++) { + char c = String_.CharAt(raw, i); + if (i == 0 && c == '-') + sign = -1; + else + Add(c); + } + } + int XbyChar(char c) { + if (c == '0') return 0; else if (c == '1') return 1; else if (c == '2') return 2; else if (c == '3') return 3; else if (c == '4') return 4; + else if (c == '5') return 5; else if (c == '6') return 6; else if (c == '7') return 7; else if (c == '8') return 8; else if (c == '9') return 9; + else return -(int)c; // error handling: don't throw error; store ascii value in digit and throw if needed + } + int[] digits; int idx, digitsLen; int sign = 1; + public static IntBldr new_(int digitsMax) { + IntBldr rv = new IntBldr(); + rv.digits = new int[digitsMax]; + rv.digitsLen = digitsMax; + return rv; + } +} diff --git a/100_core/src_120_basicDataType/gplx/DateAdp_parser_tst.java b/100_core/src_120_basicDataType/gplx/DateAdp_parser_tst.java new file mode 100644 index 000000000..c36d347c2 --- /dev/null +++ b/100_core/src_120_basicDataType/gplx/DateAdp_parser_tst.java @@ -0,0 +1,34 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class DateAdp_parser_tst { + @Before public void init() {} DateAdp_parser_fxt fxt = new DateAdp_parser_fxt(); + @Test public void Parse_gplx() { + fxt.Test_Parse_iso8651_like("2000-01-02T03:04:05.006-05:00" , 2000, 1, 2, 3, 4, 5, 6); + fxt.Test_Parse_iso8651_like("2000-01-02" , 2000, 1, 2, 0, 0, 0, 0); + } +} +class DateAdp_parser_fxt { + DateAdp_parser parser = DateAdp_parser.new_(); int[] actl = new int[7]; + public void Test_Parse_iso8651_like(String s, int... expd) { + byte[] bry = Bry_.new_a7(s); + parser.Parse_iso8651_like(actl, bry, 0, bry.length); + Tfds.Eq_ary(expd, actl, s); + } +} diff --git a/100_core/src_120_basicDataType/gplx/DecimalAdp.java b/100_core/src_120_basicDataType/gplx/DecimalAdp.java new file mode 100644 index 000000000..c0d528a50 --- /dev/null +++ b/100_core/src_120_basicDataType/gplx/DecimalAdp.java @@ -0,0 +1,67 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import java.math.BigDecimal; +import java.math.MathContext; +import java.math.RoundingMode; +import java.text.DecimalFormat; +public class DecimalAdp implements CompareAble { + public int compareTo(Object obj) {DecimalAdp comp = (DecimalAdp)obj; return under.compareTo(comp.under);} + + protected DecimalAdp(BigDecimal v) {this.under = v;} BigDecimal under; + protected DecimalAdp(int v) {this.under = new BigDecimal(v);} + public String Xto_str() { + BigDecimal tmp = under; + int tmp_scale = tmp.scale(); + if (tmp_scale <= -14) return tmp.toString(); // NOTE: if large number, call .toString which will return exponential notaion (1E##) instead of literal (1000....); 14 matches MW code; DATE:2015-04-10 + if (tmp_scale > 14) + tmp = tmp.setScale(14, RoundingMode.DOWN); // NOTE: if small number, round down to remove excessive zeroes; 14 matches PHP/C# values more closely; RoundingMode.Down for same reason; see E, Pi tests + return tmp .stripTrailingZeros() // NOTE: stripTrailingZeros for exp tests; EX: 120.0 -> 120; 0.01200000000000 -> .012 + .toPlainString(); // NOTE: toPlainString b/c stripTrailingZeros now converts 120 to 1.2E+2 (and any other value that is a multiple of 10) + } + public String Xto_str(String fmt) {return new DecimalFormat(fmt).format(under);} + @Override public String toString() {return under.toString();} + public boolean Eq(DecimalAdp v) {return v.under.doubleValue() == under.doubleValue();} + public BigDecimal Xto_decimal() {return under;} + public long Xto_long_mult_1000() {return under.movePointRight(3).longValue();} + public int Fraction1000() {return (int)(under.movePointRight(3).floatValue() % 1000);} + public double Xto_double() {return under.doubleValue();} + public int Xto_int() {return (int)under.doubleValue();} + public long Xto_long() {return (long)under.doubleValue();} + public DecimalAdp Op_add(DecimalAdp v) {return new DecimalAdp(under.add(v.under, DecimalAdp_.Gplx_rounding_context));} + public DecimalAdp Op_subtract(DecimalAdp v) {return new DecimalAdp(under.subtract(v.under, DecimalAdp_.Gplx_rounding_context));} + public DecimalAdp Op_mult(DecimalAdp v) {return new DecimalAdp(under.multiply(v.under));} + public DecimalAdp Op_mult(double v) {return new DecimalAdp(under.multiply(new BigDecimal(v, DecimalAdp_.Gplx_rounding_context)));} + public DecimalAdp Op_mult(long v) {return new DecimalAdp(under.multiply(new BigDecimal(v)));} + public DecimalAdp Op_divide(DecimalAdp v) {return new DecimalAdp(under.divide(v.under, DecimalAdp_.Gplx_rounding_context));} + public DecimalAdp Op_mod(DecimalAdp v) {return new DecimalAdp(under.remainder(v.under, DecimalAdp_.Gplx_rounding_context));} + public DecimalAdp Op_sqrt() {return new DecimalAdp(new BigDecimal(Math_.Sqrt(under.doubleValue())));} + public DecimalAdp Op_abs() {return new DecimalAdp(under.abs(DecimalAdp_.Gplx_rounding_context));} + public DecimalAdp Op_pow(int v) {return new DecimalAdp(under.pow(v, DecimalAdp_.Gplx_rounding_context));} + public DecimalAdp Op_truncate_decimal() {return new DecimalAdp(under.intValue());} + public DecimalAdp Op_round(int v) {return new DecimalAdp(under.setScale(v, RoundingMode.HALF_UP));} + public boolean Comp_gte(DecimalAdp v) {return under.doubleValue() >= v.under.doubleValue();} + public boolean Comp_gte(int v) {return under.doubleValue() >= v;} + public boolean Comp_lte(DecimalAdp v) {return under.doubleValue() <= v.under.doubleValue();} + public boolean Comp_lte(int v) {return under.doubleValue() <= v;} + public boolean Comp_gt(DecimalAdp v) {return under.doubleValue() > v.under.doubleValue();} + public boolean Comp_gt(int v) {return under.doubleValue() > v;} + public boolean Comp_lt(DecimalAdp v) {return under.doubleValue() < v.under.doubleValue();} + public boolean Comp_lt(int v) {return under.doubleValue() < v;} + public boolean Eq(int v) {return under.doubleValue() == v;} + } diff --git a/100_core/src_120_basicDataType/gplx/DecimalAdp_.java b/100_core/src_120_basicDataType/gplx/DecimalAdp_.java new file mode 100644 index 000000000..219cd1822 --- /dev/null +++ b/100_core/src_120_basicDataType/gplx/DecimalAdp_.java @@ -0,0 +1,57 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import java.math.BigDecimal; import java.math.MathContext; import java.math.RoundingMode; public class DecimalAdp_ { + public static final Class Cls_ref_type = DecimalAdp.class; + public static DecimalAdp as_(Object obj) {return obj instanceof DecimalAdp ? (DecimalAdp)obj : null;} + public static final DecimalAdp Zero = new DecimalAdp(0); + public static final DecimalAdp One = new DecimalAdp(1); + public static final DecimalAdp Neg1 = new DecimalAdp(-1); + public static final DecimalAdp Const_e = DecimalAdp_.double_(Math_.E); + public static final DecimalAdp Const_pi = DecimalAdp_.double_(Math_.Pi); + public static DecimalAdp base1000_(long v) {return divide_(v, 1000);} + public static DecimalAdp parts_1000_(long num, int frc) {return divide_((num * (1000)) + frc, 1000);} + public static DecimalAdp parts_(long num, int frc) { + // int log10 = frc == 0 ? 0 : (Math_.Log10(frc) + 1); + // int pow10 = (int)Math_.Pow(10, log10); + int pow10 = XtoPow10(frc); + return divide_((num * (pow10)) + frc, pow10); + } + public static DecimalAdp cast_(Object obj) {return (DecimalAdp)obj;} + static int XtoPow10(int v) { + if (v > -1 && v < 10) return 10; + else if (v > 9 && v < 100) return 100; + else if (v > 99 && v < 1000) return 1000; + else if (v > 999 && v < 10000) return 10000; + else if (v > 9999 && v < 100000) return 100000; + else if (v > 99999 && v < 1000000) return 1000000; + else if (v > 999999 && v < 10000000) return 10000000; + else if (v > 9999999 && v < 100000000) return 100000000; + else if (v > 99999999 && v < 1000000000) return 1000000000; + else throw Exc_.new_("value must be between 0 and 1 billion", "v", v); + } + public static String CalcPctStr(long dividend, long divisor, String fmt) { + if (divisor == 0) return "%ERR"; + return DecimalAdp_.float_(Float_.Div(dividend, divisor) * 100).Xto_str(fmt) + "%"; + } + public static DecimalAdp divide_safe_(long lhs, long rhs) {return rhs == 0 ? Zero : divide_(lhs, rhs);} + public static DecimalAdp divide_(long lhs, long rhs) { return new DecimalAdp(new BigDecimal(lhs).divide(new BigDecimal(rhs), Gplx_rounding_context)); } public static DecimalAdp int_(int v) {return new DecimalAdp(new BigDecimal(v));} public static DecimalAdp long_(long v) {return new DecimalAdp(new BigDecimal(v));} + public static DecimalAdp float_(float v) {return new DecimalAdp(new BigDecimal(v));} public static DecimalAdp double_(double v) {return new DecimalAdp(new BigDecimal(v));} + public static DecimalAdp double_thru_str_(double v) {return new DecimalAdp(BigDecimal.valueOf(v));} + public static DecimalAdp db_(Object v) {return new DecimalAdp((BigDecimal)v);} public static DecimalAdp parse_(String raw) {return new DecimalAdp(new BigDecimal(raw));} public static DecimalAdp pow_10_(int v) {return new DecimalAdp(new BigDecimal(1).scaleByPowerOfTen(v));} + public static final MathContext RoundDownContext = new MathContext(0, RoundingMode.DOWN); static final MathContext Gplx_rounding_context = new MathContext(28, RoundingMode.HALF_UP); } diff --git a/100_core/src_120_basicDataType/gplx/DecimalAdp__tst.java b/100_core/src_120_basicDataType/gplx/DecimalAdp__tst.java new file mode 100644 index 000000000..8e0db6b64 --- /dev/null +++ b/100_core/src_120_basicDataType/gplx/DecimalAdp__tst.java @@ -0,0 +1,62 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class DecimalAdp__tst { + @Test public void divide_() { + tst_divide_(1, 1000, "0.001"); + tst_divide_(1, 3, "0.33333333333333"); + tst_divide_(1, 7, "0.14285714285714"); + } void tst_divide_(int lhs, int rhs, String expd) {Tfds.Eq(expd, DecimalAdp_.divide_(lhs, rhs).Xto_str());} + @Test public void base1000_() { + tst_base1000_(1000, "1"); + tst_base1000_(1234, "1.234"); + tst_base1000_(123, "0.123"); + } void tst_base1000_(int val, String expd) {Tfds.Eq(expd, DecimalAdp_.base1000_(val).Xto_str());} + @Test public void parts_() { + tst_parts_(1, 0, "1"); + tst_parts_(1, 2, "1.2"); + tst_parts_(1, 23, "1.23"); + tst_parts_(123, 4567, "123.4567"); + } void tst_parts_(int num, int fracs, String expd) {Tfds.Eq(expd, DecimalAdp_.parts_(num, fracs).Xto_str());} + @Test public void parse_() { + tst_parse_("1", "1"); + tst_parse_("1.2", "1.2"); + tst_parse_("0.1", "0.1"); + } void tst_parse_(String raw, String expd) {Tfds.Eq(expd, DecimalAdp_.parse_(raw).Xto_str());} + @Test public void Truncate_decimal() { + tst_Truncate_decimal("1", "1"); + tst_Truncate_decimal("1.1", "1"); + tst_Truncate_decimal("1.9", "1"); + } void tst_Truncate_decimal(String raw, String expd) {Tfds.Eq(DecimalAdp_.parse_(expd).Xto_str(), DecimalAdp_.parse_(raw).Op_truncate_decimal().Xto_str());} + @Test public void Fraction1000() { + tst_Fraction1000(1, 1000, 1); // 0.001 + tst_Fraction1000(1, 3, 333); // 0.33333333 + tst_Fraction1000(1234, 1000, 234); // 1.234 + tst_Fraction1000(12345, 10000, 234); // 1.2345 + } void tst_Fraction1000(int lhs, int rhs, int expd) {Tfds.Eq(expd, DecimalAdp_.divide_(lhs, rhs).Fraction1000());} + @Test public void Lt() { + tst_Lt(1,123, 2, true); + tst_Lt(1,99999999, 2, true); + } void tst_Lt(int lhsNum, int lhsFrc, int rhs, boolean expd) {Tfds.Eq(expd, DecimalAdp_.parts_(lhsNum, lhsFrc).Comp_lt(rhs));} + @Test public void XtoStr_fmt() { + tst_XtoStr_fmt(1, 2, "0.0", "0.5"); + tst_XtoStr_fmt(1, 3, "0.0", "0.3"); + tst_XtoStr_fmt(10000, 7, "0,000.000", "1,428.571"); + } void tst_XtoStr_fmt(int l, int r, String fmt, String expd) {Tfds.Eq(expd, DecimalAdp_.divide_(l, r).Xto_str(fmt));} +} diff --git a/100_core/src_120_basicDataType/gplx/EnmMgr.java b/100_core/src_120_basicDataType/gplx/EnmMgr.java new file mode 100644 index 000000000..53fabd0a3 --- /dev/null +++ b/100_core/src_120_basicDataType/gplx/EnmMgr.java @@ -0,0 +1,72 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.core.strings.*; +public class EnmMgr { + public String BitRngSpr() {return bitRngSpr;} public EnmMgr BitRngSpr_(String val) {bitRngSpr = val; return this;} private String bitRngSpr = "+"; + public String Prefix() {return prefix;} public EnmMgr Prefix_(String val) {prefix = val; return this;} private String prefix; + public int BitRngBgn() {return bitRngBgn;} public EnmMgr BitRngBgn_(int val) {bitRngBgn = val; return this;} int bitRngBgn = 1; + public int BitRngEnd() {return bitRngEnd;} public EnmMgr BitRngEnd_(int val) {bitRngEnd = val; return this;} int bitRngEnd = Int_.MaxValue; + public void RegObj(int val, String raw, Object o) { + rawRegy.Add(raw, val); + valRegy.Add(val, raw); + objRegy.Add(val, o); + } + public Object Get(int val) {return objRegy.Get_by(val);} + public int GetVal(String raw) { + String[] ary = String_.Split(raw, bitRngSpr); + int rv = 0; + for (int i = 0; i < ary.length; i++) { + String term = String_.Trim(ary[i]); // ex: key.ctrl + key.a + if (prefix != null) term = String_.Replace(term, prefix, ""); + int cur = -1; + if (String_.Has_at_bgn(term, "#")) + cur = Int_.parse_(String_.Mid(term, 1)); + else + cur = Int_.cast_(rawRegy.Get_by(term)); + rv |= cur; + } + return rv; + } + public String GetStr(int v) { + String_bldr sb = String_bldr_.new_(); + int cur = v, curModifier = bitRngBgn; + while (true) { + if (cur == 0 + || curModifier > bitRngEnd // loop until all Modifers have been shifted out + ) break; + if ((cur & curModifier) == curModifier) { // cur has Modifier + AppendRaw(sb, curModifier); + cur ^= curModifier; // shift Modifier out + } + curModifier *= 2; // move to next Modifier; relies on Shift, Ctrl, Alt enum values + } + if (cur > 0 // cur is non-Modifier; NOTE: check needed for args that are just a Modifier; + || sb.Count() == 0) // cur is IptKey.None; cur == 0, but sb.length will also be 0 + AppendRaw(sb, cur); + return sb.XtoStr(); + } + void AppendRaw(String_bldr sb, int key) { + String raw = (String)valRegy.Get_by(key); + if (sb.Count() > 0) sb.Add(bitRngSpr); + if (prefix != null) sb.Add(prefix); + sb.Add(raw); + } + Hash_adp rawRegy = Hash_adp_.new_(), valRegy = Hash_adp_.new_(), objRegy = Hash_adp_.new_(); + public static EnmMgr new_() {return new EnmMgr();} EnmMgr() {} +} diff --git a/100_core/src_120_basicDataType/gplx/Enm_.java b/100_core/src_120_basicDataType/gplx/Enm_.java new file mode 100644 index 000000000..a5be6491e --- /dev/null +++ b/100_core/src_120_basicDataType/gplx/Enm_.java @@ -0,0 +1,30 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Enm_ { + public static int XtoInt(Object enm) {return Ordinal_lang(enm);} + public static boolean HasInt(int val, int find) {return find == (val & find);} + public static int AddInt(int lhs, int rhs) {return lhs | rhs;} + public static int FlipInt(boolean enable, int val, int find) { + boolean has = find == (val & find); + return (has ^ enable) ? val ^ find : val; + } + public static boolean Has_byte(byte val, byte find) {return find == (val & find);} + public static byte Add_byte(byte flag, byte itm) {return (byte)(flag | itm);} + static int Ordinal_lang(Object v) {return ((Enum)v).ordinal();} +} diff --git a/100_core/src_120_basicDataType/gplx/Guid_adp.java b/100_core/src_120_basicDataType/gplx/Guid_adp.java new file mode 100644 index 000000000..04822f682 --- /dev/null +++ b/100_core/src_120_basicDataType/gplx/Guid_adp.java @@ -0,0 +1,22 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Guid_adp { + public String XtoStr() {return guid.toString();} + public Guid_adp(java.util.UUID guid) {this.guid = guid;} java.util.UUID guid; +} \ No newline at end of file diff --git a/100_core/src_120_basicDataType/gplx/Guid_adp_.java b/100_core/src_120_basicDataType/gplx/Guid_adp_.java new file mode 100644 index 000000000..7cda6af35 --- /dev/null +++ b/100_core/src_120_basicDataType/gplx/Guid_adp_.java @@ -0,0 +1,24 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Guid_adp_ { + public static final String Cls_ref_name = "Guid"; + public static final Guid_adp Empty = parse_("00000000-0000-0000-0000-000000000000"); + public static Guid_adp new_() {return new Guid_adp(java.util.UUID.randomUUID());} + public static Guid_adp parse_(String s) {return new Guid_adp(java.util.UUID.fromString(s));} +} \ No newline at end of file diff --git a/100_core/src_120_basicDataType/gplx/Guid_adp__tst.java b/100_core/src_120_basicDataType/gplx/Guid_adp__tst.java new file mode 100644 index 000000000..e3c11cb66 --- /dev/null +++ b/100_core/src_120_basicDataType/gplx/Guid_adp__tst.java @@ -0,0 +1,28 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class Guid_adp__tst { + @Test public void parse_() { + tst_parse_("467ffb41-cdfe-402f-b22b-be855425784b"); + } + void tst_parse_(String s) { + Guid_adp uuid = Guid_adp_.parse_(s); + Tfds.Eq(uuid.XtoStr(), s); + } +} diff --git a/100_core/src_120_basicDataType/gplx/Io_url.java b/100_core/src_120_basicDataType/gplx/Io_url.java new file mode 100644 index 000000000..a1d264e9b --- /dev/null +++ b/100_core/src_120_basicDataType/gplx/Io_url.java @@ -0,0 +1,98 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.core.strings.*; import gplx.ios.*; /*IoUrlInfo*/ +public class Io_url implements CompareAble, EqAble, ParseAble, GfoInvkAble { //_20101005 URL:doc/Io_url.txt + public IoUrlInfo Info() {return info;} IoUrlInfo info; + public String Raw() {return raw;} final String raw; + public byte[] RawBry() {return Bry_.new_u8(raw);} +// public byte[] Http_file_bry() { +// try {return Bry_.new_u8(String_.Concat(http_file_str, java.net.URLEncoder.encode(raw, "UTF-8")));} +// catch (Exception e) {throw Err_.err_(e, "Http_file_bry");} +// } + public String To_http_file_str() {return Http_file_str + Http_file_str_encoder.Encode_str(raw);} + public byte[] To_http_file_bry() { + return Bry_.Add(Http_file_bry, Http_file_str_encoder.Encode_bry(raw)); + } + public static Url_encoder_interface Http_file_str_encoder = Url_encoder_interface_same._; + + public static final String Http_file_str = "file:///"; + public static final int Http_file_len = String_.Len(Http_file_str); + public static final byte[] Http_file_bry = Bry_.new_a7(Http_file_str); + public boolean Type_dir() {return info.IsDir(raw);} public boolean Type_fil() {return !info.IsDir(raw);} + public Io_url OwnerDir() {return Io_url_.new_inf_(info.OwnerDir(raw), info);} + public Io_url OwnerRoot() {return Io_url_.new_inf_(info.OwnerRoot(raw), info);} + public String NameAndExt() {return info.NameAndExt(raw);} + public String NameAndExt_noDirSpr() {return this.Type_dir() ? this.NameOnly() : this.NameAndExt();} + public String NameOnly() {return info.NameOnly(raw);} + public String Ext() {return info.Ext(raw);} + public String Xto_api() {return info.Xto_api(raw);} + public String XtoCaseNormalized() {return String_.CaseNormalize(info.CaseSensitive(), raw);} + public Io_url GenSubDir(String subDirName) {return Io_url_.new_inf_(String_.Concat(raw, subDirName, info.DirSpr()), info);} + public Io_url GenSubDir_nest(String... ary) {return GenSub(false, ary);} + public Io_url GenSubFil(String val) {return Io_url_.new_inf_(raw + val, info);} + public Io_url GenSubFil_ary(String... ary) {return Io_url_.new_inf_(raw + String_.Concat(ary), info);} + public Io_url GenSubFil_nest(String... ary) {return GenSub(true, ary);} + public Io_url GenNewNameAndExt(String val) {return this.OwnerDir().GenSubFil(val);} + public Io_url GenNewNameOnly(String val) {return this.OwnerDir().GenSubFil(val + this.Ext());} + public Io_url GenNewExt(String val) {return this.OwnerDir().GenSubFil(this.NameOnly() + val);} + public String Gen_sub_path_for_os(String val) { + if (Op_sys.Cur().Tid_is_wnt()) val = String_.Replace(val, Op_sys.Lnx.Fsys_dir_spr_str(), Op_sys.Wnt.Fsys_dir_spr_str()); + return raw + val; + } + public String GenRelUrl_orEmpty(Io_url dir) { + String dirRaw = dir.Raw(); + return String_.Has_at_bgn(raw, dirRaw) + ? String_.DelBgn(raw, String_.Len(dirRaw)) + : String_.Empty; + } + public List_adp XtoNames() { + List_adp list = List_adp_.new_(); + Io_url cur = this; + while (!cur.EqNull()) { + list.Add(cur.NameAndExt_noDirSpr()); + cur = cur.OwnerDir(); + } + list.Reverse(); + return list; + } + public Io_url GenParallel(Io_url oldRoot, Io_url newRoot) {return newRoot.GenSubFil_ary(GenRelUrl_orEmpty(oldRoot));} + public boolean Eq(Object obj) {if (obj == null) return false; return String_.Eq(raw, ((Io_url)obj).raw);} + public boolean EqNull() {return this.Eq(Io_url_.Empty);} + Io_url GenSub(boolean isFil, String[] ary) { + String_bldr sb = String_bldr_.new_().Add(raw); + int len = Array_.Len(ary); + for (int i = 0; i < len; i++) { + sb.Add(ary[i]); + if (isFil && i == len - 1) break; // do not add closing backslash if last term + sb.Add(info.DirSpr()); + } + return Io_url_.new_inf_(sb.XtoStr(), info); + } + public Object ParseAsObj(String raw) {return Io_url_.new_any_(raw);} + @Override public String toString() {return raw;} + public int compareTo(Object obj) {return CompareAble_.Compare_obj(raw, ((Io_url)obj).raw);} + @Override public boolean equals(Object obj) {return String_.Eq(raw, Io_url_.as_(obj).raw);} + @Override public int hashCode() {return raw.hashCode();} + @gplx.Internal protected Io_url(String raw, IoUrlInfo info) {this.raw = raw; this.info = info;} + public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) { + if (ctx.Match(k, Invk_to_http_file)) return To_http_file_str(); + else if (ctx.Match(k, Invk_gen_sub_path_for_os)) return Gen_sub_path_for_os(m.ReadStr("v")); + else return GfoInvkAble_.Rv_unhandled; + } static final String Invk_to_http_file = "to_http_file", Invk_gen_sub_path_for_os = "gen_sub_path_for_os"; +} diff --git a/100_core/src_120_basicDataType/gplx/Io_url_.java b/100_core/src_120_basicDataType/gplx/Io_url_.java new file mode 100644 index 000000000..33ea855fd --- /dev/null +++ b/100_core/src_120_basicDataType/gplx/Io_url_.java @@ -0,0 +1,96 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.ios.*; /*IoUrlInfo_*/ +public class Io_url_ { + public static final Io_url Empty = new Io_url("", IoUrlInfo_.Nil); + public static final Io_url NullPtr = null; + public static final Io_url Parser = new Io_url("", IoUrlInfo_.Nil); + public static Io_url as_(Object obj) {return obj instanceof Io_url ? (Io_url)obj : null;} + public static Io_url cast_(Object obj) {try {return (Io_url)obj;} catch(Exception exc) {throw Exc_.new_type_mismatch_w_exc(exc, Io_url.class, obj);}} + public static Io_url Usr() { + if (usr_dir == null) { + switch (Op_sys.Cur().Tid()) { + case Op_sys.Tid_wnt: usr_dir = Io_url_.new_inf_("C:\\", IoUrlInfo_.Wnt); break; + case Op_sys.Tid_lnx: usr_dir = Io_url_.new_inf_(String_.Format("/home/{0}/", Env_.UserName()), IoUrlInfo_.Lnx); break; + case Op_sys.Tid_osx: usr_dir = Io_url_.new_inf_(String_.Format("/Users/{0}/", Env_.UserName()), IoUrlInfo_.Lnx); break; + case Op_sys.Tid_drd: usr_dir = Io_url_.new_inf_(String_.Format("/mnt/{0}/", Env_.UserName()), IoUrlInfo_.Lnx); break; + default: throw Exc_.new_unhandled(Op_sys.Cur().Tid()); + } + } + return usr_dir; + } static Io_url usr_dir; + public static Io_url Usr_Gplx() {return Usr().GenSubDir("gplx");} + public static Io_url mem_dir_(String raw) { + raw = EndsWith_or_add(raw, Op_sys.Lnx.Fsys_dir_spr_str()); + return new Io_url(raw, IoUrlInfoRegy._.Match(raw)); + } + public static Io_url mem_fil_(String raw) {return new_inf_(raw, IoUrlInfoRegy._.Match(raw));} + public static Io_url wnt_fil_(String raw) {return new_inf_(raw, IoUrlInfo_.Wnt);} + public static Io_url wnt_dir_(String raw) {return new_inf_(EndsWith_or_add(raw, Op_sys.Wnt.Fsys_dir_spr_str()), IoUrlInfo_.Wnt);} + public static Io_url lnx_fil_(String raw) {return new_inf_(raw, IoUrlInfo_.Lnx);} + public static Io_url lnx_dir_(String raw) {return new_inf_(EndsWith_or_add(raw, Op_sys.Lnx.Fsys_dir_spr_str()), IoUrlInfo_.Lnx);} + public static Io_url new_fil_(String raw) {return new_any_(raw);} + public static Io_url new_dir_(String raw) {return new_any_(raw);} // NOTE: for now, same as new_fil; stack overflow when doing new_dir + public static Io_url new_any_(String raw) {return new_inf_(raw, IoUrlInfoRegy._.Match(raw));} + public static Io_url new_inf_(String raw, IoUrlInfo info) {return String_.Eq(raw, "") ? Io_url_.Empty : new Io_url(raw, info);} + public static Io_url http_any_(String src, boolean wnt) { + return new_any_(parse_http_file(src, wnt)); + } + private static String parse_http_file(String v, boolean wnt) { + byte[] v_bry = Bry_.new_u8(v); + int v_len = v_bry.length; + if (Bry_.Has_at_bgn(v_bry, Io_url.Http_file_bry, 0, v_len)) { + byte[] rv = new byte[v_len - Io_url.Http_file_len]; + for (int i = 0; i < rv.length; i++) { + byte b = v_bry[i + Io_url.Http_file_len]; + if (wnt && b == Byte_ascii.Slash) b = Byte_ascii.Backslash; + rv[i] = b; + } + return String_.new_u8(rv); + } + return v; + } + + public static Io_url store_orFail_(SrlMgr mgr, String key, Io_url v) { + String s = mgr.SrlStrOr(key, v.Raw()); + return (mgr.Type_rdr()) ? Io_url_.new_any_(s) : v; + } + public static Io_url store_orSelf_(SrlMgr mgr, String key, Io_url v) { + String s = mgr.SrlStrOr(key, v.Raw()); + return (mgr.Type_rdr()) ? Io_url_.new_any_(s) : v; + } + public static Io_url rdrOr_(DataRdr rdr, String key, Io_url or) { + String val = rdr.ReadStrOr(key, null); if (val == null) return or; // NOTE: val == null also checks for rdr == DataRdr_.Null + return Io_url_.new_any_(val); + } + static String EndsWith_or_add(String raw, String endsWith) { + if (String_.Has_at_end(raw, endsWith)) return raw; + return raw += endsWith; + } + public static Io_url Rel_dir(String s) {return IsAbs(s) ? Io_url_.new_dir_(s) : Env_.AppUrl().OwnerDir().GenSubDir(s);} + public static Io_url Rel_fil(String s) {return IsAbs(s) ? Io_url_.new_fil_(s) : Env_.AppUrl().OwnerDir().GenSubFil(s);} + static boolean IsAbs(String s) { + return String_.Has_at_bgn(s, Op_sys.Lnx.Fsys_dir_spr_str()) + || (String_.Len(s) > 2 + && ( (String_.CharAt(s, 1) == ':' && String_.CharAt(s, 2) == '\\') + || (String_.CharAt(s, 1) == '\\' && String_.CharAt(s, 2) == '\\') + ) + ); + } +} diff --git a/100_core/src_120_basicDataType/gplx/KeyVal.java b/100_core/src_120_basicDataType/gplx/KeyVal.java new file mode 100644 index 000000000..9df3f77fb --- /dev/null +++ b/100_core/src_120_basicDataType/gplx/KeyVal.java @@ -0,0 +1,31 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class KeyVal implements XtoStrAble { + @gplx.Internal protected KeyVal(byte key_tid, Object k, Object v) {this.key_tid = key_tid; key = k; val = v;} + public String Key() {return Object_.Xto_str_strict_or_null(key);} + public byte Key_tid() {return key_tid;} private byte key_tid; + public Object Key_as_obj() {return key;} private Object key; + public KeyVal Key_(Object v) {this.key = v; return this;} + public Object Val() {return val;} public KeyVal Val_(Object v) {val = v; return this;} private Object val; + public String Val_to_str_or_empty() {return Object_.Xto_str_strict_or_empty(val);} + public String Val_to_str_or_null() {return Object_.Xto_str_strict_or_null(val);} + public byte[] Val_to_bry() {return Bry_.new_u8(Object_.Xto_str_strict_or_null(val));} + @Override public String toString() {return XtoStr();} + public String XtoStr() {return Key() + "=" + Object_.Xto_str_strict_or_null_mark(val);} +} diff --git a/100_core/src_120_basicDataType/gplx/KeyValHash.java b/100_core/src_120_basicDataType/gplx/KeyValHash.java new file mode 100644 index 000000000..8ae05c87a --- /dev/null +++ b/100_core/src_120_basicDataType/gplx/KeyValHash.java @@ -0,0 +1,60 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class KeyValHash { + private Ordered_hash hash = Ordered_hash_.new_(); + public int Count() {return hash.Count();} + public KeyValHash Clear() {hash.Clear(); return this;} + public boolean Has(String key) {return hash.Has(key);} + public KeyVal Get_at(int i) {return (KeyVal)hash.Get_at(i);} + public Object FetchValOr(String key, Object or) {KeyVal rv = FetchOrNull(key); return rv == null ? or : rv.Val();} + public Object FetchValOrNull(String key) {return FetchValOr(key, null);} + public Object FetchValOrFail(String key) {return KeyVal_.as_(hash.Get_by_or_fail(key)).Val();} + public KeyValHash Add(KeyVal kv) {hash.Add(kv.Key(), kv); return this;} + public KeyValHash Add(String key, Object val) {hash.Add(key, KeyVal_.new_(key, val)); return this;} + public KeyValHash Add_if_dupe_use_nth(String key, Object val) {hash.Add_if_dupe_use_nth(key, KeyVal_.new_(key, val)); return this;} + public void Del(String key) {hash.Del(key);} + public KeyVal[] Xto_bry() { + KeyVal[] rv = new KeyVal[this.Count()]; + for (int i = 0; i < rv.length; i++) + rv[i] = this.Get_at(i); + return rv; + } + public static KeyValHash new_() {return new KeyValHash();} protected KeyValHash() {} + public static KeyValHash new_by_ary(KeyVal[] ary) { + int ary_len = ary.length; + KeyValHash rv = new KeyValHash(); + for (int i = 0; i < ary_len; i++) + rv.Add(ary[i]); + return rv; + } + public KeyVal FetchOrNull(String key) {return KeyVal_.as_(hash.Get_by(key));} + public static KeyValHash strAry_(String[] ary) {// needed for consoleLine + int aryLen = Array_.Len(ary); if (aryLen % 2 != 0) throw Exc_.new_("array length must be divisible by 2", "aryLen", aryLen, "ary", String_.Concat_lines_crlf(ary)); + KeyValHash rv = new KeyValHash(); + String key = null; + for (int i = 0; i < aryLen; i++) { + if (i % 2 == 0) + key = ary[i]; + else + rv.Add(key, ary[i]); + } + return rv; + } + public static final KeyValHash Empty = new KeyValHash(); +} \ No newline at end of file diff --git a/100_core/src_120_basicDataType/gplx/KeyValHash_tst.java b/100_core/src_120_basicDataType/gplx/KeyValHash_tst.java new file mode 100644 index 000000000..8155f8e65 --- /dev/null +++ b/100_core/src_120_basicDataType/gplx/KeyValHash_tst.java @@ -0,0 +1,36 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class KeyValHash_tst { + @Test public void AryVals() { + tst_AryVals(ary_()); + tst_AryVals(ary_("key1", "1"), kv_("key1", "1")); + tst_AryVals(ary_("key1", "1", "key2", "2"), kv_("key1", "1"), kv_("key2", "2")); + } + @Test public void Fail_lengthMustBeEven() { + try { + tst_AryVals(ary_("key1"), kv_("key1", "1")); + Tfds.Fail_expdError(); + } + catch (Exception e) {Exc_.Noop(e);} + } + void tst_AryVals(String[] ary, KeyVal... expd) {Tfds.Eq_ary_str(expd, KeyValHash.strAry_(ary).Xto_bry());} + KeyVal kv_(String key, Object val) {return KeyVal_.new_(key, val);} + String[] ary_(String... ary) {return ary;} +} diff --git a/100_core/src_120_basicDataType/gplx/KeyValList.java b/100_core/src_120_basicDataType/gplx/KeyValList.java new file mode 100644 index 000000000..e6e3957f2 --- /dev/null +++ b/100_core/src_120_basicDataType/gplx/KeyValList.java @@ -0,0 +1,36 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.core.strings.*; +public class KeyValList {//20101217 + public int Count() {return list.Count();} List_adp list = List_adp_.new_(); + public void Clear() {list.Clear();} + public KeyVal GetAt(int i) {return (KeyVal)list.Get_at(i);} + public KeyValList Add(String key, Object val) {list.Add(KeyVal_.new_(key, val)); return this;} + public KeyVal[] Xto_bry() {return (KeyVal[])list.To_ary(KeyVal.class);} + public String XtoStr() { + String_bldr sb = String_bldr_.new_(); + for (int i = 0; i < list.Count(); i++) { + KeyVal kv = (KeyVal)list.Get_at(i); + sb.Add_spr_unless_first(kv.Key(), " ", i); + sb.Add("=").Add(kv.Val_to_str_or_empty()); + } + return sb.XtoStr(); + } + public static KeyValList args_(String key, Object val) {return new KeyValList().Add(key, val);} +} diff --git a/100_core/src_120_basicDataType/gplx/KeyVal_.java b/100_core/src_120_basicDataType/gplx/KeyVal_.java new file mode 100644 index 000000000..5d78fbdd5 --- /dev/null +++ b/100_core/src_120_basicDataType/gplx/KeyVal_.java @@ -0,0 +1,104 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.core.strings.*; +public class KeyVal_ { + public static final KeyVal[] Ary_empty = new KeyVal[0]; + public static KeyVal[] Ary(KeyVal... ary) {return ary;} + public static KeyVal[] Ary_cast_(Object o) { + try {return (KeyVal[])o;} + catch (Exception e) {throw Exc_.new_cast(e, KeyVal.class, o);} + } + public static KeyVal[] Ary_insert(KeyVal[] orig, boolean insert_at_end, KeyVal... vals) { + int orig_len = orig.length, vals_len = vals.length; + int rv_len = orig_len + vals_len; + KeyVal[] rv = new KeyVal[rv_len]; + int vals_bgn = 0 , vals_end = vals_len; + int orig_bgn = vals_len , orig_end = rv_len; + if (insert_at_end) { + orig_bgn = 0 ; orig_end = orig_len; + vals_bgn = orig_len ; vals_end = rv_len; + } + for (int i = orig_bgn; i < orig_end; i++) + rv[i] = orig[i - orig_bgn]; + for (int i = vals_bgn; i < vals_end; i++) + rv[i] = vals[i - vals_bgn]; + return rv; + } + public static String Ary_x_to_str(KeyVal... ary) { + String_bldr sb = String_bldr_.new_(); + int len = ary.length; + for (int i = 0; i < len; i++) { + KeyVal itm = ary[i]; + sb.Add(itm.Key()).Add("="); + Object itm_val = itm.Val(); + if (ClassAdp_.Eq_typeSafe(itm_val, KeyVal[].class)) + sb.Add(Ary_x_to_str((KeyVal[])itm_val)); + else + sb.Add(Object_.Xto_str_strict_or_null_mark(itm_val)); + sb.Add_char_nl(); + } + return sb.XtoStr(); + } + public static Object Ary_get_by_key_or_null(KeyVal[] ary, String key) { + int len = ary.length; + for (int i = 0; i < len; i++) { + KeyVal kv = ary[i]; + if (String_.Eq(kv.Key(), key)) return kv.Val(); + } + return null; + } + public static String Ary_xto_str_nested(KeyVal... ary) { + Bry_bfr bfr = Bry_bfr.new_(); + Ary_xto_str_nested(bfr, 0, ary); + return bfr.Xto_str_and_clear(); + } + private static void Ary_xto_str_nested(Bry_bfr bfr, int indent, KeyVal[] ary) { + int len = ary.length; + for (int i = 0; i < len; ++i) { + KeyVal itm = ary[i]; + if (indent > 0) + bfr.Add_byte_repeat(Byte_ascii.Space, indent * 2); // add indent : " " + bfr.Add_str(Object_.Xto_str_strict_or_empty(itm.Key())).Add_byte_eq(); // add key + eq : "key=" + Object val = itm.Val(); + if (val == null) + bfr.Add_str(String_.Null_mark); + else { + Class val_type = ClassAdp_.ClassOf_obj(val); + if (ClassAdp_.Eq(val_type, KeyVal[].class)) { // val is KeyVal[]; recurse + bfr.Add_byte_nl(); // add nl : "\n" + Ary_xto_str_nested(bfr, indent + 1, (KeyVal[])val); + continue; // don't add \n below + } + else if (ClassAdp_.Eq(val_type, Bool_.Cls_ref_type)) { // val is boolean + boolean val_as_bool = Bool_.cast_(val); + bfr.Add(val_as_bool ? Bool_.True_bry : Bool_.False_bry); // add "true" or "false"; don't call toString + } + else + bfr.Add_str(Object_.Xto_str_strict_or_null_mark(val)); // call toString() + } + bfr.Add_byte_nl(); + } + } + public static KeyVal as_(Object obj) {return obj instanceof KeyVal ? (KeyVal)obj : null;} + public static KeyVal new_(String key) {return new KeyVal(KeyVal_.Key_tid_str, key, key);} + public static KeyVal new_(String key, Object val) {return new KeyVal(KeyVal_.Key_tid_str, key, val);} + public static KeyVal int_(int key, Object val) {return new KeyVal(KeyVal_.Key_tid_int, key, val);} + public static KeyVal obj_(Object key, Object val) {return new KeyVal(KeyVal_.Key_tid_obj, key, val);} + public static final byte Key_tid_obj = 0, Key_tid_str = 1, Key_tid_int = 2; +} diff --git a/100_core/src_120_basicDataType/gplx/Math_.java b/100_core/src_120_basicDataType/gplx/Math_.java new file mode 100644 index 000000000..1d42eb32c --- /dev/null +++ b/100_core/src_120_basicDataType/gplx/Math_.java @@ -0,0 +1,72 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Math_ { + public static double Pow(double val, double exponent) {return java.lang.Math.pow(val, exponent);} + public static double Pi = java.lang.Math.PI; + public static double E = java.lang.Math.E; + public static double Ceil(double v) {return java.lang.Math.ceil(v);} + public static double Floor(double v) {return java.lang.Math.floor(v);} + public static double Round(double v, int places) { + return java.math.BigDecimal.valueOf(v).setScale(places, java.math.BigDecimal.ROUND_HALF_UP).doubleValue(); + } + public static int Trunc(double v) {return (int)v;} + public static double Exp(double v) {return java.lang.Math.exp(v);} + public static double Log(double v) {return java.lang.Math.log(v);} + public static double Sin(double v) {return java.lang.Math.sin(v);} + public static double Cos(double v) {return java.lang.Math.cos(v);} + public static double Tan(double v) {return java.lang.Math.tan(v);} + public static double Asin(double v) {return java.lang.Math.asin(v);} + public static double Acos(double v) {return java.lang.Math.acos(v);} + public static double Atan(double v) {return java.lang.Math.atan(v);} + public static double Sqrt(double v) {return java.lang.Math.sqrt(v);} + public static int Abs(int val) {return val > 0 ? val : val * -1;} + public static long Abs(long val) {return val > 0 ? val : val * -1;} + public static float Abs(float val) {return val > 0 ? val : val * -1;} + public static double Abs_double(double val) {return val > 0 ? val : val * -1;} + public static int Log10(int val) { + if (val <= 0) return Int_.MinValue; + int rv = -1, baseVal = 10; + while (val != 0) { + val = (val / baseVal); + rv++; + } + return rv; + } + public static int Div_safe_as_int(int val, int divisor) {return divisor == 0 ? 0 : val / divisor;} + public static long Div_safe_as_long(long val, long divisor) {return divisor == 0 ? 0 : val / divisor;} + public static double Div_safe_as_double(double val, double divisor) {return divisor == 0 ? 0 : val / divisor;} + public static int Min(int val0, int val1) {return val0 < val1 ? val0 : val1;} + public static int Max(int val0, int val1) {return val0 > val1 ? val0 : val1;} + public static int[] Base2Ary(int v, int max) { + int[] idxs = new int[32]; + int cur = v, mult = max, idx = 0; + while (mult > 0) { + int tmp = cur / mult; + if (tmp >= 1) { + idxs[idx++] = mult; + cur -= mult; + } + mult /= 2; + } + int[] rv = new int[idx]; + for (int i = 0; i < idx; i++) + rv[i] = idxs[idx - i - 1]; + return rv; + } +} \ No newline at end of file diff --git a/100_core/src_120_basicDataType/gplx/Math__tst.java b/100_core/src_120_basicDataType/gplx/Math__tst.java new file mode 100644 index 000000000..983cf8015 --- /dev/null +++ b/100_core/src_120_basicDataType/gplx/Math__tst.java @@ -0,0 +1,61 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class Math__tst { + @Test public void Abs() { + tst_Abs(1, 1); + tst_Abs(-1, 1); + tst_Abs(0, 0); + } void tst_Abs(int val, int expd) {Tfds.Eq(expd, Math_.Abs(val));} + @Test public void Log10() { + tst_Log10(0, Int_.MinValue); + tst_Log10(9, 0); + tst_Log10(10, 1); + tst_Log10(99, 1); + tst_Log10(100, 2); + } void tst_Log10(int val, int expd) {Tfds.Eq(expd, Math_.Log10(val));} + @Test public void Min() { + tst_Min(0, 1, 0); + tst_Min(1, 0, 0); + tst_Min(0, 0, 0); + } void tst_Min(int val0, int val1, int expd) {Tfds.Eq(expd, Math_.Min(val0, val1));} + @Test public void Pow() { + tst_Pow(2, 0, 1); + tst_Pow(2, 1, 2); + tst_Pow(2, 2, 4); + } void tst_Pow(int val, int exponent, double expd) {Tfds.Eq(expd, Math_.Pow(val, exponent));} + @Test public void Mult() { + tst_Mult(100, .01f, 1); + } void tst_Mult(int val, float multiplier, int expd) {Tfds.Eq(expd, Int_.Mult(val, multiplier));} + @Test public void Base2Ary() { + tst_Base2Ary( 1, 256, 1); + tst_Base2Ary( 2, 256, 2); + tst_Base2Ary( 3, 256, 1, 2); + tst_Base2Ary( 4, 256, 4); + tst_Base2Ary( 5, 256, 1, 4); + tst_Base2Ary( 6, 256, 2, 4); + tst_Base2Ary(511, 256, 1, 2, 4, 8, 16, 32, 64, 128, 256); + } void tst_Base2Ary(int v, int max, int... expd) {Tfds.Eq_ary(expd, Math_.Base2Ary(v, max));} + @Test public void Round() { + tst_Round(1.5 , 0, 2); + tst_Round(2.5 , 0, 3); + tst_Round(2.123 , 2, 2.12); + tst_Round(21.1 , -1, 20); + } void tst_Round(double v, int places, double expd) {Tfds.Eq(expd, Math_.Round(v, places));} +} diff --git a/100_core/src_120_basicDataType/gplx/ObjAry.java b/100_core/src_120_basicDataType/gplx/ObjAry.java new file mode 100644 index 000000000..e90849fd3 --- /dev/null +++ b/100_core/src_120_basicDataType/gplx/ObjAry.java @@ -0,0 +1,36 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class ObjAry { + public Object[] Ary() {return ary;} Object[] ary; + public Object Get(int i) {return ary[i];} + public Object Get0() {return ary[0];} + public Object Get1() {return ary[1];} + public static ObjAry pair_(Object val0, Object val1) { + ObjAry rv = new ObjAry(); + rv.ary = new Object[2]; + rv.ary[0] = val0; + rv.ary[1] = val1; + return rv; + } ObjAry() {} + public static ObjAry many_(Object... ary) { + ObjAry rv = new ObjAry(); + rv.ary = ary; + return rv; + } +} diff --git a/100_core/src_120_basicDataType/gplx/RandomAdp.java b/100_core/src_120_basicDataType/gplx/RandomAdp.java new file mode 100644 index 000000000..604c90dd5 --- /dev/null +++ b/100_core/src_120_basicDataType/gplx/RandomAdp.java @@ -0,0 +1,24 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import java.util.*; +public class RandomAdp { + public int Next(int max) {return under.nextInt(max);} + public RandomAdp(Random v) {under = v;} + Random under; +} diff --git a/100_core/src_120_basicDataType/gplx/RandomAdp_.java b/100_core/src_120_basicDataType/gplx/RandomAdp_.java new file mode 100644 index 000000000..ee45c701b --- /dev/null +++ b/100_core/src_120_basicDataType/gplx/RandomAdp_.java @@ -0,0 +1,30 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import java.util.*; +public class RandomAdp_ implements GfoInvkAble { + public static RandomAdp new_() { + Random random = new Random(System.currentTimeMillis()); + return new RandomAdp(random); + } + public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) { + if (ctx.Match(k, Invk_Next)) return RandomAdp_.new_().Next(m.ReadInt("max")); + else return GfoInvkAble_.Rv_unhandled; + } static final String Invk_Next = "Next"; + public static final RandomAdp_ Gfs = new RandomAdp_(); +} diff --git a/100_core/src_120_basicDataType/gplx/TimeSpanAdp.java b/100_core/src_120_basicDataType/gplx/TimeSpanAdp.java new file mode 100644 index 000000000..af14af134 --- /dev/null +++ b/100_core/src_120_basicDataType/gplx/TimeSpanAdp.java @@ -0,0 +1,85 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.core.strings.*; +public class TimeSpanAdp implements CompareAble, EqAble { + public long Fracs() {return fracs;} long fracs; public int FracsAsInt() {return (int)fracs;} + public DecimalAdp TotalSecs() { + return DecimalAdp_.divide_(fracs, TimeSpanAdp_.Divisors[TimeSpanAdp_.Idx_Sec]); + } + public DecimalAdp Total_days() { + return DecimalAdp_.divide_(fracs, TimeSpanAdp_.Divisors[TimeSpanAdp_.Idx_Hour] * 24); + } + public int[] Units() {return TimeSpanAdp_.Split_long(fracs, TimeSpanAdp_.Divisors);} + public int Units_fracs() { + int[] ary = TimeSpanAdp_.Split_long(fracs, TimeSpanAdp_.Divisors); + return ary[TimeSpanAdp_.Idx_Frac]; + } + public TimeSpanAdp Add(TimeSpanAdp val) {return new TimeSpanAdp(fracs + val.fracs);} + public TimeSpanAdp Add_fracs(long val) {return new TimeSpanAdp(fracs + val);} + public TimeSpanAdp Add_unit(int idx, int val) { + int[] units = TimeSpanAdp_.Split_long(fracs, TimeSpanAdp_.Divisors); + units[idx] += val; + int sign = fracs >= 0 ? 1 : -1; + long rv = sign * TimeSpanAdp_.Merge_long(units, TimeSpanAdp_.Divisors); + return TimeSpanAdp_.fracs_(rv); + } + public TimeSpanAdp Subtract(TimeSpanAdp val) {return new TimeSpanAdp(fracs - val.fracs);} + + public int compareTo(Object obj) {TimeSpanAdp comp = TimeSpanAdp_.cast_(obj); return CompareAble_.Compare_obj(fracs, comp.fracs);} + public boolean Eq(Object o) { + TimeSpanAdp comp = TimeSpanAdp_.cast_(o); if (comp == null) return false; + return fracs == comp.fracs; + } + @Override public String toString() {return XtoStr(TimeSpanAdp_.Fmt_Default);} + @Override public boolean equals(Object obj) {TimeSpanAdp comp = TimeSpanAdp_.cast_(obj); return Object_.Eq(fracs, comp.fracs);} + @Override public int hashCode() {return super.hashCode();} + + public String XtoStr() {return TimeSpanAdp_.XtoStr(fracs, TimeSpanAdp_.Fmt_Default);} + public String XtoStr(String format) { + return TimeSpanAdp_.XtoStr(fracs, format); + } + public String XtoStrUiAbbrv() { + if (fracs == 0) return "0" + UnitAbbrv(0); + int[] units = Units(); + boolean started = false; + String_bldr sb = String_bldr_.new_(); + for (int i = units.length - 1; i > -1; i--) { + int unit = units[i]; + if (!started) { + if (unit == 0) + continue; + else + started = true; + } + if (sb.Count() != 0) sb.Add(" "); + sb.Add_obj(unit).Add(UnitAbbrv(i)); + } + return sb.XtoStr(); + } + String UnitAbbrv(int i) { + switch (i) { + case 0: return "f"; + case 1: return "s"; + case 2: return "m"; + case 3: return "h"; + default: return "unknown:<" + Int_.Xto_str(i) + ">"; + } + } + @gplx.Internal protected TimeSpanAdp(long fracs) {this.fracs = fracs;} +} diff --git a/100_core/src_120_basicDataType/gplx/TimeSpanAdp_.java b/100_core/src_120_basicDataType/gplx/TimeSpanAdp_.java new file mode 100644 index 000000000..394eb434b --- /dev/null +++ b/100_core/src_120_basicDataType/gplx/TimeSpanAdp_.java @@ -0,0 +1,162 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.core.strings.*; +public class TimeSpanAdp_ { + public static final TimeSpanAdp Zero = new TimeSpanAdp(0); + public static final TimeSpanAdp Null = new TimeSpanAdp(-1); + public static TimeSpanAdp fracs_(long val) {return new TimeSpanAdp(val);} + public static TimeSpanAdp seconds_(double seconds) { + long fracs = (long)(seconds * Divisors[Idx_Sec]); + return new TimeSpanAdp(fracs); + } + public static TimeSpanAdp decimal_(DecimalAdp seconds) { + return new TimeSpanAdp(seconds.Xto_long_mult_1000()); + } + public static TimeSpanAdp units_(int frc, int sec, int min, int hour) { + int[] units = new int[] {frc, sec, min, hour}; + long fracs = Merge_long(units, TimeSpanAdp_.Divisors); + return TimeSpanAdp_.fracs_(fracs); + } + public static TimeSpanAdp from_(long bgn) {return TimeSpanAdp_.fracs_(Env_.TickCount() - bgn);} + public static final long parse_null = Long_.MinValue; + public static TimeSpanAdp parse_(String raw) { + byte[] bry = Bry_.new_u8(raw); + long fracs = parse_to_fracs(bry, 0, bry.length, false); + return fracs == parse_null ? null : TimeSpanAdp_.fracs_(fracs); + } + public static long parse_to_fracs(byte[] raw, int bgn, int end, boolean fail_if_ws) { + int sign = 1, val_f = 0, val_s = 0, val_m = 0, val_h = 0, colon_pos = 0, unit_val = 0, unit_multiple = 1; + for (int i = end - 1; i >= bgn; i--) { // start from end; fracs should be lowest unit + byte b = raw[i]; + switch (b) { + case Byte_ascii.Num_0: case Byte_ascii.Num_1: case Byte_ascii.Num_2: case Byte_ascii.Num_3: case Byte_ascii.Num_4: + case Byte_ascii.Num_5: case Byte_ascii.Num_6: case Byte_ascii.Num_7: case Byte_ascii.Num_8: case Byte_ascii.Num_9: + int unit_digit = Byte_ascii.Xto_digit(b); + unit_val = (unit_multiple == 1) ? unit_digit : unit_val + (unit_digit * unit_multiple); + switch (colon_pos) { + case 0: val_s = unit_val; break; + case 1: val_m = unit_val; break; + case 2: val_h = unit_val; break; + default: return parse_null; // only hour:minute:second supported for ':' separator; ':' count should be <= 2 + } + unit_multiple *= 10; + break; + case Byte_ascii.Dot: + double factor = (double)1000 / (double)unit_multiple; // factor is necessary to handle non-standard decimals; ex: .1 -> 100; .00199 -> .001 + val_f = (int)((double)val_s * factor); // move val_s unit_val to val_f; logic is indirect, b/c of differing inputs: "123" means 123 seconds; ".123" means 123 fractionals + val_s = 0; + unit_multiple = 1; + break; + case Byte_ascii.Colon: + colon_pos++; + unit_multiple = 1; + break; + case Byte_ascii.Dash: + if (i == 0 && unit_val > 0) // only if first char && unit_val > 0 + sign = -1; + break; + case Byte_ascii.Space: case Byte_ascii.Tab: case Byte_ascii.Nl: case Byte_ascii.Cr: + if (fail_if_ws) return parse_null; + break; + default: + return parse_null; // invalid char; return null; + } + } + return sign * (val_f + (val_s * Divisors[1]) + (val_m * Divisors[2]) + (val_h * Divisors[3])); + } + @gplx.Internal protected static String XtoStr(long frc, String fmt) { + String_bldr sb = String_bldr_.new_(); + int[] units = Split_long(frc, Divisors); + + if (String_.Eq(fmt, TimeSpanAdp_.Fmt_Short)) { + for (int i = Idx_Hour; i > -1; i--) { + int val = units[i]; + if (val == 0 && i == Idx_Hour) continue; // skip hour if 0; ex: 01:02, instead of 00:01:02 + if (i == Idx_Frac) continue; // skip frac b/c fmt is short + if (sb.Count() > 0) // sb already has unit; add delimiter + sb.Add(Sprs[i]); + if (val < 10) // zeroPad + sb.Add("0"); + sb.Add(Int_.Xto_str(val)); + } + return sb.Xto_str_and_clear(); + } + boolean fmt_fracs = !String_.Eq(fmt, TimeSpanAdp_.Fmt_NoFractionals); + boolean fmt_padZeros = String_.Eq(fmt, TimeSpanAdp_.Fmt_PadZeros); + if (frc == 0) return fmt_padZeros ? "00:00:00.000" : "0"; + + int[] padZerosAry = ZeroPadding; + boolean first = true; + String dlm = ""; + int zeros = 0; + if (frc < 0) sb.Add("-"); // negative sign + for (int i = Idx_Hour; i > -1; i--) { // NOTE: "> Idx_Frac" b/c frc will be handled below + int val = units[i]; + if (i == Idx_Frac // only write fracs... + && !(val == 0 && fmt_padZeros) // ... if val == 0 && fmt is PadZeros + && !(val != 0 && fmt_fracs) // ... or val != 0 && fmt is PadZeros or Default + ) continue; + if (first && val == 0 && !fmt_padZeros) continue; // if first and val == 0, don't full pad (avoid "00:") + zeros = first && !fmt_padZeros ? 1 : padZerosAry[i]; // if first, don't zero pad (avoid "01") + dlm = first ? "" : Sprs[i]; // if first, don't use dlm (avoid ":01") + sb.Add(dlm); + sb.Add(Int_.Xto_str_pad_bgn_zero(val, zeros)); + first = false; + } + return sb.XtoStr(); + } + @gplx.Internal protected static int[] Split_long(long fracs, int[] divisors) { + int divLength = Array_.Len(divisors); + int[] rv = new int[divLength]; + long cur = Math_.Abs(fracs); + for (int i = divLength - 1; i > -1; i--) { + int divisor = divisors[i]; + long factor = cur / divisor; + rv[i] = (int)factor; + cur -= (factor * divisor); + } + return rv; + } + @gplx.Internal protected static long Merge_long(int[] vals, int[] divisors) { + long rv = 0; int valLength = Array_.Len(vals); + for (int i = 0; i < valLength; i++) { + rv += vals[i] * divisors[i]; + } + return rv; + } + public static final String Fmt_PadZeros = "00:00:00.000"; // u,h00:m00:s00.f000 + public static final String Fmt_Short = "short"; // u,h##:m#0:s00; + public static final String Fmt_Default = "0.000"; // v,#.000 + public static final String Fmt_NoFractionals = "0"; // v,# + @gplx.Internal protected static final int[] Divisors = { + 1, //1 fracs + 1000, //1,000 fracs in a second + 60000, //60,000 fracs in a minute (60 seconds * 1,000) + 3600000, //3,600,000 fracs in an hour (60 minutes * 60,000) + }; + public static final String MajorDelimiter = ":"; + @gplx.Internal protected static final int Idx_Frac = 0; + @gplx.Internal protected static final int Idx_Sec = 1; + @gplx.Internal protected static final int Idx_Min = 2; + @gplx.Internal protected static final int Idx_Hour = 3; + static int[] ZeroPadding = {3, 2, 2, 2,}; + static String[] Sprs = {".", MajorDelimiter, MajorDelimiter, "",}; + public static TimeSpanAdp cast_(Object arg) {try {return (TimeSpanAdp)arg;} catch(Exception exc) {throw Exc_.new_type_mismatch_w_exc(exc, TimeSpanAdp.class, arg);}} + public static final double Ratio_f_to_s = 1000; +} diff --git a/100_core/src_120_basicDataType/gplx/TimeSpanAdp__parse_tst.java b/100_core/src_120_basicDataType/gplx/TimeSpanAdp__parse_tst.java new file mode 100644 index 000000000..586fb6d5d --- /dev/null +++ b/100_core/src_120_basicDataType/gplx/TimeSpanAdp__parse_tst.java @@ -0,0 +1,54 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class TimeSpanAdp__parse_tst { + @Test public void Zero() { + tst_Parse("0", 0); + } + @Test public void Milliseconds() { + tst_Parse("0.987", 987); + tst_Parse("0.00199", 1); // do not parse as 199 + tst_Parse("0.1", 100); // do not parse as 1 + } + @Test public void Seconds() { + tst_Parse("1.987", 1987); + } + @Test public void Minutes() { + tst_Parse("1:02.987", 62987); + } + @Test public void MinuteSecondOnly() { + tst_Parse("1:02", 62000); + } + @Test public void Hour() { + tst_Parse("1:02:03.987", 3723987); + } + @Test public void Negative() { + tst_Parse("-1:02:03.987", -3723987); + } + @Test public void Loopholes() { + tst_Parse("001:02", 62000); // multiple leading zeroes + tst_Parse("1.2.3.4", 1200); // ignore all decimals except first + tst_Parse("60:60.9999", 3660999); // value does not need to be bounded to limits (except fracs, which is always < 1000) + tst_Parse(" 01 : 02 : 03 . 987", 3723987); // whitespace + } + void tst_Parse(String text, long expd) { + TimeSpanAdp val = TimeSpanAdp_.parse_(text); + Tfds.Eq(expd, val.Fracs()); + } +} diff --git a/100_core/src_120_basicDataType/gplx/TimeSpanAdp_basic_tst.java b/100_core/src_120_basicDataType/gplx/TimeSpanAdp_basic_tst.java new file mode 100644 index 000000000..f7a94ca75 --- /dev/null +++ b/100_core/src_120_basicDataType/gplx/TimeSpanAdp_basic_tst.java @@ -0,0 +1,87 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class TimeSpanAdp_basic_tst { + @Test public void seconds_() { + TimeSpanAdp expd = TimeSpanAdp_.fracs_(123987); + TimeSpanAdp actl = TimeSpanAdp_.seconds_(123.987); + Tfds.Eq(expd, actl); + } + @Test public void TotalSecs() { + TimeSpanAdp val = TimeSpanAdp_.fracs_(1987); + Tfds.Eq_decimal(DecimalAdp_.parts_(1, 987), val.TotalSecs()); + } + @Test public void Units() { + tst_Units("01:02:03.987", 1, 2, 3, 987); + tst_Units("01:00:03", 1, 0, 3, 0); + tst_Units("01:00:00.987", 1, 0, 0, 987); + tst_Units("02:00.987", 0, 2, 0, 987); + } + @Test public void Add() { + TimeSpanAdp val = TimeSpanAdp_.fracs_(3); + TimeSpanAdp arg = TimeSpanAdp_.fracs_(2); + TimeSpanAdp expd = TimeSpanAdp_.fracs_(5); + TimeSpanAdp actl = val.Add(arg); + Tfds.Eq(expd, actl); + } + @Test public void Subtract() { + TimeSpanAdp val = TimeSpanAdp_.fracs_(3); + TimeSpanAdp arg = TimeSpanAdp_.fracs_(2); + TimeSpanAdp expd = TimeSpanAdp_.fracs_(1); + TimeSpanAdp actl = val.Subtract(arg); + Tfds.Eq(expd, actl); + } + @Test public void Add_unit_identity() { + tst_AddUnit("00:00:01.000", 0, 0, "00:00:01.000"); + } + @Test public void Add_unit_basic() { + tst_AddUnit("01:59:58.987", 0, 1013, "02:00:00.000"); + tst_AddUnit("01:59:58.987", 1, 2, "02:00:00.987"); + tst_AddUnit("01:59:58.987", 2, 1, "02:00:58.987"); + tst_AddUnit("01:59:58.987", 3, 1, "02:59:58.987"); + } + @Test public void Add_unit_negative() { + tst_AddUnit("01:00:00.00", 0, -1, "00:59:59.999"); + tst_AddUnit("01:00:00.00", 1, -1, "00:59:59.000"); + tst_AddUnit("01:00:00.00", 2, -1, "00:59:00.000"); + tst_AddUnit("01:00:00.00", 3, -1, "00:00:00.000"); + } + @Test public void XtoStrUiAbbrv() { + tst_XtoStrUiAbbrv("01:02:03.004", "1h 2m 3s 4f"); + tst_XtoStrUiAbbrv("00:00:03.004", "3s 4f"); + tst_XtoStrUiAbbrv("00:00:03.000", "3s 0f"); + tst_XtoStrUiAbbrv("11:22:33.444", "11h 22m 33s 444f"); + tst_XtoStrUiAbbrv("00:00:00.000", "0f"); + } void tst_XtoStrUiAbbrv(String raw, String expd) {Tfds.Eq(expd, TimeSpanAdp_.parse_(raw).XtoStrUiAbbrv());} + void tst_AddUnit(String valRaw, int unitIdx, int delta, String expdRaw) { + TimeSpanAdp val = TimeSpanAdp_.parse_(valRaw); + TimeSpanAdp actl = val.Add_unit(unitIdx, delta); + Tfds.Eq(TimeSpanAdp_.parse_(expdRaw), actl); + } + void tst_Units(String text, int... expd) { + TimeSpanAdp val = TimeSpanAdp_.parse_(text); + int hour = 0, min = 0, sec = 0, frac = 0; + int[] ary = val.Units(); + hour = ary[TimeSpanAdp_.Idx_Hour]; min = ary[TimeSpanAdp_.Idx_Min]; sec = ary[TimeSpanAdp_.Idx_Sec]; frac = ary[TimeSpanAdp_.Idx_Frac]; + Tfds.Eq(expd[0], hour); + Tfds.Eq(expd[1], min); + Tfds.Eq(expd[2], sec); + Tfds.Eq(expd[3], frac); + } +} diff --git a/100_core/src_120_basicDataType/gplx/TimeSpanAdp_xtoStr_tst.java b/100_core/src_120_basicDataType/gplx/TimeSpanAdp_xtoStr_tst.java new file mode 100644 index 000000000..7c5be5acc --- /dev/null +++ b/100_core/src_120_basicDataType/gplx/TimeSpanAdp_xtoStr_tst.java @@ -0,0 +1,59 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class TimeSpanAdp_xtoStr_tst { + @Test public void Zero() { + tst_Default(0, "0"); + } + @Test public void MinuteSeconds() { + tst_Default(77000, "1:17"); + } + @Test public void ZeroSuppression() { + tst_Default(660000, "11:00"); //fractional 0 and leading 0s are suppressed; i.e.: not 00:11:00.000 + } + @Test public void HourTest() { + tst_Default(3723987, "1:02:03.987"); + } + @Test public void NegSeconds() { + tst_Default(-2000, "-2"); + } + @Test public void NegMins() { + tst_Default(-60000, "-1:00"); + } + @Test public void NegHours() { + tst_Default(-3723981, "-1:02:03.981"); + } + @Test public void ZeroPadding() { + tst_ZeroPadding("0", "00:00:00.000"); + tst_ZeroPadding("1:02:03.123", "01:02:03.123"); + tst_ZeroPadding("1", "00:00:01.000"); + tst_ZeroPadding(".987", "00:00:00.987"); + tst_ZeroPadding("2:01.456", "00:02:01.456"); + } + void tst_Default(long fractionals, String expd) { + TimeSpanAdp ts = TimeSpanAdp_.fracs_(fractionals); + String actl = ts.XtoStr(TimeSpanAdp_.Fmt_Default); + Tfds.Eq(expd, actl); + } + void tst_ZeroPadding(String val, String expd) { + TimeSpanAdp timeSpan = TimeSpanAdp_.parse_(val); + String actl = timeSpan.XtoStr(TimeSpanAdp_.Fmt_PadZeros); + Tfds.Eq(expd, actl); + } +} diff --git a/100_core/src_120_basicDataType/gplx/Url_encoder_interface.java b/100_core/src_120_basicDataType/gplx/Url_encoder_interface.java new file mode 100644 index 000000000..041ede786 --- /dev/null +++ b/100_core/src_120_basicDataType/gplx/Url_encoder_interface.java @@ -0,0 +1,27 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public interface Url_encoder_interface { + String Encode_str(String v); + byte[] Encode_bry(String v); +} +class Url_encoder_interface_same implements Url_encoder_interface { + public String Encode_str(String v) {return v;} + public byte[] Encode_bry(String v) {return Bry_.new_u8(v);} + public static final Url_encoder_interface_same _ = new Url_encoder_interface_same(); Url_encoder_interface_same() {} +} diff --git a/100_core/src_120_basicDataType/gplx/Yn.java b/100_core/src_120_basicDataType/gplx/Yn.java new file mode 100644 index 000000000..adeaea94c --- /dev/null +++ b/100_core/src_120_basicDataType/gplx/Yn.java @@ -0,0 +1,78 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Yn { + public static final String Y = "y", N = "n"; + public static boolean parse_by_char_or(String v, boolean or) { + if (String_.Eq(v, Y)) return true; + else if (String_.Eq(v, N)) return false; + else return or; + } + public static boolean parse_or_n_(String v) {return parse_or_(v, false);} + public static int parse_as_int(String v) { + if (v == null) return Bool_.__int; + else if (String_.Eq(v, "y")) return Bool_.Y_int; + else if (String_.Eq(v, "n")) return Bool_.N_int; + else return Bool_.__int; + } + public static boolean parse_or_(String v, boolean or) { + int v_int = parse_as_int(v); + switch (v_int) { + case Bool_.N_int: return false; + case Bool_.Y_int: return true; + case Bool_.__int: return or; + default: throw Exc_.new_unhandled(v_int); + } + } + public static boolean parse_(String v) { + int v_int = parse_as_int(v); + if (v_int == Bool_.__int) Exc_.new_unhandled(v); + return v_int == Bool_.Y_int; + } + public static String Xto_str(boolean v) {return v ? "y" : "n";} + public static String Xto_nullable_str(byte v) { + switch (v) { + case Bool_.Y_byte: return "y"; + case Bool_.N_byte: return "n"; + case Bool_.__byte: return "?"; + default: throw Exc_.new_unhandled(v); + } + } + public static byte Xto_nullable_byte(String v) { + if (v != null && String_.Len(v) == 1) { + char c = String_.CharAt(v, 0); + switch (c) { + case 'y': return Bool_.Y_byte; + case 'n': return Bool_.N_byte; + case '?': return Bool_.__byte; + } + } + throw Exc_.new_unhandled(v); + } + public static boolean store_bool_or(SrlMgr mgr, String key, boolean or) { + String v = mgr.SrlStrOr(key, ""); + return mgr.Type_rdr() ? parse_or_(v, or) : or; + } + public static boolean coerce_(Object o) {String s = String_.as_(o); return s != null ? parse_or_(s, false) : Bool_.cast_(o);} + public static boolean readOrFalse_(DataRdr rdr, String key) {return read_(rdr, key, false);} + public static boolean readOrTrue_(DataRdr rdr, String key) {return read_(rdr, key, true);} + static boolean read_(DataRdr rdr, String key, boolean or) { + String v = rdr.ReadStrOr(key, null); + return parse_or_(v, or); + } +} \ No newline at end of file diff --git a/100_core/src_140_list/gplx/Hash_adp.java b/100_core/src_140_list/gplx/Hash_adp.java new file mode 100644 index 000000000..88461ff32 --- /dev/null +++ b/100_core/src_140_list/gplx/Hash_adp.java @@ -0,0 +1,31 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public interface Hash_adp extends gplx.lists.EnumerAble { + int Count(); + boolean Has(Object key); + Object Get_by(Object key); + Object Get_by_or_fail(Object key); + Object Get_by_or_new(Object key, NewAble prototype); + void Add(Object key, Object val); + void Add_as_key_and_val(Object val); + boolean Add_if_dupe_use_1st(Object key, Object val); + void Add_if_dupe_use_nth(Object key, Object val); + void Del(Object key); + void Clear(); +} diff --git a/100_core/src_140_list/gplx/Hash_adp_.java b/100_core/src_140_list/gplx/Hash_adp_.java new file mode 100644 index 000000000..bc70b0ff5 --- /dev/null +++ b/100_core/src_140_list/gplx/Hash_adp_.java @@ -0,0 +1,38 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.core.primitives.*; +public class Hash_adp_ { + public static Hash_adp new_() {return new Hash_adp_obj();} + public static final Hash_adp Noop = new Hash_adp_noop(); +} +class Hash_adp_obj extends gplx.lists.Hash_adp_base implements Hash_adp {}//_20110428 +class Hash_adp_noop implements Hash_adp { + public int Count() {return 0;} + public boolean Has(Object key) {return false;} + public Object Get_by(Object key) {return null;} + public Object Get_by_or_fail(Object key) {throw Exc_.new_missing_key(Object_.Xto_str_strict_or_null_mark(key));} + public Object Get_by_or_new(Object key, NewAble proto) {throw Exc_.new_("could not add to null hash");} + public void Add(Object key, Object val) {} + public void Add_as_key_and_val(Object val) {} + public void Add_if_dupe_use_nth(Object key, Object val) {} + public boolean Add_if_dupe_use_1st(Object key, Object val) {return false;} + public void Del(Object key) {} + public void Clear() {} + public java.util.Iterator iterator() {return gplx.lists.Iterator_null._;} +} diff --git a/100_core/src_140_list/gplx/Hash_adp_bry.java b/100_core/src_140_list/gplx/Hash_adp_bry.java new file mode 100644 index 000000000..7a82da9c2 --- /dev/null +++ b/100_core/src_140_list/gplx/Hash_adp_bry.java @@ -0,0 +1,184 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.core.primitives.*; +import gplx.intl.*; +public class Hash_adp_bry extends gplx.lists.Hash_adp_base implements Hash_adp { + private final Hash_adp_bry_itm_base proto, key_ref; + Hash_adp_bry(Hash_adp_bry_itm_base proto) { + this.proto = proto; + key_ref = proto.New(); + } + @Override protected Object Fetch_base(Object key) {return super.Fetch_base(key_ref.Init((byte[])key));} + @Override protected void Del_base(Object key) {super.Del_base(key_ref.Init((byte[])key));} + @Override protected boolean Has_base(Object key) {return super.Has_base(key_ref.Init((byte[])key));} + public Object Get_by_bry(byte[] src) {return super.Fetch_base(key_ref.Init(src));} + public Object Get_by_mid(byte[] src, int bgn, int end) {return super.Fetch_base(key_ref.Init(src, bgn, end));} + public Hash_adp_bry Add_bry_byte(byte[] key, byte val) {this.Add_base(key, Byte_obj_val.new_(val)); return this;} + public Hash_adp_bry Add_bry_int(byte[] key, int val) {this.Add_base(key, Int_obj_val.new_(val)); return this;} + public Hash_adp_bry Add_bry_bry(byte[] key) {this.Add_base(key, key); return this;} + public Hash_adp_bry Add_str_byte(String key, byte val) {this.Add_base(Bry_.new_u8(key), Byte_obj_val.new_(val)); return this;} + public Hash_adp_bry Add_str_int(String key, int val) {this.Add_base(Bry_.new_u8(key), Int_obj_val.new_(val)); return this;} + public Hash_adp_bry Add_str_obj(String key, Object val) {this.Add_base(Bry_.new_u8(key), val); return this;} + public Hash_adp_bry Add_bry_obj(byte[] key, Object val) {this.Add_base(key, val); return this;} + public Hash_adp_bry Add_many_str(String... ary) { + int ary_len = ary.length; + for (int i = 0; i < ary_len; i++) { + String itm = ary[i]; + byte[] bry = Bry_.new_u8(itm); + Add_bry_bry(bry); + } + return this; + } + @Override protected void Add_base(Object key, Object val) { + byte[] key_bry = (byte[])key; + Hash_adp_bry_itm_base key_itm = proto.New(); + key_itm.Init(key_bry, 0, key_bry.length); + super.Add_base(key_itm, val); + } + public static Hash_adp_bry cs_() {return new Hash_adp_bry(Hash_adp_bry_itm_cs._);} + public static Hash_adp_bry ci_ascii_() {return new Hash_adp_bry(Hash_adp_bry_itm_ci_ascii._);} + public static Hash_adp_bry ci_utf8_(Gfo_case_mgr case_mgr) {return new Hash_adp_bry(Hash_adp_bry_itm_ci_utf8.get_or_new(case_mgr));} + public static Hash_adp_bry c__utf8_(boolean case_match, Gfo_case_mgr case_mgr) {return case_match ? cs_() : ci_utf8_(case_mgr);} +} +abstract class Hash_adp_bry_itm_base { + public abstract Hash_adp_bry_itm_base New(); + public Hash_adp_bry_itm_base Init(byte[] src) {return this.Init(src, 0, src.length);} + public abstract Hash_adp_bry_itm_base Init(byte[] src, int src_bgn, int src_end); +} +class Hash_adp_bry_itm_cs extends Hash_adp_bry_itm_base { + private byte[] src; int src_bgn, src_end; + @Override public Hash_adp_bry_itm_base New() {return new Hash_adp_bry_itm_cs();} + @Override public Hash_adp_bry_itm_base Init(byte[] src, int src_bgn, int src_end) {this.src = src; this.src_bgn = src_bgn; this.src_end = src_end; return this;} + @Override public int hashCode() { + int rv = 0; + for (int i = src_bgn; i < src_end; i++) { + int b_int = src[i] & 0xFF; // JAVA: patch + rv = (31 * rv) + b_int; + } + return rv; + } + @Override public boolean equals(Object obj) { + if (obj == null) return false; + Hash_adp_bry_itm_cs comp = (Hash_adp_bry_itm_cs)obj; + byte[] comp_src = comp.src; int comp_bgn = comp.src_bgn, comp_end = comp.src_end; + int comp_len = comp_end - comp_bgn, src_len = src_end - src_bgn; + if (comp_len != src_len) return false; + for (int i = 0; i < comp_len; i++) { + int src_pos = src_bgn + i; + if (src_pos >= src_end) return false; // ran out of src; exit; EX: src=ab; find=abc + if (src[src_pos] != comp_src[i + comp_bgn]) return false; + } + return true; + } + public static final Hash_adp_bry_itm_cs _ = new Hash_adp_bry_itm_cs(); Hash_adp_bry_itm_cs() {} +} +class Hash_adp_bry_itm_ci_ascii extends Hash_adp_bry_itm_base { + private byte[] src; int src_bgn, src_end; + @Override public Hash_adp_bry_itm_base New() {return new Hash_adp_bry_itm_ci_ascii();} + @Override public Hash_adp_bry_itm_base Init(byte[] src, int src_bgn, int src_end) {this.src = src; this.src_bgn = src_bgn; this.src_end = src_end; return this;} + @Override public int hashCode() { + int rv = 0; + for (int i = src_bgn; i < src_end; i++) { + int b_int = src[i] & 0xFF; // JAVA: patch + if (b_int > 64 && b_int < 91) // 64=before A; 91=after Z; NOTE: lowering upper-case on PERF assumption that there will be more lower-case letters than upper-case + b_int += 32; + rv = (31 * rv) + b_int; + } + return rv; + } + @Override public boolean equals(Object obj) { + if (obj == null) return false; + Hash_adp_bry_itm_ci_ascii comp = (Hash_adp_bry_itm_ci_ascii)obj; + byte[] comp_src = comp.src; int comp_bgn = comp.src_bgn, comp_end = comp.src_end; + int comp_len = comp_end - comp_bgn, src_len = src_end - src_bgn; + if (comp_len != src_len) return false; + for (int i = 0; i < comp_len; i++) { + int src_pos = src_bgn + i; + if (src_pos >= src_end) return false; // ran out of src; exit; EX: src=ab; find=abc + byte src_byte = src[src_pos]; + if (src_byte > 64 && src_byte < 91) src_byte += 32; + byte comp_byte = comp_src[i + comp_bgn]; + if (comp_byte > 64 && comp_byte < 91) comp_byte += 32; + if (src_byte != comp_byte) return false; + } + return true; + } + public static final Hash_adp_bry_itm_ci_ascii _ = new Hash_adp_bry_itm_ci_ascii(); Hash_adp_bry_itm_ci_ascii() {} +} +class Hash_adp_bry_itm_ci_utf8 extends Hash_adp_bry_itm_base { + private final Gfo_case_mgr case_mgr; + Hash_adp_bry_itm_ci_utf8(Gfo_case_mgr case_mgr) {this.case_mgr = case_mgr;} + private byte[] src; int src_bgn, src_end; + @Override public Hash_adp_bry_itm_base New() {return new Hash_adp_bry_itm_ci_utf8(case_mgr);} + @Override public Hash_adp_bry_itm_base Init(byte[] src, int src_bgn, int src_end) {this.src = src; this.src_bgn = src_bgn; this.src_end = src_end; return this;} + @Override public int hashCode() { + int rv = 0; + for (int i = src_bgn; i < src_end; i++) { + byte b = src[i]; + int b_int = b & 0xFF; // JAVA: patch + Gfo_case_itm itm = case_mgr.Get_or_null(b, src, i, src_end); + if (itm == null) { // unknown itm; byte is a number, symbol, or unknown; just use the existing byte + } + else { // known itm; use its hash_code + b_int = itm.Hashcode_lo(); + i += itm.Len_lo() - 1; + } + rv = (31 * rv) + b_int; + } + return rv; + } + @Override public boolean equals(Object obj) { + if (obj == null) return false; + Hash_adp_bry_itm_ci_utf8 trg_itm = (Hash_adp_bry_itm_ci_utf8)obj; + byte[] trg = trg_itm.src; int trg_bgn = trg_itm.src_bgn, trg_end = trg_itm.src_end; + int src_c_bgn = src_bgn; + int trg_c_bgn = trg_bgn; + while ( src_c_bgn < src_end + && trg_c_bgn < trg_end) { // exit once one goes out of bounds + byte src_c = src[src_c_bgn]; + byte trg_c = trg[trg_c_bgn]; + int src_c_len = Utf8_.Len_of_char_by_1st_byte(src_c); + int trg_c_len = Utf8_.Len_of_char_by_1st_byte(trg_c); + int src_c_end = src_c_bgn + src_c_len; + int trg_c_end = trg_c_bgn + trg_c_len; + Gfo_case_itm src_c_itm = case_mgr.Get_or_null(src_c, src, src_c_bgn, src_c_end); + Gfo_case_itm trg_c_itm = case_mgr.Get_or_null(trg_c, trg, trg_c_bgn, trg_c_end); + if (src_c_itm != null && trg_c_itm == null) return false; // src == ltr; trg != ltr; EX: a, 1 + else if (src_c_itm == null && trg_c_itm != null) return false; // src != ltr; trg == ltr; EX: 1, a + else if (src_c_itm == null && trg_c_itm == null) { // src != ltr; trg != ltr; EX: 1, 2; _, Ⓐ + if (!Bry_.Match(src, src_c_bgn, src_c_end, trg, trg_c_bgn, trg_c_end)) return false;// syms do not match; return false; + } + else { + if (!src_c_itm.Eq_lo(trg_c_itm)) return false; // lower-case hash-codes don't match; return false; + } + src_c_bgn = src_c_end; + trg_c_bgn = trg_c_end; + } + return src_c_bgn == src_end && trg_c_bgn == trg_end; // only return true if both src and trg read to end of their brys, otherwise "a","ab" will match + } + public static Hash_adp_bry_itm_ci_utf8 get_or_new(Gfo_case_mgr case_mgr) { + switch (case_mgr.Tid()) { + case Gfo_case_mgr_.Tid_ascii: if (Itm_ascii == null) Itm_ascii = new Hash_adp_bry_itm_ci_utf8(case_mgr); return Itm_ascii; + case Gfo_case_mgr_.Tid_utf8: if (Itm_utf8 == null) Itm_utf8 = new Hash_adp_bry_itm_ci_utf8(case_mgr); return Itm_utf8; + case Gfo_case_mgr_.Tid_custom: return new Hash_adp_bry_itm_ci_utf8(case_mgr); + default: throw Exc_.new_unhandled(case_mgr.Tid()); + } + } + private static Hash_adp_bry_itm_ci_utf8 Itm_ascii, Itm_utf8; +} diff --git a/100_core/src_140_list/gplx/Hash_adp_bry_tst.java b/100_core/src_140_list/gplx/Hash_adp_bry_tst.java new file mode 100644 index 000000000..a489e5b81 --- /dev/null +++ b/100_core/src_140_list/gplx/Hash_adp_bry_tst.java @@ -0,0 +1,68 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class Hash_adp_bry_tst { + @Before public void setup() {fxt.Clear();} private Hash_adp_bry_fxt fxt = new Hash_adp_bry_fxt(); + @Test public void Add_bry() { + fxt .New_cs() + .Add("a0").Add("b0").Add("c0") + .Get_bry_tst("a0").Get_bry_tst("b0").Get_bry_tst("c0").Get_bry_tst("A0", null) + ; + } + @Test public void Get_mid() { + fxt .New_cs() + .Add("a0").Add("b0").Add("c0") + .Get_mid_tst("xyza0xyz", 3, 5, "a0") + .Get_mid_tst("xyza0xyz", 3, 4, null) + ; + } + @Test public void Case_insensitive() { + fxt .New_ci() + .Add("a0").Add("B0").Add("c0") + .Get_bry_tst("a0", "a0") + .Get_bry_tst("A0", "a0") + .Get_bry_tst("b0", "B0") + .Get_bry_tst("B0", "B0") + .Get_mid_tst("xyza0xyz", 3, 5, "a0") + .Get_mid_tst("xyzA0xyz", 3, 5, "a0") + .Count_tst(3) + ; + } +} +class Hash_adp_bry_fxt { + Hash_adp_bry hash; + public void Clear() {} + public Hash_adp_bry_fxt New_cs() {hash = Hash_adp_bry.cs_(); return this;} + public Hash_adp_bry_fxt New_ci() {hash = Hash_adp_bry.ci_ascii_(); return this;} + public Hash_adp_bry_fxt Add(String key) {byte[] key_bry = Bry_.new_u8(key); hash.Add(key_bry, key_bry); return this;} + public Hash_adp_bry_fxt Count_tst(int expd) {Tfds.Eq(expd, hash.Count()); return this;} + public Hash_adp_bry_fxt Get_bry_tst(String key) {return Get_bry_tst(key, key);} + public Hash_adp_bry_fxt Get_bry_tst(String key, String expd) { + byte[] key_bry = Bry_.new_u8(key); + byte[] actl_bry = (byte[])hash.Get_by_bry(key_bry); + Tfds.Eq(expd, String_.new_u8(actl_bry)); + return this; + } + public Hash_adp_bry_fxt Get_mid_tst(String key, int bgn, int end, String expd) { + byte[] key_bry = Bry_.new_u8(key); + byte[] actl_bry = (byte[])hash.Get_by_mid(key_bry, bgn, end); + Tfds.Eq(expd, String_.new_u8(actl_bry)); + return this; + } +} diff --git a/100_core/src_140_list/gplx/List_adp.java b/100_core/src_140_list/gplx/List_adp.java new file mode 100644 index 000000000..fc353db87 --- /dev/null +++ b/100_core/src_140_list/gplx/List_adp.java @@ -0,0 +1,73 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.lists.*; /*EnumerAble,ComparerAble*/ +public interface List_adp extends EnumerAble { + int Count(); + Object Get_at(int i); + Object Get_at_last(); + void Add(Object o); + void Add_at(int i, Object o); + void Add_many(Object... ary); + void Del(Object o); + void Del_at(int i); + void Del_range(int bgn, int end); + void Clear(); + int Idx_of(Object o); + int Idx_last(); + Object To_ary(Class memberType); + Object To_ary_and_clear(Class memberType); + String[] To_str_ary(); + Object[] To_obj_ary(); + void Resize_bounds(int i); + void Move_to(int src, int trg); + void Reverse(); + void Sort(); + void Sort_by(ComparerAble comparer); + void Shuffle(); +} +class List_adp_obj extends List_adp_base implements List_adp { + public List_adp_obj() {super();} + public List_adp_obj(int v) {super(v);} +} +class List_adp_noop implements List_adp { + public int Count() {return 0;} + public Object Get_at(int i) {return null;} + public Object Get_at_last() {return null;} + public Object PopLast() {return null;} + public void Add(Object o) {} + public void Add_at(int i, Object o) {} + public void Add_many(Object... ary) {} + public void Del(Object o) {} + public void Del_at(int i) {} + public void Del_range(int bgn, int end) {} + public void Clear() {} + public int Idx_last() {return -1;} + public int Idx_of(Object o) {return List_adp_.NotFound;} + public void Move_to(int elemPos, int newPos) {} + public void Resize_bounds(int i) {} + public Object To_ary(Class memberType) {return Object_.Ary_empty;} + public Object To_ary_and_clear(Class memberType) {return Object_.Ary_empty;} + public String[] To_str_ary() {return new String[0];} + public Object[] To_obj_ary() {return Object_.Ary_empty;} + public java.util.Iterator iterator() {return Iterator_null._;} + public void Reverse() {} + public void Sort() {} + public void Sort_by(ComparerAble comparer) {} + public void Shuffle() {} +} diff --git a/100_core/src_140_list/gplx/List_adp_.java b/100_core/src_140_list/gplx/List_adp_.java new file mode 100644 index 000000000..7ea257ecd --- /dev/null +++ b/100_core/src_140_list/gplx/List_adp_.java @@ -0,0 +1,66 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.lists.*; /*EnumerAble,ComparerAble*/ +public class List_adp_ { + public static final List_adp Noop = new List_adp_noop(); + public static List_adp as_(Object obj) {return obj instanceof List_adp ? (List_adp)obj : null;} + public static List_adp new_() {return new List_adp_obj();} + public static List_adp size_(int v) {return new List_adp_obj(v);} + public static List_adp many_(Object... ary) { + List_adp rv = new List_adp_obj(); + rv.Add_many(ary); + return rv; + } + public static void Add_list(List_adp rv, List_adp add) { + int len = add.Count(); + for (int i = 0; i < len; ++i) + rv.Add(add.Get_at(i)); + } + public static void DelAt_last(List_adp list) {list.Del_at(list.Count() - 1);} + public static Object Pop(List_adp list) { + int lastIdx = list.Count() - 1; + Object rv = list.Get_at(lastIdx); + list.Del_at(lastIdx); + return rv; + } + public static Object Pop_first(List_adp list) { // NOTE: dirty way of implementing FIFO queue; should not be used with lists with many members + Object rv = list.Get_at(0); + list.Del_at(0); + return rv; + } + public static Object Pop_last(List_adp list) { + int last_idx = list.Count() - 1; + Object rv = list.Get_at(last_idx); + list.Del_at(last_idx); + return rv; + } + public static void DisposeAll(List_adp list) { + for (int i = 0; i < list.Count(); i++) + ((RlsAble)list.Get_at(i)).Rls(); + } + public static List_adp new_ary_(Object ary) { + int ary_len = Array_.Len(ary); + List_adp rv = size_(ary_len); + for (int i = 0; i < ary_len; i++) + rv.Add(Array_.Get(ary, i)); + return rv; + } + public static final int Capacity_initial = 8; + public static final int NotFound = -1, Base1 = 1, LastIdxOffset = 1, CountToPos = 1; +} diff --git a/100_core/src_140_list/gplx/List_adp_base.java b/100_core/src_140_list/gplx/List_adp_base.java new file mode 100644 index 000000000..14ecd5b53 --- /dev/null +++ b/100_core/src_140_list/gplx/List_adp_base.java @@ -0,0 +1,166 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.core.strings.*; import gplx.lists.*; +public abstract class List_adp_base implements List_adp, GfoInvkAble { + private Object[] list; private int count; + public Object To_ary_and_clear(Class memberType) {Object rv = To_ary(memberType); this.Clear(); return rv;} + public Object To_ary(Class memberType) { + Object rv = Array_.Create(memberType, count); + for (int i = 0; i < count; i++) + Array_.Set(rv, i, list[i]); + return rv; + } + public Object[] To_obj_ary() { + Object[] rv = new Object[count]; + for (int i = 0; i < count; ++i) + rv[i] = list[i]; + return rv; + } + public java.util.Iterator iterator() { + if (count == 0) + return Iterator_null._; + else + return new Iterator_objAry(list, count); + } + public void Add_many(Object... ary) {for (Object o : ary) Add_base(o);} + public int Count() {return count;} + public int Idx_last() {return count - 1;} + protected Object Get_at_base(int index) {if (index >= count || index < 0) throw Exc_.new_missing_idx(index, count); + return list[index]; + } + protected void Add_base(Object o) { + if (count == Array_.LenAry(list)) Resize_expand(); + list[count] = o; + count++; + } + protected int Del_base(Object o) { + int index = IndexOf_base(o); if (index == List_adp_.NotFound) return List_adp_.NotFound; + this.Del_at(index); + return index; + } + public void Del_range(int delBgn, int delEnd) { + BoundsChk(delBgn, delEnd, count); + if (delBgn == 0 && delEnd == count - 1) { // entire list deleted; call .Clear, else will have 0 elem array + this.Clear(); + return; + } + int delLen = (delEnd - delBgn) + 1; // EX: 0,2 creates 3 len ary + int newLen = count - delLen; + Object[] newList = new Object[newLen]; + if (delBgn != 0) // copy elements < delBgn; skip if delBgn == 0 + Array_.CopyTo(list, 0, newList, 0, delBgn); + if (delEnd != count -1 ) // copy elements > delEnd; skip if delEnd == lastIdx + Array_.CopyTo(list, delEnd + 1, newList, delBgn, newLen - delBgn); + list = newList; + count = list.length; + } + protected int IndexOf_base(Object o) { + for (int i = 0; i < count; i++) + if (Object_.Eq(list[i], o)) return i; + return List_adp_.NotFound; + } + @gplx.Virtual public void Clear() { + for (int i = 0; i < count; i++) + list[i] = null; + count = 0; + } + @gplx.Virtual public void Del_at(int index) {if (index >= count || index < 0) throw Exc_.new_missing_idx(index, count); + Collapse(index); + count--; + } + public void Move_to(int src, int trg) {if (src >= count || src < 0) throw Exc_.new_missing_idx(src, count); if (trg >= count || trg < 0) throw Exc_.new_missing_idx(trg, count); + if (src == trg) return; // position not changed + Object o = list[src]; + int dif = trg > src ? 1 : -1; + for (int i = src; i != trg; i += dif) + list[i] = list[i + dif]; + list[trg] = o; + } + protected void AddAt_base(int pos, Object o) { + if (count + 1 >= Array_.LenAry(list)) Resize_expand(); + for (int i = count; i > pos; i--) + list[i] = list[i - 1]; + list[pos] = o; + count = count + 1; + } + public void Resize_bounds(int i) { + Resize_expand(i); + } + public void Sort() {Sort_by(null);} + public void Sort_by(ComparerAble comparer) {List_adp_sorter.new_().Sort(list, count, true, comparer);} + public void Reverse() { + int mid = count / 2; // no need to reverse pivot; ex: for 3 elements, only 1 and 3 need to be exchanged; 2 stays inplace + for (int lhs = 0; lhs < mid; lhs++) { + int rhs = count - lhs - 1; // -1 b/c list[count] is not real element + Object temp = list[lhs]; + list[lhs] = list[rhs]; + list[rhs] = temp; + } + } + @gplx.Virtual public void Shuffle() {// REF: Fisher-Yates shuffle + RandomAdp random = RandomAdp_.new_(); + for (int i = count; i > 1; i--) { + int rndIdx = random.Next(i); + Object tmp = list[rndIdx]; + list[rndIdx] = list[i-1]; + list[i-1] = tmp; + } + } + public String[] To_str_ary() {return (String[])To_ary(String.class);} + public Object Get_at(int i) {return Get_at_base(i);} + public Object Get_at_last() {if (count == 0) throw Exc_.new_invalid_op("cannot call Get_at_last on empty list"); return Get_at_base(count - 1);} + public void Add(Object item) {Add_base(item);} + public void Add_at(int i, Object o) {AddAt_base(i, o);} + public void Del(Object item) {Del_base(item);} + public int Idx_of(Object o) {return IndexOf_base(o);} + public List_adp_base() { + list = new Object[List_adp_.Capacity_initial]; + } + public List_adp_base(int capacity) { + list = new Object[capacity]; + } + private void BoundsChk(int bgn, int end, int len) { + if ( bgn >= 0 && bgn < len + && end >= 0 && end < len + && bgn <= end + ) return; + throw Exc_.new_("bounds check failed", "bgn", bgn, "end", end, "len", len); + } + void Resize_expand() {Resize_expand(count * 2);} + void Resize_expand(int newCount) { + Object[] trg = new Object[newCount]; + for (int i = 0; i < count; i++) { + trg[i] = list[i]; + list[i] = null; + } + list = trg; + } + void Collapse(int index) { + for (int i = index; i < count; i++) { + list[i] = (i == count - 1) ? null : list[i + 1]; + } + } + @gplx.Internal protected int Capacity() {return Array_.LenAry(list);} + public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) { + if (ctx.Match(k, Invk_len)) return count; + else if (ctx.Match(k, Invk_get_at)) return Get_at(m.ReadInt("v")); + else return GfoInvkAble_.Rv_unhandled; +// return this; + } private static final String Invk_len = "len", Invk_get_at = "get_at"; +} diff --git a/100_core/src_140_list/gplx/List_adp_sorter.java b/100_core/src_140_list/gplx/List_adp_sorter.java new file mode 100644 index 000000000..ec32f5b1b --- /dev/null +++ b/100_core/src_140_list/gplx/List_adp_sorter.java @@ -0,0 +1,73 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.lists.*; +public class List_adp_sorter { + private ComparerAble comparer = null; + public void Sort(Object[] orig, int origLen) {Sort(orig, origLen, true, null);} + public void Sort(Object[] orig, int origLen, boolean asc, ComparerAble comparer) { + this.comparer = comparer; + Object[] temp = new Object[origLen]; + MergeSort(asc, orig, temp, 0, origLen - 1); + this.comparer = null; + } + void MergeSort(boolean asc, Object[] orig,Object[] temp, int lhs, int rhs) { + if (lhs < rhs) { + int mid = (lhs + rhs) / 2; + MergeSort(asc, orig, temp, lhs, mid); + MergeSort(asc, orig, temp, mid + 1, rhs); + Combine(asc, orig, temp, lhs, mid + 1, rhs); + } + } + private void Combine(boolean asc, Object[] orig, Object[] temp, int lhsPos, int rhsPos, int rhsEnd) { + int lhsEnd = rhsPos - 1; + int tmpPos = lhsPos; + int aryLen = rhsEnd - lhsPos + 1; + + while (lhsPos <= lhsEnd && rhsPos <= rhsEnd) { + int compareVal = 0; + if (comparer != null) + compareVal = ComparerAble_.Compare(comparer, orig[lhsPos], orig[rhsPos]); + else { + Comparable lhsComp = (Comparable)orig[lhsPos]; + compareVal = lhsComp == null ? CompareAble_.Less : lhsComp.compareTo(orig[rhsPos]); + } + if (!asc) compareVal *= -1; + if (compareVal <= CompareAble_.Same) // NOTE: (a) must be < 0; JAVA's String.compareTo returns -number based on position; (b) must be <= else sorting sorted list will change order; EX: sorting (a,1;a,2) on fld0 will switch to (a,2;a,1) + temp[tmpPos++] = orig[lhsPos++]; + else + temp[tmpPos++] = orig[rhsPos++]; + } + + while (lhsPos <= lhsEnd) // Copy rest of first half + temp[tmpPos++] = orig[lhsPos++]; + while (rhsPos <= rhsEnd) // Copy rest of right half + temp[tmpPos++] = orig[rhsPos++]; + for (int i = 0; i < aryLen; i++, rhsEnd--) + orig[rhsEnd] = temp[rhsEnd]; + } + + public static List_adp_sorter new_() {return new List_adp_sorter();} List_adp_sorter() {} +} +class Iterator_objAry implements java.util.Iterator { + public boolean hasNext() {return ++pos < len;} + public Object next() {return ary[pos];} + public void remove() {pos = -1;} + Object[] ary; int pos = -1; int len = 0; + public Iterator_objAry(Object[] v, int count) {ary = v; len = count;} +} \ No newline at end of file diff --git a/100_core/src_140_list/gplx/List_adp_sorter_tst.java b/100_core/src_140_list/gplx/List_adp_sorter_tst.java new file mode 100644 index 000000000..b397b7254 --- /dev/null +++ b/100_core/src_140_list/gplx/List_adp_sorter_tst.java @@ -0,0 +1,37 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class List_adp_sorter_tst { + @Test public void Basic() { + Object[] src = new Object[] {0,8,1,7,2,6,3,5,4}; + List_adp_sorter.new_().Sort(src, src.length); + Tfds.Eq_ary(src, Sequential(0, 8)); + } + @Test public void Basic2() { + Object[] src = new Object[] {"0","8","1","7","2","6","3","5","4"}; + List_adp_sorter.new_().Sort(src, src.length); + Tfds.Eq_ary(src, new Object[] {"0","1","2","3","4","5","6","7","8"}); + } + Object[] Sequential(int bgn, int end) { + Object[] rv = new Object[end - bgn + 1]; + for (int i = 0; i < Array_.Len(rv); i++) + rv[i] = i + bgn; + return rv; + } +} diff --git a/100_core/src_140_list/gplx/List_adp_tst.java b/100_core/src_140_list/gplx/List_adp_tst.java new file mode 100644 index 000000000..8bf2aba9f --- /dev/null +++ b/100_core/src_140_list/gplx/List_adp_tst.java @@ -0,0 +1,222 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class List_adp_tst { + @Before public void setup() { + list = List_adp_.new_(); + listBase = (List_adp_base)list; + } List_adp list; List_adp_base listBase; + @Test public void Add() { + Tfds.Eq(0, list.Count()); + + list.Add("0"); + Tfds.Eq(1, list.Count()); + } + @Test public void Add_changeCapacity() { + int capacity = List_adp_.Capacity_initial; + for (int i = 0; i < capacity; i++) + list.Add("0"); + Tfds.Eq(capacity, list.Count()); + Tfds.Eq(capacity, listBase.Capacity()); + + list.Add(capacity); // forces resize + Tfds.Eq(capacity + 1, list.Count()); + Tfds.Eq(capacity * 2, listBase.Capacity()); + } + @Test public void Get_at() { + list.Add("0"); + + Tfds.Eq("0", list.Get_at(0)); + } + @Test public void Fetch_many() { + list_AddMany("0", "1"); + + Tfds.Eq("0", list.Get_at(0)); + Tfds.Eq("1", list.Get_at(1)); + } + @Test public void FetchAt_fail() { + try {list.Get_at(0);} + catch (Exception exc) {Exc_.Noop(exc); return;} + Tfds.Fail("Get_at should fail for out of bound index"); + } + @Test public void Del_at() { + list.Add("0"); + Tfds.Eq(1, list.Count()); + + list.Del_at(0); + Tfds.Eq(0, list.Count()); + } + @Test public void DelAt_shiftDown() { + list_AddMany("0", "1"); + Tfds.Eq(list.Count(), 2); + + list.Del_at(0); + Tfds.Eq(1, list.Count()); + Tfds.Eq("1", list.Get_at(0)); + } + @Test public void DelAt_fail() { + try {list.Del_at(0);} + catch (Exception exc) {Exc_.Noop(exc); return;} + Tfds.Fail("Del_at should fail for out of bound index"); + } + @Test public void Del() { + list.Add("0"); + Tfds.Eq(1, list.Count()); + + list.Del("0"); + Tfds.Eq(0, list.Count()); + } + @Test public void Del_matchMember() { + list_AddMany("0", "1"); + Tfds.Eq(2, list.Count()); + + list.Del("1"); + Tfds.Eq(1, list.Count()); + Tfds.Eq("0", list.Get_at(0)); + } + @Test public void Del_matchFirst() { + list_AddMany("0", "1", "0"); + Tfds.Eq(3, list.Count()); + + list.Del("0"); + tst_Enumerator("1", "0"); + } + @Test public void Enumerator() { + list_AddMany("0", "1", "2"); + tst_Enumerator("0", "1", "2"); + } + @Test public void Enumerator_stateLess() { // run 2x, to confirm no state is being cached + list_AddMany("0", "1", "2"); + tst_Enumerator("0", "1", "2"); + tst_Enumerator("0", "1", "2"); + } + @Test public void Enumerator_recursive() { // confirm separate enumerator objects are used + int pos = 0; + list_AddMany("0", "1", "2"); + for (Object valObj : list) { + String val = (String)valObj; + Tfds.Eq(Int_.Xto_str(pos++), val); + tst_Enumerator("0", "1", "2"); + } + } + @Test public void Clear() { + int capacity = List_adp_.Capacity_initial; + for (int i = 0; i < capacity + 1; i++) + list.Add("0"); + Tfds.Eq(capacity * 2, listBase.Capacity()); + + list.Clear(); + Tfds.Eq(0, list.Count()); + Tfds.Eq(16, listBase.Capacity()); // check that capacity has increased + } + @Test public void Clear_empty() { // confirm no failure + list.Clear(); + Tfds.Eq(0, list.Count()); + } + @Test public void Reverse() { + list_AddMany("0", "1", "2"); + + list.Reverse(); + tst_Enumerator("2", "1", "0"); + } + @Test public void Reverse_empty() {list.Reverse();} + @Test public void Sort() { + list_AddMany("2", "0", "1"); + + list.Sort(); + tst_Enumerator("0", "1", "2"); + } + @Test public void Sort_empty() {list.Sort();} + @Test public void Xto_bry() { + list_AddMany("0", "1"); + String[] ary = (String[])list.To_ary(String.class); + Tfds.Eq_nullNot(ary); + Tfds.Eq(2, Array_.Len(ary)); + } + @Test public void XtoAry_empty() { + String[] ary = (String[])list.To_ary(String.class); + Tfds.Eq_nullNot(ary); + Tfds.Eq(0, Array_.Len(ary)); + } + @Test public void Shuffle() { + for (int i = 0; i < 25; i++) + list.Add(i); + + list.Shuffle(); + int hasMovedCount = 0; + for (int i = 0; i < list.Count(); i++) { + int val = Int_.cast_(list.Get_at(i)); + if (val != i) hasMovedCount++; + } + Tfds.Eq_true(hasMovedCount > 0, "all documents have the same index"); // NOTE: may still fail occasionally (1%) + + int count = list.Count(); + for (int i = 0; i < count; i++) + list.Del(i); + Tfds.Eq(0, list.Count(), "shuffled list does not have the same contents as original list"); + } + @Test public void Shuffle_empty() {list.Shuffle();} + @Test public void Move_to() { + run_ClearAndAdd("0", "1", "2").run_MoveTo(0, 1).tst_Order("1", "0", "2"); + run_ClearAndAdd("0", "1", "2").run_MoveTo(0, 2).tst_Order("1", "2", "0"); + run_ClearAndAdd("0", "1", "2").run_MoveTo(2, 1).tst_Order("0", "2", "1"); + run_ClearAndAdd("0", "1", "2").run_MoveTo(2, 0).tst_Order("2", "0", "1"); + } + @Test public void Del_range() { + run_ClearAndAdd("0", "1", "2", "3").tst_DelRange(0, 2, "3"); + run_ClearAndAdd("0", "1", "2", "3").tst_DelRange(0, 3); + run_ClearAndAdd("0", "1", "2", "3").tst_DelRange(1, 2, "0", "3"); + run_ClearAndAdd("0", "1", "2", "3").tst_DelRange(1, 3, "0"); + run_ClearAndAdd("0", "1", "2", "3").tst_DelRange(0, 3); + run_ClearAndAdd("0", "1", "2", "3").tst_DelRange(0, 0, "1", "2", "3"); + } + void tst_DelRange(int bgn, int end, String... expd) { + list.Del_range(bgn, end); + Tfds.Eq_ary_str(expd, list.To_str_ary()); + } + List_adp_tst run_ClearAndAdd(String... ary) { + list.Clear(); + for (int i = 0; i < Array_.Len(ary); i++) { + String val = ary[i]; + list.Add(val); + } + return this; + } + List_adp_tst run_MoveTo(int elemPos, int newPos) {list.Move_to(elemPos, newPos); return this;} + List_adp_tst tst_Order(String... expd) { + String[] actl = (String[])list.To_ary(String.class); + Tfds.Eq_ary(expd, actl); + return this; + } + void list_AddMany(String... ary) { + for (int i = 0; i < Array_.Len(ary); i++) { + String val = ary[i]; + list.Add(val); + } + } + void tst_Enumerator(String... expd) { + int pos = 0; + int expdLength = Array_.Len(expd); + for (int i = 0; i < expdLength; i++) { + String val = expd[i]; + Tfds.Eq(expd[pos++], val); + } + Tfds.Eq(pos, expdLength); + } +} diff --git a/100_core/src_140_list/gplx/Ordered_hash.java b/100_core/src_140_list/gplx/Ordered_hash.java new file mode 100644 index 000000000..17824797d --- /dev/null +++ b/100_core/src_140_list/gplx/Ordered_hash.java @@ -0,0 +1,31 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.lists.*; /*EnumerAble,ComparerAble*/ +public interface Ordered_hash extends Hash_adp { + Object Get_at(int i); + void Add_at(int i, Object o); + int Idx_of(Object item); + void Sort(); + void Sort_by(ComparerAble comparer); + void Resize_bounds(int i); + Object To_ary(Class t); + Object To_ary_and_clear(Class t); + void Move_to(int src, int trg); + void Lock(); +} diff --git a/100_core/src_140_list/gplx/Ordered_hash_.java b/100_core/src_140_list/gplx/Ordered_hash_.java new file mode 100644 index 000000000..bdab7d3e8 --- /dev/null +++ b/100_core/src_140_list/gplx/Ordered_hash_.java @@ -0,0 +1,30 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.core.primitives.*; +public class Ordered_hash_ { + public static Ordered_hash new_() {return new Ordered_hash_base();} + public static Ordered_hash new_bry_() {return new Ordered_hash_bry();} +} +class Ordered_hash_bry extends Ordered_hash_base { + private final Bry_obj_ref tmp_ref = Bry_obj_ref.null_(); + @Override protected void Add_base(Object key, Object val) {super.Add_base(Bry_obj_ref.new_((byte[])key), val);} + @Override protected void Del_base(Object key) {synchronized (tmp_ref) {super.Del_base(tmp_ref.Val_((byte[])key));}} + @Override protected boolean Has_base(Object key) {synchronized (tmp_ref) {return super.Has_base(tmp_ref.Val_((byte[])key));}} + @Override protected Object Fetch_base(Object key) {synchronized (tmp_ref) {return super.Fetch_base(tmp_ref.Val_((byte[])key));}} +} diff --git a/100_core/src_140_list/gplx/Ordered_hash_base.java b/100_core/src_140_list/gplx/Ordered_hash_base.java new file mode 100644 index 000000000..ad6e03fce --- /dev/null +++ b/100_core/src_140_list/gplx/Ordered_hash_base.java @@ -0,0 +1,94 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.core.strings.*; +import gplx.lists.*; /*EnumerAble,ComparerAble*/ +public class Ordered_hash_base extends Hash_adp_base implements Ordered_hash, GfoInvkAble { + @Override protected void Add_base(Object key, Object val) { + super.Add_base(key, val); + ordered.Add(val); + AssertCounts(); + } + @Override public void Del(Object key) { + if (!this.Has_base(key)) return; + Object val = this.Fetch_base(key); + this.Del_base(key); + ordered.Del(val); + AssertCounts(); + } + protected Object Get_at_base(int index) {return ordered.Get_at(index);} + protected int IndexOf_base(Object obj) {return ordered.Idx_of(obj);} + @Override public void Clear() { + if (locked) Lock_fail(); + super.Clear(); + ordered.Clear(); + } + public Object To_ary(Class type) {return ordered.To_ary(type);} + public Object To_ary_and_clear(Class t) { + Object rv = To_ary(t); + this.Clear(); + return rv; + } + @gplx.Virtual public void Sort() {if (locked) Lock_fail(); ordered.Sort();} // NOTE: uses item's .compareTo + public void Sort_by(ComparerAble comparer) {if (locked) Lock_fail(); ordered.Sort_by(comparer);} + @Override public java.util.Iterator iterator() {return ordered.iterator();} + public void Add_at(int i, Object key, Object val) { + if (locked) Lock_fail(); + super.Add_base(key, val); + ordered.Add_at(i, val); + AssertCounts(); + } + void AssertCounts() { + if (super.Count() != ordered.Count()) throw Exc_.new_("counts do not match", "hash", super.Count(), "list", ordered.Count()); + } + public void Resize_bounds(int i) {if (locked) Lock_fail(); ordered.Resize_bounds(i);} + public void Lock() {locked = true;} private boolean locked = false; + void Lock_fail() {throw Exc_.new_("collection is locked");} + static final String GRP_KEY = "gplx.lists.ordered_hash"; + public void Add_at(int i, Object o) {if (locked) Lock_fail(); ordered.Add_at(i, o);} + public Object Get_at(int i) {return Get_at_base(i);} + public int Idx_of(Object obj) {return this.IndexOf_base(obj);} + public void Move_to(int src, int trg) {if (locked) Lock_fail(); ordered.Move_to(src, trg);} + private String To_str_ui() { + String_bldr sb = String_bldr_.new_(); + int count = ordered.Count(); + int pad = String_.Len(Int_.Xto_str(count)); + for (int i = 0; i < count; i++) { + sb .Add(Int_.Xto_str_pad_bgn_zero(i, pad)) + .Add(":").Add(ordered.Get_at(i).toString()) + .Add(Op_sys.Cur().Nl_str()); + } + return sb.XtoStr(); + } + public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) { + if (ctx.Match(k, Invk_SetKeyOnly)) { + String s = m.ReadStr("v"); + if (ctx.Deny()) return this; + this.Add(s, s); + } + else if (ctx.Match(k, Invk_Print)) { + if (ctx.Deny()) return this; + return To_str_ui(); + } + else return GfoInvkAble_.Rv_unhandled; + return this; + } static final String Invk_SetKeyOnly = "SetKeyOnly", Invk_Print = "Print"; + final List_adp ordered = List_adp_.new_(); + @Override public int Count() {return ordered.Count();} + public Ordered_hash_base() {} +} diff --git a/100_core/src_140_list/gplx/Ordered_hash_tst.java b/100_core/src_140_list/gplx/Ordered_hash_tst.java new file mode 100644 index 000000000..2d1781c26 --- /dev/null +++ b/100_core/src_140_list/gplx/Ordered_hash_tst.java @@ -0,0 +1,39 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class Ordered_hash_tst { + @Before public void setup() { + hash = Ordered_hash_.new_(); + } + @Test public void Get_at() { + hash.Add("key1", "val1"); + Tfds.Eq("val1", hash.Get_at(0)); + } + @Test public void iterator() { + hash.Add("key2", "val2"); + hash.Add("key1", "val1"); + + List_adp list = List_adp_.new_(); + for (Object val : hash) + list.Add(val); + Tfds.Eq("val2", list.Get_at(0)); + Tfds.Eq("val1", list.Get_at(1)); + } + Ordered_hash hash; +} diff --git a/100_core/src_140_list/gplx/lists/ComparerAble.java b/100_core/src_140_list/gplx/lists/ComparerAble.java new file mode 100644 index 000000000..e3cabb981 --- /dev/null +++ b/100_core/src_140_list/gplx/lists/ComparerAble.java @@ -0,0 +1,20 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.lists; import gplx.*; +public interface ComparerAble extends java.util.Comparator {} //_20110320 +// public int compare(Object lhsObj, Object rhsObj) {} diff --git a/100_core/src_140_list/gplx/lists/ComparerAble_.java b/100_core/src_140_list/gplx/lists/ComparerAble_.java new file mode 100644 index 000000000..2812d5cb5 --- /dev/null +++ b/100_core/src_140_list/gplx/lists/ComparerAble_.java @@ -0,0 +1,21 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.lists; import gplx.*; +public class ComparerAble_ { + public static int Compare(ComparerAble comparer, Object lhs, Object rhs) {return comparer.compare(lhs, rhs);} +} diff --git a/100_core/src_140_list/gplx/lists/EnumerAble.java b/100_core/src_140_list/gplx/lists/EnumerAble.java new file mode 100644 index 000000000..bfe79ff92 --- /dev/null +++ b/100_core/src_140_list/gplx/lists/EnumerAble.java @@ -0,0 +1,19 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.lists; import gplx.*; +public interface EnumerAble extends java.lang.Iterable {}//_20110320 diff --git a/100_core/src_140_list/gplx/lists/Hash_adp_base.java b/100_core/src_140_list/gplx/lists/Hash_adp_base.java new file mode 100644 index 000000000..26e2b82bc --- /dev/null +++ b/100_core/src_140_list/gplx/lists/Hash_adp_base.java @@ -0,0 +1,57 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.lists; import gplx.*; +public abstract class Hash_adp_base implements Hash_adp { + public boolean Has(Object key) {return Has_base(key);} + public Object Get_by(Object key) {return Fetch_base(key);} + public Object Get_by_or_fail(Object key) {return FetchOrFail_base(key);} + public Object Get_by_or_new(Object key, NewAble proto) { + Object rv = Fetch_base(key); + if (rv == null) { + rv = proto.NewByKey(key); + Add_base(key, rv); + } + return rv; + } + public void Add(Object key, Object val) {Add_base(key, val);} + public void Add_as_key_and_val(Object val) {Add_base(val, val);} + public void Add_if_dupe_use_nth(Object key, Object val) { + Object existing = Fetch_base(key); if (existing != null) Del(key); // overwrite if exists + Add(key, val); + } + public boolean Add_if_dupe_use_1st(Object key, Object val) { + if (Has(key)) return false; + Add(key, val); + return true; + } + @gplx.Virtual public void Del(Object key) {Del_base(key);} + protected Object FetchOrFail_base(Object key) { + if (key == null) throw Exc_.new_("key cannot be null"); + if (!Has_base(key)) throw Exc_.new_("key not found", "key", key); + return Fetch_base(key); + } + + java.util.Hashtable hash = new java.util.Hashtable(); + @gplx.Virtual public int Count() {return hash.size();} + @gplx.Virtual public void Clear() {hash.clear();} + @gplx.Virtual protected void Add_base(Object key, Object val) {hash.put(key, val);} + @gplx.Virtual protected void Del_base(Object key) {hash.remove(key);} + @gplx.Virtual protected boolean Has_base(Object key) {return hash.containsKey(key);} + @gplx.Virtual protected Object Fetch_base(Object key) {return hash.get(key);} + @gplx.Virtual public java.util.Iterator iterator() {return hash.values().iterator();} +} diff --git a/100_core/src_140_list/gplx/lists/Hash_adp_list.java b/100_core/src_140_list/gplx/lists/Hash_adp_list.java new file mode 100644 index 000000000..c8a6eb09f --- /dev/null +++ b/100_core/src_140_list/gplx/lists/Hash_adp_list.java @@ -0,0 +1,40 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.lists; import gplx.*; +public class Hash_adp_list extends Hash_adp_base { + @gplx.New public List_adp Get_by(Object key) {return List_adp_.as_(Fetch_base(key));} + public List_adp Get_by_or_new(Object key) { + List_adp rv = Get_by(key); + if (rv == null) { + rv = List_adp_.new_(); + Add_base(key, rv); + } + return rv; + } + public void AddInList(Object key, Object val) { + List_adp list = Get_by_or_new(key); + list.Add(val); + } + public void DelInList(Object key, Object val) { + List_adp list = Get_by(key); + if (list == null) return; + list.Del(val); + if (list.Count() == 0) Del(key); + } + public static Hash_adp_list new_() {return new Hash_adp_list();} Hash_adp_list() {} +} diff --git a/100_core/src_140_list/gplx/lists/Iterator_null.java b/100_core/src_140_list/gplx/lists/Iterator_null.java new file mode 100644 index 000000000..4d1af3975 --- /dev/null +++ b/100_core/src_140_list/gplx/lists/Iterator_null.java @@ -0,0 +1,24 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.lists; import gplx.*; +public class Iterator_null implements java.util.Iterator { + public boolean hasNext() {return false;} + public Object next() {return null;} + public void remove() {} + public static final Iterator_null _ = new Iterator_null(); +} diff --git a/100_core/src_140_list/gplx/lists/StackAdp.java b/100_core/src_140_list/gplx/lists/StackAdp.java new file mode 100644 index 000000000..c7c1315bb --- /dev/null +++ b/100_core/src_140_list/gplx/lists/StackAdp.java @@ -0,0 +1,26 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.lists; import gplx.*; +public interface StackAdp extends EnumerAble { + int Count(); + void Clear(); + void Push(Object obj); + Object Pop(); + Object Peek(); + List_adp XtoList(); +} diff --git a/100_core/src_140_list/gplx/lists/StackAdp_.java b/100_core/src_140_list/gplx/lists/StackAdp_.java new file mode 100644 index 000000000..96a401f43 --- /dev/null +++ b/100_core/src_140_list/gplx/lists/StackAdp_.java @@ -0,0 +1,41 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.lists; import gplx.*; +public class StackAdp_ { + public static StackAdp new_() {return new StackAdp_base();} +} +class StackAdp_base implements StackAdp { + public Object Peek() {return Peek_base();} + public Object Pop() {return Pop_base();} + public void Push(Object obj) {Push_base(obj);} + public List_adp XtoList() { + List_adp list = List_adp_.new_(); + for (Object obj : stack) + list.Add(obj); + // NOTE: dotnet traverses last to first; java: first to last + return list; + } + final java.util.Stack stack = new java.util.Stack(); + public StackAdp_base() {} + public int Count() {return stack.size();} + public void Clear() {stack.clear();} + protected void Push_base(Object obj) {stack.push(obj);} + protected Object Pop_base() {return stack.pop();} + protected Object Peek_base() {return stack.peek();} + public java.util.Iterator iterator() {return stack.iterator();} +} diff --git a/100_core/src_140_list/gplx/lists/StackAdp_tst.java b/100_core/src_140_list/gplx/lists/StackAdp_tst.java new file mode 100644 index 000000000..a5b495a09 --- /dev/null +++ b/100_core/src_140_list/gplx/lists/StackAdp_tst.java @@ -0,0 +1,33 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.lists; import gplx.*; +import org.junit.*; +public class StackAdp_tst { + @Test public void XtoList() { + tst_XtoList(1, 2, 3); + } + void tst_XtoList(int... ary) { + StackAdp stack = StackAdp_.new_(); + for (int i : ary) + stack.Push(i); + List_adp list = stack.XtoList(); + int[] actl = (int[])list.To_ary(int.class); + for (int i = 0; i < ary.length; i++) + Tfds.Eq(ary[i], actl[i]); + } +} diff --git a/100_core/src_150_text/gplx/intl/Gfo_case_itm.java b/100_core/src_150_text/gplx/intl/Gfo_case_itm.java new file mode 100644 index 000000000..dadf370b9 --- /dev/null +++ b/100_core/src_150_text/gplx/intl/Gfo_case_itm.java @@ -0,0 +1,24 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.intl; import gplx.*; +public interface Gfo_case_itm { + boolean Eq_lo(Gfo_case_itm itm); + int Hashcode_lo(); + int Len_lo(); + byte[] Asymmetric_bry(); +} diff --git a/100_core/src_150_text/gplx/intl/Gfo_case_mgr.java b/100_core/src_150_text/gplx/intl/Gfo_case_mgr.java new file mode 100644 index 000000000..ee46b4c35 --- /dev/null +++ b/100_core/src_150_text/gplx/intl/Gfo_case_mgr.java @@ -0,0 +1,22 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.intl; import gplx.*; +public interface Gfo_case_mgr { + byte Tid(); + Gfo_case_itm Get_or_null(byte bgn_byte, byte[] src, int bgn, int end); +} diff --git a/100_core/src_150_text/gplx/intl/Gfo_case_mgr_.java b/100_core/src_150_text/gplx/intl/Gfo_case_mgr_.java new file mode 100644 index 000000000..6f026c305 --- /dev/null +++ b/100_core/src_150_text/gplx/intl/Gfo_case_mgr_.java @@ -0,0 +1,21 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.intl; import gplx.*; +public class Gfo_case_mgr_ { + public static final byte Tid_ascii = 0, Tid_utf8 = 1, Tid_custom = 2; +} diff --git a/100_core/src_150_text/gplx/intl/Utf16_.java b/100_core/src_150_text/gplx/intl/Utf16_.java new file mode 100644 index 000000000..0d8c947df --- /dev/null +++ b/100_core/src_150_text/gplx/intl/Utf16_.java @@ -0,0 +1,137 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.intl; import gplx.*; +import gplx.core.primitives.*; +public class Utf16_ { + public static int Surrogate_merge(int hi, int lo) { // REF: http://perldoc.perl.org/Encode/Unicode.html + return 0x10000 + (hi - 0xD800) * 0x400 + (lo - 0xDC00); + } + public static void Surrogate_split(int v, Int_obj_ref hi, Int_obj_ref lo) { + hi.Val_((v - 0x10000) / 0x400 + 0xD800); + lo.Val_((v - 0x10000) % 0x400 + 0xDC00); + } + public static int Decode_to_int(byte[] ary, int pos) { + byte b0 = ary[pos]; + if ((b0 & 0x80) == 0) { + return b0; + } + else if ((b0 & 0xE0) == 0xC0) { + return ( b0 & 0x1f) << 6 + | ( ary[pos + 1] & 0x3f) + ; + } + else if ((b0 & 0xF0) == 0xE0) { + return ( b0 & 0x0f) << 12 + | ((ary[pos + 1] & 0x3f) << 6) + | ( ary[pos + 2] & 0x3f) + ; + } + else if ((b0 & 0xF8) == 0xF0) { + return ( b0 & 0x07) << 18 + | ((ary[pos + 1] & 0x3f) << 12) + | ((ary[pos + 2] & 0x3f) << 6) + | ( ary[pos + 3] & 0x3f) + ; + } + else throw Exc_.new_("invalid utf8 byte", "byte", b0); + } + public static byte[] Encode_hex_to_bry(String raw) {return Encode_hex_to_bry(Bry_.new_a7(raw));} + public static byte[] Encode_hex_to_bry(byte[] raw) { + if (raw == null) return null; + int int_val = gplx.texts.HexDecUtl.parse_or_(raw, Int_.MinValue); + return int_val == Int_.MinValue ? null : Encode_int_to_bry(int_val); + } + public static byte[] Encode_int_to_bry(int c) { + int bry_len = Len_by_int(c); + byte[] bry = new byte[bry_len]; + Encode_int(c, bry, 0); + return bry; + } + public static int Encode_char(int c, char[] c_ary, int c_pos, byte[] b_ary, int b_pos) { + if ((c > -1) + && (c < 128)) { + b_ary[ b_pos] = (byte)c; + return 1; + } + else if (c < 2048) { + b_ary[ b_pos] = (byte)(0xC0 | (c >> 6)); + b_ary[++b_pos] = (byte)(0x80 | (c & 0x3F)); + return 1; + } + else if((c > 55295) // 0xD800 + && (c < 56320)) { // 0xDFFF + if (c_pos >= c_ary.length) throw Exc_.new_("incomplete surrogate pair at end of String", "char", c); + char nxt_char = c_ary[c_pos + 1]; + int v = Surrogate_merge(c, nxt_char); + b_ary[b_pos] = (byte)(0xF0 | (v >> 18)); + b_ary[++b_pos] = (byte)(0x80 | (v >> 12) & 0x3F); + b_ary[++b_pos] = (byte)(0x80 | (v >> 6) & 0x3F); + b_ary[++b_pos] = (byte)(0x80 | (v & 0x3F)); + return 2; + } + else { + b_ary[b_pos] = (byte)(0xE0 | (c >> 12)); + b_ary[++b_pos] = (byte)(0x80 | (c >> 6) & 0x3F); + b_ary[++b_pos] = (byte)(0x80 | (c & 0x3F)); + return 1; + } + } + public static int Encode_int(int c, byte[] src, int pos) { + if ((c > -1) + && (c < 128)) { + src[ pos] = (byte)c; + return 1; + } + else if (c < 2048) { + src[ pos] = (byte)(0xC0 | (c >> 6)); + src[++pos] = (byte)(0x80 | (c & 0x3F)); + return 2; + } + else if (c < 65536) { + src[pos] = (byte)(0xE0 | (c >> 12)); + src[++pos] = (byte)(0x80 | (c >> 6) & 0x3F); + src[++pos] = (byte)(0x80 | (c & 0x3F)); + return 3; + } + else if (c < 2097152) { + src[pos] = (byte)(0xF0 | (c >> 18)); + src[++pos] = (byte)(0x80 | (c >> 12) & 0x3F); + src[++pos] = (byte)(0x80 | (c >> 6) & 0x3F); + src[++pos] = (byte)(0x80 | (c & 0x3F)); + return 4; + } + else throw Exc_.new_("UTF-16 int must be between 0 and 2097152", "char", c); + } + private static int Len_by_int(int c) { + if ((c > -1) + && (c < 128)) return 1; // 1 << 7 + else if (c < 2048) return 2; // 1 << 11 + else if (c < 65536) return 3; // 1 << 16 + else if (c < 2097152) return 4; + else throw Exc_.new_("UTF-16 int must be between 0 and 2097152", "char", c); + } + public static int Len_by_char(int c) { + if ((c > -1) + && (c < 128)) return 1; // 1 << 7 + else if (c < 2048) return 2; // 1 << 11 + else if((c > 55295) // 0xD800 + && (c < 56320)) return 4; // 0xDFFF + else if (c < 65536) return 3; // 1 << 16 + else throw Exc_.new_("UTF-16 int must be between 0 and 65536", "char", c); + } +} diff --git a/100_core/src_150_text/gplx/intl/Utf16__tst.java b/100_core/src_150_text/gplx/intl/Utf16__tst.java new file mode 100644 index 000000000..a5a9a9b61 --- /dev/null +++ b/100_core/src_150_text/gplx/intl/Utf16__tst.java @@ -0,0 +1,59 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.intl; import gplx.*; +import org.junit.*; import gplx.core.primitives.*; +public class Utf16__tst { + private Utf16__fxt fxt = new Utf16__fxt(); + @Test public void Encode_decode() { +// fxt.Test_encode_decode(162, 194, 162); // cent +// fxt.Test_encode_decode(8364, 226, 130, 172); // euro + fxt.Test_encode_decode(150370, 240, 164, 173, 162); // example from [[UTF-8]]; should be encoded as two bytes + } + @Test public void Encode_as_bry_by_hex() { + fxt.Test_Encode_hex_to_bry("00", 0); + fxt.Test_Encode_hex_to_bry("41", 65); + fxt.Test_Encode_hex_to_bry("0041", 65); + fxt.Test_Encode_hex_to_bry("00C0", 195, 128); + } + @Test public void Surrogate() { + fxt.Test_surrogate(0x64321, 0xD950, 0xDF21); // example from w:UTF-16 + fxt.Test_surrogate(66643, 55297, 56403); // example from d:Boomerang + } +} +class Utf16__fxt { + private Int_obj_ref hi_ref = Int_obj_ref.neg1_(), lo_ref = Int_obj_ref.neg1_(); + public void Test_encode_decode(int expd_c_int, int... expd_int) { + byte[] expd = Bry_.ints_(expd_int); + byte[] bfr = new byte[10]; + int bfr_len = Utf16_.Encode_int(expd_c_int, bfr, 0); + byte[] actl = Bry_.Mid_by_len(bfr, 0, bfr_len); + Tfds.Eq_ary(expd, actl); + int actl_c_int = Utf16_.Decode_to_int(bfr, 0); + Tfds.Eq(expd_c_int, actl_c_int); + } + public void Test_surrogate(int v, int hi, int lo) { + Tfds.Eq(v, Utf16_.Surrogate_merge((char)hi, (char)lo)); + Utf16_.Surrogate_split(v, hi_ref, lo_ref); + Tfds.Eq(hi, hi_ref.Val()); + Tfds.Eq(lo, lo_ref.Val()); + } + public void Test_Encode_hex_to_bry(String raw, int... expd) { + byte[] actl = Utf16_.Encode_hex_to_bry(raw); + Tfds.Eq_ary(Byte_.Ary_by_ints(expd), actl); + } +} diff --git a/100_core/src_150_text/gplx/intl/Utf8_.java b/100_core/src_150_text/gplx/intl/Utf8_.java new file mode 100644 index 000000000..94a0035fb --- /dev/null +++ b/100_core/src_150_text/gplx/intl/Utf8_.java @@ -0,0 +1,117 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.intl; import gplx.*; +public class Utf8_ { + public static int Len_of_bry(byte[] ary) { + if (ary == null) return 0; + int rv = 0; + int pos = 0, len = ary.length; + while (pos < len) { + int char_len = Len_of_char_by_1st_byte(ary[pos]); + ++rv; + pos += char_len; + } + return rv; + } + public static int Len_of_char_by_1st_byte(byte b) {// SEE:w:UTF-8 + int i = b & 0xff; // PATCH.JAVA:need to convert to unsigned byte + switch (i) { + case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: + case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: case 29: case 30: case 31: + case 32: case 33: case 34: case 35: case 36: case 37: case 38: case 39: case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47: + case 48: case 49: case 50: case 51: case 52: case 53: case 54: case 55: case 56: case 57: case 58: case 59: case 60: case 61: case 62: case 63: + case 64: case 65: case 66: case 67: case 68: case 69: case 70: case 71: case 72: case 73: case 74: case 75: case 76: case 77: case 78: case 79: + case 80: case 81: case 82: case 83: case 84: case 85: case 86: case 87: case 88: case 89: case 90: case 91: case 92: case 93: case 94: case 95: + case 96: case 97: case 98: case 99: case 100: case 101: case 102: case 103: case 104: case 105: case 106: case 107: case 108: case 109: case 110: case 111: + case 112: case 113: case 114: case 115: case 116: case 117: case 118: case 119: case 120: case 121: case 122: case 123: case 124: case 125: case 126: case 127: + case 128: case 129: case 130: case 131: case 132: case 133: case 134: case 135: case 136: case 137: case 138: case 139: case 140: case 141: case 142: case 143: + case 144: case 145: case 146: case 147: case 148: case 149: case 150: case 151: case 152: case 153: case 154: case 155: case 156: case 157: case 158: case 159: + case 160: case 161: case 162: case 163: case 164: case 165: case 166: case 167: case 168: case 169: case 170: case 171: case 172: case 173: case 174: case 175: + case 176: case 177: case 178: case 179: case 180: case 181: case 182: case 183: case 184: case 185: case 186: case 187: case 188: case 189: case 190: case 191: + return 1; + case 192: case 193: case 194: case 195: case 196: case 197: case 198: case 199: case 200: case 201: case 202: case 203: case 204: case 205: case 206: case 207: + case 208: case 209: case 210: case 211: case 212: case 213: case 214: case 215: case 216: case 217: case 218: case 219: case 220: case 221: case 222: case 223: + return 2; + case 224: case 225: case 226: case 227: case 228: case 229: case 230: case 231: case 232: case 233: case 234: case 235: case 236: case 237: case 238: case 239: + return 3; + case 240: case 241: case 242: case 243: case 244: case 245: case 246: case 247: + return 4; + default: throw Exc_.new_("invalid initial utf8 byte", "byte", b); + } + } + public static byte[] Get_char_at_pos_as_bry(byte[] bry, int pos) { + int len = Len_of_char_by_1st_byte(bry[pos]); + return Bry_.Mid(bry, pos, pos + len); + } + public static byte[] Increment_char_at_last_pos(byte[] bry) { // EX: abc -> abd; complexity is for multi-byte chars + int bry_len = bry.length; if (bry_len == 0) return bry; + int pos = bry_len - 1; + while (true) { // loop bwds + int cur_char_pos0 = Get_pos0_of_char_bwd(bry, pos); // get byte0 of char + int cur_char_len = (pos - cur_char_pos0) + 1; // calc len of char + int nxt_char = Codepoint_max; + if (cur_char_len == 1) { // len=1; just change 1 byte + nxt_char = Increment_char(bry[cur_char_pos0]); // get next char + if (nxt_char < 128) { // single-byte char; just change pos + bry = Bry_.Copy(bry); // always return new bry; never reuse existing + bry[cur_char_pos0] = (byte)nxt_char; + return bry; + } + } + int cur_char = Utf16_.Decode_to_int(bry, cur_char_pos0); + nxt_char = Increment_char(cur_char); + if (nxt_char != Int_.MinValue) { + byte[] nxt_char_as_bry = Utf16_.Encode_int_to_bry(nxt_char); + bry = Bry_.Add(Bry_.Mid(bry, 0, cur_char_pos0), nxt_char_as_bry); + return bry; + } + pos = cur_char_pos0 - 1; + if (pos < 0) return null; + } + } + public static int Get_pos0_of_char_bwd(byte[] bry, int pos) { // find pos0 of char while moving bwd through bry; see test + int stop = pos - 4; // UTF8 char has max of 4 bytes + if (stop < 0) stop = 0; // if at pos 0 - 3, stop at 0 + for (int i = pos - 1; i >= stop; i--) { // start at pos - 1, and move bwd; NOTE: pos - 1 to skip pos, b/c pos will never definitively yield any char_len info + byte b = bry[i]; + int char_len = Len_of_char_by_1st_byte(b); + switch (char_len) { // if char_len is multi-byte and pos is at correct multi-byte pos (pos - i = # of bytes - 1), then pos0 found; EX: � = {226,130,172}; 172 is skipped; 130 has len of 1 -> continue; 226 has len of 3 and is found at correct pos for 3 byte char -> return + case 2: if (pos - i == 1) return i; break; + case 3: if (pos - i == 2) return i; break; + case 4: if (pos - i == 3) return i; break; + } + } + return pos; // no mult-byte char found; return pos + } + @gplx.Internal protected static int Increment_char(int cur) { + while (cur++ < Codepoint_max) { + if (cur == Codepoint_surrogate_bgn) cur = Codepoint_surrogate_end + 1; // skip over surrogate range + if (!Codepoint_valid(cur)) continue; + return cur; + } + return Int_.MinValue; + } + private static boolean Codepoint_valid(int v) { + return Character.isDefined(v); + } + public static final int + Codepoint_max = 0x10FFFF //see http://unicode.org/glossary/ + , Codepoint_surrogate_bgn = 0xD800 + , Codepoint_surrogate_end = 0xDFFF + ; +} diff --git a/100_core/src_150_text/gplx/intl/Utf8__tst.java b/100_core/src_150_text/gplx/intl/Utf8__tst.java new file mode 100644 index 000000000..605460376 --- /dev/null +++ b/100_core/src_150_text/gplx/intl/Utf8__tst.java @@ -0,0 +1,69 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.intl; import gplx.*; +import org.junit.*; +public class Utf8__tst { + private Utf8__fxt fxt = new Utf8__fxt(); + @Test public void Get_pos0_of_char_bwd() { + fxt.Test_Get_pos0_of_char_bwd("abcd", 3); // len=1; (note that bry.len = 4) + fxt.Test_Get_pos0_of_char_bwd("a", 0); // len=1; short-String + fxt.Test_Get_pos0_of_char_bwd("abc¢", 3); // len=2; (note that bry.len = 5) + fxt.Test_Get_pos0_of_char_bwd("abc€", 3); // len=3; (note that bry.len = 6) + fxt.Test_Get_pos0_of_char_bwd("abc" + String_.new_u8(Byte_.Ary_by_ints(240, 164, 173, 162)), 3); // len=4; (note that bry.len = 7) + } + @Test public void Increment_char_at_last_pos() { + fxt.Test_Increment_char_at_last_pos("a", "b"); + fxt.Test_Increment_char_at_last_pos("abc", "abd"); + fxt.Test_Increment_char_at_last_pos("É", "Ê"); // len=2 + fxt.Test_Increment_char_at_last_pos("€", "₭"); // len=3 + } +// @Test public void Increment_char_at_last_pos_exhaustive_check() { // check all values; commented for perf +// Bry_bfr bfr = Bry_bfr.new_(); +// int bgn = 32; +// while (true) { +// byte[] bgn_bry = Utf16_.Encode_int_to_bry(bgn); +// int end = Utf8_.Increment_char(bgn); +// if (end == Utf8_.Codepoint_max) break; +//// if (bgn > 1024 * 1024) break; +// byte[] end_by_codepoint_next = Utf16_.Encode_int_to_bry(end); +// byte[] end_by_increment_char = Utf8_.Increment_char_at_last_pos(bgn_bry); +// if (!Bry_.Eq(end_by_codepoint_next, end_by_increment_char)) { +// Tfds.Write(bgn); +// } +//// bfr .Add_int_variable(bgn).Add_byte(Byte_ascii.Tab) +//// .Add(bgn_bry).Add_byte(Byte_ascii.Tab) +//// .Add(end_by_codepoint_next).Add_byte(Byte_ascii.Tab) +//// .Add(end_by_increment_char).Add_byte(Byte_ascii.Tab) +//// .Add_byte_nl() +//// ; +// bgn = end; +// bgn_bry = end_by_codepoint_next; +// } +// Tfds.WriteText(bfr.Xto_str_and_clear()); +// } +} +class Utf8__fxt { + public void Test_Get_pos0_of_char_bwd(String str, int expd) { + byte[] bry = Bry_.new_u8(str); + int pos = bry.length - 1; // always start from last char + Tfds.Eq(expd, Utf8_.Get_pos0_of_char_bwd(bry, pos)); + } + public void Test_Increment_char_at_last_pos(String str, String expd) { + Tfds.Eq(expd, String_.new_u8(Utf8_.Increment_char_at_last_pos(Bry_.new_u8(str)))); + } +} diff --git a/100_core/src_150_text/gplx/texts/Base32Converter.java b/100_core/src_150_text/gplx/texts/Base32Converter.java new file mode 100644 index 000000000..535c9d0b2 --- /dev/null +++ b/100_core/src_150_text/gplx/texts/Base32Converter.java @@ -0,0 +1,99 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.texts; import gplx.*; +public class Base32Converter { + public static String EncodeString(String orig) {return Encode(Bry_.new_u8(orig));} + public static String Encode(byte[] raw) { + int i = 0, index = 0, digit = 0; int currByte, nextByte; + int rawLen = Array_.Len(raw); + char[] ary = new char[(rawLen + 7) * 8 / 5]; int aryPos = 0; + while (i < rawLen) { + currByte = (raw[i] >= 0) ? raw[i] : raw[i] + 256; // unsign; java converts char 128+ -> byte -128 + if (index > 3) { /* Is the curPath digit going to span a byte boundary? */ + if ((i+1) < rawLen) + nextByte = (raw[i+1] >= 0) ? raw[i+1] : (raw[i+1] + 256); + else + nextByte = 0; + + digit = currByte & (0xFF >> index); + index = (index + 5) % 8; + digit <<= index; + digit |= nextByte >> (8 - index); + i++; + } + else { + digit = (currByte >> (8 - (index + 5))) & 0x1F; + index = (index + 5) % 8; + if (index == 0) i++; + } + ary[aryPos++] = String_.CharAt(chars, digit); + } + return new String(ary, 0, aryPos); + } + public static String DecodeString(String orig) {return String_.new_u8(Decode(orig));} + public static byte[] Decode(String raw) { + int i, index, lookup, offset; byte digit; + int rawLen = String_.Len(raw); + int rvLen = rawLen * 5 / 8; + byte[] rv = new byte[rvLen]; + for (i = 0, index = 0, offset = 0; i < rawLen; i++) { + lookup = String_.CharAt(raw, i) - '0'; + if (lookup < 0 || lookup >= valsLen) continue; /* Skip any char outside the lookup table */ + digit = vals[lookup]; + if (digit == 0x7F) continue; /* If this digit is not in the table, ignore it */ + + if (index <= 3) { + index = (index + 5) % 8; + if (index == 0) { + rv[offset] |= digit; + offset++; + if(offset >= rvLen) break; + } + else + rv[offset] |= (byte)(digit << (8 - index)); + } + else { + index = (index + 5) % 8; + rv[offset] |= (byte)(digit >> index); + offset++; + + if(offset >= rvLen) break; + rv[offset] |= (byte)(digit << (8 - index)); + } + } + return rv; + } + static String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; + static int valsLen = 80; + static byte[] vals = { + 0x7F,0x7F,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F, // '0', '1', '2', '3', '4', '5', '6', '7' + 0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F, // '8', '9', ':', ';', '<', '=', '>', '?' + 0x7F,0x00,0x01,0x02,0x03,0x04,0x05,0x06, // '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G' + 0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E, // 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O' + 0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16, // 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W' + 0x17,0x18,0x19,0x7F,0x7F,0x7F,0x7F,0x7F, // 'X', 'Y', 'Z', '[', '\', ']', '^', '_' + 0x7F,0x00,0x01,0x02,0x03,0x04,0x05,0x06, // '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g' + 0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E, // 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o' + 0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16, // 'p', 'q', 'r', 's', 't', 'u', 'v', 'w' + 0x17,0x18,0x19,0x7F,0x7F,0x7F,0x7F,0x7F // 'x', 'y', 'z', '{', '|', '}', '~', 'DEL' + }; +} +/* +source: Azraeus excerpt in java + http://www.koders.com/java/fidA4D6F0DF43E6E9A6B518762366AB7232C14E9DB7.aspx +*/ diff --git a/100_core/src_150_text/gplx/texts/Base64Converter.java b/100_core/src_150_text/gplx/texts/Base64Converter.java new file mode 100644 index 000000000..5b3c340c3 --- /dev/null +++ b/100_core/src_150_text/gplx/texts/Base64Converter.java @@ -0,0 +1,79 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.texts; import gplx.*; +public class Base64Converter { + private final static char[] ALPHABET = String_.XtoCharAry("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"); + private static int[] toInt = null;//new int[128]; + static void Init() { + toInt = new int[128]; + for(int i=0; i< ALPHABET.length; i++){ + toInt[ALPHABET[i]]= i; + } + } + public static String EncodeString(String orig) {return Encode(Bry_.new_u8(orig));} + public static String Encode(byte[] buf){ + if (toInt == null) Init(); + int size = buf.length; + char[] ar = new char[((size + 2) / 3) * 4]; + int a = 0; + int i=0; + while(i < size){ + byte b0 = buf[i++]; + byte b1 = (i < size) ? buf[i++] : (byte)0; + byte b2 = (i < size) ? buf[i++] : (byte)0; + + int mask = 0x3F; + ar[a++] = ALPHABET[(b0 >> 2) & mask]; + ar[a++] = ALPHABET[((b0 << 4) | ((b1 & 0xFF) >> 4)) & mask]; + ar[a++] = ALPHABET[((b1 << 2) | ((b2 & 0xFF) >> 6)) & mask]; + ar[a++] = ALPHABET[b2 & mask]; + } + switch(size % 3){ + case 1: ar[--a] = '='; + ar[--a] = '='; + break; + case 2: ar[--a] = '='; break; + } + return new String(ar); + } + public static String DecodeString(String orig) {return String_.new_u8(Decode(orig));} + public static byte[] Decode(String s){ + if (toInt == null) Init(); + int sLen = String_.Len(s); + int delta = String_.Has_at_end(s, "==") ? 2 : String_.Has_at_end(s, "=") ? 1 : 0; + byte[] buffer = new byte[sLen *3/4 - delta]; + int mask = 0xFF; + int index = 0; + for(int i=0; i< sLen; i+=4){ + int c0 = toInt[String_.CharAt(s, i)]; + int c1 = toInt[String_.CharAt(s, i + 1)]; + buffer[index++]= (byte)(((c0 << 2) | (c1 >> 4)) & mask); + if(index >= buffer.length){ + return buffer; + } + int c2 = toInt[String_.CharAt(s, i + 2)]; + buffer[index++]= (byte)(((c1 << 4) | (c2 >> 2)) & mask); + if(index >= buffer.length){ + return buffer; + } + int c3 = toInt[String_.CharAt(s, i + 3)]; + buffer[index++]= (byte)(((c2 << 6) | c3) & mask); + } + return buffer; + } +} diff --git a/100_core/src_150_text/gplx/texts/BaseXXConverter_tst.java b/100_core/src_150_text/gplx/texts/BaseXXConverter_tst.java new file mode 100644 index 000000000..9bcaf8cd8 --- /dev/null +++ b/100_core/src_150_text/gplx/texts/BaseXXConverter_tst.java @@ -0,0 +1,58 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.texts; import gplx.*; +import org.junit.*; +public class BaseXXConverter_tst { + @Test public void Base32() { + tst_Base32("", ""); + tst_Base32("f", "MY"); + tst_Base32("fo", "MZXQ"); + tst_Base32("foo", "MZXW6"); + tst_Base32("foob", "MZXW6YQ"); + tst_Base32("fooba", "MZXW6YTB"); + tst_Base32("foobar", "MZXW6YTBOI"); + tst_Base32("A", "IE"); + tst_Base32("a", "ME"); + tst_Base32("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567", "IFBEGRCFIZDUQSKKJNGE2TSPKBIVEU2UKVLFOWCZLIZDGNBVGY3Q"); + } + @Test public void Base64() { + tst_Base64("", ""); + tst_Base64("f", "Zg=="); + tst_Base64("fo", "Zm8="); + tst_Base64("foo", "Zm9v"); + tst_Base64("foob", "Zm9vYg=="); + tst_Base64("fooba", "Zm9vYmE="); + tst_Base64("foobar", "Zm9vYmFy"); +// tst_Base64("A", "IE"); +// tst_Base64("a", "ME"); +// tst_Base64("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567", "IFBEGRCFIZDUQSKKJNGE2TSPKBIVEU2UKVLFOWCZLIZDGNBVGY3Q"); + } + void tst_Base32(String orig, String expd) { + String actl = Base32Converter.EncodeString(orig); + Tfds.Eq(expd, actl); + String decode = Base32Converter.DecodeString(actl); + Tfds.Eq(orig, decode); + } + void tst_Base64(String orig, String expd) { + String actl = Base64Converter.EncodeString(orig); + Tfds.Eq(expd, actl); + String decode = Base64Converter.DecodeString(actl); + Tfds.Eq(orig, decode); + } +} +//http://tools.ietf.org/html/rfc4648: test vectors for "foobar" diff --git a/100_core/src_150_text/gplx/texts/CharStream.java b/100_core/src_150_text/gplx/texts/CharStream.java new file mode 100644 index 000000000..a047db19d --- /dev/null +++ b/100_core/src_150_text/gplx/texts/CharStream.java @@ -0,0 +1,67 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.texts; import gplx.*; +public class CharStream { + public char[] Ary() {return ary;} char[] ary; + public int Len() {return len;} int len; + public int Pos() {return pos;} int pos = BgnPos; static final int BgnPos = -1; + public boolean AtBgn() {return pos <= BgnPos;} + public boolean AtEnd() {return pos >= len;} + public boolean AtMid() {return pos > BgnPos && pos < len;} + public char Cur() {try {return ary[pos];} catch (Exception exc) {Exc_.Noop(exc); throw Exc_.new_missing_idx(pos, this.Len());}} + public void MoveNext() {pos++;} + public void MoveNextBy(int offset) {pos += offset;} + public void MoveBack() {pos--;} + public void MoveBackBy(int offset) {pos -= offset;} + public void Move_to(int val) {pos = val;} + public boolean Match(String match) { + int matchLen = String_.Len(match); + for (int i = 0; i < matchLen; i++) { + int cur = pos + i; + if (cur >= len || ary[cur] != String_.CharAt(match, i)) return false; + } + return true; + } + public boolean MatchAndMove(String match) { + int matchLen = String_.Len(match); + boolean rv = Match(match); + if (rv) MoveNextBy(matchLen); + return rv; + } + public boolean MatchAndMove(char match) { + boolean rv = ary[pos] == match; + if (rv) pos++; + return rv; + } + public String XtoStr() {return Char_.XtoStr(ary, 0, len);} + public String XtoStrAtCur(int length) { + length = (pos + length > len) ? len - pos : length; + return Char_.XtoStr(ary, pos, length); + } + public String Xto_str_by_pos(int bgn, int end) { + if (bgn < 0) bgn = 0; if (end > len - 1) end = len - 1; + return Char_.XtoStr(ary, bgn, end - bgn + 1); + } + public static CharStream pos0_(String text) { + CharStream rv = new CharStream(); + rv.ary = String_.XtoCharAry(text); + rv.len = Array_.Len(rv.ary); + rv.MoveNext(); // bgn at pos=0 + return rv; + } CharStream(){} +} diff --git a/100_core/src_150_text/gplx/texts/CharStream_tst.java b/100_core/src_150_text/gplx/texts/CharStream_tst.java new file mode 100644 index 000000000..edbefd647 --- /dev/null +++ b/100_core/src_150_text/gplx/texts/CharStream_tst.java @@ -0,0 +1,61 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.texts; import gplx.*; +import org.junit.*; +public class CharStream_tst { + @Before public void setup() { + stream = CharStream.pos0_("abcdefgh"); + } + @Test public void XtoStr() { + Tfds.Eq(stream.XtoStr(), "abcdefgh"); + } + @Test public void CurrentText() { + stream.MoveNextBy(1); + Tfds.Eq(stream.XtoStrAtCur(2), "bc"); + Tfds.Eq(stream.XtoStr(), "abcdefgh"); + } + @Test public void CurrentText_outOfBounds() { + stream.MoveNextBy(7); + Tfds.Eq(stream.XtoStrAtCur(2), "h"); + } + @Test public void Match() { + stream.MoveNextBy(6); + tst_Match(true, "g"); + tst_Match(false, "z"); + tst_Match(true, "gh"); + tst_Match(false, "gz"); + tst_Match(false, "ghi"); + } + @Test public void AtBounds() { + stream.Move_to(-1); + tst_AtBounds(true, false, false); + + stream.Move_to(0); + tst_AtBounds(false, true, false); + + stream.Move_to(stream.Len()); + tst_AtBounds(false, false, true); + } + void tst_Match(boolean expd, String text) {Tfds.Eq(expd, stream.Match(text));} + void tst_AtBounds(boolean atBgn, boolean atMid, boolean atEnd) { + Tfds.Eq(atBgn, stream.AtBgn()); + Tfds.Eq(atMid, stream.AtMid()); + Tfds.Eq(atEnd, stream.AtEnd()); + } + CharStream stream; +} diff --git a/100_core/src_150_text/gplx/texts/HexDecUtl.java b/100_core/src_150_text/gplx/texts/HexDecUtl.java new file mode 100644 index 000000000..67de8daee --- /dev/null +++ b/100_core/src_150_text/gplx/texts/HexDecUtl.java @@ -0,0 +1,96 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.texts; import gplx.*; +public class HexDecUtl { + public static int parse_or_(String raw, int or) { + int rv = 0; int digit; int factor = 1, rawLen = String_.Len(raw); + for (int i = rawLen - 1; i >= 0; i--) { + digit = XtoInt(String_.CharAt(raw, i)); + if (digit == -1) return or; + rv += digit * factor; + factor *= 16; + } + return rv; + } + public static int parse_or_(byte[] raw, int or) {return parse_or_(raw, 0, raw.length, or);} + public static int parse_or_(byte[] raw, int bgn, int end, int or) { + int rv = 0; int factor = 1; + byte b = Byte_.Max_value_127; + for (int i = end - 1; i >= bgn; i--) { + switch (raw[i]) { + case Byte_ascii.Num_0: b = 0; break; case Byte_ascii.Num_1: b = 1; break; case Byte_ascii.Num_2: b = 2; break; case Byte_ascii.Num_3: b = 3; break; case Byte_ascii.Num_4: b = 4; break; + case Byte_ascii.Num_5: b = 5; break; case Byte_ascii.Num_6: b = 6; break; case Byte_ascii.Num_7: b = 7; break; case Byte_ascii.Num_8: b = 8; break; case Byte_ascii.Num_9: b = 9; break; + case Byte_ascii.Ltr_A: b = 10; break; case Byte_ascii.Ltr_B: b = 11; break; case Byte_ascii.Ltr_C: b = 12; break; case Byte_ascii.Ltr_D: b = 13; break; case Byte_ascii.Ltr_E: b = 14; break; case Byte_ascii.Ltr_F: b = 15; break; + case Byte_ascii.Ltr_a: b = 10; break; case Byte_ascii.Ltr_b: b = 11; break; case Byte_ascii.Ltr_c: b = 12; break; case Byte_ascii.Ltr_d: b = 13; break; case Byte_ascii.Ltr_e: b = 14; break; case Byte_ascii.Ltr_f: b = 15; break; + default: b = Byte_.Max_value_127; break; + } + if (b == Byte_.Max_value_127) return or; + rv += b * factor; + factor *= 16; + } + return rv; + } + public static int parse_(String raw) { + int rv = parse_or_(raw, -1); if (rv == -1) throw Exc_.new_parse("HexDec", "raw"); + return rv; + } + public static String XtoStr(int val, int pad) { + char[] ary = new char[8]; int idx = 8; // 8 is max len of hexString; (2^4 * 8); EX: int.MaxValue = 7FFFFFFF + do { + int byt = val % 16; + ary[--idx] = XtoChar(byt); + val /= 16; + } while (val > 0); + while (8 - idx < pad) // pad left with zeros + ary[--idx] = '0'; + return String_.new_charAry_(ary, idx, 8-idx); + } + static int XtoInt(char c) { + switch (c) { + case '0': return 0; case '1': return 1; case '2': return 2; case '3': return 3; case '4': return 4; + case '5': return 5; case '6': return 6; case '7': return 7; case '8': return 8; case '9': return 9; + case 'A': return 10; case 'B': return 11; case 'C': return 12; case 'D': return 13; case 'E': return 14; case 'F': return 15; + case 'a': return 10; case 'b': return 11; case 'c': return 12; case 'd': return 13; case 'e': return 14; case 'f': return 15; + default: return -1; + } + } + static char XtoChar(int val) { + switch (val) { + case 0: return '0'; case 1: return '1'; case 2: return '2'; case 3: return '3'; case 4: return '4'; + case 5: return '5'; case 6: return '6'; case 7: return '7'; case 8: return '8'; case 9: return '9'; + case 10: return 'A'; case 11: return 'B'; case 12: return 'C'; case 13: return 'D'; case 14: return 'E'; case 15: return 'F'; + default: throw Exc_.new_parse("hexstring", Int_.Xto_str(val)); + } + } + static byte Xto_byte(int v) { + switch (v) { + case 0: return Byte_ascii.Num_0; case 1: return Byte_ascii.Num_1; case 2: return Byte_ascii.Num_2; case 3: return Byte_ascii.Num_3; case 4: return Byte_ascii.Num_4; + case 5: return Byte_ascii.Num_5; case 6: return Byte_ascii.Num_6; case 7: return Byte_ascii.Num_7; case 8: return Byte_ascii.Num_8; case 9: return Byte_ascii.Num_9; + case 10: return Byte_ascii.Ltr_A; case 11: return Byte_ascii.Ltr_B; case 12: return Byte_ascii.Ltr_C; case 13: return Byte_ascii.Ltr_D; case 14: return Byte_ascii.Ltr_E; case 15: return Byte_ascii.Ltr_F; + default: throw Exc_.new_parse("hexstring", Int_.Xto_str(v)); + } + } + public static void Write(byte[] bry, int bgn, int end, int val) { + for (int i = end - 1; i > bgn - 1; i--) { + int b = val % 16; + bry[i] = Xto_byte(b); + val /= 16; + if (val == 0) break; + } + } +} diff --git a/100_core/src_150_text/gplx/texts/HexDecUtl_tst.java b/100_core/src_150_text/gplx/texts/HexDecUtl_tst.java new file mode 100644 index 000000000..4202b5479 --- /dev/null +++ b/100_core/src_150_text/gplx/texts/HexDecUtl_tst.java @@ -0,0 +1,63 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.texts; import gplx.*; +import org.junit.*; +public class HexDecUtl_tst { + @Test public void XtoInt() { + tst_XtoInt("0", 0); + tst_XtoInt("F", 15); + tst_XtoInt("0F", 15); + tst_XtoInt("10", 16); + tst_XtoInt("20", 32); + tst_XtoInt("FF", 255); + tst_XtoInt("100", 256); + tst_XtoInt("0a", 10); + tst_XtoInt("7FFFFFFF", Int_.MaxValue); + tst_XtoInt_bry("100", 256); + } + @Test public void XtoStr() { + tst_XtoStr(0, "0"); + tst_XtoStr(15, "F"); + tst_XtoStr(16, "10"); + tst_XtoStr(32, "20"); + tst_XtoStr(255, "FF"); + tst_XtoStr(Int_.MaxValue, "7FFFFFFF"); + + tst_XtoStr(15, 2, "0F"); + tst_XtoStr(15, 3, "00F"); + } + @Test public void Write() { + tst_Write("[00000000]", 1, 9, 15, "[0000000F]"); + tst_Write("[00000000]", 1, 9, 255, "[000000FF]"); + } + private void tst_Write(String s, int bgn, int end, int val, String expd) { + byte[] bry = Bry_.new_a7(s); + HexDecUtl.Write(bry, bgn, end, val); + Tfds.Eq(expd, String_.new_a7(bry)); + } + private void tst_XtoInt(String raw, int expd) { + int actl = HexDecUtl.parse_(raw); + Tfds.Eq(expd, actl); + } + private void tst_XtoInt_bry(String raw, int expd) {Tfds.Eq(expd, HexDecUtl.parse_or_(Bry_.new_a7(raw), -1));} + private void tst_XtoStr(int val, String expd) {tst_XtoStr(val, 0, expd);} + private void tst_XtoStr(int val, int pad, String expd) { + String actl = HexDecUtl.XtoStr(val, pad); + Tfds.Eq(expd, actl); + } +} diff --git a/100_core/src_150_text/gplx/texts/RegxAdp.java b/100_core/src_150_text/gplx/texts/RegxAdp.java new file mode 100644 index 000000000..a2e881ab9 --- /dev/null +++ b/100_core/src_150_text/gplx/texts/RegxAdp.java @@ -0,0 +1,64 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.texts; import gplx.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +public class RegxAdp { + void Under_sync() { + try {under = Pattern.compile(pattern, Pattern.DOTALL | Pattern.UNICODE_CHARACTER_CLASS);} // JRE.7:UNICODE_CHARACTER_CLASS; added during %w fix for en.w:A#; DATE:2015-06-10 + catch (Exception e) { // NOTE: if invalid, then default to empty pattern (which should return nothing); EX:d:〆る generates [^]; DATE:2013-10-20 + pattern_is_invalid = true; + under = Pattern.compile("", Pattern.DOTALL | Pattern.UNICODE_CHARACTER_CLASS); + } + } private Pattern under; + public RegxMatch Match(String input, int bgn) { + Matcher match = under.matcher(input); + boolean success = match.find(bgn); + int match_bgn = success ? match.start() : String_.Find_none; + int match_end = success ? match.end() : String_.Find_none; + RegxGroup[] ary = RegxGroup.Ary_empty; + int groups_len = match.groupCount(); + if (success && groups_len > 0) { + ary = new RegxGroup[groups_len]; + for (int i = 0; i < groups_len; i++) + ary[i] = new RegxGroup(true, match.start(i + 1), match.end(i + 1), match.group(i + 1)); + } + return new RegxMatch(success, match_bgn, match_end, ary); + } + public String ReplaceAll(String input, String replace) {return under.matcher(input).replaceAll(replace);} + public String Pattern() {return pattern;} public RegxAdp Pattern_(String val) {pattern = val; Under_sync(); return this;} private String pattern; + public boolean Pattern_is_invalid() {return pattern_is_invalid;} private boolean pattern_is_invalid = false; + public RegxMatch[] Match_all(String text, int bgn) { + int idx = bgn; + List_adp rv = List_adp_.new_(); + int len = String_.Len(text); + while (idx <= len) { // NOTE: must be <= not < else "a?" will return null instead of ""; PAGE:en.d:民; DATE:2015-01-30 + RegxMatch match = this.Match(text, idx); + if (match.Rslt_none()) break; + rv.Add(match); + int find_bgn = match.Find_bgn(); + int find_len = match.Find_len(); + idx = find_len == 0 // find_bgn == find_end + ? find_bgn + 1 // add 1 to resume search from next char; DATE:2014-09-02 + : find_bgn + find_len // otherwise search after find_end + ; + } + return (RegxMatch[])rv.To_ary(RegxMatch.class); + } + @gplx.Internal protected RegxAdp(String regx) {Pattern_(regx);} +} diff --git a/100_core/src_150_text/gplx/texts/RegxAdp_.java b/100_core/src_150_text/gplx/texts/RegxAdp_.java new file mode 100644 index 000000000..e09000507 --- /dev/null +++ b/100_core/src_150_text/gplx/texts/RegxAdp_.java @@ -0,0 +1,28 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.texts; import gplx.*; +public class RegxAdp_ { + public static RegxAdp_mpo_find Find_args(String input, String find) {return new RegxAdp_mpo_find().Input_(input).Find_(find);} + public static RegxAdp_mpo_replace Replace_args(String input, String find, String replace) {return new RegxAdp_mpo_replace().Input_(input).Find_(find).Replace_(replace);} + public static RegxAdp new_(String pattern) {return new RegxAdp(pattern);} + public static String Replace(String raw, String regx, String replace) {return Replace_args(raw, regx, replace).Exec_asStr();} + public static boolean Match(String input, String pattern) { + RegxAdp rv = new RegxAdp(pattern); + return rv.Match(input, 0).Rslt(); + } +} diff --git a/100_core/src_150_text/gplx/texts/RegxAdp__tst.java b/100_core/src_150_text/gplx/texts/RegxAdp__tst.java new file mode 100644 index 000000000..e1e930ac5 --- /dev/null +++ b/100_core/src_150_text/gplx/texts/RegxAdp__tst.java @@ -0,0 +1,93 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.texts; import gplx.*; +import org.junit.*; +public class RegxAdp__tst implements TfdsEqListItmStr { + @Test public void Match() { + tst_Match("a", "a", true); // basic + tst_Match("a", "b", false); // matchNot + tst_Match("a", "ab", true); // matchPart + tst_Match("a\\+b", "a+b", true); // matchEscape + tst_Match("[^a]", "b", true); // charSet_negate + } void tst_Match(String find, String input, boolean expd) {Tfds.Eq(expd, RegxAdp_.Match(input, find));} + @Test public void Match_all() { + tst_Match_all("#REDIRECT [[Template:Error]]", "^\\p{Nd}*", 1); // handle match = true but len = 0; DATE:2013-04-11 + tst_Match_all("a", "$", 1); // $ should match once, not zero; DATE:2014-09-02 + } void tst_Match_all(String input, String regx, int expd) {Tfds.Eq(expd, RegxAdp_.new_(regx).Match_all(input, 0).length);} + @Test public void Replace() { + tst_Replace("ab", "a", "b", "bb"); // basic + tst_Replace("ab", "c", "b", "ab"); // replaceNot + tst_Replace("aba", "a", "b", "bbb"); // replaceMultiple + } void tst_Replace(String input, String find, String replace, String expd) {Tfds.Eq(expd, RegxAdp_.Replace(input, find, replace));} + @Test public void Match_WholeWord() { + tst_WholeWord("a", "ab a", true); // pass a + tst_WholeWord("a", "ab c", false); // fail ab + tst_WholeWord("a", "a_", false); // fail a_ + tst_WholeWord("[a]", "a [a] c", true); // pass [a] + tst_WholeWord("[a]", "a[a]c", false); // fail a[a]c + } void tst_WholeWord(String regx, String text, boolean expd) {Tfds.Eq(expd, RegxAdp_.Match(text, RegxBldr.WholeWord(regx)));} + @Test public void Match_As() { + tst_Regx("public static [A-Za-z0-9_]+ as_\\(Object obj\\)", "public static Obj1 as_(Object obj) {return obj instanceof Obj1 ? (Obj1)obj : null;}", true); + tst_Regx("public static [A-Za-z0-9_]+ as_\\(Object obj\\)", "public static boolean Asterisk(Object obj) {}", false); + } void tst_Regx(String regx, String text, boolean expd) {Tfds.Eq(expd, RegxAdp_.Match(text, regx));} + @Test public void Find() { + tst_Matches("b", "a b c b a", match_(2, 1), match_(6, 1)); + tst_Matches("d", "a b c b a"); + tst_Matches("b", "a b c b a b b", matches_(2, 6, 10, 12)); // BUGFIX: multiple entries did not work b/c of += instead of + + } + @Test public void Groups() { + tst_Groups("abc def ghi dz", "(d\\p{L}+)", "def", "dz"); + } + RegxMatch[] matches_(int... bgnAry) { + int aryLen = Array_.Len(bgnAry); + RegxMatch[] rv = new RegxMatch[aryLen]; + for (int i = 0; i < aryLen; i++) + rv[i] = match_(bgnAry[i]); + return rv; + } + RegxMatch match_(int bgn) {return match_(bgn, Int_.MinValue);} + RegxMatch match_(int bgn, int len) {return new RegxMatch(true, bgn, bgn + len, RegxGroup.Ary_empty);} + void tst_Matches(String find, String input, RegxMatch... expd) { + List_adp expdList = Array_.XtoList(expd); + List_adp actlList = RegxAdp_.Find_args(input, find).Exec_asList(); + Tfds.Eq_list(expdList, actlList, this); + } + void tst_Groups(String text, String regx, String... expd) { + RegxAdp regx_mgr = RegxAdp_.new_(regx); + RegxMatch[] rslts = regx_mgr.Match_all(text, 0); + Tfds.Eq_ary_str(expd, To_ary(rslts)); + } + String[] To_ary(RegxMatch[] ary) { + List_adp rv = List_adp_.new_(); + int len = ary.length; + for (int i = 0; i < len; i++) { + RegxMatch itm = ary[i]; + int cap_len = itm.Groups().length; + for (int j = 0; j < cap_len; j++) { + rv.Add(itm.Groups()[j].Val()); + } + } + return rv.To_str_ary(); + } + public String XtoStr(Object curObj, Object expdObj) { + RegxMatch cur = (RegxMatch)curObj, expd = (RegxMatch)expdObj; + String rv = "bgn=" + cur.Find_bgn(); + if (expd != null && expd.Find_len() != Int_.MinValue) rv += " len=" + cur.Find_len(); + return rv; + } +} diff --git a/100_core/src_150_text/gplx/texts/RegxAdp_mpo_find.java b/100_core/src_150_text/gplx/texts/RegxAdp_mpo_find.java new file mode 100644 index 000000000..a4d83413f --- /dev/null +++ b/100_core/src_150_text/gplx/texts/RegxAdp_mpo_find.java @@ -0,0 +1,36 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.texts; import gplx.*; +public class RegxAdp_mpo_find { + public String Input() {return input;} public RegxAdp_mpo_find Input_(String val) {input = val; return this;} private String input; + public String Find() {return find;} public RegxAdp_mpo_find Find_(String val) {find = val; return this;} private String find; + public List_adp Exec_asList() { + RegxAdp regx = RegxAdp_.new_(find); + int idx = 0; + List_adp rv = List_adp_.new_(); + while (true) { + RegxMatch match = regx.Match(input, idx); + if (match.Rslt_none()) break; + rv.Add(match); + int findBgn = match.Find_bgn(); + idx = findBgn + match.Find_len(); + if (idx > String_.Len(input)) break; + } + return rv; + } +} diff --git a/100_core/src_150_text/gplx/texts/RegxAdp_mpo_replace.java b/100_core/src_150_text/gplx/texts/RegxAdp_mpo_replace.java new file mode 100644 index 000000000..9165092e7 --- /dev/null +++ b/100_core/src_150_text/gplx/texts/RegxAdp_mpo_replace.java @@ -0,0 +1,27 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.texts; import gplx.*; +public class RegxAdp_mpo_replace { + public String Input() {return input;} public RegxAdp_mpo_replace Input_(String val) {input = val; return this;} private String input; + public String Find() {return find;} public RegxAdp_mpo_replace Find_(String val) {find = val; return this;} private String find; + public String Replace() {return replace;} public RegxAdp_mpo_replace Replace_(String val) {replace = val; return this;} private String replace; + public String Exec_asStr() { + RegxAdp regx = RegxAdp_.new_(find); + return regx.ReplaceAll(input, replace); + } +} diff --git a/100_core/src_150_text/gplx/texts/RegxBldr.java b/100_core/src_150_text/gplx/texts/RegxBldr.java new file mode 100644 index 000000000..f4489ad43 --- /dev/null +++ b/100_core/src_150_text/gplx/texts/RegxBldr.java @@ -0,0 +1,62 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.texts; import gplx.*; +import gplx.core.strings.*; +public class RegxBldr { + public static String Includes(String characters) {return String_.Concat_any(RegxBldr.Tkn_CharSetBegin, characters, RegxBldr.Tkn_CharSetEnd);} + public static String Excludes(String characters) {return String_.Concat_any(RegxBldr.Tkn_CharSetBegin, RegxBldr.Tkn_Not, characters, RegxBldr.Tkn_CharSetEnd);} + public static String WholeWord(String word) {return String_.Concat_any("(?. +*/ +package gplx.texts; import gplx.*; +public class RegxGroup { + public RegxGroup(boolean rslt, int bgn, int end, String val) {this.rslt = rslt; this.bgn = bgn; this.end = end; this.val = val;} + public boolean Rslt() {return rslt;} private boolean rslt; + public int Bgn() {return bgn;} int bgn; + public int End() {return end;} int end; + public String Val() {return val;} private String val; + public static final RegxGroup[] Ary_empty = new RegxGroup[0]; +} diff --git a/100_core/src_150_text/gplx/texts/RegxMatch.java b/100_core/src_150_text/gplx/texts/RegxMatch.java new file mode 100644 index 000000000..011b67885 --- /dev/null +++ b/100_core/src_150_text/gplx/texts/RegxMatch.java @@ -0,0 +1,28 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.texts; import gplx.*; +public class RegxMatch { + public RegxMatch(boolean rslt, int find_bgn, int find_end, RegxGroup[] groups) {this.rslt = rslt; this.find_bgn = find_bgn; this.find_end = find_end; this.groups = groups;} + public boolean Rslt() {return rslt;} private boolean rslt; + public boolean Rslt_none() {return !rslt;} // NOTE: was "|| find_end - find_bgn == 0"; DATE:2013-04-11; DATE:2014-09-02 + public int Find_bgn() {return find_bgn;} int find_bgn; + public int Find_end() {return find_end;} int find_end; + public int Find_len() {return find_end - find_bgn;} + public RegxGroup[] Groups() {return groups;} RegxGroup[] groups = RegxGroup.Ary_empty; + public static final RegxMatch[] Ary_empty = new RegxMatch[0]; +} diff --git a/100_core/src_150_text/gplx/texts/RegxPatn_cls_ioMatch.java b/100_core/src_150_text/gplx/texts/RegxPatn_cls_ioMatch.java new file mode 100644 index 000000000..f156a3e9f --- /dev/null +++ b/100_core/src_150_text/gplx/texts/RegxPatn_cls_ioMatch.java @@ -0,0 +1,34 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.texts; import gplx.*; +public class RegxPatn_cls_ioMatch { + public String Raw() {return raw;} private String raw; + public boolean CaseSensitive() {return caseSensitive;} private boolean caseSensitive; + public boolean Matches(String text) { + text = String_.CaseNormalize(caseSensitive, text); + return RegxAdp_.Match(text, compiled);} // WNT-centric: Io_mgr paths are case-insensitive; + @Override public String toString() {return raw;} + + String compiled; + @gplx.Internal protected RegxPatn_cls_ioMatch(String raw, String compiled, boolean caseSensitive) { + this.caseSensitive = caseSensitive; + this.raw = raw; + compiled = String_.CaseNormalize(caseSensitive, compiled); + this.compiled = compiled; + } +} diff --git a/100_core/src_150_text/gplx/texts/RegxPatn_cls_ioMatch_.java b/100_core/src_150_text/gplx/texts/RegxPatn_cls_ioMatch_.java new file mode 100644 index 000000000..ee5f5cfc2 --- /dev/null +++ b/100_core/src_150_text/gplx/texts/RegxPatn_cls_ioMatch_.java @@ -0,0 +1,53 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.texts; import gplx.*; +import gplx.core.strings.*; +public class RegxPatn_cls_ioMatch_ { + public static final String Wildcard = "*"; + public static final String OrDelimiter = "|"; + public static final RegxPatn_cls_ioMatch All = RegxPatn_cls_ioMatch_.parse_(Wildcard, false); + public static final String ImpossiblePath = "<>"; //"<>" should be an impossible url; NOTE: do not pick * or | or : or \ + public static final RegxPatn_cls_ioMatch None = RegxPatn_cls_ioMatch_.parse_(RegxPatn_cls_ioMatch_.ImpossiblePath, false); + public static RegxPatn_cls_ioMatch cast_(Object obj) {try {return (RegxPatn_cls_ioMatch)obj;} catch(Exception exc) {throw Exc_.new_type_mismatch_w_exc(exc, RegxPatn_cls_ioMatch.class, obj);}} + public static RegxPatn_cls_ioMatch parse_(String raw, boolean caseSensitive) { + String compiled = RegxPatn_cls_ioMatch_.Compile(raw); + return new RegxPatn_cls_ioMatch(raw, compiled, caseSensitive); + } + @gplx.Internal protected static String Compile(String raw) { + if (raw == ImpossiblePath) return ImpossiblePath; + + String_bldr sb = String_bldr_.new_(); + sb.Add(RegxBldr.Tkn_LineBegin); // Char_LineBegin for exact match (else "LIKE a" would match "abc") + int rawLen = String_.Len(raw); + for (int i = 0; i < rawLen; i++) { + char c = String_.CharAt(raw, i); + if (c == '\\') + sb.Add("\\\\"); + else if (c == '*') + sb.Add(".").Add(RegxBldr.Tkn_Wild_0Plus); + else if (c == '|') + sb.Add(RegxBldr.Tkn_LineEnd).Add("|").Add(RegxBldr.Tkn_LineBegin); // each term must be bracketed by lineBgn/lineEnd; ex: A|B -> ^A$|^B$ + else + sb.Add(c); + } + sb.Add(RegxBldr.Tkn_LineEnd); + return sb.XtoStr(); + } + public static final String InvalidCharacters = "|*?\"<>"; // : / \ are omitted b/c they will cause full paths to fail + public static final String ValidCharacters = RegxBldr.Excludes(InvalidCharacters); +} diff --git a/100_core/src_150_text/gplx/texts/RegxPatn_cls_ioMatch_tst.java b/100_core/src_150_text/gplx/texts/RegxPatn_cls_ioMatch_tst.java new file mode 100644 index 000000000..b2f2d1ee4 --- /dev/null +++ b/100_core/src_150_text/gplx/texts/RegxPatn_cls_ioMatch_tst.java @@ -0,0 +1,58 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.texts; import gplx.*; +import org.junit.*; +public class RegxPatn_cls_ioMatch_tst { + @Test public void SimpleMatches() { + tst_Matches("file.cs", "file.cs", true); // basic + tst_Matches("file.cs", "file.cs.exe", false); // fail: must match name precisely + tst_Matches("file.cs", "tst_file.cs", false); // fail: must match name precisely + } + @Test public void Wildcard() { + tst_Matches("*.cs", "file.cs", true); // pass: before + tst_Matches("file*", "file_valid.cs", true); // pass: after + tst_Matches("*.exe", "file.cs", false); // fail: before + tst_Matches("file*", "invalid_file.cs", false); // fail: after + } + @Test public void DoubleWildcard() { + tst_Matches("*cs*", "file.cs", true); // pass: after + tst_Matches("*cs*", "csFile.exe", true); // pass: before + tst_Matches("*cs*", "file.cs.exe", true); // pass: middle + tst_Matches("*cs*", "file.exe", false); // fail + } + @Test public void Compound() { + tst_Matches("*.cs|*.exe", "file.cs", true); // pass: match first + tst_Matches("*.cs|*.exe", "file.exe", true); // pass: match second + tst_Matches("*.cs|*.exe", "file.dll", false); // fail: match neither + tst_Matches("*.cs|*.exe", "file.cs.exe.dll", false); // fail: match neither (though both are embedded) + } + @Test public void Backslash() { + tst_Matches("*\\bin\\*", "C:\\project\\bin\\", true); // pass: dir + tst_Matches("*\\bin\\*", "C:\\project\\bin\\file.dll", true); // pass: fil + tst_Matches("*\\bin\\*", "C:\\project\\binFiles\\", false); // fail + } + @Test public void MixedCase() { + tst_Matches("file.cs", "file.cs", true); // pass: same case + tst_Matches("file.cs", "File.cS", true); // pass: diff case + } + void tst_Matches(String regx, String raw, boolean expd) { + RegxPatn_cls_ioMatch pattern = RegxPatn_cls_ioMatch_.parse_(regx, false); + boolean actl = pattern.Matches(raw); + Tfds.Eq(expd, actl); + } +} diff --git a/100_core/src_150_text/gplx/texts/RegxPatn_cls_like.java b/100_core/src_150_text/gplx/texts/RegxPatn_cls_like.java new file mode 100644 index 000000000..ee6580630 --- /dev/null +++ b/100_core/src_150_text/gplx/texts/RegxPatn_cls_like.java @@ -0,0 +1,31 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.texts; import gplx.*; +public class RegxPatn_cls_like { + public char Escape() {return escape;} char escape; public static final char EscapeDefault = '|'; + public String Raw() {return raw;} private String raw; + public boolean Matches(String text) {return RegxAdp_.Match(text, compiled);} + @Override public String toString() {return String_.Format("LIKE {0} ESCAPE {1} -> {2}", raw, escape, compiled);} + + String compiled; + @gplx.Internal protected RegxPatn_cls_like(String raw, String compiled, char escape) { + this.raw = raw; + this.compiled = compiled; + this.escape = escape; + } +} diff --git a/100_core/src_150_text/gplx/texts/RegxPatn_cls_like_.java b/100_core/src_150_text/gplx/texts/RegxPatn_cls_like_.java new file mode 100644 index 000000000..aae4c90b5 --- /dev/null +++ b/100_core/src_150_text/gplx/texts/RegxPatn_cls_like_.java @@ -0,0 +1,63 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.texts; import gplx.*; +import gplx.core.strings.*; +public class RegxPatn_cls_like_ { + public static RegxPatn_cls_like parse_(String regxRaw, char escape) { + String regx = Compile(regxRaw, escape); + return new RegxPatn_cls_like(regxRaw, regx, escape); + } + static String Compile(String raw, char escape) { + char Wildcard = '%', AnyChar = '_'; + boolean insideCharSet = false; + String_bldr sb = String_bldr_.new_(); + sb.Add(RegxBldr.Tkn_LineBegin); + int rawLen = String_.Len(raw); + for (int i = 0; i < rawLen; i++) { + char c = String_.CharAt(raw, i); + if (c == escape) { // escape: ignore cur, append next + i++; + if (i < rawLen) sb.Add(String_.CharAt(raw, i)); + else throw Exc_.new_("escape cannot be last char", "raw", raw, "escape", escape, "i", i); + } + else if (c == Wildcard) { // % -> .* + sb.Add(RegxBldr.Tkn_AnyChar).Add(RegxBldr.Tkn_Wild_0Plus); + } + else if (c == AnyChar) // _ -> . + sb.Add(RegxBldr.Tkn_AnyChar); + else if (c == RegxBldr.Tkn_CharSetBegin) { // toggle insideCharSet for ^ + insideCharSet = true; + sb.Add(c); + } + else if (c == RegxBldr.Tkn_CharSetEnd) { // toggle insideCharSet for ^ + insideCharSet = false; + sb.Add(c); + } + else if (c == RegxBldr.Tkn_Not && insideCharSet) { // ^ is used for Not in CharSet, but also used for LineStart; do not escape if insideCharSet + insideCharSet = false; + sb.Add(c); + } + else if (RegxBldr.RegxChar_chk(c)) + sb.Add(RegxBldr.Tkn_Escape).Add(c); + else // regular text + sb.Add(c); + } + sb.Add(RegxBldr.Tkn_LineEnd); + return sb.XtoStr(); + } +} diff --git a/100_core/src_150_text/gplx/texts/RegxPatn_cls_like_tst.java b/100_core/src_150_text/gplx/texts/RegxPatn_cls_like_tst.java new file mode 100644 index 000000000..c82f0c872 --- /dev/null +++ b/100_core/src_150_text/gplx/texts/RegxPatn_cls_like_tst.java @@ -0,0 +1,86 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.texts; import gplx.*; +import org.junit.*; +public class RegxPatn_cls_like_tst { + @Test public void Basic() { + tst_Match("abcd", "abcd", true); // basic; pass + tst_Match("abcd", "zbcd", false); // basic; fail + tst_Match("abcd", "abc", false); // no wildcard; must be exact match + tst_Match("a cd", "a cd", true); // check space works + } + @Test public void Wildcard() { + tst_Match("abcd", "a%", true); // bgn; pass + tst_Match("abcd", "b%", false); // bgn; fail + tst_Match("abcd", "%d", true); // end; pass + tst_Match("abcd", "%c", false); // end; fail + tst_Match("abcd", "%b%", true); // flank; pass + tst_Match("abcd", "%e%", false); // flank; fail + tst_Match("abcd", "%a%", true); // flank; bgn; pass + tst_Match("abcd", "%d%", true); // flank; end; pass + } + @Test public void Any() { + tst_Match("abcd", "a_cd", true); // basic; pass + tst_Match("abcd", "z_cd", false); // basic; fail + tst_Match("abcd", "a_c", false); // fail; check no wildcard + } + @Test public void CharSet() { + tst_Match("abcd", "a[b]cd", true); // pass + tst_Match("abcd", "a[x]cd", false); // fail + tst_Match("abcd", "a[bcde]cd", true); // multiple; pass + tst_Match("abcd", "a[xyz]cd", false); // multiple; fail + tst_Match("abcd", "a[^z]cd", true); // not; pass + tst_Match("abcd", "a[^b]cd", false); // not; fail + } + @Test public void Escape() { + tst_Match("a%b", "a|%b", true); // escape wildcard; pass + tst_Match("a%bc", "a|%b", false); // escape wildcard; fail + tst_Match("a|b", "a|b", false); // escape char; fail + tst_Match("a|b", "a||b", true); // escape char; pass + } + @Test public void Escape_diffChar() { + tst_Match("a%b", "a~%b", '~', true); // escape wildcard; pass + tst_Match("a%bc", "a~%b", '~', false); // escape wildcard; fail + tst_Match("a|b", "a|b", '~', true); // no escape needed + tst_Match("a~b", "a~b", '~', false); // escape char; fail + tst_Match("a~b", "a~~b", '~', true); // escape char; pass + } + @Test public void Chars() { // Escape RegxBldr; ex: LIKE 'a{' -> a\{ + tst_EscapeRegxChar(RegxBldr.Tkn_Escape); // \ + tst_EscapeRegxChar(RegxBldr.Tkn_GroupBegin); // [ + tst_EscapeRegxChar(RegxBldr.Tkn_GroupEnd); // ] + tst_EscapeRegxChar(RegxBldr.Tkn_LineBegin); // ^ + tst_EscapeRegxChar(RegxBldr.Tkn_LineEnd); // $ + tst_EscapeRegxChar(RegxBldr.Tkn_RepBegin); // { + tst_EscapeRegxChar(RegxBldr.Tkn_RepEnd); // } + tst_EscapeRegxChar(RegxBldr.Tkn_Wild_0or1); // ? + tst_EscapeRegxChar(RegxBldr.Tkn_Wild_0Plus); // * + tst_EscapeRegxChar(RegxBldr.Tkn_Wild_1Plus); // + + } + void tst_Match(String raw, String regx, boolean expd) {tst_Match(raw, regx, RegxPatn_cls_like.EscapeDefault, expd);} + void tst_Match(String raw, String regx, char escape, boolean expd) { + RegxPatn_cls_like like = RegxPatn_cls_like_.parse_(regx, escape); + boolean actl = like.Matches(raw); + Tfds.Eq(expd, actl, "raw={0} regx={1} expd={2}", raw, regx, expd); + } + void tst_EscapeRegxChar(char regexChar) { + RegxPatn_cls_like like = RegxPatn_cls_like_.parse_(Object_.Xto_str_strict_or_empty(regexChar), '|'); + Tfds.Eq(true, like.Matches(Object_.Xto_str_strict_or_empty(regexChar))); + Tfds.Eq(false, like.Matches("a")); // catches errors for improper escaping of wildcard + } +} diff --git a/100_core/src_150_text/gplx/texts/StringTableBldr.java b/100_core/src_150_text/gplx/texts/StringTableBldr.java new file mode 100644 index 000000000..39f467685 --- /dev/null +++ b/100_core/src_150_text/gplx/texts/StringTableBldr.java @@ -0,0 +1,57 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.texts; import gplx.*; +import gplx.core.strings.*; +public class StringTableBldr { + public void ClearRows() {rows.Clear();} + public StringTableCol Col_(int i) {return FetchAtOrNew(i);} + public StringTableBldr DefaultHalign_(StringTableColAlign v) {defaultHalign = v; return this;} StringTableColAlign defaultHalign = StringTableColAlign.Left; + public StringTableBldr Add(String... row) { + rows.Add(row); + for (int i = 0; i < row.length; i++) { + StringTableCol col = FetchAtOrNew(i); + col.AdjustFor(row[i]); + } + return this; + } + public StringTableCol FetchAtOrNew(int i) { + if (i < cols.Count()) return StringTableCol.as_(cols.Get_at(i)); + StringTableCol col = StringTableCol.new_(); + col.Halign_(defaultHalign); + cols.Add(i, col); + return col; + } + public String XtoStr() { + sb.Clear(); + for (int rowI = 0; rowI < rows.Count(); rowI++) { + String[] row = (String[])rows.Get_at(rowI); + for (int colI = 0; colI < row.length; colI++) { + if (colI != 0) sb.Add(" "); + StringTableCol col = StringTableCol.as_(cols.Get_at(colI)); if (col == null) throw Exc_.new_missing_idx(colI, cols.Count()); + sb.Add(col.PadCell(row[colI])); + } + sb.Add(String_.CrLf); + } + return sb.Xto_str_and_clear(); + } + + public static StringTableBldr new_() {return new StringTableBldr();} StringTableBldr() {} + Ordered_hash cols = Ordered_hash_.new_(); + List_adp rows = List_adp_.new_(); + String_bldr sb = String_bldr_.new_(); +} diff --git a/100_core/src_150_text/gplx/texts/StringTableBldr_tst.java b/100_core/src_150_text/gplx/texts/StringTableBldr_tst.java new file mode 100644 index 000000000..11ae3414e --- /dev/null +++ b/100_core/src_150_text/gplx/texts/StringTableBldr_tst.java @@ -0,0 +1,59 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.texts; import gplx.*; +import org.junit.*; +public class StringTableBldr_tst { + @Before public void setup() { + bldr = StringTableBldr.new_(); + } StringTableBldr bldr; + @Test public void TwoCols() { + bldr.Add("a", "aa") + .Add("bb", "b"); + tst_XtoStr + ( "a aa" + , "bb b " + , "" + ); + } + @Test public void RightAlign() { + bldr.Add("a", "aa") + .Add("bb", "b"); + bldr.FetchAtOrNew(0).Halign_(StringTableColAlign.Right); + bldr.FetchAtOrNew(1).Halign_(StringTableColAlign.Right); + tst_XtoStr + ( " a aa" + , "bb b" + , "" + ); + } + @Test public void CenterAlign() { + bldr.Add("aaaa", "a") + .Add("b", "bbbb"); + bldr.FetchAtOrNew(0).Halign_(StringTableColAlign.Mid); + bldr.FetchAtOrNew(1).Halign_(StringTableColAlign.Mid); + tst_XtoStr + ( "aaaa a " + , " b bbbb" + , "" + ); + } + void tst_XtoStr(String... expdLines) { + String expd = String_.ConcatWith_any(String_.CrLf, (Object[])expdLines); + Tfds.Eq(expd, bldr.XtoStr()); + } +} diff --git a/100_core/src_150_text/gplx/texts/StringTableCol.java b/100_core/src_150_text/gplx/texts/StringTableCol.java new file mode 100644 index 000000000..b2750efe9 --- /dev/null +++ b/100_core/src_150_text/gplx/texts/StringTableCol.java @@ -0,0 +1,39 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.texts; import gplx.*; +public class StringTableCol { + public StringTableColAlign Halign() {return halign;} public StringTableCol Halign_(StringTableColAlign val) {halign = val; return this;} StringTableColAlign halign = StringTableColAlign.Left; + public int LengthMax() {return lengthMax;} int lengthMax = Int_.MinValue; + public int LengthMin() {return lengthMin;} int lengthMin = Int_.MaxValue; + public void AdjustFor(String s) { + int length = String_.Len(s); + if (length > lengthMax) lengthMax = length; + if (length < lengthMin) lengthMin = length; + } + public String PadCell(String cell) { + int diff = lengthMax - String_.Len(cell); + int val = halign.Val(); + if (val == StringTableColAlign.Left.Val()) return cell + String_.Repeat(" ", diff); + else if (val == StringTableColAlign.Right.Val()) return String_.Repeat(" ", diff) + cell; + else if (val == StringTableColAlign.Mid.Val()) return String_.Concat(String_.Repeat(" ", diff / 2), cell, String_.Repeat(" ", (diff / 2) + (diff % 2))); + else throw Exc_.new_unhandled(halign.Val()); + } + public static StringTableCol new_() {return new StringTableCol();} StringTableCol() {} + public static StringTableCol as_(Object obj) {return obj instanceof StringTableCol ? (StringTableCol)obj : null;} + public static StringTableCol cast_(Object obj) {try {return (StringTableCol)obj;} catch(Exception exc) {throw Exc_.new_type_mismatch_w_exc(exc, StringTableCol.class, obj);}} +} diff --git a/100_core/src_150_text/gplx/texts/StringTableColAlign.java b/100_core/src_150_text/gplx/texts/StringTableColAlign.java new file mode 100644 index 000000000..24e919606 --- /dev/null +++ b/100_core/src_150_text/gplx/texts/StringTableColAlign.java @@ -0,0 +1,29 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.texts; import gplx.*; +public class StringTableColAlign { + public int Val() {return val;} int val = 0; + public static StringTableColAlign new_(int v) { + StringTableColAlign rv = new StringTableColAlign(); + rv.val = v; + return rv; + } StringTableColAlign() {} + public static final StringTableColAlign Left = new_(0); + public static final StringTableColAlign Mid = new_(1); + public static final StringTableColAlign Right = new_(2); +} diff --git a/100_core/src_160_hash/gplx/security/HashAlgo.java b/100_core/src_160_hash/gplx/security/HashAlgo.java new file mode 100644 index 000000000..1fad940f5 --- /dev/null +++ b/100_core/src_160_hash/gplx/security/HashAlgo.java @@ -0,0 +1,24 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.security; import gplx.*; +import gplx.ios.*; /*IoStream*/ +public interface HashAlgo { + String Key(); + String CalcHash(ConsoleDlg dialog, IoStream stream); + byte[] Calc_hash_bry(byte[] v); +} diff --git a/100_core/src_160_hash/gplx/security/HashAlgo_.java b/100_core/src_160_hash/gplx/security/HashAlgo_.java new file mode 100644 index 000000000..a603177a6 --- /dev/null +++ b/100_core/src_160_hash/gplx/security/HashAlgo_.java @@ -0,0 +1,93 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.security; import gplx.*; +import java.math.BigInteger; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import gplx.ios.*; /*IoStream*/import gplx.texts.*; /*Base32Converter*/ +public class HashAlgo_ { + public static final HashAlgo Null = new HashAlgo_null(); + public static final HashAlgo Sha1 = HashAlgo_sha1.new_(); + public static final HashAlgo Md5 = HashAlgo_md5.new_(); + public static final HashAlgo Tth192 = HashAlgo_tth192.new_(); + public static HashAlgo as_(Object obj) {return obj instanceof HashAlgo ? (HashAlgo)obj : null;} + public static HashAlgo cast_(Object obj) {if (obj == null) return null; HashAlgo rv = as_(obj); if (rv == null) throw Exc_.new_type_mismatch(HashAlgo.class, obj); return rv;} + public static HashAlgo fetch_(String key) { + if (key == HashAlgo_md5.KEY) return Md5; + else if (key == HashAlgo_sha1.KEY) return Sha1; + else if (key == HashAlgo_tth192.KEY) return Tth192; + else throw Exc_.new_unhandled(key); + } + public static HashAlgo store_orSelf_(SrlMgr mgr, String key, HashAlgo or) { + String algoType = mgr.SrlStrOr(key, or.Key()); + return mgr.Type_rdr() ? HashAlgo_.fetch_(algoType): or; + } +} +class HashAlgo_null implements HashAlgo { + public String Key() {return "HashAlgo_null";} + public byte[] Calc_hash_bry(byte[] v) {return Bry_.new_a7(CalcHash(ConsoleDlg_.Null, gplx.ios.IoStream_.ary_(v)));} + public String CalcHash(ConsoleDlg dialog, IoStream stream) {return "NullAlgoHash";} +} +class HashAlgo_md5 implements HashAlgo { + public String Key() {return KEY;} public static final String KEY = "md5"; + public byte[] Calc_hash_bry(byte[] v) {return Bry_.new_a7(CalcHash(ConsoleDlg_.Null, gplx.ios.IoStream_.ary_(v)));} + public String CalcHash(ConsoleDlg dialog, IoStream stream) {return HashAlgoUtl.CalcHashAsString(dialog, stream, "MD5");} + public static HashAlgo_md5 new_() {return new HashAlgo_md5();} HashAlgo_md5() {} +} +class HashAlgo_sha1 implements HashAlgo { + public String Key() {return KEY;} public static final String KEY = "sha1"; + public byte[] Calc_hash_bry(byte[] v) {return Bry_.new_a7(CalcHash(ConsoleDlg_.Null, gplx.ios.IoStream_.ary_(v)));} + public String CalcHash(ConsoleDlg dialog, IoStream stream) {return HashAlgoUtl.CalcHashAsString(dialog, stream, "SHA1");} + public static HashAlgo_sha1 new_() {return new HashAlgo_sha1();} HashAlgo_sha1() {} +} +class HashAlgoUtl { + public static String CalcHashAsString(ConsoleDlg dialog, IoStream stream, String key) { + MessageDigest md = null; + try {md = MessageDigest.getInstance(key);} + catch (NoSuchAlgorithmException e) {throw Err_arg.notFound_key_("key", key);} + byte[] buffer = new byte[8192]; + int read = 0; + long pos = 0, len = stream.Len(); // pos and len must be long, else will not hash files > 2 GB + while (true) { + read = stream.Read(buffer, 0, 8192); + if (pos >= len) break; + md.update(buffer, 0, read); + pos += read; + } + byte[] md5sum = md.digest(); + BigInteger bigInt = new BigInteger(1, md5sum); + String rv = bigInt.toString(16); + int rvLen = rv.length(); + while (rvLen < 32) { + rv = "0" + rv; + rvLen++; + } + return rv; + } + public static String XtoStrBase16(byte[] ary) { + BigInteger bigInt = new BigInteger(1, ary); + String rv = bigInt.toString(16); + int rvLen = rv.length(); + while (rvLen < 32) { + rv = "0" + rv; + rvLen++; + } + return rv; + } + public static String XtoStrBase32(byte[] ary) {return Base32Converter.Encode(ary);} +} diff --git a/100_core/src_160_hash/gplx/security/HashAlgo_md5_tst.java b/100_core/src_160_hash/gplx/security/HashAlgo_md5_tst.java new file mode 100644 index 000000000..3c5c52386 --- /dev/null +++ b/100_core/src_160_hash/gplx/security/HashAlgo_md5_tst.java @@ -0,0 +1,81 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.security; import gplx.*; +import org.junit.*; +import gplx.ios.*; /*IoStream*/ +public class HashAlgo_md5_tst { + @Test public void Empty() { + tst_CalcBase16FromString("", "d41d8cd98f00b204e9800998ecf8427e"); + } + @Test public void A() { + tst_CalcBase16FromString("a", "0cc175b9c0f1b6a831c399e269772661"); + } + @Test public void Abc() { + tst_CalcBase16FromString("abc", "900150983cd24fb0d6963f7d28e17f72"); + } + @Test public void A_Za_z0_9() { + tst_CalcBase16FromString("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "d174ab98d277d9f5a5611c2c9f419d9f"); + } + //@Test + public void A_1Million() { + tst_CalcBase16FromString(String_.Repeat("a", 1000000), "7707d6ae4e027c70eea2a935c2296f21"); + } + void tst_CalcBase16FromString(String raw, String expd) { + IoStream stream = IoStream_.mem_txt_(Io_url_.Empty, raw); + String actl = HashAlgo_.Md5.CalcHash(ConsoleDlg_.Null, stream); + Tfds.Eq(expd, actl); + } + /* + https://www.cosic.esat.kuleuven.be/nessie/testvectors/hash/md5/Md5-128.unverified.test-vectors + Set 1, vector# 0: + message="" (empty String) + hash=D41D8CD98F00B204E9800998ECF8427E + + Set 1, vector# 1: + message="a" + hash=0CC175B9C0F1B6A831C399E269772661 + + Set 1, vector# 2: + message="abc" + hash=900150983CD24FB0D6963F7D28E17F72 + + Set 1, vector# 3: + message="message digest" + hash=F96B697D7CB7938D525A2F31AAF161D0 + + Set 1, vector# 4: + message="abcdefghijklmnopqrstuvwxyz" + hash=C3FCD3D76192E4007DFB496CCA67E13B + + Set 1, vector# 5: + message="abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + hash=8215EF0796A20BCAAAE116D3876C664A + + Set 1, vector# 6: + message="A...Za...z0...9" + hash=D174AB98D277D9F5A5611C2C9F419D9F + + Set 1, vector# 7: + message=8 times "1234567890" + hash=57EDF4A22BE3C955AC49DA2E2107B67A + + Set 1, vector# 8: + message=1 million times "a" + hash=7707D6AE4E027C70EEA2A935C2296F21 + */ +} diff --git a/100_core/src_160_hash/gplx/security/HashAlgo_sha1_tst.java b/100_core/src_160_hash/gplx/security/HashAlgo_sha1_tst.java new file mode 100644 index 000000000..39e8e4d83 --- /dev/null +++ b/100_core/src_160_hash/gplx/security/HashAlgo_sha1_tst.java @@ -0,0 +1,81 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.security; import gplx.*; +import org.junit.*; +import gplx.ios.*; /*IoStream*/ +public class HashAlgo_sha1_tst { + @Test public void Empty() { + tst_CalcBase16FromString("", "da39a3ee5e6b4b0d3255bfef95601890afd80709"); + } + @Test public void A() { + tst_CalcBase16FromString("a", "86f7e437faa5a7fce15d1ddcb9eaeaea377667b8"); + } + @Test public void Abc() { + tst_CalcBase16FromString("abc", "a9993e364706816aba3e25717850c26c9cd0d89d"); + } + @Test public void A_Za_z0_9() { + tst_CalcBase16FromString("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "761c457bf73b14d27e9e9265c46f4b4dda11f940"); + } + //@Test + public void A_1Million() { + tst_CalcBase16FromString(String_.Repeat("a", 1000000), "34aa973cd4c4daa4f61eeb2bdbad27316534016f"); + } + void tst_CalcBase16FromString(String raw, String expd) { + IoStream stream = IoStream_.mem_txt_(Io_url_.Empty, raw); + String actl = HashAlgo_.Sha1.CalcHash(ConsoleDlg_.Null, stream); + Tfds.Eq(expd, actl); + } + /* + https://www.cosic.esat.kuleuven.be/nessie/testvectors/ + Set 1, vector# 0: + message="" (empty String) + hash=DA39A3EE5E6B4B0D3255BFEF95601890AFD80709 + + Set 1, vector# 1: + message="a" + hash=86F7E437FAA5A7FCE15D1DDCB9EAEAEA377667B8 + + Set 1, vector# 2: + message="abc" + hash=A9993E364706816ABA3E25717850C26C9CD0D89D + + Set 1, vector# 3: + message="message digest" + hash=C12252CEDA8BE8994D5FA0290A47231C1D16AAE3 + + Set 1, vector# 4: + message="abcdefghijklmnopqrstuvwxyz" + hash=32D10C7B8CF96570CA04CE37F2A19D84240D3A89 + + Set 1, vector# 5: + message="abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + hash=84983E441C3BD26EBAAE4AA1F95129E5E54670F1 + + Set 1, vector# 6: + message="A...Za...z0...9" + hash=761C457BF73B14D27E9E9265C46F4B4DDA11F940 + + Set 1, vector# 7: + message=8 times "1234567890" + hash=50ABF5706A150990A08B2C5EA40FA0E585554732 + + Set 1, vector# 8: + message=1 million times "a" + hash=34AA973CD4C4DAA4F61EEB2BDBAD27316534016F + */ +} diff --git a/100_core/src_160_hash/gplx/security/HashAlgo_tth192.java b/100_core/src_160_hash/gplx/security/HashAlgo_tth192.java new file mode 100644 index 000000000..a0a88b415 --- /dev/null +++ b/100_core/src_160_hash/gplx/security/HashAlgo_tth192.java @@ -0,0 +1,1005 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.security; import gplx.*; +import gplx.ios.*; /*IoStream*/ +public class HashAlgo_tth192 implements HashAlgo { + public String Key() {return KEY;} public static final String KEY = "tth192"; + public int BlockSize() {return blockSize;} public void BlockSize_set(int v) {blockSize = v;} int blockSize = 1024; + public byte[] Calc_hash_bry(byte[] v) {return Bry_.new_a7(CalcHash(ConsoleDlg_.Null, gplx.ios.IoStream_.ary_(v)));} + public String CalcHash(ConsoleDlg dialog, IoStream stream) { + int leafCount = (int)(stream.Len() / blockSize); + HashDlgWtr dialogWtr = HashDlgWtr_.Current; + dialogWtr.Bgn(dialog, stream.Url(), CalcWorkUnits(stream.Len())); + if (stream.Len() % blockSize > 0) // if stream.length is not multiple of blockSize, add another leaf to hold leftover bytes + leafCount++; + else if (stream.Len() == 0) // if stream.length == 0, still allocate one leaf + leafCount = 1; + + hashMain = new byte[(leafCount / 2) + 1][]; // / 2 b/c HashAllBytes looks at pairs of slots; + 1 to avoid truncation + hashMainCount = 0; + HashAllBytes(dialogWtr, stream, leafCount); + byte[] rv = HashAllHashes(dialogWtr); + return HashAlgoUtl.XtoStrBase32(rv); + } + byte[] CalcHash_next(IoStream stream) { + if (blockA == null || blockA.length != blockSize) blockA = new byte[blockSize]; + if (blockB == null || blockB.length != blockSize) blockB = new byte[blockSize]; + + int dataSize = stream.Read(blockA, 0, blockSize); // if (dataSize < BlockSize) return (CalcHash_leaf(ShrinkArray(blockA, dataSize))); // TODO: reinstate? + dataSize = stream.Read(blockB, 0, blockSize); + if (dataSize < blockSize) blockB = ShrinkArray(blockB, dataSize); // shrink array to match data size (occurs at end of stream, when lastBytesCount < BlockSize) + return CalcHash_branch(CalcHash_leaf(blockA, 0), CalcHash_leaf(blockB, 1)); + } + void HashAllBytes(HashDlgWtr dialogWtr, IoStream stream, int leafCount) { + int total = leafCount / 2; + for (int i = 0; i < total; i++) { + if (dialogWtr.Canceled()) dialogWtr.Fail(stream); + hashMain[hashMainCount++] = CalcHash_next(stream); + dialogWtr.Do(2); + } + if (leafCount % 2 == 1) { // odd number of leaves => hash last leaf (since it was never in a pair) + byte[] block = new byte[blockSize]; + int dataSize = stream.Read(block, 0 , blockSize); + if (dataSize < blockSize) block = ShrinkArray(block,dataSize); // shrink array to match data size (occurs at end of stream, when lastBytesCount < BlockSize) + + hashMain[hashMainCount++] = CalcHash_leaf(block, 0); + dialogWtr.Do(1); + } + stream.Rls(); + } + byte[] HashAllHashes(HashDlgWtr dialogWtr) { + int currIdx = 0, lastIdx = hashMainCount - 1, reuseIdx = 0; + while (currIdx < lastIdx) { // calc till 1 is left; + while (currIdx < lastIdx) { // calc till 1 is left; EX: 8 slots; loop1 calcs 8; makes 4; loop0 restarts; loop1 calcs 4; makes 2; etc.. + byte[] hashA = hashMain[currIdx++]; + byte[] hashB = hashMain[currIdx++]; + hashMain[reuseIdx++] = CalcHash_branch(hashA, hashB); + dialogWtr.Do(2); + } + if (currIdx == lastIdx) // NOTE: currIdx == lastIdx only when odd number of leaves + hashMain[reuseIdx++] = hashMain[currIdx++]; +// for (int j = reuseIdx; j < lastIdx; j++) // PERF: free unused slots (may not be necessary) +// hashMain[j] = null; + lastIdx = reuseIdx - 1; + currIdx = 0; + reuseIdx = 0; + }; + dialogWtr.End(); + return (byte[])hashMain[lastIdx]; // return last hash as root hash + } + byte[] CalcHash_branch(byte[] blockA, byte[] blockB) { + // gen array: [0x01] + [blockA] + [blockB] + if (branchRv == null || branchRv.length != blockA.length + blockB.length + 1) + branchRv = new byte[blockA.length + blockB.length + 1]; + branchRv[0] = 0x01; // branch hash mark. + Array_.CopyTo(blockA, branchRv, 1); + Array_.CopyTo(blockB, branchRv, blockA.length + 1); + return CalcHash(branchRv); + } + byte[] CalcHash_leaf(byte[] raw, int i) { + // gen array: [0x00] + [raw] + byte[] rv = null; + if (i == 0) { + if (leaf0 == null || leaf0.length != raw.length + 1) { + leaf0 = new byte[raw.length + 1]; + } + rv = leaf0; + } + else { + if (leaf1 == null || leaf1.length != raw.length + 1) { + leaf1 = new byte[raw.length + 1]; + } + rv = leaf1; + } + + rv[0] = 0x00; // leaf hash mark. + Array_.CopyTo(raw, rv, 1); + return CalcHash(rv); + } + byte[] CalcHash(byte[] raw) { + algo.Initialize(); + return algo.ComputeHash(raw); + } + byte[] ShrinkArray(byte[] raw, int newLen) { + byte[] rv = new byte[newLen]; + for (int i = 0; i < newLen; i++) + rv[i] = raw[i]; + return rv; + } + public int CalcWorkUnits(long streamLength) { + int leafCount = (int)(streamLength / blockSize); + int phase1 = leafCount; + if (leafCount == 0) phase1 = 1; + else if (streamLength % blockSize != 0) phase1++; + int phase2 = phase1 <= 1 ? 0 : phase1 - 1; // see note + return phase1 + phase2; + } + Tiger192 algo = new Tiger192(); + byte[][] hashMain; int hashMainCount = 0; + byte[] blockA, blockB, branchRv, leaf0, leaf1; + public static HashAlgo_tth192 new_() {return new HashAlgo_tth192();} HashAlgo_tth192() {} +} +interface HashDlgWtr { + boolean Canceled(); + void Bgn(ConsoleDlg dialog, Io_url url, int total); + void Do(int increment); + void End(); + void Fail(IoStream stream); +} +class HashDlgWtr_ { + public static HashDlgWtr Current = HashDlgWtrDefault.new_(); +} +class HashDlgWtrDefault implements HashDlgWtr { + public int Total() {return total;} int total; + public int LastPercentage() {return lastPercentage;} int lastPercentage = 0; + public int Current() {return current;} int current = 0; + public boolean Canceled() {return dialog.CanceledChk();} + String p; + public void Bgn(ConsoleDlg dialog, Io_url url, int total) { + this.dialog = dialog; this.total = total; + p = url.Xto_api() + " - hash: "; + this.lastPercentage = 0; this.current = 0; + } + public void Do(int increment) { + current += increment; + int percentage = (current * 100) / total; + if (percentage <= lastPercentage) return; + dialog.WriteTempText(String_.LimitToFirst(p, dialog.CharsPerLineMax()) + Int_.Xto_str(percentage) + "%"); + lastPercentage = percentage; + } + public void End() {} + public void Fail(IoStream stream) { + // stream.Dispose(); + } + ConsoleDlg dialog; + public static HashDlgWtrDefault new_() {return new HashDlgWtrDefault();} +} +class Tiger192 extends BaseHash { + public void Initialize() { + this.resetContext(); + } + public byte[] ComputeHash(byte[] input) { + this.update(input, 0, input.length); + return this.digest(); + } + protected byte[] padBuffer() { + int n = (int) (count % BLOCK_SIZE); + int padding = (n < 56) ? (56 - n) : (120 - n); + byte[] pad = new byte[padding + 8]; + + pad[0] = 1; + long bits = count << 3; + + pad[padding++] = (byte) bits; + pad[padding++] = (byte) (bits >>> 8); + pad[padding++] = (byte) (bits >>> 16); + pad[padding++] = (byte) (bits >>> 24); + pad[padding++] = (byte) (bits >>> 32); + pad[padding++] = (byte) (bits >>> 40); + pad[padding++] = (byte) (bits >>> 48); + pad[padding ] = (byte) (bits >>> 56); + + return pad; + } + + protected byte[] getResult() { + return new byte[] { + (byte) a , (byte)(a >>> 8), (byte)(a >>> 16), + (byte)(a >>> 24), (byte)(a >>> 32), (byte)(a >>> 40), + (byte)(a >>> 48), (byte)(a >>> 56), + (byte) b , (byte)(b >>> 8), (byte)(b >>> 16), + (byte)(b >>> 24), (byte)(b >>> 32), (byte)(b >>> 40), + (byte)(b >>> 48), (byte)(b >>> 56), + (byte) c , (byte)(c >>> 8), (byte)(c >>> 16), + (byte)(c >>> 24), (byte)(c >>> 32), (byte)(c >>> 40), + (byte)(c >>> 48), (byte)(c >>> 56) + }; + } + + protected void resetContext() { + a = A; + b = B; + c = C; + } + protected void transform(byte[] in, int offset) { + long x0, x1, x2, x3, x4, x5, x6, x7; + + x0 = ((long) in[offset++] & 0xFF) | ((long)(in[offset++] & 0xFF) << 8) + | ((long)(in[offset++] & 0xFF) << 16) | ((long)(in[offset++] & 0xFF) << 24) + | ((long)(in[offset++] & 0xFF) << 32) | ((long)(in[offset++] & 0xFF) << 40) + | ((long)(in[offset++] & 0xFF) << 48) | ((long)(in[offset++] & 0xFF) << 56); + x1 = ((long) in[offset++] & 0xFF) | ((long)(in[offset++] & 0xFF) << 8) + | ((long)(in[offset++] & 0xFF) << 16) | ((long)(in[offset++] & 0xFF) << 24) + | ((long)(in[offset++] & 0xFF) << 32) | ((long)(in[offset++] & 0xFF) << 40) + | ((long)(in[offset++] & 0xFF) << 48) | ((long)(in[offset++] & 0xFF) << 56); + x2 = ((long) in[offset++] & 0xFF) | ((long)(in[offset++] & 0xFF) << 8) + | ((long)(in[offset++] & 0xFF) << 16) | ((long)(in[offset++] & 0xFF) << 24) + | ((long)(in[offset++] & 0xFF) << 32) | ((long)(in[offset++] & 0xFF) << 40) + | ((long)(in[offset++] & 0xFF) << 48) | ((long)(in[offset++] & 0xFF) << 56); + x3 = ((long) in[offset++] & 0xFF) | ((long)(in[offset++] & 0xFF) << 8) + | ((long)(in[offset++] & 0xFF) << 16) | ((long)(in[offset++] & 0xFF) << 24) + | ((long)(in[offset++] & 0xFF) << 32) | ((long)(in[offset++] & 0xFF) << 40) + | ((long)(in[offset++] & 0xFF) << 48) | ((long)(in[offset++] & 0xFF) << 56); + x4 = ((long) in[offset++] & 0xFF) | ((long)(in[offset++] & 0xFF) << 8) + | ((long)(in[offset++] & 0xFF) << 16) | ((long)(in[offset++] & 0xFF) << 24) + | ((long)(in[offset++] & 0xFF) << 32) | ((long)(in[offset++] & 0xFF) << 40) + | ((long)(in[offset++] & 0xFF) << 48) | ((long)(in[offset++] & 0xFF) << 56); + x5 = ((long) in[offset++] & 0xFF) | ((long)(in[offset++] & 0xFF) << 8) + | ((long)(in[offset++] & 0xFF) << 16) | ((long)(in[offset++] & 0xFF) << 24) + | ((long)(in[offset++] & 0xFF) << 32) | ((long)(in[offset++] & 0xFF) << 40) + | ((long)(in[offset++] & 0xFF) << 48) | ((long)(in[offset++] & 0xFF) << 56); + x6 = ((long) in[offset++] & 0xFF) | ((long)(in[offset++] & 0xFF) << 8) + | ((long)(in[offset++] & 0xFF) << 16) | ((long)(in[offset++] & 0xFF) << 24) + | ((long)(in[offset++] & 0xFF) << 32) | ((long)(in[offset++] & 0xFF) << 40) + | ((long)(in[offset++] & 0xFF) << 48) | ((long)(in[offset++] & 0xFF) << 56); + x7 = ((long) in[offset++] & 0xFF) | ((long)(in[offset++] & 0xFF) << 8) + | ((long)(in[offset++] & 0xFF) << 16) | ((long)(in[offset++] & 0xFF) << 24) + | ((long)(in[offset++] & 0xFF) << 32) | ((long)(in[offset++] & 0xFF) << 40) + | ((long)(in[offset++] & 0xFF) << 48) | ((long)(in[offset ] & 0xFF) << 56); + + // save_abc ::= + long aa = a, bb = b, cc = c; + + // pass(aa, bb, cc, 5) ::= + cc ^= x0; + aa -= T1[(int) cc & 0xff] ^ T2[(int)(cc >> 16) & 0xff] + ^ T3[(int)(cc >> 32) & 0xff] ^ T4[(int)(cc >> 48) & 0xff]; + bb += T4[(int)(cc >> 8) & 0xff] ^ T3[(int)(cc >> 24) & 0xff] + ^ T2[(int)(cc >> 40) & 0xff] ^ T1[(int)(cc >> 56) & 0xff]; + bb *= 5; + aa ^= x1; + bb -= T1[(int) aa & 0xff] ^ T2[(int)(aa >> 16) & 0xff] + ^ T3[(int)(aa >> 32) & 0xff] ^ T4[(int)(aa >> 48) & 0xff]; + cc += T4[(int)(aa >> 8) & 0xff] ^ T3[(int)(aa >> 24) & 0xff] + ^ T2[(int)(aa >> 40) & 0xff] ^ T1[(int)(aa >> 56) & 0xff]; + cc *= 5; + bb ^= x2; + cc -= T1[(int) bb & 0xff] ^ T2[(int)(bb >> 16) & 0xff] + ^ T3[(int)(bb >> 32) & 0xff] ^ T4[(int)(bb >> 48) & 0xff]; + aa += T4[(int)(bb >> 8) & 0xff] ^ T3[(int)(bb >> 24) & 0xff] + ^ T2[(int)(bb >> 40) & 0xff] ^ T1[(int)(bb >> 56) & 0xff]; + aa *= 5; + cc ^= x3; + aa -= T1[(int) cc & 0xff] ^ T2[(int)(cc >> 16) & 0xff] + ^ T3[(int)(cc >> 32) & 0xff] ^ T4[(int)(cc >> 48) & 0xff]; + bb += T4[(int)(cc >> 8) & 0xff] ^ T3[(int)(cc >> 24) & 0xff] + ^ T2[(int)(cc >> 40) & 0xff] ^ T1[(int)(cc >> 56) & 0xff]; + bb *= 5; + aa ^= x4; + bb -= T1[(int) aa & 0xff] ^ T2[(int)(aa >> 16) & 0xff] + ^ T3[(int)(aa >> 32) & 0xff] ^ T4[(int)(aa >> 48) & 0xff]; + cc += T4[(int)(aa >> 8) & 0xff] ^ T3[(int)(aa >> 24) & 0xff] + ^ T2[(int)(aa >> 40) & 0xff] ^ T1[(int)(aa >> 56) & 0xff]; + cc *= 5; + bb ^= x5; + cc -= T1[(int) bb & 0xff] ^ T2[(int)(bb >> 16) & 0xff] + ^ T3[(int)(bb >> 32) & 0xff] ^ T4[(int)(bb >> 48) & 0xff]; + aa += T4[(int)(bb >> 8) & 0xff] ^ T3[(int)(bb >> 24) & 0xff] + ^ T2[(int)(bb >> 40) & 0xff] ^ T1[(int)(bb >> 56) & 0xff]; + aa *= 5; + cc ^= x6; + aa -= T1[(int) cc & 0xff] ^ T2[(int)(cc >> 16) & 0xff] + ^ T3[(int)(cc >> 32) & 0xff] ^ T4[(int)(cc >> 48) & 0xff]; + bb += T4[(int)(cc >> 8) & 0xff] ^ T3[(int)(cc >> 24) & 0xff] + ^ T2[(int)(cc >> 40) & 0xff] ^ T1[(int)(cc >> 56) & 0xff]; + bb *= 5; + aa ^= x7; + bb -= T1[(int) aa & 0xff] ^ T2[(int)(aa >> 16) & 0xff] + ^ T3[(int)(aa >> 32) & 0xff] ^ T4[(int)(aa >> 48) & 0xff]; + cc += T4[(int)(aa >> 8) & 0xff] ^ T3[(int)(aa >> 24) & 0xff] + ^ T2[(int)(aa >> 40) & 0xff] ^ T1[(int)(aa >> 56) & 0xff]; + cc *= 5; + + // key_schedule ::= + x0 -= x7 ^ 0xA5A5A5A5A5A5A5A5L; + x1 ^= x0; + x2 += x1; + x3 -= x2 ^ ((~x1) << 19); + x4 ^= x3; + x5 += x4; + x6 -= x5 ^ ((~x4) >>> 23); + x7 ^= x6; + x0 += x7; + x1 -= x0 ^ ((~x7) << 19); + x2 ^= x1; + x3 += x2; + x4 -= x3 ^ ((~x2) >>> 23); + x5 ^= x4; + x6 += x5; + x7 -= x6 ^ 0x0123456789ABCDEFL; + + // pass(cc, aa, bb, 7) ::= + bb ^= x0; + cc -= T1[(int) bb & 0xff] ^ T2[(int)(bb >> 16) & 0xff] + ^ T3[(int)(bb >> 32) & 0xff] ^ T4[(int)(bb >> 48) & 0xff]; + aa += T4[(int)(bb >> 8) & 0xff] ^ T3[(int)(bb >> 24) & 0xff] + ^ T2[(int)(bb >> 40) & 0xff] ^ T1[(int)(bb >> 56) & 0xff]; + aa *= 7; + cc ^= x1; + aa -= T1[(int) cc & 0xff] ^ T2[(int)(cc >> 16) & 0xff] + ^ T3[(int)(cc >> 32) & 0xff] ^ T4[(int)(cc >> 48) & 0xff]; + bb += T4[(int)(cc >> 8) & 0xff] ^ T3[(int)(cc >> 24) & 0xff] + ^ T2[(int)(cc >> 40) & 0xff] ^ T1[(int)(cc >> 56) & 0xff]; + bb *= 7; + aa ^= x2; + bb -= T1[(int) aa & 0xff] ^ T2[(int)(aa >> 16) & 0xff] + ^ T3[(int)(aa >> 32) & 0xff] ^ T4[(int)(aa >> 48) & 0xff]; + cc += T4[(int)(aa >> 8) & 0xff] ^ T3[(int)(aa >> 24) & 0xff] + ^ T2[(int)(aa >> 40) & 0xff] ^ T1[(int)(aa >> 56) & 0xff]; + cc *= 7; + bb ^= x3; + cc -= T1[(int) bb & 0xff] ^ T2[(int)(bb >> 16) & 0xff] + ^ T3[(int)(bb >> 32) & 0xff] ^ T4[(int)(bb >> 48) & 0xff]; + aa += T4[(int)(bb >> 8) & 0xff] ^ T3[(int)(bb >> 24) & 0xff] + ^ T2[(int)(bb >> 40) & 0xff] ^ T1[(int)(bb >> 56) & 0xff]; + aa *= 7; + cc ^= x4; + aa -= T1[(int) cc & 0xff] ^ T2[(int)(cc >> 16) & 0xff] + ^ T3[(int)(cc >> 32) & 0xff] ^ T4[(int)(cc >> 48) & 0xff]; + bb += T4[(int)(cc >> 8) & 0xff] ^ T3[(int)(cc >> 24) & 0xff] + ^ T2[(int)(cc >> 40) & 0xff] ^ T1[(int)(cc >> 56) & 0xff]; + bb *= 7; + aa ^= x5; + bb -= T1[(int) aa & 0xff] ^ T2[(int)(aa >> 16) & 0xff] + ^ T3[(int)(aa >> 32) & 0xff] ^ T4[(int)(aa >> 48) & 0xff]; + cc += T4[(int)(aa >> 8) & 0xff] ^ T3[(int)(aa >> 24) & 0xff] + ^ T2[(int)(aa >> 40) & 0xff] ^ T1[(int)(aa >> 56) & 0xff]; + cc *= 7; + bb ^= x6; + cc -= T1[(int) bb & 0xff] ^ T2[(int)(bb >> 16) & 0xff] + ^ T3[(int)(bb >> 32) & 0xff] ^ T4[(int)(bb >> 48) & 0xff]; + aa += T4[(int)(bb >> 8) & 0xff] ^ T3[(int)(bb >> 24) & 0xff] + ^ T2[(int)(bb >> 40) & 0xff] ^ T1[(int)(bb >> 56) & 0xff]; + aa *= 7; + cc ^= x7; + aa -= T1[(int) cc & 0xff] ^ T2[(int)(cc >> 16) & 0xff] + ^ T3[(int)(cc >> 32) & 0xff] ^ T4[(int)(cc >> 48) & 0xff]; + bb += T4[(int)(cc >> 8) & 0xff] ^ T3[(int)(cc >> 24) & 0xff] + ^ T2[(int)(cc >> 40) & 0xff] ^ T1[(int)(cc >> 56) & 0xff]; + bb *= 7; + + // key_schedule ::= + x0 -= x7 ^ 0xA5A5A5A5A5A5A5A5L; + x1 ^= x0; + x2 += x1; + x3 -= x2 ^ ((~x1) << 19); + x4 ^= x3; + x5 += x4; + x6 -= x5 ^ ((~x4) >>> 23); + x7 ^= x6; + x0 += x7; + x1 -= x0 ^ ((~x7) << 19); + x2 ^= x1; + x3 += x2; + x4 -= x3 ^ ((~x2) >>> 23); + x5 ^= x4; + x6 += x5; + x7 -= x6 ^ 0x0123456789ABCDEFL; + + // pass(bb,cc,aa,9) ::= + aa ^= x0; + bb -= T1[(int) aa & 0xff] ^ T2[(int)(aa >> 16) & 0xff] + ^ T3[(int)(aa >> 32) & 0xff] ^ T4[(int)(aa >> 48) & 0xff]; + cc += T4[(int)(aa >> 8) & 0xff] ^ T3[(int)(aa >> 24) & 0xff] + ^ T2[(int)(aa >> 40) & 0xff] ^ T1[(int)(aa >> 56) & 0xff]; + cc *= 9; + bb ^= x1; + cc -= T1[(int) bb & 0xff] ^ T2[(int)(bb >> 16) & 0xff] + ^ T3[(int)(bb >> 32) & 0xff] ^ T4[(int)(bb >> 48) & 0xff]; + aa += T4[(int)(bb >> 8) & 0xff] ^ T3[(int)(bb >> 24) & 0xff] + ^ T2[(int)(bb >> 40) & 0xff] ^ T1[(int)(bb >> 56) & 0xff]; + aa *= 9; + cc ^= x2; + aa -= T1[(int) cc & 0xff] ^ T2[(int)(cc >> 16) & 0xff] + ^ T3[(int)(cc >> 32) & 0xff] ^ T4[(int)(cc >> 48) & 0xff]; + bb += T4[(int)(cc >> 8) & 0xff] ^ T3[(int)(cc >> 24) & 0xff] + ^ T2[(int)(cc >> 40) & 0xff] ^ T1[(int)(cc >> 56) & 0xff]; + bb *= 9; + aa ^= x3; + bb -= T1[(int) aa & 0xff] ^ T2[(int)(aa >> 16) & 0xff] + ^ T3[(int)(aa >> 32) & 0xff] ^ T4[(int)(aa >> 48) & 0xff]; + cc += T4[(int)(aa >> 8) & 0xff] ^ T3[(int)(aa >> 24) & 0xff] + ^ T2[(int)(aa >> 40) & 0xff] ^ T1[(int)(aa >> 56) & 0xff]; + cc *= 9; + bb ^= x4; + cc -= T1[(int) bb & 0xff] ^ T2[(int)(bb >> 16) & 0xff] + ^ T3[(int)(bb >> 32) & 0xff] ^ T4[(int)(bb >> 48) & 0xff]; + aa += T4[(int)(bb >> 8) & 0xff] ^ T3[(int)(bb >> 24) & 0xff] + ^ T2[(int)(bb >> 40) & 0xff] ^ T1[(int)(bb >> 56) & 0xff]; + aa *= 9; + cc ^= x5; + aa -= T1[(int) cc & 0xff] ^ T2[(int)(cc >> 16) & 0xff] + ^ T3[(int)(cc >> 32) & 0xff] ^ T4[(int)(cc >> 48) & 0xff]; + bb += T4[(int)(cc >> 8) & 0xff] ^ T3[(int)(cc >> 24) & 0xff] + ^ T2[(int)(cc >> 40) & 0xff] ^ T1[(int)(cc >> 56) & 0xff]; + bb *= 9; + aa ^= x6; + bb -= T1[(int) aa & 0xff] ^ T2[(int)(aa >> 16) & 0xff] + ^ T3[(int)(aa >> 32) & 0xff] ^ T4[(int)(aa >> 48) & 0xff]; + cc += T4[(int)(aa >> 8) & 0xff] ^ T3[(int)(aa >> 24) & 0xff] + ^ T2[(int)(aa >> 40) & 0xff] ^ T1[(int)(aa >> 56) & 0xff]; + cc *= 9; + bb ^= x7; + cc -= T1[(int) bb & 0xff] ^ T2[(int)(bb >> 16) & 0xff] + ^ T3[(int)(bb >> 32) & 0xff] ^ T4[(int)(bb >> 48) & 0xff]; + aa += T4[(int)(bb >> 8) & 0xff] ^ T3[(int)(bb >> 24) & 0xff] + ^ T2[(int)(bb >> 40) & 0xff] ^ T1[(int)(bb >> 56) & 0xff]; + aa *= 9; + + // feedforward ::= + a ^= aa; + b = bb - b; + c += cc; + } + protected static final int HASH_SIZE = 24; + + protected static final int BLOCK_SIZE = 64; + + /** Result when no data has been input. */ + + private static final long A = 0x0123456789ABCDEFL; + private static final long B = 0xFEDCBA9876543210L; + private static final long C = 0xF096A5B4C3B2E187L; + + /** S-Box T1. */ + private static final long[] T1 = { + 0x02AAB17CF7E90C5EL, 0xAC424B03E243A8ECL, 0x72CD5BE30DD5FCD3L, 0x6D019B93F6F97F3AL, + 0xCD9978FFD21F9193L, 0x7573A1C9708029E2L, 0xB164326B922A83C3L, 0x46883EEE04915870L, + 0xEAACE3057103ECE6L, 0xC54169B808A3535CL, 0x4CE754918DDEC47CL, 0x0AA2F4DFDC0DF40CL, + 0x10B76F18A74DBEFAL, 0xC6CCB6235AD1AB6AL, 0x13726121572FE2FFL, 0x1A488C6F199D921EL, + 0x4BC9F9F4DA0007CAL, 0x26F5E6F6E85241C7L, 0x859079DBEA5947B6L, 0x4F1885C5C99E8C92L, + 0xD78E761EA96F864BL, 0x8E36428C52B5C17DL, 0x69CF6827373063C1L, 0xB607C93D9BB4C56EL, + 0x7D820E760E76B5EAL, 0x645C9CC6F07FDC42L, 0xBF38A078243342E0L, 0x5F6B343C9D2E7D04L, + 0xF2C28AEB600B0EC6L, 0x6C0ED85F7254BCACL, 0x71592281A4DB4FE5L, 0x1967FA69CE0FED9FL, + 0xFD5293F8B96545DBL, 0xC879E9D7F2A7600BL, 0x860248920193194EL, 0xA4F9533B2D9CC0B3L, + 0x9053836C15957613L, 0xDB6DCF8AFC357BF1L, 0x18BEEA7A7A370F57L, 0x037117CA50B99066L, + 0x6AB30A9774424A35L, 0xF4E92F02E325249BL, 0x7739DB07061CCAE1L, 0xD8F3B49CECA42A05L, + 0xBD56BE3F51382F73L, 0x45FAED5843B0BB28L, 0x1C813D5C11BF1F83L, 0x8AF0E4B6D75FA169L, + 0x33EE18A487AD9999L, 0x3C26E8EAB1C94410L, 0xB510102BC0A822F9L, 0x141EEF310CE6123BL, + 0xFC65B90059DDB154L, 0xE0158640C5E0E607L, 0x884E079826C3A3CFL, 0x930D0D9523C535FDL, + 0x35638D754E9A2B00L, 0x4085FCCF40469DD5L, 0xC4B17AD28BE23A4CL, 0xCAB2F0FC6A3E6A2EL, + 0x2860971A6B943FCDL, 0x3DDE6EE212E30446L, 0x6222F32AE01765AEL, 0x5D550BB5478308FEL, + 0xA9EFA98DA0EDA22AL, 0xC351A71686C40DA7L, 0x1105586D9C867C84L, 0xDCFFEE85FDA22853L, + 0xCCFBD0262C5EEF76L, 0xBAF294CB8990D201L, 0xE69464F52AFAD975L, 0x94B013AFDF133E14L, + 0x06A7D1A32823C958L, 0x6F95FE5130F61119L, 0xD92AB34E462C06C0L, 0xED7BDE33887C71D2L, + 0x79746D6E6518393EL, 0x5BA419385D713329L, 0x7C1BA6B948A97564L, 0x31987C197BFDAC67L, + 0xDE6C23C44B053D02L, 0x581C49FED002D64DL, 0xDD474D6338261571L, 0xAA4546C3E473D062L, + 0x928FCE349455F860L, 0x48161BBACAAB94D9L, 0x63912430770E6F68L, 0x6EC8A5E602C6641CL, + 0x87282515337DDD2BL, 0x2CDA6B42034B701BL, 0xB03D37C181CB096DL, 0xE108438266C71C6FL, + 0x2B3180C7EB51B255L, 0xDF92B82F96C08BBCL, 0x5C68C8C0A632F3BAL, 0x5504CC861C3D0556L, + 0xABBFA4E55FB26B8FL, 0x41848B0AB3BACEB4L, 0xB334A273AA445D32L, 0xBCA696F0A85AD881L, + 0x24F6EC65B528D56CL, 0x0CE1512E90F4524AL, 0x4E9DD79D5506D35AL, 0x258905FAC6CE9779L, + 0x2019295B3E109B33L, 0xF8A9478B73A054CCL, 0x2924F2F934417EB0L, 0x3993357D536D1BC4L, + 0x38A81AC21DB6FF8BL, 0x47C4FBF17D6016BFL, 0x1E0FAADD7667E3F5L, 0x7ABCFF62938BEB96L, + 0xA78DAD948FC179C9L, 0x8F1F98B72911E50DL, 0x61E48EAE27121A91L, 0x4D62F7AD31859808L, + 0xECEBA345EF5CEAEBL, 0xF5CEB25EBC9684CEL, 0xF633E20CB7F76221L, 0xA32CDF06AB8293E4L, + 0x985A202CA5EE2CA4L, 0xCF0B8447CC8A8FB1L, 0x9F765244979859A3L, 0xA8D516B1A1240017L, + 0x0BD7BA3EBB5DC726L, 0xE54BCA55B86ADB39L, 0x1D7A3AFD6C478063L, 0x519EC608E7669EDDL, + 0x0E5715A2D149AA23L, 0x177D4571848FF194L, 0xEEB55F3241014C22L, 0x0F5E5CA13A6E2EC2L, + 0x8029927B75F5C361L, 0xAD139FABC3D6E436L, 0x0D5DF1A94CCF402FL, 0x3E8BD948BEA5DFC8L, + 0xA5A0D357BD3FF77EL, 0xA2D12E251F74F645L, 0x66FD9E525E81A082L, 0x2E0C90CE7F687A49L, + 0xC2E8BCBEBA973BC5L, 0x000001BCE509745FL, 0x423777BBE6DAB3D6L, 0xD1661C7EAEF06EB5L, + 0xA1781F354DAACFD8L, 0x2D11284A2B16AFFCL, 0xF1FC4F67FA891D1FL, 0x73ECC25DCB920ADAL, + 0xAE610C22C2A12651L, 0x96E0A810D356B78AL, 0x5A9A381F2FE7870FL, 0xD5AD62EDE94E5530L, + 0xD225E5E8368D1427L, 0x65977B70C7AF4631L, 0x99F889B2DE39D74FL, 0x233F30BF54E1D143L, + 0x9A9675D3D9A63C97L, 0x5470554FF334F9A8L, 0x166ACB744A4F5688L, 0x70C74CAAB2E4AEADL, + 0xF0D091646F294D12L, 0x57B82A89684031D1L, 0xEFD95A5A61BE0B6BL, 0x2FBD12E969F2F29AL, + 0x9BD37013FEFF9FE8L, 0x3F9B0404D6085A06L, 0x4940C1F3166CFE15L, 0x09542C4DCDF3DEFBL, + 0xB4C5218385CD5CE3L, 0xC935B7DC4462A641L, 0x3417F8A68ED3B63FL, 0xB80959295B215B40L, + 0xF99CDAEF3B8C8572L, 0x018C0614F8FCB95DL, 0x1B14ACCD1A3ACDF3L, 0x84D471F200BB732DL, + 0xC1A3110E95E8DA16L, 0x430A7220BF1A82B8L, 0xB77E090D39DF210EL, 0x5EF4BD9F3CD05E9DL, + 0x9D4FF6DA7E57A444L, 0xDA1D60E183D4A5F8L, 0xB287C38417998E47L, 0xFE3EDC121BB31886L, + 0xC7FE3CCC980CCBEFL, 0xE46FB590189BFD03L, 0x3732FD469A4C57DCL, 0x7EF700A07CF1AD65L, + 0x59C64468A31D8859L, 0x762FB0B4D45B61F6L, 0x155BAED099047718L, 0x68755E4C3D50BAA6L, + 0xE9214E7F22D8B4DFL, 0x2ADDBF532EAC95F4L, 0x32AE3909B4BD0109L, 0x834DF537B08E3450L, + 0xFA209DA84220728DL, 0x9E691D9B9EFE23F7L, 0x0446D288C4AE8D7FL, 0x7B4CC524E169785BL, + 0x21D87F0135CA1385L, 0xCEBB400F137B8AA5L, 0x272E2B66580796BEL, 0x3612264125C2B0DEL, + 0x057702BDAD1EFBB2L, 0xD4BABB8EACF84BE9L, 0x91583139641BC67BL, 0x8BDC2DE08036E024L, + 0x603C8156F49F68EDL, 0xF7D236F7DBEF5111L, 0x9727C4598AD21E80L, 0xA08A0896670A5FD7L, + 0xCB4A8F4309EBA9CBL, 0x81AF564B0F7036A1L, 0xC0B99AA778199ABDL, 0x959F1EC83FC8E952L, + 0x8C505077794A81B9L, 0x3ACAAF8F056338F0L, 0x07B43F50627A6778L, 0x4A44AB49F5ECCC77L, + 0x3BC3D6E4B679EE98L, 0x9CC0D4D1CF14108CL, 0x4406C00B206BC8A0L, 0x82A18854C8D72D89L, + 0x67E366B35C3C432CL, 0xB923DD61102B37F2L, 0x56AB2779D884271DL, 0xBE83E1B0FF1525AFL, + 0xFB7C65D4217E49A9L, 0x6BDBE0E76D48E7D4L, 0x08DF828745D9179EL, 0x22EA6A9ADD53BD34L, + 0xE36E141C5622200AL, 0x7F805D1B8CB750EEL, 0xAFE5C7A59F58E837L, 0xE27F996A4FB1C23CL, + 0xD3867DFB0775F0D0L, 0xD0E673DE6E88891AL, 0x123AEB9EAFB86C25L, 0x30F1D5D5C145B895L, + 0xBB434A2DEE7269E7L, 0x78CB67ECF931FA38L, 0xF33B0372323BBF9CL, 0x52D66336FB279C74L, + 0x505F33AC0AFB4EAAL, 0xE8A5CD99A2CCE187L, 0x534974801E2D30BBL, 0x8D2D5711D5876D90L, + 0x1F1A412891BC038EL, 0xD6E2E71D82E56648L, 0x74036C3A497732B7L, 0x89B67ED96361F5ABL, + 0xFFED95D8F1EA02A2L, 0xE72B3BD61464D43DL, 0xA6300F170BDC4820L, 0xEBC18760ED78A77AL + }; + + /** S-Box T2. */ + private static final long[] T2 = { + 0xE6A6BE5A05A12138L, 0xB5A122A5B4F87C98L, 0x563C6089140B6990L, 0x4C46CB2E391F5DD5L, + 0xD932ADDBC9B79434L, 0x08EA70E42015AFF5L, 0xD765A6673E478CF1L, 0xC4FB757EAB278D99L, + 0xDF11C6862D6E0692L, 0xDDEB84F10D7F3B16L, 0x6F2EF604A665EA04L, 0x4A8E0F0FF0E0DFB3L, + 0xA5EDEEF83DBCBA51L, 0xFC4F0A2A0EA4371EL, 0xE83E1DA85CB38429L, 0xDC8FF882BA1B1CE2L, + 0xCD45505E8353E80DL, 0x18D19A00D4DB0717L, 0x34A0CFEDA5F38101L, 0x0BE77E518887CAF2L, + 0x1E341438B3C45136L, 0xE05797F49089CCF9L, 0xFFD23F9DF2591D14L, 0x543DDA228595C5CDL, + 0x661F81FD99052A33L, 0x8736E641DB0F7B76L, 0x15227725418E5307L, 0xE25F7F46162EB2FAL, + 0x48A8B2126C13D9FEL, 0xAFDC541792E76EEAL, 0x03D912BFC6D1898FL, 0x31B1AAFA1B83F51BL, + 0xF1AC2796E42AB7D9L, 0x40A3A7D7FCD2EBACL, 0x1056136D0AFBBCC5L, 0x7889E1DD9A6D0C85L, + 0xD33525782A7974AAL, 0xA7E25D09078AC09BL, 0xBD4138B3EAC6EDD0L, 0x920ABFBE71EB9E70L, + 0xA2A5D0F54FC2625CL, 0xC054E36B0B1290A3L, 0xF6DD59FF62FE932BL, 0x3537354511A8AC7DL, + 0xCA845E9172FADCD4L, 0x84F82B60329D20DCL, 0x79C62CE1CD672F18L, 0x8B09A2ADD124642CL, + 0xD0C1E96A19D9E726L, 0x5A786A9B4BA9500CL, 0x0E020336634C43F3L, 0xC17B474AEB66D822L, + 0x6A731AE3EC9BAAC2L, 0x8226667AE0840258L, 0x67D4567691CAECA5L, 0x1D94155C4875ADB5L, + 0x6D00FD985B813FDFL, 0x51286EFCB774CD06L, 0x5E8834471FA744AFL, 0xF72CA0AEE761AE2EL, + 0xBE40E4CDAEE8E09AL, 0xE9970BBB5118F665L, 0x726E4BEB33DF1964L, 0x703B000729199762L, + 0x4631D816F5EF30A7L, 0xB880B5B51504A6BEL, 0x641793C37ED84B6CL, 0x7B21ED77F6E97D96L, + 0x776306312EF96B73L, 0xAE528948E86FF3F4L, 0x53DBD7F286A3F8F8L, 0x16CADCE74CFC1063L, + 0x005C19BDFA52C6DDL, 0x68868F5D64D46AD3L, 0x3A9D512CCF1E186AL, 0x367E62C2385660AEL, + 0xE359E7EA77DCB1D7L, 0x526C0773749ABE6EL, 0x735AE5F9D09F734BL, 0x493FC7CC8A558BA8L, + 0xB0B9C1533041AB45L, 0x321958BA470A59BDL, 0x852DB00B5F46C393L, 0x91209B2BD336B0E5L, + 0x6E604F7D659EF19FL, 0xB99A8AE2782CCB24L, 0xCCF52AB6C814C4C7L, 0x4727D9AFBE11727BL, + 0x7E950D0C0121B34DL, 0x756F435670AD471FL, 0xF5ADD442615A6849L, 0x4E87E09980B9957AL, + 0x2ACFA1DF50AEE355L, 0xD898263AFD2FD556L, 0xC8F4924DD80C8FD6L, 0xCF99CA3D754A173AL, + 0xFE477BACAF91BF3CL, 0xED5371F6D690C12DL, 0x831A5C285E687094L, 0xC5D3C90A3708A0A4L, + 0x0F7F903717D06580L, 0x19F9BB13B8FDF27FL, 0xB1BD6F1B4D502843L, 0x1C761BA38FFF4012L, + 0x0D1530C4E2E21F3BL, 0x8943CE69A7372C8AL, 0xE5184E11FEB5CE66L, 0x618BDB80BD736621L, + 0x7D29BAD68B574D0BL, 0x81BB613E25E6FE5BL, 0x071C9C10BC07913FL, 0xC7BEEB7909AC2D97L, + 0xC3E58D353BC5D757L, 0xEB017892F38F61E8L, 0xD4EFFB9C9B1CC21AL, 0x99727D26F494F7ABL, + 0xA3E063A2956B3E03L, 0x9D4A8B9A4AA09C30L, 0x3F6AB7D500090FB4L, 0x9CC0F2A057268AC0L, + 0x3DEE9D2DEDBF42D1L, 0x330F49C87960A972L, 0xC6B2720287421B41L, 0x0AC59EC07C00369CL, + 0xEF4EAC49CB353425L, 0xF450244EEF0129D8L, 0x8ACC46E5CAF4DEB6L, 0x2FFEAB63989263F7L, + 0x8F7CB9FE5D7A4578L, 0x5BD8F7644E634635L, 0x427A7315BF2DC900L, 0x17D0C4AA2125261CL, + 0x3992486C93518E50L, 0xB4CBFEE0A2D7D4C3L, 0x7C75D6202C5DDD8DL, 0xDBC295D8E35B6C61L, + 0x60B369D302032B19L, 0xCE42685FDCE44132L, 0x06F3DDB9DDF65610L, 0x8EA4D21DB5E148F0L, + 0x20B0FCE62FCD496FL, 0x2C1B912358B0EE31L, 0xB28317B818F5A308L, 0xA89C1E189CA6D2CFL, + 0x0C6B18576AAADBC8L, 0xB65DEAA91299FAE3L, 0xFB2B794B7F1027E7L, 0x04E4317F443B5BEBL, + 0x4B852D325939D0A6L, 0xD5AE6BEEFB207FFCL, 0x309682B281C7D374L, 0xBAE309A194C3B475L, + 0x8CC3F97B13B49F05L, 0x98A9422FF8293967L, 0x244B16B01076FF7CL, 0xF8BF571C663D67EEL, + 0x1F0D6758EEE30DA1L, 0xC9B611D97ADEB9B7L, 0xB7AFD5887B6C57A2L, 0x6290AE846B984FE1L, + 0x94DF4CDEACC1A5FDL, 0x058A5BD1C5483AFFL, 0x63166CC142BA3C37L, 0x8DB8526EB2F76F40L, + 0xE10880036F0D6D4EL, 0x9E0523C9971D311DL, 0x45EC2824CC7CD691L, 0x575B8359E62382C9L, + 0xFA9E400DC4889995L, 0xD1823ECB45721568L, 0xDAFD983B8206082FL, 0xAA7D29082386A8CBL, + 0x269FCD4403B87588L, 0x1B91F5F728BDD1E0L, 0xE4669F39040201F6L, 0x7A1D7C218CF04ADEL, + 0x65623C29D79CE5CEL, 0x2368449096C00BB1L, 0xAB9BF1879DA503BAL, 0xBC23ECB1A458058EL, + 0x9A58DF01BB401ECCL, 0xA070E868A85F143DL, 0x4FF188307DF2239EL, 0x14D565B41A641183L, + 0xEE13337452701602L, 0x950E3DCF3F285E09L, 0x59930254B9C80953L, 0x3BF299408930DA6DL, + 0xA955943F53691387L, 0xA15EDECAA9CB8784L, 0x29142127352BE9A0L, 0x76F0371FFF4E7AFBL, + 0x0239F450274F2228L, 0xBB073AF01D5E868BL, 0xBFC80571C10E96C1L, 0xD267088568222E23L, + 0x9671A3D48E80B5B0L, 0x55B5D38AE193BB81L, 0x693AE2D0A18B04B8L, 0x5C48B4ECADD5335FL, + 0xFD743B194916A1CAL, 0x2577018134BE98C4L, 0xE77987E83C54A4ADL, 0x28E11014DA33E1B9L, + 0x270CC59E226AA213L, 0x71495F756D1A5F60L, 0x9BE853FB60AFEF77L, 0xADC786A7F7443DBFL, + 0x0904456173B29A82L, 0x58BC7A66C232BD5EL, 0xF306558C673AC8B2L, 0x41F639C6B6C9772AL, + 0x216DEFE99FDA35DAL, 0x11640CC71C7BE615L, 0x93C43694565C5527L, 0xEA038E6246777839L, + 0xF9ABF3CE5A3E2469L, 0x741E768D0FD312D2L, 0x0144B883CED652C6L, 0xC20B5A5BA33F8552L, + 0x1AE69633C3435A9DL, 0x97A28CA4088CFDECL, 0x8824A43C1E96F420L, 0x37612FA66EEEA746L, + 0x6B4CB165F9CF0E5AL, 0x43AA1C06A0ABFB4AL, 0x7F4DC26FF162796BL, 0x6CBACC8E54ED9B0FL, + 0xA6B7FFEFD2BB253EL, 0x2E25BC95B0A29D4FL, 0x86D6A58BDEF1388CL, 0xDED74AC576B6F054L, + 0x8030BDBC2B45805DL, 0x3C81AF70E94D9289L, 0x3EFF6DDA9E3100DBL, 0xB38DC39FDFCC8847L, + 0x123885528D17B87EL, 0xF2DA0ED240B1B642L, 0x44CEFADCD54BF9A9L, 0x1312200E433C7EE6L, + 0x9FFCC84F3A78C748L, 0xF0CD1F72248576BBL, 0xEC6974053638CFE4L, 0x2BA7B67C0CEC4E4CL, + 0xAC2F4DF3E5CE32EDL, 0xCB33D14326EA4C11L, 0xA4E9044CC77E58BCL, 0x5F513293D934FCEFL, + 0x5DC9645506E55444L, 0x50DE418F317DE40AL, 0x388CB31A69DDE259L, 0x2DB4A83455820A86L, + 0x9010A91E84711AE9L, 0x4DF7F0B7B1498371L, 0xD62A2EABC0977179L, 0x22FAC097AA8D5C0EL + }; + + /** S-Box T3. */ + private static final long[] T3 = { + 0xF49FCC2FF1DAF39BL, 0x487FD5C66FF29281L, 0xE8A30667FCDCA83FL, 0x2C9B4BE3D2FCCE63L, + 0xDA3FF74B93FBBBC2L, 0x2FA165D2FE70BA66L, 0xA103E279970E93D4L, 0xBECDEC77B0E45E71L, + 0xCFB41E723985E497L, 0xB70AAA025EF75017L, 0xD42309F03840B8E0L, 0x8EFC1AD035898579L, + 0x96C6920BE2B2ABC5L, 0x66AF4163375A9172L, 0x2174ABDCCA7127FBL, 0xB33CCEA64A72FF41L, + 0xF04A4933083066A5L, 0x8D970ACDD7289AF5L, 0x8F96E8E031C8C25EL, 0xF3FEC02276875D47L, + 0xEC7BF310056190DDL, 0xF5ADB0AEBB0F1491L, 0x9B50F8850FD58892L, 0x4975488358B74DE8L, + 0xA3354FF691531C61L, 0x0702BBE481D2C6EEL, 0x89FB24057DEDED98L, 0xAC3075138596E902L, + 0x1D2D3580172772EDL, 0xEB738FC28E6BC30DL, 0x5854EF8F63044326L, 0x9E5C52325ADD3BBEL, + 0x90AA53CF325C4623L, 0xC1D24D51349DD067L, 0x2051CFEEA69EA624L, 0x13220F0A862E7E4FL, + 0xCE39399404E04864L, 0xD9C42CA47086FCB7L, 0x685AD2238A03E7CCL, 0x066484B2AB2FF1DBL, + 0xFE9D5D70EFBF79ECL, 0x5B13B9DD9C481854L, 0x15F0D475ED1509ADL, 0x0BEBCD060EC79851L, + 0xD58C6791183AB7F8L, 0xD1187C5052F3EEE4L, 0xC95D1192E54E82FFL, 0x86EEA14CB9AC6CA2L, + 0x3485BEB153677D5DL, 0xDD191D781F8C492AL, 0xF60866BAA784EBF9L, 0x518F643BA2D08C74L, + 0x8852E956E1087C22L, 0xA768CB8DC410AE8DL, 0x38047726BFEC8E1AL, 0xA67738B4CD3B45AAL, + 0xAD16691CEC0DDE19L, 0xC6D4319380462E07L, 0xC5A5876D0BA61938L, 0x16B9FA1FA58FD840L, + 0x188AB1173CA74F18L, 0xABDA2F98C99C021FL, 0x3E0580AB134AE816L, 0x5F3B05B773645ABBL, + 0x2501A2BE5575F2F6L, 0x1B2F74004E7E8BA9L, 0x1CD7580371E8D953L, 0x7F6ED89562764E30L, + 0xB15926FF596F003DL, 0x9F65293DA8C5D6B9L, 0x6ECEF04DD690F84CL, 0x4782275FFF33AF88L, + 0xE41433083F820801L, 0xFD0DFE409A1AF9B5L, 0x4325A3342CDB396BL, 0x8AE77E62B301B252L, + 0xC36F9E9F6655615AL, 0x85455A2D92D32C09L, 0xF2C7DEA949477485L, 0x63CFB4C133A39EBAL, + 0x83B040CC6EBC5462L, 0x3B9454C8FDB326B0L, 0x56F56A9E87FFD78CL, 0x2DC2940D99F42BC6L, + 0x98F7DF096B096E2DL, 0x19A6E01E3AD852BFL, 0x42A99CCBDBD4B40BL, 0xA59998AF45E9C559L, + 0x366295E807D93186L, 0x6B48181BFAA1F773L, 0x1FEC57E2157A0A1DL, 0x4667446AF6201AD5L, + 0xE615EBCACFB0F075L, 0xB8F31F4F68290778L, 0x22713ED6CE22D11EL, 0x3057C1A72EC3C93BL, + 0xCB46ACC37C3F1F2FL, 0xDBB893FD02AAF50EL, 0x331FD92E600B9FCFL, 0xA498F96148EA3AD6L, + 0xA8D8426E8B6A83EAL, 0xA089B274B7735CDCL, 0x87F6B3731E524A11L, 0x118808E5CBC96749L, + 0x9906E4C7B19BD394L, 0xAFED7F7E9B24A20CL, 0x6509EADEEB3644A7L, 0x6C1EF1D3E8EF0EDEL, + 0xB9C97D43E9798FB4L, 0xA2F2D784740C28A3L, 0x7B8496476197566FL, 0x7A5BE3E6B65F069DL, + 0xF96330ED78BE6F10L, 0xEEE60DE77A076A15L, 0x2B4BEE4AA08B9BD0L, 0x6A56A63EC7B8894EL, + 0x02121359BA34FEF4L, 0x4CBF99F8283703FCL, 0x398071350CAF30C8L, 0xD0A77A89F017687AL, + 0xF1C1A9EB9E423569L, 0x8C7976282DEE8199L, 0x5D1737A5DD1F7ABDL, 0x4F53433C09A9FA80L, + 0xFA8B0C53DF7CA1D9L, 0x3FD9DCBC886CCB77L, 0xC040917CA91B4720L, 0x7DD00142F9D1DCDFL, + 0x8476FC1D4F387B58L, 0x23F8E7C5F3316503L, 0x032A2244E7E37339L, 0x5C87A5D750F5A74BL, + 0x082B4CC43698992EL, 0xDF917BECB858F63CL, 0x3270B8FC5BF86DDAL, 0x10AE72BB29B5DD76L, + 0x576AC94E7700362BL, 0x1AD112DAC61EFB8FL, 0x691BC30EC5FAA427L, 0xFF246311CC327143L, + 0x3142368E30E53206L, 0x71380E31E02CA396L, 0x958D5C960AAD76F1L, 0xF8D6F430C16DA536L, + 0xC8FFD13F1BE7E1D2L, 0x7578AE66004DDBE1L, 0x05833F01067BE646L, 0xBB34B5AD3BFE586DL, + 0x095F34C9A12B97F0L, 0x247AB64525D60CA8L, 0xDCDBC6F3017477D1L, 0x4A2E14D4DECAD24DL, + 0xBDB5E6D9BE0A1EEBL, 0x2A7E70F7794301ABL, 0xDEF42D8A270540FDL, 0x01078EC0A34C22C1L, + 0xE5DE511AF4C16387L, 0x7EBB3A52BD9A330AL, 0x77697857AA7D6435L, 0x004E831603AE4C32L, + 0xE7A21020AD78E312L, 0x9D41A70C6AB420F2L, 0x28E06C18EA1141E6L, 0xD2B28CBD984F6B28L, + 0x26B75F6C446E9D83L, 0xBA47568C4D418D7FL, 0xD80BADBFE6183D8EL, 0x0E206D7F5F166044L, + 0xE258A43911CBCA3EL, 0x723A1746B21DC0BCL, 0xC7CAA854F5D7CDD3L, 0x7CAC32883D261D9CL, + 0x7690C26423BA942CL, 0x17E55524478042B8L, 0xE0BE477656A2389FL, 0x4D289B5E67AB2DA0L, + 0x44862B9C8FBBFD31L, 0xB47CC8049D141365L, 0x822C1B362B91C793L, 0x4EB14655FB13DFD8L, + 0x1ECBBA0714E2A97BL, 0x6143459D5CDE5F14L, 0x53A8FBF1D5F0AC89L, 0x97EA04D81C5E5B00L, + 0x622181A8D4FDB3F3L, 0xE9BCD341572A1208L, 0x1411258643CCE58AL, 0x9144C5FEA4C6E0A4L, + 0x0D33D06565CF620FL, 0x54A48D489F219CA1L, 0xC43E5EAC6D63C821L, 0xA9728B3A72770DAFL, + 0xD7934E7B20DF87EFL, 0xE35503B61A3E86E5L, 0xCAE321FBC819D504L, 0x129A50B3AC60BFA6L, + 0xCD5E68EA7E9FB6C3L, 0xB01C90199483B1C7L, 0x3DE93CD5C295376CL, 0xAED52EDF2AB9AD13L, + 0x2E60F512C0A07884L, 0xBC3D86A3E36210C9L, 0x35269D9B163951CEL, 0x0C7D6E2AD0CDB5FAL, + 0x59E86297D87F5733L, 0x298EF221898DB0E7L, 0x55000029D1A5AA7EL, 0x8BC08AE1B5061B45L, + 0xC2C31C2B6C92703AL, 0x94CC596BAF25EF42L, 0x0A1D73DB22540456L, 0x04B6A0F9D9C4179AL, + 0xEFFDAFA2AE3D3C60L, 0xF7C8075BB49496C4L, 0x9CC5C7141D1CD4E3L, 0x78BD1638218E5534L, + 0xB2F11568F850246AL, 0xEDFABCFA9502BC29L, 0x796CE5F2DA23051BL, 0xAAE128B0DC93537CL, + 0x3A493DA0EE4B29AEL, 0xB5DF6B2C416895D7L, 0xFCABBD25122D7F37L, 0x70810B58105DC4B1L, + 0xE10FDD37F7882A90L, 0x524DCAB5518A3F5CL, 0x3C9E85878451255BL, 0x4029828119BD34E2L, + 0x74A05B6F5D3CECCBL, 0xB610021542E13ECAL, 0x0FF979D12F59E2ACL, 0x6037DA27E4F9CC50L, + 0x5E92975A0DF1847DL, 0xD66DE190D3E623FEL, 0x5032D6B87B568048L, 0x9A36B7CE8235216EL, + 0x80272A7A24F64B4AL, 0x93EFED8B8C6916F7L, 0x37DDBFF44CCE1555L, 0x4B95DB5D4B99BD25L, + 0x92D3FDA169812FC0L, 0xFB1A4A9A90660BB6L, 0x730C196946A4B9B2L, 0x81E289AA7F49DA68L, + 0x64669A0F83B1A05FL, 0x27B3FF7D9644F48BL, 0xCC6B615C8DB675B3L, 0x674F20B9BCEBBE95L, + 0x6F31238275655982L, 0x5AE488713E45CF05L, 0xBF619F9954C21157L, 0xEABAC46040A8EAE9L, + 0x454C6FE9F2C0C1CDL, 0x419CF6496412691CL, 0xD3DC3BEF265B0F70L, 0x6D0E60F5C3578A9EL + }; + + /** S-Box T4. */ + private static final long[] T4 = { + 0x5B0E608526323C55L, 0x1A46C1A9FA1B59F5L, 0xA9E245A17C4C8FFAL, 0x65CA5159DB2955D7L, + 0x05DB0A76CE35AFC2L, 0x81EAC77EA9113D45L, 0x528EF88AB6AC0A0DL, 0xA09EA253597BE3FFL, + 0x430DDFB3AC48CD56L, 0xC4B3A67AF45CE46FL, 0x4ECECFD8FBE2D05EL, 0x3EF56F10B39935F0L, + 0x0B22D6829CD619C6L, 0x17FD460A74DF2069L, 0x6CF8CC8E8510ED40L, 0xD6C824BF3A6ECAA7L, + 0x61243D581A817049L, 0x048BACB6BBC163A2L, 0xD9A38AC27D44CC32L, 0x7FDDFF5BAAF410ABL, + 0xAD6D495AA804824BL, 0xE1A6A74F2D8C9F94L, 0xD4F7851235DEE8E3L, 0xFD4B7F886540D893L, + 0x247C20042AA4BFDAL, 0x096EA1C517D1327CL, 0xD56966B4361A6685L, 0x277DA5C31221057DL, + 0x94D59893A43ACFF7L, 0x64F0C51CCDC02281L, 0x3D33BCC4FF6189DBL, 0xE005CB184CE66AF1L, + 0xFF5CCD1D1DB99BEAL, 0xB0B854A7FE42980FL, 0x7BD46A6A718D4B9FL, 0xD10FA8CC22A5FD8CL, + 0xD31484952BE4BD31L, 0xC7FA975FCB243847L, 0x4886ED1E5846C407L, 0x28CDDB791EB70B04L, + 0xC2B00BE2F573417FL, 0x5C9590452180F877L, 0x7A6BDDFFF370EB00L, 0xCE509E38D6D9D6A4L, + 0xEBEB0F00647FA702L, 0x1DCC06CF76606F06L, 0xE4D9F28BA286FF0AL, 0xD85A305DC918C262L, + 0x475B1D8732225F54L, 0x2D4FB51668CCB5FEL, 0xA679B9D9D72BBA20L, 0x53841C0D912D43A5L, + 0x3B7EAA48BF12A4E8L, 0x781E0E47F22F1DDFL, 0xEFF20CE60AB50973L, 0x20D261D19DFFB742L, + 0x16A12B03062A2E39L, 0x1960EB2239650495L, 0x251C16FED50EB8B8L, 0x9AC0C330F826016EL, + 0xED152665953E7671L, 0x02D63194A6369570L, 0x5074F08394B1C987L, 0x70BA598C90B25CE1L, + 0x794A15810B9742F6L, 0x0D5925E9FCAF8C6CL, 0x3067716CD868744EL, 0x910AB077E8D7731BL, + 0x6A61BBDB5AC42F61L, 0x93513EFBF0851567L, 0xF494724B9E83E9D5L, 0xE887E1985C09648DL, + 0x34B1D3C675370CFDL, 0xDC35E433BC0D255DL, 0xD0AAB84234131BE0L, 0x08042A50B48B7EAFL, + 0x9997C4EE44A3AB35L, 0x829A7B49201799D0L, 0x263B8307B7C54441L, 0x752F95F4FD6A6CA6L, + 0x927217402C08C6E5L, 0x2A8AB754A795D9EEL, 0xA442F7552F72943DL, 0x2C31334E19781208L, + 0x4FA98D7CEAEE6291L, 0x55C3862F665DB309L, 0xBD0610175D53B1F3L, 0x46FE6CB840413F27L, + 0x3FE03792DF0CFA59L, 0xCFE700372EB85E8FL, 0xA7BE29E7ADBCE118L, 0xE544EE5CDE8431DDL, + 0x8A781B1B41F1873EL, 0xA5C94C78A0D2F0E7L, 0x39412E2877B60728L, 0xA1265EF3AFC9A62CL, + 0xBCC2770C6A2506C5L, 0x3AB66DD5DCE1CE12L, 0xE65499D04A675B37L, 0x7D8F523481BFD216L, + 0x0F6F64FCEC15F389L, 0x74EFBE618B5B13C8L, 0xACDC82B714273E1DL, 0xDD40BFE003199D17L, + 0x37E99257E7E061F8L, 0xFA52626904775AAAL, 0x8BBBF63A463D56F9L, 0xF0013F1543A26E64L, + 0xA8307E9F879EC898L, 0xCC4C27A4150177CCL, 0x1B432F2CCA1D3348L, 0xDE1D1F8F9F6FA013L, + 0x606602A047A7DDD6L, 0xD237AB64CC1CB2C7L, 0x9B938E7225FCD1D3L, 0xEC4E03708E0FF476L, + 0xFEB2FBDA3D03C12DL, 0xAE0BCED2EE43889AL, 0x22CB8923EBFB4F43L, 0x69360D013CF7396DL, + 0x855E3602D2D4E022L, 0x073805BAD01F784CL, 0x33E17A133852F546L, 0xDF4874058AC7B638L, + 0xBA92B29C678AA14AL, 0x0CE89FC76CFAADCDL, 0x5F9D4E0908339E34L, 0xF1AFE9291F5923B9L, + 0x6E3480F60F4A265FL, 0xEEBF3A2AB29B841CL, 0xE21938A88F91B4ADL, 0x57DFEFF845C6D3C3L, + 0x2F006B0BF62CAAF2L, 0x62F479EF6F75EE78L, 0x11A55AD41C8916A9L, 0xF229D29084FED453L, + 0x42F1C27B16B000E6L, 0x2B1F76749823C074L, 0x4B76ECA3C2745360L, 0x8C98F463B91691BDL, + 0x14BCC93CF1ADE66AL, 0x8885213E6D458397L, 0x8E177DF0274D4711L, 0xB49B73B5503F2951L, + 0x10168168C3F96B6BL, 0x0E3D963B63CAB0AEL, 0x8DFC4B5655A1DB14L, 0xF789F1356E14DE5CL, + 0x683E68AF4E51DAC1L, 0xC9A84F9D8D4B0FD9L, 0x3691E03F52A0F9D1L, 0x5ED86E46E1878E80L, + 0x3C711A0E99D07150L, 0x5A0865B20C4E9310L, 0x56FBFC1FE4F0682EL, 0xEA8D5DE3105EDF9BL, + 0x71ABFDB12379187AL, 0x2EB99DE1BEE77B9CL, 0x21ECC0EA33CF4523L, 0x59A4D7521805C7A1L, + 0x3896F5EB56AE7C72L, 0xAA638F3DB18F75DCL, 0x9F39358DABE9808EL, 0xB7DEFA91C00B72ACL, + 0x6B5541FD62492D92L, 0x6DC6DEE8F92E4D5BL, 0x353F57ABC4BEEA7EL, 0x735769D6DA5690CEL, + 0x0A234AA642391484L, 0xF6F9508028F80D9DL, 0xB8E319A27AB3F215L, 0x31AD9C1151341A4DL, + 0x773C22A57BEF5805L, 0x45C7561A07968633L, 0xF913DA9E249DBE36L, 0xDA652D9B78A64C68L, + 0x4C27A97F3BC334EFL, 0x76621220E66B17F4L, 0x967743899ACD7D0BL, 0xF3EE5BCAE0ED6782L, + 0x409F753600C879FCL, 0x06D09A39B5926DB6L, 0x6F83AEB0317AC588L, 0x01E6CA4A86381F21L, + 0x66FF3462D19F3025L, 0x72207C24DDFD3BFBL, 0x4AF6B6D3E2ECE2EBL, 0x9C994DBEC7EA08DEL, + 0x49ACE597B09A8BC4L, 0xB38C4766CF0797BAL, 0x131B9373C57C2A75L, 0xB1822CCE61931E58L, + 0x9D7555B909BA1C0CL, 0x127FAFDD937D11D2L, 0x29DA3BADC66D92E4L, 0xA2C1D57154C2ECBCL, + 0x58C5134D82F6FE24L, 0x1C3AE3515B62274FL, 0xE907C82E01CB8126L, 0xF8ED091913E37FCBL, + 0x3249D8F9C80046C9L, 0x80CF9BEDE388FB63L, 0x1881539A116CF19EL, 0x5103F3F76BD52457L, + 0x15B7E6F5AE47F7A8L, 0xDBD7C6DED47E9CCFL, 0x44E55C410228BB1AL, 0xB647D4255EDB4E99L, + 0x5D11882BB8AAFC30L, 0xF5098BBB29D3212AL, 0x8FB5EA14E90296B3L, 0x677B942157DD025AL, + 0xFB58E7C0A390ACB5L, 0x89D3674C83BD4A01L, 0x9E2DA4DF4BF3B93BL, 0xFCC41E328CAB4829L, + 0x03F38C96BA582C52L, 0xCAD1BDBD7FD85DB2L, 0xBBB442C16082AE83L, 0xB95FE86BA5DA9AB0L, + 0xB22E04673771A93FL, 0x845358C9493152D8L, 0xBE2A488697B4541EL, 0x95A2DC2DD38E6966L, + 0xC02C11AC923C852BL, 0x2388B1990DF2A87BL, 0x7C8008FA1B4F37BEL, 0x1F70D0C84D54E503L, + 0x5490ADEC7ECE57D4L, 0x002B3C27D9063A3AL, 0x7EAEA3848030A2BFL, 0xC602326DED2003C0L, + 0x83A7287D69A94086L, 0xC57A5FCB30F57A8AL, 0xB56844E479EBE779L, 0xA373B40F05DCBCE9L, + 0xD71A786E88570EE2L, 0x879CBACDBDE8F6A0L, 0x976AD1BCC164A32FL, 0xAB21E25E9666D78BL, + 0x901063AAE5E5C33CL, 0x9818B34448698D90L, 0xE36487AE3E1E8ABBL, 0xAFBDF931893BDCB4L, + 0x6345A0DC5FBBD519L, 0x8628FE269B9465CAL, 0x1E5D01603F9C51ECL, 0x4DE44006A15049B7L, + 0xBF6C70E5F776CBB1L, 0x411218F2EF552BEDL, 0xCB0C0708705A36A3L, 0xE74D14754F986044L, + 0xCD56D9430EA8280EL, 0xC12591D7535F5065L, 0xC83223F1720AEF96L, 0xC3A0396F7363A51FL + }; + protected static Boolean valid; // The cached self-test result. + + protected long a, b, c; // The context. + + public Tiger192() {super("tiger192", HASH_SIZE, BLOCK_SIZE);} + + /** + * Private copying constructor for cloning. + * + * @param that The instance being cloned. + */ + private Tiger192(Tiger192 that) { + this(); + this.a = that.a; + this.b = that.b; + this.c = that.c; + this.count = that.count; + this.buffer = (that.buffer != null) ? (byte[]) that.buffer.clone() : null; + } + + // Instance methods implementing BaseHash. + // ----------------------------------------------------------------------- + + public Object clone() { + return new Tiger192(this); + } +} + +//-------------------------------------------------------------------------- +//$Id: Tiger.java,v 1.1 2003/03/22 03:09:57 rsdio Exp $ +// +//Copyright (C) 2003, Free Software Foundation, Inc. +// +//This file is part of GNU Crypto. +// +//GNU Crypto is free software; you can redistribute it and/or modify +//it under the terms of the GNU General Public License as published by +//the Free Software Foundation; either version 2, or (at your option) +//any later version. +// +//GNU Crypto is distributed in the hope that it will be useful, but +//WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//General Public License for more details. +// +//You should have received a copy of the GNU General Public License +//along with this program; see the file COPYING. If not, write to the +// +// Free Software Foundation Inc., +// 59 Temple Place - Suite 330, +// Boston, MA 02111-1307 +// USA +// +//Linking this library statically or dynamically with other modules is +//making a combined work based on this library. Thus, the terms and +//conditions of the GNU General Public License cover the whole +//combination. +// +//As a special exception, the copyright holders of this library give +//you permission to link this library with independent modules to +//produce an executable, regardless of the license terms of these +//independent modules, and to copy and distribute the resulting +//executable under terms of your choice, provided that you also meet, +//for each linked independent module, the terms and conditions of the +//license of that module. An independent module is a module which is +//not derived from or based on this library. If you modify this +//library, you may extend this exception to your version of the +//library, but you are not obligated to do so. If you do not wish to +//do so, delete this exception statement from your version. +// +//-------------------------------------------------------------------------- + +/** +* The Tiger message digest. Tiger was designed by Ross Anderson and Eli +* Biham, with the goal of producing a secure, fast hash function that +* performs especially well on next-generation 64-bit architectures, but +* is still efficient on 32- and 16-bit architectures. +* +*

Tiger processes data in 512-bit blocks and produces a 192-bit +* digest.

+* +*

References:

+*
    +*
  1. Tiger: A +* Fast New Hash Function, Ross Anderson and Eli Biham.
  2. +*
+* +* @version $Revision: 1.1 $ +*/ +abstract class BaseHash { + /** The canonical name prefix of the hash. */ + protected String name; + + /** The hash (output) size in bytes. */ + protected int hashSize; + + /** The hash (inner) block size in bytes. */ + protected int blockSize; + + /** Number of bytes processed so far. */ + protected long count; + + /** Temporary input buffer. */ + protected byte[] buffer; + + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + *

Trivial constructor for use by concrete subclasses.

+ * + * @param name the canonical name prefix of this instance. + * @param hashSize the block size of the output in bytes. + * @param blockSize the block size of the internal transform. + */ + protected BaseHash(String name, int hashSize, int blockSize) { + super(); + + this.name = name; + this.hashSize = hashSize; + this.blockSize = blockSize; + this.buffer = new byte[blockSize]; + + resetContext(); + } + + // Class methods + // ------------------------------------------------------------------------- + + // Instance methods + // ------------------------------------------------------------------------- + + // IMessageDigest interface implementation --------------------------------- + + public String name() { + return name; + } + + public int hashSize() { + return hashSize; + } + + public int blockSize() { + return blockSize; + } + + public void update(byte b) { + // compute number of bytes still unhashed; ie. present in buffer + int i = (int)(count % blockSize); + count++; + buffer[i] = b; + if (i == (blockSize - 1)) { + transform(buffer, 0); + } + } + + public void update(byte[] b, int offset, int len) { + int n = (int)(count % blockSize); + count += len; + int partLen = blockSize - n; + int i = 0; + + if (len >= partLen) { + System.arraycopy(b, offset, buffer, n, partLen); + transform(buffer, 0); + for (i = partLen; i + blockSize - 1 < len; i+= blockSize) { + transform(b, offset + i); + } + n = 0; + } + + if (i < len) { + System.arraycopy(b, offset + i, buffer, n, len - i); + } + } + + public byte[] digest() { + byte[] tail = padBuffer(); // pad remaining bytes in buffer + update(tail, 0, tail.length); // last transform of a message + byte[] result = getResult(); // make a result out of context + + reset(); // reset this instance for future re-use + + return result; + } + + public void reset() { // reset this instance for future re-use + count = 0L; + for (int i = 0; i < blockSize; ) { + buffer[i++] = 0; + } + + resetContext(); + } + + // methods to be implemented by concrete subclasses ------------------------ + + public abstract Object clone(); + + /** + *

Returns the byte array to use as padding before completing a hash + * operation.

+ * + * @return the bytes to pad the remaining bytes in the buffer before + * completing a hash operation. + */ + protected abstract byte[] padBuffer(); + + /** + *

Constructs the result from the contents of the current context.

+ * + * @return the output of the completed hash operation. + */ + protected abstract byte[] getResult(); + + /** Resets the instance for future re-use. */ + protected abstract void resetContext(); + + /** + *

The block digest transformation per se.

+ * + * @param in the blockSize long block, as an array of bytes to digest. + * @param offset the index where the data to digest is located within the + * input buffer. + */ + protected abstract void transform(byte[] in, int offset); +} + +//---------------------------------------------------------------------------- +//$Id: BaseHash.java,v 1.8 2002/11/07 17:17:45 raif Exp $ +// +//Copyright (C) 2001, 2002, Free Software Foundation, Inc. +// +//This file is part of GNU Crypto. +// +//GNU Crypto is free software; you can redistribute it and/or modify +//it under the terms of the GNU General Public License as published by +//the Free Software Foundation; either version 2, or (at your option) +//any later version. +// +//GNU Crypto is distributed in the hope that it will be useful, but +//WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +//General Public License for more details. +// +//You should have received a copy of the GNU General Public License +//along with this program; see the file COPYING. If not, write to the +// +// Free Software Foundation Inc., +// 59 Temple Place - Suite 330, +// Boston, MA 02111-1307 +// USA +// +//Linking this library statically or dynamically with other modules is +//making a combined work based on this library. Thus, the terms and +//conditions of the GNU General Public License cover the whole +//combination. +// +//As a special exception, the copyright holders of this library give +//you permission to link this library with independent modules to +//produce an executable, regardless of the license terms of these +//independent modules, and to copy and distribute the resulting +//executable under terms of your choice, provided that you also meet, +//for each linked independent module, the terms and conditions of the +//license of that module. An independent module is a module which is +//not derived from or based on this library. If you modify this +//library, you may extend this exception to your version of the +//library, but you are not obligated to do so. If you do not wish to +//do so, delete this exception statement from your version. +//---------------------------------------------------------------------------- +/** + *

A base abstract class to facilitate hash implementations.

+ * + * @version $Revision: 1.8 $ + */ diff --git a/100_core/src_160_hash/gplx/security/HashAlgo_tth192_tree_tst.java b/100_core/src_160_hash/gplx/security/HashAlgo_tth192_tree_tst.java new file mode 100644 index 000000000..455145aaa --- /dev/null +++ b/100_core/src_160_hash/gplx/security/HashAlgo_tth192_tree_tst.java @@ -0,0 +1,65 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.security; import gplx.*; +import org.junit.*; +public class HashAlgo_tth192_tree_tst { + @Test public void CalcRecursiveHalves() { + tst_CalcRecursiveHalves(129, 128); + tst_CalcRecursiveHalves(128, 127); + tst_CalcRecursiveHalves(100, 99); + tst_CalcRecursiveHalves(20, 19); + tst_CalcRecursiveHalves(6, 5); + tst_CalcRecursiveHalves(5, 4); + tst_CalcRecursiveHalves(4, 3); + tst_CalcRecursiveHalves(3, 2); + tst_CalcRecursiveHalves(2, 1); + tst_CalcRecursiveHalves(1, 0); + tst_CalcRecursiveHalves(0, 0); + } + @Test public void CalcWorkUnits() { + tst_CalcWorkUnits(101, 21); // leafs; 10 full, 1 part (+11) -> reduce 11 to 5+1 (+5) -> reduce 6 to 3 (+3) -> reduce 3 to 1+1 (+1) -> reduce 2 to 1 (+1) + tst_CalcWorkUnits(100, 19); // leafs; 10 full (+10) -> reduce 10 to 5 (+5) -> reduce 5 to 2+1 (+2) -> reduce 3 to 1+1 (+1) -> reduce 2 to 1 (+1) + tst_CalcWorkUnits(30, 5); // leafs; 3 full (+3) -> reduce 3 to 1+1 (+1) -> reduce 2 to 1 (+1) + tst_CalcWorkUnits(11, 3); // leafs: 1 full, 1 part (+2) -> reduce 2 to 1 (+1) + tst_CalcWorkUnits(10, 1); + tst_CalcWorkUnits(9, 1); + tst_CalcWorkUnits(1, 1); + tst_CalcWorkUnits(0, 1); + } + void tst_CalcWorkUnits(int length, int expd) { + HashAlgo_tth192 algo = HashAlgo_tth192.new_(); algo.BlockSize_set(10); + int actl = algo.CalcWorkUnits(length); + Tfds.Eq(expd, actl); + } + void tst_CalcRecursiveHalves(int val, int expd) { + int actl = CalcRecursiveHalvesMock(val); + Tfds.Eq(expd, actl); + } + int CalcRecursiveHalvesMock(int val) { + if (val <= 1) return 0; + int rv = 0; + while (true) { + int multiple = val / 2; + int remainder = val % 2; + rv += multiple; + val = multiple + remainder; + if (val == 1) + return remainder == 0 ? rv : ++rv; + } + } +} diff --git a/100_core/src_160_hash/gplx/security/HashAlgo_tth192_tst.java b/100_core/src_160_hash/gplx/security/HashAlgo_tth192_tst.java new file mode 100644 index 000000000..8faa04d5f --- /dev/null +++ b/100_core/src_160_hash/gplx/security/HashAlgo_tth192_tst.java @@ -0,0 +1,58 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.security; import gplx.*; +import org.junit.*; import gplx.ios.*; /*IoStream*/ +public class HashAlgo_tth192_tst { + @Test public void Char0000() {tst_CalcBase32FromString("", "LWPNACQDBZRYXW3VHJVCJ64QBZNGHOHHHZWCLNQ");} + @Test public void Char0001() {tst_CalcBase32FromString("\0", "VK54ZIEEVTWNAUI5D5RDFIL37LX2IQNSTAXFKSA");} + @Test public void Char0002() {tst_CalcBase32FromString("ab", "XQXRSGMB3PSN2VGZYJMNJG6SOOQ3JIGQHD2I6PQ");} + @Test public void Char0003() {tst_CalcBase32FromString("abc", "ASD4UJSEH5M47PDYB46KBTSQTSGDKLBHYXOMUIA");} + @Test public void Char0004() {tst_CalcBase32FromString("abcd", "SQF2PFTVIFRR5KJSI45IDENXMB43NI7EIXYGHGI");} + @Test public void Char0005() {tst_CalcBase32FromString("abcde", "SKGLNP5WV7ZUMF6IUK5CYXBE3PI4C6PHWNVM2YQ");} + @Test public void Char0009() {tst_CalcBase32FromString("abcdefghi", "RUIKHZFO4NIY6NNUHJMAC2I26U3U65FZWCO3UFY");} + @Test public void Char1024() {tst_CalcBase32FromString(String_.Repeat("A", 1024), "L66Q4YVNAFWVS23X2HJIRA5ZJ7WXR3F26RSASFA");} + @Test public void Char1025() {tst_CalcBase32FromString(String_.Repeat("A", 1025), "PZMRYHGY6LTBEH63ZWAHDORHSYTLO4LEFUIKHWY");} +// @Test // commented out due to time (approx 17.94 seconds) + public void Ax2Pow27() { // 134 MB + tst_CalcBase32FromString(String_.Repeat("A", (int)Math_.Pow(2, 27)), "QNIJO36QDIQREUT3HWK4MDVKD2T6OENAEKYADTQ"); + } + void tst_CalcBase32FromString(String raw, String expd) { + IoStream stream = IoStream_.mem_txt_(Io_url_.Empty, raw); + String actl = HashAlgo_.Tth192.CalcHash(ConsoleDlg_.Null, stream); + Tfds.Eq(expd, actl); + } +} +/* + The empty (zero-length) file: + urn:tree:tiger:LWPNACQDBZRYXW3VHJVCJ64QBZNGHOHHHZWCLNQ + + A file with a single zero byte: + urn:tree:tiger:VK54ZIEEVTWNAUI5D5RDFIL37LX2IQNSTAXFKSA + + A file with 1024 'A' characters: + urn:tree:tiger:L66Q4YVNAFWVS23X2HJIRA5ZJ7WXR3F26RSASFA + + A file with 1025 'A' characters: + urn:tree:tiger:PZMRYHGY6LTBEH63ZWAHDORHSYTLO4LEFUIKHWY + + http://open-content.net/specs/draft-jchapweske-thex-02.html + + A file with 134,217,728 'A' characters (2 Pow 27) + urn:tree:tiger:QNIJO36QDIQREUT3HWK4MDVKD2T6OENAEKYADTQ + queried against DC++ 0.698 + */ diff --git a/100_core/src_160_hash/gplx/security/HashDlgWtr_tst.java b/100_core/src_160_hash/gplx/security/HashDlgWtr_tst.java new file mode 100644 index 000000000..bd163ccce --- /dev/null +++ b/100_core/src_160_hash/gplx/security/HashDlgWtr_tst.java @@ -0,0 +1,41 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.security; import gplx.*; +import org.junit.*; import gplx.ios.*; /*IoStream*/ +public class HashDlgWtr_tst { + @Before public void setup() { + HashAlgo_tth192 algo = HashAlgo_tth192.new_(); + algo.BlockSize_set(10); + calc = algo; + } + @Test public void Basic() { + tst_Status(10, stringAry_(" - hash: 100%")); + tst_Status(11, stringAry_(" - hash: 66%")); + tst_Status(30, stringAry_(" - hash: 40%", " - hash: 60%", " - hash: 100%")); + } + void tst_Status(int count, String[] expdWritten) { + ConsoleDlg_dev dialog = ConsoleDlg_.Dev(); + String data = String_.Repeat("A", count); + IoStream stream = IoStream_.mem_txt_(Io_url_.Empty, data); + calc.CalcHash(dialog, stream); + String[] actlWritten = dialog.Written().To_str_ary(); + Tfds.Eq_ary(actlWritten, expdWritten); + } + String[] stringAry_(String... ary) {return ary;} + HashAlgo calc; +} diff --git a/100_core/src_200_io/gplx/Io_mgr.java b/100_core/src_200_io/gplx/Io_mgr.java new file mode 100644 index 000000000..4482885aa --- /dev/null +++ b/100_core/src_200_io/gplx/Io_mgr.java @@ -0,0 +1,162 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.core.primitives.*; import gplx.ios.*; /*IoItmFil, IoItmDir..*/ +public class Io_mgr { // exists primarily to gather all cmds under gplx namespace; otherwise need to use gplx.ios whenever copying/deleting file + public boolean Exists(Io_url url) {return url.Type_dir() ? ExistsDir(url) : ExistsFil(url);} + public boolean ExistsFil(Io_url url) {return IoEnginePool._.Get_by(url.Info().EngineKey()).ExistsFil_api(url);} + public void ExistsFilOrFail(Io_url url) {if (!ExistsFil(url)) throw Exc_.new_("could not find file", "url", url);} + public void SaveFilStr(String url, String text) {SaveFilStr_args(Io_url_.new_fil_(url), text).Exec();} + public void SaveFilStr(Io_url url, String text) {SaveFilStr_args(url, text).Exec();} + public IoEngine_xrg_saveFilStr SaveFilStr_args(Io_url url, String text) {return IoEngine_xrg_saveFilStr.new_(url, text);} + public void AppendFilStr(String url, String text) {AppendFilStr(Io_url_.new_fil_(url), text);} + public void AppendFilStr(Io_url url, String text) {SaveFilStr_args(url, text).Append_(true).Exec();} + public void DeleteFil(Io_url url) {DeleteFil_args(url).Exec();} + public IoEngine_xrg_deleteFil DeleteFil_args(Io_url url) {return IoEngine_xrg_deleteFil.new_(url);} + public void MoveFil(Io_url src, Io_url trg) {IoEngine_xrg_xferFil.move_(src, trg).Exec();} + public IoEngine_xrg_xferFil MoveFil_args(Io_url src, Io_url trg, boolean overwrite) {return IoEngine_xrg_xferFil.move_(src, trg).Overwrite_(overwrite);} + public void CopyFil(Io_url src, Io_url trg, boolean overwrite) {IoEngine_xrg_xferFil.copy_(src, trg).Overwrite_(overwrite).Exec();} + public IoEngine_xrg_xferFil CopyFil_args(Io_url src, Io_url trg, boolean overwrite) {return IoEngine_xrg_xferFil.copy_(src, trg).Overwrite_(overwrite);} + public IoRecycleBin RecycleBin() {return recycleBin;} IoRecycleBin recycleBin = IoRecycleBin._; + + public IoStream OpenStreamWrite(Io_url url) {return OpenStreamWrite_args(url).Exec();} + public IoEngine_xrg_openWrite OpenStreamWrite_args(Io_url url) {return IoEngine_xrg_openWrite.new_(url);} + public IoItmFil QueryFil(Io_url url) {return IoEnginePool._.Get_by(url.Info().EngineKey()).QueryFil(url);} + public void UpdateFilAttrib(Io_url url, IoItmAttrib attrib) {IoEnginePool._.Get_by(url.Info().EngineKey()).UpdateFilAttrib(url, attrib);} + public void UpdateFilModifiedTime(Io_url url, DateAdp modified) {IoEnginePool._.Get_by(url.Info().EngineKey()).UpdateFilModifiedTime(url, modified);} + + public boolean ExistsDir(Io_url url) {return IoEnginePool._.Get_by(url.Info().EngineKey()).ExistsDir(url);} + public void CreateDir(Io_url url) {IoEnginePool._.Get_by(url.Info().EngineKey()).CreateDir(url);} + public boolean CreateDirIfAbsent(Io_url url) { + boolean exists = ExistsDir(url); + if (!exists) { + CreateDir(url); + return true; + } + return false; + } + public void Create_fil_ary(Io_fil[] fil_ary) { + for (Io_fil fil : fil_ary) + SaveFilStr(fil.Url(), fil.Data()); + } + public Io_url[] QueryDir_fils(Io_url dir) {return QueryDir_args(dir).ExecAsUrlAry();} + public IoEngine_xrg_queryDir QueryDir_args(Io_url dir) {return IoEngine_xrg_queryDir.new_(dir);} + public void DeleteDirSubs(Io_url url) {IoEngine_xrg_deleteDir.new_(url).Exec();} + public IoEngine_xrg_deleteDir DeleteDir_cmd(Io_url url) {return IoEngine_xrg_deleteDir.new_(url);} + public void DeleteDirDeep(Io_url url) {IoEngine_xrg_deleteDir.new_(url).Recur_().Exec();} + public void DeleteDirDeep_ary(Io_url... urls) {for (Io_url url : urls) IoEngine_xrg_deleteDir.new_(url).Recur_().Exec();} + public int Delete_dir_empty(Io_url url) {return Io_mgr_.Delete_dir_empty(url);} + public void MoveDirDeep(Io_url src, Io_url trg) {IoEngine_xrg_xferDir.move_(src, trg).Recur_().Exec();} + public IoEngine_xrg_xferDir CopyDir_cmd(Io_url src, Io_url trg) {return IoEngine_xrg_xferDir.copy_(src, trg);} + public void CopyDirSubs(Io_url src, Io_url trg) {IoEngine_xrg_xferDir.copy_(src, trg).Exec();} + public void CopyDirDeep(Io_url src, Io_url trg) {IoEngine_xrg_xferDir.copy_(src, trg).Recur_().Exec();} + public void DeleteDirIfEmpty(Io_url url) { + if (Array_.Len(QueryDir_fils(url)) == 0) + this.DeleteDirDeep(url); + } + public void AliasDir_sysEngine(String srcRoot, String trgRoot) {AliasDir(srcRoot, trgRoot, IoEngine_.SysKey);} + public void AliasDir(String srcRoot, String trgRoot, String engineKey) {IoUrlInfoRegy._.Reg(IoUrlInfo_.alias_(srcRoot, trgRoot, engineKey));} + public IoStream OpenStreamRead(Io_url url) {return OpenStreamRead_args(url).ExecAsIoStreamOrFail();} + public IoEngine_xrg_openRead OpenStreamRead_args(Io_url url) {return IoEngine_xrg_openRead.new_(url);} + public String LoadFilStr(String url) {return LoadFilStr_args(Io_url_.new_fil_(url)).Exec();} + public String LoadFilStr(Io_url url) {return LoadFilStr_args(url).Exec();} + public IoEngine_xrg_loadFilStr LoadFilStr_args(Io_url url) {return IoEngine_xrg_loadFilStr.new_(url);} + public byte[] LoadFilBry(String url) {return LoadFilBry_reuse(Io_url_.new_fil_(url), Bry_.Empty, Int_obj_ref.zero_());} + public byte[] LoadFilBry(Io_url url) {return LoadFilBry_reuse(url, Bry_.Empty, Int_obj_ref.zero_());} + public void LoadFilBryByBfr(Io_url url, Bry_bfr bfr) { + Int_obj_ref len = Int_obj_ref.zero_(); + byte[] bry = LoadFilBry_reuse(url, Bry_.Empty, len); + bfr.Bfr_init(bry, len.Val()); + } + public static final byte[] LoadFilBry_fail = Bry_.Empty; + public byte[] LoadFilBry_reuse(Io_url url, byte[] ary, Int_obj_ref aryLen) { + if (!ExistsFil(url)) {aryLen.Val_(0); return LoadFilBry_fail;} + IoStream stream = IoStream_.Null; + try { + stream = OpenStreamRead(url); + int streamLen = (int)stream.Len(); + aryLen.Val_(streamLen); + if (streamLen > ary.length) + ary = new byte[streamLen]; + stream.ReadAry(ary); + return ary; + } + catch (Exception e) {throw Exc_.new_("failed to load file", "url", url.Xto_api(), "e", Err_.Message_lang(e));} + finally {stream.Rls();} + } + public byte[] LoadFilBry_loose(Io_url url) {return Bry_.new_u8(LoadFilStr_loose(url));} + public String LoadFilStr_loose(Io_url url) { + String rv = LoadFilStr_args(url).BomUtf8Convert_(Bool_.Y).MissingIgnored_(Bool_.Y).Exec(); + if (String_.Has(rv, "\r\n")) + rv = String_.Replace(rv, "\r\n", "\n"); + return rv; + } + public void AppendFilBfr(Io_url url, Bry_bfr bfr) {AppendFilByt(url, bfr.Bfr(), 0, bfr.Len()); bfr.ClearAndReset();} + public void AppendFilByt(Io_url url, byte[] val) {AppendFilByt(url, val, 0, val.length);} + public void AppendFilByt(Io_url url, byte[] val, int len) {AppendFilByt(url, val, 0, len);} + public void AppendFilByt(Io_url url, byte[] val, int bgn, int len) { + IoStream stream = IoStream_.Null; + try { + stream = OpenStreamWrite_args(url).Mode_(IoStream_.Mode_wtr_append).Exec(); + stream.Write(val, bgn, len); + } finally {stream.Rls();} + } + public void SaveFilBfr(Io_url url, Bry_bfr bfr) {SaveFilBry(url, bfr.Bfr(), bfr.Len()); bfr.Clear();} + public void SaveFilBry(String urlStr, byte[] val) {SaveFilBry(Io_url_.new_fil_(urlStr), val);} + public void SaveFilBry(Io_url url, byte[] val) {SaveFilBry(url, val, val.length);} + public void SaveFilBry(Io_url url, byte[] val, int len) {SaveFilBry(url, val, 0, len);} + public void SaveFilBry(Io_url url, byte[] val, int bgn, int len) { + IoStream stream = IoStream_.Null; + try { + stream = OpenStreamWrite(url); + stream.Write(val, bgn, len); + } finally {stream.Rls();} + } + public IoEngine InitEngine_mem() {return IoEngine_.Mem_init_();} + public IoEngine InitEngine_mem_(String key) { + IoEngine engine = IoEngine_.mem_new_(key); + IoEnginePool._.Add_if_dupe_use_nth(engine); + IoUrlInfoRegy._.Reg(IoUrlInfo_.mem_(key, key)); + return engine; + } + public boolean DownloadFil(String src, Io_url trg) {return IoEngine_xrg_downloadFil.new_(src, trg).Exec();} + public IoEngine_xrg_downloadFil DownloadFil_args(String src, Io_url trg) {return IoEngine_xrg_downloadFil.new_(src, trg);} + public static final Io_mgr I = new Io_mgr(); public Io_mgr() {} + public static final int Len_kb = 1024, Len_mb = 1048576, Len_gb = 1073741824, Len_gb_2 = 2147483647; + public static final long Len_mb_long = Len_mb; + public static final long Len_null = -1; +} +class Io_mgr_ { + public static int Delete_dir_empty(Io_url url) { + IoItmDir dir = Io_mgr.I.QueryDir_args(url).ExecAsDir(); + int sub_dirs_len = dir.SubDirs().Count(); + int deleted_dirs = 0; + for (int i = 0; i < sub_dirs_len; ++i) { + IoItmDir sub_dir = (IoItmDir)dir.SubDirs().Get_at(i); + deleted_dirs += Io_mgr.I.Delete_dir_empty(sub_dir.Url()); + } + if ( dir.SubFils().Count() == 0 + && deleted_dirs == sub_dirs_len + ) { + Io_mgr.I.DeleteDirIfEmpty(url); + return 1; + } + else + return 0; + } +} diff --git a/100_core/src_200_io/gplx/Io_mgr__tst.java b/100_core/src_200_io/gplx/Io_mgr__tst.java new file mode 100644 index 000000000..74c04e7dc --- /dev/null +++ b/100_core/src_200_io/gplx/Io_mgr__tst.java @@ -0,0 +1,100 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class Io_mgr__tst { + @Before public void init() {fxt.Clear();} private final Io_mgr__fxt fxt = new Io_mgr__fxt(); + @Test public void Dir_delete_empty__basic() { + fxt.Exec_itm_create("mem/dir/"); + fxt.Exec_dir_delete_empty("mem/dir/"); + fxt.Test_itm_exists_n("mem/dir/"); + } + @Test public void Dir_delete_empty__no_delete() { + fxt.Exec_itm_create + ( "mem/dir/" + , "mem/dir/fil.txt" + ); + fxt.Exec_dir_delete_empty("mem/dir/"); + fxt.Test_itm_exists_y("mem/dir/"); + } + @Test public void Dir_delete_empty__nested_simple() { + fxt.Exec_itm_create + ( "mem/dir/" + , "mem/dir/1/" + , "mem/dir/1/11/" + ); + fxt.Exec_dir_delete_empty("mem/dir/"); + fxt.Test_itm_exists_n("mem/dir/"); + } + @Test public void Dir_delete_empty__nested_many() { + fxt.Exec_itm_create + ( "mem/dir/" + , "mem/dir/1/" + , "mem/dir/1/11/" + , "mem/dir/2/22/" + , "mem/dir/2/22/222a/" + , "mem/dir/2/22/222b/" + ); + fxt.Exec_dir_delete_empty("mem/dir/"); + fxt.Test_itm_exists_n("mem/dir/"); + } + @Test public void Dir_delete_empty__nested_some() { + fxt.Exec_itm_create + ( "mem/dir/" + , "mem/dir/1/" + , "mem/dir/1/11/" + , "mem/dir/2/22/" + , "mem/dir/2/22/a.txt" + , "mem/dir/2/22/222a/" + , "mem/dir/2/22/222b/" + ); + fxt.Exec_dir_delete_empty("mem/dir/"); + fxt.Test_itm_exists_n + ( "mem/dir/1/" + , "mem/dir/1/11/" + , "mem/dir/2/22/222a/" + , "mem/dir/2/22/222b/" + ); + fxt.Test_itm_exists_y + ( "mem/dir/" + , "mem/dir/2/22/" + ); + } +} +class Io_mgr__fxt { + public void Clear() {Io_mgr.I.InitEngine_mem();} + public void Exec_itm_create(String... ary) { + for (String itm : ary) { + Io_url url = Io_url_.new_any_(itm); + if (url.Type_dir()) + Io_mgr.I.CreateDir(url); + else + Io_mgr.I.SaveFilStr(url, url.NameAndExt()); + } + } + public void Exec_dir_delete_empty(String url) {Io_mgr.I.Delete_dir_empty(Io_url_.mem_dir_(url));} + public void Test_itm_exists_n(String... ary) {Test_itm_exists(Bool_.N, ary);} + public void Test_itm_exists_y(String... ary) {Test_itm_exists(Bool_.Y, ary);} + public void Test_itm_exists(boolean expd, String... ary) { + for (String itm : ary) { + Io_url url = Io_url_.new_any_(itm); + boolean actl = url.Type_dir() ? Io_mgr.I.ExistsDir(url) : Io_mgr.I.ExistsFil(url); + Tfds.Eq(expd, actl, itm); + } + } +} diff --git a/100_core/src_200_io/gplx/ios/IoEngine.java b/100_core/src_200_io/gplx/ios/IoEngine.java new file mode 100644 index 000000000..4bb0a4001 --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoEngine.java @@ -0,0 +1,154 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import gplx.core.criterias.*; +public interface IoEngine { + String Key(); + boolean ExistsFil_api(Io_url url); + void SaveFilText_api(IoEngine_xrg_saveFilStr args); + String LoadFilStr(IoEngine_xrg_loadFilStr args); + void DeleteFil_api(IoEngine_xrg_deleteFil args); + void CopyFil(IoEngine_xrg_xferFil args); + void MoveFil(IoEngine_xrg_xferFil args); + IoItmFil QueryFil(Io_url url); + void UpdateFilAttrib(Io_url url, IoItmAttrib atr); // will fail if file does not exists + void UpdateFilModifiedTime(Io_url url, DateAdp modified); + IoStream OpenStreamRead(Io_url url); + IoStream OpenStreamWrite(IoEngine_xrg_openWrite args); + void XferFil(IoEngine_xrg_xferFil args); + void RecycleFil(IoEngine_xrg_recycleFil xrg); + + boolean ExistsDir(Io_url url); + void CreateDir(Io_url url); // creates all folder levels (EX: C:\a\b\c\ will create C:\a\ and C:\a\b\). will not fail if called on already existing folders. + void DeleteDir(Io_url url); + void MoveDir(Io_url src, Io_url trg); // will fail if trg exists + void CopyDir(Io_url src, Io_url trg); + IoItmDir QueryDir(Io_url url); + + void DeleteDirDeep(IoEngine_xrg_deleteDir args); + void MoveDirDeep(IoEngine_xrg_xferDir args); // will fail if trg exists + IoItmDir QueryDirDeep(IoEngine_xrg_queryDir args); + void XferDir(IoEngine_xrg_xferDir args); + boolean DownloadFil(IoEngine_xrg_downloadFil xrg); + Io_stream_rdr DownloadFil_as_rdr(IoEngine_xrg_downloadFil xrg); +} +class IoEngineUtl { + public int BufferLength() {return bufferLength;} public void BufferLength_set(int v) {bufferLength = v;} int bufferLength = 4096; // 0x1000 + public void DeleteRecycleGplx(IoEngine engine, IoEngine_xrg_recycleFil xrg) { + Io_url recycleUrl = xrg.RecycleUrl(); + if (recycleUrl.Type_fil()) + engine.MoveFil(IoEngine_xrg_xferFil.move_(xrg.Url(), recycleUrl).Overwrite_(false).ReadOnlyFails_(true)); + else + engine.MoveDirDeep(IoEngine_xrg_xferDir.move_(xrg.Url(), recycleUrl).Overwrite_(false).ReadOnlyFails_(true)); + } + public void DeleteDirDeep(IoEngine engine, Io_url dirUrl, IoEngine_xrg_deleteDir args) { + ConsoleDlg usrDlg = args.UsrDlg(); + IoItmDir dir = engine.QueryDir(dirUrl); if (!dir.Exists()) return; + for (Object subDirObj : dir.SubDirs()) { + IoItmDir subDir = (IoItmDir)subDirObj; + if (!args.SubDirScanCrt().Matches(subDir)) continue; + if (args.Recur()) DeleteDirDeep(engine, subDir.Url(), args); + } + for (Object subFilObj : dir.SubFils()) { + IoItmFil subFil = (IoItmFil)subFilObj; + if (!args.MatchCrt().Matches(subFil)) continue; + Io_url subFilUrl = subFil.Url(); + try {engine.DeleteFil_api(IoEngine_xrg_deleteFil.new_(subFilUrl).ReadOnlyFails_(args.ReadOnlyFails()));} + catch (Exception exc) {usrDlg.WriteLineFormat(Err_.Message_lang(exc));} + } + // all subs deleted; now delete dir + if (!args.MatchCrt().Matches(dir)) return; + try {engine.DeleteDir(dir.Url());} + catch (Exception exc) {usrDlg.WriteLineFormat(Err_.Message_lang(exc));} + } + public void XferDir(IoEngine srcEngine, Io_url src, IoEngine trgEngine, Io_url trg, IoEngine_xrg_xferDir args) { + trgEngine.CreateDir(trg); + IoItmDir srcDir = QueryDirDeep(srcEngine, IoEngine_xrg_queryDir.new_(src).Recur_(false)); + for (Object subSrcObj : srcDir.SubDirs()) { + IoItmDir subSrc = (IoItmDir)subSrcObj; + if (!args.SubDirScanCrt().Matches(subSrc)) continue; + if (!args.MatchCrt().Matches(subSrc)) continue; + Io_url subTrg = trg.GenSubDir_nest(subSrc.Url().NameOnly()); //EX: C:\abc\def\ -> C:\123\ + def\ + if (args.Recur()) XferDir(srcEngine, subSrc.Url(), trgEngine, subTrg, args); + } + IoItmList srcFils = IoItmList.list_(src.Info().CaseSensitive()); + for (Object srcFilObj : srcDir.SubFils()) { + IoItmFil srcFil = (IoItmFil)srcFilObj; + if (args.MatchCrt().Matches(srcFil)) srcFils.Add(srcFil); + } + for (Object srcFilObj : srcFils) { + IoItmFil srcFil = (IoItmFil)srcFilObj; + Io_url srcFilPath = srcFil.Url(); + Io_url trgFilPath = trg.GenSubFil(srcFilPath.NameAndExt()); //EX: C:\abc\fil.txt -> C:\123\ + fil.txt + IoEngine_xrg_xferFil xferArgs = args.Type_move() ? IoEngine_xrg_xferFil.move_(srcFilPath, trgFilPath).Overwrite_(args.Overwrite()) : IoEngine_xrg_xferFil.copy_(srcFilPath, trgFilPath).Overwrite_(args.Overwrite()); + XferFil(srcEngine, xferArgs); + } + if (args.Type_move()) srcEngine.DeleteDirDeep(IoEngine_xrg_deleteDir.new_(src).Recur_(args.Recur()).ReadOnlyFails_(args.ReadOnlyFails()));// this.DeleteDirDeep(srcEngine, src, IoEngine_xrg_deleteItm.new_(src).Recur_(args.Recur()).ReadOnlyIgnored_(args.ReadOnlyIgnored())); + } + public void XferFil(IoEngine srcEngine, IoEngine_xrg_xferFil args) { + Io_url src = args.Src(), trg = args.Trg(); + if (String_.Eq(srcEngine.Key(), trg.Info().EngineKey())) { + if (args.Type_move()) + srcEngine.MoveFil(args); + else + srcEngine.CopyFil(args); + } + else { + TransferStream(src, trg); + if (args.Type_move()) srcEngine.DeleteFil_api(IoEngine_xrg_deleteFil.new_(src)); + } + } + public IoItmDir QueryDirDeep(IoEngine engine, IoEngine_xrg_queryDir args) { + IoItmDir rv = IoItmDir_.top_(args.Url()); + rv.Exists_set(QueryDirDeepCore(rv, args.Url(), engine, args.Recur(), args.SubDirScanCrt(), args.DirCrt(), args.FilCrt(), args.UsrDlg(), args.DirInclude())); + return rv; + } + static boolean QueryDirDeepCore(IoItmDir ownerDir, Io_url url, IoEngine engine, boolean recur, Criteria subDirScanCrt, Criteria dirCrt, Criteria filCrt, ConsoleDlg usrDlg, boolean dirInclude) { + if (usrDlg.CanceledChk()) return false; + if (usrDlg.Enabled()) usrDlg.WriteTempText(String_.Concat("scan: ", url.Raw())); + IoItmDir scanDir = engine.QueryDir(url); + for (Object subDirObj : scanDir.SubDirs()) { + IoItmDir subDir = (IoItmDir)subDirObj; + if (!subDirScanCrt.Matches(subDir)) continue; + if (dirCrt.Matches(subDir)) { + ownerDir.SubDirs().Add(subDir); // NOTE: always add subDir; do not use dirCrt here, else its subFils will be added to non-existent subDir + } + if (recur) + QueryDirDeepCore(subDir, subDir.Url(), engine, recur, subDirScanCrt, dirCrt, filCrt, usrDlg, dirInclude); + } + for (Object subFilObj : scanDir.SubFils()) { + IoItmFil subFil = (IoItmFil)subFilObj; + if (filCrt.Matches(subFil)) ownerDir.SubFils().Add(subFil); + } + return scanDir.Exists(); + } + void TransferStream(Io_url src, Io_url trg) { + IoStream srcStream = null; + IoStream trgStream = null; + try { + srcStream = IoEnginePool._.Get_by(src.Info().EngineKey()).OpenStreamRead(src); + trgStream = IoEngine_xrg_openWrite.new_(trg).Exec(); + srcStream.Transfer(trgStream, bufferLength); + } + finally { + if (srcStream != null) srcStream.Rls(); + if (trgStream != null) trgStream.Rls(); + } + } + public static IoEngineUtl new_() {return new IoEngineUtl();} IoEngineUtl() {} +} diff --git a/100_core/src_200_io/gplx/ios/IoEnginePool.java b/100_core/src_200_io/gplx/ios/IoEnginePool.java new file mode 100644 index 000000000..2dc6b9684 --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoEnginePool.java @@ -0,0 +1,34 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +public class IoEnginePool { + public void Add_if_dupe_use_nth(IoEngine engine) { + hash.Del(engine.Key()); + hash.Add(engine.Key(), engine); + } + public IoEngine Get_by(String key) { + IoEngine rv = (IoEngine)hash.Get_by(key); + return rv == null ? IoEngine_.Mem : rv; // rv == null when url is null or empty; return Mem which should be a noop; DATE:2013-06-04 + } + Hash_adp hash = Hash_adp_.new_(); + public static final IoEnginePool _ = new IoEnginePool(); + IoEnginePool() { + this.Add_if_dupe_use_nth(IoEngine_.Sys); + this.Add_if_dupe_use_nth(IoEngine_.Mem); + } +} \ No newline at end of file diff --git a/100_core/src_200_io/gplx/ios/IoEngine_.java b/100_core/src_200_io/gplx/ios/IoEngine_.java new file mode 100644 index 000000000..b57ff377c --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoEngine_.java @@ -0,0 +1,30 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +public class IoEngine_ { + public static final String SysKey = "sys"; + public static final String MemKey = "mem"; + + public static final IoEngine Sys = IoEngine_system.new_(); + public static final IoEngine_memory Mem = IoEngine_memory.new_(MemKey); + public static IoEngine Mem_init_() { + Mem.Clear(); + return Mem; + } + public static IoEngine mem_new_(String key) {return IoEngine_memory.new_(key);} +} diff --git a/100_core/src_200_io/gplx/ios/IoEngine_base.java b/100_core/src_200_io/gplx/ios/IoEngine_base.java new file mode 100644 index 000000000..f316e7983 --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoEngine_base.java @@ -0,0 +1,57 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +public abstract class IoEngine_base implements IoEngine { + public abstract String Key(); + public abstract boolean ExistsFil_api(Io_url url); + public abstract void SaveFilText_api(IoEngine_xrg_saveFilStr args); + public abstract String LoadFilStr(IoEngine_xrg_loadFilStr args); + public abstract void DeleteFil_api(IoEngine_xrg_deleteFil args); + public abstract void CopyFil(IoEngine_xrg_xferFil args); + public abstract void MoveFil(IoEngine_xrg_xferFil args); + public abstract IoItmFil QueryFil(Io_url url); + public abstract void UpdateFilAttrib(Io_url url, IoItmAttrib atr); // will fail if file does not exists + public abstract void UpdateFilModifiedTime(Io_url url, DateAdp modified); + public abstract IoStream OpenStreamRead(Io_url url); + public abstract IoStream OpenStreamWrite(IoEngine_xrg_openWrite args); + public abstract void XferFil(IoEngine_xrg_xferFil args); + + public abstract boolean ExistsDir(Io_url url); + public abstract void CreateDir(Io_url url); // creates all folder levels (EX: C:\a\b\c\ will create C:\a\ and C:\a\b\). will not fail if called on already existing folders. + public abstract void DeleteDir(Io_url url); + public abstract void MoveDir(Io_url src, Io_url trg); // will fail if trg exists + public abstract void CopyDir(Io_url src, Io_url trg); + public abstract IoItmDir QueryDir(Io_url url); + + public abstract void DeleteDirDeep(IoEngine_xrg_deleteDir args); + public abstract void MoveDirDeep(IoEngine_xrg_xferDir args); // will fail if trg exists + public abstract IoItmDir QueryDirDeep(IoEngine_xrg_queryDir args); + public abstract void XferDir(IoEngine_xrg_xferDir args); + public abstract boolean DownloadFil(IoEngine_xrg_downloadFil xrg); + public abstract Io_stream_rdr DownloadFil_as_rdr(IoEngine_xrg_downloadFil xrg); + + public void RecycleFil(IoEngine_xrg_recycleFil xrg) { + Io_url recycleUrl = xrg.RecycleUrl(); + if (recycleUrl.Type_fil()) { + this.MoveFil(IoEngine_xrg_xferFil.move_(xrg.Url(), recycleUrl).Overwrite_(false).ReadOnlyFails_(true).MissingFails_(xrg.MissingFails())); + IoRecycleBin._.Regy_add(xrg); + } + else + this.MoveDirDeep(IoEngine_xrg_xferDir.move_(xrg.Url(), recycleUrl).Overwrite_(false).ReadOnlyFails_(true)); + } +} diff --git a/100_core/src_200_io/gplx/ios/IoEngine_memory.java b/100_core/src_200_io/gplx/ios/IoEngine_memory.java new file mode 100644 index 000000000..cd27b4ba4 --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoEngine_memory.java @@ -0,0 +1,200 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +public class IoEngine_memory extends IoEngine_base { + @Override public String Key() {return key;} private String key = IoEngine_.MemKey; + @Override public boolean ExistsFil_api(Io_url url) {return FetchFil(url) != IoItmFil_mem.Null;} + @Override public void DeleteFil_api(IoEngine_xrg_deleteFil args) { + Io_url url = args.Url(); + IoItmDir dir = FetchDir(url.OwnerDir()); if (dir == null) return; // url doesn't exist; just exit + IoItmFil fil = IoItmFil_.as_(dir.SubFils().Get_by(url.NameAndExt())); + if (fil != null && fil.ReadOnly() && args.ReadOnlyFails()) throw IoErr.FileIsReadOnly(url); + dir.SubFils().Del(url); + } + void DeleteFil(Io_url url) {DeleteFil_api(IoEngine_xrg_deleteFil.new_(url));} + @Override public void XferFil(IoEngine_xrg_xferFil args) {utl.XferFil(this, args);} + @Override public void MoveFil(IoEngine_xrg_xferFil args) { + Io_url src = args.Src(), trg = args.Trg(); boolean overwrite = args.Overwrite(); + if (String_.Eq(src.Xto_api(), trg.Xto_api())) throw Exc_.new_("move failed; src is same as trg", "raw", src.Raw()); + CheckTransferArgs("move", src, trg, overwrite); + if (overwrite) DeleteFil(trg); + IoItmFil_mem curFil = FetchFil(src); curFil.Name_(trg.NameAndExt()); + AddFilToDir(trg.OwnerDir(), curFil); + DeleteFil(src); + } + @Override public void CopyFil(IoEngine_xrg_xferFil args) { + Io_url src = args.Src(), trg = args.Trg(); boolean overwrite = args.Overwrite(); + CheckTransferArgs("copy", src, trg, overwrite); + if (overwrite) DeleteFil(trg); + IoItmFil_mem srcFil = FetchFil(src); + IoItmFil_mem curFil = srcFil.Clone(); curFil.Name_(trg.NameAndExt()); + AddFilToDir(trg.OwnerDir(), curFil); + } + @Override public IoItmDir QueryDirDeep(IoEngine_xrg_queryDir args) {return utl.QueryDirDeep(this, args);} + @Override public void UpdateFilAttrib(Io_url url, IoItmAttrib atr) {FetchFil(url).ReadOnly_(atr.ReadOnly());} + @Override public void UpdateFilModifiedTime(Io_url url, DateAdp modified) {FetchFil(url).ModifiedTime_(modified);} + @Override public IoItmFil QueryFil(Io_url url) {return FetchFil(url);} + @Override public void SaveFilText_api(IoEngine_xrg_saveFilStr args) { + Io_url url = args.Url(); + IoItmDir dir = FetchDir(url.OwnerDir()); + if (dir != null) { + IoItmFil fil = IoItmFil_.as_(dir.SubFils().Get_by(url.NameAndExt())); + if (fil != null && fil.ReadOnly()) throw IoErr.FileIsReadOnly(url); + } + + if (args.Append()) + AppendFilStr(args); + else + SaveFilStr(args.Url(), args.Text()); + } + @Override public String LoadFilStr(IoEngine_xrg_loadFilStr args) { + return FetchFil(args.Url()).Text(); + } + void SaveFilStr(Io_url url, String text) { + DateAdp time = DateAdp_.Now(); + IoItmFil_mem fil = IoItmFil_mem.new_(url, String_.Len(text), time, text); + AddFilToDir(url.OwnerDir(), fil); + } + void AppendFilStr(IoEngine_xrg_saveFilStr args) { + Io_url url = args.Url(); String text = args.Text(); + if (ExistsFil_api(url)) { + IoItmFil_mem fil = FetchFil(url); + fil.ModifiedTime_(DateAdp_.Now()); + fil.Text_set(fil.Text() + text); + } + else + SaveFilStr(args.Url(), args.Text()); + } + @Override public IoStream OpenStreamRead(Io_url url) { + IoItmFil_mem fil = FetchFil(url); + fil.Stream().Position_set(0); + return fil.Stream(); + } + @Override public IoStream OpenStreamWrite(IoEngine_xrg_openWrite args) { + Io_url url = args.Url(); + IoItmFil_mem fil = FetchFil(url); + if (fil == IoItmFil_mem.Null) { // file doesn't exist; create new one + SaveFilStr(url, ""); + fil = FetchFil(url); + } + else { + if (args.Mode() == IoStream_.Mode_wtr_create) + fil.Text_set(""); // NOTE: clear text b/c it still has pointer to existing stream + } + return fil.Stream(); + } + + @Override public boolean ExistsDir(Io_url url) {return FetchDir(url) != null;} + @Override public void CreateDir(Io_url url) { + IoItmDir dir = FetchDir(url); if (dir != null) return; // dir exists; exit + dir = IoItmDir_.top_(url); + dirs.Add(dir); + IoItmDir ownerDir = FetchDir(url.OwnerDir()); + if (ownerDir == null && !url.OwnerDir().Eq(Io_url_.Empty)) { // no owner dir && not "driveDir" -> create + CreateDir(url.OwnerDir()); // recursive + ownerDir = FetchDir(url.OwnerDir()); + } + if (ownerDir != null) + ownerDir.SubDirs().Add(dir); + } + @Override public void DeleteDir(Io_url url) { + FetchDir(url); // force creation if exists? + dirs.Del(url); + IoItmDir ownerDir = FetchDir(url.OwnerDir()); if (ownerDir == null) return; // no ownerDir; no need to unregister + ownerDir.SubDirs().Del(url); + } + @Override public void XferDir(IoEngine_xrg_xferDir args) {Io_url trg = args.Trg(); utl.XferDir(this, args.Src(), IoEnginePool._.Get_by(trg.Info().EngineKey()), trg, args);} + @Override public void MoveDirDeep(IoEngine_xrg_xferDir args) {Io_url trg = args.Trg(); utl.XferDir(this, args.Src(), IoEnginePool._.Get_by(trg.Info().EngineKey()), trg, args);} + @Override public void MoveDir(Io_url src, Io_url trg) {if (ExistsDir(trg)) throw Exc_.new_("trg already exists", "trg", trg); + IoItmDir dir = FetchDir(src); dir.Name_(trg.NameAndExt()); + for (Object filObj : dir.SubFils()) { // move all subFiles + IoItmFil fil = (IoItmFil)filObj; + fil.OwnerDir_set(dir); + } + dirs.Add(dir); + DeleteDir(src); + } + @Override public IoItmDir QueryDir(Io_url url) { + IoItmDir dir = FetchDir(url); + IoItmDir rv = IoItmDir_.top_(url); // always return copy b/c caller may add/del itms directly + if (dir == null) { + rv.Exists_set(false); + return rv; + } + for (Object subDirObj : dir.SubDirs()) { + IoItmDir subDir = (IoItmDir)subDirObj; + rv.SubDirs().Add(IoItmDir_.scan_(subDir.Url())); + } + for (Object subFilObj : dir.SubFils()) { + IoItmFil subFil = (IoItmFil)subFilObj; + rv.SubFils().Add(subFil); + } + return rv; + } + @Override public void DeleteDirDeep(IoEngine_xrg_deleteDir args) {utl.DeleteDirDeep(this, args.Url(), args);} + @Override public void CopyDir(Io_url src, Io_url trg) { + IoEngine_xrg_xferDir.copy_(src, trg).Recur_().Exec(); + } + void AddFilToDir(Io_url dirPath, IoItmFil fil) { + IoItmDir dir = FetchDir(dirPath); + if (dir == null) { + CreateDir(dirPath); + dir = FetchDir(dirPath); + } + dir.SubFils().Del(fil.Url()); + dir.SubFils().Add(fil); + } + IoItmDir FetchDir(Io_url url) {return IoItmDir_.as_(dirs.Get_by(url));} + IoItmFil_mem FetchFil(Io_url url) { + IoItmDir ownerDir = FetchDir(url.OwnerDir()); + if (ownerDir == null) return IoItmFil_mem.Null; + IoItmFil_mem rv = IoItmFil_mem.as_(ownerDir.SubFils().Get_by(url.NameAndExt())); + if (rv == null) rv = IoItmFil_mem.Null; + return rv; + } + void CheckTransferArgs(String op, Io_url src, Io_url trg, boolean overwrite) { + if (!ExistsFil_api(src)) throw Exc_.new_("src does not exist", "src", src); + if (ExistsFil_api(trg) && !overwrite) throw Exc_.new_invalid_op("trg already exists").Args_add("op", op, "overwrite", false, "src", src, "trg", trg); + } + public void Clear() {dirs.Clear();} + @Override public boolean DownloadFil(IoEngine_xrg_downloadFil xrg) { + Io_url src = Io_url_.mem_fil_(xrg.Src()); + if (!ExistsFil_api(src)) { + xrg.Rslt_(IoEngine_xrg_downloadFil.Rslt_fail_file_not_found); + return false; + } + XferFil(IoEngine_xrg_xferFil.copy_(src, xrg.Trg()).Overwrite_()); + return true; + } + @Override public Io_stream_rdr DownloadFil_as_rdr(IoEngine_xrg_downloadFil xrg) { + Io_url src = Io_url_.mem_fil_(xrg.Src()); + if (!ExistsFil_api(src)) { + xrg.Rslt_(IoEngine_xrg_downloadFil.Rslt_fail_file_not_found); + return Io_stream_rdr_.Noop; + } + byte[] bry = Bry_.new_u8(FetchFil(Io_url_.mem_fil_(xrg.Src())).Text()); + return Io_stream_rdr_.mem_(bry); + } + IoItmHash dirs = IoItmHash.new_(); + IoEngineUtl utl = IoEngineUtl.new_(); + @gplx.Internal protected static IoEngine_memory new_(String key) { + IoEngine_memory rv = new IoEngine_memory(); + rv.key = key; + return rv; + } IoEngine_memory() {} +} diff --git a/100_core/src_200_io/gplx/ios/IoEngine_system.java b/100_core/src_200_io/gplx/ios/IoEngine_system.java new file mode 100644 index 000000000..813e41a0e --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoEngine_system.java @@ -0,0 +1,636 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLEncoder; +import java.nio.*; +import java.nio.channels.*; +import java.util.Date; + +import javax.print.FlavorException; +import javax.tools.JavaCompiler; +import gplx.core.criterias.*; +public class IoEngine_system extends IoEngine_base { + @Override public String Key() {return IoEngine_.SysKey;} + @Override public void DeleteDirDeep(IoEngine_xrg_deleteDir args) {utl.DeleteDirDeep(this, args.Url(), args);} + @Override public void XferDir(IoEngine_xrg_xferDir args) {Io_url trg = args.Trg(); utl.XferDir(this, args.Src(), IoEnginePool._.Get_by(trg.Info().EngineKey()), trg, args);} + @Override public void XferFil(IoEngine_xrg_xferFil args) {utl.XferFil(this, args);} + @Override public IoItmDir QueryDirDeep(IoEngine_xrg_queryDir args) {return utl.QueryDirDeep(this, args);} + @Override public void CopyDir(Io_url src, Io_url trg) {IoEngine_xrg_xferDir.copy_(src, trg).Recur_().Exec();} + @Override public void MoveDirDeep(IoEngine_xrg_xferDir args) {Io_url trg = args.Trg(); utl.XferDir(this, args.Src(), IoEnginePool._.Get_by(trg.Info().EngineKey()), trg, args);} + @Override public void DeleteFil_api(IoEngine_xrg_deleteFil args) { + Io_url url = args.Url(); + File fil = Fil_(url); + if (!Fil_Exists(fil)) return; + MarkFileWritable(fil, url, args.ReadOnlyFails(), "DeleteFile"); + DeleteFil_lang(fil, url); + } + @Override public boolean ExistsFil_api(Io_url url) { + File f = new File(url.Xto_api()); + return f.exists(); + } + @Override public void SaveFilText_api(IoEngine_xrg_saveFilStr mpo) { + Io_url url = mpo.Url(); + + // encode string + byte[] textBytes = null; + textBytes = Bry_.new_u8(mpo.Text()); + + FileChannel fc = null; FileOutputStream fos = null; + if (!ExistsDir(url.OwnerDir())) CreateDir(url.OwnerDir()); + try { + // open file + try {fos = new FileOutputStream(url.Xto_api(), mpo.Append());} + catch (FileNotFoundException e) {throw Err_Fil_NotFound(e, url);} + fc = fos.getChannel(); + + // write text + try {fc.write(ByteBuffer.wrap(textBytes));} + catch (IOException e) { + Closeable_close(fc, url, false); + Closeable_close(fos, url, false); + throw Exc_.new_exc(e, "io", "write data to file failed", "url", url.Xto_api()); + } + if (!Op_sys.Cur().Tid_is_drd()) { + File fil = new File(url.Xto_api()); + IoEngine_system_xtn.SetExecutable(fil, true); + } + } + finally { + // cleanup + Closeable_close(fc, url, false); + Closeable_close(fos, url, false); + } + } + @Override public String LoadFilStr(IoEngine_xrg_loadFilStr args) { + Io_url url = args.Url(); String url_str = url.Xto_api(); + boolean file_exists = ExistsFil_api(url); // check if file exists first to avoid throwing exception; note that most callers pass Missing_ignored; DATE:2015-02-24 + if (!file_exists) { + if (args.MissingIgnored()) return ""; + else throw Err_Fil_NotFound(url); + } + // get reader for file + InputStream stream = null; + try {stream = new FileInputStream(url_str);} + catch (FileNotFoundException e) { + if (args.MissingIgnored()) return ""; + throw Err_Fil_NotFound(e, url); + } + return Load_from_stream_as_str(stream, url_str); + } + @SuppressWarnings("resource") public static String Load_from_stream_as_str(InputStream stream, String url_str) { + InputStreamReader reader = null; + try {reader = new InputStreamReader(stream, IoEngineArgs._.LoadFilStr_Encoding);} + catch (UnsupportedEncodingException e) { + Closeable_close(stream, url_str, false); + throw Err_text_unsupported_encoding(IoEngineArgs._.LoadFilStr_Encoding, "", url_str, e); + } + + // make other objects + char[] readerBuffer = new char[IoEngineArgs._.LoadFilStr_BufferSize]; + int pos = 0; + StringWriter sw = new StringWriter(); + + // transfer data + while (true) { + try {pos = reader.read(readerBuffer);} + catch (IOException e) { + try { + stream.close(); + reader.close(); + } + catch (IOException e2) {} + throw Exc_.new_exc(e, "io", "read data from file failed", "url", url_str, "pos", pos); + } + if (pos == -1) break; + sw.write(readerBuffer, 0, pos); + } + + // cleanup + Closeable_close(stream, url_str, false); + Closeable_close(reader, url_str, false); + return sw.toString(); + } + @Override public boolean ExistsDir(Io_url url) {return new File(url.Xto_api()).exists();} + @Override public void CreateDir(Io_url url) {new File(url.Xto_api()).mkdirs();} + @Override public void DeleteDir(Io_url url) { + File dir = new File(url.Xto_api()); + if (!dir.exists()) return; + boolean rv = dir.delete(); + if (!rv) throw Exc_.new_w_type(IoEngineArgs._.Err_IoException, "delete dir failed", "url", url.Xto_api()); + } + @Override public IoItmDir QueryDir(Io_url url) { + IoItmDir rv = IoItmDir_.scan_(url); + File dirInfo = new File(url.Xto_api()); + if (!dirInfo.exists()) { + rv.Exists_set(false); + return rv; + } + IoUrlInfo urlInfo = url.Info(); + File[] subItmAry = dirInfo.listFiles(); + if (subItmAry == null) return rv; // directory has no files + for (int i = 0; i < subItmAry.length; i++) { + File subItm = subItmAry[i]; + if (subItm.isFile()) { + IoItmFil subFil = QueryMkr_fil(urlInfo, subItm); + rv.SubFils().Add(subFil); + } + else { + IoItmDir subDir = QueryMkr_dir(urlInfo, subItm); + rv.SubDirs().Add(subDir); + } + } + return rv; + } + IoItmFil QueryMkr_fil(IoUrlInfo urlInfo, File apiFil) { + Io_url filUrl = Io_url_.new_inf_(apiFil.getPath(), urlInfo); // NOTE: may throw PathTooLongException when url is > 248 (exception messages states 260) + long fil_len = apiFil.exists() ? apiFil.length() : IoItmFil.Size_invalid; // NOTE: if file doesn't exist, set len to -1; needed for "boolean Exists() {return size != Size_Invalid;}"; DATE:2014-06-21 + IoItmFil rv = IoItmFil_.new_(filUrl, fil_len, DateAdp_.MinValue, DateAdp_.unixtime_lcl_ms_(apiFil.lastModified())); + rv.ReadOnly_(!apiFil.canWrite()); + return rv; + } + IoItmDir QueryMkr_dir(IoUrlInfo urlInfo, File apiDir) { + Io_url dirUrl = Io_url_.new_inf_(apiDir.getPath() + urlInfo.DirSpr(), urlInfo); // NOTE: may throw PathTooLongException when url is > 248 (exception messages states 260) + return IoItmDir_.scan_(dirUrl); + } + @Override public IoItmFil QueryFil(Io_url url) { + File fil = new File(url.Xto_api()); + return QueryMkr_fil(url.Info(), fil); + } + @Override public void UpdateFilAttrib(Io_url url, IoItmAttrib atr) { + File f = new File(url.Xto_api()); + boolean rv = true; + if (atr.ReadOnly() != Fil_ReadOnly(f)) { + if (atr.ReadOnly()) + rv = f.setReadOnly(); + else { + if (!Op_sys.Cur().Tid_is_drd()) + IoEngine_system_xtn.SetWritable(f, true); + } + if (!rv) throw Exc_.new_w_type(IoEngineArgs._.Err_IoException, "set file attribute failed", "attribute", "readOnly", "cur", Fil_ReadOnly(f), "new", atr.ReadOnly(), "url", url.Xto_api()); + } + if (atr.Hidden() != f.isHidden()) { + //Runtime.getRuntime().exec("attrib +H myHiddenFile.java"); + } + } + @Override public void UpdateFilModifiedTime(Io_url url, DateAdp modified) { + File f = new File(url.Xto_api()); + long timeInt = modified.UnderDateTime().getTimeInMillis(); +// if (timeInt < 0) { +// UsrDlg_._.Notify("{0} {1}", url.Xto_api(), timeInt); +// return; +// } + if (!f.setLastModified(timeInt)) { + if (Fil_ReadOnly(f)) { + boolean success = false; + try { + UpdateFilAttrib(url, IoItmAttrib.normal_()); + success = f.setLastModified(timeInt); + } + finally { + UpdateFilAttrib(url, IoItmAttrib.readOnly_()); + } + if (!success) throw Exc_.new_("could not update file modified time", "url", url.Xto_api(), "modifiedTime", modified.XtoStr_gplx_long()); + } + } + } + @Override public IoStream OpenStreamRead(Io_url url) {return IoStream_base.new_(url, IoStream_.Mode_rdr);} + @Override public IoStream OpenStreamWrite(IoEngine_xrg_openWrite args) { + Io_url url = args.Url(); + if (!ExistsFil_api(url)) SaveFilText_api(IoEngine_xrg_saveFilStr.new_(url, "")); + return IoStream_base.new_(url, args.Mode()); + } + @SuppressWarnings("resource") + @Override public void CopyFil(IoEngine_xrg_xferFil args) { + // TODO:JAVA6 hidden property ignored; 1.6 does not allow OS-independent way of setting isHidden (wnt only possible through jni) + boolean overwrite = args.Overwrite(); + Io_url srcUrl = args.Src(), trgUrl = args.Trg(); + File srcFil = new File(srcUrl.Xto_api()), trgFil = new File(trgUrl.Xto_api()); + if (trgFil.isFile()) { // trgFil exists; check if overwrite set and trgFil is writable + Chk_TrgFil_Overwrite(overwrite, trgUrl); + MarkFileWritable(trgFil, trgUrl, args.ReadOnlyFails(), "copy"); + } + else { // trgFil doesn't exist; must create file first else fileNotFound exception thrown +// if (overwrite) throw Err_ + boolean rv = true; //Exception exc = null; + if (!ExistsDir(trgUrl.OwnerDir())) CreateDir(trgUrl.OwnerDir()); + try { + trgFil.createNewFile(); + if (!Op_sys.Cur().Tid_is_drd()) + IoEngine_system_xtn.SetExecutable(trgFil, true); + } + catch (IOException e) { +// exc = e; + rv = false; + } + if (!rv) + throw Exc_.new_("create file failed", "trg", trgUrl.Xto_api()); + } + FileInputStream srcStream = null; FileOutputStream trgStream = null; + FileChannel srcChannel = null, trgChannel = null; + try { + // make objects + try {srcStream = new FileInputStream(srcFil);} + catch (FileNotFoundException e) {throw IoErr.FileNotFound("copy", srcUrl);} + try {trgStream = new FileOutputStream(trgFil);} + catch (FileNotFoundException e) { + trgStream = TryToUnHideFile(trgFil, trgUrl); + if (trgStream == null) + throw IoErr.FileNotFound("copy", trgUrl); +// else +// wasHidden = true; + } + srcChannel = srcStream.getChannel(); + trgChannel = trgStream.getChannel(); + + // transfer data + long pos = 0, count = 0, read = 0; + try {count = srcChannel.size();} + catch (IOException e) {throw Exc_.new_exc(e, "io", "size failed", "src", srcUrl.Xto_api());} + int totalBufferSize = IoEngineArgs._.LoadFilStr_BufferSize; + long transferSize = (count > totalBufferSize) ? totalBufferSize : count; // transfer as much as fileSize, but limit to LoadFilStr_BufferSize + while (pos < count) { + try {read = trgChannel.transferFrom(srcChannel, pos, transferSize);} + catch (IOException e) { + Closeable_close(srcChannel, srcUrl, false); + Closeable_close(trgChannel, trgUrl, false); + Closeable_close(srcStream, srcUrl, false); + Closeable_close(trgStream, srcUrl, false); + throw Exc_.new_exc(e, "io", "transfer data failed", "src", srcUrl.Xto_api(), "trg", trgUrl.Xto_api()); + } + if (read == -1) break; + pos += read; + } +// if (wasHidden) +// + } + finally { + // cleanup + Closeable_close(srcChannel, srcUrl, false); + Closeable_close(trgChannel, trgUrl, false); + Closeable_close(srcStream, srcUrl, false); + Closeable_close(trgStream, srcUrl, false); + } + UpdateFilModifiedTime(trgUrl, QueryFil(srcUrl).ModifiedTime()); // must happen after file is closed + } + FileOutputStream TryToUnHideFile(File trgFil, Io_url trgUrl) { + FileOutputStream trgStream = null; + if (trgFil.exists()) { // WORKAROUND: java fails when writing to hidden files; unmark hidden and try again + Process p = null; + try { + String d = "attrib -H \"" + trgUrl.Xto_api() + "\""; + p = Runtime.getRuntime().exec(d); + } catch (IOException e1) { + e1.printStackTrace(); + } + try { + p.waitFor(); + } catch (InterruptedException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + try {trgStream = new FileOutputStream(trgFil);} + catch (FileNotFoundException e) { + return null; + } + } + return trgStream; + } + @Override public void MoveFil(IoEngine_xrg_xferFil args) { + Io_url srcUrl = args.Src(), trgUrl = args.Trg(); + String src_api = srcUrl.Xto_api(), trg_api = trgUrl.Xto_api(); + if (String_.Eq(src_api, trg_api)) return; // ignore command if src and trg is same; EX: C:\a.txt -> C:\a.txt should be noop + File srcFil = new File(src_api), trgFil = new File(trg_api); + + // if drive is same, then rename file + if (String_.Eq(srcUrl.OwnerRoot().Raw(), trgUrl.OwnerRoot().Raw())) { + boolean overwrite = args.Overwrite(); + if (!srcFil.exists() && args.MissingFails()) throw IoErr.FileNotFound("move", srcUrl); + if (trgFil.exists()) { + Chk_TrgFil_Overwrite(overwrite, trgUrl); + MarkFileWritable(trgFil, trgUrl, args.ReadOnlyFails(), "move"); + DeleteFil_lang(trgFil, args.Trg()); // overwrite is specified and file is writable -> delete + } + if (!ExistsDir(trgUrl.OwnerDir())) CreateDir(trgUrl.OwnerDir()); + srcFil.renameTo(trgFil); + } + // else copy fil and delete + else { + if (!srcFil.exists() && !args.MissingFails()) return; + CopyFil(args); + DeleteFil_lang(srcFil, srcUrl); + } + } + void Chk_TrgFil_Overwrite(boolean overwrite, Io_url trg) { + if (!overwrite) + throw Exc_.new_invalid_op("trgFile exists but overwriteFlag not set").Args_add("trg", trg.Xto_api()); + } + @Override public void MoveDir(Io_url src, Io_url trg) { + String srcStr = src.Xto_api(), trgStr = trg.Xto_api(); + File srcFil = new File(srcStr), trgFil = new File(trgStr); + if (trgFil.exists()) {throw Exc_.new_invalid_op("cannot move dir if trg exists").Args_add("src", src, "trg", trg);} + if (String_.Eq(src.OwnerRoot().Raw(), trg.OwnerRoot().Raw())) { + srcFil.renameTo(trgFil); + } + else { + XferDir(IoEngine_xrg_xferDir.copy_(src, trg)); + } + } + protected static void Closeable_close(Closeable closeable, Io_url url, boolean throwErr) {Closeable_close(closeable, url.Xto_api(), throwErr);} + protected static void Closeable_close(Closeable closeable, String url_str, boolean throwErr) { + if (closeable == null) return; + try {closeable.close();} + catch (IOException e) { + if (throwErr) + throw Exc_.new_exc(e, "io", "close object failed", "class", ClassAdp_.NameOf_obj(closeable), "url", url_str); +// else +// UsrDlg_._.Finally("failed to close FileChannel", "url", url, "apiErr", Err_.Message_err_arg(e)); + } + } + + File Fil_(Io_url url) {return new File(url.Xto_api());} + boolean Fil_Exists(File fil) {return fil.exists();} + boolean Fil_ReadOnly(File fil) {return !fil.canWrite();} + boolean Fil_Delete(File fil) {return fil.delete();} + void Fil_Writable(File fil) { + if (!Op_sys.Cur().Tid_is_drd()) + IoEngine_system_xtn.SetWritable(fil, true); + } + private static Exc Err_text_unsupported_encoding(String encodingName, String text, String url_str, Exception e) { + return Exc_.new_exc(e, "io", "text is in unsupported encoding").Args_add("encodingName", encodingName, "text", text, "url", url_str); + } + boolean user_agent_needs_resetting = true; + @Override public Io_stream_rdr DownloadFil_as_rdr(IoEngine_xrg_downloadFil xrg) { + Io_stream_rdr_http rdr = new Io_stream_rdr_http(xrg); + rdr.Open(); + return rdr; + } + @Override public boolean DownloadFil(IoEngine_xrg_downloadFil xrg) { + IoStream trg_stream = null; + java.io.BufferedInputStream src_stream = null; + java.net.URL src_url = null; + HttpURLConnection src_conn = null; + if (user_agent_needs_resetting) {user_agent_needs_resetting = false; System.setProperty("http.agent", "");} + boolean exists = Io_mgr.I.ExistsDir(xrg.Trg().OwnerDir()); + Gfo_usr_dlg prog_dlg = null; + String src_str = xrg.Src(); + Io_download_fmt xfer_fmt = xrg.Download_fmt(); + prog_dlg = xfer_fmt.Usr_dlg(); + if (!Web_access_enabled) { + if (prog_dlg != null) { + if (session_fil == null) session_fil = prog_dlg.Log_wkr().Session_dir().GenSubFil("internet.txt"); + prog_dlg.Log_wkr().Log_msg_to_url_fmt(session_fil, "download disabled: src='~{0}' trg='~{1}'", xrg.Src(), xrg.Trg().Raw()); + } + return false; + } + try { + trg_stream = Io_mgr.I.OpenStreamWrite(xrg.Trg()); + src_url = new java.net.URL(src_str); + src_conn = (HttpURLConnection)src_url.openConnection(); +// src_conn.setReadTimeout(5000); // do not set; if file does not exist, will wait 5 seconds before timing out; want to fail immediately + String user_agent = xrg.User_agent(); if (user_agent != null) src_conn.setRequestProperty("User-Agent", user_agent); + long content_length = Long_.parse_or_(src_conn.getHeaderField("Content-Length"), IoItmFil.Size_invalid_int); + xrg.Src_content_length_(content_length); + if (xrg.Src_last_modified_query()) // NOTE: only files will have last modified (api calls will not); if no last_modified, then src_conn will throw get nullRef; avoid nullRef + xrg.Src_last_modified_(DateAdp_.unixtime_lcl_ms_(src_conn.getLastModified())); + if (xrg.Exec_meta_only()) return true; + src_stream = new java.io.BufferedInputStream(src_conn.getInputStream()); + if (!exists) { + Io_mgr.I.CreateDir(xrg.Trg().OwnerDir()); // dir must exist for OpenStreamWrite; create dir at last possible moment in case stream does not exist. + } + byte[] download_bfr = new byte[Download_bfr_len]; // NOTE: download_bfr was originally member variable; DATE:2013-05-03 + xfer_fmt.Bgn(content_length); + int count = 0; + while ((count = src_stream.read(download_bfr, 0, Download_bfr_len)) != -1) { + if (xrg.Prog_cancel()) { + src_stream.close(); + trg_stream.Rls(); + Io_mgr.I.DeleteFil(xrg.Trg()); + } + xfer_fmt.Prog(count); + trg_stream.Write(download_bfr, 0, count); + } + if (prog_dlg != null) { + xfer_fmt.Term(); + if (session_fil == null) session_fil = prog_dlg.Log_wkr().Session_dir().GenSubFil("internet.txt"); + prog_dlg.Log_wkr().Log_msg_to_url_fmt(session_fil, "download pass: src='~{0}' trg='~{1}'", src_str, xrg.Trg().Raw()); + } + return true; + } + catch (Exception exc) { + xrg.Rslt_err_(exc); + if (ClassAdp_.Eq_typeSafe(exc, java.net.UnknownHostException.class)) xrg.Rslt_(IoEngine_xrg_downloadFil.Rslt_fail_host_not_found); + else if (ClassAdp_.Eq_typeSafe(exc, java.io.FileNotFoundException.class)) xrg.Rslt_(IoEngine_xrg_downloadFil.Rslt_fail_file_not_found); + else xrg.Rslt_(IoEngine_xrg_downloadFil.Rslt_fail_unknown); + if (prog_dlg != null && !xrg.Prog_cancel()) { + if (session_fil == null) session_fil = prog_dlg.Log_wkr().Session_dir().GenSubFil("internet.txt"); + prog_dlg.Log_wkr().Log_msg_to_url_fmt(session_fil, "download fail: src='~{0}' trg='~{1}' error='~{2}'", src_str, xrg.Trg().Raw(), Err_.Message_lang(exc)); + } + if (trg_stream != null) { + try { + trg_stream.Rls(); + DeleteFil_api(IoEngine_xrg_deleteFil.new_(xrg.Trg())); + } + catch (Exception e2) {Exc_.Noop(e2);} + } + return false; + } + finally { + xrg.Prog_running_(false); + try { + if (src_stream != null) src_stream.close(); + if (src_conn != null) src_conn.disconnect(); + src_conn.getInputStream().close(); + } catch (Exception exc) { + Exc_.Noop(exc); + } + if (trg_stream != null) trg_stream.Rls(); + } + } Io_url session_fil; Bry_bfr prog_fmt_bfr; + byte[] download_bfr; static final int Download_bfr_len = Io_mgr.Len_kb * 128; + public static Exc Err_Fil_NotFound(Io_url url) { + return Exc_.new_w_type(IoEngineArgs._.Err_FileNotFound, "file not found", "url", url.Xto_api()).Stack_erase_1_(); + } + public static Exc Err_Fil_NotFound(Exception e, Io_url url) { + return Exc_.new_exc(e, "io", "file not found", "url", url.Xto_api()).Stack_erase_1_(); + } + void MarkFileWritable(File fil, Io_url url, boolean readOnlyFails, String op) { + if (Fil_ReadOnly(fil)) { + if (readOnlyFails) // NOTE: java will always allow final files to be deleted; programmer api is responsible for check + throw Exc_.new_w_type(IoEngineArgs._.Err_ReadonlyFileNotWritable, "writable operation attempted on readOnly file", "op", op, "url", url.Xto_api()); + else + Fil_Writable(fil); + } + } + void DeleteFil_lang(File fil, Io_url url) { + boolean rv = Fil_Delete(fil); + if (!rv) + throw Exc_.new_w_type(IoEngineArgs._.Err_IoException, "file not deleted", "url", url.Xto_api()); + } + IoEngineUtl utl = IoEngineUtl.new_(); + public static IoEngine_system new_() {return new IoEngine_system();} IoEngine_system() {} + static final String GRP_KEY = "Io_engine"; + public static boolean Web_access_enabled = true; +} +class IoEngineArgs { + public int LoadFilStr_BufferSize = 4096 * 256; + public String LoadFilStr_Encoding = "UTF-8"; + public String Err_ReadonlyFileNotWritable = "gplx.ios.ReadonlyFileNotWritable"; + public String Err_FileNotFound = "gplx.ios.FileNotFound"; + public String Err_IoException = "gplx.ios.IoException"; + public static final IoEngineArgs _ = new IoEngineArgs(); +} +class IoEngine_system_xtn { + // PATCH.DROID:VerifyError if file.setExecutable is referenced directly in IoEngine_system. However, if placed in separate class + public static void SetExecutable(java.io.File file, boolean v) {file.setExecutable(v);} + public static void SetWritable(java.io.File file, boolean v) {file.setWritable(v);} +} +class Io_download_http { + public static boolean User_agent_reset_needed = true; + public static void User_agent_reset() { + User_agent_reset_needed = false; + System.setProperty("http.agent", ""); // need to set http.agent to '' in order for "User-agent" to take effect + } + public static void Save_to_fsys(IoEngine_xrg_downloadFil xrg) { + Io_stream_rdr_http rdr = new Io_stream_rdr_http(xrg); + IoStream trg_stream = null; + try { + boolean exists = Io_mgr.I.ExistsDir(xrg.Trg().OwnerDir()); + if (!exists) + Io_mgr.I.CreateDir(xrg.Trg().OwnerDir()); // dir must exist for OpenStreamWrite; create dir at last possible moment in case stream does not exist. + trg_stream = Io_mgr.I.OpenStreamWrite(xrg.Trg()); + byte[] bfr = new byte[Download_bfr_len]; + rdr.Open(); + while (rdr.Read(bfr, 0, Download_bfr_len) != Read_done) { + } + } + finally { + rdr.Rls(); + if (trg_stream != null) trg_stream.Rls(); + } + if (xrg.Rslt() != IoEngine_xrg_downloadFil.Rslt_pass) + Io_mgr.I.DeleteFil_args(xrg.Trg()).MissingFails_off().Exec(); + } + public static final int Read_done = -1; + public static final int Download_bfr_len = Io_mgr.Len_kb * 128; +} +class Io_stream_rdr_http implements Io_stream_rdr { + public Io_stream_rdr_http(IoEngine_xrg_downloadFil xrg) { + this.xrg = xrg; + } private IoEngine_xrg_downloadFil xrg; + public byte Tid() {return Io_stream_.Tid_raw;} + public boolean Exists() {return exists;} private boolean exists = false; + public Io_url Url() {return url;} public Io_stream_rdr Url_(Io_url v) {url = v; return this;} private Io_url url; + public long Len() {return len;} public Io_stream_rdr Len_(long v) {len = v; return this;} private long len = IoItmFil.Size_invalid; // NOTE: must default size to -1; DATE:2014-06-21 + private String src_str; private HttpURLConnection src_conn; private java.io.BufferedInputStream src_stream; + private Io_download_fmt xfer_fmt; private Gfo_usr_dlg prog_dlg; + private boolean read_done = true, read_failed = false; + public Io_stream_rdr Open() { + if (Io_download_http.User_agent_reset_needed) Io_download_http.User_agent_reset(); + if (!IoEngine_system.Web_access_enabled) { + read_done = read_failed = true; + if (prog_dlg != null) + prog_dlg.Log_wkr().Log_msg_to_url_fmt(session_fil, "download disabled: src='~{0}' trg='~{1}'", xrg.Src(), xrg.Trg().Raw()); + return this; + } + src_str = xrg.Src(); + xfer_fmt = xrg.Download_fmt(); prog_dlg = xfer_fmt.Usr_dlg(); + try { + src_conn = (HttpURLConnection)new java.net.URL(src_str).openConnection(); + String user_agent = xrg.User_agent(); + if (user_agent != null) src_conn.setRequestProperty("User-Agent", user_agent); // NOTE: must be set right after openConnection +// src_conn.setReadTimeout(5000); // do not set; if file does not exist, will wait 5 seconds before timing out; want to fail immediately + long content_length = Long_.parse_or_(src_conn.getHeaderField("Content-Length"), IoItmFil.Size_invalid_int); + xrg.Src_content_length_(content_length); + this.len = content_length; + if (xrg.Src_last_modified_query()) // NOTE: only files will have last modified (api calls will not); if no last_modified, then src_conn will throw get nullRef; avoid nullRef + xrg.Src_last_modified_(DateAdp_.unixtime_lcl_ms_(src_conn.getLastModified())); + if (xrg.Exec_meta_only()) { + read_done = true; + return this; + } + read_done = false; + this.exists = Int_.In(src_conn.getResponseCode(), 200, 301); // ASSUME: response code of 200 (OK) or 301 (Redirect) means that file exists; note that content_length seems to always be -1; DATE:2015-05-20 + src_stream = new java.io.BufferedInputStream(src_conn.getInputStream()); + xfer_fmt.Bgn(content_length); + } + catch (Exception e) {Err_handle(e);} + return this; + } + public void Open_mem(byte[] v) {} + public Object Under() {return src_stream;} + public int Read(byte[] bry, int bgn, int len) { + if (read_done) return Io_download_http.Read_done; + if (xrg.Prog_cancel()) {read_failed = true; return Io_download_http.Read_done;} + try { + int read = src_stream.read(bry, bgn, len); + xfer_fmt.Prog(read); + return read; + } + catch (Exception e) { + Err_handle(e); + return Io_download_http.Read_done; + } + } + private Io_url session_fil = null; + private boolean rls_done = false; + public long Skip(long len) {return 0;} + public void Rls() { + if (rls_done) return; + try { + read_done = true; + if (prog_dlg != null) { + xfer_fmt.Term(); + } + if (session_fil == null && prog_dlg != null) session_fil = prog_dlg.Log_wkr().Session_dir().GenSubFil("internet.txt"); + if (read_failed) { + } + else { + if (prog_dlg != null) + prog_dlg.Log_wkr().Log_msg_to_url_fmt(session_fil, "download pass: src='~{0}' trg='~{1}'", src_str, xrg.Trg().Raw()); + xrg.Rslt_(IoEngine_xrg_downloadFil.Rslt_pass); + } + xrg.Prog_running_(false); + } + catch (Exception e) {Exc_.Noop(e);} // ignore close errors; also Err_handle calls Rls() so it would be circular + finally { + try {if (src_stream != null) src_stream.close();} + catch (Exception e) {Exc_.Noop(e);} // ignore failures when cleaning up + if (src_conn != null) src_conn.disconnect(); + src_stream = null; + src_conn = null; + rls_done = true; + } + } + private void Err_handle(Exception exc) { + read_done = read_failed = true; + len = -1; + xrg.Rslt_err_(exc); + if (ClassAdp_.Eq_typeSafe(exc, java.net.UnknownHostException.class)) xrg.Rslt_(IoEngine_xrg_downloadFil.Rslt_fail_host_not_found); + else if (ClassAdp_.Eq_typeSafe(exc, java.io.FileNotFoundException.class)) xrg.Rslt_(IoEngine_xrg_downloadFil.Rslt_fail_file_not_found); + else xrg.Rslt_(IoEngine_xrg_downloadFil.Rslt_fail_unknown); + if (prog_dlg != null && !xrg.Prog_cancel()) { + if (session_fil == null) session_fil = prog_dlg.Log_wkr().Session_dir().GenSubFil("internet.txt"); + prog_dlg.Log_wkr().Log_msg_to_url_fmt(session_fil, "download fail: src='~{0}' trg='~{1}' error='~{2}'", src_str, xrg.Trg().Raw(), Err_.Message_lang(exc)); + } + this.Rls(); + } +} diff --git a/100_core/src_200_io/gplx/ios/IoEngine_xrg_deleteDir.java b/100_core/src_200_io/gplx/ios/IoEngine_xrg_deleteDir.java new file mode 100644 index 000000000..02ec8b540 --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoEngine_xrg_deleteDir.java @@ -0,0 +1,34 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import gplx.core.criterias.*; +public class IoEngine_xrg_deleteDir { + public Io_url Url() {return url;} public IoEngine_xrg_deleteDir Url_(Io_url val) {url = val; return this;} Io_url url; + public boolean Recur() {return recur;} public IoEngine_xrg_deleteDir Recur_() {return Recur_(true);} public IoEngine_xrg_deleteDir Recur_(boolean v) {recur = v; return this;} private boolean recur = false; + public boolean ReadOnlyFails() {return readOnlyFails;} public IoEngine_xrg_deleteDir ReadOnlyFails_off() {return ReadOnlyFails_(false);} public IoEngine_xrg_deleteDir ReadOnlyFails_(boolean v) {readOnlyFails = v; return this;} private boolean readOnlyFails = true; + public boolean MissingIgnored() {return missingIgnored;} public IoEngine_xrg_deleteDir MissingIgnored_() {return MissingIgnored_(true);} public IoEngine_xrg_deleteDir MissingIgnored_(boolean v) {missingIgnored = v; return this;} private boolean missingIgnored = true; + public Criteria MatchCrt() {return matchCrt;} public IoEngine_xrg_deleteDir MatchCrt_(Criteria v) {matchCrt = v; return this;} Criteria matchCrt = Criteria_.All; + public Criteria SubDirScanCrt() {return subDirScanCrt;} public IoEngine_xrg_deleteDir SubDirScanCrt_(Criteria v) {subDirScanCrt = v; return this;} Criteria subDirScanCrt = Criteria_.All; + public ConsoleDlg UsrDlg() {return usrDlg;} public IoEngine_xrg_deleteDir UsrDlg_(ConsoleDlg v) {usrDlg = v; return this;} ConsoleDlg usrDlg = ConsoleDlg_.Null; + public void Exec() {IoEnginePool._.Get_by(url.Info().EngineKey()).DeleteDirDeep(this);} + public static IoEngine_xrg_deleteDir new_(Io_url url) { + IoEngine_xrg_deleteDir rv = new IoEngine_xrg_deleteDir(); + rv.url = url; + return rv; + } IoEngine_xrg_deleteDir() {} +} diff --git a/100_core/src_200_io/gplx/ios/IoEngine_xrg_deleteFil.java b/100_core/src_200_io/gplx/ios/IoEngine_xrg_deleteFil.java new file mode 100644 index 000000000..3f1a7e47b --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoEngine_xrg_deleteFil.java @@ -0,0 +1,30 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +public class IoEngine_xrg_deleteFil extends IoEngine_xrg_fil_affects1_base { + @gplx.New public IoEngine_xrg_deleteFil Url_(Io_url val) {Url_set(val); return this;} + public IoEngine_xrg_deleteFil ReadOnlyFails_off() {return ReadOnlyFails_(false);} public IoEngine_xrg_deleteFil ReadOnlyFails_(boolean v) {ReadOnlyFails_set(v); return this;} + public IoEngine_xrg_deleteFil MissingFails_off() {return MissingFails_(false);} public IoEngine_xrg_deleteFil MissingFails_(boolean v) {MissingFails_set(v); return this;} + @Override public void Exec() {IoEnginePool._.Get_by(this.Url().Info().EngineKey()).DeleteFil_api(this);} + public static IoEngine_xrg_deleteFil proto_() {return new IoEngine_xrg_deleteFil();} + public static IoEngine_xrg_deleteFil new_(Io_url url) { + IoEngine_xrg_deleteFil rv = new IoEngine_xrg_deleteFil(); + rv.Url_set(url); + return rv; + } IoEngine_xrg_deleteFil() {} +} diff --git a/100_core/src_200_io/gplx/ios/IoEngine_xrg_downloadFil.java b/100_core/src_200_io/gplx/ios/IoEngine_xrg_downloadFil.java new file mode 100644 index 000000000..b591e740f --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoEngine_xrg_downloadFil.java @@ -0,0 +1,69 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +public class IoEngine_xrg_downloadFil { + public String Src() {return src;} public IoEngine_xrg_downloadFil Src_(String v) {src = v; return this;} private String src; + public Io_url Trg() {return trg;} public IoEngine_xrg_downloadFil Trg_(Io_url v) {trg = v; return this;} private Io_url trg; + public byte Rslt() {return rslt;} public IoEngine_xrg_downloadFil Rslt_(byte v) {rslt = v; return this;} private byte rslt = Rslt_pass; + public Exception Rslt_err() {return rslt_err;} public IoEngine_xrg_downloadFil Rslt_err_(Exception v) {rslt_err = v; return this;} private Exception rslt_err; + public String Rslt_err_str() { + return rslt_err == null ? "none" : Err_.Message_gplx_brief(rslt_err); + } + public String User_agent() {return user_agent;} public IoEngine_xrg_downloadFil User_agent_(String v) {user_agent = v; return this;} private String user_agent; + public Gfo_usr_dlg Prog_dlg() {return prog_dlg;} public IoEngine_xrg_downloadFil Prog_dlg_(Gfo_usr_dlg v) {prog_dlg = v; download_fmt.Ctor(prog_dlg); return this;} private Gfo_usr_dlg prog_dlg; + public Bry_fmtr Prog_fmtr() {return prog_fmtr;} private final Bry_fmtr prog_fmtr = Bry_fmtr.new_("~{download_header}: ~{download_read} of ~{download_length} kb;", "download_header", "download_url", "download_read", "download_length"); + public String Prog_fmt_hdr() {return prog_fmt_hdr;} public IoEngine_xrg_downloadFil Prog_fmt_hdr_(String v) {prog_fmt_hdr = v; return this;} private String prog_fmt_hdr = ""; // NOTE: must init to "", else null ref when building String + public boolean Prog_cancel() {return prog_cancel;} public IoEngine_xrg_downloadFil Prog_cancel_y_() {prog_cancel = true; return this;} private volatile boolean prog_cancel; + public boolean Prog_running() {return prog_running;} public IoEngine_xrg_downloadFil Prog_running_(boolean v) {prog_running = v; return this;} private boolean prog_running; + public long Src_content_length() {return src_content_length;} public IoEngine_xrg_downloadFil Src_content_length_(long v) {src_content_length = v; return this;} private long src_content_length; + public DateAdp Src_last_modified() {return src_last_modified;} public IoEngine_xrg_downloadFil Src_last_modified_(DateAdp v) {src_last_modified = v; return this;} private DateAdp src_last_modified; + public boolean Src_last_modified_query() {return src_last_modified_query;} public IoEngine_xrg_downloadFil Src_last_modified_query_(boolean v) {src_last_modified_query = v; return this;} private boolean src_last_modified_query; + public String Trg_engine_key() {return trg_engine_key;} public IoEngine_xrg_downloadFil Trg_engine_key_(String v) {trg_engine_key = v; return this;} private String trg_engine_key = IoEngine_.SysKey; + public Io_download_fmt Download_fmt() {return download_fmt;} private final Io_download_fmt download_fmt = new Io_download_fmt(); + public boolean Exec() {return IoEnginePool._.Get_by(trg.Info().EngineKey()).DownloadFil(this);} + public Io_stream_rdr Exec_as_rdr() {return IoEnginePool._.Get_by(IoEngine_.SysKey).DownloadFil_as_rdr(this);} + public boolean Exec_meta_only() {return exec_meta_only;} private boolean exec_meta_only; + public byte[] Exec_as_bry(String src) { + this.Src_(src); this.Trg_(trg_mem); + download_fmt.Download_init(src, prog_fmt_hdr); // NOTE: must set src else NULL error + boolean pass = IoEnginePool._.Get_by(trg_engine_key).DownloadFil(this); + return pass ? Io_mgr.I.LoadFilBry(trg_mem) : null; + } private Io_url trg_mem = Io_url_.mem_fil_("mem/download.tmp"); + public boolean Exec_meta(String src) { + this.Src_(src); this.Trg_(trg_mem); // NOTE: set Trg_ else error in download proc + download_fmt.Download_init(src, prog_fmt_hdr); // NOTE: must set src else NULL error + exec_meta_only = true; + boolean rv = IoEnginePool._.Get_by(trg_engine_key).DownloadFil(this); + exec_meta_only = false; + return rv; + } + public void Init(String src, Io_url trg) { + this.src = src; this.trg = trg; + prog_cancel = false; + rslt_err = null; + rslt = Rslt_pass; + prog_running = true; + download_fmt.Download_init(src, "downloading ~{src_name}: ~{prog_left} left (@ ~{prog_rate}); ~{prog_done} of ~{src_len} (~{prog_pct}%)"); + } + public static IoEngine_xrg_downloadFil new_(String src, Io_url trg) { + IoEngine_xrg_downloadFil rv = new IoEngine_xrg_downloadFil(); + rv.src = src; rv.trg = trg; + return rv; + } IoEngine_xrg_downloadFil() {} + public static final byte Rslt_pass = 0, Rslt_fail_host_not_found = 1, Rslt_fail_file_not_found = 2, Rslt_fail_unknown = 3; +} diff --git a/100_core/src_200_io/gplx/ios/IoEngine_xrg_fil_affects1_base.java b/100_core/src_200_io/gplx/ios/IoEngine_xrg_fil_affects1_base.java new file mode 100644 index 000000000..0122b645c --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoEngine_xrg_fil_affects1_base.java @@ -0,0 +1,25 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +public class IoEngine_xrg_fil_affects1_base { + public Io_url Url() {return url;} public void Url_set(Io_url v) {url = v;} Io_url url; + public IoEngine_xrg_fil_affects1_base Url_(Io_url v) {url = v; return this;} + public boolean MissingFails() {return missingFails;} public void MissingFails_set(boolean v) {missingFails = v;} private boolean missingFails = true; + public boolean ReadOnlyFails() {return readOnlyFails;} public void ReadOnlyFails_set(boolean v) {readOnlyFails = v;} private boolean readOnlyFails = true; + @gplx.Virtual public void Exec() {} +} diff --git a/100_core/src_200_io/gplx/ios/IoEngine_xrg_loadFilStr.java b/100_core/src_200_io/gplx/ios/IoEngine_xrg_loadFilStr.java new file mode 100644 index 000000000..6abd4552b --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoEngine_xrg_loadFilStr.java @@ -0,0 +1,44 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import gplx.texts.*; +public class IoEngine_xrg_loadFilStr { + public Io_url Url() {return url;} public IoEngine_xrg_loadFilStr Url_(Io_url val) {url = val; return this;} Io_url url; + public boolean MissingIgnored() {return missingIgnored;} public IoEngine_xrg_loadFilStr MissingIgnored_() {return MissingIgnored_(true);} public IoEngine_xrg_loadFilStr MissingIgnored_(boolean v) {missingIgnored = v; return this;} private boolean missingIgnored = false; + public boolean BomUtf8Convert() {return bomUtf8Convert;} public IoEngine_xrg_loadFilStr BomUtf8Convert_(boolean v) {bomUtf8Convert = v; return this;} private boolean bomUtf8Convert = true; + public String Exec() { + String s = IoEnginePool._.Get_by(url.Info().EngineKey()).LoadFilStr(this); + if (bomUtf8Convert && String_.Len(s) > 0 && String_.CodePointAt(s, 0) == Bom_Utf8) { + s = String_.Mid(s, 1); + UsrDlg_._.Warn(UsrMsg.new_("UTF8 BOM removed").Add("url", url.Xto_api())); + } + return s; + } + public String[] ExecAsStrAry() {return String_.Split(Exec(), String_.CrLf);} + public String[] ExecAsStrAryLnx() { + String raw = Exec(); + if (String_.Len(raw) == 0) return String_.Ary_empty; + return String_.Split(raw, Op_sys.Dir_spr_char_lnx, false); + } + int Bom_Utf8 = 65279; // U+FEFF; see http://en.wikipedia.org/wiki/Byte_order_mark + public static IoEngine_xrg_loadFilStr new_(Io_url url) { + IoEngine_xrg_loadFilStr rv = new IoEngine_xrg_loadFilStr(); + rv.url = url; + return rv; + } IoEngine_xrg_loadFilStr() {} +} diff --git a/100_core/src_200_io/gplx/ios/IoEngine_xrg_openRead.java b/100_core/src_200_io/gplx/ios/IoEngine_xrg_openRead.java new file mode 100644 index 000000000..1fd9aaa86 --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoEngine_xrg_openRead.java @@ -0,0 +1,35 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +public class IoEngine_xrg_openRead { + public Io_url Url() {return url;} Io_url url; + public String ErrMsg() {return errMsg;} private String errMsg; + public IoStream ExecAsIoStreamOrFail() {return IoEnginePool._.Get_by(url.Info().EngineKey()).OpenStreamRead(url);} + public IoStream ExecAsIoStreamOrNull() { + try {return IoEnginePool._.Get_by(url.Info().EngineKey()).OpenStreamRead(url);} + catch (Exception exc) { + errMsg = Err_.Message_lang(exc); + return IoStream_.Null; + } + } + public static IoEngine_xrg_openRead new_(Io_url url) { + IoEngine_xrg_openRead rv = new IoEngine_xrg_openRead(); + rv.url = url; + return rv; + } IoEngine_xrg_openRead() {} +} diff --git a/100_core/src_200_io/gplx/ios/IoEngine_xrg_openWrite.java b/100_core/src_200_io/gplx/ios/IoEngine_xrg_openWrite.java new file mode 100644 index 000000000..a5906b9e3 --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoEngine_xrg_openWrite.java @@ -0,0 +1,31 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +public class IoEngine_xrg_openWrite { + public Io_url Url() {return url;} public IoEngine_xrg_openWrite Url_(Io_url val) {url = val; return this;} Io_url url; + public boolean ReadOnlyIgnored() {return readOnlyIgnored;} public IoEngine_xrg_openWrite ReadOnlyIgnored_() {return ReadOnlyIgnored_(true);} public IoEngine_xrg_openWrite ReadOnlyIgnored_(boolean v) {readOnlyIgnored = v; return this;} private boolean readOnlyIgnored = false; + public boolean MissingIgnored() {return missingIgnored;} public IoEngine_xrg_openWrite MissingIgnored_() {return MissingIgnored_(true);} public IoEngine_xrg_openWrite MissingIgnored_(boolean v) {missingIgnored = v; return this;} private boolean missingIgnored = false; + public byte Mode() {return mode;} public IoEngine_xrg_openWrite Mode_(byte v) {mode = v; return this;} private byte mode = IoStream_.Mode_wtr_create; + public IoEngine_xrg_openWrite Mode_update_() {return Mode_(IoStream_.Mode_wtr_update);} + public IoStream Exec() {return IoEnginePool._.Get_by(url.Info().EngineKey()).OpenStreamWrite(this);} + public static IoEngine_xrg_openWrite new_(Io_url url) { + IoEngine_xrg_openWrite rv = new IoEngine_xrg_openWrite(); + rv.url = url; + return rv; + } IoEngine_xrg_openWrite() {} +} diff --git a/100_core/src_200_io/gplx/ios/IoEngine_xrg_queryDir.java b/100_core/src_200_io/gplx/ios/IoEngine_xrg_queryDir.java new file mode 100644 index 000000000..17b740e38 --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoEngine_xrg_queryDir.java @@ -0,0 +1,55 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import gplx.core.criterias.*; +public class IoEngine_xrg_queryDir { + public Io_url Url() {return url;} public IoEngine_xrg_queryDir Url_(Io_url val) {url = val; return this;} Io_url url; + public boolean Recur() {return recur;} public IoEngine_xrg_queryDir Recur_() {return Recur_(true);} public IoEngine_xrg_queryDir Recur_(boolean val) {recur = val; return this;} private boolean recur = false; + public boolean DirInclude() {return dirInclude;} public IoEngine_xrg_queryDir DirInclude_() {return DirInclude_(true);} public IoEngine_xrg_queryDir DirInclude_(boolean val) {dirInclude = val; return this;} private boolean dirInclude = false; + public Criteria FilCrt() {return filCrt;} public IoEngine_xrg_queryDir FilCrt_(Criteria val) {filCrt = val; return this;} Criteria filCrt; + public Criteria DirCrt() {return dirCrt;} public IoEngine_xrg_queryDir DirCrt_(Criteria val) {dirCrt = val; return this;} Criteria dirCrt; + public Criteria SubDirScanCrt() {return subDirScanCrt;} public IoEngine_xrg_queryDir SubDirScanCrt_(Criteria val) {subDirScanCrt = val; return this;} Criteria subDirScanCrt; + public IoEngine_xrg_queryDir DirOnly_() { + DirInclude_(true); + filCrt = Criteria_.None; + return this; + } + + public ConsoleDlg UsrDlg() {return usrDlg;} public IoEngine_xrg_queryDir UsrDlg_(ConsoleDlg val) {usrDlg = val; return this;} ConsoleDlg usrDlg = ConsoleDlg_.Null; + public IoEngine_xrg_queryDir FilPath_(String val) { + Criteria_ioMatch crt = Criteria_ioMatch.parse_(true, val, url.Info().CaseSensitive()); + filCrt = Criteria_fld.new_(IoItm_base_.Prop_Path, crt); + return this; + } + public IoItmDir ExecAsDir() {return IoEnginePool._.Get_by(url.Info().EngineKey()).QueryDirDeep(this);} + public Io_url[] ExecAsUrlAry() {return ExecAsItmHash().XtoIoUrlAry();} + public IoItmHash ExecAsItmHash() { + Criteria crt = dirInclude ? Criteria_.All : Criteria_fld.new_(IoItm_base_.Prop_Type, Criteria_.eq_(IoItmFil.Type_Fil)); + IoItmHash list = ExecAsDir().XtoIoItmList(crt); + list.Sort_by(IoItmBase_comparer_nest._); + return list; + } + public static IoEngine_xrg_queryDir new_(Io_url url) { + IoEngine_xrg_queryDir rv = new IoEngine_xrg_queryDir(); + rv.url = url; + rv.filCrt = Criteria_fld.new_(IoItm_base_.Prop_Path, Criteria_.All); + rv.dirCrt = Criteria_fld.new_(IoItm_base_.Prop_Path, Criteria_.All); + rv.subDirScanCrt = Criteria_fld.new_(IoItm_base_.Prop_Path, Criteria_.All); + return rv; + } IoEngine_xrg_queryDir() {} +} diff --git a/100_core/src_200_io/gplx/ios/IoEngine_xrg_recycleFil.java b/100_core/src_200_io/gplx/ios/IoEngine_xrg_recycleFil.java new file mode 100644 index 000000000..2b4e2ecd3 --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoEngine_xrg_recycleFil.java @@ -0,0 +1,59 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import gplx.core.strings.*; +public class IoEngine_xrg_recycleFil extends IoEngine_xrg_fil_affects1_base { + public IoEngine_xrg_recycleFil MissingFails_off() {return MissingFails_(false);} public IoEngine_xrg_recycleFil MissingFails_(boolean v) {MissingFails_set(v); return this;} + + public int Mode() {return mode;} public IoEngine_xrg_recycleFil Mode_(int v) {mode = v; return this;} int mode; + public String AppName() {return appName;} public IoEngine_xrg_recycleFil AppName_(String val) {appName = val; return this;} private String appName = "unknown_app"; + public Guid_adp Uuid() {return uuid;} public IoEngine_xrg_recycleFil Uuid_(Guid_adp val) {uuid = val; return this;} Guid_adp uuid; + public boolean Uuid_include() {return uuid_include;} public IoEngine_xrg_recycleFil Uuid_include_() {uuid_include = true; return this;} private boolean uuid_include; + public DateAdp Time() {return time;} public IoEngine_xrg_recycleFil Time_(DateAdp val) {time = val; return this;} DateAdp time; + public List_adp RootDirNames() {return rootDirNames;} public IoEngine_xrg_recycleFil RootDirNames_(List_adp val) {rootDirNames = val; return this;} List_adp rootDirNames; + public Io_url RecycleUrl() { + String dayName = time.XtoStr_fmt("yyyyMMdd"), timeName = time.XtoStr_fmt("hhmmssfff"); + String rootDirStr = ConcatWith_ary(this.Url().Info().DirSpr(), rootDirNames); + Io_url recycleDir = this.Url().OwnerRoot().GenSubDir_nest(rootDirStr, dayName); + String uuidStr = uuid_include ? uuid.XtoStr() : ""; + return recycleDir.GenSubFil_ary(appName, ";", timeName, ";", uuidStr, ";", String_.LimitToFirst(this.Url().NameAndExt(), 128)); + } + String ConcatWith_ary(String separator, List_adp ary) { + String_bldr sb = String_bldr_.new_(); + int aryLen = ary.Count(); + for (int i = 0; i < aryLen; i++) { + if (i != 0) sb.Add(separator); + Object val = ary.Get_at(i); + sb.Add_obj(Object_.Xto_str_strict_or_empty(val)); + } + return sb.XtoStr(); + } + @Override public void Exec() { + IoEnginePool._.Get_by(this.Url().Info().EngineKey()).RecycleFil(this); + } + public IoEngine_xrg_recycleFil(int v) { + mode = v; + time = DateAdp_.Now(); + uuid = Guid_adp_.new_(); + rootDirNames = List_adp_.new_(); rootDirNames.Add("z_trash"); + } + public static IoEngine_xrg_recycleFil sysm_(Io_url url) {return new IoEngine_xrg_recycleFil(SysmConst);} + public static IoEngine_xrg_recycleFil gplx_(Io_url url) {IoEngine_xrg_recycleFil rv = new IoEngine_xrg_recycleFil(GplxConst); rv.Url_set(url); return rv;} + public static IoEngine_xrg_recycleFil proto_() {return gplx_(Io_url_.Empty);} + public static final int GplxConst = 0, SysmConst = 1; +} diff --git a/100_core/src_200_io/gplx/ios/IoEngine_xrg_saveFilStr.java b/100_core/src_200_io/gplx/ios/IoEngine_xrg_saveFilStr.java new file mode 100644 index 000000000..da2b44f91 --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoEngine_xrg_saveFilStr.java @@ -0,0 +1,33 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import gplx.texts.*; +public class IoEngine_xrg_saveFilStr { + public Io_url Url() {return url;} public IoEngine_xrg_saveFilStr Url_(Io_url val) {url = val; return this;} Io_url url; + public String Text() {return text;} public IoEngine_xrg_saveFilStr Text_(String val) {text = val; return this;} private String text = ""; + public boolean Append() {return append;} public IoEngine_xrg_saveFilStr Append_() {return Append_(true);} public IoEngine_xrg_saveFilStr Append_(boolean val) {append = val; return this;} private boolean append = false; + public void Exec() { + if (String_.Eq(text, "") && append) return; // no change; don't bother writing to disc + IoEnginePool._.Get_by(url.Info().EngineKey()).SaveFilText_api(this); + } + public static IoEngine_xrg_saveFilStr new_(Io_url url, String text) { + IoEngine_xrg_saveFilStr rv = new IoEngine_xrg_saveFilStr(); + rv.url = url; rv.text = text; + return rv; + } IoEngine_xrg_saveFilStr() {} +} diff --git a/100_core/src_200_io/gplx/ios/IoEngine_xrg_xferDir.java b/100_core/src_200_io/gplx/ios/IoEngine_xrg_xferDir.java new file mode 100644 index 000000000..1ce83f3bd --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoEngine_xrg_xferDir.java @@ -0,0 +1,37 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import gplx.core.criterias.*; +public class IoEngine_xrg_xferDir { + public boolean Type_move() {return move;} public boolean Type_copy() {return !move;} private boolean move = false; + public Io_url Src() {return src;} public IoEngine_xrg_xferDir Src_(Io_url val) {src = val; return this;} Io_url src; + public Io_url Trg() {return trg;} public IoEngine_xrg_xferDir Trg_(Io_url val) {trg = val; return this;} Io_url trg; + public boolean Recur() {return recur;} public IoEngine_xrg_xferDir Recur_() {recur = true; return this;} private boolean recur = false; + public boolean Overwrite() {return overwrite;} public IoEngine_xrg_xferDir Overwrite_() {return Overwrite_(true);} public IoEngine_xrg_xferDir Overwrite_(boolean v) {overwrite = v; return this;} private boolean overwrite = false; + public boolean ReadOnlyFails() {return readOnlyFails;} public IoEngine_xrg_xferDir ReadOnlyFails_() {return ReadOnlyFails_(true);} public IoEngine_xrg_xferDir ReadOnlyFails_(boolean v) {readOnlyFails = v; return this;} private boolean readOnlyFails = false; + public Criteria MatchCrt() {return matchCrt;} public IoEngine_xrg_xferDir MatchCrt_(Criteria v) {matchCrt = v; return this;} Criteria matchCrt = Criteria_.All; + public Criteria SubDirScanCrt() {return subDirScanCrt;} public IoEngine_xrg_xferDir SubDirScanCrt_(Criteria v) {subDirScanCrt = v; return this;} Criteria subDirScanCrt = Criteria_.All; + public void Exec() {IoEnginePool._.Get_by(src.Info().EngineKey()).XferDir(this);} + public static IoEngine_xrg_xferDir move_(Io_url src, Io_url trg) {return new_(src, trg, true);} + public static IoEngine_xrg_xferDir copy_(Io_url src, Io_url trg) {return new_(src, trg, false);} + static IoEngine_xrg_xferDir new_(Io_url src, Io_url trg, boolean move) { + IoEngine_xrg_xferDir rv = new IoEngine_xrg_xferDir(); + rv.src = src; rv.trg = trg; rv.move = move; + return rv; + } IoEngine_xrg_xferDir() {} +} diff --git a/100_core/src_200_io/gplx/ios/IoEngine_xrg_xferFil.java b/100_core/src_200_io/gplx/ios/IoEngine_xrg_xferFil.java new file mode 100644 index 000000000..941b0cad9 --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoEngine_xrg_xferFil.java @@ -0,0 +1,34 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +public class IoEngine_xrg_xferFil { + public boolean Type_move() {return move;} private boolean move = false; + public Io_url Src() {return src;} Io_url src; + public Io_url Trg() {return trg;} Io_url trg; + public boolean Overwrite() {return overwrite;} public IoEngine_xrg_xferFil Overwrite_() {return Overwrite_(true);} public IoEngine_xrg_xferFil Overwrite_(boolean v) {overwrite = v; return this;} private boolean overwrite = false; + public boolean ReadOnlyFails() {return readOnlyFails;} public IoEngine_xrg_xferFil ReadOnlyFails_off() {return ReadOnlyFails_(false);} public IoEngine_xrg_xferFil ReadOnlyFails_(boolean v) {readOnlyFails = v; return this;} private boolean readOnlyFails = true; + public boolean MissingFails() {return missingFails;} public IoEngine_xrg_xferFil MissingFails_off() {return MissingFails_(false);} public IoEngine_xrg_xferFil MissingFails_(boolean v) {missingFails = v; return this;} private boolean missingFails = true; + public void Exec() {IoEnginePool._.Get_by(src.Info().EngineKey()).XferFil(this);} + public static IoEngine_xrg_xferFil move_(Io_url src, Io_url trg) {return new_(src, trg, true);} + public static IoEngine_xrg_xferFil copy_(Io_url src, Io_url trg) {return new_(src, trg, false);} + static IoEngine_xrg_xferFil new_(Io_url src, Io_url trg, boolean move) { + IoEngine_xrg_xferFil rv = new IoEngine_xrg_xferFil(); + rv.src = src; rv.trg = trg; rv.move = move; + return rv; + } IoEngine_xrg_xferFil() {} +} diff --git a/100_core/src_200_io/gplx/ios/IoErr.java b/100_core/src_200_io/gplx/ios/IoErr.java new file mode 100644 index 000000000..5c2940b52 --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoErr.java @@ -0,0 +1,30 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +public class IoErr { + public static String Namespace = "gplx.ios."; + public static String FileIsReadOnly_key = Namespace + "FileIsReadOnlyError"; + public static String FileNotFound_key = Namespace + "FileNotFoundError"; + public static Exc FileIsReadOnly(Io_url url) { + return Exc_.new_w_type(FileIsReadOnly_key, "file is read-only", "url", url.Xto_api()).Stack_erase_1_(); + } + public static Exc FileNotFound(String op, Io_url url) { + // file is missing -- op='copy' file='C:\a.txt' copyFile_target='D:\a.txt' + return Exc_.new_w_type(FileNotFound_key, "file not found", "op", op, "file", url.Xto_api()).Stack_erase_1_(); + } +} \ No newline at end of file diff --git a/100_core/src_200_io/gplx/ios/IoItmAttrib.java b/100_core/src_200_io/gplx/ios/IoItmAttrib.java new file mode 100644 index 000000000..1772e57d0 --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoItmAttrib.java @@ -0,0 +1,25 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +public class IoItmAttrib { + public boolean ReadOnly() {return readOnly;} public IoItmAttrib ReadOnly_() {return ReadOnly_(true);} public IoItmAttrib ReadOnly_(boolean val) {readOnly = val; return this;} private boolean readOnly; + public boolean Hidden() {return hidden;} public IoItmAttrib Hidden_() {return Hidden_(true);} public IoItmAttrib Hidden_(boolean val) {hidden = val; return this;} private boolean hidden; + public static IoItmAttrib readOnly_() {return new IoItmAttrib().ReadOnly_();} + public static IoItmAttrib hidden_() {return new IoItmAttrib().Hidden_();} + public static IoItmAttrib normal_() {return new IoItmAttrib().ReadOnly_(false).Hidden_(false);} +} diff --git a/100_core/src_200_io/gplx/ios/IoItmClassXtn.java b/100_core/src_200_io/gplx/ios/IoItmClassXtn.java new file mode 100644 index 000000000..965daded4 --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoItmClassXtn.java @@ -0,0 +1,32 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +public class IoItmClassXtn extends ClassXtn_base implements ClassXtn { + public String Key() {return Key_const;} public static final String Key_const = "ioItemType"; + @Override public Class UnderClass() {return int.class;} + public Object DefaultValue() {return IoItmDir.Type_Dir;} + public boolean Eq(Object lhs, Object rhs) {return ((IoItm_base)lhs).compareTo(rhs) == CompareAble_.Same;} + @Override public Object ParseOrNull(String raw) { + String rawLower = String_.Lower(raw); + if (String_.Eq(rawLower, "dir")) return IoItmDir.Type_Dir; + else if (String_.Eq(rawLower, "fil")) return IoItmFil.Type_Fil; + else throw Exc_.new_unhandled(raw); + } + @Override public Object XtoDb(Object obj) {return Int_.cast_(obj);} + public static final IoItmClassXtn _ = new IoItmClassXtn(); IoItmClassXtn() {} +} diff --git a/100_core/src_200_io/gplx/ios/IoItmDir.java b/100_core/src_200_io/gplx/ios/IoItmDir.java new file mode 100644 index 000000000..04371ae7e --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoItmDir.java @@ -0,0 +1,71 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import gplx.core.criterias.*; +public class IoItmDir extends IoItm_base { + public boolean Exists() {return exists;} public void Exists_set(boolean v) {exists = v;} private boolean exists = true; + @Override public int TypeId() {return Type_Dir;} @Override public boolean Type_dir() {return true;} @Override public boolean Type_fil() {return false;} public static final int Type_Dir = 1; + @gplx.New public IoItmDir XtnProps_set(String key, Object val) {return (IoItmDir)super.XtnProps_set(key, val);} + public IoItmList SubDirs() {return subDirs;} IoItmList subDirs; + public IoItmList SubFils() {return subFils;} IoItmList subFils; + public IoItmHash XtoIoItmList(Criteria crt) { + IoItmHash rv = IoItmHash.list_(this.Url()); + XtoItmList_recur(rv, this, crt); + return rv; + } + Io_url[] XtoIoUrlAry() { + IoItmHash list = this.XtoIoItmList(Criteria_.All); +//#plat_wce list.Sort(); // NOTE: on wce, subFils retrieved in unexpected order; createTime vs pathString + int count = list.Count(); + Io_url[] rv = new Io_url[count]; + for (int i = 0; i < count; i++) + rv[i] = list.Get_at(i).Url(); + return rv; + } + public IoItmDir FetchDeepOrNull(Io_url findDirUrl) { + String dirSpr = this.Url().Info().DirSpr(); int dirSprLen = String_.Len(dirSpr); + String currDirStr = this.Url().Raw(); + String findDirStr = findDirUrl.Raw(); + if (!String_.Has_at_bgn(findDirStr, currDirStr)) return null; // findUrl must start with currUrl; + String findName = String_.DelEnd(currDirStr, dirSprLen); // seed findName for String_.MidByLen below; + IoItmDir curDir = this; + while (true) { + findDirStr = String_.DelBgn(findDirStr, String_.Len(findName) + dirSprLen); // NOTE: findName will never have trailingDirSpr; subDirs.Get_by() takes NameOnly; ex: "dir" not "dir\" + int nextDirSprPos = String_.FindFwd(findDirStr, dirSpr); if (nextDirSprPos == String_.Find_none) nextDirSprPos = String_.Len(findDirStr); + findName = String_.MidByLen(findDirStr, 0, nextDirSprPos); + if (String_.Eq(findDirStr, "")) return curDir; // findDirStr completely removed; all parts match; return curDir + curDir = IoItmDir_.as_(curDir.subDirs.Get_by(findName)); // try to find dir + if (curDir == null) return null; // dir not found; exit; NOTE: if dir found, loop restarts; with curDir as either findDir, or owner of findDir + } + } + void XtoItmList_recur(IoItmHash list, IoItmDir curDir, Criteria dirCrt) { + for (Object subFilObj : curDir.SubFils()) { + IoItmFil subFil = (IoItmFil)subFilObj; + list.Add(subFil); + } + for (Object subDirObj : curDir.SubDirs()) { + IoItmDir subDir = (IoItmDir)subDirObj; + if (dirCrt.Matches(subDir)) list.Add(subDir); + XtoItmList_recur(list, subDir, dirCrt); + } + } + @gplx.Internal protected IoItmDir(boolean caseSensitive) { + subDirs = IoItmList.new_(this, caseSensitive); + subFils = IoItmList.new_(this, caseSensitive); + } +} diff --git a/100_core/src_200_io/gplx/ios/IoItmDir_.java b/100_core/src_200_io/gplx/ios/IoItmDir_.java new file mode 100644 index 000000000..181554d82 --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoItmDir_.java @@ -0,0 +1,55 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +public class IoItmDir_ { + public static IoItmDir as_(Object obj) {return obj instanceof IoItmDir ? (IoItmDir)obj : null;} + public static final IoItmDir Null = null_(); + public static IoItmDir top_(Io_url url) {return scan_(url);} + public static IoItmDir scan_(Io_url url) { + IoItmDir rv = new IoItmDir(url.Info().CaseSensitive()); + rv.ctor_IoItmBase_url(url); + return rv; + } + public static IoItmDir sub_(String name) { + IoItmDir rv = new IoItmDir(Bool_.Y); + rv.ctor_IoItmBase_url(Io_url_.mem_dir_("mem/" + name)); + return rv; + } + static IoItmDir null_() { + IoItmDir rv = new IoItmDir(true); // TODO: NULL should be removed + rv.ctor_IoItmBase_url(Io_url_.Empty); + rv.Exists_set(false); + return rv; + } + public static void Make(IoItmDir dir) { + Io_mgr.I.CreateDir(dir.Url()); + int len = dir.SubDirs().Count(); + for (int i = 0; i < len; ++i) { + IoItmDir sub_dir = (IoItmDir)dir.SubDirs().Get_at(i); + Make(sub_dir); + } + len = dir.SubFils().Count(); + for (int i = 0; i < len; ++i) { + IoItmFil sub_fil = (IoItmFil)dir.SubFils().Get_at(i); + String text = String_.Repeat("a", (int)sub_fil.Size()); + Io_url sub_url = sub_fil.Url(); + Io_mgr.I.SaveFilStr(sub_url, text); + Io_mgr.I.UpdateFilModifiedTime(sub_url, sub_fil.ModifiedTime()); + } + } +} diff --git a/100_core/src_200_io/gplx/ios/IoItmFil.java b/100_core/src_200_io/gplx/ios/IoItmFil.java new file mode 100644 index 000000000..d02d8b8d8 --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoItmFil.java @@ -0,0 +1,42 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +public class IoItmFil extends IoItm_base { + @Override public int TypeId() {return IoItmFil.Type_Fil;} @Override public boolean Type_dir() {return false;} @Override public boolean Type_fil() {return true;} public static final int Type_Fil = 2; + public boolean Exists() {return size != Size_invalid;} // NOTE: questionable logic, but preserved for historical reasons; requires that length be set to -1 if !.exists + public DateAdp ModifiedTime() {return modifiedTime;} + public IoItmFil ModifiedTime_(DateAdp val) {modifiedTime = val; return this;} DateAdp modifiedTime; + public IoItmFil ModifiedTime_(String val) {return ModifiedTime_(DateAdp_.parse_gplx(val));} + @gplx.Virtual public long Size() {return size;} public IoItmFil Size_(long val) {size = val; return this;} private long size; + public IoItmAttrib Attrib() {return attrib;} public IoItmFil Attrib_(IoItmAttrib val) {attrib = val; return this;} IoItmAttrib attrib = IoItmAttrib.normal_(); + public boolean ReadOnly() {return attrib.ReadOnly();} public IoItmFil ReadOnly_(boolean val) {attrib.ReadOnly_(val); return this;} + @gplx.New public IoItmFil XtnProps_set(String key, Object val) {return (IoItmFil)super.XtnProps_set(key, val);} + + @gplx.Internal protected IoItmFil ctor_IoItmFil(Io_url url, long size, DateAdp modifiedTime) { + ctor_IoItmBase_url(url); this.size = size; this.modifiedTime = modifiedTime; + return this; + } + @Override public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) { + if (ctx.Match(k, IoItmFil_.Prop_Size)) return size; + else if (ctx.Match(k, IoItmFil_.Prop_Modified)) return modifiedTime; + else return super.Invk(ctx, ikey, k, m); + } + @gplx.Internal protected IoItmFil() {} + public static final long Size_invalid = -1; + public static final int Size_invalid_int = -1; +} diff --git a/100_core/src_200_io/gplx/ios/IoItmFil_.java b/100_core/src_200_io/gplx/ios/IoItmFil_.java new file mode 100644 index 000000000..9f847ce5a --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoItmFil_.java @@ -0,0 +1,31 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +public class IoItmFil_ { + public static IoItmFil as_(Object obj) {return obj instanceof IoItmFil ? (IoItmFil)obj : null;} + public static final String + Prop_Size = "size" + , Prop_Modified = "modified"; + public static IoItmFil new_(Io_url url, long size, DateAdp created, DateAdp modified) {return new IoItmFil().ctor_IoItmFil(url, size, modified);} + public static IoItmFil sub_(String name, long size, DateAdp modified) { + IoItmFil rv = new IoItmFil(); + rv.ctor_IoItmFil(Io_url_.mem_fil_("mem/" + name), size, modified); + rv.Name_(name); + return rv; + } +} diff --git a/100_core/src_200_io/gplx/ios/IoItmFil_mem.java b/100_core/src_200_io/gplx/ios/IoItmFil_mem.java new file mode 100644 index 000000000..c313a3e02 --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoItmFil_mem.java @@ -0,0 +1,39 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import gplx.ios.*; /*IoStream_mem*/ import gplx.texts.*; /*Encoding_*/ +class IoItmFil_mem extends IoItmFil { public static IoItmFil_mem as_(Object obj) {return obj instanceof IoItmFil_mem ? (IoItmFil_mem)obj : null;} + @gplx.Internal protected IoStream_mem Stream() {return stream;} IoStream_mem stream; // NOTE: using stream instead of Text, b/c no events for IoStream.Dispose; ex: stream.OpenStreamWrite; stream.Write("hi"); stream.Dispose(); "hi" would not be saved if Text is member variable + @Override public long Size() {return (int)stream.Len();} + public String Text() {return Text_get();} public void Text_set(String v) {stream = IoStream_mem.rdr_txt_(this.Url(), v);} + String Text_get() { + int len = (int)stream.Len(); + byte[] buffer = new byte[len]; + stream.Position_set(0); + stream.Read(buffer, 0, len); + return String_.new_u8(buffer); + } + public IoItmFil_mem Clone() {return new_(this.Url(), this.Size(), this.ModifiedTime(), this.Text());} + public static IoItmFil_mem new_(Io_url filPath, long size, DateAdp modified, String text) { + IoItmFil_mem rv = new IoItmFil_mem(); + rv.ctor_IoItmFil(filPath, size, modified); + rv.stream = IoStream_mem.rdr_txt_(filPath, text); + return rv; + } + public static final IoItmFil_mem Null = new_(Io_url_.Empty, -1, DateAdp_.MinValue, ""); // NOTE: size must be -1 for .Exists to be false; DATE:2015-05-16 +} diff --git a/100_core/src_200_io/gplx/ios/IoItmHash.java b/100_core/src_200_io/gplx/ios/IoItmHash.java new file mode 100644 index 000000000..210654155 --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoItmHash.java @@ -0,0 +1,43 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +public class IoItmHash extends Ordered_hash_base { + public Io_url Url() {return url;} Io_url url; + public void Add(IoItm_base itm) {Add_base(MakeKey(itm.Url()), itm);} + public void Del(Io_url url) {Del(MakeKey(url));} + public IoItm_base Get_by(Io_url url) {return IoItm_base_.as_(Fetch_base(MakeKey(url)));} + @gplx.New public IoItm_base Get_at(int i) {return IoItm_base_.as_(Get_at_base(i));} + public Io_url[] XtoIoUrlAry() { + int count = this.Count(); + Io_url[] rv = new Io_url[count]; + for (int i = 0; i < count; i++) + rv[i] = this.Get_at(i).Url(); + return rv; + } + String MakeKey(Io_url url) {return url.XtoCaseNormalized();} + public static IoItmHash new_() { + IoItmHash rv = new IoItmHash(); + rv.url = null;//Io_url_.Empty; + return rv; + } IoItmHash() {} + public static IoItmHash list_(Io_url url) { + IoItmHash rv = new IoItmHash(); + rv.url = url; + return rv; + } +} diff --git a/100_core/src_200_io/gplx/ios/IoItmList.java b/100_core/src_200_io/gplx/ios/IoItmList.java new file mode 100644 index 000000000..f265df0ae --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoItmList.java @@ -0,0 +1,76 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import gplx.lists.*; /*Ordered_hash_base*/ +public class IoItmList extends Ordered_hash_base { + public boolean Has(Io_url url) {return Has_base(MakeKey(url));} + public void Add(IoItm_base itm) { + if (ownerDir != null) itm.OwnerDir_set(ownerDir); + Add_base(MakeKey(itm.Url()), itm); + } + public void Del(Io_url url) { + String key = MakeKey(url); + IoItm_base itm = IoItm_base_.as_(Fetch_base(key)); if (itm == null) return; + itm.OwnerDir_set(null); + super.Del(key); + } + public Io_url[] XtoIoUrlAry() { + int count = this.Count(); + Io_url[] rv = new Io_url[count]; + for (int i = 0; i < count; i++) + rv[i] = IoItm_base_.as_(i).Url(); + return rv; + } + @Override public void Sort() {Sort_by(IoItmBase_comparer_nest._);} + @Override protected Object Fetch_base(Object keyObj) { + String key = MakeKey((String)keyObj); + return super.Fetch_base(key); + } + @Override public void Del(Object keyObj) { + String key = MakeKey((String)keyObj); + super.Del(key); + } + String MakeKey(Io_url url) { + String itmName = url.Type_dir() ? url.NameOnly() : url.NameAndExt(); + return MakeKey(itmName); + } + String MakeKey(String s) { + return caseSensitive ? s : String_.Lower(s); + } + IoItmDir ownerDir; boolean caseSensitive; + @gplx.Internal protected static IoItmList new_(IoItmDir v, boolean caseSensitive) { + IoItmList rv = new IoItmList(); + rv.ownerDir = v; rv.caseSensitive = caseSensitive; + return rv; + } + @gplx.Internal protected static IoItmList list_(boolean caseSensitive) {return new_(null, caseSensitive);} +} +class IoItmBase_comparer_nest implements ComparerAble { + public int compare(Object lhsObj, Object rhsObj) { + IoItm_base lhsItm = (IoItm_base)lhsObj, rhsItm = (IoItm_base)rhsObj; + Io_url lhsUrl = lhsItm.Url(), rhsUrl = rhsItm.Url(); + return String_.Eq(lhsUrl.OwnerDir().Raw(), rhsUrl.OwnerDir().Raw()) // is same dir + ? CompareAble_.Compare_obj(lhsUrl.NameAndExt(), rhsUrl.NameAndExt()) // same dir: compare name + : CompareAble_.Compare_obj(DepthOf(lhsItm), DepthOf(rhsItm)); // diff dir: compare by depth; ex: c:\fil.txt < c:\dir\fil.txt + } + int DepthOf(IoItm_base itm) { + Io_url url = itm.Url(); + return String_.Count(url.OwnerDir().Raw(), url.Info().DirSpr()); // use OwnerDir, else dir.Raw will return extra dirSeparator + } + public static final IoItmBase_comparer_nest _ = new IoItmBase_comparer_nest(); IoItmBase_comparer_nest() {} +} diff --git a/100_core/src_200_io/gplx/ios/IoItm_base.java b/100_core/src_200_io/gplx/ios/IoItm_base.java new file mode 100644 index 000000000..e80da21bc --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoItm_base.java @@ -0,0 +1,53 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +public abstract class IoItm_base implements GfoInvkAble, CompareAble { + public abstract int TypeId(); public abstract boolean Type_dir(); public abstract boolean Type_fil(); + public Io_url Url() {return ownerDir == null ? url : ownerDir.Url().GenSubFil(name); /*NOTE: must call .Url*/} Io_url url; + public IoItmDir OwnerDir() {return ownerDir;} IoItmDir ownerDir; + public void OwnerDir_set(IoItmDir v) {if (v == this) throw Exc_.new_("dir cannot be its own owner", "url", v.url.Raw()); + url = v == null && ownerDir != null + ? ownerDir.url.GenSubFil(name) // create url, since ownerDir will soon be null; NOTE: must call .url + : Io_url_.Empty; // delete url, since ownerDir will be avail + ownerDir = v; + } + public String Name() {return name;} private String name; + public IoItm_base Name_(String v) { + name = v; + if (ownerDir == null) url = url.OwnerDir().GenSubFil(name); + return this; + } + public Object XtnProps_get(String key) {return props.Get_by(key);} Hash_adp props = Hash_adp_.Noop; + public IoItm_base XtnProps_set(String key, Object val) { + if (props == Hash_adp_.Noop) props = Hash_adp_.new_(); + props.Del(key); + props.Add(key, val); + return this; + } + public int compareTo(Object comp) {return url.compareTo(((IoItm_base)comp).url);} // NOTE: needed for comic importer (sort done on IoItmHash which contains IoItm_base) +// public Object Data_get(String name) {return GfoInvkAble_.InvkCmd(this, name);} + @gplx.Virtual public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) { + if (ctx.Match(k, IoItm_base_.Prop_Type)) return this.TypeId(); + else if (ctx.Match(k, IoItm_base_.Prop_Path)) return this.Url(); + else if (ctx.Match(k, IoItm_base_.Prop_Title)) return this.Url().NameOnly(); // needed for gfio script criteria; + else if (ctx.Match(k, IoItm_base_.Prop_Ext)) return this.Url().Ext(); // needed for gfio script criteria; EX: where "ext LIKE '.java'" + else return GfoInvkAble_.Rv_unhandled; + } + @gplx.Internal protected void ctor_IoItmBase_url(Io_url url) {this.url = url; this.name = url.NameAndExt();} + @gplx.Internal protected void ctor_IoItmBase_name(String name) {this.name = name;} +} diff --git a/100_core/src_200_io/gplx/ios/IoItm_base_.java b/100_core/src_200_io/gplx/ios/IoItm_base_.java new file mode 100644 index 000000000..39d34b5ce --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoItm_base_.java @@ -0,0 +1,26 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +public class IoItm_base_ { + public static IoItm_base as_(Object obj) {return obj instanceof IoItm_base ? (IoItm_base)obj : null;} + public static final String + Prop_Type = "type" + , Prop_Path = "url" + , Prop_Title = "title" + , Prop_Ext = "ext"; +} diff --git a/100_core/src_200_io/gplx/ios/IoRecycleBin.java b/100_core/src_200_io/gplx/ios/IoRecycleBin.java new file mode 100644 index 000000000..7a390441b --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoRecycleBin.java @@ -0,0 +1,60 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import gplx.core.strings.*; +public class IoRecycleBin { + public void Send(Io_url url) {Send_xrg(url).Exec();} + public IoEngine_xrg_recycleFil Send_xrg(Io_url url) {return IoEngine_xrg_recycleFil.gplx_(url);} + public void Recover(Io_url url) { + String_bldr sb = String_bldr_.new_(); + List_adp list = Regy_search(url, sb); + int listCount = list.Count(); if (listCount > 1) throw Exc_.new_("found more than 1 url", "count", list.Count()); + Io_url trgUrl = (Io_url)list.Get_at(0); + IoEngine_xrg_xferFil.move_(url, trgUrl).ReadOnlyFails_(true).Overwrite_(false).Exec(); + IoEngine_xrg_saveFilStr.new_(FetchRegistryUrl(url), sb.XtoStr()).Exec(); + } + public void Regy_add(IoEngine_xrg_recycleFil xrg) { + Io_url url = xrg.RecycleUrl(); + Io_url regyUrl = FetchRegistryUrl(url); + String text = String_.ConcatWith_any("|", url.NameAndExt_noDirSpr(), xrg.Url().GenRelUrl_orEmpty(url.OwnerRoot()), xrg.Uuid().XtoStr(), xrg.AppName(), xrg.Time()); + IoEngine_xrg_saveFilStr.new_(regyUrl, text).Append_().Exec(); + } + public List_adp Regy_search(Io_url url, String_bldr sb) { + List_adp list = List_adp_.new_(); + Io_url regyUrl = FetchRegistryUrl(url); + String[] lines = IoEngine_xrg_loadFilStr.new_(regyUrl).ExecAsStrAry(); + int linesLen = Array_.Len(lines); + String nameAndExt = url.NameAndExt_noDirSpr() + "|"; + for (int i = linesLen; i > 0; i--) { + String line = lines[i - 1]; + if (String_.Has_at_bgn(line, nameAndExt)) { + String[] terms = String_.Split(line, "|"); + Io_url origUrl = url.OwnerRoot().GenSubFil(terms[1]); + list.Add(origUrl); + } + else + sb.Add_str_w_crlf(line); + } + return list; + } + Io_url FetchRegistryUrl(Io_url url) { + String sourceApp = String_.GetStrBefore(url.NameAndExt_noDirSpr(), ";"); + return url.OwnerDir().GenSubFil_ary(sourceApp, ".recycle.csv"); + } + public static final IoRecycleBin _ = new IoRecycleBin(); IoRecycleBin() {} +} diff --git a/100_core/src_200_io/gplx/ios/IoStream.java b/100_core/src_200_io/gplx/ios/IoStream.java new file mode 100644 index 000000000..2cae01fb2 --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoStream.java @@ -0,0 +1,33 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +public interface IoStream extends RlsAble { + Object UnderRdr(); + Io_url Url(); + long Pos(); + long Len(); + + int ReadAry(byte[] array); + int Read(byte[] array, int offset, int count); + long Seek(long pos); + void WriteAry(byte[] ary); + void Write(byte[] array, int offset, int count); + void Transfer(IoStream trg, int bufferLength); + void Flush(); + void Write_and_flush(byte[] bry, int bgn, int end); +} \ No newline at end of file diff --git a/100_core/src_200_io/gplx/ios/IoStream_.java b/100_core/src_200_io/gplx/ios/IoStream_.java new file mode 100644 index 000000000..430bc35bd --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoStream_.java @@ -0,0 +1,180 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.RandomAccessFile; +import java.io.UnsupportedEncodingException; +public class IoStream_ { + public static final IoStream Null = new IoStream_null(); + public static IoStream mem_txt_(Io_url url, String v) {return IoStream_mem.rdr_txt_(url, v);} + public static IoStream ary_(byte[] v) {return IoStream_mem.rdr_ary_(Io_url_.Empty, v);} + public static final byte Mode_rdr = 0, Mode_wtr_create = 1, Mode_wtr_append = 2, Mode_wtr_update = 3; + public static IoStream stream_rdr_() {return new IoStream_stream_rdr();} + public static IoStream stream_input_(Io_url url) {return new IoStream_stream_rdr().UnderRdr_(input_stream_(url));} + public static Object input_stream_(Io_url url) { + try { + return new java.io.FileInputStream(url.Raw()); + } catch (Exception e) {throw Exc_.new_("file not found", "url", url.Raw());} + } +} +class IoStream_null implements IoStream { + public Object UnderRdr() {return null;} + public Io_url Url() {return Io_url_.Empty;} + public long Pos() {return -1;} + public long Len() {return -1;} + public int ReadAry(byte[] array) {return -1;} + public int Read(byte[] array, int offset, int count) {return -1;} + public long Seek(long pos) {return -1;} + public void WriteAry(byte[] ary) {} + public void Write(byte[] array, int offset, int count) {} + public void Transfer(IoStream trg, int bufferLength) {} + public void Flush() {} + public void Write_and_flush(byte[] bry, int bgn, int end) {} + public void Rls() {} +} +class IoStream_base implements IoStream { + @gplx.Virtual public Io_url Url() {return url;} Io_url url = Io_url_.Empty; + public void Transfer(IoStream trg, int bufferLength) { + byte[] buffer = new byte[bufferLength]; + int read = -1; + while (read != 0) { + read = this.Read(buffer, 0, bufferLength); + trg.Write(buffer, 0, read); + } + trg.Flush(); + } + public int ReadAry(byte[] ary) {return this.Read(ary, 0, ary.length);} + public void WriteAry(byte[] ary) {this.Write(ary, 0, ary.length);} + @gplx.Virtual public Object UnderRdr() {return under;} + @gplx.Virtual public void UnderRdr_(Object v) {this.under = (RandomAccessFile)v;} + @gplx.Virtual public long Pos() {return pos;} long pos; + @gplx.Virtual public long Len() {return length;} long length; + @gplx.Virtual public int Read(byte[] array, int offset, int count) { + try { + int rv = under.read(array, offset, count); + return rv == -1 ? 0 : rv; // NOTE: fis returns -1 if nothing read; .NET returned 0; Hash will fail if -1 returned (will try to create array of 0 length) + } // NOTE: fis keeps track of offset, only need to pass in array (20110606: this NOTE no longer seems to make sense; deprecate) + catch (IOException e) {throw Exc_.new_exc(e, "io", "file read failed", "url", url);} + } + public long Seek(long seek_pos) { + try { + under.seek(seek_pos); + pos = under.getFilePointer(); + return pos; + } + catch (IOException e) {throw Exc_.new_exc(e, "io", "seek failed", "url", url);} + } + @gplx.Virtual public void Write(byte[] array, int offset, int count) {bfr.Add_mid(array, offset, offset + count); this.Flush();} Bry_bfr bfr = Bry_bfr.reset_(16); + public void Write_and_flush(byte[] bry, int bgn, int end) { +// ConsoleAdp._.WriteLine(bry.length +" " + bgn + " " + end); + Flush();// flush anything already in buffer + int buffer_len = Io_mgr.Len_kb * 16; + byte[] buffer = new byte[buffer_len]; + int buffer_bgn = bgn; boolean loop = true; + while (loop) { + int buffer_end = buffer_bgn + buffer_len; + if (buffer_end > end) { + buffer_end = end; + buffer_len = end - buffer_bgn; + loop = false; + } + for (int i = 0; i < buffer_len; i++) + buffer[i] = bry[i + buffer_bgn]; + try {under.write(buffer, 0, buffer_len);} + catch (IOException e) {throw Exc_.new_exc(e, "io", "write failed", "url", url);} + buffer_bgn = buffer_end; + } +// this.Rls(); +// OutputStream output_stream = null; +// try { +// output_stream = new FileOutputStream(url.Xto_api()); +// bry = ByteAry_.Mid(bry, bgn, end); +// output_stream.write(bry, 0, bry.length); +// } +// catch (IOException e) {throw Err_.err_key_(e, IoEngineArgs._.Err_IoException, "write failed").Add("url", url);} +// finally { +// if (output_stream != null) { +// try {output_stream.close();} +// catch (IOException ignore) {} +// } +// } + } + @gplx.Virtual public void Flush() { + try { + if (mode_is_append) under.seek(under.length()); +// else under.seek(0); + } + catch (IOException e) {throw Exc_.new_exc(e, "io", "seek failed", "url", url);} + try {under.write(bfr.Bfr(), 0, bfr.Len());} + catch (IOException e) {throw Exc_.new_exc(e, "io", "write failed", "url", url);} + bfr.Clear(); + } + @gplx.Virtual public void Rls() { + IoEngine_system.Closeable_close(under, url, true); + } + RandomAccessFile under; boolean mode_is_append; byte mode; + public static IoStream_base rdr_wrapper_() {return new IoStream_base();} + public static IoStream_base new_(Io_url url, int mode) { + IoStream_base rv = new IoStream_base(); + rv.url = url; + rv.mode = (byte)mode; + File file = new File(url.Xto_api()); + String ctor_mode = ""; + switch (mode) { // mode; SEE:NOTE_1 + case IoStream_.Mode_wtr_append: + rv.mode_is_append = mode == IoStream_.Mode_wtr_append; + ctor_mode = "rws"; + break; + case IoStream_.Mode_wtr_create: + ctor_mode = "rws"; + break; + case IoStream_.Mode_rdr: + ctor_mode = "r"; + break; + } + try {rv.under = new RandomAccessFile(file, ctor_mode);} + catch (FileNotFoundException e) {throw Exc_.new_exc(e, "io", "file open failed", "url", url);} + if (mode == IoStream_.Mode_wtr_create) { + try {rv.under.setLength(0);} + catch (IOException e) {throw Exc_.new_exc(e, "io", "file truncate failed", "url", url);} + } + rv.length = file.length(); + return rv; + } + public static IoStream_base new_(Object stream) { + IoStream_base rv = new IoStream_base(); +// rv.stream = (System.IO.Stream)stream; + rv.url = Io_url_.Empty; + return rv; + } + } +/* +NOTE_1:stream mode +my understanding of mode +rw: read/write async? +rws: read/write sync; write content + metadata changes +rwd: read/write sync; write content +*/ +//#} \ No newline at end of file diff --git a/100_core/src_200_io/gplx/ios/IoStream_mem.java b/100_core/src_200_io/gplx/ios/IoStream_mem.java new file mode 100644 index 000000000..5e96910ca --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoStream_mem.java @@ -0,0 +1,70 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import gplx.texts.*; /*Encoding_*/ +class IoStream_mem extends IoStream_base { + @Override public Io_url Url() {return url;} Io_url url; + @Override public Object UnderRdr() {throw Exc_.new_unimplemented();} // NOTE: should not use System.IO.MemoryStream, b/c resized data will not be captured in this instance's buffer + @Override public long Len() {return Array_.Len(buffer);} + public int Position() {return position;} public void Position_set(int v) {position = v;} int position; + public byte[] Buffer() {return buffer;} private byte[] buffer = new byte[0]; + + @Override public int Read(byte[] array, int offset, int count) { + int read = 0; + int len = Array_.Len(buffer); + for (int i = 0; i < count; i++) { + if (position + i >= len) break; + array[offset + i] = buffer[position + i]; + read++; + } + position += read; + return read; + } + @Override public void Write(byte[] array, int offset, int count) { + // expand buffer if needed; necessary to emulate fileStream writing; ex: FileStream fs = new FileStream(); fs.Write(data); where data may be unknown length + int length = (int)position + count + -offset; + int bufLen = Array_.Len(buffer); + if (bufLen < length) buffer = Bry_.Resize_manual(buffer, length); + for (int i = 0; i < count; i++) + buffer[position + i] = array[offset + i]; + position += count +-offset; + } + @Override public long Pos() {return position;} + @Override public long Seek(long pos) { + this.position = (int)pos; + return pos; + } + + @Override public void Flush() {} + @Override public void Rls() {} + + public static IoStream_mem rdr_txt_(Io_url url, String v) {return rdr_ary_(url, Bry_.new_u8(v));} + public static IoStream_mem rdr_ary_(Io_url url, byte[] v) { + IoStream_mem rv = new IoStream_mem(); + rv.buffer = v; + rv.url = url; + return rv; + } + public static IoStream_mem wtr_data_(Io_url url, int length) { + IoStream_mem rv = new IoStream_mem(); + rv.buffer = new byte[length]; + rv.url = url; + return rv; + } + IoStream_mem() {} +} diff --git a/100_core/src_200_io/gplx/ios/IoStream_mem_tst.java b/100_core/src_200_io/gplx/ios/IoStream_mem_tst.java new file mode 100644 index 000000000..2e0639e06 --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoStream_mem_tst.java @@ -0,0 +1,30 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import org.junit.*; //using System.IO; /*Stream*/ +public class IoStream_mem_tst { + @Test public void Write() { // confirm that changes written to Stream acquired via .AdpObj are written to IoStream_mem.Buffer + IoStream_mem stream = IoStream_mem.wtr_data_(Io_url_.Empty, 0); + byte[] data = Bry_.ints_(1); + stream.Write(data, 0, Array_.Len(data)); + + Tfds.Eq(1L , stream.Len()); + Tfds.Eq((byte)1 , stream.Buffer()[0]); + stream.Rls(); + } +} diff --git a/100_core/src_200_io/gplx/ios/IoStream_mock.java b/100_core/src_200_io/gplx/ios/IoStream_mock.java new file mode 100644 index 000000000..7ef426cb8 --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoStream_mock.java @@ -0,0 +1,45 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +public class IoStream_mock implements IoStream { + public byte[] Data_bry() {return data_bry;} public IoStream_mock Data_bry_(byte[] v) {data_bry = v; data_bry_len = v.length; return this;} private byte[] data_bry; int data_bry_len; + public int Data_bry_pos() {return data_bry_pos;} int data_bry_pos; + public void Reset() {data_bry_pos = 0;} + public IoStream_mock Read_limit_(int v) {read_limit = v; return this;} int read_limit; + public int Read(byte[] bfr, int bfr_bgn, int bfr_len) { + int bytes_read = bfr_len; + if (bytes_read > read_limit) bytes_read = read_limit; // stream may limit maximum read; EX: bfr_len of 16k but only 2k will be filled + int bytes_left = data_bry_len - data_bry_pos; + if (bytes_read > bytes_left) bytes_read = bytes_left; // not enough bytes left in data_bry; bytes_read = whatever is left + Bry_.Copy_by_pos(data_bry, data_bry_pos, data_bry_pos + bytes_read, bfr, bfr_bgn); + data_bry_pos += bytes_read; + return bytes_read; + } + public Object UnderRdr() {return null;} + public Io_url Url() {return Io_url_.Empty;} + public long Pos() {return -1;} + public long Len() {return -1;} + public int ReadAry(byte[] array) {return -1;} + public long Seek(long pos) {return -1;} + public void WriteAry(byte[] ary) {} + public void Write(byte[] array, int offset, int count) {} + public void Transfer(IoStream trg, int bufferLength) {} + public void Flush() {} + public void Write_and_flush(byte[] bry, int bgn, int end) {} + public void Rls() {} +} diff --git a/100_core/src_200_io/gplx/ios/IoStream_mock_tst.java b/100_core/src_200_io/gplx/ios/IoStream_mock_tst.java new file mode 100644 index 000000000..d3f64f0e7 --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoStream_mock_tst.java @@ -0,0 +1,48 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import org.junit.*; +public class IoStream_mock_tst { + @Before public void init() {fxt.Clear();} IoStream_mock_fxt fxt = new IoStream_mock_fxt(); + @Test public void Basic() { + fxt.Init_src_str_("abcde").Init_trg_len_(5).Init_rdr_limit_(2).Init_read_len_(2); + fxt.Test_read("ab").Test_read("cd").Test_read("e"); + } + @Test public void Read_limit() { + fxt.Init_src_str_("abcde").Init_trg_len_(5).Init_rdr_limit_(2).Init_read_len_(4); + fxt.Test_read("ab").Test_read("cd").Test_read("e"); + } +} +class IoStream_mock_fxt { + public void Clear() { + if (rdr == null) + rdr = new IoStream_mock(); + rdr.Reset(); + trg_bgn = 0; + } IoStream_mock rdr; byte[] trg_bry; + public IoStream_mock_fxt Init_src_str_(String v) {rdr.Data_bry_(Bry_.new_a7(v)); return this;} + public IoStream_mock_fxt Init_trg_len_(int v) {trg_bry = new byte[v]; return this;} + public IoStream_mock_fxt Init_read_len_(int v) {read_len = v; return this;} int read_len; + public IoStream_mock_fxt Init_rdr_limit_(int v) {rdr.Read_limit_(v); return this;} + public IoStream_mock_fxt Test_read(String expd) { + int bytes_read = rdr.Read(trg_bry, trg_bgn, read_len); + Tfds.Eq(expd, String_.new_a7(trg_bry, trg_bgn, trg_bgn + bytes_read)); + trg_bgn += bytes_read; + return this; + } int trg_bgn; +} diff --git a/100_core/src_200_io/gplx/ios/IoStream_stream_rdr.java b/100_core/src_200_io/gplx/ios/IoStream_stream_rdr.java new file mode 100644 index 000000000..285152f57 --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoStream_stream_rdr.java @@ -0,0 +1,39 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +public class IoStream_stream_rdr implements IoStream { + public int Read(byte[] bfr, int bfr_bgn, int bfr_len) { + try { + return stream.read(bfr, bfr_bgn, bfr_len); + } + catch (Exception e) {throw Exc_.new_exc(e, "core", "failed to read from stream");} + } + public IoStream UnderRdr_(Object v) {this.stream = (java.io.InputStream)v; return this;} java.io.InputStream stream; + public Object UnderRdr() {return stream;} + public Io_url Url() {return Io_url_.Empty;} + public long Pos() {return -1;} + public long Len() {return -1;} + public int ReadAry(byte[] array) {return -1;} + public long Seek(long pos) {return -1;} + public void WriteAry(byte[] ary) {} + public void Write(byte[] array, int offset, int count) {} + public void Transfer(IoStream trg, int bufferLength) {} + public void Flush() {} + public void Write_and_flush(byte[] bry, int bgn, int end) {} + public void Rls() {} +} diff --git a/100_core/src_200_io/gplx/ios/IoUrlInfo.java b/100_core/src_200_io/gplx/ios/IoUrlInfo.java new file mode 100644 index 000000000..a128beff6 --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoUrlInfo.java @@ -0,0 +1,244 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +public interface IoUrlInfo { + String Key(); + byte DirSpr_byte(); + String DirSpr(); + boolean CaseSensitive(); + String EngineKey(); + + boolean Match(String raw); + boolean IsDir(String raw); + String Xto_api(String raw); + String OwnerDir(String raw); + String OwnerRoot(String raw); + String NameAndExt(String raw); + String NameOnly(String raw); + String Ext(String raw); + String XtoRootName(String raw, int rawLen); +} +class IoUrlInfo_nil implements IoUrlInfo { + public String Key() {return KeyConst;} public static final String KeyConst = String_.Null_mark; + public String EngineKey() {return "<>";} + public String DirSpr() {return "<>";} + public byte DirSpr_byte() {return Byte_ascii.Slash;} + public String VolSpr() {return "<>";} + public boolean CaseSensitive() {return false;} + public boolean Match(String raw) {return false;} + public boolean IsDir(String raw) {return false;} + public String Xto_api(String raw) {return "";} + public String OwnerDir(String raw) {return IoUrlInfo_base.NullString;} + public String OwnerRoot(String raw) {return IoUrlInfo_base.NullString;} + public String NameAndExt(String raw) {return "";} + public String NameOnly(String raw) {return "";} + public String Ext(String raw) {return "";} + public String XtoRootName(String raw, int rawLen) {return "";} + public static final IoUrlInfo_nil _ = new IoUrlInfo_nil(); IoUrlInfo_nil() {} +} +abstract class IoUrlInfo_base implements IoUrlInfo { + @gplx.Internal protected static final int DirSprLen = 1; + @gplx.Internal protected static final String NullString = "", ExtSeparator = "."; + public abstract String Key(); + public abstract byte DirSpr_byte(); + public abstract String DirSpr(); + public abstract boolean CaseSensitive(); + public abstract boolean Match(String raw); + public abstract String EngineKey(); + public boolean IsDir(String raw) {return String_.Has_at_end(raw, DirSpr());} + public abstract String XtoRootName(String raw, int rawLen); + @gplx.Virtual public String Xto_api(String raw) { + return IsDir(raw) + ? String_.DelEnd(raw, IoUrlInfo_base.DirSprLen) // if Dir, remove trailing DirSpr, since most api will not expect it (ex: .Delete will malfunction) + : raw; + } + public String OwnerDir(String raw) { + int rawLen = String_.Len(raw); + int ownerDirSprPos = OwnerDirPos(raw, rawLen); + if (ownerDirSprPos <= OwnerDirPos_hasNoOwner) return IoUrlInfo_base.NullString; // no ownerDir found; return Null; only (a) NullUrls (b) RootUrls ("C:\") (c) relative ("fil.txt") + return String_.MidByLen(raw, 0, ownerDirSprPos + 1); // +1 to include backslash + } + @gplx.Virtual public String OwnerRoot(String raw) { + String temp = raw, rv = raw; + while (true) { + temp = OwnerDir(temp); + if (String_.Eq(temp, IoUrlInfo_base.NullString)) break; + rv = temp; + } + return rv; + } + public String NameAndExt(String raw) { // if Dir, will return \ as last char + int rawLen = String_.Len(raw); + int ownerDirSprPos = OwnerDirPos(raw, rawLen); + if (ownerDirSprPos == OwnerDirPos_isNull) return IoUrlInfo_base.NullString; // NullUrl and RootUrl return Null; + return ownerDirSprPos == OwnerDirPos_hasNoOwner || ownerDirSprPos == OwnerDirPos_isRoot + ? raw // no PathSeparator b/c (a) RootDir ("C:\"); (b) relative ("fil.txt") + : String_.DelBgn(raw, ownerDirSprPos + 1); // +1 to skip backslash + } + public String NameOnly(String raw) { + String nameAndExt = NameAndExt(raw); + if (IsDir(raw)) { + String rootName = XtoRootName(raw, String_.Len(raw)); // C:\ -> C; / -> root + return rootName == null + ? String_.DelEnd(nameAndExt, IoUrlInfo_base.DirSprLen) + : rootName; + } + int pos = String_.FindBwd(nameAndExt, IoUrlInfo_base.ExtSeparator); + return pos == String_.Find_none + ? nameAndExt // Ext not found; return entire NameAndExt + : String_.MidByLen(nameAndExt, 0, pos); + } + public String Ext(String raw) { // if Dir, return DirSpr; if Fil, return . as first char; ex: .txt; .png + if (IsDir(raw)) return this.DirSpr(); + String nameAndExt = NameAndExt(raw); + int pos = String_.FindBwd(nameAndExt, IoUrlInfo_base.ExtSeparator); + return pos == String_.Find_none ? "" : String_.DelBgn(nameAndExt, pos); + } + int OwnerDirPos(String raw, int rawLen) { + if (rawLen == 0) return OwnerDirPos_isNull; + else if (XtoRootName(raw, rawLen) != null) return OwnerDirPos_isRoot; + else {// NullUrls and RootUrls have no owners + int posAdj = IsDir(raw) ? IoUrlInfo_base.DirSprLen : 0; // Dir ends with DirSpr, adjust lastIndex by DirSprLen + return String_.FindBwd(raw, this.DirSpr(), rawLen - 1 - posAdj); // -1 to adjust for LastIdx + } + } + static final int + OwnerDirPos_hasNoOwner = -1 // List_adp_.NotFound + , OwnerDirPos_isNull = -2 + , OwnerDirPos_isRoot = -3; +} +class IoUrlInfo_wnt extends IoUrlInfo_base { + @Override public String Key() {return "wnt";} + @Override public String EngineKey() {return IoEngine_.SysKey;} + @Override public String DirSpr() {return Op_sys.Wnt.Fsys_dir_spr_str();} + @Override public byte DirSpr_byte() {return Byte_ascii.Backslash;} + @Override public boolean CaseSensitive() {return Op_sys.Wnt.Fsys_case_match();} + @Override public boolean Match(String raw) {return String_.Len(raw) > 1 && String_.CharAt(raw, 1) == ':';} // 2nd char is :; assumes 1 letter drives + @Override public String XtoRootName(String raw, int rawLen) { + return rawLen == 3 && String_.CharAt(raw, 1) == ':' // only allow single letter drives; ex: C:\; note, CharAt(raw, 1) to match Match + ? Char_.XtoStr(String_.CharAt(raw, 0)) + : null; + } + public static final IoUrlInfo_wnt _ = new IoUrlInfo_wnt(); IoUrlInfo_wnt() {} +} +class IoUrlInfo_lnx extends IoUrlInfo_base { + @Override public String Key() {return "lnx";} + @Override public String EngineKey() {return IoEngine_.SysKey;} + @Override public String DirSpr() {return DirSprStr;} static final String DirSprStr = Op_sys.Lnx.Fsys_dir_spr_str(); + @Override public byte DirSpr_byte() {return Byte_ascii.Slash;} + @Override public boolean CaseSensitive() {return Op_sys.Lnx.Fsys_case_match();} + @Override public boolean Match(String raw) {return String_.Has_at_bgn(raw, DirSprStr);} // anything that starts with / + @Override public String XtoRootName(String raw, int rawLen) { + return rawLen == 1 && String_.Eq(raw, DirSprStr) + ? "root" + : null; + } + @Override public String OwnerRoot(String raw) {return DirSprStr;} // drive is always / + @Override public String Xto_api(String raw) { + return String_.Eq(raw, DirSprStr) // is root + ? DirSprStr + : super.Xto_api(raw); // NOTE: super.Xto_api will strip off last / + } + public static final IoUrlInfo_lnx _ = new IoUrlInfo_lnx(); IoUrlInfo_lnx() {} +} +class IoUrlInfo_rel extends IoUrlInfo_base { + @Override public String Key() {return "rel";} + @Override public String EngineKey() {return IoEngine_.SysKey;} + @Override public String DirSpr() {return info.DirSpr();} + @Override public byte DirSpr_byte() {return info.DirSpr_byte();} + @Override public boolean CaseSensitive() {return info.CaseSensitive();} + @Override public String XtoRootName(String raw, int rawLen) {return info.XtoRootName(raw, rawLen);} + @Override public boolean Match(String raw) {return true;} // relPath is always lastResort; return true + IoUrlInfo info; + public static IoUrlInfo_rel new_(IoUrlInfo info) { + IoUrlInfo_rel rv = new IoUrlInfo_rel(); + rv.info = info; + return rv; + } IoUrlInfo_rel() {} +} +class IoUrlInfo_mem extends IoUrlInfo_base { + @Override public String Key() {return key;} private String key; + @Override public String EngineKey() {return engineKey;} private String engineKey; + @Override public String DirSpr() {return "/";} + @Override public byte DirSpr_byte() {return Byte_ascii.Slash;} + @Override public boolean CaseSensitive() {return false;} + @Override public String XtoRootName(String raw, int rawLen) { + return String_.Eq(raw, key) ? String_.DelEnd(key, 1) : null; + } + @Override public boolean Match(String raw) {return String_.Has_at_bgn(raw, key);} + public static IoUrlInfo_mem new_(String key, String engineKey) { + IoUrlInfo_mem rv = new IoUrlInfo_mem(); + rv.key = key; rv.engineKey = engineKey; + return rv; + } IoUrlInfo_mem() {} +} +class IoUrlInfo_alias extends IoUrlInfo_base { + @Override public String Key() {return srcDir;} + @Override public String EngineKey() {return engineKey;} private String engineKey; + @Override public String DirSpr() {return srcDirSpr;} + @Override public byte DirSpr_byte() {return srcDirSpr_byte;} private byte srcDirSpr_byte; + @Override public boolean CaseSensitive() {return false;} + @Override public String XtoRootName(String raw, int rawLen) { + return String_.Eq(raw, srcRootDir) ? srcRootName : null; + } + @Override public boolean Match(String raw) {return String_.Has_at_bgn(raw, srcDir);} + @Override public String Xto_api(String raw) { + String rv = String_.Replace(raw, srcDir, trgDir); // replace src with trg + if (!String_.Eq(srcDirSpr, trgDirSpr)) rv = String_.Replace(rv, srcDirSpr, trgDirSpr); // replace dirSprs + return IsDir(raw) + ? String_.DelEnd(rv, IoUrlInfo_base.DirSprLen) // remove trailingSeparator, else Directory.Delete will not work properly + : rv; + } + void SrcDir_set(String v) { + srcDir = v; + boolean lnx = DirSpr_lnx(v); + if (srcDirSpr == null) { + if (lnx) { + srcDirSpr = Op_sys.Lnx.Fsys_dir_spr_str(); + srcDirSpr_byte = Op_sys.Lnx.Fsys_dir_spr_byte(); + } + else { + srcDirSpr = Op_sys.Wnt.Fsys_dir_spr_str(); + srcDirSpr_byte = Op_sys.Wnt.Fsys_dir_spr_byte(); + } + } + if (srcRootName == null) srcRootName = lnx ? "root" : String_.Mid(srcDir, 0, String_.FindFwd(srcDir, ":")); + if (srcRootDir == null) srcRootDir = lnx ? "/" : srcDir; + } + void TrgDir_set(String v) { + trgDir = v; + boolean lnx = DirSpr_lnx(v); + if (trgDirSpr == null) trgDirSpr = lnx ? Op_sys.Lnx.Fsys_dir_spr_str() : Op_sys.Wnt.Fsys_dir_spr_str(); + } + boolean DirSpr_lnx(String s) {return String_.Has(s, Op_sys.Lnx.Fsys_dir_spr_str());} + void EngineKey_set(String v) {engineKey = v;} + String srcDir, trgDir, srcDirSpr, trgDirSpr, srcRootDir, srcRootName; + public static IoUrlInfo_alias new_(String srcDir, String trgDir, String engineKey) { + IoUrlInfo_alias rv = new IoUrlInfo_alias(); + rv.SrcDir_set(srcDir); + rv.TrgDir_set(trgDir); + rv.EngineKey_set(engineKey); + return rv; + } + public static final IoUrlInfo_alias KEYS = new IoUrlInfo_alias(); + public final String + Data_EngineKey = "engineKey" + , Data_SrcDir = "srcDir" + , Data_TrgDir = "trgDir" + ; +} diff --git a/100_core/src_200_io/gplx/ios/IoUrlInfoRegy.java b/100_core/src_200_io/gplx/ios/IoUrlInfoRegy.java new file mode 100644 index 000000000..a20bb3c0f --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoUrlInfoRegy.java @@ -0,0 +1,52 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +public class IoUrlInfoRegy implements GfoInvkAble { + public void Reg(IoUrlInfo info) {hash.Add_if_dupe_use_nth(info.Key(), info);} + public IoUrlInfo Match(String raw) { + if (String_.Len(raw) == 0) return IoUrlInfo_.Nil; + for (int i = hash.Count(); i > 0; i--) { + IoUrlInfo info = (IoUrlInfo)hash.Get_at(i - 1); + if (info.Match(raw)) return info; + } + throw Exc_.new_("could not match ioPathInfo", "raw", raw, "count", hash.Count()); + } + public void Reset() { + hash.Clear(); + Reg(IoUrlInfo_rel.new_(Op_sys.Cur().Tid_is_wnt() ? (IoUrlInfo)IoUrlInfo_wnt._ : (IoUrlInfo)IoUrlInfo_lnx._)); + Reg(IoUrlInfo_.Mem); + Reg(IoUrlInfo_lnx._); + Reg(IoUrlInfo_wnt._); + } + public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) { + if (ctx.Match(k, Invk_Add)) { + String srcDirStr = m.ReadStr("srcDir"); + String trgDirStr = m.ReadStr("trgDir"); + String engineKey = m.ReadStrOr("engineKey", IoEngine_.SysKey); + if (ctx.Deny()) return this; + IoUrlInfo_alias alias = IoUrlInfo_alias.new_(srcDirStr, trgDirStr, engineKey); + IoUrlInfoRegy._.Reg(alias); + } + return this; + } public static final String Invk_Add = "Add"; + Ordered_hash hash = Ordered_hash_.new_(); + public static final IoUrlInfoRegy _ = new IoUrlInfoRegy(); + IoUrlInfoRegy() { + this.Reset(); + } +} \ No newline at end of file diff --git a/100_core/src_200_io/gplx/ios/IoUrlInfo_.java b/100_core/src_200_io/gplx/ios/IoUrlInfo_.java new file mode 100644 index 000000000..897e320fa --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoUrlInfo_.java @@ -0,0 +1,34 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +public class IoUrlInfo_ { + public static final IoUrlInfo Nil = IoUrlInfo_nil._; + public static final IoUrlInfo Wnt = IoUrlInfo_wnt._; + public static final IoUrlInfo Lnx = IoUrlInfo_lnx._; + public static final IoUrlInfo Mem = IoUrlInfo_mem.new_("mem", IoEngine_.MemKey); + + public static IoUrlInfo mem_(String key, String engineKey) {return IoUrlInfo_mem.new_(key, engineKey);} + public static IoUrlInfo alias_(String srcRoot, String trgRoot, String engineKey) {return IoUrlInfo_alias.new_(srcRoot, trgRoot, engineKey);} +} +/* +wnt C:\dir\fil.txt +wce \dir\fil.txt +lnx /dir/fil.txt +mem mem/dir/fil.txt +alias app:\dir\fil.txt +*/ \ No newline at end of file diff --git a/100_core/src_200_io/gplx/ios/IoUrlTypeRegy.java b/100_core/src_200_io/gplx/ios/IoUrlTypeRegy.java new file mode 100644 index 000000000..d176fc46b --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoUrlTypeRegy.java @@ -0,0 +1,76 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import gplx.core.strings.*; +public class IoUrlTypeRegy implements GfoInvkAble { + public String[] FetchAryOr(String key, String... or) { + IoUrlTypeGrp itm = (IoUrlTypeGrp)hash.Get_by(key); + return itm == null ? or : itm.AsAry(); + } + public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) { + if (ctx.Match(k, Invk_Get)) { + String key = m.ReadStr(k); + if (ctx.Deny()) return this; + IoUrlTypeGrp itm = (IoUrlTypeGrp)hash.Get_by(key); + if (itm == null) { + itm = new IoUrlTypeGrp(key); + hash.Add(key, itm); + } + return itm; + } + else return GfoInvkAble_.Rv_unhandled; +// return this; + } public static final String Invk_Get = "Get"; + Ordered_hash hash = Ordered_hash_.new_(); + public static final IoUrlTypeRegy _ = new IoUrlTypeRegy(); IoUrlTypeRegy() {} +} +class IoUrlTypeGrp implements GfoInvkAble { + public String[] AsAry() { + String[] rv = new String[list.Count()]; + for (int i = 0; i < list.Count(); i++) + rv[i] = (String)list.Get_at(i); + return rv; + } + Ordered_hash list = Ordered_hash_.new_(); + public IoUrlTypeGrp(String key) {this.key = key;} private String key; + public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) { + if (ctx.Match(k, Invk_AddMany)) { + if (ctx.Deny()) return this; + for (int i = 0; i < m.Args_count(); i++) { + String s = m.ReadStr("v"); + if (list.Has(s)) { + ctx.Write_warn(UsrMsg.new_("itm already has filter").Add("key", key).Add("filter", s).XtoStr()); + list.Del(s); + } + list.Add(s, s); + } + } + else if (ctx.Match(k, Invk_Print)) { + if (ctx.Deny()) return this; + String_bldr sb = String_bldr_.new_(); + sb.Add(key).Add("{"); + for (int i = 0; i < list.Count(); i++) + sb.Add_spr_unless_first((String)list.Get_at(i), " ", i); + sb.Add("}"); + return sb.XtoStr(); + } + else if (ctx.Match(k, Invk_Clear)) {if (ctx.Deny()) return this; list.Clear();} + else return GfoInvkAble_.Rv_unhandled; + return this; + } public static final String Invk_AddMany = "Add_many", Invk_Clear = "Clear", Invk_Print = "Print"; +} diff --git a/100_core/src_200_io/gplx/ios/IoZipWkr.java b/100_core/src_200_io/gplx/ios/IoZipWkr.java new file mode 100644 index 000000000..f3d015f46 --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoZipWkr.java @@ -0,0 +1,40 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import gplx.stores.*; /*GfoNdeRdr_*/ +public class IoZipWkr { + public Io_url ExeUrl() {return (Io_url)GfoRegy._.FetchValOrFail(Regy_ExeUrl);} + public String ExeArgFmt() {return (String)GfoRegy._.FetchValOrFail(Regy_ExeArgFmt);} + public void Expand(Io_url srcUrl, Io_url trgUrl) { + String exeArgs = Expand_genCmdString(srcUrl, trgUrl); + process.Exe_url_(this.ExeUrl()).Args_str_(exeArgs); + process.Run_wait(); + } + @gplx.Internal protected String Expand_genCmdString(Io_url srcUrl, Io_url trgUrl) { + return String_.Format(this.ExeArgFmt(), srcUrl.Xto_api(), trgUrl.Xto_api()); + } + ProcessAdp process = new ProcessAdp(); + public static IoZipWkr regy_() {return new IoZipWkr();} + static final String Regy_ExeUrl = "gplx.ios.IoZipWkr.ExeUrl", Regy_ExeArgFmt = "gplx.ios.IoZipWkr.ExeArgFmt"; + public static IoZipWkr new_(Io_url exeUrl, String expandArgs) { + GfoRegy._.RegObj(Regy_ExeUrl, exeUrl); + GfoRegy._.RegObj(Regy_ExeArgFmt, expandArgs); + IoZipWkr rv = new IoZipWkr(); + return rv; + } +} diff --git a/100_core/src_200_io/gplx/ios/IoZipWkr_tst.java b/100_core/src_200_io/gplx/ios/IoZipWkr_tst.java new file mode 100644 index 000000000..0e84395c1 --- /dev/null +++ b/100_core/src_200_io/gplx/ios/IoZipWkr_tst.java @@ -0,0 +1,28 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import org.junit.*; +public class IoZipWkr_tst { + @Test public void Basic() { + wkr = IoZipWkr.new_(Io_url_.Empty, "e \"{0}\" -o\"{1}\" -y"); + tst_Expand_genCmdString(Io_url_.wnt_fil_("C:\\fil1.zip"), Io_url_.wnt_dir_("D:\\out\\"), "e \"C:\\fil1.zip\" -o\"D:\\out\" -y"); // NOTE: not "D:\out\" because .Xto_api + } IoZipWkr wkr; + void tst_Expand_genCmdString(Io_url srcUrl, Io_url trgUrl, String expd) { + Tfds.Eq(expd, wkr.Expand_genCmdString(srcUrl, trgUrl)); + } +} diff --git a/100_core/src_200_io/gplx/ios/Io_download_fmt.java b/100_core/src_200_io/gplx/ios/Io_download_fmt.java new file mode 100644 index 000000000..c0c3c97f3 --- /dev/null +++ b/100_core/src_200_io/gplx/ios/Io_download_fmt.java @@ -0,0 +1,94 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import gplx.brys.*; +public class Io_download_fmt { + private final Io_size_fmtr_arg size_fmtr_arg = new Io_size_fmtr_arg(), rate_fmtr_arg = new Io_size_fmtr_arg().Suffix_(Bry_.new_a7("ps")); + private final Bry_fmtr_arg_time prog_left_fmtr_arg = new Bry_fmtr_arg_time(); private final Bry_fmtr_arg_decimal_int prog_pct_fmtr_arg = new Bry_fmtr_arg_decimal_int().Places_(2); + private long time_checkpoint_interval = 250; + private long time_checkpoint = 0; + private long time_prv = 0; + public Io_download_fmt() { + this.src_name = prog_msg_hdr = ""; // NOTE: set to "" else prog_mgr will fail with null ref + } + private final Bry_bfr prog_bfr = Bry_bfr.new_(); Bry_fmtr prog_fmtr = Bry_fmtr.new_().Fail_when_invalid_escapes_(false); // NOTE: prog_fmtr can be passed file_names with ~ which are not easy to escape; DATE:2013-02-19 + public long Time_bgn() {return time_bgn;} private long time_bgn; + public long Time_now() {return time_now;} private long time_now; + public long Time_dif() {return time_dif;} private long time_dif; + public long Time_end() {return time_end;} private long time_end; + public String Src_url() {return src_url;} private String src_url; + public String Src_name() {return src_name;} private String src_name; + public long Src_len() {return src_len;} private long src_len; + public long Prog_done() {return prog_done;} private long prog_done; + public long Prog_rate() {return prog_rate;} private long prog_rate; + public long Prog_left() {return prog_left;} private long prog_left; + public long Prog_pct() {return prog_pct;} private long prog_pct; + public String Prog_msg_hdr() {return prog_msg_hdr;} private String prog_msg_hdr; + public int Prog_num_units() {return prog_num_units;} private int prog_num_units = Io_mgr.Len_kb; + public String Prog_num_fmt() {return prog_num_fmt;} private String prog_num_fmt = "#,##0"; + public String Prog_msg() {return prog_msg;} private String prog_msg; + public Gfo_usr_dlg Usr_dlg() {return usr_dlg;} private Gfo_usr_dlg usr_dlg; + public void Ctor(Gfo_usr_dlg usr_dlg) { + this.usr_dlg = usr_dlg; + } + public void Download_init(String src_url, String prog_msg_hdr) { + this.src_url = src_url; + this.src_name = String_.Extract_after_bwd(src_url, "/"); + this.prog_msg_hdr = prog_msg_hdr; + } + public void Bgn(long src_len) { + this.src_len = src_len; + prog_fmtr.Fmt_(prog_msg_hdr).Keys_("src_name", "src_len").Bld_bfr_many_and_set_fmt(src_name, size_fmtr_arg.Val_(src_len)); + prog_fmtr.Keys_("prog_done", "prog_pct", "prog_rate", "prog_left"); + prog_done = 0; + prog_pct = 0; + prog_rate = 0; + prog_left = 0; + time_bgn = time_prv = Env_.TickCount(); + time_checkpoint = 0; + } + public void Prog(int prog_read) { + time_now = Env_.TickCount(); + time_dif = time_now - time_bgn; if (time_dif == 0) time_dif = 1; // avoid div by zero error below + prog_done += prog_read; + time_checkpoint += time_now - time_prv; + time_prv = time_now; + if ((time_checkpoint < time_checkpoint_interval)) return; // NOTE: using time_checkpoint instead of size_checkpoint b/c WMF dump servers transfer in spurts (sends 5 packets, and then waits); + time_checkpoint = 0; + prog_rate = (prog_done * 1000) / (time_dif); + prog_pct = (prog_done * 10000) / src_len; // 100 00 to get 2 decimal places; EX: .1234 -> 1234 -> 12.34% + prog_left = (1000 * (src_len - prog_done)) / prog_rate; + prog_fmtr.Bld_bfr_many(prog_bfr + , size_fmtr_arg.Val_(prog_done) + , prog_pct_fmtr_arg.Val_((int)prog_pct) + , rate_fmtr_arg.Val_(prog_rate) + , prog_left_fmtr_arg.Seconds_(prog_left / 1000) + ); + prog_msg = prog_bfr.Xto_str_and_clear(); + if (usr_dlg != null) + usr_dlg.Prog_none("", "prog", prog_msg); + } + public void Term() { + time_end = Env_.TickCount(); +// prog_rate = (prog_done * 1000) / (time_dif); +// prog_pct = (prog_done * 10000) / src_len; // 100 00 to get 2 decimal places; EX: .1234 -> 1234 -> 12.34% +// prog_left = (1000 * (src_len - prog_done)) / prog_rate; +// if (usr_dlg != null) usr_dlg.Prog_none(GRP_KEY, "clear", ""); + } + public static final Io_download_fmt Null = null; +} diff --git a/100_core/src_200_io/gplx/ios/Io_download_fmt_tst.java b/100_core/src_200_io/gplx/ios/Io_download_fmt_tst.java new file mode 100644 index 000000000..dff9305ce --- /dev/null +++ b/100_core/src_200_io/gplx/ios/Io_download_fmt_tst.java @@ -0,0 +1,73 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import org.junit.*; +public class Io_download_fmt_tst { + Io_download_fmt_fxt fxt = new Io_download_fmt_fxt(); + @Before public void init() {fxt.Clear();} + @Test public void Fmt() { + fxt.Clear().Ini("downloading ~{src_name}: ~{prog_left} left (@ ~{prog_rate}); ~{prog_done} of ~{src_len} (~{prog_pct}%)", "http://a.org/b.png", Io_mgr.Len_kb * 10); + fxt.Now_add_f(1000).Prog_done_(1 * Io_mgr.Len_kb).Prog_pct_(1 * 1000).Prog_rate_(Io_mgr.Len_kb).Prog_left_(9 * 1000) + .Prog_msg_("downloading b.png: 09s left (@ 1.000 KBps); 1.000 KB of 10.000 KB (10.00%)") + .Download_(Io_mgr.Len_kb); + fxt.Now_add_f(1000).Prog_done_(2 * Io_mgr.Len_kb).Prog_pct_(2 * 1000).Prog_rate_(Io_mgr.Len_kb).Prog_left_(8 * 1000) + .Prog_msg_("downloading b.png: 08s left (@ 1.000 KBps); 2.000 KB of 10.000 KB (20.00%)") + .Download_(Io_mgr.Len_kb) + ; + fxt.Now_add_f(2000).Prog_done_(3 * Io_mgr.Len_kb).Prog_pct_(3 * 1000).Prog_rate_(768).Prog_left_(9333) + .Prog_msg_("downloading b.png: 09s left (@ 768.000 Bps); 3.000 KB of 10.000 KB (30.00%)") + .Download_(Io_mgr.Len_kb) + ; + } + @Test public void Tilde() { + fxt.Clear().Ini("a~b", "http://a.org/b.png", Io_mgr.Len_kb * 10); + } +} +class Io_download_fmt_fxt { + public Io_download_fmt_fxt Clear() { + if (fmt == null) { + fmt = new Io_download_fmt(); + } + Env_.TickCount_Test = 0; + prog_done = prog_rate = prog_pct = prog_left = -1; + prog_msg = null; + return this; + } Io_download_fmt fmt; + public Io_download_fmt_fxt Now_add_f(int v) {Env_.TickCount_Test += v; return this;} + public Io_download_fmt_fxt Prog_done_(int v) {prog_done = v; return this;} long prog_done = -1; + public Io_download_fmt_fxt Prog_pct_ (int v) {prog_pct = v; return this;} long prog_pct = -1; + public Io_download_fmt_fxt Prog_rate_(int v) {prog_rate = v; return this;} long prog_rate = -1; + public Io_download_fmt_fxt Prog_left_(int v) {prog_left = v; return this;} long prog_left = -1; + public Io_download_fmt_fxt Prog_msg_(String v) { + prog_msg = v; return this; + } String prog_msg; + public Io_download_fmt_fxt Download_(int v) { + fmt.Prog(v); + if (prog_done != -1) Tfds.Eq(prog_done, fmt.Prog_done(), "prog_done"); + if (prog_pct != -1) Tfds.Eq(prog_pct , fmt.Prog_pct(), "prog_pct"); + if (prog_rate != -1) Tfds.Eq(prog_rate, fmt.Prog_rate(), "prog_rate"); + if (prog_left != -1) Tfds.Eq(prog_left, fmt.Prog_left(), "prog_left"); + if (prog_msg != null) Tfds.Eq(prog_msg, fmt.Prog_msg(), "prog_msg"); + return this; + } + public Io_download_fmt_fxt Ini(String prog_msg_hdr, String src_url, int src_len) { + fmt.Download_init(src_url, prog_msg_hdr); + fmt.Bgn(src_len); + return this; + } +} diff --git a/100_core/src_200_io/gplx/ios/Io_fil.java b/100_core/src_200_io/gplx/ios/Io_fil.java new file mode 100644 index 000000000..b921d5a74 --- /dev/null +++ b/100_core/src_200_io/gplx/ios/Io_fil.java @@ -0,0 +1,38 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +public class Io_fil implements gplx.CompareAble { + public Io_fil(Io_url url, String data) {this.url = url; this.data = data;} + public Io_url Url() {return url;} public Io_fil Url_(Io_url v) {url = v; return this;} Io_url url; + public String Data() {return data;} public Io_fil Data_(String v) {data = v; return this;} private String data; + public int compareTo(Object obj) { + return gplx.CompareAble_.Compare(url.Raw(), ((Io_fil)obj).Url().Raw()); + } + public static Io_fil[] new_ary_(Io_url[] url_ary) { + int url_ary_len = url_ary.length; + Io_fil[] rv = new Io_fil[url_ary_len]; + for (int i = 0; i < url_ary_len; i++) { + Io_url url = url_ary[i]; + String data = Io_mgr.I.LoadFilStr(url); + Io_fil fil = new Io_fil(url, data); + rv[i] = fil; + } + return rv; + } + public static final Io_fil[] Ary_empty = new Io_fil[0]; +} diff --git a/100_core/src_200_io/gplx/ios/Io_fil_mkr.java b/100_core/src_200_io/gplx/ios/Io_fil_mkr.java new file mode 100644 index 000000000..09f38a499 --- /dev/null +++ b/100_core/src_200_io/gplx/ios/Io_fil_mkr.java @@ -0,0 +1,24 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +public class Io_fil_mkr { + private final List_adp list = List_adp_.new_(); + public Io_fil_mkr Add(String url, String data) {return Add(Io_url_.mem_fil_(url), data);} + public Io_fil_mkr Add(Io_url url, String data) {list.Add(new Io_fil(url, data)); return this;} + public Io_fil[] To_ary() {return (Io_fil[])list.To_ary(Io_fil.class);} +} diff --git a/100_core/src_200_io/gplx/ios/Io_size_.java b/100_core/src_200_io/gplx/ios/Io_size_.java new file mode 100644 index 000000000..4d9a29976 --- /dev/null +++ b/100_core/src_200_io/gplx/ios/Io_size_.java @@ -0,0 +1,116 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +public class Io_size_ { + public static String To_str(long val) { + long cur = val; int pow = 0; + while (cur >= 1024) { + cur /= 1024; + pow++; + } + long div = (long)Math_.Pow((long)1024, (long)pow); + DecimalAdp valDecimal = DecimalAdp_.divide_(val, div); + String[] unit = Io_size_.Units[pow]; + return valDecimal.Xto_str("#,##0.000") + " " + String_.PadBgn(unit[0], 2, " "); + } + public static String To_str(long val, int exp_1024, String val_fmt, String unit_pad, boolean round_0_to_1) { + long exp_val = (long)Math_.Pow(1024, exp_1024); + DecimalAdp val_as_decimal = DecimalAdp_.divide_(val, exp_val); + if (round_0_to_1 && val_as_decimal.Comp_lt(1)) val_as_decimal = DecimalAdp_.One; + String[] unit = Io_size_.Units[exp_1024]; + return val_as_decimal.Xto_str(val_fmt) + " " + String_.PadBgn(unit[0], 2, unit_pad); + } + public static long parse_or_(String raw, long or) { + if (raw == null || raw == String_.Empty) return or; + String[] terms = String_.Split(raw, " "); + int termsLen = Array_.Len(terms); if (termsLen > 2) return or; + + DecimalAdp val = null; + try {val = DecimalAdp_.parse_(terms[0]);} catch (Exception exc) {Exc_.Noop(exc); return or;} + + int unitPow = 0; + if (termsLen > 1) { + String unitStr = String_.Upper(terms[1]); + unitPow = parse_unitPow_(unitStr); if (unitPow == -1) return or; + } + int curPow = unitPow; + while (curPow > 0) { + val = val.Op_mult(1024); + curPow--; + } + // DELETED:do not check for fractional bytes; EX: 10.7 GB DATE:2015-01-06 + // DecimalAdp comp = val.Op_truncate_decimal(); + // if (!val.Eq(comp)) return or; + return val.Xto_long(); + } + private static int parse_unitPow_(String unitStr) { + int unitLen = Array_.Len(Units); + int unitPow = -1; + for (int i = 0; i < unitLen; i++) { + if (String_.Eq(unitStr, String_.Upper(Units[i][0]))) return i; + if (String_.Eq(unitStr, String_.Upper(Units[i][1]))) return i; + } + return unitPow; + } + private static final String[][] Units = new String[][] + { String_.Ary("B", "BYTE") + , String_.Ary("KB", "KILOBYTE") + , String_.Ary("MB", "MEGABYTE") + , String_.Ary("GB", "GIGABYTE") + , String_.Ary("TB", "TERABYTE") + , String_.Ary("PB", "PETABYTE") + , String_.Ary("EB", "EXABYTE") + }; + public static final byte[][] Units_bry = new byte[][] + { Bry_.new_a7("B") + , Bry_.new_a7("KB") + , Bry_.new_a7("MB") + , Bry_.new_a7("GB") + , Bry_.new_a7("TB") + , Bry_.new_a7("PB") + , Bry_.new_a7("EB") + }; + public static int Load_int_(GfoMsg m) {return (int)Load_long_(m);} + public static long Load_long_(GfoMsg m) { + String v = m.ReadStr("v"); + long rv = parse_or_(v, Long_.MinValue); if (rv == Long_.MinValue) throw Exc_.new_("invalid val", "val", v); + return rv; + } + public static String To_str_mb(long v) {return Long_.Xto_str(v / Io_mgr.Len_mb_long);} + public static long To_long_by_int_mb(int v) {return (long)v * Io_mgr.Len_mb_long;} + public static long To_long_by_msg_mb(GfoMsg m, long cur) { + long val = m.ReadLongOr("v", Int_.MinValue); + return val == Int_.MinValue ? cur : (val * Io_mgr.Len_mb_long); + } +} +class Io_size_fmtr_arg implements Bry_fmtr_arg { + public long Val() {return val;} public Io_size_fmtr_arg Val_(long v) {val = v; return this;} long val; + public byte[] Suffix() {return suffix;} public Io_size_fmtr_arg Suffix_(byte[] v) {suffix = v; return this;} private byte[] suffix; + public void XferAry(Bry_bfr bfr, int idx) { + long cur = val; int pow = 0; + while (cur >= 1024) { + cur /= 1024; + pow++; + } + long div = (long)Math_.Pow((long)1024, (long)pow); + DecimalAdp val_decimal = DecimalAdp_.divide_(val, div); + bfr.Add_str(val_decimal.Xto_str("#,###.000")).Add_byte(Byte_ascii.Space).Add(gplx.ios.Io_size_.Units_bry[pow]); + if (suffix != null) + bfr.Add(suffix); + } +} diff --git a/100_core/src_200_io/gplx/ios/Io_size__tst.java b/100_core/src_200_io/gplx/ios/Io_size__tst.java new file mode 100644 index 000000000..46c64fdd6 --- /dev/null +++ b/100_core/src_200_io/gplx/ios/Io_size__tst.java @@ -0,0 +1,69 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import org.junit.*; +public class Io_size__tst { + private Io_size__fxt fxt = new Io_size__fxt(); + @Test public void XtoLong() { + fxt.Test_XtoLong("1", 1); + fxt.Test_XtoLong("1 KB", 1024); + fxt.Test_XtoLong("1 MB", 1024 * 1024); + fxt.Test_XtoLong("1 GB", 1024 * 1024 * 1024); + fxt.Test_XtoLong("12 kb", 12 * 1024); + fxt.Test_XtoLong("1.5 kb", 1024 + 512); // 1536 + fxt.Test_XtoLong("1.5 mb", (long)(1024 * 1024 * 1.5)); + fxt.Test_XtoLong("-1", -1); // NOTE: negative bytes allowed + + fxt.Test_XtoLongFail("1 kilobite"); + fxt.Test_XtoLongFail("1 BB"); + // fxt.Test_XtoLongFail("1.1"); // DELETED:do not check for fractional bytes; EX: 10.7 GB DATE:2015-01-06 + // fxt.Test_XtoLongFail("1.51 kb"); + } + @Test public void XtoStr() { + fxt.Test_XtoStr(1, "1.000 B"); + fxt.Test_XtoStr(1024, "1.000 KB"); + fxt.Test_XtoStr(1536, "1.500 KB"); + fxt.Test_XtoStr(1024 * 1024, "1.000 MB"); + fxt.Test_XtoStr(1016, "1,016.000 B"); // NOTE: 1016 is not 1.016 KB + } + @Test public void Xto_str_full() { + fxt.Test_Xto_str( 500, 1, "#,###", " ", Bool_.Y, "1 KB"); + fxt.Test_Xto_str( 1000, 1, "#,###", " ", Bool_.Y, "1 KB"); + fxt.Test_Xto_str( 2000, 1, "#,###", " ", Bool_.Y, "2 KB"); + fxt.Test_Xto_str( 1234567, 1, "#,###", " ", Bool_.Y, "1,206 KB"); + fxt.Test_Xto_str(1234567890, 1, "#,###", " ", Bool_.Y, "1,205,633 KB"); + } + @Test public void EqualsTest() { + fxt.Test_Equals("1", "1"); + fxt.Test_Equals("1 kb", "1 kb"); + fxt.Test_Equals("1024", "1 kb"); + fxt.Test_Equals("1048576", "1 mb"); + fxt.Test_Equals("1024 kb", "1 mb"); + fxt.Test_Equals("1.5 kb", "1536 b"); + } +} +class Io_size__fxt { + public void Test_XtoLong(String raw, long expd) {Tfds.Eq(expd, Io_size_.parse_or_(raw, Long_.MinValue));} + public void Test_XtoLongFail(String raw) { + long val = Io_size_.parse_or_(raw, Long_.MinValue); + if (val != Long_.MinValue) Tfds.Fail("expd parse failure; raw=" + raw); + } + public void Test_Equals(String lhs, String rhs) {Tfds.Eq(Io_size_.parse_or_(lhs, Long_.MinValue), Io_size_.parse_or_(rhs, Long_.MinValue));} + public void Test_XtoStr(long val, String expd) {Tfds.Eq(expd, Io_size_.To_str(val));} + public void Test_Xto_str(long val, int exp_1024, String val_fmt, String unit_pad, boolean round_0_to_1, String expd) {Tfds.Eq(expd, Io_size_.To_str(val, exp_1024, val_fmt, unit_pad, round_0_to_1));} +} diff --git a/100_core/src_200_io/gplx/ios/Io_stream_.java b/100_core/src_200_io/gplx/ios/Io_stream_.java new file mode 100644 index 000000000..600e6349c --- /dev/null +++ b/100_core/src_200_io/gplx/ios/Io_stream_.java @@ -0,0 +1,55 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +public class Io_stream_ { // SERIALIZED + public static final byte Tid_null = 0, Tid_raw = 1, Tid_zip = 2, Tid_gzip = 3, Tid_bzip2 = 4; + public static final String Ext_zip = ".zip", Ext_gz = ".gz", Ext_bz2 = ".bz2"; + + public static String Obsolete_to_str(byte v) { + switch (v) { + case Io_stream_.Tid_raw : return ".xdat"; + case Io_stream_.Tid_zip : return ".zip"; + case Io_stream_.Tid_gzip : return ".gz"; + case Io_stream_.Tid_bzip2 : return ".bz2"; + default : throw Exc_.new_unhandled(v); + } + } + public static byte Obsolete_to_tid(String v) { + if (String_.Eq(v, ".xdat")) return Io_stream_.Tid_raw; + else if (String_.Eq(v, ".zip")) return Io_stream_.Tid_zip; + else if (String_.Eq(v, ".gz")) return Io_stream_.Tid_gzip; + else if (String_.Eq(v, ".bz2")) return Io_stream_.Tid_bzip2; + else throw Exc_.new_unhandled(v); + } + public static String To_str(byte v) { + switch (v) { + case Io_stream_.Tid_raw : return "raw"; + case Io_stream_.Tid_zip : return "zip"; + case Io_stream_.Tid_gzip : return "gzip"; + case Io_stream_.Tid_bzip2 : return "bzip2"; + default : throw Exc_.new_unhandled(v); + } + } + public static byte To_tid(String v) { + if (String_.Eq(v, "raw")) return Io_stream_.Tid_raw; + else if (String_.Eq(v, "zip")) return Io_stream_.Tid_zip; + else if (String_.Eq(v, "gzip")) return Io_stream_.Tid_gzip; + else if (String_.Eq(v, "bzip2")) return Io_stream_.Tid_bzip2; + else throw Exc_.new_unhandled(v); + } +} diff --git a/100_core/src_200_io/gplx/ios/Io_stream_rdr.java b/100_core/src_200_io/gplx/ios/Io_stream_rdr.java new file mode 100644 index 000000000..3b5585a0a --- /dev/null +++ b/100_core/src_200_io/gplx/ios/Io_stream_rdr.java @@ -0,0 +1,30 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +public interface Io_stream_rdr extends RlsAble { + byte Tid(); + boolean Exists(); + Io_url Url(); Io_stream_rdr Url_(Io_url v); + long Len(); Io_stream_rdr Len_(long v); + Io_stream_rdr Open(); + void Open_mem(byte[] v); + Object Under(); + + int Read(byte[] bry, int bgn, int len); + long Skip(long len); +} diff --git a/100_core/src_200_io/gplx/ios/Io_stream_rdr_.java b/100_core/src_200_io/gplx/ios/Io_stream_rdr_.java new file mode 100644 index 000000000..5f445c47a --- /dev/null +++ b/100_core/src_200_io/gplx/ios/Io_stream_rdr_.java @@ -0,0 +1,266 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +public class Io_stream_rdr_ { + public static Io_stream_rdr file_(Io_url url) {return new Io_stream_rdr_file().Url_(url);} + public static Io_stream_rdr file_(java.io.InputStream strm) {return new Io_stream_rdr_file().Under_(strm);} + public static Io_stream_rdr zip_(Io_url url) {return new Io_stream_rdr_zip().Url_(url);} + public static Io_stream_rdr gzip_(Io_url url) {return new Io_stream_rdr_gzip().Url_(url);} + public static Io_stream_rdr bzip2_(Io_url url) {return new Io_stream_rdr_bzip2().Url_(url);} + public static Io_stream_rdr new_by_url_(Io_url url) { + String ext = url.Ext(); + if (String_.Eq(ext, Io_stream_.Ext_zip)) return gplx.ios.Io_stream_rdr_.zip_(url); + else if (String_.Eq(ext, Io_stream_.Ext_gz)) return gplx.ios.Io_stream_rdr_.gzip_(url); + else if (String_.Eq(ext, Io_stream_.Ext_bz2)) return gplx.ios.Io_stream_rdr_.bzip2_(url); + else return gplx.ios.Io_stream_rdr_.file_(url); + } + public static Io_stream_rdr new_by_tid_(byte tid) { + switch (tid) { + case Io_stream_.Tid_raw: return new Io_stream_rdr_file(); + case Io_stream_.Tid_zip: return new Io_stream_rdr_zip(); + case Io_stream_.Tid_gzip: return new Io_stream_rdr_gzip(); + case Io_stream_.Tid_bzip2: return new Io_stream_rdr_bzip2(); + default: throw Exc_.new_unhandled(tid); + } + } + public static byte[] Load_all(Io_url url) { + Io_stream_rdr rdr = new_by_url_(url); + Bry_bfr rv = Bry_bfr.new_(); + try { + rdr.Open(); + return Load_all_as_bry(rv, rdr); + } + finally {rdr.Rls();} + } + public static String Load_all_as_str(Io_stream_rdr rdr) {return String_.new_u8(Load_all_as_bry(rdr));} + public static byte[] Load_all_as_bry(Io_stream_rdr rdr) {return Load_all_as_bry(Bry_bfr.new_(), rdr);} + public static byte[] Load_all_as_bry(Bry_bfr rv, Io_stream_rdr rdr) { + Load_all_to_bfr(rv, rdr); + return rv.Xto_bry_and_clear(); + } + public static void Load_all_to_bfr(Bry_bfr rv, Io_stream_rdr rdr) { + try { + byte[] bry = new byte[4096]; + while (true) { + int read = rdr.Read(bry, 0, 4096); + if (read < gplx.ios.Io_stream_rdr_.Read_done_compare) break; + rv.Add_mid(bry, 0, read); + } + } finally {rdr.Rls();} + } + public static final Io_stream_rdr Noop = new Io_stream_rdr_noop(); + public static Io_stream_rdr mem_(String v) {return mem_(Bry_.new_u8(v));} + public static Io_stream_rdr mem_(byte[] v) { + Io_stream_rdr rv = new Io_stream_rdr_adp(Stream_new_mem(v)); + rv.Len_(v.length); + return rv; + } + public static java.io.InputStream Stream_new_mem(byte[] v) { + return new java.io.ByteArrayInputStream(v); + } + public static boolean Stream_close(java.io.InputStream stream) { + try { + if (stream != null) + stream.close(); + return true; + } catch (Exception e) {Exc_.Noop(e); return false;} + } + public static int Stream_read_by_parts(java.io.InputStream stream, int part_len, byte[] bry, int bgn, int len) { + /* + NOTE: BZip2CompressorInputStream will fail if large len is used + Instead, make smaller requests and fill bry + */ + try { + int rv = 0; + int end = bgn + len; + int cur = bgn; + while (true) { + int bry_len = part_len; // read in increments of part_len + if (cur + bry_len > end) // if cur + 8 kb > bry_len, trim to end; EX: 9 kb bry passed; 1st pass is 8kb, 2nd pass should be 1kb, not 8 kb; + bry_len = end - cur; + if (cur == end) break; // no more bytes needed; break; EX: 8 kb bry passed; 1st pass is 8kb; 2nd pass is 0 and cur == end + int read = stream.read(bry, cur, bry_len); + if (read == gplx.ios.Io_stream_rdr_.Read_done) // read done; end + break; + rv += read; + cur += read; + } + return rv; + } + catch (Exception exc) { + throw Exc_.new_exc(exc, "io", "read failed", "bgn", bgn, "len", len); + } + } + public static final int Read_done = -1; + public static final int Read_done_compare = 1; +} +class Io_stream_rdr_noop implements Io_stream_rdr { + public Object Under() {return null;} + public byte Tid() {return Io_stream_.Tid_null;} + public boolean Exists() {return false;} + public Io_url Url() {return Io_url_.Empty;} public Io_stream_rdr Url_(Io_url v) {return this;} + public long Len() {return Io_mgr.Len_null;} public Io_stream_rdr Len_(long v) {return this;} + public void Open_mem(byte[] v) {} + public Io_stream_rdr Open() {return this;} + public int Read(byte[] bry, int bgn, int len) {return Io_stream_rdr_.Read_done;} + public long Skip(long len) {return Io_stream_rdr_.Read_done;} + public void Rls() {} +} +class Io_stream_rdr_adp implements Io_stream_rdr { + private java.io.InputStream strm; + public Io_stream_rdr_adp(java.io.InputStream strm) {this.strm = strm;} + public Object Under() {return strm;} + public byte Tid() {return Io_stream_.Tid_raw;} + public boolean Exists() {return len > 0;} + public Io_url Url() {return url;} public Io_stream_rdr Url_(Io_url v) {this.url = v; return this;} private Io_url url; + public long Len() {return len;} public Io_stream_rdr Len_(long v) {len = v; return this;} private long len = Io_mgr.Len_null; + public void Open_mem(byte[] v) {} + public Io_stream_rdr Open() {return this;} + public int Read(byte[] bry, int bgn, int len) { + try {return strm.read(bry, bgn, len);} + catch (Exception e) {throw Exc_.new_exc(e, "io", "read failed", "bgn", bgn, "len", len);} + } + public long Skip(long len) { + try {return strm.skip(len);} + catch (Exception e) {throw Exc_.new_exc(e, "io", "skip failed", "len", len);} + } + public void Rls() { + try {strm.close();} + catch (Exception e) {throw Exc_.new_exc(e, "io", "close failed", "url", url.Xto_api());} + } +} +abstract class Io_stream_rdr_base implements Io_stream_rdr { + public abstract byte Tid(); + public boolean Exists() {return this.Len() > 0;} + public Object Under() {return stream;} public Io_stream_rdr Under_(java.io.InputStream v) {this.stream = v; return this;} protected java.io.InputStream stream; + public Io_url Url() {return url;} public Io_stream_rdr Url_(Io_url v) {this.url = v; return this;} protected Io_url url; + public long Len() {return len;} public Io_stream_rdr Len_(long v) {len = v; return this;} private long len = Io_mgr.Len_null; + public void Open_mem(byte[] v) { + stream = Wrap_stream(new java.io.ByteArrayInputStream(v)); + } + public Io_stream_rdr Open() { + try {stream = Wrap_stream(new java.io.FileInputStream(url.Xto_api()));} + catch (Exception e) {throw Exc_.new_exc(e, "io", "open failed", "url", url.Xto_api());} + return this; + } + public int Read(byte[] bry, int bgn, int len) { + try {return stream.read(bry, bgn, len);} + catch (Exception e) {throw Exc_.new_exc(e, "io", "read failed", "bgn", bgn, "len", len);} + } + public long Skip(long len) { + try {return stream.skip(len);} + catch (Exception e) {throw Exc_.new_exc(e, "io", "skip failed", "len", len);} + } + public void Rls() { + try {stream.close();} + catch (Exception e) {throw Exc_.new_exc(e, "io", "close failed", "url", url.Xto_api());} + } + public abstract java.io.InputStream Wrap_stream(java.io.InputStream stream); +} +class Io_stream_rdr_file extends Io_stream_rdr_base { + @Override public byte Tid() {return Io_stream_.Tid_raw;} + public Io_stream_rdr Open() { + try { + if (!Io_mgr.I.Exists(url)) + stream = Wrap_stream(new java.io.ByteArrayInputStream(Bry_.Empty)); + else { + if (url.Info().EngineKey() == gplx.ios.IoEngine_.MemKey) + stream = Wrap_stream(new java.io.ByteArrayInputStream(Io_mgr.I.LoadFilBry(url.Xto_api()))); + else + stream = Wrap_stream(new java.io.FileInputStream(url.Xto_api())); + } + } + catch (Exception e) {throw Exc_.new_exc(e, "io", "open failed", "url", url.Xto_api());} + return this; + } + @Override public java.io.InputStream Wrap_stream(java.io.InputStream stream) {return stream;} +} +class Io_stream_rdr_zip implements Io_stream_rdr { + @Override public byte Tid() {return Io_stream_.Tid_zip;} + public boolean Exists() {return this.Len() > 0;} + public Io_url Url() {return url;} public Io_stream_rdr Url_(Io_url v) {this.url = v; return this;} Io_url url; + public long Len() {return len;} public Io_stream_rdr Len_(long v) {len = v; return this;} private long len = Io_mgr.Len_null; + public Object Under() {return zip_stream;} private java.util.zip.ZipInputStream zip_stream; + public void Src_bfr_(Bry_bfr v) {this.src_bfr = v;} Bry_bfr src_bfr; + public void Open_mem(byte[] v) { + Wrap_stream(new java.io.ByteArrayInputStream(v)); + } + public Io_stream_rdr Open() { + try {Wrap_stream(new java.io.FileInputStream(url.Xto_api()));} + catch (Exception e) {throw Exc_.new_exc(e, "io", "open failed", "url", url.Xto_api());} + return this; + } + void Wrap_stream(java.io.InputStream input_stream) {zip_stream = new java.util.zip.ZipInputStream(input_stream);} + public int Read(byte[] bry, int bgn, int len) { + try { + while (true){ + int read = zip_stream.read(bry, bgn, len); + if (read == gplx.ios.Io_stream_rdr_.Read_done) { + if (zip_stream.getNextEntry() == null) + return gplx.ios.Io_stream_rdr_.Read_done; + } + else + return read; + } + } + catch (Exception e) {throw Exc_.new_exc(e, "io", "read failed", "bgn", bgn, "len", len);} + } + public long Skip(long len) { + try {return zip_stream.skip(len);} + catch (Exception e) {throw Exc_.new_exc(e, "io", "skip failed", "len", len);} + } + public void Rls() { + try {zip_stream.close();} + catch (Exception e) {throw Exc_.new_exc(e, "io", "close failed", "url", url.Xto_api());} + } +} +class Io_stream_rdr_gzip extends Io_stream_rdr_base { + @Override public byte Tid() {return Io_stream_.Tid_gzip;} + @Override public int Read(byte[] bry, int bgn, int len) { + try { + int total_read = 0; + while (true) { // NOTE: the gz stream reads partially; (request 100; only get back 10); keep reading until entire bfr is full or -1 + int read = stream.read(bry, bgn, len); + if (read == gplx.ios.Io_stream_rdr_.Read_done) break; + total_read += read; + if (total_read >= len) break; // entire bfr full; stop + bgn += read; // increase bgn by amount read + len -= read; // decrease len by amount read + } + return total_read == 0 ? gplx.ios.Io_stream_rdr_.Read_done : total_read; // gzip seems to allow 0 bytes read (bz2 and zip return -1 instead); normalize return to -1; + } + catch (Exception e) { + throw Exc_.new_exc(e, "io", "read failed", "bgn", bgn, "len", len); + } + } + @Override public java.io.InputStream Wrap_stream(java.io.InputStream stream) { + try {return new java.util.zip.GZIPInputStream(stream);} + catch (Exception exc) {throw Exc_.new_("failed to open gz stream");} + } +} +class Io_stream_rdr_bzip2 extends Io_stream_rdr_base { + @Override public byte Tid() {return Io_stream_.Tid_bzip2;} + @Override public java.io.InputStream Wrap_stream(java.io.InputStream stream) { + try {return new org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream(stream, true);} + catch (Exception exc) {throw Exc_.new_("failed to open bzip2 stream");} + } + @Override public int Read(byte[] bry, int bgn, int len) { + return Io_stream_rdr_.Stream_read_by_parts(stream, Read_len, bry, bgn, len); + } + private static final int Read_len = Io_mgr.Len_mb * 128; +} diff --git a/100_core/src_200_io/gplx/ios/Io_stream_rdr_tst.java b/100_core/src_200_io/gplx/ios/Io_stream_rdr_tst.java new file mode 100644 index 000000000..4d0db151f --- /dev/null +++ b/100_core/src_200_io/gplx/ios/Io_stream_rdr_tst.java @@ -0,0 +1,56 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import org.junit.*; +public class Io_stream_rdr_tst { + @Before public void init() {fxt.Clear();} private Io_stream_rdr_fxt fxt = new Io_stream_rdr_fxt(); + @After public void term() {fxt.Rls();} + @Test public void Bz2_read() { + fxt .Init_stream("abcd") // read everything at once + .Expd_bytes_read(4).Test_read(0, 4, "abcd"); + fxt .Init_stream("abcd") // read in steps + .Expd_bytes_read(1).Test_read(0, 1, "a") + .Expd_bytes_read(2).Test_read(1, 2, "bc") + .Expd_bytes_read(1).Test_read(3, 1, "d") + ; + } +} +class Io_stream_rdr_fxt { + private java.io.InputStream stream; + private int stream_bry_len; + public void Clear() { + expd_bytes_read = Int_.MinValue; + } + public Io_stream_rdr_fxt Expd_bytes_read(int v) {expd_bytes_read = v; return this;} private int expd_bytes_read = Int_.MinValue; + public Io_stream_rdr_fxt Init_stream(String v) { + byte[] stream_bry = Bry_.new_a7(v); + stream_bry_len = stream_bry.length; + stream = Io_stream_rdr_.Stream_new_mem(stream_bry); + return this; + } + public Io_stream_rdr_fxt Test_read(int bgn, int len, String expd_str) { + byte[] bfr = new byte[stream_bry_len]; // allocate whole stream; may not use it all + int actl_bytes_read = Io_stream_rdr_.Stream_read_by_parts(stream, 8, bfr, bgn, len); + Tfds.Eq(expd_bytes_read, actl_bytes_read, "bytes_read"); + Tfds.Eq(expd_str, String_.new_u8(bfr, bgn, bgn + actl_bytes_read), "str"); + return this; + } + public void Rls() { + Io_stream_rdr_.Stream_close(stream); + } +} diff --git a/100_core/src_200_io/gplx/ios/Io_stream_wtr.java b/100_core/src_200_io/gplx/ios/Io_stream_wtr.java new file mode 100644 index 000000000..3b89f1cb2 --- /dev/null +++ b/100_core/src_200_io/gplx/ios/Io_stream_wtr.java @@ -0,0 +1,28 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +public interface Io_stream_wtr extends RlsAble { + byte Tid(); + Io_url Url(); Io_stream_wtr Url_(Io_url v); + void Trg_bfr_(Bry_bfr v); + Io_stream_wtr Open(); + byte[] To_ary_and_clear(); + + void Write(byte[] bry, int bgn, int len); + void Flush(); +} diff --git a/100_core/src_200_io/gplx/ios/Io_stream_wtr_.java b/100_core/src_200_io/gplx/ios/Io_stream_wtr_.java new file mode 100644 index 000000000..98049db83 --- /dev/null +++ b/100_core/src_200_io/gplx/ios/Io_stream_wtr_.java @@ -0,0 +1,213 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +public class Io_stream_wtr_ { + public static Io_stream_wtr bzip2_(Io_url url) {return new Io_stream_wtr_bzip2().Url_(url);} + public static Io_stream_wtr gzip_(Io_url url) {return new Io_stream_wtr_gzip().Url_(url);} + public static Io_stream_wtr zip_(Io_url url) {return new Io_stream_wtr_zip().Url_(url);} + public static Io_stream_wtr file_(Io_url url) {return new Io_stream_wtr_file().Url_(url);} + public static Io_stream_wtr new_by_url_(Io_url url) { + String ext = url.Ext(); + if (String_.Eq(ext, Io_stream_.Ext_zip)) return gplx.ios.Io_stream_wtr_.zip_(url); + else if (String_.Eq(ext, Io_stream_.Ext_gz)) return gplx.ios.Io_stream_wtr_.gzip_(url); + else if (String_.Eq(ext, Io_stream_.Ext_bz2)) return gplx.ios.Io_stream_wtr_.bzip2_(url); + else return gplx.ios.Io_stream_wtr_.file_(url); + } + public static Io_stream_wtr new_by_mem(Bry_bfr bfr, byte tid) { + Io_stream_wtr wtr = new_by_tid_(tid).Url_(Io_url_.Empty); + wtr.Trg_bfr_(bfr); + return wtr; + } + public static Io_stream_wtr new_by_tid_(byte v) { + switch (v) { + case gplx.ios.Io_stream_.Tid_raw : return new Io_stream_wtr_file(); + case gplx.ios.Io_stream_.Tid_zip : return new Io_stream_wtr_zip(); + case gplx.ios.Io_stream_.Tid_gzip : return new Io_stream_wtr_gzip(); + case gplx.ios.Io_stream_.Tid_bzip2 : return new Io_stream_wtr_bzip2(); + default : throw Exc_.new_unhandled(v); + } + } + public static void Save_all(Io_url url, byte[] bry, int bgn, int end) { + Io_stream_wtr wtr = new_by_url_(url); + try { + wtr.Open(); + wtr.Write(bry, bgn, end); + wtr.Flush(); + } + finally {wtr.Rls();} + } + public static void Save_rdr(Io_url url, Io_stream_rdr rdr, Io_download_fmt download_progress) { + byte[] bry = new byte[4096]; + Io_stream_wtr wtr = new_by_url_(url); + try { + wtr.Open(); + if (download_progress != Io_download_fmt.Null) + download_progress.Bgn(rdr.Len()); + while (true) { + int read = rdr.Read(bry, 0, 4096); + if (read < gplx.ios.Io_stream_rdr_.Read_done_compare) break; + if (download_progress != Io_download_fmt.Null) + download_progress.Prog(read); + wtr.Write(bry, 0, read); + } + wtr.Flush(); + if (download_progress != Io_download_fmt.Null) + download_progress.Term(); + } + finally {wtr.Rls(); rdr.Rls();} + } +} +abstract class Io_stream_wtr_base implements Io_stream_wtr { + java.io.OutputStream zip_stream; + public Io_url Url() {return url;} public Io_stream_wtr Url_(Io_url v) {url = v; trg_bfr = null; return this;} Io_url url; + public void Trg_bfr_(Bry_bfr v) {trg_bfr = v;} Bry_bfr trg_bfr; java.io.ByteArrayOutputStream mem_stream; + public byte[] To_ary_and_clear() {return trg_bfr.Xto_bry_and_clear();} + @SuppressWarnings("resource") public Io_stream_wtr Open() { + java.io.OutputStream bry_stream = null; + if (trg_bfr == null) { + if (!Io_mgr.I.ExistsFil(url)) Io_mgr.I.SaveFilStr(url, ""); + try {bry_stream = new java.io.FileOutputStream(url.Raw());} + catch (Exception e) {throw Exc_.new_exc(e, "io", "open failed", "url", url.Raw());} + } + else { + mem_stream = new java.io.ByteArrayOutputStream(); + bry_stream = mem_stream; + } + zip_stream = Wrap_stream(bry_stream); + return this; + } + public void Write(byte[] bry, int bgn, int len) { + try {zip_stream.write(bry, bgn, len);} + catch (Exception e) {Exc_.new_exc(e, "io", "write failed", "bgn", bgn, "len", len);} + } + public void Flush() { + if (trg_bfr != null) { + try {zip_stream.close();} catch (Exception e) {throw Exc_.new_exc(e, "io", "flush failed");} // must close zip_stream to flush all bytes + trg_bfr.Add(mem_stream.toByteArray()); + } + } + public void Rls() { + try { + if (zip_stream != null) zip_stream.close(); + if (mem_stream != null) mem_stream.close(); + } + catch (Exception e) {throw Exc_.new_exc(e, "io", "close failed", "url", url.Raw());} + } + public abstract java.io.OutputStream Wrap_stream(java.io.OutputStream stream); +} +class Io_stream_wtr_bzip2 extends Io_stream_wtr_base { + @Override public byte Tid() {return Io_stream_.Tid_bzip2;} + @Override public java.io.OutputStream Wrap_stream(java.io.OutputStream stream) { + try {return new org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream(stream);} + catch (Exception e) {throw Exc_.new_exc(e, "io", "failed to open bzip2 stream");} + } + static final byte[] Bz2_header = new byte[] {Byte_ascii.Ltr_B, Byte_ascii.Ltr_Z}; +} +class Io_stream_wtr_gzip extends Io_stream_wtr_base { + @Override public byte Tid() {return Io_stream_.Tid_gzip;} + @Override public java.io.OutputStream Wrap_stream(java.io.OutputStream stream) { + try {return new java.util.zip.GZIPOutputStream(stream);} + catch (Exception e) {throw Exc_.new_exc(e, "io", "failed to open gz stream");} + } +} +class Io_stream_wtr_zip implements Io_stream_wtr { + private java.util.zip.ZipOutputStream zip_stream; + @Override public byte Tid() {return Io_stream_.Tid_zip;} + public Io_url Url() {return url;} public Io_stream_wtr Url_(Io_url v) {url = v; trg_bfr = null; return this;} private Io_url url = Io_url_.Empty; + public void Trg_bfr_(Bry_bfr v) {trg_bfr = v;} private Bry_bfr trg_bfr; private java.io.ByteArrayOutputStream mem_stream; + @SuppressWarnings("resource") // rely on zip_stream to close bry_stream + public Io_stream_wtr Open() { + java.io.OutputStream bry_stream; + if (trg_bfr == null) { + if (!Io_mgr.I.ExistsFil(url)) Io_mgr.I.SaveFilStr(url, ""); // create file if it doesn't exist + try {bry_stream = new java.io.FileOutputStream(url.Xto_api());} + catch (Exception e) {throw Exc_.new_exc(e, "io", "open failed", "url", url.Raw());} + } + else { + mem_stream = new java.io.ByteArrayOutputStream(); + bry_stream = mem_stream; + } + zip_stream = new java.util.zip.ZipOutputStream(bry_stream); + java.util.zip.ZipEntry entry = new java.util.zip.ZipEntry("file"); + try {zip_stream.putNextEntry(entry);} + catch (Exception e) {throw Exc_.new_exc(e, "io", "open failed", "url", url.Raw());} + return this; + } + public void Write(byte[] bry, int bgn, int len) { + try {zip_stream.write(bry, bgn, len);} + catch (Exception e) {throw Exc_.new_exc(e, "io", "write failed", "url", url.Raw(), "bgn", bgn, "len", len);} + } + public void Flush() {// fixed as of DATE:2014-04-15 + try { + zip_stream.closeEntry(); + zip_stream.close(); + if (trg_bfr != null) + trg_bfr.Add(mem_stream.toByteArray()); + zip_stream.flush(); + } + catch (Exception e) {throw Exc_.new_exc(e, "io", "flush failed", "url", url.Raw());} + } + public void Rls() { + try { + if (zip_stream != null) zip_stream.close(); + if (mem_stream != null) mem_stream.close(); + } + catch (Exception e) {throw Exc_.new_exc(e, "io", "close failed", "url", url.Raw());} + } + public byte[] To_ary_and_clear() { + byte[] rv = trg_bfr.Xto_bry_and_clear(); + this.Rls(); + return rv; + } +} +class Io_stream_wtr_file implements Io_stream_wtr { + IoStream bry_stream; + @Override public byte Tid() {return Io_stream_.Tid_raw;} + public Io_url Url() {return url;} public Io_stream_wtr Url_(Io_url v) {url = v; return this;} Io_url url; + public void Trg_bfr_(Bry_bfr v) {trg_bfr = v;} private Bry_bfr trg_bfr; java.io.ByteArrayOutputStream mem_stream; + public Io_stream_wtr Open() { + try { + if (trg_bfr == null) + bry_stream = Io_mgr.I.OpenStreamWrite(url); + } + catch (Exception e) {throw Exc_.new_exc(e, "io", "open failed", "url", url.Raw());} + return this; + } + public void Write(byte[] bry, int bgn, int len) { + if (trg_bfr == null) { + try {bry_stream.Write(bry, bgn, len);} + catch (Exception e) {throw Exc_.new_exc(e, "io", "write failed", "url", url.Raw(), "bgn", bgn, "len", len);} + } + else + trg_bfr.Add_mid(bry, bgn, bgn + len); + } + public byte[] To_ary_and_clear() { + return trg_bfr == null ? Io_mgr.I.LoadFilBry(url) : trg_bfr.Xto_bry_and_clear(); + } + public void Flush() { + if (trg_bfr == null) + bry_stream.Flush(); + } + public void Rls() { + try { + if (trg_bfr == null) + bry_stream.Rls(); + } + catch (Exception e) {throw Exc_.new_exc(e, "io", "close failed", "url", url.Raw());} + } +} diff --git a/100_core/src_200_io/gplx/ios/Io_url_obj_ref.java b/100_core/src_200_io/gplx/ios/Io_url_obj_ref.java new file mode 100644 index 000000000..afb8fa113 --- /dev/null +++ b/100_core/src_200_io/gplx/ios/Io_url_obj_ref.java @@ -0,0 +1,30 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +public class Io_url_obj_ref { + public Io_url Val() {return val;} public Io_url_obj_ref Val_(Io_url v) {val = v; return this;} private Io_url val; + public String Val_as_str() {return val.Raw();} + @Override public String toString() {return val.Raw();} + @Override public int hashCode() {return val.hashCode();} + @Override public boolean equals(Object obj) {return String_.Eq(val.Raw(), ((Io_url_obj_ref)obj).val.Raw());} + public static Io_url_obj_ref new_(Io_url val) { + Io_url_obj_ref rv = new Io_url_obj_ref(); + rv.val = val; + return rv; + } Io_url_obj_ref() {} +} diff --git a/100_core/src_210_env/gplx/ClassAdp_.java b/100_core/src_210_env/gplx/ClassAdp_.java new file mode 100644 index 000000000..ead2e4b12 --- /dev/null +++ b/100_core/src_210_env/gplx/ClassAdp_.java @@ -0,0 +1,45 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class ClassAdp_ { + public static boolean Eq(Class lhs, Class rhs) { + if (lhs == null && rhs == null) return true; + else if (lhs == null || rhs == null) return false; + else return lhs.equals(rhs); + } + public static boolean Eq_typeSafe(Object o, Class expd) {if (o == null) return false; + Class actl = o.getClass(); + return Object_.Eq(expd, actl); + } + public static boolean IsAssignableFrom(Class lhs, Class rhs) {return lhs.isAssignableFrom(rhs);} + public static boolean Is_array(Class t) {return t.isArray();} + public static Class ClassOf_obj(Object o) {return o.getClass();} + public static Class ClassOf_primitive(Object o) { + Class rv = o.getClass(); + if (rv == Integer.class) rv = int.class; + else if (rv == Long.class) rv = long.class; + else if (rv == Byte.class) rv = byte.class; + else if (rv == Short.class) rv = short.class; + return rv; + } + public static String FullNameOf_obj(Object o) {return FullNameOf_type(o.getClass());} + public static String FullNameOf_type(Class type) {return type.getCanonicalName();} + public static String NameOf_type(Class type) {return type.getName();} + public static String NameOf_obj(Object obj) {return obj == null ? String_.Null_mark : obj.getClass().getName();} + public static final byte Tid_bool = 1, Tid_byte = 2, Tid_int = 3, Tid_long = 4, Tid_float = 5, Tid_double = 6, Tid_char = 7, Tid_str = 8, Tid_date = 9, Tid_decimal = 10; +} diff --git a/100_core/src_210_env/gplx/Env_.java b/100_core/src_210_env/gplx/Env_.java new file mode 100644 index 000000000..73d044750 --- /dev/null +++ b/100_core/src_210_env/gplx/Env_.java @@ -0,0 +1,98 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.core.threads.*; +public class Env_ { + public static void Init(String[] args, String appNameAndExt, Class type) { + mode_testing = false; + mode_debug = String_.In("GPLX_DEBUG_MODE_ENABLED", args); + appArgs = args; + appUrl = JarAdp_.Url_type(type).OwnerDir().GenSubFil(appNameAndExt); + } + public static void Init_swt(String[] args, Class type) { // DATE:2014-06-23 + mode_testing = false; + mode_debug = String_.In("GPLX_DEBUG_MODE_ENABLED", args); + appArgs = args; + appUrl = JarAdp_.Url_type(type); + } + public static void Init_drd() { + mode_testing = mode_debug = false; + } + public static void Init_testing() {mode_testing = true;} + public static void Init_testing_n_() {mode_testing = false;} + public static boolean Mode_testing() {return mode_testing;} static boolean mode_testing = true; + public static boolean Mode_debug() {return mode_debug;} static boolean mode_debug = false; + public static String[] AppArgs() {return appArgs;} static String[] appArgs; + public static Io_url AppUrl() { + if (mode_testing) return Io_url_.mem_fil_("mem/testing.jar"); + if (appUrl == Io_url_.Empty) throw Exc_.new_("Env_.Init was not called"); + return appUrl; + } static Io_url appUrl = Io_url_.Empty; + public static void Exit() {Exit_code(0);} + public static void Exit_code(int code) {System.exit(code);} + public static String UserName() {return System.getProperty("user.name");} + public static void GarbageCollect() {if (mode_testing) return; System.gc();} + public static long TickCount() {return TickCount_Test >= 0 ? TickCount_Test : System.currentTimeMillis();} + public static int TickCount_elapsed_in_sec(long time_bgn) {return (int)(Env_.TickCount() - time_bgn) / 1000;} + public static int TickCount_elapsed_in_frac(long time_bgn) {return (int)(Env_.TickCount() - time_bgn);} + public static long TickCount_Test = -1; // in milliseconds + public static void TickCount_normal() {TickCount_Test = -1;} + public static long System_cpu_count() {return Runtime.getRuntime().availableProcessors();} + public static long System_memory_max() {return Runtime.getRuntime().maxMemory();} + public static long System_memory_total() {return Runtime.getRuntime().totalMemory();} + public static long System_memory_free() {return Runtime.getRuntime().freeMemory();} + public static final String LocalHost = "127.0.0.1"; + public static String NewLine_lang() {return mode_testing ? "\n" : "\n";} + public static String GenHdr(boolean forSourceCode, String programName, String hdr_bgn, String hdr_end) { + String newLine = Op_sys.Lnx.Nl_str(); + String lineEnd = Op_sys.Lnx.Nl_str(); + String codeBgn = forSourceCode ? "/*" + newLine : ""; + String codeEnd = forSourceCode ? "*/" + newLine : ""; + String codeHdr = forSourceCode ? "This file is part of {0}." + newLine + newLine : ""; + String fmt = String_.Concat + ( codeBgn + , codeHdr + , hdr_bgn + , "Copyright (c) 2012 gnosygnu@gmail.com", newLine + , newLine + , "This program is free software: you can redistribute it and/or modify", lineEnd + , "it under the terms of the GNU Affero General Public License as", lineEnd + , "published by the Free Software Foundation, either version 3 of the", lineEnd + , "License, or (at your option) any later version.", newLine + , newLine + , "This program is distributed in the hope that it will be useful,", lineEnd + , "but WITHOUT ANY WARRANTY; without even the implied warranty of", lineEnd + , "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", lineEnd + , "GNU Affero General Public License for more details.", newLine + , newLine + , "You should have received a copy of the GNU Affero General Public License", lineEnd + , "along with this program. If not, see .", newLine + , codeEnd + , hdr_end + ); + return String_.Format(fmt, programName); + } + public static String Env_prop__user_language() {return Env_prop(Env_prop_key__user_language);} + public static String Env_prop(String key) { + return System.getProperty(key); + } static final String Env_prop_key__user_language = "user.language"; + public static void Term_add(GfoInvkAble invk, String cmd) { + Thread_adp thread = Thread_adp_.invk_(invk, cmd); + Runtime.getRuntime().addShutdownHook(thread.Under_thread()); + } +} diff --git a/100_core/src_210_env/gplx/JarAdp_.java b/100_core/src_210_env/gplx/JarAdp_.java new file mode 100644 index 000000000..ec4acba41 --- /dev/null +++ b/100_core/src_210_env/gplx/JarAdp_.java @@ -0,0 +1,33 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class JarAdp_ { + public static DateAdp ModifiedTime_type(Class type) {if (type == null) throw Exc_.new_null("type"); + Io_url url = Url_type(type); + return Io_mgr.I.QueryFil(url).ModifiedTime(); + } + public static Io_url Url_type(Class type) {if (type == null) throw Exc_.new_null("type"); + String codeBase = type.getProtectionDomain().getCodeSource().getLocation().getPath(); + if (Op_sys.Cur().Tid_is_wnt()) + codeBase = String_.Mid(codeBase, 1); // codebase always starts with /; remove for wnt + codeBase = String_.Replace(codeBase, "/", Op_sys.Cur().Fsys_dir_spr_str()); // java always returns DirSpr as /; change to Env_.DirSpr to handle windows + try {codeBase = java.net.URLDecoder.decode(codeBase, "UTF-8");} + catch (java.io.UnsupportedEncodingException e) {Exc_.Noop(e);} + return Io_url_.new_fil_(codeBase); + } +} diff --git a/100_core/src_210_env/gplx/Op_sys.java b/100_core/src_210_env/gplx/Op_sys.java new file mode 100644 index 000000000..ab12a67b7 --- /dev/null +++ b/100_core/src_210_env/gplx/Op_sys.java @@ -0,0 +1,85 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Op_sys { + Op_sys(byte tid, byte sub_tid, String os_name, byte bitness, String nl_str, byte fsys_dir_spr_byte, boolean fsys_case_match) { + this.tid = tid; this.sub_tid = sub_tid; this.os_name = os_name; this.bitness = bitness; this.nl_str = nl_str; this.fsys_dir_spr_byte = fsys_dir_spr_byte; this.fsys_dir_spr_str = Char_.XtoStr((char)fsys_dir_spr_byte); this.fsys_case_match = fsys_case_match; + } + public byte Tid() {return tid;} private final byte tid; + public byte Sub_tid() {return sub_tid;} private final byte sub_tid; + public String Os_name() {return os_name;} private String os_name; + public byte Bitness() {return bitness;} private final byte bitness; + public String Nl_str() {return nl_str;} private final String nl_str; + public String Fsys_dir_spr_str() {return fsys_dir_spr_str;} private final String fsys_dir_spr_str; + public byte Fsys_dir_spr_byte() {return fsys_dir_spr_byte;} private final byte fsys_dir_spr_byte; + public String Fsys_http_frag_to_url_str(String raw) {return fsys_dir_spr_byte == Byte_ascii.Slash ? raw : String_.Replace(raw, Lnx.Fsys_dir_spr_str(), fsys_dir_spr_str);} + public boolean Fsys_case_match() {return fsys_case_match;} private final boolean fsys_case_match; + public String Fsys_case_match_str(String s) {return String_.CaseNormalize(fsys_case_match, s);} + public boolean Tid_is_wnt() {return tid == Tid_wnt;} + public boolean Tid_is_lnx() {return tid == Tid_lnx;} + public boolean Tid_is_osx() {return tid == Tid_osx;} + public boolean Tid_is_drd() {return tid == Tid_drd;} + public String Xto_str() {return os_name + (bitness == Bitness_32 ? "32" : "64");} + + public static final byte Tid_nil = 0, Tid_wnt = 1, Tid_lnx = 2, Tid_osx = 3, Tid_drd = 4; + public static final byte Sub_tid_unknown = 0, Sub_tid_win_xp = 1, Sub_tid_win_7 = 2, Sub_tid_win_8 = 3; + public static final byte Bitness_32 = 1, Bitness_64 = 2; + public static final char Dir_spr_char_lnx = '\n'; + public static final Op_sys Lnx = new_unx_flavor_(Tid_lnx, "linux", Bitness_32); + public static final Op_sys Osx = new_unx_flavor_(Tid_osx, "macosx", Bitness_32); + public static final Op_sys Drd = new_unx_flavor_(Tid_drd, "windows", Bitness_32); + public static final Op_sys Wnt = new_wnt_(Sub_tid_unknown, Bitness_32); + public static Op_sys Cur() {return cur_op_sys;} static Op_sys cur_op_sys = new_auto_identify_(); + public static String Fsys_path_to_lnx(String v) { + return cur_op_sys.Tid_is_wnt() ? String_.Replace(v, Wnt.fsys_dir_spr_str, Lnx.fsys_dir_spr_str) : v; + } + public static String Fsys_path_to_wnt(String v) { + return cur_op_sys.Tid_is_wnt() ? String_.Replace(v, Lnx.fsys_dir_spr_str, Wnt.fsys_dir_spr_str) : v; + } + private static Op_sys new_wnt_(byte bitness, byte sub_tid) {return new Op_sys(Tid_wnt , sub_tid , "windows", bitness, "\r\n", Byte_ascii.Backslash , Bool_.N);} + private static Op_sys new_unx_flavor_(byte tid, String os_name, byte bitness) {return new Op_sys(tid , Sub_tid_unknown , os_name , bitness, "\n" , Byte_ascii.Slash , Bool_.Y);} + static final String GRP_KEY = "gplx.op_sys"; +// public static Op_sys Cur_() {cur_op_sys = new_auto_identify_(); return cur_op_sys;} + static Op_sys new_auto_identify_() { + String os_name = ""; + try { + String bitness_str = System.getProperty("sun.arch.data.model"); if (bitness_str == null) return Drd; + bitness_str = bitness_str.toLowerCase(); + byte bitness_byte = Bitness_32; + if (String_.Eq(bitness_str, "32")) bitness_byte = Bitness_32; + else if (String_.Eq(bitness_str, "64")) bitness_byte = Bitness_64; + else throw Exc_.new_("unknown bitness; expecting 32 or 64; System.getProperty(\"bit.level\")", "val", bitness_str); + + os_name = System.getProperty("os.name").toLowerCase(); + if (String_.Has_at_bgn(os_name, "win")) { + String os_version = System.getProperty("os.version").toLowerCase();// "Windows 7".equals(osName) && "6.1".equals(osVersion); + byte sub_tid = Sub_tid_unknown; + if (String_.Eq(os_name, "windows xp") && String_.Eq(os_version, "5.1")) sub_tid = Sub_tid_win_xp; + else if (String_.Eq(os_name, "windows 7") && String_.Eq(os_version, "6.1")) sub_tid = Sub_tid_win_7; + else if (String_.Eq(os_name, "windows 8")) sub_tid = Sub_tid_win_8; + return new_wnt_(bitness_byte, sub_tid); + } + else if (String_.Eq(os_name, "linux")) return new_unx_flavor_(Tid_lnx, os_name, bitness_byte); + else if (String_.Has_at_bgn(os_name, "mac")) return new_unx_flavor_(Tid_osx, os_name, bitness_byte); // EX:Mac OS X + else throw Exc_.new_("unknown os_name; expecting windows, linux, mac; System.getProperty(\"os.name\")", "val", os_name); + } catch (Exception exc) {Drd.os_name = os_name; return Drd;} + } + public static void OpSysIsDroid() { + cur_op_sys = Drd; + } + } diff --git a/100_core/src_210_env/gplx/Op_sys_.java b/100_core/src_210_env/gplx/Op_sys_.java new file mode 100644 index 000000000..324d5222d --- /dev/null +++ b/100_core/src_210_env/gplx/Op_sys_.java @@ -0,0 +1,34 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Op_sys_ { + public static boolean Wnt_invalid_char(byte b) { + switch (b) { + case Byte_ascii.Slash: + case Byte_ascii.Backslash: + case Byte_ascii.Lt: + case Byte_ascii.Gt: + case Byte_ascii.Colon: + case Byte_ascii.Pipe: + case Byte_ascii.Question: + case Byte_ascii.Star: + case Byte_ascii.Quote: return true; + default: return false; + } + } +} diff --git a/100_core/src_210_env/gplx/ProcessAdp.java b/100_core/src_210_env/gplx/ProcessAdp.java new file mode 100644 index 000000000..3b3263532 --- /dev/null +++ b/100_core/src_210_env/gplx/ProcessAdp.java @@ -0,0 +1,354 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.core.threads.*; +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +import javax.management.RuntimeErrorException; +import gplx.core.strings.*; +public class ProcessAdp implements GfoInvkAble, RlsAble { + public boolean Enabled() {return enabled;} public ProcessAdp Enabled_(boolean v) {enabled = v; return this;} private boolean enabled = true; + public byte Exe_exists() {return exe_exists;} public ProcessAdp Exe_exists_(byte v) {exe_exists = v; return this;} private byte exe_exists = Bool_.__byte; + public Io_url Exe_url() {return exe_url;} public ProcessAdp Exe_url_(Io_url val) {exe_url = val; exe_exists = Bool_.__byte; return this;} Io_url exe_url; + public String Args_str() {return args_str;} public ProcessAdp Args_str_(String val) {args_str = val; return this;} private String args_str = ""; + public Bry_fmtr Args_fmtr() {return args_fmtr;} Bry_fmtr args_fmtr = Bry_fmtr.new_(""); + public byte Run_mode() {return run_mode;} public ProcessAdp Run_mode_(byte v) {run_mode = v; return this;} private byte run_mode = Run_mode_sync_block; + public static final byte Run_mode_async = 0, Run_mode_sync_block = 1, Run_mode_sync_timeout = 2; + public int Exit_code() {return exit_code;} int exit_code; + public boolean Exit_code_pass() {return exit_code == Exit_pass;} + public String Rslt_out() {return rslt_out;} private String rslt_out; + public Io_url Working_dir() {return working_dir;} public ProcessAdp Working_dir_(Io_url v) {working_dir = v; return this;} Io_url working_dir; + public ProcessAdp Cmd_args(String cmd, String args) {this.Exe_url_(Io_url_.new_fil_(cmd)); this.args_fmtr.Fmt_(args); return this;} + public ProcessAdp WhenBgn_add(GfoInvkAbleCmd cmd) {whenBgnList.Add(cmd); return this;} + public ProcessAdp WhenBgn_del(GfoInvkAbleCmd cmd) {whenBgnList.Del(cmd); return this;} + public int Thread_timeout() {return thread_timeout;} public ProcessAdp Thread_timeout_seconds_(int v) {thread_timeout = v * 1000; return this;} int thread_timeout = 0; + public int Thread_interval() {return thread_interval;} public ProcessAdp Thread_interval_(int v) {thread_interval = v; return this;} int thread_interval = 20; + public String Thread_kill_name() {return thread_kill_name;} public ProcessAdp Thread_kill_name_(String v) {thread_kill_name = v; return this;} private String thread_kill_name = ""; + public Io_url Tmp_dir() {return tmp_dir;} @gplx.Virtual public ProcessAdp Tmp_dir_(Io_url v) {tmp_dir = v; return this;} Io_url tmp_dir; + private ProcessAdp WhenBgn_run() {return Invk_cmds(whenBgnList);} List_adp whenBgnList = List_adp_.new_(); + public ProcessAdp WhenEnd_add(GfoInvkAbleCmd cmd) {whenEndList.Add(cmd); return this;} + public ProcessAdp WhenEnd_del(GfoInvkAbleCmd cmd) {whenEndList.Del(cmd); return this;} + public Gfo_usr_dlg Prog_dlg() {return prog_dlg;} public ProcessAdp Prog_dlg_(Gfo_usr_dlg v) {prog_dlg = v; return this;} Gfo_usr_dlg prog_dlg; + public String Prog_fmt() {return prog_fmt;} public ProcessAdp Prog_fmt_(String v) {prog_fmt = v; return this;} private String prog_fmt = ""; // NOTE: set to "", else cmds that do not set prog_fmt will fail on fmtr.Fmt(null) + private GfoInvkAble owner; + private ProcessAdp WhenEnd_run() {return Invk_cmds(whenEndList);} List_adp whenEndList = List_adp_.new_(); + private ProcessAdp Invk_cmds(List_adp list) { + for (Object o : list) + ((GfoInvkAbleCmd)o).Invk(); + return this; + } + public ProcessAdp Run(Object... args) { + if (String_.Len_eq_0(exe_url.Raw())) return this; // noop if exe_url is ""; + if (!args_fmtr.Fmt_null()) { + Bry_bfr tmp_bfr = Bry_bfr.new_(); + args_fmtr.Bld_bfr_many(tmp_bfr, args); + args_str = tmp_bfr.Xto_str_and_clear(); + } + prog_dlg.Log_many(GRP_KEY, "run", "running process: ~{0} ~{1}", exe_url.Raw(), args_str); + exit_code = Exit_init; + switch (run_mode) { + case Run_mode_async: return Run_async(); + case Run_mode_sync_timeout: return Run_wait(); + case Run_mode_sync_block: return Run_wait_sync(); + default: throw Exc_.new_unhandled(run_mode); + } + } + public String[] Xto_process_bldr_args(String... args) { + String args_str = args_fmtr.Bld_str_many(args); + return Xto_process_bldr_args_utl(exe_url, args_str); + } + public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) { + if (ctx.Match(k, Invk_enabled)) return enabled; + else if (ctx.Match(k, Invk_enabled_)) enabled = m.ReadBool("v"); + else if (ctx.Match(k, Invk_cmd)) return exe_url.Raw(); + else if (ctx.Match(k, Invk_cmd_)) this.Exe_url_(Bry_fmtr_eval_mgr_.Eval_url(cmd_url_eval, m.ReadBry("cmd"))); + else if (ctx.Match(k, Invk_args)) return String_.new_u8(args_fmtr.Fmt()); + else if (ctx.Match(k, Invk_args_)) args_fmtr.Fmt_(m.ReadBry("v")); + else if (ctx.Match(k, Invk_cmd_args_)) {this.Exe_url_(Bry_fmtr_eval_mgr_.Eval_url(cmd_url_eval, m.ReadBry("cmd"))); args_fmtr.Fmt_(m.ReadBry("args"));} + else if (ctx.Match(k, Invk_mode_)) run_mode = m.ReadByte("v"); + else if (ctx.Match(k, Invk_timeout_)) thread_timeout = m.ReadInt("v"); + else if (ctx.Match(k, Invk_tmp_dir_)) tmp_dir = m.ReadIoUrl("v"); + else if (ctx.Match(k, Invk_owner)) return owner; + else return GfoInvkAble_.Rv_unhandled; + return this; + } + static final String Invk_cmd = "cmd", Invk_cmd_ = "cmd_", Invk_args = "args", Invk_args_ = "args_", Invk_cmd_args_ = "cmd_args_", Invk_enabled = "enabled", Invk_enabled_ = "enabled_", Invk_mode_ = "mode_", Invk_timeout_ = "timeout_", Invk_tmp_dir_ = "tmp_dir_", Invk_owner = "owner"; + Bry_fmtr_eval_mgr cmd_url_eval; + public static ProcessAdp ini_(GfoInvkAble owner, Gfo_usr_dlg usr_dlg, ProcessAdp process, Bry_fmtr_eval_mgr cmd_url_eval, byte run_mode, int timeout, String cmd_url_fmt, String args_fmt, String... args_keys) { + process.Run_mode_(run_mode).Thread_timeout_seconds_(timeout); + process.cmd_url_eval = cmd_url_eval; + Io_url cmd_url = Bry_fmtr_eval_mgr_.Eval_url(cmd_url_eval, Bry_.new_u8(cmd_url_fmt)); + process.Exe_url_(cmd_url).Tmp_dir_(cmd_url.OwnerDir()); + process.Args_fmtr().Fmt_(args_fmt).Keys_(args_keys); + process.owner = owner; + process.Prog_dlg_(usr_dlg); + return process; // return process for chaining + } + public static String Escape_ampersands_if_process_is_cmd(boolean os_is_wnt, String exe_url, String exe_args) { + return ( os_is_wnt + && String_.Eq(exe_url, "cmd")) + ? String_.Replace(exe_args, "&", "^&") // escape ampersands + : exe_args + ; + } + private Bry_fmtr notify_fmtr = Bry_fmtr.new_("", "process_exe_name", "process_exe_args", "process_seconds"); Bry_bfr notify_bfr = Bry_bfr.reset_(255); + public Process UnderProcess() {return process;} Process process; + public void Rls() {if (process != null) process.destroy();} + public ProcessAdp Run_wait_sync() { + if (Env_.Mode_testing()) return Test_runs_add(); + Process_bgn(); + Process_start(); + Process_run_and_end(); + return this; + } + public ProcessAdp Run_start() { + if (Env_.Mode_testing()) return Test_runs_add(); + Process_bgn(); + Process_start(); + return this; + } + public ProcessAdp Run_async() { + if (Env_.Mode_testing()) return Test_runs_add(); + Process_bgn(); + Thread_ProcessAdp_async thread = new Thread_ProcessAdp_async(this); + thread.start(); + return this; + } + public ProcessAdp Run_wait() { + if (Env_.Mode_testing()) return Test_runs_add(); + int notify_interval = 100; int notify_checkpoint = notify_interval; + int elapsed = 0; + try { + Process_bgn(); + Thread_ProcessAdp_sync thread = new Thread_ProcessAdp_sync(this); + thread.start(); + // thread_timeout = 15000; + boolean thread_run = false; + notify_fmtr.Fmt_(prog_fmt); + while (thread.isAlive()) { + thread_run = true; + long prv = Env_.TickCount(); + Thread_adp_.Sleep(thread_interval); +// try {thread.join(thread_interval);} +// catch (InterruptedException e) {throw Err_.err_key_(e, "gplx.ProcessAdp", "thread interrupted at join");} + long cur = Env_.TickCount(); + int dif = (int)(cur - prv); + elapsed += dif; + if (prog_dlg != null) { + if (elapsed > notify_checkpoint) { + elapsed = notify_checkpoint; + notify_checkpoint += notify_interval; + notify_fmtr.Bld_bfr_many(notify_bfr, exe_url.NameAndExt(), args_str, elapsed / 1000); + prog_dlg.Prog_none(GRP_KEY, "notify.prog", notify_bfr.Xto_str_and_clear()); + } + } + if (thread_timeout == 0) break; + if (elapsed > thread_timeout) { + thread.interrupt(); + thread.Cancel(); + try {thread.join();} + catch (InterruptedException e) {throw Exc_.new_exc(e, "core", "thread interrupted at timeout");} + break; + } + } + if (!thread_run) { + try {thread.join();} + catch (InterruptedException e) {throw Exc_.new_exc(e, "core", "thread interrupted at join 2");} + } + } catch (Exception exc) { + Tfds.Write(Err_.Message_gplx_brief(exc)); + } + if (elapsed != notify_checkpoint) { + notify_fmtr.Bld_bfr_many(notify_bfr, exe_url.NameAndExt(), args_str, elapsed / 1000); + if (prog_dlg != null) prog_dlg.Prog_none(GRP_KEY, "notify.prog", notify_bfr.Xto_str_and_clear()); + } + return this; + } + public synchronized void Process_post(String result) { + exit_code = process.exitValue(); + rslt_out = result; + WhenEnd_run(); + process.destroy(); + } + String Kill() { + if (thread_kill_name == String_.Empty) return ""; +// Runtime rt = Runtime.getRuntime(); + String kill_exe = "", kill_args = ""; + if (Op_sys.Cur().Tid_is_wnt()) { + kill_exe = "taskkill"; + kill_args = "/F /IM "; + } + else { + kill_exe = "kill"; + kill_args = "-9 "; + } + kill_args += thread_kill_name; + ProcessAdp kill_process = new ProcessAdp().Exe_url_(Io_url_.new_fil_(kill_exe)).Args_str_(kill_args).Thread_kill_name_(""); + boolean pass = kill_process.Run_wait().Exit_code_pass(); + return "killed|" + kill_exe + "|" + kill_args + "|" + pass + "|" + exe_url.Raw() + "|" + args_str; + } + synchronized void Process_bgn() { + exit_code = Exit_init; + rslt_out = ""; + WhenBgn_run(); + pb = new ProcessBuilder(Xto_process_bldr_args_utl(exe_url, args_str)); + pb.redirectErrorStream(true); // NOTE: need to redirectErrorStream or rdr.readLine() will hang; see inkscape and Ostfriesland Verkehr-de.svg + if (working_dir != null) + pb.directory(new File(working_dir.Xto_api())); + else if (!exe_url.OwnerDir().EqNull()) // only set workingDir if ownerDir is not null; NOTE: workingDir necessary for AdvMame; probably not a bad thing to do + pb.directory(new File(exe_url.OwnerDir().Xto_api())); + } ProcessBuilder pb; + protected Process Process_start() { + try {process = pb.start();} + catch (IOException e) { + java.util.List command_list = pb.command(); + String[] command_ary = new String[command_list.size()]; + command_ary = command_list.toArray(command_ary); + throw Exc_.new_exc(e, "core", "process start failed", "args", String_.Concat_with_str(" ", command_ary)); + } + return process; + } + void Process_run_and_end() { + String_bldr sb = String_bldr_.new_(); + BufferedReader rdr = new BufferedReader(new InputStreamReader(process.getInputStream())); + try { + String line = ""; + while ((line = rdr.readLine()) != null) + sb.Add_str_w_crlf(line); + process.waitFor(); + } + catch (InterruptedException e) {throw Exc_.new_exc(e, "core", "thread interrupted at wait_for", "exe_url", exe_url.Xto_api(), "exeArgs", args_str);} + catch (IOException e) {throw Exc_.new_exc(e, "core", "io error", "exe_url", exe_url.Xto_api(), "exeArgs", args_str);} + exit_code = process.exitValue(); + WhenEnd_run(); + process.destroy(); + rslt_out = sb.Xto_str_and_clear(); + } + public void Process_term() { + try { + process.getInputStream().close(); + process.getErrorStream().close(); + } catch (IOException e) {} + process.destroy(); + } + public static void run_wait_(Io_url url) { + ProcessAdp process = new ProcessAdp().Exe_url_(url); + process.Run_start(); + process.Process_run_and_end(); + return; + } + public static final List_adp Test_runs = List_adp_.new_(); + private ProcessAdp Test_runs_add() {Test_runs.Add(exe_url.Raw() + " " + args_str); exit_code = Exit_pass; return this;} + public static int run_wait_arg_(Io_url url, String arg) { + ProcessAdp process = new ProcessAdp(); + process.Exe_url_(url).Args_str_(arg).Run_wait(); + return process.Exit_code(); + } + private static final String GRP_KEY = "gplx.process"; + public static final int Exit_pass = 0, Exit_init = -1; + public static String[] Xto_process_bldr_args_utl(Io_url exe_url, String args_str) { + List_adp list = List_adp_.new_(); + list.Add(exe_url.Xto_api()); + String_bldr sb = String_bldr_.new_(); + int len = String_.Len(args_str); + boolean in_quotes = false; + for (int i = 0; i < len; i++) { + char c = String_.CharAt(args_str, i); + if (c == ' ' && !in_quotes) { // space encountered; assume arg done + list.Add(sb.XtoStr()); + sb.Clear(); + } + else if (c == '"') // NOTE: ProcessBuilder seems to have issues with quotes; do not call sb.Add() + in_quotes = !in_quotes; + else + sb.Add(c); + } + if (sb.Has_some()) list.Add(sb.XtoStr()); + return list.To_str_ary(); + } +} +class Thread_ProcessAdp_async extends Thread { + public Thread_ProcessAdp_async(ProcessAdp process_adp) {this.process_adp = process_adp;} ProcessAdp process_adp; + public boolean Done() {return done;} boolean done = false; + public void Cancel() {process_adp.UnderProcess().destroy();} + public void run() { + process_adp.Run_wait(); + } +} +class Thread_ProcessAdp_sync extends Thread { + public Thread_ProcessAdp_sync(ProcessAdp process_adp) {this.process_adp = process_adp;} private final ProcessAdp process_adp; + public boolean Done() {return done;} private boolean done = false; + public void Cancel() { + process_adp.UnderProcess().destroy(); + } + public synchronized void run() { + done = false; + try { + Process process = process_adp.Process_start(); + StreamGobbler input_gobbler = new StreamGobbler("input", process.getInputStream()); + StreamGobbler error_gobbler = new StreamGobbler("error", process.getErrorStream()); + input_gobbler.start(); + error_gobbler.start(); + try {process.waitFor();} + catch (InterruptedException e) { + this.Cancel(); + String kill_rslt = process_adp.Kill(); + process_adp.Process_post(kill_rslt); + done = false; + return; + } + while (input_gobbler.isAlive()) { + try {input_gobbler.join(50);} + catch (InterruptedException e) {throw Exc_.new_exc(e, "core", "thread interrupted at input gobbler");} + } + while (error_gobbler.isAlive()) { + try {error_gobbler.join(50);} + catch (InterruptedException e) {throw Exc_.new_exc(e, "core", "thread interrupted at error gobbler");} + } + String result = input_gobbler.Rslt() + "\n" + error_gobbler.Rslt(); + process_adp.Process_post(result); + } catch (Exception e) { // NOTE: warn; do not throw, else multiple errors if timidity not available; PAGE:fr.u:Pentatoniques_altérées/Gammes_avec_deux_notes_altérées DATE:2015-05-08 + Gfo_usr_dlg_.I.Warn_many("", "", "process.sync failed; cmd=~{0} args=~{1}", process_adp.Exe_url().Raw(), process_adp.Args_str()); + } + finally {done = true;} + } +} +class StreamGobbler extends Thread { + private final String name; private final InputStream stream; + public StreamGobbler (String name, InputStream stream) {this.name = name; this.stream = stream;} + public String Rslt() {return rslt;} private String rslt; + public void run () { + try { + String_bldr sb = String_bldr_.new_(); + InputStreamReader isr = new InputStreamReader(stream); + BufferedReader br = new BufferedReader(isr); + while (true) { + String s = br.readLine(); + if (s == null) break; + sb.Add(s); + } + stream.close(); + rslt = sb.Xto_str_and_clear(); + } + catch (Exception e) {throw Exc_.new_exc(e, "io", "failed reading stream", "name", name);} + } +} diff --git a/100_core/src_210_env/gplx/ProcessAdp_tst.java b/100_core/src_210_env/gplx/ProcessAdp_tst.java new file mode 100644 index 000000000..b3d28f380 --- /dev/null +++ b/100_core/src_210_env/gplx/ProcessAdp_tst.java @@ -0,0 +1,32 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class ProcessAdp_tst { + private ProcessAdp_fxt fxt = new ProcessAdp_fxt(); + @Test public void Escape_ampersands_if_process_is_cmd() { + fxt.Test_Escape_ampersands_if_process_is_cmd(Bool_.Y, "cmd" , "/c \"http://a.org?b=c&d=e\"", "/c \"http://a.org?b=c^&d=e\""); + fxt.Test_Escape_ampersands_if_process_is_cmd(Bool_.Y, "cmd1", "/c \"http://a.org?b=c&d=e\"", "/c \"http://a.org?b=c&d=e\""); + fxt.Test_Escape_ampersands_if_process_is_cmd(Bool_.N, "cmd" , "/c \"http://a.org?b=c&d=e\"", "/c \"http://a.org?b=c&d=e\""); + } +} +class ProcessAdp_fxt { + public void Test_Escape_ampersands_if_process_is_cmd(boolean os_is_wnt, String exe_url, String exe_args, String expd) { + Tfds.Eq(expd, ProcessAdp.Escape_ampersands_if_process_is_cmd(os_is_wnt, exe_url, exe_args)); + } +} diff --git a/100_core/src_220_console/gplx/ConsoleAdp.java b/100_core/src_220_console/gplx/ConsoleAdp.java new file mode 100644 index 000000000..6e566eb07 --- /dev/null +++ b/100_core/src_220_console/gplx/ConsoleAdp.java @@ -0,0 +1,68 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class ConsoleAdp implements GfoInvkAble, ConsoleDlg { + public boolean Enabled() {return true;} + public boolean Canceled() {return canceled;} public void Canceled_set(boolean v) {canceled = v;} private boolean canceled = false; + public boolean CanceledChk() {if (canceled) throw Exc_.new_op_canceled(); return canceled;} + public int CharsPerLineMax() {return chars_per_line_max;} public void CharsPerLineMax_set(int v) {chars_per_line_max = v;} int chars_per_line_max = 80; + public boolean Backspace_by_bytes() {return backspace_by_bytes;} public ConsoleAdp Backspace_by_bytes_(boolean v) {backspace_by_bytes = v; return this;} private boolean backspace_by_bytes; + public void WriteText(String s) {ClearTempText(); WriteText_lang(s);} + public void WriteLine(String s) {ClearTempText(); WriteLine_lang(s);} + public void WriteLineOnly() {ClearTempText(); WriteLine("");} + public void WriteLineFormat(String format, Object... args) {ClearTempText(); WriteLine_lang(String_.Format(format, args));} + public char ReadKey(String m) {WriteText(m); return ReadKey_lang();} + public String ReadLine(String m) {WriteText(m); return ReadLine_lang();} + public void WriteTempText(String s) { + ClearTempText(); + if (String_.Has(s, "\r")) s = String_.Replace(s, "\r", " "); + if (String_.Has(s, "\n")) s = String_.Replace(s, "\n", " "); + if (String_.Len(s) >= chars_per_line_max) s = String_.Mid(s, 0, chars_per_line_max - String_.Len("...") - 1) + "..."; // NOTE: >= and -1 needed b/c line needs to be 1 less than max; ex: default cmd is 80 width, but writing 80 chars will automatically create lineBreak + tempText = s; + WriteText_lang(s); + } String tempText; + public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {return this;} + void ClearTempText() { + if (tempText == null) return; + if (Env_.Mode_debug()) {WriteText_lang(String_.CrLf); return;} + int count = backspace_by_bytes ? Bry_.new_u8(tempText).length : String_.Len(tempText); + String moveBack = String_.Repeat("\b", count); + this.WriteText_lang(moveBack); // move cursor back to beginning of line + this.WriteText_lang(String_.Repeat(" ", count)); // overwrite tempText with space + this.WriteText_lang(moveBack); // move cursor back to beginning of line (so next Write will start at beginning) + tempText = null; + } + void WriteText_lang(String s) {System.out.print(s);} + void WriteLine_lang(String s) {System.out.println(s);} + String ReadLine_lang() {return System.console() == null ? "" : System.console().readLine();} + char ReadKey_lang() { + String text = ReadLine_lang(); + return String_.Len(text) == 0 ? '\0' : String_.CharAt(text, 0); + } + public void WriteLine_utf8(String s) { + java.io.PrintStream ps; + try {ps = new java.io.PrintStream(System.out, true, "UTF-8");} + catch (java.io.UnsupportedEncodingException e) {throw Exc_.new_("unsupported exception");} + ps.println(s); + } + public static final ConsoleAdp _ = new ConsoleAdp(); + public ConsoleAdp() { + if (Op_sys.Cur().Tid_is_lnx()) + backspace_by_bytes = true; // bash shows UTF8 by default; backspace in bytes, else multi-byte characters don't show; DATE:2014-03-04 + } +} diff --git a/100_core/src_220_console/gplx/ConsoleDlg.java b/100_core/src_220_console/gplx/ConsoleDlg.java new file mode 100644 index 000000000..74a79d3ea --- /dev/null +++ b/100_core/src_220_console/gplx/ConsoleDlg.java @@ -0,0 +1,28 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public interface ConsoleDlg { + boolean Enabled(); // optimization; allows Write to be skipped (since Write may Concat strings or generate arrays) + boolean CanceledChk(); + int CharsPerLineMax(); void CharsPerLineMax_set(int v); + void WriteText(String s); + void WriteLineFormat(String s, Object... args); + void WriteTempText(String s); + char ReadKey(String msg); + String ReadLine(String msg); +} diff --git a/100_core/src_220_console/gplx/ConsoleDlg_.java b/100_core/src_220_console/gplx/ConsoleDlg_.java new file mode 100644 index 000000000..39db2eaad --- /dev/null +++ b/100_core/src_220_console/gplx/ConsoleDlg_.java @@ -0,0 +1,32 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class ConsoleDlg_ { + public static final ConsoleDlg Null = new ConsoleDlg_null(); + public static ConsoleDlg_dev Dev() {return new ConsoleDlg_dev();} +} +class ConsoleDlg_null implements ConsoleDlg { + public boolean Enabled() {return false;} + public boolean CanceledChk() {return false;} + public int CharsPerLineMax() {return 80;} public void CharsPerLineMax_set(int v) {} + public void WriteText(String s) {} + public void WriteLineFormat(String s, Object... args) {} + public void WriteTempText(String s) {} + public char ReadKey(String msg) {return '\0';} + public String ReadLine(String msg) {return "";} +} diff --git a/100_core/src_220_console/gplx/ConsoleDlg_dev.java b/100_core/src_220_console/gplx/ConsoleDlg_dev.java new file mode 100644 index 000000000..a6e1e8cb1 --- /dev/null +++ b/100_core/src_220_console/gplx/ConsoleDlg_dev.java @@ -0,0 +1,49 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class ConsoleDlg_dev implements ConsoleDlg { + public boolean Enabled() {return true;} + public boolean CanceledChk() {return false;} + public int CharsPerLineMax() {return 80;} public void CharsPerLineMax_set(int v) {} + public ConsoleDlg_dev Ignore_add(String s) {ignored.Add_as_key_and_val(s); return this;} + public void WriteText(String s) {WriteString(s);} + public void WriteLineFormat(String s, Object... args) {WriteString(String_.Format(s, args) + String_.CrLf);} + public void WriteTempText(String s) {WriteString(s);} + public String ReadLine(String msg) {return "";} + public char ReadKey(String msg) {return '\0';} + public ConsoleDlg_dev CancelWhenTextWritten(String val) { + cancelVal = val; + return this; + } + void WriteString(String s) { + if (ignored.Has(s)) return; + written.Add(s); + if (cancelVal != null && String_.Has(s, cancelVal)) throw Exc_.new_("canceled", "cancel_val", s); + } + String cancelVal; + + public List_adp Written() {return written;} + public void tst_WrittenStr(String... expd) { + String[] actl = new String[written.Count()]; + int actlLength = Array_.Len(actl); + for (int i = 0; i < actlLength; i++) + actl[i] = written.Get_at(i).toString(); + Tfds.Eq_ary(actl, expd); + } + List_adp written = List_adp_.new_(), erased = List_adp_.new_(); Hash_adp ignored = Hash_adp_.new_(); +} diff --git a/100_core/src_300_classXtn/gplx/BoolClassXtn.java b/100_core/src_300_classXtn/gplx/BoolClassXtn.java new file mode 100644 index 000000000..d4d697ea4 --- /dev/null +++ b/100_core/src_300_classXtn/gplx/BoolClassXtn.java @@ -0,0 +1,41 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class BoolClassXtn extends ClassXtn_base implements ClassXtn { + public static final String Key_const = "bo" + "ol"; + public String Key() {return Key_const;} + @Override public Class UnderClass() {return boolean.class;} + public Object DefaultValue() {return false;} + public boolean Eq(Object lhs, Object rhs) {try {return Bool_.cast_(lhs) == Bool_.cast_(rhs);} catch (Exception e) {Exc_.Noop(e); return false;}} + @Override public Object ParseOrNull(String raw) { + if ( String_.Eq(raw, "true") + || String_.Eq(raw, "True") // needed for Store_Wtr() {boolVal.toString();} + || String_.Eq(raw, "1") // needed for db; gplx field for boolean is int; need simple way to convert from dbInt to langBool + ) + return true; + else if + ( String_.Eq(raw, "false") + || String_.Eq(raw, "False") + || String_.Eq(raw, "0") + ) + return false; + throw Exc_.new_parse_type(boolean.class, raw); + } + @Override public Object XtoDb(Object obj) {return obj;} + public static final BoolClassXtn _ = new BoolClassXtn(); BoolClassXtn() {} // added to ClassXtnPool by default +} \ No newline at end of file diff --git a/100_core/src_300_classXtn/gplx/ByteClassXtn.java b/100_core/src_300_classXtn/gplx/ByteClassXtn.java new file mode 100644 index 000000000..44e27d7a5 --- /dev/null +++ b/100_core/src_300_classXtn/gplx/ByteClassXtn.java @@ -0,0 +1,28 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class ByteClassXtn extends ClassXtn_base implements ClassXtn { + public static final String Key_const = "byte"; + public String Key() {return Key_const;} + @Override public Class UnderClass() {return byte.class;} + public Object DefaultValue() {return 0;} + public boolean Eq(Object lhs, Object rhs) {try {return Byte_.cast_(lhs) == Byte_.cast_(rhs);} catch (Exception e) {Exc_.Noop(e); return false;}} + @Override public Object ParseOrNull(String raw) {return raw == null ? (Object)null : Byte_.parse_(raw);} + @Override public Object XtoDb(Object obj) {return Byte_.cast_(obj);} + public static final ByteClassXtn _ = new ByteClassXtn(); ByteClassXtn() {} // added to ClassXtnPool by default +} \ No newline at end of file diff --git a/100_core/src_300_classXtn/gplx/ClassXtn.java b/100_core/src_300_classXtn/gplx/ClassXtn.java new file mode 100644 index 000000000..3732eb6e6 --- /dev/null +++ b/100_core/src_300_classXtn/gplx/ClassXtn.java @@ -0,0 +1,29 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public interface ClassXtn { + String Key(); + Class UnderClass(); + Object DefaultValue(); + Object ParseOrNull(String raw); + Object XtoDb(Object obj); + String XtoUi(Object obj, String fmt); + boolean MatchesClass(Object obj); + boolean Eq(Object lhs, Object rhs); + int compareTo(Object lhs, Object rhs); +} diff --git a/100_core/src_300_classXtn/gplx/ClassXtnPool.java b/100_core/src_300_classXtn/gplx/ClassXtnPool.java new file mode 100644 index 000000000..ef917f8c3 --- /dev/null +++ b/100_core/src_300_classXtn/gplx/ClassXtnPool.java @@ -0,0 +1,39 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.lists.*; +public class ClassXtnPool extends Hash_adp_base { + public void Add(ClassXtn typx) {Add_base(typx.Key(), typx);} + public ClassXtn Get_by_or_fail(String key) {return (ClassXtn)FetchOrFail_base(key);} + + public static final ClassXtnPool _ = new ClassXtnPool(); + public static final String Format_null = ""; + public static ClassXtnPool new_() {return new ClassXtnPool();} + ClassXtnPool() { + Add(ObjectClassXtn._); + Add(StringClassXtn._); + Add(IntClassXtn._); + Add(BoolClassXtn._); + Add(ByteClassXtn._); + Add(DateAdpClassXtn._); + Add(TimeSpanAdpClassXtn._); + Add(IoUrlClassXtn._); + Add(DecimalAdpClassXtn._); + Add(FloatClassXtn._); + } +} diff --git a/100_core/src_300_classXtn/gplx/ClassXtn_base.java b/100_core/src_300_classXtn/gplx/ClassXtn_base.java new file mode 100644 index 000000000..792f51331 --- /dev/null +++ b/100_core/src_300_classXtn/gplx/ClassXtn_base.java @@ -0,0 +1,28 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public abstract class ClassXtn_base { + public abstract Class UnderClass(); + public abstract Object ParseOrNull(String raw); + @gplx.Virtual public Object XtoDb(Object obj) {return obj;} + @gplx.Virtual public String XtoUi(Object obj, String fmt) {return Object_.Xto_str_strict_or_null_mark(obj);} + @gplx.Virtual public boolean MatchesClass(Object obj) {if (obj == null) throw Exc_.new_null("obj"); + return ClassAdp_.Eq_typeSafe(obj, UnderClass()); + } + @gplx.Virtual public int compareTo(Object lhs, Object rhs) {return CompareAble_.Compare_obj(lhs, rhs);} +} diff --git a/100_core/src_300_classXtn/gplx/DateAdpClassXtn.java b/100_core/src_300_classXtn/gplx/DateAdpClassXtn.java new file mode 100644 index 000000000..4944e999c --- /dev/null +++ b/100_core/src_300_classXtn/gplx/DateAdpClassXtn.java @@ -0,0 +1,28 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class DateAdpClassXtn extends ClassXtn_base implements ClassXtn { + public String Key() {return Key_const;} public static final String Key_const = "datetime"; + public boolean Eq(Object lhs, Object rhs) {try {return DateAdp_.cast_(lhs).Eq(DateAdp_.cast_(rhs));} catch (Exception e) {Exc_.Noop(e); return false;}} + @Override public Class UnderClass() {return DateAdp.class;} + public Object DefaultValue() {return DateAdp_.MinValue;} + @Override public Object ParseOrNull(String raw) {return DateAdp_.parse_gplx(raw);} + @Override public Object XtoDb(Object obj) {return DateAdp_.cast_(obj).XtoStr_gplx_long();} + @Override public String XtoUi(Object obj, String fmt) {return DateAdp_.cast_(obj).XtoStr_fmt(fmt);} + public static final DateAdpClassXtn _ = new DateAdpClassXtn(); DateAdpClassXtn() {} // added to ClassXtnPool by default +} diff --git a/100_core/src_300_classXtn/gplx/DateAdpClassXtn_tst.java b/100_core/src_300_classXtn/gplx/DateAdpClassXtn_tst.java new file mode 100644 index 000000000..2fe1efe22 --- /dev/null +++ b/100_core/src_300_classXtn/gplx/DateAdpClassXtn_tst.java @@ -0,0 +1,28 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class DateAdpClassXtn_tst { + @Test public void XtoDb() { + tst_XtoDb("20091115 220102.999", "2009-11-15 22:01:02.999"); + } + void tst_XtoDb(String val, String expdRaw) { + String actlRaw = (String)DateAdpClassXtn._.XtoDb(DateAdp_.parse_gplx(val)); + Tfds.Eq(expdRaw, actlRaw); + } +} diff --git a/100_core/src_300_classXtn/gplx/DecimalAdpClassXtn.java b/100_core/src_300_classXtn/gplx/DecimalAdpClassXtn.java new file mode 100644 index 000000000..e12935406 --- /dev/null +++ b/100_core/src_300_classXtn/gplx/DecimalAdpClassXtn.java @@ -0,0 +1,27 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class DecimalAdpClassXtn extends ClassXtn_base implements ClassXtn { + public String Key() {return Key_const;} public static final String Key_const = "decimal"; // current dsv files reference "decimal" + @Override public Class UnderClass() {return DecimalAdp.class;} + public Object DefaultValue() {return 0;} + public boolean Eq(Object lhs, Object rhs) {try {return DecimalAdp_.cast_(lhs).Eq(DecimalAdp_.cast_(rhs));} catch (Exception e) {Exc_.Noop(e); return false;}} + @Override public Object ParseOrNull(String raw) {return DecimalAdp_.parse_(raw);} + @Override public String XtoUi(Object obj, String fmt) {return DecimalAdp_.cast_(obj).Xto_str();} + public static final DecimalAdpClassXtn _ = new DecimalAdpClassXtn(); DecimalAdpClassXtn() {} // added to ClassXtnPool by default +} diff --git a/100_core/src_300_classXtn/gplx/DoubleClassXtn.java b/100_core/src_300_classXtn/gplx/DoubleClassXtn.java new file mode 100644 index 000000000..cbdbbced0 --- /dev/null +++ b/100_core/src_300_classXtn/gplx/DoubleClassXtn.java @@ -0,0 +1,26 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class DoubleClassXtn extends ClassXtn_base implements ClassXtn { + public String Key() {return Key_const;} public static final String Key_const = "double"; + @Override public Class UnderClass() {return double.class;} + public Object DefaultValue() {return 0;} + public boolean Eq(Object lhs, Object rhs) {try {return Double_.cast_(lhs) == Double_.cast_(rhs);} catch (Exception e) {Exc_.Noop(e); return false;}} + @Override public Object ParseOrNull(String raw) {return Double_.parse_(raw);} + public static final DoubleClassXtn _ = new DoubleClassXtn(); DoubleClassXtn() {} // added to ClassXtnPool by default +} \ No newline at end of file diff --git a/100_core/src_300_classXtn/gplx/FloatClassXtn.java b/100_core/src_300_classXtn/gplx/FloatClassXtn.java new file mode 100644 index 000000000..02d5d04ae --- /dev/null +++ b/100_core/src_300_classXtn/gplx/FloatClassXtn.java @@ -0,0 +1,26 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class FloatClassXtn extends ClassXtn_base implements ClassXtn { + public String Key() {return Key_const;} public static final String Key_const = "float"; + @Override public Class UnderClass() {return float.class;} + public Object DefaultValue() {return 0;} + public boolean Eq(Object lhs, Object rhs) {try {return Float_.cast_(lhs) == Float_.cast_(rhs);} catch (Exception e) {Exc_.Noop(e); return false;}} + @Override public Object ParseOrNull(String raw) {return Float_.parse_(raw);} + public static final FloatClassXtn _ = new FloatClassXtn(); FloatClassXtn() {} // added to ClassXtnPool by default +} \ No newline at end of file diff --git a/100_core/src_300_classXtn/gplx/IntClassXtn.java b/100_core/src_300_classXtn/gplx/IntClassXtn.java new file mode 100644 index 000000000..20a93d570 --- /dev/null +++ b/100_core/src_300_classXtn/gplx/IntClassXtn.java @@ -0,0 +1,28 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class IntClassXtn extends ClassXtn_base implements ClassXtn { + public String Key() {return Key_const;} public static final String Key_const = "int"; + @Override public Class UnderClass() {return Integer.class;} + public Object DefaultValue() {return 0;} + @Override public Object ParseOrNull(String raw) {return raw == null ? (Object)null : Int_.parse_(raw);} + public boolean Eq(Object lhs, Object rhs) {try {return Int_.cast_(lhs) == Int_.cast_(rhs);} catch (Exception e) {Exc_.Noop(e); return false;}} + @Override public Object XtoDb(Object obj) {return Int_.cast_(obj);} // necessary for enums + + public static final IntClassXtn _ = new IntClassXtn(); IntClassXtn() {} // added to ClassXtnPool by default +} diff --git a/100_core/src_300_classXtn/gplx/IoUrlClassXtn.java b/100_core/src_300_classXtn/gplx/IoUrlClassXtn.java new file mode 100644 index 000000000..825528d72 --- /dev/null +++ b/100_core/src_300_classXtn/gplx/IoUrlClassXtn.java @@ -0,0 +1,29 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class IoUrlClassXtn extends ClassXtn_base implements ClassXtn { + public String Key() {return Key_const;} public static final String Key_const = "ioPath"; + @Override public Class UnderClass() {return Io_url.class;} + public Object DefaultValue() {return Io_url_.Empty;} + @Override public Object ParseOrNull(String raw) {return Io_url_.new_any_(raw);} + @Override public Object XtoDb(Object obj) {return Io_url_.cast_(obj).Raw();} + @Override public String XtoUi(Object obj, String fmt) {return Io_url_.cast_(obj).Raw();} + @Override public boolean MatchesClass(Object obj) {return Io_url_.as_(obj) != null;} + public boolean Eq(Object lhs, Object rhs) {try {return Io_url_.cast_(lhs).Eq(Io_url_.cast_(rhs));} catch (Exception e) {Exc_.Noop(e); return false;}} + public static final IoUrlClassXtn _ = new IoUrlClassXtn(); IoUrlClassXtn() {} // added to ClassXtnPool by default +} diff --git a/100_core/src_300_classXtn/gplx/LongClassXtn.java b/100_core/src_300_classXtn/gplx/LongClassXtn.java new file mode 100644 index 000000000..988da3e8d --- /dev/null +++ b/100_core/src_300_classXtn/gplx/LongClassXtn.java @@ -0,0 +1,27 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class LongClassXtn extends ClassXtn_base implements ClassXtn { + public String Key() {return Key_const;} public static final String Key_const = "long"; + @Override public Class UnderClass() {return long.class;} + public Object DefaultValue() {return 0;} + public boolean Eq(Object lhs, Object rhs) {try {return Long_.cast_(lhs) == Long_.cast_(rhs);} catch (Exception e) {Exc_.Noop(e); return false;}} + @Override public Object ParseOrNull(String raw) {return raw == null ? (Object)null : Long_.parse_(raw);} + @Override public Object XtoDb(Object obj) {return Long_.cast_(obj);} // necessary for enums + public static final LongClassXtn _ = new LongClassXtn(); LongClassXtn() {} // added to ClassXtnPool by default +} \ No newline at end of file diff --git a/100_core/src_300_classXtn/gplx/ObjectClassXtn.java b/100_core/src_300_classXtn/gplx/ObjectClassXtn.java new file mode 100644 index 000000000..73fb5d5c4 --- /dev/null +++ b/100_core/src_300_classXtn/gplx/ObjectClassXtn.java @@ -0,0 +1,27 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class ObjectClassXtn extends ClassXtn_base implements ClassXtn { + public String Key() {return Key_const;} public static final String Key_const = "Object"; + @Override public Class UnderClass() {return Object.class;} + public Object DefaultValue() {return null;} + @Override public Object ParseOrNull(String raw) {throw Exc_.new_unimplemented();} + @Override public Object XtoDb(Object obj) {throw Exc_.new_unimplemented();} + public boolean Eq(Object lhs, Object rhs) {return lhs == rhs;} + public static final ObjectClassXtn _ = new ObjectClassXtn(); ObjectClassXtn() {} // added to ClassXtnPool by default +} diff --git a/100_core/src_300_classXtn/gplx/StringClassXtn.java b/100_core/src_300_classXtn/gplx/StringClassXtn.java new file mode 100644 index 000000000..e8a87c31e --- /dev/null +++ b/100_core/src_300_classXtn/gplx/StringClassXtn.java @@ -0,0 +1,28 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class StringClassXtn extends ClassXtn_base implements ClassXtn { + public static final String Key_const = "string"; + public String Key() {return Key_const;} + @Override public Class UnderClass() {return String.class;} + public Object DefaultValue() {return "";} + @Override public Object ParseOrNull(String raw) {return raw;} + @Override public String XtoUi(Object obj, String fmt) {return String_.as_(obj);} + public boolean Eq(Object lhs, Object rhs) {try {return String_.Eq(String_.cast_(lhs), String_.cast_(rhs));} catch (Exception e) {Exc_.Noop(e); return false;}} + public static final StringClassXtn _ = new StringClassXtn(); StringClassXtn() {} // added to ClassXtnPool by default +} \ No newline at end of file diff --git a/100_core/src_300_classXtn/gplx/TimeSpanAdpClassXtn.java b/100_core/src_300_classXtn/gplx/TimeSpanAdpClassXtn.java new file mode 100644 index 000000000..a864d3044 --- /dev/null +++ b/100_core/src_300_classXtn/gplx/TimeSpanAdpClassXtn.java @@ -0,0 +1,28 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class TimeSpanAdpClassXtn extends ClassXtn_base implements ClassXtn { + public String Key() {return Key_const;} public static final String Key_const = "timeSpan"; + @Override public Class UnderClass() {return TimeSpanAdp.class;} + public Object DefaultValue() {return TimeSpanAdp_.Zero;} + @Override public Object ParseOrNull(String raw) {return TimeSpanAdp_.parse_(raw);} + @Override public Object XtoDb(Object obj) {return TimeSpanAdp_.cast_(obj).TotalSecs();} + @Override public String XtoUi(Object obj, String fmt) {return TimeSpanAdp_.cast_(obj).XtoStr(fmt);} + public boolean Eq(Object lhs, Object rhs) {try {return TimeSpanAdp_.cast_(lhs).Eq(rhs);} catch (Exception e) {Exc_.Noop(e); return false;}} + public static final TimeSpanAdpClassXtn _ = new TimeSpanAdpClassXtn(); TimeSpanAdpClassXtn() {} // added to ClassXtnPool by default +} \ No newline at end of file diff --git a/100_core/src_310_gfoNde/gplx/GfoFld.java b/100_core/src_310_gfoNde/gplx/GfoFld.java new file mode 100644 index 000000000..74c808609 --- /dev/null +++ b/100_core/src_310_gfoNde/gplx/GfoFld.java @@ -0,0 +1,28 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class GfoFld { + public String Key() {return key;} private String key; + public ClassXtn Type() {return type;} ClassXtn type; + public static final GfoFld Null = new_(String_.Null_mark, ObjectClassXtn._); + public static GfoFld new_(String key, ClassXtn c) { + GfoFld rv = new GfoFld(); + rv.key = key; rv.type = c; + return rv; + } +} diff --git a/100_core/src_310_gfoNde/gplx/GfoFldList.java b/100_core/src_310_gfoNde/gplx/GfoFldList.java new file mode 100644 index 000000000..09ceef0db --- /dev/null +++ b/100_core/src_310_gfoNde/gplx/GfoFldList.java @@ -0,0 +1,27 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public interface GfoFldList { + int Count(); + boolean Has(String key); + int Idx_of(String key); + GfoFld Get_at(int i); + GfoFld FetchOrNull(String key); + GfoFldList Add(String key, ClassXtn c); + String XtoStr(); +} diff --git a/100_core/src_310_gfoNde/gplx/GfoFldList_.java b/100_core/src_310_gfoNde/gplx/GfoFldList_.java new file mode 100644 index 000000000..4c5d322cd --- /dev/null +++ b/100_core/src_310_gfoNde/gplx/GfoFldList_.java @@ -0,0 +1,63 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.core.strings.*; +public class GfoFldList_ { + public static final GfoFldList Null = new GfoFldList_null(); + public static GfoFldList new_() {return new GfoFldList_base();} + public static GfoFldList str_(String... names) { + GfoFldList rv = new GfoFldList_base(); + for (String name : names) + rv.Add(name, StringClassXtn._); + return rv; + } +} +class GfoFldList_base implements GfoFldList { + public int Count() {return hash.Count();} + public boolean Has(String key) {return hash.Has(key);} + public int Idx_of(String key) { + Object rv = idxs.Get_by(key); + return rv == null ? List_adp_.NotFound : Int_.cast_(rv); + } + public GfoFld Get_at(int i) {return (GfoFld)hash.Get_at(i);} + public GfoFld FetchOrNull(String key) {return (GfoFld)hash.Get_by(key);} + public GfoFldList Add(String key, ClassXtn c) { + GfoFld fld = GfoFld.new_(key, c); + hash.Add(key, fld); + idxs.Add(key, idxs.Count()); + return this; + } + public String XtoStr() { + String_bldr sb = String_bldr_.new_(); + for (int i = 0; i < hash.Count(); i++) { + GfoFld fld = this.Get_at(i); + sb.Add(fld.Key()).Add("|"); + } + return sb.XtoStr(); + } + Ordered_hash hash = Ordered_hash_.new_(); Hash_adp idxs = Hash_adp_.new_(); // PERF: idxs used for Idx_of; need to recalc if Del ever added +} +class GfoFldList_null implements GfoFldList { + public int Count() {return 0;} + public boolean Has(String key) {return false;} + public int Idx_of(String key) {return List_adp_.NotFound;} + public GfoFld Get_at(int i) {return GfoFld.Null;} + public GfoFld FetchOrNull(String key) {return null;} + public GfoFldList Add(String key, ClassXtn typx) {return this;} + public String XtoStr() {return "<>";} +} \ No newline at end of file diff --git a/100_core/src_310_gfoNde/gplx/GfoNde.java b/100_core/src_310_gfoNde/gplx/GfoNde.java new file mode 100644 index 000000000..8b3eeca68 --- /dev/null +++ b/100_core/src_310_gfoNde/gplx/GfoNde.java @@ -0,0 +1,72 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.core.strings.*; +public class GfoNde implements GfoInvkAble { + public GfoFldList Flds() {return flds;} GfoFldList flds; + public Hash_adp EnvVars() {return envVars;} Hash_adp envVars = Hash_adp_.new_(); + public String Name() {return name;} public GfoNde Name_(String v) {name = v; return this;} private String name; + public Object ReadAt(int i) {ChkIdx(i); return ary[i];} + public void WriteAt(int i, Object val) {ChkIdx(i); ary[i] = val;} + public Object Read(String key) {int i = IndexOfOrFail(key); return ary[i];} + public void Write(String key, Object val) {int i = IndexOfOrFail(key); ary[i] = val;} + public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {return Read(k);} + + public GfoNdeList Subs() {return subs;} GfoNdeList subs = GfoNdeList_.new_(); + public GfoFldList SubFlds() {return subFlds;} GfoFldList subFlds = GfoFldList_.new_(); + public void XtoStr_wtr(DataWtr wtr) {XtoStr_wtr(this, wtr);}// TEST + public String XtoStr() { + String_bldr sb = String_bldr_.new_(); + for (int i = 0; i < aryLen; i++) { + String key = i >= flds.Count() ? "<< NULL " + i + " >>" : flds.Get_at(i).Key(); + String val = i >= aryLen ? "<< NULL " + i + " >>" : Object_.Xto_str_strict_or_null_mark(ary[i]); + sb.Add(key).Add("=").Add(val); + } + return sb.XtoStr(); + } + int IndexOfOrFail(String key) { + int i = flds.Idx_of(key); + if ((i < 0 || i >= aryLen)) throw Exc_.new_("field name not found", "name", key, "index", i, "count", this.Flds().Count()); + return i; + } + boolean ChkIdx(int i) {if (i < 0 || i >= aryLen) throw Exc_.new_missing_idx(i, aryLen); return true;} + Object[] ary; int type; int aryLen; + @gplx.Internal protected GfoNde(int type, String name, GfoFldList flds, Object[] ary, GfoFldList subFlds, GfoNde[] subAry) { + this.type = type; this.name = name; this.flds = flds; this.ary = ary; aryLen = Array_.Len(ary); this.subFlds = subFlds; + for (GfoNde sub : subAry) + subs.Add(sub); + } + static void XtoStr_wtr(GfoNde nde, DataWtr wtr) { + if (nde.type == GfoNde_.Type_Leaf) { + wtr.WriteLeafBgn("flds"); + for (int i = 0; i < nde.ary.length; i++) + wtr.WriteData(nde.Flds().Get_at(i).Key(), nde.ReadAt(i)); + wtr.WriteLeafEnd(); + } + else { + if (nde.type == GfoNde_.Type_Node) // never write node info for root + wtr.WriteTableBgn(nde.Name(), nde.SubFlds()); + for (int i = 0; i < nde.Subs().Count(); i++) { + GfoNde sub = nde.Subs().FetchAt_asGfoNde(i); + XtoStr_wtr(sub, wtr); + } + if (nde.type == GfoNde_.Type_Node) + wtr.WriteNodeEnd(); + } + } +} diff --git a/100_core/src_310_gfoNde/gplx/GfoNdeFxt.java b/100_core/src_310_gfoNde/gplx/GfoNdeFxt.java new file mode 100644 index 000000000..819db4e41 --- /dev/null +++ b/100_core/src_310_gfoNde/gplx/GfoNdeFxt.java @@ -0,0 +1,35 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class GfoNdeFxt { + public GfoNde root_(GfoNde... subs) {return GfoNde_.root_(subs);} + public GfoNde tbl_(String name, GfoNde... rows) {return GfoNde_.tbl_(name, GfoFldList_.Null, rows);} + public GfoNde nde_(String name, GfoFldList flds, GfoNde... subs) {return GfoNde_.tbl_(name, flds, subs);} + public GfoNde row_(GfoFldList flds, Object... vals) {return GfoNde_.vals_(flds, vals);} + public GfoNde row_vals_(Object... vals) {return GfoNde_.vals_(GfoFldList_by_count_(vals.length), vals);} + public GfoNde csv_dat_(GfoNde... rows) {return GfoNde_.tbl_("", GfoFldList_.Null, rows);} + public GfoNde csv_hdr_(GfoFldList flds, GfoNde... rows) {return GfoNde_.tbl_("", flds, rows);} + public static GfoNdeFxt new_() {return new GfoNdeFxt();} + + static GfoFldList GfoFldList_by_count_(int count) { + GfoFldList rv = GfoFldList_.new_(); + for (int i = 0; i < count; i++) + rv.Add("fld" + Int_.Xto_str(i), StringClassXtn._); + return rv; + } +} diff --git a/100_core/src_310_gfoNde/gplx/GfoNdeList.java b/100_core/src_310_gfoNde/gplx/GfoNdeList.java new file mode 100644 index 000000000..fd6b96a2e --- /dev/null +++ b/100_core/src_310_gfoNde/gplx/GfoNdeList.java @@ -0,0 +1,27 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.lists.*; /*ComparerAble*/ +public interface GfoNdeList { + int Count(); + GfoNde FetchAt_asGfoNde(int index); + void Add(GfoNde rcd); + void Del(GfoNde rcd); + void Clear(); + void Sort_by(ComparerAble comparer); +} diff --git a/100_core/src_310_gfoNde/gplx/GfoNdeList_.java b/100_core/src_310_gfoNde/gplx/GfoNdeList_.java new file mode 100644 index 000000000..03bce5556 --- /dev/null +++ b/100_core/src_310_gfoNde/gplx/GfoNdeList_.java @@ -0,0 +1,40 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.lists.*; /*ComparerAble*/ +public class GfoNdeList_ { + public static final GfoNdeList Null = new GfoNdeList_null(); + public static GfoNdeList new_() {return new GfoNdeList_base();} +} +class GfoNdeList_base implements GfoNdeList { + public int Count() {return list.Count();} + public GfoNde FetchAt_asGfoNde(int i) {return (GfoNde)list.Get_at(i);} + public void Add(GfoNde rcd) {list.Add(rcd);} + public void Del(GfoNde rcd) {list.Del(rcd);} + public void Clear() {list.Clear();} + public void Sort_by(ComparerAble comparer) {list.Sort_by(comparer);} + List_adp list = List_adp_.new_(); +} +class GfoNdeList_null implements GfoNdeList { + public int Count() {return 0;} + public GfoNde FetchAt_asGfoNde(int index) {return null;} + public void Add(GfoNde rcd) {} + public void Del(GfoNde rcd) {} + public void Clear() {} + public void Sort_by(ComparerAble comparer) {} +} diff --git a/100_core/src_310_gfoNde/gplx/GfoNde_.java b/100_core/src_310_gfoNde/gplx/GfoNde_.java new file mode 100644 index 000000000..3cffa7a76 --- /dev/null +++ b/100_core/src_310_gfoNde/gplx/GfoNde_.java @@ -0,0 +1,46 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class GfoNde_ { + public static final GfoNde[] Ary_empty = new GfoNde[0]; + public static GfoNde[] ary_(GfoNde... ary) {return ary;} + public static GfoNde as_(Object obj) {return obj instanceof GfoNde ? (GfoNde)obj : null;} + public static GfoNde root_(GfoNde... subs) {return new GfoNde(GfoNde_.Type_Root, "RootName", GfoFldList_.Null, Object_.Ary_empty, GfoFldList_.Null, subs);} + public static GfoNde tbl_(String name, GfoFldList flds, GfoNde... rows) {return new GfoNde(GfoNde_.Type_Node, name, flds, Object_.Ary_empty, flds, rows);} + public static GfoNde vals_(GfoFldList flds, Object[] ary) {return new GfoNde(GfoNde_.Type_Leaf, "row", flds, ary, GfoFldList_.Null, Ary_empty);} + public static GfoNde vals_params_(GfoFldList flds, Object... ary) {return new GfoNde(GfoNde_.Type_Leaf, "row", flds, ary, GfoFldList_.Null, Ary_empty);} + public static GfoNde nde_(String name, Object[] ary, GfoNde... subs) {return new GfoNde(GfoNde_.Type_Node, name, GfoFldList_.Null, ary, GfoFldList_.Null, subs);} + public static GfoNde rdr_(DataRdr rdr) { + try { + List_adp rows = List_adp_.new_(); + GfoFldList flds = GfoFldList_.new_(); + int fldLen = rdr.FieldCount(); + for (int i = 0; i < fldLen; i++) + flds.Add(rdr.KeyAt(i), ObjectClassXtn._); + while (rdr.MoveNextPeer()) { + Object[] valAry = new Object[fldLen]; + for (int i = 0; i < fldLen; i++) + valAry[i] = rdr.ReadAt(i); + rows.Add(GfoNde_.vals_(flds, valAry)); + } + return GfoNde_.tbl_("", flds, (GfoNde[])rows.To_ary(GfoNde.class)); + } + finally {rdr.Rls();} + } + @gplx.Internal protected static final int Type_Leaf = 1, Type_Node = 2, Type_Root = 3; +} diff --git a/100_core/src_311_gfoObj/gplx/GfoEvMgr.java b/100_core/src_311_gfoObj/gplx/GfoEvMgr.java new file mode 100644 index 000000000..6b3be9df8 --- /dev/null +++ b/100_core/src_311_gfoObj/gplx/GfoEvMgr.java @@ -0,0 +1,131 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.lists.*; +public class GfoEvMgr { + @gplx.Internal protected void AddSub(GfoEvMgrOwner pub, String pubEvt, GfoEvObj sub, String subPrc) { + GfoEvLnk lnk = new GfoEvLnk(pub, pubEvt, sub, subPrc); + if (subsRegy == null) subsRegy = Ordered_hash_.new_(); + AddInList(subsRegy, pubEvt, lnk); + sub.EvMgr().AddPub(pubEvt, lnk); + } + @gplx.Internal protected void Lnk(GfoEvMgrOwner pub) { + if (pub.EvMgr().lnks == null) pub.EvMgr().lnks = List_adp_.new_(); + pub.EvMgr().lnks.Add(this); + } List_adp lnks; + void AddInList(Ordered_hash regy, String key, GfoEvLnk lnk) { + GfoEvLnkList list = (GfoEvLnkList)regy.Get_by(key); + if (list == null) { + list = new GfoEvLnkList(key); + regy.Add(key, list); + } + list.Add(lnk); + } + @gplx.Internal protected void AddPub(String pubEvt, GfoEvLnk lnk) { + if (pubsRegy == null) pubsRegy = Ordered_hash_.new_(); + AddInList(pubsRegy, pubEvt, lnk); + } + @gplx.Internal protected void Pub(GfsCtx ctx, String evt, GfoMsg m) { + ctx.MsgSrc_(sender); + GfoEvLnkList subs = subsRegy == null ? null : (GfoEvLnkList)subsRegy.Get_by(evt); + if (subs != null) { + for (int i = 0; i < subs.Count(); i++) { + GfoEvLnk lnk = (GfoEvLnk)subs.Get_at(i); + lnk.Sub().Invk(ctx, 0, lnk.SubPrc(), m); // NOTE: itm.Key() needed for Subscribe_diff() + } + } + if (lnks != null) { + for (int i = 0; i < lnks.Count(); i++) { + GfoEvMgr lnk = (GfoEvMgr)lnks.Get_at(i); + lnk.Pub(ctx, evt, m); + } + } + } + @gplx.Internal protected void RlsSub(GfoEvMgrOwner eobj) { + RlsRegyObj(pubsRegy, eobj, true); + RlsRegyObj(subsRegy, eobj, false); + } + @gplx.Internal protected void RlsPub(GfoEvMgrOwner eobj) { + RlsRegyObj(pubsRegy, eobj, true); + RlsRegyObj(subsRegy, eobj, false); + } + @gplx.Internal protected void RlsRegyObj(Ordered_hash regy, GfoEvMgrOwner eobj, boolean pub) { + if (regy == null) return; + List_adp delList = List_adp_.new_(); + for (int i = 0; i < regy.Count(); i++) { + GfoEvLnkList pubsList = (GfoEvLnkList)regy.Get_at(i); + delList.Clear(); + for (int j = 0; j < pubsList.Count(); j++) { + GfoEvLnk lnk = (GfoEvLnk)pubsList.Get_at(j); + if (lnk.End(!pub) == eobj) delList.Add(lnk); + } + for (int j = 0; j < delList.Count(); j++) { + GfoEvLnk del = (GfoEvLnk)delList.Get_at(j); + del.End(pub).EvMgr().RlsLnk(!pub, pubsList.Key(), del.End(!pub)); + pubsList.Del(del); + } + } + } + @gplx.Internal protected void RlsLnk(boolean pubEnd, String key, GfoEvMgrOwner endObj) { + Ordered_hash regy = pubEnd ? pubsRegy : subsRegy; + GfoEvLnkList list = (GfoEvLnkList)regy.Get_by(key); + List_adp delList = List_adp_.new_(); + for (int i = 0; i < list.Count(); i++) { + GfoEvLnk lnk = (GfoEvLnk)list.Get_at(i); + if (lnk.End(pubEnd) == endObj) delList.Add(lnk); + } + for (int i = 0; i < delList.Count(); i++) { + GfoEvLnk lnk = (GfoEvLnk)delList.Get_at(i); + list.Del(lnk); + } + delList.Clear(); + } + + Object sender; Ordered_hash subsRegy, pubsRegy; + public static GfoEvMgr new_(Object sender) { + GfoEvMgr rv = new GfoEvMgr(); + rv.sender = sender; + return rv; + } GfoEvMgr() {} +} +class GfoEvLnkList { + public String Key() {return key;} private String key; + public int Count() {return list.Count();} + public void Add(GfoEvLnk lnk) {list.Add(lnk);} + public void Del(GfoEvLnk lnk) {list.Del(lnk);} + public GfoEvLnk Get_at(int i) {return (GfoEvLnk)list.Get_at(i);} + public GfoEvLnkList(String key) {this.key = key;} + List_adp list = List_adp_.new_(); +} +class GfoEvLnk { + public GfoEvMgrOwner Pub() {return pub;} GfoEvMgrOwner pub; + public String PubEvt() {return pubEvt;} private String pubEvt; + public GfoEvObj Sub() {return sub;} GfoEvObj sub; + public String SubPrc() {return subPrc;} private String subPrc; + public GfoEvMgrOwner End(boolean pubEnd) {return pubEnd ? pub : sub;} + public GfoEvLnk(GfoEvMgrOwner pub, String pubEvt, GfoEvObj sub, String subPrc) {this.pub = pub; this.pubEvt = pubEvt; this.sub = sub; this.subPrc = subPrc;} +} +class GfoEvItm { + public String Key() {return key;} private String key; + public GfoInvkAble InvkAble() {return invkAble;} GfoInvkAble invkAble; + public static GfoEvItm new_(GfoInvkAble invkAble, String key) { + GfoEvItm rv = new GfoEvItm(); + rv.invkAble = invkAble; rv.key = key; + return rv; + } +} diff --git a/100_core/src_311_gfoObj/gplx/GfoEvMgrOwner.java b/100_core/src_311_gfoObj/gplx/GfoEvMgrOwner.java new file mode 100644 index 000000000..d2cb940a2 --- /dev/null +++ b/100_core/src_311_gfoObj/gplx/GfoEvMgrOwner.java @@ -0,0 +1,21 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public interface GfoEvMgrOwner { + GfoEvMgr EvMgr(); +} diff --git a/100_core/src_311_gfoObj/gplx/GfoEvMgr_.java b/100_core/src_311_gfoObj/gplx/GfoEvMgr_.java new file mode 100644 index 000000000..512584222 --- /dev/null +++ b/100_core/src_311_gfoObj/gplx/GfoEvMgr_.java @@ -0,0 +1,45 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class GfoEvMgr_ { + public static void Sub(GfoEvMgrOwner pub, String pubEvt, GfoEvObj sub, String subEvt) {pub.EvMgr().AddSub(pub, pubEvt, sub, subEvt);} + public static void SubSame(GfoEvMgrOwner pub, String evt, GfoEvObj sub) {pub.EvMgr().AddSub(pub, evt, sub, evt);} + public static void SubSame_many(GfoEvMgrOwner pub, GfoEvObj sub, String... evts) { + int len = evts.length; + for (int i = 0; i < len; i++) { + String evt = evts[i]; + pub.EvMgr().AddSub(pub, evt, sub, evt); + } + } + public static void Pub(GfoEvMgrOwner pub, String pubEvt) {pub.EvMgr().Pub(GfsCtx.new_(), pubEvt, GfoMsg_.new_cast_(pubEvt));} + public static void PubObj(GfoEvMgrOwner pub, String pubEvt, String key, Object v) {pub.EvMgr().Pub(GfsCtx.new_(), pubEvt, msg_(pubEvt, KeyVal_.new_(key, v)));} + public static void PubVal(GfoEvMgrOwner pub, String pubEvt, Object v) {pub.EvMgr().Pub(GfsCtx.new_(), pubEvt, msg_(pubEvt, KeyVal_.new_("v", v)));} + public static void PubVals(GfoEvMgrOwner pub, String pubEvt, KeyVal... ary) {pub.EvMgr().Pub(GfsCtx.new_(), pubEvt, msg_(pubEvt, ary));} + public static void PubMsg(GfoEvMgrOwner pub, GfsCtx ctx, String pubEvt, GfoMsg m) {pub.EvMgr().Pub(ctx, pubEvt, m);} + public static void Lnk(GfoEvMgrOwner pub, GfoEvMgrOwner sub) {sub.EvMgr().Lnk(pub);} + public static void RlsPub(GfoEvMgrOwner pub) {pub.EvMgr().RlsPub(pub);} + public static void RlsSub(GfoEvMgrOwner sub) {sub.EvMgr().RlsSub(sub);} + static GfoMsg msg_(String evt, KeyVal... kvAry) { + GfoMsg m = GfoMsg_.new_cast_(evt); + for (int i = 0; i < kvAry.length; i++) { + KeyVal kv = kvAry[i]; + m.Add(kv.Key(), kv.Val()); + } + return m; + } +} diff --git a/100_core/src_311_gfoObj/gplx/GfoEvMgr_tst.java b/100_core/src_311_gfoObj/gplx/GfoEvMgr_tst.java new file mode 100644 index 000000000..daa168245 --- /dev/null +++ b/100_core/src_311_gfoObj/gplx/GfoEvMgr_tst.java @@ -0,0 +1,69 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class GfoEvMgr_tst { + @Before public void setup() { + pub = make_(); sub = make_(); + } MockEvObj pub, sub; + @Test public void Basic() { + GfoEvMgr_.SubSame(pub, "ev1", sub); + GfoEvMgr_.PubVal(pub, "ev1", "val1"); + sub.tst_Handled("val1"); + } + @Test public void None() {// make sure no subscribers does not cause exception + GfoEvMgr_.SubSame(pub, "ev1", sub); + GfoEvMgr_.PubVal(pub, "ev2", "val1"); //ev2 does not exist + sub.tst_Handled(); + } + @Test public void Lnk() { + MockEvObj mid = make_(); + mid.EvMgr().Lnk(pub); + GfoEvMgr_.SubSame(mid, "ev1", sub); + GfoEvMgr_.PubVal(pub, "ev1", "val1"); + sub.tst_Handled("val1"); + } + @Test public void RlsSub() { + this.Basic(); + + GfoEvMgr_.RlsSub(sub); + GfoEvMgr_.PubVal(pub, "ev1", "val1"); + sub.tst_Handled(); + } + @Test public void RlsPub() { + this.Basic(); + + GfoEvMgr_.RlsSub(pub); + GfoEvMgr_.PubVal(pub, "ev1", "val1"); + sub.tst_Handled(); + } + MockEvObj make_() {return new MockEvObj();} +} +class MockEvObj implements GfoEvObj { + public GfoEvMgr EvMgr() {return eventMgr;} GfoEvMgr eventMgr; + public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) { + handled.Add(m.ReadStr("v")); + return this; + } + List_adp handled = List_adp_.new_(); + public void tst_Handled(String... expd) { + Tfds.Eq_ary_str(expd, handled.To_str_ary()); + handled.Clear(); + } + public MockEvObj(){eventMgr = GfoEvMgr.new_(this);} +} diff --git a/100_core/src_311_gfoObj/gplx/GfoEvObj.java b/100_core/src_311_gfoObj/gplx/GfoEvObj.java new file mode 100644 index 000000000..2efe9ba3d --- /dev/null +++ b/100_core/src_311_gfoObj/gplx/GfoEvObj.java @@ -0,0 +1,19 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public interface GfoEvObj extends GfoInvkAble, GfoEvMgrOwner {} diff --git a/100_core/src_311_gfoObj/gplx/GfoInvkAble.java b/100_core/src_311_gfoObj/gplx/GfoInvkAble.java new file mode 100644 index 000000000..5b734be57 --- /dev/null +++ b/100_core/src_311_gfoObj/gplx/GfoInvkAble.java @@ -0,0 +1,28 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public interface GfoInvkAble { + Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m); +} +/* + public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) { + if (ctx.Match(k, Invk_set)) {} + else return GfoInvkAble_.Rv_unhandled; + return this; + } private static final String Invk_set = "set"; +*/ diff --git a/100_core/src_311_gfoObj/gplx/GfoInvkAbleCmd.java b/100_core/src_311_gfoObj/gplx/GfoInvkAbleCmd.java new file mode 100644 index 000000000..939da6597 --- /dev/null +++ b/100_core/src_311_gfoObj/gplx/GfoInvkAbleCmd.java @@ -0,0 +1,35 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class GfoInvkAbleCmd { + private GfoMsg m; + public GfoInvkAble InvkAble() {return invkAble;} private GfoInvkAble invkAble; + public String Cmd() {return cmd;} private String cmd; + public Object Arg() {return arg;} private Object arg; + public Object Invk() { + return invkAble.Invk(GfsCtx._, 0, cmd, m); + } + public static final GfoInvkAbleCmd Null = new GfoInvkAbleCmd(); + public static GfoInvkAbleCmd new_(GfoInvkAble invkAble, String cmd) {return arg_(invkAble, cmd, null);} + public static GfoInvkAbleCmd arg_(GfoInvkAble invkAble, String cmd, Object arg) { + GfoInvkAbleCmd rv = new GfoInvkAbleCmd(); + rv.invkAble = invkAble; rv.cmd = cmd; rv.arg = arg; + rv.m = (arg == null) ? GfoMsg_.Null : GfoMsg_.new_parse_(cmd).Add("v", arg); + return rv; + } GfoInvkAbleCmd() {} +} diff --git a/100_core/src_311_gfoObj/gplx/GfoInvkAble_.java b/100_core/src_311_gfoObj/gplx/GfoInvkAble_.java new file mode 100644 index 000000000..0f1196832 --- /dev/null +++ b/100_core/src_311_gfoObj/gplx/GfoInvkAble_.java @@ -0,0 +1,37 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.core.primitives.*; +public class GfoInvkAble_ { + public static GfoInvkAble as_(Object obj) {return obj instanceof GfoInvkAble ? (GfoInvkAble)obj : null;} + public static GfoInvkAble cast_(Object obj) {try {return (GfoInvkAble)obj;} catch(Exception exc) {throw Exc_.new_type_mismatch_w_exc(exc, GfoInvkAble.class, obj);}} + public static final String_obj_val Rv_unhandled = String_obj_val.new_("Unhandled"), Rv_handled = String_obj_val.new_("Handled"), Rv_host = String_obj_val.new_("Host") + , Rv_cancel = String_obj_val.new_("Cancel"), Rv_error = String_obj_val.new_("Error"); + + public static Object InvkCmd(GfoInvkAble invk, String k) {return InvkCmd_msg(invk, k, GfoMsg_.Null);} + public static Object InvkCmd_val(GfoInvkAble invk, String k, Object v) {return InvkCmd_msg(invk, k, GfoMsg_.new_cast_(k).Add("v", v));} + public static Object InvkCmd_msg(GfoInvkAble invk, String k, GfoMsg m) { + Object rv = invk.Invk(GfsCtx._, 0, k, m); + if (rv == GfoInvkAble_.Rv_unhandled) throw Exc_.new_("invkable did not handle message", "key", k); + return rv; + } + public static final GfoInvkAble Null = new GfoInvkAble_null(); +} +class GfoInvkAble_null implements GfoInvkAble { + public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {return this;} +} diff --git a/100_core/src_311_gfoObj/gplx/GfoInvkCmdMgr.java b/100_core/src_311_gfoObj/gplx/GfoInvkCmdMgr.java new file mode 100644 index 000000000..5484ea467 --- /dev/null +++ b/100_core/src_311_gfoObj/gplx/GfoInvkCmdMgr.java @@ -0,0 +1,68 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.core.primitives.*; +public class GfoInvkCmdMgr { + public GfoInvkCmdMgr Add_cmd_many(GfoInvkAble invk, String... keys) { + for (String key : keys) + list.Add(GfoInvkCmdItm.new_(key, invk)); + return this; + } + public GfoInvkCmdMgr Add_cmd(String key, GfoInvkAble invk) { + list.Add(GfoInvkCmdItm.new_(key, invk)); + return this; + } + public GfoInvkCmdMgr Add_mgr(String key, GfoInvkAble invk) { + list.Add(GfoInvkCmdItm.new_(key, invk).Type_isMgr_(true)); + return this; + } + public GfoInvkCmdMgr Add_xtn(GfoInvkAble xtn) { + list.Add(GfoInvkCmdItm.new_("xtn", xtn).Type_isXtn_(true)); + return this; + } + public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m, Object host) { + for (int i = 0; i < list.Count(); i++) { + GfoInvkCmdItm itm = (GfoInvkCmdItm)list.Get_at(i); + if (itm.Type_isXtn()) { + Object invkVal = itm.Invk().Invk(ctx, ikey, k, m); + if (invkVal != GfoInvkAble_.Rv_unhandled) return invkVal; + } + if (!ctx.Match(k, itm.Key())) continue; + if (itm.Type_isMgr()) return itm.Invk(); + Object rv = null; + m.Add("host", host); + rv = itm.Invk().Invk(ctx, ikey, k, m); + return rv == GfoInvkAble_.Rv_host ? host : rv; // if returning "this" return host + } + return Unhandled; + } + public static final String_obj_val Unhandled = String_obj_val.new_("GfoInvkCmdMgr Unhandled"); + List_adp list = List_adp_.new_(); + public static GfoInvkCmdMgr new_() {return new GfoInvkCmdMgr();} GfoInvkCmdMgr() {} +} +class GfoInvkCmdItm { + public String Key() {return key;} private String key; + public GfoInvkAble Invk() {return invk;} GfoInvkAble invk; + public boolean Type_isMgr() {return type_isMgr;} public GfoInvkCmdItm Type_isMgr_(boolean v) {type_isMgr = v; return this;} private boolean type_isMgr; + public boolean Type_isXtn() {return type_isXtn;} public GfoInvkCmdItm Type_isXtn_(boolean v) {type_isXtn = v; return this;} private boolean type_isXtn; + public static GfoInvkCmdItm new_(String key, GfoInvkAble invk) { + GfoInvkCmdItm rv = new GfoInvkCmdItm(); + rv.key = key; rv.invk = invk; + return rv; + } GfoInvkCmdItm() {} +} diff --git a/100_core/src_311_gfoObj/gplx/GfoInvkCmdMgrOwner.java b/100_core/src_311_gfoObj/gplx/GfoInvkCmdMgrOwner.java new file mode 100644 index 000000000..37cbb9acc --- /dev/null +++ b/100_core/src_311_gfoObj/gplx/GfoInvkCmdMgrOwner.java @@ -0,0 +1,21 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public interface GfoInvkCmdMgrOwner { + GfoInvkCmdMgr InvkMgr(); +} diff --git a/100_core/src_311_gfoObj/gplx/GfoInvkRootWkr.java b/100_core/src_311_gfoObj/gplx/GfoInvkRootWkr.java new file mode 100644 index 000000000..2c2189ce1 --- /dev/null +++ b/100_core/src_311_gfoObj/gplx/GfoInvkRootWkr.java @@ -0,0 +1,21 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public interface GfoInvkRootWkr { + Object Run_str_for(GfoInvkAble invk, GfoMsg msg); +} diff --git a/100_core/src_311_gfoObj/gplx/GfoInvkXtoStr.java b/100_core/src_311_gfoObj/gplx/GfoInvkXtoStr.java new file mode 100644 index 000000000..e1985edf5 --- /dev/null +++ b/100_core/src_311_gfoObj/gplx/GfoInvkXtoStr.java @@ -0,0 +1,43 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class GfoInvkXtoStr { + public static GfoMsg ReadMsg(GfoInvkAble invk, String k) { + GfsCtx ctx = GfsCtx.wtr_(); + GfoMsg m = GfoMsg_.rdr_(k); + invk.Invk(ctx, 0, k, m); + String invkKey = GfsCore._.FetchKey(invk); + GfoMsg root = GfoMsg_.new_cast_(invkKey); + root.Subs_add(m); + return root; + } + public static GfoMsg WriteMsg(GfoInvkAble invk, String k, Object... ary) {return WriteMsg(GfsCore._.FetchKey(invk), invk, k, ary);} + public static GfoMsg WriteMsg(String invkKey, GfoInvkAble invk, String k, Object... ary) { + GfsCtx ctx = GfsCtx.wtr_(); + GfoMsg m = GfoMsg_.wtr_(); + invk.Invk(ctx, 0, k, m); + GfoMsg rv = GfoMsg_.new_cast_(k); + for (int i = 0; i < m.Args_count(); i++) { + KeyVal kv = m.Args_getAt(i); + rv.Add(kv.Key(), ary[i]); + } + GfoMsg root = GfoMsg_.new_cast_(invkKey); + root.Subs_add(rv); + return root; + } +} diff --git a/100_core/src_311_gfoObj/gplx/GfoMsg.java b/100_core/src_311_gfoObj/gplx/GfoMsg.java new file mode 100644 index 000000000..540e781b8 --- /dev/null +++ b/100_core/src_311_gfoObj/gplx/GfoMsg.java @@ -0,0 +1,71 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public interface GfoMsg { + String Key(); + GfoMsg CloneNew(); + String XtoStr(); + GfoMsg Clear(); + GfoMsg Parse_(boolean v); + + int Args_count(); + KeyVal Args_getAt(int i); + GfoMsg Args_ovr(String k, Object v); + void Args_reset(); + GfoMsg Add(String k, Object v); + int Subs_count(); + GfoMsg Subs_getAt(int i); + GfoMsg Subs_add(GfoMsg m); + GfoMsg Subs_(GfoMsg... ary); + + boolean ReadBool(String k); + boolean ReadBoolOr(String k, boolean or); + boolean ReadBoolOrFalse(String k); + boolean ReadBoolOrTrue(String k); + int ReadInt(String k); + int ReadIntOr(String k, int or); + long ReadLong(String k); + long ReadLongOr(String k, long or); + float ReadFloat(String k); + float ReadFloatOr(String k, float or); + double ReadDouble(String k); + double ReadDoubleOr(String k, double or); + DateAdp ReadDate(String k); + DateAdp ReadDateOr(String k, DateAdp or); + DecimalAdp ReadDecimal(String k); + DecimalAdp ReadDecimalOr(String k, DecimalAdp or); + String ReadStr(String k); + String ReadStrOr(String k, String or); + Io_url ReadIoUrl(String k); + Io_url ReadIoUrlOr(String k, Io_url url); + boolean ReadYn(String k); + boolean ReadYn_toggle(String k, boolean cur); + boolean ReadYnOrY(String k); + byte ReadByte(String k); + byte[] ReadBry(String k); + byte[] ReadBryOr(String k, byte[] or); + Object ReadObj(String k); + Object ReadObj(String k, ParseAble parseAble); + Object ReadObjOr(String k, ParseAble parseAble, Object or); + String[]ReadStrAry(String k, String spr); + String[]ReadStrAryIgnore(String k, String spr, String ignore); + byte[][]ReadBryAry(String k, byte spr); + Object ReadValAt(int i); + Object CastObj(String k); + Object CastObjOr(String k, Object or); +} diff --git a/100_core/src_311_gfoObj/gplx/GfoMsgUtl.java b/100_core/src_311_gfoObj/gplx/GfoMsgUtl.java new file mode 100644 index 000000000..0e5e65dec --- /dev/null +++ b/100_core/src_311_gfoObj/gplx/GfoMsgUtl.java @@ -0,0 +1,25 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class GfoMsgUtl { + public static int SetInt(GfsCtx ctx, GfoMsg m, int cur) {return ctx.Deny() ? cur : m.ReadIntOr("v", cur);} + public static boolean SetBool(GfsCtx ctx, GfoMsg m, boolean cur) {return ctx.Deny() ? cur : m.ReadBoolOr("v", cur);} + public static String SetStr(GfsCtx ctx, GfoMsg m, String cur) {return ctx.Deny() ? cur : m.ReadStrOr("v", cur);} + public static Io_url SetIoUrl(GfsCtx ctx, GfoMsg m, Io_url cur) {return ctx.Deny() ? cur : m.ReadIoUrlOr("v", cur);} + public static DecimalAdp SetDecimal(GfsCtx ctx, GfoMsg m, DecimalAdp cur) {return ctx.Deny() ? cur : m.ReadDecimalOr("v", cur);} +} diff --git a/100_core/src_311_gfoObj/gplx/GfoMsg_.java b/100_core/src_311_gfoObj/gplx/GfoMsg_.java new file mode 100644 index 000000000..974c22525 --- /dev/null +++ b/100_core/src_311_gfoObj/gplx/GfoMsg_.java @@ -0,0 +1,270 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.core.primitives.*; import gplx.core.strings.*; +public class GfoMsg_ { + public static GfoMsg as_(Object obj) {return obj instanceof GfoMsg ? (GfoMsg)obj : null;} + public static final GfoMsg Null = new GfoMsg_base().ctor_("<>", false); + public static GfoMsg new_parse_(String key) {return new GfoMsg_base().ctor_(key, true);} + public static GfoMsg new_cast_(String key) {return new GfoMsg_base().ctor_(key, false);} + public static GfoMsg srl_(GfoMsg owner, String key) { + GfoMsg rv = new_parse_(key); + owner.Subs_add(rv); + return rv; + } + public static GfoMsg root_(String... ary) {return root_leafArgs_(ary);} + public static GfoMsg root_leafArgs_(String[] ary, KeyVal... kvAry) { + int len = Array_.Len(ary); if (len == 0) throw Err_arg.cannotBe_("== 0", "@len", len); + GfoMsg root = new GfoMsg_base().ctor_(ary[0], false); + GfoMsg owner = root; + for (int i = 1; i < len; i++) { + String key = ary[i]; + GfoMsg cur = new GfoMsg_base().ctor_(key, false); + owner.Subs_add(cur); + owner = cur; + } + for (int i = 0; i < kvAry.length; i++) { + KeyVal kv = kvAry[i]; + owner.Add(kv.Key(), kv.Val()); + } + return root; + } + public static GfoMsg chain_(GfoMsg owner, String key) { + GfoMsg sub = owner; + List_adp list = List_adp_.new_(); + list.Add(sub.Key()); + while (sub != null) { + if (sub.Subs_count() == 0) break; + sub = (GfoMsg)sub.Subs_getAt(0); + list.Add(sub.Key()); + } + list.Add(key); + + GfoMsg root = GfoMsg_.new_parse_((String)list.Get_at(0)); + GfoMsg cur = root; + for (int i = 1; i < list.Count(); i++) { + String k = (String)list.Get_at(i); + GfoMsg mm = GfoMsg_.new_parse_(k); + cur.Subs_add(mm); + cur = mm; + } + return root; + } + public static GfoMsg wtr_() {return new GfoMsg_wtr().ctor_("", false);} + public static GfoMsg rdr_(String cmd) {return new GfoMsg_rdr().ctor_(cmd, false);} + public static GfoMsg basic_(String cmd, Object... vals) { + GfoMsg rv = new_cast_(cmd); + int len = vals.length; + for (int i = 0; i < len; i++) + rv.Add("", vals[i]); + return rv; + } +} +class GfoMsg_wtr extends GfoMsg_base { + @Override protected Object ReadOr(String k, Object defaultOr) { + if (args == null) args = List_adp_.new_(); + args.Add(KeyVal_.new_(k, null)); + return defaultOr; + } +} +class GfoMsg_rdr extends GfoMsg_base { + @Override protected Object ReadOr(String k, Object defaultOr) { + if (args == null) args = List_adp_.new_(); + args.Add(KeyVal_.new_(k, defaultOr)); + return defaultOr; + } +} +class GfoMsg_base implements GfoMsg { + public String Key() {return key;} private String key; + public int Subs_count() {return subs == null ? 0 : subs.Count();} + public GfoMsg Subs_getAt(int i) {return subs == null ? null : (GfoMsg)subs.Get_at(i);} + public GfoMsg Subs_add(GfoMsg m) {if (subs == null) subs = List_adp_.new_(); subs.Add(m); return this;} + public GfoMsg Subs_(GfoMsg... ary) {for (GfoMsg m : ary) Subs_add(m); return this;} + public int Args_count() {return args == null ? 0 : args.Count();} + public void Args_reset() { + counter = 0; + Args_reset(this); + } + public GfoMsg Clear() { + this.Args_reset(); + if (subs != null) subs.Clear(); + if (args != null) args.Clear(); + return this; + } + static void Args_reset(GfoMsg owner) { + int len = owner.Subs_count(); + for (int i = 0; i < len; i++) { + GfoMsg sub = owner.Subs_getAt(i); + sub.Args_reset(); + } + } + public KeyVal Args_getAt(int i) {return args == null ? null : (KeyVal)args.Get_at(i);} + public GfoMsg Args_ovr(String k, Object v) { + if (args == null) args = List_adp_.new_(); + for (int i = 0; i < args.Count(); i++) { + KeyVal kv = (KeyVal)args.Get_at(i); + if (String_.Eq(k, kv.Key())) { + kv.Val_(v); + return this; + } + } + args.Add(new KeyVal(KeyVal_.Key_tid_str, k, v)); + return this; + } + public GfoMsg Parse_(boolean v) {parse = v; return this;} + public GfoMsg Add(String k, Object v) { + if (args == null) args = List_adp_.new_(); + args.Add(new KeyVal(KeyVal_.Key_tid_str, k, v)); + return this; + } + public boolean ReadBool(String k) {Object rv = ReadOr(k,false); if (rv == Nil) ThrowNotFound(k); return parse ? Yn.parse_or_((String)rv, false) : Bool_.cast_(rv);} + public int ReadInt(String k) {Object rv = ReadOr(k, 0) ; if (rv == Nil) ThrowNotFound(k); return parse ? Int_.parse_((String)rv) : Int_.cast_(rv);} + public byte ReadByte(String k) {Object rv = ReadOr(k, 0) ; if (rv == Nil) ThrowNotFound(k); return parse ? Byte_.parse_((String)rv) : Byte_.cast_(rv);} + public long ReadLong(String k) {Object rv = ReadOr(k, 0) ; if (rv == Nil) ThrowNotFound(k); return parse ? Long_.parse_((String)rv) : Long_.cast_(rv);} + public float ReadFloat(String k) {Object rv = ReadOr(k, 0) ; if (rv == Nil) ThrowNotFound(k); return parse ? Float_.parse_((String)rv) : Float_.cast_(rv);} + public double ReadDouble(String k) {Object rv = ReadOr(k, 0) ; if (rv == Nil) ThrowNotFound(k); return parse ? Double_.parse_((String)rv) : Double_.cast_(rv);} + public DecimalAdp ReadDecimal(String k) {Object rv = ReadOr(k, 0) ; if (rv == Nil) ThrowNotFound(k); return parse ? DecimalAdp_.parse_((String)rv) : DecimalAdp_.cast_(rv);} + public String ReadStr(String k) {Object rv = ReadOr(k, null); if (rv == Nil) ThrowNotFound(k); return (String)rv;} + public DateAdp ReadDate(String k) {Object rv = ReadOr(k, null); if (rv == Nil) ThrowNotFound(k); return parse ? DateAdp_.parse_gplx((String)rv) : DateAdp_.cast_(rv);} + public Io_url ReadIoUrl(String k) {Object rv = ReadOr(k, null); if (rv == Nil) ThrowNotFound(k); return parse ? Io_url_.new_any_((String)rv) : Io_url_.cast_(rv);} + public Object CastObj(String k) {Object rv = ReadOr(k, null); if (rv == Nil) ThrowNotFound(k); return rv;} + public boolean ReadBoolOr(String k, boolean or) {Object rv = ReadOr(k, or) ; if (rv == Nil) return or ; return parse ? Yn.parse_or_((String)rv, or) : Bool_.cast_(rv);} + public int ReadIntOr(String k, int or) {Object rv = ReadOr(k, or) ; if (rv == Nil) return or ; return parse ? Int_.parse_((String)rv) : Int_.cast_(rv);} + public long ReadLongOr(String k, long or) {Object rv = ReadOr(k, or) ; if (rv == Nil) return or ; return parse ? Long_.parse_((String)rv) : Long_.cast_(rv);} + public float ReadFloatOr(String k, float or) {Object rv = ReadOr(k, or) ; if (rv == Nil) return or ; return parse ? Float_.parse_((String)rv) : Float_.cast_(rv);} + public double ReadDoubleOr(String k,double or) {Object rv = ReadOr(k, or) ; if (rv == Nil) return or ; return parse ? Double_.parse_((String)rv) : Double_.cast_(rv);} + public DecimalAdp ReadDecimalOr(String k,DecimalAdp or) {Object rv = ReadOr(k, or); if (rv == Nil) return or ; return parse ? DecimalAdp_.parse_((String)rv) : DecimalAdp_.cast_(rv);} + public String ReadStrOr(String k, String or) {Object rv = ReadOr(k, or) ; if (rv == Nil) return or ; return (String)rv;} + public DateAdp ReadDateOr(String k, DateAdp or) {Object rv = ReadOr(k, or) ; if (rv == Nil) return or ; return parse ? DateAdp_.parse_gplx((String)rv) : DateAdp_.cast_(rv);} + public Io_url ReadIoUrlOr(String k, Io_url or) {Object rv = ReadOr(k, or) ; if (rv == Nil) return or ; return parse ? Io_url_.new_any_((String)rv) : Io_url_.cast_(rv);} + public boolean ReadBoolOrFalse(String k) {Object rv = ReadOr(k,false); if (rv == Nil) return false ; return parse ? Yn.parse_or_((String)rv, false) : Bool_.cast_(rv);} + public boolean ReadBoolOrTrue(String k) {Object rv = ReadOr(k, true); if (rv == Nil) return true ; return parse ? Yn.parse_or_((String)rv, true) : Bool_.cast_(rv);} + public boolean ReadYnOrY(String k) {Object rv = ReadOr(k, true); if (rv == Nil) return true ; return parse ? Yn.parse_or_((String)rv, true) : Bool_.cast_(rv);} + public boolean ReadYn(String k) {Object rv = ReadOr(k,false); if (rv == Nil) ThrowNotFound(k); return parse ? Yn.parse_or_((String)rv, false) : Yn.coerce_(rv);} + public boolean ReadYn_toggle(String k, boolean cur) { + Object rv = ReadOr(k, "!"); + if (rv == Nil) ThrowNotFound(k); + if (!parse) throw Exc_.new_("only parse supported"); + String rv_str = (String)rv; + return (String_.Eq(rv_str, "!")) ? !cur : Yn.parse_(rv_str); + } + public byte[] ReadBry(String k) {Object rv = ReadOr(k,false); if (rv == Nil) ThrowNotFound(k); return parse ? Bry_.new_u8((String)rv) : (byte[])rv;} + public byte[] ReadBryOr(String k, byte[] or) {Object rv = ReadOr(k, or); if (rv == Nil) return or; return parse ? Bry_.new_u8((String)rv) : (byte[])rv;} + public Object CastObjOr(String k, Object or) {Object rv = ReadOr(k, or) ; if (rv == Nil) return or ; return rv;} + public Object ReadObj(String k) {Object rv = ReadOr(k, null); if (rv == Nil) ThrowNotFound(k); return rv;} + public Object ReadObj(String k, ParseAble parseAble) {Object rv = ReadOr(k, null); if (rv == Nil) ThrowNotFound(k); return parse ? parseAble.ParseAsObj((String)rv) : rv;} + public Object ReadObjOr(String k, ParseAble parseAble, Object or) {Object rv = ReadOr(k, or) ; if (rv == Nil) return or ; return parse ? parseAble.ParseAsObj((String)rv) : rv;} + public String[] ReadStrAry(String k, String spr) {return String_.Split(ReadStr(k), spr);} + public byte[][] ReadBryAry(String k, byte spr) {return Bry_.Split(ReadBry(k), spr);} + public String[] ReadStrAryIgnore(String k, String spr, String ignore) {return String_.Split(String_.Replace(ReadStr(k), ignore, ""), spr);} + public Object ReadValAt(int i) {return Args_getAt(i).Val();} + @gplx.Virtual protected Object ReadOr(String k, Object defaultOr) { + if (args == null) return Nil; // WORKAROUND.gfui: args null for DataBndr_whenEvt_execCmd + if (!String_.Eq(k, "")) { + for (int i = 0; i < args.Count(); i++) { + KeyVal kv = (KeyVal)args.Get_at(i); + if (String_.Eq(k, kv.Key())) return kv.Val(); + } + } + if (counter >= args.Count()) return Nil; + for (int i = 0; i < args.Count(); i++) { + KeyVal kv = (KeyVal)args.Get_at(i); + if (String_.Eq(kv.Key(), "") && i >= counter) { + counter++; + return kv.Val(); + } + } + return Nil; + } int counter = 0; + void ThrowNotFound(String k) {throw Exc_.new_("arg not found in msg", "k", k, "counter", counter, "args", args);} + String ArgsXtoStr() { + if (this.Args_count() == 0) return "<>"; + String_bldr sb = String_bldr_.new_(); + for (int i = 0; i < this.Args_count(); i++) { + KeyVal rv = (KeyVal)this.Args_getAt(i); + sb.Add_fmt("{0};", rv.Key()); + } + return sb.XtoStr(); + } + public GfoMsg CloneNew() { + GfoMsg_base rv = new GfoMsg_base().ctor_(key, parse); + if (args != null) { + rv.args = List_adp_.new_(); + for (int i = 0; i < args.Count(); i++) + rv.args.Add(args.Get_at(i)); + } + if (subs != null) { + rv.subs = List_adp_.new_(); + for (int i = 0; i < args.Count(); i++) { + GfoMsg sub = (GfoMsg)args.Get_at(i); + rv.subs.Add(sub.CloneNew()); // NOTE: recursion + } + } + return rv; + } + + protected List_adp args; + List_adp subs; + public String XtoStr() { + String_bldr sb = String_bldr_.new_(); + XtoStr(sb, new XtoStrWkr_gplx(), this); + return sb.Xto_str_and_clear(); + } + void XtoStr(String_bldr sb, XtoStrWkr wkr, GfoMsg m) { + sb.Add(m.Key()); + if (m.Subs_count() == 0) { + sb.Add(":"); + boolean first = true; + for (int i = 0; i < m.Args_count(); i++) { + KeyVal kv = m.Args_getAt(i); + if (kv.Val() == null) continue; + if (!first) sb.Add(" "); + sb.Add(kv.Key()); + sb.Add("='"); + sb.Add(wkr.XtoStr(kv.Val())); + sb.Add("'"); + first = false; + } + sb.Add(";"); + } + else { + sb.Add("."); + XtoStr(sb, wkr, m.Subs_getAt(0)); + } + } + + public GfoMsg_base ctor_(String key, boolean parse) {this.key = key; this.parse = parse; return this;} private boolean parse; + @gplx.Internal protected GfoMsg_base(){} + static final String_obj_val Nil = String_obj_val.new_("<>"); +} +interface XtoStrWkr { + String XtoStr(Object o); +} +class XtoStrWkr_gplx implements XtoStrWkr { + public String XtoStr(Object o) { + if (o == null) return "<>"; + Class type = ClassAdp_.ClassOf_obj(o); + String rv = null; + if (type == String.class) rv = String_.cast_(o); + else if (Int_.TypeMatch(type)) return Int_.Xto_str(Int_.cast_(o)); + else if (ClassAdp_.Eq(type, Bool_.Cls_ref_type)) return Yn.Xto_str(Bool_.cast_(o)); + else if (type == DateAdp.class) return DateAdp_.cast_(o).XtoStr_gplx(); + else rv = Object_.Xto_str_strict_or_empty(o); + return String_.Replace(rv, "'", "''"); + } +} diff --git a/100_core/src_311_gfoObj/gplx/GfoMsg_tst.java b/100_core/src_311_gfoObj/gplx/GfoMsg_tst.java new file mode 100644 index 000000000..25ea8af03 --- /dev/null +++ b/100_core/src_311_gfoObj/gplx/GfoMsg_tst.java @@ -0,0 +1,51 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class GfoMsg_tst { + @Before public void setup() { + GfsCore._.AddObj(new Mok(), "Mok"); + } + @Test public void Write1() { + GfoMsg m = GfoMsg_.root_leafArgs_(String_.Ary("a", "b"), KeyVal_.new_("int0", 1)); + tst_Msg(m, "a.b:int0='1';"); + } + @Test public void Write() { + Mok mok = new Mok(); + tst_Msg(GfoInvkXtoStr.WriteMsg(mok, Mok.Invk_Cmd0, true, 1, "a"), "Mok.Cmd0:bool0='y' int0='1' str0='a';"); + mok.Int0 = 2; + mok.Bool0 = true; + mok.Str0 = "b"; + tst_Msg(GfoInvkXtoStr.ReadMsg(mok, Mok.Invk_Cmd0), "Mok.Cmd0:bool0='y' int0='2' str0='b';"); + } + void tst_Msg(GfoMsg m, String expd) {Tfds.Eq(expd, m.XtoStr());} + class Mok implements GfoInvkAble { + public boolean Bool0; + public int Int0; + public String Str0; + public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) { + if (ctx.Match(k, Invk_Cmd0)) { + Bool0 = m.ReadBoolOr("bool0", Bool0); + Int0 = m.ReadIntOr("int0", Int0); + Str0 = m.ReadStrOr("str0", Str0); + if (ctx.Deny()) return this; + } + return this; + } public static final String Invk_Cmd0 = "Cmd0"; + } +} diff --git a/100_core/src_311_gfoObj/gplx/GfoTemplate.java b/100_core/src_311_gfoObj/gplx/GfoTemplate.java new file mode 100644 index 000000000..fb301e880 --- /dev/null +++ b/100_core/src_311_gfoObj/gplx/GfoTemplate.java @@ -0,0 +1,21 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public interface GfoTemplate { + Object NewCopy(GfoTemplate template); +} diff --git a/100_core/src_311_gfoObj/gplx/GfoTemplateFactory.java b/100_core/src_311_gfoObj/gplx/GfoTemplateFactory.java new file mode 100644 index 000000000..d484a20c6 --- /dev/null +++ b/100_core/src_311_gfoObj/gplx/GfoTemplateFactory.java @@ -0,0 +1,32 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class GfoTemplateFactory implements GfoInvkAble { + public void Reg(String key, GfoTemplate template) {hash.Add(key, template);} + public Object Make(String key) { + GfoTemplate template = (GfoTemplate)hash.Get_by(key); + return template.NewCopy(template); + } + public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) { + ctx.Match(k, k); + Object o = hash.Get_by(k); + return o == null ? GfoInvkAble_.Rv_unhandled : o; + } + public static final GfoTemplateFactory _ = new GfoTemplateFactory(); GfoTemplateFactory() {} + Hash_adp hash = Hash_adp_.new_(); +} diff --git a/100_core/src_330_store/gplx/DataRdr.java b/100_core/src_330_store/gplx/DataRdr.java new file mode 100644 index 000000000..f75377171 --- /dev/null +++ b/100_core/src_330_store/gplx/DataRdr.java @@ -0,0 +1,51 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.core.strings.*; +public interface DataRdr extends SrlMgr, RlsAble { + String NameOfNode(); String XtoStr(); + Io_url Uri(); void Uri_set(Io_url s); + Hash_adp EnvVars(); + boolean Parse(); void Parse_set(boolean v); + + int FieldCount(); + String KeyAt(int i); + Object ReadAt(int i); + KeyVal KeyValAt(int i); + + Object Read(String key); + String ReadStr(String key); String ReadStrOr(String key, String or); + byte[] ReadBryByStr(String key); byte[] ReadBryByStrOr(String key, byte[] or); + byte[] ReadBry(String key); byte[] ReadBryOr(String key, byte[] or); + char ReadChar(String key); char ReadCharOr(String key, char or); + int ReadInt(String key); int ReadIntOr(String key, int or); + boolean ReadBool(String key); boolean ReadBoolOr(String key, boolean or); + long ReadLong(String key); long ReadLongOr(String key, long or); + double ReadDouble(String key); double ReadDoubleOr(String key, double or); + float ReadFloat(String key); float ReadFloatOr(String key, float or); + byte ReadByte(String key); byte ReadByteOr(String key, byte or); + DecimalAdp ReadDecimal(String key); DecimalAdp ReadDecimalOr(String key, DecimalAdp or); + DateAdp ReadDate(String key); DateAdp ReadDateOr(String key, DateAdp or); + gplx.ios.Io_stream_rdr ReadRdr(String key); + + boolean MoveNextPeer(); + DataRdr Subs(); + DataRdr Subs_byName(String name); + DataRdr Subs_byName_moveFirst(String name); + void XtoStr_gfml(String_bldr sb); +} diff --git a/100_core/src_330_store/gplx/DataRdr_.java b/100_core/src_330_store/gplx/DataRdr_.java new file mode 100644 index 000000000..24477bb58 --- /dev/null +++ b/100_core/src_330_store/gplx/DataRdr_.java @@ -0,0 +1,68 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.core.strings.*; +public class DataRdr_ { + public static final DataRdr Null = new DataRdr_null(); + public static DataRdr as_(Object obj) {return obj instanceof DataRdr ? (DataRdr)obj : null;} + public static DataRdr cast_(Object obj) {try {return (DataRdr)obj;} catch(Exception exc) {throw Exc_.new_type_mismatch_w_exc(exc, DataRdr.class, obj);}} +} +class DataRdr_null implements DataRdr { + public String NameOfNode() {return XtoStr();} public String XtoStr() {return "<< NULL READER >>";} + public boolean Type_rdr() {return true;} + public Hash_adp EnvVars() {return Hash_adp_.Noop;} + public Io_url Uri() {return Io_url_.Empty;} public void Uri_set(Io_url s) {} + public boolean Parse() {return parse;} public void Parse_set(boolean v) {parse = v;} private boolean parse; + public int FieldCount() {return 0;} + public String KeyAt(int i) {return XtoStr();} + public Object ReadAt(int i) {return null;} + public KeyVal KeyValAt(int i) {return KeyVal_.new_(this.KeyAt(i), this.ReadAt(i));} + public Object Read(String name) {return null;} + public String ReadStr(String key) {return String_.Empty;} public String ReadStrOr(String key, String or) {return or;} + public byte[] ReadBryByStr(String key) {return Bry_.Empty;} public byte[] ReadBryByStrOr(String key, byte[] or) {return or;} + public byte[] ReadBry(String key) {return Bry_.Empty;} public byte[] ReadBryOr(String key, byte[] or) {return or;} + public char ReadChar(String key) {return Char_.Null;} public char ReadCharOr(String key, char or) {return or;} + public int ReadInt(String key) {return Int_.MinValue;} public int ReadIntOr(String key, int or) {return or;} + public boolean ReadBool(String key) {return false;} public boolean ReadBoolOr(String key, boolean or) {return or;} + public long ReadLong(String key) {return Long_.MinValue;} public long ReadLongOr(String key, long or) {return or;} + public double ReadDouble(String key) {return Double_.NaN;} public double ReadDoubleOr(String key, double or) {return or;} + public float ReadFloat(String key) {return Float_.NaN;} public float ReadFloatOr(String key, float or) {return or;} + public byte ReadByte(String key) {return Byte_.Min_value;} public byte ReadByteOr(String key, byte or) {return or;} + public DecimalAdp ReadDecimal(String key) {return DecimalAdp_.Zero;}public DecimalAdp ReadDecimalOr(String key, DecimalAdp or) {return or;} + public DateAdp ReadDate(String key) {return DateAdp_.MinValue;} public DateAdp ReadDateOr(String key, DateAdp or) {return or;} + public gplx.ios.Io_stream_rdr ReadRdr(String key) {return gplx.ios.Io_stream_rdr_.Noop;} + public boolean MoveNextPeer() {return false;} + public DataRdr Subs() {return this;} + public DataRdr Subs_byName(String name) {return this;} + public DataRdr Subs_byName_moveFirst(String name) {return this;} + public Object StoreRoot(SrlObj root, String key) {return null;} + public boolean SrlBoolOr(String key, boolean v) {return v;} + public byte SrlByteOr(String key, byte v) {return v;} + public int SrlIntOr(String key, int or) {return or;} + public long SrlLongOr(String key, long or) {return or;} + public String SrlStrOr(String key, String or) {return or;} + public DateAdp SrlDateOr(String key, DateAdp or) {return or;} + public DecimalAdp SrlDecimalOr(String key, DecimalAdp or) {return or;} + public double SrlDoubleOr(String key, double or) {return or;} + public Object SrlObjOr(String key, Object or) {return or;} + public void SrlList(String key, List_adp list, SrlObj proto, String itmKey) {} + public void TypeKey_(String v) {} + public void XtoStr_gfml(String_bldr sb) {sb.Add_str_w_crlf("NULL:;");} + public SrlMgr SrlMgr_new(Object o) {return this;} + public void Rls() {} +} diff --git a/100_core/src_330_store/gplx/DataWtr.java b/100_core/src_330_store/gplx/DataWtr.java new file mode 100644 index 000000000..e99108e13 --- /dev/null +++ b/100_core/src_330_store/gplx/DataWtr.java @@ -0,0 +1,32 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public interface DataWtr extends SrlMgr { + Hash_adp EnvVars(); + + void InitWtr(String key, Object val); + void WriteTableBgn(String name, GfoFldList fields); + void WriteNodeBgn(String nodeName); + void WriteLeafBgn(String leafName); + void WriteData(String name, Object val); + void WriteNodeEnd(); + void WriteLeafEnd(); + + void Clear(); + String XtoStr(); +} diff --git a/100_core/src_330_store/gplx/DataWtr_.java b/100_core/src_330_store/gplx/DataWtr_.java new file mode 100644 index 000000000..55ec0d214 --- /dev/null +++ b/100_core/src_330_store/gplx/DataWtr_.java @@ -0,0 +1,48 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.stores.*; /*DsvDataWtr_*/ +public class DataWtr_ { + public static final DataWtr Null = new DataWtr_null(); +} +class DataWtr_null implements DataWtr { + public boolean Type_rdr() {return false;} + public Hash_adp EnvVars() {return envVars;} Hash_adp envVars = Hash_adp_.new_(); + public void InitWtr(String key, Object val) {} + public void WriteTableBgn(String name, GfoFldList fields) {} + public void WriteNodeBgn(String nodeName) {} + public void WriteLeafBgn(String leafName) {} + public void WriteData(String name, Object val) {} + public void WriteNodeEnd() {} + public void WriteLeafEnd() {} + public void Clear() {} + public String XtoStr() {return "";} + public Object StoreRoot(SrlObj root, String key) {return null;} + public boolean SrlBoolOr(String key, boolean v) {return v;} + public byte SrlByteOr(String key, byte v) {return v;} + public int SrlIntOr(String key, int or) {return or;} + public long SrlLongOr(String key, long or) {return or;} + public String SrlStrOr(String key, String or) {return or;} + public DateAdp SrlDateOr(String key, DateAdp or) {return or;} + public DecimalAdp SrlDecimalOr(String key, DecimalAdp or) {return or;} + public double SrlDoubleOr(String key, double or) {return or;} + public Object SrlObjOr(String key, Object or) {return or;} + public void SrlList(String key, List_adp list, SrlObj proto, String itmKey) {} + public void TypeKey_(String v) {} + public SrlMgr SrlMgr_new(Object o) {return this;} +} diff --git a/100_core/src_330_store/gplx/DataWtr_base.java b/100_core/src_330_store/gplx/DataWtr_base.java new file mode 100644 index 000000000..dae47481a --- /dev/null +++ b/100_core/src_330_store/gplx/DataWtr_base.java @@ -0,0 +1,52 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public abstract class DataWtr_base implements SrlMgr { + @gplx.Virtual public Hash_adp EnvVars() {return envVars;} Hash_adp envVars = Hash_adp_.new_(); + public boolean Type_rdr() {return false;} + public abstract void WriteData(String key, Object o); + public abstract void WriteNodeBgn(String nodeName); + public abstract void WriteNodeEnd(); + @gplx.Virtual public void SrlList(String key, List_adp list, SrlObj proto, String itmKey) { + this.WriteNodeBgn(key); + for (Object itmObj : list) { + SrlObj itm = (SrlObj)itmObj; + this.WriteNodeBgn(itmKey); + itm.SrlObj_Srl(this); + this.WriteNodeEnd(); + } + this.WriteNodeEnd(); + } + @gplx.Virtual public Object StoreRoot(SrlObj root, String key) { + this.WriteNodeBgn(key); + root.SrlObj_Srl(this); + this.WriteNodeEnd(); + return root; + } + public boolean SrlBoolOr(String key, boolean v) {WriteData(key, v); return v;} + public byte SrlByteOr(String key, byte v) {WriteData(key, v); return v;} + public int SrlIntOr(String key, int or) {WriteData(key, or); return or;} + public long SrlLongOr(String key, long or) {WriteData(key, or); return or;} + public String SrlStrOr(String key, String or) {WriteData(key, or); return or;} + public DateAdp SrlDateOr(String key, DateAdp or) {WriteData(key, or.XtoStr_gplx()); return or;} + public DecimalAdp SrlDecimalOr(String key, DecimalAdp or) {WriteData(key, or.Xto_decimal()); return or;} + public double SrlDoubleOr(String key, double or) {WriteData(key, or); return or;} + public Object SrlObjOr(String key, Object or) {throw Exc_.new_unimplemented();} + public void TypeKey_(String v) {} + public abstract SrlMgr SrlMgr_new(Object o); +} diff --git a/100_core/src_330_store/gplx/SrlMgr.java b/100_core/src_330_store/gplx/SrlMgr.java new file mode 100644 index 000000000..545cfb4bd --- /dev/null +++ b/100_core/src_330_store/gplx/SrlMgr.java @@ -0,0 +1,35 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public interface SrlMgr { + boolean Type_rdr(); + Object StoreRoot(SrlObj root, String key); + + boolean SrlBoolOr(String key, boolean v); + byte SrlByteOr(String key, byte v); + int SrlIntOr(String key, int v); + long SrlLongOr(String key, long v); + String SrlStrOr(String key, String v); + double SrlDoubleOr(String key, double v); + DecimalAdp SrlDecimalOr(String key, DecimalAdp v); + DateAdp SrlDateOr(String key, DateAdp v); + Object SrlObjOr(String key, Object v); + void SrlList(String key, List_adp list, SrlObj proto, String itmKey); + void TypeKey_(String v); + SrlMgr SrlMgr_new(Object o); +} diff --git a/100_core/src_330_store/gplx/SrlObj.java b/100_core/src_330_store/gplx/SrlObj.java new file mode 100644 index 000000000..a2297a79d --- /dev/null +++ b/100_core/src_330_store/gplx/SrlObj.java @@ -0,0 +1,22 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public interface SrlObj { + SrlObj SrlObj_New(Object o); + void SrlObj_Srl(SrlMgr mgr); +} diff --git a/100_core/src_330_store/gplx/stores/DataRdr_base.java b/100_core/src_330_store/gplx/stores/DataRdr_base.java new file mode 100644 index 000000000..9b984ee32 --- /dev/null +++ b/100_core/src_330_store/gplx/stores/DataRdr_base.java @@ -0,0 +1,214 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.stores; import gplx.*; +import gplx.core.strings.*; +public abstract class DataRdr_base implements SrlMgr { + public boolean Parse() {return parse;} public void Parse_set(boolean v) {parse = v;} private boolean parse; + public Io_url Uri() {return uri;} public void Uri_set(Io_url s) {uri = s;} Io_url uri = Io_url_.Empty; + public abstract String NameOfNode(); + public boolean Type_rdr() {return true;} + public Hash_adp EnvVars() {return envVars;} Hash_adp envVars = Hash_adp_.new_(); + public abstract Object Read(String key); + public abstract int FieldCount(); + public abstract String KeyAt(int i); + public abstract Object ReadAt(int i); + @gplx.Virtual public KeyVal KeyValAt(int idx) {return KeyVal_.new_(this.KeyAt(idx), ReadAt(idx));} + public String ReadStr(String key) { + Object val = Read(key); + try {return (String)val;} + catch (Exception exc) {throw Err_dataRdr_ReadFailed_err(String.class, key, val, exc);} + } + public String ReadStrOr(String key, String or) { + Object val = Read(key); if (val == null) return or; + try {return (String)val;} + catch (Exception exc) {Err_dataRdr_ReadFailed_useOr(exc, String.class, key, val, or); return or;} + } + public byte[] ReadBryByStr(String key) {return Bry_.new_u8(ReadStr(key));} + public byte[] ReadBryByStrOr(String key, byte[] or) { + Object val = Read(key); if (val == null) return or; + try {return Bry_.new_u8((String)val);} + catch (Exception exc) {Err_dataRdr_ReadFailed_useOr(exc, byte[].class, key, val, or); return or;} + } + @gplx.Virtual public void SrlList(String key, List_adp list, SrlObj proto, String itmKey) { + list.Clear(); + DataRdr subRdr = this.Subs_byName_moveFirst(key); // collection node + subRdr = subRdr.Subs(); + while (subRdr.MoveNextPeer()) { + SrlObj itm = proto.SrlObj_New(null); + itm.SrlObj_Srl(subRdr); + list.Add(itm); + } + } + @gplx.Virtual public Object StoreRoot(SrlObj root, String key) { + SrlObj clone = root.SrlObj_New(null); + clone.SrlObj_Srl(this); + return clone; + } + public abstract DataRdr Subs_byName_moveFirst(String name); + + public int ReadInt(String key) { + Object val = Read(key); + try {return (parse) ? Int_.parse_(String_.as_(val)) : Int_.cast_(val);} + catch (Exception exc) {throw Err_dataRdr_ReadFailed_err(int.class, key, val, exc);} + } + public int ReadIntOr(String key, int or) { + Object val = Read(key); if (val == null) return or; + try {return (parse) ? Int_.parse_(String_.as_(val)) : Int_.cast_(val);} + catch (Exception exc) {Err_dataRdr_ReadFailed_useOr(exc, int.class, key, val, or); return or;} + } + public long ReadLongOr(String key, long or) { + Object val = Read(key); if (val == null) return or; + try {return (parse) ? Long_.parse_(String_.as_(val)) : Long_.cast_(val);} + catch (Exception exc) {Err_dataRdr_ReadFailed_useOr(exc, long.class, key, val, or); return or;} + } + @gplx.Virtual public boolean ReadBool(String key) { + Object val = Read(key); + try {return (parse) ? Bool_.cast_(BoolClassXtn._.ParseOrNull(String_.as_(val))) : Bool_.cast_(val);} + catch (Exception exc) {throw Err_dataRdr_ReadFailed_err(boolean.class, key, val, exc);} + } + @gplx.Virtual public boolean ReadBoolOr(String key, boolean or) { + Object val = Read(key); if (val == null) return or; + try {return (parse) ? Bool_.parse_(String_.as_(val)) : Bool_.cast_(val);} + catch (Exception exc) {Err_dataRdr_ReadFailed_useOr(exc, boolean.class, key, val, or); return or;} + } + public long ReadLong(String key) { + Object val = Read(key); + try {return (parse) ? Long_.parse_(String_.as_(val)) : Long_.cast_(val);} + catch (Exception exc) {throw Err_dataRdr_ReadFailed_err(long.class, key, val, exc);} + } + public float ReadFloat(String key) { + Object val = Read(key); + try {return (parse) ? Float_.parse_(String_.as_(val)) : Float_.cast_(val);} + catch (Exception exc) {throw Err_dataRdr_ReadFailed_err(float.class, key, val, exc);} + } + public float ReadFloatOr(String key, float or) { + Object val = Read(key); if (val == null) return or; + try {return (parse) ? Float_.parse_(String_.as_(val)) : Float_.cast_(val);} + catch (Exception exc) {Err_dataRdr_ReadFailed_useOr(exc, float.class, key, val, or); return or;} + } + public double ReadDouble(String key) { + Object val = Read(key); + try {return (parse) ? Double_.parse_(String_.as_(val)) : Double_.cast_(val);} + catch (Exception exc) {throw Err_dataRdr_ReadFailed_err(double.class, key, val, exc);} + } + public double ReadDoubleOr(String key, double or) { + Object val = Read(key); if (val == null) return or; + try {return (parse) ? Double_.parse_(String_.as_(val)) : Double_.cast_(val);} + catch (Exception exc) {Err_dataRdr_ReadFailed_useOr(exc, double.class, key, val, or); return or;} + } + @gplx.Virtual public byte ReadByte(String key) { + Object val = Read(key); + try {return (parse) ? Byte_.parse_(String_.as_(val)) : Byte_.cast_(val);} + catch (Exception exc) {throw Err_dataRdr_ReadFailed_err(byte.class, key, val, exc);} + } + @gplx.Virtual public byte ReadByteOr(String key, byte or) { + Object val = Read(key); if (val == null) return or; + try {return (parse) ? Byte_.parse_(String_.as_(val)) : Byte_.cast_(val);} + catch (Exception exc) {Err_dataRdr_ReadFailed_useOr(exc, byte.class, key, val, or); return or;} + } + @gplx.Virtual public DateAdp ReadDate(String key) { + Object val = Read(key); + try {return (parse) ? DateAdp_.parse_gplx(String_.as_(val)) : (DateAdp)val;} + catch (Exception exc) {throw Err_dataRdr_ReadFailed_err(DateAdp.class, key, val, exc);} + } + @gplx.Virtual public DateAdp ReadDateOr(String key, DateAdp or) { + Object val = Read(key); if (val == null) return or; + try {return (parse) ? DateAdp_.parse_gplx(String_.as_(val)) : (DateAdp)val;} + catch (Exception exc) {throw Err_dataRdr_ReadFailed_err(DateAdp.class, key, val, exc);} + } + @gplx.Virtual public DecimalAdp ReadDecimal(String key) { + Object val = Read(key); + try { + if (parse) return DecimalAdp_.parse_(String_.as_(val)); + DecimalAdp rv = DecimalAdp_.as_(val); + return (rv == null) + ? DecimalAdp_.db_(val) // HACK: GfoNde_.rdr_ will call ReadAt(int i) on Db_data_rdr; since no Db_data_rdr knows about DecimalAdp, it will always return decimalType + : rv; + } + catch (Exception exc) {throw Err_dataRdr_ReadFailed_err(DecimalAdp.class, key, val, exc);} + } + @gplx.Virtual public DecimalAdp ReadDecimalOr(String key, DecimalAdp or) { + Object val = Read(key); if (val == null) return or; + try { + if (parse) return DecimalAdp_.parse_(String_.as_(val)); + DecimalAdp rv = DecimalAdp_.as_(val); + return (rv == null) + ? DecimalAdp_.db_(val) // HACK: GfoNde_.rdr_ will call ReadAt(int i) on Db_data_rdr; since no Db_data_rdr knows about DecimalAdp, it will always return decimalType + : rv; + } + catch (Exception exc) {throw Err_dataRdr_ReadFailed_err(DecimalAdp.class, key, val, exc);} + } + public char ReadChar(String key) { + Object val = Read(key); + try { + if (parse) return Char_.parse_(String_.as_(val)); + return Char_.cast_(val); + } + catch (Exception exc) {throw Err_dataRdr_ReadFailed_err(char.class, key, val, exc);} + } + public char ReadCharOr(String key, char or) { + Object val = Read(key); if (val == null) return or; + try { + if (parse) return Char_.parse_(String_.as_(val)); + return Char_.cast_(val); + } + catch (Exception exc) {Exc_.Noop(exc); return or;} + } + public byte[] ReadBry(String key) { + Object val = Read(key); + try {return (byte[])val;} + catch (Exception exc) {throw Err_dataRdr_ReadFailed_err(byte[].class, key, val, exc);} + } + public byte[] ReadBryOr(String key, byte[] or) { + Object val = Read(key); if (val == null) return or; + try {return (byte[])val;} + catch (Exception exc) {Err_dataRdr_ReadFailed_useOr(exc, byte[].class, key, val, or); return or;} + } + public gplx.ios.Io_stream_rdr ReadRdr(String key) {return gplx.ios.Io_stream_rdr_.Noop;} + public boolean SrlBoolOr(String key, boolean or) {return ReadBoolOr(key, or);} + public byte SrlByteOr(String key, byte or) {return ReadByteOr(key, or);} + public int SrlIntOr(String key, int or) {return ReadIntOr(key, or);} + public long SrlLongOr(String key, long or) {return ReadLongOr(key, or);} + public String SrlStrOr(String key, String or) {return ReadStrOr(key, or);} + public DateAdp SrlDateOr(String key, DateAdp or) {return ReadDateOr(key, or);} + public DecimalAdp SrlDecimalOr(String key, DecimalAdp or) {return ReadDecimalOr(key, or);} + public double SrlDoubleOr(String key, double or) {return ReadDoubleOr(key, or);} + public Object SrlObjOr(String key, Object or) {throw Exc_.new_unimplemented();} + public void XtoStr_gfml(String_bldr sb) { + sb.Add(this.NameOfNode()).Add(":"); + for (int i = 0; i < this.FieldCount(); i++) { + KeyVal kv = this.KeyValAt(i); + if (i != 0) sb.Add(" "); + sb.Add_fmt("{0}='{1}'", kv.Key(), String_.Replace(kv.Val_to_str_or_empty(), "'", "\"")); + } + sb.Add(";"); + } + public abstract DataRdr Subs(); + public void TypeKey_(String v) {} + public abstract SrlMgr SrlMgr_new(Object o); + static Exc Err_dataRdr_ReadFailed_err(Class type, String key, Object val, Exception inner) { + String innerMsg = inner == null ? "" : Err_.Message_lang(inner); + return Exc_.new_w_type("DataRdr_ReadFailed", "failed to read data", "key", key, "val", val, "type", type, "innerMsg", innerMsg).Stack_erase_1_(); + } + static void Err_dataRdr_ReadFailed_useOr(Class type, String key, Object val, Object or) { + UsrDlg_._.Warn(UsrMsg.new_("failed to read data; substituting default").Add("key", key).Add("val", val).Add("default", or).Add("type", type)); + } + static void Err_dataRdr_ReadFailed_useOr(Exception exc, Class type, String key, Object val, Object or) { + UsrDlg_._.Warn(UsrMsg.new_("failed to read data; substituting default").Add("key", key).Add("val", val).Add("default", or).Add("type", type)); + } +} diff --git a/100_core/src_330_store/gplx/stores/DataRdr_mem.java b/100_core/src_330_store/gplx/stores/DataRdr_mem.java new file mode 100644 index 000000000..50f530b4b --- /dev/null +++ b/100_core/src_330_store/gplx/stores/DataRdr_mem.java @@ -0,0 +1,78 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.stores; import gplx.*; +public class DataRdr_mem extends DataRdr_base implements GfoNdeRdr { + @Override public String NameOfNode() {return cur.Name();} + public GfoNde UnderNde() {return cur;} + @Override public int FieldCount() {return flds.Count();} + @Override public String KeyAt(int i) {return flds.Get_at(i).Key();} + @Override public Object ReadAt(int i) {return cur.ReadAt(i);} + @Override public Object Read(String key) { + int i = flds.Idx_of(key); if (i == List_adp_.NotFound) return null; + return cur.ReadAt(i); + } + public boolean MoveNextPeer() { + if (++peerPos >= peerList.Count()) { + cur = null; + return false; + } + cur = peerList.FetchAt_asGfoNde(peerPos); + return true; + } + @Override public DataRdr Subs() { + if (cur == null && peerList.Count() == 0) return DataRdr_.Null; + return GfoNdeRdr_.peers_(Peers_get(), this.Parse()); + } + public DataRdr Subs_byName(String name) { + if (cur == null && peerList.Count() == 0) return DataRdr_.Null; + String[] names = String_.Split(name, "/"); + GfoNdeList list = GfoNdeList_.new_(); + Subs_byName(list, names, 0, Peers_get()); + return GfoNdeRdr_.peers_(list, this.Parse()); + } + @Override public DataRdr Subs_byName_moveFirst(String name) { + DataRdr subRdr = Subs_byName(name); + boolean hasFirst = subRdr.MoveNextPeer(); + return (hasFirst) ? subRdr : DataRdr_.Null; + } + public String XtoStr() {return cur.XtoStr();} + public void Rls() {this.cur = null; this.peerList = null;} + @Override public SrlMgr SrlMgr_new(Object o) {return new DataRdr_mem();} + GfoNdeList Peers_get() { + boolean initialized = cur == null && peerPos == -1 && peerList.Count() > 0; // initialized = no current, at bof, subs available + return initialized ? peerList.FetchAt_asGfoNde(0).Subs() : cur.Subs(); + } + void Subs_byName(GfoNdeList list, String[] names, int depth, GfoNdeList peers) { + String name = names[depth]; + for (int i = 0; i < peers.Count(); i++) { + GfoNde sub = peers.FetchAt_asGfoNde(i); if (sub == null) continue; + if (!String_.Eq(name, sub.Name())) continue; + if (depth == names.length - 1) + list.Add(sub); + else + Subs_byName(list, names, depth + 1, sub.Subs()); + } + } + + GfoNde cur; GfoNdeList peerList; int peerPos = -1; GfoFldList flds; + public static DataRdr_mem new_(GfoNde cur, GfoFldList flds, GfoNdeList peerList) { + DataRdr_mem rv = new DataRdr_mem(); + rv.cur = cur; rv.peerList = peerList; rv.flds = flds; + return rv; + } @gplx.Internal protected DataRdr_mem() {} +} diff --git a/100_core/src_330_store/gplx/stores/GfoNdeRdr.java b/100_core/src_330_store/gplx/stores/GfoNdeRdr.java new file mode 100644 index 000000000..e0547a337 --- /dev/null +++ b/100_core/src_330_store/gplx/stores/GfoNdeRdr.java @@ -0,0 +1,21 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.stores; import gplx.*; +public interface GfoNdeRdr extends DataRdr { + GfoNde UnderNde(); +} diff --git a/100_core/src_330_store/gplx/stores/GfoNdeRdr_.java b/100_core/src_330_store/gplx/stores/GfoNdeRdr_.java new file mode 100644 index 000000000..b5167cb6e --- /dev/null +++ b/100_core/src_330_store/gplx/stores/GfoNdeRdr_.java @@ -0,0 +1,48 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.stores; import gplx.*; +public class GfoNdeRdr_ { + public static GfoNdeRdr kvs_(KeyValList kvList) { + GfoFldList flds = GfoFldList_.new_(); + int pairsLen = kvList.Count(); + Object[] vals = new Object[pairsLen]; + for (int i = 0; i < pairsLen; i++) { + KeyVal pair = kvList.GetAt(i); + flds.Add(pair.Key(), StringClassXtn._); + vals[i] = pair.Val_to_str_or_empty(); + } + GfoNde nde = GfoNde_.vals_(flds, vals); + return root_(nde, true); + } + public static GfoNdeRdr root_parseNot_(GfoNde root) {return root_(root, true);} + public static GfoNdeRdr root_(GfoNde root, boolean parse) { + DataRdr_mem rv = DataRdr_mem.new_(root, root.Flds(), root.Subs()); rv.Parse_set(parse); + return rv; + } + public static GfoNdeRdr leaf_(GfoNde cur, boolean parse) { + DataRdr_mem rv = DataRdr_mem.new_(cur, cur.Flds(), GfoNdeList_.Null); rv.Parse_set(parse); + return rv; + } + public static GfoNdeRdr peers_(GfoNdeList peers, boolean parse) { + GfoFldList flds = peers.Count() == 0 ? GfoFldList_.Null : peers.FetchAt_asGfoNde(0).Flds(); + DataRdr_mem rv = DataRdr_mem.new_(null, flds, peers); rv.Parse_set(parse); + return rv; + } + public static GfoNdeRdr as_(Object obj) {return obj instanceof GfoNdeRdr ? (GfoNdeRdr)obj : null;} + public static GfoNdeRdr cast_(Object obj) {try {return (GfoNdeRdr)obj;} catch(Exception exc) {throw Exc_.new_type_mismatch_w_exc(exc, GfoNdeRdr.class, obj);}} +} diff --git a/100_core/src_330_store/gplx/stores/xmls/XmlDataRdr.java b/100_core/src_330_store/gplx/stores/xmls/XmlDataRdr.java new file mode 100644 index 000000000..615735946 --- /dev/null +++ b/100_core/src_330_store/gplx/stores/xmls/XmlDataRdr.java @@ -0,0 +1,77 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.stores.xmls; import gplx.*; import gplx.stores.*; +import gplx.xmls.*; /*Xpath_*/ +public class XmlDataRdr extends DataRdr_base implements DataRdr { + @Override public String NameOfNode() {return nde.Name();} public String XtoStr() {return nde.Xml_outer();} + @Override public int FieldCount() {return nde.Atrs() == null ? 0 : nde.Atrs().Count();} // nde.Attributes == null when nde is XmlText; ex: val + @Override public String KeyAt(int i) {return nde.Atrs().Get_at(i).Name();} + @Override public Object ReadAt(int i) { + XmlAtr attrib = nde.Atrs().Get_at(i); + return (attrib == null) ? null : attrib.Value(); + } + @Override public Object Read(String key) { + return nde.Atrs().FetchValOr(key, null); + } + public boolean MoveNextPeer() { + if (++pos >= peerList.Count()){ // moved out Of range + nde = null; + return false; + } + nde = peerList.Get_at(pos); + return true; + } + @Override public DataRdr Subs() { + XmlNdeList list = Xpath_.SelectElements(nde); + XmlDataRdr rv = new XmlDataRdr(); + rv.ctor_(list, null); + return rv; + } + @Override public DataRdr Subs_byName_moveFirst(String name) { + DataRdr subRdr = Subs_byName(name); + boolean hasFirst = subRdr.MoveNextPeer(); + return (hasFirst) ? subRdr : DataRdr_.Null; + } + public DataRdr Subs_byName(String name) { + XmlNdeList list = Xpath_.SelectAll(nde, name); + XmlDataRdr rv = new XmlDataRdr(); + rv.ctor_(list, null); + return rv; + } + public void Rls() {nde = null; peerList = null;} + public String NodeValue_get() { + if (nde.SubNdes().Count() != 1) return ""; + XmlNde sub = nde.SubNdes().Get_at(0); + return (sub.NdeType_textOrEntityReference()) ? sub.Text_inner() : ""; + } + public String Node_OuterXml() {return nde.Xml_outer();} + @Override public SrlMgr SrlMgr_new(Object o) {return new XmlDataRdr();} + void LoadString(String raw) { + XmlDoc xdoc = XmlDoc_.parse_(raw); + XmlNdeList list = Xpath_.SelectElements(xdoc.Root()); + ctor_(list, xdoc.Root()); + } + void ctor_(XmlNdeList peerList, XmlNde nde) { + this.peerList = peerList; this.nde = nde; pos = -1; + } + + XmlNde nde = null; + XmlNdeList peerList = null; int pos = -1; + @gplx.Internal protected XmlDataRdr(String raw) {this.LoadString(raw); this.Parse_set(true);} + XmlDataRdr() {this.Parse_set(true);} +} diff --git a/100_core/src_330_store/gplx/stores/xmls/XmlDataRdr_.java b/100_core/src_330_store/gplx/stores/xmls/XmlDataRdr_.java new file mode 100644 index 000000000..4d5b82a93 --- /dev/null +++ b/100_core/src_330_store/gplx/stores/xmls/XmlDataRdr_.java @@ -0,0 +1,25 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.stores.xmls; import gplx.*; import gplx.stores.*; +public class XmlDataRdr_ { + public static XmlDataRdr file_(Io_url url) { + String text = Io_mgr.I.LoadFilStr(url); + return new XmlDataRdr(text); + } + public static XmlDataRdr text_(String text) {return new XmlDataRdr(text);} +} diff --git a/100_core/src_330_store/gplx/stores/xmls/XmlDataWtr_.java b/100_core/src_330_store/gplx/stores/xmls/XmlDataWtr_.java new file mode 100644 index 000000000..7e64133b6 --- /dev/null +++ b/100_core/src_330_store/gplx/stores/xmls/XmlDataWtr_.java @@ -0,0 +1,113 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.stores.xmls; import gplx.*; import gplx.stores.*; +import gplx.core.strings.*; +public class XmlDataWtr_ { + public static DataWtr new_() {return XmlDataWtr.new_();} +} +class XmlDataWtr extends DataWtr_base implements DataWtr { + public void InitWtr(String key, Object val) {} + @Override public void WriteData(String name, Object val) { +// if (val == null) return; + String valString = Object_.Xto_str_strict_or_empty(val); + int valStringLen = String_.Len(valString); + sb.Add(" ").Add(name).Add("=\""); + for (int i = 0; i < valStringLen; i++) { + char c = String_.CharAt(valString, i); + if (c == '<') sb.Add("<"); + else if (c == '>') sb.Add(">"); + else if (c == '&') sb.Add("&"); + else if (c == '\"') sb.Add(""e;"); + else sb.Add(c); + } + sb.Add("\""); +// XmlAttribute atr = doc.CreateAttribute(name); +// atr.Value = (val == null) ? String_.Empty : val.toString(); +// nde.Attributes.Append(atr); + } + public void WriteLeafBgn(String leafName) {this.WriteXmlNodeBegin(leafName);} + public void WriteLeafEnd() {} + public void WriteTableBgn(String name, GfoFldList fields) {this.WriteXmlNodeBegin(name);} + @Override public void WriteNodeBgn(String nodeName) {this.WriteXmlNodeBegin(nodeName);} + @Override public void WriteNodeEnd() {this.WriteXmlNodeEnd();} + public String XtoStr() { + while (names.Count() > 0) { + WriteXmlNodeEnd(); + } + return sb.XtoStr(); +// while (nde.ParentNode != null) +// WriteXmlNodeEnd(); // close all open ndes automatically +// return doc.OuterXml; + } + public void WriteComment(String comment) { + sb.Add(""); +// XmlComment xmlComment = doc.CreateComment(comment); +// nde.AppendChild(xmlComment); + } + public void Clear() { + sb.Clear(); +// doc = new XmlDocument(); + } + void WriteXmlNodeBegin(String name) { + if (ndeOpened) { + sb.Add(">" + String_.CrLf); + } + ndeOpened = true; + names.Add(name); + sb.Add("<" + name); +// XmlNode owner = nde; +// nde = doc.CreateElement(name); +// if (owner == null) // first call to WriteXmlNodeBegin(); append child to doc +// doc.AppendChild(nde); +// else { +// WriteLineFeedIfNeeded(doc, owner); +// owner.AppendChild(nde); +// } + } + void WriteXmlNodeEnd() { + if (ndeOpened) { + sb.Add(" />" + String_.CrLf); + ndeOpened = false; + } + else { + String name = (String)names.Get_at_last(); + sb.Add("" + String_.CrLf); + } + names.Del_at(names.Count() - 1); + // if (nde.ParentNode == null) throw Err_.new_("WriteXmlNodeEnd() called on root node"); +// nde = nde.ParentNode; +// WriteLineFeed(doc, nde); + } +// void WriteLineFeed(XmlDocument doc, XmlNode owner) { +// XmlSignificantWhitespace crlf = doc.CreateSignificantWhitespace(String_.CrLf); +// owner.AppendChild(crlf); +// } +// void WriteLineFeedIfNeeded(XmlDocument doc, XmlNode owner) { +// XmlSignificantWhitespace lastSubNode = owner.ChildNodes[owner.ChildNodes.Count - 1] as XmlSignificantWhitespace; +// if (lastSubNode == null) +// WriteLineFeed(doc, owner); // write LineFeed for consecutive WriteXmlNodeBegin calls; ex: +// } + @Override public SrlMgr SrlMgr_new(Object o) {return new XmlDataWtr();} + boolean ndeOpened = false; +// int atrCount = 0; +// int ndeState = -1; static final int NdeState0_Opened = 0, NdeState0_H = 1; +// XmlDocument doc = new XmlDocument(); XmlNode nde; + List_adp names = List_adp_.new_(); + String_bldr sb = String_bldr_.new_(); + public static XmlDataWtr new_() {return new XmlDataWtr();} XmlDataWtr() {} +} diff --git a/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdrOpts.java b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdrOpts.java new file mode 100644 index 000000000..3205f8c9e --- /dev/null +++ b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdrOpts.java @@ -0,0 +1,25 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.stores.dsvs; import gplx.*; import gplx.stores.*; +public class DsvDataRdrOpts { + public boolean HasHeader() {return hasHeader;} public DsvDataRdrOpts HasHeader_(boolean val) {hasHeader = val; return this;} private boolean hasHeader = false; + public String NewLineSep() {return newLineSep;} public DsvDataRdrOpts NewLineSep_(String val) {newLineSep = val; return this;} private String newLineSep = String_.CrLf; + public String FldSep() {return fldSep;} public DsvDataRdrOpts FldSep_(String val) {fldSep = val; return this;} private String fldSep = ","; + public GfoFldList Flds() {return flds;} public DsvDataRdrOpts Flds_(GfoFldList val) {flds = val; return this;} GfoFldList flds = GfoFldList_.Null; + public static DsvDataRdrOpts new_() {return new DsvDataRdrOpts();} DsvDataRdrOpts() {} +} diff --git a/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_.java b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_.java new file mode 100644 index 000000000..200f90951 --- /dev/null +++ b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_.java @@ -0,0 +1,248 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.stores.dsvs; import gplx.*; import gplx.stores.*; +import gplx.core.strings.*; +import gplx.texts.*; /*CharStream*/ +public class DsvDataRdr_ { + public static DataRdr dsv_(String text) {return DsvParser.dsv_().ParseAsRdr(text);} + public static DataRdr csv_hdr_(String text) {return csv_opts_(text, DsvDataRdrOpts.new_().HasHeader_(true));} + public static DataRdr csv_dat_(String text) {return csv_opts_(text, DsvDataRdrOpts.new_());} + public static DataRdr csv_dat_with_flds_(String text, String... flds) {return csv_opts_(text, DsvDataRdrOpts.new_().Flds_(GfoFldList_.str_(flds)));} + public static DataRdr csv_opts_(String text, DsvDataRdrOpts opts) { + DsvParser parser = DsvParser.csv_(opts.HasHeader(), opts.Flds()); // NOTE: this sets up the bldr; do not call .Init after this + parser.Symbols().RowSep_(opts.NewLineSep()).FldSep_(opts.FldSep()); + + DataRdr root = parser.ParseAsRdr(text); // don't return root; callers expect csv to return rdr for rows + DataRdr csvTable = root.Subs(); + return csvTable.Subs(); + } +} +class DsvParser { + @gplx.Internal protected DsvSymbols Symbols() {return sym;} DsvSymbols sym = DsvSymbols.default_(); + @gplx.Internal protected void Init() {sb.Clear(); bldr.Init(); qteOn = false;} + @gplx.Internal protected DataRdr ParseAsRdr(String raw) {return GfoNdeRdr_.root_(ParseAsNde(raw), csvOn);} // NOTE: csvOn means parse; assume manual typed flds not passed in (ex: id,Int) + @gplx.Internal protected GfoNde ParseAsNde(String raw) { + if (String_.Eq(raw, "")) return bldr.BldRoot(); + CharStream strm = CharStream.pos0_(raw); + while (true) { + if (strm.AtEnd()) { + ProcessLine(strm, true); + break; + } + if (qteOn) + ReadStreamInQte(strm); + else if (strm.MatchAndMove(sym.QteDlm())) + qteOn = true; + else if (strm.MatchAndMove(sym.FldSep())) + ProcessFld(strm); + else if (strm.MatchAndMove(sym.RowSep())) + ProcessLine(strm, false); + else { + sb.Add(strm.Cur()); + strm.MoveNext(); + } + } + return bldr.BldRoot(); + } + void ReadStreamInQte(CharStream strm) { + if (strm.MatchAndMove(sym.QteDlm())) { // is quote + if (strm.MatchAndMove(sym.QteDlm())) // double quote -> quote; "a"" + sb.Add(sym.QteDlm()); + else if (strm.MatchAndMove(sym.FldSep())) { // closing quote before field; "a", + ProcessFld(strm); + qteOn = false; + } + else if (strm.MatchAndMove(sym.RowSep()) || strm.AtEnd()) { // closing quote before record; "a"\r\n + ProcessLine(strm, false); + qteOn = false; + } + else + throw Exc_.new_("invalid quote in quoted field; quote must be followed by quote, fieldSpr, or recordSpr", "sym", strm.Cur(), "text", strm.Xto_str_by_pos(strm.Pos() - 10, strm.Pos() + 10)); + } + else { // regular char; append and continue + sb.Add(strm.Cur()); + strm.MoveNext(); + } + } + void ProcessFld(CharStream strm) { + String val = sb.Xto_str_and_clear(); + if (cmdSeqOn) { + cmdSeqOn = false; + if (String_.Eq(val, sym.CmdDlm()) && qteOn) { // 2 cmdDlms in a row; cmdSeq encountered; next fld must be cmdName + nextValType = ValType_CmdName; + return; + } + tkns.Add(sym.CmdDlm()); // curTkn is not cmdDlm; prevTkn happened to be cmdDlm; add prev to tkns and continue; ex: a, ,b + } + if (String_.Eq(val, sym.CmdDlm())) // val is cmdDlm; do not add now; wait til next fld to decide + cmdSeqOn = true; + else if (nextValType == ValType_Data) { + if (String_.Len(val) == 0) val = qteOn ? "" : null; // differentiate between null and emptyString; ,, vs ,"", + tkns.Add(val); + } + else if (nextValType == ValType_CmdName) { + if (String_.Eq(val, sym.TblNameSym())) lineMode = LineType_TblBgn; // # + else if (String_.Eq(val, sym.FldNamesSym())) lineMode = LineType_FldNames; // @ + else if (String_.Eq(val, sym.FldTypesSym())) lineMode = LineType_FldTypes; // $ + else if (String_.Eq(val, sym.CommentSym())) lineMode = LineType_Comment; // ' + else throw Exc_.new_("unknown dsv cmd", "cmd", val); + } + else + throw Exc_.new_("unable to process field value", "value", val); + } + void ProcessLine(CharStream strm, boolean cleanup) { + if (sb.Count() == 0 && tkns.Count() == 0) + if (csvOn) { // csvOn b/c csvMode allows blank lines as empty data + if (cleanup) // cleanup b/c blankLine should not be added when called by cleanup, else will always add extra row at end + return; // cleanup, so no further action needed; return; + else + ProcessFld(strm); + } + else + lineMode = LineType_BlankLine; + else + ProcessFld(strm); // always process fld; either (1) chars waiting in sb "a,b"; or (2) last char was fldSep "a," + if (cmdSeqOn) { // only happens if last fld is comma space (, ); do not let cmds span lines + cmdSeqOn = false; + tkns.Add(sym.CmdDlm()); + } + if (lineMode == LineType_TblBgn) bldr.MakeTblBgn(tkns); + else if (lineMode == LineType_FldNames) bldr.MakeFldNames(tkns); + else if (lineMode == LineType_FldTypes) bldr.MakeFldTypes(tkns); + else if (lineMode == LineType_Comment) bldr.MakeComment(tkns); + else if (lineMode == LineType_BlankLine) bldr.MakeBlankLine(); + else bldr.MakeVals(tkns); + nextValType = ValType_Data; + lineMode = LineType_Data; + } + String_bldr sb = String_bldr_.new_(); List_adp tkns = List_adp_.new_(); DsvTblBldr bldr = DsvTblBldr.new_(); + boolean cmdSeqOn = false, qteOn = false, csvOn = false; + int nextValType = ValType_Data, lineMode = LineType_Data; + @gplx.Internal protected static DsvParser dsv_() {return new DsvParser();} + @gplx.Internal protected static DsvParser csv_(boolean hasHdr, GfoFldList flds) { + DsvParser rv = new DsvParser(); + rv.csvOn = true; + rv.lineMode = hasHdr ? LineType_FldNames : LineType_Data; + List_adp names = List_adp_.new_(), types = List_adp_.new_(); + for (int i = 0; i < flds.Count(); i++) { + GfoFld fld = flds.Get_at(i); + names.Add(fld.Key()); types.Add(fld.Type().Key()); + } + rv.bldr.MakeFldNames(names); rv.bldr.MakeFldTypes(types); + return rv; + } + static final int ValType_Data = 0, ValType_CmdName = 1; + static final int LineType_Data = 0, LineType_Comment = 1, LineType_TblBgn = 2, LineType_FldNames = 3, LineType_FldTypes = 4, LineType_BlankLine = 5; +} +class DsvTblBldr { + public void Init() { + root = GfoNde_.root_(); tbl = GfoNde_.tbl_(NullTblName, GfoFldList_.new_()); + fldNames.Clear(); fldTypes.Clear(); + stage = Stage_Init; + } + public GfoNde BldRoot() { + if (stage != Stage_Init) CreateTbl(); // CreateTbl if HDR or ROW is in progress + return root; + } + public void MakeTblBgn(List_adp tkns) { + if (stage != Stage_Init) CreateTbl(); // CreateTbl if HDR or ROW is in progress + tbl.Name_((String)tkns.Get_at(0)); + layout.HeaderList().Add_TableName(); + stage = Stage_Hdr; tkns.Clear(); + } + public void MakeFldNames(List_adp tkns) { + if (stage == Stage_Row) CreateTbl(); // CreateTbl if ROW is in progress; NOTE: exclude HDR, as first HDR would have called CreateTbl + fldNames.Clear(); + for (Object fldNameObj : tkns) + fldNames.Add(fldNameObj); + layout.HeaderList().Add_LeafNames(); + stage = Stage_Hdr; tkns.Clear(); + } + public void MakeFldTypes(List_adp tkns) { + if (stage == Stage_Row) CreateTbl(); // CreateTbl if ROW is in progress; NOTE: exclude HDR, as first HDR would have called CreateTbl + fldTypes.Clear(); + for (Object fldTypeObj : tkns) { + ClassXtn type = ClassXtnPool._.Get_by_or_fail((String)fldTypeObj); + fldTypes.Add(type); + } + layout.HeaderList().Add_LeafTypes(); + stage = Stage_Hdr; tkns.Clear(); + } + public void MakeComment(List_adp tkns) { + if (stage == Stage_Row) // comments in ROW; ignore; NOTE: tkns.Clear() could be merged, but this seems clearer + tkns.Clear(); + else { // comments in HDR + String_bldr sb = String_bldr_.new_(); + for (int i = 0; i < tkns.Count(); i++) + sb.Add((String)tkns.Get_at(i)); + layout.HeaderList().Add_Comment(sb.XtoStr()); + tkns.Clear(); + } + } + public void MakeBlankLine() { + if (stage != Stage_Init) CreateTbl(); // CreateTbl if HDR or ROW is in progress; + layout.HeaderList().Add_BlankLine(); + stage = Stage_Init; // NOTE: mark stage as INIT; + } + public void MakeVals(List_adp tkns) { + if (stage != Stage_Row) CreateFlds(tkns.Count()); // stage != Stage_Row means if (noRowsCreated) + GfoNde row = GfoNde_.vals_(tbl.SubFlds(), MakeValsAry(tkns)); + tbl.Subs().Add(row); + stage = Stage_Row; tkns.Clear(); + } + Object[] MakeValsAry(List_adp tkns) { + GfoFldList subFlds = tbl.SubFlds(); int subFldsCount = subFlds.Count(); + if (tkns.Count() > subFldsCount) throw Exc_.new_("values.Count cannot be greater than fields.Count", "values.Count", tkns.Count(), "fields.Count", subFldsCount); + Object[] rv = new Object[subFldsCount]; + for (int i = 0; i < subFldsCount; i++) { + ClassXtn typx = subFlds.Get_at(i).Type(); + String val = i < tkns.Count() ? (String)tkns.Get_at(i) : null; + rv[i] = typx.ParseOrNull(val); + } + return rv; + } + void CreateTbl() { + if (tbl.SubFlds().Count() == 0) CreateFlds(0); // this check occurs when tbl has no ROW; (TOMB: tdb test fails) + tbl.EnvVars().Add(DsvStoreLayout.Key_const, layout); + root.Subs().Add(tbl); // add pending table + layout = DsvStoreLayout.dsv_brief_(); + tbl = GfoNde_.tbl_(NullTblName, GfoFldList_.new_()); + stage = Stage_Hdr; + } + void CreateFlds(int valCount) { + int fldNamesCount = fldNames.Count(), fldTypesCount = fldTypes.Count(); + if (fldNamesCount == 0 && fldTypesCount == 0) { // csv tbls where no names or types, just values + for (int i = 0; i < valCount; i++) + tbl.SubFlds().Add("fld" + i, StringClassXtn._); + } + else { // all else, where either names or types is defined + int maxCount = fldNamesCount > fldTypesCount ? fldNamesCount : fldTypesCount; + for (int i = 0; i < maxCount; i++) { + String name = i < fldNamesCount ? (String)fldNames.Get_at(i) : "fld" + i; + ClassXtn typx = i < fldTypesCount ? (ClassXtn)fldTypes.Get_at(i) : StringClassXtn._; + tbl.SubFlds().Add(name, typx); + } + } + } + GfoNde root; GfoNde tbl; DsvStoreLayout layout = DsvStoreLayout.dsv_brief_(); + List_adp fldNames = List_adp_.new_(); List_adp fldTypes = List_adp_.new_(); + int stage = Stage_Init; + public static DsvTblBldr new_() {return new DsvTblBldr();} DsvTblBldr() {this.Init();} + @gplx.Internal protected static final String NullTblName = ""; + static final int Stage_Init = 0, Stage_Hdr = 1, Stage_Row = 2; +} diff --git a/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_csv_dat_tst.java b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_csv_dat_tst.java new file mode 100644 index 000000000..13703ac51 --- /dev/null +++ b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_csv_dat_tst.java @@ -0,0 +1,216 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.stores.dsvs; import gplx.*; import gplx.stores.*; +import org.junit.*; import gplx.core.strings.*; +public class DsvDataRdr_csv_dat_tst { + @Before public void setup() { + fx.Parser_(DsvParser.csv_(false, GfoFldList_.Null)); + fx.Clear(); + } DsvDataRdr_fxt fx = DsvDataRdr_fxt.new_(); + @Test public void Empty() { + fx.run_parse_(""); + fx.tst_DatNull(); + } + @Test public void Fld_0() { + fx.run_parse_("a"); + fx.tst_DatCsv(fx.ary_("a")); + } + @Test public void Fld_N() { + fx.run_parse_("a,b,c"); + fx.tst_FldListCsv("fld0", "fld1", "fld2"); + fx.tst_DatCsv(fx.ary_("a", "b", "c")); + } + @Test public void Row_N() { + fx.run_parse_ + ( "a,b,c", String_.CrLf + , "1,2,3" + ); + fx.tst_DatCsv + ( fx.ary_("a", "b", "c") + , fx.ary_("1", "2", "3") + ); + } + @Test public void Escape_WhiteSpace() { + fx.run_parse_("a,\" \t\",c"); + fx.tst_DatCsv(fx.ary_("a", " \t", "c")); + } + @Test public void Escape_FldSep() { + fx.run_parse_("a,\",\",c"); + fx.tst_DatCsv(fx.ary_("a", ",", "c")); + } + @Test public void Escape_RowSep() { + fx.run_parse_("a,\"" + String_.CrLf + "\",c"); + fx.tst_DatCsv(fx.ary_("a", String_.CrLf, "c")); + } + @Test public void Escape_Quote() { + fx.run_parse_("a,\"\"\"\",c"); + fx.tst_DatCsv(fx.ary_("a", "\"", "c")); + } + @Test public void Blank_Null() { + fx.run_parse_("a,,c"); + fx.tst_DatCsv(fx.ary_("a", null, "c")); + } + @Test public void Blank_EmptyString() { + fx.run_parse_("a,\"\",c"); + fx.tst_DatCsv(fx.ary_("a", "", "c")); + } + @Test public void Blank_Null_Multiple() { + fx.run_parse_(",,"); + fx.tst_DatCsv(fx.ary_(null, null, null)); + } + @Test public void TrailingNull() { + fx.run_parse_("a,"); + fx.tst_DatCsv(fx.ary_("a", null)); + } + @Test public void TrailingEmpty() { + fx.run_parse_("a,\"\""); + fx.tst_DatCsv(fx.ary_("a", "")); + } + @Test public void Quote_Error() { + try { + fx.run_parse_("a,\"\" ,c"); + Tfds.Fail_expdError(); + } + catch (Exc e) { + Tfds.Eq_true(String_.Has(Err_.Message_lang(e), "invalid quote in quoted field")); + } + } + @Test public void Misc_AllowValsLessThanFields() { + // assume null when vals.Count < fields.Count; PURPOSE: MsExcel will not save trailing commas for csvExport; ex: a, -> a + fx.run_parse_ + ( "a0,a1", String_.CrLf + , "b0" + ); + fx.tst_DatCsv + ( fx.ary_("a0", "a1") + , fx.ary_("b0", null) + ); + } + @Test public void Misc_NewLineValidForSingleColumnTables() { + fx.run_parse_ + ( "a", String_.CrLf + , String_.CrLf + , "c" , String_.CrLf + , String_.CrLf + ); + fx.tst_DatCsv + ( fx.ary_("a") + , fx.ary_null_() + , fx.ary_("c") + , fx.ary_null_() + ); + } + @Test public void Misc_NewLineValidForSingleColumnTables_FirstLine() { + fx.run_parse_ + ( String_.CrLf + , "b", String_.CrLf + , "c" + ); + fx.tst_DatCsv + ( fx.ary_null_() + , fx.ary_("b") + , fx.ary_("c") + ); + } + @Test public void Hdr_Basic() { + fx.Parser_(DsvParser.csv_(true, GfoFldList_.Null)); + fx.run_parse_ + ( "id,name", String_.CrLf + , "0,me" + ); + fx.tst_FldListCsv("id", "name"); + fx.tst_DatCsv(fx.ary_("0", "me")); + } +// @Test public void Hdr_Manual() { +// fx.Parser_(DsvParser.csv_(false, GfoFldList_.new_().Add("id", IntClassXtn._).Add("name", StringClassXtn._), true)); +// fx.run_parse_("0,me"); +// fx.tst_DatCsv(fx.ary_(0, "me")); // NOTE: testing auto-parsing of id to int b/c id fld is IntClassXtn._; +// } +} +class DsvDataRdr_fxt { + public Object[] ary_(Object... ary) {return ary;} + public Object[] ary_null_() {return new Object[] {null};} + public void Clear() {parser.Init(); root = null;} + public DsvParser Parser() {return parser;} public DsvDataRdr_fxt Parser_(DsvParser val) {parser = val; return this;} DsvParser parser = DsvParser.dsv_(); + public GfoNde Root() {return root;} GfoNde root; + public void run_parse_(String... ary) {root = parser.ParseAsNde(String_.Concat(ary));} + public void run_parse_lines_(String... ary) {root = parser.ParseAsNde(String_.Concat_lines_crlf(ary));} + public DsvDataRdr_fxt tst_FldListCsv(String... names) {return tst_Flds(TblIdx0, GfoFldList_.str_(names));} + public DsvDataRdr_fxt tst_Flds(int tblIdx, GfoFldList expdFlds) { + GfoNde tbl = root.Subs().FetchAt_asGfoNde(tblIdx); + List_adp expdList = List_adp_.new_(), actlList = List_adp_.new_(); + String_bldr sb = String_bldr_.new_(); + GfoFldList_BldDbgList(expdFlds, expdList, sb); + GfoFldList_BldDbgList(tbl.SubFlds(), actlList, sb); + Tfds.Eq_list(expdList, actlList); + return this; + } + void GfoFldList_BldDbgList(GfoFldList flds, List_adp list, String_bldr sb) { + for (int i = 0; i < flds.Count(); i++) { + GfoFld fld = flds.Get_at(i); + sb.Add(fld.Key()).Add(",").Add(fld.Type().Key()); + list.Add(sb.Xto_str_and_clear()); + } + } + public DsvDataRdr_fxt tst_Tbls(String... expdNames) { + List_adp actlList = List_adp_.new_(); + for (int i = 0; i < root.Subs().Count(); i++) { + GfoNde tbl = root.Subs().FetchAt_asGfoNde(i); + actlList.Add(tbl.Name()); + } + Tfds.Eq_ary(expdNames, actlList.To_str_ary()); + return this; + } + public DsvDataRdr_fxt tst_DatNull() { + Tfds.Eq(0, root.Subs().Count()); + return this; + } + public DsvDataRdr_fxt tst_DatCsv(Object[]... expdRows) {return tst_Dat(0, expdRows);} + public DsvDataRdr_fxt tst_Dat(int tblIdx, Object[]... expdRows) { + GfoNde tbl = root.Subs().FetchAt_asGfoNde(tblIdx); + if (expdRows.length == 0) { + Tfds.Eq(0, tbl.Subs().Count()); + return this; + } + List_adp expdList = List_adp_.new_(), actlList = List_adp_.new_(); + String_bldr sb = String_bldr_.new_(); + for (int i = 0; i < tbl.Subs().Count(); i++) { + GfoNde row = tbl.Subs().FetchAt_asGfoNde(i); + for (int j = 0; j < row.Flds().Count(); j++) { + if (j != 0) sb.Add("~"); + sb.Add_obj(Object_.Xto_str_strict_or_null_mark(row.ReadAt(j))); + } + expdList.Add(sb.Xto_str_and_clear()); + } + for (Object[] expdRow : expdRows) { + if (expdRow == null) { + actlList.Add(""); + continue; + } + for (int j = 0; j < expdRow.length; j++) { + if (j != 0) sb.Add("~"); + sb.Add_obj(Object_.Xto_str_strict_or_null_mark(expdRow[j])); + } + actlList.Add(sb.Xto_str_and_clear()); + } + Tfds.Eq_list(expdList, actlList); + return this; + } + public static DsvDataRdr_fxt new_() {return new DsvDataRdr_fxt();} + static final int TblIdx0 = 0; +} diff --git a/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_dsv_dat_tst.java b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_dsv_dat_tst.java new file mode 100644 index 000000000..b8849711e --- /dev/null +++ b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_dsv_dat_tst.java @@ -0,0 +1,70 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.stores.dsvs; import gplx.*; import gplx.stores.*; +import org.junit.*; +public class DsvDataRdr_dsv_dat_tst { + @Before public void setup() {fx.Clear();} DsvDataRdr_fxt fx = DsvDataRdr_fxt.new_(); + @Test public void NameOnly() { + fx.run_parse_("tableName, ,\" \",#"); + fx.tst_Tbls("tableName"); + fx.tst_Dat(0); + } + @Test public void Rows_N() { + fx.run_parse_lines_ + ( "numbers, ,\" \",#" + , "1,2,3" + , "4,5,6" + ); + fx.tst_Tbls("numbers"); + fx.tst_Dat(0 + , fx.ary_("1", "2", "3") + , fx.ary_("4", "5", "6") + ); + } + @Test public void Tbls_N() { + fx.run_parse_lines_ + ( "letters, ,\" \",#" + , "a,b,c" + , "numbers, ,\" \",#" + , "1,2,3" + , "4,5,6" + ); + fx.tst_Tbls("letters", "numbers"); + fx.tst_Dat(0, fx.ary_("a", "b", "c")); + fx.tst_Dat(1, fx.ary_("1", "2", "3"), fx.ary_("4", "5", "6")); + } + @Test public void IgnoreTrailingBlankRow() { + fx.run_parse_lines_ + ( "letters, ,\" \",#" + , "a,b,c" + , "" // ignored + ); + fx.tst_Tbls("letters"); + fx.tst_Dat(0, fx.ary_("a", "b", "c")); + } + @Test public void AllowCommentsDuringData() { + fx.run_parse_lines_ + ( "letters, ,\" \",#" + , "a,b,c" + , "// letters omitted, ,\" \",//" // these comments are not preserved + , "x,y,z" + ); + fx.tst_Tbls("letters"); + fx.tst_Dat(0, fx.ary_("a", "b", "c"), fx.ary_("x", "y", "z")); + } +} diff --git a/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_dsv_hdr_tst.java b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_dsv_hdr_tst.java new file mode 100644 index 000000000..3c16fe6de --- /dev/null +++ b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_dsv_hdr_tst.java @@ -0,0 +1,82 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.stores.dsvs; import gplx.*; import gplx.stores.*; +import org.junit.*; +public class DsvDataRdr_dsv_hdr_tst { + @Before public void setup() {fx.Clear();} DsvDataRdr_fxt fx = DsvDataRdr_fxt.new_(); + @Test public void Names() { + fx.run_parse_lines_ + ( "id,name, ,\" \",@" + , "0,me" + , "1,you" + ); + fx.tst_Flds(0, GfoFldList_.str_("id", "name")); + fx.tst_Tbls(DsvTblBldr.NullTblName); + fx.tst_Dat(0 + , fx.ary_("0", "me") + , fx.ary_("1", "you") + ); + } + @Test public void Types() { + fx.run_parse_lines_ + ( "int," + StringClassXtn.Key_const + ", ,\" \",$" + , "0,me" + , "1,you" + ); + fx.tst_Flds(0, GfoFldList_.new_().Add("fld0", IntClassXtn._).Add("fld1", StringClassXtn._)); + fx.tst_Dat(0 + , fx.ary_(0, "me") + , fx.ary_(1, "you") + ); + } + @Test public void NamesAndTypes() { + fx.run_parse_lines_ + ( "id,name, ,\" \",@" + , "int," + StringClassXtn.Key_const + ", ,\" \",$" + , "0,me" + , "1,you" + ); + fx.tst_Flds(0, GfoFldList_.new_().Add("id", IntClassXtn._).Add("name", StringClassXtn._)); + fx.tst_Dat(0 + , fx.ary_(0, "me") + , fx.ary_(1, "you") + ); + } + @Test public void MultipleTables_NoData() { + fx.run_parse_lines_ + ( "persons, ,\" \",#" + , "id,name, ,\" \",@" + , "things, ,\" \",#" + , "id,data, ,\" \",@" + ); + fx.tst_Tbls("persons", "things"); + fx.tst_Flds(0, GfoFldList_.str_("id", "name")); + fx.tst_Flds(1, GfoFldList_.str_("id", "data")); + fx.tst_Dat(0); + fx.tst_Dat(1); + } + @Test public void Comment() { + fx.run_parse_lines_ + ( "--------------------, ,\" \",//" + , "tbl0, ,\" \",#" + , "a0,a1" + ); + fx.tst_Tbls("tbl0"); + fx.tst_Dat(0, fx.ary_("a0", "a1")); + } +} diff --git a/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_dsv_misc_tst.java b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_dsv_misc_tst.java new file mode 100644 index 000000000..680827565 --- /dev/null +++ b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_dsv_misc_tst.java @@ -0,0 +1,76 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.stores.dsvs; import gplx.*; import gplx.stores.*; +import org.junit.*; +public class DsvDataRdr_dsv_misc_tst { + @Before public void setup() {fx.Clear();} DsvDataRdr_fxt fx = DsvDataRdr_fxt.new_(); + @Test public void CmdDlm_NearMatches() { + fx.run_parse_("a, ,b"); + fx.tst_DatCsv(fx.ary_("a", " ", "b")); + fx.Clear(); + + fx.run_parse_("a,\" \",b"); + fx.tst_DatCsv(fx.ary_("a", " ", "b")); + fx.Clear(); + + fx.run_parse_("a, ,b,\" \",c"); + fx.tst_DatCsv(fx.ary_("a", " ", "b", " ", "c")); + fx.Clear(); + } + @Test public void CmdDlm_DoNotSpanLines() { + fx.run_parse_lines_ + ( "a, " + , "\" \",b" + ); + fx.tst_DatCsv + ( fx.ary_("a", " ") + , fx.ary_(" ", "b") + ); + } + @Test public void CmdDlm_SecondFldMustBeQuoted() { + fx.run_parse_lines_("a, , ,b"); // will fail with "invalid command: b", if second , , is interpreted as command delimiter + fx.tst_DatCsv(fx.ary_("a", " ", " ", "b")); + } + @Test public void Null_Int() { + fx.run_parse_ // not using run_parse_lines_ b/c (a) will have extra lineBreak; (b) test will look funny; + ( "int," + StringClassXtn.Key_const + ", ,\" \",$", String_.CrLf + , ",val1" + ); + fx.tst_Tbls(DsvTblBldr.NullTblName); + fx.tst_Flds(0, GfoFldList_.new_().Add("fld0", IntClassXtn._).Add("fld1", StringClassXtn._)); + fx.tst_Dat(0, fx.ary_(null, "val1")); + } + @Test public void Null_String() { + fx.run_parse_ // not using run_parse_lines_ b/c (a) will have extra lineBreak; (b) test will look funny; + ( StringClassXtn.Key_const + "," + StringClassXtn.Key_const + ", ,\" \",$", String_.CrLf + , ",val1" + ); + fx.tst_Tbls(DsvTblBldr.NullTblName); + fx.tst_Flds(0, GfoFldList_.new_().Add("fld0", StringClassXtn._).Add("fld1", StringClassXtn._)); + fx.tst_Dat(0, fx.ary_(null, "val1")); + } + @Test public void EmptyString() { + fx.run_parse_ // not using run_parse_lines_ b/c (a) will have extra lineBreak; (b) test will look funny; + ( StringClassXtn.Key_const + "," + StringClassXtn.Key_const + ", ,\" \",$", String_.CrLf + , "\"\",val1" + ); + fx.tst_Tbls(DsvTblBldr.NullTblName); + fx.tst_Flds(0, GfoFldList_.new_().Add("fld0", StringClassXtn._).Add("fld1", StringClassXtn._)); + fx.tst_Dat(0, fx.ary_("", "val1")); + } +} diff --git a/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_layout_tst.java b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_layout_tst.java new file mode 100644 index 000000000..5c2592e0a --- /dev/null +++ b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataRdr_layout_tst.java @@ -0,0 +1,131 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.stores.dsvs; import gplx.*; import gplx.stores.*; +import org.junit.*; +public class DsvDataRdr_layout_tst { + @Test public void TableName() { + run_parse_lines("table0, ,\" \",#"); + tst_Layout(0, DsvHeaderItm.Id_TableName); + } + @Test public void Comment() { + run_parse_lines("-------------, ,\" \",//", "data"); // need dataLine or parser will throw away standalone header + tst_Layout(0, DsvHeaderItm.Id_Comment); + } + @Test public void BlankLine() { + run_parse_lines("", "data"); // need dataLine or parser will throw away standalone header + tst_Layout(0, DsvHeaderItm.Id_BlankLine); + } + @Test public void LeafNames() { + run_parse_lines("id,name, ,\" \",@"); + tst_Layout(0, DsvHeaderItm.Id_LeafNames); + } + @Test public void LeafTypes() { + run_parse_lines("int," + StringClassXtn.Key_const + ", ,\" \",$"); + tst_Layout(0, DsvHeaderItm.Id_LeafTypes); + } + @Test public void Combined() { + run_parse_lines + ( "" + , "-------------, ,\" \",//" + , "table0, ,\" \",#" + , "int," + StringClassXtn.Key_const + ", ,\" \",$" + , "id,name, ,\" \",@" + , "-------------, ,\" \",//" + , "0,me" + ); + tst_Layout(0 + , DsvHeaderItm.Id_BlankLine + , DsvHeaderItm.Id_Comment + , DsvHeaderItm.Id_TableName + , DsvHeaderItm.Id_LeafTypes + , DsvHeaderItm.Id_LeafNames + , DsvHeaderItm.Id_Comment + ); + } + @Test public void Tbl_N() { + run_parse_lines + ( "" + , "*************, ,\" \",//" + , "table0, ,\" \",#" + , "-------------, ,\" \",//" + , "0,me" + , "" + , "*************, ,\" \",//" + , "table1, ,\" \",#" + , " extended data, ,\" \",//" + , "-------------, ,\" \",//" + , "1,you,more" + ); + tst_Layout(0 + , DsvHeaderItm.Id_BlankLine + , DsvHeaderItm.Id_Comment + , DsvHeaderItm.Id_TableName + , DsvHeaderItm.Id_Comment + ); + tst_Layout(1 + , DsvHeaderItm.Id_BlankLine + , DsvHeaderItm.Id_Comment + , DsvHeaderItm.Id_TableName + , DsvHeaderItm.Id_Comment + , DsvHeaderItm.Id_Comment + ); + } + @Test public void Tbl_N_FirstIsEmpty() { + run_parse_lines + ( "" + , "*************, ,\" \",//" + , "table0, ,\" \",#" + , "-------------, ,\" \",//" + , "" + , "" + , "*************, ,\" \",//" + , "table1, ,\" \",#" + , " extended data, ,\" \",//" + , "-------------, ,\" \",//" + , "1,you,more" + ); + tst_Layout(0 + , DsvHeaderItm.Id_BlankLine + , DsvHeaderItm.Id_Comment + , DsvHeaderItm.Id_TableName + , DsvHeaderItm.Id_Comment + ); + tst_Layout(1 + , DsvHeaderItm.Id_BlankLine + , DsvHeaderItm.Id_BlankLine + , DsvHeaderItm.Id_Comment + , DsvHeaderItm.Id_TableName + , DsvHeaderItm.Id_Comment + , DsvHeaderItm.Id_Comment + ); + } + void run_parse_lines(String... ary) { + String raw = String_.Concat_lines_crlf(ary); + DsvParser parser = DsvParser.dsv_(); + root = parser.ParseAsNde(raw); + } + void tst_Layout(int subIdx, int... expd) { + GfoNde tbl = root.Subs().FetchAt_asGfoNde(subIdx); + DsvStoreLayout layout = (DsvStoreLayout)tbl.EnvVars().Get_by(DsvStoreLayout.Key_const); + int[] actl = new int[layout.HeaderList().Count()]; + for (int i = 0; i < actl.length; i++) + actl[i] = layout.HeaderList().Get_at(i).Id(); + Tfds.Eq_ary(expd, actl); + } + GfoNde root; +} diff --git a/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataWtr.java b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataWtr.java new file mode 100644 index 000000000..7e3fc3cb1 --- /dev/null +++ b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataWtr.java @@ -0,0 +1,115 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.stores.dsvs; import gplx.*; import gplx.stores.*; +import gplx.core.strings.*; +public class DsvDataWtr extends DataWtr_base implements DataWtr { + public void InitWtr(String key, Object val) { + if (key == DsvStoreLayout.Key_const) layout = (DsvStoreLayout)val; + } + @Override public void WriteData(String name, Object val) {sb.WriteFld(val == null ? null : val.toString());} + public void WriteLeafBgn(String leafName) {} + public void WriteLeafEnd() {sb.WriteRowSep();} + @Override public void WriteNodeBgn(String name) {WriteTableBgn(name, GfoFldList_.Null);} + public void WriteTableBgn(String name, GfoFldList flds) { + for (int i = 0; i < layout.HeaderList().Count(); i++) { + DsvHeaderItm data = layout.HeaderList().Get_at(i); + int id = data.Id(); + if (id == DsvHeaderItm.Id_TableName) WriteTableName(name); + else if (id == DsvHeaderItm.Id_LeafNames) WriteMeta(flds, true, sym.FldNamesSym()); + else if (id == DsvHeaderItm.Id_LeafTypes) WriteMeta(flds, false, sym.FldTypesSym()); + else if (id == DsvHeaderItm.Id_BlankLine) sb.WriteRowSep(); + else if (id == DsvHeaderItm.Id_Comment) WriteComment(data.Val().toString()); + } + } + @Override public void WriteNodeEnd() {} + public void Clear() {sb.Clear();} + public String XtoStr() {return sb.XtoStr();} + void WriteTableName(String tableName) { + sb.WriteFld(tableName); + sb.WriteCmd(sym.TblNameSym()); + sb.WriteRowSep(); + } + void WriteMeta(GfoFldList flds, boolean isName, String cmd) { + for (int i = 0; i < flds.Count(); i++) { + GfoFld fld = flds.Get_at(i); + String val = isName ? fld.Key(): fld.Type().Key(); + sb.WriteFld(val); + } + if (layout.WriteCmdSequence()) sb.WriteCmd(cmd); + sb.WriteRowSep(); + } + void WriteComment(String comment) { + sb.WriteFld(comment); + sb.WriteCmd(sym.CommentSym()); + sb.WriteRowSep(); + } + @Override public SrlMgr SrlMgr_new(Object o) {return new DsvDataWtr();} + DsvStringBldr sb; DsvSymbols sym = DsvSymbols.default_(); DsvStoreLayout layout = DsvStoreLayout.csv_dat_(); + @gplx.Internal protected DsvDataWtr() {sb = DsvStringBldr.new_(sym);} +} +class DsvStringBldr { + public void Clear() {sb.Clear();} + public String XtoStr() {return sb.XtoStr();} + public void WriteCmd(String cmd) { + WriteFld(sym.CmdSequence(), true); + WriteFld(cmd); + } + public void WriteFldSep() {sb.Add(sym.FldSep());} + public void WriteRowSep() { + sb.Add(sym.RowSep()); + isNewRow = true; + } + public void WriteFld(String val) {WriteFld(val, false);} + void WriteFld(String val, boolean writeRaw) { + if (isNewRow) // if isNewRow, then fld is first, and no fldSpr needed (RowSep serves as fldSpr) + isNewRow = false; + else + sb.Add(sym.FldSep()); + + if (val == null) {} // null -> append nothing + else if (String_.Eq(val, String_.Empty))// "" -> append "" + sb.Add("\"\""); + else if (writeRaw) // only cmds should be writeRaw (will append ," ") + sb.Add(val); + else { // escape as necessary; ex: "the quote "" char"; "the comma , char" + boolean quoteField = false; + if (String_.Has(val, sym.QteDlm())) { + val = String_.Replace(val, "\"", "\"\""); + quoteField = true; + } + else if (String_.Has(val, sym.FldSep())) + quoteField = true; + else if (sym.RowSepIsNewLine() + && (String_.Has(val, "\n") || String_.Has(val, "\r"))) + quoteField = true; + else if (String_.Has(val, sym.RowSep())) + quoteField = true; + + if (quoteField) sb.Add(sym.QteDlm()); + sb.Add(val); + if (quoteField) sb.Add(sym.QteDlm()); + } + } + + String_bldr sb = String_bldr_.new_(); DsvSymbols sym; boolean isNewRow = true; + public static DsvStringBldr new_(DsvSymbols sym) { + DsvStringBldr rv = new DsvStringBldr(); + rv.sym = sym; + return rv; + } DsvStringBldr() {} +} diff --git a/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataWtr_.java b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataWtr_.java new file mode 100644 index 000000000..f13b4b8f3 --- /dev/null +++ b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataWtr_.java @@ -0,0 +1,31 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.stores.dsvs; import gplx.*; import gplx.stores.*; +public class DsvDataWtr_ { + public static DsvDataWtr csv_hdr_() { + DsvDataWtr rv = new DsvDataWtr(); + rv.InitWtr(DsvStoreLayout.Key_const, DsvStoreLayout.csv_hdr_()); + return rv; + } + public static DsvDataWtr csv_dat_() { + DsvDataWtr rv = new DsvDataWtr(); + rv.InitWtr(DsvStoreLayout.Key_const, DsvStoreLayout.csv_dat_()); + return rv; + } + public static DsvDataWtr new_() {return new DsvDataWtr();} +} diff --git a/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataWtr_csv_tst.java b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataWtr_csv_tst.java new file mode 100644 index 000000000..1954777e6 --- /dev/null +++ b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataWtr_csv_tst.java @@ -0,0 +1,100 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.stores.dsvs; import gplx.*; import gplx.stores.*; +import org.junit.*; +public class DsvDataWtr_csv_tst { + @Test public void Dat_Val_0() { + root = fx_nde.csv_dat_(); this.AddCsvRow(root); + expd = String_.Concat_lines_crlf(""); + fx.tst_XtoStr(wtr, root, expd); + } + @Test public void Dat_Val_1() { + root = fx_nde.csv_dat_(); this.AddCsvRow(root, "a"); + expd = String_.Concat_lines_crlf("a"); + fx.tst_XtoStr(wtr, root, expd); + } + @Test public void Dat_Val_N() { + root = fx_nde.csv_dat_(); this.AddCsvRow(root, "a", "b", "c"); + expd = String_.Concat_lines_crlf("a,b,c"); + fx.tst_XtoStr(wtr, root, expd); + } + @Test public void Dat_Row_N() { + root = fx_nde.csv_dat_(); + this.AddCsvRow(root, "a", "b", "c"); + this.AddCsvRow(root, "d", "e", "f"); + expd = String_.Concat_lines_crlf + ( "a,b,c" + , "d,e,f" + ); + fx.tst_XtoStr(wtr, root, expd); + } + @Test public void Dat_Escape_FldSpr() { // , + root = fx_nde.csv_dat_(); this.AddCsvRow(root, "a", ",", "c"); + expd = String_.Concat_lines_crlf("a,\",\",c"); + fx.tst_XtoStr(wtr, root, expd); + } + @Test public void Dat_Escape_RcdSpr() { // NewLine + root = fx_nde.csv_dat_(); this.AddCsvRow(root, "a", String_.CrLf, "c"); + expd = String_.Concat_lines_crlf("a,\"" + String_.CrLf + "\",c"); + fx.tst_XtoStr(wtr, root, expd); + } + @Test public void Dat_Escape_Quote() { // " -> "" + root = fx_nde.csv_dat_(); this.AddCsvRow(root, "a", "\"", "c"); + expd = String_.Concat_lines_crlf("a,\"\"\"\",c"); + fx.tst_XtoStr(wtr, root, expd); + } + @Test public void Dat_Whitespace() { + root = fx_nde.csv_dat_(); this.AddCsvRow(root, "a", " b\t", "c"); + expd = String_.Concat_lines_crlf("a, b\t,c"); + fx.tst_XtoStr(wtr, root, expd); + } + @Test public void Dat_Null() { + root = fx_nde.csv_dat_(); this.AddCsvRow(root, "a", null, "c"); + expd = String_.Concat_lines_crlf("a,,c"); + fx.tst_XtoStr(wtr, root, expd); + } + @Test public void Dat_EmptyString() { + root = fx_nde.csv_dat_(); this.AddCsvRow(root, "a", "", "c"); + expd = String_.Concat_lines_crlf("a,\"\",c"); + fx.tst_XtoStr(wtr, root, expd); + } + @Test public void Hdr_Flds() { + wtr = DsvDataWtr_.csv_hdr_(); + GfoFldList flds = GfoFldList_.new_().Add("id", StringClassXtn._).Add("name", StringClassXtn._); + root = fx_nde.csv_hdr_(flds); this.AddCsvRow(root, "0", "me"); + expd = String_.Concat_lines_crlf + ( "id,name" + , "0,me" + ); + fx.tst_XtoStr(wtr, root, expd); + } + void AddCsvRow(GfoNde root, String... ary) { + GfoNde sub = GfoNde_.vals_(root.SubFlds(), ary); + root.Subs().Add(sub); + } + GfoNde root; String expd; DsvDataWtr wtr = DsvDataWtr_.csv_dat_(); DsvDataWtr_fxt fx = DsvDataWtr_fxt.new_(); GfoNdeFxt fx_nde = GfoNdeFxt.new_(); +} +class DsvDataWtr_fxt { + public void tst_XtoStr(DsvDataWtr wtr, GfoNde root, String expd) { + wtr.Clear(); + root.XtoStr_wtr(wtr); + String actl = wtr.XtoStr(); + Tfds.Eq(expd, actl); + } + public static DsvDataWtr_fxt new_() {return new DsvDataWtr_fxt();} DsvDataWtr_fxt() {} +} diff --git a/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataWtr_tbls_tst.java b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataWtr_tbls_tst.java new file mode 100644 index 000000000..981de747a --- /dev/null +++ b/100_core/src_340_dsv/gplx/stores/dsvs/DsvDataWtr_tbls_tst.java @@ -0,0 +1,73 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.stores.dsvs; import gplx.*; import gplx.stores.*; +import org.junit.*; +public class DsvDataWtr_tbls_tst { + @Before public void setup() { + DsvStoreLayout layout = DsvStoreLayout.dsv_brief_(); + layout.HeaderList().Add_TableName(); + wtr.InitWtr(DsvStoreLayout.Key_const, layout); + } + @Test public void Rows_0() { + root = fx_nde.tbl_("tbl0"); + expd = String_.Concat_lines_crlf( "tbl0, ,\" \",#"); + fx.tst_XtoStr(wtr, root, expd); + } + @Test public void Rows_N() { + root = fx_nde.tbl_ + ( "numbers" + , fx_nde.row_vals_(1, 2, 3) + , fx_nde.row_vals_(4, 5, 6) + ); + expd = String_.Concat_lines_crlf + ( "numbers, ,\" \",#" + , "1,2,3" + , "4,5,6" + ); + fx.tst_XtoStr(wtr, root, expd); + } + @Test public void Tbls_N_Empty() { + root = fx_nde.root_ + ( fx_nde.tbl_("tbl0") + , fx_nde.tbl_("tbl1") + ); + expd = String_.Concat_lines_crlf + ( "tbl0, ,\" \",#" + , "tbl1, ,\" \",#" + ); + fx.tst_XtoStr(wtr, root, expd); + } + @Test public void Tbls_N() { + root = fx_nde.root_ + ( fx_nde.tbl_("letters" + , fx_nde.row_vals_("a", "b", "c")) + , fx_nde.tbl_("numbers" + , fx_nde.row_vals_(1, 2, 3) + , fx_nde.row_vals_(4, 5, 6) + )); + expd = String_.Concat_lines_crlf + ( "letters, ,\" \",#" + , "a,b,c" + , "numbers, ,\" \",#" + , "1,2,3" + , "4,5,6" + ); + fx.tst_XtoStr(wtr, root, expd); + } + GfoNde root; String expd; DsvDataWtr wtr = DsvDataWtr_.csv_dat_(); DsvDataWtr_fxt fx = DsvDataWtr_fxt.new_(); GfoNdeFxt fx_nde = GfoNdeFxt.new_(); +} diff --git a/100_core/src_340_dsv/gplx/stores/dsvs/DsvHeaderList.java b/100_core/src_340_dsv/gplx/stores/dsvs/DsvHeaderList.java new file mode 100644 index 000000000..0a87283a4 --- /dev/null +++ b/100_core/src_340_dsv/gplx/stores/dsvs/DsvHeaderList.java @@ -0,0 +1,44 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.stores.dsvs; import gplx.*; import gplx.stores.*; +public class DsvHeaderList { + @gplx.Internal protected int Count() {return list.Count();} + @gplx.Internal protected DsvHeaderItm Get_at(int i) {return (DsvHeaderItm)list.Get_at(i);} + public DsvHeaderList Add_LeafTypes() {this.Add(new DsvHeaderItm(DsvHeaderItm.Id_LeafTypes, null)); return this;} + public DsvHeaderList Add_LeafNames() {this.Add(new DsvHeaderItm(DsvHeaderItm.Id_LeafNames, null)); return this;} + public DsvHeaderList Add_TableName() {this.Add(new DsvHeaderItm(DsvHeaderItm.Id_TableName, null)); return this;} + public DsvHeaderList Add_BlankLine() {this.Add(new DsvHeaderItm(DsvHeaderItm.Id_BlankLine, null)); return this;} + public DsvHeaderList Add_Comment(String comment) {this.Add(new DsvHeaderItm(DsvHeaderItm.Id_Comment, comment)); return this;} + void Add(DsvHeaderItm data) {list.Add(data);} + + List_adp list = List_adp_.new_(); + public static DsvHeaderList new_() {return new DsvHeaderList();} DsvHeaderList() {} +} +class DsvHeaderItm { + public int Id() {return id;} int id; + public Object Val() {return val;} Object val; + @gplx.Internal protected DsvHeaderItm(int id, Object val) {this.id = id; this.val = val;} + + public static final int + Id_Comment = 1 + , Id_TableName = 2 + , Id_BlankLine = 3 + , Id_LeafTypes = 4 + , Id_LeafNames = 5 + ; +} diff --git a/100_core/src_340_dsv/gplx/stores/dsvs/DsvStoreLayout.java b/100_core/src_340_dsv/gplx/stores/dsvs/DsvStoreLayout.java new file mode 100644 index 000000000..d03cc8518 --- /dev/null +++ b/100_core/src_340_dsv/gplx/stores/dsvs/DsvStoreLayout.java @@ -0,0 +1,51 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.stores.dsvs; import gplx.*; import gplx.stores.*; +public class DsvStoreLayout { + public DsvHeaderList HeaderList() {return headerList;} DsvHeaderList headerList = DsvHeaderList.new_(); + @gplx.Internal protected boolean WriteCmdSequence() {return writeCmdSequence;} @gplx.Internal protected DsvStoreLayout WriteCmdSequence_(boolean val) {writeCmdSequence = val; return this;} private boolean writeCmdSequence; + + static DsvStoreLayout new_() {return new DsvStoreLayout();} + public static DsvStoreLayout csv_dat_() {return new_();} + public static DsvStoreLayout csv_hdr_() { + DsvStoreLayout rv = new_(); + rv.HeaderList().Add_LeafNames(); + return rv; + } + public static DsvStoreLayout dsv_brief_() { + DsvStoreLayout rv = new_(); + rv.writeCmdSequence = true; + return rv; + } + public static DsvStoreLayout dsv_full_() { + DsvStoreLayout rv = DsvStoreLayout.new_(); + rv.writeCmdSequence = true; + rv.HeaderList().Add_BlankLine(); + rv.HeaderList().Add_BlankLine(); + rv.HeaderList().Add_Comment("================================"); + rv.HeaderList().Add_TableName(); + rv.HeaderList().Add_Comment("================================"); + rv.HeaderList().Add_LeafTypes(); + rv.HeaderList().Add_LeafNames(); + rv.HeaderList().Add_Comment("================================"); + return rv; + } + public static DsvStoreLayout as_(Object obj) {return obj instanceof DsvStoreLayout ? (DsvStoreLayout)obj : null;} + public static DsvStoreLayout cast_(Object obj) {try {return (DsvStoreLayout)obj;} catch(Exception exc) {throw Exc_.new_type_mismatch_w_exc(exc, DsvStoreLayout.class, obj);}} + public static final String Key_const = "StoreLayoutWtr"; +} diff --git a/100_core/src_340_dsv/gplx/stores/dsvs/DsvSymbols.java b/100_core/src_340_dsv/gplx/stores/dsvs/DsvSymbols.java new file mode 100644 index 000000000..2e2e5f9ed --- /dev/null +++ b/100_core/src_340_dsv/gplx/stores/dsvs/DsvSymbols.java @@ -0,0 +1,52 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.stores.dsvs; import gplx.*; import gplx.stores.*; +class DsvSymbols { + public String FldSep() {return fldSep;} public DsvSymbols FldSep_(String v) {fldSep = v; CmdSequence_set(); return this;} private String fldSep; + public String RowSep() {return rowSep;} + public DsvSymbols RowSep_(String v) { + rowSep = v; + rowSepIsNewLine = String_.Has(v, "\n") || String_.Has(v, "\r"); + return this; + } String rowSep; + public String QteDlm() {return qteDlm;} public void QteDlm_set(String v) {qteDlm = v; CmdSequence_set();} private String qteDlm; + public String CmdDlm() {return cmdDlm;} public void CmdDlm_set(String v) {cmdDlm = v; CmdSequence_set();} private String cmdDlm; + public String CmdSequence() {return cmdSequence;} private String cmdSequence; + public String CommentSym() {return commentSym;} public void CommentSym_set(String v) {commentSym = v;} private String commentSym; + public String TblNameSym() {return tblNameSym;} public void TblNamesSym_set(String v) {tblNameSym = v;} private String tblNameSym; + public String FldNamesSym() {return fldNamesSym;} public void FldNamesSym_set(String v) {fldNamesSym = v;} private String fldNamesSym; + public String FldTypesSym() {return fldTypesSym;} public void FldTypesSym_set(String v) {fldTypesSym = v;} private String fldTypesSym; + public boolean RowSepIsNewLine() {return rowSepIsNewLine;} private boolean rowSepIsNewLine; + public void Reset() { + fldSep = ","; + RowSep_ ("\r\n"); + + qteDlm = "\""; + cmdDlm = " "; + CmdSequence_set(); + + commentSym = "//"; + tblNameSym = "#"; + fldNamesSym = "@"; + fldTypesSym = "$"; + } + void CmdSequence_set() { // commandDelimiters are repeated; once without quotes and once with quotes; ex: , ," ", + cmdSequence = String_.Concat(cmdDlm, fldSep, qteDlm, cmdDlm, qteDlm); + } + public static DsvSymbols default_() {return new DsvSymbols();} DsvSymbols() {this.Reset();} +} diff --git a/100_core/src_400_gfs/gplx/GfsCore.java b/100_core/src_400_gfs/gplx/GfsCore.java new file mode 100644 index 000000000..a4ea2a2b7 --- /dev/null +++ b/100_core/src_400_gfs/gplx/GfsCore.java @@ -0,0 +1,167 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class GfsCore implements GfoInvkAble { + public GfoInvkAble Root() {return root;} + @gplx.Internal protected GfsRegy Root_as_regy() {return root;} GfsRegy root = GfsRegy.new_(); + public void Clear() {root.Clear();} + public GfoMsgParser MsgParser() {return msgParser;} public GfsCore MsgParser_(GfoMsgParser v) {msgParser = v; return this;} GfoMsgParser msgParser; + public void Del(String key) {root.Del(key);} + public void AddLib(GfsLibIni... ary) {for (GfsLibIni itm : ary) itm.Ini(this);} + public void AddCmd(GfoInvkAble invk, String key) {root.AddCmd(invk, key);} + public void AddObj(GfoInvkAble invk, String key) {root.AddObj(invk, key);} + public void AddDeep(GfoInvkAble invk, String... ary) { + GfoInvkCmdMgrOwner cur = (GfoInvkCmdMgrOwner)((GfsRegyItm)root.Get_by(ary[0])).InvkAble(); + for (int i = 1; i < ary.length - 1; i++) + cur = (GfoInvkCmdMgrOwner)cur.InvkMgr().Invk(GfsCtx._, 0, ary[i], GfoMsg_.Null, cur); + cur.InvkMgr().Add_cmd(ary[ary.length - 1], invk); + } + public String FetchKey(GfoInvkAble invk) {return root.FetchByType(invk).Key();} + public Object ExecOne(GfsCtx ctx, GfoMsg msg) {return GfsCore_.Exec(ctx, root, msg, null, 0);} + public Object ExecOne_to(GfsCtx ctx, GfoInvkAble invk, GfoMsg msg) {return GfsCore_.Exec(ctx, invk, msg, null, 0);} + public Object ExecMany(GfsCtx ctx, GfoMsg rootMsg) { + Object rv = null; + for (int i = 0; i < rootMsg.Subs_count(); i++) { + GfoMsg subMsg = (GfoMsg)rootMsg.Subs_getAt(i); + rv = GfsCore_.Exec(ctx, root, subMsg, null, 0); + } + return rv; + } + public void ExecRegy(String key) { + GfoRegyItm itm = GfoRegy._.FetchOrNull(key); + if (itm == null) {UsrDlg_._.Warn(UsrMsg.new_("could not find script for key").Add("key", key)); return;} + Io_url url = itm.Url(); + if (!Io_mgr.I.ExistsFil(url)) { + UsrDlg_._.Warn(UsrMsg.new_("script url does not exist").Add("key", key).Add("url", url)); + return; + } + this.ExecText(Io_mgr.I.LoadFilStr(url)); + } + public Object ExecFile_ignoreMissing(Io_url url) {if (!Io_mgr.I.ExistsFil(url)) return null; return ExecText(Io_mgr.I.LoadFilStr(url));} + public Object ExecFile(Io_url url) {return ExecText(Io_mgr.I.LoadFilStr(url));} + public Object ExecFile_ignoreMissing(GfoInvkAble root, Io_url url) { + if (!Io_mgr.I.ExistsFil(url)) return null; + if (msgParser == null) throw Exc_.new_("msgParser is null"); + return Exec_bry(Io_mgr.I.LoadFilBry(url), root); + } + public Object Exec_bry(byte[] bry) {return Exec_bry(bry, root);} + public Object Exec_bry(byte[] bry, GfoInvkAble root) { + GfoMsg rootMsg = msgParser.ParseToMsg(String_.new_u8(bry)); + Object rv = null; + GfsCtx ctx = GfsCtx.new_(); + for (int i = 0; i < rootMsg.Subs_count(); i++) { + GfoMsg subMsg = (GfoMsg)rootMsg.Subs_getAt(i); + rv = GfsCore_.Exec(ctx, root, subMsg, null, 0); + } + return rv; + } + public Object ExecText(String text) { + if (msgParser == null) throw Exc_.new_("msgParser is null"); + GfsCtx ctx = GfsCtx.new_(); + return ExecMany(ctx, msgParser.ParseToMsg(text)); + } + public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) { + if (ctx.Match(k, Invk_ExecFil)) { + Io_url url = m.ReadIoUrl("url"); + if (ctx.Deny()) return this; + return ExecFile(url); + } + else return GfoInvkAble_.Rv_unhandled; +// return this; + } public static final String Invk_ExecFil = "ExecFil"; + public static final GfsCore _ = new GfsCore(); + @gplx.Internal protected static GfsCore new_() {return new GfsCore();} +} +class GfsCore_ { + public static final String Arg_primitive = "v"; + public static Object Exec(GfsCtx ctx, GfoInvkAble owner_invk, GfoMsg owner_msg, Object owner_primitive, int depth) { + if (owner_msg.Args_count() == 0 && owner_msg.Subs_count() == 0 && String_.Eq(owner_msg.Key(), "")) {UsrDlg_._.Warn("empty msg"); return GfoInvkAble_.Rv_unhandled;} + if (owner_primitive != null) owner_msg.Parse_(false).Add(GfsCore_.Arg_primitive, owner_primitive); + Object rv = owner_invk.Invk(ctx, 0, owner_msg.Key(), owner_msg); + if (rv == GfoInvkAble_.Rv_cancel) return rv; + else if (rv == GfoInvkAble_.Rv_unhandled) { + if (ctx.Fail_if_unhandled()) + throw Exc_.new_("Object does not support key", "key", owner_msg.Key(), "ownerType", ClassAdp_.FullNameOf_obj(owner_invk)); + else { + Gfo_usr_dlg usr_dlg = ctx.Usr_dlg(); + if (usr_dlg != null) usr_dlg.Warn_many(GRP_KEY, "unhandled_key", "Object does not support key: key=~{0} ownerType=~{1}", owner_msg.Key(), ClassAdp_.FullNameOf_obj(owner_invk)); + return GfoInvkAble_.Null; + } + } + if (owner_msg.Subs_count() == 0) { // msg is leaf + GfsRegyItm regyItm = GfsRegyItm.as_(rv); + if (regyItm == null) return rv; // rv is primitive or other non-regy Object + if (regyItm.IsCmd()) // rv is cmd; invk cmd + return regyItm.InvkAble().Invk(ctx, 0, owner_msg.Key(), owner_msg); + else // rv is host + return regyItm.InvkAble(); + } + else { // intermediate; cast to invk and call Exec + GfoInvkAble invk = GfoInvkAble_.as_(rv); + Object primitive = null; + if (invk == null) { // rv is primitive; find appropriate mgr + Class type = rv.getClass(); + if (type == String.class) invk = String_.Gfs; + else if (Int_.TypeMatch(type)) invk = Int_.Gfs; + else if (ClassAdp_.Eq(type, Bool_.Cls_ref_type)) invk = Bool_.Gfs; + else throw Exc_.new_("unknown primitive", "type", ClassAdp_.NameOf_type(type), "obj", Object_.Xto_str_strict_or_null_mark(rv)); + primitive = rv; + } + Object exec_rv = null; + int len = owner_msg.Subs_count(); + for (int i = 0; i < len; i++) // iterate over subs; needed for a{b;c;d;} + exec_rv = Exec(ctx, invk, owner_msg.Subs_getAt(i), primitive, depth + 1); + return exec_rv; + } + } + static final String GRP_KEY = "gplx.gfs_core"; +} +// class GfsRegyMgr : GfoInvkAble { +// public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) { +// if (ctx.Match(k, Invk_Add)) { +// String libKey = m.ReadStr("libKey"), regKey = m.ReadStr("regKey"); +// if (ctx.Deny()) return this; +// GfsRegyItm itm = regy.Get_by(libKey); +// if (regy.Has(regKey)) {ctx.Write_warn("'{0}' already exists", regKey); return this;} +// regy.Add(regKey, itm.InvkAble(), itm.Type_cmd()); +// ctx.Write_note("added '{0}' as '{1}'", regKey, libKey); +// } +// else if (ctx.Match(k, Invk_Del)) { +// String regKey = m.ReadStr("regKey"); +// if (ctx.Deny()) return this; +// if (!regy.Has(regKey)) {ctx.Write_warn("{0} does not exist", regKey); return this;} +// regy.Del(regKey); +// ctx.Write_note("removed '{0}'", regKey); +// } +// else if (ctx.Match(k, Invk_Load)) { +// Io_url url = (Io_url)m.ReadObj("url", Io_url_.Parser); +// if (ctx.Deny()) return this; +// String loadText = Io_mgr.I.LoadFilStr(url); +// GfoMsg loadMsg = core.MsgParser().ParseToMsg(loadText); +// return core.Exec(ctx, loadMsg); +// } +// else return GfoInvkAble_.Rv_unhandled; +// return this; +// } public static final String Invk_Add = "Add", Invk_Del = "Del", Invk_Load = "Load"; +// GfsCore core; GfsRegy regy; +// public static GfsRegyMgr new_(GfsCore core, GfsRegy regy) { +// GfsRegyMgr rv = new GfsRegyMgr(); +// rv.core = core; rv.regy = regy; +// return rv; +// } GfsRegyMgr() {} +// } diff --git a/100_core/src_400_gfs/gplx/GfsCoreHelp.java b/100_core/src_400_gfs/gplx/GfsCoreHelp.java new file mode 100644 index 000000000..daebbe855 --- /dev/null +++ b/100_core/src_400_gfs/gplx/GfsCoreHelp.java @@ -0,0 +1,73 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.core.strings.*; +class GfsCoreHelp implements GfoInvkAble { + public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) { + String path = m.ReadStrOr("path", ""); + if (String_.Eq(path, "")) { + String_bldr sb = String_bldr_.new_(); + for (int i = 0; i < core.Root_as_regy().Count(); i++) { + GfsRegyItm itm = (GfsRegyItm)core.Root_as_regy().Get_at(i); + sb.Add_spr_unless_first(itm.Key(), String_.CrLf, i); + } + return sb.XtoStr(); + } + else return Exec(ctx, core.Root_as_regy(), path); + } + public static Exc Err_Unhandled(String objPath, String key) {return Exc_.new_("obj does not handle msgKey", "objPath", objPath, "key", key).Stack_erase_1_();} + static Exc Err_Unhandled(String[] itmAry, int i) { + String_bldr sb = String_bldr_.new_(); + for (int j = 0; j < i; j++) + sb.Add_spr_unless_first(itmAry[j], ".", j); + return Err_Unhandled(sb.XtoStr(), itmAry[i]); + } + static Object Exec(GfsCtx rootCtx, GfoInvkAble rootInvk, String path) { + String[] itmAry = String_.Split(path, "."); + GfoInvkAble invk = rootInvk; + GfsCtx ctx = GfsCtx.new_(); + Object curRv = null; + for (int i = 0; i < itmAry.length; i++) { + String itm = itmAry[i]; + curRv = invk.Invk(ctx, 0, itm, GfoMsg_.Null); + if (curRv == GfoInvkAble_.Rv_unhandled) throw Err_Unhandled(itmAry, i); + invk = GfoInvkAble_.as_(curRv); + } + GfsCoreHelp helpData = GfsCoreHelp.as_(curRv); + if (helpData != null) { // last itm is actually Method + return ""; + } + else { + ctx = GfsCtx.new_().Help_browseMode_(true); + invk.Invk(ctx, 0, "", GfoMsg_.Null); + String_bldr sb = String_bldr_.new_(); + for (int i = 0; i < ctx.Help_browseList().Count(); i++) { + String s = (String)ctx.Help_browseList().Get_at(i); + sb.Add_spr_unless_first(s, String_.CrLf, i); + } + return sb.XtoStr(); + } + } + public static GfsCoreHelp as_(Object obj) {return obj instanceof GfsCoreHelp ? (GfsCoreHelp)obj : null;} + public static GfsCoreHelp new_(GfsCore core) { + GfsCoreHelp rv = new GfsCoreHelp(); + rv.core = core; + return rv; + } GfsCoreHelp() {} + GfsCore core; +} diff --git a/100_core/src_400_gfs/gplx/GfsCore_tst.java b/100_core/src_400_gfs/gplx/GfsCore_tst.java new file mode 100644 index 000000000..d0bf0ccb0 --- /dev/null +++ b/100_core/src_400_gfs/gplx/GfsCore_tst.java @@ -0,0 +1,113 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class GfsCore_tst { + @Before public void setup() { + core = GfsCore.new_(); + core.AddObj(String_.Gfs, "String_"); + core.AddObj(Int_.Gfs, "Int_"); + } GfsCore core; + @Test public void Basic() { // String_.Len('abc') >> 3 + tst_Msg + ( msg_("String_").Subs_ + ( msg_("Len").Add("v", "abc")) + , 3); + } + @Test public void PrimitiveConversion() { // String_.Len('abc').Add(-3) >> 0 + tst_Msg + ( msg_("String_").Subs_ + ( msg_("Len").Add("v", "abc").Subs_ + ( msg_("Add").Add("operand", -3)) + ) + , 0); + } +// @Test public void Fail_notFound() { // String_.DoesNotExists +// tst_Err +// ( msg_("help").Add("", "String_.DoesNotExist") +// , GfsHelp.Err_Unhandled("String_", "DoesNotExist")); +// } + @Test public void Cmd() { // cmd + core.AddCmd(new GfsTest_cmd(), "testCmd"); + tst_Msg + ( msg_("testCmd").Add("s", "pass") + , "pass"); + } + @Test public void EmptyMsg() { + tst_Msg + ( msg_("") + , GfoInvkAble_.Rv_unhandled); + } +// @Test public void Fail_argMissing() { // String_.Len() +// tst_String__Len_Err(msg_("Len"), GfsCtx.Err_KeyNotFound("v", "<>")); +// } +// @Test public void Fail_argWrongKey() { // String_.Len(badKey='abc') +// tst_String__Len_Err(msg_("Len").Add("badKey", "abc"), GfsCtx.Err_KeyNotFound("v", "badKey;")); +// } +// @Test public void Fail_argExtraKey() { // String_.Len(v='abc' extraKey=1) +// tst_String__Len_Err(msg_("Len").Add("v", "abc").Add("extraKey", 1), GfsCtx.Err_KeyNotFound("v", "badKey;")); +// } + @Test public void Add_obj_deep() { // String_.Len(badKey='abc') + GfsCore_tst_nest obj1 = GfsCore_tst_nest.new_("1", "val1"); + GfsCore_tst_nest obj1_1 = GfsCore_tst_nest.new_("1_1", "val2"); + core.AddObj(obj1, "1"); + core.AddDeep(obj1_1, "1", "1_1"); + + GfoMsg root = GfoMsg_.root_("1", "1_1", GfsCore_tst_nest.Prop2); + Object actl = core.ExecOne(GfsCtx._, root); + Tfds.Eq("val2", actl); + } + void tst_String__Len_Err(GfoMsg m, Err expd) { + tst_Err(msg_("String_").Subs_(m), expd); + } + void tst_Err(GfoMsg msg, Err expd) { + GfoMsg root = msg; + GfsCtx ctx = GfsCtx.new_(); + try { + core.ExecOne(ctx, root); + Tfds.Fail_expdError(); + } + catch (Exception e) { + Tfds.Eq_err(expd, e); + } + } + GfoMsg msg_(String k) {return GfoMsg_.new_cast_(k);} + void tst_Msg(GfoMsg msg, Object expd) { + GfsCtx ctx = GfsCtx.new_(); + Object actl = core.ExecOne(ctx, msg); + Tfds.Eq(expd, actl); + } +} +class GfsCore_tst_nest implements GfoInvkAble, GfoInvkCmdMgrOwner { + public GfoInvkCmdMgr InvkMgr() {return invkMgr;} GfoInvkCmdMgr invkMgr = GfoInvkCmdMgr.new_(); + public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) { + if (ctx.Match(k, Prop1)) {return prop1;} + else if (ctx.Match(k, Prop2)) {return prop2;} + else if (ctx.Match(k, prop1)) {return this;} + else return invkMgr.Invk(ctx, ikey, k, m, this); + } public static final String Prop1 = "Prop1", Prop2 = "Prop2"; + String prop1, prop2; + public static GfsCore_tst_nest new_(String prop1, String prop2) { + GfsCore_tst_nest rv = new GfsCore_tst_nest(); + rv.prop1 = prop1; rv.prop2 = prop2; + return rv; + } GfsCore_tst_nest() {} +} +class GfsTest_cmd implements GfoInvkAble { + public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {return m.ReadStr("s");} +} diff --git a/100_core/src_400_gfs/gplx/GfsCtx.java b/100_core/src_400_gfs/gplx/GfsCtx.java new file mode 100644 index 000000000..eb9c9d35f --- /dev/null +++ b/100_core/src_400_gfs/gplx/GfsCtx.java @@ -0,0 +1,65 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class GfsCtx { + public Ordered_hash Vars() {return vars;} Ordered_hash vars = Ordered_hash_.new_(); + public boolean Fail_if_unhandled() {return fail_if_unhandled;} public GfsCtx Fail_if_unhandled_(boolean v) {fail_if_unhandled = v; return this;} private boolean fail_if_unhandled; + public Gfo_usr_dlg Usr_dlg() {return usr_dlg;} public GfsCtx Usr_dlg_(Gfo_usr_dlg v) {usr_dlg = v; return this;} Gfo_usr_dlg usr_dlg; + public boolean Help_browseMode() {return help_browseMode;} public GfsCtx Help_browseMode_(boolean v) {help_browseMode = v; return this;} private boolean help_browseMode; + @gplx.Internal protected List_adp Help_browseList() {return help_browseList;} List_adp help_browseList = List_adp_.new_(); + public Object MsgSrc() {return msgSrc;} public GfsCtx MsgSrc_(Object v) {msgSrc = v; return this;} Object msgSrc; + public boolean Match(String k, String match) { + if (help_browseMode) { + help_browseList.Add(match); + return false; + } + else + return String_.Eq(k, match); + } + public boolean MatchPriv(String k, String match) {return help_browseMode ? false : String_.Eq(k, match);} + public boolean MatchIn(String k, String... match) { + if (help_browseMode) { + for (String i : match) + help_browseList.Add(i); + return false; + } + return String_.In(k, match); + } + public boolean Write_note(String fmt, Object... ary) {UsrDlg_._.Note(fmt, ary); return false;} + public boolean Write_warn(String fmt, Object... ary) {UsrDlg_._.Note("! " + fmt, ary); return false;} + public boolean Write_stop(UsrMsg umsg) {UsrDlg_._.Note("* " + umsg.XtoStr()); return false;} + public boolean Write_stop(String fmt, Object... ary) {UsrDlg_._.Note("* " + fmt, ary); return false;} + public boolean Deny() {return deny;} private boolean deny; + public static final GfsCtx _ = new GfsCtx(); + public static GfsCtx new_() {return new GfsCtx();} GfsCtx() {} + public static GfsCtx rdr_() { + GfsCtx rv = new GfsCtx(); + rv.deny = true; + rv.mode = "read"; + return rv; + } + public static GfsCtx wtr_() { + GfsCtx rv = new GfsCtx(); + rv.deny = true; + rv.mode = Mode_write; + return rv; + } + public String Mode() {return mode;} public GfsCtx Mode_(String v) {mode = v; return this;} private String mode = "regular"; + public static final String Mode_write = "write"; + public static final int Ikey_null = -1; +} diff --git a/100_core/src_400_gfs/gplx/GfsLibIni.java b/100_core/src_400_gfs/gplx/GfsLibIni.java new file mode 100644 index 000000000..da359de29 --- /dev/null +++ b/100_core/src_400_gfs/gplx/GfsLibIni.java @@ -0,0 +1,21 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public interface GfsLibIni { + void Ini(GfsCore core); +} diff --git a/100_core/src_400_gfs/gplx/GfsLibIni_core.java b/100_core/src_400_gfs/gplx/GfsLibIni_core.java new file mode 100644 index 000000000..2b1e241a7 --- /dev/null +++ b/100_core/src_400_gfs/gplx/GfsLibIni_core.java @@ -0,0 +1,35 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class GfsLibIni_core implements GfsLibIni { + public void Ini(GfsCore core) { + core.AddCmd(GfsCoreHelp.new_(core), "help"); + core.AddObj(String_.Gfs, "String_"); + core.AddObj(Int_.Gfs, "Int_"); + core.AddObj(DateAdp_.Gfs, "Date_"); + core.AddObj(RandomAdp_.Gfs, "RandomAdp_"); + core.AddObj(GfoTemplateFactory._, "factory"); + core.AddObj(GfoRegy._, "GfoRegy_"); + core.AddObj(GfsCore._, "GfsCore_"); + core.AddObj(gplx.ios.IoUrlInfoRegy._, "IoUrlInfoRegy_"); + core.AddObj(gplx.ios.IoUrlTypeRegy._, "IoUrlTypeRegy_"); + + GfoRegy._.Parsers().Add("Io_url", Io_url_.Parser); + } + public static final GfsLibIni_core _ = new GfsLibIni_core(); GfsLibIni_core() {} +} diff --git a/100_core/src_400_gfs/gplx/GfsRegy.java b/100_core/src_400_gfs/gplx/GfsRegy.java new file mode 100644 index 000000000..0c97dd164 --- /dev/null +++ b/100_core/src_400_gfs/gplx/GfsRegy.java @@ -0,0 +1,54 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +class GfsRegy implements GfoInvkAble { + public int Count() {return hash.Count();} + public void Clear() {hash.Clear(); typeHash.Clear();} + public boolean Has(String k) {return hash.Has(k);} + public GfsRegyItm Get_at(int i) {return (GfsRegyItm)hash.Get_at(i);} + public GfsRegyItm Get_by(String key) {return (GfsRegyItm)hash.Get_by(key);} + public GfsRegyItm FetchByType(GfoInvkAble invk) {return (GfsRegyItm)typeHash.Get_by(ClassAdp_.FullNameOf_obj(invk));} + public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) { + Object rv = (GfsRegyItm)hash.Get_by(k); if (rv == null) throw Exc_.new_missing_key(k); + return rv; + } + public void AddObj(GfoInvkAble invk, String key) {Add(key, invk, false);} + public void AddCmd(GfoInvkAble invk, String key) {Add(key, invk, true);} + public void Add(String key, GfoInvkAble invk, boolean typeCmd) { + if (hash.Has(key)) return; + GfsRegyItm regyItm = new GfsRegyItm().Key_(key).InvkAble_(invk).IsCmd_(typeCmd).TypeKey_(ClassAdp_.FullNameOf_obj(invk)); + hash.Add(key, regyItm); + typeHash.Add_if_dupe_use_1st(regyItm.TypeKey(), regyItm); // NOTE: changed to allow same Object to be added under different aliases (app, xowa) DATE:2014-06-09; + } + public void Del(String k) { + GfsRegyItm itm =(GfsRegyItm)hash.Get_by(k); + if (itm != null) typeHash.Del(itm.TypeKey()); + hash.Del(k); + } + Hash_adp typeHash = Hash_adp_.new_(); + Ordered_hash hash = Ordered_hash_.new_(); + public static GfsRegy new_() {return new GfsRegy();} GfsRegy() {} +} +class GfsRegyItm implements GfoInvkAble { + public String Key() {return key;} public GfsRegyItm Key_(String v) {key = v; return this;} private String key; + public String TypeKey() {return typeKey;} public GfsRegyItm TypeKey_(String v) {typeKey = v; return this;} private String typeKey; + public boolean IsCmd() {return isCmd;} public GfsRegyItm IsCmd_(boolean v) {isCmd = v; return this;} private boolean isCmd; + public GfoInvkAble InvkAble() {return invkAble;} public GfsRegyItm InvkAble_(GfoInvkAble v) {invkAble = v; return this;} GfoInvkAble invkAble; + public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {return invkAble.Invk(ctx, ikey, k, m);} + public static GfsRegyItm as_(Object obj) {return obj instanceof GfsRegyItm ? (GfsRegyItm)obj : null;} +} diff --git a/100_core/src_400_gfs/gplx/GfsTypeNames.java b/100_core/src_400_gfs/gplx/GfsTypeNames.java new file mode 100644 index 000000000..70c581f50 --- /dev/null +++ b/100_core/src_400_gfs/gplx/GfsTypeNames.java @@ -0,0 +1,28 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class GfsTypeNames { + public static final String + String = "string" + , Int = "int" + , Bool = "bool" + , Float = "float" + , YesNo = "yn" + , Date = "date" + ; +} diff --git a/100_core/src_400_gfs/gplx/Gfs_Date_tst.java b/100_core/src_400_gfs/gplx/Gfs_Date_tst.java new file mode 100644 index 000000000..d98177f83 --- /dev/null +++ b/100_core/src_400_gfs/gplx/Gfs_Date_tst.java @@ -0,0 +1,42 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class Gfs_Date_tst { + @Before public void setup() { + fx = new GfsCoreFxt(); + fx.AddObj(DateAdp_.Gfs, "Date_"); + Tfds.Now_enabled_y_(); + } GfsCoreFxt fx; + @Test public void Now() { + fx.tst_MsgStr(fx.msg_(String_.Ary("Date_", "Now")), DateAdp_.parse_gplx("2001-01-01 00:00:00.000")); + } + @Test public void Add_day() { + fx.tst_MsgStr(fx.msg_(String_.Ary("Date_", "Now", "Add_day"), KeyVal_.new_("days", 1)), DateAdp_.parse_gplx("2001-01-02 00:00:00.000")); + } +} +class GfsCoreFxt { + public GfsCore Core() {return core;} GfsCore core = GfsCore.new_(); + public GfoMsg msg_(String[] ary, KeyVal... kvAry) {return GfoMsg_.root_leafArgs_(ary, kvAry);} + public void AddObj(GfoInvkAble invk, String s) {core.AddObj(invk, s);} + public void tst_MsgStr(GfoMsg msg, Object expd) { + GfsCtx ctx = GfsCtx.new_(); + Object actl = core.ExecOne(ctx, msg); + Tfds.Eq(Object_.Xto_str_strict_or_null_mark(expd), Object_.Xto_str_strict_or_null_mark(actl)); + } +} diff --git a/100_core/src_410_gfoCfg/gplx/GfoMsgParser.java b/100_core/src_410_gfoCfg/gplx/GfoMsgParser.java new file mode 100644 index 000000000..a149505f1 --- /dev/null +++ b/100_core/src_410_gfoCfg/gplx/GfoMsgParser.java @@ -0,0 +1,21 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public interface GfoMsgParser { + GfoMsg ParseToMsg(String s); +} diff --git a/100_core/src_410_gfoCfg/gplx/GfoRegy.java b/100_core/src_410_gfoCfg/gplx/GfoRegy.java new file mode 100644 index 000000000..3e4f95ae9 --- /dev/null +++ b/100_core/src_410_gfoCfg/gplx/GfoRegy.java @@ -0,0 +1,94 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class GfoRegy implements GfoInvkAble { + public int Count() {return hash.Count();} + public Hash_adp Parsers() {return parsers;} Hash_adp parsers = Hash_adp_.new_(); + public GfoRegyItm FetchOrNull(String key) {return (GfoRegyItm)hash.Get_by(key);} + public Object FetchValOrFail(String key) { + GfoRegyItm rv = (GfoRegyItm)hash.Get_by(key); if (rv == null) throw Exc_.new_("regy does not have key", "key", key); + return rv.Val(); + } + public Object FetchValOrNull(String key) {return FetchValOr(key, null);} + public Object FetchValOr(String key, Object or) { + GfoRegyItm itm = FetchOrNull(key); + return itm == null ? or : itm.Val(); + } + public void Del(String key) {hash.Del(key);} + public void RegObj(String key, Object val) {RegItm(key, val, GfoRegyItm.ValType_Obj, Io_url_.Empty);} + public void RegDir(Io_url dirUrl, String match, boolean recur, String chopBgn, String chopEnd) { + Io_url[] filUrls = Io_mgr.I.QueryDir_args(dirUrl).FilPath_(match).Recur_(recur).ExecAsUrlAry(); + if (filUrls.length == 0 && !Io_mgr.I.ExistsDir(dirUrl)) {UsrDlg_._.Stop(UsrMsg.new_("dirUrl does not exist").Add("dirUrl", dirUrl.Xto_api())); return;} + for (Io_url filUrl : filUrls) { + String key = filUrl.NameAndExt(); + int pos = String_.Find_none; + if (String_.EqNot(chopBgn, "")) { + pos = String_.FindFwd(key, chopBgn); + if (pos == String_.Len(key) - 1) + throw Exc_.new_(Err_ChopBgn, "key", key, "chopBgn", chopBgn); + else if (pos != String_.Find_none) + key = String_.Mid(key, pos + 1); + } + if (String_.EqNot(chopEnd, "")) { + pos = String_.FindBwd(key, chopEnd); + if (pos == 0) + throw Exc_.new_(Err_ChopEnd, "key", key, "chopEnd", chopEnd); + else if (pos != String_.Find_none) + key = String_.MidByLen(key, 0, pos); + } + if (hash.Has(key)) throw Exc_.new_(Err_Dupe, "key", key, "filUrl", filUrl); + RegItm(key, null, GfoRegyItm.ValType_Url, filUrl); + } + } + public void RegObjByType(String key, String val, String type) { + Object o = val; + if (String_.EqNot(type, StringClassXtn.Key_const)) { + ParseAble parser = (ParseAble)parsers.Get_by(type); + if (parser == null) throw Exc_.new_("could not find parser", "type", type, "key", key, "val", val); + o = parser.ParseAsObj(val); + } + RegItm(key, o, GfoRegyItm.ValType_Obj, Io_url_.Empty); + } + public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) { + if (ctx.Match(k, Invk_RegDir)) { + Io_url dir = m.ReadIoUrl("dir"); + String match = m.ReadStrOr("match", "*.*"); + boolean recur = m.ReadBoolOr("recur", false); + String chopBgn = m.ReadStrOr("chopBgn", ""); + String chopEnd = m.ReadStrOr("chopEnd", "."); + if (ctx.Deny()) return this; + RegDir(dir, match, recur, chopBgn, chopEnd); + } + else if (ctx.Match(k, Invk_RegObj)) { + String key = m.ReadStr("key"); + String val = m.ReadStr("val"); + String type = m.ReadStrOr("type", StringClassXtn.Key_const); + if (ctx.Deny()) return this; + RegObjByType(key, val, type); + } + else return GfoInvkAble_.Rv_unhandled; + return this; + } public static final String Invk_RegDir = "RegDir", Invk_RegObj = "RegObj"; + void RegItm(String key, Object val, int valType, Io_url url) { + hash.Add_if_dupe_use_nth(key, new GfoRegyItm(key, val, valType, url)); + } + Hash_adp hash = Hash_adp_.new_(); + public static final String Err_ChopBgn = "chopBgn results in null key", Err_ChopEnd = "chopEnd results in null key", Err_Dupe = "key already registered"; + public static final GfoRegy _ = new GfoRegy(); GfoRegy() {} + @gplx.Internal protected static GfoRegy new_() {return new GfoRegy();} +} diff --git a/100_core/src_410_gfoCfg/gplx/GfoRegyItm.java b/100_core/src_410_gfoCfg/gplx/GfoRegyItm.java new file mode 100644 index 000000000..afada9f7c --- /dev/null +++ b/100_core/src_410_gfoCfg/gplx/GfoRegyItm.java @@ -0,0 +1,31 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class GfoRegyItm { + public String Key() {return key;} private String key; + public Object Val() {return val;} Object val; + public Io_url Url() {return url;} Io_url url; + public int ValType() {return valType;} int valType; + public GfoRegyItm(String key, Object val, int valType, Io_url url) {this.key = key; this.val = val; this.valType = valType; this.url = url;} + + public static final int + ValType_Obj = 1 + , ValType_Url = 2 + , ValType_B64 = 3 + ; +} diff --git a/100_core/src_410_gfoCfg/gplx/GfoRegy_RegDir_tst.java b/100_core/src_410_gfoCfg/gplx/GfoRegy_RegDir_tst.java new file mode 100644 index 000000000..e213c2f19 --- /dev/null +++ b/100_core/src_410_gfoCfg/gplx/GfoRegy_RegDir_tst.java @@ -0,0 +1,61 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class GfoRegy_RegDir_tst { + @Before public void setup() { + regy = GfoRegy.new_(); + Io_mgr.I.InitEngine_mem(); + root = Io_url_.mem_dir_("mem/root"); + } GfoRegy regy; Io_url root; + @Test public void Basic() { + ini_fil("101_tsta.txt"); + ini_fil("102_tstb.txt"); + ini_fil("103_tstc.png"); + ini_fil("dir1", "104_tstd.txt"); + regy.RegDir(root, "*.txt", false, "_", "."); + tst_Count(2); + tst_Exists("tsta"); + tst_Exists("tstb"); + } + @Test public void Err_dupe() { + ini_fil("101_tsta.txt"); + ini_fil("102_tsta.txt"); + try {regy.RegDir(root, "*.txt", false, "_", ".");} + catch (Exception e) {Tfds.Err_has(e, GfoRegy.Err_Dupe); return;} + Tfds.Fail_expdError(); + } + @Test public void Err_chopBgn() { + ini_fil("123_"); + try {regy.RegDir(root, "*", false, "_", ".");} + catch (Exception e) {Tfds.Err_has(e, GfoRegy.Err_ChopBgn); return;} + Tfds.Fail_expdError(); + } + @Test public void Err_chopEnd() { + ini_fil(".txt"); + try {regy.RegDir(root, "*.txt", false, "_", ".");} + catch (Exception e) {Tfds.Err_has(e, GfoRegy.Err_ChopEnd); return;} + Tfds.Fail_expdError(); + } + void tst_Count(int expd) {Tfds.Eq(expd, regy.Count());} + void tst_Exists(String expd) { + GfoRegyItm itm = regy.FetchOrNull(expd); + Tfds.Eq_nullNot(itm); + } + void ini_fil(String... nest) {Io_mgr.I.SaveFilStr(root.GenSubFil_nest(nest), "");} +} diff --git a/100_core/src_410_gfoCfg/gplx/GfoRegy_basic_tst.java b/100_core/src_410_gfoCfg/gplx/GfoRegy_basic_tst.java new file mode 100644 index 000000000..b28c0c0c9 --- /dev/null +++ b/100_core/src_410_gfoCfg/gplx/GfoRegy_basic_tst.java @@ -0,0 +1,31 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class GfoRegy_basic_tst { + @Before public void setup() { + regy = GfoRegy.new_(); + } GfoRegy regy; + @Test public void RegObjByType() { + regy.Parsers().Add("Io_url", Io_url_.Parser); + Io_url expd = Io_url_.new_any_("C:\\fil.txt"); + regy.RegObjByType("test", expd.Xto_api(), "Io_url"); + Io_url actl = (Io_url)regy.FetchValOr("test", Io_url_.Empty); + Tfds.Eq(expd.Xto_api(), actl.Xto_api()); + } +} diff --git a/100_core/src_420_usrMsg/gplx/Gfo_log_bfr.java b/100_core/src_420_usrMsg/gplx/Gfo_log_bfr.java new file mode 100644 index 000000000..f3a59c692 --- /dev/null +++ b/100_core/src_420_usrMsg/gplx/Gfo_log_bfr.java @@ -0,0 +1,29 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Gfo_log_bfr { + private Bry_bfr bfr = Bry_bfr.reset_(255); + public Gfo_log_bfr Add(String s) { + bfr.Add_str(DateAdp_.Now().XtoUtc().XtoStr_fmt_yyyyMMdd_HHmmss_fff()); + bfr.Add_byte_space(); + bfr.Add_str(s); + bfr.Add_byte_nl(); + return this; + } + public String Xto_str() {return bfr.Xto_str_and_clear();} +} diff --git a/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg.java b/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg.java new file mode 100644 index 000000000..8563adbb3 --- /dev/null +++ b/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg.java @@ -0,0 +1,35 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public interface Gfo_usr_dlg extends Cancelable { + void Canceled_y_(); void Canceled_n_(); + Gfo_usr_dlg__log Log_wkr(); void Log_wkr_(Gfo_usr_dlg__log v); + Gfo_usr_dlg__gui Gui_wkr(); void Gui_wkr_(Gfo_usr_dlg__gui v); + String Log_many(String grp_key, String msg_key, String fmt, Object... args); + String Warn_many(String grp_key, String msg_key, String fmt, Object... args); + Exc Fail_many(String grp_key, String msg_key, String fmt, Object... args); + String Prog_many(String grp_key, String msg_key, String fmt, Object... args); + String Prog_none(String grp_key, String msg_key, String fmt); + String Note_many(String grp_key, String msg_key, String fmt, Object... args); + String Note_none(String grp_key, String msg_key, String fmt); + String Note_gui_none(String grp_key, String msg_key, String fmt); + String Prog_one(String grp_key, String msg_key, String fmt, Object arg); + String Prog_direct(String msg); + String Log_direct(String msg); + String Plog_many(String grp_key, String msg_key, String fmt, Object... args); +} diff --git a/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg_.java b/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg_.java new file mode 100644 index 000000000..b46eaee7e --- /dev/null +++ b/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg_.java @@ -0,0 +1,48 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Gfo_usr_dlg_ { + public static Gfo_usr_dlg I = Gfo_usr_dlg_noop._; // NOTE: global instance which can be reassigned + public static final Gfo_usr_dlg Noop = Gfo_usr_dlg_noop._; + public static Gfo_usr_dlg Test() { + if (test == null) + test = new Gfo_usr_dlg_base(Gfo_usr_dlg__log_.Noop, Gfo_usr_dlg__gui_.Test); + return test; + } private static Gfo_usr_dlg_base test; +} +class Gfo_usr_dlg_noop implements Gfo_usr_dlg { + public boolean Canceled() {return false;} public void Canceled_y_() {} public void Canceled_n_() {} + public void Cancel() {} public void Cancel_reset() {} + public void Clear() {} + public Gfo_usr_dlg__log Log_wkr() {return Gfo_usr_dlg__log_.Noop;} public void Log_wkr_(Gfo_usr_dlg__log v) {} + public Gfo_usr_dlg__gui Gui_wkr() {return Gfo_usr_dlg__gui_.Noop;} public void Gui_wkr_(Gfo_usr_dlg__gui v) {} + public String Log_many(String grp_key, String msg_key, String fmt, Object... args) {return "";} + public String Warn_many(String grp_key, String msg_key, String fmt, Object... args) {return "";} + public Exc Fail_many(String grp_key, String msg_key, String fmt, Object... args) {return Exc_.new_(fmt);} + public String Prog_many(String grp_key, String msg_key, String fmt, Object... args) {return "";} + public String Prog_none(String grp_key, String msg_key, String fmt) {return "";} + public String Note_many(String grp_key, String msg_key, String fmt, Object... args) {return "";} + public String Note_none(String grp_key, String msg_key, String fmt) {return "";} + public String Note_gui_none(String grp_key, String msg_key, String fmt) {return "";} + public String Prog_one(String grp_key, String msg_key, String fmt, Object arg) {return "";} + public String Prog_direct(String msg) {return "";} + public String Log_direct(String msg) {return "";} + public String Plog_many(String grp_key, String msg_key, String fmt, Object... args) {return "";} + public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {return this;} + public static final Gfo_usr_dlg_noop _ = new Gfo_usr_dlg_noop(); Gfo_usr_dlg_noop() {} +} diff --git a/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg__gui.java b/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg__gui.java new file mode 100644 index 000000000..5a688eed3 --- /dev/null +++ b/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg__gui.java @@ -0,0 +1,27 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.core.strings.*; +public interface Gfo_usr_dlg__gui { + void Clear(); + String_ring Prog_msgs(); + void Write_prog(String text); + void Write_note(String text); + void Write_warn(String text); + void Write_stop(String text); +} diff --git a/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg__gui_.java b/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg__gui_.java new file mode 100644 index 000000000..8d54f6543 --- /dev/null +++ b/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg__gui_.java @@ -0,0 +1,41 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.core.strings.*; +public class Gfo_usr_dlg__gui_ { + public static final Gfo_usr_dlg__gui Noop = new Gfo_usr_dlg__gui_noop(); + public static final Gfo_usr_dlg__gui Console = new Gfo_usr_dlg__gui_console(); + public static final Gfo_usr_dlg__gui Test = new Gfo_usr_dlg__gui_test(); +} +class Gfo_usr_dlg__gui_noop implements Gfo_usr_dlg__gui { + public void Clear() {} + public String_ring Prog_msgs() {return ring;} String_ring ring = new String_ring().Max_(0); + public void Write_prog(String text) {} + public void Write_note(String text) {} + public void Write_warn(String text) {} + public void Write_stop(String text) {} +} +class Gfo_usr_dlg__gui_console implements Gfo_usr_dlg__gui { + public void Clear() {} + public String_ring Prog_msgs() {return ring;} String_ring ring = new String_ring().Max_(0); + public void Write_prog(String text) {console.WriteTempText(text);} + public void Write_note(String text) {console.WriteLine(text);} + public void Write_warn(String text) {console.WriteLine(text);} + public void Write_stop(String text) {console.WriteLine(text);} + ConsoleAdp console = ConsoleAdp._; +} diff --git a/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg__gui_test.java b/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg__gui_test.java new file mode 100644 index 000000000..d1183b28b --- /dev/null +++ b/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg__gui_test.java @@ -0,0 +1,29 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.core.strings.*; +public class Gfo_usr_dlg__gui_test implements Gfo_usr_dlg__gui { + public String[] Xto_str_ary() {return msgs.To_str_ary();} + public List_adp Warns() {return warns;} + public String_ring Prog_msgs() {return ring;} String_ring ring = new String_ring().Max_(0); + public void Clear() {msgs.Clear(); warns.Clear();} + public void Write_prog(String text) {msgs.Add(text);} List_adp msgs = List_adp_.new_(); + public void Write_note(String text) {msgs.Add(text);} + public void Write_warn(String text) {warns.Add(text);} List_adp warns = List_adp_.new_(); + public void Write_stop(String text) {msgs.Add(text);} +} diff --git a/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg__log.java b/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg__log.java new file mode 100644 index 000000000..665965b22 --- /dev/null +++ b/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg__log.java @@ -0,0 +1,31 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public interface Gfo_usr_dlg__log extends GfoInvkAble { + boolean Enabled(); void Enabled_(boolean v); + boolean Queue_enabled(); void Queue_enabled_(boolean v); + Io_url Log_dir(); void Log_dir_(Io_url v); + Io_url Session_dir(); + Io_url Session_fil(); + void Log_msg_to_url_fmt(Io_url url, String fmt, Object... args); + void Log_to_session(String txt); + void Log_to_session_fmt(String fmt, Object... args); + void Log_to_session_direct(String txt); + void Log_to_err(String txt); + void Log_term(); +} diff --git a/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg__log_.java b/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg__log_.java new file mode 100644 index 000000000..d3da9c519 --- /dev/null +++ b/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg__log_.java @@ -0,0 +1,35 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Gfo_usr_dlg__log_ { + public static final Gfo_usr_dlg__log Noop = new Gfo_usr_dlg__log_noop(); +} +class Gfo_usr_dlg__log_noop implements Gfo_usr_dlg__log { + public Io_url Session_fil() {return Io_url_.Empty;} + public Io_url Session_dir() {return Io_url_.Empty;} + public Io_url Log_dir() {return Io_url_.Empty;} public void Log_dir_(Io_url v) {} + public boolean Enabled() {return enabled;} public void Enabled_(boolean v) {enabled = v;} private boolean enabled; + public boolean Queue_enabled() {return queue_enabled;} public void Queue_enabled_(boolean v) {queue_enabled = v;} private boolean queue_enabled; + public void Log_msg_to_url_fmt(Io_url url, String fmt, Object... args) {} + public void Log_to_session_fmt(String fmt, Object... args) {} + public void Log_to_session(String txt) {} + public void Log_to_session_direct(String txt) {} + public void Log_to_err(String txt) {} + public void Log_term() {} + public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {return this;} +} diff --git a/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg__log_base.java b/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg__log_base.java new file mode 100644 index 000000000..3882dd54a --- /dev/null +++ b/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg__log_base.java @@ -0,0 +1,123 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.core.strings.*; +public class Gfo_usr_dlg__log_base implements Gfo_usr_dlg__log { + private int archive_dirs_max = 8; + private Io_url log_dir, err_fil; + private Ordered_hash queued_list = Ordered_hash_.new_(); + private Bry_fmtr fmtr = Bry_fmtr.tmp_(); private Bry_bfr tmp_bfr = Bry_bfr.reset_(255); + public boolean Queue_enabled() {return queue_enabled;} public void Queue_enabled_(boolean v) {queue_enabled = v; if (!v) this.Flush();} private boolean queue_enabled; + public boolean Enabled() {return enabled;} public void Enabled_(boolean v) {enabled = v;} private boolean enabled = true; + public Io_url Session_dir() {return session_dir;} private Io_url session_dir; + public Io_url Session_fil() {return session_fil;} private Io_url session_fil; + private void Flush() { + int queued_len = queued_list.Count(); + for (int i = 0; i < queued_len; i++) { + Usr_log_fil fil = (Usr_log_fil)queued_list.Get_at(i); + if (fil.Url() == null) { + fil.Url_(session_dir.GenSubFil("session.txt")); + } + fil.Flush(); + } + } + public Io_url Log_dir() {return log_dir;} + public void Log_dir_(Io_url log_dir) { + this.log_dir = log_dir; + session_dir = log_dir.GenSubDir(Dir_name_current); + session_fil = session_dir.GenSubFil("session.txt"); + err_fil = session_dir.GenSubFil("err.txt"); + } + public void Log_term() { + if (!enabled) return; + Io_url[] archive_dirs = Io_mgr.I.QueryDir_args(log_dir).DirInclude_().DirOnly_().ExecAsUrlAry(); + int archive_dirs_len = archive_dirs.length; + int session_cutoff = archive_dirs_len - archive_dirs_max; + for (int i = 0; i < session_cutoff; i++) { + Io_url archive_dir = archive_dirs[i]; + Io_mgr.I.DeleteDirDeep(archive_dir); + this.Log_to_session("archive dir del: " + session_dir.Raw()); + } + this.Log_to_session("app term"); + MoveCurrentToArchive(session_dir); + } + private void MoveCurrentToArchive(Io_url dir) {Io_mgr.I.MoveDirDeep(dir, dir.OwnerDir().GenSubDir(DateAdp_.Now().XtoStr_fmt_yyyyMMdd_HHmmss_fff()));} + public void Log_info(boolean warn, String s) {if (warn) Log_to_err(s); else Log_to_session(s);} + public void Log_msg_to_url_fmt(Io_url url, String fmt, Object... args) { + if (!enabled) return; + String msg = Bld_msg(String_.new_u8(fmtr.Fmt_(fmt).Bld_bry_many(tmp_bfr, args))); + Log_msg(url, msg); + Log_msg(session_fil, msg); + } + public void Log_to_session_fmt(String fmt, Object... args) {Log_to_session(String_.new_u8(fmtr.Fmt_(fmt).Bld_bry_many(tmp_bfr, args)));} + public void Log_to_session(String s) { + if (!enabled) return; + String line = Bld_msg(s); + Log_msg(session_fil, line); + } + public void Log_to_session_direct(String s) { + if (!enabled) return; + Log_msg(session_fil, s); + } + public void Log_to_err(String s) { + if (!enabled) return; + try { + String line = Bld_msg(s); + Log_msg(session_fil, line); + Log_msg(err_fil, line); + } + catch (Exception e) {Exc_.Noop(e);} // java.lang.StringBuilder can throw exceptions in some situations when called on a different thread; ignore errors + } private String_bldr sb = String_bldr_.new_thread(); // NOTE: use java.lang.StringBuffer to try to avoid random exceptions when called on a different thread + private String Bld_msg(String s) {return sb.Add(DateAdp_.Now().XtoUtc().XtoStr_fmt_yyyyMMdd_HHmmss_fff()).Add(" ").Add(s).Add_char_nl().Xto_str_and_clear();} + private void Log_msg(Io_url url, String txt) { + if (queue_enabled) { + String url_raw = url == null ? "mem" : url.Raw(); + Usr_log_fil fil = (Usr_log_fil)queued_list.Get_by(url_raw); + if (fil == null) { + fil = new Usr_log_fil(url); + queued_list.Add(url_raw, fil); + } + fil.Add(txt); + } + else + Io_mgr.I.AppendFilStr(url, txt); + } + public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) { + if (ctx.Match(k, Invk_enabled_)) enabled = m.ReadYn("v"); + else if (ctx.Match(k, Invk_archive_dirs_max_)) archive_dirs_max = m.ReadInt("v"); + else if (ctx.Match(k, Invk_log_dir_)) log_dir = m.ReadIoUrl("v"); + else return GfoInvkAble_.Rv_unhandled; + return this; + } public static final String Invk_enabled_ = "enabled_", Invk_archive_dirs_max_ = "archive_dirs_max_", Invk_log_dir_ = "log_dir_"; + static final String Dir_name_log = "log", Dir_name_current = "current"; + public static final Gfo_usr_dlg__log_base _ = new Gfo_usr_dlg__log_base(); +} +class Usr_log_fil { + public Usr_log_fil(Io_url url) {this.url = url;} + public Io_url Url() {return url;} public Usr_log_fil Url_(Io_url v) {url = v; return this;} Io_url url; + public void Add(String text) {sb.Add(text);} String_bldr sb = String_bldr_.new_(); + public void Flush() { + if (sb.Count() == 0) return; + try { + Io_mgr.I.AppendFilStr(url, sb.Xto_str_and_clear()); + } + catch (Exception e) { + ConsoleAdp._.WriteLine(Err_.Message_gplx_brief(e)); + } + } +} diff --git a/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg_base.java b/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg_base.java new file mode 100644 index 000000000..98ac64d79 --- /dev/null +++ b/100_core/src_420_usrMsg/gplx/Gfo_usr_dlg_base.java @@ -0,0 +1,55 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Gfo_usr_dlg_base implements Gfo_usr_dlg { + private final Bry_bfr tmp_bfr = Bry_bfr.reset_(255); + private final Bry_fmtr tmp_fmtr = Bry_fmtr.tmp_().Fail_when_invalid_escapes_(false); // do not fail b/c msgs may contain excerpt of random text; EX:[[User:A|~A~]] DATE:2014-11-28 + public Gfo_usr_dlg_base(Gfo_usr_dlg__log log_wkr, Gfo_usr_dlg__gui gui_wkr) {this.log_wkr = log_wkr; this.gui_wkr = gui_wkr;} + public Gfo_usr_dlg__log Log_wkr() {return log_wkr;} public void Log_wkr_(Gfo_usr_dlg__log v) {log_wkr = v;} private Gfo_usr_dlg__log log_wkr; + public Gfo_usr_dlg__gui Gui_wkr() {return gui_wkr;} public void Gui_wkr_(Gfo_usr_dlg__gui v) {gui_wkr = v;} private Gfo_usr_dlg__gui gui_wkr; + public boolean Canceled() {return canceled;} public void Canceled_y_() {canceled = true;} public void Canceled_n_() {canceled = false;} private boolean canceled; + public void Cancel() {canceled = true;} public void Cancel_reset() {canceled = false;} + public String Log_many(String grp_key, String msg_key, String fmt, Object... args) {String rv = Bld_msg_many(grp_key, msg_key, fmt, args ); log_wkr.Log_to_session(rv); return rv;} + public String Warn_many(String grp_key, String msg_key, String fmt, Object... args) {String rv = Bld_msg_many(grp_key, msg_key, fmt, args ); log_wkr.Log_to_err(rv); gui_wkr.Write_warn(rv); return rv;} + public String Prog_many(String grp_key, String msg_key, String fmt, Object... args) {String rv = Bld_msg_many(grp_key, msg_key, fmt, args ); gui_wkr.Write_prog(rv); return rv;} + public String Prog_one(String grp_key, String msg_key, String fmt, Object arg) {String rv = Bld_msg_one (grp_key, msg_key, fmt, arg ); gui_wkr.Write_prog(rv); return rv;} + public String Prog_none(String grp_key, String msg_key, String fmt) {String rv = Bld_msg_none(grp_key, msg_key, fmt ); gui_wkr.Write_prog(rv); return rv;} + public String Prog_direct(String msg) { gui_wkr.Write_prog(msg); return msg;} + public String Log_direct(String msg) { log_wkr.Log_to_session(msg); return msg;} + public String Note_many(String grp_key, String msg_key, String fmt, Object... args) {String rv = Bld_msg_many(grp_key, msg_key, fmt, args ); log_wkr.Log_to_session(rv); gui_wkr.Write_note(rv); return rv;} + public String Note_none(String grp_key, String msg_key, String fmt) {String rv = Bld_msg_none(grp_key, msg_key, fmt ); log_wkr.Log_to_session(rv); gui_wkr.Write_note(rv); return rv;} + public String Note_gui_none(String grp_key, String msg_key, String fmt) {String rv = Bld_msg_none(grp_key, msg_key, fmt ); gui_wkr.Write_note(rv); return rv;} + public String Plog_many(String grp_key, String msg_key, String fmt, Object... args) { + String rv = Log_many(grp_key, msg_key, fmt, args); + return Prog_direct(rv); + } + public Exc Fail_many(String grp_key, String msg_key, String fmt, Object... args) { + Exc rv = Exc_.new_(Bld_msg_many(grp_key, msg_key, fmt, args)); + log_wkr.Log_to_err(rv.To_str_all()); + return rv; + } + private String Bld_msg_many(String grp_key, String msg_key, String fmt, Object[] args) { + tmp_fmtr.Fmt_(fmt).Bld_bfr_many(tmp_bfr, args); + return tmp_bfr.Xto_str_and_clear(); + } + private String Bld_msg_one(String grp_key, String msg_key, String fmt, Object val) { + tmp_fmtr.Fmt_(fmt).Bld_bfr_one(tmp_bfr, val); + return tmp_bfr.Xto_str_and_clear(); + } + private String Bld_msg_none(String grp_key, String msg_key, String fmt) {return fmt;} +} diff --git a/100_core/src_420_usrMsg/gplx/UsrDlg.java b/100_core/src_420_usrMsg/gplx/UsrDlg.java new file mode 100644 index 000000000..113713f8b --- /dev/null +++ b/100_core/src_420_usrMsg/gplx/UsrDlg.java @@ -0,0 +1,51 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class UsrDlg { + public int Verbosity() {return verbosity;} public UsrDlg Verbosity_(int v) {verbosity = v; return this;} int verbosity = UsrMsgWkr_.Type_Note; + public void Note(String text, Object... ary) {Exec(text, ary, noteWkrs);} + public void Warn(String text, Object... ary) {Exec(text, ary, warnWkrs);} + public void Stop(String text, Object... ary) {Exec(text, ary, stopWkrs);} + public void Note(UsrMsg msg) {Exec(UsrMsgWkr_.Type_Note, msg);} + public void Warn(UsrMsg msg) {Exec(UsrMsgWkr_.Type_Warn, msg);} + public void Stop(UsrMsg msg) {Exec(UsrMsgWkr_.Type_Stop, msg);} + public void Exec(int type, UsrMsg umsg) { + UsrMsgWkrList list = GetList(type); + list.Exec(umsg); + } + void Exec(String text, Object[] ary, UsrMsgWkrList list) { + String msg = String_.Format(text, ary); + list.Exec(UsrMsg.new_(msg)); + } + public void Reg(int type, UsrMsgWkr wkr) { + UsrMsgWkrList list = GetList(type); + list.Add(wkr); + } + public void RegOff(int type, UsrMsgWkr wkr) { + UsrMsgWkrList list = GetList(type); + list.Del(wkr); + } + UsrMsgWkrList GetList(int type) { + if (type == UsrMsgWkr_.Type_Note) return noteWkrs; + else if (type == UsrMsgWkr_.Type_Warn) return warnWkrs; + else if (type == UsrMsgWkr_.Type_Stop) return stopWkrs; + else throw Exc_.new_unhandled(type); + } + UsrMsgWkrList noteWkrs = new UsrMsgWkrList(UsrMsgWkr_.Type_Note), warnWkrs = new UsrMsgWkrList(UsrMsgWkr_.Type_Warn), stopWkrs = new UsrMsgWkrList(UsrMsgWkr_.Type_Stop); + public static UsrDlg new_() {return new UsrDlg();} +} diff --git a/100_core/src_420_usrMsg/gplx/UsrDlg_.java b/100_core/src_420_usrMsg/gplx/UsrDlg_.java new file mode 100644 index 000000000..72fb054e4 --- /dev/null +++ b/100_core/src_420_usrMsg/gplx/UsrDlg_.java @@ -0,0 +1,21 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class UsrDlg_ { + public static final UsrDlg _ = UsrDlg.new_(); +} diff --git a/100_core/src_420_usrMsg/gplx/UsrMsg.java b/100_core/src_420_usrMsg/gplx/UsrMsg.java new file mode 100644 index 000000000..940e20a82 --- /dev/null +++ b/100_core/src_420_usrMsg/gplx/UsrMsg.java @@ -0,0 +1,68 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.core.strings.*; +public class UsrMsg { + public int VisibilityDuration() {return visibilityDuration;} public UsrMsg VisibilityDuration_(int v) {visibilityDuration = v; return this;} int visibilityDuration = 3000; + public String Hdr() {return hdr;} public UsrMsg Hdr_(String val) {hdr = val; return this;} private String hdr; + public Ordered_hash Args() {return args;} Ordered_hash args = Ordered_hash_.new_(); + public UsrMsg Add(String k, Object v) { + args.Add(k, KeyVal_.new_(k, v)); + return this; + } + public UsrMsg Add_if_dupe_use_nth(String k, Object v) { + args.Add_if_dupe_use_nth(k, KeyVal_.new_(k, v)); + return this; + } + public String XtoStrSingleLine() {return XtoStr(" ");} + public String XtoStr() {return XtoStr(Op_sys.Cur().Nl_str());} + String XtoStr(String spr) { + if (hdr == null) { + GfoMsg m = GfoMsg_.new_cast_(cmd); + for (int i = 0; i < args.Count(); i++) { + KeyVal kv = (KeyVal)args.Get_at(i); + m.Add(kv.Key(), kv.Val()); + } + return Object_.Xto_str_strict_or_null_mark(invk.Invk(GfsCtx._, 0, cmd, m)); + } + String_bldr sb = String_bldr_.new_(); + sb.Add(hdr).Add(spr); + for (int i = 0; i < args.Count(); i++) { + KeyVal kv = (KeyVal)args.Get_at(i); + sb.Add_spr_unless_first("", " ", i); + sb.Add_fmt("{0}={1}", kv.Key(), kv.Val(), spr); + } + return sb.XtoStr(); + } + public static UsrMsg fmt_(String hdr, Object... ary) { + UsrMsg rv = new UsrMsg(); + rv.hdr = String_.Format(hdr, ary); + return rv; + } UsrMsg() {} + public static UsrMsg new_(String hdr) { + UsrMsg rv = new UsrMsg(); + rv.hdr = hdr; + return rv; + } + public static UsrMsg invk_(GfoInvkAble invk, String cmd) { + UsrMsg rv = new UsrMsg(); + rv.invk = invk; + rv.cmd = cmd; + return rv; + } GfoInvkAble invk; String cmd; +} diff --git a/100_core/src_420_usrMsg/gplx/UsrMsgWkr.java b/100_core/src_420_usrMsg/gplx/UsrMsgWkr.java new file mode 100644 index 000000000..1b41cb375 --- /dev/null +++ b/100_core/src_420_usrMsg/gplx/UsrMsgWkr.java @@ -0,0 +1,50 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public interface UsrMsgWkr { + void ExecUsrMsg(int type, UsrMsg umsg); +} +class UsrMsgWkrList { + public void Add(UsrMsgWkr v) { + if (wkr == null && list == null) + wkr = v; + else { + if (list == null) { + list = List_adp_.new_(); + list.Add(wkr); + wkr = null; + } + list.Add(v); + } + } + public void Del(UsrMsgWkr v) { +// list.Del(v); + } + public void Exec(UsrMsg umsg) { + if (wkr != null) + wkr.ExecUsrMsg(type, umsg); + else if (list != null) { + for (Object lObj : list) { + UsrMsgWkr l = (UsrMsgWkr)lObj; + l.ExecUsrMsg(type, umsg); + } + } + } + List_adp list; UsrMsgWkr wkr; int type; + public UsrMsgWkrList(int type) {this.type = type;} +} diff --git a/100_core/src_420_usrMsg/gplx/UsrMsgWkr_.java b/100_core/src_420_usrMsg/gplx/UsrMsgWkr_.java new file mode 100644 index 000000000..2bedb2294 --- /dev/null +++ b/100_core/src_420_usrMsg/gplx/UsrMsgWkr_.java @@ -0,0 +1,27 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class UsrMsgWkr_ { + public static final int + Type_None = 0 + , Type_Stop = 1 + , Type_Warn = 2 + , Type_Note = 4 + , Type_Log = 8 + ; +} diff --git a/100_core/src_420_usrMsg/gplx/UsrMsgWkr_console.java b/100_core/src_420_usrMsg/gplx/UsrMsgWkr_console.java new file mode 100644 index 000000000..7ba18b027 --- /dev/null +++ b/100_core/src_420_usrMsg/gplx/UsrMsgWkr_console.java @@ -0,0 +1,34 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class UsrMsgWkr_console implements UsrMsgWkr { + public void ExecUsrMsg(int type, UsrMsg umsg) { + String text = umsg.XtoStr(); + if (type == UsrMsgWkr_.Type_Warn) + text = "!!!!" + text; + else if (type == UsrMsgWkr_.Type_Stop) + text = "****" + text; + ConsoleAdp._.WriteText(text); + } + public static void RegAll(UsrDlg dlg) { + UsrMsgWkr wkr = new UsrMsgWkr_console(); + dlg.Reg(UsrMsgWkr_.Type_Note, wkr); + dlg.Reg(UsrMsgWkr_.Type_Stop, wkr); + dlg.Reg(UsrMsgWkr_.Type_Warn, wkr); + } +} diff --git a/100_core/src_420_usrMsg/gplx/UsrMsgWkr_test.java b/100_core/src_420_usrMsg/gplx/UsrMsgWkr_test.java new file mode 100644 index 000000000..4d95fa164 --- /dev/null +++ b/100_core/src_420_usrMsg/gplx/UsrMsgWkr_test.java @@ -0,0 +1,38 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class UsrMsgWkr_test implements UsrMsgWkr { + public void ExecUsrMsg(int type, UsrMsg m) { + msgs.Add(m); + } + public boolean HasWarn(UsrMsg um) { + for (int i = 0; i < msgs.Count(); i++) { + UsrMsg found = (UsrMsg)msgs.Get_at(i); + if (String_.Eq(um.XtoStr(), found.XtoStr())) return true; + } + return false; + } + public static UsrMsgWkr_test RegAll(UsrDlg dlg) { + UsrMsgWkr_test wkr = new UsrMsgWkr_test(); + dlg.Reg(UsrMsgWkr_.Type_Note, wkr); + dlg.Reg(UsrMsgWkr_.Type_Stop, wkr); + dlg.Reg(UsrMsgWkr_.Type_Warn, wkr); + return wkr; + } + List_adp msgs = List_adp_.new_(); +} diff --git a/100_core/src_800_tst/gplx/PerfLogMgr_fxt.java b/100_core/src_800_tst/gplx/PerfLogMgr_fxt.java new file mode 100644 index 000000000..72df704cd --- /dev/null +++ b/100_core/src_800_tst/gplx/PerfLogMgr_fxt.java @@ -0,0 +1,66 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.core.strings.*; +public class PerfLogMgr_fxt { + public void Init(Io_url url, String text) { + this.url = url; + entries.Resize_bounds(1000); + entries.Add(new PerfLogItm(0, text + "|" + DateAdp_.Now().XtoStr_gplx())); + tmr.Bgn(); + } + public void Write(String text) { + long milliseconds = tmr.ElapsedMilliseconds(); + entries.Add(new PerfLogItm(milliseconds, text)); + tmr.Bgn(); + } + public void WriteFormat(String fmt, Object... ary) { + long milliseconds = tmr.ElapsedMilliseconds(); + String text = String_.Format(fmt, ary); + entries.Add(new PerfLogItm(milliseconds, text)); + tmr.Bgn(); + } + public void Flush() { + String_bldr sb = String_bldr_.new_(); + for (Object itmObj : entries) { + PerfLogItm itm = (PerfLogItm)itmObj; + sb.Add(itm.XtoStr()).Add_char_crlf(); + } + Io_mgr.I.AppendFilStr(url, sb.XtoStr()); + entries.Clear(); + } + List_adp entries = List_adp_.new_(); PerfLogTmr tmr = PerfLogTmr.new_(); Io_url url = Io_url_.Empty; + public static final PerfLogMgr_fxt _ = new PerfLogMgr_fxt(); PerfLogMgr_fxt() {} + class PerfLogItm { + public String XtoStr() { + String secondsStr = TimeSpanAdp_.XtoStr(milliseconds, TimeSpanAdp_.Fmt_Default); + secondsStr = String_.PadBgn(secondsStr, 7, "0"); // 7=000.000; left-aligns all times + return String_.Concat(secondsStr, "|", text); + } + long milliseconds; String text; + @gplx.Internal protected PerfLogItm(long milliseconds, String text) { + this.milliseconds = milliseconds; this.text = text; + } + } + +} +class PerfLogTmr { + public void Bgn() {bgn = Env_.TickCount();} long bgn; + public long ElapsedMilliseconds() {return Env_.TickCount() - bgn; } + public static PerfLogTmr new_() {return new PerfLogTmr();} PerfLogTmr() {} +} diff --git a/100_core/src_800_tst/gplx/Tfds.java b/100_core/src_800_tst/gplx/Tfds.java new file mode 100644 index 000000000..1d15aa522 --- /dev/null +++ b/100_core/src_800_tst/gplx/Tfds.java @@ -0,0 +1,245 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.core.strings.*; +public class Tfds { // URL:doc/gplx.tfds/Tfds.txt + public static boolean SkipDb = false; + public static void Eq(Object expd, Object actl) {Eq_wkr(expd, actl, true, EmptyStr);} + public static void Eq_able(EqAble expd, EqAble actl) {Eq_able_wkr(expd, actl, true, EmptyStr);} + public static void Eq_able(EqAble expd, EqAble actl, String fmt, Object... args) {Eq_able_wkr(expd, actl, true, String_.Format(fmt, args));} + public static void Eq_byte(byte expd, byte actl) {Eq_wkr(expd, actl, true, EmptyStr);} + public static void Eq_long(long expd, long actl) {Eq_wkr(expd, actl, true, EmptyStr);} + public static void Eq_float(float expd, float actl) {Eq_wkr(expd, actl, true, EmptyStr);} + public static void Eq_decimal(DecimalAdp expd, DecimalAdp actl) {Eq_wkr(expd.Xto_double(), actl.Xto_double(), true, EmptyStr);} + public static void Eq_date(DateAdp expd, DateAdp actl) {Eq_wkr(expd.XtoStr_gplx(), actl.XtoStr_gplx(), true, EmptyStr);} + public static void Eq_date(DateAdp expd, DateAdp actl, String fmt, Object... args){Eq_wkr(expd.XtoStr_gplx(), actl.XtoStr_gplx(), true, String_.Format(fmt, args));} + public static void Eq_url(Io_url expd, Io_url actl) {Eq_wkr(expd.Raw(), actl.Raw(), true, EmptyStr);} + public static void Eq_bry(String expd, byte[] actl) {Eq_wkr(expd, String_.new_u8(actl), true, EmptyStr);} + public static void Eq_bry(byte[] expd, byte[] actl) {Eq_wkr(String_.new_u8(expd), String_.new_u8(actl), true, EmptyStr);} + public static void Eq_str(XtoStrAble expd, XtoStrAble actl, String msg) {Eq_wkr(expd.XtoStr(), actl.XtoStr(), true, msg);} + public static void Eq_str(XtoStrAble expd, XtoStrAble actl) {Eq_wkr(expd.XtoStr(), actl.XtoStr(), true, String_.Empty);} + public static void Eq_str_lines(String lhs, String rhs) {Eq_str_lines(lhs, rhs, EmptyStr);} + public static void Eq_str_lines(String lhs, String rhs, String note) { + if (lhs == null && rhs == null) return; // true + else if (lhs == null) throw Exc_.new_("lhs is null", "note", note); + else if (rhs == null) throw Exc_.new_("rhs is null", "note", note); + else Eq_ary_wkr(String_.Split(lhs, Char_.NewLine), String_.Split(rhs, Char_.NewLine), false, note); + } + public static void Eq(Object expd, Object actl, String fmt, Object... args) {Eq_wkr(expd, actl, true, String_.Format(fmt, args));} + public static void Eq_rev(Object actl, Object expd) {Eq_wkr(expd, actl, true, EmptyStr);} + public static void Eq_rev(Object actl, Object expd, String fmt, Object... args) {Eq_wkr(expd, actl, true, String_.Format(fmt, args));} + public static void Eq_true(Object actl) {Eq_wkr(true, actl, true, EmptyStr);} + public static void Eq_true(Object actl, String fmt, Object... args) {Eq_wkr(true, actl, true, String_.Format(fmt, args));} + public static void Eq_false(Object actl) {Eq_wkr(false, actl, true, EmptyStr);} + public static void Eq_false(Object actl, String fmt, Object... args) {Eq_wkr(false, actl, true, String_.Format(fmt, args));} + public static void Eq_null(Object actl) {Eq_wkr(null, actl, true, EmptyStr);} + public static void Eq_null(Object actl, String fmt, Object... args) {Eq_wkr(null, actl, true, String_.Format(fmt, args));} + public static void Eq_nullNot(Object actl) {Eq_wkr(null, actl, false, EmptyStr);} + public static void Eq_nullNot(Object actl, String fmt, Object... args) {Eq_wkr(null, actl, false, String_.Format(fmt, args));} + public static void Fail_expdError() {Eq_wkr(true, false, true, "fail expd error");} + public static void Fail(String fmt, Object... args) {Eq_wkr(true, false, true, String_.Format(fmt, args));} + public static void Eq_ary(Object lhs, Object rhs) {Eq_ary_wkr(lhs, rhs, true, EmptyStr);} + public static void Eq_ary(Object lhs, Object rhs, String fmt, Object... args){Eq_ary_wkr(lhs, rhs, true, String_.Format(fmt, args));} + public static void Eq_ary_str(Object lhs, Object rhs, String note) {Eq_ary_wkr(lhs, rhs, false, note);} + public static void Eq_ary_str(Object lhs, Object rhs) {Eq_ary_wkr(lhs, rhs, false, EmptyStr);} + public static void Eq_list(List_adp lhs, List_adp rhs) {Eq_list_wkr(lhs, rhs, TfdsEqListItmStr_cls_default._, EmptyStr);} + public static void Eq_list(List_adp lhs, List_adp rhs, TfdsEqListItmStr xtoStr) {Eq_list_wkr(lhs, rhs, xtoStr, EmptyStr);} + static void Eq_able_wkr(EqAble lhs, EqAble rhs, boolean expd, String customMsg) { + boolean actl = false; + if (lhs == null && rhs != null) actl = false; + else if (lhs != null && rhs == null) actl = false; + else actl = lhs.Eq(rhs); + if (expd == actl) return; + String msg = msgBldr.Eq_xtoStr(lhs, rhs, customMsg); + throw Exc_.new_(msg); + } + static void Eq_wkr(Object lhs, Object rhs, boolean expd, String customMsg) { + boolean actl = Object_.Eq(lhs, rhs); + if (expd == actl) return; + String msg = msgBldr.Eq_xtoStr(lhs, rhs, customMsg); + throw Exc_.new_(msg); + } + static void Eq_ary_wkr(Object lhsAry, Object rhsAry, boolean compareUsingEquals, String customMsg) { + List_adp list = List_adp_.new_(); boolean pass = true; + int lhsLen = Array_.Len(lhsAry), rhsLen = Array_.Len(rhsAry); + for (int i = 0; i < lhsLen; i++) { + Object lhs = Array_.Get_at(lhsAry, i); + Object rhs = i >= rhsLen ? "<>" : Array_.Get_at(rhsAry, i); + String lhsString = msgBldr.Obj_xtoStr(lhs); String rhsString = msgBldr.Obj_xtoStr(rhs); // even if compareUsingEquals, method does ToStr on each itm for failMsg + boolean isEq = compareUsingEquals + ? Object_.Eq(lhs, rhs) + : Object_.Eq(lhsString, rhsString); + Eq_ary_wkr_addItm(list, i, isEq, lhsString, rhsString); + if (!isEq) pass = false; + } + for (int i = lhsLen; i < rhsLen; i++) { + String lhsString = "<>"; + String rhsString = msgBldr.Obj_xtoStr(Array_.Get_at(rhsAry, i)); + Eq_ary_wkr_addItm(list, i, false, lhsString, rhsString); + pass = false; + } + if (pass) return; + String msg = msgBldr.Eq_ary_xtoStr(list, lhsLen, rhsLen, customMsg); + throw Exc_.new_(msg); + } + static void Eq_list_wkr(List_adp lhsList, List_adp rhsList, TfdsEqListItmStr xtoStr, String customMsg) { + List_adp list = List_adp_.new_(); boolean pass = true; + int lhsLen = lhsList.Count(), rhsLen = rhsList.Count(); + for (int i = 0; i < lhsLen; i++) { + Object lhs = lhsList.Get_at(i); + Object rhs = i >= rhsLen ? null : rhsList.Get_at(i); + String lhsStr = xtoStr.XtoStr(lhs, lhs); + String rhsStr = rhs == null ? "<>" : xtoStr.XtoStr(rhs, lhs); + boolean isEq = Object_.Eq(lhsStr, rhsStr); if (!isEq) pass = false; + Eq_ary_wkr_addItm(list, i, isEq, lhsStr, rhsStr); + } + for (int i = lhsLen; i < rhsLen; i++) { + String lhsStr = "<>"; + Object rhs = rhsList.Get_at(i); + String rhsStr = xtoStr.XtoStr(rhs, null); + Eq_ary_wkr_addItm(list, i, false, lhsStr, rhsStr); + pass = false; + } + if (pass) return; + String msg = msgBldr.Eq_ary_xtoStr(list, lhsLen, rhsLen, customMsg); + throw Exc_.new_(msg); + } + static void Eq_ary_wkr_addItm(List_adp list, int i, boolean isEq, String lhsString, String rhsString) { + TfdsEqAryItm itm = new TfdsEqAryItm().Idx_(i).Eq_(isEq).Lhs_(lhsString).Rhs_(rhsString); + list.Add(itm); + } + public static void Err_classMatch(Exception exc, Class type) { + boolean match = ClassAdp_.Eq_typeSafe(exc, type); + if (!match) throw Exc_.new_w_type("Tfds", "error types do not match", "expdType", ClassAdp_.FullNameOf_type(type), "actlType", ClassAdp_.NameOf_obj(exc), "actlMsg", Err_.Message_lang(exc)); + } + public static void Eq_err(Err expd, Exception actlExc) { + Tfds.Eq(XtoStr_Err(expd), XtoStr_Err(actlExc)); + } + public static void Err_has(Exception e, String hdr) { + Tfds.Eq_true(String_.Has(Err_.Message_gplx_brief(e), hdr), "could not find '{0}' in '{1}'", hdr, Err_.Message_gplx_brief(e)); + } + static String XtoStr_Err(Exception e) { + Err err = Err_.as_(e); if (err == null) return Err_.Message_lang(e); + String_bldr sb = String_bldr_.new_(); + sb.Add(err.Hdr()).Add(":"); + for (Object kvo : err.Args()) { + KeyVal kv = (KeyVal)kvo; + if (sb.Count() != 0) sb.Add(" "); + sb.Add_fmt("{0}={1}", kv.Key(), kv.Val()); + } + return sb.XtoStr(); + } + static final String EmptyStr = TfdsMsgBldr.EmptyStr; + static TfdsMsgBldr msgBldr = TfdsMsgBldr.new_(); + public static final Io_url RscDir = Io_url_.Usr().GenSubDir_nest("xowa", "dev", "tst"); + public static DateAdp Now_time0_add_min(int minutes) {return time0.Add_minute(minutes);} + @gplx.Internal protected static boolean Now_enabled() {return now_enabled;} static boolean now_enabled; + public static void Now_enabled_n_() {now_enabled = false;} + public static void Now_set(DateAdp date) {now_enabled = true; nowTime = date;} + public static void Now_enabled_y_() {now_enabled = true; nowTime = time0;} + @gplx.Internal protected static DateAdp Now() { + DateAdp rv = nowTime; + nowTime = rv.Add_minute(1); + return rv; + } + private static final DateAdp time0 = DateAdp_.parse_gplx("2001-01-01 00:00:00.000"); + private static DateAdp nowTime; // NOTE: cannot set to time0 due to static initialization; + public static void WriteText(String text) {ConsoleAdp._.WriteText(text);} + public static void Write_bry(byte[] ary) {Write(String_.new_u8(ary));} + public static void Write() {Write("tmp");} + public static void Write(Object... ary) { + String_bldr sb = String_bldr_.new_(); + int aryLen = Array_.Len(ary); + for (int i = 0; i < aryLen; i++) + sb.Add_many("'", Object_.Xto_str_strict_or_null_mark(ary[i]), "'", " "); + WriteText(sb.XtoStr() + String_.CrLf); + } +} +class TfdsEqListItmStr_cls_default implements TfdsEqListItmStr { + public String XtoStr(Object cur, Object actl) { + return Object_.Xto_str_strict_or_null_mark(cur); + } + public static final TfdsEqListItmStr_cls_default _ = new TfdsEqListItmStr_cls_default(); TfdsEqListItmStr_cls_default() {} +} +class TfdsEqAryItm { + public int Idx() {return idx;} public TfdsEqAryItm Idx_(int v) {idx = v; return this;} int idx; + public String Lhs() {return lhs;} public TfdsEqAryItm Lhs_(String v) {lhs = v; return this;} private String lhs; + public String Rhs() {return rhs;} public TfdsEqAryItm Rhs_(String v) {rhs = v; return this;} private String rhs; + public boolean Eq() {return eq;} public TfdsEqAryItm Eq_(boolean v) {eq = v; return this;} private boolean eq; +} +class TfdsMsgBldr { + public String Eq_xtoStr(Object expd, Object actl, String customMsg) { + String expdString = Obj_xtoStr(expd); String actlString = Obj_xtoStr(actl); + String detail = String_.Concat + ( CustomMsg_xtoStr(customMsg) + , "\t\t", "expd: ", expdString, String_.CrLf + , "\t\t", "actl: ", actlString, String_.CrLf + ); + return WrapMsg(detail); + } + public String Eq_ary_xtoStr(List_adp list, int lhsAryLen, int rhsAryLen, String customMsg) { + String_bldr sb = String_bldr_.new_(); + sb.Add(CustomMsg_xtoStr(customMsg)); + if (lhsAryLen != rhsAryLen) + sb.Add_fmt_line("{0}element counts differ: {1} {2}", "\t\t", lhsAryLen, rhsAryLen); + int lhsLenMax = 0, rhsLenMax = 0; + for (int i = 0; i < list.Count(); i++) { + TfdsEqAryItm itm = (TfdsEqAryItm)list.Get_at(i); + int lhsLen = String_.Len(itm.Lhs()), rhsLen = String_.Len(itm.Rhs()); + if (lhsLen > lhsLenMax) lhsLenMax = lhsLen; + if (rhsLen > rhsLenMax) rhsLenMax = rhsLen; + } + for (int i = 0; i < list.Count(); i++) { + TfdsEqAryItm itm = (TfdsEqAryItm)list.Get_at(i); + sb.Add_fmt_line("{0}: {1} {2} {3}" + , Int_.Xto_str_pad_bgn_zero(itm.Idx(), 4) + , String_.PadBgn(itm.Lhs(), lhsLenMax, " ") + , itm.Eq() ? "==" : "!=" + , String_.PadBgn(itm.Rhs(), rhsLenMax, " ") + ); + } +// String compSym = isEq ? " " : "!="; +// String result = String_.Format("{0}: {1}{2} {3} {4}", Int_.Xto_str_pad_bgn_zero(i, 4), lhsString, String_.CrLf + "\t\t", compSym, rhsString); +// foreach (Object obj in list) { +// String itmComparison = (String)obj; +// sb.Add_fmt_line("{0}{1}", "\t\t", itmComparison); +// } + return WrapMsg(sb.XtoStr()); + } + String CustomMsg_xtoStr(String customMsg) { + return (customMsg == EmptyStr) + ? "" + : String_.Concat(customMsg, String_.CrLf); + } + public String Obj_xtoStr(Object obj) { + String s = String_.as_(obj); + if (s != null) return String_.Concat("'", s, "'"); // if Object is String, put quotes around it for legibility + XtoStrAble xtoStrAble = XtoStrAble_.as_(obj); + if (xtoStrAble != null) return xtoStrAble.XtoStr(); + return Object_.Xto_str_strict_or_null_mark(obj); + } + String WrapMsg(String text) { + return String_.Concat(String_.CrLf + , "************************************************************************************************", String_.CrLf + , text + , "________________________________________________________________________________________________" + ); + } + public static TfdsMsgBldr new_() {return new TfdsMsgBldr();} TfdsMsgBldr() {} + public static final String EmptyStr = ""; +} diff --git a/100_core/src_800_tst/gplx/TfdsEqListItmStr.java b/100_core/src_800_tst/gplx/TfdsEqListItmStr.java new file mode 100644 index 000000000..92d98f50e --- /dev/null +++ b/100_core/src_800_tst/gplx/TfdsEqListItmStr.java @@ -0,0 +1,21 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public interface TfdsEqListItmStr { + String XtoStr(Object cur, Object actl); +} diff --git a/100_core/src_800_tst/gplx/Tfds_tst.java b/100_core/src_800_tst/gplx/Tfds_tst.java new file mode 100644 index 000000000..a3d9fd624 --- /dev/null +++ b/100_core/src_800_tst/gplx/Tfds_tst.java @@ -0,0 +1,29 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class Tfds_tst { + @Before public void init() {fxt.Clear();} private final Tfds_fxt fxt = new Tfds_fxt(); + @Test public void Basic() { + } +} +class Tfds_fxt { + public void Clear() {} + public void Test() { + } +} diff --git a/100_core/src_900_xml/gplx/Base64_utl.java b/100_core/src_900_xml/gplx/Base64_utl.java new file mode 100644 index 000000000..681c0f580 --- /dev/null +++ b/100_core/src_900_xml/gplx/Base64_utl.java @@ -0,0 +1,24 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Base64_utl { + public static void Encode(Bry_bfr bfr, byte[] bry, int bgn, int end) { + for (int i = bgn; i < end; ++i) { + } + } +} diff --git a/100_core/src_900_xml/gplx/Base85_utl.java b/100_core/src_900_xml/gplx/Base85_utl.java new file mode 100644 index 000000000..b9a014736 --- /dev/null +++ b/100_core/src_900_xml/gplx/Base85_utl.java @@ -0,0 +1,66 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class Base85_utl { + public static String XtoStr(int val, int minLen) {return String_.new_u8(XtoStrByAry(val, null, 0, minLen));} + public static byte[] XtoStrByAry(int val, int minLen) {return XtoStrByAry(val, null, 0, minLen);} + public static byte[] XtoStrByAry(int val, byte[] ary, int aryPos, int minLen) { + int strLen = DigitCount(val); + int aryLen = strLen, padLen = 0; + boolean pad = aryLen < minLen; + if (pad) { + padLen = minLen - aryLen; + aryLen = minLen; + } + if (ary == null) ary = new byte[aryLen]; + if (pad) { + for (int i = 0; i < padLen; i++) // fill ary with padLen + ary[i + aryPos] = AsciiOffset; + } + for (int i = aryLen - padLen; i > 0; i--) { + int div = Pow85[i - 1]; + byte tmp = (byte)(val / div); + ary[aryPos + aryLen - i] = (byte)(tmp + AsciiOffset); + val -= tmp * div; + } + return ary; + } + public static byte XtoByteChar(int v) {return (byte)(v + AsciiOffset);} + public static int XtoInt(byte v) {return v - AsciiOffset;} + public static int XtoIntByStr(String s) { + byte[] ary = Bry_.new_u8(s); + return XtoIntByAry(ary, 0, ary.length - 1); + } + public static int XtoIntByAry(byte[] ary, int bgn, int end) { + int rv = 0, factor = 1; + for (int i = end; i >= bgn; i--) { + rv += (ary[i] - AsciiOffset) * factor; + factor *= Radix; + } + return rv; + } + public static int DigitCount(int v) { + if (v == 0) return 1; + for (int i = Pow85Last; i > -1; i--) + if (v >= Pow85[i]) return i + 1; + throw Exc_.new_("neg number not allowed", "v", v); + } + static int[] Pow85 = new int[]{1, 85, 7225, 614125, 52200625}; // NOTE: ary constructed to match index to exponent; Pow85[1] = 85^1 + static final int Pow85Last = 4, Radix = 85; static final byte AsciiOffset = 33; + public static final int Len_int = 5; +} diff --git a/100_core/src_900_xml/gplx/Base85_utl_tst.java b/100_core/src_900_xml/gplx/Base85_utl_tst.java new file mode 100644 index 000000000..be649d09c --- /dev/null +++ b/100_core/src_900_xml/gplx/Base85_utl_tst.java @@ -0,0 +1,56 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class Base85_utl_tst { + @Test public void Log() { + tst_Log( 0, 1); + tst_Log( 84, 1); + tst_Log( 85, 2); + tst_Log( 7224, 2); + tst_Log( 7225, 3); + tst_Log( 614124, 3); + tst_Log( 614125, 4); + tst_Log( 52200624, 4); + tst_Log( 52200625, 5); + tst_Log(Int_.MaxValue, 5); + } void tst_Log(int val, int expd) {Tfds.Eq(expd, Base85_utl.DigitCount(val));} + @Test public void XtoStr() { + tst_XtoStr( 0, "!"); + tst_XtoStr( 84, "u"); + tst_XtoStr( 85, "\"!"); + tst_XtoStr( 7224, "uu"); + tst_XtoStr( 7225, "\"!!"); + tst_XtoStr( 614124, "uuu"); + tst_XtoStr( 614125, "\"!!!"); + tst_XtoStr( 52200624, "uuuu"); + tst_XtoStr( 52200625, "\"!!!!"); + } + void tst_XtoStr(int val, String expd) { + String actl = Base85_utl.XtoStr(val, 0); + Tfds.Eq(expd, actl); + Tfds.Eq(val, Base85_utl.XtoIntByStr(expd)); + } + @Test public void XtoStrAry() { + byte[] ary = new byte[9]; + run_XtoStr(ary, 0, 2); // !!# + run_XtoStr(ary, 3, 173); // !#$ + run_XtoStr(ary, 6, 14709); // #$% + Tfds.Eq("!!#!#$#$%", String_.new_u8(ary)); + } void run_XtoStr(byte[] ary, int aryPos, int val) {Base85_utl.XtoStrByAry(val, ary, aryPos, 3);} +} diff --git a/100_core/src_900_xml/gplx/HierStrBldr.java b/100_core/src_900_xml/gplx/HierStrBldr.java new file mode 100644 index 000000000..d2f2bd5ea --- /dev/null +++ b/100_core/src_900_xml/gplx/HierStrBldr.java @@ -0,0 +1,56 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.core.strings.*; +public class HierStrBldr { + public String Root() {return root;} public HierStrBldr Root_(String v) {root = v; return this;} private String root; + public Io_url RootAsIoUrl() {return Io_url_.new_dir_(root);} + public String DirFmt() {return dirFmt;} private String dirFmt; + public String DirSpr() {return dirSpr;} private String dirSpr = Op_sys.Cur().Fsys_dir_spr_str(); + public String FilFmt() {return filFmt;} private String filFmt; + public String NumFmt() {return numFmt;} private String numFmt; + public int[] FilCountMaxs() {return filCountMaxs;} int[] filCountMaxs; + public Io_url GenStrIdxOnlyAsoUrl(int idx) {return Io_url_.new_fil_(GenStrIdxOnly(idx));} + public String GenStrIdxOnly(int idx) {return GenStr(String_.Ary_empty, idx);} + public Io_url GenStrAsIoUrl(String[] subDirs, int idx) { + return Io_url_.new_fil_(GenStr(subDirs, idx)); + } + String GenStr(String[] subDirs, int idx) { + String_bldr sb = String_bldr_.new_(); + sb.Add(root); + for (String subDir : subDirs) + sb.Add(subDir).Add(dirSpr); + int multiple = 1; + int[] multipleAry = new int[filCountMaxs.length]; + for (int i = filCountMaxs.length - 1; i >= 0; i--) { + multiple *= filCountMaxs[i]; + multipleAry[i] = (idx / multiple) * multiple; // NOTE: rounds down to multiple; EX: 11 -> 10 + } + for (int i = 0; i < multipleAry.length; i++) + sb.Add_fmt(dirFmt, Int_.Xto_str_fmt(multipleAry[i], numFmt)); + sb.Add_fmt(filFmt, Int_.Xto_str_fmt(idx, numFmt)); + return sb.XtoStr(); + } + public HierStrBldr Ctor_io(Io_url root, String dirFmt, String filFmt, String numFmt, int... filCountMaxs) { + this.Ctor(root.Raw(), dirFmt + dirSpr, filFmt, numFmt, filCountMaxs); + return this; + } + public void Ctor(String root, String dirFmt, String filFmt, String numFmt, int... filCountMaxs) { + this.root = root; this.dirFmt = dirFmt; this.filFmt = filFmt; this.numFmt = numFmt; this.filCountMaxs = filCountMaxs; + } +} diff --git a/100_core/src_900_xml/gplx/HierStrBldr_tst.java b/100_core/src_900_xml/gplx/HierStrBldr_tst.java new file mode 100644 index 000000000..68db38e89 --- /dev/null +++ b/100_core/src_900_xml/gplx/HierStrBldr_tst.java @@ -0,0 +1,47 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +import gplx.ios.*; import gplx.texts.*; +public class HierStrBldr_tst { + @Before public void setup() {bldr = new HierStrBldr();} HierStrBldr bldr; + @Test public void Hier0() { + bldr.Ctor("/root/", "dir_{0}/", "idx_{0}.csv", "000"); + tst_MakeName( 0, "/root/idx_000.csv"); + tst_MakeName( 1, "/root/idx_001.csv"); + tst_MakeName(10, "/root/idx_010.csv"); + } + @Test public void Hier1() { + bldr.Ctor("/root/", "dir_{0}/", "idx_{0}.csv", "000", 10); + tst_MakeName( 0, "/root/dir_000/idx_000.csv"); + tst_MakeName( 1, "/root/dir_000/idx_001.csv"); + tst_MakeName(10, "/root/dir_010/idx_010.csv"); + } + @Test public void Hier2() { + bldr.Ctor("/root/", "dir_{0}/", "idx_{0}.csv", "000", 5, 10); + tst_MakeName( 0, "/root/dir_000/dir_000/idx_000.csv"); + tst_MakeName( 1, "/root/dir_000/dir_000/idx_001.csv"); + tst_MakeName( 10, "/root/dir_000/dir_010/idx_010.csv"); + tst_MakeName( 49, "/root/dir_000/dir_040/idx_049.csv"); + tst_MakeName( 50, "/root/dir_050/dir_050/idx_050.csv"); + tst_MakeName( 99, "/root/dir_050/dir_090/idx_099.csv"); + tst_MakeName(100, "/root/dir_100/dir_100/idx_100.csv"); + tst_MakeName(110, "/root/dir_100/dir_110/idx_110.csv"); + } + void tst_MakeName(int val, String expd) {Tfds.Eq(expd, bldr.GenStrIdxOnly(val));} +} diff --git a/100_core/src_900_xml/gplx/xmls/XmlAtr.java b/100_core/src_900_xml/gplx/xmls/XmlAtr.java new file mode 100644 index 000000000..d99b1b427 --- /dev/null +++ b/100_core/src_900_xml/gplx/xmls/XmlAtr.java @@ -0,0 +1,24 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.xmls; import gplx.*; +import org.w3c.dom.Node; +public class XmlAtr { + public String Name() {return xatr.getNodeName();} + public String Value() {return xatr.getNodeValue();} + @gplx.Internal protected XmlAtr(Node xatr) {this.xatr = xatr;} Node xatr; +} diff --git a/100_core/src_900_xml/gplx/xmls/XmlAtrList.java b/100_core/src_900_xml/gplx/xmls/XmlAtrList.java new file mode 100644 index 000000000..3553fab23 --- /dev/null +++ b/100_core/src_900_xml/gplx/xmls/XmlAtrList.java @@ -0,0 +1,37 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.xmls; import gplx.*; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +public class XmlAtrList { + public int Count() {return list == null ? 0 : list.getLength();} + public String FetchValOr(String key, String or) { + Node xatr = list.getNamedItem(key); + return (xatr == null) ? or : xatr.getNodeValue(); + } + public XmlAtr Fetch(String key) { + Node xatr = list.getNamedItem(key); if (xatr == null) throw Err_arg.notFound_key_("key", key); + return new XmlAtr(xatr); + } + public XmlAtr Fetch_or_null(String key) { + Node xatr = list.getNamedItem(key); if (xatr == null) return null; + return new XmlAtr(xatr); + } + public XmlAtr Get_at(int i) {return list == null ? null : new XmlAtr(list.item(i));} + @gplx.Internal protected XmlAtrList(NamedNodeMap list) {this.list = list;} NamedNodeMap list; +} diff --git a/100_core/src_900_xml/gplx/xmls/XmlDoc.java b/100_core/src_900_xml/gplx/xmls/XmlDoc.java new file mode 100644 index 000000000..7c2df540a --- /dev/null +++ b/100_core/src_900_xml/gplx/xmls/XmlDoc.java @@ -0,0 +1,24 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.xmls; import gplx.*; +import org.w3c.dom.Document; +public class XmlDoc { + public XmlNde Root() {return new XmlNde(xdoc.getDocumentElement());} + @gplx.Internal protected XmlDoc(Document xdoc) {this.xdoc = xdoc;} Document xdoc; +} +//#} \ No newline at end of file diff --git a/100_core/src_900_xml/gplx/xmls/XmlDoc_.java b/100_core/src_900_xml/gplx/xmls/XmlDoc_.java new file mode 100644 index 000000000..05eba9976 --- /dev/null +++ b/100_core/src_900_xml/gplx/xmls/XmlDoc_.java @@ -0,0 +1,53 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.xmls; import gplx.*; +import gplx.Io_url; +import java.io.File; +import java.io.IOException; +import java.io.StringReader; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import org.w3c.dom.Document; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +public class XmlDoc_ { + public static XmlDoc parse_(String raw) {return new XmlDoc(doc_(raw));} + static Document doc_(String raw) { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + DocumentBuilder bldr = null; + try {bldr = factory.newDocumentBuilder();} + catch (ParserConfigurationException e) {throw Exc_.new_exc(e, "xml", "failed to create newDocumentBuilder");} + StringReader reader = new StringReader(raw); + InputSource source = new InputSource(reader); + Document doc = null; + try {doc = bldr.parse(source);} + catch (SAXException e) {throw Exc_.new_exc(e, "xml", "failed to parse xml", "raw", raw);} + catch (IOException e) {throw Exc_.new_exc(e, "xml", "failed to parse xml", "raw", raw);} + return doc; + } + public static final String Err_XmlException = "gplx.xmls.XmlException"; +} +//#} \ No newline at end of file diff --git a/100_core/src_900_xml/gplx/xmls/XmlDoc_tst.java b/100_core/src_900_xml/gplx/xmls/XmlDoc_tst.java new file mode 100644 index 000000000..50c8f71ea --- /dev/null +++ b/100_core/src_900_xml/gplx/xmls/XmlDoc_tst.java @@ -0,0 +1,71 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.xmls; import gplx.*; +import org.junit.*; +public class XmlDoc_tst { + String xml; XmlDoc xdoc; XmlNde xnde; + @Test public void parse_() { + xml = String_.Concat(""); + xdoc = XmlDoc_.parse_(xml); + Tfds.Eq("root", xdoc.Root().Name()); + Tfds.Eq(true, xdoc.Root().NdeType_element()); + } + @Test public void Xml_outer() { + xml = String_.Concat + ( "" + , "" + , "" + , "" + , "" + , "" + ); + xdoc = XmlDoc_.parse_(xml); + xnde = xdoc.Root().SubNdes().Get_at(0); + Tfds.Eq("a", xnde.Name()); + Tfds.Eq("", xnde.Xml_outer()); + } + @Test public void Text_inner() { + xml = String_.Concat + ( "" + , "" + , "test me" + , "" + , "" + ); + xdoc = XmlDoc_.parse_(xml); + xnde = xdoc.Root().SubNdes().Get_at(0); + Tfds.Eq("a", xnde.Name()); + Tfds.Eq("test me", xnde.Text_inner()); + } + @Test public void Atrs() { + xml = String_.Concat + ( "" + , "" + ); + xdoc = XmlDoc_.parse_(xml); + XmlAtrList atrs = xdoc.Root().Atrs(); + XmlAtr atr = atrs.Get_at(1); + tst_Atr(atr, "atr1", "1"); + atr = atrs.Get_at(1); + tst_Atr(atr, "atr1", "1"); + } + void tst_Atr(XmlAtr atr, String expdName, String expdVal) { + Tfds.Eq(expdName, atr.Name()); + Tfds.Eq(expdVal, atr.Value()); + } +} diff --git a/100_core/src_900_xml/gplx/xmls/XmlFileSplitter.java b/100_core/src_900_xml/gplx/xmls/XmlFileSplitter.java new file mode 100644 index 000000000..734b5bfaf --- /dev/null +++ b/100_core/src_900_xml/gplx/xmls/XmlFileSplitter.java @@ -0,0 +1,140 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.xmls; import gplx.*; +import gplx.ios.*; +import gplx.texts.*; +public class XmlFileSplitter { + public XmlFileSplitterOpts Opts() {return opts;} XmlFileSplitterOpts opts = new XmlFileSplitterOpts(); + public byte[] Hdr() {return hdr;} private byte[] hdr; + public void Clear() {hdr = null;} + public void Split(Io_url xmlUrl) { + Io_url partDir = opts.PartDir(); + byte[] xmlEndTagAry = Bry_.new_u8(opts.XmlEnd()); + byte[][] nameAry = XtoByteAry(opts.XmlNames()); + int partIdx = 0; + + // bgn reading file + XmlSplitRdr rdr = new XmlSplitRdr().Init_(xmlUrl, opts.FileSizeMax()); + + // split hdr: includes , xmlNamespaces, and any DTD headers; will be prepended to each partFile + rdr.Read(); + int findPos = FindMatchPos(rdr.CurAry(), nameAry); if (findPos == String_.Find_none) throw Exc_.new_("could not find any names in first segment"); + byte[] dataAry = SplitHdr(rdr.CurAry(), findPos); + if (opts.XmlBgn() != null) + hdr = Bry_.new_u8(opts.XmlBgn()); + byte[] tempAry = new byte[0]; + int newFindPos = FindMatchPosRev(dataAry, nameAry); + findPos = (newFindPos <= findPos) ? String_.Find_none : newFindPos; + boolean first = true; + + // split files + XmlSplitWtr partWtr = new XmlSplitWtr().Init_(partDir, hdr, opts); + while (true) { + partWtr.Bgn(partIdx++); + if (opts.StatusFmt() != null) ConsoleAdp._.WriteLine(String_.Format(opts.StatusFmt(), partWtr.Url().NameOnly())); + partWtr.Write(tempAry); + if (!first) { + rdr.Read(); + dataAry = rdr.CurAry(); + findPos = FindMatchPosRev(dataAry, nameAry); + } + else + first = false; + + // find last closing node + while (findPos == String_.Find_none) { + if (rdr.Done()) { + findPos = rdr.CurRead(); + break; + } + else { + partWtr.Write(dataAry); + rdr.Read(); + dataAry = rdr.CurAry(); + findPos = FindMatchPosRev(dataAry, nameAry); + } + } + + byte[][] rv = SplitRest(dataAry, findPos); + partWtr.Write(rv[0]); + tempAry = rv[1]; + boolean done = rdr.Done() && tempAry.length == 0; + if (!done) + partWtr.Write(xmlEndTagAry); + partWtr.Rls(); + if (done) break; + } + rdr.Rls(); + } + public byte[] SplitHdr(byte[] src, int findPos) { + hdr = new byte[findPos]; + Array_.CopyTo(src, 0, hdr, 0, findPos); + byte[] rv = new byte[src.length - findPos]; + Array_.CopyTo(src, findPos, rv, 0, rv.length); + return rv; + } + public byte[][] SplitRest(byte[] src, int findPos) { + byte[][] rv = new byte[2][]; + rv[0] = new byte[findPos]; + Array_.CopyTo(src, 0, rv[0], 0, findPos); + rv[1] = new byte[src.length - findPos]; + Array_.CopyTo(src, findPos, rv[1], 0, rv[1].length); + return rv; + } + public int FindMatchPos(byte[] src, byte[][] wordAry) {return FindMatchPos(src, wordAry, true);} + public int FindMatchPosRev(byte[] src, byte[][] wordAry) {return FindMatchPos(src, wordAry, false);} + int FindMatchPos(byte[] src, byte[][] wordAry, boolean fwd) { + int[] findAry = new int[wordAry.length]; + for (int i = 0; i < findAry.length; i++) + findAry[i] = fwd ? -1 : Int_.MaxValue; + for (int i = 0; i < wordAry.length; i++) { // look at each word in wordAry + int srcLen = src.length, srcPos, srcEnd, srcDif; + if (fwd) {srcPos = 0; srcEnd = srcLen; srcDif = 1;} + else {srcPos = srcLen - 1; srcEnd = -1; srcDif = -1;} + while (srcPos != srcEnd) { // look at each byte in src + byte[] ary = wordAry[i]; + int aryLen = ary.length, aryPos, aryEnd, aryDif; + if (fwd) {aryPos = 0; aryEnd = aryLen; aryDif = 1;} + else {aryPos = aryLen - 1; aryEnd = -1; aryDif = -1;} + boolean found = true; + while (aryPos != aryEnd) { // look at each byte in word + int lkpPos = srcPos + aryPos; + if (lkpPos >= srcLen) {found = false; break;} // outside bounds; exit + if (ary[aryPos] != src[lkpPos]) {found = false; break;} // srcByte doesn't match wordByte; exit + aryPos += aryDif; + } + if (found) {findAry[i] = srcPos; break;} // result found; stop now and keep "best" result + srcPos += srcDif; + } + } + int best = fwd ? -1 : Int_.MaxValue; + for (int find : findAry) { + if ((fwd && find > best) + || (!fwd && find < best)) + best = find; + } + if (best == Int_.MaxValue) best = -1; + return best; + } + byte[][] XtoByteAry(String[] names) { + byte[][] rv = new byte[names.length][]; + for (int i = 0; i < names.length; i++) + rv[i] = Bry_.new_u8(names[i]); + return rv; + } +} diff --git a/100_core/src_900_xml/gplx/xmls/XmlFileSplitterOpts.java b/100_core/src_900_xml/gplx/xmls/XmlFileSplitterOpts.java new file mode 100644 index 000000000..39825f2d8 --- /dev/null +++ b/100_core/src_900_xml/gplx/xmls/XmlFileSplitterOpts.java @@ -0,0 +1,27 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.xmls; import gplx.*; +public class XmlFileSplitterOpts { + public int FileSizeMax() {return fileSizeMax;} public XmlFileSplitterOpts FileSizeMax_(int v) {fileSizeMax = v; return this;} int fileSizeMax = 1024 * 1024; + public String[] XmlNames() {return xmlNames;} public XmlFileSplitterOpts XmlNames_(String... v) {xmlNames = v; return this;} private String[] xmlNames; + public String XmlBgn() {return xmlBgn;} public XmlFileSplitterOpts XmlBgn_(String v) {xmlBgn = v; return this;} private String xmlBgn; + public String XmlEnd() {return xmlEnd;} public XmlFileSplitterOpts XmlEnd_(String v) {xmlEnd = v; return this;} private String xmlEnd; + public Io_url PartDir() {return partDir;} public XmlFileSplitterOpts PartDir_(Io_url v) {partDir = v; return this;} Io_url partDir; + public String StatusFmt() {return statusFmt;} public XmlFileSplitterOpts StatusFmt_(String v) {statusFmt = v; return this;} private String statusFmt = "splitting {0}"; + public HierStrBldr Namer() {return namer;} HierStrBldr namer = new HierStrBldr(); +} diff --git a/100_core/src_900_xml/gplx/xmls/XmlFileSplitter_tst.java b/100_core/src_900_xml/gplx/xmls/XmlFileSplitter_tst.java new file mode 100644 index 000000000..3614916fc --- /dev/null +++ b/100_core/src_900_xml/gplx/xmls/XmlFileSplitter_tst.java @@ -0,0 +1,88 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.xmls; import gplx.*; +import org.junit.*; +import gplx.ios.*; import gplx.texts.*; +public class XmlFileSplitter_tst { + @Before public void setup() { + splitter = new XmlFileSplitter(); + Io_mgr.I.InitEngine_mem(); + } XmlFileSplitter splitter; + @Test public void FindMatchPos() { + tst_FindMatchPos("abcde", "a", 0); + tst_FindMatchPos("abcde", "b", 1); + tst_FindMatchPos("abcde", "cd", 2); + tst_FindMatchPos("abcde", "f", -1); + tst_FindMatchPos("abcde", "fg", -1); + } void tst_FindMatchPos(String src, String find, int expd) {Tfds.Eq(expd, splitter.FindMatchPos(byte_(src), byteAry_(find)));} + @Test public void FindMatchPosRev() { + tst_FindMatchPosRev("abcde", "a", 0); + tst_FindMatchPosRev("abcde", "b", 1); + tst_FindMatchPosRev("abcde", "cd", 2); + tst_FindMatchPosRev("abcde", "f", -1); + tst_FindMatchPosRev("abcde", "ef", -1); + tst_FindMatchPosRev("abcde", "za", -1); + tst_FindMatchPosRev("dbcde", "d", 3); + } void tst_FindMatchPosRev(String src, String find, int expd) {Tfds.Eq(expd, splitter.FindMatchPosRev(byte_(src), byteAry_(find)));} + @Test public void ExtractHdr() { + tst_ExtractHdr("", "", ""); + } + @Test public void Split() { + splitter.Opts().FileSizeMax_(30).XmlNames_(""); + tst_Split + ( "" + , "" + , "" + , "" + ); + tst_Split + ( "" + , "" + , "" + ); + } + void tst_Split(String txt, String... expd) { + Io_url xmlFil = Io_url_.mem_fil_("mem/800_misc/txt.xml"); + Io_url tmpDir = xmlFil.OwnerDir().GenSubDir("temp_xml"); + Io_mgr.I.DeleteDirDeep(tmpDir); + splitter.Opts().StatusFmt_(null).PartDir_(tmpDir); + splitter.Opts().Namer().Ctor_io(tmpDir, "", "fil_{0}.xml", "000"); + Io_mgr.I.SaveFilStr(xmlFil, txt); + splitter.Split(xmlFil); + Io_url[] tmpFilAry = Io_mgr.I.QueryDir_fils(tmpDir); + Tfds.Eq(expd.length, tmpFilAry.length); + for (int i = 0; i < tmpFilAry.length; i++) { + Io_url tmpFil = tmpFilAry[i]; + Tfds.Eq(expd[i], Io_mgr.I.LoadFilStr(tmpFil)); + } + } + byte[] byte_(String s) {return Bry_.new_u8(s);} + byte[][] byteAry_(String s) { + byte[][] rv = new byte[1][]; + rv[0] = Bry_.new_u8(s); + return rv; + } + void tst_ExtractHdr(String src, String find, String expdHdr, String expdSrc) { + splitter.Clear(); + byte[] srcAry = byte_(src); + int findPos = splitter.FindMatchPos(srcAry, byteAry_(find)); + srcAry = splitter.SplitHdr(srcAry, findPos); + Tfds.Eq(String_.new_u8(splitter.Hdr()), expdHdr); + Tfds.Eq(String_.new_u8(srcAry), expdSrc); + } +} diff --git a/100_core/src_900_xml/gplx/xmls/XmlNde.java b/100_core/src_900_xml/gplx/xmls/XmlNde.java new file mode 100644 index 000000000..3d70ff751 --- /dev/null +++ b/100_core/src_900_xml/gplx/xmls/XmlNde.java @@ -0,0 +1,51 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.xmls; import gplx.*; +import java.io.StringWriter; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.TransformerFactoryConfigurationError; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import org.w3c.dom.Node; +public class XmlNde { + public XmlAtrList Atrs() {return new XmlAtrList(xnde.getAttributes());} + public XmlNdeList SubNdes() {return new XmlNdeList_cls_xml(xnde.getChildNodes());} + public String Name() {return xnde.getNodeName();} + public String Xml_outer() { + Transformer transformer = transformer_(); + StringWriter writer = new StringWriter(); + try {transformer.transform(new DOMSource(xnde), new StreamResult(writer));} + catch (TransformerException e) {throw Exc_.new_exc(e, "xml", "failed to get xml string");} + return writer.toString(); + } + public String Text_inner() {return xnde.getTextContent();} + public boolean NdeType_element() {return xnde.getNodeType() == Node.ELEMENT_NODE;} + public boolean NdeType_textOrEntityReference() {return xnde.getNodeType() == Node.TEXT_NODE || xnde.getNodeType() == Node.ENTITY_REFERENCE_NODE;} + @gplx.Internal protected XmlNde(Node xnde) {this.xnde = xnde;} Node xnde; + static Transformer transformer_() { + TransformerFactory transformerfactory = TransformerFactory.newInstance(); + Transformer transformer = null; + try {transformer = transformerfactory.newTransformer();} + catch (TransformerConfigurationException e) {throw Exc_.new_exc(e, "xml", "failed to get create transformer");} + transformer.setOutputProperty("omit-xml-declaration", "yes"); + return transformer; + } + } diff --git a/100_core/src_900_xml/gplx/xmls/XmlNdeList.java b/100_core/src_900_xml/gplx/xmls/XmlNdeList.java new file mode 100644 index 000000000..fe12b87fd --- /dev/null +++ b/100_core/src_900_xml/gplx/xmls/XmlNdeList.java @@ -0,0 +1,35 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.xmls; import gplx.*; +import org.w3c.dom.NodeList; +public interface XmlNdeList { + int Count(); + XmlNde Get_at(int i); +} +class XmlNdeList_cls_xml implements XmlNdeList { + public int Count() {return list.getLength();} + public XmlNde Get_at(int i) {return new XmlNde(list.item(i));} + @gplx.Internal protected XmlNdeList_cls_xml(NodeList list) {this.list = list;} NodeList list; +} +class XmlNdeList_cls_list implements XmlNdeList { + public int Count() {return list.Count();} + public XmlNde Get_at(int i) {return (XmlNde)list.Get_at(i);} + public void Add(XmlNde xnde) {list.Add(xnde);} + @gplx.Internal protected XmlNdeList_cls_list(int count) {list = List_adp_.new_(); list.Resize_bounds(count);} List_adp list; +} +//#} \ No newline at end of file diff --git a/100_core/src_900_xml/gplx/xmls/XmlSplitRdr.java b/100_core/src_900_xml/gplx/xmls/XmlSplitRdr.java new file mode 100644 index 000000000..83dec3b2c --- /dev/null +++ b/100_core/src_900_xml/gplx/xmls/XmlSplitRdr.java @@ -0,0 +1,51 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.xmls; import gplx.*; +import gplx.ios.*; +public class XmlSplitRdr { + public byte[] CurAry() {return curAry;} private byte[] curAry; + public long CurSum() {return curSum;} long curSum; + public int CurRead() {return curRead;} int curRead; + public boolean Done() {return done;} private boolean done; + public XmlSplitRdr InitAll_(Io_url url) { + stream = Io_mgr.I.OpenStreamRead(url); + curLen = stream.Len(); + curAry = new byte[(int)curLen]; + curSum = 0; + curRead = 0; + done = false; + return this; + } + public XmlSplitRdr Init_(Io_url url, int curArySize) { + stream = Io_mgr.I.OpenStreamRead(url); + curLen = Io_mgr.I.QueryFil(url).Size(); + curAry = new byte[curArySize]; + curSum = 0; + curRead = 0; + done = false; + return this; + } IoStream stream; long curLen; + public void Read() { + curRead = stream.ReadAry(curAry); + curSum += curRead; + done = curSum == curLen; + if (done && curRead != curAry.length) // on last pass, readAry may have garbage at end, remove + curAry = (byte[])Bry_.Resize_manual(curAry, curRead); + } + public void Rls() {stream.Rls();} +} diff --git a/100_core/src_900_xml/gplx/xmls/XmlSplitWtr.java b/100_core/src_900_xml/gplx/xmls/XmlSplitWtr.java new file mode 100644 index 000000000..48266d86b --- /dev/null +++ b/100_core/src_900_xml/gplx/xmls/XmlSplitWtr.java @@ -0,0 +1,40 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.xmls; import gplx.*; +import gplx.ios.*; +public class XmlSplitWtr { + public Io_url Url() {return url;} Io_url url; + public XmlSplitWtr Init_(Io_url partDir, byte[] hdr, XmlFileSplitterOpts opts) { + this.partDir = partDir; this.hdr = hdr; this.opts = opts; + return this; + } + public void Bgn(int partIdx) { + String partStr = opts.Namer().GenStrIdxOnly(partIdx); + url = Io_url_.mem_fil_(partStr); + stream = Io_mgr.I.OpenStreamWrite(url); + init = true; + } boolean init = true; byte[] hdr; XmlFileSplitterOpts opts; Io_url partDir; IoStream stream; + public void Write(byte[] ary) { + if (init) { + stream.WriteAry(hdr); + init = false; + } + stream.WriteAry(ary); + } + public void Rls() {stream.Rls();} +} diff --git a/100_core/src_900_xml/gplx/xmls/Xpath_.java b/100_core/src_900_xml/gplx/xmls/Xpath_.java new file mode 100644 index 000000000..671120ef9 --- /dev/null +++ b/100_core/src_900_xml/gplx/xmls/Xpath_.java @@ -0,0 +1,106 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.xmls; import gplx.*; +import gplx.core.primitives.*; +public class Xpath_ { + public static XmlNdeList SelectAll(XmlNde owner, String xpath) {return Select(owner, xpath, Xpath_Args.all_());} + public static XmlNde SelectFirst(XmlNde owner, String xpath) { + XmlNdeList rv = Select(owner, xpath, Xpath_Args.first_()); + return rv.Count() == 0 ? null : rv.Get_at(0); // selects first + } + public static XmlNdeList SelectElements(XmlNde owner) { + XmlNdeList subNdes = owner.SubNdes(); int count = subNdes.Count(); + XmlNdeList_cls_list list = new XmlNdeList_cls_list(count); + for (int i = 0; i < count; i++) { + XmlNde sub = subNdes.Get_at(i); + if (sub.NdeType_element()) + list.Add(sub); + } + return list; + } + static XmlNdeList Select(XmlNde owner, String xpath, Xpath_Args args) { + XmlNdeList_cls_list rv = new XmlNdeList_cls_list(List_adp_.Capacity_initial); + String[] parts = String_.Split(xpath, "/"); + TraverseSubs(owner, parts, 0, rv, args); + return rv; + } + static void TraverseSubs(XmlNde owner, String[] parts, int depth, XmlNdeList_cls_list results, Xpath_Args args) { + int partsLen = Array_.Len(parts); + if (depth == partsLen) return; + String name = parts[depth]; + XmlNdeList subNdes = owner.SubNdes(); int count = subNdes.Count(); + for (int i = 0; i < count; i++) { + XmlNde sub = subNdes.Get_at(i); + if (args.Cancel) return; + if (!String_.Eq(name, sub.Name())) continue; + if (depth == partsLen - 1) { + results.Add(sub); + if (args.SelectFirst) args.Cancel = true; + } + else + TraverseSubs(sub, parts, depth + 1, results, args); + } + } + public static final String InnetTextKey = "&innerText"; + public static KeyValHash ExtractKeyVals(String xml, Int_obj_ref posRef, String nodeName) { + int pos = posRef.Val(); + Exc xmlErr = Exc_.new_("error parsing xml", "xml", xml, "pos", pos); + String headBgnFind = "<" + nodeName + " "; int headBgnFindLen = String_.Len(headBgnFind); + int headBgn = String_.FindFwd(xml, headBgnFind, pos); if (headBgn == String_.Find_none) return null; + int headEnd = String_.FindFwd(xml, ">", headBgn + headBgnFindLen); if (headEnd == String_.Find_none) throw xmlErr; + String atrXml = String_.Mid(xml, headBgn, headEnd); + KeyValHash rv = ExtractNodeVals(atrXml, xmlErr); + boolean noInnerText = String_.CharAt(xml, headEnd - 1) == '/'; // if />, then no inner text + if (!noInnerText) { + int tail = String_.FindFwd(xml, "", headBgn); if (tail == String_.Find_none) throw Exc_.new_("could not find tailPos", "headBgn", headBgn); + String innerText = String_.Mid(xml, headEnd + 1, tail); + rv.Add(InnetTextKey, innerText); + } + posRef.Val_(headEnd); + return rv; + } + static KeyValHash ExtractNodeVals(String xml, Exc xmlErr) { + KeyValHash rv = KeyValHash.new_(); + int pos = 0; + while (true) { + int eqPos = String_.FindFwd(xml, "=", pos); if (eqPos == String_.Find_none) break; + int q0Pos = String_.FindFwd(xml, "\"", eqPos + 1); if (q0Pos == String_.Find_none) throw xmlErr.Args_add("eqPos", eqPos); + int q1Pos = String_.FindFwd(xml, "\"", q0Pos + 1); if (q1Pos == String_.Find_none) throw xmlErr.Args_add("q1Pos", q1Pos); + int spPos = eqPos - 1; + while (spPos > -1) { + char c = String_.CharAt(xml, spPos); + if (Char_.IsWhitespace(c)) break; + spPos--; + } + if (spPos == String_.Find_none) throw xmlErr.Args_add("sub_msg", "could not find hdr", "eqPos", eqPos); + String key = String_.Mid(xml, spPos + 1, eqPos); + String val = String_.Mid(xml, q0Pos + 1, q1Pos); + rv.Add(key, val); + pos = q1Pos; + } + return rv; + } +} +class Xpath_Args { + public boolean SelectFirst; // false=SelectAll + public boolean Cancel; + public static Xpath_Args all_() {return new Xpath_Args(false);} + public static Xpath_Args first_() {return new Xpath_Args(true);} + Xpath_Args(boolean selectFirst) {this.SelectFirst = selectFirst;} +} +enum Xpath_SelectMode {All, First} diff --git a/100_core/src_900_xml/gplx/xmls/Xpath__tst.java b/100_core/src_900_xml/gplx/xmls/Xpath__tst.java new file mode 100644 index 000000000..85ba60488 --- /dev/null +++ b/100_core/src_900_xml/gplx/xmls/Xpath__tst.java @@ -0,0 +1,44 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.xmls; import gplx.*; +import org.junit.*; +public class Xpath__tst { + @Test public void Select_all() { + String xml = String_.Concat + ( "" + , "" + , "" + , "" + , "" + , "" + , "" + , "" + , "" + , "" + , "" + ); + tst_SelectAll(xml, "a", 2); + tst_SelectAll(xml, "b", 1); + tst_SelectAll(xml, "b/c", 3); + } + void tst_SelectAll(String raw, String xpath, int expdCount) { + XmlDoc xdoc = XmlDoc_.parse_(raw); + XmlNdeList xndeList = Xpath_.SelectAll(xdoc.Root(), xpath); + Tfds.Eq(expdCount, xndeList.Count()); + } +} diff --git a/100_core/tst/gplx/EnmParser_tst.java b/100_core/tst/gplx/EnmParser_tst.java new file mode 100644 index 000000000..bdb7e3ec6 --- /dev/null +++ b/100_core/tst/gplx/EnmParser_tst.java @@ -0,0 +1,60 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class EnmParser_tst { + @Before public void setup() { + parser = EnmMgr.new_(); + } + @Test public void Basic() { // 1,2,4,8 + parser.BitRngEnd_(8); + run_Reg(0, "zero"); + run_Reg(1, "one"); + run_Reg(2, "two"); + run_Reg(4, "four"); + run_Reg(8, "eight"); + + tst_Convert("zero", 0); + tst_Convert("one", 1); + tst_Convert("eight", 8); + tst_Convert("one+eight", 9); + } + @Test public void Keys() { + parser.BitRngBgn_(65536).BitRngEnd_(262144); + run_Reg( 65, "a"); + run_Reg( 65536, "shift"); + run_Reg(131072, "ctrl"); + run_Reg(262144, "alt"); + tst_Convert("a", 65); + tst_Convert("shift+a", 65 + 65536); + tst_Convert("ctrl+a", 65 + 131072); + tst_Convert("shift+ctrl+a", 65 + 65536 + 131072); + } + @Test public void Prefix() { + parser.Prefix_("key.").BitRngBgn_(128).BitRngEnd_(128); + run_Reg(65, "a"); + tst_Convert("key.a", 65); + } + void run_Reg(int i, String s) {parser.RegObj(i, s, "NULL");} + void tst_Convert(String raw, int val) { + int actlVal = parser.GetVal(raw); + Tfds.Eq(val, actlVal); + Tfds.Eq(raw, parser.GetStr(val)); + } + EnmMgr parser; +} diff --git a/100_core/tst/gplx/GfoMsg_rdr_tst.java b/100_core/tst/gplx/GfoMsg_rdr_tst.java new file mode 100644 index 000000000..373564288 --- /dev/null +++ b/100_core/tst/gplx/GfoMsg_rdr_tst.java @@ -0,0 +1,57 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import org.junit.*; +public class GfoMsg_rdr_tst { + @Before public void setup() { + msg = msg_().Add("a", "1").Add("b", "2").Add("c", "3"); + ctx.Match("init", "init"); + } GfoMsg msg; GfsCtx ctx = GfsCtx.new_(); + @Test public void Key() { + tst_Msg(msg, "a", "1"); + tst_Msg(msg, "b", "2"); + tst_Msg(msg, "c", "3"); + tst_Msg(msg, "d", null); + } + @Test public void Pos() { + msg = msg_().Add("", "1").Add("", "2").Add("", "3"); + tst_Msg(msg, "", "1"); + tst_Msg(msg, "", "2"); + tst_Msg(msg, "", "3"); + tst_Msg(msg, "", null); + } + @Test public void OutOfOrder() { + tst_Msg(msg, "c", "3"); + tst_Msg(msg, "b", "2"); + tst_Msg(msg, "a", "1"); + } + @Test public void Key3_Pos1_Pos2() { + msg = msg_().Add("", "1").Add("", "2").Add("c", "3"); + tst_Msg(msg, "c", "3"); + tst_Msg(msg, "", "1"); + tst_Msg(msg, "", "2"); + } + @Test public void MultipleEmpty() { + msg = msg_().Add("", "1").Add("", "2").Add("", "3"); + tst_Msg(msg, "", "1"); + tst_Msg(msg, "", "2"); + tst_Msg(msg, "", "3"); + } + GfoMsg msg_() {return GfoMsg_.new_parse_("test");} + void tst_Msg(GfoMsg m, String k, String expd) {Tfds.Eq(expd, m.ReadStrOr(k, null));} +} diff --git a/100_core/tst/gplx/GfoTreeBldr_fxt.java b/100_core/tst/gplx/GfoTreeBldr_fxt.java new file mode 100644 index 000000000..a42abf785 --- /dev/null +++ b/100_core/tst/gplx/GfoTreeBldr_fxt.java @@ -0,0 +1,32 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class GfoTreeBldr_fxt { + public List_adp Atrs() {return atrs;} List_adp atrs = List_adp_.new_(); + public List_adp Subs() {return subs;} List_adp subs = List_adp_.new_(); + public GfoTreeBldr_fxt atr_(Object key, Object val) { + atrs.Add(new Object[] {key, val}); + return this; + } + public GfoTreeBldr_fxt sub_(GfoTreeBldr_fxt... ary) { + for (GfoTreeBldr_fxt sub : ary) + subs.Add(sub); + return this; + } + public static GfoTreeBldr_fxt new_() {return new GfoTreeBldr_fxt();} GfoTreeBldr_fxt() {} +} diff --git a/100_core/tst/gplx/TfdsTstr_fxt.java b/100_core/tst/gplx/TfdsTstr_fxt.java new file mode 100644 index 000000000..86c351958 --- /dev/null +++ b/100_core/tst/gplx/TfdsTstr_fxt.java @@ -0,0 +1,99 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +import gplx.core.strings.*; +import gplx.lists.*; +public class TfdsTstr_fxt { + public TfdsTstr_fxt Eq_str(Object expd, Object actl, String name) { + int nameLen = String_.Len(name); if (nameLen > nameLenMax) nameLenMax = nameLen; + TfdsTstrItm itm = TfdsTstrItm.new_().Expd_(expd).Actl_(actl).Name_(name); + list.Add(itm); + return this; + } + public void SubName_push(String s) { + stack.Push(s); + TfdsTstrItm itm = TfdsTstrItm.new_(); + itm.SubName_make(stack); + itm.TypeOf = 1; + list.Add(itm); + } StackAdp stack = StackAdp_.new_(); + public void Fail() { + manualFail = true; + }boolean manualFail = false; + public int List_Max(List_adp expd, List_adp actl) {return Math_.Max(expd.Count(), actl.Count());} + public int List_Max(String[] expd, String[] actl) {return Math_.Max(expd.length, actl.length);} + public Object List_FetchAtOrNull(List_adp l, int i) {return (i >= l.Count()) ? null : l.Get_at(i);} + + public void SubName_pop() {stack.Pop();} + int nameLenMax = 0; + public void tst_Equal(String hdr) { + boolean pass = true; + for (int i = 0; i < list.Count(); i++) { + TfdsTstrItm itm = (TfdsTstrItm)list.Get_at(i); + if (!itm.Compare()) pass = false; // don't break early; Compare all vals + } + if (pass && !manualFail) return; + String_bldr sb = String_bldr_.new_(); + sb.Add_char_crlf(); + sb.Add_str_w_crlf(hdr); + for (int i = 0; i < list.Count(); i++) { + TfdsTstrItm itm = (TfdsTstrItm)list.Get_at(i); + if (itm.TypeOf == 1) { + sb.Add_fmt_line(" /{0}", itm.SubName()); + continue; + } + boolean hasError = itm.CompareResult() != TfdsTstrItm.CompareResult_eq; + String errorKey = hasError ? "*" : " "; + sb.Add_fmt_line("{0}{1} {2}", errorKey, String_.PadEnd(itm.Name(), nameLenMax, " "), itm.Expd()); + if (hasError) + sb.Add_fmt_line("{0}{1} {2}", errorKey, String_.PadEnd("", nameLenMax, " "), itm.Actl()); + } + sb.Add(String_.Repeat("_", 80)); + throw Exc_.new_(sb.XtoStr()); + } + List_adp list = List_adp_.new_(); + public static TfdsTstr_fxt new_() {return new TfdsTstr_fxt();} TfdsTstr_fxt() {} +} +class TfdsTstrItm { + public String Name() {return name;} public TfdsTstrItm Name_(String val) {name = val; return this;} private String name; + public Object Expd() {return expd;} public TfdsTstrItm Expd_(Object val) {expd = val; return this;} Object expd; + public Object Actl() {return actl;} public TfdsTstrItm Actl_(Object val) {actl = val; return this;} Object actl; + public String SubName() {return subName;} private String subName = ""; + public int TypeOf; + public void SubName_make(StackAdp stack) { + if (stack.Count() == 0) return; + List_adp list = stack.XtoList(); + String_bldr sb = String_bldr_.new_(); + for (int i = 0; i < list.Count(); i++) { + if (i != 0) sb.Add("."); + sb.Add((String)list.Get_at(i)); + } + subName = sb.XtoStr(); + } + public int CompareResult() {return compareResult;} public TfdsTstrItm CompareResult_(int val) {compareResult = val; return this;} int compareResult; + public boolean Compare() { + boolean eq = Object_.Eq(expd, actl); + compareResult = eq ? 1 : 0; + return eq; + } + public String CompareSym() { + return compareResult == 1 ? "==" : "!="; + } + public static TfdsTstrItm new_() {return new TfdsTstrItm();} TfdsTstrItm() {} + public static final int CompareResult_none = 0, CompareResult_eq = 1, CompareResult_eqn = 2; +} diff --git a/100_core/tst/gplx/ios/IoEngineFxt.java b/100_core/tst/gplx/ios/IoEngineFxt.java new file mode 100644 index 000000000..c4e5771f7 --- /dev/null +++ b/100_core/tst/gplx/ios/IoEngineFxt.java @@ -0,0 +1,54 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +public class IoEngineFxt { + IoEngine EngineOf(Io_url url) {return IoEnginePool._.Get_by(url.Info().EngineKey());} + public void tst_ExistsPaths(boolean expd, Io_url... ary) { + for (Io_url fil : ary) { + if (fil.Type_dir()) + Tfds.Eq(expd, EngineOf(fil).ExistsDir(fil), "ExistsDir failed; dir={0}", fil); + else + Tfds.Eq(expd, EngineOf(fil).ExistsFil_api(fil), "ExistsFil failed; fil={0}", fil); + } + } + public void tst_LoadFilStr(Io_url fil, String expd) {Tfds.Eq(expd, EngineOf(fil).LoadFilStr(IoEngine_xrg_loadFilStr.new_(fil)));} + public void run_SaveFilText(Io_url fil, String expd) {EngineOf(fil).SaveFilText_api(IoEngine_xrg_saveFilStr.new_(fil, expd));} + public void run_UpdateFilModifiedTime(Io_url fil, DateAdp modifiedTime) {EngineOf(fil).UpdateFilModifiedTime(fil, modifiedTime);} + public void tst_QueryFilReadOnly(Io_url fil, boolean expd) {Tfds.Eq(expd, EngineOf(fil).QueryFil(fil).ReadOnly());} + public IoEngineFxt tst_QueryFil_size(Io_url fil, long expd) {Tfds.Eq(expd, EngineOf(fil).QueryFil(fil).Size()); return this;} + public IoEngineFxt tst_QueryFil_modifiedTime(Io_url fil, DateAdp expd) {Tfds.Eq_date(expd, EngineOf(fil).QueryFil(fil).ModifiedTime()); return this;} + public IoItmDir tst_ScanDir(Io_url dir, Io_url... expd) { + IoItmDir dirItem = EngineOf(dir).QueryDir(dir); + Io_url[] actl = new Io_url[dirItem.SubDirs().Count() + dirItem.SubFils().Count()]; + for (int i = 0; i < dirItem.SubDirs().Count(); i++) { + IoItmDir subDir = IoItmDir_.as_(dirItem.SubDirs().Get_at(i)); + actl[i] = subDir.Url(); + } + for (int i = 0; i < dirItem.SubFils().Count(); i++) { + IoItmFil subFil = IoItmFil_.as_(dirItem.SubFils().Get_at(i)); + actl[i + dirItem.SubDirs().Count()] = subFil.Url(); + } + Tfds.Eq_ary_str(expd, actl); + return dirItem; + } + public static IoEngineFxt new_() { + IoEngineFxt rv = new IoEngineFxt(); + return rv; + } + public IoEngineFxt() {} +} diff --git a/100_core/tst/gplx/ios/IoEngine_dir_basic_base.java b/100_core/tst/gplx/ios/IoEngine_dir_basic_base.java new file mode 100644 index 000000000..c80d93e92 --- /dev/null +++ b/100_core/tst/gplx/ios/IoEngine_dir_basic_base.java @@ -0,0 +1,79 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import org.junit.*; +public abstract class IoEngine_dir_basic_base { + @Before public void setup() { + engine = engine_(); + fx = IoEngineFxt.new_(); + setup_hook(); + } protected IoEngine engine; @gplx.Internal protected IoEngineFxt fx; protected Io_url fil, root; + protected abstract IoEngine engine_(); + protected abstract void setup_hook(); + @Test @gplx.Virtual public void CreateDir() { + fx.tst_ExistsPaths(false, root); + + engine.CreateDir(root); + fx.tst_ExistsPaths(true, root); + } + @Test public void DeleteDir() { + engine.CreateDir(root); + fx.tst_ExistsPaths(true, root); + + engine.DeleteDir(root); + fx.tst_ExistsPaths(false, root); + } + @Test public void CreateDir_createAllOwners() { + Io_url subDir = root.GenSubDir_nest("sub1"); + fx.tst_ExistsPaths(false, subDir, subDir.OwnerDir()); + + engine.CreateDir(subDir); + fx.tst_ExistsPaths(true, subDir, subDir.OwnerDir()); + } +// @Test public void DeleteDir_missing_fail() { +// try {engine.DeleteDir(root);} +// catch {return;} +// Tfds.Fail_expdError(); +// } + @Test public void DeleteDir_missing_pass() { + engine.DeleteDir(root); + } + @Test @gplx.Virtual public void ScanDir() { + Io_url fil = root.GenSubFil("fil1.txt"); fx.run_SaveFilText(fil, "test"); + Io_url dir1 = root.GenSubDir_nest("dir1"); engine.CreateDir(dir1); + Io_url dir1_1 = dir1.GenSubDir_nest("dir1_1"); engine.CreateDir(dir1_1); // NOTE: QueryDir should not recurse by default; dir1_1 should not be returned below + + fx.tst_ScanDir(root, dir1, fil); + } + @Test public void MoveDir() { + Io_url src = root.GenSubDir_nest("src"), trg = root.GenSubDir_nest("trg"); + engine.CreateDir(src); + fx.tst_ExistsPaths(true, src); fx.tst_ExistsPaths(false, trg); + + engine.MoveDir(src, trg); + fx.tst_ExistsPaths(false, src); fx.tst_ExistsPaths(true, trg); +} +@Test @gplx.Virtual public void CopyDir() { + Io_url src = root.GenSubDir_nest("src"), trg = root.GenSubDir_nest("trg"); + engine.CreateDir(src); + fx.tst_ExistsPaths(true, src); fx.tst_ExistsPaths(false, trg); + + engine.CopyDir(src, trg); + fx.tst_ExistsPaths(true, src, trg); +} +} diff --git a/100_core/tst/gplx/ios/IoEngine_dir_basic_memory_tst.java b/100_core/tst/gplx/ios/IoEngine_dir_basic_memory_tst.java new file mode 100644 index 000000000..d11cae4f3 --- /dev/null +++ b/100_core/tst/gplx/ios/IoEngine_dir_basic_memory_tst.java @@ -0,0 +1,24 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import org.junit.*; +public class IoEngine_dir_basic_memory_tst extends IoEngine_dir_basic_base { + @Override protected void setup_hook() { + root = Io_url_.mem_dir_("mem"); + } @Override protected IoEngine engine_() {return IoEngine_.Mem_init_();} +} diff --git a/100_core/tst/gplx/ios/IoEngine_dir_basic_system_tst.java b/100_core/tst/gplx/ios/IoEngine_dir_basic_system_tst.java new file mode 100644 index 000000000..b0c92c571 --- /dev/null +++ b/100_core/tst/gplx/ios/IoEngine_dir_basic_system_tst.java @@ -0,0 +1,28 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import org.junit.*; +public class IoEngine_dir_basic_system_tst extends IoEngine_dir_basic_base { + @Override protected void setup_hook() { + root = Tfds.RscDir.GenSubDir_nest("100_core", "ioEngineTest", "_temp"); + IoEngine_xrg_deleteDir.new_(root).Recur_().ReadOnlyFails_off().Exec(); + } @Override protected IoEngine engine_() {return IoEngine_system.new_();} + @Test @Override public void ScanDir() { + super.ScanDir(); + } +} diff --git a/100_core/tst/gplx/ios/IoEngine_dir_deep_base.java b/100_core/tst/gplx/ios/IoEngine_dir_deep_base.java new file mode 100644 index 000000000..4bd5bc4fa --- /dev/null +++ b/100_core/tst/gplx/ios/IoEngine_dir_deep_base.java @@ -0,0 +1,126 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import org.junit.*; +public abstract class IoEngine_dir_deep_base { + @Before public void setup() { + engine = engine_(); + fx = IoEngineFxt.new_(); + setup_hook(); + setup_paths(); + setup_objs(); + } protected IoEngine engine; protected Io_url fil, root; @gplx.Internal protected IoEngineFxt fx; + protected abstract IoEngine engine_(); + protected abstract void setup_hook(); + @Test @gplx.Virtual public void SearchDir() { + Io_url[] expd = paths_(src_dir0a, src_fil0a, src_dir0a_dir0a, src_dir0a_fil0a); + Io_url[] actl = IoEngine_xrg_queryDir.new_(src).Recur_().DirInclude_().ExecAsUrlAry(); + Tfds.Eq_ary(expd, actl); + } + @Test @gplx.Virtual public void MoveDirDeep() { + fx.tst_ExistsPaths(true, srcTree); fx.tst_ExistsPaths(false, trgTree); + + engine.MoveDirDeep(IoEngine_xrg_xferDir.move_(src, trg).Recur_()); + fx.tst_ExistsPaths(false, srcTree); + fx.tst_ExistsPaths(true, trgTree); + } + @Test @gplx.Virtual public void CopyDir() { + fx.tst_ExistsPaths(true, srcTree); fx.tst_ExistsPaths(false, trgTree); + + engine.CopyDir(src, trg); + fx.tst_ExistsPaths(true, srcTree); + fx.tst_ExistsPaths(true, trgTree); + } + @Test @gplx.Virtual public void DeleteDir() { + fx.tst_ExistsPaths(true, srcTree); + + engine.DeleteDirDeep(IoEngine_xrg_deleteDir.new_(src).Recur_()); + fx.tst_ExistsPaths(false, srcTree); + } +// @Test public virtual void CopyDir_IgnoreExisting() { +// fx.tst_ExistsPaths(true, srcTree); fx.tst_ExistsPaths(false, trgTree); +// engine.SaveFilStr(trg_dir0a_fil0a, "x"); // NOTE: this file is different than src counterpart; should be overwritten by Copy +// fx.tst_ExistsPaths(true, trg_dir0a, trg_dir0a_fil0a); +// +// engine.CopyDir(src, trg); +// fx.tst_ExistsPaths(true, srcTree); +// fx.tst_ExistsPaths(true, trgTree); +// } +// @Test public virtual void CopyDir_IgnoreExistingReadOnlyFile() { +// fx.tst_ExistsPaths(true, srcTree); fx.tst_ExistsPaths(false, trgTree); +// engine.SaveFilStr(trg_fil0a, "x"); // NOTE: this file is different than src counterpart; should be overwritten by Copy +// fx.tst_ExistsPaths(true, trg_fil0a); +// engine.UpdateFilAttrib(trg_fil0a, IoItmAttrib.ReadOnlyFile); +// +// engine.CopyDir(src, trg); +// fx.tst_ExistsPaths(true, srcTree); +// fx.tst_ExistsPaths(true, trgTree); +// } +// @Test public void MoveDir_IgnoreExisting() { +// fx.tst_ExistsPaths(true, srcTree); +// fx.tst_ExistsPaths(false, trgTree); +// engine.SaveFilStr(trg_dir0a_fil0a, @"x"); // NOTE: this file is different than src counterpart; should be overwritten by Copy +// fx.tst_ExistsPaths(true, trg_dir0a, trg_dir0a_fil0a); +// +// engine.MoveDir(src, trg); +// +// fx.tst_ExistsPaths(true, srcTree); +// fx.tst_ExistsPaths(true, trgTree); +// } +// @Test public virtual void ProgressUi() { +// ConsoleDlg_dev dialog = ConsoleDlg_dev.new_(); +// engine.SearchDir(src).Recur_().Prog_(dialog).ExecAsDir(); +// +// Tfds.Eq(dialog.Written.Count, 3); // 3 levels +// tst_(dialog, 0, "scan", src); +// tst_(dialog, 1, "scan", src_dir0a); +// tst_(dialog, 2, "scan", src_dir0a_dir0a); +// } +// void tst_(ConsoleDlg_dev dialog, int i, String s, Io_url root) { +// Object o = dialog.Written.Get_at(i); +// IoStatusArgs args = (IoStatusArgs)o; +// Tfds.Eq(s, args.Op); +// Tfds.Eq(root, args.Path); +// } + protected Io_url src, src_dir0a, src_dir0a_dir0a; + Io_url src_fil0a, src_dir0a_fil0a; + protected Io_url trg, trg_dir0a, trg_dir0a_dir0a; + Io_url trg_fil0a, trg_dir0a_fil0a; + Io_url[] srcTree, trgTree; + Io_url[] paths_(Io_url... ary) {return ary;} + protected void setup_paths() { + src = root.GenSubDir_nest("src"); + src_dir0a = root.GenSubDir_nest("src", "dir0a"); + src_dir0a_dir0a = root.GenSubDir_nest("src", "dir0a", "dir0a"); + src_fil0a = root.GenSubFil_nest("src", "fil0a.txt"); + src_dir0a_fil0a = root.GenSubFil_nest("src", "dir0a", "fil0a.txt"); + trg = root.GenSubDir_nest("trg"); + trg_dir0a = root.GenSubDir_nest("trg", "dir0a"); + trg_dir0a_dir0a = root.GenSubDir_nest("trg", "dir0a", "dir0a"); + trg_fil0a = root.GenSubFil_nest("trg", "fil0a.txt"); + trg_dir0a_fil0a = root.GenSubFil_nest("trg", "dir0a", "fil0a.txt"); + srcTree = new Io_url[] {src, src_dir0a, src_dir0a_dir0a, src_fil0a, src_dir0a_fil0a}; + trgTree = new Io_url[] {trg, trg_dir0a, trg_dir0a_dir0a, trg_fil0a, trg_dir0a_fil0a}; + } + void setup_objs() { + fx.run_SaveFilText(src_fil0a, "src_fil0a"); // NOTE: automatically creates src + fx.run_SaveFilText(src_dir0a_fil0a, "src_dir0a_fil0a"); // NOTE: automatically creates src_dir0a_dir0a + fx.tst_ExistsPaths(true, src_fil0a); + engine.CreateDir(src_dir0a_dir0a); + } +} diff --git a/100_core/tst/gplx/ios/IoEngine_dir_deep_memory_tst.java b/100_core/tst/gplx/ios/IoEngine_dir_deep_memory_tst.java new file mode 100644 index 000000000..d2f75c244 --- /dev/null +++ b/100_core/tst/gplx/ios/IoEngine_dir_deep_memory_tst.java @@ -0,0 +1,36 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import org.junit.*; +public class IoEngine_dir_deep_memory_tst extends IoEngine_dir_deep_base { + @Override protected void setup_hook() { + root = Io_url_.mem_dir_("mem/root"); + } @Override protected IoEngine engine_() {return IoEngine_.Mem_init_();} + @Test @Override public void SearchDir() { + super.SearchDir(); + } + @Test @Override public void MoveDirDeep() { + super.MoveDirDeep(); + } + @Test @Override public void CopyDir() { + super.CopyDir(); + } + @Test @Override public void DeleteDir() { + super.DeleteDir(); + } +} diff --git a/100_core/tst/gplx/ios/IoEngine_dir_deep_system_tst.java b/100_core/tst/gplx/ios/IoEngine_dir_deep_system_tst.java new file mode 100644 index 000000000..79672c36f --- /dev/null +++ b/100_core/tst/gplx/ios/IoEngine_dir_deep_system_tst.java @@ -0,0 +1,25 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import org.junit.*; +public class IoEngine_dir_deep_system_tst extends IoEngine_dir_deep_base { + @Override protected void setup_hook() { + root = Tfds.RscDir.GenSubDir_nest("100_core", "ioEngineTest", "_temp"); + IoEngine_xrg_deleteDir.new_(root).Recur_().ReadOnlyFails_off().Exec(); + } @Override protected IoEngine engine_() {return IoEngine_.Sys;} +} diff --git a/100_core/tst/gplx/ios/IoEngine_fil_basic_base.java b/100_core/tst/gplx/ios/IoEngine_fil_basic_base.java new file mode 100644 index 000000000..c244aef7e --- /dev/null +++ b/100_core/tst/gplx/ios/IoEngine_fil_basic_base.java @@ -0,0 +1,176 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import org.junit.*; import gplx.texts.*;/*EncodingAdp_*/ +public abstract class IoEngine_fil_basic_base { + @Before public void setup() { + engine = engine_(); + fx = IoEngineFxt.new_(); + setup_hook(); + } protected IoEngine engine; protected IoEngineFxt fx; protected Io_url fil, root; + protected abstract IoEngine engine_(); + protected abstract void setup_hook(); + @Test @gplx.Virtual public void ExistsFil() { + fx.tst_ExistsPaths(false, fil); + } + @Test @gplx.Virtual public void ExistsFil_deep() { + fx.tst_ExistsPaths(false, root.GenSubFil_nest("dir1", "dir2", "fil1.txt")); + } + @Test @gplx.Virtual public void SaveFilStr() { + fx.tst_ExistsPaths(false, fil, fil.OwnerDir()); + + fx.run_SaveFilText(fil, "text"); + fx.tst_ExistsPaths(true, fil, fil.OwnerDir()); + } + @Test @gplx.Virtual public void SaveFilText_autoCreateOwnerDir() { + fil = fil.OwnerDir().GenSubFil_nest("sub1", "fil1.txt"); + fx.tst_ExistsPaths(false, fil, fil.OwnerDir()); + + fx.run_SaveFilText(fil, "text"); + fx.tst_ExistsPaths(true, fil, fil.OwnerDir()); + } + @Test @gplx.Virtual public void SaveFilText_overwrite() { + fx.run_SaveFilText(fil, "text"); + fx.tst_ExistsPaths(true, fil); + + fx.run_SaveFilText(fil, "changed"); + fx.tst_LoadFilStr(fil, "changed"); + } + @Test @gplx.Virtual public void SaveFilText_append() { + fx.run_SaveFilText(fil, "text"); + + engine.SaveFilText_api(IoEngine_xrg_saveFilStr.new_(fil, "appended").Append_()); + fx.tst_LoadFilStr(fil, "text" + "appended"); + } + @Test @gplx.Virtual public void SaveFilText_caseInsensitive() { + if (root.Info().CaseSensitive()) return; + Io_url lcase = root.GenSubFil_nest("dir", "fil.txt"); + Io_url ucase = root.GenSubFil_nest("DIR", "FIL.TXT"); + fx.run_SaveFilText(lcase, "text"); + + fx.tst_ExistsPaths(true, lcase, ucase); + fx.tst_LoadFilStr(lcase, "text"); + fx.tst_LoadFilStr(ucase, "text"); + } + @Test @gplx.Virtual public void SaveFilText_readOnlyFails() { + fx.run_SaveFilText(fil, "text"); + engine.UpdateFilAttrib(fil, IoItmAttrib.readOnly_()); + + try {fx.run_SaveFilText(fil, "changed");} + catch (Exception exc) { + fx.tst_LoadFilStr(fil, "text"); + Exc_.Noop(exc); + return; + } + Tfds.Fail_expdError(); + } + @Test @gplx.Virtual public void LoadFilStr() { + fx.run_SaveFilText(fil, "text"); + fx.tst_LoadFilStr(fil, "text"); + } + @Test @gplx.Virtual public void LoadFilStr_missingIgnored() { + Tfds.Eq("", engine.LoadFilStr(IoEngine_xrg_loadFilStr.new_(fil).MissingIgnored_())); + } + @Test @gplx.Virtual public void UpdateFilAttrib() { + fx.run_SaveFilText(fil, "text"); + fx.tst_QueryFilReadOnly(fil, false); + + engine.UpdateFilAttrib(fil, IoItmAttrib.readOnly_()); + fx.tst_QueryFilReadOnly(fil, true); + } + @Test @gplx.Virtual public void DeleteFil() { + fx.run_SaveFilText(fil, "text"); + fx.tst_ExistsPaths(true, fil); + + engine.DeleteFil_api(IoEngine_xrg_deleteFil.new_(fil)); + fx.tst_ExistsPaths(false, fil); + } + @Test @gplx.Virtual public void DeleteFil_missing_pass() { + fil = root.GenSubFil("fileThatDoesntExist.txt"); + + engine.DeleteFil_api(IoEngine_xrg_deleteFil.new_(fil).MissingFails_off()); + fx.tst_ExistsPaths(false, fil); + } + @Test @gplx.Virtual public void DeleteFil_readOnly_fail() { + fx.run_SaveFilText(fil, "text"); + + engine.UpdateFilAttrib(fil, IoItmAttrib.readOnly_()); + try {engine.DeleteFil_api(IoEngine_xrg_deleteFil.new_(fil));} + catch (Exception exc) {Exc_.Noop(exc); + fx.tst_ExistsPaths(true, fil); + return; + } + Tfds.Fail_expdError(); + } + @Test @gplx.Virtual public void DeleteFil_readOnly_pass() { + fx.run_SaveFilText(fil, "text"); + engine.UpdateFilAttrib(fil, IoItmAttrib.readOnly_()); + + engine.DeleteFil_api(IoEngine_xrg_deleteFil.new_(fil).ReadOnlyFails_off()); + fx.tst_ExistsPaths(false, fil); + } + @Test @gplx.Virtual public void QueryFil_size() { + fx.run_SaveFilText(fil, "text"); + + fx.tst_QueryFil_size(fil, String_.Len("text")); + } + @Test @gplx.Virtual public void UpdateFilModifiedTime() { + fx.run_SaveFilText(fil, "text"); + + DateAdp time = Tfds.Now_time0_add_min(10); + engine.UpdateFilModifiedTime(fil, time); + fx.tst_QueryFil_modifiedTime(fil, time); + } + @Test @gplx.Virtual public void OpenStreamRead() { + fx.run_SaveFilText(fil, "text"); + + int textLen = String_.Len("text"); + byte[] buffer = new byte[textLen]; + IoStream stream = IoStream_.Null; + try { + stream = engine.OpenStreamRead(fil); + stream.Read(buffer, 0, textLen); + } + finally {stream.Rls();} + String actl = String_.new_u8(buffer); + Tfds.Eq("text", actl); + } + @Test @gplx.Virtual public void OpenStreamWrite() { + IoStream stream = IoEngine_xrg_openWrite.new_(fil).Exec(); + byte[] buffer = Bry_.new_u8("text"); + int textLen = String_.Len("text"); + stream.Write(buffer, 0, textLen); + stream.Rls(); + + fx.tst_LoadFilStr(fil, "text"); + } +// @Test public virtual void OpenStreamWrite_in_place() { +// byte[] buffer = Bry_.new_u8("a|b|c"); +// IoStream stream = IoEngine_xrg_openWrite.new_(fil).Exec(); +// stream.Write(buffer, 0, buffer.length); +// stream.Rls(); +// +// buffer = Bry_.new_u8("B"); +// stream = IoEngine_xrg_openWrite.new_(fil).Exec(); +// stream.Seek(2); +// stream.Write(buffer, 0, buffer.length); +// stream.Rls(); +// +// fx.tst_LoadFilStr(fil, "a|B|c"); +// } +} diff --git a/100_core/tst/gplx/ios/IoEngine_fil_basic_memory_tst.java b/100_core/tst/gplx/ios/IoEngine_fil_basic_memory_tst.java new file mode 100644 index 000000000..0e67e2532 --- /dev/null +++ b/100_core/tst/gplx/ios/IoEngine_fil_basic_memory_tst.java @@ -0,0 +1,57 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import org.junit.*; +public class IoEngine_fil_basic_memory_tst extends IoEngine_fil_basic_base { + @Override protected IoEngine engine_() {return IoEngine_.Mem_init_();} + @Override protected void setup_hook() { + root = Io_url_.mem_dir_("mem"); + fil = root.GenSubFil_nest("root", "fil.txt"); + } + @Test @Override public void OpenStreamRead() { + super.OpenStreamRead (); + } + @Test @Override public void SaveFilText_overwrite() { + super.SaveFilText_overwrite(); + + // bugfix: verify changed file in ownerDir's hash + IoItmDir dirItm = fx.tst_ScanDir(fil.OwnerDir(), fil); + IoItmFil_mem filItm = (IoItmFil_mem)dirItm.SubFils().Get_at(0); + Tfds.Eq(filItm.Text(), "changed"); + } + @Test public void RecycleFil() { + fx.run_SaveFilText(fil, "text"); + fx.tst_ExistsPaths(true, fil); + + IoRecycleBin bin = IoRecycleBin._; + List_adp list = Tfds.RscDir.XtoNames(); +// foreach (String s in list) +// Tfds.Write(s); + list.Del_at(0); // remove drive + IoEngine_xrg_recycleFil recycleXrg = bin.Send_xrg(fil) + .RootDirNames_(list) + .AppName_("gplx.test").Time_(DateAdp_.parse_gplx("20100102_115559123")).Uuid_(Guid_adp_.parse_("467ffb41-cdfe-402f-b22b-be855425784b")); + recycleXrg.Exec(); + fx.tst_ExistsPaths(false, fil); + fx.tst_ExistsPaths(true, recycleXrg.RecycleUrl()); + + bin.Recover(recycleXrg.RecycleUrl()); + fx.tst_ExistsPaths(true, fil); + fx.tst_ExistsPaths(false, recycleXrg.RecycleUrl()); + } +} diff --git a/100_core/tst/gplx/ios/IoEngine_fil_basic_system_tst.java b/100_core/tst/gplx/ios/IoEngine_fil_basic_system_tst.java new file mode 100644 index 000000000..9f467a3b8 --- /dev/null +++ b/100_core/tst/gplx/ios/IoEngine_fil_basic_system_tst.java @@ -0,0 +1,58 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import org.junit.*; +public class IoEngine_fil_basic_system_tst extends IoEngine_fil_basic_base { + @Override protected void setup_hook() { + root = Tfds.RscDir.GenSubDir_nest("100_core", "ioEngineTest", "_temp"); + fil = root.GenSubFil("fil.txt"); + IoEngine_xrg_deleteDir.new_(fil.OwnerDir()).Recur_().ReadOnlyFails_off().Exec(); + } @Override protected IoEngine engine_() {return IoEngine_system.new_();} + @Test public void ExistsFil_IgnoreDifferentCasing() { + if (root.Info().CaseSensitive()) return; + fx.run_SaveFilText(fil, "text"); + fx.tst_ExistsPaths(true, fil); + fx.tst_ExistsPaths(true, fil.OwnerDir().GenSubFil("FIL.txt")); + } + @Test @gplx.Virtual public void RecycleFil() { + fx.run_SaveFilText(fil, "text"); + fx.tst_ExistsPaths(true, fil); + + IoRecycleBin bin = IoRecycleBin._; + List_adp list = root.XtoNames(); list.Del_at(0); // remove drive + IoEngine_xrg_recycleFil recycleXrg = bin.Send_xrg(fil) + .RootDirNames_(list) + .AppName_("gplx.test").Time_(DateAdp_.parse_gplx("20100102_115559123")).Uuid_(Guid_adp_.parse_("467ffb41-cdfe-402f-b22b-be855425784b")); + recycleXrg.Exec(); + fx.tst_ExistsPaths(false, fil); + fx.tst_ExistsPaths(true, recycleXrg.RecycleUrl()); + + bin.Recover(recycleXrg.RecycleUrl()); + fx.tst_ExistsPaths(true, fil); + fx.tst_ExistsPaths(false, recycleXrg.RecycleUrl()); + } + @Test @Override public void DeleteFil_missing_pass() { + super.DeleteFil_missing_pass(); + } + @Test @Override public void DeleteFil_readOnly_pass() { + super.DeleteFil_readOnly_pass (); + } + @Test @Override public void SaveFilText_readOnlyFails() { + super.SaveFilText_readOnlyFails(); + } +} diff --git a/100_core/tst/gplx/ios/IoEngine_fil_xfer_base.java b/100_core/tst/gplx/ios/IoEngine_fil_xfer_base.java new file mode 100644 index 000000000..746cb29f1 --- /dev/null +++ b/100_core/tst/gplx/ios/IoEngine_fil_xfer_base.java @@ -0,0 +1,106 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import org.junit.*; +public abstract class IoEngine_fil_xfer_base { + @Before public void setup() { + engine = engine_(); + fx = IoEngineFxt.new_(); + setup_hook(); + src = root.GenSubFil("src.txt"); trg = root.GenSubFil("trg.txt"); + } protected IoEngine engine; @gplx.Internal protected IoEngineFxt fx; protected Io_url src, trg, root; + DateAdp srcModifiedTime = DateAdp_.parse_gplx("2010.04.12 20.26.01.000"), trgModifiedTime = DateAdp_.parse_gplx("2010.04.01 01.01.01.000"); + protected abstract IoEngine engine_(); + protected abstract void setup_hook(); + protected abstract Io_url AltRoot(); + @Test @gplx.Virtual public void CopyFil() { + fx.run_SaveFilText(src, "src"); fx.run_UpdateFilModifiedTime(src, srcModifiedTime); + fx.tst_ExistsPaths(true, src); + fx.tst_ExistsPaths(false, trg); + + IoEngine_xrg_xferFil.copy_(src, trg).Exec(); + fx.tst_ExistsPaths(true, src, trg); + fx.tst_LoadFilStr(trg, "src"); + fx.tst_QueryFil_modifiedTime(trg, srcModifiedTime); + } + @Test @gplx.Virtual public void CopyFil_overwrite_fail() { + fx.run_SaveFilText(src, "src"); + fx.run_SaveFilText(trg, "trg"); + + try {IoEngine_xrg_xferFil.copy_(src, trg).Exec();} + catch (Exception exc) {Exc_.Noop(exc); + fx.tst_ExistsPaths(true, src, trg); + fx.tst_LoadFilStr(trg, "trg"); + return; + } + Tfds.Fail_expdError(); + } + @Test @gplx.Virtual public void CopyFil_overwrite_pass() { + fx.run_SaveFilText(src, "src"); fx.run_UpdateFilModifiedTime(src, srcModifiedTime); + fx.run_SaveFilText(trg, "trg"); fx.run_UpdateFilModifiedTime(trg, trgModifiedTime); + + IoEngine_xrg_xferFil.copy_(src, trg).Overwrite_().Exec(); + fx.tst_ExistsPaths(true, src, trg); + fx.tst_LoadFilStr(trg, "src"); + fx.tst_QueryFil_modifiedTime(trg, srcModifiedTime); + } + @Test @gplx.Virtual public void MoveFil() { + fx.run_SaveFilText(src, "src"); + fx.tst_ExistsPaths(true, src); + fx.tst_ExistsPaths(false, trg); + + IoEngine_xrg_xferFil.move_(src, trg).Exec(); + fx.tst_ExistsPaths(false, src); + fx.tst_ExistsPaths(true, trg); + } + @Test @gplx.Virtual public void MoveFil_overwrite_fail() { + fx.run_SaveFilText(src, "src"); + fx.run_SaveFilText(trg, "trg"); + + try {IoEngine_xrg_xferFil.move_(src, trg).Exec();} + catch (Exception exc) {Exc_.Noop(exc); + fx.tst_ExistsPaths(true, src); + fx.tst_ExistsPaths(true, trg); + fx.tst_LoadFilStr(trg, "trg"); + return; + } + Tfds.Fail_expdError(); + } + @Test @gplx.Virtual public void MoveFil_overwrite_pass() { + fx.run_SaveFilText(src, "src"); fx.run_UpdateFilModifiedTime(src, srcModifiedTime); + fx.run_SaveFilText(trg, "trg"); fx.run_UpdateFilModifiedTime(trg, trgModifiedTime); + + IoEngine_xrg_xferFil.move_(src, trg).Overwrite_().Exec(); + fx.tst_ExistsPaths(false, src); + fx.tst_ExistsPaths(true, trg); + fx.tst_LoadFilStr(trg, "src"); + fx.tst_QueryFil_modifiedTime(trg, srcModifiedTime); + } + @Test @gplx.Virtual public void MoveFil_betweenDrives() { + IoEngine_xrg_deleteDir.new_(AltRoot()).Recur_().ReadOnlyFails_off().Exec(); + src = root.GenSubFil_nest("dir", "fil1a.txt"); + trg = AltRoot().GenSubFil_nest("dir", "fil1b.txt"); + fx.run_SaveFilText(src, "src"); + fx.tst_ExistsPaths(true, src); + fx.tst_ExistsPaths(false, trg); + + IoEngine_xrg_xferFil.move_(src, trg).Exec(); + fx.tst_ExistsPaths(false, src); + fx.tst_ExistsPaths(true, trg); + } +} diff --git a/100_core/tst/gplx/ios/IoEngine_fil_xfer_memory_tst.java b/100_core/tst/gplx/ios/IoEngine_fil_xfer_memory_tst.java new file mode 100644 index 000000000..cf3b97ea6 --- /dev/null +++ b/100_core/tst/gplx/ios/IoEngine_fil_xfer_memory_tst.java @@ -0,0 +1,28 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import org.junit.*; +public class IoEngine_fil_xfer_memory_tst extends IoEngine_fil_xfer_base { + @Override protected void setup_hook() { + root = Io_url_.mem_dir_("mem"); + } @Override protected IoEngine engine_() {return IoEngine_.Mem_init_();} + @Override protected Io_url AltRoot() { + Io_mgr.I.InitEngine_mem_("mem2"); + return Io_url_.mem_dir_("mem2"); + } +} diff --git a/100_core/tst/gplx/ios/IoEngine_fil_xfer_system_tst.java b/100_core/tst/gplx/ios/IoEngine_fil_xfer_system_tst.java new file mode 100644 index 000000000..793de5756 --- /dev/null +++ b/100_core/tst/gplx/ios/IoEngine_fil_xfer_system_tst.java @@ -0,0 +1,28 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import org.junit.*; +public class IoEngine_fil_xfer_system_tst extends IoEngine_fil_xfer_base { + @Override protected void setup_hook() { + root = Tfds.RscDir.GenSubDir_nest("100_core", "ioEngineTest", "_temp"); + IoEngine_xrg_deleteDir.new_(root.OwnerDir()).Recur_().ReadOnlyFails_off().Exec(); + } @Override protected IoEngine engine_() {return IoEngine_system.new_();} + @Override protected Io_url AltRoot() { + return Tfds.RscDir.GenSubDir_nest("100_core", "ioEngineTest", "_temp"); + } +} diff --git a/100_core/tst/gplx/ios/IoEngine_stream_xfer_tst.java b/100_core/tst/gplx/ios/IoEngine_stream_xfer_tst.java new file mode 100644 index 000000000..a4418ee9d --- /dev/null +++ b/100_core/tst/gplx/ios/IoEngine_stream_xfer_tst.java @@ -0,0 +1,49 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import org.junit.*; +public class IoEngine_stream_xfer_tst { + @Before public void setup() { + srcEngine = IoEngine_memory.new_("mock1"); + trgEngine = IoEngine_memory.new_("mock2"); + IoEnginePool._.Add_if_dupe_use_nth(srcEngine); IoEnginePool._.Add_if_dupe_use_nth(trgEngine); + IoUrlInfoRegy._.Reg(IoUrlInfo_.mem_("mem1/", srcEngine.Key())); + IoUrlInfoRegy._.Reg(IoUrlInfo_.mem_("mem2/", trgEngine.Key())); + srcDir = Io_url_.mem_dir_("mem1/dir"); trgDir = Io_url_.mem_dir_("mem2/dir"); + } + @Test public void TransferBetween() { + Io_url srcPath = srcDir.GenSubFil("fil.txt"); + Io_url trgPath = trgDir.GenSubFil("fil.txt"); + tst_TransferStreams(srcEngine, srcPath, trgEngine, trgPath); + } + void tst_TransferStreams(IoEngine srcEngine, Io_url srcPath, IoEngine trgEngine, Io_url trgPath) { + srcEngine.SaveFilText_api(IoEngine_xrg_saveFilStr.new_(srcPath, "test1")); + trgEngine.DeleteFil_api(IoEngine_xrg_deleteFil.new_(trgPath)); // make sure file is deleted + fx.tst_ExistsPaths(true, srcPath); + fx.tst_ExistsPaths(false, trgPath); + + IoEngineUtl utl = IoEngineUtl.new_(); + utl.BufferLength_set(4); + utl.XferFil(srcEngine, IoEngine_xrg_xferFil.copy_(srcPath, trgPath)); + fx.tst_ExistsPaths(true, srcPath, trgPath); + fx.tst_LoadFilStr(trgPath, "test1"); + } + IoEngineFxt fx = IoEngineFxt.new_(); + Io_url srcDir, trgDir; + IoEngine srcEngine, trgEngine; +} diff --git a/100_core/tst/gplx/ios/IoEngine_xrg_queryDir_tst.java b/100_core/tst/gplx/ios/IoEngine_xrg_queryDir_tst.java new file mode 100644 index 000000000..dab411088 --- /dev/null +++ b/100_core/tst/gplx/ios/IoEngine_xrg_queryDir_tst.java @@ -0,0 +1,65 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import org.junit.*; +public class IoEngine_xrg_queryDir_tst { + @Before public void setup() { + engine = IoEngine_.Mem_init_(); + } IoEngine engine; Io_url[] ary; + @Test public void Basic() { + ary = save_text_(fil_("fil1.txt")); + + tst_ExecPathAry(finder_(), ary); + } + @Test public void FilPath() { + ary = save_text_(fil_("fil1.txt"), fil_("fil2.jpg"), fil_("fil3.txt")); + + tst_ExecPathAry(finder_(), ary); // default: all files + tst_ExecPathAry(finder_().FilPath_("*.txt") // findPattern of *.txt + , fil_("fil1.txt"), fil_("fil3.txt")); + } + @Test public void Recur() { + ary = save_text_(fil_("fil1.txt"), fil_("dirA", "fil1A.jpg")); + + tst_ExecPathAry(finder_(), fil_("fil1.txt")); // default: no recursion + tst_ExecPathAry(finder_().Recur_(), ary); // recurse + } + @Test public void DirPattern() { + save_text_(fil_("fil1.txt"), fil_("dirA", "fil1A.jpg")); + + tst_ExecPathAry(finder_(), fil_("fil1.txt")); // default: files only + tst_ExecPathAry(finder_().DirInclude_() // include dirs; NOTE: fil1A not returned b/c Recur_ is not true + , dir_("dirA"), fil_("fil1.txt")); + } + @Test public void Sort_by() { + save_text_(fil_("fil2a.txt"), fil_("fil1.txt")); + + tst_ExecPathAry(finder_() // default: sortByAscOrder + , fil_("fil1.txt"), fil_("fil2a.txt")); + } + IoEngine_xrg_queryDir finder_() {return IoEngine_xrg_queryDir.new_(Io_url_.mem_dir_("mem/root"));}// NOTE: not in setup b/c finder must be newed several times inside test method + Io_url fil_(String... ary) {return Io_url_.mem_dir_("mem/root").GenSubFil_nest(ary);} + Io_url dir_(String... ary) {return Io_url_.mem_dir_("mem/root").GenSubDir_nest(ary);} + + Io_url[] save_text_(Io_url... ary) { + for (Io_url url : ary) + Io_mgr.I.SaveFilStr(url, url.Raw()); + return ary; + } + void tst_ExecPathAry(IoEngine_xrg_queryDir finder, Io_url... expd) {Tfds.Eq_ary(expd, finder.ExecAsUrlAry());} +} diff --git a/100_core/tst/gplx/ios/IoEngine_xrg_recycleFil_tst.java b/100_core/tst/gplx/ios/IoEngine_xrg_recycleFil_tst.java new file mode 100644 index 000000000..36e6493d1 --- /dev/null +++ b/100_core/tst/gplx/ios/IoEngine_xrg_recycleFil_tst.java @@ -0,0 +1,32 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import org.junit.*; +public class IoEngine_xrg_recycleFil_tst { + @Before public void setup() { + IoEngine_.Mem_init_(); + } + @Test public void GenRecycleUrl() { + tst_GenRecycleUrl(recycle_(), Io_url_.mem_fil_("mem/z_trash/20100102/gplx.images;115559123;;fil.txt")); + tst_GenRecycleUrl(recycle_().Uuid_include_(), Io_url_.mem_fil_("mem/z_trash/20100102/gplx.images;115559123;467ffb41-cdfe-402f-b22b-be855425784b;fil.txt")); + } + IoEngine_xrg_recycleFil recycle_() {return IoEngine_xrg_recycleFil.gplx_(Io_url_.mem_fil_("mem/dir/fil.txt")).AppName_("gplx.images").Uuid_(Guid_adp_.parse_("467ffb41-cdfe-402f-b22b-be855425784b")).Time_(DateAdp_.parse_gplx("20100102_115559123"));} + void tst_GenRecycleUrl(IoEngine_xrg_recycleFil xrg, Io_url expd) { + Tfds.Eq(expd, xrg.RecycleUrl()); + } +} diff --git a/100_core/tst/gplx/ios/IoItmDir_FetchDeepOrNull_tst.java b/100_core/tst/gplx/ios/IoItmDir_FetchDeepOrNull_tst.java new file mode 100644 index 000000000..25233d520 --- /dev/null +++ b/100_core/tst/gplx/ios/IoItmDir_FetchDeepOrNull_tst.java @@ -0,0 +1,40 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import org.junit.*; +public class IoItmDir_FetchDeepOrNull_tst { + @Before public void setup() { + drive = Io_url_.mem_dir_("mem"); + rootDir = bldr.dir_(drive, bldr.dir_(drive.GenSubDir("sub1"))); + } IoItm_fxt bldr = IoItm_fxt.new_(); Io_url drive; IoItmDir rootDir; + @Test public void FetchDeepOrNull() { + tst_FetchDeepOrNull(rootDir, drive.GenSubDir("sub1"), true); + tst_FetchDeepOrNull(rootDir, drive.GenSubDir("sub2"), false); + tst_FetchDeepOrNull(rootDir.SubDirs().Get_at(0), drive.GenSubDir("sub1"), true); + tst_FetchDeepOrNull(rootDir.SubDirs().Get_at(0), drive.GenSubDir("sub2"), false); + } + void tst_FetchDeepOrNull(Object rootDirObj, Io_url find, boolean expdFound) { + IoItmDir rootDir = IoItmDir_.as_(rootDirObj); + IoItmDir actlDir = rootDir.FetchDeepOrNull(find); + if (actlDir == null) { + if (expdFound) Tfds.Fail("actlDir is null, but expd dir to be found"); + else return; // actlDir is null but expdFound was false; return; + } + Tfds.Eq(find.Raw(), actlDir.Url().Raw()); + } +} diff --git a/100_core/tst/gplx/ios/IoItm_fxt.java b/100_core/tst/gplx/ios/IoItm_fxt.java new file mode 100644 index 000000000..c11ba52fc --- /dev/null +++ b/100_core/tst/gplx/ios/IoItm_fxt.java @@ -0,0 +1,34 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +public class IoItm_fxt { + public IoItmFil fil_wnt_(String s) {return fil_(Io_url_.wnt_fil_(s));} + public IoItmFil fil_(Io_url url) {return IoItmFil_.new_(url, 1, DateAdp_.parse_gplx("2001-01-01"), DateAdp_.parse_gplx("2001-01-01"));} + public IoItmDir dir_wnt_(String s) {return dir_(Io_url_.wnt_dir_(s));} + public IoItmDir dir_(Io_url url, IoItm_base... ary) { + IoItmDir rv = IoItmDir_.top_(url); + for (IoItm_base itm : ary) { + if (itm.Type_dir()) + rv.SubDirs().Add(itm); + else + rv.SubFils().Add(itm); + } + return rv; + } + public static IoItm_fxt new_() {return new IoItm_fxt();} IoItm_fxt() {} +} diff --git a/100_core/tst/gplx/ios/IoUrlInfo_alias_tst.java b/100_core/tst/gplx/ios/IoUrlInfo_alias_tst.java new file mode 100644 index 000000000..424a7302f --- /dev/null +++ b/100_core/tst/gplx/ios/IoUrlInfo_alias_tst.java @@ -0,0 +1,58 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import org.junit.*; +public class IoUrlInfo_alias_tst { + IoUrlInfo_alias alias; + @Test public void MapWntToWnt() { + Make("usr:\\", "D:\\usr\\"); + tst_Xto_api("usr:\\dir\\fil.txt", "D:\\usr\\dir\\fil.txt"); + tst_OwnerDir("usr:\\dir\\", "usr:\\"); + tst_OwnerDir("usr:\\", ""); + tst_NameOnly("usr:\\", "usr"); + } + @Test public void MapToLnx() { + Make("usr:\\", "/home/"); + tst_Xto_api("usr:\\dir\\fil.txt", "/home/dir/fil.txt"); + } + @Test public void MapLnxToWnt() { + Make("usr:/", "C:\\usr\\"); + tst_Xto_api("usr:/dir/fil.txt", "C:\\usr\\dir\\fil.txt"); + } + @Test public void WntToWnt() { + Make("C:\\", "X:\\"); + tst_Xto_api("C:\\dir\\fil.txt", "X:\\dir\\fil.txt"); + tst_NameOnly("C:\\", "C"); + } + @Test public void WntToLnx() { + Make("C:\\", "/home/"); + tst_Xto_api("C:\\dir\\fil.txt", "/home/dir/fil.txt"); + } + @Test public void LnxToWnt() { + Make("/home/", "C:\\"); + tst_Xto_api("/home/dir/fil.txt", "C:\\dir\\fil.txt"); + tst_NameOnly("/home/", "home"); + tst_NameOnly("/", "root"); + } + void tst_Xto_api(String raw, String expd) {Tfds.Eq(expd, alias.Xto_api(raw));} + void tst_OwnerDir(String raw, String expd) {Tfds.Eq(expd, alias.OwnerDir(raw));} + void tst_NameOnly(String raw, String expd) {Tfds.Eq(expd, alias.NameOnly(raw));} + void Make(String srcDir, String trgDir) { + alias = IoUrlInfo_alias.new_(srcDir, trgDir, IoEngine_.SysKey); + } +} diff --git a/100_core/tst/gplx/ios/IoUrl_lnx_tst.java b/100_core/tst/gplx/ios/IoUrl_lnx_tst.java new file mode 100644 index 000000000..912e4045a --- /dev/null +++ b/100_core/tst/gplx/ios/IoUrl_lnx_tst.java @@ -0,0 +1,55 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import org.junit.*; +public class IoUrl_lnx_tst { + IoUrlFxt fx = IoUrlFxt.new_(); + @Test public void Raw() { + fx.tst_Xto_gplx(Io_url_.lnx_dir_("/home/"), "/home/"); + fx.tst_Xto_gplx(Io_url_.lnx_dir_("/home"), "/home/"); // add / + fx.tst_Xto_gplx(Io_url_.lnx_dir_("/"), "/"); + fx.tst_Xto_gplx(Io_url_.lnx_fil_("/home/fil.txt"), "/home/fil.txt"); + } + @Test public void Xto_api() { + fx.tst_Xto_api(Io_url_.lnx_fil_("/home/fil.txt"), "/home/fil.txt"); + fx.tst_Xto_api(Io_url_.lnx_dir_("/home/"), "/home"); // del / + fx.tst_Xto_api(Io_url_.lnx_dir_("/"), "/"); + } + @Test public void OwnerRoot() { + fx.tst_OwnerRoot(Io_url_.lnx_dir_("/home/fil.txt"), "/"); + fx.tst_OwnerRoot(Io_url_.lnx_dir_("/home"), "/"); + fx.tst_OwnerRoot(Io_url_.lnx_dir_("root"), "/"); + } + @Test public void XtoNames() { + fx.tst_XtoNames(Io_url_.lnx_dir_("/home/fil.txt"), fx.ary_("root", "home", "fil.txt")); + fx.tst_XtoNames(Io_url_.lnx_dir_("/home"), fx.ary_("root", "home")); + } + @Test public void IsDir() { + fx.tst_IsDir(Io_url_.lnx_dir_("/home"), true); + fx.tst_IsDir(Io_url_.lnx_fil_("/home/file.txt"), false); + } + @Test public void OwnerDir() { + fx.tst_OwnerDir(Io_url_.lnx_dir_("/home/lnxusr"), Io_url_.lnx_dir_("/home")); + fx.tst_OwnerDir(Io_url_.lnx_dir_("/fil.txt"), Io_url_.lnx_dir_("/")); + fx.tst_OwnerDir(Io_url_.lnx_dir_("/"), Io_url_.Empty); + } + @Test public void NameAndExt() { + fx.tst_NameAndExt(Io_url_.lnx_fil_("/fil.txt"), "fil.txt"); + fx.tst_NameAndExt(Io_url_.lnx_dir_("/dir"), "dir/"); + } +} diff --git a/100_core/tst/gplx/ios/IoUrl_map_tst.java b/100_core/tst/gplx/ios/IoUrl_map_tst.java new file mode 100644 index 000000000..2b2a094e3 --- /dev/null +++ b/100_core/tst/gplx/ios/IoUrl_map_tst.java @@ -0,0 +1,31 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import org.junit.*; +public class IoUrl_map_tst { + IoUrlFxt fx = IoUrlFxt.new_(); + @Test public void Xto_api() { + IoUrlInfo inf = IoUrlInfo_.alias_("tst:\\", "C:\\tst\\", IoEngine_.SysKey); + fx.tst_Xto_api(Io_url_.new_inf_("tst:\\dir\\fil.txt", inf), "C:\\tst\\dir\\fil.txt"); + fx.tst_Xto_api(Io_url_.new_inf_("tst:\\dir\\", inf), "C:\\tst\\dir"); // no trailing \ + } + @Test public void Xto_api_wce() { + IoUrlInfo inf = IoUrlInfo_.alias_("wce:\\", "\\SD Card\\", IoEngine_.SysKey); + fx.tst_Xto_api(Io_url_.new_inf_("wce:\\dir\\", inf), "\\SD Card\\dir"); + } +} diff --git a/100_core/tst/gplx/ios/IoUrl_wnt_tst.java b/100_core/tst/gplx/ios/IoUrl_wnt_tst.java new file mode 100644 index 000000000..ed10bbd58 --- /dev/null +++ b/100_core/tst/gplx/ios/IoUrl_wnt_tst.java @@ -0,0 +1,98 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.ios; import gplx.*; +import org.junit.*; +public class IoUrl_wnt_tst { + IoUrlFxt fx = IoUrlFxt.new_(); + @Test public void Raw() { + fx.tst_Xto_gplx(Io_url_.wnt_fil_("C:\\dir\\fil.txt"), "C:\\dir\\fil.txt"); + fx.tst_Xto_gplx(Io_url_.wnt_dir_("C:\\dir\\"), "C:\\dir\\"); + fx.tst_Xto_gplx(Io_url_.wnt_dir_("C:\\dir") , "C:\\dir\\"); // add \ + } + @Test public void Xto_api() { + fx.tst_Xto_api(Io_url_.wnt_fil_("C:\\fil.txt"), "C:\\fil.txt"); + fx.tst_Xto_api(Io_url_.wnt_dir_("C:\\dir\\"), "C:\\dir"); // del \ + fx.tst_Xto_api(Io_url_.wnt_dir_("C:"), "C:"); + } + @Test public void OwnerRoot() { + fx.tst_OwnerRoot(Io_url_.wnt_dir_("C:\\dir") , "C:\\"); + fx.tst_OwnerRoot(Io_url_.wnt_dir_("C:\\fil.png") , "C:\\"); + fx.tst_OwnerRoot(Io_url_.wnt_dir_("C:") , "C:\\"); + } + @Test public void IsDir() { + fx.tst_IsDir(Io_url_.wnt_dir_("C:\\dir\\"), true); + fx.tst_IsDir(Io_url_.wnt_fil_("C:\\dir"), false); + fx.tst_IsDir(Io_url_.wnt_fil_("C:\\fil.txt"), false); + } + @Test public void OwnerDir() { + fx.tst_OwnerDir(Io_url_.wnt_dir_("C:\\dir\\sub1"), Io_url_.wnt_dir_("C:\\dir")); + fx.tst_OwnerDir(Io_url_.wnt_fil_("C:\\fil.txt"), Io_url_.wnt_dir_("C:")); + fx.tst_OwnerDir(Io_url_.wnt_dir_("C:"), Io_url_.Empty); +// fx.tst_OwnerDir(Io_url_.wnt_fil_("press enter to select this folder"), Io_url_.Empty); + } + @Test public void NameAndExt() { + fx.tst_NameAndExt(Io_url_.wnt_fil_("C:\\fil.txt"), "fil.txt"); + fx.tst_NameAndExt(Io_url_.wnt_dir_("C:\\dir"), "dir\\"); + } + @Test public void NameOnly() { + fx.tst_NameOnly(Io_url_.wnt_fil_("C:\\fil.txt"), "fil"); + fx.tst_NameOnly(Io_url_.wnt_dir_("C:\\dir"), "dir"); + fx.tst_NameOnly(Io_url_.wnt_dir_("C:"), "C"); + } + @Test public void Ext() { + fx.tst_Ext(Io_url_.wnt_fil_("C:\\fil.txt"), ".txt"); // fil + fx.tst_Ext(Io_url_.wnt_fil_("C:\\fil.multiple.txt"), ".txt"); // multiple ext + fx.tst_Ext(Io_url_.wnt_fil_("C:\\fil"), ""); // no ext + fx.tst_Ext(Io_url_.wnt_dir_("C:\\dir"), "\\"); // dir + } + @Test public void GenSubDir_nest() { + fx.tst_GenSubDir_nest(Io_url_.wnt_dir_("C:"), fx.ary_("dir1", "sub1"), Io_url_.wnt_dir_("C:\\dir1\\sub1")); + } + @Test public void GenNewExt() { + fx.tst_GenNewExt(Io_url_.wnt_fil_("C:\\fil.gif"), ".png", Io_url_.wnt_fil_("C:\\fil.png")); // basic + fx.tst_GenNewExt(Io_url_.wnt_fil_("C:\\fil.tst.gif"), ".png", Io_url_.wnt_fil_("C:\\fil.tst.png")); // last in multiple dotted + } + @Test public void GenRelUrl_orEmpty() { + fx.tst_GenRelUrl_orEmpty(Io_url_.wnt_fil_("C:\\root\\fil.txt") , Io_url_.wnt_dir_("C:\\root") , "fil.txt"); // fil + fx.tst_GenRelUrl_orEmpty(Io_url_.wnt_dir_("C:\\root\\dir") , Io_url_.wnt_dir_("C:\\root") , "dir\\"); // dir + fx.tst_GenRelUrl_orEmpty(Io_url_.wnt_fil_("C:\\root\\dir\\fil.txt") , Io_url_.wnt_dir_("C:\\root") , "dir\\fil.txt"); // fil: nested1 + fx.tst_GenRelUrl_orEmpty(Io_url_.wnt_fil_("C:\\root\\dir\\fil.txt") , Io_url_.wnt_dir_("C:") , "root\\dir\\fil.txt"); // fil: nested2 + } + @Test public void GenParallel() { + fx.tst_GenParallel(Io_url_.wnt_fil_("C:\\root1\\fil.txt"), Io_url_.wnt_dir_("C:\\root1"), Io_url_.wnt_dir_("D:\\root2"), Io_url_.wnt_fil_("D:\\root2\\fil.txt")); + fx.tst_GenParallel(Io_url_.wnt_dir_("C:\\root1\\dir") , Io_url_.wnt_dir_("C:\\root1"), Io_url_.wnt_dir_("D:\\root2"), Io_url_.wnt_dir_("D:\\root2\\dir")); + } +} +class IoUrlFxt { + public void tst_Xto_api(Io_url url, String expd) {Tfds.Eq(expd, url.Xto_api());} + public void tst_OwnerRoot(Io_url url, String expd) {Tfds.Eq(expd, url.OwnerRoot().Raw());} + public void tst_XtoNames(Io_url url, String... expdAry) {Tfds.Eq_ary(expdAry, url.XtoNames().To_str_ary());} + public void tst_NameAndExt(Io_url url, String expd) {Tfds.Eq(expd, url.NameAndExt());} + public void tst_Xto_gplx(Io_url url, String expd) {Tfds.Eq(expd, url.Raw());} + public void tst_IsDir(Io_url url, boolean expd) {Tfds.Eq(expd, url.Type_dir());} + public void tst_OwnerDir(Io_url url, Io_url expd) {Tfds.Eq_url(expd, url.OwnerDir());} + public void tst_NameOnly(Io_url url, String expd) {Tfds.Eq(expd, url.NameOnly());} + public void tst_Ext(Io_url url, String expd) {Tfds.Eq(expd, url.Ext());} + public void tst_GenSubDir_nest(Io_url rootDir, String[] parts, Io_url expd) {Tfds.Eq(expd, rootDir.GenSubDir_nest(parts));} + public void tst_GenNewExt(Io_url url, String ext, Io_url expd) {Tfds.Eq_url(expd, url.GenNewExt(ext));} + public void tst_GenRelUrl_orEmpty(Io_url url, Io_url rootDir, String expd) {Tfds.Eq(expd, url.GenRelUrl_orEmpty(rootDir));} + public void tst_GenParallel(Io_url url, Io_url oldRoot, Io_url newRoot, Io_url expd) {Tfds.Eq_url(expd, url.GenParallel(oldRoot, newRoot));} + + public String[] ary_(String... ary) {return String_.Ary(ary);} + public static IoUrlFxt new_() {return new IoUrlFxt();} IoUrlFxt() {} +} diff --git a/100_core/tst/gplx/stores/GfoNdeRdr_read_tst.java b/100_core/tst/gplx/stores/GfoNdeRdr_read_tst.java new file mode 100644 index 000000000..1b52b1a20 --- /dev/null +++ b/100_core/tst/gplx/stores/GfoNdeRdr_read_tst.java @@ -0,0 +1,48 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.stores; import gplx.*; +import org.junit.*; +public class GfoNdeRdr_read_tst { + @Test public void ReadInt() { + rdr = rdr_(IntClassXtn._, "id", 1); + Tfds.Eq(rdr.ReadInt("id"), 1); + } + @Test public void ReadIntOr() { + rdr = rdr_(IntClassXtn._, "id", 1); + Tfds.Eq(rdr.ReadIntOr("id", -1), 1); + } + @Test public void ReadIntElse_minus1() { + rdr = rdr_(IntClassXtn._, "id", null); + Tfds.Eq(rdr.ReadIntOr("id", -1), -1); + } + @Test public void ReadInt_parse() { + rdr = rdr_(StringClassXtn._, "id", "1"); + Tfds.Eq(rdr.ReadInt("id"), 1); + } + @Test public void ReadIntElse_parse() { + rdr = rdr_(StringClassXtn._, "id", "2"); + Tfds.Eq(rdr.ReadIntOr("id", -1), 2); + } + GfoNdeRdr rdr_(ClassXtn type, String key, Object val) { // makes rdr with one row and one val + GfoFldList flds = GfoFldList_.new_().Add(key, type); + GfoNde row = GfoNde_.vals_(flds, new Object[] {val}); + boolean parse = type == StringClassXtn._; // assumes type is either StringClassXtn or IntClassXtn + return GfoNdeRdr_.leaf_(row, parse); + } + GfoNdeRdr rdr; +} diff --git a/100_core/tst/gplx/stores/GfoNdeRdr_tst.java b/100_core/tst/gplx/stores/GfoNdeRdr_tst.java new file mode 100644 index 000000000..fa3a9d4d7 --- /dev/null +++ b/100_core/tst/gplx/stores/GfoNdeRdr_tst.java @@ -0,0 +1,189 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.stores; import gplx.*; +import org.junit.*; +public class GfoNdeRdr_tst { + @Test public void Subs_leafs() { + root = + fx.root_ + ( fx.row_vals_(0) + , fx.row_vals_(1) + , fx.row_vals_(2) + ); + tst_NdeVals(root, 0, 1, 2); + } + @Test public void Subs_ndes() { + root = + fx.root_ + ( leaf_("", 0) + , leaf_("", 1) + , leaf_("", 2) + ); + tst_NdeVals(root, 0, 1, 2); + } + @Test public void Subs_mix() { + root = + fx.root_ + ( leaf_("", 0) + , fx.row_vals_(1) + , fx.row_vals_(2) + ); + tst_NdeVals(root, 0, 1, 2); + } + @Test public void Subs_rdr() { + root = + fx.root_ + ( fx.row_vals_(0) + ); + rootRdr = GfoNdeRdr_.root_parseNot_(root); + DataRdr rdr = rootRdr.Subs(); + Tfds.Eq_true(rdr.MoveNextPeer()); + Tfds.Eq(0, rdr.ReadAt(0)); + Tfds.Eq_false(rdr.MoveNextPeer()); + } + @Test public void MoveNextPeer_implicit() { + root = + fx.root_ + ( fx.csv_dat_ + ( fx.row_vals_(0) + , fx.row_vals_(1) + , fx.row_vals_(2) + ) + ); + GfoNdeRdr rootRdr = GfoNdeRdr_.root_parseNot_(root); + DataRdr subsRdr = rootRdr.Subs(); // pos=-1; bof + DataRdr subRdr = subsRdr.Subs(); // MoveNextPeer not needed; implicitly moves to pos=0 + tst_RdrVals(subRdr, Object_.Ary(0, 1, 2)); + } + @Test public void MoveNextPeer_explicit() { + root = + fx.root_ + ( fx.csv_dat_ + ( fx.row_vals_(0) + , fx.row_vals_(1) + , fx.row_vals_(2) + ) + ); + GfoNdeRdr rootRdr = GfoNdeRdr_.root_parseNot_(root); + DataRdr subsRdr = rootRdr.Subs(); // pos=-1; bof + Tfds.Eq_true(subsRdr.MoveNextPeer()); // explicitly moves to pos=0 + DataRdr subRdr = subsRdr.Subs(); + tst_RdrVals(subRdr, Object_.Ary(0, 1, 2)); + } + @Test public void Xpath_basic() { + root = fx.root_ + ( leaf_("root", 0) + , leaf_("root", 1) + , leaf_("root", 2) + ); + tst_Xpath_all(root, "root", 0, 1, 2); + } + @Test public void Xpath_nested() { + root = fx.root_ + ( fx.tbl_("owner" + , leaf_("root", 0) + , leaf_("root", 1) + , leaf_("root", 2) + )); + tst_Xpath_all(root, "owner/root", 0, 1, 2); + } + @Test public void Xpath_null() { + root = fx.root_ + ( leaf_("match", 0) + ); + rootRdr = GfoNdeRdr_.root_parseNot_(root); + DataRdr sub = rootRdr.Subs_byName("no_match"); + Tfds.Eq_false(sub.MoveNextPeer()); + } + @Test public void Xpath_moveFirst_basic() { + root = fx.root_ + ( leaf_("nde0", 0) + ); + tst_Xpath_first(root, "nde0", 0); + } + @Test public void Xpath_moveFirst_shallow() { + root = fx.root_ + ( leaf_("nde0", 0) + , leaf_("nde1", 1) + , leaf_("nde2", 2) + ); + tst_Xpath_first(root, "nde2", 2); + } + @Test public void Xpath_moveFirst_nested() { + root = fx.root_ + ( node_("nde0", Object_.Ary("0") + , leaf_("nde00", "00") + )); + tst_Xpath_first(root, "nde0", "0"); + tst_Xpath_first(root, "nde0/nde00", "00"); + } + @Test public void Xpath_moveFirst_nested_similarName() { + root = fx.root_ + ( node_("nde0", Object_.Ary("0") + , leaf_("nde00", "00") + ) + , node_("nde1", Object_.Ary("1") + , leaf_("nde00", "10") + )); + tst_Xpath_first(root, "nde1/nde00", "10"); + } + @Test public void Xpath_moveFirst_many() { + root = fx.root_ + ( leaf_("root", 0) + , leaf_("root", 1) + , leaf_("root", 2) + ); + tst_Xpath_first(root, "root", 0); // returns first + } + @Test public void Xpath_moveFirst_null() { + root = fx.root_ + ( leaf_("nde0", 0) + , leaf_("nde1", 1) + , leaf_("nde2", 2) + ); + rootRdr = GfoNdeRdr_.root_parseNot_(root); + DataRdr rdr = rootRdr.Subs_byName("nde3"); + Tfds.Eq_false(rdr.MoveNextPeer()); + } + + GfoNde leaf_(String name, Object... vals) {return GfoNde_.nde_(name, vals, GfoNde_.Ary_empty);} + GfoNde node_(String name, Object[] vals, GfoNde... subs) {return GfoNde_.nde_(name, vals, subs);} + void tst_NdeVals(GfoNde nde, Object... exptVals) { + DataRdr rdr = GfoNdeRdr_.root_parseNot_(nde); + tst_RdrVals(rdr.Subs(), exptVals); + } + void tst_RdrVals(DataRdr rdr, Object[] exptVals) { + int count = 0; + while (rdr.MoveNextPeer()) { + Object actl = rdr.ReadAt(0); + Tfds.Eq(actl, exptVals[count++]); + } + Tfds.Eq(count, exptVals.length); + } + void tst_Xpath_first(GfoNde root, String xpath, Object expt) { + DataRdr rdr = GfoNdeRdr_.root_parseNot_(root); + DataRdr sel = rdr.Subs_byName_moveFirst(xpath); + Object actl = sel.ReadAt(0); + Tfds.Eq(actl, expt); + } + void tst_Xpath_all(GfoNde root, String xpath, Object... exptVals) { + DataRdr rdr = GfoNdeRdr_.root_parseNot_(root); + tst_RdrVals(rdr.Subs_byName(xpath), exptVals); + } + GfoNde root; DataRdr rootRdr; GfoNdeFxt fx = GfoNdeFxt.new_(); +} diff --git a/100_core/tst/gplx/stores/xmls/XmlDataRdr_tst.java b/100_core/tst/gplx/stores/xmls/XmlDataRdr_tst.java new file mode 100644 index 000000000..cb5252131 --- /dev/null +++ b/100_core/tst/gplx/stores/xmls/XmlDataRdr_tst.java @@ -0,0 +1,102 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.stores.xmls; import gplx.*; import gplx.stores.*; +import org.junit.*; +public class XmlDataRdr_tst { + @Test public void Read() { + DataRdr rdr = fx.rdr_(""); + Tfds.Eq(rdr.NameOfNode(), "title"); + Tfds.Eq(rdr.ReadStr("name"), "first"); + Tfds.Eq(rdr.ReadInt("id"), 1); + Tfds.Eq(rdr.ReadBool("profiled"), false); + } + @Test public void None() { + DataRdr rdr = fx.rdr_ + ( "<root>" + , "<find/>" + , "</root>" + ); + fx.tst_Subs_ByName(rdr, "no_nde", "no_atr"); + } + @Test public void One() { + DataRdr rdr = fx.rdr_ + ( "<root>" + , "<find id=\"f0\" />" + , "</root>" + ); + fx.tst_Subs_ByName(rdr, "find", "id", "f0"); + } + @Test public void One_IgnoreOthers() { + DataRdr rdr = fx.rdr_ + ( "<root>" + , "<find id=\"f0\" />" + , "<skip id=\"s0\" />" + , "</root>" + ); + fx.tst_Subs_ByName(rdr, "find", "id", "f0"); + } + @Test public void Many() { + DataRdr rdr = fx.rdr_ + ( "<root>" + , "<find id=\"f0\" />" + , "<find id=\"f1\" />" + , "</root>" + ); + fx.tst_Subs_ByName(rdr, "find", "id", "f0", "f1"); + } + @Test public void Nested() { + DataRdr rdr = fx.rdr_ + ( "<root>" + , "<sub1>" + , "<find id=\"f0\" />" + , "<find id=\"f1\" />" + , "</sub1>" + , "</root>" + ); + fx.tst_Subs_ByName(rdr, "sub1/find", "id", "f0", "f1"); + } + @Test public void Nested_IgnoreOthers() { + DataRdr rdr = fx.rdr_ + ( "<root>" + , "<sub1>" + , "<find id=\"f0\" />" + , "<skip id=\"s0\" />" + , "</sub1>" + , "<sub1>" + , "<find id=\"f1\" />" // NOTE: find across ndes + , "<skip id=\"s1\" />" + , "</sub1>" + , "</root>" + ); + fx.tst_Subs_ByName(rdr, "sub1/find", "id", "f0", "f1"); + } + XmlDataRdr_fxt fx = XmlDataRdr_fxt.new_(); +} +class XmlDataRdr_fxt { + public DataRdr rdr_(String... ary) {return XmlDataRdr_.text_(String_.Concat(ary));} + public void tst_Subs_ByName(DataRdr rdr, String xpath, String key, String... expdAry) { + DataRdr subRdr = rdr.Subs_byName(xpath); + List_adp list = List_adp_.new_(); + while (subRdr.MoveNextPeer()) + list.Add(subRdr.Read(key)); + + String[] actlAry = list.To_str_ary(); + Tfds.Eq_ary(actlAry, expdAry); + } + public static XmlDataRdr_fxt new_() {return new XmlDataRdr_fxt();} XmlDataRdr_fxt() {} +} diff --git a/100_core/tst/gplx/stores/xmls/XmlDataWtr_tst.java b/100_core/tst/gplx/stores/xmls/XmlDataWtr_tst.java new file mode 100644 index 000000000..d2bbde0c2 --- /dev/null +++ b/100_core/tst/gplx/stores/xmls/XmlDataWtr_tst.java @@ -0,0 +1,95 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ +package gplx.stores.xmls; import gplx.*; import gplx.stores.*; +import org.junit.*; +public class XmlDataWtr_tst { + @Before public void setup() { + wtr = XmlDataWtr.new_(); + } + @Test public void WriteNodeBgn() { + wtr.WriteNodeBgn("chapter"); + tst_XStr(wtr, "<chapter />", String_.CrLf); + } + @Test public void Attributes() { + wtr.WriteNodeBgn("chapter"); + wtr.WriteData("id", 1); + wtr.WriteData("name", "first"); + tst_XStr(wtr, "<chapter id=\"1\" name=\"first\" />", String_.CrLf); + } + @Test public void Subs() { + wtr.WriteNodeBgn("title"); + wtr.WriteNodeBgn("chapters"); + wtr.WriteNodeBgn("chapter"); + tst_XStr(wtr + , "<title>", String_.CrLf + , "<chapters>", String_.CrLf + , "<chapter />", String_.CrLf + , "</chapters>", String_.CrLf + , "", String_.CrLf + ); + } + @Test public void Subs_Iterate() { + wtr.WriteNodeBgn("titles"); + for (int title = 1; title <= 2; title++) { + wtr.WriteNodeBgn("title"); + wtr.WriteData("id", title); + wtr.WriteNodeBgn("chapters"); + wtr.WriteNodeEnd(); // chapters + wtr.WriteNodeEnd(); // title + } + wtr.WriteNodeEnd(); //titles + tst_XStr(wtr + , "", String_.CrLf + , "", String_.CrLf + , "<chapters />", String_.CrLf + , "", String_.CrLf + , "", String_.CrLf + , "<chapters />", String_.CrLf + , "", String_.CrLf + , "", String_.CrLf + ); + } + @Test public void Peers() { + wtr.WriteNodeBgn("title"); + wtr.WriteNodeBgn("chapters"); + wtr.WriteNodeEnd(); + wtr.WriteNodeBgn("audioStreams"); + tst_XStr(wtr + , "", String_.CrLf + , "<chapters />", String_.CrLf + , "<audioStreams />", String_.CrLf + , "", String_.CrLf + ); + } + @Test public void AtrsWithNesting() { + wtr.WriteNodeBgn("title"); + wtr.WriteData("id", 1); + wtr.WriteData("name", "first"); + wtr.WriteNodeBgn("chapters"); + tst_XStr(wtr + , "", String_.CrLf + , "<chapters />", String_.CrLf + , "", String_.CrLf + ); + } + void tst_XStr(XmlDataWtr wtr, String... parts) { + String expd = String_.Concat(parts); + Tfds.Eq(expd, wtr.XtoStr()); + } + XmlDataWtr wtr; +} diff --git a/100_core/xtn/gplx/Internal.java b/100_core/xtn/gplx/Internal.java new file mode 100644 index 000000000..eb976259b --- /dev/null +++ b/100_core/xtn/gplx/Internal.java @@ -0,0 +1,20 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public @interface Internal {} + diff --git a/100_core/xtn/gplx/MainClass.java b/100_core/xtn/gplx/MainClass.java new file mode 100644 index 000000000..f50b9e082 --- /dev/null +++ b/100_core/xtn/gplx/MainClass.java @@ -0,0 +1,22 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public class MainClass { + public static void main(String s[]) { + } +} diff --git a/100_core/xtn/gplx/New.java b/100_core/xtn/gplx/New.java new file mode 100644 index 000000000..4c0e76d55 --- /dev/null +++ b/100_core/xtn/gplx/New.java @@ -0,0 +1,20 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public @interface New {} + diff --git a/100_core/xtn/gplx/Virtual.java b/100_core/xtn/gplx/Virtual.java new file mode 100644 index 000000000..6f019ddee --- /dev/null +++ b/100_core/xtn/gplx/Virtual.java @@ -0,0 +1,20 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx; +public @interface Virtual {} + diff --git a/110_gfml/.classpath b/110_gfml/.classpath new file mode 100644 index 000000000..d858d25a6 --- /dev/null +++ b/110_gfml/.classpath @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/110_gfml/.project b/110_gfml/.project new file mode 100644 index 000000000..2ccedcf3e --- /dev/null +++ b/110_gfml/.project @@ -0,0 +1,17 @@ + + + 110_gfml + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/110_gfml/src_100_tkn/gplx/gfml/GfmlLxr.java b/110_gfml/src_100_tkn/gplx/gfml/GfmlLxr.java new file mode 100644 index 000000000..155d3fcfe --- /dev/null +++ b/110_gfml/src_100_tkn/gplx/gfml/GfmlLxr.java @@ -0,0 +1,34 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.gfml; import gplx.*; +import gplx.texts.*; /*CharStream*/ +public interface GfmlLxr extends GfoEvObj { + String Key(); + String[] Hooks(); + GfmlTkn CmdTkn(); + void CmdTkn_set(GfmlTkn val); // needed for lxr pragma + GfmlTkn MakeTkn(CharStream stream, int hookLength); + GfmlLxr SubLxr(); + void SubLxr_Add(GfmlLxr... lexer); +} +class GfmlLxrRegy { + public int Count() {return hash.Count();} + public void Add(GfmlLxr lxr) {hash.Add(lxr.Key(), lxr);} + public GfmlLxr Get_by(String key) {return (GfmlLxr)hash.Get_by(key);} + Hash_adp hash = Hash_adp_.new_(); +} diff --git a/110_gfml/src_100_tkn/gplx/gfml/GfmlLxr_.java b/110_gfml/src_100_tkn/gplx/gfml/GfmlLxr_.java new file mode 100644 index 000000000..781832fb8 --- /dev/null +++ b/110_gfml/src_100_tkn/gplx/gfml/GfmlLxr_.java @@ -0,0 +1,217 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.gfml; import gplx.*; +import gplx.core.strings.*; +import gplx.texts.*; /*CharStream*/ +public class GfmlLxr_ { + public static GfmlLxr general_(String key, GfmlTkn protoTkn) {return GfmlLxr_general.new_(key, protoTkn);} + public static GfmlLxr solo_(String key, GfmlTkn singletonTkn) {return GfmlLxr_singleton.new_(key, singletonTkn.Raw(), singletonTkn);} + public static GfmlLxr range_(String key, String[] ary, GfmlTkn protoTkn, boolean ignoreOutput) {return GfmlLxr_group.new_(key, ary, protoTkn, ignoreOutput);} + + @gplx.Internal protected static GfmlLxr symbol_(String key, String raw, String val, GfmlBldrCmd cmd) { + GfmlTkn tkn = GfmlTkn_.singleton_(key, raw, val, cmd); + return GfmlLxr_.solo_(key, tkn); + } + @gplx.Internal protected static GfmlLxr frame_(String key, GfmlFrame frame, String bgn, String end) {return GfmlLxr_frame.new_(key, frame, bgn, end, GfmlBldrCmd_pendingTkns_add._, GfmlBldrCmd_frameEnd.data_());} + public static final GfmlLxr Null = new GfmlLxr_null(); + public static final String CmdTknChanged_evt = "Changed"; + public static GfmlLxr as_(Object obj) {return obj instanceof GfmlLxr ? (GfmlLxr)obj : null;} + public static GfmlLxr cast_(Object obj) {try {return (GfmlLxr)obj;} catch(Exception exc) {throw Exc_.new_type_mismatch_w_exc(exc, GfmlLxr.class, obj);}} +} +class GfmlLxr_null implements GfmlLxr { + public String Key() {return "gfml.nullLxr";} + public GfoEvMgr EvMgr() {if (evMgr == null) evMgr = GfoEvMgr.new_(this); return evMgr;} GfoEvMgr evMgr; + public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {return GfoInvkAble_.Rv_unhandled;} + public GfmlTkn CmdTkn() {return GfmlTkn_.Null;} public void CmdTkn_set(GfmlTkn val) {} + public String[] Hooks() {return String_.Ary_empty;} + public GfmlTkn MakeTkn(CharStream stream, int hookLength) {return GfmlTkn_.Null;} + public void SubLxr_Add(GfmlLxr... lexer) {} + public GfmlLxr SubLxr() {return this;} +} +class GfmlLxr_singleton implements GfmlLxr, GfoEvObj { + public GfoEvMgr EvMgr() {if (evMgr == null) evMgr = GfoEvMgr.new_(this); return evMgr;} GfoEvMgr evMgr; + public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {return GfoInvkAble_.Rv_unhandled;} + public String Key() {return key;} private String key; + public GfmlTkn CmdTkn() {return singletonTkn;} GfmlTkn singletonTkn; + public void CmdTkn_set(GfmlTkn val) { + String oldRaw = singletonTkn.Raw(); + singletonTkn = val; + hooks = String_.Ary(val.Raw()); + GfoEvMgr_.PubVals(this, GfmlLxr_.CmdTknChanged_evt, KeyVal_.new_("old", oldRaw), KeyVal_.new_("new", val.Raw()), KeyVal_.new_("lxr", this)); + } + public String[] Hooks() {return hooks;} private String[] hooks; + public GfmlTkn MakeTkn(CharStream stream, int hookLength) { + stream.MoveNextBy(hookLength); + return singletonTkn; + } + public GfmlLxr SubLxr() {return subLxr;} GfmlLxr subLxr; + public void SubLxr_Add(GfmlLxr... lexer) {subLxr.SubLxr_Add(lexer);} + public static GfmlLxr_singleton new_(String key, String hook, GfmlTkn singletonTkn) { + GfmlLxr_singleton rv = new GfmlLxr_singleton(); + rv.ctor_(key, hook, singletonTkn, GfmlLxr_.Null); + return rv; + } protected GfmlLxr_singleton() {} + @gplx.Internal protected void ctor_(String key, String hook, GfmlTkn singletonTkn, GfmlLxr subLxr) { + this.key = key; + this.hooks = String_.Ary(hook); + this.subLxr = subLxr; + this.singletonTkn = singletonTkn; + } +} +class GfmlLxr_group implements GfmlLxr { + public String Key() {return key;} private String key; + public GfoEvMgr EvMgr() {if (evMgr == null) evMgr = GfoEvMgr.new_(this); return evMgr;} GfoEvMgr evMgr; + public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {return GfoInvkAble_.Rv_unhandled;} + public GfmlTkn CmdTkn() {return outputTkn;} public void CmdTkn_set(GfmlTkn val) {} GfmlTkn outputTkn; + public String[] Hooks() {return trie.Symbols();} + public GfmlTkn MakeTkn(CharStream stream, int hookLength) { + while (stream.AtMid()) { + if (!ignoreOutput) + sb.Add_mid(stream.Ary(), stream.Pos(), hookLength); + stream.MoveNextBy(hookLength); + + String found = String_.cast_(trie.FindMatch(stream)); + if (found == null) break; + hookLength = trie.LastMatchCount; + } + if (ignoreOutput) return GfmlTkn_.IgnoreOutput; + String raw = sb.Xto_str_and_clear(); + return outputTkn.MakeNew(raw, raw); + } + public GfmlLxr SubLxr() {throw Err_sublxr();} + public void SubLxr_Add(GfmlLxr... lexer) {throw Err_sublxr();} + Exc Err_sublxr() {return Exc_.new_unimplemented_w_msg("group lxr does not have subLxrs", "key", key, "output_tkn", outputTkn.Raw()).Stack_erase_1_();} + GfmlTrie trie = GfmlTrie.new_(); String_bldr sb = String_bldr_.new_(); boolean ignoreOutput; + public static GfmlLxr_group new_(String key, String[] hooks, GfmlTkn outputTkn, boolean ignoreOutput) { + GfmlLxr_group rv = new GfmlLxr_group(); + rv.key = key; + for (String hook : hooks) + rv.trie.Add(hook, hook); + rv.outputTkn = outputTkn; rv.ignoreOutput = ignoreOutput; + return rv; + } GfmlLxr_group() {} +} +class GfmlLxr_general implements GfmlLxr, GfoInvkAble { + public GfoEvMgr EvMgr() {if (evMgr == null) evMgr = GfoEvMgr.new_(this); return evMgr;} GfoEvMgr evMgr; + public String Key() {return key;} private String key; + public GfmlTkn CmdTkn() {return txtTkn;} public void CmdTkn_set(GfmlTkn val) {} GfmlTkn txtTkn; + public String[] Hooks() {return symTrie.Symbols();} + public GfmlTkn MakeTkn(CharStream stream, int firstTknLength) { + GfmlTkn rv = null; + if (symLxr != null) { // symLxr has something; produce + rv = MakeTkn_symLxr(stream); + if (rv != GfmlTkn_.IgnoreOutput) return rv; + } + while (stream.AtMid()) { // keep moving til (a) symChar or (b) endOfStream + Object result = symTrie.FindMatch(stream); + symTknLen = symTrie.LastMatchCount; + if (result == null) { // no match; must be txtChar; + txtBfr.Add(stream); + stream.MoveNext(); + } + else { // symChar + symLxr = (GfmlLxr)result; // set symLxr for next pass + if (txtBfr.Has()) // txtBfr has something: gen txtTkn + rv = txtBfr.MakeTkn(stream, txtTkn); + else { // txtBfr empty: gen symbol + rv = MakeTkn_symLxr(stream); + if (rv == GfmlTkn_.IgnoreOutput) continue; + } + return rv; + } + } + if (txtBfr.Has()) // endOfStream, but txtBfr has chars + return txtBfr.MakeTkn(stream, txtTkn); + return GfmlTkn_.EndOfStream; + } + public void SubLxr_Add(GfmlLxr... lxrs) { + for (GfmlLxr lxr : lxrs) { + for (String hook : lxr.Hooks()) + symTrie.Add(hook, lxr); + GfoEvMgr_.SubSame(lxr, GfmlLxr_.CmdTknChanged_evt, this); + } + } + public GfmlLxr SubLxr() {return this;} + GfmlTkn MakeTkn_symLxr(CharStream stream) { + GfmlLxr lexer = symLxr; symLxr = null; + int length = symTknLen; symTknLen = 0; + return lexer.MakeTkn(stream, length); + } + GfmlLxr_general_txtBfr txtBfr = new GfmlLxr_general_txtBfr(); GfmlTrie symTrie = GfmlTrie.new_(); GfmlLxr symLxr; int symTknLen; + @gplx.Internal protected static GfmlLxr_general new_(String key, GfmlTkn txtTkn) { + GfmlLxr_general rv = new GfmlLxr_general(); + rv.key = key; rv.txtTkn = txtTkn; + return rv; + } protected GfmlLxr_general() {} + public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) { + if (ctx.Match(k, GfmlLxr_.CmdTknChanged_evt)) { + symTrie.Del(m.ReadStr("old")); + symTrie.Add(m.ReadStr("new"), m.CastObj("lxr")); + } + else return GfoInvkAble_.Rv_unhandled; + return this; + } +} +class GfmlLxr_general_txtBfr { + public int Bgn = NullPos; + public int Len; + public boolean Has() {return Bgn != NullPos;} + public void Add(CharStream stream) { + if (Bgn == NullPos) Bgn = stream.Pos(); + Len++; + } static final int NullPos = -1; + public GfmlTkn MakeTkn(CharStream stream, GfmlTkn textTkn) { + String raw = String_.new_charAry_(stream.Ary(), Bgn, Len); + Bgn = -1; Len = 0; + return textTkn.MakeNew(raw, raw); + } +} +class GfmlLxr_frame extends GfmlLxr_singleton { GfmlFrame frame; GfmlLxr endLxr, txtLxr; + public void BgnRaw_set(String val) {// needed for lxr pragma + GfmlBldrCmd_frameBgn bgnCmd = GfmlBldrCmd_frameBgn.new_(frame, txtLxr); + GfmlTkn bgnTkn = GfmlTkn_.singleton_(this.Key() + "_bgn", val, GfmlTkn_.NullVal, bgnCmd); + this.CmdTkn_set(bgnTkn); + } + public void EndRaw_set(String val) {// needed for lxr pragma + GfmlBldrCmd_frameEnd endCmd = GfmlBldrCmd_frameEnd.data_(); + GfmlTkn endTkn = GfmlTkn_.singleton_(this.Key() + "_end", val, GfmlTkn_.NullVal, endCmd); + endLxr.CmdTkn_set(endTkn); + } + public static GfmlLxr new_(String key, GfmlFrame frame, String bgn, String end, GfmlBldrCmd txtCmd, GfmlBldrCmd endCmd) { + GfmlLxr_frame rv = new GfmlLxr_frame(); + GfmlTkn txtTkn = frame.FrameType() == GfmlFrame_.Type_comment + ? GfmlTkn_.valConst_(key + "_txt", GfmlTkn_.NullVal, txtCmd) + : GfmlTkn_.cmd_(key + "_txt", txtCmd) + ; + GfmlLxr txtLxr = GfmlLxr_.general_(key + "_txt", txtTkn); + + GfmlTkn bgnTkn = GfmlTkn_.singleton_(key + "_bgn", bgn, GfmlTkn_.NullVal, GfmlBldrCmd_frameBgn.new_(frame, txtLxr)); + rv.ctor_(key, bgn, bgnTkn, txtLxr); + + GfmlTkn endTkn = GfmlTkn_.singleton_(key + "_end", end, GfmlTkn_.NullVal, endCmd); + GfmlLxr endLxr = GfmlLxr_.solo_(key + "_end", endTkn); + rv.SubLxr_Add(endLxr); + + rv.frame = frame; + rv.endLxr = endLxr; + rv.txtLxr = txtLxr; + return rv; + } GfmlLxr_frame() {} + public static GfmlLxr_frame as_(Object obj) {return obj instanceof GfmlLxr_frame ? (GfmlLxr_frame)obj : null;} + public static GfmlLxr_frame cast_(Object obj) {try {return (GfmlLxr_frame)obj;} catch(Exception exc) {throw Exc_.new_type_mismatch_w_exc(exc, GfmlLxr_frame.class, obj);}} +} diff --git a/110_gfml/src_100_tkn/gplx/gfml/GfmlObj.java b/110_gfml/src_100_tkn/gplx/gfml/GfmlObj.java new file mode 100644 index 000000000..d9a19a05e --- /dev/null +++ b/110_gfml/src_100_tkn/gplx/gfml/GfmlObj.java @@ -0,0 +1,29 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.gfml; import gplx.*; +public interface GfmlObj { + int ObjType(); +} +class GfmlObj_ { + public static final int + Type_tkn = 1 + , Type_atr = 2 + , Type_nde = 3 + , Type_prg = 4 + ; +} diff --git a/110_gfml/src_100_tkn/gplx/gfml/GfmlObjList.java b/110_gfml/src_100_tkn/gplx/gfml/GfmlObjList.java new file mode 100644 index 000000000..12f8d0e82 --- /dev/null +++ b/110_gfml/src_100_tkn/gplx/gfml/GfmlObjList.java @@ -0,0 +1,25 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.gfml; import gplx.*; +public class GfmlObjList extends List_adp_base { + @gplx.New public GfmlObj Get_at(int idx) {return (GfmlObj)Get_at_base(idx);} + public void Add(GfmlObj tkn) {Add_base(tkn);} + public void Add_at(GfmlObj tkn, int idx) {super.AddAt_base(idx, tkn);} + public void Del(GfmlObj tkn) {Del_base(tkn);} + public static GfmlObjList new_() {return new GfmlObjList();} GfmlObjList() {} +} diff --git a/110_gfml/src_100_tkn/gplx/gfml/GfmlTkn.java b/110_gfml/src_100_tkn/gplx/gfml/GfmlTkn.java new file mode 100644 index 000000000..7e5d2b6fb --- /dev/null +++ b/110_gfml/src_100_tkn/gplx/gfml/GfmlTkn.java @@ -0,0 +1,46 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.gfml; import gplx.*; +import gplx.core.strings.*; +public interface GfmlTkn extends GfmlObj { + String TknType(); + String Raw(); + String Val(); + GfmlTkn[] SubTkns(); + GfmlBldrCmd Cmd_of_Tkn(); + GfmlTkn MakeNew(String raw, String val); +} +class GfmlTknAry_ { + public static final GfmlTkn[] Empty = new GfmlTkn[0]; + public static GfmlTkn[] ary_(GfmlTkn... ary) {return ary;} + @gplx.Internal protected static String XtoRaw(GfmlTkn[] ary) { + String_bldr sb = String_bldr_.new_(); + for (GfmlTkn tkn : ary) + sb.Add(tkn.Raw()); + return sb.XtoStr(); + } + @gplx.Internal protected static String XtoVal(GfmlTkn[] ary) {return XtoVal(ary, 0, ary.length);} + static String XtoVal(GfmlTkn[] ary, int bgn, int end) { + String_bldr sb = String_bldr_.new_(); + for (int i = bgn; i < end; i++) { + GfmlTkn tkn = ary[i]; + sb.Add(tkn.Val()); + } + return sb.XtoStr(); + } +} diff --git a/110_gfml/src_100_tkn/gplx/gfml/GfmlTkn_.java b/110_gfml/src_100_tkn/gplx/gfml/GfmlTkn_.java new file mode 100644 index 000000000..640ac8a27 --- /dev/null +++ b/110_gfml/src_100_tkn/gplx/gfml/GfmlTkn_.java @@ -0,0 +1,65 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.gfml; import gplx.*; +public class GfmlTkn_ { + @gplx.Internal protected static final String NullRaw = "", NullVal = ""; static final String Type_base = "gfml.baseTkn"; + @gplx.Internal protected static final GfmlTkn + Null = new GfmlTkn_base().ctor_GfmlTkn_base("gfml.nullTkn", NullRaw, NullVal, GfmlBldrCmd_.Null) + , EndOfStream = GfmlTkn_.raw_("<>") + , IgnoreOutput = GfmlTkn_.raw_("<>"); + public static GfmlTkn as_(Object obj) {return obj instanceof GfmlTkn ? (GfmlTkn)obj : null;} + @gplx.Internal protected static GfmlTkn new_(String raw, String val) {return new GfmlTkn_base().ctor_GfmlTkn_base(Type_base, raw, val, GfmlBldrCmd_.Null);} + public static GfmlTkn raw_(String raw) {return new GfmlTkn_base().ctor_GfmlTkn_base(Type_base, raw, raw, GfmlBldrCmd_.Null);} + @gplx.Internal protected static GfmlTkn val_(String val) {return new GfmlTkn_base().ctor_GfmlTkn_base(Type_base, NullRaw, val, GfmlBldrCmd_.Null);} + @gplx.Internal protected static GfmlTkn cmd_(String tknType, GfmlBldrCmd cmd) {return new GfmlTkn_base().ctor_GfmlTkn_base(tknType, NullRaw, NullVal, cmd);} + @gplx.Internal protected static GfmlTkn valConst_(String tknType, String val, GfmlBldrCmd cmd) {return new GfmlTkn_valConst().ctor_GfmlTkn_base(tknType, GfmlTkn_.NullRaw, val, cmd);} + @gplx.Internal protected static GfmlTkn singleton_(String tknType, String raw, String val, GfmlBldrCmd cmd) {return new GfmlTkn_singleton().ctor_GfmlTkn_base(tknType, raw, val, cmd);} + @gplx.Internal protected static GfmlTkn composite_(String tknType, GfmlTkn[] ary) {return new GfmlTkn_composite(tknType, ary);} + @gplx.Internal protected static GfmlTkn composite_list_(String tknType, GfmlObjList list) { + GfmlTkn[] ary = new GfmlTkn[list.Count()]; + for (int i = 0; i < list.Count(); i++) + ary[i] = (GfmlTkn)list.Get_at(i); + return GfmlTkn_.composite_(tknType, ary); + } +} +class GfmlTkn_base implements GfmlTkn { + public int ObjType() {return GfmlObj_.Type_tkn;} + public String TknType() {return tknType;} private String tknType; + public String Raw() {return raw;} private String raw; + public String Val() {return val;} private String val; + public GfmlBldrCmd Cmd_of_Tkn() {return cmd;} GfmlBldrCmd cmd; + public GfmlTkn[] SubTkns() {return GfmlTknAry_.Empty;} + @gplx.Virtual public GfmlTkn MakeNew(String rawNew, String valNew) {return new GfmlTkn_base().ctor_GfmlTkn_base(tknType, rawNew, valNew, cmd);} + @gplx.Internal protected GfmlTkn_base ctor_GfmlTkn_base(String tknType, String raw, String val, GfmlBldrCmd cmd) {this.tknType = tknType; this.raw = raw; this.val = val; this.cmd = cmd; return this;} +} +class GfmlTkn_valConst extends GfmlTkn_base { + @Override public GfmlTkn MakeNew(String rawNew, String valNew) {return new GfmlTkn_base().ctor_GfmlTkn_base(this.TknType(), rawNew, this.Val(), this.Cmd_of_Tkn());} +} +class GfmlTkn_singleton extends GfmlTkn_base { + @Override public GfmlTkn MakeNew(String rawNew, String valNew) {return this;} +} +class GfmlTkn_composite implements GfmlTkn { + public int ObjType() {return GfmlObj_.Type_tkn;} + public String TknType() {return tknType;} private String tknType; + public String Raw() {return GfmlTknAry_.XtoRaw(ary);} + public String Val() {return GfmlTknAry_.XtoVal(ary);} + public GfmlBldrCmd Cmd_of_Tkn() {return GfmlBldrCmd_.Null;} + public GfmlTkn[] SubTkns() {return ary;} GfmlTkn[] ary; + public GfmlTkn MakeNew(String rawNew, String valNew) {throw Exc_.new_unimplemented_w_msg(".MakeNew cannot be invoked on GfmlTkn_composite (raw is available, but not val)", "tknType", tknType, "rawNew", rawNew, "valNew", valNew);} + @gplx.Internal protected GfmlTkn_composite(String tknType, GfmlTkn[] ary) {this.tknType = tknType; this.ary = ary;} +} diff --git a/110_gfml/src_100_tkn/gplx/gfml/GfmlTrie.java b/110_gfml/src_100_tkn/gplx/gfml/GfmlTrie.java new file mode 100644 index 000000000..83858ba79 --- /dev/null +++ b/110_gfml/src_100_tkn/gplx/gfml/GfmlTrie.java @@ -0,0 +1,114 @@ +/* +XOWA: the XOWA Offline Wiki Application +Copyright (C) 2012 gnosygnu@gmail.com + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +package gplx.gfml; import gplx.*; +import gplx.texts.*; /*CharStream*/ +public class GfmlTrie { + public String[] Symbols() { + String[] rv = new String[symbols.Count()]; + for (int i = 0; i < rv.length; i++) + rv[i] = String_.cast_(symbols.Get_at(i)); + return rv; + } Ordered_hash symbols = Ordered_hash_.new_(); + public int LastMatchCount; // PERF: prop is faster than method + public Object FindMatch(CharStream stream) { + Object result = null; int moveCount = 0; LastMatchCount = 0; + IntObjHash_base link = rootLink; + while (stream.AtMid()) { + Object found = link.Get_by(stream.Cur()); + if (found == null) break; // found is null; can happen for false matches; ex: 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
    " + , "
  1. ^ b
  2. " + , "
" + ) + ); + } + @Test public void Packed() { + fxt.Test_html_frag("File:A.png|a", "