aboutsummaryrefslogtreecommitdiffstats
path: root/lib/stdlib/test
diff options
context:
space:
mode:
authorErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
committerErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
commit84adefa331c4159d432d22840663c38f155cd4c1 (patch)
treebff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/stdlib/test
downloadotp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz
otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2
otp-84adefa331c4159d432d22840663c38f155cd4c1.zip
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/stdlib/test')
-rw-r--r--lib/stdlib/test/Makefile134
-rw-r--r--lib/stdlib/test/array_SUITE.erl816
-rw-r--r--lib/stdlib/test/base64_SUITE.erl257
-rw-r--r--lib/stdlib/test/beam_lib_SUITE.erl761
-rw-r--r--lib/stdlib/test/c_SUITE.erl116
-rw-r--r--lib/stdlib/test/c_SUITE_data/m.erl25
-rw-r--r--lib/stdlib/test/calendar_SUITE.erl251
-rw-r--r--lib/stdlib/test/dets_SUITE.erl4136
-rw-r--r--lib/stdlib/test/dets_SUITE_data/dets_test_v8b.detsbin0 -> 37396 bytes
-rw-r--r--lib/stdlib/test/dets_SUITE_data/dets_test_v8b_little_endian.detsbin0 -> 37396 bytes
-rw-r--r--lib/stdlib/test/dets_SUITE_data/version_9a.detsbin0 -> 5917 bytes
-rw-r--r--lib/stdlib/test/dets_SUITE_data/version_9b_phash.datbin0 -> 5981 bytes
-rw-r--r--lib/stdlib/test/dets_SUITE_data/version_r2d.detsbin0 -> 33885 bytes
-rw-r--r--lib/stdlib/test/dets_SUITE_data/version_r3b02.detsbin0 -> 34484 bytes
-rw-r--r--lib/stdlib/test/dict_SUITE.erl133
-rw-r--r--lib/stdlib/test/dict_test_lib.erl83
-rw-r--r--lib/stdlib/test/digraph_SUITE.erl520
-rw-r--r--lib/stdlib/test/digraph_utils_SUITE.erl316
-rw-r--r--lib/stdlib/test/dummy1_h.erl70
-rw-r--r--lib/stdlib/test/dummy_h.erl88
-rw-r--r--lib/stdlib/test/epp_SUITE.erl1148
-rw-r--r--lib/stdlib/test/epp_SUITE_data/mac.erl46
-rw-r--r--lib/stdlib/test/epp_SUITE_data/mac2.erl38
-rw-r--r--lib/stdlib/test/epp_SUITE_data/mac3.erl36
-rw-r--r--lib/stdlib/test/epp_SUITE_data/pmod.erl25
-rw-r--r--lib/stdlib/test/epp_SUITE_data/variable_1.erl24
-rw-r--r--lib/stdlib/test/epp_SUITE_data/variable_1_include.hrl19
-rw-r--r--lib/stdlib/test/epp_SUITE_data/variable_1_include_dir.hrl19
-rw-r--r--lib/stdlib/test/erl_eval_SUITE.erl1399
-rw-r--r--lib/stdlib/test/erl_eval_helper.erl28
-rw-r--r--lib/stdlib/test/erl_expand_records_SUITE.erl823
-rw-r--r--lib/stdlib/test/erl_internal_SUITE.erl69
-rw-r--r--lib/stdlib/test/erl_lint_SUITE.erl2783
-rw-r--r--lib/stdlib/test/erl_lint_SUITE_data/format.erl55
-rw-r--r--lib/stdlib/test/erl_pp_SUITE.erl1073
-rw-r--r--lib/stdlib/test/erl_scan_SUITE.erl1214
-rw-r--r--lib/stdlib/test/error_logger_forwarder.erl48
-rw-r--r--lib/stdlib/test/escript_SUITE.erl540
-rw-r--r--lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_dict/ebin/archive_script_dict.app12
-rw-r--r--lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_dict/priv/archive_script_dict.txt1
-rw-r--r--lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_dict/src/archive_script_dict.erl125
-rw-r--r--lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_dict/src/archive_script_dict_app.erl29
-rw-r--r--lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_dict/src/archive_script_dict_sup.erl39
-rw-r--r--lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_dummy/ebin/archive_script_dummy.app10
-rw-r--r--lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_dummy/src/archive_script_dummy.erl29
-rw-r--r--lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_dummy/src/archive_script_dummy_app.erl29
-rw-r--r--lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_dummy/src/archive_script_dummy_sup.erl33
-rw-r--r--lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_main.erl61
-rw-r--r--lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_main2.erl60
-rwxr-xr-xlib/stdlib/test/escript_SUITE_data/compile_error12
-rwxr-xr-xlib/stdlib/test/escript_SUITE_data/emulator_flags11
-rwxr-xr-xlib/stdlib/test/escript_SUITE_data/factorial11
-rwxr-xr-xlib/stdlib/test/escript_SUITE_data/factorial_compile12
-rwxr-xr-xlib/stdlib/test/escript_SUITE_data/factorial_compile_main13
-rwxr-xr-xlib/stdlib/test/escript_SUITE_data/factorial_epp17
-rwxr-xr-xlib/stdlib/test/escript_SUITE_data/factorial_warning13
-rwxr-xr-xlib/stdlib/test/escript_SUITE_data/filesize11
-rwxr-xr-xlib/stdlib/test/escript_SUITE_data/lint_error14
-rwxr-xr-xlib/stdlib/test/escript_SUITE_data/strange.name7
-rwxr-xr-xlib/stdlib/test/escript_SUITE_data/tail_rec25
-rwxr-xr-xlib/stdlib/test/escript_SUITE_data/test_script_name5
-rwxr-xr-xlib/stdlib/test/escript_SUITE_data/trap_exit6
-rw-r--r--lib/stdlib/test/ets_SUITE.erl5355
-rw-r--r--lib/stdlib/test/ets_SUITE_data/dummy.txt1
-rw-r--r--lib/stdlib/test/ets_tough_SUITE.erl1093
-rw-r--r--lib/stdlib/test/file_sorter_SUITE.erl1345
-rw-r--r--lib/stdlib/test/filelib_SUITE.erl241
-rw-r--r--lib/stdlib/test/filename_SUITE.erl459
-rw-r--r--lib/stdlib/test/fixtable_SUITE.erl414
-rw-r--r--lib/stdlib/test/format_SUITE.erl51
-rw-r--r--lib/stdlib/test/gen_event_SUITE.erl846
-rw-r--r--lib/stdlib/test/gen_fsm_SUITE.erl838
-rw-r--r--lib/stdlib/test/gen_server_SUITE.erl1049
-rw-r--r--lib/stdlib/test/id_transform_SUITE.erl398
-rw-r--r--lib/stdlib/test/id_transform_SUITE_data/External.hrl41
-rw-r--r--lib/stdlib/test/id_transform_SUITE_data/m.hrl30
-rw-r--r--lib/stdlib/test/id_transform_SUITE_data/m_i.hrl29
-rw-r--r--lib/stdlib/test/id_transform_SUITE_data/oe_ex.hrl29
-rw-r--r--lib/stdlib/test/io_SUITE.erl1900
-rw-r--r--lib/stdlib/test/io_proto_SUITE.erl1824
-rw-r--r--lib/stdlib/test/io_proto_SUITE_data/external_utf16_big_bom.datbin0 -> 22 bytes
-rw-r--r--lib/stdlib/test/io_proto_SUITE_data/external_utf16_little_bom.datbin0 -> 22 bytes
-rw-r--r--lib/stdlib/test/io_proto_SUITE_data/external_utf8_bom.dat1
-rw-r--r--lib/stdlib/test/io_proto_SUITE_data/testdata_latin1.dat2
-rw-r--r--lib/stdlib/test/io_proto_SUITE_data/testdata_utf16_big.datbin0 -> 98 bytes
-rw-r--r--lib/stdlib/test/io_proto_SUITE_data/testdata_utf16_big_bom.datbin0 -> 100 bytes
-rw-r--r--lib/stdlib/test/io_proto_SUITE_data/testdata_utf16_little.datbin0 -> 98 bytes
-rw-r--r--lib/stdlib/test/io_proto_SUITE_data/testdata_utf16_little_bom.datbin0 -> 100 bytes
-rw-r--r--lib/stdlib/test/io_proto_SUITE_data/testdata_utf32_big.datbin0 -> 196 bytes
-rw-r--r--lib/stdlib/test/io_proto_SUITE_data/testdata_utf32_big_bom.datbin0 -> 200 bytes
-rw-r--r--lib/stdlib/test/io_proto_SUITE_data/testdata_utf32_little.datbin0 -> 196 bytes
-rw-r--r--lib/stdlib/test/io_proto_SUITE_data/testdata_utf32_little_bom.datbin0 -> 200 bytes
-rw-r--r--lib/stdlib/test/io_proto_SUITE_data/testdata_utf8.dat1
-rw-r--r--lib/stdlib/test/io_proto_SUITE_data/testdata_utf8_bom.dat1
-rw-r--r--lib/stdlib/test/lists_SUITE.erl2657
-rw-r--r--lib/stdlib/test/log_mf_h_SUITE.erl92
-rw-r--r--lib/stdlib/test/ms_transform_SUITE.erl730
-rw-r--r--lib/stdlib/test/naughty_child.erl101
-rw-r--r--lib/stdlib/test/proc_lib_SUITE.erl344
-rw-r--r--lib/stdlib/test/qlc_SUITE.erl8179
-rw-r--r--lib/stdlib/test/queue_SUITE.erl604
-rw-r--r--lib/stdlib/test/random_SUITE.erl110
-rw-r--r--lib/stdlib/test/random_iolist.erl195
-rw-r--r--lib/stdlib/test/random_unicode_list.erl270
-rw-r--r--lib/stdlib/test/re_SUITE.erl526
-rw-r--r--lib/stdlib/test/re_SUITE_data/testoutput16608
-rw-r--r--lib/stdlib/test/re_SUITE_data/testoutput10669
-rw-r--r--lib/stdlib/test/re_SUITE_data/testoutput29388
-rw-r--r--lib/stdlib/test/re_SUITE_data/testoutput3163
-rw-r--r--lib/stdlib/test/re_SUITE_data/testoutput41074
-rw-r--r--lib/stdlib/test/re_SUITE_data/testoutput51611
-rw-r--r--lib/stdlib/test/re_SUITE_data/testoutput61682
-rw-r--r--lib/stdlib/test/re_SUITE_data/testoutput77215
-rw-r--r--lib/stdlib/test/re_SUITE_data/testoutput81287
-rw-r--r--lib/stdlib/test/re_SUITE_data/testoutput91643
-rw-r--r--lib/stdlib/test/re_testoutput1_replacement_test.erl18596
-rw-r--r--lib/stdlib/test/re_testoutput1_split_test.erl29418
-rw-r--r--lib/stdlib/test/run_pcre_tests.erl1201
-rw-r--r--lib/stdlib/test/select_SUITE.erl804
-rw-r--r--lib/stdlib/test/sets_SUITE.erl495
-rw-r--r--lib/stdlib/test/sets_test_lib.erl124
-rw-r--r--lib/stdlib/test/shell_SUITE.erl2822
-rw-r--r--lib/stdlib/test/slave_SUITE.erl261
-rw-r--r--lib/stdlib/test/sofs_SUITE.erl2374
-rw-r--r--lib/stdlib/test/stdlib.cover10
-rw-r--r--lib/stdlib/test/stdlib.spec4
-rw-r--r--lib/stdlib/test/stdlib.spec.vxworks8
-rw-r--r--lib/stdlib/test/stdlib_SUITE.erl64
-rw-r--r--lib/stdlib/test/string_SUITE.erl511
-rw-r--r--lib/stdlib/test/suite_release.exclude4
-rw-r--r--lib/stdlib/test/supervisor_1.erl79
-rw-r--r--lib/stdlib/test/supervisor_SUITE.erl1203
-rw-r--r--lib/stdlib/test/supervisor_bridge_SUITE.erl178
-rw-r--r--lib/stdlib/test/sys_SUITE.erl173
-rw-r--r--lib/stdlib/test/tar_SUITE.erl718
-rw-r--r--lib/stdlib/test/tar_SUITE_data/bad_checksum.tarbin0 -> 2560 bytes
-rw-r--r--lib/stdlib/test/tar_SUITE_data/bad_even_shorter.tarbin0 -> 567 bytes
-rw-r--r--lib/stdlib/test/tar_SUITE_data/bad_octal.tarbin0 -> 2560 bytes
-rw-r--r--lib/stdlib/test/tar_SUITE_data/bad_too_short.tarbin0 -> 1072 bytes
-rw-r--r--lib/stdlib/test/tar_SUITE_data/cooked_tar_problem.tar.gzbin0 -> 7099 bytes
-rw-r--r--lib/stdlib/test/tar_SUITE_data/long_names.tarbin0 -> 7168 bytes
-rwxr-xr-xlib/stdlib/test/tar_SUITE_data/make_tar21
-rw-r--r--lib/stdlib/test/tar_SUITE_data/no_fancy_stuff.tarbin0 -> 17408 bytes
-rw-r--r--lib/stdlib/test/timer_SUITE.erl391
-rw-r--r--lib/stdlib/test/timer_simple_SUITE.erl551
-rw-r--r--lib/stdlib/test/unicode_SUITE.erl1241
-rw-r--r--lib/stdlib/test/win32reg_SUITE.erl89
-rw-r--r--lib/stdlib/test/y2k_SUITE.erl185
-rw-r--r--lib/stdlib/test/zip_SUITE.erl759
-rw-r--r--lib/stdlib/test/zip_SUITE_data/META-INF/MANIFEST.MF3
-rw-r--r--lib/stdlib/test/zip_SUITE_data/abc.txt23
-rw-r--r--lib/stdlib/test/zip_SUITE_data/abc.zipbin0 -> 2358 bytes
-rw-r--r--lib/stdlib/test/zip_SUITE_data/bad_central_directory.zipbin0 -> 847 bytes
-rw-r--r--lib/stdlib/test/zip_SUITE_data/bad_crc.zipbin0 -> 847 bytes
-rw-r--r--lib/stdlib/test/zip_SUITE_data/bad_eocd.zipbin0 -> 847 bytes
-rw-r--r--lib/stdlib/test/zip_SUITE_data/bad_file_header.zipbin0 -> 847 bytes
-rw-r--r--lib/stdlib/test/zip_SUITE_data/emptyFile0
-rw-r--r--lib/stdlib/test/zip_SUITE_data/quotes/rain.txt1
-rw-r--r--lib/stdlib/test/zip_SUITE_data/test.jarbin0 -> 471 bytes
-rw-r--r--lib/stdlib/test/zip_SUITE_data/test.txt1
-rw-r--r--lib/stdlib/test/zip_SUITE_data/wikipedia.txt30
161 files changed, 141116 insertions, 0 deletions
diff --git a/lib/stdlib/test/Makefile b/lib/stdlib/test/Makefile
new file mode 100644
index 0000000000..7a87eef5f3
--- /dev/null
+++ b/lib/stdlib/test/Makefile
@@ -0,0 +1,134 @@
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+
+MODULES= \
+ array_SUITE \
+ base64_SUITE \
+ beam_lib_SUITE \
+ c_SUITE \
+ calendar_SUITE \
+ dets_SUITE \
+ dict_SUITE \
+ dict_test_lib \
+ digraph_SUITE \
+ digraph_utils_SUITE \
+ dummy1_h \
+ dummy_h \
+ epp_SUITE \
+ erl_eval_helper \
+ erl_eval_SUITE \
+ erl_expand_records_SUITE \
+ erl_internal_SUITE \
+ erl_lint_SUITE \
+ erl_pp_SUITE \
+ erl_scan_SUITE \
+ escript_SUITE \
+ ets_SUITE \
+ ets_tough_SUITE \
+ filelib_SUITE \
+ file_sorter_SUITE \
+ filename_SUITE \
+ fixtable_SUITE \
+ format_SUITE \
+ gen_event_SUITE \
+ gen_fsm_SUITE \
+ gen_server_SUITE \
+ id_transform_SUITE \
+ io_SUITE \
+ io_proto_SUITE \
+ lists_SUITE \
+ log_mf_h_SUITE \
+ ms_transform_SUITE \
+ proc_lib_SUITE \
+ qlc_SUITE \
+ queue_SUITE \
+ random_SUITE \
+ re_SUITE \
+ run_pcre_tests \
+ re_testoutput1_replacement_test \
+ re_testoutput1_split_test \
+ slave_SUITE \
+ sets_SUITE \
+ sets_test_lib \
+ sofs_SUITE \
+ stdlib_SUITE \
+ string_SUITE \
+ supervisor_1 \
+ naughty_child \
+ shell_SUITE \
+ supervisor_SUITE \
+ supervisor_bridge_SUITE \
+ sys_SUITE \
+ tar_SUITE \
+ timer_SUITE \
+ timer_simple_SUITE \
+ unicode_SUITE \
+ win32reg_SUITE \
+ y2k_SUITE \
+ select_SUITE \
+ zip_SUITE \
+ random_unicode_list \
+ random_iolist \
+ error_logger_forwarder
+
+ERL_FILES= $(MODULES:%=%.erl)
+
+TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
+
+INSTALL_PROGS= $(TARGET_FILES)
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/stdlib_test
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+
+ERL_MAKE_FLAGS +=
+ERL_COMPILE_FLAGS += -I$(ERL_TOP)/lib/test_server/include \
+ -I$(ERL_TOP)/lib/kernel/include
+
+EBIN = .
+
+EMAKEFILE=Emakefile
+COVERFILE=stdlib.cover
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+
+make_emakefile:
+ $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) $(MODULES) \
+ >> $(EMAKEFILE)
+
+tests debug opt: make_emakefile
+ erl $(ERL_MAKE_FLAGS) -make
+
+clean:
+ rm -f $(EMAKEFILE)
+ rm -f $(TARGET_FILES)
+ rm -f core
+
+docs:
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+release_spec: opt
+
+release_tests_spec: make_emakefile
+ $(INSTALL_DIR) $(RELSYSDIR)
+ $(INSTALL_DATA) stdlib.spec stdlib.spec.vxworks $(EMAKEFILE) \
+ $(ERL_FILES) $(COVERFILE) $(RELSYSDIR)
+ chmod -f -R u+w $(RELSYSDIR)
+ @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
+
+release_docs_spec:
diff --git a/lib/stdlib/test/array_SUITE.erl b/lib/stdlib/test/array_SUITE.erl
new file mode 100644
index 0000000000..7cfdcf6dfd
--- /dev/null
+++ b/lib/stdlib/test/array_SUITE.erl
@@ -0,0 +1,816 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(array_SUITE).
+
+-include("test_server.hrl").
+
+%% Default timetrap timeout (set in init_per_testcase).
+%% This should be set relatively high (10-15 times the expected
+%% max testcasetime).
+-define(default_timeout, ?t:seconds(60)).
+
+%% Test server specific exports
+-export([all/1]).
+-export([init_per_testcase/2, fin_per_testcase/2]).
+
+-export([
+ new_test/1,
+ fix_test/1,
+ relax_test/1,
+ resize_test/1,
+ set_get_test/1,
+ to_list_test/1,
+ sparse_to_list_test/1,
+ from_list_test/1,
+ to_orddict_test/1,
+ sparse_to_orddict_test/1,
+ from_orddict_test/1,
+ map_test/1,
+ sparse_map_test/1,
+ foldl_test/1,
+ sparse_foldl_test/1,
+ foldr_test/1,
+ sparse_foldr_test/1
+ ]).
+
+
+-export([t/0,t/1,extract_tests/0]).
+
+-import(array,
+ [new/0, new/1, new/2, is_array/1, set/3, get/2, %size/1,
+ sparse_size/1, default/1, reset/2, to_list/1, sparse_to_list/1,
+ from_list/1, from_list/2, to_orddict/1, sparse_to_orddict/1,
+ from_orddict/1, from_orddict/2, map/2, sparse_map/2, foldl/3,
+ foldr/3, sparse_foldl/3, sparse_foldr/3, fix/1, relax/1, is_fix/1,
+ resize/1, resize/2]).
+
+%%
+%% all/1
+%%
+all(doc) ->
+ [];
+all(suite) ->
+ [new_test,
+ fix_test,
+ relax_test,
+ resize_test,
+ set_get_test,
+ to_list_test,
+ sparse_to_list_test,
+ from_list_test,
+ to_orddict_test,
+ sparse_to_orddict_test,
+ from_orddict_test,
+ map_test,
+ sparse_map_test,
+ foldl_test,
+ sparse_foldl_test,
+ foldr_test,
+ sparse_foldr_test
+ ].
+
+init_per_testcase(_Case, Config) ->
+ ?line Dog=test_server:timetrap(?default_timeout),
+ [{watchdog, Dog}|Config].
+
+fin_per_testcase(_Case, Config) ->
+ Dog=?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+-define(LEAFSIZE,10).
+-define(NODESIZE,?LEAFSIZE).
+
+-record(array, {size, %% number of defined entries
+ max, %% maximum number of entries in current tree
+ default, %% the default value (usually 'undefined')
+ elements %% the tuple tree
+ }).
+
+-define(_assert(What),
+ begin ?line true = What end
+ ).
+-define(_assertNot(What),
+ begin ?line false = What end
+ ).
+
+-define(_assertMatch(Res,What),
+ begin
+ ?line case What of Res -> ok end
+ end
+ ).
+-define(_assertError(Reas,What),
+ begin ?line fun() ->
+ try What of
+ A_Success -> exit({test_error, A_Success})
+ catch error:Reas -> ok end
+ end()
+ end
+ ).
+
+-define(LET(Var,Expr, Test), begin ?line fun() -> Var = Expr, Test end() end).
+
+-define(_test(Expr), begin ?line Expr end).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Some helpers to be able to run the tests without testserver
+%%%%%%%%%%%%%%%%%%%%%%%%%
+t() -> t([all]).
+
+t(What) when not is_list(What) ->
+ t([What]);
+t(What) ->
+ lists:foreach(fun(T) ->
+ io:format("Test ~p ~n",[T]),
+ try
+ ?MODULE:T([])
+ catch _E:_R ->
+ Line = get(test_server_loc),
+ io:format("Failed ~p:~p ~p ~p~n ~p~n",
+ [T,Line,_E,_R, erlang:get_stacktrace()])
+ end
+ end, expand(What)).
+
+expand(All) ->
+ lists:reverse(expand(All,[])).
+expand([H|T], Acc) ->
+ case ?MODULE:H(suite) of
+ [] -> expand(T,[H|Acc]);
+ Cs ->
+ R = expand(Cs, Acc),
+ expand(T, R)
+ end;
+expand([], Acc) -> Acc.
+
+%%%%% extract tests
+
+extract_tests() ->
+ {ok, In} = file:open("../src/array.erl", [read]),
+ {ok, Out} = file:open("array_temp.erl", [write]),
+ try
+ Tests = extract_tests(In,Out,[]),
+ Call = fun(Test) ->
+ io:format(Out, "~s(doc) -> [];~n", [Test]),
+ io:format(Out, "~s(suite) -> [];~n", [Test]),
+ io:format(Out, "~s(Config) when is_list(Config) -> ~s_(), ok.~n",
+ [Test, Test])
+ end,
+ [Call(Test) || Test <- Tests],
+ io:format("Tests ~p~n", [Tests])
+ catch _:Err ->
+ io:format("Error: ~p ~p~n", [Err, erlang:get_stacktrace()])
+ end,
+ file:close(In),
+ file:close(Out).
+
+extract_tests(In,Out,Tests) ->
+ case io:get_line(In,"") of
+ eof -> lists:reverse(Tests);
+ "-ifdef(EUNIT)" ++ _ ->
+ Test = write_test(In,Out),
+ extract_tests(In,Out, [Test|Tests]);
+ _E ->
+ extract_tests(In,Out,Tests)
+ end.
+
+write_test(In,Out) ->
+ Line = io:get_line(In,""),
+ io:put_chars(Out, Line),
+ [$_|Test] = lists:dropwhile(fun($_) -> false;(_) -> true end,lists:reverse(Line)),
+ write_test_1(In,Out),
+ lists:reverse(Test).
+
+write_test_1(In,Out) ->
+ case io:get_line(In,"") of
+ "-endif" ++ _ ->
+ io:nl(Out),
+ ok;
+ Line ->
+ io:put_chars(Out, Line),
+ write_test_1(In,Out)
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Actual tests
+
+new_test_() ->
+ N0 = ?LEAFSIZE,
+ N01 = N0+1,
+ N1 = ?NODESIZE*N0,
+ N11 = N1+1,
+ N2 = ?NODESIZE*N1,
+ [?_test(new()),
+
+ ?_test(new([])),
+ ?_test(new(10)),
+ ?_test(new({size,10})),
+ ?_test(new(fixed)),
+ ?_test(new({fixed,true})),
+ ?_test(new({fixed,false})),
+ ?_test(new({default,undefined})),
+ ?_test(new([{size,100},{fixed,false},{default,undefined}])),
+ ?_test(new([100,fixed,{default,0}])),
+
+ ?_assert(new() =:= new([])),
+ ?_assert(new() =:= new([{size,0},{default,undefined},{fixed,false}])),
+ ?_assert(new() =:= new(0, {fixed,false})),
+ ?_assert(new(fixed) =:= new(0)),
+ ?_assert(new(fixed) =:= new(0, [])),
+ ?_assert(new(10) =:= new([{size,0},{size,5},{size,10}])),
+ ?_assert(new(10) =:= new(0, {size,10})),
+ ?_assert(new(10, []) =:= new(10, [{default,undefined},{fixed,true}])),
+
+ ?_assertError(badarg, new(-1)),
+ ?_assertError(badarg, new(10.0)),
+ ?_assertError(badarg, new(undefined)),
+ ?_assertError(badarg, new([undefined])),
+ ?_assertError(badarg, new([{default,0} | fixed])),
+
+ ?_assertError(badarg, new(-1, [])),
+ ?_assertError(badarg, new(10.0, [])),
+ ?_assertError(badarg, new(undefined, [])),
+
+ ?_assertMatch(#array{size=0,max=N0,default=undefined,elements=N0},
+ new()),
+ ?_assertMatch(#array{size=0,max=0,default=undefined,elements=N0},
+ new(fixed)),
+ ?_assertMatch(#array{size=N0,max=N0,elements=N0},
+ new(N0, {fixed,false})),
+ ?_assertMatch(#array{size=N01,max=N1,elements=N1},
+ new(N01, {fixed,false})),
+ ?_assertMatch(#array{size=N1,max=N1,elements=N1},
+ new(N1, {fixed,false})),
+ ?_assertMatch(#array{size=N11,max=N2,elements=N2},
+ new(N11, {fixed,false})),
+ ?_assertMatch(#array{size=N2, max=N2, default=42,elements=N2},
+ new(N2, [{fixed,false},{default,42}])),
+
+ ?_assert(0 =:= array:size(new())),
+ ?_assert(17 =:= array:size(new(17))),
+ ?_assert(100 =:= array:size(array:set(99,0,new()))),
+ ?_assertError(badarg, array:size({bad_data,gives_error})),
+
+ ?_assert(undefined =:= default(new())),
+ ?_assert(4711 =:= default(new({default,4711}))),
+ ?_assert(0 =:= default(new(10, {default,0}))),
+ ?_assertError(badarg, default({bad_data,gives_error})),
+
+ ?_assert(is_array(new())),
+ ?_assert(false =:= is_array({foobar, 23, 23})),
+ ?_assert(false =:= is_array(#array{size=bad})),
+ ?_assert(false =:= is_array(#array{max=bad})),
+ ?_assert(is_array(new(10))),
+ ?_assert(is_array(new(10, {fixed,false})))
+ ].
+
+fix_test_() ->
+ [?_assert(is_array(fix(new()))),
+ ?_assert(fix(new()) =:= new(fixed)),
+
+ ?_assertNot(is_fix(new())),
+ ?_assertNot(is_fix(new([]))),
+ ?_assertNot(is_fix(new({fixed,false}))),
+ ?_assertNot(is_fix(new(10, {fixed,false}))),
+ ?_assert(is_fix(new({fixed,true}))),
+ ?_assert(is_fix(new(fixed))),
+ ?_assert(is_fix(new(10))),
+ ?_assert(is_fix(new(10, []))),
+ ?_assert(is_fix(new(10, {fixed,true}))),
+ ?_assert(is_fix(fix(new()))),
+ ?_assert(is_fix(fix(new({fixed,false})))),
+
+ ?_test(set(0, 17, new())),
+ ?_assertError(badarg, set(0, 17, new(fixed))),
+ ?_assertError(badarg, set(1, 42, fix(set(0, 17, new())))),
+
+ ?_test(set(9, 17, new(10))),
+ ?_assertError(badarg, set(10, 17, new(10))),
+ ?_assertError(badarg, set(10, 17, fix(new(10, {fixed,false}))))
+ ].
+
+relax_test_() ->
+ [?_assert(is_array(relax(new(fixed)))),
+ ?_assertNot(is_fix(relax(fix(new())))),
+ ?_assertNot(is_fix(relax(new(fixed)))),
+
+ ?_assert(new() =:= relax(new(fixed))),
+ ?_assert(new() =:= relax(new(0))),
+ ?_assert(new(17, {fixed,false}) =:= relax(new(17))),
+ ?_assert(new(100, {fixed,false})
+ =:= relax(fix(new(100, {fixed,false}))))
+ ].
+
+resize_test_() ->
+ [?_assert(resize(0, new()) =:= new()),
+ ?_assert(resize(99, new(99)) =:= new(99)),
+ ?_assert(resize(99, relax(new(99))) =:= relax(new(99))),
+ ?_assert(is_fix(resize(100, new(10)))),
+ ?_assertNot(is_fix(resize(100, relax(new(10))))),
+
+ ?_assert(array:size(resize(100, new())) =:= 100),
+ ?_assert(array:size(resize(0, new(100))) =:= 0),
+ ?_assert(array:size(resize(99, new(10))) =:= 99),
+ ?_assert(array:size(resize(99, new(1000))) =:= 99),
+
+ ?_assertError(badarg, set(99, 17, new(10))),
+ ?_test(set(99, 17, resize(100, new(10)))),
+ ?_assertError(badarg, set(100, 17, resize(100, new(10)))),
+
+ ?_assert(array:size(resize(new())) =:= 0),
+ ?_assert(array:size(resize(new(8))) =:= 0),
+ ?_assert(array:size(resize(array:set(7, 0, new()))) =:= 8),
+ ?_assert(array:size(resize(array:set(7, 0, new(10)))) =:= 8),
+ ?_assert(array:size(resize(array:set(99, 0, new(10,{fixed,false}))))
+ =:= 100),
+ ?_assert(array:size(resize(array:set(7, undefined, new()))) =:= 0),
+ ?_assert(array:size(resize(array:from_list([1,2,3,undefined])))
+ =:= 3),
+ ?_assert(array:size(
+ resize(array:from_orddict([{3,0},{17,0},{99,undefined}])))
+ =:= 18),
+ ?_assertError(badarg, resize(foo, bad_argument))
+ ].
+
+set_get_test_() ->
+ N0 = ?LEAFSIZE,
+ N1 = ?NODESIZE*N0,
+ [?_assert(array:get(0, new()) =:= undefined),
+ ?_assert(array:get(1, new()) =:= undefined),
+ ?_assert(array:get(99999, new()) =:= undefined),
+
+ ?_assert(array:get(0, new(1)) =:= undefined),
+ ?_assert(array:get(0, new(1,{default,0})) =:= 0),
+ ?_assert(array:get(9, new(10)) =:= undefined),
+
+ ?_assertError(badarg, array:get(0, new(fixed))),
+ ?_assertError(badarg, array:get(1, new(1))),
+ ?_assertError(badarg, array:get(-1, new(1))),
+ ?_assertError(badarg, array:get(10, new(10))),
+ ?_assertError(badarg, array:set(-1, foo, new(10))),
+ ?_assertError(badarg, array:set(10, foo, no_array)),
+
+ ?_assert(array:size(set(0, 17, new())) =:= 1),
+ ?_assert(array:size(set(N1-1, 17, new())) =:= N1),
+ ?_assert(array:size(set(0, 42, set(0, 17, new()))) =:= 1),
+ ?_assert(array:size(set(9, 42, set(0, 17, new()))) =:= 10),
+
+ ?_assert(array:get(0, set(0, 17, new())) =:= 17),
+ ?_assert(array:get(0, set(1, 17, new())) =:= undefined),
+ ?_assert(array:get(1, set(1, 17, new())) =:= 17),
+
+ ?_assert(array:get(0, fix(set(0, 17, new()))) =:= 17),
+ ?_assertError(badarg, array:get(1, fix(set(0, 17, new())))),
+
+ ?_assert(array:get(N1-2, set(N1-1, 17, new())) =:= undefined),
+ ?_assert(array:get(N1-1, set(N1-1, 17, new())) =:= 17),
+ ?_assertError(badarg, array:get(N1, fix(set(N1-1, 17, new())))),
+
+ ?_assert(array:get(0, set(0, 42, set(0, 17, new()))) =:= 42),
+
+ ?_assert(array:get(0, reset(0, new())) =:= undefined),
+ ?_assert(array:get(0, reset(0, set(0, 17, new()))) =:= undefined),
+ ?_assert(array:get(0, reset(0, new({default,42}))) =:= 42),
+ ?_assert(array:get(0, reset(0, set(0, 17, new({default,42}))))
+ =:= 42)
+ ].
+
+to_list_test_() ->
+ N0 = ?LEAFSIZE,
+ [?_assert([] =:= to_list(new())),
+ ?_assert([undefined] =:= to_list(new(1))),
+ ?_assert([undefined,undefined] =:= to_list(new(2))),
+ ?_assert(lists:duplicate(N0,0) =:= to_list(new(N0,{default,0}))),
+ ?_assert(lists:duplicate(N0+1,1) =:= to_list(new(N0+1,{default,1}))),
+ ?_assert(lists:duplicate(N0+2,2) =:= to_list(new(N0+2,{default,2}))),
+ ?_assert(lists:duplicate(666,6) =:= to_list(new(666,{default,6}))),
+ ?_assert([1,2,3] =:= to_list(set(2,3,set(1,2,set(0,1,new()))))),
+ ?_assert([3,2,1] =:= to_list(set(0,3,set(1,2,set(2,1,new()))))),
+ ?_assert([1|lists:duplicate(N0-2,0)++[1]] =:=
+ to_list(set(N0-1,1,set(0,1,new({default,0}))))),
+ ?_assert([1|lists:duplicate(N0-1,0)++[1]] =:=
+ to_list(set(N0,1,set(0,1,new({default,0}))))),
+ ?_assert([1|lists:duplicate(N0,0)++[1]] =:=
+ to_list(set(N0+1,1,set(0,1,new({default,0}))))),
+ ?_assert([1|lists:duplicate(N0*3,0)++[1]] =:=
+ to_list(set((N0*3)+1,1,set(0,1,new({default,0}))))),
+ ?_assertError(badarg, to_list(no_array))
+ ].
+
+sparse_to_list_test_() ->
+ N0 = ?LEAFSIZE,
+ [?_assert([] =:= sparse_to_list(new())),
+ ?_assert([] =:= sparse_to_list(new(1))),
+ ?_assert([] =:= sparse_to_list(new(1,{default,0}))),
+ ?_assert([] =:= sparse_to_list(new(2))),
+ ?_assert([] =:= sparse_to_list(new(2,{default,0}))),
+ ?_assert([] =:= sparse_to_list(new(N0,{default,0}))),
+ ?_assert([] =:= sparse_to_list(new(N0+1,{default,1}))),
+ ?_assert([] =:= sparse_to_list(new(N0+2,{default,2}))),
+ ?_assert([] =:= sparse_to_list(new(666,{default,6}))),
+ ?_assert([1,2,3] =:= sparse_to_list(set(2,3,set(1,2,set(0,1,new()))))),
+ ?_assert([3,2,1] =:= sparse_to_list(set(0,3,set(1,2,set(2,1,new()))))),
+ ?_assert([0,1] =:= sparse_to_list(set(N0-1,1,set(0,0,new())))),
+ ?_assert([0,1] =:= sparse_to_list(set(N0,1,set(0,0,new())))),
+ ?_assert([0,1] =:= sparse_to_list(set(N0+1,1,set(0,0,new())))),
+ ?_assert([0,1,2] =:= sparse_to_list(set(N0*10+1,2,set(N0*2+1,1,set(0,0,new()))))),
+ ?_assertError(badarg, sparse_to_list(no_array))
+ ].
+
+from_list_test_() ->
+ N0 = ?LEAFSIZE,
+ N1 = ?NODESIZE*N0,
+ N2 = ?NODESIZE*N1,
+ N3 = ?NODESIZE*N2,
+ N4 = ?NODESIZE*N3,
+ [?_assert(array:size(from_list([])) =:= 0),
+ ?_assert(array:is_fix(from_list([])) =:= false),
+ ?_assert(array:size(from_list([undefined])) =:= 1),
+ ?_assert(array:is_fix(from_list([undefined])) =:= false),
+ ?_assert(array:size(from_list(lists:seq(1,N1))) =:= N1),
+ ?_assert(to_list(from_list(lists:seq(1,N0))) =:= lists:seq(1,N0)),
+ ?_assert(to_list(from_list(lists:seq(1,N0+1))) =:= lists:seq(1,N0+1)),
+ ?_assert(to_list(from_list(lists:seq(1,N0+2))) =:= lists:seq(1,N0+2)),
+ ?_assert(to_list(from_list(lists:seq(1,N2))) =:= lists:seq(1,N2)),
+ ?_assert(to_list(from_list(lists:seq(1,N2+1))) =:= lists:seq(1,N2+1)),
+ ?_assert(to_list(from_list(lists:seq(0,N3))) =:= lists:seq(0,N3)),
+ ?_assert(to_list(from_list(lists:seq(0,N4))) =:= lists:seq(0,N4)),
+ ?_assertError(badarg, from_list([a,b,a,c|d])),
+ ?_assertError(badarg, from_list(no_array))
+ ].
+
+to_orddict_test_() ->
+ N0 = ?LEAFSIZE,
+ [?_assert([] =:= to_orddict(new())),
+ ?_assert([{0,undefined}] =:= to_orddict(new(1))),
+ ?_assert([{0,undefined},{1,undefined}] =:= to_orddict(new(2))),
+ ?_assert([{N,0}||N<-lists:seq(0,N0-1)]
+ =:= to_orddict(new(N0,{default,0}))),
+ ?_assert([{N,1}||N<-lists:seq(0,N0)]
+ =:= to_orddict(new(N0+1,{default,1}))),
+ ?_assert([{N,2}||N<-lists:seq(0,N0+1)]
+ =:= to_orddict(new(N0+2,{default,2}))),
+ ?_assert([{N,6}||N<-lists:seq(0,665)]
+ =:= to_orddict(new(666,{default,6}))),
+ ?_assert([{0,1},{1,2},{2,3}] =:=
+ to_orddict(set(2,3,set(1,2,set(0,1,new()))))),
+ ?_assert([{0,3},{1,2},{2,1}] =:=
+ to_orddict(set(0,3,set(1,2,set(2,1,new()))))),
+ ?_assert([{0,1}|[{N,0}||N<-lists:seq(1,N0-2)]++[{N0-1,1}]]
+ =:= to_orddict(set(N0-1,1,set(0,1,new({default,0}))))),
+ ?_assert([{0,1}|[{N,0}||N<-lists:seq(1,N0-1)]++[{N0,1}]]
+ =:= to_orddict(set(N0,1,set(0,1,new({default,0}))))),
+ ?_assert([{0,1}|[{N,0}||N<-lists:seq(1,N0)]++[{N0+1,1}]]
+ =:= to_orddict(set(N0+1,1,set(0,1,new({default,0}))))),
+ ?_assert([{0,0} | [{N,undefined}||N<-lists:seq(1,N0*2)]] ++
+ [{N0*2+1,1} | [{N,undefined}||N<-lists:seq(N0*2+2,N0*10)]] ++
+ [{N0*10+1,2}] =:=
+ to_orddict(set(N0*10+1,2,set(N0*2+1,1,set(0,0,new()))))),
+ ?_assertError(badarg, to_orddict(no_array))
+ ].
+
+sparse_to_orddict_test_() ->
+ N0 = ?LEAFSIZE,
+ [?_assert([] =:= sparse_to_orddict(new())),
+ ?_assert([] =:= sparse_to_orddict(new(1))),
+ ?_assert([] =:= sparse_to_orddict(new(1,{default,0}))),
+ ?_assert([] =:= sparse_to_orddict(new(2))),
+ ?_assert([] =:= sparse_to_orddict(new(2,{default,0}))),
+ ?_assert([] =:= sparse_to_orddict(new(N0,{default,0}))),
+ ?_assert([] =:= sparse_to_orddict(new(N0+1,{default,1}))),
+ ?_assert([] =:= sparse_to_orddict(new(N0+2,{default,2}))),
+ ?_assert([] =:= sparse_to_orddict(new(666,{default,6}))),
+ ?_assert([{0,1},{1,2},{2,3}] =:=
+ sparse_to_orddict(set(2,3,set(1,2,set(0,1,new()))))),
+ ?_assert([{0,3},{1,2},{2,1}] =:=
+ sparse_to_orddict(set(0,3,set(1,2,set(2,1,new()))))),
+ ?_assert([{0,1},{N0-1,1}] =:=
+ sparse_to_orddict(set(N0-1,1,set(0,1,new({default,0}))))),
+ ?_assert([{0,1},{N0,1}] =:=
+ sparse_to_orddict(set(N0,1,set(0,1,new({default,0}))))),
+ ?_assert([{0,1},{N0+1,1}] =:=
+ sparse_to_orddict(set(N0+1,1,set(0,1,new({default,0}))))),
+ ?_assert([{0,0},{N0*2+1,1},{N0*10+1,2}] =:=
+ sparse_to_orddict(set(N0*10+1,2,set(N0*2+1,1,set(0,0,new()))))),
+ ?_assertError(badarg, sparse_to_orddict(no_array))
+ ].
+
+from_orddict_test_() ->
+ N0 = ?LEAFSIZE,
+ N1 = ?NODESIZE*N0,
+ N2 = ?NODESIZE*N1,
+ N3 = ?NODESIZE*N2,
+ N4 = ?NODESIZE*N3,
+ [?_assert(array:size(from_orddict([])) =:= 0),
+ ?_assert(array:is_fix(from_orddict([])) =:= false),
+ ?_assert(array:size(from_orddict([{0,undefined}])) =:= 1),
+ ?_assert(array:is_fix(from_orddict([{0,undefined}])) =:= false),
+ ?_assert(array:size(from_orddict([{N0-1,undefined}])) =:= N0),
+ ?_assert(array:size(from_orddict([{N,0}||N<-lists:seq(0,N1-1)]))
+ =:= N1),
+ ?_assertError({badarg,_}, from_orddict([foo])),
+ ?_assertError({badarg,_}, from_orddict([{200,foo},{1,bar}])),
+ ?_assertError({badarg,_}, from_orddict([{N,0}||N<-lists:seq(0,N0-1)] ++ not_a_list)),
+ ?_assertError(badarg, from_orddict(no_array)),
+
+
+ ?_assert(?LET(L, [{N,0}||N<-lists:seq(0,N0-1)],
+ L =:= to_orddict(from_orddict(L)))),
+ ?_assert(?LET(L, [{N,0}||N<-lists:seq(0,N0)],
+ L =:= to_orddict(from_orddict(L)))),
+ ?_assert(?LET(L, [{N,0}||N<-lists:seq(0,N2-1)],
+ L =:= to_orddict(from_orddict(L)))),
+ ?_assert(?LET(L, [{N,0}||N<-lists:seq(0,N2)],
+ L =:= to_orddict(from_orddict(L)))),
+ ?_assert(?LET(L, [{N,0}||N<-lists:seq(0,N3-1)],
+ L =:= to_orddict(from_orddict(L)))),
+ ?_assert(?LET(L, [{N,0}||N<-lists:seq(0,N4-1)],
+ L =:= to_orddict(from_orddict(L)))),
+
+ %% Hole in the begining
+ ?_assert(?LET(L, [{0,0}],
+ L =:= sparse_to_orddict(from_orddict(L)))),
+ ?_assert(?LET(L, [{N0,0}],
+ L =:= sparse_to_orddict(from_orddict(L)))),
+ ?_assert(?LET(L, [{N1,0}],
+ L =:= sparse_to_orddict(from_orddict(L)))),
+ ?_assert(?LET(L, [{N3,0}],
+ L =:= sparse_to_orddict(from_orddict(L)))),
+ ?_assert(?LET(L, [{N4,0}],
+ L =:= sparse_to_orddict(from_orddict(L)))),
+ ?_assert(?LET(L, [{N0-1,0}],
+ L =:= sparse_to_orddict(from_orddict(L)))),
+ ?_assert(?LET(L, [{N1-1,0}],
+ L =:= sparse_to_orddict(from_orddict(L)))),
+ ?_assert(?LET(L, [{N3-1,0}],
+ L =:= sparse_to_orddict(from_orddict(L)))),
+ ?_assert(?LET(L, [{N4-1,0}],
+ L =:= sparse_to_orddict(from_orddict(L)))),
+
+ %% Hole in middle
+
+ ?_assert(?LET(L, [{0,0},{N0,0}],
+ L =:= sparse_to_orddict(from_orddict(L)))),
+ ?_assert(?LET(L, [{0,0},{N1,0}],
+ L =:= sparse_to_orddict(from_orddict(L)))),
+ ?_assert(?LET(L, [{0,0},{N3,0}],
+ L =:= sparse_to_orddict(from_orddict(L)))),
+ ?_assert(?LET(L, [{0,0},{N4,0}],
+ L =:= sparse_to_orddict(from_orddict(L)))),
+ ?_assert(?LET(L, [{0,0},{N0-1,0}],
+ L =:= sparse_to_orddict(from_orddict(L)))),
+ ?_assert(?LET(L, [{0,0},{N1-1,0}],
+ L =:= sparse_to_orddict(from_orddict(L)))),
+ ?_assert(?LET(L, [{0,0},{N3-1,0}],
+ L =:= sparse_to_orddict(from_orddict(L)))),
+ ?_assert(?LET(L, [{0,0},{N4-1,0}],
+ L =:= sparse_to_orddict(from_orddict(L))))
+
+ ].
+
+map_test_() ->
+ N0 = ?LEAFSIZE,
+ Id = fun (_,X) -> X end,
+ Plus = fun(N) -> fun (_,X) -> X+N end end,
+ Default = fun(_K,undefined) -> no_value;
+ (K,V) -> K+V
+ end,
+ [?_assertError(badarg, map([], new())),
+ ?_assertError(badarg, map([], new(10))),
+ ?_assert(to_list(map(Id, new())) =:= []),
+ ?_assert(to_list(map(Id, new(1))) =:= [undefined]),
+ ?_assert(to_list(map(Id, new(5,{default,0}))) =:= [0,0,0,0,0]),
+ ?_assert(to_list(map(Id, from_list([1,2,3,4]))) =:= [1,2,3,4]),
+ ?_assert(to_list(map(Plus(1), from_list([0,1,2,3]))) =:= [1,2,3,4]),
+ ?_assert(to_list(map(Plus(-1), from_list(lists:seq(1,11))))
+ =:= lists:seq(0,10)),
+ ?_assert(to_list(map(Plus(11), from_list(lists:seq(0,99999))))
+ =:= lists:seq(11,100010)),
+ ?_assert([{0,0},{N0*2+1,N0*2+1+1},{N0*100+1,N0*100+1+2}] =:=
+ sparse_to_orddict((map(Default,
+ set(N0*100+1,2,
+ set(N0*2+1,1,
+ set(0,0,new())))))#array{default = no_value}))
+ ].
+
+sparse_map_test_() ->
+ N0 = ?LEAFSIZE,
+ Id = fun (_,X) -> X end,
+ Plus = fun(N) -> fun (_,X) -> X+N end end,
+ KeyPlus = fun (K,X) -> K+X end,
+ [?_assertError(badarg, sparse_map([], new())),
+ ?_assertError(badarg, sparse_map([], new(10))),
+ ?_assert(to_list(sparse_map(Id, new())) =:= []),
+ ?_assert(to_list(sparse_map(Id, new(1))) =:= [undefined]),
+ ?_assert(to_list(sparse_map(Id, new(5,{default,0}))) =:= [0,0,0,0,0]),
+ ?_assert(to_list(sparse_map(Id, from_list([1,2,3,4]))) =:= [1,2,3,4]),
+ ?_assert(to_list(sparse_map(Plus(1), from_list([0,1,2,3])))
+ =:= [1,2,3,4]),
+ ?_assert(to_list(sparse_map(Plus(-1), from_list(lists:seq(1,11))))
+ =:= lists:seq(0,10)),
+ ?_assert(to_list(sparse_map(Plus(11), from_list(lists:seq(0,99999))))
+ =:= lists:seq(11,100010)),
+ ?_assert(to_list(sparse_map(Plus(1), set(1,1,new({default,0}))))
+ =:= [0,2]),
+ ?_assert(to_list(sparse_map(Plus(1),
+ set(3,4,set(0,1,new({default,0})))))
+ =:= [2,0,0,5]),
+ ?_assert(to_list(sparse_map(Plus(1),
+ set(9,9,set(1,1,new({default,0})))))
+ =:= [0,2,0,0,0,0,0,0,0,10]),
+ ?_assert([{0,0},{N0*2+1,N0*2+1+1},{N0*100+1,N0*100+1+2}] =:=
+ sparse_to_orddict(sparse_map(KeyPlus,
+ set(N0*100+1,2,
+ set(N0*2+1,1,
+ set(0,0,new()))))))
+
+ ].
+
+foldl_test_() ->
+ N0 = ?LEAFSIZE,
+ Count = fun (_,_,N) -> N+1 end,
+ Sum = fun (_,X,N) -> N+X end,
+ Reverse = fun (_,X,L) -> [X|L] end,
+ Vals = fun(_K,undefined,{C,L}) -> {C+1,L};
+ (K,X,{C,L}) -> {C,[K+X|L]}
+ end,
+ [?_assertError(badarg, foldl([], 0, new())),
+ ?_assertError(badarg, foldl([], 0, new(10))),
+ ?_assert(foldl(Count, 0, new()) =:= 0),
+ ?_assert(foldl(Count, 0, new(1)) =:= 1),
+ ?_assert(foldl(Count, 0, new(10)) =:= 10),
+ ?_assert(foldl(Count, 0, from_list([1,2,3,4])) =:= 4),
+ ?_assert(foldl(Count, 10, from_list([0,1,2,3,4,5,6,7,8,9])) =:= 20),
+ ?_assert(foldl(Count, 1000, from_list(lists:seq(0,999))) =:= 2000),
+ ?_assert(foldl(Sum, 0, from_list(lists:seq(0,10))) =:= 55),
+ ?_assert(foldl(Reverse, [], from_list(lists:seq(0,1000)))
+ =:= lists:reverse(lists:seq(0,1000))),
+ ?_assert({999,[N0*100+1+2,N0*2+1+1,0]} =:=
+ foldl(Vals, {0,[]},
+ set(N0*100+1,2,
+ set(N0*2+1,1,
+ set(0,0,new())))))
+
+ ].
+
+sparse_foldl_test_() ->
+ N0 = ?LEAFSIZE,
+ Count = fun (_,_,N) -> N+1 end,
+ Sum = fun (_,X,N) -> N+X end,
+ Reverse = fun (_,X,L) -> [X|L] end,
+ Vals = fun(_K,undefined,{C,L}) -> {C+1,L};
+ (K,X,{C,L}) -> {C,[K+X|L]}
+ end,
+ [?_assertError(badarg, sparse_foldl([], 0, new())),
+ ?_assertError(badarg, sparse_foldl([], 0, new(10))),
+ ?_assert(sparse_foldl(Count, 0, new()) =:= 0),
+ ?_assert(sparse_foldl(Count, 0, new(1)) =:= 0),
+ ?_assert(sparse_foldl(Count, 0, new(10,{default,1})) =:= 0),
+ ?_assert(sparse_foldl(Count, 0, from_list([0,1,2,3,4],0)) =:= 4),
+ ?_assert(sparse_foldl(Count, 0, from_list([0,1,2,3,4,5,6,7,8,9,0],0))
+ =:= 9),
+ ?_assert(sparse_foldl(Count, 0, from_list(lists:seq(0,999),0))
+ =:= 999),
+ ?_assert(sparse_foldl(Sum, 0, from_list(lists:seq(0,10), 5)) =:= 50),
+ ?_assert(sparse_foldl(Reverse, [], from_list(lists:seq(0,1000), 0))
+ =:= lists:reverse(lists:seq(1,1000))),
+ ?_assert({0,[N0*100+1+2,N0*2+1+1,0]} =:=
+ sparse_foldl(Vals, {0,[]},
+ set(N0*100+1,2,
+ set(N0*2+1,1,
+ set(0,0,new())))))
+ ].
+
+foldr_test_() ->
+ N0 = ?LEAFSIZE,
+ Count = fun (_,_,N) -> N+1 end,
+ Sum = fun (_,X,N) -> N+X end,
+ List = fun (_,X,L) -> [X|L] end,
+ Vals = fun(_K,undefined,{C,L}) -> {C+1,L};
+ (K,X,{C,L}) -> {C,[K+X|L]}
+ end,
+ [?_assertError(badarg, foldr([], 0, new())),
+ ?_assertError(badarg, foldr([], 0, new(10))),
+ ?_assert(foldr(Count, 0, new()) =:= 0),
+ ?_assert(foldr(Count, 0, new(1)) =:= 1),
+ ?_assert(foldr(Count, 0, new(10)) =:= 10),
+ ?_assert(foldr(Count, 0, from_list([1,2,3,4])) =:= 4),
+ ?_assert(foldr(Count, 10, from_list([0,1,2,3,4,5,6,7,8,9])) =:= 20),
+ ?_assert(foldr(Count, 1000, from_list(lists:seq(0,999))) =:= 2000),
+ ?_assert(foldr(Sum, 0, from_list(lists:seq(0,10))) =:= 55),
+ ?_assert(foldr(List, [], from_list(lists:seq(0,1000)))
+ =:= lists:seq(0,1000)),
+ ?_assert({999,[0,N0*2+1+1,N0*100+1+2]} =:=
+ foldr(Vals, {0,[]},
+ set(N0*100+1,2,
+ set(N0*2+1,1,
+ set(0,0,new())))))
+
+ ].
+
+sparse_foldr_test_() ->
+ N0 = ?LEAFSIZE,
+ Count = fun (_,_,N) -> N+1 end,
+ Sum = fun (_,X,N) -> N+X end,
+ List = fun (_,X,L) -> [X|L] end,
+ Vals = fun(_K,undefined,{C,L}) -> {C+1,L};
+ (K,X,{C,L}) -> {C,[K+X|L]}
+ end,
+ [?_assertError(badarg, sparse_foldr([], 0, new())),
+ ?_assertError(badarg, sparse_foldr([], 0, new(10))),
+ ?_assert(sparse_foldr(Count, 0, new()) =:= 0),
+ ?_assert(sparse_foldr(Count, 0, new(1)) =:= 0),
+ ?_assert(sparse_foldr(Count, 0, new(10,{default,1})) =:= 0),
+ ?_assert(sparse_foldr(Count, 0, from_list([0,1,2,3,4],0)) =:= 4),
+ ?_assert(sparse_foldr(Count, 0, from_list([0,1,2,3,4,5,6,7,8,9,0],0))
+ =:= 9),
+ ?_assert(sparse_foldr(Count, 0, from_list(lists:seq(0,999),0))
+ =:= 999),
+ ?_assert(sparse_foldr(Sum, 0, from_list(lists:seq(0,10),5)) =:= 50),
+ ?_assert(sparse_foldr(List, [], from_list(lists:seq(0,1000),0))
+ =:= lists:seq(1,1000)),
+
+ ?_assert(sparse_size(new()) =:= 0),
+ ?_assert(sparse_size(new(8)) =:= 0),
+ ?_assert(sparse_size(array:set(7, 0, new())) =:= 8),
+ ?_assert(sparse_size(array:set(7, 0, new(10))) =:= 8),
+ ?_assert(sparse_size(array:set(99, 0, new(10,{fixed,false})))
+ =:= 100),
+ ?_assert(sparse_size(array:set(7, undefined, new())) =:= 0),
+ ?_assert(sparse_size(array:from_list([1,2,3,undefined])) =:= 3),
+ ?_assert(sparse_size(array:from_orddict([{3,0},{17,0},{99,undefined}]))
+ =:= 18),
+ ?_assert({0,[0,N0*2+1+1,N0*100+1+2]} =:=
+ sparse_foldr(Vals, {0,[]},
+ set(N0*100+1,2,
+ set(N0*2+1,1,
+ set(0,0,new())))))
+ ].
+
+new_test(doc) -> [];
+new_test(suite) -> [];
+new_test(Config) when is_list(Config) -> new_test_(), ok.
+fix_test(doc) -> [];
+fix_test(suite) -> [];
+fix_test(Config) when is_list(Config) -> fix_test_(), ok.
+relax_test(doc) -> [];
+relax_test(suite) -> [];
+relax_test(Config) when is_list(Config) -> relax_test_(), ok.
+resize_test(doc) -> [];
+resize_test(suite) -> [];
+resize_test(Config) when is_list(Config) -> resize_test_(), ok.
+set_get_test(doc) -> [];
+set_get_test(suite) -> [];
+set_get_test(Config) when is_list(Config) -> set_get_test_(), ok.
+to_list_test(doc) -> [];
+to_list_test(suite) -> [];
+to_list_test(Config) when is_list(Config) -> to_list_test_(), ok.
+sparse_to_list_test(doc) -> [];
+sparse_to_list_test(suite) -> [];
+sparse_to_list_test(Config) when is_list(Config) -> sparse_to_list_test_(), ok.
+from_list_test(doc) -> [];
+from_list_test(suite) -> [];
+from_list_test(Config) when is_list(Config) -> from_list_test_(), ok.
+to_orddict_test(doc) -> [];
+to_orddict_test(suite) -> [];
+to_orddict_test(Config) when is_list(Config) -> to_orddict_test_(), ok.
+sparse_to_orddict_test(doc) -> [];
+sparse_to_orddict_test(suite) -> [];
+sparse_to_orddict_test(Config) when is_list(Config) -> sparse_to_orddict_test_(), ok.
+from_orddict_test(doc) -> [];
+from_orddict_test(suite) -> [];
+from_orddict_test(Config) when is_list(Config) -> from_orddict_test_(), ok.
+map_test(doc) -> [];
+map_test(suite) -> [];
+map_test(Config) when is_list(Config) -> map_test_(), ok.
+sparse_map_test(doc) -> [];
+sparse_map_test(suite) -> [];
+sparse_map_test(Config) when is_list(Config) -> sparse_map_test_(), ok.
+foldl_test(doc) -> [];
+foldl_test(suite) -> [];
+foldl_test(Config) when is_list(Config) -> foldl_test_(), ok.
+sparse_foldl_test(doc) -> [];
+sparse_foldl_test(suite) -> [];
+sparse_foldl_test(Config) when is_list(Config) -> sparse_foldl_test_(), ok.
+foldr_test(doc) -> [];
+foldr_test(suite) -> [];
+foldr_test(Config) when is_list(Config) -> foldr_test_(), ok.
+sparse_foldr_test(doc) -> [];
+sparse_foldr_test(suite) -> [];
+sparse_foldr_test(Config) when is_list(Config) -> sparse_foldr_test_(), ok.
diff --git a/lib/stdlib/test/base64_SUITE.erl b/lib/stdlib/test/base64_SUITE.erl
new file mode 100644
index 0000000000..44742063b3
--- /dev/null
+++ b/lib/stdlib/test/base64_SUITE.erl
@@ -0,0 +1,257 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(base64_SUITE).
+-author('[email protected]').
+
+-include("test_server.hrl").
+-include("test_server_line.hrl").
+
+%% Test server specific exports
+-export([all/1, init_per_testcase/2, end_per_testcase/2]).
+
+%% Test cases must be exported.
+-export([base64_encode/1, base64_decode/1, base64_otp_5635/1,
+ base64_otp_6279/1, big/1, illegal/1, mime_decode/1,
+ roundtrip/1]).
+
+init_per_testcase(_, Config) ->
+ Dog = test_server:timetrap(?t:minutes(2)),
+ NewConfig = lists:keydelete(watchdog, 1, Config),
+ [{watchdog, Dog} | NewConfig].
+
+end_per_testcase(_, Config) ->
+ Dog = ?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+%%-------------------------------------------------------------------------
+%% Test cases starts here.
+%%-------------------------------------------------------------------------
+all(doc) ->
+ ["Test library functions for base64 encode and decode "
+ "(taken from inets/test/http_format_SUITE)"];
+all(suite) ->
+ [base64_encode, base64_decode, base64_otp_5635,
+ base64_otp_6279, big, illegal, mime_decode,
+ roundtrip].
+
+
+%%-------------------------------------------------------------------------
+base64_encode(doc) ->
+ ["Test base64:encode/1."];
+base64_encode(suite) ->
+ [];
+base64_encode(Config) when is_list(Config) ->
+ %% Two pads
+ <<"QWxhZGRpbjpvcGVuIHNlc2FtZQ==">> =
+ base64:encode("Aladdin:open sesame"),
+ %% One pad
+ <<"SGVsbG8gV29ybGQ=">> = base64:encode(<<"Hello World">>),
+ %% No pad
+ "QWxhZGRpbjpvcGVuIHNlc2Ft" =
+ base64:encode_to_string("Aladdin:open sesam"),
+
+ "MDEyMzQ1Njc4OSFAIzBeJiooKTs6PD4sLiBbXXt9" =
+ base64:encode_to_string(<<"0123456789!@#0^&*();:<>,. []{}">>),
+ ok.
+%%-------------------------------------------------------------------------
+base64_decode(doc) ->
+ ["Test base64:decode/1."];
+base64_decode(suite) ->
+ [];
+base64_decode(Config) when is_list(Config) ->
+ %% Two pads
+ <<"Aladdin:open sesame">> =
+ base64:decode("QWxhZGRpbjpvcGVuIHNlc2FtZQ=="),
+ %% One pad
+ <<"Hello World">> = base64:decode(<<"SGVsbG8gV29ybGQ=">>),
+ %% No pad
+ <<"Aladdin:open sesam">> =
+ base64:decode("QWxhZGRpbjpvcGVuIHNlc2Ft"),
+
+ Alphabet = list_to_binary(lists:seq(0, 255)),
+ Alphabet = base64:decode(base64:encode(Alphabet)),
+
+ %% Encoded base 64 strings may be devided by non base 64 chars.
+ %% In this cases whitespaces.
+ "0123456789!@#0^&*();:<>,. []{}" =
+ base64:decode_to_string(
+ "MDEy MzQ1Njc4 \tOSFAIzBeJ \niooKTs6 PD4sLi \r\nBbXXt9"),
+ "0123456789!@#0^&*();:<>,. []{}" =
+ base64:decode_to_string(
+ <<"MDEy MzQ1Njc4 \tOSFAIzBeJ \niooKTs6 PD4sLi \r\nBbXXt9">>),
+ ok.
+%%-------------------------------------------------------------------------
+base64_otp_5635(doc) ->
+ ["OTP-5635: Some data doesn't pass through base64:decode/1 "
+ "correctly"];
+base64_otp_5635(suite) ->
+ [];
+base64_otp_5635(Config) when is_list(Config) ->
+ <<"===">> = base64:decode(base64:encode("===")),
+ ok.
+%%-------------------------------------------------------------------------
+base64_otp_6279(doc) ->
+ ["OTP-6279: Guard needed so that function fails in a correct"
+ "way for faulty input i.e. function_clause"];
+base64_otp_6279(suite) ->
+ [];
+base64_otp_6279(Config) when is_list(Config) ->
+ {'EXIT',{function_clause, _}} = (catch base64:decode("dGVzda==a")),
+ ok.
+%%-------------------------------------------------------------------------
+big(doc) ->
+ ["Encode and decode big binaries."];
+big(suite) ->
+ [];
+big(Config) when is_list(Config) ->
+ Big = make_big_binary(300000),
+ B = base64:encode(Big),
+ true = is_binary(B),
+ 400000 = byte_size(B),
+ Big = base64:decode(B),
+ Big = base64:mime_decode(B),
+ ok.
+%%-------------------------------------------------------------------------
+illegal(doc) ->
+ ["Make sure illegal characters are rejected when decoding."];
+illegal(suite) ->
+ [];
+illegal(Config) when is_list(Config) ->
+ {'EXIT',{function_clause, _}} = (catch base64:decode("()")),
+ ok.
+%%-------------------------------------------------------------------------
+mime_decode(doc) ->
+ ["Test base64:mime_decode/1."];
+mime_decode(suite) ->
+ [];
+mime_decode(Config) when is_list(Config) ->
+ %% Two pads
+ <<"Aladdin:open sesame">> =
+ base64:mime_decode("QWxhZGRpbjpvc()GVuIHNlc2FtZQ=="),
+ %% One pad, followed by ignored text
+ <<"Hello World">> = base64:mime_decode(<<"SGVsb)(G8gV29ybGQ=apa">>),
+ %% No pad
+ "Aladdin:open sesam" =
+ base64:mime_decode_to_string("QWxhZGRpbjpvcG�\")(VuIHNlc2Ft"),
+
+ %% Encoded base 64 strings may be divided by non base 64 chars.
+ %% In this cases whitespaces.
+ "0123456789!@#0^&*();:<>,. []{}" =
+ base64:mime_decode_to_string(
+ <<"MDEy MzQ1Njc4 \tOSFAIzBeJ \nio)(oKTs6 PD4sLi \r\nBbXXt9">>),
+ ok.
+
+
+roundtrip(Config) when is_list(Config) ->
+ Sizes = lists:seq(1, 255) ++ lists:seq(2400-5, 2440),
+ roundtrip_1(Sizes, []).
+
+roundtrip_1([NextSize|Sizes], Current) ->
+ Len = length(Current),
+ io:format("~p", [Len]),
+ do_roundtrip(Current),
+ Next = random_byte_list(NextSize - Len, Current),
+ roundtrip_1(Sizes, Next);
+roundtrip_1([], Last) ->
+ io:format("~p", [length(Last)]),
+ do_roundtrip(Last).
+
+do_roundtrip(List) ->
+ Bin = list_to_binary(List),
+ Base64Bin = base64:encode(List),
+ Base64Bin = base64:encode(Bin),
+ Base64List = base64:encode_to_string(List),
+ Base64Bin = list_to_binary(Base64List),
+ Bin = base64:decode(Base64Bin),
+ List = base64:decode_to_string(Base64Bin),
+ Bin = base64:mime_decode(Base64Bin),
+ List = base64:mime_decode_to_string(Base64Bin),
+ append_roundtrip(8, Bin, List, Base64Bin),
+ prepend_roundtrip(8, Bin, List, Base64List),
+ interleaved_ws_roundtrip(Bin, List, Base64List).
+
+append_roundtrip(0, _, _, _) -> ok;
+append_roundtrip(N, Bin, List, Base64Bin0) ->
+ Base64Bin = <<Base64Bin0/binary,"\n">>,
+ Bin = base64:decode(Base64Bin),
+ List = base64:decode_to_string(Base64Bin),
+ Bin = base64:mime_decode(Base64Bin),
+ List = base64:mime_decode_to_string(Base64Bin),
+
+ Base64List = binary_to_list(Base64Bin),
+ Bin = base64:decode(Base64List),
+ List = base64:decode_to_string(Base64List),
+ Bin = base64:mime_decode(Base64List),
+ List = base64:mime_decode_to_string(Base64List),
+ append_roundtrip(N-1, Bin, List, Base64Bin).
+
+prepend_roundtrip(0, _, _, _) -> ok;
+prepend_roundtrip(N, Bin, List, Base64List0) ->
+ Base64List = [$\s|Base64List0],
+ Bin = base64:decode(Base64List),
+ List = base64:decode_to_string(Base64List),
+ Bin = base64:mime_decode(Base64List),
+ List = base64:mime_decode_to_string(Base64List),
+
+ Base64Bin = list_to_binary(Base64List),
+ Bin = base64:decode(Base64Bin),
+ List = base64:decode_to_string(Base64Bin),
+ Bin = base64:mime_decode(Base64Bin),
+ List = base64:mime_decode_to_string(Base64Bin),
+ prepend_roundtrip(N-1, Bin, List, Base64List).
+
+%% Do an exhaustive test of interleaving whitespace (for short strings).
+interleaved_ws_roundtrip(Bin, List, Base64List) when byte_size(Bin) =< 6 ->
+ interleaved_ws_roundtrip_1(lists:reverse(Base64List), [], Bin, List);
+interleaved_ws_roundtrip(_, _, _) -> ok.
+
+interleaved_ws_roundtrip_1([H|T], Tail, Bin, List) ->
+ interleaved_ws_roundtrip_1(T, [H|Tail], Bin, List),
+ interleaved_ws_roundtrip_1(T, [H,$\s|Tail], Bin, List),
+ interleaved_ws_roundtrip_1(T, [H,$\s,$\t|Tail], Bin, List),
+ interleaved_ws_roundtrip_1(T, [H,$\n,$\t|Tail], Bin, List);
+interleaved_ws_roundtrip_1([], Base64List, Bin, List) ->
+ Bin = base64:decode(Base64List),
+ List = base64:decode_to_string(Base64List),
+ Bin = base64:mime_decode(Base64List),
+ List = base64:mime_decode_to_string(Base64List),
+
+ Base64Bin = list_to_binary(Base64List),
+ Bin = base64:decode(Base64Bin),
+ List = base64:decode_to_string(Base64Bin),
+ Bin = base64:mime_decode(Base64Bin),
+ List = base64:mime_decode_to_string(Base64Bin),
+ ok.
+
+random_byte_list(0, Acc) ->
+ Acc;
+random_byte_list(N, Acc) ->
+ random_byte_list(N-1, [random:uniform(255)|Acc]).
+
+make_big_binary(N) ->
+ list_to_binary(mbb(N, [])).
+
+mbb(N, Acc) when N > 256 ->
+ B = list_to_binary(lists:seq(0, 255)),
+ mbb(N - 256, [B | Acc]);
+mbb(N, Acc) ->
+ B = list_to_binary(lists:seq(0, N-1)),
+ lists:reverse(Acc, B).
diff --git a/lib/stdlib/test/beam_lib_SUITE.erl b/lib/stdlib/test/beam_lib_SUITE.erl
new file mode 100644
index 0000000000..bc867a3770
--- /dev/null
+++ b/lib/stdlib/test/beam_lib_SUITE.erl
@@ -0,0 +1,761 @@
+%%
+%% %CopyrightBegin%
+%%
+%% %CopyrightEnd%
+%%
+-module(beam_lib_SUITE).
+
+%-define(debug, true).
+
+-ifdef(debug).
+-define(format(S, A), io:format(S, A)).
+-define(line, put(line, ?LINE), ).
+-define(config(X,Y), "./log_dir/").
+-define(t,test_server).
+-define(privdir, "beam_lib_SUITE_priv").
+-else.
+-include("test_server.hrl").
+-define(format(S, A), ok).
+-define(privdir, ?config(priv_dir, Conf)).
+-endif.
+
+-export([all/1, normal/1, error/1, cmp/1, cmp_literals/1, strip/1, otp_6711/1,
+ building/1, md5/1, encrypted_abstr/1, encrypted_abstr_file/1]).
+
+-export([init_per_testcase/2, fin_per_testcase/2]).
+
+all(suite) ->
+ [error, normal, cmp, cmp_literals, strip, otp_6711, building, md5,
+ encrypted_abstr, encrypted_abstr_file].
+
+init_per_testcase(_Case, Config) ->
+ Dog=?t:timetrap(?t:minutes(2)),
+ [{watchdog, Dog}|Config].
+
+fin_per_testcase(_Case, Config) ->
+ Dog=?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+normal(suite) -> [];
+normal(doc) -> ["Read correct beam file"];
+normal(Conf) when is_list(Conf) ->
+ ?line PrivDir = ?privdir,
+ ?line Simple = filename:join(PrivDir, "simple"),
+ ?line Source = Simple ++ ".erl",
+ ?line BeamFile = Simple ++ ".beam",
+ ?line simple_file(Source),
+
+ ?line NoOfTables = length(ets:all()),
+ ?line P0 = pps(),
+
+ CompileFlags = [{outdir,PrivDir}, debug_info],
+ ?line {ok,_} = compile:file(Source, CompileFlags),
+ ?line {ok, Binary} = file:read_file(BeamFile),
+
+ ?line do_normal(BeamFile),
+ ?line do_normal(Binary),
+
+ ?line {ok,_} = compile:file(Source, [{outdir,PrivDir}, no_debug_info]),
+ ?line {ok, {simple, [{abstract_code, no_abstract_code}]}} =
+ beam_lib:chunks(BeamFile, [abstract_code]),
+
+ %% ?line {ok,_} = compile:file(Source, [compressed | CompileFlags]),
+ %% ?line do_normal(BeamFile),
+
+ ?line file:delete(BeamFile),
+ ?line file:delete(Source),
+ ?line NoOfTables = length(ets:all()),
+ ?line true = (P0 == pps()),
+ ok.
+
+do_normal(BeamFile) ->
+ ?line Imports = {imports, [{erlang, get_module_info, 1},
+ {erlang, get_module_info, 2},
+ {lists, member, 2}]},
+ ?line Exports = {exports, [{module_info, 0}, {module_info, 1}, {t, 0}]},
+ ?line Local = {locals, [{t, 1}]},
+ ?line {ok, {simple, [Imports]}} = beam_lib:chunks(BeamFile, [imports]),
+ ?line {ok, {simple, [{"ImpT",_Bin}]}} =
+ beam_lib:chunks(BeamFile, ["ImpT"]),
+ ?line {ok, {simple, [Exports]}} = beam_lib:chunks(BeamFile, [exports]),
+ ?line {ok, {simple, [{attributes, [{vsn, [_]}]}]}} =
+ beam_lib:chunks(BeamFile, [attributes]),
+ ?line {ok, {simple, [{compile_info, _}=CompileInfo]}} =
+ beam_lib:chunks(BeamFile, [compile_info]),
+ ?line {ok, {simple, [Local]}} = beam_lib:chunks(BeamFile, [locals]),
+ ?line {ok, {simple, [{attributes, [{vsn, [_]}]}, CompileInfo,
+ Exports, Imports, Local]}} =
+ beam_lib:chunks(BeamFile, [attributes, compile_info, exports, imports, locals]),
+ ?line {ok, {simple, [{atoms, _Atoms}]}} =
+ beam_lib:chunks(BeamFile, [atoms]),
+ ?line {ok, {simple, [{labeled_exports, _LExports}]}} =
+ beam_lib:chunks(BeamFile, [labeled_exports]),
+ ?line {ok, {simple, [{labeled_locals, _LLocals}]}} =
+ beam_lib:chunks(BeamFile, [labeled_locals]),
+ ?line {ok, {simple, [_Vsn]}} = beam_lib:version(BeamFile),
+ ?line {ok, {simple, [{abstract_code, _}]}} =
+ beam_lib:chunks(BeamFile, [abstract_code]),
+
+ %% Test reading optional chunks.
+ All = ["Atom", "Code", "StrT", "ImpT", "ExpT", "FunT", "LitT"],
+ ?line {ok,{simple,Chunks}} = beam_lib:chunks(BeamFile, All, [allow_missing_chunks]),
+ ?line verify_simple(Chunks).
+
+verify_simple([{"Atom", AtomBin},
+ {"Code", CodeBin},
+ {"StrT", StrBin},
+ {"ImpT", ImpBin},
+ {"ExpT", ExpBin},
+ {"FunT", missing_chunk},
+ {"LitT", missing_chunk}])
+ when is_binary(AtomBin), is_binary(CodeBin), is_binary(StrBin),
+ is_binary(ImpBin), is_binary(ExpBin) ->
+ ok.
+
+error(suite) -> [];
+error(doc) -> ["Read invalid beam files"];
+error(Conf) when is_list(Conf) ->
+ ?line PrivDir = ?privdir,
+ ?line Simple = filename:join(PrivDir, "simple"),
+ ?line Source = Simple ++ ".erl",
+ ?line BeamFile = Simple ++ ".beam",
+ ?line WrongFile = Simple ++ "foo.beam",
+ ?line simple_file(Source),
+
+ ?line NoOfTables = length(ets:all()),
+ ?line P0 = pps(),
+ ?line {ok,_} = compile:file(Source, [{outdir,PrivDir},debug_info]),
+ ?line ACopy = filename:join(PrivDir, "a_copy.beam"),
+ ?line copy_file(BeamFile, ACopy),
+
+ ?line {ok, Binary} = file:read_file(BeamFile),
+
+ ?line copy_file(ACopy, WrongFile),
+ ?line verify(file_error, beam_lib:info("./does_simply_not_exist")),
+
+ ?line do_error(BeamFile, ACopy),
+ ?line do_error(Binary, ACopy),
+
+ ?line copy_file(ACopy, BeamFile),
+ ?line verify(unknown_chunk, beam_lib:chunks(BeamFile, [not_a_chunk])),
+
+ ?line ok = file:write_file(BeamFile, <<>>),
+ ?line verify(not_a_beam_file, beam_lib:info(BeamFile)),
+ ?line verify(not_a_beam_file, beam_lib:info(<<>>)),
+ ?line ok = file:write_file(BeamFile, <<"short">>),
+ ?line verify(not_a_beam_file, beam_lib:info(BeamFile)),
+ ?line verify(not_a_beam_file, beam_lib:info(<<"short">>)),
+
+ ?line {Binary1, _} = split_binary(Binary, byte_size(Binary)-10),
+ ?line verify(chunk_too_big, beam_lib:chunks(Binary1, ["Abst"])),
+ ?line Chunks = chunk_info(Binary),
+ ?line {value, {_, AbstractStart, _}} = lists:keysearch("Abst", 1, Chunks),
+ ?line {Binary2, _} = split_binary(Binary, AbstractStart),
+ ?line verify(chunk_too_big, beam_lib:chunks(Binary2, ["Abst"])),
+ ?line {Binary3, _} = split_binary(Binary, AbstractStart-4),
+ ?line verify(invalid_beam_file, beam_lib:chunks(Binary3, ["Abst"])),
+
+ %% Instead of the 5:32 field below, there used to be control characters
+ %% (including zero bytes) directly in the string. Because inferior programs
+ %% such as sed and clearcasediff don't like zero bytes in text files,
+ %% we have eliminated them.
+ ?line ok = file:write_file(BeamFile, <<"FOR1",5:32,"BEAMfel">>),
+% ?line verify(invalid_beam_file, beam_lib:info(BeamFile)),
+% ?line verify(invalid_beam_file, beam_lib:info(<<"FOR1",5:32,"BEAMfel">>)),
+
+ ?line NoOfTables = length(ets:all()),
+ ?line true = (P0 == pps()),
+ ?line file:delete(Source),
+ ?line file:delete(WrongFile),
+ ?line file:delete(BeamFile),
+ ?line file:delete(ACopy),
+ ok.
+
+do_error(BeamFile, ACopy) ->
+ % evil tests
+ ?line Chunks = chunk_info(BeamFile),
+ ?line {value, {_, AtomStart, _}} = lists:keysearch("Atom", 1, Chunks),
+ ?line {value, {_, ImportStart, _}} = lists:keysearch("ImpT", 1, Chunks),
+ ?line {value, {_, AbstractStart, _}} = lists:keysearch("Abst", 1, Chunks),
+ ?line {value, {_, AttributesStart, _}} =
+ lists:keysearch("Attr", 1, Chunks),
+ ?line {value, {_, CompileInfoStart, _}} =
+ lists:keysearch("CInf", 1, Chunks),
+ ?line verify(missing_chunk, beam_lib:chunks(BeamFile, ["__"])),
+ ?line BF2 = set_byte(ACopy, BeamFile, ImportStart+4, 17),
+ ?line verify(invalid_chunk, beam_lib:chunks(BF2, [imports])),
+ ?line BF3 = set_byte(ACopy, BeamFile, AtomStart-6, 17),
+ ?line verify(missing_chunk, beam_lib:chunks(BF3, [imports])),
+ ?line BF4 = set_byte(ACopy, BeamFile, AbstractStart+10, 17),
+ ?line verify(invalid_chunk, beam_lib:chunks(BF4, [abstract_code])),
+ ?line BF5 = set_byte(ACopy, BeamFile, AttributesStart+10, 17),
+ ?line verify(invalid_chunk, beam_lib:chunks(BF5, [attributes])),
+
+ ?line BF6 = set_byte(ACopy, BeamFile, 1, 17),
+ ?line verify(not_a_beam_file, beam_lib:info(BF6)),
+ ?line BF7 = set_byte(ACopy, BeamFile, 9, 17),
+ ?line verify(not_a_beam_file, beam_lib:info(BF7)),
+
+ ?line BF8 = set_byte(ACopy, BeamFile, 13, 17),
+ ?line verify(missing_chunk, beam_lib:chunks(BF8, ["Atom"])),
+
+ ?line BF9 = set_byte(ACopy, BeamFile, CompileInfoStart+10, 17),
+ ?line verify(invalid_chunk, beam_lib:chunks(BF9, [compile_info])).
+
+
+cmp(suite) -> [];
+cmp(doc) -> ["Compare contents of BEAM files and directories"];
+cmp(Conf) when is_list(Conf) ->
+ ?line PrivDir = ?privdir,
+
+ ?line Dir1 = filename:join(PrivDir, dir1),
+ ?line Dir2 = filename:join(PrivDir, dir2),
+
+ ok = file:make_dir(Dir1),
+ ok = file:make_dir(Dir2),
+
+ ?line {SourceD1, BeamFileD1} = make_beam(Dir1, simple, member),
+ ?line {Source2D1, BeamFile2D1} = make_beam(Dir1, simple2, concat),
+ ?line {SourceD2, BeamFileD2} = make_beam(Dir2, simple, concat),
+
+ ?line NoOfTables = length(ets:all()),
+ ?line P0 = pps(),
+
+ %% cmp
+ ?line ok = beam_lib:cmp(BeamFileD1, BeamFileD1),
+ ?line ver(modules_different, beam_lib:cmp(BeamFileD1, BeamFile2D1)),
+ ?line ver(chunks_different, beam_lib:cmp(BeamFileD1, BeamFileD2)),
+ ?line verify(file_error, beam_lib:cmp(foo, bar)),
+
+ ?line {ok, B1} = file:read_file(BeamFileD1),
+ ?line ok = beam_lib:cmp(B1, BeamFileD1),
+ ?line {ok, B2} = file:read_file(BeamFileD2),
+ ?line ver(chunks_different, beam_lib:cmp(B1, B2)),
+
+ %% cmp_dirs
+ ?line {[],[],[]} = beam_lib:cmp_dirs(Dir1, Dir1),
+ ?line true = {[BeamFile2D1], [], [{BeamFileD1,BeamFileD2}]} ==
+ beam_lib:cmp_dirs(Dir1, Dir2),
+ ?line true = {[], [BeamFile2D1], [{BeamFileD2,BeamFileD1}]} ==
+ beam_lib:cmp_dirs(Dir2, Dir1),
+ ?line ver(not_a_directory, beam_lib:cmp_dirs(foo, bar)),
+
+ %% diff_dirs
+ ?line ok = beam_lib:diff_dirs(Dir1, Dir1),
+ ?line ver(not_a_directory, beam_lib:diff_dirs(foo, bar)),
+
+ ?line true = (P0 == pps()),
+ ?line NoOfTables = length(ets:all()),
+ ?line delete_files([SourceD1, BeamFileD1, Source2D1,
+ BeamFile2D1, SourceD2, BeamFileD2]),
+
+ file:del_dir(Dir1),
+ file:del_dir(Dir2),
+ ok.
+
+cmp_literals(suite) -> [];
+cmp_literals(doc) -> ["Compare contents of BEAM files having literals"];
+cmp_literals(Conf) when is_list(Conf) ->
+ ?line PrivDir = ?privdir,
+
+ ?line Dir1 = filename:join(PrivDir, dir1),
+ ?line Dir2 = filename:join(PrivDir, dir2),
+
+ ok = file:make_dir(Dir1),
+ ok = file:make_dir(Dir2),
+
+ ?line {SourceD1, BeamFileD1} = make_beam(Dir1, simple, constant),
+ ?line {SourceD2, BeamFileD2} = make_beam(Dir2, simple, constant2),
+
+ ?line NoOfTables = length(ets:all()),
+ ?line P0 = pps(),
+
+ %% cmp
+ ?line ok = beam_lib:cmp(BeamFileD1, BeamFileD1),
+ ?line ver(chunks_different, beam_lib:cmp(BeamFileD1, BeamFileD2)),
+
+ ?line {ok, B1} = file:read_file(BeamFileD1),
+ ?line ok = beam_lib:cmp(B1, BeamFileD1),
+ ?line {ok, B2} = file:read_file(BeamFileD2),
+ ?line ver(chunks_different, beam_lib:cmp(B1, B2)),
+
+ ?line true = (P0 == pps()),
+ ?line NoOfTables = length(ets:all()),
+
+ ?line delete_files([SourceD1, BeamFileD1, SourceD2, BeamFileD2]),
+
+ file:del_dir(Dir1),
+ file:del_dir(Dir2),
+ ok.
+
+strip(suite) -> [];
+strip(doc) -> ["Strip BEAM files"];
+strip(Conf) when is_list(Conf) ->
+ ?line PrivDir = ?privdir,
+ ?line {SourceD1, BeamFileD1} = make_beam(PrivDir, simple, member),
+ ?line {Source2D1, BeamFile2D1} = make_beam(PrivDir, simple2, concat),
+ ?line {Source3D1, BeamFile3D1} = make_beam(PrivDir, make_fun, make_fun),
+ ?line {Source4D1, BeamFile4D1} = make_beam(PrivDir, constant, constant),
+
+ ?line NoOfTables = length(ets:all()),
+ ?line P0 = pps(),
+
+ %% strip binary
+ ?line verify(not_a_beam_file, beam_lib:strip(<<>>)),
+ ?line {ok, B1} = file:read_file(BeamFileD1),
+ ?line {ok, {simple, NB1}} = beam_lib:strip(B1),
+ ?line BId1 = chunk_ids(B1),
+ ?line NBId1 = chunk_ids(NB1),
+ ?line true = length(BId1) > length(NBId1),
+ ?line compare_chunks(B1, NB1, NBId1),
+
+ %% strip file
+ ?line verify(file_error, beam_lib:strip(foo)),
+ ?line {ok, {simple, _}} = beam_lib:strip(BeamFileD1),
+ ?line compare_chunks(NB1, BeamFileD1, NBId1),
+
+ %% strip_files
+ ?line {ok, B2} = file:read_file(BeamFile2D1),
+ ?line {ok, [{simple,_},{simple2,_}]} = beam_lib:strip_files([B1, B2]),
+ ?line {ok, [{simple,_},{simple2,_},{make_fun,_},{constant,_}]} =
+ beam_lib:strip_files([BeamFileD1, BeamFile2D1, BeamFile3D1, BeamFile4D1]),
+
+ %% check that each module can be loaded.
+ ?line {module, simple} = code:load_abs(filename:rootname(BeamFileD1)),
+ ?line {module, simple2} = code:load_abs(filename:rootname(BeamFile2D1)),
+ ?line {module, make_fun} = code:load_abs(filename:rootname(BeamFile3D1)),
+ ?line {module, constant} = code:load_abs(filename:rootname(BeamFile4D1)),
+
+ ?line true = (P0 == pps()),
+ ?line NoOfTables = length(ets:all()),
+
+ ?line delete_files([SourceD1, BeamFileD1,
+ Source2D1, BeamFile2D1,
+ Source3D1, BeamFile3D1,
+ Source4D1, BeamFile4D1]),
+ ok.
+
+
+otp_6711(Conf) when is_list(Conf) ->
+ ?line {'EXIT',{function_clause,_}} = (catch {a, beam_lib:info(3)}),
+ ?line {'EXIT',{function_clause,_}} = (catch {a, beam_lib:chunks(a, b)}),
+ ?line {'EXIT',{function_clause,_}} = (catch {a, beam_lib:chunks(a,b,c)}),
+ ?line {'EXIT',{function_clause,_}} = (catch {a, beam_lib:all_chunks(3)}),
+ ?line {'EXIT',{function_clause,_}} = (catch {a, beam_lib:cmp(3,4)}),
+ ?line {'EXIT',{function_clause,_}} = (catch {a, beam_lib:strip(3)}),
+ ?line {'EXIT',{function_clause,_}} =
+ (catch {a, beam_lib:strip_files([3])}),
+
+ ?line PrivDir = ?privdir,
+ ?line Dir = filename:join(PrivDir, dir),
+ ?line Lib = filename:join(Dir, "lib"),
+ ?line App = filename:join(Lib, "app"),
+ ?line EBin = filename:join(App, "ebin"),
+
+ ok = file:make_dir(Dir),
+ ok = file:make_dir(Lib),
+ ok = file:make_dir(App),
+ ok = file:make_dir(EBin),
+
+ ?line {SourceD, BeamFileD} = make_beam(EBin, simple, member),
+
+ unwritable(BeamFileD),
+
+ %% There is no way that strip_release can fail with
+ %% function_clause or something like that...
+ ?line {error,_,{file_error,_,_}} = beam_lib:strip_release(Dir),
+
+ ?line delete_files([SourceD, BeamFileD]),
+ file:del_dir(EBin),
+ file:del_dir(App),
+ file:del_dir(Lib),
+ file:del_dir(Dir),
+ ok.
+
+-include_lib("kernel/include/file.hrl").
+
+unwritable(Fname) ->
+ {ok, Info} = file:read_file_info(Fname),
+ Mode = Info#file_info.mode - 8#00200,
+ file:write_file_info(Fname, Info#file_info{mode = Mode}).
+
+building(doc) -> "Testing building of BEAM files.";
+building(Conf) when is_list(Conf) ->
+ ?line PrivDir = ?privdir,
+
+ ?line Dir1 = filename:join(PrivDir, b_dir1),
+ ?line Dir2 = filename:join(PrivDir, b_dir2),
+
+ ok = file:make_dir(Dir1),
+ ok = file:make_dir(Dir2),
+
+ ?line {SourceD1, BeamFileD1} = make_beam(Dir1, building, member),
+
+ ?line NoOfTables = length(ets:all()),
+ ?line P0 = pps(),
+
+ %% read all chunks
+ ?line ChunkIds = chunk_ids(BeamFileD1),
+ ?line {ok, _Mod, Chunks} = beam_lib:all_chunks(BeamFileD1),
+ ?line ChunkIds = lists:map(fun ({Id, Data}) when is_binary(Data) -> Id
+ end, Chunks),
+
+ %% write a new beam file, with reversed chunk order
+ ?line BeamFileD2 = filename:join(Dir2, "building.beam"),
+ ?line {ok,RevBeam} = beam_lib:build_module(lists:reverse(Chunks)),
+ ?line file:write_file(BeamFileD2, RevBeam),
+
+ %% compare files
+ ?line compare_chunks(BeamFileD1, BeamFileD2, ChunkIds),
+
+ %% test that we can retrieve a chunk before the atom table
+ %% (actually, try to retrieve all chunks)
+
+ ?line lists:foreach(fun(Id) ->
+ {ok, {building, [{Id, _Data}]}} =
+ beam_lib:chunks(BeamFileD1, [Id])
+ end, ChunkIds),
+ ?line lists:foreach(fun(Id) ->
+ {ok, {building, [{Id, _Data}]}} =
+ beam_lib:chunks(BeamFileD2, [Id])
+ end, ChunkIds),
+
+ ?line true = (P0 == pps()),
+ ?line NoOfTables = length(ets:all()),
+
+ ?line delete_files([SourceD1, BeamFileD1, BeamFileD2]),
+ file:del_dir(Dir1),
+ file:del_dir(Dir2),
+ ok.
+
+md5(suite) -> [];
+md5(doc) -> ["Compare beam_lib:md5/1 and code:module_md5/1."];
+md5(Conf) when is_list(Conf) ->
+ ?line Beams = collect_beams(),
+ io:format("Found ~w beam files", [length(Beams)]),
+ md5_1(Beams).
+
+md5_1([N|Ns]) ->
+ {ok,Beam0} = file:read_file(N),
+ Beam = maybe_uncompress(Beam0),
+ {ok,{Mod,MD5}} = beam_lib:md5(Beam),
+ {Mod,MD5} = {Mod,code:module_md5(Beam)},
+ md5_1(Ns);
+md5_1([]) -> ok.
+
+collect_beams() ->
+ SuperDir = filename:dirname(filename:dirname(code:which(?MODULE))),
+ TestDirs = filelib:wildcard(filename:join([SuperDir,"*_test"])),
+ AbsDirs = [filename:absname(X) || X <- code:get_path()],
+ collect_beams_1(AbsDirs ++ TestDirs).
+
+collect_beams_1([Dir|Dirs]) ->
+ filelib:wildcard(filename:join(Dir, "*.beam")) ++ collect_beams_1(Dirs);
+collect_beams_1([]) -> [].
+
+maybe_uncompress(<<"FOR1",_/binary>>=Beam) -> Beam;
+maybe_uncompress(Beam) -> zlib:gunzip(Beam).
+
+encrypted_abstr(suite) -> [];
+encrypted_abstr(doc) -> ["Test encrypted abstract format"];
+encrypted_abstr(Conf) when is_list(Conf) ->
+ run_if_crypto_works(fun() -> encrypted_abstr_1(Conf) end).
+
+encrypted_abstr_1(Conf) ->
+ ?line PrivDir = ?privdir,
+ ?line Simple = filename:join(PrivDir, "simple"),
+ ?line Source = Simple ++ ".erl",
+ ?line BeamFile = Simple ++ ".beam",
+ ?line simple_file(Source),
+
+ %% Avoid getting an extra port when crypto starts erl_ddll.
+ ?line erl_ddll:start(),
+
+ ?line NoOfTables = length(ets:all()),
+ ?line P0 = pps(),
+
+ Key = "#a_crypto_key",
+ CompileFlags = [{outdir,PrivDir}, debug_info, {debug_info_key,Key}],
+ ?line {ok,_} = compile:file(Source, CompileFlags),
+ ?line {ok, Binary} = file:read_file(BeamFile),
+
+ ?line do_encrypted_abstr(BeamFile, Key),
+ ?line do_encrypted_abstr(Binary, Key),
+
+ ?line ok = crypto:stop(), %To get rid of extra ets tables.
+ ?line file:delete(BeamFile),
+ ?line file:delete(Source),
+ ?line NoOfTables = length(ets:all()),
+ ?line true = (P0 == pps()),
+ ok.
+
+do_encrypted_abstr(Beam, Key) ->
+ ?line verify(key_missing_or_invalid, beam_lib:chunks(Beam, [abstract_code])),
+
+ %% The raw chunk "Abst" can still be read even without a key.
+ ?line {ok,{simple,[{"Abst",Abst}]}} = beam_lib:chunks(Beam, ["Abst"]),
+ ?line <<0:8,8:8,"des3_cbc",_/binary>> = Abst,
+
+ %% Try som invalid funs.
+ ?line bad_fun(badfun, fun() -> ok end),
+ ?line bad_fun(badfun, {a,b}),
+ ?line bad_fun(blurf),
+ ?line {function_clause,_} = bad_fun(fun(glurf) -> ok end),
+
+ %% Funs that return something strange.
+ ?line bad_fun(badfun, fun(init) -> {ok,fun() -> ok end} end),
+ ?line glurf = bad_fun(fun(init) -> {error,glurf} end),
+
+ %% Try clearing (non-existing fun).
+ ?line undefined = beam_lib:clear_crypto_key_fun(),
+
+ %% Install a fun which cannot retrieve a key.
+ ?line ok = beam_lib:crypto_key_fun(fun(init) -> ok end),
+ ?line {error,beam_lib,Error} = beam_lib:chunks(Beam, [abstract_code]),
+
+ %% Install a fun which returns an incorrect key.
+ ?line {ok,_} = beam_lib:clear_crypto_key_fun(),
+ ?line ok = beam_lib:crypto_key_fun(simple_crypto_fun("wrong key...")),
+ ?line {error,beam_lib,Error} = beam_lib:chunks(Beam, [abstract_code]),
+
+ %% Installing a new key fun is not possible without clearing the old.
+ ?line verify(exists, beam_lib:crypto_key_fun(simple_crypto_fun(Key))),
+
+ %% Install the simplest possible working key fun.
+ ?line {ok,_} = beam_lib:clear_crypto_key_fun(),
+ ?line ok = beam_lib:crypto_key_fun(simple_crypto_fun(Key)),
+ ?line verify_abstract(Beam),
+ ?line {ok,{simple,[{"Abst",Abst}]}} = beam_lib:chunks(Beam, ["Abst"]),
+
+ %% Installing a new key fun is not possible without clearing the old.
+ verify(exists, beam_lib:crypto_key_fun(ets_crypto_fun(Key))),
+
+ %% Install a key using an ets table.
+ ?line {ok,_} = beam_lib:clear_crypto_key_fun(),
+ ?line ok = beam_lib:crypto_key_fun(ets_crypto_fun(Key)),
+ ?line verify_abstract(Beam),
+ ?line {ok,{simple,[{"Abst",Abst}]}} = beam_lib:chunks(Beam, ["Abst"]),
+
+ ?line {ok,cleared} = beam_lib:clear_crypto_key_fun(),
+ ok.
+
+
+bad_fun(F) ->
+ {error,E} = beam_lib:crypto_key_fun(F),
+ E.
+
+bad_fun(S, F) ->
+ verify(S, beam_lib:crypto_key_fun(F)).
+
+
+verify_abstract(Beam) ->
+ {ok,{simple,[Chunk]}} = beam_lib:chunks(Beam, [abstract_code]),
+ {abstract_code,{raw_abstract_v1,_}} = Chunk.
+
+simple_crypto_fun(Key) ->
+ fun(init) -> ok;
+ ({debug_info, des3_cbc, simple, _}) -> Key
+ end.
+
+ets_crypto_fun(Key) ->
+ fun(init) ->
+ T = ets:new(beam_lib_SUITE_keys, [private, set]),
+ true = ets:insert(T, {key,Key}),
+ {ok,fun({debug_info, des3_cbc, simple, _}) ->
+ [{key,Val}] = ets:lookup(T, key),
+ Val;
+ (clear) ->
+ ets:delete(T),
+ cleared
+ end}
+ end.
+
+encrypted_abstr_file(suite) -> [];
+encrypted_abstr_file(doc) ->
+ ["Test encrypted abstract format with the key in .erlang.crypt"];
+encrypted_abstr_file(Conf) when is_list(Conf) ->
+ run_if_crypto_works(fun() -> encrypted_abstr_file_1(Conf) end).
+
+encrypted_abstr_file_1(Conf) ->
+ ?line PrivDir = ?privdir,
+ ?line Simple = filename:join(PrivDir, "simple"),
+ ?line Source = Simple ++ ".erl",
+ ?line BeamFile = Simple ++ ".beam",
+ ?line simple_file(Source),
+
+ %% Avoid getting an extra port when crypto starts erl_ddll.
+ ?line erl_ddll:start(),
+
+ ?line NoOfTables = length(ets:all()),
+ ?line P0 = pps(),
+
+ Key = "Long And niCe 99Krypto Key",
+ CompileFlags = [{outdir,PrivDir}, debug_info, {debug_info_key,Key}],
+ ?line {ok,_} = compile:file(Source, CompileFlags),
+ ?line {ok, Binary} = file:read_file(BeamFile),
+
+ ?line {ok,OldCwd} = file:get_cwd(),
+ ?line ok = file:set_cwd(PrivDir),
+ ?line do_encrypted_abstr_file(BeamFile, Key),
+ ?line do_encrypted_abstr_file(Binary, Key),
+ ?line ok = file:set_cwd(OldCwd),
+
+ ?line ok = crypto:stop(), %To get rid of extra ets tables.
+ ?line file:delete(filename:join(PrivDir, ".erlang.crypt")),
+ ?line file:delete(BeamFile),
+ ?line file:delete(Source),
+ ?line NoOfTables = length(ets:all()),
+ ?line true = (P0 == pps()),
+ ok.
+
+do_encrypted_abstr_file(Beam, Key) ->
+ %% No key.
+ ?line write_crypt_file(""),
+ ?line {error,beam_lib,Error} = beam_lib:chunks(Beam, [abstract_code]),
+
+ %% A wrong key.
+ ?line write_crypt_file(["[{debug_info,des3_cbc,simple,\"A Wrong Key\"}].\n"]),
+ ?line {error,beam_lib,Error} = beam_lib:chunks(Beam, [abstract_code]),
+
+ %% Write correct key...
+ ?line write_crypt_file(["[{debug_info,des3_cbc,simple,\"",Key,"\"}].\n"]),
+
+ %% ... but the fun with the wrong key is still there.
+ ?line {error,beam_lib,Error} = beam_lib:chunks(Beam, [abstract_code]),
+
+ %% Clear the fun. Now it should work.
+ ?line {ok,_} = beam_lib:clear_crypto_key_fun(),
+ ?line verify_abstract(Beam),
+ ?line verify_abstract(Beam),
+ ?line ok = file:delete(".erlang.crypt"),
+ ?line verify_abstract(Beam),
+
+ %% Clear, otherwise the second pass will fail.
+ ?line {ok,_} = beam_lib:clear_crypto_key_fun(),
+ ?line {error,beam_lib,Error} = beam_lib:chunks(Beam, [abstract_code]),
+ ok.
+
+write_crypt_file(Contents0) ->
+ Contents = list_to_binary([Contents0]),
+ io:format("~s\n", [binary_to_list(Contents)]),
+ ok = file:write_file(".erlang.crypt", Contents).
+
+compare_chunks(File1, File2, ChunkIds) ->
+ ?line {ok, {_, Chunks1}} = beam_lib:chunks(File1, ChunkIds),
+ ?line {ok, {_, Chunks2}} = beam_lib:chunks(File2, ChunkIds),
+ ?line true = Chunks1 == Chunks2.
+
+chunk_ids(File) ->
+ ?line lists:map(fun({Id,_Start,_Size}) -> Id end, chunk_info(File)).
+
+chunk_info(File) ->
+ ?line {value, {chunks, Chunks}} =
+ lists:keysearch(chunks, 1, beam_lib:info(File)),
+ Chunks.
+
+make_beam(Dir, Module, F) ->
+ ?line FileBase = filename:join(Dir, Module),
+ ?line Source = FileBase ++ ".erl",
+ ?line BeamFile = FileBase ++ ".beam",
+ ?line simple_file(Source, Module, F),
+ ?line {ok, _} = compile:file(Source, [{outdir,Dir}, debug_info, report]),
+ {Source, BeamFile}.
+
+set_byte(_Backup, Binary, Pos, Byte) when is_binary(Binary) ->
+ ?line <<B1:Pos/binary, _:1/binary, B2/binary>> = Binary,
+ NB = <<B1/binary, Byte:8, B2/binary>>,
+ NB;
+set_byte(Backup, File, Pos, Byte) ->
+ ?line copy_file(Backup, File),
+ ?line set_byte(File, Pos, Byte),
+ File.
+
+set_byte(File, Pos, Byte) ->
+ ?line {ok, Fd} = file:open(File, [read, write]),
+ ?line {ok, _} = file:position(Fd, Pos),
+ ?line ok = file:write(Fd, [Byte]),
+ ?line file:close(Fd).
+
+copy_file(Src, Dest) ->
+ % ?t:format("copying from ~p to ~p~n", [Src, Dest]),
+ ?line {ok, _} = file:copy(Src, Dest),
+ ?line ok = file:change_mode(Dest, 8#0666).
+
+delete_files(Files) ->
+ lists:foreach(fun(F) -> file:delete(F) end, Files).
+
+verify(S, {error, beam_lib, R}) ->
+ verify_error(S, R);
+verify(S, {error, R}) ->
+ verify_error(S, R).
+
+verify_error(S, R) ->
+ if
+ S =:= R -> ok;
+ true -> [S|_] = tuple_to_list(R)
+ end,
+
+ %% Most formatted messages begin with "./simple.beam:" or "<<...".
+ FM = string:str(lists:flatten(beam_lib:format_error(R)), "simpl") > 0,
+ BM = string:str(lists:flatten(beam_lib:format_error(R)), "<<") > 0,
+
+ %% Also make sure that formatted message is not just the term printed.
+ Handled = beam_lib:format_error(R) =/= io_lib:format("~p~n", [R]),
+ true = ((FM > 0) or (BM > 0)) and Handled.
+
+ver(S, {error, beam_lib, R}) ->
+ [S|_] = tuple_to_list(R),
+ case lists:flatten(beam_lib:format_error(R)) of
+ [${ | _] ->
+ test_server:fail({bad_format_error, R});
+ _ ->
+ ok
+ end.
+
+pps() ->
+ {erlang:ports()}.
+
+simple_file(File) ->
+ simple_file(File, simple).
+
+simple_file(File, Module) ->
+ simple_file(File, Module, member).
+
+simple_file(File, Module, make_fun) ->
+ B = list_to_binary(["-module(", atom_to_list(Module), "). "
+ "-export([t/1]). "
+ "t(A) -> "
+ " fun(X) -> A+X end. "]),
+ ok = file:write_file(File, B);
+simple_file(File, Module, constant) ->
+ B = list_to_binary(["-module(", atom_to_list(Module), "). "
+ "-export([t/1]). "
+ "t(A) -> "
+ " {a,b,[2,3],c,d}. "]),
+ ok = file:write_file(File, B);
+simple_file(File, Module, constant2) ->
+ B = list_to_binary(["-module(", atom_to_list(Module), "). "
+ "-export([t/1]). "
+ "t(A) -> "
+ " {a,b,[2,3],x,y}. "]),
+ ok = file:write_file(File, B);
+simple_file(File, Module, F) ->
+ B = list_to_binary(["-module(", atom_to_list(Module), "). "
+ "-export([t/0]). "
+ "t() -> "
+ " t([]). "
+ "t(L) -> "
+ " lists:",
+ atom_to_list(F), "(a, L). "]),
+ ok = file:write_file(File, B).
+
+run_if_crypto_works(Test) ->
+ try begin crypto:start(), crypto:info(), crypto:stop(), ok end of
+ ok ->
+ Test()
+ catch
+ error:_ ->
+ {skip,"The crypto application is missing or broken"}
+ end.
+
diff --git a/lib/stdlib/test/c_SUITE.erl b/lib/stdlib/test/c_SUITE.erl
new file mode 100644
index 0000000000..5608d73d19
--- /dev/null
+++ b/lib/stdlib/test/c_SUITE.erl
@@ -0,0 +1,116 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1998-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(c_SUITE).
+-export([all/1]).
+-export([c_1/1, c_2/1, c_3/1, c_4/1, memory/1]).
+
+-include("test_server.hrl").
+
+-import(c, [c/2]).
+
+all(doc) -> ["Test cases for the 'c' module."];
+all(suite) ->
+ [c_1, c_2, c_3, c_4, memory].
+
+%%% Write output to a directory other than current directory:
+
+c_1(doc) ->
+ ["Checks that c:c works also with option 'outdir' [ticket OTP-1209]."];
+c_1(suite) ->
+ [];
+c_1(Config) when list(Config) ->
+ ?line R = filename:join(?config(data_dir, Config), "m.erl"),
+ ?line W = ?config(priv_dir, Config),
+ ?line Result = c(R,[{outdir,W}]),
+ ?line {ok, m} = Result.
+
+c_2(doc) ->
+ ["Checks that c:c works also with option 'outdir' [ticket OTP-1209]."];
+c_2(suite) ->
+ [];
+c_2(Config) when list(Config) ->
+ ?line R = filename:join(?config(data_dir, Config), "m"),
+ ?line W = ?config(priv_dir, Config),
+ ?line Result = c(R,[{outdir,W}]),
+ ?line {ok, m} = Result.
+
+
+%%% Put results in current directory (or rather, change current dir
+%%% to the output dir):
+
+c_3(doc) ->
+ ["Checks that c:c works also with option 'outdir' (same as current"
+ "directory). [ticket OTP-1209]."];
+c_3(suite) ->
+ [];
+c_3(Config) when list(Config) ->
+ ?line R = filename:join(?config(data_dir, Config), "m.erl"),
+ ?line W = ?config(priv_dir, Config),
+ ?line file:set_cwd(W),
+ ?line Result = c(R,[{outdir,W}]),
+ ?line {ok, m} = Result.
+
+c_4(doc) ->
+ ["Checks that c:c works also with option 'outdir' (same as current"
+ "directory). [ticket OTP-1209]."];
+c_4(suite) ->
+ [];
+c_4(Config) when list(Config) ->
+ ?line R = filename:join(?config(data_dir, Config), "m"),
+ ?line W = ?config(priv_dir, Config),
+ ?line file:set_cwd(W),
+ ?line Result = c(R,[{outdir,W}]),
+ ?line {ok, m} = Result.
+
+memory(doc) ->
+ ["Checks that c:memory/[0,1] returns consistent results."];
+memory(suite) ->
+ [];
+memory(Config) when list(Config) ->
+ try
+ ?line ML = c:memory(),
+ ?line T = mget(total, ML),
+ ?line P = mget(processes, ML),
+ ?line S = mget(system, ML),
+ ?line A = mget(atom, ML),
+ ?line AU = mget(atom_used, ML),
+ ?line B = mget(binary, ML),
+ ?line C = mget(code, ML),
+ ?line E = mget(ets, ML),
+ ?line T = P + S,
+ ?line if S >= A + B + C + E -> ok end,
+ ?line if A >= AU -> ok end,
+ ?line ok
+ catch
+ error:notsup ->
+ ?line {skipped,
+ "erlang:memory/[0,1] and c:memory/[0,1] not supported"}
+ end.
+
+% Help function for c_SUITE:memory/1
+mget(K, L) ->
+ ?line {value,{K,V}} = lists:keysearch(K, 1, L),
+ ?line test_v(c:memory(K)), % Check that c:memory/1 also accept this
+ % argument and returns an integer (usally
+ % *not* the same as V).
+ ?line test_v(V).
+
+% Help function for c_SUITE:memory/1
+test_v(V) when integer(V) ->
+ ?line V.
diff --git a/lib/stdlib/test/c_SUITE_data/m.erl b/lib/stdlib/test/c_SUITE_data/m.erl
new file mode 100644
index 0000000000..59e0d80b83
--- /dev/null
+++ b/lib/stdlib/test/c_SUITE_data/m.erl
@@ -0,0 +1,25 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1998-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(m).
+-export([factorial/1]).
+
+factorial(0) ->
+ 1;
+factorial(N) ->
+ N * factorial(N-1).
diff --git a/lib/stdlib/test/calendar_SUITE.erl b/lib/stdlib/test/calendar_SUITE.erl
new file mode 100644
index 0000000000..ea81bb99a9
--- /dev/null
+++ b/lib/stdlib/test/calendar_SUITE.erl
@@ -0,0 +1,251 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(calendar_SUITE).
+
+-include("test_server.hrl").
+
+-export([all/1,
+ gregorian_days/1,
+ gregorian_seconds/1,
+ day_of_the_week/1,
+ day_of_the_week_calibrate/1,
+ leap_years/1,
+ last_day_of_the_month/1,
+ local_time_to_universal_time_dst/1]).
+
+-define(START_YEAR, 1947).
+-define(END_YEAR, 2012).
+
+all(suite) -> [gregorian_days,
+ gregorian_seconds,
+ day_of_the_week,
+ day_of_the_week_calibrate,
+ leap_years,
+ last_day_of_the_month,
+ local_time_to_universal_time_dst];
+
+all(doc) -> "This is the test suite for calendar.erl".
+
+gregorian_days(doc) ->
+ "Tests that date_to_gregorian_days and gregorian_days_to_date "
+ "are each others inverses from ?START_YEAR-01-01 up to ?END_YEAR-01-01. "
+ "At the same time valid_date is tested.";
+gregorian_days(suite) ->
+ [];
+gregorian_days(Config) when list(Config) ->
+ ?line Days = calendar:date_to_gregorian_days({?START_YEAR, 1, 1}),
+ ?line MaxDays = calendar:date_to_gregorian_days({?END_YEAR, 1, 1}),
+ ?line check_gregorian_days(Days, MaxDays).
+
+gregorian_seconds(doc) ->
+ "Tests that datetime_to_gregorian_seconds and "
+ "gregorian_seconds_to_date are each others inverses for a sampled "
+ "number of seconds from ?START_YEAR-01-01 up to ?END_YEAR-01-01: We check "
+ "every 2 days + 1 second.";
+gregorian_seconds(suite) ->
+ [];
+gregorian_seconds(Config) when list(Config) ->
+ ?line Secs = calendar:datetime_to_gregorian_seconds({{?START_YEAR, 1, 1},
+ {0, 0, 0}}),
+ ?line MaxSecs = calendar:datetime_to_gregorian_seconds({{?END_YEAR, 1, 1},
+ {0, 0, 0}}),
+ ?line check_gregorian_seconds(Secs, MaxSecs).
+
+day_of_the_week(doc) ->
+ "Tests that day_of_the_week reports correctly the day of the week from "
+ "year ?START_YEAR up to ?END_YEAR.";
+day_of_the_week(suite) ->
+ [];
+day_of_the_week(Config) when list(Config) ->
+ ?line Days = calendar:date_to_gregorian_days({?START_YEAR, 1, 1}),
+ ?line MaxDays = calendar:date_to_gregorian_days({?END_YEAR, 1, 1}),
+ ?line DayNumber = calendar:day_of_the_week({?START_YEAR, 1, 1}),
+ ?line check_day_of_the_week(Days, MaxDays, DayNumber).
+
+day_of_the_week_calibrate(doc) ->
+ "Tests that day_of_the_week for 1997-11-11 is Tuesday (2)";
+day_of_the_week_calibrate(suite) ->
+ [];
+day_of_the_week_calibrate(Config) when list(Config) ->
+ ?line 2 = calendar:day_of_the_week({1997, 11, 11}).
+
+leap_years(doc) ->
+ "Tests that is_leap_year reports correctly the leap years from "
+ "year ?START_YEAR up to ?END_YEAR.";
+leap_years(suite) ->
+ [];
+leap_years(Config) when list(Config) ->
+ ?line check_leap_years(?START_YEAR, ?END_YEAR).
+
+last_day_of_the_month(doc) ->
+ "Tests that last_day_of_the_month reports correctly from "
+ "year ?START_YEAR up to ?END_YEAR.";
+last_day_of_the_month(suite) ->
+ [];
+last_day_of_the_month(Config) when list(Config) ->
+ ?line check_last_day_of_the_month({?START_YEAR, 1}, {?END_YEAR, 1}).
+
+local_time_to_universal_time_dst(doc) ->
+ "Tests local_time_to_universal_time_dst for MET";
+local_time_to_universal_time_dst(suite) ->
+ [];
+local_time_to_universal_time_dst(Config) when list(Config) ->
+ case os:type() of
+ {unix,_} ->
+ case os:cmd("date '+%Z'") of
+ "SAST"++_ ->
+ {comment, "Spoky time zone with zero-set DST, skipped"};
+ _ ->
+ local_time_to_universal_time_dst_x(Config)
+ end;
+ _ ->
+ local_time_to_universal_time_dst_x(Config)
+ end.
+local_time_to_universal_time_dst_x(Config) when list(Config) ->
+ %% Assumes MET (UTC+1 / UTC+2(dst)
+ ?line LtW = {{2003,01,15},{14,00,00}}, % Winter
+ ?line UtW = {{2003,01,15},{13,00,00}}, %
+ ?line UtWd = {{2003,01,15},{12,00,00}}, % dst
+ ?line LtS = {{2003,07,15},{14,00,00}}, % Summer
+ ?line UtS = {{2003,07,15},{13,00,00}}, %
+ ?line UtSd = {{2003,07,15},{12,00,00}}, % dst
+ ?line LtWS = {{2003,03,30},{02,30,00}}, % Winter->Summer
+ ?line UtWS = {{2003,03,30},{01,30,00}}, %
+ ?line UtWSd = {{2003,03,30},{00,30,00}}, % dst
+ ?line LtSW = {{2003,10,26},{02,30,00}}, % Summer->Winter
+ ?line UtSW = {{2003,10,26},{01,30,00}}, %
+ ?line UtSWd = {{2003,10,26},{00,30,00}}, % dst
+ %%
+ ?line UtW = calendar:local_time_to_universal_time(LtW, false),
+ ?line UtWd = calendar:local_time_to_universal_time(LtW, true),
+ ?line UtW = calendar:local_time_to_universal_time(LtW, undefined),
+ %%
+ ?line UtS = calendar:local_time_to_universal_time(LtS, false),
+ ?line UtSd = calendar:local_time_to_universal_time(LtS, true),
+ ?line UtSd = calendar:local_time_to_universal_time(LtS, undefined),
+ %%
+ case calendar:local_time_to_universal_time(LtWS, false) of
+ UtWS ->
+ ?line UtWSd = calendar:local_time_to_universal_time(LtWS, true),
+ ?line [] = calendar:local_time_to_universal_time_dst(LtWS),
+ %%
+ ?line UtSW = calendar:local_time_to_universal_time(LtSW, false),
+ ?line UtSWd = calendar:local_time_to_universal_time(LtSW, true),
+ ?line [UtSWd, UtSW] = calendar:local_time_to_universal_time_dst(LtSW),
+ ok;
+ {{1969,12,31},{23,59,59}} ->
+ %% It seems that Apple has no intention of fixing this bug in
+ %% Mac OS 10.3.9, and we have no intention of implementing a
+ %% workaround.
+ {comment,"Bug in mktime() in this OS"}
+ end.
+
+
+%%
+%% LOCAL FUNCTIONS
+%%
+
+%% check_gregorian_days
+%%
+check_gregorian_days(Days, MaxDays) when Days < MaxDays ->
+ ?line Date = calendar:gregorian_days_to_date(Days),
+ ?line true = calendar:valid_date(Date),
+ ?line Days = calendar:date_to_gregorian_days(Date),
+ ?line check_gregorian_days(Days + 1, MaxDays);
+check_gregorian_days(_Days, _MaxDays) ->
+ ok.
+
+%% check_gregorian_seconds
+%%
+%% We increment with something prime (172801 = 2 days + 1 second).
+%%
+check_gregorian_seconds(Secs, MaxSecs) when Secs < MaxSecs ->
+ ?line DateTime = calendar:gregorian_seconds_to_datetime(Secs),
+ ?line Secs = calendar:datetime_to_gregorian_seconds(DateTime),
+ ?line check_gregorian_seconds(Secs + 172801, MaxSecs);
+check_gregorian_seconds(_Secs, _MaxSecs) ->
+ ok.
+
+
+%% check_day_of_the_week
+%%
+check_day_of_the_week(Days, MaxDays, DayNumber) when Days < MaxDays ->
+ ?line Date = calendar:gregorian_days_to_date(Days),
+ ?line DayNumber = calendar:day_of_the_week(Date),
+ ?line check_day_of_the_week(Days + 1, MaxDays,
+ ((DayNumber rem 7) + 1));
+check_day_of_the_week(_Days, _MaxDays, _DayNumber) ->
+ ok.
+
+%% check_leap_years
+%%
+%% SYr must be larger than 1800, and EYr must be less than ?END_YEAR.
+%%
+check_leap_years(SYr, EYr) when SYr < EYr ->
+ ?line Rem = SYr rem 4,
+ case Rem of
+ 0 ->
+ case SYr of
+ 1900 ->
+ ?line false = calendar:is_leap_year(SYr);
+ 2000 ->
+ ?line true = calendar:is_leap_year(SYr);
+ _ ->
+ ?line true = calendar:is_leap_year(SYr)
+ end;
+ _ ->
+ ?line false = calendar:is_leap_year(SYr)
+ end,
+ check_leap_years(SYr + 1, EYr);
+check_leap_years(_SYr, _EYr) ->
+ ok.
+
+check_last_day_of_the_month({SYr, SMon}, {EYr, EMon}) when SYr < EYr ->
+ ?line LastDay = calendar:last_day_of_the_month(SYr, SMon),
+ ?line LastDay = case SMon of
+ 1 -> 31;
+ 2 ->
+ case calendar:is_leap_year(SYr) of
+ true -> 29;
+ false -> 28
+ end;
+ 3 -> 31;
+ 4 -> 30;
+ 5 -> 31;
+ 6 -> 30;
+ 7 -> 31;
+ 8 -> 31;
+ 9 -> 30;
+ 10 -> 31;
+ 11 -> 30;
+ 12 -> 31
+ end,
+ ?line NYr = case SMon of
+ 12 -> SYr + 1;
+ _ -> SYr
+ end,
+ ?line check_last_day_of_the_month({NYr, (SMon rem 12) + 1},
+ {EYr, EMon});
+check_last_day_of_the_month(_, _) ->
+ ok.
+
+
+
+
+
diff --git a/lib/stdlib/test/dets_SUITE.erl b/lib/stdlib/test/dets_SUITE.erl
new file mode 100644
index 0000000000..760e610e00
--- /dev/null
+++ b/lib/stdlib/test/dets_SUITE.erl
@@ -0,0 +1,4136 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(dets_SUITE).
+
+%-define(debug, true).
+
+-ifdef(debug).
+-define(format(S, A), io:format(S, A)).
+-define(line, put(line, ?LINE), ).
+-define(config(X,Y), foo).
+-define(t, test_server).
+-define(privdir(_), "./dets_SUITE_priv").
+-define(datadir(_), "./dets_SUITE_data").
+-else.
+-include("test_server.hrl").
+-define(format(S, A), ok).
+-define(privdir(Conf), ?config(priv_dir, Conf)).
+-define(datadir(Conf), ?config(data_dir, Conf)).
+-endif.
+
+-export([all/1, not_run/1, newly_started/1, basic_v8/1, basic_v9/1,
+ open_v8/1, open_v9/1, sets_v8/1, sets_v9/1, bags_v8/1,
+ bags_v9/1, duplicate_bags_v8/1, duplicate_bags_v9/1,
+ access_v8/1, access_v9/1, dirty_mark/1, dirty_mark2/1,
+ bag_next_v8/1, bag_next_v9/1, oldbugs_v8/1, oldbugs_v9/1,
+ unsafe_assumptions/1, truncated_segment_array_v8/1,
+ truncated_segment_array_v9/1, open_file_v8/1, open_file_v9/1,
+ init_table_v8/1, init_table_v9/1, repair_v8/1, repair_v9/1,
+ hash_v8b_v8c/1, phash/1, fold_v8/1, fold_v9/1, fixtable_v8/1,
+ fixtable_v9/1, match_v8/1, match_v9/1, select_v8/1,
+ select_v9/1, update_counter/1, badarg/1, cache_sets_v8/1,
+ cache_sets_v9/1, cache_bags_v8/1, cache_bags_v9/1,
+ cache_duplicate_bags_v8/1, cache_duplicate_bags_v9/1,
+ otp_4208/1, otp_4989/1, many_clients/1, otp_4906/1, otp_5402/1,
+ simultaneous_open/1, insert_new/1, repair_continuation/1,
+ otp_5487/1, otp_6206/1, otp_6359/1, otp_4738/1, otp_7146/1,
+ otp_8070/1]).
+
+-export([dets_dirty_loop/0]).
+
+-export([histogram/1, sum_histogram/1, ave_histogram/1]).
+
+-export([init_per_testcase/2, fin_per_testcase/2]).
+
+%% Internal export.
+-export([client/2]).
+
+-import(lists,
+ [append/1, delete/2, duplicate/2, filter/2, foreach/2, keysearch/3,
+ last/1, map/2, member/2, reverse/1, seq/2, sort/1, usort/1]).
+
+-include_lib("kernel/include/file.hrl").
+
+-define(DETS_SERVER, dets).
+
+%% HEADSZ taken from dets_v8.erl and dets_v9.erl.
+-define(HEADSZ_v8, 40).
+-define(HEADSZ_v9, (56+28*4+16)).
+-define(NO_KEYS_POS_v9, 36).
+-define(CLOSED_PROPERLY_POS, 8).
+
+-define(NOT_PROPERLY_CLOSED,0).
+-define(CLOSED_PROPERLY,1).
+
+init_per_testcase(_Case, Config) ->
+ Dog=?t:timetrap(?t:minutes(15)),
+ [{watchdog, Dog}|Config].
+
+fin_per_testcase(_Case, _Config) ->
+ Dog=?config(watchdog, _Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+all(suite) ->
+ case os:type() of
+ vxworks ->
+ [not_run];
+ _ ->
+ {req,[stdlib],
+ [basic_v8, basic_v9, open_v8, open_v9, sets_v8, sets_v9,
+ bags_v8, bags_v9, duplicate_bags_v8, duplicate_bags_v9,
+ newly_started, open_file_v8, open_file_v9,
+ init_table_v8, init_table_v9, repair_v8, repair_v9,
+ access_v8, access_v9, oldbugs_v8, oldbugs_v9,
+ unsafe_assumptions, truncated_segment_array_v8,
+ truncated_segment_array_v9, dirty_mark, dirty_mark2,
+ bag_next_v8, bag_next_v9, hash_v8b_v8c, phash, fold_v8,
+ fold_v9, fixtable_v8, fixtable_v9, match_v8, match_v9,
+ select_v8, select_v9, update_counter, badarg,
+ cache_sets_v8, cache_sets_v9, cache_bags_v8,
+ cache_bags_v9, cache_duplicate_bags_v8,
+ cache_duplicate_bags_v9, otp_4208, otp_4989, many_clients,
+ otp_4906, otp_5402, simultaneous_open, insert_new,
+ repair_continuation, otp_5487, otp_6206, otp_6359, otp_4738,
+ otp_7146, otp_8070]}
+ end.
+
+not_run(suite) -> [];
+not_run(Conf) when is_list(Conf) ->
+ {comment, "Not runnable VxWorks/NFS"}.
+
+newly_started(doc) ->
+ ["OTP-3621"];
+newly_started(suite) ->
+ [];
+newly_started(Config) when is_list(Config) ->
+ ?line true = is_alive(),
+ ?line {ok, Node} = test_server:start_node(slave1, slave, []),
+ ?line [] = rpc:call(Node, dets, all, []),
+ ?line test_server:stop_node(Node),
+ ok.
+
+basic_v8(doc) ->
+ ["Basic test case."];
+basic_v8(suite) ->
+ [];
+basic_v8(Config) when is_list(Config) ->
+ basic(Config, 8).
+
+basic_v9(doc) ->
+ ["Basic test case."];
+basic_v9(suite) ->
+ [];
+basic_v9(Config) when is_list(Config) ->
+ basic(Config, 9).
+
+basic(Config, Version) ->
+ ?line Tab = dets_basic_test,
+ ?line FName = filename(Tab, Config),
+
+ P0 = pps(),
+ ?line {ok, _} = dets:open_file(Tab,[{file, FName},{version,Version}]),
+ ?line ok = dets:insert(Tab,{mazda,japan}),
+ ?line ok = dets:insert(Tab,{toyota,japan}),
+ ?line ok = dets:insert(Tab,{suzuki,japan}),
+ ?line ok = dets:insert(Tab,{honda,japan}),
+ ?line ok = dets:insert(Tab,{renault,france}),
+ ?line ok = dets:insert(Tab,{citroen,france}),
+ ?line ok = dets:insert(Tab,{opel,germany}),
+ ?line ok = dets:insert(Tab,{saab,sweden}),
+ ?line ok = dets:insert(Tab,{volvo,sweden}),
+ ?line [{opel,germany}] = dets:lookup(Tab,opel),
+ ?line Japs = dets:traverse(Tab, fun(Obj) ->
+ case Obj of
+ {_, japan} -> {continue, Obj};
+ _ -> continue
+ end
+ end),
+ ?line 4 = length(Japs),
+ ?line ok = dets:close(Tab),
+ ?line file:delete(FName),
+ ?line check_pps(P0),
+ ok.
+
+
+open_v8(doc) ->
+ [];
+open_v8(suite) ->
+ [];
+open_v8(Config) when is_list(Config) ->
+ open(Config, 8).
+
+open_v9(doc) ->
+ [];
+open_v9(suite) ->
+ [];
+open_v9(Config) when is_list(Config) ->
+ open(Config, 9).
+
+open(Config, Version) ->
+ %% Running this test twice means that the Dets server is restarted
+ %% twice. dets_sup specifies a maximum of 4 restarts in an hour.
+ %% If this becomes a problem, one should consider running this
+ %% test on a slave node.
+
+ ?line {Sets, Bags, Dups} = args(Config),
+
+ ?line All = Sets ++ Bags ++ Dups,
+ ?line delete_files(All),
+
+ ?line Data = make_data(1),
+
+ P0 = pps(),
+ ?line Tabs = open_files(1, All, Version),
+ ?line initialize(Tabs, Data),
+ ?line check(Tabs, Data),
+
+ ?line foreach(fun(Tab) -> ok = dets:close(Tab) end, Tabs),
+ %% Now reopen the files
+ ?format("Reopening closed files \n", []),
+ ?line Tabs = open_files(1, All, Version),
+ ?format("Checking contents of reopened files \n", []),
+ ?line check(Tabs, Data),
+ %% crash the dets server
+
+ ?format("Crashing dets server \n", []),
+ process_flag(trap_exit, true),
+ Procs = [whereis(?DETS_SERVER) | map(fun(Tab) -> dets:info(Tab, pid) end,
+ Tabs)],
+ foreach(fun(Pid) -> exit(Pid, kill) end, Procs),
+ timer:sleep(100),
+ c:flush(), %% flush all the EXIT sigs
+ timer:sleep(200),
+
+ %% Now reopen the files again
+ ?format("Reopening crashed files \n", []),
+ ?line open_files(1, All, Version),
+ ?format("Checking contents of repaired files \n", []),
+ ?line check(Tabs, Data),
+
+ ?line close_all(Tabs),
+
+ ?line delete_files(All),
+ P1 = pps(),
+ {Ports0, Procs0} = P0,
+ {Ports1, Procs1} = P1,
+ ?line true = Ports1 =:= Ports0,
+ %% The dets_server process has been restarted:
+ ?line [_] = Procs0 -- Procs1,
+ ?line [_] = Procs1 -- Procs0,
+ ok.
+
+check(Tabs, Data) ->
+ foreach(fun(Tab) ->
+ ?line Kp = dets:info(Tab, keypos),
+ ?format("checking ~p~n", [Tab]),
+ foreach(fun(Item) ->
+ case dets:lookup(Tab, k(Kp,Item)) of
+ [Item] -> ok;
+ _Other -> bad(Tab,Item)
+ end
+ end, Data)
+ end, Tabs),
+ ok.
+
+k(Kp, Obj) -> element(Kp, Obj).
+
+bad(_Tab, _Item) ->
+ ?format("Can't find item ~p in ~p ~n", [_Item, _Tab]),
+ exit(badtab).
+
+sets_v8(doc) ->
+ ["Performs traversal and match testing on set type dets tables."];
+sets_v8(suite) ->
+ [];
+sets_v8(Config) when is_list(Config) ->
+ sets(Config, 8).
+
+sets_v9(doc) ->
+ ["Performs traversal and match testing on set type dets tables."];
+sets_v9(suite) ->
+ [];
+sets_v9(Config) when is_list(Config) ->
+ sets(Config, 9).
+
+sets(Config, Version) ->
+ ?line {Sets, _, _} = args(Config),
+
+ ?line Data = make_data(1),
+ ?line delete_files(Sets),
+ P0 = pps(),
+ ?line Tabs = open_files(1, Sets, Version),
+ Bigger = [{17,q,w,w}, {48,q,w,w,w,w,w,w}], % 48 requires a bigger buddy
+ ?line initialize(Tabs, Data++Bigger++Data), % overwrite
+ ?line Len = length(Data),
+ ?line foreach(fun(Tab) -> trav_test(Data, Len, Tab) end, Tabs),
+ ?line size_test(Len, Tabs),
+ ?line no_keys_test(Tabs),
+ ?line foreach(fun(Tab) -> del_test(Tab) end, Tabs),
+ ?line initialize(Tabs, Data),
+ ?line foreach(fun(Tab) -> del_obj_test(Tab) end, Tabs),
+ ?line initialize(Tabs, Data),
+ ?line foreach(fun(Tab) ->
+ Len = dets:info(Tab, size) end,
+ Tabs),
+ ?line foreach(fun(Tab) -> match_test(Data, Tab) end, Tabs),
+ ?line foreach(fun(Tab) -> match_del_test(Tab) end, Tabs),
+
+ ?line close_all(Tabs),
+ ?line delete_files(Sets),
+ ?line check_pps(P0),
+ ok.
+
+bags_v8(doc) ->
+ ["Performs traversal and match testing on bag type dets tables."];
+bags_v8(suite) ->
+ [];
+bags_v8(Config) when is_list(Config) ->
+ bags(Config, 8).
+
+bags_v9(doc) ->
+ ["Performs traversal and match testing on bag type dets tables."];
+bags_v9(suite) ->
+ [];
+bags_v9(Config) when is_list(Config) ->
+ bags(Config, 9).
+
+bags(Config, Version) ->
+ {_, Bags, _} = args(Config),
+ ?line Data = make_data(1, bag), %% gives twice as many objects
+ ?line delete_files(Bags),
+ P0 = pps(),
+ ?line Tabs = open_files(1, Bags, Version),
+ ?line initialize(Tabs, Data++Data),
+ ?line Len = length(Data),
+ ?line foreach(fun(Tab) -> trav_test(Data, Len, Tab) end, Tabs),
+ ?line size_test(Len, Tabs),
+ ?line no_keys_test(Tabs),
+ ?line foreach(fun(Tab) -> del_test(Tab) end, Tabs),
+ ?line initialize(Tabs, Data),
+ ?line foreach(fun(Tab) -> del_obj_test(Tab) end, Tabs),
+ ?line initialize(Tabs, Data),
+ ?line foreach(fun(Tab) ->
+ Len = dets:info(Tab, size) end,
+ Tabs),
+ ?line foreach(fun(Tab) -> match_test(Data, Tab) end, Tabs),
+ ?line foreach(fun(Tab) -> match_del_test(Tab) end, Tabs),
+ ?line close_all(Tabs),
+ ?line delete_files(Bags),
+ ?line check_pps(P0),
+ ok.
+
+
+duplicate_bags_v8(doc) ->
+ ["Performs traversal and match testing on duplicate_bag type dets tables."];
+duplicate_bags_v8(suite) ->
+ [];
+duplicate_bags_v8(Config) when is_list(Config) ->
+ duplicate_bags(Config, 8).
+
+duplicate_bags_v9(doc) ->
+ ["Performs traversal and match testing on duplicate_bag type dets tables."];
+duplicate_bags_v9(suite) ->
+ [];
+duplicate_bags_v9(Config) when is_list(Config) ->
+ duplicate_bags(Config, 9).
+
+duplicate_bags(Config, Version) when is_list(Config) ->
+ {_, _, Dups} = args(Config),
+ ?line Data = make_data(1, duplicate_bag), %% gives twice as many objects
+ ?line delete_files(Dups),
+ P0 = pps(),
+ ?line Tabs = open_files(1, Dups, Version),
+ ?line initialize(Tabs, Data),
+ ?line Len = length(Data),
+ ?line foreach(fun(Tab) -> trav_test(Data, Len, Tab) end, Tabs),
+ ?line size_test(Len, Tabs),
+ ?line no_keys_test(Tabs),
+ ?line foreach(fun(Tab) -> del_test(Tab) end, Tabs),
+ ?line initialize(Tabs, Data),
+ ?line foreach(fun(Tab) -> del_obj_test(Tab) end, Tabs),
+ ?line initialize(Tabs, Data),
+ ?line foreach(fun(Tab) ->
+ Len = dets:info(Tab, size) end,
+ Tabs),
+ ?line foreach(fun(Tab) -> match_test(Data, Tab) end, Tabs),
+ ?line foreach(fun(Tab) -> match_del_test(Tab) end, Tabs),
+ ?line close_all(Tabs),
+ ?line delete_files(Dups),
+ ?line check_pps(P0),
+ ok.
+
+
+access_v8(doc) ->
+ [];
+access_v8(suite) ->
+ [];
+access_v8(Config) when is_list(Config) ->
+ access(Config, 8).
+
+access_v9(doc) ->
+ [];
+access_v9(suite) ->
+ [];
+access_v9(Config) when is_list(Config) ->
+ access(Config, 9).
+
+access(Config, Version) ->
+ Args_acc = [[{ram_file, true}, {access, read}],
+ [{access, read}]],
+ Args = [[{ram_file, true}],
+ []],
+
+ ?line {Args_acc_1, _, _} = zip_filename(Args_acc, [], [], Config),
+ ?line delete_files(Args_acc_1),
+ ?line {Args_1, _, _} = zip_filename(Args, [], [], Config),
+
+ P0 = pps(),
+ ?line {error, {file_error,_,enoent}} = dets:open_file('1', hd(Args_acc_1)),
+
+ ?line Tabs = open_files(1, Args_1, Version),
+ ?line close_all(Tabs),
+ ?line Tabs = open_files(1, Args_acc_1, Version),
+
+ ?line foreach(fun(Tab) ->
+ {error, {access_mode,_}} = dets:insert(Tab, {1,2}),
+ [] = dets:lookup(Tab, 11),
+ '$end_of_table' = dets:first(Tab),
+ {error, {access_mode,_}} = dets:delete(Tab, 22)
+ end, Tabs),
+ ?line close_all(Tabs),
+ ?line delete_files(Args_acc_1),
+ ?line check_pps(P0),
+ ok.
+
+
+dirty_mark(doc) ->
+ ["Test that the table is not marked dirty if not written"];
+dirty_mark(suite) ->
+ [];
+dirty_mark(Config) when is_list(Config) ->
+ ?line true = is_alive(),
+ ?line Tab = dets_dirty_mark_test,
+ ?line FName = filename(Tab, Config),
+ P0 = pps(),
+ ?line dets:open_file(Tab,[{file, FName}]),
+ ?line dets:insert(Tab,{mazda,japan}),
+ ?line dets:insert(Tab,{toyota,japan}),
+ ?line dets:insert(Tab,{suzuki,japan}),
+ ?line dets:insert(Tab,{honda,japan}),
+ ?line dets:insert(Tab,{renault,france}),
+ ?line dets:insert(Tab,{citroen,france}),
+ ?line dets:insert(Tab,{opel,germany}),
+ ?line dets:insert(Tab,{saab,sweden}),
+ ?line dets:insert(Tab,{volvo,sweden}),
+ ?line [{opel,germany}] = dets:lookup(Tab,opel),
+ ?line ok = dets:close(Tab),
+ ?line Call = fun(P,A) ->
+ P ! {self(), A},
+ receive
+ {P, Ans} ->
+ Ans
+ after 5000 ->
+ exit(other_process_dead)
+ end
+ end,
+ ?line {ok, Node} = test_server:start_node(dets_dirty_mark,
+ slave,
+ [{linked, false},
+ {args, "-pa " ++
+ filename:dirname
+ (code:which(?MODULE))}]),
+ ?line ok = ensure_node(20, Node),
+ %% io:format("~p~n",[rpc:call(Node, code, get_path, [])]),
+ %% io:format("~p~n",[rpc:call(Node, file, get_cwd, [])]),
+ %% io:format("~p~n",[Config]),
+ ?line Pid = rpc:call(Node,erlang, spawn,
+ [?MODULE, dets_dirty_loop, []]),
+ ?line {ok, Tab} = Call(Pid, [open, Tab, [{file, FName}]]),
+ ?line [{opel,germany}] = Call(Pid, [read,Tab,opel]),
+ ?line test_server:stop_node(Node),
+ ?line {ok, Tab} = dets:open_file(Tab,[{file, FName},
+ {repair,false}]),
+ ?line ok = dets:close(Tab),
+ ?line file:delete(FName),
+ ?line check_pps(P0),
+ ok.
+
+dirty_mark2(doc) ->
+ ["Test that the table is flushed when auto_save is in effect"];
+dirty_mark2(suite) ->
+ [];
+dirty_mark2(Config) when is_list(Config) ->
+ ?line true = is_alive(),
+ ?line Tab = dets_dirty_mark2_test,
+ ?line FName = filename(Tab, Config),
+ P0 = pps(),
+ ?line dets:open_file(Tab,[{file, FName}]),
+ ?line dets:insert(Tab,{toyota,japan}),
+ ?line dets:insert(Tab,{suzuki,japan}),
+ ?line dets:insert(Tab,{honda,japan}),
+ ?line dets:insert(Tab,{renault,france}),
+ ?line dets:insert(Tab,{citroen,france}),
+ ?line dets:insert(Tab,{opel,germany}),
+ ?line dets:insert(Tab,{saab,sweden}),
+ ?line dets:insert(Tab,{volvo,sweden}),
+ ?line [{opel,germany}] = dets:lookup(Tab,opel),
+ ?line ok = dets:close(Tab),
+ ?line Call = fun(P,A) ->
+ P ! {self(), A},
+ receive
+ {P, Ans} ->
+ Ans
+ after 5000 ->
+ exit(other_process_dead)
+ end
+ end,
+ ?line {ok, Node} = test_server:start_node(dets_dirty_mark2,
+ slave,
+ [{linked, false},
+ {args, "-pa " ++
+ filename:dirname
+ (code:which(?MODULE))}]),
+ ?line ok = ensure_node(20, Node),
+ ?line Pid = rpc:call(Node,erlang, spawn,
+ [?MODULE, dets_dirty_loop, []]),
+ ?line {ok, Tab} = Call(Pid, [open, Tab, [{file, FName},{auto_save,1000}]]),
+ ?line ok = Call(Pid, [write,Tab,{mazda,japan}]),
+ ?line timer:sleep(2100),
+ %% Read something, just to give auto save time to finish.
+ ?line [{opel,germany}] = Call(Pid, [read,Tab,opel]),
+ ?line test_server:stop_node(Node),
+ ?line {ok, Tab} = dets:open_file(Tab, [{file, FName}, {repair,false}]),
+ ?line ok = dets:close(Tab),
+ ?line file:delete(FName),
+ ?line check_pps(P0),
+ ok.
+
+dets_dirty_loop() ->
+ receive
+ {From, [open, Name, Args]} ->
+ Ret = dets:open_file(Name, Args),
+ From ! {self(), Ret},
+ dets_dirty_loop();
+ {From, [read, Name, Key]} ->
+ Ret = dets:lookup(Name, Key),
+ From ! {self(), Ret},
+ dets_dirty_loop();
+ {From, [write, Name, Value]} ->
+ Ret = dets:insert(Name, Value),
+ From ! {self(), Ret},
+ dets_dirty_loop()
+ end.
+
+
+bag_next_v8(suite) ->
+ [];
+bag_next_v8(doc) ->
+ ["Check that bags and next work as expected."];
+bag_next_v8(Config) when is_list(Config) ->
+ bag_next(Config, 8).
+
+bag_next_v9(suite) ->
+ [];
+bag_next_v9(doc) ->
+ ["Check that bags and next work as expected."];
+bag_next_v9(Config) when is_list(Config) ->
+ ?line Tab = dets_bag_next_test,
+ ?line FName = filename(Tab, Config),
+
+ %% first and next crash upon error
+ ?line dets:open_file(Tab,[{file, FName}, {type, bag},{version,9}]),
+ ?line ok = dets:insert(Tab, [{1,1},{2,2},{3,3},{4,4}]),
+ ?line FirstKey = dets:first(Tab),
+ ?line NextKey = dets:next(Tab, FirstKey),
+ ?line [FirstObj | _] = dets:lookup(Tab, FirstKey),
+ ?line [NextObj | _] = dets:lookup(Tab, NextKey),
+ ?line {ok, FirstPos} = dets:where(Tab, FirstObj),
+ ?line {ok, NextPos} = dets:where(Tab, NextObj),
+ crash(FName, NextPos+12),
+ ?line {'EXIT',BadObject1} = (catch dets:next(Tab, FirstKey)),
+ ?line bad_object(BadObject1, FName),
+ crash(FName, FirstPos+12),
+ ?line {'EXIT',BadObject2} = (catch dets:first(Tab)),
+ ?line bad_object(BadObject2, FName),
+ ?line dets:close(Tab),
+ ?line file:delete(FName),
+
+ bag_next(Config, 9).
+
+bag_next(Config, Version) ->
+ ?line Tab = dets_bag_next_test,
+ ?line FName = filename(Tab, Config),
+ P0 = pps(),
+ ?line dets:open_file(Tab,[{file, FName}, {type, bag},{version,Version}]),
+ ?line dets:insert(Tab,{698,hopp}),
+ ?line dets:insert(Tab,{186,hopp}),
+ ?line dets:insert(Tab,{hej,hopp}),
+ ?line dets:insert(Tab,{186,plopp}),
+ Loop = fun(N, Last, Self) ->
+ case N of
+ 0 ->
+ exit({unterminated_first_next_sequence, N, Last});
+ _ ->
+ case Last of
+ '$end_of_table' ->
+ ok;
+ _ ->
+ Self(N-1, dets:next(Tab,Last), Self)
+ end
+ end
+ end,
+ ?line ok = Loop(4,dets:first(Tab),Loop),
+ ?line dets:close(Tab),
+ ?line file:delete(FName),
+ ?line check_pps(P0),
+ ok.
+
+oldbugs_v8(doc) ->
+ [];
+oldbugs_v8(suite) ->
+ [];
+oldbugs_v8(Config) when is_list(Config) ->
+ oldbugs(Config, 8).
+
+oldbugs_v9(doc) ->
+ [];
+oldbugs_v9(suite) ->
+ [];
+oldbugs_v9(Config) when is_list(Config) ->
+ oldbugs(Config, 9).
+
+oldbugs(Config, Version) ->
+ FName = filename(dets_suite_oldbugs_test, Config),
+ P0 = pps(),
+ ?line {ok, ob} = dets:open_file(ob, [{version, Version},
+ {type, bag}, {file, FName}]),
+ ?line ok = dets:insert(ob, {1, 2}),
+ ?line ok = dets:insert(ob, {1,3}),
+ ?line ok = dets:insert(ob, {1, 2}),
+ ?line 2 = dets:info(ob, size), %% assertion
+ ?line ok = dets:close(ob),
+ ?line file:delete(FName),
+ ?line check_pps(P0),
+ ok.
+
+unsafe_assumptions(suite) -> [];
+unsafe_assumptions(doc) ->
+ "Tests that shrinking an object and then expanding it works.";
+unsafe_assumptions(Config) when is_list(Config) ->
+ FName = filename(dets_suite_unsafe_assumptions_test, Config),
+ ?line file:delete(FName),
+ P0 = pps(),
+ ?line {ok, a} = dets:open_file(a, [{version,8},{file, FName}]),
+ O0 = {2,false},
+ O1 = {1, false},
+ O2 = {1, true},
+ O3 = {1, duplicate(20,false)},
+ O4 = {1, duplicate(25,false)}, % same 2-log as O3
+ ?line ok = dets:insert(a, O1),
+ ?line ok = dets:insert(a, O0),
+ ?line true = [O1,O0] =:= sort(get_all_objects(a)),
+ ?line true = [O1,O0] =:= sort(get_all_objects_fast(a)),
+ ?line ok = dets:insert(a, O2),
+ ?line true = [O2,O0] =:= sort(get_all_objects(a)),
+ ?line true = [O2,O0] =:= sort(get_all_objects_fast(a)),
+ ?line ok = dets:insert(a, O3),
+ ?line true = [O3,O0] =:= sort(get_all_objects(a)),
+ ?line true = [O3,O0] =:= sort(get_all_objects_fast(a)),
+ ?line ok = dets:insert(a, O4),
+ ?line true = [O4,O0] =:= sort(get_all_objects(a)),
+ ?line true = [O4,O0] =:= sort(get_all_objects_fast(a)),
+ ?line ok = dets:close(a),
+ ?line file:delete(FName),
+ ?line check_pps(P0),
+ ok.
+
+truncated_segment_array_v8(suite) -> [];
+truncated_segment_array_v8(doc) ->
+ "Tests that a file where the segment array has been truncated "
+ "is possible to repair.";
+truncated_segment_array_v8(Config) when is_list(Config) ->
+ trunc_seg_array(Config, 8).
+
+truncated_segment_array_v9(suite) -> [];
+truncated_segment_array_v9(doc) ->
+ "Tests that a file where the segment array has been truncated "
+ "is possible to repair.";
+truncated_segment_array_v9(Config) when is_list(Config) ->
+ trunc_seg_array(Config, 9).
+
+trunc_seg_array(Config, V) ->
+ TabRef = dets_suite_truncated_segment_array_test,
+ Fname = filename(TabRef, Config),
+ %% Create file that needs to be repaired
+ ?line file:delete(Fname),
+ P0 = pps(),
+ ?line {ok, TabRef} = dets:open_file(TabRef, [{file, Fname},{version,V}]),
+ ?line ok = dets:close(TabRef),
+
+ %% Truncate the file
+ ?line HeadSize = headsz(V),
+ ?line truncate(Fname, HeadSize + 10),
+
+ %% Open the truncated file
+ ?line io:format("Expect repair:~n"),
+ ?line {ok, TabRef} = dets:open_file(TabRef,
+ [{file, Fname}, {repair, true}]),
+ ?line ok = dets:close(TabRef),
+ ?line file:delete(Fname),
+ ?line check_pps(P0),
+ ok.
+
+open_file_v8(doc) ->
+ ["open_file/1 test case."];
+open_file_v8(suite) ->
+ [];
+open_file_v8(Config) when is_list(Config) ->
+ open_1(Config, 8).
+
+open_file_v9(doc) ->
+ ["open_file/1 test case."];
+open_file_v9(suite) ->
+ [];
+open_file_v9(Config) when is_list(Config) ->
+ T = open_v9,
+ Fname = filename(T, Config),
+ ?line {ok, _} = dets:open_file(T, [{file,Fname},{version,9}]),
+ ?line 9 = dets:info(T, version),
+ ?line true = [self()] =:= dets:info(T, users),
+ ?line {ok, _} = dets:open_file(T, [{file,Fname},{version,9}]),
+ ?line {error,incompatible_arguments} =
+ dets:open_file(T, [{file,Fname},{version,8}]),
+ ?line true = [self(),self()] =:= dets:info(T, users),
+ ?line ok = dets:close(T),
+ ?line true = [self()] =:= dets:info(T, users),
+ ?line ok = dets:close(T),
+ ?line undefined = ets:info(T, users),
+ ?line file:delete(Fname),
+
+ open_1(Config, 9).
+
+open_1(Config, V) ->
+ TabRef = open_file_1_test,
+ Fname = filename(TabRef, Config),
+ ?line file:delete(Fname),
+
+ P0 = pps(),
+ ?line {error,{file_error,Fname,enoent}} = dets:open_file(Fname),
+
+ ?line ok = file:write_file(Fname, duplicate(100,65)),
+ ?line {error,{not_a_dets_file,Fname}} = dets:open_file(Fname),
+ ?line file:delete(Fname),
+
+ HeadSize = headsz(V),
+ ?line {ok, TabRef} = dets:open_file(TabRef, [{file, Fname},{version,V}]),
+ ?line ok = dets:close(TabRef),
+ ?line truncate(Fname, HeadSize + 10),
+ ?line true = dets:is_dets_file(Fname),
+ ?line io:format("Expect repair:~n"),
+ ?line {ok, Ref} = dets:open_file(Fname), % repairing
+ ?line ok = dets:close(Ref),
+ ?line file:delete(Fname),
+
+ %% truncated file header, invalid type
+ ?line {ok, TabRef} = dets:open_file(TabRef, [{file,Fname},{version,V}]),
+ ?line ok = ins(TabRef, 3000),
+ ?line ok = dets:close(TabRef),
+ TypePos = 12,
+ crash(Fname, TypePos),
+ ?line {error, {invalid_type_code,Fname}} = dets:open_file(Fname),
+ ?line truncate(Fname, HeadSize - 10),
+ ?line {error, {tooshort,Fname}} = dets:open_file(Fname),
+ ?line {ok, TabRef} = dets:open_file(TabRef, [{file,Fname},{version,V}]),
+ ?line ok = dets:close(TabRef),
+ ?line file:delete(Fname),
+
+ ?line {error,{file_error,{foo,bar},_}} = dets:is_dets_file({foo,bar}),
+ ?line check_pps(P0),
+ ok.
+
+init_table_v8(doc) ->
+ ["initialize_table/2 and from_ets/2 test case."];
+init_table_v8(suite) ->
+ [];
+init_table_v8(Config) when is_list(Config) ->
+ init_table(Config, 8).
+
+init_table_v9(doc) ->
+ ["initialize_table/2 and from_ets/2 test case."];
+init_table_v9(suite) ->
+ [];
+init_table_v9(Config) when is_list(Config) ->
+ %% Objects are returned in "time order".
+ T = init_table_v9,
+ Fname = filename(T, Config),
+ ?line file:delete(Fname),
+ L = [{1,a},{2,b},{1,c},{2,c},{1,c},{2,a},{1,b}],
+ Input = init([L]),
+ ?line {ok, _} = dets:open_file(T, [{file,Fname},{version,9},
+ {type,duplicate_bag}]),
+ ?line ok = dets:init_table(T, Input),
+ ?line [{1,a},{1,c},{1,c},{1,b}] = dets:lookup(T, 1),
+ ?line [{2,b},{2,c},{2,a}] = dets:lookup(T, 2),
+ ?line ok = dets:close(T),
+ ?line file:delete(Fname),
+
+ init_table(Config, 9),
+ fast_init_table(Config).
+
+init_table(Config, V) ->
+ TabRef = init_table_test,
+ Fname = filename(TabRef, Config),
+ ?line file:delete(Fname),
+ P0 = pps(),
+
+ Args = [{file,Fname},{version,V},{auto_save,120000}],
+ ?line {ok, _} = dets:open_file(TabRef, Args),
+ ?line {'EXIT', _} =
+ (catch dets:init_table(TabRef, fun(foo) -> bar end)),
+ dets:close(TabRef),
+ ?line {ok, _} = dets:open_file(TabRef, Args),
+ ?line {'EXIT', _} = (catch dets:init_table(TabRef, fun() -> foo end)),
+ dets:close(TabRef),
+ ?line {ok, _} = dets:open_file(TabRef, Args),
+ ?line {'EXIT', {badarg, _}} = (catch dets:init_table(TabRef, nofun)),
+ ?line {'EXIT', {badarg, _}} =
+ (catch dets:init_table(TabRef, fun(_X) -> end_of_input end,
+ [{foo,bar}])),
+ dets:close(TabRef),
+ ?line {ok, _} = dets:open_file(TabRef, Args),
+ ?line away = (catch dets:init_table(TabRef, fun(_) -> throw(away) end)),
+ dets:close(TabRef),
+ ?line {ok, _} = dets:open_file(TabRef, Args),
+ ?line {error, {init_fun, fopp}} =
+ dets:init_table(TabRef, fun(read) -> fopp end),
+ dets:close(TabRef),
+
+ ?line {ok, _} = dets:open_file(TabRef, Args),
+ ?line dets:safe_fixtable(TabRef, true),
+ ?line {error, {fixed_table, TabRef}} = dets:init_table(TabRef, init([])),
+ ?line dets:safe_fixtable(TabRef, false),
+ ?line ET = ets:new(foo,[]),
+ ?line ok = dets:from_ets(TabRef, ET),
+ ?line [] = get_all_objects(TabRef),
+ ?line [] = get_all_objects_fast(TabRef),
+ ?line true = ets:insert(ET, {1,a}),
+ ?line true = ets:insert(ET, {2,b}),
+ ?line ok = dets:from_ets(TabRef, ET),
+ ?line [{1,a},{2,b}] = sort(get_all_objects(TabRef)),
+ ?line [{1,a},{2,b}] = sort(get_all_objects_fast(TabRef)),
+ ?line true = ets:delete(ET),
+ ?line 120000 = dets:info(TabRef, auto_save),
+ ?line ok = dets:close(TabRef),
+
+ ?line {ok, _} = dets:open_file(TabRef, [{access,read} | Args]),
+ ?line {error, {access_mode, Fname}} = dets:init_table(TabRef, init([])),
+ ?line ok = dets:close(TabRef),
+
+ ?line {ok, _} = dets:open_file(TabRef, Args),
+ ?line {error, invalid_objects_list} =
+ (catch dets:init_table(TabRef, init([[{1,2},bad,{3,4}]]))),
+ ?line _ = dets:close(TabRef),
+ ?line file:delete(Fname),
+
+ L1 = [[{1,a},{2,b}],[],[{3,c}],[{4,d}],[]],
+ bulk_init(L1, set, 4, Config, V),
+ L2 = [[{1,a},{2,b}],[],[{2,q},{3,c}],[{4,d}],[{4,e},{2,q}]],
+ bulk_init(L2, set, 4, Config, V),
+ bulk_init(L2, bag, 6, Config, V),
+ bulk_init(L2, duplicate_bag, 7, Config, V),
+ bulk_init(L1, set, 4, 512, Config, V),
+ bulk_init([], set, 0, 10000, Config, V),
+ file:delete(Fname),
+
+ %% Initiate a file that contains a lot of objects.
+ ?line {ok, _} = dets:open_file(TabRef, [{min_no_slots,10000} | Args]),
+ ?line ok = ins(TabRef, 6000),
+ Fun = init_fun(0, 10000),
+ ?line ok = dets:init_table(TabRef, Fun,{format,term}),
+ ?line All = sort(get_all_objects(TabRef)),
+ ?line FAll = get_all_objects_fast(TabRef),
+ ?line true = All =:= sort(FAll),
+ ?line true = length(All) =:= 10000,
+ ?line ok = dets:close(TabRef),
+ ?line file:delete(Fname),
+
+ ?line {ok, _} = dets:open_file(TabRef, [{min_no_slots,4000} | Args]),
+ ?line ok = ins(TabRef, 6000),
+ ?line FileSize1 = dets:info(TabRef, file_size),
+ Fun2 = init_fun(0, 4000),
+ ?line ok = dets:init_table(TabRef, Fun2),
+ ?line FileSize2 = dets:info(TabRef, file_size),
+ ?line ok = dets:close(TabRef),
+ ?line true = FileSize1 > FileSize2,
+ ?line file:delete(Fname),
+
+ ?line check_pps(P0),
+ ok.
+
+bulk_init(Ls, Type, N, Config, V) ->
+ bulk_init(Ls, Type, N, 256, Config, V).
+
+bulk_init(Ls, Type, N, Est, Config, V) ->
+ T = init_table_test,
+ Fname = filename(T, Config),
+ ?line file:delete(Fname),
+ Input = init(Ls),
+ Args = [{ram_file,false}, {type,Type},{keypos,1},{file,Fname},
+ {estimated_no_objects, Est},{version,V}],
+ ?line {ok, T} = dets:open_file(T, Args),
+ ?line ok = dets:init_table(T, Input),
+ ?line All = sort(get_all_objects(T)),
+ ?line FAll = get_all_objects_fast(T),
+ ?line true = All =:= sort(FAll),
+ ?line true = length(All) =:= N,
+ ?line true = dets:info(T, size) =:= N,
+ ?line ok = dets:close(T),
+
+ ?line {ok, T} = dets:open_file(T, Args),
+ ?line All2 = sort(get_all_objects(T)),
+ ?line FAll2 = get_all_objects_fast(T),
+ ?line true = All =:= All2,
+ ?line true = All =:= sort(FAll2),
+ ?line ok = dets:close(T),
+ ?line file:delete(Fname).
+
+init(L) ->
+ fun(close) ->
+ ok;
+ (read) when [] =:= L ->
+ end_of_input;
+ (read) ->
+ [E | Es] = L,
+ {E, init(Es)}
+ end.
+
+init_fun(I, N) ->
+ fun(read) when I =:= N ->
+ end_of_input;
+ (read) ->
+ {NewN, Items} = items(I, N, 1000, []),
+ {Items, init_fun(NewN, N)};
+ (close) ->
+ ignored
+ end.
+
+fast_init_table(Config) ->
+ V = 9,
+ TabRef = init_table_test,
+ Fname = filename(TabRef, Config),
+ ?line file:delete(Fname),
+ P0 = pps(),
+
+ Args = [{file,Fname},{version,V},{auto_save,120000}],
+
+ Source = init_table_test_source,
+ SourceFname = filename(Source, Config),
+ ?line file:delete(SourceFname),
+ SourceArgs = [{file,SourceFname},{version,V},{auto_save,120000}],
+
+ ?line {ok, Source} = dets:open_file(Source, SourceArgs),
+
+ ?line {ok, _} = dets:open_file(TabRef, Args),
+ ?line {'EXIT', _} =
+ (catch dets:init_table(TabRef, fun(foo) -> bar end, {format,bchunk})),
+ dets:close(TabRef),
+ ?line {ok, _} = dets:open_file(TabRef, Args),
+ ?line {'EXIT', _} = (catch dets:init_table(TabRef, fun() -> foo end,
+ {format,bchunk})),
+ dets:close(TabRef),
+ ?line {ok, _} = dets:open_file(TabRef, Args),
+ ?line {'EXIT', {badarg, _}} =
+ (catch dets:init_table(TabRef, nofun, {format,bchunk})),
+ dets:close(TabRef),
+ ?line {ok, _} = dets:open_file(TabRef, Args),
+ ?line away = (catch dets:init_table(TabRef, fun(_) -> throw(away) end,
+ {format,bchunk})),
+ dets:close(TabRef),
+ ?line {ok, _} = dets:open_file(TabRef, Args),
+ ?line {error, {init_fun, fopp}} =
+ dets:init_table(TabRef, fun(read) -> fopp end, {format,bchunk}),
+ dets:close(TabRef),
+ ?line {ok, _} = dets:open_file(TabRef, Args),
+ ?line dets:safe_fixtable(TabRef, true),
+ ?line {error, {fixed_table, TabRef}} =
+ dets:init_table(TabRef, init([]), {format,bchunk}),
+ ?line dets:safe_fixtable(TabRef, false),
+ ?line ok = dets:close(TabRef),
+
+ ?line {ok, _} = dets:open_file(TabRef, [{access,read} | Args]),
+ ?line {error, {access_mode, Fname}} =
+ dets:init_table(TabRef, init([]), {format,bchunk}),
+ ?line ok = dets:close(TabRef),
+
+ ?line {ok, _} = dets:open_file(TabRef, Args),
+ ?line {error, {init_fun,{1,2}}} =
+ dets:init_table(TabRef, init([[{1,2},bad,{3,4}]]), {format,bchunk}),
+ ?line _ = dets:close(TabRef),
+ ?line file:delete(Fname),
+
+ ?line {ok, _} = dets:open_file(TabRef, Args),
+ ?line {error, {init_fun, end_of_input}} =
+ dets:init_table(TabRef, init([]),{format,bchunk}),
+ ?line _ = dets:close(TabRef),
+ ?line file:delete(Fname),
+
+ ?line {ok, _} = dets:open_file(TabRef, Args),
+ ?line {'EXIT', {badarg, _}} =
+ (catch dets:init_table(TabRef, init([]),{format,foppla})),
+ ?line _ = dets:close(TabRef),
+ ?line file:delete(Fname),
+
+ ?line {ok, _} = dets:open_file(TabRef, Args),
+ ?line ok = ins(TabRef, 100),
+
+ ?line [BParms | Objs] = collect_bchunk(TabRef, init_bchunk(TabRef)),
+ ?line Parms = binary_to_term(BParms),
+ ?line {error, {init_fun, <<"foobar">>}} =
+ dets:init_table(TabRef, init([[<<"foobar">>]]),{format,bchunk}),
+ ?line _ = dets:close(TabRef),
+ ?line file:delete(Fname),
+
+ ?line {ok, _} = dets:open_file(TabRef, Args),
+ ?line Parms1 = setelement(1, Parms, foobar),
+ BParms1 = term_to_binary(Parms1),
+ ?line {error, {init_fun, BParms1}} =
+ dets:init_table(TabRef, init([[BParms1 | Objs]]),{format,bchunk}),
+ ?line _ = dets:close(TabRef),
+ ?line file:delete(Fname),
+
+ ?line {ok, _} = dets:open_file(TabRef, Args),
+ [{Sz1,No1} | NoColls17] = element(tuple_size(Parms), Parms),
+ Parms2 = setelement(tuple_size(Parms), Parms, [{Sz1,No1+1} | NoColls17]),
+ BParms2 = term_to_binary(Parms2),
+ ?line {error, invalid_objects_list} =
+ dets:init_table(TabRef, init([[BParms2 | Objs]]),{format,bchunk}),
+ ?line _ = dets:close(TabRef),
+ ?line file:delete(Fname),
+
+ ?line {ok, _} = dets:open_file(TabRef, Args),
+ ?line [{LSize1,Slot1,Obj1} | ObjsRest] = Objs,
+
+ ?line BadSize = byte_size(Obj1)-1,
+ ?line <<BadSizeObj:BadSize/binary,_:1/binary>> = Obj1,
+ ?line BadObjs = [{LSize1,Slot1,BadSizeObj} | ObjsRest],
+ ?line {error, invalid_objects_list} =
+ dets:init_table(TabRef, init([[BParms | BadObjs]]),{format,bchunk}),
+ ?line _ = dets:close(TabRef),
+ ?line file:delete(Fname),
+
+ ?line {ok, _} = dets:open_file(TabRef, Args),
+ ?line <<Size:32,BigObj0/binary>> = list_to_binary(lists:duplicate(16,Obj1)),
+ ?line BigObj = <<(Size*16):32,BigObj0/binary>>,
+ ?line BadColl = [BParms, {LSize1+4,Slot1,BigObj} | ObjsRest],
+ ?line {error, invalid_objects_list} =
+ dets:init_table(TabRef, init([BadColl]),{format,bchunk}),
+ ?line _ = dets:close(TabRef),
+ ?line file:delete(Fname),
+
+ ?line {ok, _} = dets:open_file(TabRef, Args),
+ BadObj = <<"foobar">>,
+ ?line {error, invalid_objects_list} =
+ dets:init_table(TabRef, init([[BParms, BadObj]]),{format,bchunk}),
+ ?line _ = dets:close(TabRef),
+ ?line file:delete(Fname),
+
+ ?line {ok, _} = dets:open_file(TabRef, [{type,bag} | Args]),
+ ?line {error, {init_fun, _}} =
+ dets:init_table(TabRef, init([[BParms]]),{format,bchunk}),
+ ?line _ = dets:close(TabRef),
+ ?line file:delete(Fname),
+
+ ?line ok = dets:close(Source),
+ ?line file:delete(SourceFname),
+
+ L1 = [{1,a},{2,b},{3,c},{4,d}],
+ fast_bulk_init(L1, set, 4, 4, Config, V),
+ L2 = [{1,a},{2,b},{2,q},{3,c},{4,d},{4,e},{2,q}],
+ fast_bulk_init(L2, set, 4, 4, Config, V),
+ fast_bulk_init(L2, bag, 6, 4, Config, V),
+ fast_bulk_init(L2, duplicate_bag, 7, 4, Config, V),
+ fast_bulk_init(L1, set, 4, 4, 512, Config, V),
+ fast_bulk_init([], set, 0, 0, 10000, Config, V),
+ file:delete(Fname),
+
+ %% Initiate a file that contains a lot of objects.
+ ?line {ok, _} = dets:open_file(Source, [{min_no_slots,10000} | SourceArgs]),
+ Fun1 = init_fun(0, 10000),
+ ?line ok = dets:init_table(Source, Fun1, {format,term}),
+
+ ?line {ok, _} = dets:open_file(TabRef, [{min_no_slots,10000} | Args]),
+ ?line ok = ins(TabRef, 6000),
+ Fun2 = init_bchunk(Source),
+ ?line true =
+ dets:is_compatible_bchunk_format(TabRef,
+ dets:info(Source, bchunk_format)),
+ ?line false = dets:is_compatible_bchunk_format(TabRef, <<"foobar">>),
+ ?line ok = dets:init_table(TabRef, Fun2, {format, bchunk}),
+ ?line ok = dets:close(Source),
+ ?line file:delete(SourceFname),
+ ?line All = sort(get_all_objects(TabRef)),
+ ?line FAll = get_all_objects_fast(TabRef),
+ ?line true = All =:= sort(FAll),
+ ?line true = length(All) =:= 10000,
+ ?line ok = dets:close(TabRef),
+ ?line file:delete(Fname),
+
+ %% Initiate inserts fewer objects than the table contains.
+ ?line {ok, _} = dets:open_file(Source, [{min_no_slots,1000} | SourceArgs]),
+ ?line ok = ins(Source, 4000),
+
+ ?line {ok, _} = dets:open_file(TabRef, [{min_no_slots,1000} | Args]),
+ ?line ok = ins(TabRef, 6000),
+ ?line FileSize1 = dets:info(TabRef, file_size),
+ Fun4 = init_bchunk(Source),
+ ?line ok = dets:init_table(TabRef, Fun4, {format, bchunk}),
+ ?line ok = dets:close(Source),
+ ?line file:delete(SourceFname),
+ ?line FileSize2 = dets:info(TabRef, file_size),
+ ?line All_2 = sort(get_all_objects(TabRef)),
+ ?line FAll_2 = get_all_objects_fast(TabRef),
+ ?line true = All_2 =:= sort(FAll_2),
+ ?line true = length(All_2) =:= 4000,
+ ?line ok = dets:close(TabRef),
+ ?line true = FileSize1 > FileSize2,
+
+ %% Bchunk and fixed table.
+ ?line {ok, _} = dets:open_file(TabRef, Args),
+ ?line NoItems = dets:info(TabRef, no_objects),
+ ?line AllObjects1 = sort(get_all_objects_fast(TabRef)),
+ ?line dets:safe_fixtable(TabRef, true),
+ ?line true = dets:info(TabRef, fixed),
+ ?line Cont1 = init_bchunk(TabRef),
+ ?line NoDel =
+ dets:select_delete(TabRef, [{{'_',{item,'_','_'}},[],[true]}]),
+ ?line true = (NoDel > 0),
+ ?line AllObjects2 = sort(get_all_objects_fast(TabRef)),
+ ?line true = dets:info(TabRef, fixed),
+ ?line Cont2 = init_bchunk(TabRef),
+ ?line NoItems2 = dets:info(TabRef, no_objects),
+ ?line true = (NoItems =:= NoItems2 + NoDel),
+ ?line NoDel2 = dets:select_delete(TabRef, [{'_',[],[true]}]),
+ ?line true = (NoDel2 > 0),
+ ?line AllObjects3 = sort(get_all_objects_fast(TabRef)),
+ ?line NoItems3 = dets:info(TabRef, no_objects),
+ ?line true = (NoItems3 =:= 0),
+ ?line true = dets:info(TabRef, fixed),
+ ?line true = (NoItems2 =:= NoItems3 + NoDel2),
+ ?line Cont3 = init_bchunk(TabRef),
+
+ ?line BinColl1 = collect_bchunk(TabRef, Cont1),
+ ?line BinColl2 = collect_bchunk(TabRef, Cont2),
+ ?line BinColl3 = collect_bchunk(TabRef, Cont3),
+ ?line dets:safe_fixtable(TabRef, false),
+ ?line ok = dets:close(TabRef),
+ ?line file:delete(Fname),
+
+ %% Now check that the above collected binaries are correct.
+ ?line {ok, _} = dets:open_file(TabRef, Args),
+ ?line ok = dets:init_table(TabRef, init([BinColl1]),{format,bchunk}),
+ ?line true = (AllObjects1 =:= sort(get_all_objects_fast(TabRef))),
+ ?line true = (length(AllObjects1) =:= dets:info(TabRef, no_objects)),
+ ?line ok = dets:init_table(TabRef, init([BinColl2]),{format,bchunk}),
+ ?line true = (AllObjects2 =:= sort(get_all_objects_fast(TabRef))),
+ ?line true = (length(AllObjects2) =:= dets:info(TabRef, no_objects)),
+ ?line ok = dets:init_table(TabRef, init([BinColl3]),{format,bchunk}),
+ ?line true = (AllObjects3 =:= sort(get_all_objects_fast(TabRef))),
+ ?line true = (length(AllObjects3) =:= dets:info(TabRef, no_objects)),
+ ?line ok = dets:close(TabRef),
+ ?line file:delete(Fname),
+ ?line check_pps(P0),
+ ok.
+
+fast_bulk_init(L, Type, N, NoKeys, Config, V) ->
+ fast_bulk_init(L, Type, N, NoKeys, 256, Config, V).
+
+fast_bulk_init(L, Type, N, NoKeys, Est, Config, V) ->
+ T = init_table_test,
+ Fname = filename(T, Config),
+ ?line file:delete(Fname),
+
+ Args0 = [{ram_file,false}, {type,Type},{keypos,1},
+ {estimated_no_objects, Est},{version,V}],
+ Args = [{file,Fname} | Args0],
+ S = init_table_test_source,
+ SFname = filename(S, Config),
+ ?line file:delete(SFname),
+ SArgs = [{file,SFname} | Args0],
+
+ ?line {ok, S} = dets:open_file(S, SArgs),
+ ?line ok = dets:insert(S, L),
+
+ Input = init_bchunk(S),
+ ?line {ok, T} = dets:open_file(T, Args),
+ ?line ok = dets:init_table(T, Input, [{format,bchunk}]),
+ ?line All = sort(get_all_objects(T)),
+ ?line FAll = get_all_objects_fast(T),
+ ?line true = All =:= sort(FAll),
+ ?line true = length(All) =:= N,
+ ?line true = dets:info(T, size) =:= N,
+ ?line true = dets:info(T, no_keys) =:= NoKeys,
+ ?line ok = dets:close(T),
+
+ ?line {ok, T} = dets:open_file(T, Args),
+ ?line All2 = sort(get_all_objects(T)),
+ ?line FAll2 = get_all_objects_fast(T),
+ ?line true = All =:= All2,
+ ?line true = All =:= sort(FAll2),
+ ?line ok = dets:close(T),
+ ?line file:delete(Fname),
+
+ ?line ok = dets:close(S),
+ ?line file:delete(SFname),
+ ok.
+
+init_bchunk(T) ->
+ Start = dets:bchunk(T, start),
+ init_bchunk(T, Start).
+
+init_bchunk(Tab, State) ->
+ fun(read) when State =:= '$end_of_table' ->
+ end_of_input;
+ (read) when element(1, State) =:= error ->
+ State;
+ (read) ->
+ {Cont, Objs} = State,
+ {Objs, init_bchunk(Tab, dets:bchunk(Tab, Cont))};
+ (close) ->
+ ok
+ end.
+
+collect_bchunk(Tab, Fun) ->
+ collect_bchunk(Tab, Fun, []).
+
+collect_bchunk(Tab, Fun, L) ->
+ case Fun(read) of
+ end_of_input ->
+ lists:append(lists:reverse(L));
+ {Objs, Fun2} when is_list(Objs) ->
+ collect_bchunk(Tab, Fun2, [Objs | L]);
+ Error ->
+ Error
+ end.
+
+items(I, N, C, L) when I =:= N; C =:= 0 ->
+ {I, L};
+items(I, N, C, L) ->
+ items(I+1, N, C-1, [{I, item(I)} | L]).
+
+repair_v8(doc) ->
+ ["open_file and repair."];
+repair_v8(suite) ->
+ [];
+repair_v8(Config) when is_list(Config) ->
+ repair(Config, 8).
+
+repair_v9(doc) ->
+ ["open_file and repair."];
+repair_v9(suite) ->
+ [];
+repair_v9(Config) when is_list(Config) ->
+ %% Convert from format 9 to format 8.
+ T = convert_98,
+ Fname = filename(T, Config),
+ ?line file:delete(Fname),
+ ?line {ok, _} = dets:open_file(T, [{file,Fname},{version,9},
+ {type,duplicate_bag}]),
+ ?line 9 = dets:info(T, version),
+ ?line true = is_binary(dets:info(T, bchunk_format)),
+ ?line ok = dets:insert(T, [{1,a},{2,b},{1,c},{2,c},{1,c},{2,a},{1,b}]),
+ ?line dets:close(T),
+ ?line {error, {version_mismatch, _}} =
+ dets:open_file(T, [{file,Fname},{version,8},{type,duplicate_bag}]),
+ ?line {ok, _} = dets:open_file(T, [{file,Fname},{version,8},
+ {type,duplicate_bag},{repair,force}]),
+ ?line 8 = dets:info(T, version),
+ ?line true = undefined =:= dets:info(T, bchunk_format),
+ ?line [{1,a},{1,b},{1,c},{1,c}] = sort(dets:lookup(T, 1)),
+ ?line [{2,a},{2,b},{2,c}] = sort(dets:lookup(T, 2)),
+ ?line 7 = dets:info(T, no_objects),
+ ?line no_keys_test(T),
+ ?line _ = histogram(T, silent),
+ ?line ok = dets:close(T),
+ ?line file:delete(Fname),
+
+ %% The short lived format 9(a).
+ %% Not very throughly tested here.
+ A9 = a9,
+ ?line Version9aS = filename:join(?datadir(Config), "version_9a.dets"),
+ ?line Version9aT = filename('v9a.dets', Config),
+ ?line {ok, _} = file:copy(Version9aS, Version9aT),
+ ?line {ok, A9} = dets:open_file(A9, [{file,Version9aT}]),
+ ?line undefined = dets:info(A9, bchunk_format),
+ ?line [{1,a},{2,b},{3,c}] = sort(dets:match_object(A9, '_')),
+ ?line ok = dets:insert(A9, {4,d}),
+ ?line ok = dets:close(A9),
+ ?line {ok, A9} = dets:open_file(A9, [{file,Version9aT}]),
+ ?line {error, old_version} = dets:bchunk(A9, start),
+ ?line ok = dets:close(A9),
+ ?line io:format("Expect forced repair:~n"),
+ ?line {ok, A9} = dets:open_file(A9, [{file,Version9aT},{repair,force}]),
+ ?line {_, _} = dets:bchunk(A9, start),
+ ?line ok = dets:close(A9),
+ ?line file:delete(Version9aT),
+
+ repair(Config, 9).
+
+repair(Config, V) ->
+ TabRef = repair_test,
+ Fname = filename(TabRef, Config),
+ ?line file:delete(Fname),
+ HeadSize = headsz(V),
+
+ P0 = pps(),
+ ?line {'EXIT', {badarg, _}} =
+ (catch dets:open_file(TabRef, [{min_no_slots,1000},
+ {max_no_slots,500}])),
+ ?line {error,{file_error,hoppla,enoent}} = dets:file_info(hoppla),
+ ?line {error,{file_error,Fname,enoent}} =
+ dets:open_file(TabRef, [{file, Fname}, {access, read}]),
+
+ %% compacting, and some kind of test that free lists are saved OK on file
+ ?line {ok, TabRef} = dets:open_file(TabRef, [{file,Fname},{version,V}]),
+ ?line 0 = dets:info(TabRef, size),
+ ?line ok = ins(TabRef, 30000),
+ ?line ok = del(TabRef, 30000, 3),
+ ?line ok = dets:close(TabRef),
+ ?line {error, {access_mode,Fname}} =
+ dets:open_file(foo, [{file,Fname},{repair,force},{access,read}]),
+ ?line {ok, Ref3} = dets:open_file(Fname), % no repair!
+ ?line 20000 = dets:info(Ref3, size),
+ ?line 20000 = dets:foldl(fun(_, N) -> N+1 end, 0, Ref3),
+ ?line 20000 = count_objects_quite_fast(Ref3), % actually a test of match
+ ?line no_keys_test(Ref3),
+ ?line ok = dets:close(Ref3),
+ if
+ V =:= 8 ->
+ ?line {ok, TabRef} = dets:open_file(TabRef,
+ [{file, Fname},{version,V},{access,read}]),
+ ?line ok = dets:close(TabRef),
+ ?line io:format("Expect compacting repair:~n"),
+ ?line {ok, TabRef} = dets:open_file(TabRef,
+ [{file, Fname},{version,V}]),
+ ?line 20000 = dets:info(TabRef, size),
+ ?line _ = histogram(TabRef, silent),
+ ?line ok = dets:close(TabRef);
+ true ->
+ ok
+ end,
+ ?line {error,{keypos_mismatch,Fname}} =
+ dets:open_file(TabRef, [{file, Fname},{keypos,17}]),
+ ?line {error,{type_mismatch,Fname}} =
+ dets:open_file(TabRef, [{file, Fname},{type,duplicate_bag}]),
+
+ %% make one of the temporary files unwritable
+ TmpFile = if
+ V =:= 8 ->
+ Fname ++ ".TMP.10000";
+ true -> Fname ++ ".TMP.1"
+ end,
+ ?line file:delete(TmpFile),
+ ?line {ok, TmpFd} = file:open(TmpFile, [read,write]),
+ ?line ok = file:close(TmpFd),
+ ?line unwritable(TmpFile),
+ ?line {error,{file_error,TmpFile,eacces}} = dets:fsck(Fname, V),
+ ?line {ok, _} = dets:open_file(TabRef,
+ [{repair,false},{file, Fname},{version,V}]),
+ ?line 20000 = length(get_all_objects(TabRef)),
+ ?line _ = histogram(TabRef, silent),
+ ?line 20000 = length(get_all_objects_fast(TabRef)),
+ ?line ok = dets:close(TabRef),
+ ?line writable(TmpFile),
+ ?line file:delete(TmpFile),
+
+ ?line truncate(Fname, HeadSize + 10),
+ ?line {error,{not_closed, Fname}} =
+ dets:open_file(TabRef, [{file, Fname}, {access, read}]),
+ ?line {error,{not_closed, Fname}} =
+ dets:open_file(TabRef, [{file, Fname}, {access, read},
+ {repair,force}]),
+ ?line {error,{needs_repair, Fname}} =
+ dets:open_file(TabRef, [{file, Fname}, {repair, false}]),
+ ?line file:delete(Fname),
+
+ %% truncated file header
+ ?line {ok, TabRef} = dets:open_file(TabRef, [{file,Fname},{version,V}]),
+ ?line ok = ins(TabRef, 100),
+ ?line ok = dets:close(TabRef),
+ ?line truncate(Fname, HeadSize - 10),
+ %% a new file is created ('tooshort')
+ ?line {ok, TabRef} = dets:open_file(TabRef,
+ [{file,Fname},{version,V},
+ {min_no_slots,1000},
+ {max_no_slots,1000000}]),
+ case dets:info(TabRef, no_slots) of
+ undefined -> ok;
+ {Min1,Slot1,Max1} ->
+ ?line true = Min1 =< Slot1, true = Slot1 =< Max1,
+ ?line true = 1000 < Min1, true = 1000+256 > Min1,
+ ?line true = 1000000 < Max1, true = (1 bsl 20)+256 > Max1
+ end,
+ ?line 0 = dets:info(TabRef, size),
+ ?line no_keys_test(TabRef),
+ ?line _ = histogram(TabRef, silent),
+ ?line ok = dets:close(TabRef),
+ ?line file:delete(Fname),
+
+ %% version bump (v8)
+ ?line Version7S = filename:join(?datadir(Config), "version_r2d.dets"),
+ ?line Version7T = filename('v2.dets', Config),
+ ?line {ok, _} = file:copy(Version7S, Version7T),
+ ?line {error,{version_bump, Version7T}} = dets:open_file(Version7T),
+ ?line {error,{version_bump, Version7T}} =
+ dets:open_file(Version7T, [{file,Version7T},{repair,false}]),
+ ?line {error,{version_bump, Version7T}} =
+ dets:open_file(Version7T, [{file, Version7T}, {access, read}]),
+ ?line io:format("Expect upgrade:~n"),
+ ?line {ok, _} = dets:open_file(Version7T,
+ [{file, Version7T},{version, V}]),
+ ?line [{1,a},{2,b}] = sort(get_all_objects(Version7T)),
+ ?line [{1,a},{2,b}] = sort(get_all_objects_fast(Version7T)),
+ Phash = if
+ V =:= 8 -> phash;
+ true -> phash2
+ end,
+ ?line Phash = dets:info(Version7T, hash),
+ ?line _ = histogram(Version7T, silent),
+ ?line ok = dets:close(Version7T),
+ ?line {ok, _} = dets:open_file(Version7T, [{file, Version7T}]),
+ ?line Phash = dets:info(Version7T, hash),
+ ?line ok = dets:close(Version7T),
+ ?line file:delete(Version7T),
+
+ %% converting free lists
+ ?line Version8aS = filename:join(?datadir(Config), "version_r3b02.dets"),
+ ?line Version8aT = filename('v3.dets', Config),
+ ?line {ok, _} = file:copy(Version8aS, Version8aT),
+ %% min_no_slots and max_no_slots are ignored - no repair is taking place
+ ?line {ok, _} = dets:open_file(version_8a,
+ [{file, Version8aT},{min_no_slots,1000},
+ {max_no_slots,100000}]),
+ ?line [{1,b},{2,a},{a,1},{b,2}] = sort(get_all_objects(version_8a)),
+ ?line [{1,b},{2,a},{a,1},{b,2}] = sort(get_all_objects_fast(version_8a)),
+ ?line ok = ins(version_8a, 1000),
+ ?line 1002 = dets:info(version_8a, size),
+ ?line no_keys_test(version_8a),
+ ?line All8a = sort(get_all_objects(version_8a)),
+ ?line 1002 = length(All8a),
+ ?line FAll8a = sort(get_all_objects_fast(version_8a)),
+ ?line true = sort(All8a) =:= sort(FAll8a),
+ ?line ok = del(version_8a, 300, 3),
+ ?line 902 = dets:info(version_8a, size),
+ ?line no_keys_test(version_8a),
+ ?line All8a2 = sort(get_all_objects(version_8a)),
+ ?line 902 = length(All8a2),
+ ?line FAll8a2 = sort(get_all_objects_fast(version_8a)),
+ ?line true = sort(All8a2) =:= sort(FAll8a2),
+ ?line _ = histogram(version_8a, silent),
+ ?line ok = dets:close(version_8a),
+ ?line file:delete(Version8aT),
+
+ %% will fail unless the slots are properly sorted when repairing (v8)
+ BArgs = [{file, Fname},{type,duplicate_bag},
+ {delayed_write,{3000,10000}},{version,V}],
+ ?line {ok, TabRef} = dets:open_file(TabRef, BArgs),
+ Seq = seq(1, 500),
+ Small = map(fun(X) -> {X,X} end, Seq),
+ Big = map(fun(X) -> erlang:make_tuple(20, X) end, Seq),
+ ?line ok = dets:insert(TabRef, Small),
+ ?line ok = dets:insert(TabRef, Big),
+ ?line ok = dets:insert(TabRef, Small),
+ ?line ok = dets:insert(TabRef, Big),
+ ?line All = sort(safe_get_all_objects(TabRef)),
+ ?line ok = dets:close(TabRef),
+ ?line io:format("Expect forced repair:~n"),
+ ?line {ok, _} =
+ dets:open_file(TabRef, [{repair,force},{min_no_slots,2000} | BArgs]),
+ if
+ V =:= 9 ->
+ ?line {MinNoSlots,_,MaxNoSlots} = dets:info(TabRef, no_slots),
+ ?line ok = dets:close(TabRef),
+ ?line io:format("Expect compaction:~n"),
+ ?line {ok, _} =
+ dets:open_file(TabRef, [{repair,force},
+ {min_no_slots,MinNoSlots},
+ {max_no_slots,MaxNoSlots} | BArgs]);
+ true ->
+ ok
+ end,
+ ?line All2 = get_all_objects(TabRef),
+ ?line true = All =:= sort(All2),
+ ?line FAll2 = get_all_objects_fast(TabRef),
+ ?line true = All =:= sort(FAll2),
+ ?line true = length(All) =:= dets:info(TabRef, size),
+ ?line no_keys_test(TabRef),
+ Fun = fun(X) -> 4 = length(dets:lookup(TabRef, X)) end,
+ ?line foreach(Fun, Seq),
+ ?line _ = histogram(TabRef, silent),
+ ?line ok = dets:close(TabRef),
+ ?line file:delete(Fname),
+
+ %% object bigger than segments, the "hole" is taken care of
+ ?line {ok, TabRef} = dets:open_file(TabRef, [{file, Fname},{version,V}]),
+ Tuple = erlang:make_tuple(1000, foobar), % > 2 kB
+ ?line ok = dets:insert(TabRef, Tuple),
+ %% at least one full segment (objects smaller than 2 kB):
+ ?line ins(TabRef, 2000),
+ ?line ok = dets:close(TabRef),
+
+ if
+ V =:= 8 ->
+ %% first estimated number of objects is wrong, repair once more
+ ?line {ok, Fd} = file:open(Fname, read_write),
+ NoPos = HeadSize - 8, % no_objects
+ ?line file:pwrite(Fd, NoPos, <<0:32>>), % NoItems
+ ok = file:close(Fd),
+ ?line dets:fsck(Fname, V),
+ ?line {ok, _} =
+ dets:open_file(TabRef,
+ [{repair,false},{file, Fname},{version,V}]),
+ ?line 2001 = length(get_all_objects(TabRef)),
+ ?line _ = histogram(TabRef, silent),
+ ?line 2001 = length(get_all_objects_fast(TabRef)),
+ ?line ok = dets:close(TabRef);
+ true ->
+ ok
+ end,
+
+ ?line {ok, _} =
+ dets:open_file(TabRef,
+ [{repair,false},{file, Fname},{version,V}]),
+ ?line {ok, ObjPos} = dets:where(TabRef, {66,{item,number,66}}),
+ ?line ok = dets:close(TabRef),
+ %% Damaged object.
+ Pos = 12, % v9: compaction fails, proper repair follows
+ crash(Fname, ObjPos+Pos),
+ ?line io:format(
+ "Expect forced repair (possibly after attempted compaction):~n"),
+ ?line {ok, _} =
+ dets:open_file(TabRef, [{repair,force},{file, Fname},{version,V}]),
+ ?line true = dets:info(TabRef, size) < 2001,
+ ?line ok = dets:close(TabRef),
+ ?line file:delete(Fname),
+
+ %% The file is smaller than the padded object.
+ ?line {ok, TabRef} = dets:open_file(TabRef, [{file,Fname},{version,V}]),
+ ?line ok = dets:insert(TabRef, Tuple),
+ ?line ok = dets:close(TabRef),
+ ?line io:format("Expect forced repair or compaction:~n"),
+ ?line {ok, _} =
+ dets:open_file(TabRef, [{repair,force},{file, Fname},{version,V}]),
+ ?line true = 1 =:= dets:info(TabRef, size),
+ ?line ok = dets:close(TabRef),
+ ?line file:delete(Fname),
+
+ %% Damaged free lists.
+ ?line {ok, TabRef} = dets:open_file(TabRef, [{file,Fname},{version,V}]),
+ ?line ok = ins(TabRef, 300),
+ ?line ok = dets:sync(TabRef),
+ ?line ok = del(TabRef, 300, 3),
+ %% FileSize is approximately where the free lists will be written.
+ ?line FileSize = dets:info(TabRef, memory),
+ ?line ok = dets:close(TabRef),
+ crash(Fname, FileSize+20),
+ ?line {error, {bad_freelists, Fname}} =
+ dets:open_file(TabRef, [{file,Fname},{version,V}]),
+ ?line file:delete(Fname),
+
+ %% File not closed, opening with read and read_write access tried.
+ ?line {ok, TabRef} = dets:open_file(TabRef, [{file,Fname},{version,V}]),
+ ?line ok = ins(TabRef, 300),
+ ?line ok = dets:close(TabRef),
+ ?line crash(Fname, ?CLOSED_PROPERLY_POS+3, ?NOT_PROPERLY_CLOSED),
+ ?line {error, {not_closed, Fname}} =
+ dets:open_file(foo, [{file,Fname},{version,V},{repair,force},
+ {access,read}]),
+ ?line {error, {not_closed, Fname}} =
+ dets:open_file(foo, [{file,Fname},{version,V},{repair,true},
+ {access,read}]),
+ ?line io:format("Expect repair:~n"),
+ ?line {ok, TabRef} =
+ dets:open_file(TabRef, [{file,Fname},{version,V},{repair,true},
+ {access,read_write}]),
+ ?line ok = dets:close(TabRef),
+ ?line crash(Fname, ?CLOSED_PROPERLY_POS+3, ?NOT_PROPERLY_CLOSED),
+ ?line io:format("Expect forced repair:~n"),
+ ?line {ok, TabRef} =
+ dets:open_file(TabRef, [{file,Fname},{version,V},{repair,force},
+ {access,read_write}]),
+ ?line ok = dets:close(TabRef),
+ ?line file:delete(Fname),
+
+ %% The size of an object is huge.
+ ?line {ok, TabRef} = dets:open_file(TabRef, [{file,Fname},{version,V}]),
+ ?line ok = dets:insert(TabRef, [{1,2,3},{2,3,4}]),
+ ?line {ok, ObjPos2} = dets:where(TabRef, {1,2,3}),
+ ?line ok = dets:close(TabRef),
+ ObjPos3 = if
+ V =:= 8 -> ObjPos2 + 4;
+ V =:= 9 -> ObjPos2
+ end,
+ crash(Fname, ObjPos3, 255),
+ ?line io:format("Expect forced repair:~n"),
+ ?line {ok, TabRef} =
+ dets:open_file(TabRef, [{file,Fname},{version,V},{repair,force}]),
+ ?line ok = dets:close(TabRef),
+ ?line file:delete(Fname),
+
+ ?line check_pps(P0),
+ ok.
+
+hash_v8b_v8c(doc) ->
+ ["Test the use of different hashing algorithms in v8b and v8c of the "
+ "Dets file format."];
+hash_v8b_v8c(suite) ->
+ [];
+hash_v8b_v8c(Config) when is_list(Config) ->
+ ?line Source =
+ filename:join(?datadir(Config), "dets_test_v8b.dets"),
+ %% Little endian version of old file (there is an endianess bug in
+ %% the old hash). This is all about version 8 of the dets file format.
+
+ P0 = pps(),
+ ?line SourceLE =
+ filename:join(?datadir(Config),
+ "dets_test_v8b_little_endian.dets"),
+ ?line Target1 = filename('oldhash1.dets', Config),
+ ?line Target1LE = filename('oldhash1le.dets', Config),
+ ?line Target2 = filename('oldhash2.dets', Config),
+ ?line {ok, Bin} = file:read_file(Source),
+ ?line {ok, BinLE} = file:read_file(SourceLE),
+ ?line ok = file:write_file(Target1,Bin),
+ ?line ok = file:write_file(Target1LE,BinLE),
+ ?line ok = file:write_file(Target2,Bin),
+ ?line {ok, d1} = dets:open_file(d1,[{file,Target1}]),
+ ?line {ok, d1le} = dets:open_file(d1le,[{file,Target1LE}]),
+ ?line {ok, d2} = dets:open_file(d2,[{file,Target2},{repair,force},
+ {version,8}]),
+ ?line FF = fun(N,_F,_T) when N > 16#FFFFFFFFFFFFFFFF ->
+ ok;
+ (N,F,T) ->
+ V = integer_to_list(N),
+ case dets:lookup(T,N) of
+ [{N,V}] ->
+ F(N*2,F,T);
+ _Error ->
+ exit({failed,{lookup,T,N}})
+ end
+ end,
+ ?line Mess = case (catch FF(1,FF,d1)) of
+ {'EXIT', {failed, {lookup,_,_}}} ->
+ ?line ok = dets:close(d1),
+ ?line FF(1,FF,d1le),
+ ?line hash = dets:info(d1le,hash),
+ ?line dets:insert(d1le,{33333333333,hejsan}),
+ ?line [{33333333333,hejsan}] =
+ dets:lookup(d1le,33333333333),
+ ?line ok = dets:close(d1le),
+ ?line {ok, d1le} = dets:open_file(d1le,
+ [{file,Target1LE}]),
+ ?line [{33333333333,hejsan}] =
+ dets:lookup(d1le,33333333333),
+ ?line FF(1,FF,d1le),
+ ?line ok = dets:close(d1le),
+ "Seems to be a little endian machine";
+ {'EXIT', Fault} ->
+ exit(Fault);
+ _ ->
+ ?line ok = dets:close(d1le),
+ ?line hash = dets:info(d1,hash),
+ ?line dets:insert(d1,{33333333333,hejsan}),
+ ?line [{33333333333,hejsan}] =
+ dets:lookup(d1,33333333333),
+ ?line ok = dets:close(d1),
+ ?line {ok, d1} = dets:open_file(d1,[{file,Target1}]),
+ ?line [{33333333333,hejsan}] =
+ dets:lookup(d1,33333333333),
+ ?line FF(1,FF,d1),
+ ?line ok = dets:close(d1),
+ "Seems to be a big endian machine"
+ end,
+ ?line FF(1,FF,d2),
+ ?line phash = dets:info(d2,hash),
+ ?line ok = dets:close(d2),
+ ?line file:delete(Target1),
+ ?line file:delete(Target1LE),
+ ?line file:delete(Target2),
+ ?line check_pps(P0),
+ {comment, Mess}.
+
+phash(doc) ->
+ ["Test version 9(b) with erlang:phash/2 as hash function."];
+phash(suite) ->
+ [];
+phash(Config) when is_list(Config) ->
+ T = phash,
+ Phash_v9bS = filename:join(?datadir(Config), "version_9b_phash.dat"),
+ Fname = filename('v9b.dets', Config),
+ ?line {ok, _} = file:copy(Phash_v9bS, Fname),
+
+ %% Deleting all objects changes the hash function.
+ %% A feature... (it's for free)
+ ?line {ok, T} = dets:open_file(T, [{file, Fname}]),
+ ?line phash = dets:info(T, hash),
+ ?line dets:delete_all_objects(T),
+ ?line phash2 = dets:info(T, hash),
+ ?line [] = get_all_objects(T),
+ ?line [] = get_all_objects_fast(T),
+ ?line ok = dets:close(T),
+
+ %% The hash function is kept when compacting a table.
+ ?line {ok, _} = file:copy(Phash_v9bS, Fname),
+ ?line io:format("Expect compaction:~n"),
+ ?line {ok, T} = dets:open_file(T, [{file, Fname},{repair,force}]),
+ ?line phash = dets:info(T, hash),
+ ?line [{1,a},{2,b},{3,c},{4,d},{5,e}] =
+ lists:sort(dets:lookup_keys(T, [1,2,3,4,5])),
+ ?line ok = dets:close(T),
+
+ %% The hash function is updated when repairing a table (no cost).
+ ?line {ok, _} = file:copy(Phash_v9bS, Fname),
+ crash(Fname, ?CLOSED_PROPERLY_POS+3, 0),
+ ?line io:format("Expect repair:~n"),
+ ?line {ok, T} = dets:open_file(T, [{file, Fname}]),
+ ?line phash2 = dets:info(T, hash),
+ ?line [{1,a},{2,b},{3,c},{4,d},{5,e}] =
+ lists:sort(dets:lookup_keys(T, [1,2,3,4,5])),
+ ?line ok = dets:close(T),
+
+ %% One cannot use the bchunk format when copying between a phash
+ %% table and a phash2 table. (There is no test for the case an R9
+ %% (or later) node (using phash2) copies a table to an R8 node
+ %% (using phash).) See also the comment on HASH_PARMS in dets_v9.erl.
+ ?line {ok, _} = file:copy(Phash_v9bS, Fname),
+ ?line {ok, T} = dets:open_file(T, [{file, Fname}]),
+ ?line Type = dets:info(T, type),
+ ?line KeyPos = dets:info(T, keypos),
+ Input = init_bchunk(T),
+ T2 = phash_table,
+ Fname2 = filename(T2, Config),
+ Args = [{type,Type},{keypos,KeyPos},{version,9},{file,Fname2}],
+ ?line {ok, T2} = dets:open_file(T2, Args),
+ ?line {error, {init_fun, _}} =
+ dets:init_table(T2, Input, {format,bchunk}),
+ ?line _ = dets:close(T2),
+ ?line ok = dets:close(T),
+ ?line file:delete(Fname2),
+
+ ?line file:delete(Fname),
+ ok.
+
+fold_v8(doc) ->
+ ["foldl, foldr, to_ets"];
+fold_v8(suite) ->
+ [];
+fold_v8(Config) when is_list(Config) ->
+ fold(Config, 8).
+
+fold_v9(doc) ->
+ ["foldl, foldr, to_ets"];
+fold_v9(suite) ->
+ [];
+fold_v9(Config) when is_list(Config) ->
+ fold(Config, 9).
+
+fold(Config, Version) ->
+ T = test_table,
+ N = 100,
+ ?line Fname = filename(T, Config),
+ ?line file:delete(Fname),
+ P0 = pps(),
+
+ Args = [{version, Version}, {file,Fname}, {estimated_no_objects, N}],
+ ?line {ok, _} = dets:open_file(T, Args),
+
+ ?line ok = ins(T, N),
+
+ ?line Ets = ets:new(to_ets, [public]),
+ ?line dets:to_ets(T, Ets),
+ ?line true = N =:= ets:info(Ets, size),
+ ?line ets:delete(Ets),
+
+ ?line Ets2 = ets:new(to_ets, [private]),
+ ?line dets:to_ets(T, Ets2),
+ ?line true = N =:= ets:info(Ets2, size),
+ ?line ets:delete(Ets2),
+
+ ?line {'EXIT', {badarg, _}} = (catch dets:to_ets(T, not_an_ets_table)),
+
+ F0 = fun(X, A) -> [X | A] end,
+ ?line true = N =:= length(dets:foldl(F0, [], T)),
+ ?line true = N =:= length(dets:foldr(F0, [], T)),
+
+ F1 = fun(_X, _A) -> throw(away) end,
+ ?line away = (catch dets:foldl(F1, [], T)),
+ ?line away = (catch dets:foldr(F1, [], T)),
+
+ F2 = fun(X, A) -> X + A end,
+ ?line {'EXIT', _} = (catch dets:foldl(F2, [], T)),
+ ?line {'EXIT', _} = (catch dets:foldr(F2, [], T)),
+
+ F3 = fun(_X) -> throw(away) end,
+ ?line away = (catch dets:traverse(T, F3)),
+
+ F4 = fun(X) -> X + 17 end,
+ ?line {'EXIT', _} = (catch dets:traverse(T, F4)),
+
+ ?line F5 = fun(_X) -> done end,
+ ?line done = dets:traverse(T, F5),
+
+ ?line {ok, ObjPos} = dets:where(T, {66,{item,number,66}}),
+ ?line ok = dets:close(T),
+
+ %% Damaged object.
+ Pos = if
+ Version =:= 8 -> 12;
+ Version =:= 9 -> 8
+ end,
+ crash(Fname, ObjPos+Pos),
+ ?line {ok, _} = dets:open_file(T, Args),
+ ?line io:format("Expect corrupt table:~n"),
+ ?line BadObject1 = dets:foldl(F0, [], T),
+ ?line bad_object(BadObject1, Fname),
+ ?line BadObject2 = dets:close(T),
+ ?line bad_object(BadObject2, Fname),
+
+ ?line file:delete(Fname),
+ ?line check_pps(P0),
+ ok.
+
+fixtable_v8(doc) ->
+ ["Add objects to a fixed table."];
+fixtable_v8(suite) ->
+ [];
+fixtable_v8(Config) when is_list(Config) ->
+ fixtable(Config, 8).
+
+fixtable_v9(doc) ->
+ ["Add objects to a fixed table."];
+fixtable_v9(suite) ->
+ [];
+fixtable_v9(Config) when is_list(Config) ->
+ fixtable(Config, 9).
+
+fixtable(Config, Version) when is_list(Config) ->
+ T = fixtable,
+ ?line Fname = filename(fixtable, Config),
+ ?line file:delete(Fname),
+ Args = [{version,Version},{file,Fname}],
+ P0 = pps(),
+ ?line {ok, _} = dets:open_file(T, Args),
+
+ %% badarg
+ ?line {'EXIT', {badarg, [{dets,safe_fixtable,[no_table,true]}|_]}} =
+ (catch dets:safe_fixtable(no_table,true)),
+ ?line {'EXIT', {badarg, [{dets,safe_fixtable,[T,undefined]}|_]}} =
+ (catch dets:safe_fixtable(T,undefined)),
+
+ %% The table is not allowed to grow while the elements are inserted:
+
+ ?line ok = ins(T, 500),
+ ?line dets:safe_fixtable(T, false),
+ %% Now the table can grow. At the same time as elements are inserted,
+ %% the table tries to catch up with the previously inserted elements.
+ ?line ok = ins(T, 1000),
+ ?line 1000 = dets:info(T, size),
+ ?line ok = dets:close(T),
+ ?line file:delete(Fname),
+
+ ?line {ok, _} = dets:open_file(T, [{type, duplicate_bag} | Args]),
+ %% In a fixed table, delete and re-insert an object.
+ ?line ok = dets:insert(T, {1, a, b}),
+ ?line dets:safe_fixtable(T, true),
+ ?line ok = dets:match_delete(T, {1, a, b}),
+ ?line ok = dets:insert(T, {1, a, b}),
+ ?line dets:safe_fixtable(T, false),
+ ?line 1 = length(dets:match_object(T, '_')),
+
+ ?line ok = dets:match_delete(T, '_'),
+ %% In a fixed table, delete and insert a smaller object.
+ ?line ok = dets:insert(T, {1, duplicate(100, e)}),
+ ?line dets:safe_fixtable(T, true),
+ ?line ok = dets:match_delete(T, {1, '_'}),
+ ?line ok = dets:insert(T, {1, a, b}),
+ ?line dets:safe_fixtable(T, false),
+ ?line 1 = length(dets:match_object(T, '_')),
+
+ ?line ok = dets:delete_all_objects(T),
+ %% Like the last one, but one extra object.
+ ?line ok = dets:insert(T, {1, duplicate(100, e)}),
+ ?line ok = dets:insert(T, {2, duplicate(100, e)}),
+ ?line dets:safe_fixtable(T, true),
+ ?line ok = dets:match_delete(T, {1, '_'}),
+ ?line ok = dets:insert(T, {1, a, b}),
+ ?line dets:safe_fixtable(T, false),
+ ?line 2 = length(dets:match_object(T, '_')),
+ ?line dets:safe_fixtable(T, true),
+ ?line ok = dets:delete_all_objects(T),
+ ?line true = dets:info(T, fixed),
+ ?line 0 = length(dets:match_object(T, '_')),
+
+ ?line ok = dets:close(T),
+ ?line file:delete(Fname),
+ ?line check_pps(P0),
+ ok.
+
+match_v8(doc) ->
+ ["Matching objects of a fixed table."];
+match_v8(suite) ->
+ [];
+match_v8(Config) when is_list(Config) ->
+ match(Config, 8).
+
+match_v9(doc) ->
+ ["Matching objects of a fixed table."];
+match_v9(suite) ->
+ [];
+match_v9(Config) when is_list(Config) ->
+ match(Config, 9).
+
+match(Config, Version) ->
+ T = match,
+ ?line Fname = filename(match, Config),
+ ?line file:delete(Fname),
+ P0 = pps(),
+
+ Args = [{version, Version}, {file,Fname}, {type, duplicate_bag},
+ {estimated_no_objects,550}],
+ ?line {ok, _} = dets:open_file(T, Args),
+ ?line ok = dets:insert(T, {1, a, b}),
+ ?line ok = dets:insert(T, {1, b, a}),
+ ?line ok = dets:insert(T, {2, a, b}),
+ ?line ok = dets:insert(T, {2, b, a}),
+
+ %% match, badarg
+ MSpec = [{'_',[],['$_']}],
+ ?line {'EXIT', {badarg, [{dets,safe_fixtable,[no_table,true]}|_]}} =
+ (catch dets:match(no_table, '_')),
+ ?line {'EXIT', {badarg, [{dets,match,[T,'_',not_a_number]}|_]}} =
+ (catch dets:match(T, '_', not_a_number)),
+ ?line {EC1, _} = dets:select(T, MSpec, 1),
+ ?line {'EXIT', {badarg, [{dets,match,[EC1]}|_]}} =
+ (catch dets:match(EC1)),
+
+ %% match_object, badarg
+ ?line {'EXIT', {badarg, [{dets,safe_fixtable,[no_table,true]}|_]}} =
+ (catch dets:match_object(no_table, '_')),
+ ?line {'EXIT', {badarg, [{dets,match_object,[T,'_',not_a_number]}|_]}} =
+ (catch dets:match_object(T, '_', not_a_number)),
+ ?line {EC2, _} = dets:select(T, MSpec, 1),
+ ?line {'EXIT', {badarg, [{dets,match_object,[EC2]}|_]}} =
+ (catch dets:match_object(EC2)),
+
+ dets:safe_fixtable(T, true),
+ ?line {[_, _], C1} = dets:match_object(T, '_', 2),
+ ?line {[_, _], C2} = dets:match_object(C1),
+ ?line '$end_of_table' = dets:match_object(C2),
+ ?line {[_, _], C3} = dets:match_object(T, {1, '_', '_'}, 100),
+ ?line '$end_of_table' = dets:match_object(C3),
+ ?line '$end_of_table' = dets:match_object(T, {'_'}, default),
+ ?line dets:safe_fixtable(T, false),
+
+ ?line dets:safe_fixtable(T, true),
+ ?line {[_, _], C30} = dets:match(T, '$1', 2),
+ ?line {[_, _], C31} = dets:match(C30),
+ ?line '$end_of_table' = dets:match(C31),
+ ?line {[_, _], C32} = dets:match(T, {1, '$1', '_'}, 100),
+ ?line '$end_of_table' = dets:match(C32),
+ ?line '$end_of_table' = dets:match(T, {'_'}, default),
+ ?line dets:safe_fixtable(T, false),
+ ?line [[1],[1],[2],[2]] = sort(dets:match(T, {'$1','_','_'})),
+
+ %% delete and insert while chunking
+ %% (this case almost worthless after changes in OTP-5232)
+ ?line ok = dets:match_delete(T, '_'),
+ L500 = seq(1, 500),
+ Fun = fun(X) -> ok = dets:insert(T, {X, a, b, c, d}) end,
+ ?line foreach(Fun, L500),
+ %% Select one object DI in L3 below to be deleted.
+ ?line {_, TmpCont} = dets:match_object(T, '_', 200),
+ ?line {_, TmpCont1} = dets:match_object(TmpCont),
+ ?line {TTL, _} = dets:match_object(TmpCont1),
+ ?line DI = if Version =:= 8 -> last(TTL); Version =:= 9 -> hd(TTL) end,
+ ?line dets:safe_fixtable(T, true),
+ ?line {L1, C20} = dets:match_object(T, '_', 200),
+ ?line true = 200 =< length(L1),
+ ?line ok = dets:match_delete(T, {'2','_','_'}), % no match
+ ?line ok = dets:match_delete(T, DI), % last object
+ Tiny = {1050},
+ ?line ok = dets:insert(T, Tiny),
+ ?line true = member(Tiny, dets:match_object(T, '_')),
+ ?line {_L2, C21} = dets:match_object(C20),
+ ?line {_L3, _C22} = dets:match_object(C21),
+ %% It used to be that Tiny was not visible here, but since the
+ %% scanning of files was changed to inspect the free lists every
+ %% now and then it may very well be visible here.
+ %% ?line false = member(Tiny, _L3),
+ %% DI used to visible here, but the above mentioned modification
+ %% has changed that; it may or may not be visible.
+ %% ?line true = member(DI, _L3),
+ ?line dets:safe_fixtable(T, false),
+ ?line true = dets:member(T, 1050),
+ ?line true = member(Tiny, dets:match_object(T, '_')),
+ ?line false = member(DI, dets:match_object(T, '_')),
+
+ ?line ok = dets:close(T),
+ ?line file:delete(Fname),
+
+ N = 100,
+ ?line {ok, _} = dets:open_file(T, [{estimated_no_objects,N} | Args]),
+ ?line ok = ins(T, N),
+ Obj = {66,{item,number,66}},
+ Spec = {'_','_'},
+ ?line {ok, ObjPos} = dets:where(T, Obj),
+ ?line ok = dets:close(T),
+ %% Damaged object.
+ crash(Fname, ObjPos+12),
+ ?line {ok, _} = dets:open_file(T, Args),
+ ?line io:format("Expect corrupt table:~n"),
+ ?line case ins(T, N) of
+ ok ->
+ ?line bad_object(dets:sync(T), Fname);
+ Else ->
+ ?line bad_object(Else, Fname)
+ end,
+ ?line io:format("Expect corrupt table:~n"),
+ ?line bad_object(dets:match(T, Spec), Fname),
+ ?line io:format("Expect corrupt table:~n"),
+ ?line bad_object(dets:match_delete(T, Spec), Fname),
+ ?line bad_object(dets:close(T), Fname),
+ ?line file:delete(Fname),
+
+ ?line {ok, _} = dets:open_file(T, [{estimated_no_objects,N} | Args]),
+ ?line ok = ins(T, N),
+ ?line {ok, ObjPos2} = dets:where(T, Obj),
+ ?line ok = dets:close(T),
+
+ %% Damaged size of object.
+ %% In v8, there is a next pointer before the size.
+ CrashPos = if Version =:= 8 -> 5; Version =:= 9 -> 1 end,
+ crash(Fname, ObjPos2+CrashPos),
+ ?line {ok, _} = dets:open_file(T, Args),
+ ?line io:format("Expect corrupt table:~n"),
+ ?line case ins(T, N) of
+ ok ->
+ ?line bad_object(dets:sync(T), Fname);
+ Else2 ->
+ ?line bad_object(Else2, Fname)
+ end,
+ %% Just echoes...
+ ?line bad_object(dets:match(T, Spec), Fname),
+ ?line bad_object(dets:match_delete(T, Spec), Fname),
+ ?line bad_object(dets:close(T), Fname),
+ ?line file:delete(Fname),
+
+ ?line {ok, _} = dets:open_file(T, [{estimated_no_objects,N} | Args]),
+ ?line ok = ins(T, N),
+ ?line {ok, ObjPos3} = dets:where(T, Obj),
+ ?line ok = dets:close(T),
+
+ %% match_delete finds an error
+ CrashPos3 = if Version =:= 8 -> 12; Version =:= 9 -> 16 end,
+ crash(Fname, ObjPos3+CrashPos3),
+ ?line {ok, _} = dets:open_file(T, Args),
+ ?line bad_object(dets:match_delete(T, Spec), Fname),
+ ?line bad_object(dets:close(T), Fname),
+ ?line file:delete(Fname),
+
+ %% The key is not fixed, but not all objects with the key are removed.
+ ?line {ok, _} = dets:open_file(T, Args),
+ ?line ok = dets:insert(T, [{1,a},{1,b},{1,c},{1,a},{1,b},{1,c}]),
+ ?line 6 = dets:info(T, size),
+ ?line ok = dets:match_delete(T, {'_',a}),
+ ?line 4 = dets:info(T, size),
+ ?line [{1,b},{1,b},{1,c},{1,c}] =
+ sort(dets:match_object(T,{'_','_'})),
+ ?line ok = dets:close(T),
+ ?line file:delete(Fname),
+
+ ?line check_pps(P0),
+ ok.
+
+select_v8(doc) ->
+ ["Selecting objects of a fixed table."];
+select_v8(suite) ->
+ [];
+select_v8(Config) when is_list(Config) ->
+ select(Config, 8).
+
+select_v9(doc) ->
+ ["Selecting objects of a fixed table."];
+select_v9(suite) ->
+ [];
+select_v9(Config) when is_list(Config) ->
+ select(Config, 9).
+
+select(Config, Version) ->
+ T = select,
+ ?line Fname = filename(select, Config),
+ ?line file:delete(Fname),
+ P0 = pps(),
+
+ ?line Args = [{version,Version}, {file,Fname}, {type, duplicate_bag},
+ {estimated_no_objects,550}],
+ ?line {ok, _} = dets:open_file(T, Args),
+ ?line ok = dets:insert(T, {1, a, b}),
+ ?line ok = dets:insert(T, {1, b, a}),
+ ?line ok = dets:insert(T, {2, a, b}),
+ ?line ok = dets:insert(T, {2, b, a}),
+ ?line ok = dets:insert(T, {3, a, b}),
+ ?line ok = dets:insert(T, {3, b, a}),
+
+ %% badarg
+ MSpec = [{'_',[],['$_']}],
+ ?line {'EXIT', {badarg, [{dets,safe_fixtable,[no_table,true]}|_]}} =
+ (catch dets:select(no_table, MSpec)),
+ ?line {'EXIT', {badarg, [{dets,select,[T,<<17>>]}|_]}} =
+ (catch dets:select(T, <<17>>)),
+ ?line {'EXIT', {badarg, [{dets,select,[T,[]]}|_]}} =
+ (catch dets:select(T, [])),
+ ?line {'EXIT', {badarg, [{dets,select,[T,MSpec,not_a_number]}|_]}} =
+ (catch dets:select(T, MSpec, not_a_number)),
+ ?line {EC, _} = dets:match(T, '_', 1),
+ ?line {'EXIT', {badarg, [{dets,select,[EC]}|_]}} =
+ (catch dets:select(EC)),
+
+ AllSpec = [{'_',[],['$_']}],
+
+ ?line dets:safe_fixtable(T, true),
+ ?line {[_, _], C1} = dets:select(T, AllSpec, 2),
+ ?line {[_, _], C2} = dets:select(C1),
+ ?line {[_, _], C2a} = dets:select(C2),
+ ?line '$end_of_table' = dets:select(C2a),
+ ?line {[_, _], C3} = dets:select(T, [{{1,'_','_'},[],['$_']}], 100),
+ ?line '$end_of_table' = dets:select(C3),
+ ?line '$end_of_table' = dets:select(T, [{{'_'},[],['$_']}], default),
+ ?line dets:safe_fixtable(T, false),
+ Sp1 = [{{1,'_','_'},[],['$_']},{{1,'_','_'},[],['$_']},
+ {{2,'_','_'},[],['$_']}],
+ ?line [_,_,_,_] = dets:select(T, Sp1),
+ Sp2 = [{{1,'_','_'},[],['$_']},{{1,'_','_'},[],['$_']},
+ {{'_','_','_'},[],['$_']}],
+ ?line [_,_,_,_,_,_] = dets:select(T, Sp2),
+
+ AllDeleteSpec = [{'_',[],[true]}],
+ %% delete and insert while chunking
+ %% (this case almost worthless after changes in OTP-5232)
+ ?line 6 = dets:select_delete(T, AllDeleteSpec),
+ L500 = seq(1, 500),
+ Fun = fun(X) -> ok = dets:insert(T, {X, a, b, c, d}) end,
+ ?line foreach(Fun, L500),
+ %% Select one object DI in L3 below to be deleted.
+ ?line {_, TmpCont} = dets:match_object(T, '_', 200),
+ ?line {_, TmpCont1} = dets:match_object(TmpCont),
+ ?line {TTL, _} = dets:match_object(TmpCont1),
+ ?line DI = if Version =:= 8 -> last(TTL); Version =:= 9 -> hd(TTL) end,
+ ?line dets:safe_fixtable(T, true),
+ ?line {L1, C20} = dets:select(T, AllSpec, 200),
+ ?line true = 200 =< length(L1),
+ ?line 0 = dets:select_delete(T, [{{2,'_','_'},[],[true]}]),
+ ?line 1 = dets:select_delete(T, [{DI,[],[true]}]), % last object
+ Tiny = {1050},
+ ?line ok = dets:insert(T, Tiny),
+ ?line true = member(Tiny, dets:select(T, AllSpec)),
+ ?line {_L2, C21} = dets:select(C20),
+ ?line {_L3, _C22} = dets:select(C21),
+ %% It used to be that Tiny was not visible here, but since the
+ %% scanning of files was changed to inspect the free lists every
+ %% now and then it may very well be visible here.
+ %% ?line false = member(Tiny, _L3),
+ %% DI used to visible here, but the above mentioned modification
+ %% has changed that; it may or may not be visible.
+ %% ?line true = member(DI, _L3),
+ ?line true = dets:member(T, 1050),
+ ?line true = member(Tiny, dets:select(T, AllSpec)),
+ ?line false = member(DI, dets:select(T, AllSpec)),
+ ?line dets:safe_fixtable(T, false),
+ ?line true = dets:member(T, 1050),
+ ?line true = member(Tiny, dets:select(T, AllSpec)),
+ ?line false = member(DI, dets:select(T, AllSpec)),
+ ?line ok = dets:close(T),
+ ?line file:delete(Fname),
+
+ %% The key is not fixed, but not all objects with the key are removed.
+ ?line {ok, _} = dets:open_file(T, Args),
+ ?line ok = dets:insert(T, [{1,a},{1,b},{1,c},{1,a},{1,b},{1,c}]),
+ ?line 6 = dets:info(T, size),
+ ?line 2 = dets:select_delete(T, [{{'_',a},[],[true]}]),
+ ?line 4 = dets:info(T, size),
+ ?line [{1,b},{1,b},{1,c},{1,c}] = sort(dets:select(T, AllSpec)),
+ ?line ok = dets:close(T),
+ ?line file:delete(Fname),
+
+ ?line check_pps(P0),
+ ok.
+
+update_counter(doc) ->
+ ["Test update_counter/1."];
+update_counter(suite) ->
+ [];
+update_counter(Config) when is_list(Config) ->
+ T = update_counter,
+ ?line Fname = filename(select, Config),
+ ?line file:delete(Fname),
+ P0 = pps(),
+
+ ?line {'EXIT', {badarg, [{dets,update_counter,[no_table,1,1]}|_]}} =
+ (catch dets:update_counter(no_table, 1, 1)),
+
+ Args = [{file,Fname},{keypos,2}],
+ ?line {ok, _} = dets:open_file(T, [{type,set} | Args]),
+ ?line {'EXIT', {badarg, _}} = (catch dets:update_counter(T, 1, 1)),
+ ?line ok = dets:insert(T, {1,a}),
+ ?line {'EXIT', {badarg, _}} = (catch dets:update_counter(T, 1, 1)),
+ ?line ok = dets:insert(T, {0,1}),
+ ?line {'EXIT', {badarg, _}} = (catch dets:update_counter(T, 1, 1)),
+ ?line ok = dets:insert(T, {0,1,0}),
+ ?line 1 = dets:update_counter(T, 1, 1),
+ ?line 2 = dets:update_counter(T, 1, 1),
+ ?line 6 = dets:update_counter(T, 1, {3,4}),
+ ?line {'EXIT', {badarg, _}} = (catch dets:update_counter(T, 1, {0,3})),
+ ?line ok = dets:close(T),
+ ?line file:delete(Fname),
+
+ ?line {ok, _} = dets:open_file(T, [{type,bag} | Args]),
+ ?line ok = dets:insert(T, {0,1,0}),
+ ?line {'EXIT', {badarg, _}} = (catch dets:update_counter(T, 1, 1)),
+ ?line ok = dets:close(T),
+ ?line file:delete(Fname),
+ ?line check_pps(P0),
+
+ ok.
+
+badarg(doc) ->
+ ["Call some functions with bad arguments."];
+badarg(suite) ->
+ [];
+badarg(Config) when is_list(Config) ->
+ T = badarg,
+ ?line Fname = filename(select, Config),
+ ?line file:delete(Fname),
+ P0 = pps(),
+
+ Args = [{file,Fname},{keypos,3}],
+ ?line {ok, _} = dets:open_file(T, [{type,set} | Args]),
+ % ?line dets:verbose(),
+
+ %% badargs are tested in match, select and fixtable too.
+
+ %% open
+ ?line {'EXIT', {badarg, [{dets,open_file,[{a,tuple},[]]}|_]}} =
+ (catch dets:open_file({a,tuple},[])),
+ ?line {'EXIT', {badarg, [{dets,open_file,[{a,tuple}]}|_]}} =
+ (catch dets:open_file({a,tuple})),
+ ?line {'EXIT', {badarg, [{dets,open_file,[file,[foo]]}|_]}} =
+ (catch dets:open_file(file,[foo])),
+ ?line {'EXIT', {badarg,[{dets,open_file,[{hej,san},[{type,set}|3]]}|_]}} =
+ (catch dets:open_file({hej,san},[{type,set}|3])),
+
+ %% insert
+ ?line {'EXIT', {badarg, [{dets,insert,[no_table,{1,2}]}|_]}} =
+ (catch dets:insert(no_table, {1,2})),
+ ?line {'EXIT', {badarg, [{dets,insert,[no_table,[{1,2}]]}|_]}} =
+ (catch dets:insert(no_table, [{1,2}])),
+ ?line {'EXIT', {badarg, [{dets,insert,[T,{1,2}]}|_]}} =
+ (catch dets:insert(T, {1,2})),
+ ?line {'EXIT', {badarg, [{dets,insert,[T,[{1,2}]]}|_]}} =
+ (catch dets:insert(T, [{1,2}])),
+ ?line {'EXIT', {badarg, [{dets,insert,[T,[{1,2,3}|3]]}|_]}} =
+ (catch dets:insert(T, [{1,2,3} | 3])),
+
+ %% lookup{_keys}
+ ?line {'EXIT', {badarg, [{dets,lookup_keys,[badarg,[]]}|_]}} =
+ (catch dets:lookup_keys(T, [])),
+ ?line {'EXIT', {badarg, [{dets,lookup,[no_table,1]}|_]}} =
+ (catch dets:lookup(no_table, 1)),
+ ?line {'EXIT', {badarg, [{dets,lookup_keys,[T,[1|2]]}|_]}} =
+ (catch dets:lookup_keys(T, [1 | 2])),
+
+ %% member
+ ?line {'EXIT', {badarg, [{dets,member,[no_table,1]}|_]}} =
+ (catch dets:member(no_table, 1)),
+
+ %% sync
+ ?line {'EXIT', {badarg, [{dets,sync,[no_table]}|_]}} =
+ (catch dets:sync(no_table)),
+
+ %% delete{_keys}
+ ?line {'EXIT', {badarg, [{dets,delete,[no_table,1]}|_]}} =
+ (catch dets:delete(no_table, 1)),
+
+ %% delete_object
+ ?line {'EXIT', {badarg, [{dets,delete_object,[no_table,{1,2,3}]}|_]}} =
+ (catch dets:delete_object(no_table, {1,2,3})),
+ ?line {'EXIT', {badarg, [{dets,delete_object,[T,{1,2}]}|_]}} =
+ (catch dets:delete_object(T, {1,2})),
+ ?line {'EXIT', {badarg, [{dets,delete_object,[no_table,[{1,2,3}]]}|_]}} =
+ (catch dets:delete_object(no_table, [{1,2,3}])),
+ ?line {'EXIT', {badarg, [{dets,delete_object,[T,[{1,2}]]}|_]}} =
+ (catch dets:delete_object(T, [{1,2}])),
+ ?line {'EXIT', {badarg, [{dets,delete_object,[T,[{1,2,3}|3]]}|_]}} =
+ (catch dets:delete_object(T, [{1,2,3} | 3])),
+
+ %% first,next,slot
+ ?line {'EXIT', {badarg, [{dets,first,[no_table]}|_]}} =
+ (catch dets:first(no_table)),
+ ?line {'EXIT', {badarg, [{dets,next,[no_table,1]}|_]}} =
+ (catch dets:next(no_table, 1)),
+ ?line {'EXIT', {badarg, [{dets,slot,[no_table,0]}|_]}} =
+ (catch dets:slot(no_table, 0)),
+
+ %% info
+ ?line undefined = dets:info(no_table),
+ ?line undefined = dets:info(no_table, foo),
+ ?line undefined = dets:info(T, foo),
+
+ %% match_delete
+ ?line {'EXIT', {badarg, [{dets,safe_fixtable,[no_table,true]}|_]}} =
+ (catch dets:match_delete(no_table, '_')),
+
+ %% delete_all_objects
+ ?line {'EXIT', {badarg, [{dets,delete_all_objects,[no_table]}|_]}} =
+ (catch dets:delete_all_objects(no_table)),
+
+ %% select_delete
+ MSpec = [{'_',[],['$_']}],
+ ?line {'EXIT', {badarg, [{dets,safe_fixtable,[no_table,true]}|_]}} =
+ (catch dets:select_delete(no_table, MSpec)),
+ ?line {'EXIT', {badarg, [{dets,select_delete,[T, <<17>>]}|_]}} =
+ (catch dets:select_delete(T, <<17>>)),
+
+ %% traverse, fold
+ ?line {'EXIT', {badarg, [{dets,safe_fixtable,[no_table,true]}|_]}} =
+ (catch dets:traverse(no_table, fun(_) -> continue end)),
+ ?line {'EXIT', {badarg, [{dets,safe_fixtable,[no_table,true]}|_]}} =
+ (catch dets:foldl(fun(_, A) -> A end, [], no_table)),
+ ?line {'EXIT', {badarg, [{dets,safe_fixtable,[no_table,true]}|_]}} =
+ (catch dets:foldr(fun(_, A) -> A end, [], no_table)),
+
+ %% close
+ ?line ok = dets:close(T),
+ ?line {error, not_owner} = dets:close(T),
+ ?line {error, not_owner} = dets:close(T),
+
+ %% init_table
+ ?line {'EXIT', {badarg,[{dets,init_table,[no_table,_,[]]}|_]}} =
+ (catch dets:init_table(no_table, fun(X) -> X end)),
+ ?line {'EXIT', {badarg,[{dets,init_table,[no_table,_,[]]}|_]}} =
+ (catch dets:init_table(no_table, fun(X) -> X end, [])),
+
+ %% from_ets
+ Ets = ets:new(ets,[]),
+ ?line {'EXIT', {badarg,[{dets,from_ets,[no_table,_]}|_]}} =
+ (catch dets:from_ets(no_table, Ets)),
+ ets:delete(Ets),
+
+ ?line {ok, T} = dets:open_file(T, Args),
+ ?line {error,incompatible_arguments} =
+ dets:open_file(T, [{type,bag} | Args]),
+ ?line ok = dets:close(T),
+
+ file:delete(Fname),
+ ?line check_pps(P0),
+ ok.
+
+cache_sets_v8(doc) ->
+ ["Test the write cache for sets."];
+cache_sets_v8(suite) ->
+ [];
+cache_sets_v8(Config) when is_list(Config) ->
+ cache_sets(Config, 8).
+
+cache_sets_v9(doc) ->
+ ["Test the write cache for sets."];
+cache_sets_v9(suite) ->
+ [];
+cache_sets_v9(Config) when is_list(Config) ->
+ cache_sets(Config, 9).
+
+cache_sets(Config, Version) ->
+ Small = 2,
+ cache_sets(Config, {0,0}, false, Small, Version),
+ cache_sets(Config, {0,0}, true, Small, Version),
+ cache_sets(Config, {5000,5000}, false, Small, Version),
+ cache_sets(Config, {5000,5000}, true, Small, Version),
+ %% Objects of size greater than 2 kB.
+ Big = 1200,
+ cache_sets(Config, {0,0}, false, Big, Version),
+ cache_sets(Config, {0,0}, true, Big, Version),
+ cache_sets(Config, {5000,5000}, false, Big, Version),
+ cache_sets(Config, {5000,5000}, true, Big, Version),
+ ok.
+
+cache_sets(Config, DelayedWrite, Extra, Sz, Version) ->
+ %% Extra = bool(). Insert tuples until the tested key is not alone.
+ %% Sz = integer(). Size of the inserted tuples.
+
+ T = cache,
+ ?line Fname = filename(cache, Config),
+ ?line file:delete(Fname),
+ P0 = pps(),
+
+ ?line {ok, _} =
+ dets:open_file(T,[{version, Version}, {file,Fname}, {type,set},
+ {delayed_write, DelayedWrite}]),
+
+ Dups = 1,
+ {Key, OtherKeys} =
+ if
+ Extra ->
+ %% Insert enough to get three keys in some slot.
+ ?line dets:safe_fixtable(T, true),
+ insert_objs(T, 1, Sz, Dups);
+ true ->
+ {1,[]}
+ end,
+ Tuple = erlang:make_tuple(Sz, Key),
+ ?line ok = dets:delete(T, Key),
+ ?line ok = dets:sync(T),
+
+ %% The values of keys in the same slot as Key are checked.
+ ?line OtherValues = sort(lookup_keys(T, OtherKeys)),
+
+ ?line ok = dets:insert(T, Tuple),
+ ?line [Tuple] = dets:lookup(T, Key),
+ ?line true = dets:member(T, Key),
+ ?line ok = dets:insert(T, [Tuple,Tuple]),
+ %% If no delay, the cache gets filled immediately, and written.
+ ?line [Tuple] = dets:lookup_keys(T, [Key,a,b,c,d,e,f]),
+ ?line true = dets:member(T, Key),
+
+ %% If delay, this happens without file access.
+ ?line ok = dets:delete(T,Key),
+ ?line ok = dets:insert(T,Tuple),
+ ?line ok = dets:insert(T,Tuple),
+ ?line [Tuple] = dets:lookup(T, Key),
+ ?line true = dets:member(T, Key),
+ ?line ok = dets:sync(T),
+ ?line [Tuple] = dets:lookup(T, Key),
+ ?line true = dets:member(T, Key),
+
+ %% Key's objects are is on file only,
+ %% key 'toto' in the cache (if there is one).
+ ?line ok = dets:delete(T,toto),
+ ?line ok = dets:insert(T,[{toto,b},{toto,b}]),
+ ?line true = sort([Tuple,{toto,b}]) =:=
+ sort(dets:lookup_keys(T, [Key,toto])),
+ ?line true = dets:member(T, toto),
+
+ ?line ok = dets:delete(T, Key),
+ ?line ok = dets:sync(T),
+ ?line false = dets:member(T, Key),
+ ?line Size = dets:info(T, size),
+
+ %% No object with the key on the file.
+ %% Delete, add one object.
+ Size1 = Size + 2,
+ del_and_ins(key, T, Size1, Tuple, Key, 1),
+ del_and_ins(object, T, Size1, Tuple, Key, 1),
+ del_and_ins(both, T, Size1, Tuple, Key, 1),
+
+ %% One object with the key on the file.
+ %% Delete it, add one object.
+ Size2 = Size + 2,
+ del_and_ins(key, T, Size2, Tuple, Key, 1),
+ del_and_ins(object, T, Size2, Tuple, Key, 1),
+ del_and_ins(both, T, Size2, Tuple, Key, 1),
+
+ %% Overwrite an old objekt with exactly the same size.
+ Element = case element(2, Tuple) of
+ 255 -> 254;
+ E -> E + 1
+ end,
+ Tuple2 = setelement(2, Tuple, Element),
+ ?line ok = dets:sync(T),
+ ?line ok = dets:insert(T, Tuple2),
+ ?line [Tuple2] = dets:lookup(T, Key),
+ ?line true = dets:member(T, Key),
+ ?line ok = dets:sync(T),
+ ?line [Tuple2] = dets:lookup(T, Key),
+ ?line true = dets:member(T, Key),
+
+ ?line ok = dets:insert(T, {3,a}),
+ ?line ok = dets:insert(T, {3,b}),
+ ?line ok = dets:delete_object(T, {3,c}),
+ ?line ok = dets:delete_object(T, {3,d}),
+ ?line [{3,b}] = dets:lookup(T, 3),
+
+ ?line ok = dets:delete(T, 3),
+ ?line ok = dets:delete_object(T, {3,c}),
+ ?line ok = dets:delete_object(T, {3,d}),
+ ?line [] = dets:lookup(T, 3),
+
+ ?line OtherValues = sort(lookup_keys(T, OtherKeys)),
+ if
+ Extra ->
+ %% Let the table grow a while, if it needs to.
+ ?line All1 = get_all_objects(T),
+ ?line dets:safe_fixtable(T, false),
+ ?line timer:sleep(1000),
+ ?line OtherValues = sort(lookup_keys(T, OtherKeys)),
+ ?line dets:safe_fixtable(T, true),
+ ?line All2 = get_all_objects(T),
+ ?line FAll2 = get_all_objects_fast(T),
+ ?line true = sort(All2) =:= sort(FAll2),
+ case symdiff(All1, All2) of
+ {[],[]} -> ok;
+ {X,Y} ->
+ NoBad = length(X) + length(Y),
+ test_server:fail({sets,DelayedWrite,Extra,Sz,NoBad})
+ end;
+ true ->
+ ok
+ end,
+ ?line ok = dets:close(T),
+
+ file:delete(Fname),
+ ?line check_pps(P0),
+ ok.
+
+cache_bags_v8(doc) ->
+ ["Test the write cache for bags."];
+cache_bags_v8(suite) ->
+ [];
+cache_bags_v8(Config) when is_list(Config) ->
+ cache_bags(Config, 8).
+
+cache_bags_v9(doc) ->
+ ["Test the write cache for bags."];
+cache_bags_v9(suite) ->
+ [];
+cache_bags_v9(Config) when is_list(Config) ->
+ cache_bags(Config, 9).
+
+cache_bags(Config, Version) ->
+ Small = 2,
+ cache_bags(Config, {0,0}, false, Small, Version),
+ cache_bags(Config, {0,0}, true, Small, Version),
+ cache_bags(Config, {5000,5000}, false, Small, Version),
+ cache_bags(Config, {5000,5000}, true, Small, Version),
+ %% Objects of size greater than 2 kB.
+ Big = 1200,
+ cache_bags(Config, {0,0}, false, Big, Version),
+ cache_bags(Config, {0,0}, true, Big, Version),
+ cache_bags(Config, {5000,5000}, false, Big, Version),
+ cache_bags(Config, {5000,5000}, true, Big, Version),
+ ok.
+
+cache_bags(Config, DelayedWrite, Extra, Sz, Version) ->
+ %% Extra = bool(). Insert tuples until the tested key is not alone.
+ %% Sz = integer(). Size of the inserted tuples.
+
+ T = cache,
+ ?line Fname = filename(cache, Config),
+ ?line file:delete(Fname),
+ P0 = pps(),
+
+ ?line {ok, _} =
+ dets:open_file(T,[{version, Version}, {file,Fname}, {type,bag},
+ {delayed_write, DelayedWrite}]),
+
+ Dups = 1,
+ {Key, OtherKeys} =
+ if
+ Extra ->
+ %% Insert enough to get three keys in some slot.
+ ?line dets:safe_fixtable(T, true),
+ insert_objs(T, 1, Sz, Dups);
+ true ->
+ {1,[]}
+ end,
+ Tuple = erlang:make_tuple(Sz, Key),
+ ?line ok = dets:delete(T, Key),
+ ?line ok = dets:sync(T),
+
+ %% The values of keys in the same slot as Key are checked.
+ ?line OtherValues = sort(lookup_keys(T, OtherKeys)),
+
+ ?line ok = dets:insert(T, Tuple),
+ ?line [Tuple] = dets:lookup(T, Key),
+ ?line true = dets:member(T, Key),
+ ?line ok = dets:insert(T, [Tuple,Tuple]),
+ %% If no delay, the cache gets filled immediately, and written.
+ ?line [Tuple] = dets:lookup_keys(T, [Key,a,b,c,d,e,f]),
+ ?line true = dets:member(T, Key),
+
+ %% If delay, this happens without file access.
+ %% (This is no longer true; cache lookup has been simplified.)
+ ?line ok = dets:delete(T,Key),
+ ?line ok = dets:insert(T,Tuple),
+ ?line ok = dets:insert(T,Tuple),
+ ?line [Tuple] = dets:lookup(T, Key),
+ ?line true = dets:member(T, Key),
+ ?line ok = dets:sync(T),
+ ?line [Tuple] = dets:lookup(T, Key),
+ ?line true = dets:member(T, Key),
+
+ %% Key's objects are is on file only,
+ %% key toto in the cache (if there is one).
+ ?line ok = dets:delete(T,toto),
+ ?line false = dets:member(T, toto),
+ ?line ok = dets:insert(T,[{toto,b},{toto,b}]),
+ ?line true = sort([Tuple,{toto,b}]) =:=
+ sort(dets:lookup_keys(T, [Key,toto])),
+ ?line true = dets:member(T, toto),
+
+ ?line ok = dets:delete(T, Key),
+ ?line ok = dets:sync(T),
+ ?line Size = dets:info(T, size),
+
+ %% No object with the key on the file.
+ %% Delete, add one object.
+ Size1 = Size + 2,
+ del_and_ins(key, T, Size1, Tuple, Key, 1),
+ del_and_ins(object, T, Size1, Tuple, Key, 1),
+ del_and_ins(both, T, Size1, Tuple, Key, 1),
+
+ %% One object with the key on the file.
+ %% Delete it, add one object.
+ Size2 = Size + 2,
+ del_and_ins(key, T, Size2, Tuple, Key, 1),
+ del_and_ins(object, T, Size2, Tuple, Key, 1),
+ del_and_ins(both, T, Size2, Tuple, Key, 1),
+
+ %% Overwrite an objekt on file with the same object.
+ ?line ok = dets:insert(T, Tuple),
+ ?line ok = dets:sync(T),
+ ?line [Tuple2] = dets:lookup(T, Key),
+ ?line true = dets:member(T, Key),
+ ?line ok = dets:insert(T, Tuple),
+ ?line ok = dets:sync(T),
+ ?line [Tuple2] = dets:lookup(T, Key),
+ ?line true = dets:member(T, Key),
+
+ %% A mix of insert and delete.
+ ?line ok = dets:delete(T, Key),
+ ?line ok = dets:sync(T),
+ ?line ok = dets:delete(T, Key),
+ ?line ok = dets:insert(T, {Key,foo}),
+ ?line ok = dets:insert(T, {Key,bar}),
+ ?line [{Key,bar},{Key,foo}] = sort(dets:lookup(T, Key)),
+ ?line true = dets:member(T, Key),
+ ?line ok = dets:delete_object(T, {Key,foo}),
+ ?line ok = dets:insert(T, {Key,kar}),
+ ?line [{Key,bar},{Key,kar}] = sort(dets:lookup(T, Key)),
+ ?line true = dets:member(T, Key),
+ ?line ok = dets:insert(T, [{Key,kar},{Key,kar}]),
+ ?line [{Key,bar},{Key,kar}] = sort(dets:lookup(T, Key)),
+ ?line true = dets:member(T, Key),
+ ?line ok = dets:delete_object(T, {Key,bar}),
+ ?line ok = dets:delete_object(T, {Key,kar}),
+ ?line [] = dets:lookup(T, Key),
+ ?line false = dets:member(T, Key),
+ ?line ok = dets:sync(T),
+ ?line [] = dets:lookup(T, Key),
+ ?line false = dets:member(T, Key),
+
+ ?line OtherValues = sort(lookup_keys(T, OtherKeys)),
+ if
+ Extra ->
+ %% Let the table grow for a while, if it needs to.
+ ?line All1 = get_all_objects(T),
+ ?line dets:safe_fixtable(T, false),
+ ?line timer:sleep(1200),
+ ?line OtherValues = sort(lookup_keys(T, OtherKeys)),
+ ?line dets:safe_fixtable(T, true),
+ ?line All2 = get_all_objects(T),
+ ?line FAll2 = get_all_objects_fast(T),
+ ?line true = sort(All2) =:= sort(FAll2),
+ case symdiff(All1, All2) of
+ {[],[]} -> ok;
+ {X,Y} ->
+ NoBad = length(X) + length(Y),
+ test_server:fail({bags,DelayedWrite,Extra,Sz,NoBad})
+ end;
+ true ->
+ ok
+ end,
+ ?line ok = dets:close(T),
+ file:delete(Fname),
+
+ %% Second object of a key added and looked up simultaneously.
+ R1 = {index_test,1,2,3,4},
+ R2 = {index_test,2,2,13,14},
+ R3 = {index_test,1,12,13,14},
+ ?line {ok, _} = dets:open_file(T,[{version,Version},{type,bag},
+ {keypos,2},{file,Fname}]),
+ ?line ok = dets:insert(T,R1),
+ ?line ok = dets:sync(T),
+ ?line ok = dets:insert(T,R2),
+ ?line ok = dets:sync(T),
+ ?line ok = dets:insert(T,R3),
+ ?line [R1,R3] = sort(dets:lookup(T,1)),
+ ?line true = dets:member(T, 1),
+ ?line [R1,R3] = sort(dets:lookup(T,1)),
+ ?line true = dets:member(T, 1),
+ ?line ok = dets:close(T),
+ file:delete(Fname),
+
+ ?line check_pps(P0),
+ ok.
+
+cache_duplicate_bags_v8(doc) ->
+ ["Test the write cache for duplicate bags."];
+cache_duplicate_bags_v8(suite) ->
+ [];
+cache_duplicate_bags_v8(Config) when is_list(Config) ->
+ cache_duplicate_bags(Config, 8).
+
+cache_duplicate_bags_v9(doc) ->
+ ["Test the write cache for duplicate bags."];
+cache_duplicate_bags_v9(suite) ->
+ [];
+cache_duplicate_bags_v9(Config) when is_list(Config) ->
+ cache_duplicate_bags(Config, 9).
+
+cache_duplicate_bags(Config, Version) ->
+ Small = 2,
+ cache_dup_bags(Config, {0,0}, false, Small, Version),
+ cache_dup_bags(Config, {0,0}, true, Small, Version),
+ cache_dup_bags(Config, {5000,5000}, false, Small, Version),
+ cache_dup_bags(Config, {5000,5000}, true, Small, Version),
+ %% Objects of size greater than 2 kB.
+ Big = 1200,
+ cache_dup_bags(Config, {0,0}, false, Big, Version),
+ cache_dup_bags(Config, {0,0}, true, Big, Version),
+ cache_dup_bags(Config, {5000,5000}, false, Big, Version),
+ cache_dup_bags(Config, {5000,5000}, true, Big, Version).
+
+cache_dup_bags(Config, DelayedWrite, Extra, Sz, Version) ->
+ %% Extra = bool(). Insert tuples until the tested key is not alone.
+ %% Sz = integer(). Size of the inserted tuples.
+
+ T = cache,
+ ?line Fname = filename(cache, Config),
+ ?line file:delete(Fname),
+ P0 = pps(),
+
+ ?line {ok, _} =
+ dets:open_file(T,[{version, Version}, {file,Fname},
+ {type,duplicate_bag},
+ {delayed_write, DelayedWrite}]),
+
+ Dups = 2,
+ {Key, OtherKeys} =
+ if
+ Extra ->
+ %% Insert enough to get three keys in some slot.
+ ?line dets:safe_fixtable(T, true),
+ insert_objs(T, 1, Sz, Dups);
+ true ->
+ {1,[]}
+ end,
+ Tuple = erlang:make_tuple(Sz, Key),
+ ?line ok = dets:delete(T, Key),
+ ?line ok = dets:sync(T),
+ ?line false = dets:member(T, Key),
+
+ %% The values of keys in the same slot as Key are checked.
+ ?line OtherValues = sort(lookup_keys(T, OtherKeys)),
+
+ ?line ok = dets:insert(T, Tuple),
+ ?line [Tuple] = dets:lookup(T, Key),
+ ?line true = dets:member(T, Key),
+ ?line ok = dets:insert(T, [Tuple,Tuple]),
+ %% If no delay, the cache gets filled immediately, and written.
+ ?line [Tuple,Tuple,Tuple] = dets:lookup_keys(T, [Key,a,b,c,d,e,f]),
+ ?line true = dets:member(T, Key),
+
+ %% If delay, this happens without file access.
+ %% (This is no longer true; cache lookup has been simplified.)
+ ?line ok = dets:delete(T,Key),
+ ?line ok = dets:insert(T,Tuple),
+ ?line ok = dets:insert(T,Tuple),
+ ?line [Tuple,Tuple] = dets:lookup(T, Key),
+ ?line true = dets:member(T, Key),
+ ?line ok = dets:sync(T),
+ ?line [Tuple,Tuple] = dets:lookup(T, Key),
+ ?line true = dets:member(T, Key),
+
+ %% One object in the cache, one on the file.
+ ?line ok = dets:delete(T,Key),
+ ?line ok = dets:insert(T,Tuple),
+ ?line ok = dets:sync(T),
+ ?line ok = dets:insert(T,Tuple),
+ ?line true = dets:member(T, Key), % should not read the file, but it does..
+
+ %% Key's objects are is on file only,
+ %% key toto in the cache (if there is one).
+ ?line ok = dets:delete(T,toto),
+ ?line ok = dets:insert(T,[{toto,b},{toto,b}]),
+ ?line true = sort([Tuple,Tuple,{toto,b},{toto,b}]) =:=
+ sort(dets:lookup_keys(T, [Key,toto])),
+ ?line true = dets:member(T, toto),
+ ?line Size = dets:info(T, size),
+
+ %% Two objects with the same key on the file.
+ %% Delete them, add two objects.
+ del_and_ins(key, T, Size, Tuple, Key, 2),
+
+ del_and_ins(object, T, Size, Tuple, Key, 2),
+ del_and_ins(both, T, Size, Tuple, Key, 2),
+
+ %% Two objects with the same key on the file.
+ %% Delete them, add three objects.
+ del_and_ins(key, T, Size, Tuple, Key, 3),
+ del_and_ins(object, T, Size, Tuple, Key, 3),
+ del_and_ins(both, T, Size, Tuple, Key, 3),
+
+ %% Two objects with the same key on the file.
+ %% Delete them, add one object.
+ del_and_ins(key, T, Size, Tuple, Key, 1),
+ del_and_ins(object, T, Size, Tuple, Key, 1),
+ del_and_ins(both, T, Size, Tuple, Key, 1),
+
+ ?line OtherValues = sort(lookup_keys(T, OtherKeys)),
+ if
+ Extra ->
+ %% Let the table grow for a while, if it needs to.
+ ?line All1 = get_all_objects(T),
+ ?line dets:safe_fixtable(T, false),
+ ?line timer:sleep(1200),
+ ?line OtherValues = sort(lookup_keys(T, OtherKeys)),
+ ?line dets:safe_fixtable(T, true),
+ ?line All2 = get_all_objects(T),
+ ?line FAll2 = get_all_objects_fast(T),
+ ?line true = sort(All2) =:= sort(FAll2),
+ case symdiff(All1, All2) of
+ {[],[]} -> ok;
+ {X,Y} ->
+ NoBad = length(X) + length(Y),
+ test_server:fail({dup_bags,DelayedWrite,Extra,Sz,NoBad})
+ end;
+ true ->
+ ok
+ end,
+ ?line ok = dets:close(T),
+
+ file:delete(Fname),
+ ?line check_pps(P0),
+ ok.
+
+lookup_keys(_T, []) ->
+ [];
+lookup_keys(T, Keys) ->
+ dets:lookup_keys(T, Keys).
+
+del_and_ins(W, T, Size, Obj, Key, N) ->
+ case W of
+ object ->
+ ?line ok = dets:delete_object(T, Obj);
+ key ->
+
+ ?line ok = dets:delete(T, Key);
+ both ->
+ ?line ok = dets:delete(T, Key),
+ ?line ok = dets:delete_object(T, Obj)
+ end,
+ Objs = duplicate(N, Obj),
+ ?line [] = dets:lookup(T, Key),
+ ?line ok = dets:insert(T, Objs),
+ ?line Objs = dets:lookup_keys(T, [snurrespratt,Key]),
+ ?line true = Size + length(Objs)-2 =:= dets:info(T, size),
+ ?line Objs = dets:lookup(T, Key).
+
+
+insert_objs(T, N, Sz, Dups) ->
+ Seq = seq(N,N+255),
+ L0 = map(fun(I) -> erlang:make_tuple(Sz, I) end, Seq),
+ L = append(duplicate(Dups, L0)),
+ ?line ok = dets:insert(T, L),
+ ?line case search_slot(T, 0) of
+ false ->
+ insert_objs(T, N+256, Sz, Dups);
+ Keys ->
+ Keys
+ end.
+
+search_slot(T, I) ->
+ ?line case dets:slot(T, I) of
+ '$end_of_table' ->
+ false;
+ Objs ->
+ case usort(map(fun(X) -> element(1, X) end, Objs)) of
+ [_, Key, _ | _] = Keys0 ->
+ Keys = delete(Key, Keys0),
+ {Key, Keys};
+ _ ->
+ search_slot(T, I+1)
+ end
+ end.
+
+symdiff(L1, L2) ->
+ {X, _, Y} =
+ sofs:symmetric_partition(sofs:set(L1), sofs:set(L2)),
+ {sofs:to_external(X), sofs:to_external(Y)}.
+
+otp_4208(doc) ->
+ ["Read only table and traversal caused crash."];
+otp_4208(suite) ->
+ [];
+otp_4208(Config) when is_list(Config) ->
+ Tab = otp_4208,
+ ?line FName = filename(Tab, Config),
+ Expected = sort([{3,ghi,12},{1,abc,10},{4,jkl,13},{2,def,11}]),
+
+ file:delete(FName),
+ ?line {ok, Tab} = dets:open_file(Tab, [{file,FName}]),
+ ?line ok = dets:insert(Tab, [{1,abc,10},{2,def,11},{3,ghi,12},{4,jkl,13}]),
+ ?line Expected = sort(dets:traverse(Tab, fun(X) -> {continue, X} end)),
+ ?line ok = dets:close(Tab),
+
+ ?line {ok, Tab} = dets:open_file(Tab, [{access, read},{file,FName}]),
+ ?line Expected = sort(dets:traverse(Tab, fun(X) -> {continue, X} end)),
+ ?line ok = dets:close(Tab),
+ file:delete(FName),
+
+ ok.
+
+otp_4989(doc) ->
+ ["Read only table and growth."];
+otp_4989(suite) ->
+ [];
+otp_4989(Config) when is_list(Config) ->
+ Tab = otp_4989,
+ ?line FName = filename(Tab, Config),
+
+ %% Do exactly as in the error report.
+ ?line _Ets = ets:new(Tab, [named_table]),
+ ets_init(Tab, 100000),
+ ?line {ok, Tab} =
+ dets:open_file(Tab, [{access, read_write}, {file,FName}, {keypos,2}]),
+ ?line ok = dets:from_ets(Tab, Tab),
+ ?line ok = dets:close(Tab),
+ %% Restore.
+ ?line {ok, Tab} =
+ dets:open_file(Tab, [{access, read}, {keypos, 2}, {file, FName}]),
+ ?line true = ets:delete_all_objects(Tab),
+ ?line true = ets:from_dets(Tab, Tab),
+ ?line ok = dets:close(Tab),
+ ets:delete(Tab),
+ file:delete(FName),
+ ok.
+
+ets_init(_Tab, 0) ->
+ ok;
+ets_init(Tab, N) ->
+ ets:insert(Tab, {N,N}),
+ ets_init(Tab, N - 1).
+
+many_clients(doc) ->
+ ["Several clients accessing a table simultaneously."];
+many_clients(suite) ->
+ [];
+many_clients(Config) when is_list(Config) ->
+ Tab = many_clients,
+ ?line FName = filename(Tab, Config),
+
+ Server = self(),
+
+ ?line file:delete(FName),
+ P0 = pps(),
+ ?line {ok, _} = dets:open_file(Tab,[{file, FName},{version,9}]),
+ ?line [P1,P2,P3,P4] = new_clients(4, Tab),
+
+ %% dets:init_table/2 is used for making sure that all processes
+ %% start sending requests before the Dets process begins to handle
+ %% them; the requests arrive "in parallel".
+
+ %% Four processes accessing the same table at almost the same time.
+
+ %% One key is read, updated, and read again.
+ Seq1 = [{P1,[{lookup,1,[{1,a}]}]}, {P2,[{insert,{1,b}}]},
+ {P3,[{lookup,1,[{1,b}]}]}, {P4,[{lookup,1,[{1,b}]}]}],
+ ?line atomic_requests(Server, Tab, [[{1,a}]], Seq1),
+ ?line true = get_replies([{P1,ok}, {P2,ok}, {P3,ok}, {P4,ok}]),
+
+ %% Different keys read by different processes
+ Seq2 = [{P1,[{member,1,true}]}, {P2,[{lookup,2,[{2,b}]}]},
+ {P3,[{lookup,1,[{1,a}]}]}, {P4,[{lookup,3,[{3,c}]}]}],
+ ?line atomic_requests(Server, Tab, [[{1,a},{2,b},{3,c}]], Seq2),
+ ?line true = get_replies([{P1,ok}, {P2,ok}, {P3,ok}, {P4,ok}]),
+
+ %% Reading deleted key.
+ Seq3 = [{P1,[{delete_key,2}]}, {P2,[{lookup,1,[{1,a}]}]},
+ {P3,[{lookup,1,[{1,a}]}]}, {P4,[{member,2,false}]}],
+ ?line atomic_requests(Server, Tab, [[{1,a},{2,b},{3,c}]], Seq3),
+ ?line true = get_replies([{P1,ok}, {P2,ok}, {P3,ok}, {P4,ok}]),
+
+ %% Inserting objects.
+ Seq4 = [{P1,[{insert,[{1,a},{2,b}]}]}, {P2,[{insert,[{2,c},{3,a}]}]},
+ {P3,[{insert,[{3,b},{4,d}]}]},
+ {P4,[{lookup_keys,[1,2,3,4],[{1,a},{2,c},{3,b},{4,d}]}]}],
+ ?line atomic_requests(Server, Tab, [], Seq4),
+ ?line true = get_replies([{P1,ok}, {P2,ok}, {P3,ok}, {P4,ok}]),
+
+ %% Deleting objects.
+ Seq5 = [{P1,[{delete_object,{1,a}}]}, {P2,[{delete_object,{1,a}}]},
+ {P3,[{delete_object,{3,c}}]},
+ {P4,[{lookup_keys,[1,2,3,4],[{2,b}]}]}],
+ ?line atomic_requests(Server, Tab, [[{1,a},{2,b},{3,c}]], Seq5),
+ ?line true = get_replies([{P1,ok}, {P2,ok}, {P3,ok}, {P4,ok}]),
+
+ %% Some request not streamed.
+ Seq6 = [{P1,[{lookup,1,[{1,a}]}]}, {P2,[{info,size,3}]},
+ {P3,[{lookup,1,[{1,a}]}]}, {P4,[{info,size,3}]}],
+ ?line atomic_requests(Server, Tab, [[{1,a},{2,b},{3,c}]], Seq6),
+ ?line true = get_replies([{P1,ok}, {P2,ok}, {P3,ok}, {P4,ok}]),
+
+ %% Some request not streamed.
+ Seq7 = [{P1,[{insert,[{3,a}]}]}, {P2,[{insert,[{3,b}]}]},
+ {P3,[{delete_object,{3,c}}]},
+ {P4,[{lookup,3,[{3,b}]}]}],
+ ?line atomic_requests(Server, Tab, [[{3,c}]], Seq7),
+ ?line true = get_replies([{P1,ok}, {P2,ok}, {P3,ok}, {P4,ok}]),
+
+ ?line put_requests(Server, [{P1,stop},{P2,stop},{P3,stop},{P4,stop}]),
+ ?line ok = dets:close(Tab),
+ ?line file:delete(FName),
+
+ %% Check that errors are handled correctly by the streaming operators.
+ ?line {ok, _} = dets:open_file(Tab,[{file, FName},{version,9}]),
+ ?line ok = ins(Tab, 100),
+ Obj = {66,{item,number,66}},
+ ?line {ok, ObjPos} = dets:where(Tab, Obj),
+ ?line ok = dets:close(Tab),
+ %% Damaged object.
+ crash(FName, ObjPos+12),
+ ?line {ok, _} = dets:open_file(Tab,[{file, FName},{version,9}]),
+ ?line BadObject1 = dets:lookup_keys(Tab, [65,66,67,68,69]),
+ ?line bad_object(BadObject1, FName),
+ ?line _Error = dets:close(Tab),
+ ?line file:delete(FName),
+
+ ?line check_pps(P0),
+
+ ok.
+
+%% Tab is initiated with the objects in Objs. Objs = [[object()]].
+atomic_requests(Server, Tab, Objs, Req) ->
+ ok = dets:init_table(Tab, atomic_requests(Server, Objs, Req)).
+
+atomic_requests(Server, L, Req) ->
+ fun(close) ->
+ ok;
+ (read) when [] =:= L ->
+ put_requests(Server, Req),
+ end_of_input;
+ (read) ->
+ [E | Es] = L,
+ {E, atomic_requests(Server, Es, Req)}
+ end.
+
+put_requests(Server, L) ->
+ lists:foreach(fun({Pid,R}) -> Pid ! {Server,R}, timer:sleep(1) end, L).
+
+get_replies(L) ->
+ lists:all(fun({Pid,Reply}) -> Reply =:= get_reply(Pid) end, L).
+
+get_reply(Pid) ->
+ ?line receive {Pid, Reply} -> Reply end.
+
+new_clients(0, _Tab) ->
+ [];
+new_clients(N, Tab) ->
+ [new_client(Tab) | new_clients(N-1, Tab)].
+
+new_client(Tab) ->
+ spawn(?MODULE, client, [self(), Tab]).
+
+client(S, Tab) ->
+ receive
+ {S, stop} ->
+ exit(normal);
+ {S, ToDo} ->
+ ?line Reply = eval(ToDo, Tab),
+ case Reply of
+ {error, _} -> io:format("~p: ~p~n", [self(), Reply]);
+ _ -> ok
+ end,
+ S ! {self(), Reply}
+ end,
+ client(S, Tab).
+
+eval([], _Tab) ->
+ ok;
+eval([sync | L], Tab) ->
+ ?line case dets:sync(Tab) of
+ ok -> eval(L, Tab);
+ Error -> {error, {sync,Error}}
+ end;
+eval([{insert,Stuff} | L], Tab) ->
+ ?line case dets:insert(Tab, Stuff) of
+ ok -> eval(L, Tab);
+ Error -> {error, {insert,Stuff,Error}}
+ end;
+eval([{lookup,Key,Expected} | L], Tab) ->
+ ?line case dets:lookup(Tab, Key) of
+ Expected -> eval(L, Tab);
+ Else -> {error, {lookup,Key,Expected,Else}}
+ end;
+eval([{lookup_keys,Keys,Expected} | L], Tab) ->
+ %% Time order is destroyed...
+ ?line case dets:lookup_keys(Tab, Keys) of
+ R when is_list(R) ->
+ case lists:sort(Expected) =:= lists:sort(R) of
+ true -> eval(L, Tab);
+ false -> {error, {lookup_keys,Keys,Expected,R}}
+ end;
+ Else -> {error, {lookup_keys,Keys,Expected,Else}}
+ end;
+eval([{member,Key,Expected} | L], Tab) ->
+ ?line case dets:member(Tab, Key) of
+ Expected -> eval(L, Tab);
+ Else -> {error, {member,Key,Expected,Else}}
+ end;
+eval([{delete_key,Key} | L], Tab) ->
+ ?line case dets:delete(Tab, Key) of
+ ok -> eval(L, Tab);
+ Else -> {error, {delete_key,Key,Else}}
+ end;
+eval([{delete_object,Object} | L], Tab) ->
+ ?line case dets:delete_object(Tab, Object) of
+ ok -> eval(L, Tab);
+ Else -> {error, {delete_object,Object,Else}}
+ end;
+eval([{info,Tag,Expected} | L], Tab) ->
+ ?line case dets:info(Tab, Tag) of
+ Expected -> eval(L, Tab);
+ Else -> {error, {info,Tag,Else,Expected}}
+ end;
+eval(Else, _Tab) ->
+ {error, {bad_request,Else}}.
+
+otp_4906(doc) ->
+ ["More than 128k keys caused crash."];
+otp_4906(suite) ->
+ [];
+otp_4906(Config) when is_list(Config) ->
+ N = 256*512 + 400,
+ Tab = otp_4906,
+ ?line FName = filename(Tab, Config),
+
+ file:delete(FName),
+ ?line {ok, Tab} = dets:open_file(Tab, [{file, FName}]),
+ ?line ok = ins_small(Tab, 0, N),
+ ?line ok = dets:close(Tab),
+ ?line {ok, Tab} = dets:open_file(Tab, [{file, FName}]),
+ ?line ok = read_4906(Tab, N-1),
+ ?line ok = dets:close(Tab),
+ file:delete(FName),
+
+ %% If the (only) process fixing a table updates the table, the
+ %% process will no longer be punished with a 1 ms delay (hm, the
+ %% server is delayed, it should be the client...). In this example
+ %% the writing process *is* delayed.
+ ?line {ok,Tab} = dets:open_file(Tab, [{file,FName}]),
+ Parent = self(),
+ FixPid = spawn_link(fun() ->
+ dets:safe_fixtable(Tab, true),
+ receive {Parent, stop} -> ok end
+ end),
+ ?line ok = ins_small(Tab, 0, 1000),
+ FixPid ! {Parent, stop},
+ timer:sleep(1),
+ ?line ok = dets:close(Tab),
+ file:delete(FName),
+ ok.
+
+read_4906(_T, N) when N < 0 ->
+ ok;
+read_4906(T, N) ->
+ ?line [_] = dets:lookup(T, N),
+ read_4906(T, N-1).
+
+ins_small(_T, I, N) when I =:= N ->
+ ok;
+ins_small(T, I, N) ->
+ ?line ok = dets:insert(T, {I}),
+ ins_small(T, I+1, N).
+
+otp_5402(doc) ->
+ ["Unwritable ramfile caused krasch."];
+otp_5402(suite) ->
+ [];
+otp_5402(Config) when is_list(Config) ->
+ Tab = otp_5402,
+ ?line File = filename:join([cannot, write, this, file]),
+
+ %% close
+ ?line{ok, T} = dets:open_file(Tab, [{ram_file,true},
+ {file, File}]),
+ ?line ok = dets:insert(T, {1,a}),
+ ?line {error,{file_error,_,_}} = dets:close(T),
+
+ %% sync
+ ?line {ok, T} = dets:open_file(Tab, [{ram_file,true},
+ {file, File}]),
+ ?line ok = dets:insert(T, {1,a}),
+ ?line {error,{file_error,_,_}} = dets:sync(T),
+ ?line {error,{file_error,_,_}} = dets:close(T),
+
+ %% auto_save
+ ?line {ok, T} = dets:open_file(Tab, [{ram_file,true},
+ {auto_save, 2000},
+ {file, File}]),
+ ?line ok = dets:insert(T, {1,a}),
+ ?line timer:sleep(5000),
+ ?line {error,{file_error,_,_}} = dets:close(T),
+ ok.
+
+simultaneous_open(doc) ->
+ ["Several clients open and close tables simultaneously."];
+simultaneous_open(suite) ->
+ [];
+simultaneous_open(Config) ->
+ Tab = sim_open,
+ File = filename(Tab, Config),
+
+ ?line ok = monit(Tab, File),
+ ?line ok = kill_while_repairing(Tab, File),
+ ?line ok = kill_while_init(Tab, File),
+ ?line ok = open_ro(Tab, File),
+ ?line ok = open_w(Tab, File, 0, Config),
+ ?line ok = open_w(Tab, File, 100, Config),
+ ok.
+
+%% One process logs and another process closes the log. Before
+%% monitors were used, this would make the client never return.
+monit(Tab, File) ->
+ file:delete(File),
+ {ok, Tab} = dets:open_file(Tab, [{file,File}]),
+ F1 = fun() -> dets:close(Tab) end,
+ F2 = fun() -> {'EXIT', {badarg, _}} = do_log(Tab) end,
+ spawn(F2),
+ timer:sleep(100),
+ spawn(F1),
+ dets:close(Tab),
+ file:delete(File),
+ ok.
+
+do_log(Tab) ->
+ case catch dets:insert(Tab, {hej,san,sa}) of
+ ok -> do_log(Tab);
+ Else -> Else
+ end.
+
+%% Kill the Dets process while repair is in progress.
+kill_while_repairing(Tab, File) ->
+ ?line create_opened_log(File),
+ Delay = 1000,
+ dets:start(),
+ Parent = self(),
+ Ps = processes(),
+ F = fun() ->
+ R = (catch dets:open_file(Tab, [{file,File}])),
+ timer:sleep(Delay),
+ Parent ! {self(), R}
+ end,
+ ?line P1 = spawn(F), % will repair
+ timer:sleep(100),
+ ?line P2 = spawn(F), % pending...
+ ?line P3 = spawn(F), % pending...
+ ?line DetsPid = find_dets_pid([P1, P2, P3 | Ps]),
+ exit(DetsPid, kill),
+
+ ?line receive {P1,R1} -> {'EXIT', {dets_process_died, _}} = R1 end,
+ ?line receive {P2,R2} -> {ok, _} = R2 end,
+ ?line receive {P3,R3} -> {ok, _} = R3 end,
+
+ timer:sleep(200),
+ case dets:info(Tab) of
+ undefined ->
+ ok;
+ _Info ->
+ timer:sleep(5000),
+ ?line undefined = dets:info(Tab)
+ end,
+
+ file:delete(File),
+ ok.
+
+find_dets_pid(P0) ->
+ case lists:sort(processes() -- P0) of
+ [P, _] -> P;
+ _ -> timer:sleep(100), find_dets_pid(P0)
+ end.
+
+%% Kill the Dets process when there are users and an on-going
+%% initiailization.
+kill_while_init(Tab, File) ->
+ file:delete(File),
+ Parent = self(),
+ F = fun() ->
+ R = dets:open_file(Tab, [{file,File}]),
+ Parent ! {self(), R},
+ receive {Parent, die} -> ok end,
+ {error, not_owner} = dets:close(Tab)
+ end,
+ ?line P1 = spawn(F),
+ ?line P2 = spawn(F),
+ ?line P3 = spawn(F),
+ IF = fun() ->
+ R = dets:open_file(Tab, [{file,File}]),
+ Parent ! {self(), R},
+ Fun = fun(_) -> timer:sleep(100000) end,
+ {'EXIT', {badarg, _}} = (catch dets:init_table(Tab, Fun)),
+ receive {Parent, die} -> ok end
+ end,
+ ?line P4 = spawn(IF),
+ ?line receive {P1,R1} -> {ok, _} = R1 end,
+ ?line receive {P2,R2} -> {ok, _} = R2 end,
+ ?line receive {P3,R3} -> {ok, _} = R3 end,
+ ?line receive {P4,R4} -> {ok, _} = R4 end,
+ ?line [DetsPid] =
+ lists:filter(fun(P) -> dets:pid2name(P) =/= undefined end,
+ erlang:processes()),
+ exit(DetsPid, kill),
+
+ timer:sleep(1000),
+ ?line undefined = dets:info(Tab),
+ ?line P1 ! {Parent, die},
+ ?line P2 ! {Parent, die},
+ ?line P3 ! {Parent, die},
+ ?line P4 ! {Parent, die},
+
+ file:delete(File),
+ timer:sleep(100),
+ ok.
+
+open_ro(Tab, File) ->
+ ?line create_opened_log(File),
+ Delay = 1000,
+ Parent = self(),
+ F = fun() ->
+ R = dets:open_file(Tab, [{file,File},{access,read}]),
+ timer:sleep(Delay),
+ Parent ! {self(), R}
+ end,
+ ?line P1 = spawn(F),
+ ?line P2 = spawn(F),
+ ?line P3 = spawn(F),
+
+ ?line receive {P1,R1} -> {error,{not_closed,_}} = R1 end,
+ ?line receive {P2,R2} -> {error,{not_closed,_}} = R2 end,
+ ?line receive {P3,R3} -> {error,{not_closed,_}} = R3 end,
+ ok.
+
+open_w(Tab, File, Delay, Config) ->
+ ?line create_opened_log(File),
+ Parent = self(),
+ F = fun() ->
+ R = dets:open_file(Tab, [{file,File}]),
+ timer:sleep(Delay),
+ Parent ! {self(), R}
+ end,
+ ?line Pid1 = spawn(F),
+ ?line Pid2 = spawn(F),
+ ?line Pid3 = spawn(F),
+ ?line undefined = dets:info(Tab), % is repairing now
+ ?line 0 = qlen(),
+
+ Tab2 = t2,
+ File2 = filename(Tab2, Config),
+ ?line file:delete(File2),
+ ?line {ok,Tab2} = dets:open_file(Tab2, [{file,File2}]),
+ ?line ok = dets:close(Tab2),
+ ?line file:delete(File2),
+ ?line 0 = qlen(), % still repairing
+
+ ?line receive {Pid1,R1} -> {ok, Tab} = R1 end,
+ ?line receive {Pid2,R2} -> {ok, Tab} = R2 end,
+ ?line receive {Pid3,R3} -> {ok, Tab} = R3 end,
+ timer:sleep(200),
+ case dets:info(Tab) of
+ undefined ->
+ ok;
+ _Info ->
+ timer:sleep(5000),
+ ?line undefined = dets:info(Tab)
+ end,
+
+ file:delete(File),
+ ok.
+
+qlen() ->
+ {_, {_, N}} = lists:keysearch(message_queue_len, 1, process_info(self())),
+ N.
+
+create_opened_log(File) ->
+ Tab = t,
+ file:delete(File),
+ ?line {ok, Tab} = dets:open_file(Tab, [{file,File}]),
+ ?line ok = ins(Tab, 60000),
+ ?line ok = dets:close(Tab),
+ ?line crash(File, ?CLOSED_PROPERLY_POS+3, ?NOT_PROPERLY_CLOSED),
+ ok.
+
+insert_new(doc) ->
+ ["OTP-5075. insert_new/2"];
+insert_new(suite) ->
+ [];
+insert_new(Config) ->
+ Tab = insert_new,
+ File = filename(Tab, Config),
+ file:delete(File),
+ ?line {ok, T} = dets:open_file(Tab, [{file,File}]),
+ ?line {'EXIT', {badarg, _}} = (catch dets:insert_new(Tab, 14)),
+ ?line {'EXIT', {badarg, _}} = (catch dets:insert_new(Tab, {})),
+ ?line true = dets:insert_new(Tab, {1,a}),
+ ?line false = dets:insert_new(Tab, {1,a}),
+ ?line true = dets:insert_new(Tab, [{2,b}, {3,c}]),
+ ?line false = dets:insert_new(Tab, [{2,b}, {3,c}]),
+ ?line false = dets:insert_new(Tab, [{1,a}, {4,d}]),
+ ?line ok = dets:close(Tab),
+
+ file:delete(File),
+ ?line {ok, T} = dets:open_file(Tab, [{file,File},{type,bag}]),
+ ?line true = dets:insert_new(Tab, {1,a}),
+ ?line false = dets:insert_new(Tab, {1,b}),
+ ?line true = dets:insert_new(Tab, [{2,b}, {3,c}]),
+ ?line false = dets:insert_new(Tab, [{2,a}, {3,d}]),
+ ?line false = dets:insert_new(Tab, [{1,a}, {4,d}]),
+ ?line ok = dets:close(Tab),
+
+
+ file:delete(File),
+ ok.
+
+repair_continuation(doc) ->
+ ["OTP-5126. repair_continuation/2"];
+repair_continuation(suite) ->
+ [];
+repair_continuation(Config) ->
+ Tab = repair_continuation_table,
+ ?line Fname = filename(repair_cont, Config),
+ ?line file:delete(Fname),
+ ?line {ok, _} = dets:open_file(Tab, [{file,Fname}]),
+ ?line ok = dets:insert(Tab, [{1,a},{2,b},{3,c}]),
+
+ ?line MS = [{'_',[],[true]}],
+
+ ?line {[true], C1} = dets:select(Tab, MS, 1),
+ ?line C2 = binary_to_term(term_to_binary(C1)),
+ ?line {'EXIT', {badarg, _}} = (catch dets:select(C2)),
+ ?line C3 = dets:repair_continuation(C2, MS),
+ ?line {[true], C4} = dets:select(C3),
+ ?line C5 = dets:repair_continuation(C4, MS),
+ ?line {[true], _} = dets:select(C5),
+ ?line {'EXIT', {badarg, _}} = (catch dets:repair_continuation(Tab, bu)),
+
+ ?line ok = dets:close(Tab),
+ ?line file:delete(Fname),
+ ok.
+
+otp_5487(doc) ->
+ ["OTP-5487. Growth of read-only table (again)."];
+otp_5487(suite) ->
+ [];
+otp_5487(Config) ->
+ otp_5487(Config, 9),
+ otp_5487(Config, 8),
+ ok.
+
+otp_5487(Config, Version) ->
+ Tab = otp_5487,
+ ?line Fname = filename(otp_5487, Config),
+ ?line file:delete(Fname),
+ ?line Ets = ets:new(otp_5487, [public, set]),
+ ?line lists:foreach(fun(I) -> ets:insert(Ets, {I,I+1}) end,
+ lists:seq(0,1000)),
+ ?line {ok, _} = dets:open_file(Tab, [{file,Fname},{version,Version}]),
+ ?line ok = dets:from_ets(Tab, Ets),
+ ?line ok = dets:sync(Tab),
+ ?line ok = dets:close(Tab),
+ ?line {ok, _} = dets:open_file(Tab, [{file,Fname},{access,read}]),
+ ?line [{1,2}] = dets:lookup(Tab, 1),
+ ?line ok = dets:close(Tab),
+ ?line ets:delete(Ets),
+ ?line file:delete(Fname).
+
+otp_6206(doc) ->
+ ["OTP-6206. Badly formed free lists."];
+otp_6206(suite) ->
+ [];
+otp_6206(Config) ->
+ Tab = otp_6206,
+ File = filename(Tab, Config),
+
+ file:delete(File),
+ Options = [{file,File}],
+ ?line {ok, Tab} = dets:open_file(Tab, Options),
+ NObjs = 13006,
+ ?line ok = ins(Tab, NObjs),
+ ?line ok = del(Tab, NObjs, 2),
+ ?line ok = dets:close(Tab),
+
+ %% Used to return {badmatch,{error,{bad_freelists,File}}.
+ ?line {ok, Tab} = dets:open_file(Tab, [{repair,false}|Options]),
+ ?line ok = dets:close(Tab),
+ file:delete(File),
+ ok.
+
+otp_6359(doc) ->
+ ["OTP-6359. select and match never return the empty list."];
+otp_6359(suite) ->
+ [];
+otp_6359(Config) ->
+ Tab = otp_6359,
+ File = filename(Tab, Config),
+
+ file:delete(File),
+ ?line {ok, _} = dets:open_file(Tab, [{file, File}]),
+ %% Used to return {[], Cont}:
+ ?line '$end_of_table' = dets:match(Tab, '_', 100),
+ ?line ok = dets:close(Tab),
+ file:delete(File),
+ ok.
+
+otp_4738(doc) ->
+ ["OTP-4738. ==/2 and =:=/2."];
+otp_4738(suite) ->
+ [];
+otp_4738(Config) ->
+ %% Version 8 has not been corrected.
+ %% (The constant -12857447 is for version 9 only.)
+ otp_4738_set(9, Config),
+ otp_4738_bag(9, Config),
+ otp_4738_dupbag(9, Config),
+ ok.
+
+otp_4738_dupbag(Version, Config) ->
+ Tab = otp_4738,
+ File = filename(Tab, Config),
+ file:delete(File),
+ I = -12857447,
+ F = float(I),
+ One = 1,
+ FOne = float(One),
+ Args = [{file,File},{type,duplicate_bag},{version,Version}],
+ ?line {ok, Tab} = dets:open_file(Tab, Args),
+ ?line ok = dets:insert(Tab, [{I,One},{F,One},{I,FOne},{F,FOne}]),
+ ?line ok = dets:sync(Tab),
+ ?line [{F,One},{F,FOne}] = dets:lookup(Tab, F),
+ ?line [{I,One},{I,FOne}] = dets:lookup(Tab, I),
+ ?line ok = dets:insert(Tab, [{F,One},{F,FOne}]),
+ ?line [{I,One},{I,FOne},{F,One},{F,FOne},{F,One},{F,FOne}] =
+ dets_utils:mkeysort(1, dets:match_object(Tab, '_')),
+ ?line ok = dets:insert(Tab, [{F,FOne},{F,One}]),
+ ?line [{I,One},{I,FOne},{F,One},{F,FOne},{F,One},
+ {F,FOne},{F,FOne},{F,One}] =
+ dets_utils:mkeysort(1, dets:match_object(Tab, '_')),
+ ?line ok = dets:delete_object(Tab, {I,FOne}),
+ ?line [{I,One},{F,One},{F,FOne},{F,One},{F,FOne},{F,FOne},{F,One}] =
+ dets_utils:mkeysort(1, dets:match_object(Tab, '_')),
+ ?line ok = dets:insert(Tab, {I,FOne}),
+ ?line [{I,One},{I,FOne},{F,One},{F,FOne},{F,One},
+ {F,FOne},{F,FOne},{F,One}] =
+ dets_utils:mkeysort(1, dets:match_object(Tab, '_')),
+ ?line ok = dets:delete_object(Tab, {F,FOne}),
+ ?line [{I,One},{I,FOne},{F,One},{F,One},{F,One}] =
+ dets_utils:mkeysort(1, dets:match_object(Tab, '_')),
+ ?line ok = dets:delete(Tab, F),
+ ?line [{I,One},{I,FOne}] = dets:match_object(Tab, '_'),
+ ?line ok = dets:close(Tab),
+ file:delete(File),
+
+ Zero = 0,
+ FZero = float(Zero),
+ ?line {ok, Tab} = dets:open_file(Tab, Args),
+ ?line ok = dets:insert(Tab, [{I,One},{F,One},{I,FOne},{F,FOne}]),
+ ?line ok = dets:insert(Tab, [{I,One},{F,One},{I,FOne},{F,FOne}]),
+ ?line ok = dets:insert(Tab, [{I,Zero},{F,Zero},{I,FZero},{I,FZero}]),
+ ?line Objs0 = dets_utils:mkeysort(1, dets:match_object(Tab, '_')),
+ ?line ok = dets:close(Tab),
+ crash(File, ?CLOSED_PROPERLY_POS+3, ?NOT_PROPERLY_CLOSED),
+ io:format("Expect repair:~n"),
+ ?line {ok, Tab} = dets:open_file(Tab, Args),
+ ?line Objs1 = dets_utils:mkeysort(1, dets:match_object(Tab, '_')),
+ ?line ok = dets:close(Tab),
+ ?line Objs1 = Objs0,
+ file:delete(File),
+ ok.
+
+otp_4738_bag(Version, Config) ->
+ Tab = otp_4738,
+ File = filename(Tab, Config),
+ file:delete(File),
+ I = -12857447,
+ F = float(I),
+ One = 1,
+ FOne = float(One),
+ Args = [{file,File},{type,bag},{version,Version}],
+ ?line {ok, Tab} = dets:open_file(Tab, Args),
+ ?line ok = dets:insert(Tab, [{I,One},{F,One},{I,FOne},{F,FOne}]),
+ ?line ok = dets:sync(Tab),
+ ?line [{F,One},{F,FOne}] = dets:lookup(Tab, F),
+ ?line [{I,One},{I,FOne}] = dets:lookup(Tab, I),
+ ?line ok = dets:insert(Tab, [{F,One},{F,FOne}]),
+ ?line [{I,One},{I,FOne},{F,One},{F,FOne}] =
+ dets_utils:mkeysort(1, dets:match_object(Tab, '_')),
+ ?line ok = dets:insert(Tab, [{F,FOne},{F,One}]),
+ ?line [{I,One},{I,FOne},{F,FOne},{F,One}] =
+ dets_utils:mkeysort(1, dets:match_object(Tab, '_')),
+ ?line ok = dets:delete_object(Tab, {I,FOne}),
+ ?line [{I,One},{F,FOne},{F,One}] =
+ dets_utils:mkeysort(1, dets:match_object(Tab, '_')),
+ ?line ok = dets:insert(Tab, {I,FOne}),
+ ?line [{I,One},{I,FOne},{F,FOne},{F,One}] =
+ dets_utils:mkeysort(1, dets:match_object(Tab, '_')),
+ ?line ok = dets:delete(Tab, F),
+ ?line [{I,One},{I,FOne}] = dets:match_object(Tab, '_'),
+ ?line ok = dets:close(Tab),
+ file:delete(File).
+
+otp_4738_set(Version, Config) ->
+ Tab = otp_4738,
+ File = filename(Tab, Config),
+ file:delete(File),
+ Args = [{file,File},{type,set},{version,Version}],
+
+ %% I and F share the same slot.
+ I = -12857447,
+ F = float(I),
+ ?line {ok, Tab} = dets:open_file(Tab, Args),
+ ?line ok = dets:insert(Tab, [{I},{F}]),
+ ?line ok = dets:sync(Tab),
+ ?line [{F}] = dets:lookup(Tab, F),
+ ?line [{I}] = dets:lookup(Tab, I),
+ ?line ok = dets:insert(Tab, [{F}]),
+ ?line [{I},{F}] = dets_utils:mkeysort(1, dets:match_object(Tab, '_')),
+ ?line ok = dets:close(Tab),
+ file:delete(File),
+
+ ?line {ok, Tab} = dets:open_file(Tab, Args),
+ ?line ok = dets:insert(Tab, [{I}]),
+ ?line ok = dets:sync(Tab),
+ ?line [] = dets:lookup(Tab, F),
+ ?line [{I}] = dets:lookup(Tab, I),
+ ?line ok = dets:insert(Tab, [{F}]),
+ ?line [{I},{F}] = dets_utils:mkeysort(1, dets:match_object(Tab, '_')),
+ ?line ok = dets:close(Tab),
+ file:delete(File),
+
+ ?line {ok, Tab} = dets:open_file(Tab, Args),
+ ok = dets:insert(Tab, [{I},{F}]),
+ %% {insert, ...} in the cache, try lookup:
+ ?line [{F}] = dets:lookup(Tab, F),
+ ?line [{I}] = dets:lookup(Tab, I),
+ %% Both were found, but that cannot be verified.
+ ?line [{I},{F}] = dets_utils:mkeysort(1, dets:match_object(Tab, '_')),
+ ?line ok = dets:close(Tab),
+ file:delete(File),
+
+ ?line {ok, Tab} = dets:open_file(Tab, Args),
+ ?line ok = dets:insert(Tab, [{I}]),
+ ?line ok = dets:sync(Tab),
+ ?line ok = dets:insert(Tab, [{F}]),
+ %% {insert, ...} in the cache, try lookup:
+ ?line [{F}] = dets:lookup(Tab, F),
+ ?line [{I}] = dets:lookup(Tab, I),
+ ?line [{I},{F}] = dets_utils:mkeysort(1, dets:match_object(Tab, '_')),
+ ?line ok = dets:close(Tab),
+ file:delete(File),
+
+ ?line {ok, Tab} = dets:open_file(Tab, Args),
+ %% Both operations in the cache:
+ ?line ok = dets:insert(Tab, [{I}]),
+ ?line ok = dets:insert(Tab, [{F}]),
+ ?line [{I},{F}] = dets_utils:mkeysort(1, dets:match_object(Tab, '_')),
+ ?line ok = dets:close(Tab),
+ file:delete(File),
+ ok.
+
+otp_7146(doc) ->
+ ["OTP-7146. Bugfix: missing test when re-hashing."];
+otp_7146(suite) ->
+ [];
+otp_7146(Config) ->
+ Tab = otp_7146,
+ File = filename(Tab, Config),
+ file:delete(File),
+
+ Max = 2048,
+ ?line {ok, Tab} = dets:open_file(Tab, [{max_no_slots,Max}, {file,File}]),
+ write_dets(Tab, Max),
+ ?line ok = dets:close(Tab),
+
+ file:delete(File),
+ ok.
+
+write_dets(Tab, Max) ->
+ write_dets(Tab, 0, Max).
+
+write_dets(_Tab, N, Max) when N > Max ->
+ ok;
+write_dets(Tab, N, Max) ->
+ ok = dets:insert(Tab,{ N, {entry,N}}),
+ write_dets(Tab, N+1, Max).
+
+otp_8070(doc) ->
+ ["OTP-8070. Duplicated objects with insert_new() and duplicate_bag."];
+otp_8070(suite) ->
+ [];
+otp_8070(Config) when is_list(Config) ->
+ Tab = otp_8070,
+ File = filename(Tab, Config),
+ file:delete(File),
+ ?line {ok, _} = dets:open_file(Tab, [{file,File},{type, duplicate_bag}]),
+ ?line ok = dets:insert(Tab, [{3,0}]),
+ ?line false = dets:insert_new(Tab, [{3,1},{3,1}]),
+ ?line [{3,0}] = dets:lookup(Tab, 3),
+ ?line ok = dets:close(Tab),
+ file:delete(File),
+ ok.
+
+%%
+%% Parts common to several test cases
+%%
+
+crash(File, Where) ->
+ crash(File, Where, 10).
+
+crash(File, Where, What) when is_integer(What) ->
+ ?line {ok, Fd} = file:open(File, read_write),
+ ?line file:position(Fd, Where),
+ ?line ok = file:write(Fd, [What]),
+ ?line ok = file:close(Fd).
+
+args(Config) ->
+ {Sets, Bags, Dups} =
+ {[
+ [],
+ [{type, set}, {estimated_no_objects, 300},
+ {ram_file, true}],
+ [{type, set}, {estimated_no_objects, 300}],
+ [{type, set}, {estimated_no_objects, 300}],
+ [{auto_save,20}, {type, set},
+ {estimated_no_objects, 300}]
+ ],
+
+ [
+ [{type, bag}, {estimated_no_objects, 300}, {ram_file, true}],
+ [{type, bag}],
+ [{type, bag}, {estimated_no_objects, 300}],
+ [{type, bag}, {estimated_no_objects, 300}],
+ [{type, bag},
+ {auto_save,20}, {estimated_no_objects, 300}],
+ [{type, bag}, {estimated_no_objects, 300}, {ram_file, true}]
+ ],
+
+ [
+ [{type, duplicate_bag}, {estimated_no_objects, 300},
+ {ram_file, true}],
+ [{type, duplicate_bag}],
+ [{type, duplicate_bag}, {estimated_no_objects, 300}],
+ [{type, duplicate_bag}, {estimated_no_objects, 300}],
+ [{type, duplicate_bag},
+ {auto_save,20}, {estimated_no_objects, 300}],
+ [{type, duplicate_bag}, {estimated_no_objects, 300},
+ {ram_file, true}]
+ ]
+ },
+ zip_filename(Sets, Bags, Dups, Config).
+
+zip_filename(S, B, D, Conf) ->
+ zip_filename(S, B, D, [], [], [], 1, Conf).
+
+zip_filename([H|T], B, D, S1, B1, D1, I, Conf) ->
+ zip_filename(T, B, D, [[{file, new_filename(I, Conf)} | H] | S1],
+ B1, D1, I+1, Conf);
+zip_filename([], [H|B], D, S1, B1, D1, I, Conf) ->
+ zip_filename([], B, D, S1, [[{file, new_filename(I, Conf)} | H] | B1],
+ D1, I+1, Conf);
+zip_filename([], [], [H|T], S1, B1, D1, I, Conf) ->
+ zip_filename([], [], T, S1, B1, [[{file, new_filename(I, Conf)} | H] | D1],
+ I+1, Conf);
+zip_filename([], [], [], S1, B1, D1, _, _Conf) ->
+ {reverse(S1), reverse(B1), reverse(D1)}.
+
+del_test(Tab) ->
+ ?format("Deltest on ~p~n", [Tab]),
+ ?line Objs = safe_get_all_objects(Tab),
+ ?line Keys = map(fun(X) -> element(1, X) end, Objs),
+ ?line foreach(fun(Key) -> dets:delete(Tab, Key) end, Keys),
+ ?line 0 = length(get_all_objects(Tab)),
+ ?line [] = get_all_objects_fast(Tab),
+ ?line 0 = dets:info(Tab, size).
+
+del_obj_test(Tab) ->
+ ?format("Delobjtest on ~p~n", [Tab]),
+ ?line Objs = safe_get_all_objects(Tab),
+ ?line LL = length(Objs),
+ ?line LL = dets:info(Tab, size),
+ ?line foreach(fun(Obj) -> dets:delete_object(Tab, Obj) end, Objs),
+ ?line 0 = length(get_all_objects(Tab)),
+ ?line [] = get_all_objects_fast(Tab),
+ ?line 0 = dets:info(Tab, size).
+
+match_del_test(Tab) ->
+ ?line ?format("Match delete test on ~p~n", [Tab]),
+ ?line ok = dets:match_delete(Tab, {'_','_','_'}),
+ ?line Sz = dets:info(Tab, size),
+ ?line true = Sz =:= length(dets:match_object(Tab, '_')),
+ ?line ok = dets:match_delete(Tab, '_'),
+ ?line 0 = dets:info(Tab, size),
+ ?line 0 = length(get_all_objects(Tab)),
+ ?line [] = get_all_objects_fast(Tab).
+
+trav_test(_Data, Len, Tab) ->
+ ?format("Travtest on ~p~n", [Tab]),
+ ?line _X0 = dets:traverse(Tab, fun(_X) -> continue end),
+ ?line XX = dets:traverse(Tab, fun(X) -> {continue, X} end),
+ ?line case Len =:= length(XX) of
+ false -> ?format("DIFF ~p~n", [XX -- _Data]);
+ true -> ok
+ end,
+ ?line 1 = length(dets:traverse(Tab, fun(X) -> {done, X} end)).
+
+match_test(Data, Tab) ->
+ ?line ?format("Match test on ~p~n", [Tab]),
+ ?line Data1 = sort(filter(fun(X) when tuple_size(X) =:= 3 -> true;
+ (_X) -> false
+ end, Data)),
+ ?line Data1 = sort(dets:match_object(Tab, {'$1', '$2', '$3'})),
+
+ ?line Len = length(Data),
+ ?line Len = length(dets:match(Tab, '_')),
+ ?line Len2 = length(Data1),
+ ?line Len2 = length(dets:match(Tab, {'$1', '_', '_'})),
+
+ ?line Data3 =
+ filter(fun(X) ->
+ K = element(1, X),
+ if
+ tuple_size(X) =:= 3, tuple_size(K) =:= 2 -> true;
+ true -> false
+ end
+ end, Data),
+ ?line Len3 = length(Data3),
+ ?line Len3 = length(dets:match(Tab, {{'$1', '$2'}, '_', '_'})),
+ ?line Len3 = length(dets:match_object(Tab, {{'$1', '$2'}, '_', '_'})),
+
+ ?line R = make_ref(),
+ ?line dets:insert(Tab, {{R, R}, 33 ,44}),
+ ?line 1 = length(dets:match(Tab, {{R, R}, '_', '_'})),
+ ?line 1 = length(dets:match_object(Tab, {{R, R}, '_', '_'})).
+
+%%
+%% Utilities
+%%
+
+headsz(8) ->
+ ?HEADSZ_v8;
+headsz(_) ->
+ ?HEADSZ_v9.
+
+unwritable(Fname) ->
+ ?line {ok, Info} = file:read_file_info(Fname),
+ Mode = Info#file_info.mode - 8#00200,
+ ?line file:write_file_info(Fname, Info#file_info{mode = Mode}).
+
+writable(Fname) ->
+ ?line {ok, Info} = file:read_file_info(Fname),
+ Mode = Info#file_info.mode bor 8#00200,
+ ?line file:write_file_info(Fname, Info#file_info{mode = Mode}).
+
+truncate(File, Where) ->
+ ?line {ok, Fd} = file:open(File, read_write),
+ ?line file:position(Fd, Where),
+ ?line ok = file:truncate(Fd),
+ ?line ok = file:close(Fd).
+
+new_filename(Name, _Config) when is_integer(Name) ->
+ filename:join(?privdir(_Config),
+ integer_to_list(Name) ++ ".DETS").
+
+filename(Name, Config) when is_atom(Name) ->
+ filename(atom_to_list(Name), Config);
+filename(Name, _Config) ->
+ filename:join(?privdir(_Config), Name).
+
+open_files(_Name, [], _Version) ->
+ [];
+open_files(Name0, [Args | Tail], Version) ->
+ ?format("init ~p~n", [Args]),
+ ?line Name = list_to_atom(integer_to_list(Name0)),
+ ?line {ok, Name} = dets:open_file(Name, [{version,Version} | Args]),
+ [Name | open_files(Name0+1, Tail, Version)].
+
+close_all(Tabs) -> foreach(fun(Tab) -> ok = dets:close(Tab) end, Tabs).
+
+delete_files(Args) ->
+ Fun = fun(F) ->
+ {value, {file, File}} = keysearch(file, 1, F),
+ file:delete(File),
+ File
+ end,
+ map(Fun, Args).
+
+%% Initialize all tables
+initialize(Tabs, Data) ->
+ ?line foreach(fun(Tab) ->
+ Fun = fun(Obj) -> ok = dets:insert(Tab, Obj) end,
+ foreach(Fun, Data),
+ dets:sync(Tab)
+ end, Tabs).
+
+%% need more than 512 objects to really trig overflow
+make_data(Kp) ->
+ make_data(Kp, set).
+
+make_data(Kp, Type) ->
+ dup(Type, make_data(Kp, Type, 520)).
+
+dup(duplicate_bag, [H1, H2 |T]) ->
+ [H1,H2, H1, H2 | dup(duplicate_bag, T)];
+dup(_, Other) ->
+ Other.
+
+make_data(_Kp, Type, 0) ->
+ odd_keys(Type);
+make_data(1, set, I) ->
+ [{I, q,w} | make_data(1, set, I-1)];
+make_data(2, set, I) ->
+ [{hh, I, q,w} | make_data(2, set, I-1)];
+make_data(1, bag, I) ->
+ [{I, q,w} , {I, hah, 77} | make_data(1, bag, I-1)];
+make_data(2, bag, I) ->
+ [{hh, I, q,w} , {hh, I, lalal, 900} | make_data(2, bag, I-1)];
+make_data(1, duplicate_bag, I) ->
+ [{I, q,w} , {I, hah, 77} | make_data(1, duplicate_bag, I-1)];
+make_data(2, duplicate_bag, I) ->
+ [{hh, I, q,w} , {hh, I, lalal, 900} | make_data(2, duplicate_bag, I-1)].
+
+odd_keys(_) ->
+ [{foo, 1 ,2},
+ {{foo, foo}, 2,3},
+ {"kakaka", {{{}}}, jj},
+ {{"kallll", "kkk", []}, 66.7777},
+ {make_ref(), 99, 66},
+ {{1},2,3,4,5,6,7,duplicate(50, 8)},
+ {self(), 7,8,88},
+ {[self()], 8, 11}].
+
+
+ins(_T, 0) ->
+ ok;
+ins(T, N) ->
+ case dets:insert(T, {N, item(N)}) of
+ ok -> ins(T, N-1);
+ Error -> Error
+ end.
+
+item(N) when N rem 2 =:= 0 ->
+ {item, number, N};
+item(N) ->
+ {item, number, N, a, much, bigger, one, i, think}.
+
+del(_T, N, _I) when N =< 0 ->
+ ok;
+del(T, N, I) ->
+ ok = dets:delete(T, N),
+ del(T, N-I, I).
+
+ensure_node(0, _Node) ->
+ could_not_start_node;
+ensure_node(N, Node) ->
+ case net_adm:ping(Node) of
+ pang ->
+ receive after 1000 ->
+ ok
+ end,
+ ensure_node(N-1,Node);
+ pong ->
+ ok
+ end.
+
+size_test(Len, Tabs) ->
+ ?line foreach(fun(Tab) ->
+ Len = dets:info(Tab, size)
+ end, Tabs).
+
+no_keys_test([T | Ts]) ->
+ no_keys_test(T),
+ no_keys_test(Ts);
+no_keys_test([]) ->
+ ok;
+no_keys_test(T) ->
+ case dets:info(T, version) of
+ 8 ->
+ ok;
+ 9 ->
+ Kp = dets:info(T, keypos),
+ ?line All = dets:match_object(T, '_'),
+ ?line L = lists:map(fun(X) -> element(Kp, X) end, All),
+ ?line NoKeys = length(lists:usort(L)),
+ ?line case {dets:info(T, no_keys), NoKeys} of
+ {N, N} ->
+ ok;
+ {N1, N2} ->
+ exit({no_keys_test, N1, N2})
+ end
+ end.
+
+safe_get_all_objects(Tab) ->
+ dets:safe_fixtable(Tab, true),
+ Objects = get_all_objects(Tab),
+ dets:safe_fixtable(Tab, false),
+ Objects.
+
+%% Caution: unless the table has been fixed, strange results can be returned.
+get_all_objects(Tab) -> get_all_objects(dets:first(Tab), Tab, []).
+
+%% Assuming no key matches {error, Reason}...
+get_all_objects('$end_of_table', _Tab, L) -> L;
+get_all_objects({error, Reason}, _Tab, _L) ->
+ exit({get_all_objects, get(line), {error, Reason}});
+get_all_objects(Key, Tab, L) ->
+ Objs = dets:lookup(Tab, Key),
+ ?line get_all_objects(dets:next(Tab, Key), Tab, Objs ++ L).
+
+count_objects_quite_fast(Tab) ->
+ ?line R1 = dets:match_object(Tab, '_', 1),
+ count_objs_1(R1, 0).
+
+count_objs_1('$end_of_table', N) ->
+ N;
+count_objs_1({Ts,C}, N) when is_list(Ts) ->
+ count_objs_1(dets:match_object(C), length(Ts) + N).
+
+get_all_objects_fast(Tab) ->
+ dets:match_object(Tab, '_').
+
+%% Relevant for version 8.
+histogram(Tab) ->
+ OnePercent = case dets:info(Tab, no_slots) of
+ undefined -> undefined;
+ {_, NoSlots, _} -> NoSlots/100
+ end,
+ histogram(Tab, OnePercent).
+
+histogram(Tab, OnePercent) ->
+ ?line E = ets:new(histo, []),
+ ?line dets:safe_fixtable(Tab, true),
+ ?line Hist = histo(Tab, E, 0, OnePercent, OnePercent),
+ ?line dets:safe_fixtable(Tab, false),
+ ?line case Hist of
+ ok ->
+ ?line H = ets:tab2list(E),
+ ?line true = ets:delete(E),
+ sort(H);
+ Error ->
+ ets:delete(E),
+ Error
+ end.
+
+histo(T, E, I, One, Count) when is_number(Count), I > Count ->
+ io:format("."),
+ histo(T, E, I, One, Count+One);
+histo(T, E, I, One, Count) ->
+ ?line case dets:slot(T, I) of
+ '$end_of_table' when is_number(Count) ->
+ io:format("~n"),
+ ok;
+ '$end_of_table' ->
+ ok;
+ Objs when is_list(Objs) ->
+ L = length(Objs),
+ case catch ets:update_counter(E, L, 1) of
+ {'EXIT', _} ->
+ ets:insert(E, {L, 1});
+ _ ->
+ ok
+ end,
+ histo(T, E, I+1, One, Count);
+ Error ->
+ Error
+ end.
+
+sum_histogram(H) ->
+ sum_histogram(H, 0).
+
+sum_histogram([{S,N1} | H], N) ->
+ sum_histogram(H, N + S*N1);
+sum_histogram([], N) ->
+ N.
+
+ave_histogram(H) ->
+ ave_histogram(H, 0)/sum_histogram(H).
+
+ave_histogram([{S,N1} | H], N) ->
+ ave_histogram(H, N + S*S*N1);
+ave_histogram([], N) ->
+ N.
+
+bad_object({error,{bad_object,FileName}}, FileName) ->
+ ok; % Version 8, no debug.
+bad_object({error,{{bad_object,_,_},FileName}}, FileName) ->
+ ok; % Version 8, debug...
+bad_object({error,{{bad_object,_}, FileName}}, FileName) ->
+ ok; % No debug.
+bad_object({error,{{{bad_object,_,_},_,_,_}, FileName}}, FileName) ->
+ ok. % Debug.
+
+check_pps(P0) ->
+ case pps() of
+ P0 ->
+ ok;
+ _ ->
+ %% On some (rare) occasions the dets process is still
+ %% running although the call to close() has returned, as
+ %% it seems...
+ timer:sleep(500),
+ case pps() of
+ P0 ->
+ ok;
+ P1 ->
+ io:format("failure, got ~p~n, expected ~p\n", [P1, P0]),
+ {Ports0,Procs0} = P0,
+ {Ports1,Procs1} = P1,
+ show("Old ports", Ports0 -- Ports1),
+ show("New ports", Ports1 -- Ports0),
+ show("Old procs", Procs0 -- Procs1),
+ show("New procs", Procs1 -- Procs0),
+ ?t:fail()
+ end
+ end.
+
+show(_S, []) ->
+ ok;
+show(S, L) ->
+ io:format("~s: ~p~n", [S, L]).
+
+pps() ->
+ dets:start(),
+ {port_list(), process_list()}.
+
+port_list() ->
+ [{P,safe_second_element(erlang:port_info(P, name))} ||
+ P <- erlang:ports()].
+
+process_list() ->
+ [{P,process_info(P, registered_name),
+ safe_second_element(process_info(P, initial_call))} ||
+ P <- processes()].
+
+safe_second_element({_,Info}) -> Info;
+safe_second_element(Other) -> Other.
diff --git a/lib/stdlib/test/dets_SUITE_data/dets_test_v8b.dets b/lib/stdlib/test/dets_SUITE_data/dets_test_v8b.dets
new file mode 100644
index 0000000000..d0aa20fe06
--- /dev/null
+++ b/lib/stdlib/test/dets_SUITE_data/dets_test_v8b.dets
Binary files differ
diff --git a/lib/stdlib/test/dets_SUITE_data/dets_test_v8b_little_endian.dets b/lib/stdlib/test/dets_SUITE_data/dets_test_v8b_little_endian.dets
new file mode 100644
index 0000000000..bf490afa1a
--- /dev/null
+++ b/lib/stdlib/test/dets_SUITE_data/dets_test_v8b_little_endian.dets
Binary files differ
diff --git a/lib/stdlib/test/dets_SUITE_data/version_9a.dets b/lib/stdlib/test/dets_SUITE_data/version_9a.dets
new file mode 100644
index 0000000000..6023d79c94
--- /dev/null
+++ b/lib/stdlib/test/dets_SUITE_data/version_9a.dets
Binary files differ
diff --git a/lib/stdlib/test/dets_SUITE_data/version_9b_phash.dat b/lib/stdlib/test/dets_SUITE_data/version_9b_phash.dat
new file mode 100644
index 0000000000..ebf254010f
--- /dev/null
+++ b/lib/stdlib/test/dets_SUITE_data/version_9b_phash.dat
Binary files differ
diff --git a/lib/stdlib/test/dets_SUITE_data/version_r2d.dets b/lib/stdlib/test/dets_SUITE_data/version_r2d.dets
new file mode 100644
index 0000000000..327072f99e
--- /dev/null
+++ b/lib/stdlib/test/dets_SUITE_data/version_r2d.dets
Binary files differ
diff --git a/lib/stdlib/test/dets_SUITE_data/version_r3b02.dets b/lib/stdlib/test/dets_SUITE_data/version_r3b02.dets
new file mode 100644
index 0000000000..058cd15b31
--- /dev/null
+++ b/lib/stdlib/test/dets_SUITE_data/version_r3b02.dets
Binary files differ
diff --git a/lib/stdlib/test/dict_SUITE.erl b/lib/stdlib/test/dict_SUITE.erl
new file mode 100644
index 0000000000..6a90870bda
--- /dev/null
+++ b/lib/stdlib/test/dict_SUITE.erl
@@ -0,0 +1,133 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%% This module tests the ordsets, sets, and gb_sets modules.
+%%
+
+-module(dict_SUITE).
+
+-export([all/1,init_per_testcase/2,fin_per_testcase/2,
+ create/1,store/1]).
+
+-include("test_server.hrl").
+
+-import(lists, [foldl/3,reverse/1]).
+
+all(suite) ->
+ [create,store].
+
+init_per_testcase(_Case, Config) ->
+ ?line Dog = ?t:timetrap(?t:minutes(5)),
+ [{watchdog,Dog}|Config].
+
+fin_per_testcase(_Case, Config) ->
+ Dog = ?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+create(Config) when is_list(Config) ->
+ test_all(fun create_1/1).
+
+create_1(M) ->
+ ?line D0 = M:empty(),
+ ?line [] = M:to_list(D0),
+ ?line 0 = M:size(D0),
+ D0.
+
+store(Config) when is_list(Config) ->
+ test_all([{0,132},{253,258},{510,514}], fun store_1/2).
+
+store_1(List, M) ->
+ ?line D0 = M:from_list(List),
+
+ %% Make sure that we get the same result by inserting
+ %% elements one at the time.
+ ?line D1 = foldl(fun({K,V}, Dict) -> M:enter(K, V, Dict) end,
+ M:empty(), List),
+ ?line true = M:equal(D0, D1),
+ D0.
+
+%%%
+%%% Helper functions.
+%%%
+
+dict_mods() ->
+ Orddict = dict_test_lib:new(orddict, fun(X, Y) -> X == Y end),
+ Dict = dict_test_lib:new(dict, fun(X, Y) ->
+ lists:sort(dict:to_list(X)) ==
+ lists:sort(dict:to_list(Y)) end),
+ Gb = dict_test_lib:new(gb_trees, fun(X, Y) ->
+ gb_trees:to_list(X) ==
+ gb_trees:to_list(Y) end),
+ [Orddict,Dict,Gb].
+
+test_all(Tester) ->
+ ?line Pids = [spawn_tester(M, Tester) || M <- dict_mods()],
+ collect_all(Pids, []).
+
+spawn_tester(M, Tester) ->
+ Parent = self(),
+ spawn_link(fun() ->
+ random:seed(1, 2, 42),
+ S = Tester(M),
+ Res = {M:size(S),lists:sort(M:to_list(S))},
+ Parent ! {result,self(),Res}
+ end).
+
+collect_all([Pid|Pids], Acc) ->
+ receive
+ {result,Pid,Result} ->
+ collect_all(Pids, [Result|Acc])
+ end;
+collect_all([], Acc) ->
+ all_same(Acc).
+
+test_all(ListTemplate, Tester) ->
+ List = random_list(ListTemplate),
+ test_all(fun(M) -> Tester(List, M) end).
+
+all_same([H|T]) ->
+ all_same_1(T, H).
+
+all_same_1([H|T], H) ->
+ all_same_1(T, H);
+all_same_1([], _) -> ok.
+
+rnd_list(Sz) ->
+ rnd_list_1(Sz, []).
+
+random_list([{Low,High}|T]) ->
+ random_list(lists:seq(Low, High)++T);
+random_list([Sz|T]) when is_integer(Sz) ->
+ rnd_list(Sz)++random_list(T);
+random_list([]) -> [].
+
+rnd_list_1(0, Acc) ->
+ Acc;
+rnd_list_1(N, Acc) ->
+ Key = atomic_rnd_term(),
+ Value = random:uniform(100),
+ rnd_list_1(N-1, [{Key,Value}|Acc]).
+
+atomic_rnd_term() ->
+ case random:uniform(3) of
+ 1 -> list_to_atom(integer_to_list($\s+random:uniform(94))++"rnd");
+ 2 -> random:uniform();
+ 3 -> random:uniform(50)-37
+ end.
diff --git a/lib/stdlib/test/dict_test_lib.erl b/lib/stdlib/test/dict_test_lib.erl
new file mode 100644
index 0000000000..fd15baa5ff
--- /dev/null
+++ b/lib/stdlib/test/dict_test_lib.erl
@@ -0,0 +1,83 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(dict_test_lib, [Mod,Equal]).
+
+-export([module/0,equal/2,empty/0,size/1,to_list/1,from_list/1,
+ enter/3,delete/2,lookup/2]).
+
+module() ->
+ Mod.
+
+equal(X, Y) ->
+ Equal(X, Y).
+
+empty() ->
+ case erlang:function_exported(Mod, new, 0) of
+ false -> Mod:empty();
+ true -> Mod:new()
+ end.
+
+size(S) ->
+ Mod:size(S).
+
+to_list(S) ->
+ Mod:to_list(S).
+
+from_list(S) ->
+ case erlang:function_exported(Mod, from_orddict, 1) of
+ false ->
+ Mod:from_list(S);
+ true ->
+ %% The gb_trees module has no from_list/1 function.
+ %%
+ %% The keys in S are not unique. To make sure
+ %% that we pick the same key/value pairs as
+ %% dict/orddict, first convert the list to an orddict.
+ Orddict = orddict:from_list(S),
+ Mod:from_orddict(Orddict)
+ end.
+
+%% Store new value into dictionary or update previous value in dictionary.
+enter(Key, Val, Dict) ->
+ case erlang:function_exported(Mod, store, 3) of
+ false ->
+ Mod:enter(Key, Val, Dict);
+ true ->
+ Mod:store(Key, Val, Dict)
+ end.
+
+%% Delete an EXISTING key.
+delete(Key, Dict) ->
+ case erlang:function_exported(Mod, delete, 2) of
+ true -> Mod:delete(Key, Dict);
+ false -> Mod:erase(Key, Dict)
+ end.
+
+%% -> none | {value,Value}
+lookup(Key, Dict) ->
+ case erlang:function_exported(Mod, lookup, 2) of
+ false ->
+ case Mod:find(Key, Dict) of
+ error -> none;
+ {ok,Value} -> {value,Value}
+ end;
+ true ->
+ Mod:lookup(Key, Dict)
+ end.
diff --git a/lib/stdlib/test/digraph_SUITE.erl b/lib/stdlib/test/digraph_SUITE.erl
new file mode 100644
index 0000000000..6ef5b1ddef
--- /dev/null
+++ b/lib/stdlib/test/digraph_SUITE.erl
@@ -0,0 +1,520 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(digraph_SUITE).
+
+%-define(STANDALONE,1).
+
+-ifdef(STANDALONE).
+-define(line, put(line, ?LINE), ).
+-else.
+-include("test_server.hrl").
+-endif.
+
+-export([all/1]).
+
+-export([opts/1, degree/1, path/1, cycle/1, misc/1, vertices/1,
+ edges/1, data/1, tickets/1, otp_3522/1, otp_3630/1, otp_8066/1]).
+
+-export([spawn_graph/2]).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+all(suite) -> {req, [stdlib], [opts, degree, path, cycle, misc, tickets]}.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+opts(doc) -> [];
+opts(suite) -> [];
+opts(Config) when is_list(Config) ->
+ %% OTP-5985: the 'public' option has been removed
+ ?line {'EXIT',{badarg,_}} = (catch digraph:new([public])),
+ ?line {P2,G2} = spawn_graph([private]),
+ ?line {'EXIT',{badarg,_}} = (catch digraph:add_vertex(G2, x)),
+ ?line kill_graph(P2),
+ ?line {P3,G3} = spawn_graph([protected]),
+ ?line {'EXIT',{badarg,_}} = (catch digraph:add_vertex(G3, x)),
+ ?line kill_graph(P3),
+ ?line Template = [{v1,[v2]}, {v2,[v3]}, {v3,[v4]}, {v4,[]}],
+ ?line G4 = build_graph([], Template),
+ ?line e = digraph:add_edge(G4, e, v4, v1, []),
+ ?line digraph:delete(G4),
+ ?line G5 = build_graph([cyclic], Template),
+ ?line e = digraph:add_edge(G5, e, v4, v1, []),
+ ?line digraph:delete(G5),
+ ?line G6 = build_graph([acyclic], Template),
+ ?line acyclic = info(G6, cyclicity),
+ ?line {error, {bad_edge,_}} = digraph:add_edge(G6, v4, v1),
+ ?line digraph:delete(G6),
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+degree(doc) -> [];
+degree(suite) -> [];
+degree(Config) when is_list(Config) ->
+ ?line G = build_graph([], [{x1,[]}, {x2,[x1]}, {x3,[x1,x2]},
+ {x4,[x1,x2,x3]}, {x5,[x1,x2,x3,x4]}]),
+ %% out degree
+ ?line 0 = digraph:out_degree(G, x1),
+ ?line 1 = digraph:out_degree(G, x2),
+ ?line 2 = digraph:out_degree(G, x3),
+ ?line 3 = digraph:out_degree(G, x4),
+ ?line 4 = digraph:out_degree(G, x5),
+ %% out neighbours
+ ?line [] = check(digraph:out_neighbours(G, x1), []),
+ ?line [] = check(digraph:out_neighbours(G, x2), [x1]),
+ ?line [] = check(digraph:out_neighbours(G, x3), [x1,x2]),
+ ?line [] = check(digraph:out_neighbours(G, x4), [x1,x2,x3]),
+ ?line [] = check(digraph:out_neighbours(G, x5), [x1,x2,x3,x4]),
+
+ %% in degree
+ ?line 4 = digraph:in_degree(G, x1),
+ ?line 3 = digraph:in_degree(G, x2),
+ ?line 2 = digraph:in_degree(G, x3),
+ ?line 1 = digraph:in_degree(G, x4),
+ ?line 0 = digraph:in_degree(G, x5),
+ %% in neighbours
+ ?line [] = check(digraph:in_neighbours(G, x1), [x2,x3,x4,x5]),
+ ?line [] = check(digraph:in_neighbours(G, x2), [x3,x4,x5]),
+ ?line [] = check(digraph:in_neighbours(G, x3), [x4,x5]),
+ ?line [] = check(digraph:in_neighbours(G, x4), [x5]),
+ ?line [] = check(digraph:in_neighbours(G, x5), []),
+ digraph:delete(G),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+path(doc) -> [];
+path(suite) -> [];
+path(Config) when is_list(Config) ->
+ ?line G = build_graph([], [{x1,[x2,x3]}, {x2,[x4]}, {x3,[x4]},
+ {x4,[x5,x6]}, {x5,[x7]}, {x6,[x7]}]),
+ ?line Vi = case digraph:get_path(G, x1, x7) of
+ [x1,x2,x4,x5,x7] -> digraph:del_vertex(G, x5), x6;
+ [x1,x2,x4,x6,x7] -> digraph:del_vertex(G, x6), x5;
+ [x1,x3,x4,x5,x7] -> digraph:del_vertex(G, x5), x6;
+ [x1,x3,x4,x6,x7] -> digraph:del_vertex(G, x6), x5
+ end,
+ ?line Vj = case digraph:get_path(G, x1, x7) of
+ [x1,x2,x4,Vi,x7] -> digraph:del_vertex(G,x2), x3;
+ [x1,x3,x4,Vi,x7] -> digraph:del_vertex(G,x3), x2
+ end,
+ ?line [x1,Vj,x4,Vi,x7] = digraph:get_path(G, x1, x7),
+ ?line digraph:del_vertex(G, Vj),
+ ?line false = digraph:get_path(G, x1, x7),
+ ?line [] = check(digraph:vertices(G), [x1,x4,Vi,x7]),
+ digraph:delete(G),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+cycle(doc) -> [];
+cycle(suite) -> [];
+cycle(Config) when is_list(Config) ->
+ ?line G = build_graph([], [{x1,[x2,x3]}, {x2,[x4]}, {x3,[x4]},
+ {x4,[x5,x6]}, {x5,[x7]}, {x6,[x7,x8]},
+ {x8,[x3,x8]}]),
+ ?line false = digraph:get_cycle(G, x1),
+ ?line false = digraph:get_cycle(G, x2),
+ ?line false = digraph:get_cycle(G, x5),
+ ?line false = digraph:get_cycle(G, x7),
+ ?line [x3,x4,x6,x8,x3] = digraph:get_cycle(G, x3),
+ ?line [x4,x6,x8,x3,x4] = digraph:get_cycle(G, x4),
+ ?line [x6,x8,x3,x4,x6] = digraph:get_cycle(G, x6),
+ ?line [x8,x3,x4,x6,x8] = digraph:get_cycle(G, x8),
+ ?line digraph:del_vertex(G, x4),
+ ?line [x8] = digraph:get_cycle(G, x8),
+ digraph:delete(G),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+misc(suite) -> [vertices, edges, data].
+
+vertices(doc) -> [];
+vertices(suite) -> [];
+vertices(Config) when is_list(Config) ->
+ ?line G = build_graph([], [{x,[]}, {y,[]}]),
+ ?line [] = check(digraph:vertices(G), [x,y]),
+ ?line digraph:del_vertices(G, [x,y]),
+ ?line [] = digraph:vertices(G),
+ ?line digraph:delete(G),
+ ok.
+
+edges(doc) -> [];
+edges(suite) -> [];
+edges(Config) when is_list(Config) ->
+ ?line G = build_graph([], [{x, [{exy,y},{exx,x}]},
+ {y, [{eyx,x}]}
+ ]),
+ ?line [] = check(digraph:edges(G), [exy, eyx, exx]),
+ ?line [] = check(digraph:out_edges(G, x), [exy,exx]),
+ ?line [] = check(digraph:in_edges(G, x), [eyx,exx]),
+ ?line [] = check(digraph:out_edges(G, y), [eyx]),
+ ?line [] = check(digraph:in_edges(G, y), [exy]),
+ ?line true = digraph:del_edges(G, [exy, eyx, does_not_exist]),
+ ?line [exx] = digraph:edges(G),
+ ?line [] = check(digraph:out_edges(G, x), [exx]),
+ ?line [] = check(digraph:in_edges(G, x), [exx]),
+ ?line [] = check(digraph:out_edges(G, y), []),
+ ?line [] = check(digraph:in_edges(G, y), []),
+ ?line digraph:del_vertices(G, [x,y]),
+ ?line [] = digraph:edges(G),
+ ?line [] = digraph:vertices(G),
+ ?line digraph:delete(G),
+ ok.
+
+data(doc) -> [];
+data(suite) -> [];
+data(Config) when is_list(Config) ->
+ ?line G = build_graph([], [{x, [{exy, y}]}, {y, []}]),
+
+ ?line {x,[]} = digraph:vertex(G, x),
+ ?line {y,[]} = digraph:vertex(G, y),
+ ?line {exy,x,y,[]} = digraph:edge(G, exy),
+
+ ?line digraph:add_edge(G, exy, x, y, {data,x,y}),
+ ?line E = digraph:add_edge(G, x, y, {data,y,x}),
+ ?line digraph:add_vertex(G, x, {any}),
+ ?line digraph:add_vertex(G, y, '_'),
+
+ ?line {x,{any}} = digraph:vertex(G, x),
+ ?line {y,'_'} = digraph:vertex(G, y),
+ ?line {exy,x,y,{data,x,y}} = digraph:edge(G, exy),
+ ?line {E,x,y,{data,y,x}} = digraph:edge(G, E),
+ ?line true = digraph:del_edge(G, E),
+ ?line false = digraph:edge(G, E),
+ ?line true = sane(G),
+ ?line digraph:delete(G),
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+tickets(suite) -> [otp_3522, otp_3630, otp_8066].
+
+otp_3522(doc) -> [];
+otp_3522(suite) -> [];
+otp_3522(Config) when is_list(Config) ->
+ ?line G1 = build_graph([acyclic], [{x, []}]),
+ ?line {error, {bad_edge,_}} = digraph:add_edge(G1, x, x),
+ ?line true = digraph:delete(G1),
+
+ ?line G = digraph:new(),
+ ?line 0 = digraph:no_vertices(G),
+ ?line 0 = digraph:no_edges(G),
+ ?line V1 = digraph:add_vertex(G),
+ ?line '$vid' = digraph:add_vertex(G, '$vid'),
+ ?line V2 = digraph:add_vertex(G),
+ ?line '$eid' = digraph:add_edge(G, '$eid', V1, V2, []),
+ ?line E = digraph:add_edge(G, V1, V2),
+ ?line 3 = digraph:no_vertices(G),
+ ?line 2 = digraph:no_edges(G),
+ ?line cyclic = info(G, cyclicity),
+ ?line protected = info(G, protection),
+
+ ?line [] = check(digraph:in_edges(G, V2), ['$eid', E]),
+ ?line [] = check(digraph:out_edges(G, V1), ['$eid', E]),
+ ?line [] = check(digraph:vertices(G), [V1,V2,'$vid']),
+ ?line [] = check(digraph:edges(G), [E, '$eid']),
+ ?line true = sane(G),
+ ?line true = digraph:delete(G),
+ ok.
+
+otp_3630(doc) -> [];
+otp_3630(suite) -> [];
+otp_3630(Config) when is_list(Config) ->
+ ?line G = build_graph([], [{x, [{exy,y},{exx,x}]},
+ {y, [{eyy,y},{eyx,x}]}
+ ]),
+ ?line [x,y] = digraph:get_path(G, x, y),
+ ?line [y,x] = digraph:get_path(G, y, x),
+
+ ?line [x,x] = digraph:get_short_path(G, x, x),
+ ?line [y,y] = digraph:get_short_path(G, y, y),
+ ?line true = digraph:delete(G),
+
+ ?line G1 = build_graph([], [{1, [{12,2},{13,3},{11,1}]},
+ {2, [{23,3}]},
+ {3, [{34,4},{35,5}]},
+ {4, [{45,5}]},
+ {5, [{56,6},{57,7}]},
+ {6, [{67,7}]},
+ {7, [{71,1}]}
+ ]),
+
+ ?line [1,3,5,7] = digraph:get_short_path(G1, 1, 7),
+ ?line [3,5,7,1,3] = digraph:get_short_cycle(G1, 3),
+ ?line [1,1] = digraph:get_short_cycle(G1, 1),
+ ?line true = digraph:delete(G1),
+
+ F = 0.0, I = round(F),
+ ?line G2 = digraph:new([acyclic]),
+ ?line digraph:add_vertex(G2, F),
+ ?line digraph:add_vertex(G2, I),
+ ?line E = digraph:add_edge(G2, F, I),
+ ?line true = not is_tuple(E),
+ ?line true = sane(G2),
+ ?line true = digraph:delete(G2),
+
+ ok.
+
+otp_8066(doc) -> [];
+otp_8066(suite) -> [];
+otp_8066(Config) when is_list(Config) ->
+ fun() ->
+ D = digraph:new(),
+ V1 = digraph:add_vertex(D),
+ V2 = digraph:add_vertex(D),
+ _ = digraph:add_edge(D, V1, V2),
+ ?line [V1, V2] = digraph:get_path(D, V1, V2),
+ ?line true = sane(D),
+ ?line true = digraph:del_path(D, V1, V2),
+ ?line true = sane(D),
+ ?line false = digraph:get_path(D, V1, V2),
+ ?line true = digraph:del_path(D, V1, V2),
+ ?line true = digraph:delete(D)
+ end(),
+
+ fun() ->
+ D = digraph:new(),
+ V1 = digraph:add_vertex(D),
+ V2 = digraph:add_vertex(D),
+ _ = digraph:add_edge(D, V1, V2),
+ _ = digraph:add_edge(D, V1, V2),
+ _ = digraph:add_edge(D, V1, V1),
+ _ = digraph:add_edge(D, V2, V2),
+ ?line [V1, V2] = digraph:get_path(D, V1, V2),
+ ?line true = sane(D),
+ ?line true = digraph:del_path(D, V1, V2),
+ ?line false = digraph:get_short_path(D, V2, V1),
+
+ ?line true = sane(D),
+ ?line false = digraph:get_path(D, V1, V2),
+ ?line true = digraph:del_path(D, V1, V2),
+ ?line true = digraph:delete(D)
+ end(),
+
+ fun() ->
+ G = digraph:new(),
+ W1 = digraph:add_vertex(G),
+ W2 = digraph:add_vertex(G),
+ W3 = digraph:add_vertex(G),
+ W4 = digraph:add_vertex(G),
+ _ = digraph:add_edge(G,['$e'|0], W1, W2, {}),
+ ?line {error,{bad_vertex, bv}} =
+ digraph:add_edge(G, edge, bv, W1, {}),
+ ?line {error,{bad_vertex, bv}} =
+ digraph:add_edge(G, edge, W1, bv, {}),
+ ?line false = digraph:get_short_cycle(G, W1),
+ ?line {error, {bad_edge,_}} =
+ digraph:add_edge(G,['$e'|0], W3, W4, {}),
+ ?line true = sane(G),
+ ?line true = digraph:delete(G)
+ end(),
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+sane(G) ->
+ sane1(G),
+ erase(sane) =:= undefined.
+
+sane1(G) ->
+ %% etab: {E, V1, V2, Label}
+ %% ntab: {{out,V},E} eller {{in,V},E}
+ %% vtab: {V,Label}
+
+ Es = digraph:edges(G),
+ Vs = digraph:vertices(G),
+ VEs = lists:flatmap(fun(V) -> digraph:edges(G, V) end, Vs),
+ case lists:sort(Es++Es) =:= lists:sort(VEs) of
+ true -> ok;
+ false ->
+ io:format("Bad edges~n", []), put(sane, no)
+ end,
+
+ lists:foreach(
+ fun(E) ->
+ Edge = {E, V1, V2, _L} = digraph:edge(G, E),
+ case {digraph:vertex(G, V1), digraph:vertex(G, V2)} of
+ {{V1, _}, {V2, _}} -> ok;
+ _ -> io:format("Missing vertex ~p~n", [Edge]), put(sane, no)
+ end,
+ In = digraph:in_edges(G, V2),
+ case lists:member(E, In) of
+ true -> ok;
+ false ->
+ io:format("Missing in-neighbour ~p~n", [Edge]),
+ put(sane, no)
+ end,
+ Out = digraph:out_edges(G, V1),
+ case lists:member(E, Out) of
+ true -> ok;
+ false ->
+ io:format("Missing out-neighbour ~p~n", [Edge]),
+ put(sane, no)
+ end
+ end, Es),
+
+ lists:foreach(
+ fun(V) ->
+ InEs = digraph:in_edges(G, V),
+ %% Nu har man *alla* inkanter f�r V
+ lists:foreach(
+ fun(E) ->
+ case digraph:edge(G, E) of
+ {E, _, V, _} -> ok;
+ _ ->
+ io:format("Bad in-edge ~p: ~p~n", [V, E]),
+ put(sane, no)
+ end
+ end, InEs),
+ OutEs = digraph:out_edges(G, V),
+ lists:foreach(
+ fun(E) ->
+ case digraph:edge(G, E) of
+ {E, V, _, _} -> ok;
+ _ ->
+ io:format("Bad out-edge ~p: ~p~n", [V, E]),
+ put(sane, no)
+ end
+ end, OutEs)
+ end, Vs),
+
+ InEs = lists:flatmap(fun(V) -> digraph:in_edges(G, V) end, Vs),
+ OutEs = lists:flatmap(fun(V) -> digraph:out_edges(G, V) end, Vs),
+ lists:foreach(
+ fun(E) ->
+ case digraph:edge(G, E) of
+ {E, _, _, _} -> ok;
+ _ ->
+ io:format("Unknown edge (neighbour) ~p~n", [E]),
+ put(sane, no)
+ end
+ end, InEs++OutEs),
+
+ N_in = length(InEs),
+ N_out = length(OutEs),
+ N_edges = digraph:no_edges(G),
+ if
+ N_in =/= N_out ->
+ io:format("Number of in- and out-edges differs~n", []),
+ put(sane, no);
+ N_in+N_out =/= N_edges+N_edges ->
+ io:format("Invalid number of edges (~p+~p =/= 2*~p)~n",
+ [N_in, N_out, N_edges]),
+ put(sane, no);
+ true -> ok
+ end,
+ Edges = [digraph:edge(G, E) || E <- Es],
+ EVs = lists:usort([V || {_, V, _, _} <- Edges] ++
+ [V || {_, _, V, _} <- Edges]),
+ lists:foreach(
+ fun(V) ->
+ case digraph:vertex(G, V) of
+ {_, _} -> ok;
+ false ->
+ io:format("Unknown vertex in edge: ~p~n", [V]),
+ put(sane, no)
+ end
+ end, EVs),
+
+ %% sink_vertices and source_vertices were introduced in 2001. They
+ %% are not documented.
+
+ %% sink: a vertex with no outgoing edges
+ SinkVs = [V || V <- Vs, digraph:out_edges(G, V) =:= [] ],
+ case lists:sort(SinkVs) =:= lists:sort(digraph:sink_vertices(G)) of
+ true -> ok;
+ false ->
+ io:format("Bad sinks~n"), put(sane, no)
+ end,
+ %% sink: a vertex with no incoming edges
+ SourceVs = [V || V <- Vs, digraph:in_edges(G, V) =:= [] ],
+ case lists:sort(SourceVs) =:= lists:sort(digraph:source_vertices(G)) of
+ true -> ok;
+ false ->
+ io:format("Bad sources~n"), put(sane, no)
+ end,
+
+ true.
+
+build_graph(Opts, Gs) ->
+ G = digraph:new(Opts),
+ build_g(G, Gs).
+
+build_g(G, [{V,Ns} | Gs]) ->
+ digraph:add_vertex(G, V),
+ build_ns(G, V, Ns),
+ build_g(G, Gs);
+build_g(G, []) ->
+ true = sane(G),
+ G.
+
+build_ns(G, V, [{E,W} | Ns]) ->
+ digraph:add_vertex(G, W),
+ digraph:add_edge(G, E, V, W, []),
+ build_ns(G, V, Ns);
+build_ns(G, V, [W | Ns]) ->
+ digraph:add_vertex(G, W),
+ digraph:add_edge(G, V, W),
+ build_ns(G, V, Ns);
+build_ns(_G, _V, []) ->
+ true.
+
+%% Spawn a process that create a graph return {Pid, Graph}
+
+spawn_graph(Opts) ->
+ Pid = spawn(?MODULE, spawn_graph, [self(),Opts]),
+ receive
+ {Pid, G} -> {Pid,G}
+ end.
+
+%% Create a graph and wait for die message
+spawn_graph(Starter, Opts) ->
+ G = digraph:new(Opts),
+ Starter ! {self(), G},
+ receive
+ die -> true
+ end.
+
+info(G, What) ->
+ case lists:keysearch(What, 1, digraph:info(G)) of
+ {value, {What, Value}} -> Value;
+ false -> []
+ end.
+
+%% Kill process created by spawn_graph
+kill_graph(Pid) ->
+ Pid ! die.
+
+check(R0, E0) ->
+ R = lists:sort(R0),
+ E = lists:sort(E0),
+ case R of
+ E ->
+ [];
+ _ ->
+ (R -- E) ++ (E -- R)
+ end.
diff --git a/lib/stdlib/test/digraph_utils_SUITE.erl b/lib/stdlib/test/digraph_utils_SUITE.erl
new file mode 100644
index 0000000000..d6d477b388
--- /dev/null
+++ b/lib/stdlib/test/digraph_utils_SUITE.erl
@@ -0,0 +1,316 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(digraph_utils_SUITE).
+
+%-define(debug, true).
+-ifdef(debug).
+-define(line, put(line, ?LINE), ).
+-else.
+-include("test_server.hrl").
+-endif.
+
+-export([all/1]).
+
+-export([simple/1, loop/1, isolated/1, topsort/1, subgraph/1,
+ condensation/1, tree/1]).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+all(suite) -> {req, [stdlib], [simple, loop, isolated, topsort,
+ subgraph, condensation, tree]}.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+simple(doc) -> [];
+simple(suite) -> [];
+simple(Config) when is_list(Config) ->
+ ?line G = digraph:new(),
+ ?line add_vertices(G, [a]),
+ ?line add_edges(G, [{b,c},{b,d},{e,f},{f,g},{g,e},{h,h},{i,i},{i,j}]),
+ ?line 10 = length(digraph_utils:postorder(G)),
+ ?line 10 = length(digraph_utils:preorder(G)),
+ ?line ok = evall(digraph_utils:components(G),
+ [[a],[b,c,d],[e,f,g],[h],[i,j]]),
+ ?line ok = evall(digraph_utils:strong_components(G),
+ [[a],[b],[c],[d],[e,f,g],[h],[i],[j]]),
+ ?line ok = evall(digraph_utils:cyclic_strong_components(G),
+ [[e,f,g],[h],[i]]),
+ ?line true = path(G, e, e),
+ ?line false = path(G, e, j),
+ ?line false = path(G, a, a),
+ ?line false = digraph_utils:topsort(G),
+ ?line false = digraph_utils:is_acyclic(G),
+ ?line ok = eval(digraph_utils:loop_vertices(G), [h,i]),
+ ?line ok = eval(digraph_utils:reaching([e], G), [e,f,g]),
+ ?line ok = eval(digraph_utils:reaching_neighbours([e], G), [e,f,g]),
+ ?line ok = eval(digraph_utils:reachable([e], G), [e,f,g]),
+ ?line ok = eval(digraph_utils:reachable_neighbours([e], G), [e,f,g]),
+ ?line ok = eval(digraph_utils:reaching([b], G), [b]),
+ ?line ok = eval(digraph_utils:reaching_neighbours([b], G), []),
+ ?line ok = eval(digraph_utils:reachable([b], G), [b,c,d]),
+ ?line ok = eval(digraph_utils:reachable_neighbours([b], G), [c,d]),
+ ?line ok = eval(digraph_utils:reaching([h], G), [h]),
+ ?line ok = eval(digraph_utils:reaching_neighbours([h], G), [h]),
+ ?line ok = eval(digraph_utils:reachable([h], G), [h]),
+ ?line ok = eval(digraph_utils:reachable_neighbours([h], G), [h]),
+ ?line ok = eval(digraph_utils:reachable([e,f], G), [e,f,g]),
+ ?line ok = eval(digraph_utils:reachable_neighbours([e,f], G), [e,f,g]),
+ ?line ok = eval(digraph_utils:reachable([h,h,h], G), [h]),
+ ?line true = digraph:delete(G),
+ ok.
+
+loop(doc) -> [];
+loop(suite) -> [];
+loop(Config) when is_list(Config) ->
+ ?line G = digraph:new(),
+ ?line add_vertices(G, [a,b]),
+ ?line add_edges(G, [{a,a},{b,b}]),
+ ?line ok = evall(digraph_utils:components(G), [[a],[b]]),
+ ?line ok = evall(digraph_utils:strong_components(G), [[a],[b]]),
+ ?line ok = evall(digraph_utils:cyclic_strong_components(G), [[a],[b]]),
+ ?line [_,_] = digraph_utils:topsort(G),
+ ?line false = digraph_utils:is_acyclic(G),
+ ?line ok = eval(digraph_utils:loop_vertices(G), [a,b]),
+ ?line [_,_] = digraph_utils:preorder(G),
+ ?line [_,_] = digraph_utils:postorder(G),
+ ?line ok = eval(digraph_utils:reaching([b], G), [b]),
+ ?line ok = eval(digraph_utils:reaching_neighbours([b], G), [b]),
+ ?line ok = eval(digraph_utils:reachable([b], G), [b]),
+ ?line ok = eval(digraph_utils:reachable_neighbours([b], G), [b]),
+ ?line true = path(G, a, a),
+ ?line true = digraph:delete(G),
+ ok.
+
+isolated(doc) -> [];
+isolated(suite) -> [];
+isolated(Config) when is_list(Config) ->
+ ?line G = digraph:new(),
+ ?line add_vertices(G, [a,b]),
+ ?line ok = evall(digraph_utils:components(G), [[a],[b]]),
+ ?line ok = evall(digraph_utils:strong_components(G), [[a],[b]]),
+ ?line ok = evall(digraph_utils:cyclic_strong_components(G), []),
+ ?line [_,_] = digraph_utils:topsort(G),
+ ?line true = digraph_utils:is_acyclic(G),
+ ?line ok = eval(digraph_utils:loop_vertices(G), []),
+ ?line [_,_] = digraph_utils:preorder(G),
+ ?line [_,_] = digraph_utils:postorder(G),
+ ?line ok = eval(digraph_utils:reaching([b], G), [b]),
+ ?line ok = eval(digraph_utils:reaching_neighbours([b], G), []),
+ ?line ok = eval(digraph_utils:reachable([b], G), [b]),
+ ?line ok = eval(digraph_utils:reachable_neighbours([b], G), []),
+ ?line false = path(G, a, a),
+ ?line true = digraph:delete(G),
+ ok.
+
+topsort(doc) -> [];
+topsort(suite) -> [];
+topsort(Config) when is_list(Config) ->
+ ?line G = digraph:new(),
+ ?line add_edges(G, [{a,b},{b,c},{c,d},{d,e},{e,f}]),
+ ?line ok = eval(digraph_utils:topsort(G), [a,b,c,d,e,f]),
+ ?line true = digraph:delete(G),
+ ok.
+
+subgraph(doc) -> [];
+subgraph(suite) -> [];
+subgraph(Config) when is_list(Config) ->
+ ?line G = digraph:new([acyclic]),
+ ?line add_edges(G, [{b,c},{b,d},{e,f},{f,fg,fgl,g},{f,fg2,fgl2,g},{g,e},
+ {h,h},{i,i},{i,j}]),
+ ?line add_vertices(G, [{b,bl},{f,fl}]),
+ ?line SG = digraph_utils:subgraph(G, [u1,b,c,u2,f,g,i,u3]),
+ ?line [b,c,f,g,i] = lists:sort(digraph:vertices(SG)),
+ ?line {b,bl} = digraph:vertex(SG, b),
+ ?line {c,[]} = digraph:vertex(SG, c),
+ ?line {fg,f,g,fgl} = digraph:edge(SG, fg),
+ ?line {fg2,f,g,fgl2} = digraph:edge(SG, fg2),
+ ?line {_, {_, acyclic}} = lists:keysearch(cyclicity, 1, digraph:info(SG)),
+ ?line true = digraph:delete(SG),
+
+ ?line SG1 = digraph_utils:subgraph(G, [f, g, h],
+ [{type, []}, {keep_labels, false}]),
+ ?line [f,g,h] = lists:sort(digraph:vertices(SG1)),
+ ?line {f,[]} = digraph:vertex(SG1, f),
+ ?line {fg,f,g,[]} = digraph:edge(SG1, fg),
+ ?line {_, {_, cyclic}} = lists:keysearch(cyclicity, 1, digraph:info(SG1)),
+ ?line true = digraph:delete(SG1),
+
+ ?line SG2 = digraph_utils:subgraph(G, [f, g, h],
+ [{type, [acyclic]},
+ {keep_labels, true}]),
+ ?line [f,g,h] = lists:sort(digraph:vertices(SG2)),
+ ?line {f,fl} = digraph:vertex(SG2, f),
+ ?line {fg,f,g,fgl} = digraph:edge(SG2, fg),
+ ?line {_, {_, acyclic}} = lists:keysearch(cyclicity, 1, digraph:info(SG2)),
+ ?line true = digraph:delete(SG2),
+
+ ?line {'EXIT',{badarg,_}} =
+ (catch digraph_utils:subgraph(G, [f], [{invalid, opt}])),
+ ?line {'EXIT',{badarg,_}} =
+ (catch digraph_utils:subgraph(G, [f], [{keep_labels, not_Bool}])),
+ ?line {'EXIT',{badarg,_}} =
+ (catch digraph_utils:subgraph(G, [f], [{type, not_type}])),
+ ?line {'EXIT',{badarg,_}} =
+ (catch digraph_utils:subgraph(G, [f], [{type, [not_type]}])),
+ ?line {'EXIT',{badarg,_}} =
+ (catch digraph_utils:subgraph(G, [f], not_a_list)),
+
+ ?line true = digraph:delete(G),
+
+ ok.
+
+condensation(doc) -> [];
+condensation(suite) -> [];
+condensation(Config) when is_list(Config) ->
+ ?line G = digraph:new([]),
+ ?line add_edges(G, [{b,c},{b,d},{e,f},{f,fg,fgl,g},{f,fg2,fgl2,g},{g,e},
+ {h,h},{j,i},{i,j}]),
+ ?line add_vertices(G, [q]),
+ ?line CG = digraph_utils:condensation(G),
+ ?line Vs = sort_2(digraph:vertices(CG)),
+ ?line [[b],[c],[d],[e,f,g],[h],[i,j],[q]] = Vs,
+ ?line Fun = fun(E) ->
+ {_E, V1, V2, _L} = digraph:edge(CG, E),
+ {lists:sort(V1), lists:sort(V2)}
+ end,
+ ?line Es = lists:map(Fun, digraph:edges(CG)),
+ ?line [{[b],[c]},{[b],[d]},{[e,f,g],[e,f,g]},{[h],[h]},{[i,j],[i,j]}] =
+ lists:sort(Es),
+ ?line true = digraph:delete(CG),
+ ?line true = digraph:delete(G),
+ ok.
+
+tree(doc) -> ["OTP-7081"];
+tree(suite) -> [];
+tree(Config) when is_list(Config) ->
+ ?line false = is_tree([], []),
+ ?line true = is_tree([a], []),
+ ?line false = is_tree([a,b], []),
+ ?line true = is_tree([{a,b}]),
+ ?line false = is_tree([{a,b},{b,a}]),
+ ?line true = is_tree([{a,b},{a,c},{b,d},{b,e}]),
+ ?line false = is_tree([{a,b},{a,c},{b,d},{b,e}, {d,e}]),
+ ?line false = is_tree([{a,b},{a,c},{b,d},{b,e}, {b,e}]),
+ ?line true = is_tree([{a,c},{c,b}]),
+ ?line true = is_tree([{b,a},{c,a}]),
+ %% Parallel edges. Acyclic and with one componets
+ %% (according to the digraph module).
+ ?line false = is_tree([{a,b},{a,b}]),
+
+ ?line no = arborescence_root([], []),
+ ?line {yes, a} = arborescence_root([a], []),
+ ?line no = arborescence_root([a,b], []),
+ ?line {yes, a} = arborescence_root([{a,b}]),
+ ?line no = arborescence_root([{a,b},{b,a}]),
+ ?line {yes, a} = arborescence_root([{a,b},{a,c},{b,d},{b,e}]),
+ ?line no = arborescence_root([{a,b},{a,c},{b,d},{b,e}, {d,e}]),
+ ?line no = arborescence_root([{a,b},{a,c},{b,d},{b,e}, {b,e}]),
+ ?line {yes, a} = arborescence_root([{a,c},{c,b}]),
+ ?line no = arborescence_root([{b,a},{c,a}]),
+
+ ?line false = is_arborescence([], []),
+ ?line true = is_arborescence([a], []),
+ ?line false = is_arborescence([a,b], []),
+ ?line true = is_arborescence([{a,b}]),
+ ?line false = is_arborescence([{a,b},{b,a}]),
+ ?line true = is_arborescence([{a,b},{a,c},{b,d},{b,e}]),
+ ?line false = is_arborescence([{a,b},{a,c},{b,d},{b,e}, {d,e}]),
+ ?line false = is_arborescence([{a,b},{a,c},{b,d},{b,e}, {b,e}]),
+ ?line true = is_arborescence([{a,c},{c,b}]),
+ ?line false = is_arborescence([{b,a},{c,a}]),
+
+ %% Parallel edges.
+ ?line false = is_arborescence([{a,b},{a,b}]),
+
+ ok.
+
+is_tree(Es) ->
+ is_tree([], Es).
+
+is_tree(Vs, Es) ->
+ gu(Vs, Es, is_tree).
+
+is_arborescence(Es) ->
+ is_arborescence([], Es).
+
+is_arborescence(Vs, Es) ->
+ gu(Vs, Es, is_arborescence).
+
+arborescence_root(Es) ->
+ arborescence_root([], Es).
+
+arborescence_root(Vs, Es) ->
+ gu(Vs, Es, arborescence_root).
+
+gu(Vs, Es, F) ->
+ G = digraph:new(),
+ add_vertices(G, Vs),
+ add_edges(G, Es),
+ Reply = digraph_utils:F(G),
+ true = digraph:delete(G),
+ Reply.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+sort_2(L) ->
+ lists:sort(lists:map(fun(V) -> lists:sort(V) end, L)).
+
+path(G, V1, V2) ->
+ digraph:get_path(G, V1, V2) /= false.
+
+add_vertices(G, Vs) ->
+ lists:foreach(fun({V, Label}) -> digraph:add_vertex(G, V, Label);
+ (V) -> digraph:add_vertex(G, V)
+ end, Vs).
+
+add_edges(G, L) ->
+ Fun = fun({From, To}) ->
+ digraph:add_vertex(G, From),
+ digraph:add_vertex(G, To),
+ digraph:add_edge(G, From, To);
+ ({From, Edge, Label, To}) ->
+ digraph:add_vertex(G, From),
+ digraph:add_vertex(G, To),
+ digraph:add_edge(G, Edge, From, To, Label)
+ end,
+ lists:foreach(Fun, L).
+
+eval(L, E) ->
+ Expected = lists:sort(E),
+ Got = lists:sort(L),
+ if
+ Expected == Got ->
+ ok;
+ true ->
+ not_ok
+ end.
+
+evall(L, E) ->
+ F = fun(L1) -> lists:sort(L1) end,
+ Fun = fun(LL) -> F(lists:map(F, LL)) end,
+
+ Expected = Fun(E),
+ Got = Fun(L),
+ if
+ Expected == Got ->
+ ok;
+ true ->
+ not_ok
+ end.
diff --git a/lib/stdlib/test/dummy1_h.erl b/lib/stdlib/test/dummy1_h.erl
new file mode 100644
index 0000000000..4377d774a3
--- /dev/null
+++ b/lib/stdlib/test/dummy1_h.erl
@@ -0,0 +1,70 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(dummy1_h).
+
+%% Test event handler for gen_event_SUITE.erl
+
+-export([init/1, handle_event/2, handle_call/2, handle_info/2,
+ terminate/2]).
+
+init(make_error) ->
+ {error, my_error};
+init({_, error}) -> % swap from non-existing handler.
+ non_existing;
+init({swap, {ok, OldState}}) ->
+ {ok, OldState};
+init([Parent]) ->
+ {ok, Parent}. %% We will send special responses for every handled event.
+
+handle_event(delete_event, _Parent) ->
+ remove_handler;
+handle_event(do_crash, _State) ->
+ erlang:error({badmatch,4});
+%Inverse of dummy_h
+handle_event(hibernate, Parent) ->
+ {ok,Parent};
+handle_event(wakeup, Parent) ->
+ {ok,Parent,hibernate};
+handle_event(Event, Parent) ->
+ Parent ! {dummy1_h, Event},
+ {ok, Parent}.
+
+handle_call(delete_call, _State) ->
+ {remove_handler, ok};
+handle_call(_Query, State) ->
+ {ok, ok, State}.
+
+handle_info(delete_info, _Parent) ->
+ remove_handler;
+handle_info(do_crash, _State) ->
+ erlang:error({badmatch,4});
+handle_info(gnurf, Parent) ->
+ {ok, Parent, hibernate};
+handle_info(Info, Parent) ->
+ Parent ! {dummy1_h, Info},
+ {ok, Parent}.
+
+terminate(return_hej, _State) ->
+ return_hej;
+terminate(remove_handler, Parent) ->
+ Parent ! {dummy1_h, removed};
+terminate(_Reason, _State) ->
+ ok.
+
+
diff --git a/lib/stdlib/test/dummy_h.erl b/lib/stdlib/test/dummy_h.erl
new file mode 100644
index 0000000000..01eb790a75
--- /dev/null
+++ b/lib/stdlib/test/dummy_h.erl
@@ -0,0 +1,88 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(dummy_h).
+
+%% Test event handler for gen_event_SUITE.erl
+
+-export([init/1, handle_event/2, handle_call/2, handle_info/2,
+ terminate/2]).
+
+init(make_error) ->
+ {error, my_error};
+init([Parent]) ->
+ {ok, Parent}; %% We will send special responses for every handled event.
+init([Parent,hibernate]) ->
+ {ok, Parent, hibernate}. %% We will send special responses for every handled event.
+
+handle_event({swap_event,Mod,Args}, State) ->
+ {swap_handler, swap, State, Mod, Args};
+handle_event(error_event, _State) ->
+ {return, faulty};
+handle_event(do_crash, _State) ->
+ erlang:error({badmatch,4});
+handle_event(hibernate, _State) ->
+ {ok,[],hibernate};
+handle_event(wakeup, _State) ->
+ {ok,[]};
+handle_event(Event, Parent) ->
+ Parent ! {dummy_h, Event},
+ {ok, Parent}.
+
+handle_call(hejsan, State) ->
+ {ok, {ok, hejhopp}, State};
+handle_call({swap_call,Mod,Args}, State) ->
+ {swap_handler, {ok, swapped}, swap, State, Mod, Args};
+handle_call(error_call, _State) ->
+ {return, faulty};
+handle_call(exit_call, _State) ->
+ erlang:error({badmatch,4});
+handle_call(hibernate, _State) ->
+ {ok,true,[],hibernate};
+handle_call(hibernate_later, _State) ->
+ timer:send_after(1000,sleep),
+ {ok,later,[]};
+handle_call(_Query, State) ->
+ {ok, ok, State}.
+
+handle_info({swap_info,Mod,Args}, State) ->
+ {swap_handler, swap, State, Mod, Args};
+handle_info(error_info, _State) ->
+ {return, faulty};
+handle_info(do_crash, _State) ->
+ erlang:error({badmatch,4});
+handle_info(sleep, _State) ->
+ {ok, [], hibernate};
+handle_info(wake, _State) ->
+ {ok, []};
+handle_info(gnurf, _State) ->
+ {ok, []};
+handle_info(Info, Parent) ->
+ Parent ! {dummy_h, Info},
+ {ok, Parent}.
+
+terminate(return_hej, _State) ->
+ return_hej;
+terminate(swap, State) ->
+ {ok, State};
+terminate({error, {return, faulty}}, Parent) ->
+ Parent ! {dummy_h, returned_error};
+terminate(_Reason, _State) ->
+ ok.
+
+
diff --git a/lib/stdlib/test/epp_SUITE.erl b/lib/stdlib/test/epp_SUITE.erl
new file mode 100644
index 0000000000..67e20fd2e1
--- /dev/null
+++ b/lib/stdlib/test/epp_SUITE.erl
@@ -0,0 +1,1148 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1998-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+
+-module(epp_SUITE).
+-export([all/1]).
+
+-export([rec_1/1, predef_mac/1,
+ upcase_mac/1, upcase_mac_1/1, upcase_mac_2/1,
+ variable/1, variable_1/1, otp_4870/1, otp_4871/1, otp_5362/1,
+ pmod/1, not_circular/1, skip_header/1, otp_6277/1, otp_7702/1,
+ otp_8130/1]).
+
+-export([epp_parse_erl_form/2]).
+
+%%
+%% Define to run outside of test server
+%%
+%-define(STANDALONE,1).
+
+-ifdef(STANDALONE).
+-compile(export_all).
+-define(line, put(line, ?LINE), ).
+-define(config(A,B),config(A,B)).
+%% -define(t, test_server).
+-define(t, io).
+config(priv_dir, _) ->
+ filename:absname("./epp_SUITE_priv");
+config(data_dir, _) ->
+ filename:absname("./epp_SUITE_data").
+-else.
+-include("test_server.hrl").
+-export([init_per_testcase/2, fin_per_testcase/2]).
+
+% Default timetrap timeout (set in init_per_testcase).
+-define(default_timeout, ?t:minutes(1)).
+
+init_per_testcase(_, Config) ->
+ ?line Dog = ?t:timetrap(?default_timeout),
+ [{watchdog, Dog} | Config].
+fin_per_testcase(_, Config) ->
+ Dog = ?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+-endif.
+
+all(doc) ->
+ ["Test cases for epp."];
+all(suite) ->
+ [rec_1, upcase_mac, predef_mac, variable, otp_4870, otp_4871, otp_5362,
+ pmod, not_circular, skip_header, otp_6277, otp_7702, otp_8130].
+
+rec_1(doc) ->
+ ["Recursive macros hang or crash epp (OTP-1398)."];
+rec_1(suite) ->
+ [];
+rec_1(Config) when is_list(Config) ->
+ ?line File = filename:join(?config(data_dir, Config), "mac.erl"),
+ ?line {ok, List} = epp_parse_file(File, [], []),
+ %% we should encounter errors
+ ?line {value, _} = lists:keysearch(error, 1, List),
+ ?line check_errors(List),
+ ok.
+
+%%% Here is a little reimplementation of epp:parse_file, which times out
+%%% after 4 seconds if the epp server doesn't respond. If we use the
+%%% regular epp:parse_file, the test case will time out, and then epp
+%%% server will go on growing until we dump core.
+epp_parse_file(File, Inc, Predef) ->
+ {ok, Epp} = epp:open(File, Inc, Predef),
+ List = collect_epp_forms(Epp),
+ epp:close(Epp),
+ {ok, List}.
+
+collect_epp_forms(Epp) ->
+ Result = epp_parse_erl_form(Epp),
+ case Result of
+ {error, _Error} ->
+ [Result | collect_epp_forms(Epp)];
+ {ok, Form} ->
+ [Form | collect_epp_forms(Epp)];
+ {eof, _} ->
+ [Result]
+ end.
+
+epp_parse_erl_form(Epp) ->
+ P = spawn(?MODULE, epp_parse_erl_form, [Epp, self()]),
+ receive
+ {P, Result} ->
+ Result
+ after 4000 ->
+ exit(Epp, kill),
+ exit(P, kill),
+ timeout
+ end.
+
+epp_parse_erl_form(Epp, Parent) ->
+ Parent ! {self(), epp:parse_erl_form(Epp)}.
+
+check_errors([]) ->
+ ok;
+check_errors([{error, Info} | Rest]) ->
+ ?line {Line, Mod, Desc} = Info,
+ ?line case Line of
+ I when is_integer(I) -> ok;
+ {L,C} when is_integer(L), is_integer(C), C >= 1 -> ok
+ end,
+ ?line Str = lists:flatten(Mod:format_error(Desc)),
+ ?line [Str] = io_lib:format("~s", [Str]),
+ check_errors(Rest);
+check_errors([_ | Rest]) ->
+ check_errors(Rest).
+
+upcase_mac(doc) ->
+ ["Check that uppercase macro names are implicitly quoted (OTP-2608)"];
+upcase_mac(suite) ->
+ [upcase_mac_1, upcase_mac_2].
+
+upcase_mac_1(doc) ->
+ [];
+upcase_mac_1(suite) ->
+ [];
+upcase_mac_1(Config) when is_list(Config) ->
+ ?line File = filename:join(?config(data_dir, Config), "mac2.erl"),
+ ?line {ok, List} = epp:parse_file(File, [], []),
+ ?line [_, {attribute, _, plupp, Tuple} | _] = List,
+ ?line Tuple = {1, 1, 3, 3},
+ ok.
+
+upcase_mac_2(doc) ->
+ [];
+upcase_mac_2(suite) ->
+ [];
+upcase_mac_2(Config) when is_list(Config) ->
+ ?line File = filename:join(?config(data_dir, Config), "mac2.erl"),
+ ?line {ok, List} = epp:parse_file(File, [], [{p, 5}, {'P', 6}]),
+ ?line [_, {attribute, _, plupp, Tuple} | _] = List,
+ ?line Tuple = {5, 5, 6, 6},
+ ok.
+
+predef_mac(doc) ->
+ [];
+predef_mac(suite) ->
+ [];
+predef_mac(Config) when is_list(Config) ->
+ ?line File = filename:join(?config(data_dir, Config), "mac3.erl"),
+ ?line {ok, List} = epp:parse_file(File, [], []),
+ ?line [_,
+ {attribute, LineCol1, l, Line1},
+ {attribute, _, f, File},
+ {attribute, _, machine1, _},
+ {attribute, _, module, mac3},
+ {attribute, _, m, mac3},
+ {attribute, _, ms, "mac3"},
+ {attribute, _, machine2, _}
+ | _] = List,
+ ?line case LineCol1 of
+ Line1 -> ok;
+ {Line1,_} -> ok
+ end,
+ ok.
+
+variable(doc) ->
+ ["Check variable as first file component of the include directives."];
+variable(suite) ->
+ [variable_1].
+
+variable_1(doc) ->
+ [];
+variable_1(suite) ->
+ [];
+variable_1(Config) when is_list(Config) ->
+ ?line DataDir = ?config(data_dir, Config),
+ ?line File = filename:join(DataDir, "variable_1.erl"),
+ ?line true = os:putenv("VAR", DataDir),
+ %% variable_1.erl includes variable_1_include.hrl and
+ %% variable_1_include_dir.hrl.
+ ?line {ok, List} = epp:parse_file(File, [], []),
+ ?line {value, {attribute,_,a,{value1,value2}}} =
+ lists:keysearch(a,3,List),
+ ok.
+
+otp_4870(doc) ->
+ ["undef without module declaration"];
+otp_4870(suite) ->
+ [];
+otp_4870(Config) when is_list(Config) ->
+ Ts = [{otp_4870,
+ <<"-undef(foo).
+ ">>,
+ []}],
+ ?line [] = check(Config, Ts),
+ ok.
+
+otp_4871(doc) ->
+ ["crashing erl_scan"];
+otp_4871(suite) ->
+ [];
+otp_4871(Config) when is_list(Config) ->
+ ?line Dir = ?config(priv_dir, Config),
+ ?line File = filename:join(Dir, "otp_4871.erl"),
+ ?line ok = file:write_file(File, "-module(otp_4871)."),
+ %% Testing crash in erl_scan. Unfortunately there currently is
+ %% no known way to crash erl_scan so it is emulated by killing the
+ %% file io server. This assumes lots of things about how
+ %% the processes are started and how monitors are set up,
+ %% so there are some sanity checks before killing.
+ ?line {ok,Epp} = epp:open(File, []),
+ timer:sleep(1),
+ ?line {current_function,{epp,_,_}} = process_info(Epp, current_function),
+ ?line {monitored_by,[Io]} = process_info(Epp, monitored_by),
+ ?line {current_function,{file_io_server,_,_}} =
+ process_info(Io, current_function),
+ ?line exit(Io, emulate_crash),
+ timer:sleep(1),
+ ?line {error,{_Line,epp,cannot_parse}} = otp_4871_parse_file(Epp),
+ ?line epp:close(Epp),
+ ok.
+
+otp_4871_parse_file(Epp) ->
+ case epp:parse_erl_form(Epp) of
+ {ok,_} -> otp_4871_parse_file(Epp);
+ Other -> Other
+ end.
+
+otp_5362(doc) ->
+ ["OTP-5362. The -file attribute is recognized."];
+otp_5362(suite) ->
+ [];
+otp_5362(Config) when is_list(Config) ->
+ Dir = ?config(priv_dir, Config),
+
+ Copts = [return, strong_validation,{i,Dir}],
+
+ File_Incl = filename:join(Dir, "incl_5362.erl"),
+ File_Incl2 = filename:join(Dir, "incl2_5362.erl"),
+ File_Incl3 = filename:join(Dir, "incl3_5362.erl"),
+ Incl = <<"-module(incl_5362).
+
+ -include(\"incl2_5362.erl\").
+
+ -include_lib(\"incl3_5362.erl\").
+
+ hi(There) -> % line 7
+ a.
+ ">>,
+ Incl2 = <<"-file(\"some.file\", 100).
+
+ foo(Bar) -> % line 102
+ foo.
+ ">>,
+ Incl3 = <<"glurk(Foo) -> % line 1
+ bar.
+ ">>,
+ ?line ok = file:write_file(File_Incl, Incl),
+ ?line ok = file:write_file(File_Incl2, Incl2),
+ ?line ok = file:write_file(File_Incl3, Incl3),
+
+ ?line {ok, incl_5362, InclWarnings} = compile:file(File_Incl, Copts),
+ ?line true = message_compare(
+ [{File_Incl3,[{{1,1},erl_lint,{unused_function,{glurk,1}}},
+ {{1,7},erl_lint,{unused_var,'Foo'}}]},
+ {File_Incl,[{{7,15},erl_lint,{unused_function,{hi,1}}},
+ {{7,18},erl_lint,{unused_var,'There'}}]},
+ {"some.file",[{{102,16},erl_lint,{unused_function,{foo,1}}},
+ {{102,20},erl_lint,{unused_var,'Bar'}}]}],
+ lists:usort(InclWarnings)),
+
+ file:delete(File_Incl),
+ file:delete(File_Incl2),
+ file:delete(File_Incl3),
+
+ %% A -file attribute referring back to the including file.
+ File_Back = filename:join(Dir, "back_5362.erl"),
+ File_Back_hrl = filename:join(Dir, "back_5362.hrl"),
+ Back = <<"-module(back_5362).
+
+ -compile(export_all).
+
+ -file(?FILE, 1).
+ -include(\"back_5362.hrl\").
+
+ foo(V) -> % line 4
+ bar.
+ ">>,
+ Back_hrl = [<<"
+ -file(\"">>,File_Back,<<"\", 2).
+ ">>],
+
+ ?line ok = file:write_file(File_Back, Back),
+ ?line ok = file:write_file(File_Back_hrl, list_to_binary(Back_hrl)),
+
+ ?line {ok, back_5362, BackWarnings} = compile:file(File_Back, Copts),
+ ?line true = message_compare(
+ [{File_Back,[{{4,19},erl_lint,{unused_var,'V'}}]}],
+ BackWarnings),
+ file:delete(File_Back),
+ file:delete(File_Back_hrl),
+
+ %% Set filename but keep line.
+ File_Change = filename:join(Dir, "change_5362.erl"),
+ Change = [<<"-module(change_5362).
+
+ -file(?FILE, 100).
+
+ -compile(export_all).
+
+ -file(\"other.file\", ?LINE). % like an included file...
+ foo(A) -> % line 105
+ bar.
+
+ -file(\"">>,File_Change,<<"\", 1000).
+
+ bar(B) -> % line 1002
+ foo.
+ ">>],
+
+ ?line ok = file:write_file(File_Change, list_to_binary(Change)),
+
+ ?line {ok, change_5362, ChangeWarnings} =
+ compile:file(File_Change, Copts),
+ ?line true = message_compare(
+ [{File_Change,[{{1002,21},erl_lint,{unused_var,'B'}}]},
+ {"other.file",[{{105,21},erl_lint,{unused_var,'A'}}]}],
+ lists:usort(ChangeWarnings)),
+
+ file:delete(File_Change),
+
+ %% -file attribute ending with a blank (not a newline).
+ File_Blank = filename:join(Dir, "blank_5362.erl"),
+
+ Blank = <<"-module(blank_5362).
+
+ -compile(export_all).
+
+ -
+ file(?FILE, 18). q(Q) -> foo. % line 18
+
+ a(A) -> % line 20
+ 1.
+
+ -file(?FILE, 42).
+
+ b(B) -> % line 44
+ 2.
+
+ -file(?FILE, ?LINE). c(C) -> % line 47
+ 3.
+ ">>,
+ ?line ok = file:write_file(File_Blank, Blank),
+ ?line {ok, blank_5362, BlankWarnings} = compile:file(File_Blank, Copts),
+ ?line true = message_compare(
+ [{File_Blank,[{{18,3},erl_lint,{unused_var,'Q'}},
+ {{20,18},erl_lint,{unused_var,'A'}},
+ {{44,18},erl_lint,{unused_var,'B'}},
+ {{47,3},erl_lint,{unused_var,'C'}}]}],
+ lists:usort(BlankWarnings)),
+ file:delete(File_Blank),
+
+ %% __FILE__ is set by inclusion and by -file attribute
+ FILE_incl = filename:join(Dir, "file_5362.erl"),
+ FILE_incl1 = filename:join(Dir, "file_incl_5362.erl"),
+ FILE = <<"-module(file_5362).
+
+ -export([ff/0, ii/0]).
+
+ -include(\"file_incl_5362.erl\").
+
+ -file(\"other_file\", 100).
+
+ ff() ->
+ ?FILE.">>,
+ FILE1 = <<"ii() -> ?FILE.
+ ">>,
+ FILE_Mod = file_5362,
+ ?line ok = file:write_file(FILE_incl, FILE),
+ ?line ok = file:write_file(FILE_incl1, FILE1),
+ FILE_Copts = [return, {i,Dir},{outdir,Dir}],
+ ?line {ok, file_5362, []} = compile:file(FILE_incl, FILE_Copts),
+ AbsFile = filename:rootname(FILE_incl, ".erl"),
+ ?line {module, FILE_Mod} = code:load_abs(AbsFile, FILE_Mod),
+ ?line II = FILE_Mod:ii(),
+ ?line "file_incl_5362.erl" = filename:basename(II),
+ ?line FF = FILE_Mod:ff(),
+ ?line "other_file" = filename:basename(FF),
+ code:purge(file_5362),
+
+ file:delete(FILE_incl),
+ file:delete(FILE_incl1),
+
+ ok.
+
+pmod(Config) when is_list(Config) ->
+ ?line DataDir = ?config(data_dir, Config),
+ ?line Pmod = filename:join(DataDir, "pmod.erl"),
+ ?line case epp:parse_file([Pmod], [], []) of
+ {ok,Forms} ->
+ %% ?line io:format("~p\n", [Forms]),
+ ?line [] = [F || {error,_}=F <- Forms],
+ ok
+ end,
+ ok.
+
+not_circular(Config) when is_list(Config) ->
+ %% Used to generate a compilation error, wrongly saying that it
+ %% was a circular definition.
+
+ Ts = [{circular_1,
+ <<"-define(S(S), ??S).\n"
+ "t() -> \"string\" = ?S(string), ok.\n">>,
+ ok}],
+ ?line [] = run(Config, Ts),
+ ok.
+
+skip_header(doc) ->
+ ["Skip some bytes in the beginning of the file."];
+skip_header(suite) ->
+ [];
+skip_header(Config) when is_list(Config) ->
+ ?line PrivDir = ?config(priv_dir, Config),
+ ?line File = filename:join([PrivDir, "epp_test_skip_header.erl"]),
+ ?line ok = file:write_file(File,
+ <<"some bytes
+ in the beginning of the file
+ that should be skipped
+ -module(epp_test_skip_header).
+ -export([main/1]).
+
+ main(_) -> ?MODULE.
+
+ ">>),
+ ?line {ok, Fd} = file:open(File, [read]),
+ ?line io:get_line(Fd, ''),
+ ?line io:get_line(Fd, ''),
+ ?line io:get_line(Fd, ''),
+ ?line {ok, Epp} = epp:open(list_to_atom(File), Fd, 4, [], []),
+
+ ?line Forms = epp:parse_file(Epp),
+ ?line [] = [Reason || {error, Reason} <- Forms],
+ ?line ok = epp:close(Epp),
+ ?line ok = file:close(Fd),
+
+ ok.
+
+otp_6277(doc) ->
+ ["?MODULE before module declaration."];
+otp_6277(suite) ->
+ [];
+otp_6277(Config) when is_list(Config) ->
+ Ts = [{otp_6277,
+ <<"-undef(ASSERT).
+ -define(ASSERT, ?MODULE).
+
+ ?ASSERT().">>,
+ [{error,{{4,16},epp,{undefined,'MODULE'}}}]}],
+ ?line [] = check(Config, Ts),
+ ok.
+
+otp_7702(doc) ->
+ ["OTP-7702. Wrong line number in stringifying macro expansion."];
+otp_7702(suite) ->
+ [];
+otp_7702(Config) when is_list(Config) ->
+ Dir = ?config(priv_dir, Config),
+ File = filename:join(Dir, "file_7702.erl"),
+ Contents = <<"-module(file_7702).
+
+ -export([t/0]).
+
+ -define(RECEIVE(Msg,Body),
+ receive
+ Msg -> Body;
+ M ->
+ exit({unexpected_message,M,on_line,?LINE,was_expecting,??Msg})
+ after 10000 ->
+ exit({timeout,on_line,?LINE,was_expecting,??Msg})
+ end).
+ t() ->
+ ?RECEIVE(foo, bar).">>,
+ ?line ok = file:write_file(File, Contents),
+ ?line {ok, file_7702, []} =
+ compile:file(File, [debug_info,return,{outdir,Dir}]),
+
+ BeamFile = filename:join(Dir, "file_7702.beam"),
+ {ok, AC} = beam_lib:chunks(BeamFile, [abstract_code]),
+
+ {file_7702,[{abstract_code,{_,Forms}}]} = AC,
+ Fun = fun(Attrs) ->
+ {line, L} = erl_parse:get_attribute(Attrs, line),
+ L
+ end,
+ Forms2 = [erl_lint:modify_line(Form, Fun) || Form <- Forms],
+ ?line
+ [{attribute,1,file,_},
+ _,
+ _,
+ {function,_,t,0,
+ [{clause,_,[],[],
+ [{'receive',14,
+ [_,
+ {clause,14,
+ [{var,14,'M'}],
+ [],
+ [{_,_,_,
+ [{tuple,14,
+ [{atom,14,unexpected_message},
+ {var,14,'M'},
+ {atom,14,on_line},
+ {integer,14,14},
+ {atom,14,was_expecting},
+ {string,14,"foo"}]}]}]}],
+ {integer,14,10000},
+ [{call,14,
+ {atom,14,exit},
+ [{tuple,14,
+ [{atom,14,timeout},
+ {atom,14,on_line},
+ {integer,14,14},
+ {atom,14,was_expecting},
+ {string,14,"foo"}]}]}]}]}]},
+ {eof,14}] = Forms2,
+
+ file:delete(File),
+ file:delete(BeamFile),
+
+ ok.
+
+otp_8130(doc) ->
+ ["OTP-8130. Misc tests."];
+otp_8130(suite) ->
+ [];
+otp_8130(Config) when is_list(Config) ->
+ true = os:putenv("epp_inc1", "stdlib"),
+ Ts = [{otp_8130_1,
+ %% The scanner handles UNICODE in a special way. Hopefully
+ %% temporarily.
+ <<"-define(M(A), ??A). "
+ "t() -> "
+ " \"{ 34 , [ $1 , 2730 ] , \\\"34\\\" , X . a , 2730 }\" = "
+ " ?M({34,\"1\\x{aaa}\",\"34\",X.a,$\\x{aaa}}), ok. ">>,
+ ok},
+
+ {otp_8130_2,
+ <<"-define(M(A), ??B). "
+ "t() -> B = 18, 18 = ?M(34), ok. ">>,
+ ok},
+
+ {otp_8130_2a,
+ <<"-define(m(A), ??B). "
+ "t() -> B = 18, 18 = ?m(34), ok. ">>,
+ ok},
+
+ {otp_8130_3,
+ <<"-define(M1(A, B), {A,B}).\n"
+ "t0() -> 1.\n"
+ "t() ->\n"
+ " {2,7} =\n"
+ " ?M1(begin 1 = fun() -> 1 end(),\n" % Bug -R13B01
+ " 2 end,\n"
+ " 7),\n"
+ " {2,7} =\n"
+ " ?M1(begin 1 = fun t0/0(),\n"
+ " 2 end,\n"
+ " 7),\n"
+ " {2,7} =\n"
+ " ?M1(begin 2 = byte_size(<<\"34\">>),\n"
+ " 2 end,\n"
+ " 7),\n"
+ " R2 = math:sqrt(2.0),\n"
+ " {2,7} =\n"
+ " ?M1(begin yes = if R2 > 1 -> yes end,\n"
+ " 2 end,\n"
+ " 7),\n"
+ " {2,7} =\n"
+ " ?M1(begin yes = case R2 > 1 of true -> yes end,\n"
+ " 2 end,\n"
+ " 7),\n"
+ " {2,7} =\n"
+ " ?M1(begin yes = receive 1 -> 2 after 0 -> yes end,\n"
+ " 2 end,\n"
+ " 7),\n"
+ " {2,7} =\n"
+ " ?M1(begin yes = try 1 of 1 -> yes after foo end,\n"
+ " 2 end,\n"
+ " 7),\n"
+ "ok.\n">>,
+ ok},
+
+ {otp_8130_4,
+ <<"-define(M3(), A).\n"
+ "t() -> A = 1, ?M3(), ok.\n">>,
+ ok},
+
+ {otp_8130_5,
+ <<"-include_lib(\"$epp_inc1/include/qlc.hrl\").\n"
+ "t() -> [1] = qlc:e(qlc:q([X || X <- [1]])), ok.\n">>,
+ ok},
+
+ {otp_8130_6,
+ <<"-include_lib(\"kernel/include/file.hrl\").\n"
+ "t() -> 14 = (#file_info{size = 14})#file_info.size, ok.\n">>,
+ ok},
+
+ {otp_8130_7,
+ <<"-record(b, {b}).\n"
+ "-define(A, {{a,#b.b.\n"
+ "t() -> {{a,2}} = ?A}}, ok.">>,
+ ok},
+
+ {otp_8130_8,
+ <<"\n-define(A(B), B).\n"
+ "-undef(A).\n"
+ "-define(A, ok).\n"
+ "t() -> ?A.\n">>,
+ ok},
+ {otp_8130_9,
+ <<"-define(a, 1).\n"
+ "-define(b, {?a,?a}).\n"
+ "t() -> ?b.\n">>,
+ {1,1}}
+
+ ],
+ ?line [] = run(Config, Ts),
+
+ Cs = [{otp_8130_c1,
+ <<"-define(M1(A), if\n"
+ "A =:= 1 -> B;\n"
+ "true -> 2\n"
+ "end).\n"
+ "t() -> {?M1(1), ?M1(2)}. \n">>,
+ {errors,[{{5,13},erl_lint,{unbound_var,'B'}},
+ {{5,21},erl_lint,{unbound_var,'B'}}],
+ []}},
+
+ {otp_8130_c2,
+ <<"-define(M(A), A).\n"
+ "t() -> ?M(1\n">>,
+ {errors,[{{2,9},epp,{arg_error,'M'}}],[]}},
+
+ {otp_8130_c3,
+ <<"-define(M(A), A).\n"
+ "t() -> ?M.\n">>,
+ {errors,[{{2,9},epp,{mismatch,'M'}}],[]}},
+
+ {otp_8130_c4,
+ <<"-define(M(A), A).\n"
+ "t() -> ?M(1, 2).\n">>,
+ {errors,[{{2,9},epp,{mismatch,'M'}}],[]}},
+
+ {otp_8130_c5,
+ <<"-define(M(A), A).\n"
+ "t() -> ?M().\n">>,
+ {errors,[{{2,9},epp,{mismatch,'M'}}],[]}},
+
+ {otp_8130_c6,
+ <<"-define(M3(), A).\n"
+ "t() -> A = 1, ?3.14159}.\n">>,
+ {errors,[{{2,16},epp,{call,"?3.14159"}}],[]}},
+
+ {otp_8130_c7,
+ <<"\nt() -> ?A.\n">>,
+ {errors,[{{2,9},epp,{undefined,'A'}}],[]}},
+
+ {otp_8130_c8,
+ <<"\n-include_lib(\"$apa/foo.hrl\").\n">>,
+ {errors,[{{2,2},epp,{include,lib,"$apa/foo.hrl"}}],[]}},
+
+
+ {otp_8130_c9,
+ <<"-define(S, ?S).\n"
+ "t() -> ?S.\n">>,
+ {errors,[{{2,9},epp,{circular,'S'}}],[]}},
+
+ {otp_8130_c10,
+ <<"\n-file.">>,
+ {errors,[{{2,2},epp,{bad,file}}],[]}},
+
+ {otp_8130_c11,
+ <<"\n-include_lib 92.">>,
+ {errors,[{{2,2},epp,{bad,include_lib}}],[]}},
+
+ {otp_8130_c12,
+ <<"\n-include_lib(\"kernel/include/fopp.hrl\").\n">>,
+ {errors,[{{2,2},epp,{include,lib,"kernel/include/fopp.hrl"}}],[]}},
+
+ {otp_8130_c13,
+ <<"\n-include(foo).\n">>,
+ {errors,[{{2,2},epp,{bad,include}}],[]}},
+
+ {otp_8130_c14,
+ <<"\n-undef({foo}).\n">>,
+ {errors,[{{2,2},epp,{bad,undef}}],[]}},
+
+ {otp_8130_c15,
+ <<"\n-define(a, 1).\n"
+ "-define(a, 1).\n">>,
+ {errors,[{{3,9},epp,{redefine,a}}],[]}},
+
+ {otp_8130_c16,
+ <<"\n-define(A, 1).\n"
+ "-define(A, 1).\n">>,
+ {errors,[{{3,9},epp,{redefine,'A'}}],[]}},
+
+ {otp_8130_c17,
+ <<"\n-define(A(B), B).\n"
+ "-define(A, 1).\n">>,
+ {errors,[{{3,9},epp,{redefine,'A'}}],[]}},
+
+ {otp_8130_c18,
+ <<"\n-define(A, 1).\n"
+ "-define(A(B), B).\n">>,
+ {errors,[{{3,9},epp,{redefine,'A'}}],[]}},
+
+ {otp_8130_c19,
+ <<"\n-define(a(B), B).\n"
+ "-define(a, 1).\n">>,
+ {errors,[{{3,9},epp,{redefine,a}}],[]}},
+
+ {otp_8130_c20,
+ <<"\n-define(a, 1).\n"
+ "-define(a(B), B).\n">>,
+ {errors,[{{3,9},epp,{redefine,a}}],[]}},
+
+ {otp_8130_c21,
+ <<"\n-define(A(B, B), B).\n">>,
+ {errors,[{{2,2},epp,{bad,define}}],[]}},
+
+ {otp_8130_c22,
+ <<"\n-define(a(B, B), B).\n">>,
+ {errors,[{{2,2},epp,{bad,define}}],[]}},
+
+ {otp_8130_c23,
+ <<"\n-file(?b, 3).\n">>,
+ {errors,[{{2,8},epp,{undefined,b}}],[]}},
+
+ {otp_8130_c24,
+ <<"\n-include(\"no such file.erl\").\n">>,
+ {errors,[{{2,2},epp,{include,file,"no such file.erl"}}],[]}}
+
+ ],
+ ?line [] = compile(Config, Cs),
+
+ Cks = [{otp_check_1,
+ <<"\n-include_lib(\"epp_test.erl\").\n">>,
+ [{error,{{2,2},epp,{depth,"include_lib"}}}]},
+
+ {otp_check_2,
+ <<"\n-include(\"epp_test.erl\").\n">>,
+ [{error,{{2,2},epp,{depth,"include"}}}]}
+ ],
+ ?line [] = check(Config, Cks),
+
+ ?line Dir = ?config(priv_dir, Config),
+ ?line File = filename:join(Dir, "otp_8130.erl"),
+ ?line ok = file:write_file(File,
+ "-module(otp_8130).\n"
+ "-define(a, 3.14).\n"
+ "t() -> ?a.\n"),
+ ?line {ok,Epp} = epp:open(File, []),
+ ?line ['BASE_MODULE','BASE_MODULE_STRING','BEAM','FILE','LINE',
+ 'MACHINE','MODULE','MODULE_STRING'] = macs(Epp),
+ ?line {ok,[{'-',_},{atom,_,file}|_]} = epp:scan_erl_form(Epp),
+ ?line {ok,[{'-',_},{atom,_,module}|_]} = epp:scan_erl_form(Epp),
+ ?line {ok,[{atom,_,t}|_]} = epp:scan_erl_form(Epp),
+ ?line {eof,_} = epp:scan_erl_form(Epp),
+ ?line ['BASE_MODULE','BASE_MODULE_STRING','BEAM','FILE','LINE',
+ 'MACHINE','MODULE','MODULE_STRING',a] = macs(Epp),
+ ?line epp:close(Epp),
+
+ %% escript
+ ModuleStr = "any_name",
+ Module = list_to_atom(ModuleStr),
+ fun() ->
+ PreDefMacros = [{'MODULE', Module, redefine},
+ {'MODULE_STRING', ModuleStr, redefine},
+ a, {b,2}],
+ ?line {ok,Epp2} = epp:open(File, [], PreDefMacros),
+ ?line [{atom,_,true}] = macro(Epp2, a),
+ ?line [{integer,_,2}] = macro(Epp2, b),
+ ?line false = macro(Epp2, c),
+ ?line epp:close(Epp2)
+ end(),
+ fun() ->
+ PreDefMacros = [{a,b,c}],
+ ?line {error,{bad,{a,b,c}}} = epp:open(File, [], PreDefMacros)
+ end(),
+ fun() ->
+ PreDefMacros = [a, {a,1}],
+ ?line {error,{redefine,a}} = epp:open(File, [], PreDefMacros)
+ end(),
+ fun() ->
+ PreDefMacros = [{a,1},a],
+ ?line {error,{redefine,a}} = epp:open(File, [], PreDefMacros)
+ end(),
+
+ ?line {error,enoent} = epp:open("no such file", []),
+ ?line {error,enoent} = epp:parse_file("no such file", [], []),
+
+ _ = ifdef(Config),
+
+ ok.
+
+macs(Epp) ->
+ Macros = epp:macro_defs(Epp), % not documented
+ lists:sort([MName || {{atom,MName},_} <- Macros]).
+
+macro(Epp, N) ->
+ case lists:keyfind({atom,N}, 1, epp:macro_defs(Epp)) of
+ false -> false;
+ {{atom,N},{_,V}} -> V
+ end.
+
+ifdef(Config) ->
+ Cs = [{ifdef_c1,
+ <<"-ifdef(a).\n"
+ "a bug.\n"
+ "-else.\n"
+ "-ifdef(A).\n"
+ "a bug.\n"
+ "-endif.\n"
+ "-else.\n"
+ "t() -> ok.\n"
+ "-endif.">>,
+ {errors,[{{7,2},epp,{illegal,"repeated",'else'}}],[]}},
+
+ {ifdef_c2,
+ <<"-define(a, true).\n"
+ "-ifdef(a).\n"
+ "a bug.\n"
+ "-endif.">>,
+ {errors,[{{3,3},erl_parse,["syntax error before: ","bug"]}],[]}},
+
+ {ifdef_c3,
+ <<"-define(a, true).\n"
+ "-ifdef(a).\n"
+ "-endif">>,
+
+ {errors,[{{3,2},epp,{bad,endif}},
+ {{3,7},epp,{illegal,"unterminated",ifdef}}],
+ []}},
+
+ {ifdef_c4,
+ <<"\n-ifdef a.\n"
+ "-endif.\n">>,
+ {errors,[{{2,2},epp,{bad,ifdef}}],[]}},
+
+ {ifdef_c5,
+ <<"-ifdef(a).\n"
+ "-else.\n"
+ "-endif.\n"
+ "-endif.\n">>,
+ {errors,[{{4,2},epp,{illegal,"unbalanced",endif}}],[]}},
+
+ {ifdef_c6,
+ <<"-ifdef(a).\n"
+ "-else.\n"
+ "-endif.\n"
+ "-else.\n">>,
+ {errors,[{{4,2},epp,{illegal,"unbalanced",'else'}}],[]}},
+
+ {ifdef_c7,
+ <<"-ifndef(a).\n"
+ "-else\n"
+ "foo bar\n"
+ "-else.\n"
+ "t() -> a.\n"
+ "-endif.\n">>,
+ {errors,[{{2,2},epp,{bad,else}}],[]}},
+
+ {ifdef_c8,
+ <<"-ifdef(a).\n"
+ "-foo bar.">>,
+ {errors,[{{2,10},epp,{illegal,"unterminated",ifdef}}],[]}},
+
+ {ifdef_c9,
+ <<"-ifdef(a).\n"
+ "3.3e12000.\n"
+ "-endif.\n">>,
+ []},
+
+ {ifdef_c10,
+ <<"\nt() -> 3.3e12000.\n">>,
+ {errors,[{{2,8},erl_scan,{illegal,float}},
+ {{2,17},erl_parse,["syntax error before: ","'.'"]}], % ...
+ []}},
+
+ {ifndef_c1,
+ <<"-ifndef(a).\n"
+ "-ifndef(A).\n"
+ "t() -> ok.\n"
+ "-endif.\n"
+ "-else.\n"
+ "a bug.\n"
+ "-else.\n"
+ "a bug.\n"
+ "-endif.">>,
+ {errors,[{{7,2},epp,{illegal,"repeated",'else'}}],[]}},
+
+ {ifndef_c3,
+ <<"-ifndef(a).\n"
+ "-endif">>,
+
+ {errors,[{{2,2},epp,{bad,endif}},
+ {{2,7},epp,{illegal,"unterminated",ifndef}}],
+ []}},
+
+ {ifndef_c4,
+ <<"\n-ifndef a.\n"
+ "-endif.\n">>,
+ {errors,[{{2,2},epp,{bad,ifndef}}],[]}},
+
+ {define_c5,
+ <<"-\ndefine a.\n">>,
+ {errors,[{{2,1},epp,{bad,define}}],[]}},
+
+ {define_c6,
+ <<"\n-if.\n"
+ "-endif.\n">>,
+ {errors,[{{2,2},epp,{'NYI','if'}}],[]}},
+
+ {define_c7,
+ <<"-ifndef(a).\n"
+ "-elif.\n"
+ "-endif.\n">>,
+ {errors,[{{2,2},epp,{'NYI',elif}}],[]}},
+
+ {define_c7,
+ <<"-ifndef(a).\n"
+ "-if.\n"
+ "-elif.\n"
+ "-endif.\n"
+ "-endif.\n"
+ "t() -> a.\n">>,
+ {errors,[{{2,2},epp,{'NYI','if'}}],[]}}
+ ],
+ ?line [] = compile(Config, Cs),
+
+ Ts = [{ifdef_1,
+ <<"-ifdef(a).\n"
+ "a bug.\n"
+ "-else.\n"
+ "-ifdef(A).\n"
+ "a bug.\n"
+ "-endif.\n"
+ "t() -> ok.\n"
+ "-endif.">>,
+ ok},
+
+ {ifdef_2,
+ <<"-define(a, true).\n"
+ "-ifdef(a).\n"
+ "-define(A, true).\n"
+ "-ifdef(A).\n"
+ "t() -> ok.\n"
+ "-else.\n"
+ "a bug.\n"
+ "-endif.\n"
+ "-else.\n"
+ "a bug.\n"
+ "-endif.">>,
+ ok},
+
+ {ifdef_3,
+ <<"\n-define(a, true).\n"
+ "-ifndef(a).\n"
+ "a bug.\n"
+ "-else.\n"
+ "-define(A, true).\n"
+ "-ifndef(A).\n"
+ "a bug.\n"
+ "-else.\n"
+ "t() -> ok.\n"
+ "-endif.\n"
+ "-endif.">>,
+ ok},
+
+ {ifdef_4,
+ <<"-ifdef(a).\n"
+ "a bug.\n"
+ "-ifdef(a).\n"
+ "a bug.\n"
+ "-else.\n"
+ "-endif.\n"
+ "-ifdef(A).\n"
+ "a bug.\n"
+ "-endif.\n"
+ "-else.\n"
+ "t() -> ok.\n"
+ "-endif.">>,
+ ok},
+
+ {ifdef_5,
+ <<"-ifdef(a).\n"
+ "-ifndef(A).\n"
+ "a bug.\n"
+ "-else.\n"
+ "-endif.\n"
+ "a bug.\n"
+ "-else.\n"
+ "t() -> ok.\n"
+ "-endif.">>,
+ ok},
+
+ {ifdef_6,
+ <<"-ifdef(a).\n"
+ "-if(A).\n"
+ "a bug.\n"
+ "-else.\n"
+ "-endif.\n"
+ "a bug.\n"
+ "-else.\n"
+ "t() -> ok.\n"
+ "-endif.">>,
+ ok}
+
+ ],
+ ?line [] = run(Config, Ts).
+
+check(Config, Tests) ->
+ eval_tests(Config, fun check_test/2, Tests).
+
+compile(Config, Tests) ->
+ eval_tests(Config, fun compile_test/2, Tests).
+
+run(Config, Tests) ->
+ eval_tests(Config, fun run_test/2, Tests).
+
+eval_tests(Config, Fun, Tests) ->
+ F = fun({N,P,E}, BadL) ->
+ %% io:format("Testing ~p~n", [P]),
+ Return = Fun(Config, P),
+ case message_compare(E, Return) of
+ true ->
+ BadL;
+ false ->
+ ?t:format("~nTest ~p failed. Expected~n ~p~n"
+ "but got~n ~p~n", [N, E, Return]),
+ fail()
+ end
+ end,
+ lists:foldl(F, [], Tests).
+
+
+check_test(Config, Test) ->
+ Filename = 'epp_test.erl',
+ ?line PrivDir = ?config(priv_dir, Config),
+ ?line File = filename:join(PrivDir, Filename),
+ ?line ok = file:write_file(File, Test),
+ ?line case epp:parse_file(File, [PrivDir], []) of
+ {ok,Forms} ->
+ [E || E={error,_} <- Forms];
+ {error,Error} ->
+ Error
+ end.
+
+compile_test(Config, Test0) ->
+ Test = [<<"-module(epp_test). -compile(export_all). ">>, Test0],
+ Filename = 'epp_test.erl',
+ ?line PrivDir = ?config(priv_dir, Config),
+ ?line File = filename:join(PrivDir, Filename),
+ ?line ok = file:write_file(File, Test),
+ Opts = [export_all,return,nowarn_unused_record,{outdir,PrivDir}],
+ case compile_file(File, Opts) of
+ {ok, Ws} -> warnings(File, Ws);
+ Else -> Else
+ end.
+
+warnings(File, Ws) ->
+ case lists:append([W || {F, W} <- Ws, F =:= File]) of
+ [] -> [];
+ L -> {warnings, L}
+ end.
+
+compile_file(File, Opts) ->
+ case compile:file(File, Opts) of
+ {ok, _M, Ws} -> {ok, Ws};
+ {error, FEs, []} -> {errors, errs(FEs, File), []};
+ {error, FEs, [{File,Ws}]} -> {error, errs(FEs, File), Ws}
+ end.
+
+errs([{File,Es}|L], File) ->
+ Es ++ errs(L, File);
+errs([_|L], File) ->
+ errs(L, File);
+errs([], _File) ->
+ [].
+
+run_test(Config, Test0) ->
+ Test = [<<"-module(epp_test). -compile(export_all). ">>, Test0],
+ Filename = "epp_test.erl",
+ ?line PrivDir = ?config(priv_dir, Config),
+ ?line File = filename:join(PrivDir, Filename),
+ ?line ok = file:write_file(File, Test),
+ Opts = [return, {i,PrivDir},{outdir,PrivDir}],
+ ?line {ok, epp_test, []} = compile:file(File, Opts),
+ AbsFile = filename:rootname(File, ".erl"),
+ ?line {module, epp_test} = code:load_abs(AbsFile, epp_test),
+ ?line Reply = epp_test:t(),
+ code:purge(epp_test),
+ Reply.
+
+fail() ->
+ io:format("failed~n"),
+ test_server:fail().
+
+message_compare(T, T) ->
+ true;
+message_compare(T1, T2) ->
+ ln(T1) =:= T2.
+
+%% Replaces locations like {Line,Column} with Line.
+ln({warnings,L}) ->
+ {warnings,ln0(L)};
+ln({errors,EL,WL}) ->
+ {errors,ln0(EL),ln0(WL)};
+ln(L) ->
+ ln0(L).
+
+ln0(L) ->
+ lists:keysort(1, ln1(L)).
+
+ln1([]) ->
+ [];
+ln1([{File,Ms}|MsL]) when is_list(File) ->
+ [{File,ln0(Ms)}|ln1(MsL)];
+ln1([M|Ms]) ->
+ [ln2(M)|ln1(Ms)].
+
+ln2({{L,_C},Mod,Mess}) ->
+ {L,Mod,Mess};
+ln2({error,M}) ->
+ {error,ln2(M)};
+ln2(M) ->
+ M.
diff --git a/lib/stdlib/test/epp_SUITE_data/mac.erl b/lib/stdlib/test/epp_SUITE_data/mac.erl
new file mode 100644
index 0000000000..e3329d76f9
--- /dev/null
+++ b/lib/stdlib/test/epp_SUITE_data/mac.erl
@@ -0,0 +1,46 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1998-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(mac).
+
+-compile(export_all).
+
+-define(A, ?A + ?A).
+
+-define(a, ?a + ?a).
+-define(b, x + ?c(2)).
+-define(c(Y), x + Y).
+-define(d(X), X X).
+
+bar() ->
+ 1 ?d(?d(?d(?d(?d(?d(?d(+1))))))).
+
+foo1() ->
+ ?a.
+
+foo2() ->
+ ?b.
+
+foo3() ->
+ ?A.
+
+-define( this, ?that).
+-define( that, ?this).
+
+talkAbout()->
+ ?this==?that.
diff --git a/lib/stdlib/test/epp_SUITE_data/mac2.erl b/lib/stdlib/test/epp_SUITE_data/mac2.erl
new file mode 100644
index 0000000000..0547cdb8b3
--- /dev/null
+++ b/lib/stdlib/test/epp_SUITE_data/mac2.erl
@@ -0,0 +1,38 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1998-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-ifndef(p).
+-define(p, 1).
+-endif.
+
+-ifndef('p').
+-define('p', 2).
+-endif.
+
+-ifndef(P).
+-define(P, 3).
+-endif.
+
+-ifndef('P').
+-define('P', 4).
+-endif.
+
+-plupp({?p,
+ ?'p',
+ ?P,
+ ?'P'}).
diff --git a/lib/stdlib/test/epp_SUITE_data/mac3.erl b/lib/stdlib/test/epp_SUITE_data/mac3.erl
new file mode 100644
index 0000000000..e5fb964a91
--- /dev/null
+++ b/lib/stdlib/test/epp_SUITE_data/mac3.erl
@@ -0,0 +1,36 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1998-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-l(?LINE).
+
+-f(?FILE).
+
+-machine1(?MACHINE).
+
+-module(mac3).
+
+-m(?MODULE).
+-ms(?MODULE_STRING).
+
+-ifdef(JAM).
+-machine2(jam).
+-endif.
+
+-ifdef(BEAM).
+-machine2(beam).
+-endif.
diff --git a/lib/stdlib/test/epp_SUITE_data/pmod.erl b/lib/stdlib/test/epp_SUITE_data/pmod.erl
new file mode 100644
index 0000000000..a4d4843a69
--- /dev/null
+++ b/lib/stdlib/test/epp_SUITE_data/pmod.erl
@@ -0,0 +1,25 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(pmod, [Props]).
+
+-export([update/1]).
+
+update(X) ->
+ ?MODULE:new(X).
+
diff --git a/lib/stdlib/test/epp_SUITE_data/variable_1.erl b/lib/stdlib/test/epp_SUITE_data/variable_1.erl
new file mode 100644
index 0000000000..b178f519a9
--- /dev/null
+++ b/lib/stdlib/test/epp_SUITE_data/variable_1.erl
@@ -0,0 +1,24 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2002-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(variable_1).
+
+-include("$VAR/variable_1_include.hrl").
+-include_lib("$VAR/variable_1_include_dir.hrl").
+
+-a({?variable_1_var1, ?variable_1_var2}).
diff --git a/lib/stdlib/test/epp_SUITE_data/variable_1_include.hrl b/lib/stdlib/test/epp_SUITE_data/variable_1_include.hrl
new file mode 100644
index 0000000000..039d72aa49
--- /dev/null
+++ b/lib/stdlib/test/epp_SUITE_data/variable_1_include.hrl
@@ -0,0 +1,19 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2002-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-define(variable_1_var1, value1).
diff --git a/lib/stdlib/test/epp_SUITE_data/variable_1_include_dir.hrl b/lib/stdlib/test/epp_SUITE_data/variable_1_include_dir.hrl
new file mode 100644
index 0000000000..727ccd421b
--- /dev/null
+++ b/lib/stdlib/test/epp_SUITE_data/variable_1_include_dir.hrl
@@ -0,0 +1,19 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2002-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-define(variable_1_var2, value2).
diff --git a/lib/stdlib/test/erl_eval_SUITE.erl b/lib/stdlib/test/erl_eval_SUITE.erl
new file mode 100644
index 0000000000..c60a558fa1
--- /dev/null
+++ b/lib/stdlib/test/erl_eval_SUITE.erl
@@ -0,0 +1,1399 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1998-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+
+-module(erl_eval_SUITE).
+-export([all/1]).
+
+-export([guard_1/1, guard_2/1,
+ match_pattern/1,
+ match_bin/1,
+ string_plusplus/1,
+ pattern_expr/1,
+ guard_3/1, guard_4/1,
+ lc/1,
+ simple_cases/1,
+ unary_plus/1,
+ apply_atom/1,
+ otp_5269/1,
+ otp_6539/1,
+ otp_6543/1,
+ otp_6787/1,
+ otp_6977/1,
+ otp_7550/1,
+ otp_8133/1,
+ funs/1,
+ try_catch/1,
+ eval_expr_5/1]).
+
+%%
+%% Define to run outside of test server
+%%
+%%-define(STANDALONE,1).
+
+-import(lists,[concat/1, sort/1]).
+
+-export([count_down/2, count_down_fun/0, do_apply/2,
+ local_func/3, local_func_value/2]).
+
+-ifdef(STANDALONE).
+-define(config(A,B),config(A,B)).
+-export([config/2]).
+-define(line, noop, ).
+config(priv_dir,_) ->
+ ".".
+-else.
+-include("test_server.hrl").
+-export([init_per_testcase/2, fin_per_testcase/2]).
+% Default timetrap timeout (set in init_per_testcase).
+-define(default_timeout, ?t:minutes(1)).
+init_per_testcase(_Case, Config) ->
+ ?line Dog = ?t:timetrap(?default_timeout),
+ [{watchdog, Dog} | Config].
+fin_per_testcase(_Case, Config) ->
+ Dog = ?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+-endif.
+
+all(doc) ->
+ ["Test cases for the 'erl_eval' module."];
+all(suite) ->
+ [guard_1, guard_2, match_pattern, string_plusplus, pattern_expr,
+ match_bin, guard_3, guard_4,
+ lc, simple_cases, unary_plus, apply_atom, otp_5269, otp_6539, otp_6543,
+ otp_6787, otp_6977, otp_7550, otp_8133, funs, try_catch, eval_expr_5].
+
+guard_1(doc) ->
+ ["(OTP-2405)"];
+guard_1(suite) ->
+ [];
+guard_1(Config) when is_list(Config) ->
+ ?line {ok,Tokens ,_} =
+ erl_scan:string("if a+4 == 4 -> yes; true -> no end. "),
+ ?line {ok, [Expr]} = erl_parse:parse_exprs(Tokens),
+ ?line no = guard_1_compiled(),
+ ?line {value, no, []} = erl_eval:expr(Expr, []),
+ ok.
+
+guard_1_compiled() ->
+ if a+4 == 4 -> yes; true -> no end.
+
+guard_2(doc) ->
+ ["Similar to guard_1, but type-correct"];
+guard_2(suite) ->
+ [];
+guard_2(Config) when is_list(Config) ->
+ ?line {ok,Tokens ,_} =
+ erl_scan:string("if 6+4 == 4 -> yes; true -> no end. "),
+ ?line {ok, [Expr]} = erl_parse:parse_exprs(Tokens),
+ ?line no = guard_2_compiled(),
+ ?line {value, no, []} = erl_eval:expr(Expr, []),
+ ok.
+
+guard_2_compiled() ->
+ if 6+4 == 4 -> yes; true -> no end.
+
+string_plusplus(doc) ->
+ ["OTP-3069: syntactic sugar string ++ ..."];
+string_plusplus(suite) ->
+ [];
+string_plusplus(Config) when is_list(Config) ->
+ ?line check(fun() -> case "abc" of "ab" ++ L -> L end end,
+ "case \"abc\" of \"ab\" ++ L -> L end. ",
+ "c"),
+ ?line check(fun() -> case "abcde" of "ab" ++ "cd" ++ L -> L end end,
+ "case \"abcde\" of \"ab\" ++ \"cd\" ++ L -> L end. ",
+ "e"),
+ ?line check(fun() -> case "abc" of [97, 98] ++ L -> L end end,
+ "case \"abc\" of [97, 98] ++ L -> L end. ",
+ "c"),
+ ok.
+
+match_pattern(doc) ->
+ ["OTP-2983: match operator in pattern"];
+match_pattern(suite) ->
+ [];
+match_pattern(Config) when is_list(Config) ->
+ ?line check(fun() -> case {a, b} of {a, _X}=Y -> {x,Y} end end,
+ "case {a, b} of {a, X}=Y -> {x,Y} end. ",
+ {x, {a, b}}),
+ ?line check(fun() -> case {a, b} of Y={a, _X} -> {x,Y} end end,
+ "case {a, b} of Y={a, X} -> {x,Y} end. ",
+ {x, {a, b}}),
+ ?line check(fun() -> case {a, b} of Y={a, _X}=Z -> {Z,Y} end end,
+ "case {a, b} of Y={a, X}=Z -> {Z,Y} end. ",
+ {{a, b}, {a, b}}),
+ ?line check(fun() -> A = 4, B = 28, <<13:(A+(X=B))>>, X end,
+ "begin A = 4, B = 28, <<13:(A+(X=B))>>, X end.",
+ 28),
+ ok.
+
+match_bin(doc) ->
+ ["binary match problems"];
+match_bin(suite) ->
+ [];
+match_bin(Config) when is_list(Config) ->
+ ?line check(fun() -> <<"abc">> = <<"abc">> end,
+ "<<\"abc\">> = <<\"abc\">>. ",
+ <<"abc">>),
+ ?line check(fun() ->
+ <<Size,B:Size/binary,Rest/binary>> = <<2,"AB","CD">>,
+ {Size,B,Rest}
+ end,
+ "begin <<Size,B:Size/binary,Rest/binary>> = <<2,\"AB\",\"CD\">>, "
+ "{Size,B,Rest} end. ",
+ {2,<<"AB">>,<<"CD">>}),
+ ok.
+
+pattern_expr(doc) ->
+ ["OTP-3144: compile-time expressions in pattern"];
+pattern_expr(suite) ->
+ [];
+pattern_expr(Config) when is_list(Config) ->
+ ?line check(fun() -> case 4 of 2+2 -> ok end end,
+ "case 4 of 2+2 -> ok end. ",
+ ok),
+ ?line check(fun() -> case 2 of +2 -> ok end end,
+ "case 2 of +2 -> ok end. ",
+ ok),
+ ok.
+
+guard_3(doc) ->
+ ["OTP-4518."];
+guard_3(suite) ->
+ [];
+guard_3(Config) when is_list(Config) ->
+ ?line check(fun() -> if false -> false; true -> true end end,
+ "if false -> false; true -> true end.",
+ true),
+ ?line check(fun() -> if <<"hej">> == <<"hopp">> -> true;
+ true -> false end end,
+ "begin if <<\"hej\">> == <<\"hopp\">> -> true;
+ true -> false end end.",
+ false),
+ ?line check(fun() -> if <<"hej">> == <<"hej">> -> true;
+ true -> false end end,
+ "begin if <<\"hej\">> == <<\"hej\">> -> true;
+ true -> false end end.",
+ true),
+ ok.
+
+guard_4(doc) ->
+ ["OTP-4885."];
+guard_4(suite) ->
+ [];
+guard_4(Config) when is_list(Config) ->
+ ?line check(fun() -> if {erlang,'+'}(3,a) -> true ; true -> false end end,
+ "if {erlang,'+'}(3,a) -> true ; true -> false end.",
+ false),
+ ?line check(fun() -> if {erlang,is_integer}(3) -> true ; true -> false end
+ end,
+ "if {erlang,is_integer}(3) -> true ; true -> false end.",
+ true),
+ ?line check(fun() -> [X || X <- [1,2,3], erlang:is_integer(X)] end,
+ "[X || X <- [1,2,3], erlang:is_integer(X)].",
+ [1,2,3]),
+ ?line check(fun() -> if is_atom(is_integer(a)) -> true ; true -> false end
+ end,
+ "if is_atom(is_integer(a)) -> true ; true -> false end.",
+ true),
+ ?line check(fun() -> if {erlang,is_atom}({erlang,is_integer}(a)) -> true;
+ true -> false end end,
+ "if {erlang,is_atom}({erlang,is_integer}(a)) -> true; "
+ "true -> false end.",
+ true),
+ ?line check(fun() -> if is_atom(3+a) -> true ; true -> false end end,
+ "if is_atom(3+a) -> true ; true -> false end.",
+ false),
+ ?line check(fun() -> if erlang:is_atom(3+a) -> true ; true -> false end
+ end,
+ "if erlang:is_atom(3+a) -> true ; true -> false end.",
+ false),
+ ok.
+
+
+lc(doc) ->
+ ["OTP-4518."];
+lc(suite) ->
+ [];
+lc(Config) when is_list(Config) ->
+ ?line check(fun() -> X = 32, [X || X <- [1,2,3]] end,
+ "begin X = 32, [X || X <- [1,2,3]] end.",
+ [1,2,3]),
+ ?line check(fun() -> X = 32,
+ [X || <<X:X>> <- [<<1:32>>,<<2:32>>,<<3:8>>]] end,
+ %% "binsize variable" ^
+ "begin X = 32,
+ [X || <<X:X>> <- [<<1:32>>,<<2:32>>,<<3:8>>]] end.",
+ [1,2]),
+ ?line check(fun() -> Y = 13,[X || {X,Y} <- [{1,2}]] end,
+ "begin Y = 13,[X || {X,Y} <- [{1,2}]] end.",
+ [1]),
+ ?line error_check("begin [A || X <- [{1,2}], 1 == A] end.",
+ {unbound_var,'A'}),
+ ?line error_check("begin X = 32,
+ [{Y,W} || X <- [1,2,32,Y=4], Z <- [1,2,W=3]] end.",
+ {unbound_var,'Y'}),
+ ?line error_check("begin X = 32,<<A:B>> = <<100:X>> end.",
+ {unbound_var,'B'}),
+ ?line check(fun() -> [X || X <- [1,2,3,4], not (X < 2)] end,
+ "begin [X || X <- [1,2,3,4], not (X < 2)] end.",
+ [2,3,4]),
+ ?line check(fun() -> [X || X <- [true,false], X] end,
+ "[X || X <- [true,false], X].", [true]),
+ ok.
+
+simple_cases(doc) ->
+ ["Simple cases, just to cover some code."];
+simple_cases(suite) ->
+ [];
+simple_cases(Config) when is_list(Config) ->
+ ?line check(fun() -> A = $C end, "A = $C.", $C),
+ %% ?line check(fun() -> A = 3.14 end, "A = 3.14.", 3.14),
+ ?line check(fun() -> self() ! a, A = receive a -> true end end,
+ "begin self() ! a, A = receive a -> true end end.",
+ true),
+ ?line check(fun() -> c:flush(), self() ! a, self() ! b, self() ! c,
+ receive b -> b end,
+ {messages, [a,c]} =
+ erlang:process_info(self(), messages),
+ c:flush() end,
+ "begin c:flush(), self() ! a, self() ! b, self() ! c,"
+ "receive b -> b end,"
+ "{messages, [a,c]} ="
+ " erlang:process_info(self(), messages), c:flush() end.",
+ ok),
+ ?line check(fun() -> self() ! a, A = receive a -> true
+ after 0 -> false end end,
+ "begin self() ! a, A = receive a -> true"
+ " after 0 -> false end end.",
+ true),
+ ?line check(fun() -> c:flush(), self() ! a, self() ! b, self() ! c,
+ receive b -> b after 0 -> true end,
+ {messages, [a,c]} =
+ erlang:process_info(self(), messages),
+ c:flush() end,
+ "begin c:flush(), self() ! a, self() ! b, self() ! c,"
+ "receive b -> b after 0 -> true end,"
+ "{messages, [a,c]} ="
+ " erlang:process_info(self(), messages), c:flush() end.",
+ ok),
+ ?line check(fun() -> receive _ -> true after 10 -> false end end,
+ "receive _ -> true after 10 -> false end.",
+ false),
+ ?line check(fun() -> F = fun(A) -> A end, true = 3 == F(3) end,
+ "begin F = fun(A) -> A end, true = 3 == F(3) end.",
+ true),
+ ?line check(fun() -> F = fun(A) -> A end, true = 3 == apply(F, [3]) end,
+ "begin F = fun(A) -> A end, true = 3 == apply(F,[3]) end.",
+ true),
+ ?line check(fun() -> catch throw(a) end, "catch throw(a).", a),
+ ?line check(fun() -> catch a end, "catch a.", a),
+ ?line check(fun() -> 4 == 3 end, "4 == 3.", false),
+ ?line check(fun() -> not true end, "not true.", false),
+ ?line check(fun() -> -3 end, "-3.", -3),
+
+ ?line error_check("3.0 = 4.0.", {badmatch,4.0}),
+ ?line check(fun() -> <<(3.0+2.0):32/float>> = <<5.0:32/float>> end,
+ "<<(3.0+2.0):32/float>> = <<5.0:32/float>>.",
+ <<5.0:32/float>>),
+
+ ?line check(fun() -> false andalso kludd end, "false andalso kludd.",
+ false),
+ ?line check(fun() -> true andalso true end, "true andalso true.",
+ true),
+ ?line check(fun() -> true andalso false end, "true andalso false.",
+ false),
+ ?line check(fun() -> true andalso kludd end, "true andalso kludd.",
+ kludd),
+ ?line error_check("kladd andalso kludd.", {badarg,kladd}),
+
+ ?line check(fun() -> if false andalso kludd -> a; true -> b end end,
+ "if false andalso kludd -> a; true -> b end.",
+ b),
+ ?line check(fun() -> if true andalso true -> a; true -> b end end,
+ "if true andalso true -> a; true -> b end.",
+ a),
+ ?line check(fun() -> if true andalso false -> a; true -> b end end,
+ "if true andalso false -> a; true -> b end.",
+ b),
+
+ ?line check(fun() -> true orelse kludd end,
+ "true orelse kludd.", true),
+ ?line check(fun() -> false orelse false end,
+ "false orelse false.", false),
+ ?line check(fun() -> false orelse true end,
+ "false orelse true.", true),
+ ?line check(fun() -> false orelse kludd end,
+ "false orelse kludd.", kludd),
+ ?line error_check("kladd orelse kludd.", {badarg,kladd}),
+ ?line error_check("[X || X <- [1,2,3], begin 1 end].",{bad_filter,1}),
+ ?line error_check("[X || X <- a].",{bad_generator,a}),
+
+ ?line check(fun() -> if true orelse kludd -> a; true -> b end end,
+ "if true orelse kludd -> a; true -> b end.", a),
+ ?line check(fun() -> if false orelse false -> a; true -> b end end,
+ "if false orelse false -> a; true -> b end.", b),
+ ?line check(fun() -> if false orelse true -> a; true -> b end end,
+ "if false orelse true -> a; true -> b end.", a),
+
+ ?line check(fun() -> [X || X <- [1,2,3], X+2] end,
+ "[X || X <- [1,2,3], X+2].", []),
+
+ ?line check(fun() -> [X || X <- [1,2,3], [X] == [X || X <- [2]]] end,
+ "[X || X <- [1,2,3], [X] == [X || X <- [2]]].",
+ [2]),
+ ?line check(fun() -> F = fun(1) -> ett; (2) -> zwei end,
+ ett = F(1), zwei = F(2) end,
+ "begin F = fun(1) -> ett; (2) -> zwei end,
+ ett = F(1), zwei = F(2) end.",
+ zwei),
+ ?line check(fun() -> F = fun(X) when X == 1 -> ett;
+ (X) when X == 2 -> zwei end,
+ ett = F(1), zwei = F(2) end,
+ "begin F = fun(X) when X == 1 -> ett;
+ (X) when X == 2 -> zwei end,
+ ett = F(1), zwei = F(2) end.",
+ zwei),
+ ?line error_check("begin F = fun(1) -> ett end, zwei = F(2) end.",
+ function_clause),
+ ?line check(fun() -> if length([1]) == 1 -> yes;
+ true -> no end end,
+ "if length([1]) == 1 -> yes;
+ true -> no end.",
+ yes),
+ ?line check(fun() -> if is_integer(3) -> true; true -> false end end,
+ "if is_integer(3) -> true; true -> false end.", true),
+ ?line check(fun() -> if integer(3) -> true; true -> false end end,
+ "if integer(3) -> true; true -> false end.", true),
+ ?line check(fun() -> if is_float(3) -> true; true -> false end end,
+ "if is_float(3) -> true; true -> false end.", false),
+ ?line check(fun() -> if float(3) -> true; true -> false end end,
+ "if float(3) -> true; true -> false end.", false),
+ ?line check(fun() -> if is_number(3) -> true; true -> false end end,
+ "if is_number(3) -> true; true -> false end.", true),
+ ?line check(fun() -> if number(3) -> true; true -> false end end,
+ "if number(3) -> true; true -> false end.", true),
+ ?line check(fun() -> if is_atom(a) -> true; true -> false end end,
+ "if is_atom(a) -> true; true -> false end.", true),
+ ?line check(fun() -> if atom(a) -> true; true -> false end end,
+ "if atom(a) -> true; true -> false end.", true),
+ ?line check(fun() -> if is_list([]) -> true; true -> false end end,
+ "if is_list([]) -> true; true -> false end.", true),
+ ?line check(fun() -> if list([]) -> true; true -> false end end,
+ "if list([]) -> true; true -> false end.", true),
+ ?line check(fun() -> if is_tuple({}) -> true; true -> false end end,
+ "if is_tuple({}) -> true; true -> false end.", true),
+ ?line check(fun() -> if tuple({}) -> true; true -> false end end,
+ "if tuple({}) -> true; true -> false end.", true),
+ ?line check(fun() -> if is_pid(self()) -> true; true -> false end end,
+ "if is_pid(self()) -> true; true -> false end.", true),
+ ?line check(fun() -> if pid(self()) -> true; true -> false end end,
+ "if pid(self()) -> true; true -> false end.", true),
+ ?line check(fun() -> R = make_ref(), if is_reference(R) -> true;
+ true -> false end end,
+ "begin R = make_ref(), if is_reference(R) -> true;"
+ "true -> false end end.", true),
+ ?line check(fun() -> R = make_ref(), if reference(R) -> true;
+ true -> false end end,
+ "begin R = make_ref(), if reference(R) -> true;"
+ "true -> false end end.", true),
+ ?line check(fun() -> if is_port(a) -> true; true -> false end end,
+ "if is_port(a) -> true; true -> false end.", false),
+ ?line check(fun() -> if port(a) -> true; true -> false end end,
+ "if port(a) -> true; true -> false end.", false),
+ ?line check(fun() -> if is_function(a) -> true; true -> false end end,
+ "if is_function(a) -> true; true -> false end.", false),
+ ?line check(fun() -> if function(a) -> true; true -> false end end,
+ "if function(a) -> true; true -> false end.", false),
+ ?line check(fun() -> if is_binary(<<>>) -> true; true -> false end end,
+ "if is_binary(<<>>) -> true; true -> false end.", true),
+ ?line check(fun() -> if binary(<<>>) -> true; true -> false end end,
+ "if binary(<<>>) -> true; true -> false end.", true),
+ ?line check(fun() -> if is_integer(a) == true -> yes;
+ true -> no end end,
+ "if is_integer(a) == true -> yes;
+ true -> no end.",
+ no),
+ ?line check(fun() -> if [] -> true; true -> false end end,
+ "if [] -> true; true -> false end.", false),
+ ?line error_check("if lists:member(1,[1]) -> true; true -> false end.",
+ illegal_guard_expr),
+ ?line error_check("if false -> true end.", if_clause),
+ ?line check(fun() -> if a+b -> true; true -> false end end,
+ "if a + b -> true; true -> false end.", false),
+ ?line check(fun() -> if + b -> true; true -> false end end,
+ "if + b -> true; true -> false end.", false),
+ ?line error_check("case foo of bar -> true end.", {case_clause,foo}),
+ ?line error_check("case 4 of 2+a -> true; _ -> false end.",
+ illegal_pattern),
+ ?line error_check("case 4 of +a -> true; _ -> false end.",
+ illegal_pattern),
+ ?line check(fun() -> case a of
+ X when X == b -> one;
+ X when X == a -> two
+ end end,
+ "begin case a of
+ X when X == b -> one;
+ X when X == a -> two
+ end end.", two),
+ ?line error_check("3 = 4.", {badmatch,4}),
+ ?line error_check("a = 3.", {badmatch,3}),
+ %% ?line error_check("3.1 = 2.7.",{badmatch,2.7}),
+ ?line error_check("$c = 4.", {badmatch,4}),
+ ?line check(fun() -> $c = $c end, "$c = $c.", $c),
+ ?line check(fun() -> _ = bar end, "_ = bar.", bar),
+ ?line check(fun() -> A = 14, A = 14 end,
+ "begin A = 14, A = 14 end.", 14),
+ ?line error_check("begin A = 14, A = 16 end.", {badmatch,16}),
+ ?line error_check("\"hej\" = \"san\".", {badmatch,"san"}),
+ ?line check(fun() -> "hej" = "hej" end,
+ "\"hej\" = \"hej\".", "hej"),
+ ?line error_check("[] = [a].", {badmatch,[a]}),
+ ?line check(fun() -> [] = [] end, "[] = [].", []),
+ ?line error_check("[a] = [].", {badmatch,[]}),
+ ?line error_check("{a,b} = 34.", {badmatch,34}),
+ ?line check(fun() -> <<X:7>> = <<8:7>>, X end,
+ "begin <<X:7>> = <<8:7>>, X end.", 8),
+ ?line error_check("<<34:32>> = \"hej\".", {badmatch,"hej"}),
+ ?line check(fun() -> trunc((1 * 3 div 3 + 4 - 3) / 1) rem 2 end,
+ "begin trunc((1 * 3 div 3 + 4 - 3) / 1) rem 2 end.", 0),
+ ?line check(fun() -> (2#101 band 2#10101) bor (2#110 bxor 2#010) end,
+ "(2#101 band 2#10101) bor (2#110 bxor 2#010).", 5),
+ ?line check(fun() -> (2#1 bsl 4) + (2#10000 bsr 3) end,
+ "(2#1 bsl 4) + (2#10000 bsr 3).", 18),
+ ?line check(fun() -> ((1<3) and ((1 =:= 2) or (1 =/= 2))) xor (1=<2) end,
+ "((1<3) and ((1 =:= 2) or (1 =/= 2))) xor (1=<2).", false),
+ ?line check(fun() -> (a /= b) or (2 > 4) or (3 >= 3) end,
+ "(a /= b) or (2 > 4) or (3 >= 3).", true),
+ ?line check(fun() -> "hej" ++ "san" =/= "hejsan" -- "san" end,
+ "\"hej\" ++ \"san\" =/= \"hejsan\" -- \"san\".", true),
+ ?line check(fun() -> (bnot 1) < -0 end, "(bnot (+1)) < -0.", true),
+ ok.
+
+unary_plus(doc) ->
+ ["OTP-4929. Unary plus rejects non-numbers."];
+unary_plus(suite) ->
+ [];
+unary_plus(Config) when is_list(Config) ->
+ ?line check(fun() -> F = fun(X) -> + X end,
+ true = -1 == F(-1) end,
+ "begin F = fun(X) -> + X end,"
+ " true = -1 == F(-1) end.", true, ['F'], none, none),
+ ?line error_check("+a.", badarith),
+ ok.
+
+apply_atom(doc) ->
+ ["OTP-5064. Can no longer apply atoms."];
+apply_atom(suite) ->
+ [];
+apply_atom(Config) when is_list(Config) ->
+ ?line error_check("[X || X <- [[1],[2]],
+ begin L = length, L(X) =:= 1 end].",
+ {badfun,length}),
+ ok.
+
+otp_5269(doc) ->
+ ["OTP-5269. Bugs in the bit syntax."];
+otp_5269(suite) ->
+ [];
+otp_5269(Config) when is_list(Config) ->
+ ?line check(fun() -> L = 8,
+ F = fun(<<A:L,B:A>>) -> B end,
+ F(<<16:8, 7:16>>)
+ end,
+ "begin
+ L = 8, F = fun(<<A:L,B:A>>) -> B end, F(<<16:8, 7:16>>)
+ end.",
+ 7),
+ ?line check(fun() -> L = 8,
+ F = fun(<<L:L,B:L>>) -> B end,
+ F(<<16:8, 7:16>>)
+ end,
+ "begin
+ L = 8, F = fun(<<L:L,B:L>>) -> B end, F(<<16:8, 7:16>>)
+ end.",
+ 7),
+ ?line check(fun() -> L = 8, <<A:L,B:A>> = <<16:8, 7:16>>, B end,
+ "begin L = 8, <<A:L,B:A>> = <<16:8, 7:16>>, B end.",
+ 7),
+ ?line error_check("begin L = 8, <<L:L,B:L>> = <<16:8, 7:16>> end.",
+ {badmatch,<<16:8,7:16>>}),
+
+ ?line error_check("begin <<L:16,L:L>> = <<16:16,8:16>>, L end.",
+ {badmatch, <<16:16,8:16>>}),
+ ?line check(fun() -> U = 8, (fun(<<U:U>>) -> U end)(<<32:8>>) end,
+ "begin U = 8, (fun(<<U:U>>) -> U end)(<<32:8>>) end.",
+ 32),
+ ?line check(fun() -> U = 8, [U || <<U:U>> <- [<<32:8>>]] end,
+ "begin U = 8, [U || <<U:U>> <- [<<32:8>>]] end.",
+ [32]),
+ ?line error_check("(fun({3,<<A:32,A:32>>}) -> a end)
+ ({3,<<17:32,19:32>>}).",
+ function_clause),
+ ?line check(fun() -> [X || <<A:8,
+ B:A>> <- [<<16:8,19:16>>],
+ <<X:8>> <- [<<B:8>>]] end,
+ "[X || <<A:8,
+ B:A>> <- [<<16:8,19:16>>],
+ <<X:8>> <- [<<B:8>>]].",
+ [19]),
+ ok.
+
+otp_6539(doc) ->
+ ["OTP-6539. try/catch bugs."];
+otp_6539(suite) ->
+ [];
+otp_6539(Config) when is_list(Config) ->
+ ?line check(fun() ->
+ F = fun(A,B) ->
+ try A+B
+ catch _:_ -> dontthinkso
+ end
+ end,
+ lists:zipwith(F, [1,2], [2,3])
+ end,
+ "begin
+ F = fun(A,B) ->
+ try A+B
+ catch _:_ -> dontthinkso
+ end
+ end,
+ lists:zipwith(F, [1,2], [2,3])
+ end.",
+ [3, 5]),
+ ok.
+
+otp_6543(doc) ->
+ ["OTP-6543. bitlevel binaries."];
+otp_6543(suite) ->
+ [];
+otp_6543(Config) when is_list(Config) ->
+ ?line check(fun() ->
+ << <<X>> || <<X>> <- [1,2,3] >>
+ end,
+ "<< <<X>> || <<X>> <- [1,2,3] >>.",
+ <<>>),
+ ?line check(fun() ->
+ << <<X>> || X <- [1,2,3] >>
+ end,
+ "<< <<X>> || X <- [1,2,3] >>.",
+ <<1,2,3>>),
+ ?line check(fun() ->
+ << <<X:8>> || <<X:2>> <= <<"hej">> >>
+ end,
+ "<< <<X:8>> || <<X:2>> <= <<\"hej\">> >>.",
+ <<1,2,2,0,1,2,1,1,1,2,2,2>>),
+ ?line check(fun() ->
+ << <<X:8>> ||
+ <<65,X:4>> <= <<65,7:4,65,3:4,66,8:4>> >>
+ end,
+ "<< <<X:8>> ||
+ <<65,X:4>> <= <<65,7:4,65,3:4,66,8:4>> >>.",
+ <<7,3>>),
+ ?line check(fun() -> <<34:18/big>> end,
+ "<<34:18/big>>.",
+ <<0,8,2:2>>),
+ ?line check(fun() -> <<34:18/big-unit:2>> end,
+ "<<34:18/big-unit:2>>.",
+ <<0,0,0,2,2:4>>),
+ ?line check(fun() -> <<34:18/little>> end,
+ "<<34:18/little>>.",
+ <<34,0,0:2>>),
+ ?line case eval_string("<<34:18/native>>.") of
+ <<0,8,2:2>> -> ok;
+ <<34,0,0:2>> -> ok
+ end,
+ ?line check(fun() -> <<34:18/big-signed>> end,
+ "<<34:18/big-signed>>.",
+ <<0,8,2:2>>),
+ ?line check(fun() -> <<34:18/little-signed>> end,
+ "<<34:18/little-signed>>.",
+ <<34,0,0:2>>),
+ ?line case eval_string("<<34:18/native-signed>>.") of
+ <<0,8,2:2>> -> ok;
+ <<34,0,0:2>> -> ok
+ end,
+ ?line check(fun() -> <<34:18/big-unsigned>> end,
+ "<<34:18/big-unsigned>>.",
+ <<0,8,2:2>>),
+ ?line check(fun() -> <<34:18/little-unsigned>> end,
+ "<<34:18/little-unsigned>>.",
+ <<34,0,0:2>>),
+ ?line case eval_string("<<34:18/native-unsigned>>.") of
+ <<0,8,2:2>> -> ok;
+ <<34,0,0:2>> -> ok
+ end,
+ ?line check(fun() -> <<3.14:32/float-big>> end,
+ "<<3.14:32/float-big>>.",
+ <<64,72,245,195>>),
+ ?line check(fun() -> <<3.14:32/float-little>> end,
+ "<<3.14:32/float-little>>.",
+ <<195,245,72,64>>),
+ ?line case eval_string("<<3.14:32/float-native>>.") of
+ <<64,72,245,195>> -> ok;
+ <<195,245,72,64>> -> ok
+ end,
+ ?line error_check("<<(<<17,3:2>>)/binary>>.", badarg),
+ ?line check(fun() -> <<(<<17,3:2>>)/bitstring>> end,
+ "<<(<<17,3:2>>)/bitstring>>.",
+ <<17,3:2>>),
+ ?line check(fun() -> <<(<<17,3:2>>):10/bitstring>> end,
+ "<<(<<17,3:2>>):10/bitstring>>.",
+ <<17,3:2>>),
+ ?line check(fun() -> <<<<344:17>>/binary-unit:17>> end,
+ "<<<<344:17>>/binary-unit:17>>.",
+ <<344:17>>),
+
+ ?line check(fun() -> <<X:18/big>> = <<34:18/big>>, X end,
+ "begin <<X:18/big>> = <<34:18/big>>, X end.",
+ 34),
+ ?line check(fun() -> <<X:18/big-unit:2>> = <<34:18/big-unit:2>>, X end,
+ "begin <<X:18/big-unit:2>> = <<34:18/big-unit:2>>, X end.",
+ 34),
+ ?line check(fun() -> <<X:18/little>> = <<34:18/little>>, X end,
+ "begin <<X:18/little>> = <<34:18/little>>, X end.",
+ 34),
+ ?line check(fun() -> <<X:18/native>> = <<34:18/native>>, X end,
+ "begin <<X:18/native>> = <<34:18/native>>, X end.",
+ 34),
+ ?line check(fun() -> <<X:18/big-signed>> = <<34:18/big-signed>>, X end,
+ "begin <<X:18/big-signed>> = <<34:18/big-signed>>, X end.",
+ 34),
+ ?line check(fun() -> <<X:18/little-signed>> = <<34:18/little-signed>>,
+ X end,
+ "begin <<X:18/little-signed>> = <<34:18/little-signed>>,
+ X end.",
+ 34),
+ ?line check(fun() -> <<X:18/native-signed>> = <<34:18/native-signed>>,
+ X end,
+ "begin <<X:18/native-signed>> = <<34:18/native-signed>>,
+ X end.",
+ 34),
+ ?line check(fun() -> <<X:18/big-unsigned>> = <<34:18/big-unsigned>>,
+ X end,
+ "begin <<X:18/big-unsigned>> = <<34:18/big-unsigned>>,
+ X end.",
+ 34),
+ ?line check(fun() ->
+ <<X:18/little-unsigned>> = <<34:18/little-unsigned>>,
+ X end,
+ "begin <<X:18/little-unsigned>> = <<34:18/little-unsigned>>,
+ X end.",
+ 34),
+ ?line check(fun() ->
+ <<X:18/native-unsigned>> = <<34:18/native-unsigned>>,
+ X end,
+ "begin <<X:18/native-unsigned>> = <<34:18/native-unsigned>>,
+ X end.",
+ 34),
+ ?line check(fun() -> <<X:32/float-big>> = <<2.0:32/float-big>>, X end,
+ "begin <<X:32/float-big>> = <<2.0:32/float-big>>,
+ X end.",
+ 2.0),
+ ?line check(fun() -> <<X:32/float-little>> = <<2.0:32/float-little>>,
+ X end,
+ "begin <<X:32/float-little>> = <<2.0:32/float-little>>,
+ X end.",
+ 2.0),
+ ?line check(fun() -> <<X:32/float-native>> = <<2.0:32/float-native>>,
+ X end,
+ "begin <<X:32/float-native>> = <<2.0:32/float-native>>,
+ X end.",
+ 2.0),
+
+ ?line check(
+ fun() ->
+ [X || <<"hej",X:8>> <= <<"hej",8,"san",9,"hej",17,"hej">>]
+ end,
+ "[X || <<\"hej\",X:8>> <=
+ <<\"hej\",8,\"san\",9,\"hej\",17,\"hej\">>].",
+ [8,17]),
+ ?line check(
+ fun() ->
+ L = 8, << <<B:32>> || <<L:L,B:L>> <= <<16:8, 7:16>> >>
+ end,
+ "begin L = 8, << <<B:32>> || <<L:L,B:L>> <= <<16:8, 7:16>> >>
+ end.",
+ <<0,0,0,7>>),
+ %% Test the Value part of a binary segment.
+ %% "Old" bugs have been fixed (partial_eval is called on Value).
+ ?line check(fun() -> [ 3 || <<17/float>> <= <<17.0/float>>] end,
+ "[ 3 || <<17/float>> <= <<17.0/float>>].",
+ [3]),
+ ?line check(fun() -> [ 3 || <<17/float>> <- [<<17.0/float>>]] end,
+ "[ 3 || <<17/float>> <- [<<17.0/float>>]].",
+ [3]),
+ ?line check(fun() -> [ X || <<17/float,X:3>> <= <<17.0/float,2:3>>] end,
+ "[ X || <<17/float,X:3>> <= <<17.0/float,2:3>>].",
+ [2]),
+ ?line check(fun() ->
+ [ foo || <<(1 bsl 1023)/float>> <= <<(1 bsl 1023)/float>>]
+ end,
+ "[ foo || <<(1 bsl 1023)/float>> <= <<(1 bsl 1023)/float>>].",
+ [foo]),
+ ?line check(fun() ->
+ [ foo || <<(1 bsl 1023)/float>> <- [<<(1 bsl 1023)/float>>]]
+ end,
+ "[ foo || <<(1 bsl 1023)/float>> <- [<<(1 bsl 1023)/float>>]].",
+ [foo]),
+ ?line error_check("[ foo || <<(1 bsl 1024)/float>> <-
+ [<<(1 bsl 1024)/float>>]].",
+ badarg),
+ ?line check(fun() ->
+ [ foo || <<(1 bsl 1024)/float>> <- [<<(1 bsl 1023)/float>>]]
+ end,
+ "[ foo || <<(1 bsl 1024)/float>> <-
+ [<<(1 bsl 1023)/float>>]].",
+ []),
+ ?line check(fun() ->
+ [ foo || <<(1 bsl 1024)/float>> <= <<(1 bsl 1023)/float>>]
+ end,
+ "[ foo || <<(1 bsl 1024)/float>> <=
+ <<(1 bsl 1023)/float>>].",
+ []),
+ ?line check(fun() ->
+ L = 8,
+ [{L,B} || <<L:L,B:L/float>> <= <<32:8,7:32/float>>]
+ end,
+ "begin L = 8,
+ [{L,B} || <<L:L,B:L/float>> <= <<32:8,7:32/float>>]
+ end.",
+ [{32,7.0}]),
+ ?line check(fun() ->
+ L = 8,
+ [{L,B} || <<L:L,B:L/float>> <- [<<32:8,7:32/float>>]]
+ end,
+ "begin L = 8,
+ [{L,B} || <<L:L,B:L/float>> <- [<<32:8,7:32/float>>]]
+ end.",
+ [{32,7.0}]),
+ ?line check(fun() ->
+ [foo || <<"s">> <= <<"st">>]
+ end,
+ "[foo || <<\"s\">> <= <<\"st\">>].",
+ [foo]),
+ ?line check(fun() -> <<_:32>> = <<17:32>> end,
+ "<<_:32>> = <<17:32>>.",
+ <<17:32>>),
+ ?line check(fun() -> [foo || <<_:32>> <= <<17:32,20:32>>] end,
+ "[foo || <<_:32>> <= <<17:32,20:32>>].",
+ [foo,foo]),
+
+ ?line check(fun() -> << <<X:32>> || X <- [1,2,3], X > 1 >> end,
+ "<< <<X:32>> || X <- [1,2,3], X > 1 >>.",
+ <<0,0,0,2,0,0,0,3>>),
+ ?line error_check("[X || <<X>> <= [a,b]].",{bad_generator,[a,b]}),
+ ok.
+
+otp_6787(doc) ->
+ ["OTP-6787. bitlevel binaries."];
+otp_6787(suite) ->
+ [];
+otp_6787(Config) when is_list(Config) ->
+ ?line check(
+ fun() -> <<16:(1024*1024)>> = <<16:(1024*1024)>> end,
+ "<<16:(1024*1024)>> = <<16:(1024*1024)>>.",
+ <<16:1048576>>),
+ ok.
+
+otp_6977(doc) ->
+ ["OTP-6977. ++ bug."];
+otp_6977(suite) ->
+ [];
+otp_6977(Config) when is_list(Config) ->
+ ?line check(
+ fun() -> (fun([$X] ++ _) -> ok end)("X") end,
+ "(fun([$X] ++ _) -> ok end)(\"X\").",
+ ok),
+ ok.
+
+otp_7550(doc) ->
+ ["OTP-7550. Support for UTF-8, UTF-16, UTF-32."];
+otp_7550(Config) when is_list(Config) ->
+
+ %% UTF-8.
+ ?line check(
+ fun() -> <<65>> = <<65/utf8>> end,
+ "<<65>> = <<65/utf8>>.",
+ <<65>>),
+ ?line check(
+ fun() -> <<350/utf8>> = <<197,158>> end,
+ "<<350/utf8>> = <<197,158>>.",
+ <<197,158>>),
+ ?line check(
+ fun() -> <<$b,$j,$\303,$\266,$r,$n>> = <<"bj\366rn"/utf8>> end,
+ "<<$b,$j,$\303,$\266,$r,$n>> = <<\"bj\366rn\"/utf8>>.",
+ <<$b,$j,$\303,$\266,$r,$n>>),
+
+ %% UTF-16.
+ ?line check(
+ fun() -> <<0,65>> = <<65/utf16>> end,
+ "<<0,65>> = <<65/utf16>>.",
+ <<0,65>>),
+ ?line check(
+ fun() -> <<16#D8,16#08,16#DF,16#45>> = <<16#12345/utf16>> end,
+ "<<16#D8,16#08,16#DF,16#45>> = <<16#12345/utf16>>.",
+ <<16#D8,16#08,16#DF,16#45>>),
+ ?line check(
+ fun() -> <<16#08,16#D8,16#45,16#DF>> = <<16#12345/little-utf16>> end,
+ "<<16#08,16#D8,16#45,16#DF>> = <<16#12345/little-utf16>>.",
+ <<16#08,16#D8,16#45,16#DF>>),
+
+ ?line check(
+ fun() -> <<350/utf16>> = <<1,94>> end,
+ "<<350/utf16>> = <<1,94>>.",
+ <<1,94>>),
+ ?line check(
+ fun() -> <<350/little-utf16>> = <<94,1>> end,
+ "<<350/little-utf16>> = <<94,1>>.",
+ <<94,1>>),
+ ?line check(
+ fun() -> <<16#12345/utf16>> = <<16#D8,16#08,16#DF,16#45>> end,
+ "<<16#12345/utf16>> = <<16#D8,16#08,16#DF,16#45>>.",
+ <<16#D8,16#08,16#DF,16#45>>),
+ ?line check(
+ fun() -> <<16#12345/little-utf16>> = <<16#08,16#D8,16#45,16#DF>> end,
+ "<<16#12345/little-utf16>> = <<16#08,16#D8,16#45,16#DF>>.",
+ <<16#08,16#D8,16#45,16#DF>>),
+
+ %% UTF-32.
+ ?line check(
+ fun() -> <<16#12345/utf32>> = <<16#0,16#01,16#23,16#45>> end,
+ "<<16#12345/utf32>> = <<16#0,16#01,16#23,16#45>>.",
+ <<16#0,16#01,16#23,16#45>>),
+ ?line check(
+ fun() -> <<16#0,16#01,16#23,16#45>> = <<16#12345/utf32>> end,
+ "<<16#0,16#01,16#23,16#45>> = <<16#12345/utf32>>.",
+ <<16#0,16#01,16#23,16#45>>),
+ ?line check(
+ fun() -> <<16#12345/little-utf32>> = <<16#45,16#23,16#01,16#00>> end,
+ "<<16#12345/little-utf32>> = <<16#45,16#23,16#01,16#00>>.",
+ <<16#45,16#23,16#01,16#00>>),
+ ?line check(
+ fun() -> <<16#12345/little-utf32>> end,
+ "<<16#12345/little-utf32>>.",
+ <<16#45,16#23,16#01,16#00>>),
+
+ %% Mixed.
+ ?line check(
+ fun() -> <<16#41,16#12345/utf32,16#0391:16,16#2E:8>> end,
+ "<<16#41,16#12345/utf32,16#0391:16,16#2E:8>>.",
+ <<16#41,16#00,16#01,16#23,16#45,16#03,16#91,16#2E>>),
+ ok.
+
+
+otp_8133(doc) ->
+ ["OTP-8133. Bit comprehension bug."];
+otp_8133(suite) ->
+ [];
+otp_8133(Config) when is_list(Config) ->
+ ?line check(
+ fun() ->
+ E = fun(N) ->
+ if
+ is_integer(N) -> <<N/integer>>;
+ true -> throw(foo)
+ end
+ end,
+ try << << (E(V))/binary >> || V <- [1,2,3,a] >>
+ catch foo -> ok
+ end
+ end,
+ "begin
+ E = fun(N) ->
+ if is_integer(N) -> <<N/integer>>;
+ true -> throw(foo)
+ end
+ end,
+ try << << (E(V))/binary >> || V <- [1,2,3,a] >>
+ catch foo -> ok
+ end
+ end.",
+ ok),
+ ?line check(
+ fun() ->
+ E = fun(N) ->
+ if
+ is_integer(N) -> <<N/integer>>;
+ true -> erlang:error(foo)
+ end
+ end,
+ try << << (E(V))/binary >> || V <- [1,2,3,a] >>
+ catch error:foo -> ok
+ end
+ end,
+ "begin
+ E = fun(N) ->
+ if is_integer(N) -> <<N/integer>>;
+ true -> erlang:error(foo)
+ end
+ end,
+ try << << (E(V))/binary >> || V <- [1,2,3,a] >>
+ catch error:foo -> ok
+ end
+ end.",
+ ok),
+ ok.
+
+funs(doc) ->
+ ["Simple cases, just to cover some code."];
+funs(suite) ->
+ [];
+funs(Config) when is_list(Config) ->
+ do_funs(none, none),
+ do_funs(lfh(), none),
+ do_funs(lfh(), efh()),
+
+ ?line error_check("nix:foo().", {access_not_allowed,nix}, lfh(), efh()),
+ ?line error_check("bar().", undef, none, none),
+
+ ?line check(fun() -> F1 = fun(F,N) -> ?MODULE:count_down(F, N) end,
+ F1(F1, 1000) end,
+ "begin F1 = fun(F,N) -> count_down(F, N) end,"
+ "F1(F1,1000) end.",
+ 0, ['F1'], lfh(), none),
+
+ ?line check(fun() -> F1 = fun(F,N) -> ?MODULE:count_down(F, N) end,
+ F1(F1, 1000) end,
+ "begin F1 = fun(F,N) -> count_down(F, N) end,"
+ "F1(F1,1000) end.",
+ 0, ['F1'], lfh_value(), none),
+
+ ?line check(fun() -> F1 = fun(F,N) -> ?MODULE:count_down(F, N) end,
+ F1(F1, 1000) end,
+ "begin F1 = fun(F,N) -> count_down(F, N) end,"
+ "F1(F1,1000) end.",
+ 0, ['F1'], lfh_value_extra(), none),
+
+ ?line check(fun() -> F1 = fun(F,N) -> ?MODULE:count_down(F, N) end,
+ F1(F1, 1000) end,
+ "begin F1 = fun(F,N) -> count_down(F, N) end,"
+ "F1(F1,1000) end.",
+ 0, ['F1'], {?MODULE,local_func_value}, none),
+ %% This is not documented, and only for backward compatibility (good!).
+ B0 = erl_eval:new_bindings(),
+ ?line check(fun() -> is_function(?MODULE:count_down_fun()) end,
+ "begin is_function(count_down_fun()) end.",
+ true, [], {?MODULE,local_func,[B0]},none),
+
+ EF = fun({timer,sleep}, As) when length(As) == 1 -> exit({got_it,sleep});
+ ({M,F}, As) -> apply(M, F, As)
+ end,
+ EFH = {value, EF},
+ ?line error_check("apply(timer, sleep, [1]).", got_it, none, EFH),
+ ?line error_check("begin F = fun(T) -> timer:sleep(T) end,F(1) end.",
+ got_it, none, EFH),
+ ?line error_check("fun c/1.", undef),
+ ?line error_check("fun a:b/0().", undef),
+
+ MaxArgs = 20,
+ ?line [true] =
+ lists:usort([run_many_args(SAs) || SAs <- many_args(MaxArgs)]),
+ ?line {'EXIT',{{argument_limit,_},_}} =
+ (catch run_many_args(many_args1(MaxArgs+1))),
+ ok.
+
+run_many_args({S, As}) ->
+ apply(eval_string(S), As) =:= As.
+
+many_args(N) ->
+ [many_args1(I) || I <- lists:seq(1, N)].
+
+many_args1(N) ->
+ F = fun(L, P) ->
+ tl(lists:flatten([","++P++integer_to_list(E) || E <- L]))
+ end,
+ L = lists:seq(1, N),
+ T = F(L, "V"),
+ S = lists:flatten(io_lib:format("fun(~s) -> [~s] end.", [T, T])),
+ {S, L}.
+
+do_funs(LFH, EFH) ->
+ %% LFH is not really used by these examples...
+
+ %% These tests do not prove that tail recursive functions really
+ %% work (that the process does not grow); one should also run them
+ %% manually with 1000 replaced by 1000000.
+
+ M = atom_to_list(?MODULE),
+ ?line check(fun() -> F1 = fun(F,N) -> ?MODULE:count_down(F, N) end,
+ F1(F1, 1000) end,
+ concat(["begin F1 = fun(F,N) -> ", M,
+ ":count_down(F, N) end, F1(F1,1000) end."]),
+ 0, ['F1'], LFH, EFH),
+ ?line check(fun() -> F1 = fun(F,N) -> apply(?MODULE,count_down,[F,N])
+ end, F1(F1, 1000) end,
+ concat(["begin F1 = fun(F,N) -> apply(", M,
+ ",count_down,[F, N]) end, F1(F1,1000) end."]),
+ 0, ['F1'], LFH, EFH),
+ ?line check(fun() -> F1 = fun(F,N) -> {?MODULE,count_down}(F,N)
+ end, F1(F1, 1000) end,
+ concat(["begin F1 = fun(F,N) -> {", M,
+ ",count_down}(F, N) end, F1(F1,1000) end."]),
+ 0, ['F1'], LFH, EFH),
+ ?line check(fun() -> F = fun(F,N) when N > 0 -> apply(F,[F,N-1]);
+ (_F,0) -> ok end,
+ F(F, 1000)
+ end,
+ "begin F = fun(F,N) when N > 0 -> apply(F,[F,N-1]);"
+ "(_F,0) -> ok end,"
+ "F(F, 1000) end.",
+ ok, ['F'], LFH, EFH),
+ ?line check(fun() -> F = fun(F,N) when N > 0 ->
+ apply(erlang,apply,[F,[F,N-1]]);
+ (_F,0) -> ok end,
+ F(F, 1000)
+ end,
+ "begin F = fun(F,N) when N > 0 ->"
+ "apply(erlang,apply,[F,[F,N-1]]);"
+ "(_F,0) -> ok end,"
+ "F(F, 1000) end.",
+ ok, ['F'], LFH, EFH),
+ ?line check(fun() -> F = count_down_fun(),
+ SF = fun(SF, F1, N) -> F(SF, F1, N) end,
+ SF(SF, F, 1000) end,
+ concat(["begin F = ", M, ":count_down_fun(),"
+ "SF = fun(SF, F1, N) -> F(SF, F1, N) end,"
+ "SF(SF, F, 1000) end."]),
+ ok, ['F','SF'], LFH, EFH),
+
+
+ ?line check(fun() -> F = fun(X) -> A = 1+X, {X,A} end,
+ true = {2,3} == F(2) end,
+ "begin F = fun(X) -> A = 1+X, {X,A} end,
+ true = {2,3} == F(2) end.", true, ['F'], LFH, EFH),
+ ?line check(fun() -> F = fun(X) -> {erlang,'+'}(X,2) end,
+ true = 3 == F(1) end,
+ "begin F = fun(X) -> {erlang,'+'}(X,2) end,"
+ " true = 3 == F(1) end.", true, ['F'],
+ LFH, EFH),
+ ?line check(fun() -> F = fun(X) -> byte_size(X) end,
+ ?MODULE:do_apply(F,<<"hej">>) end,
+ concat(["begin F = fun(X) -> size(X) end,",
+ M,":do_apply(F,<<\"hej\">>) end."]),
+ 3, ['F'], LFH, EFH),
+
+ ?line check(fun() -> F1 = fun(X, Z) -> {X,Z} end,
+ Z = 5,
+ F2 = fun(X, Y) -> F1(Z,{X,Y}) end,
+ F3 = fun(X, Y) -> {a,F1(Z,{X,Y})} end,
+ {5,{x,y}} = F2(x,y),
+ {a,{5,{y,x}}} = F3(y,x),
+ {5,{5,y}} = F2(Z,y),
+ true = {5,{x,5}} == F2(x,Z) end,
+ "begin F1 = fun(X, Z) -> {X,Z} end,
+ Z = 5,
+ F2 = fun(X, Y) -> F1(Z,{X,Y}) end,
+ F3 = fun(X, Y) -> {a,F1(Z,{X,Y})} end,
+ {5,{x,y}} = F2(x,y),
+ {a,{5,{y,x}}} = F3(y,x),
+ {5,{5,y}} = F2(Z,y),
+ true = {5,{x,5}} == F2(x,Z) end.",
+ true, ['F1','Z','F2','F3'], LFH, EFH),
+ ?line check(fun() -> F = fun(X) -> byte_size(X) end,
+ F2 = fun(Y) -> F(Y) end,
+ ?MODULE:do_apply(F2,<<"hej">>) end,
+ concat(["begin F = fun(X) -> size(X) end,",
+ "F2 = fun(Y) -> F(Y) end,",
+ M,":do_apply(F2,<<\"hej\">>) end."]),
+ 3, ['F','F2'], LFH, EFH),
+ ?line check(fun() -> Z = 5, F = fun(X) -> {Z,X} end,
+ F2 = fun(Z) -> F(Z) end, F2(3) end,
+ "begin Z = 5, F = fun(X) -> {Z,X} end,
+ F2 = fun(Z) -> F(Z) end, F2(3) end.",
+ {5,3},['F','F2','Z'], LFH, EFH),
+ ?line check(fun() -> F = fun(Z) -> Z end,
+ F2 = fun(X) -> F(X), Z = {X,X}, Z end,
+ {1,1} = F2(1), Z = 7, Z end,
+ "begin F = fun(Z) -> Z end,
+ F2 = fun(X) -> F(X), Z = {X,X}, Z end,
+ {1,1} = F2(1), Z = 7, Z end.", 7, ['F','F2','Z'],
+ LFH, EFH),
+ ?line check(fun() -> F = fun(F, N) -> [?MODULE:count_down(F,N) || X <-[1]]
+ end, F(F,2) end,
+ concat(["begin F = fun(F, N) -> [", M,
+ ":count_down(F,N) || X <-[1]] end, F(F,2) end."]),
+ [[[0]]], ['F'], LFH, EFH),
+
+ %% Tests for a bug found by the Dialyzer - used to crash.
+ ?line check(fun() -> Pmod = erl_eval_helper:new(42), Pmod:add(5) end,
+ "begin Pmod = erl_eval_helper:new(42), Pmod:add(5) end.",
+ 47,
+ ['Pmod'], LFH, EFH),
+ ?line check(fun() -> Pmod = erl_eval_helper:new(42), B = Pmod:add(7), B end,
+ "begin Pmod = erl_eval_helper:new(42), B = Pmod:add(7), B end.",
+ 49,
+ ['B','Pmod'], LFH, EFH),
+
+ ok.
+
+count_down(F, N) when N > 0 ->
+ F(F, N-1);
+count_down(_F, N) ->
+ N.
+
+count_down_fun() ->
+ fun(SF,F,N) when N > 0 -> SF(SF,F,N-1);
+ (_SF,_F,_N) -> ok
+ end.
+
+do_apply(F, V) ->
+ F(V).
+
+lfh() ->
+ {eval, fun(F, As, Bs) -> local_func(F, As, Bs) end}.
+
+local_func(F, As0, Bs0) when is_atom(F) ->
+ {As,Bs} = erl_eval:expr_list(As0, Bs0, {eval,lfh()}),
+ case erlang:function_exported(?MODULE, F, length(As)) of
+ true ->
+ {value,apply(?MODULE, F, As),Bs};
+ false ->
+ {value,apply(shell_default, F, As),Bs}
+ end.
+
+lfh_value_extra() ->
+ %% Not documented.
+ {value, fun(F, As) -> local_func_value(F, As) end, []}.
+
+lfh_value() ->
+ {value, fun(F, As) -> local_func_value(F, As) end}.
+
+local_func_value(F, As) when is_atom(F) ->
+ case erlang:function_exported(?MODULE, F, length(As)) of
+ true ->
+ apply(?MODULE, F, As);
+ false ->
+ apply(shell_default, F, As)
+ end.
+
+efh() ->
+ {value, fun(F, As) -> external_func(F, As) end}.
+
+external_func({M,_}, _As) when M == nix ->
+ exit({{access_not_allowed,M},[mfa]});
+external_func(F, As) when is_function(F) ->
+ apply(F, As);
+external_func({M,F}, As) ->
+ apply(M, F, As).
+
+
+
+try_catch(doc) ->
+ ["Test try-of-catch-after-end statement"];
+try_catch(suite) ->
+ [];
+try_catch(Config) when is_list(Config) ->
+ %% Match in of with catch
+ ?line check(fun() -> try 1 of 1 -> 2 catch _:_ -> 3 end end,
+ "try 1 of 1 -> 2 catch _:_ -> 3 end.", 2),
+ ?line check(fun() -> try 1 of 1 -> 2; 3 -> 4 catch _:_ -> 5 end end,
+ "try 1 of 1 -> 2; 3 -> 4 catch _:_ -> 5 end.", 2),
+ ?line check(fun() -> try 3 of 1 -> 2; 3 -> 4 catch _:_ -> 5 end end,
+ "try 3 of 1 -> 2; 3 -> 4 catch _:_ -> 5 end.", 4),
+ %% Just after
+ ?line check(fun () -> X = try 1 after put(try_catch, 2) end,
+ {X,get(try_catch)} end,
+ "begin X = try 1 after put(try_catch, 2) end, "
+ "{X,get(try_catch)} end.", {1,2}),
+ %% Match in of with after
+ ?line check(fun() -> X = try 1 of 1 -> 2 after put(try_catch, 3) end,
+ {X,get(try_catch)} end,
+ "begin X = try 1 of 1 -> 2 after put(try_catch, 3) end, "
+ "{X,get(try_catch)} end.", {2,3}),
+ ?line check(fun() -> X = try 1 of 1 -> 2; 3 -> 4
+ after put(try_catch, 5) end,
+ {X,get(try_catch)} end,
+ "begin X = try 1 of 1 -> 2; 3 -> 4 "
+ " after put(try_catch, 5) end, "
+ " {X,get(try_catch)} end.", {2,5}),
+ ?line check(fun() -> X = try 3 of 1 -> 2; 3 -> 4
+ after put(try_catch, 5) end,
+ {X,get(try_catch)} end,
+ "begin X = try 3 of 1 -> 2; 3 -> 4 "
+ " after put(try_catch, 5) end, "
+ " {X,get(try_catch)} end.", {4,5}),
+ %% Nomatch in of
+ ?line error_check("try 1 of 2 -> 3 catch _:_ -> 4 end.",
+ {try_clause,1}),
+ %% Nomatch in of with after
+ ?line check(fun () -> {'EXIT',{{try_clause,1},_}} =
+ begin catch try 1 of 2 -> 3
+ after put(try_catch, 4) end end,
+ get(try_catch) end,
+ "begin {'EXIT',{{try_clause,1},_}} = "
+ " begin catch try 1 of 2 -> 3 "
+ " after put(try_catch, 4) end end, "
+ " get(try_catch) end. ", 4),
+ %% Exception in try
+ ?line check(fun () -> try 1=2 catch error:{badmatch,2} -> 3 end end,
+ "try 1=2 catch error:{badmatch,2} -> 3 end.", 3),
+ ?line check(fun () -> try 1=2 of 3 -> 4
+ catch error:{badmatch,2} -> 5 end end,
+ "try 1=2 of 3 -> 4 "
+ "catch error:{badmatch,2} -> 5 end.", 5),
+ %% Exception in try with after
+ ?line check(fun () -> X = try 1=2
+ catch error:{badmatch,2} -> 3
+ after put(try_catch, 4) end,
+ {X,get(try_catch)} end,
+ "begin X = try 1=2 "
+ " catch error:{badmatch,2} -> 3 "
+ " after put(try_catch, 4) end, "
+ " {X,get(try_catch)} end. ", {3,4}),
+ ?line check(fun () -> X = try 1=2 of 3 -> 4
+ catch error:{badmatch,2} -> 5
+ after put(try_catch, 6) end,
+ {X,get(try_catch)} end,
+ "begin X = try 1=2 of 3 -> 4"
+ " catch error:{badmatch,2} -> 5 "
+ " after put(try_catch, 6) end, "
+ " {X,get(try_catch)} end. ", {5,6}),
+ %% Uncaught exception
+ ?line error_check("try 1=2 catch error:undefined -> 3 end. ",
+ {badmatch,2}),
+ ?line error_check("try 1=2 of 3 -> 4 catch error:undefined -> 5 end. ",
+ {badmatch,2}),
+ %% Uncaught exception with after
+ ?line check(fun () -> {'EXIT',{{badmatch,2},_}} =
+ begin catch try 1=2
+ after put(try_catch, 3) end end,
+ get(try_catch) end,
+ "begin {'EXIT',{{badmatch,2},_}} = "
+ " begin catch try 1=2 "
+ " after put(try_catch, 3) end end, "
+ " get(try_catch) end. ", 3),
+ ?line check(fun () -> {'EXIT',{{badmatch,2},_}} =
+ begin catch try 1=2 of 3 -> 4
+ after put(try_catch, 5) end end,
+ get(try_catch) end,
+ "begin {'EXIT',{{badmatch,2},_}} = "
+ " begin catch try 1=2 of 3 -> 4"
+ " after put(try_catch, 5) end end, "
+ " get(try_catch) end. ", 5),
+ ?line check(fun () -> {'EXIT',{{badmatch,2},_}} =
+ begin catch try 1=2 catch error:undefined -> 3
+ after put(try_catch, 4) end end,
+ get(try_catch) end,
+ "begin {'EXIT',{{badmatch,2},_}} = "
+ " begin catch try 1=2 catch error:undefined -> 3 "
+ " after put(try_catch, 4) end end, "
+ " get(try_catch) end. ", 4),
+ ?line check(fun () -> {'EXIT',{{badmatch,2},_}} =
+ begin catch try 1=2 of 3 -> 4
+ catch error:undefined -> 5
+ after put(try_catch, 6) end end,
+ get(try_catch) end,
+ "begin {'EXIT',{{badmatch,2},_}} = "
+ " begin catch try 1=2 of 3 -> 4 "
+ " catch error:undefined -> 5 "
+ " after put(try_catch, 6) end end, "
+ " get(try_catch) end. ", 6),
+ ok.
+
+
+eval_expr_5(doc) ->
+ ["(OTP-7933)"];
+eval_expr_5(suite) ->
+ [];
+eval_expr_5(Config) when is_list(Config) ->
+ ?line {ok,Tokens ,_} =
+ erl_scan:string("if a+4 == 4 -> yes; true -> no end. "),
+ ?line {ok, [Expr]} = erl_parse:parse_exprs(Tokens),
+ ?line {value, no, []} = erl_eval:expr(Expr, [], none, none, none),
+ ?line no = erl_eval:expr(Expr, [], none, none, value),
+ try
+ erl_eval:expr(Expr, [], none, none, 4711),
+ ?line function_clause = should_never_reach_here
+ catch
+ error:function_clause ->
+ ok
+ end.
+
+%% Check the string in different contexts: as is; in fun; from compiled code.
+check(F, String, Result) ->
+ check1(F, String, Result),
+ FunString = concat(["fun() -> ", no_final_dot(String), " end(). "]),
+ check1(F, FunString, Result),
+ CompileString = concat(["hd(lists:map(fun(_) -> ", no_final_dot(String),
+ " end, [foo])). "]),
+ check1(F, CompileString, Result).
+
+check1(F, String, Result) ->
+ Result = F(),
+ case catch parse_and_run(String) of
+ {value, Result, _} ->
+ ok;
+ Other ->
+ test_server:fail({eval, Other, Result})
+ end.
+
+check(F, String, Result, BoundVars, LFH, EFH) ->
+ Result = F(),
+ case catch parse_and_run(String, LFH, EFH) of
+ {value, Result, Bs} ->
+ %% We just assume that Bs is an orddict...
+ Keys = orddict:fetch_keys(Bs),
+ case sort(BoundVars) == Keys of
+ true ->
+ ok;
+ false ->
+ test_server:fail({check, BoundVars, Keys})
+ end,
+ ok;
+ Other ->
+ test_server:fail({check, Other, Result})
+ end.
+
+error_check(String, Result) ->
+ case catch parse_and_run(String) of
+ {'EXIT', {Result,_}} ->
+ ok;
+ Other ->
+ test_server:fail({eval, Other, Result})
+ end.
+
+error_check(String, Result, LFH, EFH) ->
+ case catch parse_and_run(String, LFH, EFH) of
+ {'EXIT', {Result,_}} ->
+ ok;
+ Other ->
+ test_server:fail({eval, Other, Result})
+ end.
+
+eval_string(String) ->
+ {value, Result, _} = parse_and_run(String),
+ Result.
+
+parse_and_run(String) ->
+ {ok,Tokens,_} = erl_scan:string(String),
+ {ok, [Expr]} = erl_parse:parse_exprs(Tokens),
+ erl_eval:expr(Expr, []).
+
+parse_and_run(String, LFH, EFH) ->
+ {ok,Tokens,_} = erl_scan:string(String),
+ {ok, [Expr]} = erl_parse:parse_exprs(Tokens),
+ erl_eval:expr(Expr, [], LFH, EFH).
+
+no_final_dot(S) ->
+ case lists:reverse(S) of
+ " ." ++ R -> lists:reverse(R);
+ "." ++ R -> lists:reverse(R);
+ _ -> S
+ end.
diff --git a/lib/stdlib/test/erl_eval_helper.erl b/lib/stdlib/test/erl_eval_helper.erl
new file mode 100644
index 0000000000..7fdbabcb17
--- /dev/null
+++ b/lib/stdlib/test/erl_eval_helper.erl
@@ -0,0 +1,28 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(erl_eval_helper, [Base]).
+
+-export([add/1]).
+
+add(Arg) ->
+ Base+Arg.
+
+
+
diff --git a/lib/stdlib/test/erl_expand_records_SUITE.erl b/lib/stdlib/test/erl_expand_records_SUITE.erl
new file mode 100644
index 0000000000..1d621c65df
--- /dev/null
+++ b/lib/stdlib/test/erl_expand_records_SUITE.erl
@@ -0,0 +1,823 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(erl_expand_records_SUITE).
+
+%-define(debug, true).
+
+-ifdef(debug).
+-define(line, put(line, ?LINE), ).
+-define(config(X,Y), foo).
+-define(privdir, "erl_expand_records_SUITE_priv").
+-define(t, test_server).
+-else.
+-include("test_server.hrl").
+-define(privdir, ?config(priv_dir, Config)).
+-endif.
+
+-export([all/1, init_per_testcase/2, fin_per_testcase/2]).
+
+-export([abstract_module/1, attributes/1, expr/1, guard/1,
+ init/1, pattern/1, strict/1, update/1,
+ tickets/1, otp_5915/1, otp_7931/1, otp_5990/1,
+ otp_7078/1, otp_7101/1]).
+
+% Default timetrap timeout (set in init_per_testcase).
+-define(default_timeout, ?t:minutes(1)).
+
+init_per_testcase(_Case, Config) ->
+ ?line Dog = ?t:timetrap(?default_timeout),
+ [{watchdog, Dog} | Config].
+
+fin_per_testcase(_Case, _Config) ->
+ Dog = ?config(watchdog, _Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+all(suite) ->
+ [abstract_module, attributes, expr, guard, init, pattern,
+ strict, update, tickets].
+
+abstract_module(doc) ->
+ "Compile an abstract module.";
+abstract_module(suite) -> [];
+abstract_module(Config) when is_list(Config) ->
+ %% erl_expand_records does not handle abstract modules. But anyway...
+ File = filename("param.erl", Config),
+ Beam = filename("param.beam", Config),
+ Test = <<"-module(param, [A, B]).
+
+ -export([args/1]).
+
+ args(C) ->
+ X = local(C),
+ Z = new(A, B),
+ {X, Z}.
+
+ local(C) ->
+ module_info(C).
+ ">>,
+
+ ?line ok = file:write_file(File, Test),
+ ?line {ok, param} = compile:file(File, [{outdir,?privdir}]),
+
+ ?line ok = file:delete(File),
+ ?line ok = file:delete(Beam),
+ ok.
+
+attributes(doc) ->
+ "Import module and functions.";
+attributes(suite) -> [];
+attributes(Config) when is_list(Config) ->
+ Ts = [
+ <<"-import(erl_expand_records_SUITE).
+ -import(lists, [append/2, reverse/1]).
+
+ -record(r, {a,b}).
+
+ t() ->
+ [2,1] = reverse(append([1],[2])),
+ 3 = length([1,2,3]),
+ 3 = record_info(size, r),
+ [a, b] = record_info(fields, r),
+ [] = erl_expand_records_SUITE:attributes(suite),
+ ok.
+ ">>
+ ],
+ ?line run(Config, Ts),
+ ok.
+
+expr(doc) ->
+ "Some expressions.";
+expr(suite) -> [];
+expr(Config) when is_list(Config) ->
+ Ts = [
+ <<"
+ -record(r, {a,b,c}).
+
+ t() ->
+ [1,2] = [R#r.a || R <- [#r{a = 1}, #r{a = 2}, #r{a = 3}],
+ R#r.a < 3],
+ [1,2] = [R#r.a || R <- [#r{a = 1}, #r{a = 2}, #r{a = 3}],
+ begin R#r.a < 3 end],
+ [1,2,3] = [R#r.a || R <- [#r{a = 1}, #r{a = 2}, #r{a = 3}],
+ begin is_record(R, r) end],
+ [1,2,3] = [R#r.a || R <- [#r{a = 1}, #r{a = 2}, #r{a = 3}],
+ begin erlang:is_record(R, r) end],
+ ok.
+ ">>,
+ <<"
+ -record(r, {a,b,c}).
+
+ f(X) -> X.
+
+ t() ->
+ A = {$c, 1, 3.14, a, \"hi\", [], [a,b]},
+ R = #r{a = element(6, A), b = #r.b},
+ 3 = R#r.b,
+ <<1:8>> = <<(begin erlang:element(2, A) end):8>>,
+ self() ! {a, message, []},
+ One = 1 = fun f/1(1),
+ 2 = fun(X) -> X end(One + One),
+ 3 = fun exprec_test:f/1(3),
+ 4 = {exprec_test,f}(4),
+ 5 = ''.f(5),
+ L = receive
+ {a,message,L0} ->
+ L0
+ end,
+ case catch a.b.c:foo(bar) of
+ {'EXIT', _} -> ok
+ end,
+ _ = receive %Suppress warning.
+ noop ->
+ 1/(length(L) - 0)
+ after 0 ->
+ ok
+ end,
+ if
+ R#r.c =:= undefined ->
+ ok;
+ true ->
+ not_ok
+ end.
+ ">>
+ ],
+
+ %% The code above should run equally well with and without
+ %% strict record tests.
+ ?line run(Config, Ts, [no_strict_record_tests]),
+ ?line run(Config, Ts, [strict_record_tests]),
+
+ ok.
+
+guard(doc) ->
+ "is_record in guards.";
+guard(suite) -> [];
+guard(Config) when is_list(Config) ->
+ File = filename("guard.erl", Config),
+ Beam = filename("guard.beam", Config),
+ Test = <<"-module(guard, [A, B]).
+
+ -export([t/1]).
+
+ -record(r, {a,b}).
+
+ t(_) when is_record(3, r) ->
+ 1;
+ t(_) when is_record(a, r) ->
+ 2;
+ t(_) when is_record(3.14, r) ->
+ 3;
+ t(_) when is_record([], r) ->
+ 4;
+ t(_) when is_record([a], r) ->
+ 5;
+ t(_) when is_record($a, r) ->
+ 6;
+ t(_) when is_record(\"foo\", r) ->
+ 7;
+ t(_) when is_record(#r.a, r) ->
+ 8;
+ t(_) when is_record(<<\"foo\">>, r) -> % line 23
+ 9;
+ t(_) when is_record(1 + 2, r) ->
+ 10;
+ t(_) when is_record(+ 3, r) ->
+ 11;
+ t(_) ->
+ 12.
+ ">>,
+
+ ?line ok = file:write_file(File, Test),
+ ?line {ok, guard, Ws} = compile:file(File, [return,{outdir,?privdir}]),
+ ?line Warnings = [L || {_File,WL} <- Ws, {L,_M,nomatch_guard} <- WL],
+ ?line [7,9,11,13,15,17,19,21,23,25,27] = Warnings,
+
+ ?line ok = file:delete(File),
+ ?line ok = file:delete(Beam),
+ ok.
+
+init(doc) ->
+ "Wildcard initialisation.";
+init(suite) -> [];
+init(Config) when is_list(Config) ->
+ Ts = [
+ <<"
+ -record(r, {a,b,c,d = foo}).
+
+ t() ->
+ R = #r{_ = init, b = b},
+ #r{c = init, b = b, a = init} = R,
+ case R of
+ #r{b = b, _ = init} -> ok;
+ _ -> not_ok
+ end.
+ ">>
+ ],
+ ?line run(Config, Ts),
+ ok.
+
+pattern(doc) ->
+ "Some patterns.";
+pattern(suite) -> [];
+pattern(Config) when is_list(Config) ->
+ Ts = [
+ <<"-import(erl_expand_records_SUITE).
+ -import(lists, [append/2, reverse/1]).
+
+ -record(r, {a,b}).
+
+ t() ->
+ 1 = t(#r{}),
+ 2 = t($a),
+ 3 = t(1000),
+ 4 = t({1000}),
+ 5 = t(3),
+ 6 = t(-3.14),
+ 7 = t({4.0}),
+ 8 = t(3.14),
+ 9 = t(\"str\"),
+ 10 = t([]),
+ 11 = t([a|b]),
+ 12 = t(\"string\"),
+ 13 = t({[]}),
+ 14 = t({a,b}),
+ 15 = t({{}}),
+ 16 = t({tuple,tupel}),
+ 17 = t(4),
+ 18 = t(10),
+ 19 = t({a}),
+ 20 = t(<<100:8,220:8>>),
+ 21 = t(#r{a = #r{}}),
+ 22 = t(2),
+ 23 = t(#r{a = #r{}, b = b}),
+ 24 = t(a.b.c),
+ ok.
+
+ t(a.b.c) ->
+ 24;
+ t($a) ->
+ 2;
+ t(3) ->
+ 5;
+ t(3.14) ->
+ 8;
+ t(\"str\") ->
+ 9;
+ t([]) ->
+ 10;
+ t([a|b]) ->
+ 11;
+ t(L) when is_list(L) ->
+ 12;
+ t({L}) when list(L) ->
+ 13;
+ t({a,b}) ->
+ 14;
+ t({T}) when is_tuple(T) ->
+ 15;
+ t(+ 4) ->
+ 17;
+ t(3+7) ->
+ 18;
+ t(<<A:8, (100+120):8>>) when A =:= 100 ->
+ 20;
+ t(#r{a = #r{}, b = undefined}) ->
+ 21;
+ t(#r.a) ->
+ 22;
+ t(A) when is_record(A, r), record(element(2, A), r) ->
+ 23;
+ t(A) when is_record(A, r) ->
+ 1;
+ t(I) when is_integer(I) ->
+ 3;
+ t({I}) when integer(I) ->
+ 4;
+ t({F}) when float(F) ->
+ 7;
+ t({A} = B) when A < B ->
+ 19;
+ t(F) when is_float(F) ->
+ 6;
+ t(T) when tuple(T) ->
+ 16.
+ ">>
+ ],
+ ?line run(Config, Ts),
+ ok.
+
+strict(doc) ->
+ "";
+strict(suite) -> [];
+strict(Config) when is_list(Config) ->
+ Ts1 = [
+ <<"-record(r1, {a,b}).
+ -record(r2, {a,b}).
+
+ t() ->
+ A = #r1{a = 1, b = 2},
+ ok = try
+ {1, 2} = {A#r2.a, A#r2.b},
+ not_ok
+ catch error:{badrecord,r2} -> ok
+ end,
+ try
+ case foo of
+ _ when A#r2.a =:= 1 -> not_ok
+ end
+ catch error:_ -> ok
+ end.
+ ">>
+ ],
+ ?line run(Config, Ts1, [strict_record_tests]),
+
+ Ts2 = [
+ <<"-record(r1, {a,b}).
+ -record(r2, {a,b}).
+
+ t() ->
+ A = #r1{a = 1, b = 2},
+ {1, 2} = {A#r2.a, A#r2.b},
+ case foo of
+ _ when A#r2.a =:= 1 -> ok
+ end.
+ ">>
+ ],
+ ?line run(Config, Ts2, [no_strict_record_tests]),
+ ok.
+
+update(doc) ->
+ "Record updates.";
+update(suite) -> [];
+update(Config) when is_list(Config) ->
+ Ts = [
+ <<"-record(r, {a,b,c,d,e,f}).
+
+ t() ->
+ R0 = #r{},
+ R1 = R0#r{a = #r.a, e = {x,y}},
+ 2 = R1#r.a,
+ R2 = R1#r{},
+ true = R1 =:= R2,
+ R3 = R2#r{c = fun(X) -> X end,
+ d = <<\"foo\">>,
+ e = [x,y,z],
+ f = {R0,R1}},
+ R4 = R3#r{a = R3#r{b = #r{}}},
+ true = erlang:is_record((R4#r.a)#r.b, r),
+ #r{a = R0, b = 3, c = 3.14, d = [], e = [[]], f = [{}]} =
+ R4#r{a = R0, b = 3, c = 3.14, d = [], e = [[]], f = [{}]},
+ ok.
+
+ %% Just playing around a bit...
+ t1() ->
+ ((#r{a = (#r{b = #r{}})#r{a = #r{}}})#r{b = #r{}})#r{c = #r{}}.
+
+ t2() ->
+ R0 = #r{},
+ #r{_ = R0#r{a = ok}}.
+ ">>
+ ],
+ ?line run(Config, Ts),
+ ok.
+
+tickets(suite) ->
+ [otp_5915, otp_7931, otp_5990, otp_7078, otp_7101].
+
+otp_5915(doc) ->
+ "Strict record tests in guards.";
+otp_5915(suite) -> [];
+otp_5915(Config) when is_list(Config) ->
+ %% These tests are also run by the compiler's record_SUITE.
+ Ts = [
+ <<"-record(r, {a = 4,b}).
+ -record(r1, {a,b}).
+ -record(r2, {a = #r1{},b,c=length([1,2,3])}).
+ -record(r3, {a = fun(_) -> #r1{} end(1), b}).
+
+ t() ->
+ foo = fun(A) when A#r1.a > A#r1.b -> foo end(#r1{b = 2}),
+ 0 = fun(A) when A#r2.a -> 0 end(#r2{a = true}),
+ 1 = fun(A) when (#r1{a = A})#r1.a > 2 -> 1 end(3),
+ 2 = fun(N) when ((#r2{a = #r{a = 4}, b = length([a,b,c])})#r2.a)#r.a > N ->
+ 2 end(2),
+ 3 = fun(A) when (A#r2.a)#r1.a =:= 3 -> 3 end(#r2{a = #r1{a = 3}}),
+ ok = fun() ->
+ F = fun(A) when record(A#r.a, r1) -> 4;
+ (A) when record(A#r1.a, r1) -> 5
+ end,
+ 5 = F(#r1{a = #r1{}}),
+ 4 = F(#r{a = #r1{}}),
+ ok
+ end(),
+ 3 = fun(A) when record(A#r1.a, r),
+ (A#r1.a)#r.a > 3 -> 3
+ end(#r1{a = #r{a = 4}}),
+ 7 = fun(A) when record(A#r3.a, r1) -> 7 end(#r3{}),
+ [#r1{a = 2,b = 1}] =
+ fun() ->
+ [A || A <- [#r1{a = 1, b = 3},
+ #r2{a = 2,b = 1},
+ #r1{a = 2, b = 1}],
+ A#r1.a >
+ A#r1.b]
+ end(),
+ {[_],b} =
+ fun(L) ->
+ %% A is checked only once:
+ R1 = [{A,B} || A <- L, A#r1.a, B <- L, A#r1.b],
+ A = #r2{a = true},
+ %% A is checked again:
+ B = if A#r1.a -> a; true -> b end,
+ {R1,B}
+ end([#r1{a = true, b = true}]),
+
+ p = fun(A) when (A#r1.a =:= 2) or (A#r2.a =:= 1) -> o;
+ (_) -> p
+ end(#r1{a = 2}),
+
+ o = fun(A) when (A#r1.a =:= 2) orelse (A#r2.a =:= 1) -> o;
+ (_) -> p
+ end(#r1{a = 2}),
+
+ 3 = fun(A) when A#r1.a > 3,
+ record(A, r1) -> 3
+ end(#r1{a = 5}),
+
+ ok = fun() ->
+ F = fun(A) when (A#r2.a =:= 1) orelse (A#r2.a) -> 2;
+ (A) when (A#r1.a =:= 1) orelse (A#r1.a) -> 1;
+ (A) when (A#r2.a =:= 2) andalso (A#r2.b) -> 3
+ end,
+ 1 = F(#r1{a = 1}),
+ 2 = F(#r2{a = true}),
+ 3 = F(#r2{a = 2, b = true}),
+ ok
+ end(),
+
+ b = fun(A) when false or not (A#r.a =:= 1) -> a;
+ (_) -> b
+ end(#r1{a = 1}),
+ b = fun(A) when not (A#r.a =:= 1) or false -> a;
+ (_) -> b
+ end(#r1{a = 1}),
+
+ ok = fun() ->
+ F = fun(A) when not (A#r.a =:= 1) -> yes;
+ (_) -> no
+ end,
+ no = F(#r1{a = 2}),
+ yes = F(#r{a = 2}),
+ no = F(#r{a = 1}),
+ ok
+ end(),
+
+ a = fun(A) when record(A, r),
+ A#r.a =:= 1,
+ A#r.b =:= 2 ->a
+ end(#r{a = 1, b = 2}),
+ a = fun(A) when erlang:is_record(A, r),
+ A#r.a =:= 1,
+ A#r.b =:= 2 -> a
+ end(#r{a = 1, b = 2}),
+ a = fun(A) when is_record(A, r),
+ A#r.a =:= 1,
+ A#r.b =:= 2 -> a
+ end(#r{a = 1, b = 2}),
+
+ nop = fun(A) when (is_record(A, r1) and (A#r1.a > 3)) or (A#r2.a < 1) ->
+ japp;
+ (_) ->
+ nop
+ end(#r2{a = 0}),
+ nop = fun(A) when (A#r1.a > 3) or (A#r2.a < 1) -> japp;
+ (_) ->
+ nop
+ end(#r2{a = 0}),
+
+ ok = fun() ->
+ F = fun(A) when (A#r1.a =:= 2) or (A#r2.a =:= 1) -> o;
+ (_) -> p
+ end,
+ p = F(#r2{a = 1}),
+ p = F(#r1{a = 2}),
+ ok
+ end(),
+
+ ok = fun() ->
+ F = fun(A) when fail, A#r1.a; A#r1.a -> ab;
+ (_) -> bu
+ end,
+ ab = F(#r1{a = true}),
+ bu = F(#r2{a = true}),
+ ok
+ end(),
+
+ both = fun(A) when A#r.a, A#r.b -> both
+ end(#r{a = true, b = true}),
+
+ ok = fun() ->
+ F = fun(A, B) when ((A#r1.a) orelse (B#r2.a))
+ or (B#r2.b) or (A#r1.b) -> true;
+ (_, _) -> false
+ end,
+ true = F(#r1{a = false, b = false}, #r2{a = false, b = true}),
+ false = F(#r1{a = true, b = true}, #r1{a = false, b = true}),
+ ok
+ end(),
+
+ ok.
+ ">>
+ ],
+ ?line run(Config, Ts, [strict_record_tests]),
+ ok.
+
+otp_7931(doc) ->
+ "Test optimization of record accesses and is_record/3 tests in guards";
+otp_7931(suite) -> [];
+otp_7931(Config) when is_list(Config) ->
+ Ts = [
+ <<"-record(r, {a = 4,b}).
+ -record(r1, {a,b}).
+ -record(r2, {a = #r1{},b,c=length([1,2,3])}).
+ -record(r3, {a = fun(_) -> #r1{} end(1), b}).
+
+ t() ->
+ ok = fun() ->
+ F = fun(F, [H,H|T]) when is_record(H, r) ->
+ [H|F(F, T)];
+ (F, [H|T]) when is_record(H, r) ->
+ [H|F(F, T)];
+ (_, []) -> []
+ end,
+ [#r{a=4,b=7},#r{a=1,b=42}] =
+ F(F, [#r{a=4,b=7},#r{a=4,b=7},#r{a=1,b=42}]),
+ {'EXIT',_} = (catch F(F, [#r1{}])),
+ ok
+ end(),
+
+ true = fun() ->
+ R = #r{},
+ if is_record(R, r) -> true; true -> false end
+ end(),
+
+ ok = fun() ->
+ F = fun(true, B) when B#r1.a -> ok;
+ (false, _) -> error
+ end,
+ ok = F(true, #r1{a=true}),
+ error = F(false, anything_goes),
+ {'EXIT',_} = (catch F(true, #r1{})),
+ {'EXIT',_} = (catch F(true, #r{})),
+ ok
+ end(),
+
+ ok = fun() ->
+ F = fun([{a,R}=T]) when R#r.a =:= 42 ->
+ {ok,tuple_size(T)};
+ ([{a,R}=T]) when R#r1.a =:= 7 ->
+ {ok,tuple_size(T)};
+ (_) -> error
+ end,
+ {ok,2} = F([{a,#r{a=42}}]),
+ {ok,2} = F([{a,#r1{a=7}}]),
+ error = F([{a,#r1{}}]),
+ error = F({a,b,c}),
+ error = F([]),
+ ok
+ end(),
+
+ ok = fun() ->
+ F = fun(X, Y, Z) when is_record(X, r1) andalso
+ (is_record(Y, r2) orelse
+ is_record(Z, r3)) -> true;
+ (_, _, _) -> false
+ end,
+ true = F(#r1{}, #r2{}, #r3{}),
+ true = F(#r1{}, #r2{}, blurf),
+ true = F(#r1{}, blurf, #r3{}),
+ false = F(#r1{}, blurf, blurf),
+ false = F(blurf, #r2{}, #r3{}),
+ false = F(blurf, #r2{}, blurf),
+ false = F(blurf, blurf, #r3{}),
+ false = F(blurf, blurf, blurf),
+ ok
+ end(),
+
+ ok = fun() ->
+ F = fun(R=#r{a=42}) when R#r.b =:= 7 ->
+ {ok,R};
+ (_) -> error
+ end,
+ {ok,#r{a=42,b=7}} = F(#r{a=42,b=7}),
+ error = F(#r{}),
+ error = F([a,b,c]),
+ ok
+ end(),
+
+ ok.
+ ">>
+ ],
+ ?line run(Config, Ts, [strict_record_tests]),
+ ok.
+
+otp_5990(doc) ->
+ "OTP-5990. {erlang,is_record}.";
+otp_5990(suite) -> [];
+otp_5990(Config) when is_list(Config) ->
+ Ts = [
+ <<"
+ -record(r, {a,b,c}).
+
+ t() ->
+ [1,2,3] = [R#r.a || R <- [#r{a = 1}, #r{a = 2}, #r{a = 3}],
+ begin {erlang,is_record}(R, r) end],
+ [1,2,3] = [R#r.a || R <- [#r{a = 1}, #r{a = 2}, #r{a = 3}],
+ begin {erlang,is_record}(R, r) end],
+ ok.
+ ">>,
+
+ <<"
+ -record('OrdSet', {orddata = {},
+ ordtype = {}}).
+
+ to_sets(S) when tuple(S#'OrdSet'.ordtype) ->
+ ok.
+
+ lc(S) ->
+ [X || X <- [S], tuple(X#'OrdSet'.ordtype)].
+
+ t() ->
+ S = #'OrdSet'{},
+ ok = to_sets(S),
+ [S] = lc(S),
+ ok.
+ ">>
+ ],
+ ?line run(Config, Ts, [strict_record_tests]),
+ ok.
+
+
+otp_7078(doc) ->
+ "OTP-7078. Record update: missing test.";
+otp_7078(suite) -> [];
+otp_7078(Config) when is_list(Config) ->
+ Ts = [
+ <<"
+ -record(r, {f}).
+ -record(r2, {}).
+
+ t() ->
+ {'EXIT',_} = (catch (#r2{})#r{}),
+ {'EXIT',_} = (catch (#r2{})#r{f = 2}),
+ ok.
+ ">>,
+
+ <<"
+ -record(r, {f}).
+
+ maker(F) ->
+ put(a, get(a)+1),
+ #r{f = F}.
+
+ t() ->
+ put(a, 0),
+ (maker(2))#r{},
+ 1 = get(a),
+ ok.
+ ">>
+
+ ],
+ ?line run(Config, Ts, [strict_record_tests]),
+ ok.
+
+-record(otp_7101, {a,b,c=[],d=[],e=[]}).
+
+otp_7101(doc) ->
+ "OTP-7101. Record update: more than one call to setelement/3.";
+otp_7101(suite) -> [];
+otp_7101(Config) when is_list(Config) ->
+ Rec = #otp_7101{},
+
+ %% Spawn a tracer process to count the number of setelement/3 calls.
+ %% The tracer will forward all trace messages to us.
+ Self = self(),
+ Tracer = spawn_link(fun() -> otp_7101_tracer(Self, 0) end),
+ ?line 1 = erlang:trace_pattern({erlang,setelement,3}, true),
+ ?line erlang:trace(self(), true, [{tracer,Tracer},call]),
+
+ %% Update the record.
+ ?line #otp_7101{a=2,b=1,c=[],d=[],e=[]} = otp_7101_update1(Rec),
+ ?line #otp_7101{a=1,b=2,c=[],d=[],e=[]} = otp_7101_update2(Rec),
+ ?line #otp_7101{a=2,b=1,c=[],d=[],e=[]} = otp_7101_update3(Rec),
+ ?line #otp_7101{a=1,b=2,c=[],d=[],e=[]} = otp_7101_update4(Rec),
+
+ %% Verify that setelement/3 was called the same number of times as
+ %% the number of record updates.
+ ?line Ref = erlang:trace_delivered(Self),
+ receive
+ {trace_delivered, Self, Ref} ->
+ Tracer ! done
+ end,
+ ?line 1 = erlang:trace_pattern({erlang,setelement,3}, false),
+ receive
+ 4 ->
+ ok;
+ Other ->
+ ?line ?t:fail({unexpected,Other})
+ end.
+
+otp_7101_tracer(Parent, N) ->
+ receive
+ {trace,Parent,call,{erlang,setelement,[_,_,_]}} ->
+ otp_7101_tracer(Parent, N+1);
+ done ->
+ Parent ! N
+ end.
+
+otp_7101_update1(R) ->
+ R#otp_7101{b=1,
+ a=2}.
+
+otp_7101_update2(R) ->
+ R#otp_7101{a=1,
+ b=2}.
+
+otp_7101_update3(R) ->
+ R#otp_7101{b=1,a=2}.
+
+otp_7101_update4(R) ->
+ R#otp_7101{a=1,b=2}.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+run(Config, Tests) ->
+ run(Config, Tests, []).
+
+run(Config, Tests, Opts) ->
+ F = fun(P) ->
+ {SourceFile, Mod} = compile_file_mod(Config),
+ _ = compile_file(Config, P, Opts),
+ AbsFile = filename:rootname(SourceFile, ".erl"),
+ code:purge(Mod),
+ code:load_abs(AbsFile, Mod),
+%io:format("run~n"),
+ case catch Mod:t() of
+ {'EXIT', _Reason} = Error ->
+ ?t:format("failed, got ~p~n", [Error]),
+ fail();
+ ok ->
+ ok
+ end
+ end,
+ lists:foreach(F, Tests).
+
+%% Compiles a test module and returns the list of errors and warnings.
+
+compile_file(Config, Test0, Opts0) ->
+ {File, _Mod} = compile_file_mod(Config),
+ Filename = 'exprec_test.erl',
+ Test = list_to_binary(["-module(exprec_test). "
+ "-compile(export_all). ",
+ Test0]),
+ File = filename(Filename, Config),
+ Opts = [export_all,return,{outdir,?privdir}|Opts0],
+ ok = file:write_file(File, Test),
+ {ok, _M, Ws} = compile:file(File, Opts),
+ warnings(File, Ws).
+
+compile_file_mod(Config) ->
+ {filename('exprec_test.erl', Config), exprec_test}.
+
+filename(Name, Config) when is_atom(Name) ->
+ filename(atom_to_list(Name), Config);
+filename(Name, Config) ->
+ filename:join(?privdir, Name).
+
+warnings(File, Ws) ->
+ case lists:append([W || {F, W} <- Ws, F =:= File]) of
+ [] -> [];
+ L -> {warnings, L}
+ end.
+
+fail() ->
+ io:format("failed~n"),
+ ?t:fail().
diff --git a/lib/stdlib/test/erl_internal_SUITE.erl b/lib/stdlib/test/erl_internal_SUITE.erl
new file mode 100644
index 0000000000..8f675c94ec
--- /dev/null
+++ b/lib/stdlib/test/erl_internal_SUITE.erl
@@ -0,0 +1,69 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(erl_internal_SUITE).
+
+-export([all/1]).
+
+-export([behav/1]).
+
+-export([init_per_testcase/2, fin_per_testcase/2]).
+
+-include("test_server.hrl").
+
+all(suite) -> [behav].
+
+-define(default_timeout, ?t:minutes(2)).
+
+init_per_testcase(_Case, Config) ->
+ ?line Dog = test_server:timetrap(?default_timeout),
+ [{watchdog, Dog}|Config].
+
+fin_per_testcase(_Case, Config) ->
+ Dog=?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+behav(suite) -> [];
+behav(doc) ->
+ ["Check that the behaviour callbacks are correctly defined"];
+behav(_) ->
+ ?line check_behav_list([{start,2}, {stop,1}],
+ application:behaviour_info(callbacks)),
+ ?line check_behav_list([{init,1}, {handle_call,3}, {handle_cast,2},
+ {handle_info,2}, {terminate,2}, {code_change,3}],
+ gen_server:behaviour_info(callbacks)),
+ ?line check_behav_list([{init,1}, {handle_event,3}, {handle_sync_event,4},
+ {handle_info,3}, {terminate,3}, {code_change,4}],
+ gen_fsm:behaviour_info(callbacks)),
+ ?line check_behav_list([{init,1}, {handle_event,2}, {handle_call,2},
+ {handle_info,2}, {terminate,2}, {code_change,3}],
+ gen_event:behaviour_info(callbacks)),
+ ?line check_behav_list( [{init,1}, {terminate,2}],
+ supervisor_bridge:behaviour_info(callbacks)),
+ ?line check_behav_list([{init,1}],
+ supervisor:behaviour_info(callbacks)),
+ ok.
+
+check_behav_list([], []) -> ok;
+check_behav_list([L | L1], L2) ->
+ ?line true = lists:member(L, L2),
+ ?line L3 = lists:delete(L, L2),
+ check_behav_list(L1, L3).
+
+
diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl
new file mode 100644
index 0000000000..bfbd7b3dc1
--- /dev/null
+++ b/lib/stdlib/test/erl_lint_SUITE.erl
@@ -0,0 +1,2783 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(erl_lint_SUITE).
+
+%-define(debug, true).
+
+-ifdef(debug).
+-define(line, put(line, ?LINE), ).
+-define(config(X,Y), foo).
+-define(datadir, "erl_lint_SUITE_data").
+-define(privdir, "erl_lint_SUITE_priv").
+-define(t, test_server).
+-else.
+-include("test_server.hrl").
+-define(datadir, ?config(data_dir, Conf)).
+-define(privdir, ?config(priv_dir, Conf)).
+-endif.
+
+-export([all/1, init_per_testcase/2, fin_per_testcase/2]).
+
+-export([unused_vars_warn/1,
+ unused_vars_warn_basic/1,
+ unused_vars_warn_lc/1,
+ unused_vars_warn_rec/1,
+ unused_vars_warn_fun/1,
+ unused_vars_OTP_4858/1,
+ export_vars_warn/1,
+ shadow_vars/1,
+ unused_import/1,
+ unused_function/1,
+ unsafe_vars/1,unsafe_vars2/1,
+ unsafe_vars_try/1,
+ guard/1, otp_4886/1, otp_4988/1, otp_5091/1, otp_5276/1, otp_5338/1,
+ otp_5362/1, otp_5371/1, otp_7227/1, otp_5494/1, otp_5644/1, otp_5878/1,
+ otp_5917/1, otp_6585/1, otp_6885/1, export_all/1,
+ bif_clash/1,
+ behaviour_basic/1, behaviour_multiple/1,
+ otp_7550/1,
+ otp_8051/1,
+ format_warn/1,
+ on_load/1, on_load_successful/1, on_load_failing/1
+ ]).
+
+% Default timetrap timeout (set in init_per_testcase).
+-define(default_timeout, ?t:minutes(1)).
+
+init_per_testcase(_Case, Config) ->
+ ?line Dog = ?t:timetrap(?default_timeout),
+ [{watchdog, Dog} | Config].
+
+fin_per_testcase(_Case, _Config) ->
+ Dog = ?config(watchdog, _Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+all(suite) ->
+ [unused_vars_warn, export_vars_warn,
+ shadow_vars, unused_import, unused_function,
+ unsafe_vars, unsafe_vars2, unsafe_vars_try,
+ guard, otp_4886, otp_4988, otp_5091, otp_5276, otp_5338,
+ otp_5362, otp_5371, otp_7227, otp_5494, otp_5644, otp_5878, otp_5917, otp_6585,
+ otp_6885, export_all, bif_clash,
+ behaviour_basic, behaviour_multiple, otp_7550, otp_8051, format_warn,
+ on_load].
+
+unused_vars_warn(suite) ->
+ [unused_vars_warn_basic, unused_vars_warn_lc, unused_vars_warn_rec,
+ unused_vars_warn_fun, unused_vars_OTP_4858].
+
+unused_vars_warn_basic(doc) ->
+ "Warnings for unused variables in some simple cases.";
+unused_vars_warn_basic(suite) -> [];
+unused_vars_warn_basic(Config) when is_list(Config) ->
+ Ts = [{basic1,
+ <<"f(F) -> % F unused.
+ ok.
+
+ f(F, F) ->
+ ok.
+
+ g(_X) ->
+ y.
+
+ h(P) ->
+ P.
+
+ x(N) ->
+ case a:b() of
+ [N|Y] -> % Y unused.
+ ok
+ end.
+
+ y(N, L) ->
+ lists:map(fun(T) -> T*N end, L).
+
+ z(N, L) -> % N unused
+ lists:map(fun(N, T) -> T*N end, L). % N shadowed.
+
+
+ c(A) ->
+ case A of
+ 1 -> B = []; % B unused.
+ 2 -> B = []; % B unused.
+ 3 -> B = f, B
+ end.
+ ">>,
+ [warn_unused_vars],
+ {warnings,[{1,erl_lint,{unused_var,'F'}},
+ {15,erl_lint,{unused_var,'Y'}},
+ {22,erl_lint,{unused_var,'N'}},
+ {23,erl_lint,{shadowed_var,'N','fun'}},
+ {28,erl_lint,{unused_var,'B'}},
+ {29,erl_lint,{unused_var,'B'}}]}}],
+ ?line [] = run(Config, Ts),
+ ok.
+
+unused_vars_warn_lc(doc) ->
+ "Warnings for unused variables in list comprehensions.";
+unused_vars_warn_lc(suite) -> [];
+unused_vars_warn_lc(Config) when is_list(Config) ->
+ Ts = [{lc1,
+ <<"bin([X]) ->
+ [A || <<A:X>> <- []]; % X used, not shadowed.
+ bin({X}) ->
+ [X || <<X:X>> <- []]; % X used, and shadowed.
+ bin({X,Y,Z}) ->
+ [{A,B} || <<A:X>> <- Z, <<B:Y>> <- Z];
+ bin([X,Y,Z]) -> % Y unused.
+ [C || <<V:X>> <- Z, <<B:V>> <- Z, <<C:B>> <- Z].
+ ">>,
+ [warn_unused_vars],
+ {warnings, [{4,erl_lint,{shadowed_var,'X',generate}},
+ {7,erl_lint,{unused_var,'Y'}}]}},
+
+ {lc2,
+ <<"bin([X]) ->
+ [A || <<A:X>> <- []]; % X used, not shadowed.
+ bin({X}) ->
+ [X || <<X:X>> <- []]; % X used, and shadowed.
+ bin({X,Y,Z}) ->
+ [{A,B} || <<A:X>> <- Z, <<B:Y>> <- Z];
+ bin([X,Y,Z]) -> % Y unused.
+ [C || <<V:X>> <- Z, <<B:V>> <- Z, <<C:B>> <- Z].
+ ">>,
+ [warn_unused_vars],
+ {warnings,[{4,erl_lint,{shadowed_var,'X',generate}},
+ {7,erl_lint,{unused_var,'Y'}}]}},
+
+ {lc3,
+ <<"a([A]) ->
+ B = foo,
+ [{C,B} || {C,_} <- A];
+ a({A}) ->
+ B = foo,
+ [C || {C,_} <- [B,A]];
+ a({A,A}) ->
+ B = foo,
+ [C || {C,_} <- B, B < A].
+ ">>,
+ [warn_unused_vars],
+ []},
+
+ {lc4,
+ <<"b(A) ->
+ B = foo, % B unused.
+ [C || {C,_} <- A].
+ ">>,
+ [warn_unused_vars],
+ {warnings,[{2,erl_lint,{unused_var,'B'}}]}},
+
+ {lc5,
+ <<"c(A) ->
+ B = foo,
+ [C || {C,_} <- A],
+ B.
+ ">>,
+ [warn_unused_vars],
+ []},
+
+ {lc6,
+ <<"d(A) ->
+ B = foo,
+ [{A,B} || {Id,_} <- A]. % Id unused.
+ ">>,
+ [warn_unused_vars],
+ {warnings,[{3,erl_lint,{unused_var,'Id'}}]}},
+
+ {lc7,
+ <<"e(A) ->
+ B = foo, % B unused.
+ [B || B <- A]. % B shadowed.
+ ">>,
+ [warn_unused_vars],
+ {warnings,[{2,erl_lint,{unused_var,'B'}},
+ {3,erl_lint,{shadowed_var,'B',generate}}]}},
+
+ {lc8,
+ <<"f(A) ->
+ B = foo,
+ [B || B <- A], % B shadowed.
+ B.
+ ">>,
+ [warn_unused_vars],
+ {warnings,[{3,erl_lint,{shadowed_var,'B',generate}}]}},
+
+ {lc9,
+ <<"g(A) ->
+ B = foo, % B unused.
+ [A || B <- A]. % B shadowed, B unused.
+ ">>,
+ [warn_unused_vars],
+ {warnings,[{2,erl_lint,{unused_var,'B'}},
+ {3,erl_lint,{unused_var,'B'}},
+ {3,erl_lint,{shadowed_var,'B',generate}}]}},
+
+ {lc10,
+ <<"h(A) ->
+ B = foo,
+ [A || B <- A], % B shadowed, B unused.
+ B.
+ ">>,
+ [warn_unused_vars],
+ {warnings,[{3,erl_lint,{unused_var,'B'}},
+ {3,erl_lint,{shadowed_var,'B',generate}}]}},
+
+ {lc11,
+ <<"i(X) ->
+ [Z || Z <- X, % Z unused.
+ Z = X <- [foo]]. % X and Z shadowed. X unused!
+ ">>,
+ [warn_unused_vars],
+ {warnings,[{2,erl_lint,{unused_var,'Z'}},
+ {3,erl_lint,{unused_var,'X'}},
+ {3,erl_lint,{shadowed_var,'X',generate}},
+ {3,erl_lint,{shadowed_var,'Z',generate}}]}},
+
+ {lc12,
+ <<"j({X}) ->
+ [Z || Z <- X, % Z unused.
+ Z <- X = [[1,2,3]], % Z shadowed. Z unused.
+ Z <- X, % Z shadowed. Z unused.
+ Z <- X]; % Z shadowed.
+ j(X) ->
+ [foo || X <- X, % X shadowed.
+ X <- % X shadowed. X unused.
+ X =
+ Y = [[1,2,3]], % Y unused.
+ X <- [], % X shadowed.
+ X <- X]. % X shadowed. X unused.
+ ">>,
+ [warn_unused_vars],
+ {warnings,[{2,erl_lint,{unused_var,'Z'}},
+ {3,erl_lint,{unused_var,'Z'}},
+ {3,erl_lint,{shadowed_var,'Z',generate}},
+ {4,erl_lint,{unused_var,'Z'}},
+ {4,erl_lint,{shadowed_var,'Z',generate}},
+ {5,erl_lint,{shadowed_var,'Z',generate}},
+ {7,erl_lint,{shadowed_var,'X',generate}},
+ {8,erl_lint,{unused_var,'X'}},
+ {8,erl_lint,{shadowed_var,'X',generate}},
+ {10,erl_lint,{unused_var,'Y'}},
+ {11,erl_lint,{shadowed_var,'X',generate}},
+ {12,erl_lint,{unused_var,'X'}},
+ {12,erl_lint,{shadowed_var,'X',generate}}]}},
+
+ {lc13,
+ <<"k(X) ->
+ [Z || Z <- Y = X]; % Y unused.
+ k(X) ->
+ [Z || Z <- X = Y = X]; % Y unused!
+ k(X) ->
+ [Z || Z <- begin X = Y = X, Y end];
+ k(X) ->
+ [{Y,W} || W <- Y = X]; % Y unbound
+ k(X) ->
+ [Z || Z <- (Y = X), % Y unused.
+ Y > X]; % Y unbound.
+ k(X) ->
+ [Y || Y = X > 3, Z = X]; % Z unused.
+ k(X) ->
+ [Z || Y = X > 3, Z = X]. % Y unused.
+ ">>,
+ [warn_unused_vars],
+ {error,[{8,erl_lint,{unbound_var,'Y'}},
+ {11,erl_lint,{unbound_var,'Y'}}],
+ [{2,erl_lint,{unused_var,'Y'}},
+ {4,erl_lint,{unused_var,'Y'}},
+ {8,erl_lint,{unused_var,'Y'}},
+ {10,erl_lint,{unused_var,'Y'}},
+ {13,erl_lint,{unused_var,'Z'}},
+ {15,erl_lint,{unused_var,'Y'}}]}},
+
+ {lc14,
+ <<"lc2() ->
+ Z = [[1],[2],[3]],
+ [X || Z <- Z, % Z shadowed.
+ X <- Z].
+ ">>,
+ [warn_unused_vars],
+ {warnings,[{3,erl_lint,{shadowed_var,'Z',generate}}]}},
+
+ {lc15,
+ <<"lc3() ->
+ Z = [1,2,3],
+ [X || X <- Z,
+ Z <- Z]. % Z shadowed. Z unused.
+ ">>,
+ [warn_unused_vars],
+ {warnings,[{4,erl_lint,{unused_var,'Z'}},
+ {4,erl_lint,{shadowed_var,'Z',generate}}]}},
+
+ {lc16,
+ <<"bin(Z) ->
+ case bar of
+ true ->
+ U = 2;
+ false ->
+ true
+ end,
+ case bar of
+ true ->
+ X = 2;
+ false ->
+ X = 3
+ end,
+ case foo of
+ true ->
+ Y = 3; % Y unused.
+ false ->
+ 4
+ end,
+ case foo of
+ 1 ->
+ U; % U unsafe.
+ 2 ->
+ [Z || <<U:X>> <- Z]; % (X exported.) U unused.
+ 3 ->
+ [Z || <<U:X>> <- Z], % (X exported.) U unused.
+ U % U unsafe.
+ end.
+ ">>,
+ [warn_unused_vars],
+ {error,[{22,erl_lint,{unsafe_var,'U',{'case',2}}},
+ {27,erl_lint,{unsafe_var,'U',{'case',2}}}],
+ [{16,erl_lint,{unused_var,'Y'}},
+ % {24,erl_lint,{exported_var,'X',{'case',8}}},
+ {24,erl_lint,{unused_var,'U'}},
+ % {26,erl_lint,{exported_var,'X',{'case',8}}},
+ {26,erl_lint,{unused_var,'U'}}]}},
+
+ {lc17,
+ <<"bin(Z) ->
+ %% This used to pass erl_lint...
+ case bar of
+ true ->
+ U = 2;
+ false ->
+ true
+ end,
+ case bar of
+ true ->
+ X = 2;
+ false ->
+ X = 3
+ end,
+ case foo of
+ true ->
+ Y = 3; % Y unused.
+ false ->
+ 4
+ end,
+ [Z || <<U:X>> <- Z], % (X exported.) U unused.
+ U. % U unsafe.
+ ">>,
+ [warn_unused_vars],
+ {error,[{22,erl_lint,{unsafe_var,'U',{'case',3}}}],
+ [{17,erl_lint,{unused_var,'Y'}},
+ % {21,erl_lint,{exported_var,'X',{'case',9}}},
+ {21,erl_lint,{unused_var,'U'}}]}},
+
+ {lc18,
+ <<"bin(Z) ->
+ case bar of
+ true ->
+ U = 2;
+ false ->
+ true
+ end,
+ case bar of
+ true ->
+ X = 2;
+ false ->
+ X = 3
+ end,
+ case foo of
+ true ->
+ Y = 3;
+ false ->
+ 4
+ end,
+ [B || <<U: % U unused
+ U>> <- X, <<B:Y>> <- Z]. % U unsafe. Y unsafe.
+ % U shadowed. (X exported.)
+ ">>,
+ [warn_unused_vars],
+ {error,[{21,erl_lint,{unsafe_var,'U',{'case',2}}},
+ {21,erl_lint,{unsafe_var,'Y',{'case',14}}}],
+ [{20,erl_lint,{unused_var,'U'}}
+ % ,{21,erl_lint,{exported_var,'X',{'case',8}}}
+ % ,{21,erl_lint,{shadowed_var,'U',generate}}
+ ]}},
+
+ {lc19,
+ <<"p({B,C}) ->
+ <<A:B,A:C>> = <<17:32>>;
+ p(B) ->
+ <<A:B>> = <<17:32>>. % A unused.
+ ">>,
+ [warn_unused_vars],
+ {warnings,[{4,erl_lint,{unused_var,'A'}}]}},
+
+ {lc20,
+ <<"c({I1,I2}) ->
+ if
+ <<I1:I2>> == <<>> ->
+ foo
+ end;
+ c([C1,C2]) -> % C1 unused.
+ case foo of
+ <<C2:C2,
+ C3:C2>> -> % C3 unused.
+ bar
+ end.
+
+ ">>,
+ [warn_unused_vars],
+ {warnings,[{6,erl_lint,{unused_var,'C1'}},
+ {7,sys_core_fold,no_clause_match},
+ {9,erl_lint,{unused_var,'C3'}}]}},
+
+ {lc21,
+ <<"t() ->
+ S = 8,
+ case <<3:8>> of
+ <<X:S>> ->
+ X;
+ <<S:X>> -> % X unbound
+ foo
+ end;
+ t() ->
+ S = 8,
+ case <<3:8>> of
+ <<S:S>> ->
+ S;
+ <<Q:32>> -> % Q unused.
+ foo
+ end.
+ ">>,
+ [warn_unused_vars],
+ {error,[{6,erl_lint,{unbound_var,'X'}}],
+ [{14,erl_lint,{unused_var,'Q'}}]}}
+
+ ],
+ ?line [] = run(Config, Ts),
+ ok.
+
+
+unused_vars_warn_rec(doc) ->
+ "Warnings for unused variables in records.";
+unused_vars_warn_rec(suite) -> [];
+unused_vars_warn_rec(Config) when is_list(Config) ->
+ Ts = [{rec1, % An example provided by Bjorn.
+ <<"-record(edge,
+ {ltpr,
+ ltsu,
+ rtpr,
+ rtsu
+ }).
+
+ f1(#edge{ltpr = A, ltsu = A}) ->
+ true;
+ f1({Q, Q}) ->
+ true.
+
+ f2(Edge, Etab) ->
+ case gb_trees:lookup(Edge, Etab) of
+ {value,#edge{ltpr=Same,ltsu=Same}} -> ok;
+ {value,_} -> error
+ end.
+
+ bar(Edge, Etab) ->
+ case gb_trees:lookup(Edge, Etab) of
+ {Same,Same} -> ok;
+ {value,#edge{ltpr=Same}} -> ok; % Same unused.
+ {value,_} -> error
+ end.
+ ">>,
+ [warn_unused_vars],
+ {warnings,[{22,erl_lint,{unused_var,'Same'}}]}}],
+ ?line [] = run(Config, Ts),
+ ok.
+
+unused_vars_warn_fun(doc) ->
+ "Warnings for unused variables in records.";
+unused_vars_warn_fun(suite) -> [];
+unused_vars_warn_fun(Config) when is_list(Config) ->
+ Ts = [{fun1,
+ <<"a({A,B}) -> % A unused.
+ fun(A) -> B end; % A shadowed. A unused.
+ a([A,B]) ->
+ fun(<<A:B>>, % A shadowed. A unused.
+ <<Q:A>>) -> foo % Q unused.
+ end;
+ a({A,B,C,D,E}) ->
+ fun(E) when C == <<A:A>>, <<17:B>> == D -> % E shadowed. E unused.
+ foo
+ end,
+ E;
+ a([A,B,C,D,E]) -> % E unused.
+ fun() ->
+ (C == <<A:A>>) and (<<17:B>> == D)
+ end.
+ ">>,
+ [warn_unused_vars],
+ {warnings,[{1,erl_lint,{unused_var,'A'}},
+ {2,erl_lint,{unused_var,'A'}},
+ {2,erl_lint,{shadowed_var,'A','fun'}},
+ {4,erl_lint,{unused_var,'A'}},
+ {4,erl_lint,{shadowed_var,'A','fun'}},
+ {5,erl_lint,{unused_var,'Q'}},
+ {8,erl_lint,{unused_var,'E'}},
+ {8,erl_lint,{shadowed_var,'E','fun'}},
+ {8,sys_core_fold,useless_building},
+ {12,erl_lint,{unused_var,'E'}}]}},
+
+ {fun2,
+ <<"u() ->
+ case foo of
+ true ->
+ U = 2;
+ false ->
+ true
+ end,
+ fun(U) -> foo end, % U unused.
+ U; % U unsafe.
+ u() ->
+ case foo of
+ true ->
+ U = 2;
+ false ->
+ U = 3
+ end,
+ fun(U) -> foo end, % U shadowed. U unused.
+ U;
+ u() ->
+ case foo of
+ true ->
+ U = 2; % U unused.
+ false ->
+ U = 3 % U unused.
+ end,
+ fun(U) -> foo end. % U shadowed. U unused.
+ ">>,
+ [warn_unused_vars],
+ {error,[{9,erl_lint,{unsafe_var,'U',{'case',2}}}],
+ [{8,erl_lint,{unused_var,'U'}},
+ {17,erl_lint,{unused_var,'U'}},
+ {17,erl_lint,{shadowed_var,'U','fun'}},
+ {22,erl_lint,{unused_var,'U'}},
+ {24,erl_lint,{unused_var,'U'}},
+ {26,erl_lint,{unused_var,'U'}},
+ {26,erl_lint,{shadowed_var,'U','fun'}}]}}
+ ],
+ ?line [] = run(Config, Ts),
+ ok.
+
+unused_vars_OTP_4858(doc) ->
+ "Bit syntax, binsize variable used in the same matching.";
+unused_vars_OTP_4858(suite) -> [];
+unused_vars_OTP_4858(Config) when is_list(Config) ->
+ Ts = [{otp_4858,
+ <<"objs(<<Size:4/unit:8, B:Size/binary>>) ->
+ B.
+
+ fel(<<Size:4/unit:8, B:BadSize/binary>>) -> % BadSize unbound.
+ BadSize. % B, Size unused.
+
+ r9c_highlight() -> % B, Rest unused.
+ <<Size, B:Size/binary,Rest/binary>> = <<2,\"AB\",3,\"CDE\">>.
+ ">>,
+ [warn_unused_vars],
+ {error,[{4,erl_lint,{unbound_var,'BadSize'}}],
+ [{4,erl_lint,{unused_var,'B'}},
+ {4,erl_lint,{unused_var,'Size'}},
+ {8,erl_lint,{unused_var,'B'}},
+ {8,erl_lint,{unused_var,'Rest'}}]}}
+ ],
+ ?line [] = run(Config, Ts),
+ ok.
+
+export_vars_warn(doc) ->
+ "Warnings for exported variables";
+export_vars_warn(suite) -> [];
+export_vars_warn(Config) when is_list(Config) ->
+ Ts = [{exp1,
+ <<"u() ->
+ case foo of
+ 1 ->
+ A = 1,
+ B = 2,
+ W = 3, % W unused.
+ Z = 3; % Z unused.
+ 2 ->
+ B = 2,
+ Z = 4 % Z unused.
+ end,
+ case bar of
+ true ->
+ A = 17, % A unsafe.
+ X = 3, % X unused.
+ U = 2,
+ U;
+ false ->
+ B = 19, % B exported.
+ U = 3; % U unused.
+ foo ->
+ X = 3,
+ X;
+ bar ->
+ X = 9, % X unused.
+ U = 14 % U unused.
+ end.
+ ">>,
+ [warn_unused_vars],
+ {error,[{14,erl_lint,{unsafe_var,'A',{'case',2}}}],
+ [{6,erl_lint,{unused_var,'W'}},
+ {7,erl_lint,{unused_var,'Z'}},
+ {10,erl_lint,{unused_var,'Z'}},
+ {15,erl_lint,{unused_var,'X'}},
+ {19,erl_lint,{exported_var,'B',{'case',2}}},
+ {20,erl_lint,{unused_var,'U'}},
+ {25,erl_lint,{unused_var,'X'}},
+ {26,erl_lint,{unused_var,'U'}}]}},
+
+ {exp2,
+ <<"bin(A) ->
+ receive
+ M ->
+ X = M,
+ Y = M,
+ Z = M
+ end,
+ [B || <<B:X>> <- A], % X exported.
+ Y = B, % Y exported. B unbound.
+ [B || B <- Z]. % Z exported. B shadowed.
+ ">>,
+ [warn_export_vars],
+ {error,[{9,erl_lint,{unbound_var,'B'}}],
+ [{8,erl_lint,{exported_var,'X',{'receive',2}}},
+ {9,erl_lint,{exported_var,'Y',{'receive',2}}},
+ {10,erl_lint,{exported_var,'Z',{'receive',2}}},
+ {10,erl_lint,{shadowed_var,'B',generate}}]}},
+
+ {exp3,
+ <<"bin(A) ->
+ receive
+ M ->
+ X = M,
+ Y = M,
+ Z = M
+ end,
+ [B || <<B:X>> <- A], % (X exported.)
+ Y = B, % Y exported. B unbound.
+ [B || B <- Z]. % (Z exported.) B shadowed.
+ ">>,
+ [],
+ {error,[{9,erl_lint,{unbound_var,'B'}}],
+ [{9,erl_lint,{exported_var,'Y',{'receive',2}}},
+ {10,erl_lint,{shadowed_var,'B',generate}}]}}
+ ],
+ ?line [] = run(Config, Ts),
+ ok.
+
+shadow_vars(doc) ->
+ "Shadowed variables are tested in other places, but here we test "
+ "that the warning can be turned off.";
+shadow_vars(suite) -> [];
+shadow_vars(Config) when is_list(Config) ->
+ Ts = [{shadow1,
+ <<"bin(A) ->
+ receive
+ M ->
+ X = M,
+ Y = M,
+ Z = M
+ end,
+ [B || <<B:X>> <- A],
+ Y = B,
+ [B || B <- Z]. % B shadowed.
+ ">>,
+ [nowarn_shadow_vars],
+ {error,[{9,erl_lint,{unbound_var,'B'}}],
+ [{9,erl_lint,{exported_var,'Y',{'receive',2}}}]}}],
+
+ ?line [] = run(Config, Ts),
+ ok.
+
+unused_import(doc) ->
+ "Test that the 'warn_unused_import' option works.";
+unused_import(suite) -> [];
+unused_import(Config) when is_list(Config) ->
+ Ts = [{imp1,
+ <<"-import(lists, [map/2,foldl/3]).
+ t(L) ->
+ map(fun(X) -> 2*X end, L).
+ ">>,
+ [warn_unused_import],
+ {warnings,[{1,erl_lint,{unused_import,{{foldl,3},lists}}}]}}],
+ ?line [] = run(Config, Ts),
+ ok.
+
+unused_function(doc) ->
+ "Test warnings for unused functions.";
+unused_function(suite) -> [];
+unused_function(Config) when is_list(Config) ->
+ Ts = [{func1,
+ <<"-export([t/1]).
+ t(L) ->
+ lists:map(fun(X) -> 2*X end, L).
+
+ fact(N) ->
+ fact_1(N, 1).
+
+ fact_1(1, P) -> P;
+ fact_1(N, P) -> fact_1(N-1, P*N).
+ ">>,
+ {[]}, %Tuple indicates no 'export_all'.
+ {warnings,[{5,erl_lint,{unused_function,{fact,1}}},
+ {8,erl_lint,{unused_function,{fact_1,2}}}]}},
+
+ %% Turn off warnings for unused functions.
+ {func2,
+ <<"-export([t/1]).
+ t(L) ->
+ lists:map(fun(X) -> 2*X end, L).
+
+ b(X) ->
+ 32*X.
+ ">>,
+ {[nowarn_unused_function]}, %Tuple indicates no 'export_all'.
+ []},
+
+ %% Turn off warnings for unused functions using a -compile() directive.
+ {func3,
+ <<"-export([t/1]).
+ -compile(nowarn_unused_function).
+
+ t(L) ->
+ lists:map(fun(X) -> 2*X end, L).
+
+ b(X) ->
+ 32*X.
+ ">>,
+ {[]}, %Tuple indicates no 'export_all'.
+ []}],
+
+ ?line [] = run(Config, Ts),
+ ok.
+
+unsafe_vars(doc) ->
+ "OTP-4671. Errors for unsafe variables";
+unsafe_vars(suite) -> [];
+unsafe_vars(Config) when is_list(Config) ->
+ Ts = [{unsafe1,
+ <<"t() ->
+ (X = true) orelse (Y = false),
+ Y.
+ ">>,
+ [warn_unused_vars],
+ {error,[{3,erl_lint,{unsafe_var,'Y',{'orelse',2}}}],
+ [{2,erl_lint,{unused_var,'X'}}]}},
+ {unsafe2,
+ <<"t2() ->
+ (X = true) orelse (Y = false),
+ X.
+ ">>,
+ [warn_unused_vars],
+ {warnings,[{2,erl_lint,{unused_var,'Y'}}]}},
+ {unsafe3,
+ <<"t3() ->
+ (X = true) andalso (Y = false),
+ Y.
+ ">>,
+ [warn_unused_vars],
+ {error,[{3,erl_lint,{unsafe_var,'Y',{'andalso',2}}}],
+ [{2,erl_lint,{unused_var,'X'}}]}},
+ {unsafe4,
+ <<"t4() ->
+ (X = true) andalso (true = X),
+ X.
+ ">>,
+ [warn_unused_vars],
+ []},
+ {unsafe5,
+ <<"t5() ->
+ Y = 3,
+ (X = true) andalso (X = true),
+ {X,Y}.
+ ">>,
+ [warn_unused_vars],
+ []},
+ {unsafe6,
+ <<"t6() ->
+ X = true,
+ (X = true) andalso (true = X),
+ X.
+ ">>,
+ [warn_unused_vars],
+ []},
+ {unsafe7,
+ <<"t7() ->
+ (if true -> X = 3; false -> true end)
+ andalso (X > 2),
+ X.
+ ">>,
+ [warn_unused_vars],
+ {errors,[{3,erl_lint,{unsafe_var,'X',{'if',2}}},
+ {4,erl_lint,{unsafe_var,'X',{'if',2}}}],
+ []}}
+ ],
+ ?line [] = run(Config, Ts),
+ ok.
+
+unsafe_vars2(doc) ->
+ "OTP-4831, seq8202. No warn_unused_vars and unsafe variables";
+unsafe_vars2(suite) -> [];
+unsafe_vars2(Config) when is_list(Config) ->
+ Ts = [{unsafe2_1,
+ <<"foo(State) ->
+ case State of
+ true ->
+ if
+ false -> ok;
+ true -> State1=State
+ end
+ end,
+ State1. % unsafe
+ ">>,
+ [warn_unused_vars],
+ {errors,[{9,erl_lint,{unsafe_var,'State1',{'if',4}}}],[]}},
+ {unsafe2_2,
+ <<"foo(State) ->
+ case State of
+ true ->
+ if
+ false -> ok;
+ true -> State1=State
+ end
+ end,
+ State1. % unsafe
+ ">>,
+ [],
+ {errors,[{9,erl_lint,{unsafe_var,'State1',{'if',4}}}],[]}}
+ ],
+ ?line [] = run(Config, Ts),
+ ok.
+
+unsafe_vars_try(doc) ->
+ "Errors for unsafe variables in try/catch constructs.";
+unsafe_vars_try(suite) -> [];
+unsafe_vars_try(Config) when is_list(Config) ->
+ Ts = [{unsafe_try1,
+ <<"foo2() ->
+ try self()
+ catch
+ Class:Data -> Result={Class,Data}
+ end,
+ Result.
+ foo3a() ->
+ try self() of
+ R -> R
+ catch
+ Class:Data -> Result={Class,Data}
+ end,
+ Result.
+ foo3b() ->
+ try self() of
+ Result -> ok
+ catch
+ Class:Data -> {Class,Data}
+ end,
+ Result.
+ ">>,
+ [],
+ {errors,[{6,erl_lint,{unsafe_var,'Result',{'try',2}}},
+ {13,erl_lint,{unsafe_var,'Result',{'try',8}}},
+ {20,erl_lint,{unsafe_var,'Result',{'try',15}}}],
+ []}},
+ {unsafe_try2,
+ <<"foo1a() ->
+ Try =
+ try self()
+ catch
+ Class:Data -> Rc={Class,Data}
+ after
+ Ra=ok
+ end,
+ {Try,Rc,Ra}.
+ foo1b() ->
+ Try =
+ try self() of
+ R -> R
+ catch
+ Class:Data -> Rc={Class,Data}
+ after
+ Ra=R
+ end,
+ {Try,Rc,Ra}.
+ foo2() ->
+ Try =
+ try self() of
+ R -> Ro=R
+ catch
+ Class:Data -> {Class,Data}
+ after
+ Ra=R
+ end,
+ {Try,Ro,Ra}.
+ foo3() ->
+ Try =
+ try self() of
+ R -> Ro=R
+ catch
+ Class:Data -> Rc={Class,Data}
+ after
+ Ra=R
+ end,
+ {Try,R,Ro,Rc,Ra}.
+ ">>,
+ [],
+ {errors,[{9,erl_lint,{unsafe_var,'Ra',{'try',3}}},
+ {9,erl_lint,{unsafe_var,'Rc',{'try',3}}},
+ {17,erl_lint,{unsafe_var,'R',{'try',12}}},
+ {19,erl_lint,{unsafe_var,'Ra',{'try',12}}},
+ {19,erl_lint,{unsafe_var,'Rc',{'try',12}}},
+ {27,erl_lint,{unsafe_var,'R',{'try',22}}},
+ {29,erl_lint,{unsafe_var,'Ra',{'try',22}}},
+ {29,erl_lint,{unsafe_var,'Ro',{'try',22}}},
+ {37,erl_lint,{unsafe_var,'R',{'try',32}}},
+ {39,erl_lint,{unsafe_var,'R',{'try',32}}},
+ {39,erl_lint,{unsafe_var,'Ra',{'try',32}}},
+ {39,erl_lint,{unsafe_var,'Rc',{'try',32}}},
+ {39,erl_lint,{unsafe_var,'Ro',{'try',32}}}],
+ []}},
+ {unsafe_try3,
+ <<"foo1(X) ->
+ Try =
+ try R=self()
+ catch
+ Class:Data -> Rc={X,R,Class,Data}
+ end,
+ {X,Try,Rc}.
+ foo2(X) ->
+ Try =
+ try R=self() of
+ RR -> Ro={X,R,RR}
+ catch
+ Class:Data -> {X,R,RR,Ro,Class,Data}
+ end,
+ {X,Try,R,RR,Ro,Class,Data}.
+ foo3(X) ->
+ Try =
+ try R=self() of
+ RR -> {X,R,RR}
+ catch
+ Class:Data -> {X,R,RR,Class,Data}
+ after
+ Ra={X,R,RR,Class,Data}
+ end,
+ {X,Try,R,RR,Ra,Class,Data}.
+ ">>,
+ [],
+ {errors,[{5,erl_lint,{unsafe_var,'R',{'try',3}}},
+ {7,erl_lint,{unsafe_var,'Rc',{'try',3}}},
+ {11,erl_lint,{unsafe_var,'R',{'try',10}}},
+ {13,erl_lint,{unbound_var,'RR'}},
+ {13,erl_lint,{unbound_var,'Ro'}},
+ {13,erl_lint,{unsafe_var,'R',{'try',10}}},
+ {15,erl_lint,{unsafe_var,'Class',{'try',10}}},
+ {15,erl_lint,{unsafe_var,'Data',{'try',10}}},
+ {15,erl_lint,{unsafe_var,'R',{'try',10}}},
+ {15,erl_lint,{unsafe_var,'RR',{'try',10}}},
+ {15,erl_lint,{unsafe_var,'Ro',{'try',10}}},
+ {19,erl_lint,{unsafe_var,'R',{'try',18}}},
+ {21,erl_lint,{unbound_var,'RR'}},
+ {21,erl_lint,{unsafe_var,'R',{'try',18}}},
+ {23,erl_lint,{unsafe_var,'Class',{'try',18}}},
+ {23,erl_lint,{unsafe_var,'Data',{'try',18}}},
+ {23,erl_lint,{unsafe_var,'R',{'try',18}}},
+ {23,erl_lint,{unsafe_var,'RR',{'try',18}}},
+ {25,erl_lint,{unsafe_var,'Class',{'try',18}}},
+ {25,erl_lint,{unsafe_var,'Data',{'try',18}}},
+ {25,erl_lint,{unsafe_var,'R',{'try',18}}},
+ {25,erl_lint,{unsafe_var,'RR',{'try',18}}},
+ {25,erl_lint,{unsafe_var,'Ra',{'try',18}}}],
+ []}},
+ {unsafe_try4,
+ <<"foo1(X) ->
+ Try =
+ try R=self() of
+ RR -> Ro={X,R,RR}
+ catch
+ Class:Data -> Rc={X,R,RR,Ro,Class,Data}
+ after
+ Ra={X,R,RR,Ro,Rc,Class,Data}
+ end,
+ {X,Try,R,RR,Ro,Rc,Ra,Class,Data}.
+ ">>,
+ [],
+ {errors,[{4,erl_lint,{unsafe_var,'R',{'try',3}}},
+ {6,erl_lint,{unbound_var,'RR'}},
+ {6,erl_lint,{unbound_var,'Ro'}},
+ {6,erl_lint,{unsafe_var,'R',{'try',3}}},
+ {8,erl_lint,{unsafe_var,'Class',{'try',3}}},
+ {8,erl_lint,{unsafe_var,'Data',{'try',3}}},
+ {8,erl_lint,{unsafe_var,'R',{'try',3}}},
+ {8,erl_lint,{unsafe_var,'RR',{'try',3}}},
+ {8,erl_lint,{unsafe_var,'Rc',{'try',3}}},
+ {8,erl_lint,{unsafe_var,'Ro',{'try',3}}},
+ {10,erl_lint,{unsafe_var,'Class',{'try',3}}},
+ {10,erl_lint,{unsafe_var,'Data',{'try',3}}},
+ {10,erl_lint,{unsafe_var,'R',{'try',3}}},
+ {10,erl_lint,{unsafe_var,'RR',{'try',3}}},
+ {10,erl_lint,{unsafe_var,'Ra',{'try',3}}},
+ {10,erl_lint,{unsafe_var,'Rc',{'try',3}}},
+ {10,erl_lint,{unsafe_var,'Ro',{'try',3}}}],
+ []}}],
+ ?line [] = run(Config, Ts),
+ ok.
+
+guard(doc) ->
+ "OTP-4670. Guards, is_record in particular.";
+guard(suite) -> [];
+guard(Config) when is_list(Config) ->
+ %% Well, these could be plain code...
+ Ts = [{guard1,
+ <<"-record(apa, {}).
+ t(A) when atom(A) ->
+ atom;
+ t(A) when binary(A) ->
+ binary;
+ t(A) when constant(A) ->
+ constant;
+ t(A) when float(A) ->
+ float;
+ t(A) when function(A) ->
+ function;
+ t(A) when integer(A) ->
+ integer;
+ t(A) when is_atom(A) ->
+ is_atom;
+ t(A) when is_binary(A) ->
+ is_binary;
+ t(A) when is_constant(A) ->
+ is_constant;
+ t(A) when is_float(A) ->
+ is_float;
+ t(A) when is_function(A) ->
+ is_function;
+ t(A) when is_integer(A) ->
+ is_integer;
+ t(A) when is_list(A) ->
+ is_list;
+ t(A) when is_number(A) ->
+ is_number;
+ t(A) when is_pid(A) ->
+ is_pid;
+ t(A) when is_port(A) ->
+ is_port;
+ t(A) when is_record(A, apa) ->
+ is_record;
+ t(A) when is_record(A, apa, 1) ->
+ is_record;
+ t(A) when is_reference(A) ->
+ is_reference;
+ t(A) when is_tuple(A) ->
+ is_tuple;
+ t(A) when list(A) ->
+ list;
+ t(A) when number(A) ->
+ number;
+ t(A) when pid(A) ->
+ pid;
+ t(A) when port(A) ->
+ port;
+ t(A) when record(A, apa) ->
+ record;
+ t(A) when reference(A) ->
+ reference;
+ t(A) when tuple(A) ->
+ tuple.
+ ">>,
+ [nowarn_obsolete_guard],
+ {error,
+ [{6,erl_lint,illegal_guard_expr},{18,erl_lint,illegal_guard_expr}],
+ [{18,erl_lint,{removed,{erlang,is_constant,1},
+ "Removed in R13B"}}]}},
+ {guard2,
+ <<"-record(apa,{}).
+ t1(A) when atom(A), atom(A) ->
+ atom;
+ t1(A) when binary(A), binary(A) ->
+ binary;
+ t1(A) when constant(A), constant(A) ->
+ constant;
+ t1(A) when float(A), float(A) ->
+ float;
+ t1(A) when function(A), function(A) ->
+ function;
+ t1(A) when integer(A), integer(A) ->
+ integer;
+ t1(A) when is_atom(A), is_atom(A) ->
+ is_atom;
+ t1(A) when is_binary(A), is_binary(A) ->
+ is_binary;
+ t1(A) when is_constant(A), is_constant(A) ->
+ is_constant;
+ t1(A) when is_float(A), is_float(A) ->
+ is_float;
+ t1(A) when is_function(A), is_function(A) ->
+ is_function;
+ t1(A) when is_integer(A), is_integer(A) ->
+ is_integer;
+ t1(A) when is_list(A), is_list(A) ->
+ is_list;
+ t1(A) when is_number(A), is_number(A) ->
+ is_number;
+ t1(A) when is_pid(A), is_pid(A) ->
+ is_pid;
+ t1(A) when is_port(A), is_port(A) ->
+ is_port;
+ t1(A) when is_record(A, apa), is_record(A, apa) ->
+ is_record;
+ t1(A) when is_record(A, apa, 1), is_record(A, apa, 1) ->
+ is_record;
+ t1(A) when is_reference(A), is_reference(A) ->
+ is_reference;
+ t1(A) when is_tuple(A), is_tuple(A) ->
+ is_tuple;
+ t1(A) when list(A), list(A) ->
+ list;
+ t1(A) when number(A), number(A) ->
+ number;
+ t1(A) when pid(A), pid(A) ->
+ pid;
+ t1(A) when port(A), port(A) ->
+ port;
+ t1(A) when record(A, apa), record(A, apa) ->
+ record;
+ t1(A) when reference(A), reference(A) ->
+ reference;
+ t1(A) when tuple(A), tuple(A) ->
+ tuple.
+ ">>,
+ [nowarn_obsolete_guard],
+ {error,[{6,erl_lint,illegal_guard_expr},
+ {6,erl_lint,illegal_guard_expr},
+ {18,erl_lint,illegal_guard_expr},
+ {18,erl_lint,illegal_guard_expr}],
+ [{18,erl_lint,{removed,{erlang,is_constant,1},
+ "Removed in R13B"}},
+ {18,erl_lint,{removed,{erlang,is_constant,1},
+ "Removed in R13B"}}]}},
+ {guard3,
+ <<"-record(apa,{}).
+ t2(A) when atom(A); atom(A) ->
+ atom;
+ t2(A) when binary(A); binary(A) ->
+ binary;
+ t2(A) when float(A); float(A) ->
+ float;
+ t2(A) when function(A); function(A) ->
+ function;
+ t2(A) when integer(A); integer(A) ->
+ integer;
+ t2(A) when is_atom(A); is_atom(A) ->
+ is_atom;
+ t2(A) when is_binary(A); is_binary(A) ->
+ is_binary;
+ t2(A) when is_float(A); is_float(A) ->
+ is_float;
+ t2(A) when is_function(A); is_function(A) ->
+ is_function;
+ t2(A) when is_integer(A); is_integer(A) ->
+ is_integer;
+ t2(A) when is_list(A); is_list(A) ->
+ is_list;
+ t2(A) when is_number(A); is_number(A) ->
+ is_number;
+ t2(A) when is_pid(A); is_pid(A) ->
+ is_pid;
+ t2(A) when is_port(A); is_port(A) ->
+ is_port;
+ t2(A) when is_record(A, apa); is_record(A, apa) ->
+ is_record;
+ t2(A) when is_record(A, gurka, 1); is_record(A, gurka, 1) ->
+ is_record;
+ t2(A) when is_reference(A); is_reference(A) ->
+ is_reference;
+ t2(A) when is_tuple(A); is_tuple(A) ->
+ is_tuple;
+ t2(A) when list(A); list(A) ->
+ list;
+ t2(A) when number(A); number(A) ->
+ number;
+ t2(A) when pid(A); pid(A) ->
+ pid;
+ t2(A) when port(A); port(A) ->
+ port;
+ t2(A) when record(A, apa); record(A, apa) ->
+ record;
+ t2(A) when reference(A); reference(A) ->
+ reference;
+ t2(A) when tuple(A); tuple(A) ->
+ tuple.
+ ">>,
+ [nowarn_obsolete_guard],
+ []},
+ {guard4,
+ <<"-record(apa, {}).
+ t3(A) when float(A) or float(A) -> % coercing... (badarg)
+ float;
+ t3(A) when is_atom(A) or is_atom(A) ->
+ is_atom;
+ t3(A) when is_binary(A) or is_binary(A) ->
+ is_binary;
+ t3(A) when is_float(A) or is_float(A) ->
+ is_float;
+ t3(A) when is_function(A) or is_function(A) ->
+ is_function;
+ t3(A) when is_integer(A) or is_integer(A) ->
+ is_integer;
+ t3(A) when is_list(A) or is_list(A) ->
+ is_list;
+ t3(A) when is_number(A) or is_number(A) ->
+ is_number;
+ t3(A) when is_pid(A) or is_pid(A) ->
+ is_pid;
+ t3(A) when is_port(A) or is_port(A) ->
+ is_port;
+ t3(A) when is_record(A, apa) or is_record(A, apa) ->
+ is_record;
+ t3(A) when is_record(A, apa, 1) or is_record(A, apa, 1) ->
+ is_record;
+ t3(A) when is_reference(A) or is_reference(A) ->
+ is_reference;
+ t3(A) when is_tuple(A) or is_tuple(A) ->
+ is_tuple.
+ ">>,
+ [nowarn_obsolete_guard],
+ []}],
+ ?line [] = run(Config, Ts),
+ Ts1 = [{guard5,
+ <<"-record(apa, {}).
+ t3(A) when record(A, {apa}) ->
+ foo;
+ t3(A) when is_record(A, {apa}) ->
+ foo;
+ t3(A) when erlang:is_record(A, {apa}) ->
+ foo;
+ t3(A) when {erlang,is_record}(A, {apa}) ->
+ foo;
+ t3(A) when is_record(A, {apa}, 1) ->
+ foo;
+ t3(A) when erlang:is_record(A, {apa}, 1) ->
+ foo;
+ t3(A) when {erlang,is_record}(A, {apa}, 1) ->
+ foo;
+ t3(A) when is_record(A, apa, []) ->
+ foo;
+ t3(A) when erlang:is_record(A, apa, []) ->
+ foo;
+ t3(A) when {erlang,is_record}(A, apa, []) ->
+ foo;
+ t3(A) when record(A, apa) ->
+ foo;
+ t3(A) when is_record(A, apa) ->
+ foo;
+ t3(A) when erlang:is_record(A, apa) ->
+ foo;
+ t3(A) when {erlang,is_record}(A, apa) ->
+ foo.
+ ">>,
+ [warn_unused_vars, nowarn_obsolete_guard],
+ {errors,[{2,erl_lint,illegal_guard_expr},
+ {4,erl_lint,illegal_guard_expr},
+ {6,erl_lint,illegal_guard_expr},
+ {8,erl_lint,illegal_guard_expr},
+ {10,erl_lint,illegal_guard_expr},
+ {12,erl_lint,illegal_guard_expr},
+ {14,erl_lint,illegal_guard_expr},
+ {16,erl_lint,illegal_guard_expr},
+ {18,erl_lint,illegal_guard_expr},
+ {20,erl_lint,illegal_guard_expr}],
+ []}},
+ {guard6,
+ <<"-record(apa,{a=a,b=foo:bar()}).
+ apa() ->
+ [X || X <- [], #apa{a = a} == {r,X,foo}];
+ apa() ->
+ [X || X <- [], #apa{b = b} == {r,X,foo}];
+ apa() ->
+ [X || X <- [], #ful{a = a} == {r,X,foo}].
+ ">>,
+ [],
+ {errors,[{7,erl_lint,{undefined_record,ful}}],
+ []}},
+ {guard7,
+ <<"-record(apa,{}).
+ t() ->
+ [X || X <- [1,#apa{},3], (3+is_record(X, apa)) or
+ (is_record(X, apa)*2)].
+ ">>,
+ [],
+ []}],
+ ?line [] = run(Config, Ts1),
+ ok.
+
+otp_4886(doc) ->
+ "OTP-4886. Calling is_record with given record name.";
+otp_4886(suite) -> [];
+otp_4886(Config) when is_list(Config) ->
+ Ts = [{otp_4886,
+ <<"t() ->
+ X = {foo},
+ is_record(X, foo),
+ erlang:is_record(X, foo),
+ {erlang,is_record}(X, foo),
+ %% Note: is_record/3 does not verify that the record is defined,
+ %% so the following lines should give no errors.
+ is_record(X, foo, 1),
+ erlang:is_record(X, foo, 1),
+ {erlang,is_record}(X, foo, 1).
+ ">>,
+ [],
+ {errors,[{3,erl_lint,{undefined_record,foo}},
+ {4,erl_lint,{undefined_record,foo}},
+ {5,erl_lint,{undefined_record,foo}}],
+ []}}],
+ ?line [] = run(Config, Ts),
+ ok.
+
+otp_4988(doc) ->
+ "OTP-4988. Error when in-lining non-existent functions.";
+otp_4988(suite) -> [];
+otp_4988(Config) when is_list(Config) ->
+ Ts = [{otp_4988,
+ <<"-compile({inline, [{f,3},{f,4},{f,2},{f,a},{1,foo}]}).
+ -compile({inline, {g,1}}).
+ -compile({inline, {g,12}}).
+ -compile(inline).
+ -compile({inline_size,100}).
+
+ f(A, B) ->
+ {g(A), B}.
+
+ g(A) ->
+ {A}.
+ ">>,
+ [],
+ {errors,[{1,erl_lint,{bad_inline,{1,foo}}},
+ {1,erl_lint,{bad_inline,{f,3}}},
+ {1,erl_lint,{bad_inline,{f,4}}},
+ {1,erl_lint,{bad_inline,{f,a}}},
+ {3,erl_lint,{bad_inline,{g,12}}}],
+ []}}],
+ ?line [] = run(Config, Ts),
+ ok.
+
+otp_5091(doc) ->
+ "OTP-5091. Patterns and the bit syntax: invalid warnings.";
+otp_5091(suite) -> [];
+otp_5091(Config) when is_list(Config) ->
+ Ts = [{otp_5091_1,
+ <<"t() ->
+ [{Type, Value} || <<Type:16, _Len:16,
+ Value:_Len/binary>> <- []].
+ ">>,
+ [],
+ []},
+ {otp_5091_2,
+ <<"t() ->
+ %% This one has always been handled OK:
+ <<Type:16, _Len:16,
+ Value:_Len/binary>> = <<18:16, 9:16, \"123456789\">>,
+ {Type, Value}.
+ ">>,
+ [],
+ []},
+ {otp_5091_3,
+ <<"t() ->
+ fun(<<Type:16, _Len:16, Value:_Len/binary>>) ->
+ {Type, Value}
+ end.
+ ">>,
+ [],
+ []},
+ {otp_5091_4,
+ <<"t() ->
+ L = 8,
+ F = fun(<<A:L,B:A>>) -> B end,
+ F(<<16:8, 7:16>>).
+ ">>,
+ [],
+ []},
+ {otp_5091_5,
+ <<"t() ->
+ L = 8,
+ F = fun(<<L: % L shadowed.
+ L,
+ B:
+ L>>) -> B end,
+ F(<<16:8, 7:16>>).
+ ">>,
+ [],
+ {warnings,[{3,erl_lint,{shadowed_var,'L','fun'}}]}},
+ {otp_5091_6,
+ <<"t(A) ->
+ (fun(<<L:16,M:L,N:M>>) -> ok end)(A).
+ ">>,
+ [],
+ {warnings,[{2,erl_lint,{unused_var,'N'}}]}},
+ {otp_5091_7,
+ <<"t() ->
+ U = 8,
+ (fun(<<U: % U shadowed.
+ U>>) -> U end)(<<32:8>>).
+ ">>,
+ [],
+ {warnings,[{3,erl_lint,{shadowed_var,'U','fun'}}]}},
+ {otp_5091_8,
+ <<"t() ->
+ [X || <<A:8,
+ B:A>> <- [],
+ <<X:8>> <- [B]].
+ ">>,
+ [],
+ []},
+ {otp_5091_9,
+ <<"t() ->
+ L = 8,
+ F = fun(<<L: % Shadow.
+ L,
+ L:
+ L,
+ L:
+ L
+ >>) ->
+ L
+ end,
+ F(<<16:8, 8:16, 32:8>>).
+ ">>,
+ [],
+ {warnings,[{3,erl_lint,{shadowed_var,'L','fun'}}]}},
+ {otp_5091_10,
+ <<"t() ->
+ L = 8, <<A:L,B:A>> = <<16:8, 7:16>>, B.
+ ">>,
+ [],
+ []},
+ {otp_5091_11,
+ <<"t() ->
+ fun(<<L:16,L:L,L:L>>) -> ok end.
+ ">>,
+ [],
+ []},
+ {otp_5091_12,
+ <<"t([A,B]) ->
+ fun(<<A:B>>, % A shadowed and unused
+ <<Q:A>>) -> foo % Q unused. 'outer' A is used.
+ end.
+ ">>,
+ [],
+ {warnings,[{2,erl_lint,{unused_var,'A'}},
+ {2,erl_lint,{shadowed_var,'A','fun'}},
+ {3,erl_lint,{unused_var,'Q'}}]}},
+ {otp_5091_13,
+ <<"t([A,B]) -> % A unused, B unused
+ fun({A,B}, % A shadowed, B unused, B shadowed
+ {Q,A}) -> foo % Q unused. 'inner' A is used
+ end.
+ ">>,
+ [],
+ {warnings,[{1,erl_lint,{unused_var,'A'}},
+ {1,erl_lint,{unused_var,'B'}},
+ {2,erl_lint,{unused_var,'B'}},
+ {2,erl_lint,{shadowed_var,'A','fun'}},
+ {2,erl_lint,{shadowed_var,'B','fun'}},
+ {3,erl_lint,{unused_var,'Q'}}]}},
+ {otp_5091_14,
+ <<"t() ->
+ A = 4,
+ fun(<<A: % shadowed, unused
+ A>>) -> 2 end.
+ ">>,
+ [],
+ {warnings,[{3,erl_lint,{unused_var,'A'}},
+ {3,erl_lint,{shadowed_var,'A','fun'}}]}},
+ {otp_5091_15,
+ <<"t() ->
+ A = 4, % unused
+ fun(<<A:8, % shadowed
+ 16:A>>) -> 2 end.
+ ">>,
+ [],
+ {warnings,[{2,erl_lint,{unused_var,'A'}},
+ {3,erl_lint,{shadowed_var,'A','fun'}}]}},
+ {otp_5091_16,
+ <<"t() ->
+ A = 4,
+ fun(<<8:A, %
+ A:8>>) -> 7 end. % shadowed, unused
+ ">>,
+ [],
+ {warnings,[{4,erl_lint,{unused_var,'A'}},
+ {4,erl_lint,{shadowed_var,'A','fun'}}]}},
+ {otp_5091_17,
+ <<"t() ->
+ L = 16,
+ fun(<<L: % shadow
+ L>>, % 'outer' L
+ <<L: % shadow and match
+ L>>) -> % 'outer' L
+ a
+ end.
+ ">>,
+ [],
+ {warnings,[{3,erl_lint,{shadowed_var,'L','fun'}}]}},
+ {otp_5091_18,
+ <<"t() ->
+ L = 4, % L unused
+ fun({L, % L shadowed
+ L},
+ {L,
+ L}) ->
+ a
+ end.
+ ">>,
+ [],
+ {warnings,[{2,erl_lint,{unused_var,'L'}},
+ {3,erl_lint,{shadowed_var,'L','fun'}}]}},
+ {otp_5091_19,
+ <<"t() ->
+ L = 4,
+ [L || <<L: % shadowed
+ L,
+ L:
+ L>> <- []].
+ ">>,
+ [],
+ {warnings,[{3,erl_lint,{shadowed_var,'L',generate}}]}},
+ {otp_5091_20,
+ <<"t() ->
+ L = 4, % L unused.
+ [1 || L <- []]. % L unused, L shadowed.
+ ">>,
+ [],
+ {warnings,[{2,erl_lint,{unused_var,'L'}},
+ {3,erl_lint,{unused_var,'L'}},
+ {3,erl_lint,{shadowed_var,'L',generate}}]}},
+ {otp_5091_21,
+ <<"t() ->
+ L = 4,
+ [1 || L <- [L]]. % L shadowed. L unused.
+ ">>,
+ [],
+ {warnings,[{3,erl_lint,{unused_var,'L'}},
+ {3,erl_lint,{shadowed_var,'L',generate}}]}},
+ {otp_5091_22,
+ <<"t() ->
+ L = 4, % unused
+ fun(L) -> L end. % shadowed
+ ">>,
+ [],
+ {warnings,[{2,erl_lint,{unused_var,'L'}},
+ {3,erl_lint,{shadowed_var,'L','fun'}}]}},
+ {otp_5091_23,
+ <<"t([A,A]) -> a.">>, [], []},
+ {otp_5091_24,
+ <<"t({A,A}) -> a.">>, [], []},
+ {otp_5091_25,
+ <<"-record(r, {f1,f2}).
+ t(#r{f1 = A, f2 = A}) -> a.">>, [], []}],
+
+ ?line [] = run(Config, Ts),
+ ok.
+
+otp_5276(doc) ->
+ "OTP-5276. Check the 'deprecated' attributed.";
+otp_5276(suite) -> [];
+otp_5276(Config) when is_list(Config) ->
+ Ts = [{otp_5276_1,
+ <<"-deprecated([{frutt,0,next_version}]).
+ -deprecated([{does_not_exist,1}]).
+ -deprecated('foo bar').
+ -deprecated(module).
+ -deprecated([{f,'_'}]).
+ -deprecated([{t,0}]).
+ -deprecated([{t,'_',eventually}]).
+ -deprecated([{'_','_',never}]).
+ -deprecated([{{badly,formed},1}]).
+ -deprecated([{'_','_',next_major_release}]).
+ -export([t/0]).
+ frutt() -> ok.
+ t() -> ok.
+ ">>,
+ {[]},
+ {error,[{1,erl_lint,{bad_deprecated,{frutt,0}}},
+ {2,erl_lint,{bad_deprecated,{does_not_exist,1}}},
+ {3,erl_lint,{invalid_deprecated,'foo bar'}},
+ {5,erl_lint,{bad_deprecated,{f,'_'}}},
+ {8,erl_lint,{invalid_deprecated,{'_','_',never}}},
+ {9,erl_lint,{invalid_deprecated,{{badly,formed},1}}}],
+ [{12,erl_lint,{unused_function,{frutt,0}}}]}}],
+ ?line [] = run(Config, Ts),
+ ok.
+
+otp_5917(doc) ->
+ "OTP-5917. Check the 'deprecated' attributed.";
+otp_5917(suite) -> [];
+otp_5917(Config) when is_list(Config) ->
+ Ts = [{otp_5917_1,
+ <<"-compile(export_all).
+
+ -deprecated({t,0}).
+
+ t() ->
+ foo.
+ ">>,
+ {[]},
+ []}],
+ ?line [] = run(Config, Ts),
+ ok.
+
+otp_6585(doc) ->
+ "OTP-6585. Check the deprecated guards list/1, pid/1, ....";
+otp_6585(suite) -> [];
+otp_6585(Config) when is_list(Config) ->
+ Ts = [{otp_6585_1,
+ <<"-compile(export_all).
+
+ -record(r, {}).
+
+ f(A) when list(A) -> list;
+ f(R) when record(R, r) -> rec;
+ f(P) when pid(P) -> pid.
+
+ t() ->
+ f([]).
+ ">>,
+ [warn_obsolete_guard],
+ {warnings,[{5,erl_lint,{obsolete_guard,{list,1}}},
+ {6,erl_lint,{obsolete_guard,{record,2}}},
+ {7,erl_lint,{obsolete_guard,{pid,1}}}]}}],
+ ?line [] = run(Config, Ts),
+ ok.
+
+otp_5338(doc) ->
+ "OTP-5338. Bad warning in record initialization.";
+otp_5338(suite) -> [];
+otp_5338(Config) when is_list(Config) ->
+ %% OTP-5878: variables like X are no longer allowed in initialisations
+ Ts = [{otp_5338,
+ <<"-record(c, {a = <<X:7/binary-unit:8>>}).
+ t() ->
+ X = <<\"hejsans\">>,
+ #c{}.
+ ">>,
+ [],
+ {error,[{1,erl_lint,{unbound_var,'X'}}],
+ [{3,erl_lint,{unused_var,'X'}}]}}],
+ ?line [] = run(Config, Ts),
+ ok.
+
+otp_5362(doc) ->
+ "OTP-5362. deprecated_function, "
+ "{nowarn_unused_funtion,FAs}, 'better' line numbers.";
+otp_5362(suite) -> [];
+otp_5362(Config) when is_list(Config) ->
+ Ts = [{otp_5362_1,
+ <<"-include_lib(\"stdlib/include/qlc.hrl\").
+
+ -file(?FILE, 1000).
+
+ t() ->
+ qlc:q([X || X <- [],
+ begin A = 3, true end]).
+ ">>,
+ {[warn_unused_vars]},
+ {warnings,[{1002,erl_lint,{unused_function,{t,0}}},
+ {1004,erl_lint,{unused_var,'A'}}]}},
+
+ {otp_5362_2,
+ <<"-export([inline/0]).
+
+ -import(lists.foo, [a/1,b/1]). % b/1 is not used
+
+ -compile([{inline,{inl,7}}]). % undefined
+ -compile([{inline,[{inl,17}]}]). % undefined
+ -compile([{inline,{inl,1}}]). % OK
+
+ foop() -> % unused function
+ a([]), % used import, OK
+ fipp(). % undefined
+
+ inline() ->
+ inl(foo).
+
+ inl(_) ->
+ true.
+
+ not_used() -> % unused function
+ true.
+
+ -compile({nowarn_unused_function,[{and_not_used,2}]}). % unknown
+ and_not_used(_) -> % unused function
+ foo.
+
+ -compile({nowarn_unused_function,{unused_function,2}}).
+ unused_function(_, _) ->
+ ok.
+ ">>,
+ {[warn_unused_vars, warn_unused_import]},
+ {error,[{5,erl_lint,{bad_inline,{inl,7}}},
+ {6,erl_lint,{bad_inline,{inl,17}}},
+ {11,erl_lint,{undefined_function,{fipp,0}}},
+ {22,erl_lint,{bad_nowarn_unused_function,{and_not_used,2}}}],
+ [{3,erl_lint,{unused_import,{{b,1},'lists.foo'}}},
+ {9,erl_lint,{unused_function,{foop,0}}},
+ {19,erl_lint,{unused_function,{not_used,0}}},
+ {23,erl_lint,{unused_function,{and_not_used,1}}}]}},
+
+ {otp_5362_3,
+ <<"-record(a, {x,
+ x}).
+ -record(a, {x,
+ X}). % erl_parse
+ -record(a, [x,
+ x]). % erl_parse
+ -record(ok, {a,b}).
+
+ -record(r, {a = #ok{},
+ b = (#ok{})#ok.a}).
+
+ t() ->
+ {#a{},
+ #nix{},
+ #ok{nix = []},
+ #ok{Var = 4},
+ #r{}
+ }.
+ ">>,
+ {[nowarn_unused_function]},
+ {errors2, [{4,erl_parse,"bad record field"},
+ {5,erl_parse,"bad record declaration"}],
+ [{2,erl_lint,{redefine_field,a,x}},
+ {14,erl_lint,{undefined_record,nix}},
+ {15,erl_lint,{undefined_field,ok,nix}},
+ {16,erl_lint,{field_name_is_variable,ok,'Var'}}]}},
+
+ {otp_5362_4,
+ <<"-compile(nowarn_deprecated_function).
+ -compile(nowarn_bif_clash).
+ spawn(A) ->
+ erlang:hash(A, 3000),
+ spawn(A).
+ ">>,
+ {[nowarn_unused_function,
+ warn_deprecated_function,
+ warn_bif_clash]},
+ {error,
+ [{5,erl_lint,{call_to_redefined_bif,{spawn,1}}}],
+ [{3,erl_lint,{redefine_bif,{spawn,1}}},
+ {4,erl_lint,{deprecated,{erlang,hash,2},{erlang,phash2,2},
+ "in a future release"}}]}},
+
+ {otp_5362_5,
+ <<"-compile(nowarn_deprecated_function).
+ -compile(nowarn_bif_clash).
+ spawn(A) ->
+ erlang:hash(A, 3000),
+ spawn(A).
+ ">>,
+ {[nowarn_unused_function]},
+ {warnings,
+ [{3,erl_lint,{redefine_bif,{spawn,1}}}]}},
+
+ %% The special nowarn_X are not affected by general warn_X.
+ {otp_5362_6,
+ <<"-compile({nowarn_deprecated_function,{erlang,hash,2}}).
+ -compile({nowarn_bif_clash,{spawn,1}}).
+ spawn(A) ->
+ erlang:hash(A, 3000),
+ spawn(A).
+ ">>,
+ {[nowarn_unused_function,
+ warn_deprecated_function,
+ warn_bif_clash]},
+ {warnings,
+ [{3,erl_lint,{redefine_bif,{spawn,1}}}]}},
+
+ {otp_5362_7,
+ <<"-export([spawn/1]).
+ -compile({nowarn_deprecated_function,{erlang,hash,2}}).
+ -compile({nowarn_bif_clash,{spawn,1}}).
+ -compile({nowarn_bif_clash,{spawn,2}}). % bad
+ -compile([{nowarn_deprecated_function,
+ [{erlang,hash,-1},{3,hash,-1}]}, % 2 bad
+ {nowarn_deprecated_function, {{a,b,c},hash,-1}}]). % bad
+ spawn(A) ->
+ erlang:hash(A, 3000),
+ spawn(A).
+ ">>,
+ {[nowarn_unused_function]},
+ {error,[{4,erl_lint,{bad_nowarn_bif_clash,{spawn,2}}}],
+ [{5,erl_lint,{bad_nowarn_deprecated_function,{3,hash,-1}}},
+ {5,erl_lint,{bad_nowarn_deprecated_function,{erlang,hash,-1}}},
+ {5,erl_lint,{bad_nowarn_deprecated_function,{{a,b,c},hash,-1}}}]}
+ },
+
+ {otp_5362_8,
+ <<"-export([spawn/1]).
+ -compile(warn_deprecated_function).
+ -compile(warn_bif_clash).
+ spawn(A) ->
+ erlang:hash(A, 3000),
+ spawn(A).
+ ">>,
+ {[nowarn_unused_function,
+ {nowarn_bif_clash,{spawn,1}}]}, % has no effect
+ {warnings,
+ [{5,erl_lint,{deprecated,{erlang,hash,2},{erlang,phash2,2},
+ "in a future release"}}]}},
+
+ {otp_5362_9,
+ <<"-include_lib(\"stdlib/include/qlc.hrl\").
+ -record(a, {x = qlc:q([{X,Y} || {X} <- [],{Y} <- [],X =:= Y])}).
+ -export([t/0]).
+ t() -> #a{}.
+ ">>,
+ {[]},
+ []}
+
+ ],
+
+ ?line [] = run(Config, Ts),
+ ok.
+
+otp_5371(doc) ->
+ "OTP-5371. Aliases for bit syntax expressions are no longer allowed.";
+otp_5371(suite) -> [];
+otp_5371(Config) when is_list(Config) ->
+ Ts = [{otp_5371_1,
+ <<"t(<<A:8>> = <<B:8>>) ->
+ {A,B}.
+ ">>,
+ [],
+ {errors,[{1,erl_lint,illegal_bin_pattern}],[]}},
+ {otp_5371_2,
+ <<"x([<<A:8>>] = [<<B:8>>]) ->
+ {A,B}.
+ y({a,<<A:8>>} = {b,<<B:8>>}) ->
+ {A,B}.
+ ">>,
+ [],
+ {errors,[{1,erl_lint,illegal_bin_pattern},
+ {3,erl_lint,illegal_bin_pattern}],[]}},
+ {otp_5371_3,
+ <<"-record(foo, {a,b,c}).
+ -record(bar, {x,y,z}).
+ -record(buzz, {x,y}).
+ a(#foo{a = <<X:8>>} = #bar{x = <<Y:8>>}) ->
+ {X,Y}.
+ b(#foo{b = <<X:8>>} = #foo{b = <<Y:4,Z:4>>}) ->
+ {X,Y,Z}.
+ c(#foo{a = <<X:8>>} = #buzz{x = <<Y:8>>}) ->
+ {X,Y}.
+ d(#foo{a=x,b = <<X:8>>} = #buzz{y = <<Y:8>>}) ->
+ {X,Y}.
+ e(#foo{a=x,b = <<X:8>>} = #buzz{x=glurf,y = <<Y:8>>}) ->
+ {X,Y}.
+ ">>,
+ [],
+ {errors,[{4,erl_lint,illegal_bin_pattern},
+ {6,erl_lint,illegal_bin_pattern},
+ {8,erl_lint,illegal_bin_pattern},
+ {10,erl_lint,illegal_bin_pattern},
+ {12,erl_lint,illegal_bin_pattern}],[]}},
+ {otp_5371_4,
+ <<"-record(foo, {a,b,c}).
+ -record(bar, {x,y,z}).
+ -record(buzz, {x,y}).
+ a(#foo{a = <<X:8>>,b=x} = #foo{b = <<Y:8>>}) ->
+ {X,Y}.
+ b(#foo{a = <<X:8>>} = #bar{y = <<Y:4,Z:4>>}) ->
+ {X,Y,Z}.
+ c(#foo{a = <<X:8>>} = #buzz{y = <<Y:8>>}) ->
+ {X,Y}.
+ ">>,
+ [],
+ {warnings,[{4,v3_core,nomatch},
+ {6,v3_core,nomatch},
+ {8,v3_core,nomatch}]}}
+ ],
+ ?line [] = run(Config, Ts),
+ ok.
+
+otp_7227(doc) -> "OTP_7227. Some aliases for bit syntax expressions were still allowed.";
+otp_7227(Config) when is_list(Config) ->
+ Ts = [{otp_7227_1,
+ <<"t([<<A:8>> = {C,D} = <<B:8>>]) ->
+ {A,B,C,D}.
+ ">>,
+ [],
+ {errors,[{1,erl_lint,illegal_bin_pattern}],[]}},
+ {otp_7227_2,
+ <<"t([(<<A:8>> = {C,D}) = <<B:8>>]) ->
+ {A,B,C,D}.
+ ">>,
+ [],
+ {errors,[{1,erl_lint,illegal_bin_pattern}],[]}},
+ {otp_7227_3,
+ <<"t([(<<A:8>> = {C,D}) = (<<B:8>> = <<C:8>>)]) ->
+ {A,B,C,D}.
+ ">>,
+ [],
+ {errors,[{1,erl_lint,illegal_bin_pattern},
+ {1,erl_lint,illegal_bin_pattern},
+ {1,erl_lint,illegal_bin_pattern}],[]}},
+ {otp_7227_4,
+ <<"t(Val) ->
+ <<A:8>> = <<B:8>> = Val,
+ {A,B}.
+ ">>,
+ [],
+ {errors,[{2,erl_lint,illegal_bin_pattern}],[]}},
+ {otp_7227_5,
+ <<"t(Val) ->
+ <<A:8>> = X = <<B:8>> = Val,
+ {A,B,X}.
+ ">>,
+ [],
+ {errors,[{2,erl_lint,illegal_bin_pattern}],[]}},
+ {otp_7227_6,
+ <<"t(X, Y) ->
+ <<A:8>> = <<X:4,Y:4>>,
+ A.
+ ">>,
+ [],
+ []},
+ {otp_7227_7,
+ <<"t(Val) ->
+ (<<A:8>> = X) = (<<B:8>> = <<A:4,B:4>>) = Val,
+ {A,B,X}.
+ ">>,
+ [],
+ {errors,[{2,erl_lint,illegal_bin_pattern},
+ {2,erl_lint,illegal_bin_pattern},
+ {2,erl_lint,illegal_bin_pattern}],[]}},
+ {otp_7227_8,
+ <<"t(Val) ->
+ (<<A:8>> = X) = (Y = <<B:8>>) = Val,
+ {A,B,X,Y}.
+ ">>,
+ [],
+ {errors,[{2,erl_lint,illegal_bin_pattern}],[]}},
+ {otp_7227_9,
+ <<"t(Val) ->
+ (Z = <<A:8>> = X) = (Y = <<B:8>> = W) = Val,
+ {A,B,X,Y,Z,W}.
+ ">>,
+ [],
+ {errors,[{2,erl_lint,illegal_bin_pattern}],[]}}
+ ],
+ ?line [] = run(Config, Ts),
+ ok.
+
+otp_5494(doc) ->
+ "OTP-5494. Warnings for functions exported more than once.";
+otp_5494(suite) -> [];
+otp_5494(Config) when is_list(Config) ->
+ Ts = [{otp_5494_1,
+ <<"-export([t/0]).
+ -export([t/0]).
+ t() -> a.
+ ">>,
+ [],
+ {warnings,[{2,erl_lint,{duplicated_export,{t,0}}}]}}],
+ ?line [] = run(Config, Ts),
+ ok.
+
+otp_5644(doc) ->
+ "OTP-5644. M:F/A in record initialization.";
+otp_5644(suite) -> [];
+otp_5644(Config) when is_list(Config) ->
+ %% This test is a no-op. Although {function,mfa,i,1} was
+ %% transformed into {function,Line,i,1} by copy_expr, the module
+ %% was never checked (Line is the line number).
+ %% (OTP-5878: somewhat modified.)
+ Ts = [{otp_5644,
+ <<"-record(c, {a = fun ?MODULE:i/1(17)}).
+ t() ->
+ #c{}.
+
+ i(X) ->
+ X.
+ ">>,
+ [],
+ []}],
+ ?line [] = run(Config, Ts),
+ ok.
+
+otp_5878(doc) ->
+ "OTP-5878. Record declaration: forward references, introduced variables.";
+otp_5878(suite) -> [];
+otp_5878(Config) when is_list(Config) ->
+ Ts = [{otp_5878_10,
+ <<"-record(rec1, {a = #rec2{}}).
+ -record(rec2, {a = #rec1{}}).
+ t() ->#rec1{}.
+ ">>,
+ [warn_unused_record],
+ {error,[{1,erl_lint,{undefined_record,rec2}}],
+ [{2,erl_lint,{unused_record,rec2}}]}},
+
+ {otp_5878_20,
+ <<"-record(r1, {a = begin A = 4, {A,B} end}). % B unbound
+ -record(r2, {e = begin A = 3, #r1{} end}).
+ t() -> #r2{}.
+ ">>,
+ [warn_unused_record],
+ {error,[{1,erl_lint,{unbound_var,'B'}},
+ {1,erl_lint,{variable_in_record_def,'A'}},
+ {2,erl_lint,{variable_in_record_def,'A'}}],
+ [{1,erl_lint,{unused_record,r1}}]}},
+
+ {otp_5878_30,
+ <<"-record(r1, {t = case foo of _ -> 3 end}).
+ -record(r2, {a = case foo of A -> A; _ -> 3 end}).
+ -record(r3, {a = case foo of A -> A end}).
+ t() -> {#r1{},#r2{},#r3{}}.
+ ">>,
+ [warn_unused_record],
+ {errors,[{2,erl_lint,{variable_in_record_def,'A'}},
+ {3,erl_lint,{variable_in_record_def,'A'}}],
+ []}},
+
+ {otp_5878_40,
+ <<"-record(r1, {foo = A}). % A unbound
+ -record(r2, {a = fun(X) -> X end(3)}).
+ -record(r3, {a = [X || X <- [1,2,3]]}).
+ t() -> {#r1{},#r2{},#r3{}}.
+ ">>,
+ [warn_unused_record],
+ {errors,[{1,erl_lint,{unbound_var,'A'}}],[]}},
+
+ {otp_5878_50,
+ <<"-record(r1, {a = {A, % A unbound
+ A}}). % A unbound
+ -record(r2, {a = begin case foo of
+ A -> A
+ end,
+ A
+ end}).
+ -record(r3, {a = fun(X) ->
+ case foo of
+ A -> A
+ end
+ end
+ }).
+ -record(r4, {a = case foo of
+ foo ->
+ case foo of
+ A -> A
+ end;
+ _ ->
+ bar
+ end}).
+ t() -> {#r1{},#r2{},#r3{},#r4{}}.
+ ">>,
+ [warn_unused_record],
+ {error,[{1,erl_lint,{unbound_var,'A'}},
+ {2,erl_lint,{unbound_var,'A'}},
+ {4,erl_lint,{variable_in_record_def,'A'}},
+ {17,erl_lint,{variable_in_record_def,'A'}}],
+ [{8,erl_lint,{unused_var,'X'}}]}},
+
+ {otp_5878_60,
+ <<"-record(r1, {a = fun(NotShadowing) -> NotShadowing end}).
+ t() ->
+ NotShadowing = 17,
+ {#r1{}, NotShadowing}.
+ ">>,
+ [warn_unused_record],
+ []},
+
+ {otp_5878_70,
+ <<"-record(r1, {a = fun(<<X:8>>) -> X end,
+ b = case <<17:8>> of
+ <<_:Y>> -> Y;
+ <<Y:8>> ->
+ Y
+ end}).
+ t() -> #r1{}.
+ ">>,
+ [warn_unused_record],
+ {errors,[{3,erl_lint,{unbound_var,'Y'}},
+ {4,erl_lint,{variable_in_record_def,'Y'}}],
+ []}},
+
+ {otp_5878_80,
+ <<"-record(r, {a = [X || {A,Y} <- [{1,2},V={3,4}],
+ begin Z = [1,2,3], true end,
+ X <- Z ++ [A,Y]]}).
+ t() ->#r{}.
+ ">>,
+ [warn_unused_record],
+ {warnings,[{1,erl_lint,{unused_var,'V'}}]}},
+
+ {otp_5878_90,
+ <<"-record(r, {a = foo()}). % unused
+
+ t() -> ok.
+ ">>,
+ [warn_unused_record],
+ {error,[{1,erl_lint,{undefined_function,{foo,0}}}],
+ [{1,erl_lint,{unused_record,r}}]}}
+
+ ],
+ ?line [] = run(Config, Ts),
+
+ Abstr = <<"-module(lint_test, [A, B]).
+
+ -export([args/1]).
+
+ -record(r, {a = A, b = THIS}). % A and THIS are unbound
+
+ %% param:args(compile,param:new(1,2)).
+
+ args(C) ->
+ X = local(C),
+ Z = new(A, B),
+ F = fun(THIS) -> {x, A} end, % THIS unused and shadowed
+ {X, Z, THIS, F, #r{}}.
+
+ local(C) ->
+ module_info(C).
+ ">>,
+ ?line {error,[{5,erl_lint,{unbound_var,'A'}},
+ {5,erl_lint,{unbound_var,'THIS'}}],
+ [{12,erl_lint,{unused_var,'THIS'}},
+ {12,erl_lint,{shadowed_var,'THIS','fun'}}]}
+ = run_test2(Config, Abstr, [warn_unused_record]),
+
+ QLC1 = <<"-module(lint_test).
+ -include_lib(\"stdlib/include/qlc.hrl\").
+ -export([t/0]).
+ -record(r1, {a = qlc:e(qlc:q([X || X <- [1,2,3]]))}).
+ -record(r2, {a = qlc:q([X || X <- [1,2,3]])}).
+ -record(r3, {a = qlc:q([X || {A,Y} <- [{1,2},V={3,4}],
+ begin Z = [1,2,3], true end,
+ X <- Z ++ [A,Y]])}).
+ t() -> {#r1{},#r2{},#r3{}}.
+ ">>,
+ ?line {error,[{8,qlc,{used_generator_variable,'A'}},
+ {8,qlc,{used_generator_variable,'Y'}},
+ {8,qlc,{used_generator_variable,'Z'}}],
+ [{6,erl_lint,{unused_var,'V'}}]} =
+ run_test2(Config, QLC1, [warn_unused_record]),
+
+ Ill1 = <<"-module(lint_test).
+ -export([t/0]).
+ -record(r, {a = true}).
+ -record(r1, {a,b}).
+ -record(r2, {a = #r1{a = true}}).
+ -record(r3, {a = A}). % A is unbound
+ -record(r4, {a = dict:new()}).
+
+ t() ->
+ case x() of
+ _ when (#r{})#r.a ->
+ a;
+ _ when (#r4{})#r.a -> % illegal
+ b;
+ _ when (#r3{q = 5})#r.a -> % no warning for unbound A
+ q;
+ _ when (#r{q = 5})#r.a ->
+ a;
+ _ when (((#r{a = #r2{}})#r.a)#r2.a)#r1.a ->
+ b;
+ _ when #r{a = dict:new()} -> % illegal
+ c;
+ _ when l() > 3 -> % illegal, does not use l/0...
+ d;
+ _ ->
+ w
+ end.
+
+ l() ->
+ foo.
+
+ x() ->
+ bar.
+ ">>,
+
+ ?line {errors,[{6,erl_lint,{unbound_var,'A'}},
+ {13,erl_lint,illegal_guard_expr},
+ {15,erl_lint,{undefined_field,r3,q}},
+ {17,erl_lint,{undefined_field,r,q}},
+ {21,erl_lint,illegal_guard_expr},
+ {23,erl_lint,illegal_guard_expr}],
+ []} =
+ run_test2(Config, Ill1, [warn_unused_record]),
+
+ Ill2 = <<"-module(lint_test).
+ -export([t/0]).
+ t() ->
+ case x() of
+ _ when l()
+ or
+ l() ->
+ foo
+ end.
+ ">>,
+ ?line {errors,[{4,erl_lint,{undefined_function,{x,0}}},
+ {5,erl_lint,illegal_guard_expr},
+ {7,erl_lint,illegal_guard_expr}],
+ []} =
+ run_test2(Config, Ill2, [warn_unused_record]),
+
+ Ill3 = <<"t() -> ok.">>,
+ ?line {errors,[{1,erl_lint,undefined_module}],[]} =
+ run_test2(Config, Ill3, [warn_unused_record]),
+
+ Usage1 = <<"-module(lint_test).
+ -export([t/0]).
+ -record(u1, {a}).
+ -record(u2, {a = #u1{}}).
+ -record(u3, {a}). % unused
+ -record(u4, {a = #u3{}}). % unused
+
+ t() ->
+ {#u2{}}.
+ ">>,
+ ?line {warnings,[{5,erl_lint,{unused_record,u3}},
+ {6,erl_lint,{unused_record,u4}}]} =
+ run_test2(Config, Usage1, [warn_unused_record]),
+
+ Usage2 = <<"-module(lint_test).
+ -export([t/0]).
+ -record(u1, {a}).
+ -record(u2, {a = #u1{}}).
+ -file(\"some_file.hrl\", 1).
+ -record(u3, {a}). % unused, but on other file
+ -record(u4, {a = #u3{}}). % -\"-
+
+ t() ->
+ {#u2{}}.
+ ">>,
+ ?line [] = run_test2(Config, Usage2, [warn_unused_record]),
+
+ %% This a completely different story...
+ %% The linter checks if qlc.hrl hasn't been included
+ QLC2 = <<"-module(lint_test).
+ -import(qlc, [q/2]).
+ -export([t/0]).
+
+ t() ->
+ H1 = qlc:q([X || X <- [1,2]]),
+ H2 = qlc:q([X || X <- [1,2]], []),
+ H3 = q([X || X <- [1,2]], []),
+ {H1,H2,H3}.
+ ">>,
+ ?line {warnings,[{6,erl_lint,{missing_qlc_hrl,1}},
+ {7,erl_lint,{missing_qlc_hrl,2}},
+ {8,erl_lint,{missing_qlc_hrl,2}}]} =
+ run_test2(Config, QLC2, [warn_unused_record]),
+
+ %% Records that are used by types are not unused.
+ %% (Thanks to Fredrik Thulin and Kostis Sagonas.)
+ UsedByType = <<"-module(t).
+ -export([foo/1]).
+ -record(sipurl, {host :: string()}).
+ -record(keylist, {list = [] :: [_]}).
+ -type sip_headers() :: #keylist{}.
+ -record(request, {uri :: #sipurl{}, header :: sip_headers()}).
+
+ foo(#request{}) -> ok.
+ ">>,
+ ?line [] = run_test2(Config, UsedByType, [warn_unused_record]),
+
+ ok.
+
+otp_6885(doc) ->
+ "OTP-6885. Binary fields in bit syntax matching is now only allowed at the end.";
+otp_6885(suite) -> [];
+otp_6885(Config) when is_list(Config) ->
+ Ts = <<"-module(otp_6885).
+ -export([t/1]).
+ t(<<_/binary,I>>) -> I;
+ t(<<X/binary,I:X>>) -> I;
+ t(<<B/binary,T/binary>>) -> {B,T}.
+
+ build(A, B) ->
+ <<A/binary,B/binary>>.
+
+ foo(<<\"abc\"/binary>>) ->
+ ok;
+ foo(<<\"abc\":13/integer>>) ->
+ ok;
+ foo(<<\"abc\"/float>>) ->
+ ok;
+ foo(<<\"abc\":19>>) ->
+ ok;
+ foo(<<\"abc\"/utf8>>) ->
+ ok;
+ foo(<<\"abc\"/utf16>>) ->
+ ok;
+ foo(<<\"abc\"/utf32>>) ->
+ ok.
+
+ ">>,
+ ?line {errors,[{3,erl_lint,unsized_binary_not_at_end},
+ {4,erl_lint,unsized_binary_not_at_end},
+ {5,erl_lint,unsized_binary_not_at_end},
+ {10,erl_lint,typed_literal_string},
+ {12,erl_lint,typed_literal_string},
+ {14,erl_lint,typed_literal_string},
+ {16,erl_lint,typed_literal_string}],
+ []} = run_test2(Config, Ts, []),
+ ok.
+
+export_all(doc) ->
+ "OTP-7392. Warning for export_all.";
+export_all(Config) when is_list(Config) ->
+ Ts = <<"-module(export_all_module).
+ -compile([export_all]).
+
+ id(I) -> I.
+ ">>,
+ ?line [] = run_test2(Config, Ts, []),
+ ?line {warnings,[{2,erl_lint,export_all}]} =
+ run_test2(Config, Ts, [warn_export_all]),
+ ok.
+
+bif_clash(doc) ->
+ "Test warnings for functions that clash with BIFs.";
+bif_clash(suite) -> [];
+bif_clash(Config) when is_list(Config) ->
+ Ts = [{clash1,
+ <<"t(X) ->
+ size(X).
+
+ %% No warning for the following calls, since they
+ %% are unambigous.
+ b(X) ->
+ erlang:size(X).
+
+ c(X) ->
+ ?MODULE:size(X).
+
+ size({N,_}) ->
+ N.
+ ">>,
+ [],
+ {errors,[{2,erl_lint,{call_to_redefined_bif,{size,1}}}],[]}},
+
+ %% Verify that (some) warnings can be turned off.
+ {clash2,
+ <<"-export([t/1,size/1]).
+ t(X) ->
+ size(X).
+
+ size({N,_}) ->
+ N.
+
+ %% My own abs/1 function works on lists too.
+ %% Unfortunately, it is not exported, so there will
+ %% be a warning that can't be turned off.
+ abs([H|T]) when $a =< H, H =< $z -> [H-($a-$A)|abs(T)];
+ abs([H|T]) -> [H|abs(T)];
+ abs([]) -> [];
+ abs(X) -> erlang:abs(X).
+ ">>,
+ {[nowarn_bif_clash]},
+ {warnings,[{11,erl_lint,{redefine_bif,{abs,1}}},
+ {11,erl_lint,{unused_function,{abs,1}}}]}}],
+
+ ?line [] = run(Config, Ts),
+ ok.
+
+behaviour_basic(doc) ->
+ "Basic tests with one behaviour.";
+behaviour_basic(suite) -> [];
+behaviour_basic(Config) when is_list(Config) ->
+ Ts = [{behaviour1,
+ <<"-behaviour(application).
+ ">>,
+ [],
+ {warnings,[{1,erl_lint,{undefined_behaviour_func,{start,2},application}},
+ {1,erl_lint,{undefined_behaviour_func,{stop,1},application}}]}},
+
+ {behaviour2,
+ <<"-behaviour(application).
+ -export([stop/1]).
+ stop(_) -> ok.
+ ">>,
+ [],
+ {warnings,[{1,erl_lint,{undefined_behaviour_func,{start,2},application}}]}},
+
+ {behaviour3,
+ <<"-behavior(application). %% Test American spelling.
+ -export([start/2,stop/1]).
+ start(_, _) -> ok.
+ stop(_) -> ok.
+ ">>,
+ [],
+ []}
+ ],
+ ?line [] = run(Config, Ts),
+ ok.
+
+behaviour_multiple(doc) ->
+ "Basic tests with multiple behaviours.";
+behaviour_multiple(suite) -> [];
+behaviour_multiple(Config) when is_list(Config) ->
+ Ts = [{behaviour1,
+ <<"-behaviour(application).
+ -behaviour(supervisor).
+ ">>,
+ [],
+ {warnings,[{1,erl_lint,{undefined_behaviour_func,{start,2},application}},
+ {1,erl_lint,{undefined_behaviour_func,{stop,1},application}},
+ {2,erl_lint,{undefined_behaviour_func,{init,1},supervisor}}]}},
+
+ {behaviour2,
+ <<"-behaviour(application).
+ -behaviour(supervisor).
+ -export([start/2,stop/1,init/1]).
+ start(_, _) -> ok.
+ stop(_) -> ok.
+ init(_) -> ok.
+ ">>,
+ [],
+ []},
+
+ {american_behavior2,
+ <<"-behavior(application).
+ -behavior(supervisor).
+ -export([start/2,stop/1,init/1]).
+ start(_, _) -> ok.
+ stop(_) -> ok.
+ init(_) -> ok.
+ ">>,
+ [],
+ []},
+
+ {behaviour3,
+ <<"-behaviour(gen_server).
+ -behaviour(supervisor).
+ -export([handle_call/3,handle_cast/2,handle_info/2]).
+ handle_call(_, _, _) -> ok.
+ handle_cast(_, _) -> ok.
+ handle_info(_, _) -> ok.
+ ">>,
+ [],
+ {warnings,[{1,erl_lint,
+ {undefined_behaviour_func,{code_change,3},gen_server}},
+ {1,erl_lint,{undefined_behaviour_func,{init,1},gen_server}},
+ {1,erl_lint,{undefined_behaviour_func,{terminate,2},gen_server}},
+ {2,erl_lint,{undefined_behaviour_func,{init,1},supervisor}},
+ {2,
+ erl_lint,
+ {conflicting_behaviours,{init,1},supervisor,1,gen_server}}]}},
+ {american_behavior3,
+ <<"-behavior(gen_server).
+ -behavior(supervisor).
+ -export([handle_call/3,handle_cast/2,handle_info/2]).
+ handle_call(_, _, _) -> ok.
+ handle_cast(_, _) -> ok.
+ handle_info(_, _) -> ok.
+ ">>,
+ [],
+ {warnings,[{1,erl_lint,
+ {undefined_behaviour_func,{code_change,3},gen_server}},
+ {1,erl_lint,{undefined_behaviour_func,{init,1},gen_server}},
+ {1,erl_lint,{undefined_behaviour_func,{terminate,2},gen_server}},
+ {2,erl_lint,{undefined_behaviour_func,{init,1},supervisor}},
+ {2,
+ erl_lint,
+ {conflicting_behaviours,{init,1},supervisor,1,gen_server}}]}},
+
+ {behaviour4,
+ <<"-behaviour(gen_server).
+ -behaviour(gen_fsm).
+ -behaviour(supervisor).
+ -export([init/1,handle_call/3,handle_cast/2,
+ handle_info/2,handle_info/3,
+ handle_event/3,handle_sync_event/4,
+ code_change/3,code_change/4,
+ terminate/2,terminate/3,terminate/4]).
+ init(_) -> ok.
+ handle_call(_, _, _) -> ok.
+ handle_event(_, _, _) -> ok.
+ handle_sync_event(_, _, _, _) -> ok.
+ handle_cast(_, _) -> ok.
+ handle_info(_, _) -> ok.
+ handle_info(_, _, _) -> ok.
+ code_change(_, _, _) -> ok.
+ code_change(_, _, _, _) -> ok.
+ terminate(_, _) -> ok.
+ terminate(_, _, _) -> ok.
+ terminate(_, _, _, _) -> ok.
+ ">>,
+ [],
+ {warnings,[{2,
+ erl_lint,
+ {conflicting_behaviours,{init,1},gen_fsm,1,gen_server}},
+ {3,
+ erl_lint,
+ {conflicting_behaviours,{init,1},supervisor,1,gen_server}}]}}
+ ],
+ ?line [] = run(Config, Ts),
+ ok.
+
+otp_7550(doc) ->
+ "Test that the new utf8/utf16/utf32 types do not allow size or unit specifiers.";
+otp_7550(Config) when is_list(Config) ->
+ Ts = [{otp_7550,
+ <<"f8(A) ->
+ <<A:8/utf8>>.
+ g8(A) ->
+ <<A:8/utf8-unit:1>>.
+ h8(A) ->
+ <<A/utf8-unit:1>>.
+
+ f16(A) ->
+ <<A:8/utf16>>.
+ g16(A) ->
+ <<A:8/utf16-unit:1>>.
+ h16(A) ->
+ <<A/utf16-unit:1>>.
+
+ f32(A) ->
+ <<A:8/utf32>>.
+ g32(A) ->
+ <<A:8/utf32-unit:1>>.
+ h32(A) ->
+ <<A/utf32-unit:1>>.
+ ">>,
+ [],
+ {errors,[{2,erl_lint,utf_bittype_size_or_unit},
+ {4,erl_lint,utf_bittype_size_or_unit},
+ {6,erl_lint,utf_bittype_size_or_unit},
+ {9,erl_lint,utf_bittype_size_or_unit},
+ {11,erl_lint,utf_bittype_size_or_unit},
+ {13,erl_lint,utf_bittype_size_or_unit},
+ {16,erl_lint,utf_bittype_size_or_unit},
+ {18,erl_lint,utf_bittype_size_or_unit},
+ {20,erl_lint,utf_bittype_size_or_unit}
+ ],
+ []}}],
+ ?line [] = run(Config, Ts),
+ ok.
+
+
+otp_8051(doc) ->
+ "Bugfix: -opaque with invalid type.";
+otp_8051(Config) when is_list(Config) ->
+ Ts = [{otp_8051,
+ <<"-opaque foo() :: bar().
+ ">>,
+ [],
+ {error,[{1,erl_lint,{type_ref,{bar,0}}}],
+ [{1,erl_lint,{unused_type,{foo,0}}}]}}],
+ ?line [] = run(Config, Ts),
+ ok.
+
+format_warn(doc) ->
+ "Check that format warnings are generated.";
+format_warn(suite) -> [];
+format_warn(Config) when is_list(Config) ->
+ L1 = 14,
+ L2 = 4,
+ format_level(1, L1, Config),
+ format_level(2, L1+L2, Config),
+ format_level(3, L1+L2, Config), %there is no level 3
+ ok.
+
+format_level(Level, Count, Config) ->
+ ?line W = get_compilation_warnings(Config, "format",
+ [{warn_format, Level}]),
+ %% Pick out the 'format' warnings.
+ ?line FW = lists:filter(fun({_Line, erl_lint, {format_error, _}}) -> true;
+ (_) -> false
+ end,
+ W),
+ ?line case length(FW) of
+ Count ->
+ ok;
+ Other ->
+ ?t:format("Expected ~w warning(s); got ~w", [Count,Other]),
+ fail()
+ end,
+ ok.
+
+%% Test the -on_load(Name/0) directive.
+
+on_load(suite) ->
+ [on_load_successful, on_load_failing].
+
+on_load_successful(Config) when is_list(Config) ->
+ Ts = [{on_load_1,
+ %% Exported on_load function.
+ <<"-export([do_on_load/0]).
+ -on_load(do_on_load/0).
+ do_on_load() -> ok.
+ ">>,
+ {[]}, %Tuple indicates no 'export_all'.
+ []},
+
+ {on_load_2,
+ %% Local on_load function.
+ <<"-on_load(do_on_load/0).
+ do_on_load() -> ok.
+ ">>,
+ {[]}, %Tuple indicates no 'export_all'.
+ []},
+
+ {on_load_3,
+ %% Local on_load function, calling other local functions.
+ <<"-on_load(do_on_load/0).
+ do_on_load() -> foo().
+ foo() -> bar(5) + 42.
+ bar(N) -> 2*N.
+ ">>,
+ {[]}, %Tuple indicates no 'export_all'.
+ []}
+ ],
+ ?line [] = run(Config, Ts),
+ ok.
+
+on_load_failing(Config) when is_list(Config) ->
+ Ts = [{on_load_1,
+ %% Badly formed.
+ <<"-on_load(atom).
+ ">>,
+ {[]}, %Tuple indicates no 'export_all'.
+ {errors,
+ [{1,erl_lint,{bad_on_load,atom}}],[]}},
+
+ {on_load_2,
+ %% Badly formed.
+ <<"-on_load({42,0}).
+ ">>,
+ {[]}, %Tuple indicates no 'export_all'.
+ {errors,
+ [{1,erl_lint,{bad_on_load,{42,0}}}],[]}},
+
+ {on_load_3,
+ %% Multiple on_load attributes.
+ <<"-on_load(foo/0).
+ -on_load(bar/0).
+ foo() -> ok.
+ bar() -> ok.
+ ">>,
+ {[]}, %Tuple indicates no 'export_all'.
+ {errors,
+ [{2,erl_lint,multiple_on_loads}],[]}},
+
+ {on_load_4,
+ %% Wrong arity.
+ <<"-on_load(foo/1).
+ foo(_) -> ok.
+ ">>,
+ {[]}, %Tuple indicates no 'export_all'.
+ {errors,
+ [{1,erl_lint,{bad_on_load_arity,{foo,1}}}],[]}},
+
+ {on_load_5,
+ %% Non-existing function.
+ <<"-on_load(non_existing/0).
+ ">>,
+ {[]}, %Tuple indicates no 'export_all'.
+ {errors,
+ [{1,erl_lint,{undefined_on_load,{non_existing,0}}}],[]}}
+ ],
+ ?line [] = run(Config, Ts),
+ ok.
+
+run(Config, Tests) ->
+ F = fun({N,P,Ws,E}, BadL) ->
+ case catch run_test(Config, P, Ws) of
+ E ->
+ BadL;
+ Bad ->
+ ?t:format("~nTest ~p failed. Expected~n ~p~n"
+ "but got~n ~p~n", [N, E, Bad]),
+ fail()
+ end
+ end,
+ lists:foldl(F, [], Tests).
+
+%% Compiles a test file and returns the list of warnings.
+
+get_compilation_warnings(Conf, Filename, Warnings) ->
+ ?line DataDir = ?datadir,
+ ?line File = filename:join(DataDir, Filename),
+ {ok,Bin} = file:read_file(File++".erl"),
+ FileS = binary_to_list(Bin),
+ {match,[{Start,Length}|_]} = re:run(FileS, "-module.*\\n"),
+ Test = lists:nthtail(Start+Length, FileS),
+ {warnings, Ws} = run_test(Conf, Test, Warnings),
+ Ws.
+
+%% Compiles a test module and returns the list of errors and warnings.
+
+run_test(Conf, Test0, Warnings0) ->
+ Test = list_to_binary(["-module(lint_test). ", Test0]),
+ run_test2(Conf, Test, Warnings0).
+
+run_test2(Conf, Test, Warnings0) ->
+ Filename = 'lint_test.erl',
+ DataDir = ?privdir,
+ File = filename:join(DataDir, Filename),
+ Opts = case Warnings0 of
+ {Warnings} -> %Hairy trick to not add export_all.
+ [return|Warnings];
+ Warnings ->
+ [export_all,return|Warnings]
+ end,
+ ok = file:write_file(File, Test),
+
+ %% We will use the 'binary' option so that the compiler will not
+ %% compare the module name to the output file name. Also, there
+ %% is no reason to produce an output file since we are only
+ %% interested in the errors and warnings.
+
+ %% Print warnings, call erl_lint:format_error/1.
+ compile:file(File, [binary,report|Opts]),
+
+ case compile:file(File, [binary|Opts]) of
+ {ok, _M, Code, Ws} when is_binary(Code) -> warnings(File, Ws);
+ {error, [{File,Es}], []} -> {errors, Es, []};
+ {error, [{File,Es}], [{File,Ws}]} -> {error, Es, Ws};
+ {error, [{File,Es1},{File,Es2}], []} -> {errors2, Es1, Es2}
+ end.
+
+warnings(File, Ws) ->
+ case lists:append([W || {F, W} <- Ws, F =:= File]) of
+ [] -> [];
+ L -> {warnings, L}
+ end.
+
+fail() ->
+ io:format("failed~n"),
+ ?t:fail().
diff --git a/lib/stdlib/test/erl_lint_SUITE_data/format.erl b/lib/stdlib/test/erl_lint_SUITE_data/format.erl
new file mode 100644
index 0000000000..20c4c5b57f
--- /dev/null
+++ b/lib/stdlib/test/erl_lint_SUITE_data/format.erl
@@ -0,0 +1,55 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(format).
+
+-export([f/1]).
+
+%%% There will be warnings at level 2 and 3.
+
+f(F) ->
+ io:format("~", F), %2
+ io:format("~", [F]), %1
+ io:format(a, b), %1
+ io:format(a, "abc"), %1
+ io:format(a, [a | "abc"]), %2
+ io:format(4,5,6,7), %1
+
+ io:format("la cucaracha~n"),
+ io:format(""),
+ io:format("~p ~p~n", [F]), %1
+ io:format("~p~n", [F]),
+ io:format("~m"), %1
+ io:format(F, "~p", []), %1
+ io:format("~x~n", [F]), %1
+ io:format("~p~n", F), %2
+ io:format(F, [3]), %2
+
+ io:format("~p", a), %1
+ io:format("~p~", [F]), %1
+ io:format("~p ~p", [F, 4 | 7]), %1
+ io:format("~14p", [F]),
+ io:format("~*p", [a, F]), %no type checking
+ io:format("~*p", [14, F]),
+
+ io:fwrite("~p", []), %1
+ io_lib:format("~p", []), %1
+ foo:format("~p", []),
+ io:format(), %1
+
+ ok.
diff --git a/lib/stdlib/test/erl_pp_SUITE.erl b/lib/stdlib/test/erl_pp_SUITE.erl
new file mode 100644
index 0000000000..0a119d1e38
--- /dev/null
+++ b/lib/stdlib/test/erl_pp_SUITE.erl
@@ -0,0 +1,1073 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%%----------------------------------------------------------------
+%%% Purpose:Test Suite for the 'erl_pp' module.
+%%%-----------------------------------------------------------------
+-module(erl_pp_SUITE).
+
+%-define(debug, true).
+
+-ifdef(debug).
+-define(line, put(line, ?LINE), ).
+-define(config(X,Y), foo).
+-define(datadir, "erl_pp_SUITE_data").
+-define(privdir, "erl_pp_SUITE_priv").
+-define(t, test_server).
+-else.
+-include("test_server.hrl").
+-define(datadir, ?config(data_dir, Config)).
+-define(privdir, ?config(priv_dir, Config)).
+-endif.
+
+-export([all/1, init_per_testcase/2, fin_per_testcase/2]).
+
+-export([expr/1, func/1, call/1, recs/1, try_catch/1, if_then/1,
+ receive_after/1, bits/1, head_tail/1, package/1,
+ cond1/1, block/1, case1/1, ops/1, messages/1,
+ old_mnemosyne_syntax/1,
+ attributes/1, import_export/1, misc_attrs/1,
+ hook/1,
+ neg_indent/1,
+ tickets/1,
+ otp_6321/1, otp_6911/1, otp_6914/1, otp_8150/1, otp_8238/1]).
+
+%% Internal export.
+-export([ehook/6]).
+
+% Default timetrap timeout (set in init_per_testcase).
+-define(default_timeout, ?t:minutes(2)).
+
+init_per_testcase(_Case, Config) ->
+ ?line Dog = ?t:timetrap(?default_timeout),
+ [{watchdog, Dog} | Config].
+
+fin_per_testcase(_Case, _Config) ->
+ Dog = ?config(watchdog, _Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+all(suite) ->
+ [expr, attributes, hook, neg_indent, tickets].
+
+expr(suite) ->
+ [func, call, recs, try_catch, if_then, receive_after, bits, head_tail,
+ package, cond1, block, case1, ops, messages, old_mnemosyne_syntax].
+
+func(suite) ->
+ [];
+func(Config) when is_list(Config) ->
+ Ts = [{func_1,
+ <<"-record(r1, {a,b}).
+ -record(r3, {a = fun(_) -> #r1{} end(1), b}).
+
+ t() ->
+ fun(A) when record(A#r3.a, r1) -> 7 end(#r3{}).
+ ">>},
+ {func_2,
+ <<"-record(r1, {a,b}).
+ -record(r3, {a = fun(_) -> #r1{} end(1), b}).
+
+ t() ->
+ fsdfsdfjsdfjkljf:sdlfjdsfjlf(
+ fun(sdfsd) -> {sdkjsdf,sdfjsdkljfsdl,sdfkjdklf} end).
+ ">>},
+ {func_3,
+ <<"t() -> fun t/0.">>},
+ {func_4,
+ %% Has already been expanded away in sys_pre_expand.
+ <<"t() -> fun modul:foo/3.">>},
+ {func_5, % 'when' is moved down one line
+ <<"tkjlksjflksdjflsdjlk()
+ when kljlsajflksjdfklsjdlkjfklsdklfjsdlf <
+ kljasjfdsjflsdjfklsdjfklsdjfklsd ->
+ foo.">>},
+ {func_6,
+ <<"t() ->
+ (fun() ->
+ true
+ end)().">>}
+ ],
+ ?line compile(Config, Ts),
+ ok.
+
+call(suite) ->
+ [];
+call(Config) when is_list(Config) ->
+ Ts = [{call_1,
+ <<"t() ->
+ fookjljsflj:barlkjlkjsdfj(kjdslfjsdl,hej,san,sa,
+ foo,sdfds,sdfsdf,sdfsd,sdfdsf,sdfdsf,sfdsf,
+ sfds,sdfsdf,sfds).
+ ">>}
+ ],
+ ?line compile(Config, Ts),
+ ok.
+
+recs(suite) ->
+ [];
+recs(Config) when is_list(Config) ->
+ %% Evolved while testing strict record tests in guards...
+ Ts = [{recs_1,
+ <<"-compile(strict_record_tests).
+ -record(r, {a = 4,b}).
+ -record(r1, {a,b}).
+ -record(r2, {a = #r1{},b,c=length([1,2,3])}).
+ -record(r3, {a = fun(_) -> #r1{} end(1), b}).
+
+ t() ->
+ foo = fun(A) when A#r1.a > A#r1.b -> foo end(#r1{b = 2}),
+ 0 = fun(A) when A#r2.a -> 0 end(#r2{a = true}),
+ 1 = fun(A) when (#r1{a = A})#r1.a > 2 -> 1 end(3),
+ 2 = fun(N) when ((#r2{a = #r{a = 4}, b = length([a,b,c])})#r2.a)#r.a > N ->
+ 2 end(2),
+ 3 = fun(A) when (A#r2.a)#r1.a =:= 3 -> 3 end(#r2{a = #r1{a = 3}}),
+ ok = fun() ->
+ F = fun(A) when record(A#r.a, r1) -> 4;
+ (A) when record(A#r1.a, r1) -> 5
+ end,
+ 5 = F(#r1{a = #r1{}}),
+ 4 = F(#r{a = #r1{}}),
+ ok
+ end(),
+ 3 = fun(A) when record(A#r1.a, r),
+ (A#r1.a)#r.a > 3 -> 3
+ end(#r1{a = #r{a = 4}}),
+ 7 = fun(A) when record(A#r3.a, r1) -> 7 end(#r3{}),
+ [#r1{a = 2,b = 1}] =
+ fun() ->
+ [A || A <- [#r1{a = 1, b = 3},
+ #r2{a = 2,b = 1},
+ #r1{a = 2, b = 1}],
+ A#r1.a >
+ A#r1.b]
+ end(),
+ {[_],b} =
+ fun(L) ->
+ %% A is checked only once:
+ R1 = [{A,B} || A <- L, A#r1.a, B <- L, A#r1.b],
+ A = #r2{a = true},
+ %% A is checked again:
+ B = if A#r1.a -> a; true -> b end,
+ {R1,B}
+ end([#r1{a = true, b = true}]),
+
+ p = fun(A) when (A#r1.a =:= 2) or (A#r2.a =:= 1) -> o;
+ (_) -> p
+ end(#r1{a = 2}),
+
+ o = fun(A) when (A#r1.a =:= 2) orelse (A#r2.a =:= 1) -> o;
+ (_) -> p
+ end(#r1{a = 2}),
+
+ %% The test done twice (an effect of doing the test as soon as possible).
+ 3 = fun(A) when A#r1.a > 3,
+ record(A, r1) -> 3
+ end(#r1{a = 5}),
+
+ ok = fun() ->
+ F = fun(A) when (A#r2.a =:= 1) orelse (A#r2.a) -> 2;
+ (A) when (A#r1.a =:= 1) orelse (A#r1.a) -> 1;
+ (A) when (A#r2.a =:= 2) andalso (A#r2.b) -> 3
+ end,
+ 1 = F(#r1{a = 1}),
+ 2 = F(#r2{a = true}),
+ 3 = F(#r2{a = 2, b = true}),
+ ok
+ end(),
+
+ b = fun(A) when false or not (A#r.a =:= 1) -> a;
+ (_) -> b
+ end(#r1{a = 1}),
+ b = fun(A) when not (A#r.a =:= 1) or false -> a;
+ (_) -> b
+ end(#r1{a = 1}),
+
+ ok = fun() ->
+ F = fun(A) when not (A#r.a =:= 1) -> yes;
+ (_) -> no
+ end,
+ no = F(#r1{a = 2}),
+ yes = F(#r{a = 2}),
+ no = F(#r{a = 1}),
+ ok
+ end(),
+
+ %% No extra check added:
+ a = fun(A) when record(A, r),
+ A#r.a =:= 1,
+ A#r.b =:= 2 ->a
+ end(#r{a = 1, b = 2}),
+ a = fun(A) when erlang:is_record(A, r),
+ A#r.a =:= 1,
+ A#r.b =:= 2 -> a
+ end(#r{a = 1, b = 2}),
+ a = fun(A) when is_record(A, r),
+ A#r.a =:= 1,
+ A#r.b =:= 2 -> a
+ end(#r{a = 1, b = 2}),
+
+ nop = fun(A) when (is_record(A, r1) and (A#r1.a > 3)) or (A#r2.a < 1) ->
+ japp;
+ (_) ->
+ nop
+ end(#r2{a = 0}),
+ nop = fun(A) when (A#r1.a > 3) or (A#r2.a < 1) -> japp;
+ (_) ->
+ nop
+ end(#r2{a = 0}),
+
+ ok = fun() ->
+ F = fun(A) when (A#r1.a =:= 2) or (A#r2.a =:= 1) -> o;
+ (_) -> p
+ end,
+ p = F(#r2{a = 1}),
+ p = F(#r1{a = 2}),
+ ok
+ end(),
+
+ ok = fun() ->
+ F = fun(A) when fail, A#r1.a; A#r1.a -> ab;
+ (_) -> bu
+ end,
+ ab = F(#r1{a = true}),
+ bu = F(#r2{a = true}),
+ ok
+ end(),
+
+ both = fun(A) when A#r.a, A#r.b -> both
+ end(#r{a = true, b = true}),
+
+ ok = fun() ->
+ F = fun(A, B) when ((A#r1.a) orelse (B#r2.a))
+ or (B#r2.b) or (A#r1.b) ->
+ true;
+ (_, _) -> false
+ end,
+ true = F(#r1{a = false, b = false},
+ #r2{a = false, b = true}),
+ false = F(#r1{a = true, b = true},
+ #r1{a = false, b = true}),
+ ok
+ end(),
+
+ ok.
+ ">>},
+ {recs_2,
+ <<"-record(r1, {a, b = foo:bar(kljlfjsdlf, kjlksdjf)}).
+ -record(r2, {c = #r1{}, d = #r1{a = bar:foo(kljklsjdf)}}).
+
+ t() ->
+ R = #r2{},
+ R#r2{c = R, d = #r1{}}.">>}
+ ],
+ ?line compile(Config, Ts),
+
+ ?line ok = pp_expr(<<"case #r{a={1,2},b=#r{}} of
+ X=Y=#r{a=foo,b=bar} ->
+ {(foooo:baaaar(X))#r{a = rep},Y,#r.b}
+ end">>),
+ ?line ok = pp_expr(<<"R#r{a = {kljasdklf,sdkfjsdl,sdafjkllsdf,sdfkjsd,
+ sdafjsd,sdf,sdafsd,sdfdsf,sdfdsf,dsfds}}">>),
+ ok.
+
+try_catch(suite) ->
+ [];
+try_catch(Config) when is_list(Config) ->
+ Ts = [{try_1, % copied from erl_eval_SUITE
+ <<"t() -> try 1 of 1 -> 2 catch _:_ -> 3 end.">>},
+ {try_2,
+ <<"t() -> try 1 of 1 -> 2; 3 -> 4 catch _:_ -> 5 end.">>},
+ {try_3,
+ <<"t() -> try 3 of 1 -> 2; 3 -> 4 catch _:_ -> 5 end.">>},
+ {try_4,
+ <<"t() -> try 1 after put(try_catch, 2) end.">>},
+ {try_5,
+ <<"t() -> try 1 of 1 -> 2; 3 -> 4
+ after put(try_catch, 5) end.">>},
+ {try_6,
+ <<"t() -> try 1=2 catch throw:{badmatch,2} -> 3 end.">>},
+ {try_7,
+ <<"t() -> try 1=2 of 3 -> 4
+ catch error:{badmatch,2} -> 5 end.">>},
+ {try_8,
+ <<"t() -> try 1=2
+ catch error:{badmatch,2} -> 3
+ after put(try_catch, 4) end.">>},
+ {try_9,
+ <<"t() -> try 1=2
+ catch error:{badmatch,2} -> 3
+ after put(try_catch, 4) end.">>},
+ {try_10,
+ <<"t() -> try a,b,c
+ catch exit:_ -> d;
+ throw:_ -> t;
+ error:{foo,bar} -> foo,
+ bar
+ end.">>},
+
+ {catch_1,
+ <<"t() -> catch foo.">>},
+ {catch_2,
+ <<"t() -> case catch foo of bar -> foo end.">>},
+ {catch_3,
+ <<"t() -> catch begin begin foo, bar, foo:bar(kljsldkfjdls,kljsdl),
+ (catch bar:foo(foo)) end end.">>}
+ ],
+ ?line compile(Config, Ts),
+ ?line ok = pp_expr(<<"try
+ erl_internal:bif(M,F,length(Args))
+ of
+ true ->
+ call(N,Args,Prec,Hook);
+ false ->
+ call(Name,Args,Prec,Hook)
+ after foo end">>),
+ ok.
+
+if_then(suite) ->
+ [];
+if_then(Config) when is_list(Config) ->
+ Ts = [{if_1,
+ <<"t() -> if 1 > 2 -> 1; true -> b end.">>},
+ {if_2,
+ <<"t() -> if true -> true end.">>},
+ {if_3,
+ <<"t() -> if 1 == 2 -> a; 1 > 2 -> b; 1 < 2 -> c end.">>}
+ ],
+ ?line compile(Config, Ts),
+ ok.
+
+receive_after(suite) ->
+ [];
+receive_after(Config) when is_list(Config) ->
+ Ts = [{rec_1,
+ <<"t() -> receive foo -> bar; bar -> foo end.">>},
+ {rec_2,
+ <<"t() -> receive foo -> bar after foo:bar() -> 0 end.">>},
+ {rec_3,
+ <<"t() -> receive after 1 -> ok end.">>},
+ {rec_4,
+ <<"t() -> receive {X,Y} -> {a,X,Y} end.">>},
+ {rec_5,
+ <<"t() -> receive
+ {X,Y} ->
+ {X,Y};
+ Z ->
+ Z
+ after
+ foo:bar() ->
+ {3,4}
+ end.">>}
+ ],
+ ?line compile(Config, Ts),
+ ok.
+
+bits(suite) ->
+ [];
+bits(Config) when is_list(Config) ->
+ Ts = [{bit_1, % copied from shell_SUITE
+ <<"t() -> <<(<<\"abc\">>):3/binary>>.">>},
+ {bit_2,
+ <<"t() -> <<(<<\"abc\">>)/binary>>.">>},
+ {bit_3,
+ <<"t() -> <<3.14:64/float>>.">>},
+ {bit_4,
+ <<"t() -> <<-20/signed>> = <<-20>>.">>},
+ {bit_5,
+ <<"t() -> <<-300:16/signed>> = <<-300:16>>.">>},
+ {bit_6,
+ <<"t() -> <<-(1 bsl 29):32/signed>> = <<-(1 bsl 29):32>>.">>},
+ {bit_7,
+ <<"t() -> <<A:4,B:4,C:4,D:4,E:4,F:4>> = <<\"hej\">>.">>},
+ {bit_8,
+ <<"t() -> <<>>.">>},
+ {bit_9,
+ <<"">>}
+ ],
+ ?line compile(Config, Ts),
+ ?line ok = pp_expr(<<"<<(list_to_binary([1,2]))/binary>>">>),
+ ?line ok = pp_expr(
+ <<"<<(list_to_binary([1,2])):all/binary-unit:8-unsigned-big>>">>),
+ ?line ok = pp_expr(<<"<<<<\"hej\">>/binary>>">>),
+ ?line ok = pp_expr(<<"<<(foo:bar())/binary>>">>),
+ ?line ok = pp_expr(<<"<<(a)/binary>>">>),
+ ?line ok = pp_expr(<<"<<a/binary>>">>),
+ ?line ok = pp_expr(<<"<<{a,b}/binary>>">>),
+ ?line ok = pp_expr(<<"<<{foo:bar(),b}/binary>>">>),
+ ?line ok = pp_expr(<<"<<(foo:bar()):(foo:bar())/binary>>">>),
+ ?line ok = pp_expr(<<"<<(foo.bar)/binary>>">>),
+ ?line ok = pp_expr(<<"<<(foo.bar):all/binary>>">>),
+ ?line ok = pp_expr(<<"<<(foo.bar):(foo.bar)/binary>>">>),
+ ok.
+
+head_tail(suite) ->
+ [];
+head_tail(Config) when is_list(Config) ->
+ Ts = [{list_1,
+ <<"t() -> [a | b].">>},
+ {list_2,
+ <<"t() -> [a,b,$\n].">>},
+ {list_3,
+ <<"t() -> [].">>},
+ {list_4,
+ <<"t() -> [a].">>},
+ {list_5,
+ <<"t() ->
+ [foo:bar(lkjljlskdfj, klsdajflds, sdafkljsdlfkjdas, kjlsdadjl),
+ bar:foo(kljlkjsdf, lkjsdlfj, [kljsfj, sdfdsfsad])].">>}
+ ],
+ ?line compile(Config, Ts),
+ ok.
+
+package(suite) ->
+ [];
+package(Config) when is_list(Config) ->
+ Ts = [{package_1,
+ <<"t() -> a.b:foo().">>},
+ {package_2,
+ <<"t() -> .lists:sort([]).">>}
+ ],
+ ?line compile(Config, Ts),
+ ok.
+
+cond1(suite) ->
+ [];
+cond1(Config) when is_list(Config) ->
+ C = {'cond',1,[{clause,2,[],[[{tuple,2,[{atom,2,foo},{atom,2,bar}]}]],
+ [{cons,3,{atom,3,a},{cons,3,{atom,3,b},{nil,3}}}]},
+ {clause,4,[],[[{atom,4,true}]],
+ [{tuple,5,[{atom,5,x},{atom,5,y}]}]}]},
+ ?line CChars = lists:flatten(erl_pp:expr(C)),
+% ?line "cond {foo,bar} -> [a,b]; true -> {x,y} end" = CChars,
+ ?line "cond\n"
+ " {foo,bar} ->\n"
+ " [a,b];\n"
+ " true ->\n"
+ " {x,y}\n"
+ "end" = CChars,
+% ?line ok = pp_expr(<<"cond
+% {foo,bar} ->
+% [a,b];
+% true ->
+% {x,y}
+% end">>),
+ ok.
+
+block(suite) ->
+ [];
+block(Config) when is_list(Config) ->
+ Ts = [{block_1,
+ <<"t() -> begin a,{c,d} end.">>}
+ ],
+ ?line compile(Config, Ts),
+ ok.
+
+case1(suite) ->
+ [];
+case1(Config) when is_list(Config) ->
+ Ts = [{case_1,
+ <<"t() -> case {foo,bar} of
+ {A,B} when true ->
+ [A,B];
+ _ ->
+ foo
+ end.">>}
+ ],
+ ?line compile(Config, Ts),
+ ?line ok = pp_expr(<<"case
+ erl_internal:bif(M,F,length(Args))
+ of
+ true ->
+ call(N,Args,Prec,Hook);
+ false ->
+ call(Name,Args,Prec,Hook)
+ end">>),
+ ok.
+
+ops(suite) ->
+ [];
+ops(Config) when is_list(Config) ->
+ Ts = [{ops_1,
+ <<"t() -> {a,b} + (3 - 2) + 4.">>},
+ {ops_2,
+ <<"t() -> a - (3 + 4).">>},
+ {ops_3,
+ <<"t() -> - (- (- (- (- 3)))).">>}
+ ],
+ ?line compile(Config, Ts),
+ ok.
+
+messages(suite) ->
+ [];
+messages(Config) when is_list(Config) ->
+ ?line true = "{error,{some,\"error\"}}\n" =:=
+ lists:flatten(erl_pp:form({error,{some,"error"}})),
+ ?line true = "{warning,{some,\"warning\"}}\n" =:=
+ lists:flatten(erl_pp:form({warning,{some,"warning"}})),
+ ?line true = "\n" =:= lists:flatten(erl_pp:form({eof,0})),
+ ok.
+
+old_mnemosyne_syntax(suite) ->
+ [];
+old_mnemosyne_syntax(Config) when is_list(Config) ->
+ %% Since we have kept the 'query' syntax and ':-' token,
+ %% better test that we can pretty print it.
+ Q = {'query',6,
+ {lc,6,
+ {var,6,'X'},
+ [{generate,6,
+ {var,6,'X'},
+ {call,6,{atom,6,table},[{atom,6,tab}]}},
+ {match,7,
+ {record_field,7,{var,7,'X'},{atom,7,foo}},
+ {atom,7,bar}}]}},
+ ?line "query\n"
+ " [ \n" % extra space...
+ " X ||\n"
+ " X <- table(tab),\n"
+ " X.foo = bar\n"
+ " ]\n"
+ "end" =
+ lists:flatten(erl_pp:expr(Q)),
+
+ R = {rule,12,sales,2,
+ [{clause,12,
+ [{var,12,'E'},{atom,12,employee}],
+ [],
+ [{generate,13,
+ {var,13,'E'},
+ {call,13,{atom,13,table},[{atom,13,employee}]}},
+ {match,14,
+ {record_field,14,{var,14,'E'},{atom,14,salary}},
+ {atom,14,sales}}]}]},
+ ?line "sales(E, employee) :-\n"
+ " E <- table(employee),\n"
+ " E.salary = sales.\n" =
+ lists:flatten(erl_pp:form(R)),
+ ok.
+
+
+attributes(suite) ->
+ [misc_attrs, import_export].
+
+import_export(suite) ->
+ [];
+import_export(Config) when is_list(Config) ->
+ Ts = [{import_1,
+ <<"-import(lists, [max/1, reverse/1]).
+ -import(sofs, []).
+ t(L) ->
+ max(reverse(L)).">>},
+ {export_1,
+ <<"-export([t/0]).
+ -export([]).
+ t() -> [].">>},
+ {qlc_1,
+ <<"-include_lib(\"stdlib/include/qlc.hrl\").
+ t() -> qlc:q([X || X <- []]).">>}
+ ],
+ ?line compile(Config, Ts),
+ ok.
+
+misc_attrs(suite) ->
+ [];
+misc_attrs(Config) when is_list(Config) ->
+ ?line ok = pp_forms(<<"-module(m). ">>),
+ ?line ok = pp_forms(<<"-module(m.p, [A,B]). ">>),
+ ?line ok = pp_forms(<<"-module(m, [Aafjlksfjdlsjflsdfjlsdjflkdsfjlk,"
+ "Blsjfdlslfjsdf]). ">>),
+ ?line ok = pp_forms(<<"-export([]). ">>),
+ ?line ok = pp_forms(<<"-export([foo/2, bar/0]). ">>),
+ ?line ok = pp_forms(<<"-export([bar/0]). ">>),
+ ?line ok = pp_forms(<<"-import(.lists). ">>),
+ ?line ok = pp_forms(<<"-import(lists, []). ">>),
+ ?line ok = pp_forms(<<"-import(lists, [map/2]). ">>),
+ ?line ok = pp_forms(<<"-import(lists, [map/2, foreach/2]). ">>),
+ ?line ok = pp_forms(<<"-'wild '({attr2,3}). ">>),
+ ?line ok = pp_forms(<<"-record(a, {b,c}). ">>),
+ ?line ok = pp_forms(<<"-record(' a ', {}). ">>),
+ ?line ok = pp_forms(<<"-record(' a ', {foo = foo:bar()}). ">>),
+
+ ok.
+
+hook(suite) ->
+ [];
+hook(Config) when is_list(Config) ->
+ Lc = parse_expr(binary_to_list(<<"[X || X <- [1,2,3]].">>)),
+ H = fun hook/4,
+ Expr = {call,0,{atom,0,fff},[{foo,Lc},{foo,Lc},{foo,Lc}]},
+ EChars = lists:flatten(erl_pp:expr(Expr, 0, H)),
+ Call = {call,0,{atom,0,foo},[Lc]},
+ Expr2 = {call,0,{atom,0,fff},[Call,Call,Call]},
+ EChars2 = erl_pp:exprs([Expr2]),
+ ?line true = EChars =:= lists:flatten(EChars2),
+
+ EsChars = erl_pp:exprs([Expr], H),
+ ?line true = EChars =:= lists:flatten(EsChars),
+
+ F = {function,1,ffff,0,[{clause,1,[],[],[Expr]}]},
+ FuncChars = lists:flatten(erl_pp:function(F, H)),
+ F2 = {function,1,ffff,0,[{clause,1,[],[],[Expr2]}]},
+ FuncChars2 = erl_pp:function(F2),
+ ?line true = FuncChars =:= lists:flatten(FuncChars2),
+ FFormChars = erl_pp:form(F, H),
+ ?line true = FuncChars =:= lists:flatten(FFormChars),
+
+ A = {attribute,1,record,{r,[{record_field,1,{atom,1,a},Expr}]}},
+ AChars = lists:flatten(erl_pp:attribute(A, H)),
+ A2 = {attribute,1,record,{r,[{record_field,1,{atom,1,a},Expr2}]}},
+ AChars2 = erl_pp:attribute(A2),
+ ?line true = AChars =:= lists:flatten(AChars2),
+ AFormChars = erl_pp:form(A, H),
+ ?line true = AChars =:= lists:flatten(AFormChars),
+
+ R = {rule,0,sales,0,
+ [{clause,0,[{var,0,'E'},{atom,0,employee}],[],
+ [{generate,2,{var,2,'E'},
+ {call,2,{atom,2,table},[{atom,2,employee}]}},
+ {match,3,
+ {record_field,3,{var,3,'E'},{atom,3,salary}},
+ {foo,Expr}}]}]},
+ RChars = lists:flatten(erl_pp:rule(R, H)),
+ R2 = {rule,0,sales,0,
+ [{clause,0,[{var,0,'E'},{atom,0,employee}],[],
+ [{generate,2,{var,2,'E'},
+ {call,2,{atom,2,table},[{atom,2,employee}]}},
+ {match,3,
+ {record_field,3,{var,3,'E'},{atom,3,salary}},
+ {call,0,{atom,0,foo},[Expr2]}}]}]},
+ RChars2 = erl_pp:rule(R2),
+ ?line true = RChars =:= lists:flatten(RChars2),
+ ARChars = erl_pp:form(R, H),
+ ?line true = RChars =:= lists:flatten(ARChars),
+
+ ?line "INVALID-FORM:{foo,bar}:" = lists:flatten(erl_pp:expr({foo,bar})),
+
+ %% A list (as before R6), not a list of lists.
+ G = [{op,1,'>',{atom,1,a},{foo,{atom,1,b}}}], % not a proper guard
+ GChars = lists:flatten(erl_pp:guard(G, H)),
+ G2 = [{op,1,'>',{atom,1,a},
+ {call,0,{atom,0,foo},[{atom,1,b}]}}], % not a proper guard
+ GChars2 = erl_pp:guard(G2),
+ ?line true = GChars =:= lists:flatten(GChars2),
+
+ EH = {?MODULE, ehook, [foo,bar]},
+ XEChars = erl_pp:expr(Expr, -1, EH),
+ ?line true = remove_indentation(EChars) =:= lists:flatten(XEChars),
+ XEChars2 = erl_pp:expr(Expr, EH),
+ ?line true = EChars =:= lists:flatten(XEChars2),
+
+ %% Note: no leading spaces before "begin".
+ Block = {block,0,[{match,0,{var,0,'A'},{integer,0,3}},
+ {atom,0,true}]},
+ ?line "begin\n A =" ++ _ =
+ lists:flatten(erl_pp:expr(Block, 17, none)),
+
+ %% Special...
+ ?line true =
+ "{some,value}" =:= lists:flatten(erl_pp:expr({value,0,{some,value}})),
+
+ %% Silly...
+ ?line true =
+ "if true -> 0 end" =:=
+ flat_expr({'if',0,[{clause,0,[],[],[{atom,0,0}]}]}),
+
+ %% More compatibility: before R6
+ OldIf = {'if',0,[{clause,0,[],[{atom,0,true}],[{atom,0,b}]}]},
+ NewIf = {'if',0,[{clause,0,[],[[{atom,0,true}]],[{atom,0,b}]}]},
+ OldIfChars = lists:flatten(erl_pp:expr(OldIf)),
+ NewIfChars = lists:flatten(erl_pp:expr(NewIf)),
+ ?line true = OldIfChars =:= NewIfChars,
+
+ ok.
+
+remove_indentation(S) ->
+ %% T is for the very special leaf(" ") used for lc and bc.
+ T = re:replace(S, " \n *", "", [{return,list},global]),
+ re:replace(T, "\n *", " ", [{return,list},global]).
+
+ehook(HE, I, P, H, foo, bar) ->
+ hook(HE, I, P, H).
+
+hook({foo,E}, I, P, H) ->
+ erl_pp:expr({call,0,{atom,0,foo},[E]}, I, P, H).
+
+neg_indent(suite) ->
+ [];
+neg_indent(Config) when is_list(Config) ->
+ ?line ok = pp_expr(<<"begin a end">>),
+ ?line ok = pp_expr(<<"begin a,b end">>),
+ ?line ok = pp_expr(<<"try a,b,c
+ catch exit:_ -> d;
+ throw:_ -> t;
+ error:{foo,bar} -> foo,
+ bar
+ end">>),
+ ?line ok = pp_expr(
+ <<"fun() ->
+ F = fun(A, B) when ((A#r1.a) orelse (B#r2.a))
+ or (B#r2.b) or (A#r1.b) ->
+ true;
+ (_, _) -> false
+ end,
+ true = F(#r1{a = false, b = false},
+ #r2{a = false, b = true}),
+ false = F(#r1{a = true, b = true},
+ #r1{a = false, b = true}),
+ ok
+ end()">>),
+
+ ?line ok = pp_expr(<<"[X || X <- a, true]">>),
+ ?line ok = pp_expr(<<"{[a,b,c],[d,e|f]}">>),
+ ?line ok = pp_expr(<<"f(a,b,c)">>),
+ ?line ok = pp_expr(<<"fun() when a,b;c,d -> a end">>),
+ ?line ok = pp_expr(<<"<<34:32,17:32>>">>),
+ ?line ok = pp_expr(<<"if a,b,c -> d; e,f,g -> h,i end">>),
+ ?line ok = pp_expr(<<"if a -> d; c -> d end">>),
+ ?line ok = pp_expr(<<"receive after 1 -> 2 end">>),
+ ?line ok = pp_expr(<<"begin a,b,c end">>),
+
+ ?line "\"\"" = flat_expr({string,0,""}),
+ ?line ok = pp_expr(<<"\"abc\"">>),
+ ?line ok = pp_expr(<<"\"abc\n\n\n\n\nkjsd\n\n\n\n\nkljsddf\n\n\n\n\n"
+ "klafd\n\n\n\n\nkljsdf\n\n\n\n\nsdf\n\n\n\n\n\"">>),
+ ?line ok = pp_expr(<<"fkjlskljklkkljlkjlkjkljlkjsljklf"
+ "lsdjlfdsjlfjsdlfjdslfjdlsjfsdjfklsdkfjsdf("
+ "\"abc\n\n\n\n\nkjsd\n\n\n\n\nkljsddf\n\n\n\n\n"
+ "kljsafd\n\n\n\n\nkljsdf\n\n\n\n\nkjsdf"
+ "\n\n\n\n\n\")">>),
+
+ %% fun-info is skipped when everything is to fit on one single line
+ Fun1 = {'fun',1,{function,t,0},{0,45353021,'-t/0-fun-0-'}},
+ ?line "fun t/0" = flat_expr(Fun1),
+ Fun2 = {'fun',2,{clauses,[{clause,2,[],[],[{atom,3,true}]}]},
+ {0,108059557,'-t/0-fun-0-'}},
+ ?line "fun() -> true end" = flat_expr(Fun2),
+
+ ok.
+
+tickets(suite) ->
+ [otp_6321, otp_6911, otp_6914, otp_8150, otp_8238].
+
+otp_6321(doc) ->
+ "OTP_6321. Bug fix of exprs().";
+otp_6321(suite) -> [];
+otp_6321(Config) when is_list(Config) ->
+ Str = "S = hopp, {hej, S}. ",
+ {done, {ok, Tokens, _EndLine}, ""} = erl_scan:tokens("", Str, _L=1),
+ {ok, Exprs} = erl_parse:parse_exprs(Tokens),
+ "S = hopp, {hej,S}" = lists:flatten(erl_pp:exprs(Exprs)),
+ ok.
+
+otp_6911(doc) ->
+ "OTP_6911. More newlines.";
+otp_6911(suite) -> [];
+otp_6911(Config) when is_list(Config) ->
+ F = {function,5,thomas,1,
+ [{clause,5,
+ [{var,5,'X'}],
+ [],
+ [{'case',6,
+ {var,6,'X'},
+ [{clause,7,[{atom,7,true}],[],[{integer,7,12}]},
+ {clause,8,[{atom,8,false}],[],[{integer,8,14}]}]}]}]},
+ ?line Chars = lists:flatten(erl_pp:form(F)),
+ ?line "thomas(X) ->\n"
+ " case X of\n"
+ " true ->\n"
+ " 12;\n"
+ " false ->\n"
+ " 14\n"
+ " end.\n" = Chars,
+ ?line ok = pp_expr(<<"case X of true -> 12; false -> 14 end">>),
+ ?line ok = pp_expr(<<"receive after 1 -> ok end">>),
+ ok.
+
+otp_6914(doc) ->
+ "OTP_6914. Binary comprehensions.";
+otp_6914(suite) -> [];
+otp_6914(Config) when is_list(Config) ->
+ ?line ok = pp_expr(<<"<< <<B:1>> || B <- [0,1,1] >>">>),
+ ?line ok = pp_expr(<<"[ B || <<B:1>> <= <<\"hi\">>]">>),
+ ?line ok = pp_expr(<<"<< <<1:1>> || true >>">>),
+ ok.
+
+otp_8150(doc) ->
+ "OTP_8150. Types.";
+otp_8150(suite) -> [];
+otp_8150(Config) when is_list(Config) ->
+ ?line _ = [{N,ok} = {N,pp_forms(B)} ||
+ {N,B} <- type_examples()
+ ],
+ ok.
+
+otp_8238(doc) ->
+ "OTP_8238. Bugfix 'E'.";
+otp_8238(suite) -> [];
+otp_8238(Config) when is_list(Config) ->
+ Ex = [<<"-record(rec1, {}).\n"
+ "-record(rec2, {a, b}).\n"
+ "-record(rec3, {f123, g, h}).\n">>,
+ <<"-type line() :: integer().\n">>,
+ <<"-type info_line() :: integer() | term().\n">>,
+ <<"-type column() :: pos_integer().\n">>,
+ [["\n", B] || {_,B} <- type_examples()],
+ <<"t1(T) ->\n"
+ " foo:bar(#rec1{}, #rec2{}),\n"
+ " T.\n"
+ "t2() ->\n"
+ " #r{}.\n">>
+ ],
+ ?line compile(Config, [{otp_8238,iolist_to_binary(Ex)}]),
+ ok.
+
+type_examples() ->
+ [{ex1,<<"-type ann() :: Var :: integer(). ">>},
+ {ex2,<<"-type ann2() :: Var :: "
+ "'return' | 'return_white_spaces' | 'return_comments'"
+ " | 'text' | ann(). ">>},
+ {ex3,<<"-type paren() :: (ann2()). ">>},
+ {ex4,<<"-type t1() :: atom(). ">>},
+ {ex5,<<"-type t2() :: [t1()]. ">>},
+ {ex6,<<"-type t3(Atom) :: integer(Atom). ">>},
+ {ex7,<<"-type t4() :: t3(foobar). ">>},
+ {ex8,<<"-type t5() :: {t1(), t3(foo)}. ">>},
+ {ex9,<<"-type t6() :: 1 | 2 | 3 | 'foo' | 'bar'. ">>},
+ {ex10,<<"-type t7() :: []. ">>},
+ {ex11,<<"-type t71() :: [_]. ">>},
+ {ex12,<<"-type t8() :: {any(),none(),pid(),port(),"
+ "reference(),float()}. ">>},
+ {ex13,<<"-type t9() :: [1|2|3|foo|bar] | "
+ "list(a | b | c) | t71(). ">>},
+ {ex14,<<"-type t10() :: {1|2|3|foo|t9()} | {}. ">>},
+ {ex15,<<"-type t11() :: 1..2. ">>},
+ {ex16,<<"-type t13() :: maybe_improper_list(integer(), t11()). ">>},
+ {ex17,<<"-type t14() :: [erl_scan:foo() | "
+ "erl_scan:bar(34, 92) | t13() | m:f(integer() | <<_:_*16>>)]. ">>},
+ {ex18,<<"-type t15() :: {binary(),<<>>,<<_:34>>,<<_:_*42>>,"
+ "<<_:3,_:_*14>>,<<>>} | [<<>>|<<_:34>>|<<_:16>>|"
+ "<<_:3,_:_*1472>>|<<_:19,_:_*14>>| <<_:34>>|"
+ "<<_:34>>|<<_:34>>|<<_:34>>]. ">>},
+ {ex19,<<"-type t16() :: fun(). ">>},
+ {ex20,<<"-type t17() :: fun((...) -> paren()). ">>},
+ {ex21,<<"-type t18() :: fun(() -> t17() | t16()). ">>},
+ {ex22,<<"-type t19() :: fun((t18()) -> t16()) |"
+ "fun((nonempty_maybe_improper_list('integer', any())|"
+ "1|2|3|a|b|<<_:3,_:_*14>>|integer()) ->"
+ "nonempty_maybe_improper_list('integer', any())|"
+ "1|2|3|a|b|<<_:3,_:_*14>>|integer()). ">>},
+ {ex23,<<"-type t20() :: [t19(), ...]. ">>},
+ {ex24,<<"-type t21() :: tuple(). ">>},
+ {ex25,<<"-type t21(A) :: A. ">>},
+ {ex26,<<"-type t22() :: t21(integer()). ">>},
+ {ex27,<<"-type t23() :: #rec1{}. ">>},
+ {ex28,<<"-type t24() :: #rec2{a :: t23(), b :: [atom()]}. ">>},
+ {ex29,<<"-type t25() :: #rec3{f123 :: [t24() | "
+ "1|2|3|4|a|b|c|d| "
+ "nonempty_maybe_improper_list(integer, any())]}. ">>},
+ {ex30,<<"-type t99() ::"
+ "{t2(),t4(),t5(),t6(),t7(),t8(),t10(),t14(),"
+ "t15(),t20(),t21(), t22(),t25()}. ">>},
+ {ex31,<<"-spec t1(FooBar :: t99()) -> t99();"
+ "(t2()) -> t2();"
+ "(t4()) -> t4() when is_subtype(t4(), t24);"
+ "(t23()) -> t23() when is_subtype(t23(), atom()),"
+ " is_subtype(t23(), t14());"
+ "(t24()) -> t24() when is_subtype(t24(), atom()),"
+ " is_subtype(t24(), t14()),"
+ " is_subtype(t24(), t4()).">>},
+ {ex32,<<"-spec mod:t2() -> any(). ">>},
+ {ex33,<<"-opaque attributes_data() :: "
+ "[{'column', column()} | {'line', info_line()} |"
+ " {'text', string()}] | {line(),column()}. ">>},
+ {ex34,<<"-record(r,{"
+ "f1 :: attributes_data(),"
+ "f222 = foo:bar(34, #rec3{}, 234234234423, "
+ " aassdsfsdfsdf, 2234242323) :: "
+ " [t24() | 1|2|3|4|a|b|c|d| "
+ " nonempty_maybe_improper_list(integer, any())],"
+ "f333 :: [t24() | 1|2|3|4|a|b|c|d| "
+ " nonempty_maybe_improper_list(integer, any())],"
+ "f3 = x:y(),"
+ "f4 = x:z() :: t99(),"
+ "f17 :: 'undefined',"
+ "f18 :: 1 | 2 | 'undefined',"
+ "f19 = 3 :: integer()|undefined,"
+ "f5 = 3 :: undefined|integer()}). ">>}].
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+compile(Config, Tests) ->
+ F = fun({N,P}, BadL) ->
+ case catch compile_file(Config, P) of
+ ok ->
+ case pp_forms(P) of
+ ok ->
+ BadL;
+ not_ok ->
+ ?t:format("~nTest ~p failed.~n", [N]),
+ fail()
+ end;
+ Bad ->
+ ?t:format("~nTest ~p failed. got~n ~p~n",
+ [N, Bad]),
+ fail()
+ end
+ end,
+ lists:foldl(F, [], Tests).
+
+compile_file(Config, Test0) ->
+ case compile_file(Config, Test0, ['E']) of
+ {ok, RootFile} ->
+ File = RootFile ++ ".E",
+ {ok, Bin0} = file:read_file(File),
+ Bin = strip_module_info(Bin0),
+ %% A very simple check: just try to compile the output.
+ case compile_file(Config, Bin, []) of
+ {ok, RootFile2} ->
+ File2 = RootFile2 ++ ".E",
+ {ok, Bin1} = file:read_file(File2),
+ case Bin0 =:= Bin1 of
+ true ->
+ test_max_line(binary_to_list(Bin));
+ false ->
+ {error, file_contents_modified, {Bin0, Bin1}}
+ end;
+ Error ->
+ {error, could_not_compile_E_file, Error}
+ end;
+ Error ->
+ Error
+ end.
+
+compile_file(Config, Test0, Opts0) ->
+ FileName = filename('erl_pp_test.erl', Config),
+ Test = list_to_binary(["-module(erl_pp_test). "
+ "-compile(export_all). ",
+ Test0]),
+ Opts = [export_all,return,nowarn_unused_record,{outdir,?privdir} | Opts0],
+ ok = file:write_file(FileName, Test),
+ case compile:file(FileName, Opts) of
+ {ok, _M, _Ws} ->
+ {ok, filename:rootname(FileName)};
+ Error -> Error
+ end.
+
+strip_module_info(Bin) ->
+ {match, [{Start,_Len}|_]} = re:run(Bin, "module_info"),
+ <<R:Start/binary,_/binary>> = Bin,
+ R.
+
+flat_expr(Expr) ->
+ lists:flatten(erl_pp:expr(Expr, -1, none)).
+
+pp_forms(Bin) ->
+ pp_forms(Bin, none).
+
+pp_forms(Bin, Hook) ->
+ PP1 = (catch parse_and_pp_forms(binary_to_list(Bin), Hook)),
+ PP2 = (catch parse_and_pp_forms(PP1, Hook)),
+ case PP1 =:= PP2 of % same line numbers
+ true ->
+ test_max_line(PP1);
+ false ->
+ not_ok
+ end.
+
+parse_and_pp_forms(String, Hook) ->
+ lists:append(lists:map(fun(AF) -> erl_pp:form(AF, Hook)
+ end, parse_forms(String))).
+
+parse_forms(Chars) ->
+ String = lists:flatten(Chars),
+ parse_forms2(String, [], 1, []).
+
+parse_forms2([], _Cont, _Line, Forms) ->
+ lists:reverse(Forms);
+parse_forms2(String, Cont0, Line, Forms) ->
+ case erl_scan:tokens(Cont0, String, Line) of
+ {done, {ok, Tokens, EndLine}, Chars} ->
+ {ok, Form} = erl_parse:parse_form(Tokens),
+ parse_forms2(Chars, [], EndLine, [Form | Forms]);
+ {more, Cont} when element(3, Cont) =:= [] ->
+ %% extra spaces after forms...
+ parse_forms2([], Cont, Line, Forms);
+ {more, Cont} ->
+ %% final dot needs a space...
+ parse_forms2(" ", Cont, Line, Forms)
+ end.
+
+pp_expr(Bin) ->
+ pp_expr(Bin, none).
+
+%% Final dot is added.
+pp_expr(Bin, Hook) ->
+ PP1 = (catch parse_and_pp_expr(binary_to_list(Bin), 0, Hook)),
+ PPneg = (catch parse_and_pp_expr(binary_to_list(Bin), -1, Hook)),
+ PP2 = (catch parse_and_pp_expr(PPneg, 0, Hook)),
+ if
+ PP1 =:= PP2 -> % same line numbers
+ case
+ (test_max_line(PP1) =:= ok) and (test_new_line(PPneg) =:= ok)
+ of
+ true ->
+ ok;
+ false ->
+ not_ok
+ end;
+ true ->
+ not_ok
+ end.
+
+parse_and_pp_expr(String, Indent, Hook) ->
+ StringDot = lists:flatten(String) ++ ".",
+ erl_pp:expr(parse_expr(StringDot), Indent, Hook).
+
+parse_expr(Chars) ->
+ {ok, Tokens, _} = erl_scan:string(Chars),
+ {ok, [Expr]} = erl_parse:parse_exprs(Tokens),
+ Expr.
+
+test_new_line(String) ->
+ case string:chr(String, $\n) of
+ 0 -> ok;
+ _ -> not_ok
+ end.
+
+test_max_line(String) ->
+ case max_line(String) of
+ ML when ML > 100 ->
+ {error, max_line_too_big, {ML,String}};
+ _ML ->
+ ok
+ end.
+
+max_line(String) ->
+ lists:max([0 | [length(Sub) ||
+ Sub <- string:tokens(String, "\n"),
+ string:substr(Sub, 1, 5) =/= "-file"]]).
+
+filename(Name, Config) when is_atom(Name) ->
+ filename(atom_to_list(Name), Config);
+filename(Name, Config) ->
+ filename:join(?privdir, Name).
+
+fail() ->
+ io:format("failed~n"),
+ ?t:fail().
diff --git a/lib/stdlib/test/erl_scan_SUITE.erl b/lib/stdlib/test/erl_scan_SUITE.erl
new file mode 100644
index 0000000000..32a06d15c7
--- /dev/null
+++ b/lib/stdlib/test/erl_scan_SUITE.erl
@@ -0,0 +1,1214 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1998-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+
+-module(erl_scan_SUITE).
+-export([all/1]).
+
+-export([error/1, error_1/1, error_2/1, iso88591/1, otp_7810/1]).
+
+-import(lists, [nth/2,flatten/1]).
+-import(io_lib, [print/1]).
+
+%%
+%% Define to run outside of test server
+%%
+%-define(STANDALONE,1).
+
+-ifdef(STANDALONE).
+-compile(export_all).
+-define(line, put(line, ?LINE), ).
+-define(config(A,B),config(A,B)).
+-define(t, test_server).
+%% config(priv_dir, _) ->
+%% ".";
+%% config(data_dir, _) ->
+%% ".".
+-else.
+-include("test_server.hrl").
+-export([init_per_testcase/2, fin_per_testcase/2]).
+
+init_per_testcase(_Case, Config) when is_list(Config) ->
+ ?line Dog=test_server:timetrap(test_server:seconds(1200)),
+ [{watchdog, Dog}|Config].
+
+fin_per_testcase(_Case, Config) ->
+ Dog=?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+-endif.
+
+% Default timetrap timeout (set in init_per_testcase).
+-define(default_timeout, ?t:minutes(1)).
+
+all(doc) ->
+ ["Test cases for the 'erl_scan' module."];
+all(suite) ->
+ [error,iso88591,otp_7810].
+
+error(doc) ->
+ ["Error cases"];
+error(suite) ->
+ [error_1, error_2].
+
+error_1(doc) ->
+ ["(OTP-2347)"];
+error_1(suite) ->
+ [];
+error_1(Config) when is_list(Config) ->
+ ?line {error, _, _} = erl_scan:string("'a"),
+ ok.
+
+error_2(doc) ->
+ ["Checks that format_error works on the error cases."];
+error_2(suite) ->
+ [];
+error_2(Config) when is_list(Config) ->
+ ?line lists:foreach(fun check/1, error_cases()),
+ ok.
+
+error_cases() ->
+ ["'a",
+ "\"a",
+ "'\\",
+ "\"\\",
+ "$",
+ "$\\",
+ "2.3e",
+ "2.3e-",
+ "91#9"
+].
+
+assert_type(N, integer) when is_integer(N) ->
+ ok;
+assert_type(N, atom) when is_atom(N) ->
+ ok.
+
+check(String) ->
+ Error = erl_scan:string(String),
+ check_error(Error, erl_scan).
+
+%%% (This should be useful for all format_error functions.)
+check_error({error, Info, EndLine}, Module0) ->
+ ?line {ErrorLine, Module, Desc} = Info,
+ ?line true = (Module == Module0),
+ ?line assert_type(EndLine, integer),
+ ?line assert_type(ErrorLine, integer),
+ ?line true = (ErrorLine =< EndLine),
+ ?line String = lists:flatten(Module0:format_error(Desc)),
+ ?line true = io_lib:printable_list(String).
+
+iso88591(doc) -> ["Tests the support for ISO-8859-1 i.e Latin-1"];
+iso88591(suite) -> [];
+iso88591(Config) when is_list(Config) ->
+ ?line ok =
+ case catch begin
+ %% Some atom and variable names
+ V1s = [$�,$�,$�,$�],
+ V2s = [$N,$�,$r],
+ A1s = [$h,$�,$r],
+ A2s = [$�,$r,$e],
+ %% Test parsing atom and variable characters.
+ {ok,Ts1,_} = erl_scan:string(V1s ++ " " ++ V2s ++
+ "\327" ++
+ A1s ++ " " ++ A2s),
+ V1s = atom_to_list(element(3, nth(1, Ts1))),
+ V2s = atom_to_list(element(3, nth(2, Ts1))),
+ A1s = atom_to_list(element(3, nth(4, Ts1))),
+ A2s = atom_to_list(element(3, nth(5, Ts1))),
+ %% Test printing atoms
+ A1s = flatten(print(element(3, nth(4, Ts1)))),
+ A2s = flatten(print(element(3, nth(5, Ts1)))),
+ %% Test parsing and printing strings.
+ S1 = V1s ++ "\327" ++ A1s ++ "\250" ++ A2s,
+ S1s = "\"" ++ S1 ++ "\"",
+ {ok,Ts2,_} = erl_scan:string(S1s),
+ S1 = element(3, nth(1, Ts2)),
+ S1s = flatten(print(element(3, nth(1, Ts2)))),
+ ok %It all worked
+ end of
+ {'EXIT',R} -> %Something went wrong!
+ {error,R};
+ ok -> ok %Aok
+ end.
+
+otp_7810(doc) ->
+ ["OTP-7810. White spaces, comments, and more.."];
+otp_7810(suite) ->
+ [];
+otp_7810(Config) when is_list(Config) ->
+ ?line ok = reserved_words(),
+ ?line ok = atoms(),
+ ?line ok = punctuations(),
+ ?line ok = comments(),
+ ?line ok = errors(),
+ ?line ok = integers(),
+ ?line ok = base_integers(),
+ ?line ok = floats(),
+ ?line ok = dots(),
+ ?line ok = chars(),
+ ?line ok = variables(),
+ ?line ok = eof(),
+ ?line ok = illegal(),
+ ?line ok = crashes(),
+
+ ?line ok = options(),
+ ?line ok = token_info(),
+ ?line ok = column_errors(),
+ ?line ok = white_spaces(),
+
+ ?line ok = unicode(),
+
+ ?line ok = more_chars(),
+ ?line ok = more_options(),
+ ?line ok = attributes_info(),
+ ?line ok = set_attribute(),
+
+ ok.
+
+reserved_words() ->
+ L = ['after', 'begin', 'case', 'try', 'cond', 'catch',
+ 'andalso', 'orelse', 'end', 'fun', 'if', 'let', 'of',
+ 'query', 'receive', 'when', 'bnot', 'not', 'div',
+ 'rem', 'band', 'and', 'bor', 'bxor', 'bsl', 'bsr',
+ 'or', 'xor', 'spec'] , % 'spec' shouldn't be there...
+ [begin
+ ?line {RW, true} = {RW, erl_scan:reserved_word(RW)},
+ S = atom_to_list(RW),
+ Ts = [{RW,1}],
+ ?line test_string(S, Ts)
+ end || RW <- L],
+ ok.
+
+
+atoms() ->
+ ?line test_string("a
+ b", [{atom,1,a},{atom,2,b}]),
+ ?line test_string("'a b'", [{atom,1,'a b'}]),
+ ?line test_string("a", [{atom,1,a}]),
+ ?line test_string("a@2", [{atom,1,a@2}]),
+ ?line test_string([39,65,200,39], [{atom,1,'A�'}]),
+ ?line test_string("�rlig �sten", [{atom,1,�rlig},{atom,1,�sten}]),
+ ?line {ok,[{atom,_,'$a'}],{1,6}} =
+ erl_scan:string("'$\\a'", {1,1}),
+ ?line test("'$\\a'"),
+ ok.
+
+punctuations() ->
+ L = ["<<", "<-", "<=", "<", ">>", ">=", ">", "->", "--",
+ "-", "++", "+", "=:=", "=/=", "=<", "==", "=", "/=",
+ "/", "||", "|", ":-", "::", ":"],
+ %% One token at a time:
+ [begin
+ W = list_to_atom(S),
+ Ts = [{W,1}],
+ ?line test_string(S, Ts)
+ end || S <- L],
+ Three = ["/=:=", "<=:=", "==:=", ">=:="], % three tokens...
+ No = Three ++ L,
+ SL0 = [{S1++S2,{-length(S1),S1,S2}} ||
+ S1 <- L,
+ S2 <- L,
+ not lists:member(S1++S2, No)],
+ SL = family_list(SL0),
+ %% Two tokens. When there are several answers, the one with
+ %% the longest first token is chosen:
+ %% [the special case "=<<" is among the tested ones]
+ [begin
+ W1 = list_to_atom(S1),
+ W2 = list_to_atom(S2),
+ Ts = [{W1,1},{W2,1}],
+ ?line test_string(S, Ts)
+ end || {S,[{_,S1,S2}|_]} <- SL],
+
+ PTs1 = [{'!',1},{'(',1},{')',1},{',',1},{';',1},{'=',1},{'[',1},
+ {']',1},{'{',1},{'|',1},{'}',1}],
+ ?line test_string("!(),;=[]{|}", PTs1),
+
+ PTs2 = [{'#',1},{'&',1},{'*',1},{'+',1},{'/',1},
+ {':',1},{'<',1},{'>',1},{'?',1},{'@',1},
+ {'\\',1},{'^',1},{'`',1},{'~',1}],
+ ?line test_string("#&*+/:<>?@\\^`~", PTs2),
+
+ ok.
+
+comments() ->
+ ?line test("a %%\n b"),
+ ?line {ok,[],1} = erl_scan:string("%"),
+ ?line test("a %%\n b"),
+ ?line {ok,[{atom,_,a},{atom,_,b}],{2,3}} =
+ erl_scan:string("a %%\n b",{1,1}),
+ ?line {ok,[{atom,_,a},{comment,_,"%%"},{atom,_,b}],{2,3}} =
+ erl_scan:string("a %%\n b",{1,1}, [return_comments]),
+ ?line {ok,[{atom,_,a},
+ {white_space,_," "},
+ {white_space,_,"\n "},
+ {atom,_,b}],
+ {2,3}} =
+ erl_scan:string("a %%\n b",{1,1},[return_white_spaces]),
+ ?line {ok,[{atom,_,a},
+ {white_space,_," "},
+ {comment,_,"%%"},
+ {white_space,_,"\n "},
+ {atom,_,b}],
+ {2,3}} = erl_scan:string("a %%\n b",{1,1},[return]),
+ ok.
+
+errors() ->
+ ?line {error,{1,erl_scan,{string,$',"qa"}},1} = erl_scan:string("'qa"), %'
+ ?line {error,{1,erl_scan,{string,$","str"}},1} = %"
+ erl_scan:string("\"str"), %"
+ ?line {error,{1,erl_scan,char},1} = erl_scan:string("$"),
+ ?line test_string([34,65,200,34], [{string,1,"A�"}]),
+ ?line test_string("\\", [{'\\',1}]),
+ ?line {'EXIT',_} =
+ (catch {foo, erl_scan:string('$\\a', {1,1})}), % type error
+ ?line {'EXIT',_} =
+ (catch {foo, erl_scan:tokens([], '$\\a', {1,1})}), % type error
+
+ ?line "{a,tuple}" = erl_scan:format_error({a,tuple}),
+ ok.
+
+integers() ->
+ [begin
+ I = list_to_integer(S),
+ Ts = [{integer,1,I}],
+ ?line test_string(S, Ts)
+ end || S <- [[N] || N <- lists:seq($0, $9)] ++ ["2323","000"] ],
+ ok.
+
+base_integers() ->
+ [begin
+ B = list_to_integer(BS),
+ I = erlang:list_to_integer(S, B),
+ Ts = [{integer,1,I}],
+ ?line test_string(BS++"#"++S, Ts)
+ end || {BS,S} <- [{"2","11"}, {"5","23234"}, {"12","05a"},
+ {"16","abcdef"}, {"16","ABCDEF"}] ],
+
+ ?line {error,{1,erl_scan,{base,1}},1} = erl_scan:string("1#000"),
+
+ ?line test_string("12#bc", [{integer,1,11},{atom,1,c}]),
+
+ [begin
+ Str = BS ++ "#" ++ S,
+ ?line {error,{1,erl_scan,{illegal,integer}},1} =
+ erl_scan:string(Str)
+ end || {BS,S} <- [{"3","3"},{"15","f"}, {"12","c"}] ],
+
+ ?line {ok,[{integer,1,239},{'@',1}],1} = erl_scan:string("16#ef@"),
+ ?line {ok,[{integer,1,14},{atom,1,g@}],1} = erl_scan:string("16#eg@"),
+
+ ok.
+
+floats() ->
+ [begin
+ F = list_to_float(FS),
+ Ts = [{float,1,F}],
+ ?line test_string(FS, Ts)
+ end || FS <- ["1.0","001.17","3.31200","1.0e0","1.0E17",
+ "34.21E-18", "17.0E+14"]],
+ ?line test_string("1.e2", [{integer,1,1},{'.',1},{atom,1,e2}]),
+
+ ?line {error,{1,erl_scan,{illegal,float}},1} =
+ erl_scan:string("1.0e400"),
+ [begin
+ ?line {error,{1,erl_scan,{illegal,float}},1} = erl_scan:string(S)
+ end || S <- ["1.14Ea"]],
+
+ ok.
+
+dots() ->
+ Dot = [{".", {ok,[{dot,1}],1}},
+ {". ", {ok,[{dot,1}],1}},
+ {".\n", {ok,[{dot,1}],2}},
+ {".%", {ok,[{dot,1}],1}},
+ {".\210",{ok,[{dot,1}],1}},
+ {".% �h",{ok,[{dot,1}],1}},
+ {".%\n", {ok,[{dot,1}],2}},
+ {".$", {error,{1,erl_scan,char},1}},
+ {".$\\", {error,{1,erl_scan,char},1}},
+ {".a", {ok,[{'.',1},{atom,1,a}],1}}
+ ],
+ ?line [R = erl_scan:string(S) || {S, R} <- Dot],
+
+ ?line {ok,[{dot,_}=T1],{1,2}} = erl_scan:string(".", {1,1}, text),
+ ?line [{column,1},{length,1},{line,1},{text,"."}] =
+ erl_scan:token_info(T1, [column, length, line, text]),
+ ?line {ok,[{dot,_}=T2],{1,3}} = erl_scan:string(".%", {1,1}, text),
+ ?line [{column,1},{length,1},{line,1},{text,"."}] =
+ erl_scan:token_info(T2, [column, length, line, text]),
+ ?line {ok,[{dot,_}=T3],{1,6}} =
+ erl_scan:string(".% �h", {1,1}, text),
+ ?line [{column,1},{length,1},{line,1},{text,"."}] =
+ erl_scan:token_info(T3, [column, length, line, text]),
+ ?line {error,{{1,2},erl_scan,char},{1,3}} =
+ erl_scan:string(".$", {1,1}),
+ ?line {error,{{1,2},erl_scan,char},{1,4}} =
+ erl_scan:string(".$\\", {1,1}),
+
+ ?line test(". "),
+ ?line test(". "),
+ ?line test(".\n"),
+ ?line test(".\n\n"),
+ ?line test(".\n\r"),
+ ?line test(".\n\n\n"),
+ ?line test(".\210"),
+ ?line test(".%\n"),
+ ?line test(".a"),
+
+ ?line test("%. \n. "),
+ ?line {more,C} = erl_scan:tokens([], "%. ",{1,1}, return),
+ ?line {done,{ok,[{comment,_,"%. "},
+ {white_space,_,"\n"},
+ {dot,_}],
+ {2,3}}, ""} =
+ erl_scan:tokens(C, "\n. ", {1,1}, return), % any loc, any options
+
+ ?line [test_string(S, R) ||
+ {S, R} <- [{".$\n", [{'.',1},{char,1,$\n}]},
+ {"$\\\n", [{char,1,$\n}]},
+ {"'\\\n'", [{atom,1,'\n'}]},
+ {"$\n", [{char,1,$\n}]}] ],
+ ok.
+
+chars() ->
+ [begin
+ L = lists:flatten(io_lib:format("$\\~.8b", [C])),
+ Ts = [{char,1,C}],
+ ?line test_string(L, Ts)
+ end || C <- lists:seq(0, 255)],
+
+ %% Leading zeroes...
+ [begin
+ L = lists:flatten(io_lib:format("$\\~3.8.0b", [C])),
+ Ts = [{char,1,C}],
+ ?line test_string(L, Ts)
+ end || C <- lists:seq(0, 255)],
+
+ %% $\^\n now increments the line...
+ [begin
+ L = "$\\^" ++ [C],
+ Ts = [{char,1,C band 2#11111}],
+ ?line test_string(L, Ts)
+ end || C <- lists:seq(0, 255)],
+
+ [begin
+ L = "$\\" ++ [C],
+ Ts = [{char,1,V}],
+ ?line test_string(L, Ts)
+ end || {C,V} <- [{$n,$\n}, {$r,$\r}, {$t,$\t}, {$v,$\v},
+ {$b,$\b}, {$f,$\f}, {$e,$\e}, {$s,$\s},
+ {$d,$\d}]],
+
+ EC = [$\n,$\r,$\t,$\v,$\b,$\f,$\e,$\s,$\d],
+ Ds = lists:seq($0, $9),
+ X = [$^,$n,$r,$t,$v,$b,$f,$e,$s,$d],
+ New = [${,$x],
+ No = EC ++ Ds ++ X ++ New,
+ [begin
+ L = "$\\" ++ [C],
+ Ts = [{char,1,C}],
+ ?line test_string(L, Ts)
+ end || C <- lists:seq(0, 255) -- No],
+
+ [begin
+ L = "'$\\" ++ [C] ++ "'",
+ Ts = [{atom,1,list_to_atom("$"++[C])}],
+ ?line test_string(L, Ts)
+ end || C <- lists:seq(0, 255) -- No],
+
+ ?line test_string("\"\\013a\\\n\"", [{string,1,"\va\n"}]),
+
+ ?line test_string("'\n'", [{atom,1,'\n'}]),
+ ?line test_string("\"\n\a\"", [{string,1,"\na"}]),
+
+ %% No escape
+ [begin
+ L = "$" ++ [C],
+ Ts = [{char,1,C}],
+ ?line test_string(L, Ts)
+ end || C <- lists:seq(0, 255) -- (No ++ [$\\])],
+ ?line test_string("$\n", [{char,1,$\n}]),
+
+ ?line {error,{{1,1},erl_scan,char},{1,4}} =
+ erl_scan:string("$\\^",{1,1}),
+ ?line test_string("$\\\n", [{char,1,$\n}]),
+ %% Robert's scanner returns line 1:
+ ?line test_string("$\\\n", [{char,1,$\n}]),
+ ?line test_string("$\n\n", [{char,1,$\n}]),
+ ?line test("$\n\n"),
+ ok.
+
+
+variables() ->
+ ?line test_string(" \237_Aou�eiy��", [{var,1,'_Aou�eiy��'}]),
+ ?line test_string("A_b_c@", [{var,1,'A_b_c@'}]),
+ ?line test_string("V@2", [{var,1,'V@2'}]),
+ ?line test_string("ABD�", [{var,1,'ABD�'}]),
+ ?line test_string("�rlig �sten", [{var,1,'�rlig'},{var,1,'�sten'}]),
+ ok.
+
+eof() ->
+ ?line {done,{eof,1},eof} = erl_scan:tokens([], eof, 1),
+ {more, C1} = erl_scan:tokens([]," \n", 1),
+ ?line {done,{eof,2},eof} = erl_scan:tokens(C1, eof, 1),
+ {more, C2} = erl_scan:tokens([], "abra", 1),
+ %% An error before R13A.
+ %% ?line {done,Err={error,{1,erl_scan,scan},1},eof} =
+ ?line {done,{ok,[{atom,1,abra}],1},eof} =
+ erl_scan:tokens(C2, eof, 1),
+
+ %% With column.
+ ?line {more, C3} = erl_scan:tokens([]," \n",{1,1}),
+ ?line {done,{eof,{2,1}},eof} = erl_scan:tokens(C3, eof, 1),
+ {more, C4} = erl_scan:tokens([], "abra", {1,1}),
+ %% An error before R13A.
+ %% ?line {done,{error,{{1,1},erl_scan,scan},{1,5}},eof} =
+ ?line {done,{ok,[{atom,_,abra}],{1,5}},eof} =
+ erl_scan:tokens(C4, eof, 1),
+
+ %% Robert's scanner returns "" as LeftoverChars;
+ %% the R12B scanner returns eof as LeftoverChars: (eof is correct)
+ ?line {more, C5} = erl_scan:tokens([], "a", 1),
+ %% An error before R13A.
+ %% ?line {done,{error,{1,erl_scan,scan},1},eof} =
+ ?line {done,{ok,[{atom,1,a}],1},eof} =
+ erl_scan:tokens(C5,eof,1),
+
+ %% A dot followed by eof is special:
+ ?line {more, C} = erl_scan:tokens([], "a.", 1),
+ ?line {done,{ok,[{atom,1,a},{dot,1}],1},eof} = erl_scan:tokens(C,eof,1),
+ ?line {ok,[{atom,1,foo},{dot,1}],1} = erl_scan:string("foo."),
+
+ ok.
+
+illegal() ->
+ Atom = lists:duplicate(1000, $a),
+ ?line {error,{1,erl_scan,{illegal,atom}},1} = erl_scan:string(Atom),
+ ?line {done,{error,{1,erl_scan,{illegal,atom}},1},". "} =
+ erl_scan:tokens([], Atom++". ", 1),
+ QAtom = "'" ++ Atom ++ "'",
+ ?line {error,{1,erl_scan,{illegal,atom}},1} = erl_scan:string(QAtom),
+ ?line {done,{error,{1,erl_scan,{illegal,atom}},1},". "} =
+ erl_scan:tokens([], QAtom++". ", 1),
+ Var = lists:duplicate(1000, $A),
+ ?line {error,{1,erl_scan,{illegal,var}},1} = erl_scan:string(Var),
+ ?line {done,{error,{1,erl_scan,{illegal,var}},1},". "} =
+ erl_scan:tokens([], Var++". ", 1),
+ Float = "1" ++ lists:duplicate(400, $0) ++ ".0",
+ ?line {error,{1,erl_scan,{illegal,float}},1} = erl_scan:string(Float),
+ ?line {done,{error,{1,erl_scan,{illegal,float}},1},". "} =
+ erl_scan:tokens([], Float++". ", 1),
+ String = "\"43\\x{aaaaaa}34\"",
+ ?line {error,{1,erl_scan,{illegal,character}},1} = erl_scan:string(String),
+ ?line {done,{error,{1,erl_scan,{illegal,character}},1},"34\". "} =
+ %% Would be nice if `34\"' were skipped...
+ %% Maybe, but then the LeftOverChars would not be the characters
+ %% immediately following the end location of the error.
+ erl_scan:tokens([], String++". ", 1),
+
+ ?line {error,{{1,1},erl_scan,{illegal,atom}},{1,1001}} =
+ erl_scan:string(Atom, {1,1}),
+ ?line {done,{error,{{1,5},erl_scan,{illegal,atom}},{1,1005}},". "} =
+ erl_scan:tokens([], "foo "++Atom++". ", {1,1}),
+ ?line {error,{{1,1},erl_scan,{illegal,atom}},{1,1003}} =
+ erl_scan:string(QAtom, {1,1}),
+ ?line {done,{error,{{1,5},erl_scan,{illegal,atom}},{1,1007}},". "} =
+ erl_scan:tokens([], "foo "++QAtom++". ", {1,1}),
+ ?line {error,{{1,1},erl_scan,{illegal,var}},{1,1001}} =
+ erl_scan:string(Var, {1,1}),
+ ?line {done,{error,{{1,5},erl_scan,{illegal,var}},{1,1005}},". "} =
+ erl_scan:tokens([], "foo "++Var++". ", {1,1}),
+ ?line {error,{{1,1},erl_scan,{illegal,float}},{1,404}} =
+ erl_scan:string(Float, {1,1}),
+ ?line {done,{error,{{1,5},erl_scan,{illegal,float}},{1,408}},". "} =
+ erl_scan:tokens([], "foo "++Float++". ", {1,1}),
+ ?line {error,{{1,4},erl_scan,{illegal,character}},{1,14}} =
+ erl_scan:string(String, {1,1}),
+ ?line {done,{error,{{1,4},erl_scan,{illegal,character}},{1,14}},"34\". "} =
+ erl_scan:tokens([], String++". ", {1,1}),
+ ok.
+
+crashes() ->
+ ?line {'EXIT',_} = (catch {foo, erl_scan:string([-1])}), % type error
+ ?line {'EXIT',_} = (catch {foo, erl_scan:string("$"++[-1])}),
+ ?line {'EXIT',_} = (catch {foo, erl_scan:string("$\\"++[-1])}),
+ ?line {'EXIT',_} = (catch {foo, erl_scan:string("$\\^"++[-1])}),
+ ?line {'EXIT',_} = (catch {foo, erl_scan:string([$",-1,$"],{1,1})}),
+ ?line {'EXIT',_} = (catch {foo, erl_scan:string("\"\\v"++[-1,$"])}), %$"
+ ?line {'EXIT',_} = (catch {foo, erl_scan:string([$",-1,$"])}),
+ ?line {'EXIT',_} = (catch {foo, erl_scan:string("% foo"++[-1])}),
+ ?line {'EXIT',_} =
+ (catch {foo, erl_scan:string("% foo"++[-1],{1,1})}),
+
+ ?line {'EXIT',_} = (catch {foo, erl_scan:string([a])}), % type error
+ ?line {'EXIT',_} = (catch {foo, erl_scan:string("$"++[a])}),
+ ?line {'EXIT',_} = (catch {foo, erl_scan:string("$\\"++[a])}),
+ ?line {'EXIT',_} = (catch {foo, erl_scan:string("$\\^"++[a])}),
+ ?line {'EXIT',_} = (catch {foo, erl_scan:string([$",a,$"],{1,1})}),
+ ?line {'EXIT',_} = (catch {foo, erl_scan:string("\"\\v"++[a,$"])}), %$"
+ ?line {'EXIT',_} = (catch {foo, erl_scan:string([$",a,$"])}),
+ ?line {'EXIT',_} = (catch {foo, erl_scan:string("% foo"++[a])}),
+ ?line {'EXIT',_} =
+ (catch {foo, erl_scan:string("% foo"++[a],{1,1})}),
+
+ ?line {'EXIT',_} = (catch {foo, erl_scan:string([3.0])}), % type error
+
+ ok.
+
+options() ->
+ %% line and column are not options, but tested here
+ ?line {ok,[{atom,1,foo},{white_space,1," "},{comment,1,"% bar"}], 1} =
+ erl_scan:string("foo % bar", 1, return),
+ ?line {ok,[{atom,1,foo},{white_space,1," "}],1} =
+ erl_scan:string("foo % bar", 1, return_white_spaces),
+ ?line {ok,[{atom,1,foo},{comment,1,"% bar"}],1} =
+ erl_scan:string("foo % bar", 1, return_comments),
+ ?line {ok,[{atom,17,foo}],17} =
+ erl_scan:string("foo % bar", 17),
+ ?line {'EXIT',{function_clause,_}} =
+ (catch {foo,
+ erl_scan:string("foo % bar", {a,1}, [])}), % type error
+ ?line {ok,[{atom,_,foo}],{17,18}} =
+ erl_scan:string("foo % bar", {17,9}, []),
+ ?line {'EXIT',{function_clause,_}} =
+ (catch {foo,
+ erl_scan:string("foo % bar", {1,0}, [])}), % type error
+ ?line {ok,[{foo,1}],1} =
+ erl_scan:string("foo % bar",1, [{reserved_word_fun,
+ fun(W) -> W =:= foo end}]),
+ ?line {'EXIT',{badarg,_}} =
+ (catch {foo,
+ erl_scan:string("foo % bar",1, % type error
+ [{reserved_word_fun,
+ fun(W,_) -> W =:= foo end}])}),
+ ok.
+
+more_options() ->
+ ?line {ok,[{atom,A1,foo}],{19,20}} =
+ erl_scan:string("foo", {19,17},[]),
+ ?line [{column,17},{line,19}] = erl_scan:attributes_info(A1),
+ ?line {done,{ok,[{atom,A2,foo},{dot,_}],{19,22}},[]} =
+ erl_scan:tokens([], "foo. ", {19,17}, [bad_opt]), % type error
+ ?line [{column,17},{line,19}] = erl_scan:attributes_info(A2),
+ ?line {ok,[{atom,A3,foo}],{19,20}} =
+ erl_scan:string("foo", {19,17},[text]),
+ ?line [{column,17},{length,3},{line,19},{text,"foo"}] =
+ erl_scan:attributes_info(A3),
+
+ ?line {ok,[{atom,A4,foo}],1} = erl_scan:string("foo", 1, [text]),
+ ?line [{length,3},{line,1},{text,"foo"}] = erl_scan:attributes_info(A4),
+
+ ok.
+
+token_info() ->
+ ?line {ok,[T1],_} = erl_scan:string("foo", {1,18}, [text]),
+ {'EXIT',{badarg,_}} =
+ (catch {foo, erl_scan:token_info(T1, foo)}), % type error
+ ?line {line,1} = erl_scan:token_info(T1, line),
+ ?line {column,18} = erl_scan:token_info(T1, column),
+ ?line {length,3} = erl_scan:token_info(T1, length),
+ ?line {text,"foo"} = erl_scan:token_info(T1, text),
+ ?line [{category,atom},{column,18},{length,3},{line,1},
+ {symbol,foo},{text,"foo"}] =
+ erl_scan:token_info(T1),
+ ?line [{length,3},{column,18}] =
+ erl_scan:token_info(T1, [length, column]),
+ ?line [{location,{1,18}}] =
+ erl_scan:token_info(T1, [location]),
+ ?line {category,atom} = erl_scan:token_info(T1, category),
+ ?line [{symbol,foo}] = erl_scan:token_info(T1, [symbol]),
+
+ ?line {ok,[T2],_} = erl_scan:string("foo", 1, []),
+ ?line {line,1} = erl_scan:token_info(T2, line),
+ ?line undefined = erl_scan:token_info(T2, column),
+ ?line undefined = erl_scan:token_info(T2, length),
+ ?line undefined = erl_scan:token_info(T2, text),
+ ?line {location,1} = erl_scan:token_info(T2, location),
+ ?line [{category,atom},{line,1},{symbol,foo}] = erl_scan:token_info(T2),
+ ?line [{line,1}] = erl_scan:token_info(T2, [length, line]),
+
+ ?line {ok,[T3],_} = erl_scan:string("=", 1, []),
+ ?line [{line,1}] = erl_scan:token_info(T3, [column, line]),
+ ?line {category,'='} = erl_scan:token_info(T3, category),
+ ?line [{symbol,'='}] = erl_scan:token_info(T3, [symbol]),
+ ok.
+
+attributes_info() ->
+ ?line {'EXIT',_} =
+ (catch {foo,erl_scan:attributes_info(foo)}), % type error
+ ?line [{line,18}] = erl_scan:attributes_info(18),
+ ?line {location,19} = erl_scan:attributes_info(19, location),
+ ?line {ok,[{atom,A0,foo}],_} = erl_scan:string("foo", 19, [text]),
+ ?line {location,19} = erl_scan:attributes_info(A0, location),
+
+ ?line {ok,[{atom,A3,foo}],_} = erl_scan:string("foo", {1,3}, [text]),
+ ?line {line,1} = erl_scan:attributes_info(A3, line),
+ ?line {column,3} = erl_scan:attributes_info(A3, column),
+ ?line {location,{1,3}} = erl_scan:attributes_info(A3, location),
+ ?line {text,"foo"} = erl_scan:attributes_info(A3, text),
+
+ ?line {ok,[{atom,A4,foo}],_} = erl_scan:string("foo", 2, [text]),
+ ?line {line,2} = erl_scan:attributes_info(A4, line),
+ ?line undefined = erl_scan:attributes_info(A4, column),
+ ?line {location,2} = erl_scan:attributes_info(A4, location),
+ ?line {text,"foo"} = erl_scan:attributes_info(A4, text),
+
+ ?line {ok,[{atom,A5,foo}],_} = erl_scan:string("foo", {1,3}, []),
+ ?line {line,1} = erl_scan:attributes_info(A5, line),
+ ?line {column,3} = erl_scan:attributes_info(A5, column),
+ ?line {location,{1,3}} = erl_scan:attributes_info(A5, location),
+ ?line undefined = erl_scan:attributes_info(A5, text),
+
+ ?line undefined = erl_scan:attributes_info([], line), % type error
+
+ ok.
+
+set_attribute() ->
+ F = fun(Line) -> -Line end,
+ ?line -2 = erl_scan:set_attribute(line, 2, F),
+ ?line {ok,[{atom,A1,foo}],_} = erl_scan:string("foo", {9,17}),
+ ?line A2 = erl_scan:set_attribute(line, A1, F),
+ ?line {line,-9} = erl_scan:attributes_info(A2, line),
+ ?line {location,{-9,17}} = erl_scan:attributes_info(A2, location),
+ ?line [{line,-9},{column,17}] =
+ erl_scan:attributes_info(A2, [line,column,text]),
+
+ F2 = fun(Line) -> {17,Line} end,
+ ?line Attr1 = erl_scan:set_attribute(line, 2, F2),
+ ?line {line,{17,2}} = erl_scan:attributes_info(Attr1, line),
+ ?line undefined = erl_scan:attributes_info(Attr1, column),
+ ?line {location,{17,2}} = % a bit mixed up
+ erl_scan:attributes_info(Attr1, location),
+
+ ?line A3 = erl_scan:set_attribute(line, A1, F2),
+ ?line {line,{17,9}} = erl_scan:attributes_info(A3, line),
+ ?line {location,{{17,9},17}} = erl_scan:attributes_info(A3, location),
+ ?line [{line,{17,9}},{column,17}] =
+ erl_scan:attributes_info(A3, [line,column,text]),
+
+ ?line {ok,[{atom,A4,foo}],_} = erl_scan:string("foo", {9,17}, [text]),
+ ?line A5 = erl_scan:set_attribute(line, A4, F),
+ ?line {line,-9} = erl_scan:attributes_info(A5, line),
+ ?line {location,{-9,17}} = erl_scan:attributes_info(A5, location),
+ ?line [{line,-9},{column,17},{text,"foo"}] =
+ erl_scan:attributes_info(A5, [line,column,text]),
+
+ ?line {ok,[{atom,A6,foo}],_} = erl_scan:string("foo", 11, [text]),
+ ?line A7 = erl_scan:set_attribute(line, A6, F2),
+ ?line {line,{17,11}} = erl_scan:attributes_info(A7, line),
+ ?line {location,{17,11}} = % mixed up
+ erl_scan:attributes_info(A7, location),
+ ?line [{line,{17,11}},{text,"foo"}] =
+ erl_scan:attributes_info(A7, [line,column,text]),
+
+ ?line {'EXIT',_} =
+ (catch {foo, erl_scan:set_attribute(line, [], F2)}), % type error
+ ?line {'EXIT',{badarg,_}} =
+ (catch {foo, erl_scan:set_attribute(column, [], F2)}), % type error
+ ok.
+
+column_errors() ->
+ ?line {error,{{1,1},erl_scan,{string,$',""}},{1,3}} = % $'
+ erl_scan:string("'\\",{1,1}),
+ ?line {error,{{1,1},erl_scan,{string,$",""}},{1,3}} = % $"
+ erl_scan:string("\"\\",{1,1}),
+
+ ?line {error,{{1,1},erl_scan,{string,$',""}},{1,2}} = % $'
+ erl_scan:string("'",{1,1}),
+ ?line {error,{{1,1},erl_scan,{string,$",""}},{1,2}} = % $"
+ erl_scan:string("\"",{1,1}),
+
+ ?line {error,{{1,1},erl_scan,char},{1,2}} =
+ erl_scan:string("$",{1,1}),
+
+ ?line {error,{{1,2},erl_scan,{string,$',"1234567890123456"}},{1,20}} = %'
+ erl_scan:string(" '12345678901234567", {1,1}),
+ ?line {error,{{1,2},erl_scan,{string,$',"123456789012345 "}}, {1,20}} = %'
+ erl_scan:string(" '123456789012345\\s", {1,1}),
+ ?line {error,{{1,2},erl_scan,{string,$","1234567890123456"}},{1,20}} = %"
+ erl_scan:string(" \"12345678901234567", {1,1}),
+ ?line {error,{{1,2},erl_scan,{string,$","123456789012345 "}}, {1,20}} = %"
+ erl_scan:string(" \"123456789012345\\s", {1,1}),
+ ?line {error,{{1,2},erl_scan,{string,$',"1234567890123456"}},{2,1}} = %'
+ erl_scan:string(" '12345678901234567\n", {1,1}),
+ ok.
+
+white_spaces() ->
+ ?line {ok,[{white_space,_,"\r"},
+ {white_space,_," "},
+ {atom,_,a},
+ {white_space,_,"\n"}],
+ _} = erl_scan:string("\r a\n", {1,1}, return),
+ ?line test("\r a\n"),
+ L = "{\"a\nb\", \"a\\nb\",\nabc\r,def}.\n\n",
+ ?line {ok,[{'{',_},
+ {string,_,"a\nb"},
+ {',',_},
+ {white_space,_," "},
+ {string,_,"a\nb"},
+ {',',_},
+ {white_space,_,"\n"},
+ {atom,_,abc},
+ {white_space,_,"\r"},
+ {',',_},
+ {atom,_,def},
+ {'}',_},
+ {dot,_},
+ {white_space,_,"\n"}],
+ _} = erl_scan:string(L, {1,1}, return),
+ ?line test(L),
+ ?line test("\"\n\"\n"),
+ ?line test("\n\r\n"),
+ ?line test("\n\r"),
+ ?line test("\r\n"),
+ ?line test("\n\f"),
+ ?line [test(lists:duplicate(N, $\t)) || N <- lists:seq(1, 20)],
+ ?line [test([$\n|lists:duplicate(N, $\t)]) || N <- lists:seq(1, 20)],
+ ?line [test(lists:duplicate(N, $\s)) || N <- lists:seq(1, 20)],
+ ?line [test([$\n|lists:duplicate(N, $\s)]) || N <- lists:seq(1, 20)],
+ ?line test("\v\f\n\v "),
+ ?line test("\n\e\n\b\f\n\da\n"),
+ ok.
+
+unicode() ->
+ ?line {ok,[{char,1,83},{integer,1,45}],1} =
+ erl_scan:string("$\\12345"), % not unicode
+
+ ?line {error,{1,erl_scan,{illegal,character}},1} =
+ erl_scan:string([1089]),
+ ?line {error,{{1,1},erl_scan,{illegal,character}},{1,2}} =
+ erl_scan:string([1089], {1,1}),
+ ?line {error,{1,erl_scan,{illegal,character}},1} =
+ %% ?line {error,{1,erl_scan,{illegal,atom}},1} =
+ erl_scan:string("'a"++[1089]++"b'"),
+ ?line {error,{{1,3},erl_scan,{illegal,character}},{1,4}} =
+ erl_scan:string("'a"++[1089]++"b'", {1,1}),
+ ?line test("\"a"++[1089]++"b\""),
+ ?line {ok,[{char,1,1}],1} = erl_scan:string([$$,$\\,$^,1089]),
+
+ ?line {error,{1,erl_scan,Error},1} = erl_scan:string("\"qa\x{aaa}"),
+ ?line "unterminated string starting with \"qa\\x{AAA}\"" =
+ erl_scan:format_error(Error),
+ ?line {error,{{1,1},erl_scan,_},{1,11}} =
+ erl_scan:string("\"qa\\x{aaa}",{1,1}),
+ ?line {error,{{1,4},erl_scan,{illegal,character}},{1,11}} =
+ erl_scan:string("'qa\\x{aaa}'",{1,1}),
+
+ Tags = [category, column, length, line, symbol, text],
+
+ %% Workaround. No character codes greater than 255! To be changed.
+ %% Note: don't remove these tests, just modify them!
+
+ ?line {ok,[{integer,1,1089}],1} = erl_scan:string([$$,1089]),
+ ?line {ok,[{integer,1,1089}],1} = erl_scan:string([$$,$\\,1089]),
+
+ Qs = "$\\x{aaa}",
+ ?line {ok,[{integer,1,16#aaa}],1} = erl_scan:string(Qs),
+ ?line {ok,[Q2],{1,9}} = erl_scan:string("$\\x{aaa}", {1,1}, text),
+ ?line [{category,integer},{column,1},{length,8},
+ {line,1},{symbol,16#aaa},{text,Qs}] =
+ erl_scan:token_info(Q2),
+
+ U1 = "\"\\x{aaa}\"",
+ ?line {ok,[T1,T2,T3],{1,10}} = erl_scan:string(U1, {1,1}, text),
+ ?line [{category,'['},{column,1},{length,1},{line,1},
+ {symbol,'['},{text,"\""}] = erl_scan:token_info(T1, Tags),
+ ?line [{category,integer},{column,2},{length,7},
+ {line,1},{symbol,16#aaa},{text,"\\x{aaa}"}] =
+ erl_scan:token_info(T2, Tags),
+ ?line [{category,']'},{column,9},{length,1},{line,1},
+ {symbol,']'},{text,"\""}] = erl_scan:token_info(T3, Tags),
+ ?line {ok,[{'[',1},{integer,1,16#aaa},{']',1}],1} =
+ erl_scan:string(U1, 1),
+
+ U2 = "\"\\x41\\x{fff}\\x42\"",
+ ?line {ok,[{'[',1},{char,1,16#41},{',',1},{integer,1,16#fff},
+ {',',1},{char,1,16#42},{']',1}],1} = erl_scan:string(U2, 1),
+
+ U3 = "\"a\n\\x{fff}\n\"",
+ ?line {ok,[{'[',1},{char,1,$a},{',',1},{char,1,$\n},
+ {',',2},{integer,2,16#fff},{',',2},{char,2,$\n},
+ {']',3}],3} =
+ erl_scan:string(U3, 1),
+
+ U4 = "\"\\^\n\\x{aaa}\\^\n\"",
+ ?line {ok,[{'[',1},{char,1,$\n},{',',2},{integer,2,16#aaa},
+ {',',2},{char,2,$\n},{']',3}],3} = erl_scan:string(U4, 1),
+
+ %% Keep these tests:
+ ?line test(Qs),
+ ?line test(U1),
+ ?line test(U2),
+ ?line test(U3),
+ ?line test(U4),
+
+ Str1 = "\"ab" ++ [1089] ++ "cd\"",
+ ?line {ok,[{'[',1},{char,1,$a},{',',1},{char,1,$b},{',',1},
+ {integer,1,1089},{',',1},{char,1,$c},{',',1},
+ {char,1,$d},{']',1}],1} = erl_scan:string(Str1),
+ ?line {ok,[{'[',_},{char,_,$a},{',',_},{char,_,$b},{',',_},
+ {integer,_,1089},{',',_},{char,_,$c},{',',_},
+ {char,_,$d},{']',_}],{1,8}} = erl_scan:string(Str1, {1,1}),
+ ?line test(Str1),
+ Comment = "%% "++[1089],
+ ?line {ok,[{comment,1,[$%,$%,$\s,1089]}],1} =
+ erl_scan:string(Comment, 1, return),
+ ?line {ok,[{comment,_,[$%,$%,$\s,1089]}],{1,5}} =
+ erl_scan:string(Comment, {1,1}, return),
+ ok.
+
+more_chars() ->
+ %% Due to unicode, the syntax has been incompatibly augmented:
+ %% $\x{...}, $\xHH
+
+ %% All kinds of tests...
+ ?line {ok,[{char,_,123}],{1,4}} =
+ erl_scan:string("$\\{",{1,1}),
+ ?line {more, C1} = erl_scan:tokens([], "$\\{", {1,1}),
+ ?line {done,{ok,[{char,_,123}],{1,4}},eof} =
+ erl_scan:tokens(C1, eof, 1),
+ ?line {ok,[{char,1,123},{atom,1,a},{'}',1}],1} =
+ erl_scan:string("$\\{a}"),
+
+ ?line {error,{{1,1},erl_scan,char},{1,4}} =
+ erl_scan:string("$\\x", {1,1}),
+ ?line {error,{{1,1},erl_scan,char},{1,5}} =
+ erl_scan:string("$\\x{",{1,1}),
+ ?line {more, C3} = erl_scan:tokens([], "$\\x", {1,1}),
+ ?line {done,{error,{{1,1},erl_scan,char},{1,4}},eof} =
+ erl_scan:tokens(C3, eof, 1),
+ ?line {error,{{1,1},erl_scan,char},{1,5}} =
+ erl_scan:string("$\\x{",{1,1}),
+ ?line {more, C2} = erl_scan:tokens([], "$\\x{", {1,1}),
+ ?line {done,{error,{{1,1},erl_scan,char},{1,5}},eof} =
+ erl_scan:tokens(C2, eof, 1),
+ ?line {error,{1,erl_scan,{illegal,character}},1} =
+ erl_scan:string("$\\x{g}"),
+ ?line {error,{{1,1},erl_scan,{illegal,character}},{1,5}} =
+ erl_scan:string("$\\x{g}", {1,1}),
+ ?line {error,{{1,1},erl_scan,{illegal,character}},{1,6}} =
+ erl_scan:string("$\\x{}",{1,1}),
+
+ ?line test("\"\\{0}\""),
+ ?line test("\"\\x{0}\""),
+ ?line test("\'\\{0}\'"),
+ ?line test("\'\\x{0}\'"),
+
+ ?line {error,{{2,3},erl_scan,{illegal,character}},{2,6}} =
+ erl_scan:string("\"ab \n $\\x{g}\"",{1,1}),
+ ?line {error,{{2,3},erl_scan,{illegal,character}},{2,6}} =
+ erl_scan:string("\'ab \n $\\x{g}\'",{1,1}),
+
+ ?line test("$\\{34}"),
+ ?line test("$\\x{34}"),
+ ?line test("$\\{377}"),
+ ?line test("$\\x{FF}"),
+ ?line test("$\\{400}"),
+ ?line test("$\\x{100}"),
+ ?line test("$\\x{10FFFF}"),
+ ?line test("$\\x{10ffff}"),
+ ?line test("\"$\n \\{1}\""),
+ ?line {error,{1,erl_scan,{illegal,character}},1} =
+ erl_scan:string("$\\x{110000}"),
+ ?line {error,{{1,1},erl_scan,{illegal,character}},{1,12}} =
+ erl_scan:string("$\\x{110000}", {1,1}),
+
+ ?line {error,{{1,1},erl_scan,{illegal,character}},{1,4}} =
+ erl_scan:string("$\\xfg", {1,1}),
+
+ ?line test("$\\xffg"),
+
+ ?line {error,{{1,1},erl_scan,{illegal,character}},{1,4}} =
+ erl_scan:string("$\\xg", {1,1}),
+ ok.
+
+test_string(String, Expected) ->
+ {ok, Expected, _End} = erl_scan:string(String),
+ test(String).
+
+%% test_string(String, Expected, StartLocation, Options) ->
+%% {ok, Expected, _End} = erl_scan:string(String, StartLocation, Options),
+%% test(String).
+
+%% There are no checks of the tags...
+test(String) ->
+ %% io:format("Testing `~ts'~n", [String]),
+ [{Tokens, End},
+ {Wtokens, Wend},
+ {Ctokens, Cend},
+ {CWtokens, CWend},
+ {CWtokens2, _}] =
+ [scan_string_with_column(String, X) ||
+ X <- [[],
+ [return_white_spaces],
+ [return_comments],
+ [return],
+ [return]]], % for white space compaction test
+
+ {end1,End,Wend} = {end1,Wend,End},
+ {end2,Wend,Cend} = {end2,Cend,Wend},
+ {end3,Cend,CWend} = {end3,CWend,Cend},
+
+ %% Test that the tokens that are common to two token lists are identical.
+ {none,Tokens} = {none, filter_tokens(CWtokens, [white_space,comment])},
+ {comments,Ctokens} =
+ {comments,filter_tokens(CWtokens, [white_space])},
+ {white_spaces,Wtokens} =
+ {white_spaces,filter_tokens(CWtokens, [comment])},
+
+ %% Use token attributes to extract parts from the original string,
+ %% and check that the parts are identical to the token strings.
+ {Line,Column} = test_decorated_tokens(String, CWtokens),
+ {deco,{Line,Column},End} = {deco,End,{Line,Column}},
+
+ %% Almost the same again: concat texts to get the original:
+ Text = get_text(CWtokens),
+ {text,Text,String} = {text,String,Text},
+
+ %% Test that white spaces occupy less heap than the worst case.
+ ok = test_white_space_compaction(CWtokens, CWtokens2),
+
+ %% Test that white newlines are always first in text:
+ WhiteTokens = select_tokens(CWtokens, [white_space]),
+ ok = newlines_first(WhiteTokens),
+
+ %% Line attribute only:
+ [Simple,Wsimple,Csimple,WCsimple] = Simples =
+ [element(2, erl_scan:string(String, 1, Opts)) ||
+ Opts <- [[],
+ [return_white_spaces],
+ [return_comments],
+ [return]]],
+ {consistent,true} = {consistent,consistent_attributes(Simples)},
+ {simple_wc,WCsimple} = {simple_wc,simplify(CWtokens)},
+ {simple,Simple} = {simple,filter_tokens(WCsimple, [white_space,comment])},
+ {simple_c,Csimple} = {simple_c,filter_tokens(WCsimple, [white_space])},
+ {simple_w,Wsimple} = {simple_w,filter_tokens(WCsimple, [comment])},
+
+ %% Line attribute only, with text:
+ [SimpleTxt,WsimpleTxt,CsimpleTxt,WCsimpleTxt] = SimplesTxt =
+ [element(2, erl_scan:string(String, 1, [text|Opts])) ||
+ Opts <- [[],
+ [return_white_spaces],
+ [return_comments],
+ [return]]],
+ TextTxt = get_text(WCsimpleTxt),
+ {text_txt,TextTxt,String} = {text_txt,String,TextTxt},
+ {consistent_txt,true} =
+ {consistent_txt,consistent_attributes(SimplesTxt)},
+ {simple_txt,SimpleTxt} =
+ {simple_txt,filter_tokens(WCsimpleTxt, [white_space,comment])},
+ {simple_c_txt,CsimpleTxt} =
+ {simple_c_txt,filter_tokens(WCsimpleTxt, [white_space])},
+ {simple_w_txt,WsimpleTxt} =
+ {simple_w_txt,filter_tokens(WCsimpleTxt, [comment])},
+
+ ok.
+
+test_white_space_compaction(Tokens, Tokens2) when Tokens =:= Tokens2 ->
+ [WS, WS2] = [select_tokens(Ts, [white_space]) || Ts <- [Tokens, Tokens2]],
+ test_wsc(WS, WS2).
+
+test_wsc([], []) ->
+ ok;
+test_wsc([Token|Tokens], [Token2|Tokens2]) ->
+ [Text, Text2] = [Text ||
+ {text, Text} <-
+ [erl_scan:token_info(T, text) ||
+ T <- [Token, Token2]]],
+ Sz = erts_debug:size(Text),
+ Sz2 = erts_debug:size({Text, Text2}),
+ IsCompacted = Sz2 < 2*Sz+erts_debug:size({a,a}),
+ ToBeCompacted = is_compacted(Text),
+ if
+ IsCompacted =:= ToBeCompacted ->
+ test_wsc(Tokens, Tokens2);
+ true ->
+ {compaction_error, Token}
+ end.
+
+is_compacted("\r") ->
+ true;
+is_compacted("\n\r") ->
+ true;
+is_compacted("\n\f") ->
+ true;
+is_compacted([$\n|String]) ->
+ all_spaces(String)
+ orelse
+ all_tabs(String);
+is_compacted(String) ->
+ all_spaces(String)
+ orelse
+ all_tabs(String).
+
+all_spaces(L) ->
+ all_same(L, $\s).
+
+all_tabs(L) ->
+ all_same(L, $\t).
+
+all_same(L, Char) ->
+ lists:all(fun(C) -> C =:= Char end, L).
+
+newlines_first([]) ->
+ ok;
+newlines_first([Token|Tokens]) ->
+ {text,Text} = erl_scan:token_info(Token, text),
+ Nnls = length([C || C <- Text, C =:= $\n]),
+ OK = case Text of
+ [$\n|_] ->
+ Nnls =:= 1;
+ _ ->
+ Nnls =:= 0
+ end,
+ if
+ OK -> newlines_first(Tokens);
+ true -> OK
+ end.
+
+filter_tokens(Tokens, Tags) ->
+ lists:filter(fun(T) -> not lists:member(element(1, T), Tags) end, Tokens).
+
+select_tokens(Tokens, Tags) ->
+ lists:filter(fun(T) -> lists:member(element(1, T), Tags) end, Tokens).
+
+simplify([Token|Tokens]) ->
+ {line,Line} = erl_scan:token_info(Token, line),
+ [setelement(2, Token, Line) | simplify(Tokens)];
+simplify([]) ->
+ [].
+
+get_text(Tokens) ->
+ lists:flatten(
+ [T ||
+ Token <- Tokens,
+ ({text,T} = erl_scan:token_info(Token, text)) =/= []]).
+
+test_decorated_tokens(String, Tokens) ->
+ ToksAttrs = token_attrs(Tokens),
+ test_strings(ToksAttrs, String, 1, 1).
+
+token_attrs(Tokens) ->
+ [{L,C,Len,T} ||
+ Token <- Tokens,
+ ([{line,L},{column,C},{length,Len},{text,T}] =
+ erl_scan:token_info(Token, [line,column,length,text])) =/= []].
+
+test_strings([], _S, Line, Column) ->
+ {Line,Column};
+test_strings([{L,C,Len,T}=Attr|Attrs], String0, Line0, Column0) ->
+ {String1, Column1} = skip_newlines(String0, L, Line0, Column0),
+ String = skip_chars(String1, C-Column1),
+ {Str,Rest} = lists:split(Len, String),
+ if
+ Str =:= T ->
+ {Line,Column} = string_newlines(T, L, C),
+ test_strings(Attrs, Rest, Line, Column);
+ true ->
+ {token_error, Attr, Str}
+ end.
+
+skip_newlines(String, Line, Line, Column) ->
+ {String, Column};
+skip_newlines([$\n|String], L, Line, _Column) ->
+ skip_newlines(String, L, Line+1, 1);
+skip_newlines([_|String], L, Line, Column) ->
+ skip_newlines(String, L, Line, Column+1).
+
+skip_chars(String, 0) ->
+ String;
+skip_chars([_|String], N) ->
+ skip_chars(String, N-1).
+
+string_newlines([$\n|String], Line, _Column) ->
+ string_newlines(String, Line+1, 1);
+string_newlines([], Line, Column) ->
+ {Line, Column};
+string_newlines([_|String], Line, Column) ->
+ string_newlines(String, Line, Column+1).
+
+scan_string_with_column(String, Options0) ->
+ Options = [text | Options0],
+ StartLoc = {1, 1},
+ {ok, Ts1, End1} = erl_scan:string(String, StartLoc, Options),
+ TString = String ++ ". ",
+ {ok,Ts2,End2} = scan_tokens(TString, Options, [], StartLoc),
+ {ok, Ts3, End3} =
+ scan_tokens_1({more, []}, TString, Options, [], StartLoc),
+ {end_2,End2,End3} = {end_2,End3,End2},
+ {EndLine1,EndColumn1} = End1,
+ End2 = {EndLine1,EndColumn1+2},
+ {ts_1,Ts2,Ts3} = {ts_1,Ts3,Ts2},
+ Ts2 = Ts1 ++ [lists:last(Ts2)],
+
+ %% Attributes are keylists, but have no text.
+ {ok, Ts7, End7} = erl_scan:string(String, {1,1}, Options),
+ {ok, Ts8, End8} = scan_tokens(TString, Options, [], {1,1}),
+ {end1, End1} = {end1, End7},
+ {end2, End2} = {end2, End8},
+ Ts8 = Ts7 ++ [lists:last(Ts8)],
+ {cons,true} = {cons,consistent_attributes([Ts1,Ts2,Ts3,Ts7,Ts8])},
+
+ {Ts1, End1}.
+
+scan_tokens(String, Options, Rs, Location) ->
+ case erl_scan:tokens([], String, Location, Options) of
+ {done, {ok,Ts,End}, ""} ->
+ {ok, lists:append(lists:reverse([Ts|Rs])), End};
+ {done, {ok,Ts,End}, Rest} ->
+ scan_tokens(Rest, Options, [Ts|Rs], End)
+ end.
+
+scan_tokens_1({done, {ok,Ts,End}, ""}, "", _Options, Rs, _Location) ->
+ {ok,lists:append(lists:reverse([Ts|Rs])),End};
+scan_tokens_1({done, {ok,Ts,End}, Rest}, Cs, Options, Rs, _Location) ->
+ scan_tokens_1({more,[]}, Rest++Cs, Options, [Ts|Rs], End);
+scan_tokens_1({more, Cont}, [C | Cs], Options, Rs, Loc) ->
+ R = erl_scan:tokens(Cont, [C], Loc, Options),
+ scan_tokens_1(R, Cs, Options, Rs, Loc).
+
+consistent_attributes([]) ->
+ true;
+consistent_attributes([Ts | TsL]) ->
+ L = [T || T <- Ts, is_integer(element(2, T))],
+ case L of
+ [] ->
+ TagsL = [[Tag || {Tag,_} <-
+ erl_scan:attributes_info(element(2, T))] ||
+ T <- Ts],
+ case lists:usort(TagsL) of
+ [_] ->
+ consistent_attributes(TsL);
+ [] when Ts =:= [] ->
+ consistent_attributes(TsL);
+ _ ->
+ Ts
+ end;
+ Ts ->
+ consistent_attributes(TsL);
+ _ ->
+ Ts
+ end.
+
+family_list(L) ->
+ sofs:to_external(family(L)).
+
+family(L) ->
+ sofs:relation_to_family(sofs:relation(L)).
diff --git a/lib/stdlib/test/error_logger_forwarder.erl b/lib/stdlib/test/error_logger_forwarder.erl
new file mode 100644
index 0000000000..7d99d07860
--- /dev/null
+++ b/lib/stdlib/test/error_logger_forwarder.erl
@@ -0,0 +1,48 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(error_logger_forwarder).
+
+%% API.
+-export([register/0]).
+
+%% Internal export for error_logger.
+-export([init/1,
+ handle_event/2, handle_call/2, handle_info/2,
+ terminate/2]).
+
+%% Any crash report messages generated will be forwarded
+%% to the current process (the one doing the call to register/0).
+%%
+register() ->
+ error_logger:add_report_handler(?MODULE, self()).
+
+init(Tester) ->
+ {ok,Tester}.
+
+handle_event(Event, Tester) ->
+ Tester ! Event,
+ {ok,Tester}.
+
+handle_info(_, State) ->
+ {ok,State}.
+
+handle_call(_Query, State) -> {ok,{error,bad_query},State}.
+
+terminate(_Reason, State) ->
+ State.
diff --git a/lib/stdlib/test/escript_SUITE.erl b/lib/stdlib/test/escript_SUITE.erl
new file mode 100644
index 0000000000..70aae54d62
--- /dev/null
+++ b/lib/stdlib/test/escript_SUITE.erl
@@ -0,0 +1,540 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+
+-module(escript_SUITE).
+-export([
+ all/1,
+ init_per_testcase/2,
+ fin_per_testcase/2,
+ basic/1,
+ errors/1,
+ strange_name/1,
+ emulator_flags/1,
+ module_script/1,
+ beam_script/1,
+ archive_script/1,
+ epp/1
+ ]).
+
+-include("test_server.hrl").
+
+all(suite) ->
+ [
+ basic,
+ errors,
+ strange_name,
+ emulator_flags,
+ module_script,
+ beam_script,
+ archive_script,
+ epp
+ ].
+
+init_per_testcase(_Case, Config) ->
+ ?line Dog = ?t:timetrap(?t:minutes(1)),
+ [{watchdog,Dog}|Config].
+
+fin_per_testcase(_Case, Config) ->
+ Dog = ?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+basic(Config) when is_list(Config) ->
+ Data = ?config(data_dir, Config),
+ Dir = filename:absname(Data), %Get rid of trailing slash.
+ ?line run(Dir, "factorial 5",
+ <<"factorial 5 = 120\nExitCode:0">>),
+ ?line run(Dir, "factorial_compile 10",
+ <<"factorial 10 = 3628800\nExitCode:0">>),
+ ?line run(Dir, "factorial_compile_main 7",
+ <<"factorial 7 = 5040\nExitCode:0">>),
+ ?line run(Dir, "factorial_warning 20",
+ [data_dir,<<"factorial_warning:12: Warning: function bar/0 is unused\n"
+ "factorial 20 = 2432902008176640000\nExitCode:0">>]),
+ ?line run(Dir, "-s", "factorial_warning",
+ [data_dir,<<"factorial_warning:12: Warning: function bar/0 is unused\nExitCode:0">>]),
+ ?line run(Dir, "-s -i", "factorial_warning",
+ [data_dir,<<"factorial_warning:12: Warning: function bar/0 is unused\nExitCode:0">>]),
+ ?line run(Dir, "-c -s", "factorial_warning",
+ [data_dir,<<"factorial_warning:12: Warning: function bar/0 is unused\nExitCode:0">>]),
+ ?line run(Dir, "filesize "++filename:join(?config(data_dir, Config),"filesize"),
+ [data_dir,<<"filesize:11: Warning: function id/1 is unused\n324\nExitCode:0">>]),
+ ?line run(Dir, "test_script_name",
+ [data_dir,<<"test_script_name\nExitCode:0">>]),
+ ?line run(Dir, "tail_rec 1000",
+ [<<"ok\nExitCode:0">>]),
+
+ %% We expect the trap_exit flag for the process to be false,
+ %% since that is the default state for newly spawned processes.
+ ?line run(Dir, "trap_exit",
+ <<"false\nExitCode:0">>),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+errors(Config) when is_list(Config) ->
+ Data = ?config(data_dir, Config),
+ Dir = filename:absname(Data), %Get rid of trailing slash.
+ ?line run(Dir, "compile_error",
+ [data_dir,<<"compile_error:5: syntax error before: '*'\n">>,
+ data_dir,<<"compile_error:8: syntax error before: blarf\n">>,
+ <<"escript: There were compilation errors.\nExitCode:127">>]),
+ ?line run(Dir, "lint_error",
+ [data_dir,<<"lint_error:6: function main/1 already defined\n">>,
+ data_dir,"lint_error:8: variable 'ExitCode' is unbound\n",
+ <<"escript: There were compilation errors.\nExitCode:127">>]),
+ ?line run(Dir, "-s", "lint_error",
+ [data_dir,<<"lint_error:6: function main/1 already defined\n">>,
+ data_dir,"lint_error:8: variable 'ExitCode' is unbound\n",
+ <<"escript: There were compilation errors.\nExitCode:127">>]),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+strange_name(Config) when is_list(Config) ->
+ Data = ?config(data_dir, Config),
+ Dir = filename:absname(Data), %Get rid of trailing slash.
+ ?line run(Dir, "strange.name -arg1 arg2 arg3",
+ [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n"
+ "ExitCode:0">>]),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+emulator_flags(Config) when is_list(Config) ->
+ Data = ?config(data_dir, Config),
+ Dir = filename:absname(Data), %Get rid of trailing slash.
+ ?line run(Dir, "emulator_flags -arg1 arg2 arg3",
+ [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n"
+ "nostick:[{nostick,[]}]\n"
+ "mnesia:[{mnesia,[\"dir\",\"a/directory\"]},{mnesia,[\"debug\",\"verbose\"]}]\n"
+ "ERL_FLAGS=false\n"
+ "unknown:[]\n"
+ "ExitCode:0">>]),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Pick the source code from the emulator_flags script
+%% Generate a new escript with a module header
+
+module_script(Config) when is_list(Config) ->
+ %% Read orig file
+ Data = ?config(data_dir, Config),
+ OrigFile = filename:join([Data,"emulator_flags"]),
+ {ok, OrigBin} = file:read_file(OrigFile),
+ ?line [Shebang, Mode, Flags | Source] = string:tokens(binary_to_list(OrigBin), "\n"),
+ ?line {ok, OrigFI} = file:read_file_info(OrigFile),
+
+ %% Write source file
+ Priv = ?config(priv_dir, Config),
+ Dir = filename:absname(Priv), % Get rid of trailing slash.
+ Base = "module_script",
+ ErlFile = filename:join([Priv, Base ++ ".erl"]),
+ ErlCode = ["-module(", Base, ").\n",
+ "-export([main/1]).\n\n",
+ string:join(Source, "\n"),
+ "\n"],
+ ?line ok = file:write_file(ErlFile, ErlCode),
+
+ %%%%%%%
+ %% Create and run scripts without emulator flags
+
+ %% With shebang
+ NoArgsBase = Base ++ "_no_args_with_shebang",
+ NoArgsFile = filename:join([Priv, NoArgsBase]),
+ ?line ok = file:write_file(NoArgsFile,
+ [Shebang, "\n",
+ ErlCode]),
+ ?line ok = file:write_file_info(NoArgsFile, OrigFI),
+
+ ?line run(Dir, NoArgsBase ++ " -arg1 arg2 arg3",
+ [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n"
+ "nostick:[]\n"
+ "mnesia:[]\n"
+ "ERL_FLAGS=false\n"
+ "unknown:[]\n"
+ "ExitCode:0">>]),
+
+ ?line run(Dir, "", NoArgsBase ++ " -arg1 arg2 arg3",
+ [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n"
+ "nostick:[]\n"
+ "mnesia:[]\n"
+ "ERL_FLAGS=false\n"
+ "unknown:[]\n"
+ "ExitCode:0">>]),
+
+ %% Without shebang
+ NoArgsBase2 = Base ++ "_no_args_without_shebang",
+ NoArgsFile2 = filename:join([Priv, NoArgsBase2]),
+ ?line ok = file:write_file(NoArgsFile2,
+ ["Something else than shebang!!!", "\n",
+ ErlCode]),
+ ?line ok = file:write_file_info(NoArgsFile2, OrigFI),
+
+ ?line run(Dir, "", NoArgsBase2 ++ " -arg1 arg2 arg3",
+ [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n"
+ "nostick:[]\n"
+ "mnesia:[]\n"
+ "ERL_FLAGS=false\n"
+ "unknown:[]\n"
+ "ExitCode:0">>]),
+
+ %% Plain module without header
+ NoArgsBase3 = Base ++ "_no_args_without_header",
+ NoArgsFile3 = filename:join([Priv, NoArgsBase3]),
+ ?line ok = file:write_file(NoArgsFile3, [ErlCode]),
+ ?line ok = file:write_file_info(NoArgsFile3, OrigFI),
+
+ ?line run(Dir, "", NoArgsBase3 ++ " -arg1 arg2 arg3",
+ [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n"
+ "nostick:[]\n"
+ "mnesia:[]\n"
+ "ERL_FLAGS=false\n"
+ "unknown:[]\n"
+ "ExitCode:0">>]),
+
+ %%%%%%%
+ %% Create and run scripts with emulator flags
+
+ %% With shebang
+ ArgsBase = Base ++ "_args_with_shebang",
+ ArgsFile = filename:join([Priv, ArgsBase]),
+ ?line ok = file:write_file(ArgsFile,
+ [Shebang, "\n",
+ Mode, "\n",
+ Flags, "\n",
+ ErlCode]),
+ ?line ok = file:write_file_info(ArgsFile, OrigFI),
+
+ ?line run(Dir, ArgsBase ++ " -arg1 arg2 arg3",
+ [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n"
+ "nostick:[{nostick,[]}]\n"
+ "mnesia:[{mnesia,[\"dir\",\"a/directory\"]},{mnesia,[\"debug\",\"verbose\"]}]\n"
+ "ERL_FLAGS=false\n"
+ "unknown:[]\n"
+ "ExitCode:0">>]),
+
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Pick the source code from the emulator_flags script and compile it.
+%% Generate a new escript containing the beam code and the escript header
+beam_script(Config) when is_list(Config) ->
+ %% Read orig file
+ Data = ?config(data_dir, Config),
+ OrigFile = filename:join([Data,"emulator_flags"]),
+ {ok, OrigBin} = file:read_file(OrigFile),
+ ?line [Shebang, Mode, Flags | Source] = string:tokens(binary_to_list(OrigBin), "\n"),
+ ?line {ok, OrigFI} = file:read_file_info(OrigFile),
+
+ %% Write source file
+ Priv = ?config(priv_dir, Config),
+ Dir = filename:absname(Priv), % Get rid of trailing slash.
+ Base = "beam_script",
+ ErlFile = filename:join([Priv, Base ++ ".erl"]),
+ ?line ok = file:write_file(ErlFile,
+ ["-module(", Base, ").\n",
+ "-export([main/1]).\n\n",
+ string:join(Source, "\n"),
+ "\n"]),
+
+ %% Compile the code
+ ?line {ok, _Mod, BeamCode} = compile:file(ErlFile, [binary]),
+
+ %%%%%%%
+ %% Create and run scripts without emulator flags
+
+ %% With shebang
+ NoArgsBase = Base ++ "_no_args_with_shebang",
+ NoArgsFile = filename:join([Priv, NoArgsBase]),
+ ?line ok = file:write_file(NoArgsFile,
+ [Shebang, "\n",
+ BeamCode]),
+ ?line ok = file:write_file_info(NoArgsFile, OrigFI),
+
+ ?line run(Dir, NoArgsBase ++ " -arg1 arg2 arg3",
+ [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n"
+ "nostick:[]\n"
+ "mnesia:[]\n"
+ "ERL_FLAGS=false\n"
+ "unknown:[]\n"
+ "ExitCode:0">>]),
+
+ ?line run(Dir, "", NoArgsBase ++ " -arg1 arg2 arg3",
+ [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n"
+ "nostick:[]\n"
+ "mnesia:[]\n"
+ "ERL_FLAGS=false\n"
+ "unknown:[]\n"
+ "ExitCode:0">>]),
+
+ %% Without shebang
+ NoArgsBase2 = Base ++ "_no_args_without_shebang",
+ NoArgsFile2 = filename:join([Priv, NoArgsBase2]),
+ ?line ok = file:write_file(NoArgsFile2,
+ ["Something else than shebang!!!", "\n",
+ BeamCode]),
+ ?line ok = file:write_file_info(NoArgsFile2, OrigFI),
+
+ ?line run(Dir, "", NoArgsBase2 ++ " -arg1 arg2 arg3",
+ [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n"
+ "nostick:[]\n"
+ "mnesia:[]\n"
+ "ERL_FLAGS=false\n"
+ "unknown:[]\n"
+ "ExitCode:0">>]),
+
+ %% Plain beam file without header
+ NoArgsBase3 = Base ++ "_no_args_without_header",
+ NoArgsFile3 = filename:join([Priv, NoArgsBase3]),
+ ?line ok = file:write_file(NoArgsFile3, [BeamCode]),
+ ?line ok = file:write_file_info(NoArgsFile3, OrigFI),
+
+ ?line run(Dir, "", NoArgsBase3 ++ " -arg1 arg2 arg3",
+ [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n"
+ "nostick:[]\n"
+ "mnesia:[]\n"
+ "ERL_FLAGS=false\n"
+ "unknown:[]\n"
+ "ExitCode:0">>]),
+
+ %%%%%%%
+ %% Create and run scripts with emulator flags
+
+ %% With shebang
+ ArgsBase = Base ++ "_args",
+ ArgsFile = filename:join([Priv, ArgsBase]),
+ ?line ok = file:write_file(ArgsFile,
+ [Shebang, "\n",
+ Mode, "\n",
+ Flags, "\n",
+ BeamCode]),
+ ?line ok = file:write_file_info(ArgsFile, OrigFI),
+
+ ?line run(Dir, ArgsBase ++ " -arg1 arg2 arg3",
+ [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n"
+ "nostick:[{nostick,[]}]\n"
+ "mnesia:[{mnesia,[\"dir\",\"a/directory\"]},{mnesia,[\"debug\",\"verbose\"]}]\n"
+ "ERL_FLAGS=false\n"
+ "unknown:[]\n"
+ "ExitCode:0">>]),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Create an archive file containing two entire applications plus two
+%% alternate main modules. Generate a new escript containing the archive
+%% (with .app and .beam files and ) and the escript header.
+
+archive_script(Config) when is_list(Config) ->
+ %% Copy the orig files to priv_dir
+ DataDir = ?config(data_dir, Config),
+ PrivDir = ?config(priv_dir, Config),
+ Archive = filename:join([PrivDir, "archive_script.zip"]),
+ ?line {ok, _} = zip:create(Archive, ["archive_script"],
+ [{compress, []}, {cwd, DataDir}]),
+ ?line {ok, _} = zip:extract(Archive, [{cwd, PrivDir}]),
+ TopDir = filename:join([PrivDir, "archive_script"]),
+
+ %% Compile the code
+ ?line ok = compile_app(TopDir, "archive_script_dict"),
+ ?line ok = compile_app(TopDir, "archive_script_dummy"),
+ ?line {ok, MainFiles} = file:list_dir(TopDir),
+ ?line ok = compile_files(MainFiles, TopDir, TopDir),
+
+ %% Create the archive
+ {ok, TopFiles} = file:list_dir(TopDir),
+ ?line {ok, {_, ArchiveBin}} = zip:create(Archive, TopFiles,
+ [memory, {compress, []}, {cwd, TopDir}]),
+
+ %% Read the source script
+ OrigFile = filename:join([DataDir, "emulator_flags"]),
+ {ok, OrigBin} = file:read_file(OrigFile),
+ ?line [Shebang, Mode, _Flags | _Source] =
+ string:tokens(binary_to_list(OrigBin), "\n"),
+ Flags = "%%! -archive_script_dict foo bar"
+ " -archive_script_dict foo"
+ " -archive_script_dummy bar",
+ ?line {ok, OrigFI} = file:read_file_info(OrigFile),
+
+ %%%%%%%
+ %% Create and run scripts without emulator flags
+ MainBase = "archive_script_main",
+ MainScript = filename:join([PrivDir, MainBase]),
+
+ %% With shebang
+ ?line ok = file:write_file(MainScript,
+ [Shebang, "\n",
+ Flags, "\n",
+ ArchiveBin]),
+ ?line ok = file:write_file_info(MainScript, OrigFI),
+
+ ?line run(PrivDir, MainBase ++ " -arg1 arg2 arg3",
+ [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n"
+ "dict:[{archive_script_dict,[\"foo\",\"bar\"]},{archive_script_dict,[\"foo\"]}]\n"
+ "dummy:[{archive_script_dummy,[\"bar\"]}]\n"
+ "priv:{ok,<<\"Some private data...\\n\">>}\n"
+ "ExitCode:0">>]),
+
+ ?line run(PrivDir, "", MainBase ++ " -arg1 arg2 arg3",
+ [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n"
+ "dict:[{archive_script_dict,[\"foo\",\"bar\"]},{archive_script_dict,[\"foo\"]}]\n"
+ "dummy:[{archive_script_dummy,[\"bar\"]}]\n"
+ "priv:{ok,<<\"Some private data...\\n\">>}\n"
+ "ExitCode:0">>]),
+
+ ?line ok = file:rename(MainScript, MainScript ++ "_with_shebang"),
+
+ %% Without shebang (no flags)
+ ?line ok = file:write_file(MainScript,
+ ["Something else than shebang!!!", "\n",
+ ArchiveBin]),
+ ?line ok = file:write_file_info(MainScript, OrigFI),
+
+ ?line run(PrivDir, "", MainBase ++ " -arg1 arg2 arg3",
+ [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n"
+ "dict:[]\n"
+ "dummy:[]\n"
+ "priv:{ok,<<\"Some private data...\\n\">>}\n"
+ "ExitCode:0">>]),
+ ?line ok = file:rename(MainScript, MainScript ++ "_without_shebang"),
+
+ %% Plain archive without header (no flags)
+
+ ?line ok = file:write_file(MainScript, [ArchiveBin]),
+ ?line ok = file:write_file_info(MainScript, OrigFI),
+
+ ?line run(PrivDir, "", MainBase ++ " -arg1 arg2 arg3",
+ [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n"
+ "dict:[]\n"
+ "dummy:[]\n"
+ "priv:{ok,<<\"Some private data...\\n\">>}\n"
+ "ExitCode:0">>]),
+ ?line ok = file:rename(MainScript, MainScript ++ "_without_header"),
+
+ %%%%%%%
+ %% Create and run scripts with emulator flags
+ AltBase = "archive_script_alternate_main",
+ AltScript = filename:join([PrivDir, AltBase]),
+ ?line ok = file:write_file(AltScript,
+ [Shebang, "\n",
+ Mode, "\n",
+ Flags, " -escript main archive_script_main2\n",
+ ArchiveBin]),
+ ?line ok = file:write_file_info(AltScript, OrigFI),
+
+ ?line run(PrivDir, AltBase ++ " -arg1 arg2 arg3",
+ [<<"main2:[\"-arg1\",\"arg2\",\"arg3\"]\n"
+ "dict:[{archive_script_dict,[\"foo\",\"bar\"]},{archive_script_dict,[\"foo\"]}]\n"
+ "dummy:[{archive_script_dummy,[\"bar\"]}]\n"
+ "priv:{ok,<<\"Some private data...\\n\">>}\n"
+ "ExitCode:0">>]),
+
+ ok.
+
+compile_app(TopDir, AppName) ->
+ AppDir = filename:join([TopDir, AppName]),
+ SrcDir = filename:join([AppDir, "src"]),
+ OutDir = filename:join([AppDir, "ebin"]),
+ ?line {ok, Files} = file:list_dir(SrcDir),
+ compile_files(Files, SrcDir, OutDir).
+
+compile_files([File | Files], SrcDir, OutDir) ->
+ case filename:extension(File) of
+ ".erl" ->
+ AbsFile = filename:join([SrcDir, File]),
+ case compile:file(AbsFile, [{outdir, OutDir}]) of
+ {ok, _Mod} ->
+ compile_files(Files, SrcDir, OutDir);
+ Error ->
+ {compilation_error, AbsFile, OutDir, Error}
+ end;
+ _ ->
+ compile_files(Files, SrcDir, OutDir)
+ end;
+compile_files([], _, _) ->
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+epp(Config) when is_list(Config) ->
+ Data = ?config(data_dir, Config),
+ Dir = filename:absname(Data), %Get rid of trailing slash.
+ ?line run(Dir, "factorial_epp 5",
+ <<"factorial 5 = 120\nExitCode:0">>),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+run(Dir, Cmd0, Expected0) ->
+ Expected = iolist_to_binary(expected_output(Expected0, Dir)),
+ Cmd = case os:type() of
+ {win32,_} -> "escript " ++ filename:nativename(Dir) ++ "\\" ++ Cmd0;
+ _ -> Cmd0
+ end,
+ do_run(Dir, Cmd, Expected).
+
+run(Dir, Opts, Cmd0, Expected) ->
+ Cmd = case os:type() of
+ {win32,_} -> "escript " ++ Opts ++ " " ++ filename:nativename(Dir) ++ "\\" ++ Cmd0;
+ _ -> "escript " ++ Opts ++ " " ++ Dir ++ "/" ++ Cmd0
+ end,
+ do_run(Dir, Cmd, Expected).
+
+do_run(Dir, Cmd, Expected0) ->
+ io:format("Run: ~p\n", [Cmd]),
+ Expected = iolist_to_binary(expected_output(Expected0, Dir)),
+
+ Env = [{"PATH",Dir++":"++os:getenv("PATH")}],
+ Port = open_port({spawn,Cmd}, [exit_status,eof,in,{env,Env}]),
+ Res = get_data(Port, []),
+ receive
+ {Port,{exit_status,ExitCode}} ->
+ case iolist_to_binary([Res,"ExitCode:"++integer_to_list(ExitCode)]) of
+ Expected ->
+ ok;
+ Actual ->
+ io:format("Expected: ~p\n", [Expected]),
+ io:format("Actual: ~p\n", [Actual]),
+ ?t:fail()
+ end
+ end.
+
+get_data(Port, SoFar) ->
+ receive
+ {Port,{data,Bytes}} ->
+ get_data(Port, [SoFar|Bytes]);
+ {Port,eof} ->
+ erlang:port_close(Port),
+ SoFar
+ end.
+
+expected_output([data_dir|T], Data) ->
+ Slash = case os:type() of
+ {win32,_} -> "\\";
+ _ -> "/"
+ end,
+ [filename:nativename(Data)++Slash|expected_output(T, Data)];
+expected_output([H|T], Data) ->
+ [H|expected_output(T, Data)];
+expected_output([], _) ->
+ [];
+expected_output(Bin, _) when is_binary(Bin) ->
+ Bin.
+
diff --git a/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_dict/ebin/archive_script_dict.app b/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_dict/ebin/archive_script_dict.app
new file mode 100644
index 0000000000..d703977a1d
--- /dev/null
+++ b/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_dict/ebin/archive_script_dict.app
@@ -0,0 +1,12 @@
+{application, archive_script_dict,
+ [{description, "archive_script_dict"},
+ {vsn, "0.1"},
+ {modules, [
+ archive_script_dict,
+ archive_script_dict_sup
+ ]},
+ {registered, [
+ archive_script_dict_sup
+ ]},
+ {applications, [kernel, stdlib]},
+ {mod, {archive_script_dict_app, [[]]}}]}.
diff --git a/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_dict/priv/archive_script_dict.txt b/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_dict/priv/archive_script_dict.txt
new file mode 100644
index 0000000000..8fa2c8c064
--- /dev/null
+++ b/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_dict/priv/archive_script_dict.txt
@@ -0,0 +1 @@
+Some private data...
diff --git a/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_dict/src/archive_script_dict.erl b/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_dict/src/archive_script_dict.erl
new file mode 100644
index 0000000000..a614817b04
--- /dev/null
+++ b/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_dict/src/archive_script_dict.erl
@@ -0,0 +1,125 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(archive_script_dict).
+-behaviour(sys).
+
+%% Public
+-export([new/1, store/3, erase/2, find/2, foldl/3, erase/1]).
+
+%% Internal
+-export([init/3, loop/3]).
+
+%% supervisor callback
+-export([start_link/2]).
+
+%% sys callback functions
+-export([
+ system_continue/3,
+ system_terminate/4,
+ system_code_change/4
+ ]).
+
+-define(SUPERVISOR, archive_script_dict_sup).
+
+start_link(Name, Debug) ->
+ proc_lib:start_link(?MODULE, init, [self(), Name, Debug], infinity, []).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Client
+
+new(Name) ->
+ supervisor:start_child(?SUPERVISOR, [Name]).
+
+store(Pid, Key, Val) ->
+ call(Pid, {store, Key, Val}).
+
+erase(Pid, Key) ->
+ call(Pid, {erase, Key}).
+
+find(Pid, Key) ->
+ call(Pid, {find, Key}).
+
+foldl(Pid, Fun, Acc) ->
+ call(Pid, {foldl, Fun, Acc}).
+
+erase(Pid) ->
+ call(Pid, stop).
+
+call(Name, Msg) when is_atom(Name) ->
+ call(whereis(Name), Msg);
+call(Pid, Msg) when is_pid(Pid) ->
+ Ref = erlang:monitor(process, Pid),
+ Pid ! {self(), Ref, Msg},
+ receive
+ {Ref, Reply} ->
+ erlang:demonitor(Ref, [flush]),
+ Reply;
+ {'DOWN', Ref, _, _, Reason} ->
+ {error, Reason}
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Server
+
+init(Parent, Name, Debug) ->
+ register(Name, self()),
+ Dict = dict:new(),
+ proc_lib:init_ack(Parent, {ok, self()}),
+ loop(Dict, Parent, Debug).
+
+loop(Dict, Parent, Debug) ->
+ receive
+ {system, From, Msg} ->
+ sys:handle_system_msg(Msg, From, Parent, ?MODULE, Debug, Dict);
+ {ReplyTo, Ref, {store, Key, Val}} ->
+ Dict2 = dict:store(Key, Val, Dict),
+ ReplyTo ! {Ref, ok},
+ ?MODULE:loop(Dict2, Parent, Debug);
+ {ReplyTo, Ref, {erase, Key}} ->
+ Dict2 = dict:erase(Key, Dict),
+ ReplyTo ! {Ref, ok},
+ ?MODULE:loop(Dict2, Parent, Debug);
+ {ReplyTo, Ref, {find, Key}} ->
+ Res = dict:find(Key, Dict),
+ ReplyTo ! {Ref, Res},
+ ?MODULE:loop(Dict, Parent, Debug);
+ {ReplyTo, Ref, {foldl, Fun, Acc}} ->
+ Acc2 = dict:foldl(Fun, Acc, Dict),
+ ReplyTo ! {Ref, {ok, Acc2}},
+ ?MODULE:loop(Dict, Parent, Debug);
+ {ReplyTo, Ref, stop} ->
+ ReplyTo ! {Ref, ok},
+ exit(normal);
+ Msg ->
+ error_logger:format("~p got unexpected message: ~p\n",
+ [self(), Msg]),
+ ?MODULE:loop(Dict, Parent, Debug)
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% sys callbacks
+
+system_continue(Parent, Debug, Dict) ->
+ ?MODULE:loop(Dict, Parent, Debug).
+
+system_terminate(Reason, _Parent, _Debug, _Dict) ->
+ exit(Reason).
+
+system_code_change(Dict,_Module,_OldVsn,_Extra) ->
+ {ok, Dict}.
diff --git a/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_dict/src/archive_script_dict_app.erl b/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_dict/src/archive_script_dict_app.erl
new file mode 100644
index 0000000000..09b22ea532
--- /dev/null
+++ b/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_dict/src/archive_script_dict_app.erl
@@ -0,0 +1,29 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(archive_script_dict_app).
+-behaviour(application).
+
+%% Public
+-export([start/2, stop/1]).
+
+start(_Type, Args) ->
+ archive_script_dict_sup:start_link(Args).
+
+stop(_State) ->
+ ok.
diff --git a/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_dict/src/archive_script_dict_sup.erl b/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_dict/src/archive_script_dict_sup.erl
new file mode 100644
index 0000000000..9a6c088552
--- /dev/null
+++ b/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_dict/src/archive_script_dict_sup.erl
@@ -0,0 +1,39 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(archive_script_dict_sup).
+-behaviour(supervisor).
+
+%% Public
+-export([start_link/1]).
+
+%% Internal
+-export([init/1, start_simple_child/2]).
+
+-define(CHILD_MOD, archive_script_dict).
+
+start_link(Debug) ->
+ supervisor:start_link({local, ?MODULE}, ?MODULE, [Debug]).
+
+init([Debug]) ->
+ Flags = {simple_one_for_one, 0, 3600},
+ MFA = {?MODULE, start_simple_child, [Debug]},
+ {ok, {Flags, [{?MODULE, MFA, transient, timer:seconds(3), worker, [?CHILD_MOD]}]}}.
+
+start_simple_child(Debug, Name) ->
+ ?CHILD_MOD:start_link(Name, Debug).
diff --git a/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_dummy/ebin/archive_script_dummy.app b/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_dummy/ebin/archive_script_dummy.app
new file mode 100644
index 0000000000..bbb071c19b
--- /dev/null
+++ b/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_dummy/ebin/archive_script_dummy.app
@@ -0,0 +1,10 @@
+{application, archive_script_dummy,
+ [{description, "archive_script_dummy"},
+ {vsn, "0.1"},
+ {modules, [
+ archive_script_main,
+ archive_script_main2
+ ]},
+ {registered, []},
+ {applications, [kernel, stdlib, archive_script_dict]},
+ {mod, {archive_script_dummy_app, [[]]}}]}.
diff --git a/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_dummy/src/archive_script_dummy.erl b/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_dummy/src/archive_script_dummy.erl
new file mode 100644
index 0000000000..7c19ebf82f
--- /dev/null
+++ b/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_dummy/src/archive_script_dummy.erl
@@ -0,0 +1,29 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(archive_script_dummy).
+-behaviour(application).
+
+%% Public
+-export([start/2, stop/1]).
+
+start(_Type, Args) ->
+ archive_script_main_sup:start_link(Args).
+
+stop(_State) ->
+ ok.
diff --git a/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_dummy/src/archive_script_dummy_app.erl b/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_dummy/src/archive_script_dummy_app.erl
new file mode 100644
index 0000000000..c0910d379e
--- /dev/null
+++ b/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_dummy/src/archive_script_dummy_app.erl
@@ -0,0 +1,29 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(archive_script_dummy_app).
+-behaviour(application).
+
+%% Public
+-export([start/2, stop/1]).
+
+start(_Type, Args) ->
+ archive_script_dummy_sup:start_link(Args).
+
+stop(_State) ->
+ ok.
diff --git a/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_dummy/src/archive_script_dummy_sup.erl b/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_dummy/src/archive_script_dummy_sup.erl
new file mode 100644
index 0000000000..8dff5c9335
--- /dev/null
+++ b/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_dummy/src/archive_script_dummy_sup.erl
@@ -0,0 +1,33 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(archive_script_dummy_sup).
+-behaviour(supervisor).
+
+%% Public
+-export([start_link/1]).
+
+%% Internal
+-export([init/1]).
+
+start_link(Debug) ->
+ supervisor:start_link({local, ?MODULE}, ?MODULE, [Debug]).
+
+init([Debug]) ->
+ Flags = {one_for_one, 0, 3600},
+ {ok, {Flags, []}}.
diff --git a/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_main.erl b/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_main.erl
new file mode 100644
index 0000000000..d257744cd7
--- /dev/null
+++ b/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_main.erl
@@ -0,0 +1,61 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(archive_script_main).
+-behaviour(escript).
+
+-export([main/1]).
+
+-define(DUMMY, archive_script_dummy).
+-define(DICT, archive_script_dict).
+
+main(MainArgs) ->
+ %% Some printouts
+ io:format("main:~p\n",[MainArgs]),
+ ErlArgs = init:get_arguments(),
+ io:format("dict:~p\n",[[E || E <- ErlArgs, element(1, E) =:= ?DICT]]),
+ io:format("dummy:~p\n",[[E || E <- ErlArgs, element(1, E) =:= ?DUMMY]]),
+
+ %% Start the applications
+ {error, {not_started, ?DICT}} = application:start(?DUMMY),
+ ok = application:start(?DICT),
+ ok = application:start(?DUMMY),
+
+ %% Access dict priv dir
+ PrivDir = code:priv_dir(?DICT),
+ PrivFile = filename:join([PrivDir, "archive_script_dict.txt"]),
+ case erl_prim_loader:get_file(PrivFile) of
+ {ok, Bin, _FullPath} ->
+ io:format("priv:~p\n", [{ok, Bin}]);
+ error ->
+ io:format("priv:~p\n", [{error, PrivFile}])
+ end,
+
+ %% Use the dict app
+ Tab = archive_script_main_tab,
+ Key = foo,
+ Val = bar,
+ {ok, _Pid} = ?DICT:new(Tab),
+ error = ?DICT:find(Tab, Key),
+ ok = ?DICT:store(Tab, Key, Val),
+ {ok, Val} = ?DICT:find(Tab, Key),
+ ok = ?DICT:erase(Tab, Key),
+ error = ?DICT:find(Tab, Key),
+ ok = ?DICT:erase(Tab),
+ ok.
+
diff --git a/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_main2.erl b/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_main2.erl
new file mode 100644
index 0000000000..de56579998
--- /dev/null
+++ b/lib/stdlib/test/escript_SUITE_data/archive_script/archive_script_main2.erl
@@ -0,0 +1,60 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(archive_script_main2).
+-behaviour(escript).
+
+-export([main/1]).
+
+-define(DUMMY, archive_script_dummy).
+-define(DICT, archive_script_dict).
+
+main(MainArgs) ->
+ %% Some printouts
+ io:format("main2:~p\n",[MainArgs]),
+ ErlArgs = init:get_arguments(),
+ io:format("dict:~p\n",[[E || E <- ErlArgs, element(1, E) =:= ?DICT]]),
+ io:format("dummy:~p\n",[[E || E <- ErlArgs, element(1, E) =:= ?DUMMY]]),
+
+ %% Start the applications
+ {error, {not_started, ?DICT}} = application:start(archive_script_dummy),
+ ok = application:start(?DICT),
+ ok = application:start(?DUMMY),
+
+ %% Access dict priv dir
+ PrivDir = code:priv_dir(?DICT),
+ PrivFile = filename:join([PrivDir, "archive_script_dict.txt"]),
+ case erl_prim_loader:get_file(PrivFile) of
+ {ok, Bin, _FullPath} ->
+ io:format("priv:~p\n", [{ok, Bin}]);
+ error ->
+ io:format("priv:~p\n", [{error, PrivFile}])
+ end,
+
+ %% Use the dict app
+ Tab = archive_script_main_tab,
+ Key = foo,
+ Val = bar,
+ {ok, _Pid} = ?DICT:new(Tab),
+ error = ?DICT:find(Tab, Key),
+ ok = ?DICT:store(Tab, Key, Val),
+ {ok, Val} = ?DICT:find(Tab, Key),
+ ok = ?DICT:erase(Tab, Key),
+ error = ?DICT:find(Tab, Key),
+ ok = ?DICT:erase(Tab),
+ ok.
diff --git a/lib/stdlib/test/escript_SUITE_data/compile_error b/lib/stdlib/test/escript_SUITE_data/compile_error
new file mode 100755
index 0000000000..ae644a9af7
--- /dev/null
+++ b/lib/stdlib/test/escript_SUITE_data/compile_error
@@ -0,0 +1,12 @@
+#!/usr/bin/env escript
+%% -*- erlang -*-
+
+foo() ->
+ gurka ** nisse.
+
+
+blurf() blarf().
+
+
+
+
diff --git a/lib/stdlib/test/escript_SUITE_data/emulator_flags b/lib/stdlib/test/escript_SUITE_data/emulator_flags
new file mode 100755
index 0000000000..9e16818da5
--- /dev/null
+++ b/lib/stdlib/test/escript_SUITE_data/emulator_flags
@@ -0,0 +1,11 @@
+#! /usr/bin/env escript
+%% -*- erlang -*-
+%%! -nostick -mnesia dir a/directory -mnesia debug verbose
+
+main(MainArgs) ->
+ io:format("main:~p\n",[MainArgs]),
+ ErlArgs = init:get_arguments(),
+ io:format("nostick:~p\n",[[E || E <- ErlArgs, element(1, E) =:= nostick]]),
+ io:format("mnesia:~p\n", [[E || E <- ErlArgs, element(1, E) =:= mnesia]]),
+ io:format("ERL_FLAGS=~p\n", [os:getenv("ERL_FLAGS")]),
+ io:format("unknown:~p\n",[[E || E <- ErlArgs, element(1, E) =:= unknown]]).
diff --git a/lib/stdlib/test/escript_SUITE_data/factorial b/lib/stdlib/test/escript_SUITE_data/factorial
new file mode 100755
index 0000000000..200e320e9a
--- /dev/null
+++ b/lib/stdlib/test/escript_SUITE_data/factorial
@@ -0,0 +1,11 @@
+#!/usr/bin/env escript
+
+main([In]) ->
+ X = list_to_integer(In),
+ N = fac(X),
+ io:format("factorial ~w = ~w~n",[X, N]).
+
+fac(0) -> 1;
+fac(N) ->
+ N * fac(N-1).
+
diff --git a/lib/stdlib/test/escript_SUITE_data/factorial_compile b/lib/stdlib/test/escript_SUITE_data/factorial_compile
new file mode 100755
index 0000000000..c822808b90
--- /dev/null
+++ b/lib/stdlib/test/escript_SUITE_data/factorial_compile
@@ -0,0 +1,12 @@
+#!/usr/bin/env escript
+-mode(compile).
+
+main([In]) ->
+ X = list_to_integer(In),
+ N = fac(X),
+ io:format("factorial ~w = ~w~n",[X, N]).
+
+fac(0) -> 1;
+fac(N) ->
+ N * fac(N-1).
+
diff --git a/lib/stdlib/test/escript_SUITE_data/factorial_compile_main b/lib/stdlib/test/escript_SUITE_data/factorial_compile_main
new file mode 100755
index 0000000000..a59bb105dc
--- /dev/null
+++ b/lib/stdlib/test/escript_SUITE_data/factorial_compile_main
@@ -0,0 +1,13 @@
+#!/usr/bin/env escript
+-mode(compile).
+-export([main/1]).
+
+main([In]) ->
+ X = list_to_integer(In),
+ N = fac(X),
+ io:format("factorial ~w = ~w~n",[X, N]).
+
+fac(0) -> 1;
+fac(N) ->
+ N * fac(N-1).
+
diff --git a/lib/stdlib/test/escript_SUITE_data/factorial_epp b/lib/stdlib/test/escript_SUITE_data/factorial_epp
new file mode 100755
index 0000000000..dbdf974985
--- /dev/null
+++ b/lib/stdlib/test/escript_SUITE_data/factorial_epp
@@ -0,0 +1,17 @@
+#!/usr/bin/env escript
+%% -*- erlang -*-
+
+-module(factorial).
+-export([main/1]).
+
+-define(PREFIX, ?MODULE_STRING).
+
+main([In]) ->
+ X = list_to_integer(In),
+ N = fac(X),
+ io:format("~s ~w = ~w~n",[?PREFIX, X, N]).
+
+fac(0) -> 1;
+fac(N) ->
+ N * fac(N-1).
+
diff --git a/lib/stdlib/test/escript_SUITE_data/factorial_warning b/lib/stdlib/test/escript_SUITE_data/factorial_warning
new file mode 100755
index 0000000000..ef214e096a
--- /dev/null
+++ b/lib/stdlib/test/escript_SUITE_data/factorial_warning
@@ -0,0 +1,13 @@
+#!/usr/bin/env escript
+
+main([In]) ->
+ X = list_to_integer(In),
+ N = fac(X),
+ io:format("factorial ~w = ~w~n",[X, N]).
+
+fac(0) -> 1;
+fac(N) ->
+ N * fac(N-1).
+
+bar() ->
+ ok.
diff --git a/lib/stdlib/test/escript_SUITE_data/filesize b/lib/stdlib/test/escript_SUITE_data/filesize
new file mode 100755
index 0000000000..fd211c55cd
--- /dev/null
+++ b/lib/stdlib/test/escript_SUITE_data/filesize
@@ -0,0 +1,11 @@
+#!/usr/bin/env escript
+%% -*- erlang -*-
+-include_lib("kernel/include/file.hrl").
+
+main([Filename]) ->
+ {ok,#file_info{size=Size}} = file:read_file_info(Filename),
+ io:format("~p\n", [Size]).
+
+%% Deliberate warning follows so that we can check that line numbers
+%% correct after an -include_lib directive.
+id(I) -> I.
diff --git a/lib/stdlib/test/escript_SUITE_data/lint_error b/lib/stdlib/test/escript_SUITE_data/lint_error
new file mode 100755
index 0000000000..7be6e59b1d
--- /dev/null
+++ b/lib/stdlib/test/escript_SUITE_data/lint_error
@@ -0,0 +1,14 @@
+#!/usr/bin/env escript
+%% -*- erlang -*-
+
+main([]) ->
+ ok.
+main(Args) ->
+ io:format("~p\n", [length(Args)]),
+ halt(ExitCode).
+
+
+
+
+
+
diff --git a/lib/stdlib/test/escript_SUITE_data/strange.name b/lib/stdlib/test/escript_SUITE_data/strange.name
new file mode 100755
index 0000000000..19ad8aa40a
--- /dev/null
+++ b/lib/stdlib/test/escript_SUITE_data/strange.name
@@ -0,0 +1,7 @@
+#! /usr/bin/env escript
+%% -*- erlang -*-
+
+-mode(compile).
+
+main(MainArgs) ->
+ io:format("main:~p\n",[MainArgs]).
diff --git a/lib/stdlib/test/escript_SUITE_data/tail_rec b/lib/stdlib/test/escript_SUITE_data/tail_rec
new file mode 100755
index 0000000000..2ef64e1239
--- /dev/null
+++ b/lib/stdlib/test/escript_SUITE_data/tail_rec
@@ -0,0 +1,25 @@
+#!/usr/bin/env escript
+%% -*- erlang -*-
+-mode(interpret).
+
+tail_rec(PrevSize, N) ->
+ {_, Size} = process_info(self(), stack_size),
+ if
+ N =< 0 ->
+ ok;
+ PrevSize =:= undefined ->
+ tail_rec(Size, N - 1);
+ PrevSize =:= Size ->
+ tail_rec(Size, N - 1);
+ true ->
+ io:format("Not tail recursive (~p): Stack size ~p should be ~p\n",
+ [N, Size, PrevSize]),
+ tail_rec(Size, N - 1)
+ end.
+
+main([Repetitions]) ->
+ tail_rec(undefined, list_to_integer(Repetitions)),
+ io:format("ok\n", []);
+main(_) ->
+ io:format("Usage: ~s Repetitions\n", [escript:script_name()]),
+ init:stop(1).
diff --git a/lib/stdlib/test/escript_SUITE_data/test_script_name b/lib/stdlib/test/escript_SUITE_data/test_script_name
new file mode 100755
index 0000000000..c4a3d93646
--- /dev/null
+++ b/lib/stdlib/test/escript_SUITE_data/test_script_name
@@ -0,0 +1,5 @@
+#!/usr/bin/env escript
+
+main(_) ->
+ io:format("~s\n", [escript:script_name()]).
+
diff --git a/lib/stdlib/test/escript_SUITE_data/trap_exit b/lib/stdlib/test/escript_SUITE_data/trap_exit
new file mode 100755
index 0000000000..81fcfa9d12
--- /dev/null
+++ b/lib/stdlib/test/escript_SUITE_data/trap_exit
@@ -0,0 +1,6 @@
+#!/usr/bin/env escript
+%% -*- erlang -*-
+
+main(_) ->
+ {trap_exit,Bool} = process_info(self(), trap_exit),
+ io:format("~p\n", [Bool]).
diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl
new file mode 100644
index 0000000000..6016bc9bdc
--- /dev/null
+++ b/lib/stdlib/test/ets_SUITE.erl
@@ -0,0 +1,5355 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(ets_SUITE).
+
+-export([all/1]).
+-export([new/1,default/1,setbag/1,badnew/1,verybadnew/1,named/1,keypos2/1,
+ privacy/1,privacy_owner/2]).
+-export([insert/1,empty/1,badinsert/1]).
+-export([lookup/1,time_lookup/1,badlookup/1,lookup_order/1]).
+-export([delete/1,delete_elem/1,delete_tab/1,delete_large_tab/1,
+ delete_large_named_table/1,
+ evil_delete/1,baddelete/1,match_delete/1,table_leak/1]).
+-export([match_delete3/1]).
+-export([firstnext/1,firstnext_concurrent/1]).
+-export([slot/1]).
+-export([match/1, match1/1, match2/1, match_object/1, match_object2/1]).
+-export([misc/1, dups/1, misc1/1, safe_fixtable/1, info/1, tab2list/1]).
+-export([files/1, tab2file/1, tab2file2/1, tab2file3/1, tabfile_ext1/1,
+ tabfile_ext2/1, tabfile_ext3/1, tabfile_ext4/1]).
+-export([heavy/1, heavy_lookup/1, heavy_lookup_element/1]).
+-export([lookup_element/1, lookup_element_mult/1]).
+-export([fold/1]).
+-export([foldl_ordered/1, foldr_ordered/1, foldl/1, foldr/1, fold_empty/1]).
+-export([t_delete_object/1, t_init_table/1, t_whitebox/1,
+ t_delete_all_objects/1, t_insert_list/1, t_test_ms/1,
+ t_select_delete/1,t_ets_dets/1]).
+
+-export([do_lookup/2, do_lookup_element/3]).
+
+-export([ordered/1, ordered_match/1, interface_equality/1,
+ fixtable_next/1, fixtable_insert/1, rename/1, rename_unnamed/1, evil_rename/1,
+ update_element/1, update_counter/1, evil_update_counter/1, partly_bound/1, match_heavy/1]).
+-export([member/1]).
+-export([memory/1]).
+-export([select_fail/1]).
+-export([t_insert_new/1]).
+-export([t_repair_continuation/1]).
+-export([t_match_spec_run/1]).
+-export([t_bucket_disappears/1]).
+-export([otp_5340/1]).
+-export([otp_6338/1]).
+-export([otp_6842_select_1000/1]).
+-export([otp_7665/1]).
+-export([meta_wb/1]).
+-export([grow_shrink/1, grow_pseudo_deleted/1, shrink_pseudo_deleted/1]).
+-export([meta_smp/1,
+ meta_lookup_unnamed_read/1, meta_lookup_unnamed_write/1,
+ meta_lookup_named_read/1, meta_lookup_named_write/1,
+ meta_newdel_unnamed/1, meta_newdel_named/1]).
+-export([smp_insert/1, smp_fixed_delete/1, smp_unfix_fix/1, smp_select_delete/1, otp_8166/1]).
+-export([exit_large_table_owner/1,
+ exit_many_large_table_owner/1,
+ exit_many_tables_owner/1,
+ exit_many_many_tables_owner/1]).
+-export([write_concurrency/1, heir/1, give_away/1, setopts/1]).
+-export([bad_table/1]).
+
+-export([init_per_testcase/2, fin_per_testcase/2, end_per_suite/1]).
+%% Convenience for manual testing
+-export([random_test/0]).
+
+% internal exports
+-export([dont_make_worse_sub/0, make_better_sub1/0, make_better_sub2/0]).
+-export([t_repair_continuation_do/1, default_do/1, t_bucket_disappears_do/1,
+ select_fail_do/1, whitebox_1/1, whitebox_2/1, t_delete_all_objects_do/1,
+ t_delete_object_do/1, t_init_table_do/1, t_insert_list_do/1,
+ update_element_opts/1, update_element_opts/4, update_element/4, update_element_do/4,
+ update_element_neg/1, update_element_neg_do/1, update_counter_do/1, update_counter_neg/1,
+ evil_update_counter_do/1, fixtable_next_do/1, heir_do/1, give_away_do/1, setopts_do/1,
+ rename_do/1, rename_unnamed_do/1, interface_equality_do/1, ordered_match_do/1,
+ ordered_do/1, privacy_do/1, empty_do/1, badinsert_do/1, time_lookup_do/1,
+ lookup_order_do/1, lookup_element_mult_do/1, delete_tab_do/1, delete_elem_do/1,
+ match_delete_do/1, match_delete3_do/1, firstnext_do/1,
+ slot_do/1, match1_do/1, match2_do/1, match_object_do/1, match_object2_do/1,
+ misc1_do/1, safe_fixtable_do/1, info_do/1, dups_do/1, heavy_lookup_do/1,
+ heavy_lookup_element_do/1, member_do/1, otp_5340_do/1, otp_7665_do/1, meta_wb_do/1
+ ]).
+
+-include("test_server.hrl").
+
+init_per_testcase(Case, Config) ->
+ Seed = {S1,S2,S3} = random:seed0(), %now(),
+ random:seed(S1,S2,S3),
+ io:format("*** SEED: ~p ***\n", [Seed]),
+ start_spawn_logger(),
+ wait_for_test_procs(), %% Ensure previous case cleaned up
+ Dog=test_server:timetrap(test_server:minutes(20)),
+ [{watchdog, Dog}, {test_case, Case} | Config].
+
+fin_per_testcase(_Func, Config) ->
+ Dog=?config(watchdog, Config),
+ wait_for_test_procs(true),
+ test_server:timetrap_cancel(Dog).
+
+
+end_per_suite(_Config) ->
+ stop_spawn_logger(),
+ catch erts_debug:set_internal_state(available_internal_state, false).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+all(suite) ->
+ [
+ new,insert,lookup,delete,firstnext,firstnext_concurrent,slot,match,
+ t_match_spec_run,
+ lookup_element, misc,files, heavy,
+ ordered, ordered_match, interface_equality,
+ fixtable_next, fixtable_insert, rename, rename_unnamed, evil_rename,
+ update_element, update_counter, evil_update_counter, partly_bound,
+ match_heavy, fold, member,
+ t_delete_object, t_init_table, t_whitebox,
+ t_delete_all_objects, t_insert_list, t_test_ms,
+ t_select_delete, t_ets_dets, memory,
+ t_bucket_disappears,
+ select_fail,t_insert_new, t_repair_continuation, otp_5340, otp_6338,
+ otp_6842_select_1000, otp_7665,
+ meta_wb,
+ grow_shrink, grow_pseudo_deleted, shrink_pseudo_deleted,
+ meta_smp,
+ smp_insert, smp_fixed_delete, smp_unfix_fix, smp_select_delete, otp_8166,
+ exit_large_table_owner,
+ exit_many_large_table_owner,
+ exit_many_tables_owner,
+ exit_many_many_tables_owner,
+ write_concurrency, heir, give_away, setopts,
+ bad_table
+ ].
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+t_bucket_disappears(suite) ->
+ [];
+t_bucket_disappears(doc) ->
+ ["Test that a disappearing bucket during select of a non-fixed table works."];
+t_bucket_disappears(Config) when is_list(Config) ->
+ repeat_for_opts(t_bucket_disappears_do).
+
+t_bucket_disappears_do(Opts) ->
+ ?line EtsMem = etsmem(),
+ ?line ets:new(abcd, [named_table, public, {keypos, 2} | Opts]),
+ ?line ets:insert(abcd, {abcd,1,2}),
+ ?line ets:insert(abcd, {abcd,2,2}),
+ ?line ets:insert(abcd, {abcd,3,2}),
+ ?line {_, Cont} = ets:select(abcd, [{{'_', '$1', '_'},
+ [{'<', '$1', {const, 10}}],
+ ['$1']}], 1),
+ ?line ets:delete(abcd, 2),
+ ?line ets:select(Cont),
+ ?line true = ets:delete(abcd),
+ ?line verify_etsmem(EtsMem).
+
+
+t_match_spec_run(suite) ->
+ [];
+t_match_spec_run(doc) ->
+ ["Check ets:match_spec_run/2."];
+t_match_spec_run(Config) when is_list(Config) ->
+ ?line EtsMem = etsmem(),
+ ?line [2,3] = ets:match_spec_run([{1},{2},{3}],
+ ets:match_spec_compile(
+ [{{'$1'},[{'>','$1',1}],['$1']}])),
+ ?line Huge = [{X} || X <- lists:seq(1,2500)],
+ ?line L = lists:seq(2476,2500),
+ ?line L = ets:match_spec_run(Huge,
+ ets:match_spec_compile(
+ [{{'$1'},[{'>','$1',2475}],['$1']}])),
+ ?line L2 = [{X*16#FFFFFFF} || X <- L],
+ ?line L2 = ets:match_spec_run(Huge,
+ ets:match_spec_compile(
+ [{{'$1'},
+ [{'>','$1',2475}],
+ [{{{'*','$1',16#FFFFFFF}}}]}])),
+ ?line [500,1000,1500,2000,2500] =
+ ets:match_spec_run(Huge,
+ ets:match_spec_compile(
+ [{{'$1'},
+ [{'=:=',{'rem','$1',500},0}],
+ ['$1']}])),
+ ?line verify_etsmem(EtsMem).
+
+
+
+t_repair_continuation(suite) ->
+ [];
+t_repair_continuation(doc) ->
+ ["Check ets:repair_continuation/2."];
+t_repair_continuation(Config) when is_list(Config) ->
+ repeat_for_opts(t_repair_continuation_do).
+
+
+t_repair_continuation_do(Opts) ->
+ ?line EtsMem = etsmem(),
+ ?line MS = [{'_',[],[true]}],
+ ?line MS2 = [{{{'$1','_'},'_'},[],['$1']}],
+ (fun() ->
+ ?line T = ets:new(x,[ordered_set|Opts]),
+ ?line F = fun(0,_)->ok;(N,F) -> ets:insert(T,{N,N}), F(N-1,F) end,
+ ?line F(1000,F),
+ ?line {_,C} = ets:select(T,MS,5),
+ ?line C2 = erlang:setelement(5,C,<<>>),
+ ?line {'EXIT',{badarg,_}} = (catch ets:select(C2)),
+ ?line C3 = ets:repair_continuation(C2,MS),
+ ?line {[true,true,true,true,true],_} = ets:select(C3),
+ ?line {[true,true,true,true,true],_} = ets:select(C),
+ ?line true = ets:delete(T)
+ end)(),
+ (fun() ->
+ ?line T = ets:new(x,[ordered_set|Opts]),
+ ?line F = fun(0,_)->ok;(N,F) -> ets:insert(T,{N,N}), F(N-1,F) end,
+ ?line F(1000,F),
+ ?line {_,C} = ets:select(T,MS,1001),
+ ?line C = '$end_of_table',
+ ?line C3 = ets:repair_continuation(C,MS),
+ ?line '$end_of_table' = ets:select(C3),
+ ?line '$end_of_table' = ets:select(C),
+ ?line true = ets:delete(T)
+ end)(),
+
+ (fun() ->
+ ?line T = ets:new(x,[ordered_set|Opts]),
+ ?line F = fun(0,_)->ok;(N,F) ->
+ ets:insert(T,{integer_to_list(N),N}),
+ F(N-1,F)
+ end,
+ ?line F(1000,F),
+ ?line {_,C} = ets:select(T,MS,5),
+ ?line C2 = erlang:setelement(5,C,<<>>),
+ ?line {'EXIT',{badarg,_}} = (catch ets:select(C2)),
+ ?line C3 = ets:repair_continuation(C2,MS),
+ ?line {[true,true,true,true,true],_} = ets:select(C3),
+ ?line {[true,true,true,true,true],_} = ets:select(C),
+ ?line true = ets:delete(T)
+ end)(),
+ (fun() ->
+ ?line T = ets:new(x,[ordered_set|Opts]),
+ ?line F = fun(0,_)->ok;(N,F) ->
+ ets:insert(T,{{integer_to_list(N),N},N}),
+ F(N-1,F)
+ end,
+ ?line F(1000,F),
+ ?line {_,C} = ets:select(T,MS2,5),
+ ?line C2 = erlang:setelement(5,C,<<>>),
+ ?line {'EXIT',{badarg,_}} = (catch ets:select(C2)),
+ ?line C3 = ets:repair_continuation(C2,MS2),
+ ?line {[_,_,_,_,_],_} = ets:select(C3),
+ ?line {[_,_,_,_,_],_} = ets:select(C),
+ ?line true = ets:delete(T)
+ end)(),
+
+ (fun() ->
+ ?line T = ets:new(x,[set|Opts]),
+ ?line F = fun(0,_)->ok;(N,F) ->
+ ets:insert(T,{N,N}),
+ F(N-1,F)
+ end,
+ ?line F(1000,F),
+ ?line {_,C} = ets:select(T,MS,5),
+ ?line C2 = erlang:setelement(4,C,<<>>),
+ ?line {'EXIT',{badarg,_}} = (catch ets:select(C2)),
+ ?line C3 = ets:repair_continuation(C2,MS),
+ ?line {[true,true,true,true,true],_} = ets:select(C3),
+ ?line {[true,true,true,true,true],_} = ets:select(C),
+ ?line true = ets:delete(T)
+ end)(),
+ (fun() ->
+ ?line T = ets:new(x,[set|Opts]),
+ ?line F = fun(0,_)->ok;(N,F) ->
+ ets:insert(T,{integer_to_list(N),N}),
+ F(N-1,F)
+ end,
+ ?line F(1000,F),
+ ?line {_,C} = ets:select(T,MS,5),
+ ?line C2 = erlang:setelement(4,C,<<>>),
+ ?line {'EXIT',{badarg,_}} = (catch ets:select(C2)),
+ ?line C3 = ets:repair_continuation(C2,MS),
+ ?line {[true,true,true,true,true],_} = ets:select(C3),
+ ?line {[true,true,true,true,true],_} = ets:select(C),
+ ?line true = ets:delete(T)
+ end)(),
+ (fun() ->
+ ?line T = ets:new(x,[bag|Opts]),
+ ?line F = fun(0,_)->ok;(N,F) ->
+ ets:insert(T,{integer_to_list(N),N}),
+ F(N-1,F)
+ end,
+ ?line F(1000,F),
+ ?line {_,C} = ets:select(T,MS,5),
+ ?line C2 = erlang:setelement(4,C,<<>>),
+ ?line {'EXIT',{badarg,_}} = (catch ets:select(C2)),
+ ?line C3 = ets:repair_continuation(C2,MS),
+ ?line {[true,true,true,true,true],_} = ets:select(C3),
+ ?line {[true,true,true,true,true],_} = ets:select(C),
+ ?line true = ets:delete(T)
+ end)(),
+ (fun() ->
+ ?line T = ets:new(x,[duplicate_bag|Opts]),
+ ?line F = fun(0,_)->ok;(N,F) ->
+ ets:insert(T,{integer_to_list(N),N}),
+ F(N-1,F)
+ end,
+ ?line F(1000,F),
+ ?line {_,C} = ets:select(T,MS,5),
+ ?line C2 = erlang:setelement(4,C,<<>>),
+ ?line {'EXIT',{badarg,_}} = (catch ets:select(C2)),
+ ?line C3 = ets:repair_continuation(C2,MS),
+ ?line {[true,true,true,true,true],_} = ets:select(C3),
+ ?line {[true,true,true,true,true],_} = ets:select(C),
+ ?line true = ets:delete(T)
+ end)(),
+ ?line false = ets:is_compiled_ms(<<>>),
+ ?line true = ets:is_compiled_ms(ets:match_spec_compile(MS)),
+ ?line verify_etsmem(EtsMem).
+
+new(suite) -> [default,setbag,badnew,verybadnew,named,keypos2,privacy].
+
+default(doc) ->
+ ["Test case to check that a new ets table is defined as a `set' and "
+ "`protected'"];
+default(suite) -> [];
+default(Config) when is_list(Config) ->
+ %% Default should be set,protected
+ repeat_for_opts(default_do).
+
+default_do(Opts) ->
+ ?line EtsMem = etsmem(),
+ ?line Def = ets:new(def,Opts),
+ ?line set = ets:info(Def,type),
+ ?line protected = ets:info(Def,protection),
+ ?line ets:delete(Def),
+ ?line verify_etsmem(EtsMem).
+
+select_fail(doc) ->
+ ["Test that select fails even if nothing can match"];
+select_fail(suite) ->
+ [];
+select_fail(Config) when is_list(Config) ->
+ ?line EtsMem = etsmem(),
+ repeat_for_opts(select_fail_do, [all_types,write_concurrency]),
+ ?line verify_etsmem(EtsMem).
+
+select_fail_do(Opts) ->
+ ?line T = ets:new(x,Opts),
+ ?line ets:insert(T,{a,a}),
+ ?line case (catch
+ ets:select(T,[{{a,'_'},[],[{snuffla}]}])) of
+ {'EXIT',{badarg,_}} ->
+ ok;
+ Else0 ->
+ exit({type,ets:info(T,type),
+ expected,'EXIT',got,Else0})
+ end,
+ ?line case (catch
+ ets:select(T,[{{b,'_'},[],[{snuffla}]}])) of
+ {'EXIT',{badarg,_}} ->
+ ok;
+ Else1 ->
+ exit({type,ets:info(T,type),
+ expected,'EXIT',got,Else1})
+ end,
+ ?line ets:delete(T).
+
+
+-define(S(T),ets:info(T,memory)).
+-define(TAB_STRUCT_SZ, erts_debug:get_internal_state('DbTable_words')).
+-define(NORMAL_TAB_STRUCT_SZ, 26). %% SunOS5.8, 32-bit, non smp, private heap
+%%
+%% The hardcoded expected memory sizes (in words) are the ones we expect on:
+%% SunOS5.8, 32-bit, non smp, private heap
+%%
+memory(doc) ->
+ ["Whitebox test of ets:info(X,memory)"];
+memory(suite) ->
+ [];
+memory(Config) when is_list(Config) ->
+ ?line erts_debug:set_internal_state(available_internal_state, true),
+ ?line ok = chk_normal_tab_struct_size(),
+ ?line L = [T1,T2,T3,T4] = fill_sets_int(1000),
+ ?line XRes1 = adjust_xmem(L, {16862,16072,16072,16078}),
+ ?line Res1 = {?S(T1),?S(T2),?S(T3),?S(T4)},
+ ?line lists:foreach(fun(T) ->
+ Before = ets:info(T,size),
+ Key = 2, %894, %%ets:first(T),
+ Objs = ets:lookup(T,Key),
+ ?line ets:delete(T,Key),
+ io:format("deleted key ~p from ~p changed size ~p to ~p: ~p\n",
+ [Key, ets:info(T,type), Before, ets:info(T,size), Objs])
+ end,
+ L),
+ ?line XRes2 = adjust_xmem(L, {16849,16060,16048,16054}),
+ ?line Res2 = {?S(T1),?S(T2),?S(T3),?S(T4)},
+ ?line lists:foreach(fun(T) ->
+ Before = ets:info(T,size),
+ Key = 4, %802, %ets:first(T),
+ Objs = ets:lookup(T,Key),
+ ?line ets:match_delete(T,{Key,'_'}),
+ io:format("match_deleted key ~p from ~p changed size ~p to ~p: ~p\n",
+ [Key, ets:info(T,type), Before, ets:info(T,size), Objs])
+ end,
+ L),
+ ?line XRes3 = adjust_xmem(L, {16836,16048,16024,16030}),
+ ?line Res3 = {?S(T1),?S(T2),?S(T3),?S(T4)},
+ ?line lists:foreach(fun(T) ->
+ ?line ets:delete_all_objects(T)
+ end,
+ L),
+ ?line XRes4 = adjust_xmem(L, {76,286,286,286}),
+ ?line Res4 = {?S(T1),?S(T2),?S(T3),?S(T4)},
+ lists:foreach(fun(T) ->
+ ?line ets:delete(T)
+ end,
+ L),
+ ?line L2 = [T11,T12,T13,T14] = fill_sets_int(1000),
+ ?line lists:foreach(fun(T) ->
+ ?line ets:select_delete(T,[{'_',[],[true]}])
+ end,
+ L2),
+ ?line XRes5 = adjust_xmem(L2, {76,286,286,286}),
+ ?line Res5 = {?S(T11),?S(T12),?S(T13),?S(T14)},
+ ?line ?t:format("XRes1 = ~p~n"
+ " Res1 = ~p~n~n"
+ "XRes2 = ~p~n"
+ " Res2 = ~p~n~n"
+ "XRes3 = ~p~n"
+ " Res3 = ~p~n~n"
+ "XRes4 = ~p~n"
+ " Res4 = ~p~n~n"
+ "XRes5 = ~p~n"
+ " Res5 = ~p~n~n",
+ [XRes1, Res1,
+ XRes2, Res2,
+ XRes3, Res3,
+ XRes4, Res4,
+ XRes5, Res5]),
+ ?line XRes1 = Res1,
+ ?line XRes2 = Res2,
+ ?line XRes3 = Res3,
+ ?line XRes4 = Res4,
+ ?line XRes5 = Res5,
+ ?line catch erts_debug:set_internal_state(available_internal_state, false),
+ ?line ok.
+
+chk_normal_tab_struct_size() ->
+ ?line System = {os:type(),
+ os:version(),
+ erlang:system_info(wordsize),
+ erlang:system_info(smp_support),
+ erlang:system_info(heap_type)},
+ ?line ?t:format("System = ~p~n", [System]),
+ ?line ?t:format("?NORMAL_TAB_STRUCT_SZ=~p~n", [?NORMAL_TAB_STRUCT_SZ]),
+ ?line ?t:format("?TAB_STRUCT_SZ=~p~n", [?TAB_STRUCT_SZ]),
+ ?line case System of
+ {{unix, sunos}, {5, 8, 0}, 4, false, private} ->
+ ?line ?NORMAL_TAB_STRUCT_SZ = ?TAB_STRUCT_SZ,
+ ?line ok;
+ _ ->
+ ?line ok
+ end.
+
+adjust_xmem([T1,T2,T3,T4], {A0,B0,C0,D0} = Mem0) ->
+ %% Adjust for 64-bit, smp, and os:
+ %% Table struct size may differ.
+ Mem1 = case ?TAB_STRUCT_SZ of
+ ?NORMAL_TAB_STRUCT_SZ ->
+ Mem0;
+ TabStructSz ->
+ TabDiff = TabStructSz - ?NORMAL_TAB_STRUCT_SZ,
+ {A0+TabDiff, B0+TabDiff, C0+TabDiff, D0+TabDiff}
+ end,
+ %% Adjust for hybrid and shared heaps:
+ %% Each record is one word smaller.
+ Mem2 = case erlang:system_info(heap_type) of
+ private ->
+ Mem1;
+ _ ->
+ {A1,B1,C1,D1} = Mem1,
+ {A1-ets:info(T1, size),B1-ets:info(T2, size),
+ C1-ets:info(T3, size),D1-ets:info(T4, size)}
+ end,
+ %%{Mem2,{ets:info(T1,stats),ets:info(T2,stats),ets:info(T3,stats),ets:info(T4,stats)}}.
+ Mem2.
+
+t_whitebox(doc) ->
+ ["Diverse whitebox testes"];
+t_whitebox(suite) ->
+ [];
+t_whitebox(Config) when is_list(Config) ->
+ ?line EtsMem = etsmem(),
+ repeat_for_opts(whitebox_1),
+ repeat_for_opts(whitebox_1),
+ repeat_for_opts(whitebox_1),
+ repeat_for_opts(whitebox_2),
+ repeat_for_opts(whitebox_2),
+ repeat_for_opts(whitebox_2),
+ ?line verify_etsmem(EtsMem).
+
+whitebox_1(Opts) ->
+ ?line T=ets:new(x,[bag | Opts]),
+ ?line ets:insert(T,[{du,glade},{ta,en}]),
+ ?line ets:insert(T,[{hej,hopp2},{du,glade2},{ta,en2}]),
+ ?line {_,C}=ets:match(T,{ta,'$1'},1),
+ ?line ets:select(C),
+ ?line ets:match(C),
+ ?line ets:delete(T),
+ ok.
+
+whitebox_2(Opts) ->
+ ?line T=ets:new(x,[ordered_set, {keypos,2} | Opts]),
+ ?line T2=ets:new(x,[set, {keypos,2}| Opts]),
+ ?line 0 = ets:select_delete(T,[{{hej},[],[true]}]),
+ ?line 0 = ets:select_delete(T,[{{hej,hopp},[],[true]}]),
+ ?line 0 = ets:select_delete(T2,[{{hej},[],[true]}]),
+ ?line 0 = ets:select_delete(T2,[{{hej,hopp},[],[true]}]),
+ ?line ets:delete(T),
+ ?line ets:delete(T2),
+ ok.
+
+
+t_ets_dets(doc) ->
+ ["Test ets:to/from_dets"];
+t_ets_dets(suite) ->
+ [];
+t_ets_dets(Config) when is_list(Config) ->
+ repeat_for_opts(fun(Opts) -> t_ets_dets(Config,Opts) end).
+
+t_ets_dets(Config, Opts) ->
+ ?line Fname = gen_dets_filename(Config,1),
+ ?line (catch file:delete(Fname)),
+ ?line {ok,DTab} = dets:open_file(testdets_1,
+ [{file, Fname}]),
+ ?line ETab = ets:new(x,Opts),
+ ?line filltabint(ETab,3000),
+ ?line DTab = ets:to_dets(ETab,DTab),
+ ?line ets:delete_all_objects(ETab),
+ ?line 0 = ets:info(ETab,size),
+ ?line true = ets:from_dets(ETab,DTab),
+ ?line 3000 = ets:info(ETab,size),
+ ?line ets:delete(ETab),
+ ?line {'EXIT',{badarg,[{ets,to_dets,[ETab,DTab]}|_]}} =
+ (catch ets:to_dets(ETab,DTab)),
+ ?line {'EXIT',{badarg,[{ets,from_dets,[ETab,DTab]}|_]}} =
+ (catch ets:from_dets(ETab,DTab)),
+ ?line ETab2 = ets:new(x,Opts),
+ ?line filltabint(ETab2,3000),
+ ?line dets:close(DTab),
+ ?line {'EXIT',{badarg,[{ets,to_dets,[ETab2,DTab]}|_]}} =
+ (catch ets:to_dets(ETab2,DTab)),
+ ?line {'EXIT',{badarg,[{ets,from_dets,[ETab2,DTab]}|_]}} =
+ (catch ets:from_dets(ETab2,DTab)),
+ ?line ets:delete(ETab2),
+ ?line (catch file:delete(Fname)),
+ ok.
+
+t_delete_all_objects(doc) ->
+ ["Test ets:delete_all_objects/1"];
+t_delete_all_objects(suite) ->
+ [];
+t_delete_all_objects(Config) when is_list(Config) ->
+ ?line EtsMem = etsmem(),
+ repeat_for_opts(t_delete_all_objects_do),
+ ?line verify_etsmem(EtsMem).
+
+t_delete_all_objects_do(Opts) ->
+ ?line T=ets:new(x,Opts),
+ ?line filltabint(T,4000),
+ ?line O=ets:first(T),
+ ?line ets:next(T,O),
+ ?line ets:safe_fixtable(T,true),
+ ?line true = ets:delete_all_objects(T),
+ ?line '$end_of_table' = ets:next(T,O),
+ ?line 0 = ets:info(T,size),
+ ?line 4000 = ets:info(T,kept_objects),
+ ?line ets:safe_fixtable(T,false),
+ ?line 0 = ets:info(T,size),
+ ?line 0 = ets:info(T,kept_objects),
+ ?line filltabint(T,4000),
+ ?line 4000 = ets:info(T,size),
+ ?line true = ets:delete_all_objects(T),
+ ?line 0 = ets:info(T,size),
+ ?line ets:delete(T).
+
+
+t_delete_object(doc) ->
+ ["Test ets:delete_object/2"];
+t_delete_object(suite) ->
+ [];
+t_delete_object(Config) when is_list(Config) ->
+ ?line EtsMem = etsmem(),
+ repeat_for_opts(t_delete_object_do),
+ ?line verify_etsmem(EtsMem).
+
+t_delete_object_do(Opts) ->
+ ?line T = ets:new(x,Opts),
+ ?line filltabint(T,4000),
+ ?line del_one_by_one_set(T,1,4001),
+ ?line filltabint(T,4000),
+ ?line del_one_by_one_set(T,4000,0),
+ ?line filltabint(T,4000),
+ ?line First = ets:first(T),
+ ?line Next = ets:next(T,First),
+ ?line ets:safe_fixtable(T,true),
+ ?line ets:delete_object(T,{First, integer_to_list(First)}),
+ ?line Next = ets:next(T,First),
+ ?line 3999 = ets:info(T,size),
+ ?line 1 = ets:info(T,kept_objects),
+ ?line ets:safe_fixtable(T,false),
+ ?line 3999 = ets:info(T,size),
+ ?line 0 = ets:info(T,kept_objects),
+ ?line ets:delete(T),
+ ?line T1 = ets:new(x,[ordered_set | Opts]),
+ ?line filltabint(T1,4000),
+ ?line del_one_by_one_set(T1,1,4001),
+ ?line filltabint(T1,4000),
+ ?line del_one_by_one_set(T1,4000,0),
+ ?line ets:delete(T1),
+ ?line T2 = ets:new(x,[bag | Opts]),
+ ?line filltabint2(T2,4000),
+ ?line del_one_by_one_bag(T2,1,4001),
+ ?line filltabint2(T2,4000),
+ ?line del_one_by_one_bag(T2,4000,0),
+ ?line ets:delete(T2),
+ ?line T3 = ets:new(x,[duplicate_bag | Opts]),
+ ?line filltabint3(T3,4000),
+ ?line del_one_by_one_dbag_1(T3,1,4001),
+ ?line filltabint3(T3,4000),
+ ?line del_one_by_one_dbag_1(T3,4000,0),
+ ?line filltabint(T3,4000),
+ ?line filltabint3(T3,4000),
+ ?line del_one_by_one_dbag_2(T3,1,4001),
+ ?line filltabint(T3,4000),
+ ?line filltabint3(T3,4000),
+ ?line del_one_by_one_dbag_2(T3,4000,0),
+
+ ?line filltabint2(T3,4000),
+ ?line filltabint(T3,4000),
+ ?line del_one_by_one_dbag_3(T3,4000,0),
+ ?line ets:delete(T3),
+ ok.
+
+make_init_fun(N) when N > 4000->
+ fun(read) ->
+ end_of_input;
+ (close) ->
+ exit(close_not_expected)
+ end;
+make_init_fun(N) ->
+ fun(read) ->
+ case N rem 2 of
+ 0 ->
+ {[{N, integer_to_list(N)}, {N, integer_to_list(N)}],
+ make_init_fun(N + 1)};
+ 1 ->
+ {[], make_init_fun(N + 1)}
+ end;
+ (close) ->
+ exit(close_not_expected)
+ end.
+
+t_init_table(doc) ->
+ ["Test ets:init_table/2"];
+t_init_table(suite) ->
+ [];
+t_init_table(Config) when is_list(Config)->
+ ?line EtsMem = etsmem(),
+ repeat_for_opts(t_init_table_do),
+ ?line verify_etsmem(EtsMem).
+
+t_init_table_do(Opts) ->
+ ?line T = ets:new(x,[duplicate_bag | Opts]),
+ ?line filltabint(T,4000),
+ ?line ets:init_table(T, make_init_fun(1)),
+ ?line del_one_by_one_dbag_1(T,4000,0),
+ ?line ets:delete(T),
+ ok.
+
+do_fill_dbag_using_lists(T,0) ->
+ T;
+do_fill_dbag_using_lists(T,N) ->
+ ets:insert(T,[{N,integer_to_list(N)},
+ {N + N rem 2,integer_to_list(N + N rem 2)}]),
+ do_fill_dbag_using_lists(T,N - 1).
+
+
+t_insert_new(doc) ->
+ ["Test the insert_new function"];
+t_insert_new(suite) ->
+ [];
+t_insert_new(Config) when is_list(Config) ->
+ ?line EtsMem = etsmem(),
+ ?line L = fill_sets_int(1000) ++ fill_sets_int(1000,[{write_concurrency,true}]),
+ lists:foreach(fun(Tab) ->
+ ?line false = ets:insert_new(Tab,{2,"2"}),
+ ?line true = ets:insert_new(Tab,{2002,"2002"}),
+ ?line false = ets:insert_new(Tab,{2002,"2002"}),
+ ?line true = ets:insert(Tab,{2002,"2002"}),
+ ?line false = ets:insert_new(Tab,[{2002,"2002"}]),
+ ?line false = ets:insert_new(Tab,[{2002,"2002"},
+ {2003,"2003"}]),
+ ?line false = ets:insert_new(Tab,[{2001,"2001"},
+ {2002,"2002"},
+ {2003,"2003"}]),
+ ?line false = ets:insert_new(Tab,[{2001,"2001"},
+ {2002,"2002"}]),
+ ?line true = ets:insert_new(Tab,[{2001,"2001"},
+ {2003,"2003"}]),
+ ?line false = ets:insert_new(Tab,{2001,"2001"}),
+ ?line false = ets:insert_new(Tab,{2002,"2002"}),
+ ?line false = ets:insert_new(Tab,{2003,"2003"}),
+ ?line true = ets:insert_new(Tab,{2004,"2004"}),
+ ?line true = ets:insert_new(Tab,{2000,"2000"}),
+ ?line true = ets:insert_new(Tab,[{2005,"2005"},
+ {2006,"2006"},
+ {2007,"2007"}]),
+ ?line Num =
+ case ets:info(Tab,type) of
+ bag ->
+ ?line true =
+ ets:insert(Tab,{2004,"2004-2"}),
+ ?line false =
+ ets:insert_new(Tab,{2004,"2004-3"}),
+ 1009;
+ duplicate_bag ->
+ ?line true =
+ ets:insert(Tab,{2004,"2004"}),
+ ?line false =
+ ets:insert_new(Tab,{2004,"2004"}),
+ 1010;
+ _ ->
+ 1008
+ end,
+ ?line Num = ets:info(Tab,size),
+ ?line List = ets:tab2list(Tab),
+ ?line ets:delete_all_objects(Tab),
+ ?line true = ets:insert_new(Tab,List),
+ ?line false = ets:insert_new(Tab,List),
+ ?line ets:delete(Tab)
+ end,
+ L),
+ ?line verify_etsmem(EtsMem).
+
+t_insert_list(doc) ->
+ ["Test ets:insert/2 with list of objects."];
+t_insert_list(suite) ->
+ [];
+t_insert_list(Config) when is_list(Config) ->
+ ?line EtsMem = etsmem(),
+ repeat_for_opts(t_insert_list_do),
+ ?line verify_etsmem(EtsMem).
+
+t_insert_list_do(Opts) ->
+ ?line T = ets:new(x,[duplicate_bag | Opts]),
+ ?line do_fill_dbag_using_lists(T,4000),
+ ?line del_one_by_one_dbag_2(T,4000,0),
+ ?line ets:delete(T).
+
+
+t_test_ms(doc) ->
+ ["Test interface of ets:test_ms/2"];
+t_test_ms(suite) ->
+ [];
+t_test_ms(Config) when is_list(Config) ->
+ ?line EtsMem = etsmem(),
+ ?line {ok,[a,b]} = ets:test_ms({a,b},
+ [{{'$1','$2'},[{'<','$1','$2'}],['$$']}]),
+ ?line {ok,false} = ets:test_ms({a,b},
+ [{{'$1','$2'},[{'>','$1','$2'}],['$$']}]),
+ ?line {error,[{error,String}]} = ets:test_ms({a,b},
+ [{{'$1','$2'},
+ [{'flurp','$1','$2'}],
+ ['$$']}]),
+ ?line true = (if is_list(String) -> true; true -> false end),
+ ?line verify_etsmem(EtsMem).
+
+t_select_delete(doc) ->
+ ["Test the ets:select_delete/2 and ets:select_count/2 BIF's"];
+t_select_delete(suite) ->
+ [];
+t_select_delete(Config) when is_list(Config) ->
+ ?line EtsMem = etsmem(),
+ ?line Tables = fill_sets_int(10000) ++ fill_sets_int(10000,[{write_concurrency,true}]),
+ lists:foreach
+ (fun(Table) ->
+ ?line 4000 = ets:select_count(Table,[{{'$1', '_'},
+ [{'>',
+ {'rem',
+ '$1', 5},
+ 2}],
+ [true]}]),
+ ?line 4000 = ets:select_delete(Table,[{{'$1', '_'},
+ [{'>',
+ {'rem',
+ '$1', 5},
+ 2}],
+ [true]}]),
+ ?line check(Table,
+ fun({N,_}) when (N rem 5) =< 2 ->
+ true;
+ (_) ->
+ false
+ end,
+ 6000)
+
+ end,
+ Tables),
+ lists:foreach
+ (fun(Table) ->
+ ?line ets:select_delete(Table,[{'_',[],[true]}]),
+ ?line xfilltabint(Table,4000),
+ ?line successive_delete(Table,1,4001,bound),
+ ?line 0 = ets:info(Table,size),
+ ?line xfilltabint(Table,4000),
+ ?line successive_delete(Table,4000,0, bound),
+ ?line 0 = ets:info(Table,size),
+ ?line xfilltabint(Table,4000),
+ ?line successive_delete(Table,1,4001,unbound),
+ ?line 0 = ets:info(Table,size),
+ ?line xfilltabint(Table,4000),
+ ?line successive_delete(Table,4000,0, unbound),
+ ?line 0 = ets:info(Table,size)
+
+ end,
+ Tables),
+ lists:foreach
+ (fun(Table) ->
+ F = case ets:info(Table,type) of
+ X when X == bag; X == duplicate_bag ->
+ 2;
+ _ ->
+ 1
+ end,
+ ?line xfilltabstr(Table, 4000),
+ ?line 1000 = ets:select_count(Table,
+ [{{[$3 | '$1'], '_'},
+ [{'==',
+ {'length', '$1'},
+ 3}],[true]}]) div F,
+ ?line 1000 = ets:select_delete(Table,
+ [{{[$3 | '$1'], '_'},
+ [{'==',
+ {'length', '$1'},
+ 3}],[true]}]) div F,
+ ?line check(Table, fun({[3,_,_,_],_}) -> false;
+ (_) -> true
+ end, 3000*F),
+ ?line 8 = ets:select_count(Table,
+ [{{"7",'_'},[],[false]},
+ {{['_'], '_'},
+ [],[true]}]) div F,
+ ?line 8 = ets:select_delete(Table,
+ [{{"7",'_'},[],[false]},
+ {{['_'], '_'},
+ [],[true]}]) div F,
+ ?line check(Table, fun({"7",_}) -> true;
+ ({[_],_}) -> false;
+ (_) -> true
+ end, 2992*F),
+ ?line xfilltabstr(Table, 4000),
+ %% This happens to be interesting for other select types too
+ ?line 200 = length(ets:select(Table,
+ [{{[$3,'_','_'],'_'},
+ [],[true]},
+ {{[$1,'_','_'],'_'},
+ [],[true]}])) div F,
+ ?line 200 = ets:select_count(Table,
+ [{{[$3,'_','_'],'_'},
+ [],[true]},
+ {{[$1,'_','_'],'_'},
+ [],[true]}]) div F,
+ ?line 200 = length(element(1,ets:select(Table,
+ [{{[$3,'_','_'],'_'},
+ [],[true]},
+ {{[$1,'_','_'],'_'},
+ [],[true]}],
+ 1000))) div F,
+ ?line 200 = length(
+ ets:select_reverse(Table,
+ [{{[$3,'_','_'],'_'},
+ [],[true]},
+ {{[$1,'_','_'],'_'},
+ [],[true]}])) div F,
+ ?line 200 = length(
+ element(1,
+ ets:select_reverse
+ (Table,
+ [{{[$3,'_','_'],'_'},
+ [],[true]},
+ {{[$1,'_','_'],'_'},
+ [],[true]}],
+ 1000))) div F,
+ ?line 200 = ets:select_delete(Table,
+ [{{[$3,'_','_'],'_'},
+ [],[true]},
+ {{[$1,'_','_'],'_'},
+ [],[true]}]) div F,
+ ?line 0 = ets:select_count(Table,
+ [{{[$3,'_','_'],'_'},
+ [],[true]},
+ {{[$1,'_','_'],'_'},
+ [],[true]}]) div F,
+ ?line check(Table, fun({[$3,_,_],_}) -> false;
+ ({[$1,_,_],_}) -> false;
+ (_) -> true
+ end, 3800*F)
+ end,
+ Tables),
+ lists:foreach(fun(Tab) -> ets:delete(Tab) end,Tables),
+ ?line verify_etsmem(EtsMem).
+
+partly_bound(doc) ->
+ ["Test that partly bound keys gives faster matches"];
+partly_bound(suite) ->
+ [];
+partly_bound(Config) when is_list(Config) ->
+ case os:type() of
+ {win32,_} ->
+ {skip,"Inaccurate measurements on Windows"};
+ _ ->
+ ?line EtsMem = etsmem(),
+ ?line dont_make_worse(),
+ ?line make_better(),
+ ?line verify_etsmem(EtsMem)
+ end.
+
+dont_make_worse() ->
+ seventyfive_percent_success({?MODULE,dont_make_worse_sub,[]},0,0,10).
+
+dont_make_worse_sub() ->
+ ?line T = build_table([a,b],[a,b],15000),
+ ?line T1 = time_match_object(T,{'_',a,a,1500}, [{{a,a,1500},a,a,1500}]),
+ ?line T2 = time_match_object(T,{{a,a,'_'},a,a,1500},
+ [{{a,a,1500},a,a,1500}]),
+ ?line ets:delete(T),
+ ?line true = (T1 > T2),
+ ok.
+
+make_better() ->
+ fifty_percent_success({?MODULE,make_better_sub2,[]},0,0,10),
+ fifty_percent_success({?MODULE,make_better_sub1,[]},0,0,10).
+make_better_sub1() ->
+ ?line T = build_table2([a,b],[a,b],15000),
+ ?line T1 = time_match_object(T,{'_',1500,a,a}, [{{1500,a,a},1500,a,a}]),
+ ?line T2 = time_match_object(T,{{1500,a,'_'},1500,a,a},
+ [{{1500,a,a},1500,a,a}]),
+ ?line ets:delete(T),
+ ?line io:format("~p>~p~n",[(T1 / 100),T2]),
+ ?line true = ((T1 / 100) > T2), % More marginal than needed.
+ ok.
+
+make_better_sub2() ->
+ ?line T = build_table2([a,b],[a,b],15000),
+ ?line T1 = time_match(T,{'$1',1500,a,a}),
+ ?line T2 = time_match(T,{{1500,a,'$1'},1500,a,a}),
+ ?line ets:delete(T),
+ ?line io:format("~p>~p~n",[(T1 / 100),T2]),
+ ?line true = ((T1 / 100) > T2), % More marginal than needed.
+ ok.
+
+
+match_heavy(doc) ->
+ ["Heavy random matching, comparing set with ordered_set."];
+match_heavy(suite) ->
+ [];
+match_heavy(Config) when is_list(Config) ->
+ PrivDir = ?config(priv_dir,Config),
+ DataDir = ?config(data_dir, Config),
+ %% Easier to have in process dictionary when manually
+ %% running the test function.
+ put(where_to_read,DataDir),
+ put(where_to_write,PrivDir),
+ Dog=?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+ NewDog=test_server:timetrap(test_server:seconds(1000)),
+ NewConfig = [{watchdog, NewDog} | lists:keydelete(watchdog,1,Config)],
+ random_test(),
+ drop_match(),
+ NewConfig.
+
+%%% Extra safety for the very low probability that this is not
+%%% caught by the random test (Statistically impossible???)
+drop_match() ->
+ ?line EtsMem = etsmem(),
+ ?line T = build_table([a,b],[a],1500),
+ ?line [{{a,a,1},a,a,1},{{b,a,1},b,a,1}] =
+ ets:match_object(T, {'_','_','_',1}),
+ ?line true = ets:delete(T),
+ ?line verify_etsmem(EtsMem).
+
+
+
+ets_match(Tab,Expr) ->
+ case random:uniform(2) of
+ 1 ->
+ ets:match(Tab,Expr);
+ _ ->
+ match_chunked(Tab,Expr)
+ end.
+
+match_chunked(Tab,Expr) ->
+ match_chunked_collect(ets:match(Tab,Expr,
+ random:uniform(1999) + 1)).
+match_chunked_collect('$end_of_table') ->
+ [];
+match_chunked_collect({Results, Continuation}) ->
+ Results ++ match_chunked_collect(ets:match(Continuation)).
+
+ets_match_object(Tab,Expr) ->
+ case random:uniform(2) of
+ 1 ->
+ ets:match_object(Tab,Expr);
+ _ ->
+ match_object_chunked(Tab,Expr)
+ end.
+
+match_object_chunked(Tab,Expr) ->
+ match_object_chunked_collect(ets:match_object(Tab,Expr,
+ random:uniform(1999) + 1)).
+match_object_chunked_collect('$end_of_table') ->
+ [];
+match_object_chunked_collect({Results, Continuation}) ->
+ Results ++ match_object_chunked_collect(ets:match_object(Continuation)).
+
+
+
+random_test() ->
+ ?line ReadDir = get(where_to_read),
+ ?line WriteDir = get(where_to_write),
+ ?line (catch file:make_dir(WriteDir)),
+ ?line Seed = case file:consult(filename:join([ReadDir,
+ "preset_random_seed.txt"])) of
+ {ok,[X]} ->
+ X;
+ _ ->
+ {A,B,C} = erlang:now(),
+ random:seed(A,B,C),
+ get(random_seed)
+ end,
+ put(random_seed,Seed),
+ ?line {ok, F} = file:open(filename:join([WriteDir,
+ "last_random_seed.txt"]),
+ [write]),
+ io:format(F,"~p. ~n",[Seed]),
+ file:close(F),
+ io:format("Random seed ~p written to ~s, copy to ~s to rerun with "
+ "same seed.",[Seed,
+ filename:join([WriteDir, "last_random_seed.txt"]),
+ filename:join([ReadDir,
+ "preset_random_seed.txt"])]),
+ do_random_test().
+
+do_random_test() ->
+ ?line EtsMem = etsmem(),
+ ?line OrdSet = ets:new(xxx,[ordered_set]),
+ ?line Set = ets:new(xxx,[]),
+ ?line do_n_times(fun() ->
+ ?line Key = create_random_string(25),
+ ?line Value = create_random_tuple(25),
+ ?line ets:insert(OrdSet,{Key,Value}),
+ ?line ets:insert(Set,{Key,Value})
+ end, 5000),
+ ?line io:format("~nData inserted~n"),
+ ?line do_n_times(fun() ->
+ ?line I = random:uniform(25),
+ ?line Key = create_random_string(I) ++ '_',
+ ?line L1 = ets_match_object(OrdSet,{Key,'_'}),
+ ?line L2 = lists:sort(ets_match_object(Set,{Key,'_'})),
+ case L1 == L2 of
+ false ->
+ io:format("~p != ~p~n",
+ [L1,L2]),
+ ?line exit({not_eq, L1, L2});
+ true ->
+ ok
+ end
+ end,
+ 2000),
+ ?line io:format("~nData matched~n"),
+ ?line ets:match_delete(OrdSet,'_'),
+ ?line ets:match_delete(Set,'_'),
+ ?line do_n_times(fun() ->
+ ?line Value = create_random_string(25),
+ ?line Key = create_random_tuple(25),
+ ?line ets:insert(OrdSet,{Key,Value}),
+ ?line ets:insert(Set,{Key,Value})
+ end, 2000),
+ ?line io:format("~nData inserted~n"),
+ (fun() ->
+ ?line Key = list_to_tuple(lists:duplicate(25,'_')),
+ ?line L1 = ets_match_object(OrdSet,{Key,'_'}),
+ ?line L2 = lists:sort(ets_match_object(Set,{Key,'_'})),
+ ?line 2000 = length(L1),
+ case L1 == L2 of
+ false ->
+ io:format("~p != ~p~n",
+ [L1,L2]),
+ ?line exit({not_eq, L1, L2});
+ true ->
+ ok
+ end
+ end)(),
+ (fun() ->
+ ?line Key = {'$1','$2','$3','$4',
+ '$5','$6','$7','$8',
+ '$9','$10','$11','$12',
+ '$13','$14','$15','$16',
+ '$17','$18','$19','$20',
+ '$21','$22','$23','$24',
+ '$25'},
+ ?line L1 = ets_match_object(OrdSet,{Key,'_'}),
+ ?line L2 = lists:sort(ets_match_object(Set,{Key,'_'})),
+ ?line 2000 = length(L1),
+ case L1 == L2 of
+ false ->
+ io:format("~p != ~p~n",
+ [L1,L2]),
+ ?line exit({not_eq, L1, L2});
+ true ->
+ ok
+ end
+ end)(),
+ (fun() ->
+ ?line Key = {'$1','$2','$3','$4',
+ '$5','$6','$7','$8',
+ '$9','$10','$11','$12',
+ '$13','$14','$15','$16',
+ '$17','$18','$19','$20',
+ '$21','$22','$23','$24',
+ '$25'},
+ ?line L1 = ets_match(OrdSet,{Key,'_'}),
+ ?line L2 = lists:sort(ets_match(Set,{Key,'_'})),
+ ?line 2000 = length(L1),
+ case L1 == L2 of
+ false ->
+ io:format("~p != ~p~n",
+ [L1,L2]),
+ ?line exit({not_eq, L1, L2});
+ true ->
+ ok
+ end
+ end)(),
+ ?line ets:match_delete(OrdSet,'_'),
+ ?line ets:match_delete(Set,'_'),
+ ?line do_n_times(fun() ->
+ ?line Value = create_random_string(25),
+ ?line Key = create_random_tuple(25),
+ ?line ets:insert(OrdSet,{Key,Value}),
+ ?line ets:insert(Set,{Key,Value})
+ end, 2000),
+ ?line io:format("~nData inserted~n"),
+ do_n_times(fun() ->
+ ?line Key = create_partly_bound_tuple(25),
+ ?line L1 = ets_match_object(OrdSet,{Key,'_'}),
+ ?line L2 = lists:sort(ets_match_object(Set,{Key,'_'})),
+ case L1 == L2 of
+ false ->
+ io:format("~p != ~p~n",
+ [L1,L2]),
+ ?line exit({not_eq, L1, L2});
+ true ->
+ ok
+ end
+ end,
+ 2000),
+ ?line do_n_times(fun() ->
+ ?line Key = create_partly_bound_tuple2(25),
+ ?line L1 = ets_match_object(OrdSet,{Key,'_'}),
+ ?line L2 = lists:sort(ets_match_object(Set,{Key,'_'})),
+ case L1 == L2 of
+ false ->
+ io:format("~p != ~p~n",
+ [L1,L2]),
+ ?line exit({not_eq, L1, L2});
+ true ->
+ ok
+ end
+ end,
+ 2000),
+ do_n_times(fun() ->
+ ?line Key = create_partly_bound_tuple2(25),
+ ?line L1 = ets_match(OrdSet,{Key,'_'}),
+ ?line L2 = lists:sort(ets_match(Set,{Key,'_'})),
+ case L1 == L2 of
+ false ->
+ io:format("~p != ~p~n",
+ [L1,L2]),
+ ?line exit({not_eq, L1, L2});
+ true ->
+ ok
+ end
+ end,
+ 2000),
+ io:format("~nData matched~n"),
+ ets:match_delete(OrdSet,'_'),
+ ets:match_delete(Set,'_'),
+ do_n_times(fun() ->
+ do_n_times(fun() ->
+ ?line Value =
+ create_random_string(25),
+ ?line Key = create_random_tuple(25),
+ ?line ets:insert(OrdSet,{Key,Value}),
+ ?line ets:insert(Set,{Key,Value})
+ end, 500),
+ io:format("~nData inserted~n"),
+ do_n_times(fun() ->
+ ?line Key =
+ create_partly_bound_tuple(25),
+ ets:match_delete(OrdSet,{Key,'_'}),
+ ets:match_delete(Set,{Key,'_'}),
+ L1 = ets:info(OrdSet,size),
+ L2 = ets:info(Set,size),
+ [] = ets_match_object(OrdSet,
+ {Key,'_'}),
+ case L1 == L2 of
+ false ->
+ io:format("~p != ~p "
+ "(deleted ~p)~n",
+ [L1,L2,Key]),
+ exit({not_eq, L1, L2,
+ {deleted,Key}});
+ true ->
+ ok
+ end
+ end,
+ 50),
+ io:format("~nData deleted~n")
+ end,
+ 10),
+ ets:delete(OrdSet),
+ ets:delete(Set),
+ ?line verify_etsmem(EtsMem).
+
+update_element(doc) ->
+ ["test various variants of update_element"];
+update_element(suite) ->
+ [];
+update_element(Config) when is_list(Config) ->
+ ?line EtsMem = etsmem(),
+ repeat_for_opts(update_element_opts),
+ ?line verify_etsmem(EtsMem).
+
+update_element_opts(Opts) ->
+ TupleCases = [{{key,val}, 1 ,2},
+ {{val,key}, 2, 1},
+ {{key,val}, 1 ,[2]},
+ {{key,val,val}, 1, [2,3]},
+ {{val,key,val,val}, 2, [3,4,1]},
+ {{val,val,key,val}, 3, [1,4,1,2]}, % update pos1 twice
+ {{val,val,val,key}, 4, [2,1,2,3]}],% update pos2 twice
+
+ lists:foreach(fun({Tuple,KeyPos,UpdPos}) -> update_element_opts(Tuple,KeyPos,UpdPos,Opts) end,
+ TupleCases),
+
+ update_element_neg(Opts).
+
+
+
+update_element_opts(Tuple,KeyPos,UpdPos,Opts) ->
+ Set = ets:new(set,[{keypos,KeyPos} | Opts]),
+ OrdSet = ets:new(ordered_set,[ordered_set,{keypos,KeyPos} | Opts]),
+ update_element(Set,Tuple,KeyPos,UpdPos),
+ update_element(OrdSet,Tuple,KeyPos,UpdPos),
+ true = ets:delete(Set),
+ true = ets:delete(OrdSet),
+ ok.
+
+update_element(T,Tuple,KeyPos,UpdPos) ->
+ KeyList = [Key || Key <- lists:seq(1,100)],
+ lists:foreach(fun(Key) ->
+ TupleWithKey = setelement(KeyPos,Tuple,Key),
+ update_element_do(T,TupleWithKey,Key,UpdPos)
+ end,
+ KeyList).
+
+update_element_do(Tab,Tuple,Key,UpdPos) ->
+
+ % Strategy: Step around in Values array and call ets:update_element for the values.
+ % Take Length number of steps of size 1, then of size 2, ..., Length-1.
+ % This will try all combinations of {fromValue,toValue}
+ %
+ % IMPORTANT: size(Values) must be a prime number for this to work!!!
+ Big32 = 16#12345678,
+ Big64 = 16#123456789abcdef0,
+ Values = { 623, -27, 0, Big32, -Big32, Big64, -Big64, Big32*Big32,
+ -Big32*Big32, Big32*Big64, -Big32*Big64, Big64*Big64, -Big64*Big64,
+ "A", "Sverker", [], {12,-132}, {},
+ <<45,232,0,12,133>>, <<234,12,23>>, list_to_binary(lists:seq(1,100)),
+ (fun(X) -> X*Big32 end),
+ make_ref(), make_ref(), self(), ok, update_element, 28, 29 },
+ Length = size(Values),
+
+ PosValArgF = fun(ToIx, ResList, [Pos | PosTail], Rand, MeF) ->
+ NextIx = (ToIx+Rand) rem Length,
+ MeF(NextIx, [{Pos,element(ToIx+1,Values)} | ResList], PosTail, Rand, MeF);
+
+ (_ToIx, ResList, [], _Rand, _MeF) ->
+ ResList;
+
+ (ToIx, [], Pos, _Rand, _MeF) ->
+ {Pos, element(ToIx+1,Values)} % single {pos,value} arg
+ end,
+
+ NewTupleF = fun({Pos,Val}, Tpl, _MeF) ->
+ setelement(Pos, Tpl, Val);
+ ([{Pos,Val} | Tail], Tpl, MeF) ->
+ MeF(Tail,setelement(Pos, Tpl, Val),MeF);
+ ([], Tpl, _MeF) ->
+ Tpl
+ end,
+
+ UpdateF = fun(ToIx,Rand) ->
+ PosValArg = PosValArgF(ToIx,[],UpdPos,Rand,PosValArgF),
+ %%io:format("update_element(~p)~n",[PosValArg]),
+ ArgHash = erlang:phash2({Tab,Key,PosValArg}),
+ ?line true = ets:update_element(Tab, Key, PosValArg),
+ ?line ArgHash = erlang:phash2({Tab,Key,PosValArg}),
+ NewTuple = NewTupleF(PosValArg,Tuple,NewTupleF),
+ ?line [NewTuple] = ets:lookup(Tab,Key)
+ end,
+
+ LoopF = fun(_FromIx, Incr, _Times, Checksum, _MeF) when Incr >= Length ->
+ Checksum; % done
+
+ (FromIx, Incr, 0, Checksum, MeF) ->
+ MeF(FromIx, Incr+1, Length, Checksum, MeF);
+
+ (FromIx, Incr, Times, Checksum, MeF) ->
+ ToIx = (FromIx + Incr) rem Length,
+ UpdateF(ToIx,Checksum),
+ if
+ Incr =:= 0 -> UpdateF(ToIx,Checksum); % extra update to same value
+ true -> true
+ end,
+ MeF(ToIx, Incr, Times-1, Checksum+ToIx+1, MeF)
+ end,
+
+ FirstTuple = Tuple,
+ ?line true = ets:insert(Tab,FirstTuple),
+ ?line [FirstTuple] = ets:lookup(Tab,Key),
+
+ Checksum = LoopF(0, 1, Length, 0, LoopF),
+ ?line Checksum = (Length-1)*Length*(Length+1) div 2, % if Length is a prime
+ ok.
+
+update_element_neg(Opts) ->
+ Set = ets:new(set,Opts),
+ OrdSet = ets:new(ordered_set,[ordered_set | Opts]),
+ update_element_neg_do(Set),
+ update_element_neg_do(OrdSet),
+ ets:delete(Set),
+ ?line {'EXIT',{badarg,_}} = (catch ets:update_element(Set,key,{2,1})),
+ ets:delete(OrdSet),
+ ?line {'EXIT',{badarg,_}} = (catch ets:update_element(OrdSet,key,{2,1})),
+
+ ?line Bag = ets:new(bag,[bag | Opts]),
+ ?line DBag = ets:new(duplicate_bag,[duplicate_bag | Opts]),
+ ?line {'EXIT',{badarg,_}} = (catch ets:update_element(Bag,key,{2,1})),
+ ?line {'EXIT',{badarg,_}} = (catch ets:update_element(DBag,key,{2,1})),
+ true = ets:delete(Bag),
+ true = ets:delete(DBag),
+ ok.
+
+
+update_element_neg_do(T) ->
+ Object = {key, 0, "Hej"},
+ ?line true = ets:insert(T,Object),
+
+ UpdateF = fun(Arg3) ->
+ ArgHash = erlang:phash2({T,key,Arg3}),
+ ?line {'EXIT',{badarg,_}} = (catch ets:update_element(T,key,Arg3)),
+ ?line ArgHash = erlang:phash2({T,key,Arg3}),
+ ?line [Object] = ets:lookup(T,key)
+ end,
+
+ %% List of invalid {Pos,Value} tuples
+ InvList = [false, {2}, {2,1,false}, {false,1}, {0,1}, {1,1}, {-1,1}, {4,1}],
+
+ lists:foreach(UpdateF, InvList),
+ lists:foreach(fun(InvTpl) -> UpdateF([{2,1},InvTpl]) end, InvList),
+ lists:foreach(fun(InvTpl) -> UpdateF([InvTpl,{2,1}]) end, InvList),
+ lists:foreach(fun(InvTpl) -> UpdateF([{2,1},{3,"Hello"},InvTpl]) end, InvList),
+ lists:foreach(fun(InvTpl) -> UpdateF([{3,"Hello"},{2,1},InvTpl]) end, InvList),
+ lists:foreach(fun(InvTpl) -> UpdateF([{2,1},InvTpl,{3,"Hello"}]) end, InvList),
+ lists:foreach(fun(InvTpl) -> UpdateF([InvTpl,{3,"Hello"},{2,1}]) end, InvList),
+ UpdateF([{2,1} | {3,1}]),
+ lists:foreach(fun(InvTpl) -> UpdateF([{2,1} | InvTpl]) end, InvList),
+
+ ?line true = ets:update_element(T,key,[]),
+ ?line false = ets:update_element(T,false,[]),
+ ?line false = ets:update_element(T,false,{2,1}),
+ ?line ets:delete(T,key),
+ ?line false = ets:update_element(T,key,{2,1}),
+ ok.
+
+
+update_counter(doc) ->
+ ["test various variants of update_counter"];
+update_counter(suite) ->
+ [];
+update_counter(Config) when is_list(Config) ->
+ ?line EtsMem = etsmem(),
+ repeat_for_opts(update_counter_do),
+ ?line verify_etsmem(EtsMem).
+
+update_counter_do(Opts) ->
+ Set = ets:new(set,Opts),
+ OrdSet = ets:new(ordered_set,[ordered_set | Opts]),
+ update_counter_for(Set),
+ update_counter_for(OrdSet),
+ ets:delete(Set),
+ ets:delete(OrdSet),
+ update_counter_neg(Opts).
+
+update_counter_for(T) ->
+ ?line ets:insert(T,{a,1,1}),
+ ?line 101 = ets:update_counter(T,a,100),
+ ?line [{a,101,1}] = ets:lookup(T,a),
+ ?line 101 = ets:update_counter(T,a,{3,100}),
+ ?line [{a,101,101}] = ets:lookup(T,a),
+
+
+ LooperF = fun(Obj, 0, _, _) ->
+ Obj;
+
+ (Obj, Times, Arg3, Myself) ->
+ ?line {NewObj, Ret} = uc_mimic(Obj,Arg3),
+ ArgHash = erlang:phash2({T,a,Arg3}),
+ ?line Ret = ets:update_counter(T,a,Arg3),
+ ?line ArgHash = erlang:phash2({T,a,Arg3}),
+ %%io:format("NewObj=~p~n ",[NewObj]),
+ ?line [NewObj] = ets:lookup(T,a),
+ Myself(NewObj,Times-1,Arg3,Myself)
+ end,
+
+ LoopF = fun(Obj, Times, Arg3) ->
+ %%io:format("Loop start:\nObj = ~p\nArg3=~p\n",[Obj,Arg3]),
+ LooperF(Obj,Times,Arg3,LooperF)
+ end,
+
+ SmallMax32 = (1 bsl 27) - 1,
+ SmallMax64 = (1 bsl (27+32)) - 1,
+ Big1Max32 = (1 bsl 32) - 1,
+ Big1Max64 = (1 bsl 64) - 1,
+
+ Steps = 100,
+ Obj0 = {a,0,0,0,0},
+ ?line ets:insert(T,Obj0),
+ ?line Obj1 = LoopF(Obj0, Steps, {2,(SmallMax32 div Steps)*2}),
+ ?line Obj2 = LoopF(Obj1, Steps, {3,(SmallMax64 div Steps)*2}),
+ ?line Obj3 = LoopF(Obj2, Steps, {4,(Big1Max32 div Steps)*2}),
+ ?line Obj4 = LoopF(Obj3, Steps, {5,(Big1Max64 div Steps)*2}),
+
+ ?line Obj5 = LoopF(Obj4, Steps, {2,-(SmallMax32 div Steps)*4}),
+ ?line Obj6 = LoopF(Obj5, Steps, {3,-(SmallMax64 div Steps)*4}),
+ ?line Obj7 = LoopF(Obj6, Steps, {4,-(Big1Max32 div Steps)*4}),
+ ?line Obj8 = LoopF(Obj7, Steps, {5,-(Big1Max64 div Steps)*4}),
+
+ ?line Obj9 = LoopF(Obj8, Steps, {2,(SmallMax32 div Steps)*2}),
+ ?line ObjA = LoopF(Obj9, Steps, {3,(SmallMax64 div Steps)*2}),
+ ?line ObjB = LoopF(ObjA, Steps, {4,(Big1Max32 div Steps)*2}),
+ ?line Obj0 = LoopF(ObjB, Steps, {5,(Big1Max64 div Steps)*2}),
+
+ %% back at zero, same trip again with lists
+
+ ?line Obj4 = LoopF(Obj0,Steps,[{2, (SmallMax32 div Steps)*2},
+ {3, (SmallMax64 div Steps)*2},
+ {4, (Big1Max32 div Steps)*2},
+ {5, (Big1Max64 div Steps)*2}]),
+
+ ?line Obj8 = LoopF(Obj4,Steps,[{4, -(Big1Max32 div Steps)*4},
+ {2, -(SmallMax32 div Steps)*4},
+ {5, -(Big1Max64 div Steps)*4},
+ {3, -(SmallMax64 div Steps)*4}]),
+
+ ?line Obj0 = LoopF(Obj8,Steps,[{5, (Big1Max64 div Steps)*2},
+ {2, (SmallMax32 div Steps)*2},
+ {4, (Big1Max32 div Steps)*2},
+ {3, (SmallMax64 div Steps)*2}]),
+
+ %% make them shift size at the same time
+ ?line ObjC = LoopF(Obj0,Steps,[{5, (Big1Max64 div Steps)*2},
+ {3, (Big1Max64 div Steps)*2 + 1},
+ {2, -(Big1Max64 div Steps)*2},
+ {4, -(Big1Max64 div Steps)*2 + 1}]),
+
+ %% update twice in same list
+ ?line ObjD = LoopF(ObjC,Steps,[{5, -(Big1Max64 div Steps) + 1},
+ {3, -(Big1Max64 div Steps)*2 - 1},
+ {5, -(Big1Max64 div Steps) - 1},
+ {4, (Big1Max64 div Steps)*2 - 1}]),
+
+ ?line Obj0 = LoopF(ObjD,Steps,[{2, (Big1Max64 div Steps) - 1},
+ {4, Big1Max64*2},
+ {2, (Big1Max64 div Steps) + 1},
+ {4, -Big1Max64*2}]),
+
+ %% warping with list
+ ?line ObjE = LoopF(Obj0,1000,
+ [{3,SmallMax32*4 div 5,SmallMax32*2,-SmallMax32*2},
+ {5,-SmallMax64*4 div 7,-SmallMax64*2,SmallMax64*2},
+ {4,-Big1Max32*4 div 11,-Big1Max32*2,Big1Max32*2},
+ {2,Big1Max64*4 div 13,Big1Max64*2,-Big1Max64*2}]),
+
+ %% warping without list
+ ?line ObjF = LoopF(ObjE,1000,{3,SmallMax32*4 div 5,SmallMax32*2,-SmallMax32*2}),
+ ?line ObjG = LoopF(ObjF,1000,{5,-SmallMax64*4 div 7,-SmallMax64*2,SmallMax64*2}),
+ ?line ObjH = LoopF(ObjG,1000,{4,-Big1Max32*4 div 11,-Big1Max32*2,Big1Max32*2}),
+ ?line ObjI = LoopF(ObjH,1000,{2,Big1Max64*4 div 13,Big1Max64*2,-Big1Max64*2}),
+
+ %% mixing it up
+ ?line LoopF(ObjI,1000,
+ [{3,SmallMax32*4 div 5,SmallMax32*2,-SmallMax32*2},
+ {5,-SmallMax64*4 div 3},
+ {3,-SmallMax32*4 div 11},
+ {5,0},
+ {4,1},
+ {5,-SmallMax64*4 div 7,-SmallMax64*2,SmallMax64*2},
+ {2,Big1Max64*4 div 13,Big1Max64*2,-Big1Max64*2}]),
+ ok.
+
+%% uc_mimic works kind of like the real ets:update_counter
+%% Obj = Tuple in ets
+%% Pits = {Pos,Incr} | {Pos,Incr,Thres,Warp}
+%% Returns {Updated tuple in ets, Return value from update_counter}
+uc_mimic(Obj, Pits) when is_tuple(Pits) ->
+ ?line Pos = element(1,Pits),
+ ?line NewObj = setelement(Pos, Obj, uc_adder(element(Pos,Obj),Pits)),
+ ?line {NewObj, element(Pos,NewObj)};
+
+uc_mimic(Obj, PitsList) when is_list(PitsList) ->
+ ?line {NewObj,ValList} = uc_mimic(Obj,PitsList,[]),
+ ?line {NewObj,lists:reverse(ValList)}.
+
+uc_mimic(Obj, [], Acc) ->
+ ?line {Obj,Acc};
+uc_mimic(Obj, [Pits|Tail], Acc) ->
+ ?line {NewObj,NewVal} = uc_mimic(Obj,Pits),
+ ?line uc_mimic(NewObj,Tail,[NewVal|Acc]).
+
+uc_adder(Init, {_Pos, Add}) ->
+ Init + Add;
+uc_adder(Init, {_Pos, Add, Thres, Warp}) ->
+ case Init + Add of
+ X when X > Thres, Add > 0 ->
+ Warp;
+ Y when Y < Thres, Add < 0 ->
+ Warp;
+ Z ->
+ Z
+ end.
+
+update_counter_neg(Opts) ->
+ Set = ets:new(set,Opts),
+ OrdSet = ets:new(ordered_set,[ordered_set | Opts]),
+ update_counter_neg_for(Set),
+ update_counter_neg_for(OrdSet),
+ ets:delete(Set),
+ ?line {'EXIT',{badarg,_}} = (catch ets:update_counter(Set,key,1)),
+ ets:delete(OrdSet),
+ ?line {'EXIT',{badarg,_}} = (catch ets:update_counter(OrdSet,key,1)),
+
+ ?line Bag = ets:new(bag,[bag | Opts]),
+ ?line DBag = ets:new(duplicate_bag,[duplicate_bag | Opts]),
+ ?line {'EXIT',{badarg,_}} = (catch ets:update_counter(Bag,key,1)),
+ ?line {'EXIT',{badarg,_}} = (catch ets:update_counter(DBag,key,1)),
+ true = ets:delete(Bag),
+ true = ets:delete(DBag),
+ ok.
+
+update_counter_neg_for(T) ->
+ Object = {key,0,false,1},
+ ?line true = ets:insert(T,Object),
+
+ UpdateF = fun(Arg3) ->
+ ArgHash = erlang:phash2({T,key,Arg3}),
+ ?line {'EXIT',{badarg,_}} = (catch ets:update_counter(T,key,Arg3)),
+ ?line ArgHash = erlang:phash2({T,key,Arg3}),
+ ?line [Object] = ets:lookup(T,key)
+ end,
+
+ %% List of invalid arg3-tuples
+ InvList = [false, {2}, {2,false}, {false,1},
+ {0,1}, {-1,1}, % BUG < R12B-2
+ {1,1}, {3,1}, {5,1}, {2,1,100}, {2,1,100,0,false}, {2,1,false,0}, {2,1,0,false}],
+
+ lists:foreach(UpdateF, InvList),
+ lists:foreach(fun(Inv) -> UpdateF([{2,1},Inv]) end, InvList),
+ lists:foreach(fun(Inv) -> UpdateF([Inv,{2,1}]) end, InvList),
+ lists:foreach(fun(Inv) -> UpdateF([{2,1},{4,-100},Inv]) end, InvList),
+ lists:foreach(fun(Inv) -> UpdateF([{4,100,50,0},{2,1},Inv]) end, InvList),
+ lists:foreach(fun(Inv) -> UpdateF([{2,1},Inv,{4,100,50,0}]) end, InvList),
+ lists:foreach(fun(Inv) -> UpdateF([Inv,{4,100,50,0},{2,1}]) end, InvList),
+ UpdateF([{2,1} | {4,1}]),
+ lists:foreach(fun(Inv) -> UpdateF([{2,1} | Inv]) end, InvList),
+
+ ?line {'EXIT',{badarg,_}} = (catch ets:update_counter(T,false,1)),
+ ?line ets:delete(T,key),
+ ?line {'EXIT',{badarg,_}} = (catch ets:update_counter(T,key,1)),
+ ok.
+
+
+evil_update_counter(Config) when is_list(Config) ->
+ %% The code server uses ets table. Pre-load modules that might not be
+ %% already loaded.
+ gb_sets:module_info(),
+ math:module_info(),
+ ordsets:module_info(),
+ random:module_info(),
+
+ repeat_for_opts(evil_update_counter_do).
+
+evil_update_counter_do(Opts) ->
+ ?line EtsMem = etsmem(),
+ ?line process_flag(trap_exit, true),
+ ?line Pids = [spawn_link(fun() -> evil_counter(I,Opts) end) || I <- lists:seq(1, 40)],
+ ?line wait_for_all(gb_sets:from_list(Pids)),
+ ?line verify_etsmem(EtsMem),
+ ok.
+
+wait_for_all(Pids0) ->
+ case gb_sets:is_empty(Pids0) of
+ true ->
+ ok;
+ false ->
+ receive
+ {'EXIT',Pid,normal} ->
+ ?line Pids = gb_sets:delete(Pid, Pids0),
+ wait_for_all(Pids);
+ Other ->
+ io:format("unexpected: ~p\n", [Other]),
+ ?line ?t:fail()
+ end
+ end.
+
+evil_counter(I,Opts) ->
+ T = ets:new(a, Opts),
+ Start0 = case I rem 3 of
+ 0 -> 16#12345678;
+ 1 -> 16#12345678FFFFFFFF;
+ 2 -> 16#7777777777FFFFFFFF863648726743
+ end,
+ Start = Start0 + random:uniform(100000),
+ ets:insert(T, {dracula,Start}),
+ Iter = 90000,
+ End = Start + Iter,
+ End = evil_counter_1(Iter, T),
+ ets:delete(T).
+
+evil_counter_1(0, T) ->
+ [{dracula,Count}] = ets:lookup(T, dracula),
+ Count;
+evil_counter_1(Iter, T) ->
+ ets:update_counter(T, dracula, 1),
+ evil_counter_1(Iter-1, T).
+
+fixtable_next(doc) ->
+ ["Check that a first-next sequence always works on a fixed table"];
+fixtable_next(suite) ->
+ [];
+fixtable_next(Config) when is_list(Config) ->
+ repeat_for_opts(fixtable_next_do, [write_concurrency,all_types]).
+
+fixtable_next_do(Opts) ->
+ ?line EtsMem = etsmem(),
+ ?line do_fixtable_next(ets:new(set,[public | Opts])),
+ ?line verify_etsmem(EtsMem).
+
+do_fixtable_next(Tab) ->
+ ?line F = fun(X,T,FF) -> case X of
+ 0 -> true;
+ _ ->
+ ets:insert(T, {X,
+ integer_to_list(X),
+ X rem 10}),
+ FF(X-1,T,FF)
+ end
+ end,
+ ?line F(100,Tab,F),
+ ?line ets:safe_fixtable(Tab,true),
+ ?line First = ets:first(Tab),
+ ?line ets:delete(Tab, First),
+ ?line ets:next(Tab, First),
+ ?line ets:match_delete(Tab,{'_','_','_'}),
+ ?line '$end_of_table' = ets:next(Tab, First),
+ ?line true = ets:info(Tab, fixed),
+ ?line ets:safe_fixtable(Tab, false),
+ ?line false = ets:info(Tab, fixed),
+ ?line ets:delete(Tab).
+
+fixtable_insert(doc) ->
+ ["Check inserts of deleted keys in fixed bags"];
+fixtable_insert(suite) ->
+ [];
+fixtable_insert(Config) when is_list(Config) ->
+ Combos = [[Type,{write_concurrency,WC}] || Type<- [bag,duplicate_bag],
+ WC <- [false,true]],
+ lists:foreach(fun(Opts) -> fixtable_insert_do(Opts) end,
+ Combos),
+ ok.
+
+fixtable_insert_do(Opts) ->
+ io:format("Opts = ~p\n",[Opts]),
+ Ets = make_table(ets, Opts, [{a,1}, {a,2}, {b,1}, {b,2}]),
+ ets:safe_fixtable(Ets,true),
+ ets:match_delete(Ets,{b,1}),
+ First = ets:first(Ets),
+ ?line Next = case First of
+ a -> b;
+ b -> a
+ end,
+ ?line Next = ets:next(Ets,First),
+ ets:delete(Ets,Next),
+ ?line '$end_of_table' = ets:next(Ets,First),
+ ets:insert(Ets, {Next,1}),
+ ?line false = ets:insert_new(Ets, {Next,1}),
+ ?line Next = ets:next(Ets,First),
+ ?line '$end_of_table' = ets:next(Ets,Next),
+ ets:delete(Ets,Next),
+ '$end_of_table' = ets:next(Ets,First),
+ ets:insert(Ets, {Next,2}),
+ ?line false = ets:insert_new(Ets, {Next,1}),
+ Next = ets:next(Ets,First),
+ '$end_of_table' = ets:next(Ets,Next),
+ ets:delete(Ets,First),
+ ?line Next = ets:first(Ets),
+ ?line '$end_of_table' = ets:next(Ets,Next),
+ ets:delete(Ets,Next),
+ ?line '$end_of_table' = ets:next(Ets,First),
+ ?line true = ets:insert_new(Ets,{Next,1}),
+ ?line false = ets:insert_new(Ets,{Next,2}),
+ ?line Next = ets:next(Ets,First),
+ ets:delete_object(Ets,{Next,1}),
+ ?line '$end_of_table' = ets:next(Ets,First),
+ ?line true = ets:insert_new(Ets,{Next,2}),
+ ?line false = ets:insert_new(Ets,{Next,1}),
+ ?line Next = ets:next(Ets,First),
+ ets:delete(Ets,First),
+ ets:safe_fixtable(Ets,false),
+ {'EXIT',{badarg,_}} = (catch ets:next(Ets,First)),
+ ok.
+
+write_concurrency(doc) -> ["The 'write_concurrency' option"];
+write_concurrency(suite) -> [];
+write_concurrency(Config) when is_list(Config) ->
+ ?line EtsMem = etsmem(),
+ Yes1 = ets:new(foo,[public,{write_concurrency,true}]),
+ Yes2 = ets:new(foo,[protected,{write_concurrency,true}]),
+ No1 = ets:new(foo,[private,{write_concurrency,true}]),
+
+ Yes3 = ets:new(foo,[bag,public,{write_concurrency,true}]),
+ Yes4 = ets:new(foo,[bag,protected,{write_concurrency,true}]),
+ No2 = ets:new(foo,[bag,private,{write_concurrency,true}]),
+
+ Yes5 = ets:new(foo,[duplicate_bag,public,{write_concurrency,true}]),
+ Yes6 = ets:new(foo,[duplicate_bag,protected,{write_concurrency,true}]),
+ No3 = ets:new(foo,[duplicate_bag,private,{write_concurrency,true}]),
+
+ No4 = ets:new(foo,[ordered_set,public,{write_concurrency,true}]),
+ No5 = ets:new(foo,[ordered_set,protected,{write_concurrency,true}]),
+ No6 = ets:new(foo,[ordered_set,private,{write_concurrency,true}]),
+
+ No7 = ets:new(foo,[public,{write_concurrency,false}]),
+ No8 = ets:new(foo,[protected,{write_concurrency,false}]),
+
+ ?line YesMem = ets:info(Yes1,memory),
+ ?line NoHashMem = ets:info(No1,memory),
+ ?line NoTreeMem = ets:info(No4,memory),
+ io:format("YesMem=~p NoHashMem=~p NoTreeMem=~p\n",[YesMem,NoHashMem,NoTreeMem]),
+
+ ?line YesMem = ets:info(Yes2,memory),
+ ?line YesMem = ets:info(Yes3,memory),
+ ?line YesMem = ets:info(Yes4,memory),
+ ?line YesMem = ets:info(Yes5,memory),
+ ?line YesMem = ets:info(Yes6,memory),
+ ?line NoHashMem = ets:info(No2,memory),
+ ?line NoHashMem = ets:info(No3,memory),
+ ?line NoTreeMem = ets:info(No5,memory),
+ ?line NoTreeMem = ets:info(No6,memory),
+ ?line NoHashMem = ets:info(No7,memory),
+ ?line NoHashMem = ets:info(No8,memory),
+
+ case erlang:system_info(smp_support) of
+ true ->
+ ?line true = YesMem > NoHashMem,
+ ?line true = YesMem > NoTreeMem;
+ false ->
+ ?line true = YesMem =:= NoHashMem
+ end,
+
+ ?line {'EXIT',{badarg,_}} = (catch ets:new(foo,[public,{write_concurrency,foo}])),
+ ?line {'EXIT',{badarg,_}} = (catch ets:new(foo,[public,{write_concurrency}])),
+ ?line {'EXIT',{badarg,_}} = (catch ets:new(foo,[public,{write_concurrency,true,foo}])),
+ ?line {'EXIT',{badarg,_}} = (catch ets:new(foo,[public,write_concurrency])),
+
+ lists:foreach(fun(T) -> ets:delete(T) end,
+ [Yes1,Yes2,Yes3,Yes4,Yes5,Yes6,
+ No1,No2,No3,No4,No5,No6,No7,No8]),
+ ?line verify_etsmem(EtsMem),
+ ok.
+
+
+heir(doc) -> ["The 'heir' option"];
+heir(suite) -> [];
+heir(Config) when is_list(Config) ->
+ repeat_for_opts(heir_do).
+
+heir_do(Opts) ->
+ ?line EtsMem = etsmem(),
+ Master = self(),
+
+ %% Different types of heir data and link/monitor relations
+ TestFun = fun(Arg) -> {EtsMem,Arg} end,
+ Combos = [{Data,Mode} || Data<-[foo_data, <<"binary">>,
+ lists:seq(1,10), {17,TestFun,self()},
+ "The busy heir"],
+ Mode<-[none,link,monitor]],
+ ?line lists:foreach(fun({Data,Mode})-> heir_1(Data,Mode,Opts) end,
+ Combos),
+
+ %% No heir
+ {Founder1,MrefF1} = spawn_monitor(fun()->heir_founder(Master,foo_data,Opts)end),
+ Founder1 ! {go, none},
+ ?line {"No heir",Founder1} = receive_any(),
+ ?line {'DOWN', MrefF1, process, Founder1, normal} = receive_any(),
+ ?line undefined = ets:info(foo),
+
+ %% An already dead heir
+ {Heir2,MrefH2} = spawn_monitor(fun()->die end),
+ ?line {'DOWN', MrefH2, process, Heir2, normal} = receive_any(),
+ {Founder2,MrefF2} = spawn_monitor(fun()->heir_founder(Master,foo_data,Opts)end),
+ Founder2 ! {go, Heir2},
+ ?line {"No heir",Founder2} = receive_any(),
+ ?line {'DOWN', MrefF2, process, Founder2, normal} = receive_any(),
+ ?line undefined = ets:info(foo),
+
+ %% When heir dies before founder
+ {Founder3,MrefF3} = spawn_monitor(fun()->heir_founder(Master,"The dying heir",Opts)end),
+ {Heir3,MrefH3} = spawn_monitor(fun()->heir_heir(Founder3)end),
+ Founder3 ! {go, Heir3},
+ ?line {'DOWN', MrefH3, process, Heir3, normal} = receive_any(),
+ Founder3 ! die_please,
+ ?line {'DOWN', MrefF3, process, Founder3, normal} = receive_any(),
+ ?line undefined = ets:info(foo),
+
+ %% When heir dies and pid reused before founder dies
+ erts_debug:set_internal_state(available_internal_state,true),
+ NextPidIx = erts_debug:get_internal_state(next_pid),
+ {Founder4,MrefF4} = spawn_monitor(fun()->heir_founder(Master,"The dying heir",Opts)end),
+ {Heir4,MrefH4} = spawn_monitor(fun()->heir_heir(Founder4)end),
+ Founder4 ! {go, Heir4},
+ ?line {'DOWN', MrefH4, process, Heir4, normal} = receive_any(),
+ erts_debug:set_internal_state(next_pid, NextPidIx),
+ erts_debug:set_internal_state(available_internal_state,false),
+ {Heir4,MrefH4_B} = spawn_monitor_with_pid(Heir4,
+ fun()-> ?line die_please = receive_any() end),
+ Founder4 ! die_please,
+ ?line {'DOWN', MrefF4, process, Founder4, normal} = receive_any(),
+ Heir4 ! die_please,
+ ?line {'DOWN', MrefH4_B, process, Heir4, normal} = receive_any(),
+ ?line undefined = ets:info(foo),
+
+ ?line verify_etsmem(EtsMem).
+
+heir_founder(Master, HeirData, Opts) ->
+ ?line {go,Heir} = receive_any(),
+ HeirTpl = case Heir of
+ none -> {heir,none};
+ _ -> {heir, Heir, HeirData}
+ end,
+ ?line T = ets:new(foo,[named_table, private, HeirTpl | Opts]),
+ ?line true = ets:insert(T,{key,1}),
+ ?line [{key,1}] = ets:lookup(T,key),
+ Self = self(),
+ ?line Self = ets:info(T,owner),
+ ?line case ets:info(T,heir) of
+ none ->
+ ?line true = (Heir =:= none) orelse (not is_process_alive(Heir)),
+ Master ! {"No heir",self()};
+
+ Heir ->
+ ?line true = is_process_alive(Heir),
+ Heir ! {table,T,HeirData},
+ die_please = receive_any()
+ end.
+
+
+heir_heir(Founder) ->
+ heir_heir(Founder, none).
+heir_heir(Founder, Mode) ->
+ ?line {table,T,HeirData} = receive_any(),
+ ?line {'EXIT',{badarg,_}} = (catch ets:lookup(T,key)),
+ ?line case HeirData of
+ "The dying heir" -> exit(normal);
+ _ -> ok
+ end,
+
+ ?line Mref = case Mode of
+ link -> process_flag(trap_exit, true),
+ link(Founder);
+ monitor -> erlang:monitor(process,Founder);
+ none -> ok
+ end,
+ ?line Founder ! die_please,
+ ?line Msg = case HeirData of
+ "The busy heir" -> receive_any_spinning();
+ _ -> receive_any()
+ end,
+ ?line {'ETS-TRANSFER', T, Founder, HeirData} = Msg,
+ ?line foo = T,
+ ?line Self = self(),
+ ?line Self = ets:info(T,owner),
+ ?line Self = ets:info(T,heir),
+ ?line [{key,1}] = ets:lookup(T,key),
+ ?line true = ets:insert(T,{key,2}),
+ ?line [{key,2}] = ets:lookup(T,key),
+ ?line case Mode of % Verify that EXIT or DOWN comes after ETS-TRANSFER
+ link ->
+ {'EXIT',Founder,normal} = receive_any(),
+ process_flag(trap_exit, false);
+ monitor ->
+ {'DOWN', Mref, process, Founder, normal} = receive_any();
+ none -> ok
+ end.
+
+
+heir_1(HeirData,Mode,Opts) ->
+ io:format("test with heir_data = ~p\n", [HeirData]),
+ Master = self(),
+ ?line Founder = spawn_link(fun() -> heir_founder(Master,HeirData,Opts) end),
+ io:format("founder spawned = ~p\n", [Founder]),
+ ?line {Heir,Mref} = spawn_monitor(fun() -> heir_heir(Founder,Mode) end),
+ io:format("heir spawned = ~p\n", [{Heir,Mref}]),
+ ?line Founder ! {go, Heir},
+ ?line {'DOWN', Mref, process, Heir, normal} = receive_any().
+
+give_away(doc) -> ["ets:give_way/3"];
+give_away(suite) -> [];
+give_away(Config) when is_list(Config) ->
+ repeat_for_opts(give_away_do).
+
+give_away_do(Opts) ->
+ ?line T = ets:new(foo,[named_table, private | Opts]),
+ ?line true = ets:insert(T,{key,1}),
+ ?line [{key,1}] = ets:lookup(T,key),
+ Parent = self(),
+
+ %% Give and then give back
+ ?line {Receiver,Mref} = spawn_monitor(fun()-> give_away_receiver(T,Parent) end),
+ ?line give_me = receive_any(),
+ ?line true = ets:give_away(T,Receiver,here_you_are),
+ ?line {'EXIT',{badarg,_}} = (catch ets:lookup(T,key)),
+ ?line Receiver ! give_back,
+ ?line {'ETS-TRANSFER',T,Receiver,"Tillbakakaka"} = receive_any(),
+ ?line [{key,2}] = ets:lookup(T,key),
+ ?line {'DOWN', Mref, process, Receiver, normal} = receive_any(),
+
+ %% Give and then let receiver keep it
+ ?line true = ets:insert(T,{key,1}),
+ ?line {Receiver3,Mref3} = spawn_monitor(fun()-> give_away_receiver(T,Parent) end),
+ ?line give_me = receive_any(),
+ ?line true = ets:give_away(T,Receiver3,here_you_are),
+ ?line {'EXIT',{badarg,_}} = (catch ets:lookup(T,key)),
+ ?line Receiver3 ! die_please,
+ ?line {'DOWN', Mref3, process, Receiver3, normal} = receive_any(),
+ ?line undefined = ets:info(T),
+
+ %% Give and then kill receiver to get back
+ ?line T2 = ets:new(foo,[private | Opts]),
+ ?line true = ets:insert(T2,{key,1}),
+ ?line ets:setopts(T2,{heir,self(),"Som en gummiboll..."}),
+ ?line {Receiver2,Mref2} = spawn_monitor(fun()-> give_away_receiver(T2,Parent) end),
+ ?line give_me = receive_any(),
+ ?line true = ets:give_away(T2,Receiver2,here_you_are),
+ ?line {'EXIT',{badarg,_}} = (catch ets:lookup(T2,key)),
+ ?line Receiver2 ! die_please,
+ ?line {'ETS-TRANSFER',T2,Receiver2,"Som en gummiboll..."} = receive_any(),
+ ?line [{key,2}] = ets:lookup(T2,key),
+ ?line {'DOWN', Mref2, process, Receiver2, normal} = receive_any(),
+
+ %% Some negative testing
+ ?line {'EXIT',{badarg,_}} = (catch ets:give_away(T2,Receiver,"To a dead one")),
+ ?line {'EXIT',{badarg,_}} = (catch ets:give_away(T2,self(),"To myself")),
+ ?line {'EXIT',{badarg,_}} = (catch ets:give_away(T2,"not a pid","To wrong type")),
+
+ ?line true = ets:delete(T2),
+ ?line {ReceiverNeg,MrefNeg} = spawn_monitor(fun()-> give_away_receiver(T2,Parent) end),
+ ?line give_me = receive_any(),
+ ?line {'EXIT',{badarg,_}} = (catch ets:give_away(T2,ReceiverNeg,"A deleted table")),
+
+ ?line T3 = ets:new(foo,[public | Opts]),
+ spawn_link(fun()-> {'EXIT',{badarg,_}} = (catch ets:give_away(T3,ReceiverNeg,"From non owner")),
+ Parent ! done
+ end),
+ ?line done = receive_any(),
+ ?line ReceiverNeg ! no_soup_for_you,
+ ?line {'DOWN', MrefNeg, process, ReceiverNeg, normal} = receive_any(),
+ ok.
+
+give_away_receiver(T, Giver) ->
+ ?line {'EXIT',{badarg,_}} = (catch ets:lookup(T,key)),
+ ?line Giver ! give_me,
+ ?line case receive_any() of
+ {'ETS-TRANSFER',T,Giver,here_you_are} ->
+ ?line [{key,1}] = ets:lookup(T,key),
+ ?line true = ets:insert(T,{key,2}),
+ ?line case receive_any() of
+ give_back ->
+ ?line true = ets:give_away(T,Giver,"Tillbakakaka"),
+ ?line {'EXIT',{badarg,_}} = (catch ets:lookup(T,key));
+ die_please ->
+ ok
+ end;
+ no_soup_for_you ->
+ ok
+ end.
+
+
+setopts(doc) -> ["ets:setopts/2"];
+setopts(suite) -> [];
+setopts(Config) when is_list(Config) ->
+ repeat_for_opts(setopts_do,[write_concurrency,all_types]).
+
+setopts_do(Opts) ->
+ Self = self(),
+ ?line T = ets:new(foo,[named_table, private | Opts]),
+ ?line none = ets:info(T,heir),
+ Heir = spawn_link(fun()->heir_heir(Self) end),
+ ?line ets:setopts(T,{heir,Heir,"Data"}),
+ ?line Heir = ets:info(T,heir),
+ ?line ets:setopts(T,{heir,self(),"Data"}),
+ ?line Self = ets:info(T,heir),
+ ?line ets:setopts(T,[{heir,Heir,"Data"}]),
+ ?line Heir = ets:info(T,heir),
+ ?line ets:setopts(T,[{heir,none}]),
+ ?line none = ets:info(T,heir),
+
+ ?line {'EXIT',{badarg,_}} = (catch ets:setopts(T,[{heir,self(),"Data"},false])),
+ ?line {'EXIT',{badarg,_}} = (catch ets:setopts(T,{heir,self()})),
+ ?line {'EXIT',{badarg,_}} = (catch ets:setopts(T,{heir,false})),
+ ?line {'EXIT',{badarg,_}} = (catch ets:setopts(T,heir)),
+ ?line {'EXIT',{badarg,_}} = (catch ets:setopts(T,{heir,false,"Data"})),
+ ?line {'EXIT',{badarg,_}} = (catch ets:setopts(T,{false,self(),"Data"})),
+
+ ?line ets:setopts(T,{protection,protected}),
+ ?line ets:setopts(T,{protection,public}),
+ ?line ets:setopts(T,{protection,private}),
+ ?line ets:setopts(T,[{protection,protected}]),
+ ?line ets:setopts(T,[{protection,public}]),
+ ?line ets:setopts(T,[{protection,private}]),
+
+ ?line {'EXIT',{badarg,_}} = (catch ets:setopts(T,{protection})),
+ ?line {'EXIT',{badarg,_}} = (catch ets:setopts(T,{protection,false})),
+ ?line {'EXIT',{badarg,_}} = (catch ets:setopts(T,{protection,private,false})),
+ ?line {'EXIT',{badarg,_}} = (catch ets:setopts(T,protection)),
+ ?line ets:delete(T),
+ ok.
+
+bad_table(doc) -> ["All kinds of operations with bad table argument"];
+bad_table(suite) -> [];
+bad_table(Config) when is_list(Config) ->
+
+ %% Open and close disk_log to stabilize etsmem.
+ Name = make_ref(),
+ ?line File = filename:join([?config(priv_dir, Config),"bad_table.dummy"]),
+ ?line {ok, Name} = disk_log:open([{name, Name}, {file, File}]),
+ ?line disk_log:close(Name),
+ file:delete(File),
+
+ ?line EtsMem = etsmem(),
+
+ repeat_for_opts(fun(Opts) -> bad_table_do(Opts,File) end,
+ [write_concurrency, all_types]),
+ ?line verify_etsmem(EtsMem),
+ ok.
+
+bad_table_do(Opts, DummyFile) ->
+ Parent = self(),
+ {Pid,Mref} = spawn_opt(fun()-> ets:new(priv,[private,named_table | Opts]),
+ Priv = ets:new(priv,[private | Opts]),
+ ets:new(prot,[protected,named_table | Opts]),
+ Prot = ets:new(prot,[protected | Opts]),
+ Parent ! {self(),Priv,Prot},
+ die_please = receive_any()
+ end,
+ [link, monitor]),
+ {Pid,Priv,Prot} = receive_any(),
+ MatchSpec = {{key,'_'}, [], ['$$']},
+ Fun = fun(X,_) -> X end,
+ OpList = [{delete,[key],update},
+ {delete_all_objects,[],update},
+ {delete_object,[{key,data}],update},
+ {first,[],read},
+ {foldl,[Fun, 0], read, tabarg_last},
+ {foldr,[Fun, 0], read, tabarg_last},
+ %%{from_dets,[DetsTab], update},
+ {give_away,[Pid, data], update},
+ %%{info, [], read},
+ %%{info, [safe_fixed], read},
+ %%{init_table,[Name, InitFun],update},
+ {insert, [{key,data}], update},
+ {insert_new, [{key,data}], update},
+ {insert_new, [[{key,data},{other,data}]], update},
+ {last, [], read},
+ {lookup, [key], read},
+ {lookup_element, [key, 2], read},
+ {match, [{}], read},
+ {match, [{},17], read},
+ {match_delete, [{}], update},
+ {match_object, [{}], read},
+ {match_object, [{},17], read},
+ {member,[key], read},
+ {next, [key], read},
+ {prev, [key], read},
+ {rename, [new_name], update},
+ {safe_fixtable, [true], read},
+ {select,[MatchSpec], read},
+ {select,[MatchSpec,17], read},
+ {select_count,[MatchSpec], read},
+ {select_delete,[MatchSpec], update},
+ {setopts, [{heir,none}], update},
+ {slot, [0], read},
+ {tab2file, [DummyFile], read, {return,{error,badtab}}},
+ {tab2file, [DummyFile,[]], read, {return,{error,badtab}}},
+ {tab2list, [], read},
+ %%{table,[], read},
+ %%{to_dets, [DetsTab], read},
+ {update_counter,[key,1], update},
+ {update_element,[key,{2,new_data}], update}
+ ],
+ Info = {Opts, Priv, Prot},
+ lists:foreach(fun(Op) -> bad_table_op(Info, Op) end,
+ OpList),
+ Pid ! die_please,
+ {'DOWN', Mref, process, Pid, normal} = receive_any(),
+ ok.
+
+bad_table_op({Opts,Priv,Prot}, Op) ->
+ %%io:format("Doing Op=~p on ~p's\n",[Op,Type]),
+ T1 = ets:new(noname,Opts),
+ bad_table_call(noname,Op),
+ ets:delete(T1),
+ bad_table_call(T1,Op),
+ T2 = ets:new(named,[named_table | Opts]),
+ ets:delete(T2),
+ bad_table_call(named,Op),
+ bad_table_call(T2,Op),
+ bad_table_call(priv,Op),
+ bad_table_call(Priv,Op),
+ case element(3,Op) of
+ update ->
+ bad_table_call(prot,Op),
+ bad_table_call(Prot,Op);
+ read -> ok
+ end.
+
+bad_table_call(T,{F,Args,_}) ->
+ ?line {'EXIT',{badarg,_}} = (catch apply(ets, F, [T|Args]));
+bad_table_call(T,{F,Args,_,tabarg_last}) ->
+ ?line {'EXIT',{badarg,_}} = (catch apply(ets, F, Args++[T]));
+bad_table_call(T,{F,Args,_,{return,Return}}) ->
+ try
+ ?line Return = apply(ets, F, [T|Args])
+ catch
+ error:badarg -> ok
+ end.
+
+
+rename(doc) ->
+ ["Check rename of ets tables"];
+rename(suite) ->
+ [];
+rename(Config) when is_list(Config) ->
+ repeat_for_opts(rename_do, [write_concurrency, all_types]).
+
+rename_do(Opts) ->
+ ?line EtsMem = etsmem(),
+ ets:new(foobazz,[named_table, public | Opts]),
+ ets:insert(foobazz,{foo,bazz}),
+ ungermanbazz = ets:rename(foobazz,ungermanbazz),
+ {'EXIT',{badarg, _}} = (catch ets:lookup(foobazz,foo)),
+ [{foo,bazz}] = ets:lookup(ungermanbazz,foo),
+ {'EXIT',{badarg,_}} = (catch ets:rename(ungermanbazz,"no atom")),
+ ets:delete(ungermanbazz),
+ ?line verify_etsmem(EtsMem).
+
+rename_unnamed(doc) ->
+ ["Check rename of unnamed ets table"];
+rename_unnamed(suite) ->
+ [];
+rename_unnamed(Config) when is_list(Config) ->
+ repeat_for_opts(rename_unnamed_do,[write_concurrency,all_types]).
+
+rename_unnamed_do(Opts) ->
+ ?line EtsMem = etsmem(),
+ ?line Tab = ets:new(bonkz,[public | Opts]),
+ ?line {'EXIT',{badarg, _}} = (catch ets:insert(bonkz,{foo,bazz})),
+ ?line bonkz = ets:info(Tab, name),
+ ?line Tab = ets:rename(Tab, tjabonkz),
+ ?line {'EXIT',{badarg, _}} = (catch ets:insert(tjabonkz,{foo,bazz})),
+ ?line tjabonkz = ets:info(Tab, name),
+ ?line ets:delete(Tab),
+ ?line verify_etsmem(EtsMem).
+
+evil_rename(doc) ->
+ "Rename a table with many fixations, and at the same time delete it.";
+evil_rename(Config) when is_list(Config) ->
+ ?line evil_rename_1(old_hash, new_hash, [public,named_table]),
+ ?line EtsMem = etsmem(),
+ ?line evil_rename_1(old_tree, new_tree, [public,ordered_set,named_table]),
+ ?line verify_etsmem(EtsMem).
+
+evil_rename_1(Old, New, Flags) ->
+ ?line process_flag(trap_exit, true),
+ ?line Old = ets:new(Old, Flags),
+ ?line Fixer = fun() -> ets:safe_fixtable(Old, true) end,
+ ?line crazy_fixtable(15000, Fixer),
+ ?line erlang:yield(),
+ ?line New = ets:rename(Old, New),
+ ?line erlang:yield(),
+ ets:delete(New),
+ ok.
+
+crazy_fixtable(N, Fixer) ->
+ Dracula = ets:new(count_dracula, [public]),
+ ets:insert(Dracula, {count,0}),
+ SpawnFun = fun() ->
+ Fixer(),
+ case ets:update_counter(Dracula, count, 1) rem 15 of
+ 0 -> evil_creater_destroyer();
+ _ -> erlang:hibernate(erlang, error, [dont_wake_me])
+ end
+ end,
+ crazy_fixtable_1(N, SpawnFun),
+ crazy_fixtable_wait(N, Dracula),
+ Dracula.
+
+crazy_fixtable_wait(N, Dracula) ->
+ case ets:lookup(Dracula, count) of
+ [{count,N}] ->
+ ets:delete(Dracula);
+ Other ->
+ io:format("~p\n", [Other]),
+ receive after 10 -> ok end,
+ crazy_fixtable_wait(N, Dracula)
+ end.
+
+crazy_fixtable_1(0, _) ->
+ ok;
+crazy_fixtable_1(N, Fun) ->
+ spawn_link(Fun),
+ crazy_fixtable_1(N-1, Fun).
+
+evil_creater_destroyer() ->
+ T1 = evil_create_fixed_tab(),
+ ets:delete(T1).
+
+evil_create_fixed_tab() ->
+ T = ets:new(arne, [public]),
+ ets:safe_fixtable(T, true),
+ T.
+
+interface_equality(doc) ->
+ ["Tests that the return values and errors are equal for set's and"
+ " ordered_set's where applicable"];
+interface_equality(suite) ->
+ [];
+interface_equality(Config) when is_list(Config) ->
+ repeat_for_opts(interface_equality_do).
+
+interface_equality_do(Opts) ->
+ ?line EtsMem = etsmem(),
+ ?line Set = ets:new(set,[set | Opts]),
+ ?line OrderedSet = ets:new(ordered_set,[ordered_set | Opts]),
+ ?line F = fun(X,T,FF) -> case X of
+ 0 -> true;
+ _ ->
+ ets:insert(T, {X,
+ integer_to_list(X),
+ X rem 10}),
+ FF(X-1,T,FF)
+ end
+ end,
+ ?line F(100,Set,F),
+ ?line F(100,OrderedSet,F),
+ ?line equal_results(ets, insert, Set, OrderedSet, [{a,"a"}]),
+ ?line equal_results(ets, insert, Set, OrderedSet, [{1,1,"1"}]),
+ ?line equal_results(ets, lookup, Set, OrderedSet, [10]),
+ ?line equal_results(ets, lookup, Set, OrderedSet, [1000]),
+ ?line equal_results(ets, delete, Set, OrderedSet, [10]),
+ ?line equal_results(ets, delete, Set, OrderedSet, [nott]),
+ ?line equal_results(ets, lookup, Set, OrderedSet, [1000]),
+ ?line equal_results(ets, insert, Set, OrderedSet, [10]),
+ ?line equal_results(ets, next, Set, OrderedSet, ['$end_of_table']),
+ ?line equal_results(ets, prev, Set, OrderedSet, ['$end_of_table']),
+ ?line equal_results(ets, match, Set, OrderedSet, [{'_','_','_'}]),
+ ?line equal_results(ets, match, Set, OrderedSet, [{'_','_','_','_'}]),
+ ?line equal_results(ets, match, Set, OrderedSet, [{$3,$2,2}]),
+ ?line equal_results(ets, match, Set, OrderedSet, ['_']),
+ ?line equal_results(ets, match, Set, OrderedSet, ['$1']),
+ ?line equal_results(ets, match, Set, OrderedSet, [{'_','$50',3}]),
+ ?line equal_results(ets, match, Set, OrderedSet, [['_','$50',3]]),
+ ?line equal_results(ets, match_delete, Set, OrderedSet, [{'_','_',4}]),
+ ?line equal_results(ets, match_delete, Set, OrderedSet, [{'_','_',4}]),
+ ?line equal_results(ets, match_object, Set, OrderedSet, [{'_','_',4}]),
+ ?line equal_results(ets, match_object, Set, OrderedSet, [{'_','_',5}]),
+ ?line equal_results(ets, match_object, Set, OrderedSet, [{'_','_',4}]),
+ ?line equal_results(ets, match_object, Set, OrderedSet, ['_']),
+ ?line equal_results(ets, match_object, Set, OrderedSet, ['$5011']),
+ ?line equal_results(ets, match_delete, Set, OrderedSet, ['$20']),
+ ?line equal_results(ets, lookup_element, Set, OrderedSet, [13,2]),
+ ?line equal_results(ets, lookup_element, Set, OrderedSet, [13,4]),
+ ?line equal_results(ets, lookup_element, Set, OrderedSet, [14,2]),
+ ?line equal_results(ets, delete, Set, OrderedSet, []),
+ ?line verify_etsmem(EtsMem).
+
+equal_results(M, F, FirstArg1, FirstArg2 ,ACommon) ->
+ Res = maybe_sort((catch apply(M,F, [FirstArg1 | ACommon]))),
+ Res = maybe_sort((catch apply(M,F,[FirstArg2 | ACommon]))).
+
+maybe_sort(L) when is_list(L) ->
+ lists:sort(L);
+%maybe_sort({'EXIT',{Reason, [{Module, Function, _}|_]}}) ->
+% {'EXIT',{Reason, [{Module, Function, '_'}]}};
+maybe_sort({'EXIT',{Reason, List}}) when is_list(List) ->
+ {'EXIT',{Reason, lists:map(fun({Module, Function, _}) ->
+ {Module, Function, '_'}
+ end,
+ List)}};
+maybe_sort(Any) ->
+ Any.
+
+ordered_match(doc) ->
+ ["Test match, match_object and match_delete in ordered set's"];
+ordered_match(suite) ->
+ [];
+ordered_match(Config) when is_list(Config)->
+ repeat_for_opts(ordered_match_do).
+
+ordered_match_do(Opts) ->
+ ?line EtsMem = etsmem(),
+ ?line F = fun(X,T,FF) -> case X of
+ 0 -> true;
+ _ ->
+ ets:insert(T, {X,
+ integer_to_list(X),
+ X rem 10,
+ X rem 100,
+ X rem 1000}),
+ FF(X-1,T,FF)
+ end
+ end,
+ ?line T1 = ets:new(xxx,[ordered_set| Opts]),
+ ?line F(3000,T1,F),
+ ?line [[3,3],[3,3],[3,3]] = ets:match(T1, {'_','_','$1','$2',3}),
+ ?line F2 = fun(X,Rem,Res,FF) -> case X of
+ 0 -> [];
+ _ ->
+ case X rem Rem of
+ Res ->
+ FF(X-1,Rem,Res,FF) ++
+ [{X,
+ integer_to_list(X),
+ X rem 10,
+ X rem 100,
+ X rem 1000}];
+ _ ->
+ FF(X-1,Rem,Res,FF)
+ end
+ end
+ end,
+ ?line OL1 = F2(3000,100,2,F2),
+ ?line OL1 = ets:match_object(T1, {'_','_','_',2,'_'}),
+ ?line true = ets:match_delete(T1,{'_','_','_',2,'_'}),
+ ?line [] = ets:match_object(T1, {'_','_','_',2,'_'}),
+ ?line OL2 = F2(3000,100,3,F2),
+ ?line OL2 = ets:match_object(T1, {'_','_','_',3,'_'}),
+ ?line ets:delete(T1),
+ ?line verify_etsmem(EtsMem).
+
+
+ordered(doc) ->
+ ["Test basic functionality in ordered_set's."];
+ordered(suite) ->
+ [];
+ordered(Config) when is_list(Config) ->
+ repeat_for_opts(ordered_do).
+
+ordered_do(Opts) ->
+ ?line EtsMem = etsmem(),
+ ?line T = ets:new(oset, [ordered_set | Opts]),
+ ?line InsList = [
+ 25,26,27,28,
+ 5,6,7,8,
+ 21,22,23,24,
+ 9,10,11,12,
+ 1,2,3,4,
+ 17,18,19,20,
+ 13,14,15,16
+ ],
+ ?line lists:foreach(fun(X) ->
+ ets:insert(T,{X,integer_to_list(X)})
+ end,
+ InsList),
+ ?line IL2 = lists:map(fun(X) -> {X,integer_to_list(X)} end, InsList),
+ ?line L1 = pick_all_forward(T),
+ ?line L2 = pick_all_backwards(T),
+ ?line S1 = lists:sort(IL2),
+ ?line S2 = lists:reverse(lists:sort(IL2)),
+ ?line S1 = L1,
+ ?line S2 = L2,
+ ?line [{1,"1"}] = ets:slot(T,0),
+ ?line [{28,"28"}] = ets:slot(T,27),
+ ?line 27 = ets:prev(T,28),
+ ?line [{7,"7"}] = ets:slot(T,6),
+ ?line '$end_of_table' = ets:next(T,28),
+ ?line [{12,"12"}] = ets:slot(T,11),
+ ?line '$end_of_table' = ets:slot(T,28),
+ ?line [{1,"1"}] = ets:slot(T,0),
+ ?line 28 = ets:prev(T,29),
+ ?line 1 = ets:next(T,0),
+ ?line pick_all_forward(T),
+ ?line [{7,"7"}] = ets:slot(T,6),
+ ?line L2 = pick_all_backwards(T),
+ ?line [{7,"7"}] = ets:slot(T,6),
+ ?line ets:delete(T),
+ ?line verify_etsmem(EtsMem).
+
+pick_all(_T,'$end_of_table',_How) ->
+ [];
+pick_all(T,Last,How) ->
+ ?line This = case How of
+ next ->
+ ?line ets:next(T,Last);
+ prev ->
+ ?line ets:prev(T,Last)
+ end,
+ ?line [LastObj] = ets:lookup(T,Last),
+ ?line [LastObj | pick_all(T,This,How)].
+
+pick_all_forward(T) ->
+ ?line pick_all(T,ets:first(T),next).
+pick_all_backwards(T) ->
+ ?line pick_all(T,ets:last(T),prev).
+
+
+
+setbag(doc) -> ["Small test case for both set and bag type ets tables."];
+setbag(suite) -> [];
+setbag(Config) when is_list(Config) ->
+ ?line EtsMem = etsmem(),
+ ?line Set = ets:new(set,[set]),
+ ?line Bag = ets:new(bag,[bag]),
+ ?line Key = {foo,bar},
+
+ %% insert some value
+ ?line ets:insert(Set,{Key,val1}),
+ ?line ets:insert(Bag,{Key,val1}),
+
+ %% insert new value for same key again
+ ?line ets:insert(Set,{Key,val2}),
+ ?line ets:insert(Bag,{Key,val2}),
+
+ %% check
+ ?line [{Key,val2}] = ets:lookup(Set,Key),
+ ?line [{Key,val1},{Key,val2}] = ets:lookup(Bag,Key),
+
+ true = ets:delete(Set),
+ true = ets:delete(Bag),
+ ?line verify_etsmem(EtsMem).
+
+badnew(doc) ->
+ ["Test case to check proper return values for illegal ets:new() calls."];
+badnew(suite) -> [];
+badnew(Config) when is_list(Config) ->
+ ?line EtsMem = etsmem(),
+ ?line {'EXIT',{badarg,_}} = (catch ets:new(12,[])),
+ ?line {'EXIT',{badarg,_}} = (catch ets:new({a,b},[])),
+ ?line {'EXIT',{badarg,_}} = (catch ets:new(name,[foo])),
+ ?line {'EXIT',{badarg,_}} = (catch ets:new(name,{bag})),
+ ?line {'EXIT',{badarg,_}} = (catch ets:new(name,bag)),
+ ?line verify_etsmem(EtsMem).
+
+verybadnew(doc) ->
+ ["Test case to check that a not well formed list does not crash the "
+ "emulator. OTP-2314 "];
+verybadnew(suite) -> [];
+verybadnew(Config) when is_list(Config) ->
+ ?line EtsMem = etsmem(),
+ ?line {'EXIT',{badarg,_}} = (catch ets:new(verybad,[set|protected])),
+ ?line verify_etsmem(EtsMem).
+
+named(doc) -> ["Small check to see if named tables work."];
+named(suite) -> [];
+named(Config) when is_list(Config) ->
+ ?line EtsMem = etsmem(),
+ ?line Tab = make_table(foo,
+ [named_table],
+ [{key,val}]),
+ ?line [{key,val}] = ets:lookup(foo,key),
+ ?line true = ets:delete(Tab),
+ ?line verify_etsmem(EtsMem).
+
+keypos2(doc) -> ["Test case to check if specified keypos works."];
+keypos2(suite) -> [];
+keypos2(Config) when is_list(Config) ->
+ ?line EtsMem = etsmem(),
+ ?line Tab = make_table(foo,
+ [set,{keypos,2}],
+ [{val,key}, {val2,key}]),
+ ?line [{val2,key}] = ets:lookup(Tab,key),
+ ?line true = ets:delete(Tab),
+ ?line verify_etsmem(EtsMem).
+
+privacy(doc) ->
+ ["Privacy check. Check that a named(public/private/protected) table "
+ "cannot be read by",
+ "the wrong process(es)."];
+privacy(suite) -> [];
+privacy(Config) when is_list(Config) ->
+ repeat_for_opts(privacy_do).
+
+privacy_do(Opts) ->
+ ?line EtsMem = etsmem(),
+ ?line process_flag(trap_exit,true),
+ ?line Owner = my_spawn_link(?MODULE,privacy_owner,[self(),Opts]),
+ receive
+ {'EXIT',Owner,Reason} ->
+ ?line exit({privacy_test,Reason});
+ ok ->
+ ok
+ end,
+
+ privacy_check(pub,prot,priv),
+
+ Owner ! {shift,1,{pub,prot,priv}},
+ receive {Pub1,Prot1,Priv1} -> ok end,
+ privacy_check(Pub1,Prot1,Priv1),
+
+ Owner ! {shift,2,{Pub1,Prot1,Priv1}},
+ receive {Pub2,Prot2,Priv2} -> ok end,
+ privacy_check(Pub2,Prot2,Priv2),
+
+ Owner ! {shift,0,{Pub2,Prot2,Priv2}},
+ receive {Pub2,Prot2,Priv2} -> ok end,
+ privacy_check(Pub2,Prot2,Priv2),
+
+ Owner ! die,
+ receive {'EXIT',Owner,_} -> ok end,
+ ?line verify_etsmem(EtsMem).
+
+privacy_check(Pub,Prot,Priv) ->
+ %% check read rights
+ ?line [] = ets:lookup(Pub, foo),
+ ?line [] = ets:lookup(Prot,foo),
+ ?line {'EXIT',{badarg,_}} = (catch ets:lookup(Priv,foo)),
+
+ %% check write rights
+ ?line true = ets:insert(Pub, {1,foo}),
+ ?line {'EXIT',{badarg,_}} = (catch ets:insert(Prot,{2,foo})),
+ ?line {'EXIT',{badarg,_}} = (catch ets:insert(Priv,{3,foo})),
+
+ %% check that it really wasn't written, either
+ ?line [] = ets:lookup(Prot,foo).
+
+privacy_owner(Boss, Opts) ->
+ ets:new(pub, [public,named_table | Opts]),
+ ets:new(prot,[protected,named_table | Opts]),
+ ets:new(priv,[private,named_table | Opts]),
+ Boss ! ok,
+ privacy_owner_loop(Boss).
+
+privacy_owner_loop(Boss) ->
+ receive
+ {shift,N,Pub_Prot_Priv} ->
+ {Pub,Prot,Priv} = rotate_tuple(Pub_Prot_Priv, N),
+
+ ets:setopts(Pub,{protection,public}),
+ ets:setopts(Prot,{protection,protected}),
+ ets:setopts(Priv,{protection,private}),
+ Boss ! {Pub,Prot,Priv},
+ privacy_owner_loop(Boss);
+
+ die -> ok
+ end.
+
+rotate_tuple(Tuple, 0) ->
+ Tuple;
+rotate_tuple(Tuple, N) ->
+ [H|T] = tuple_to_list(Tuple),
+ rotate_tuple(list_to_tuple(T ++ [H]), N-1).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+insert(doc) -> ["Test proper and improper inserts into a table."];
+insert(suite) -> [empty,badinsert].
+
+empty(doc) ->
+ ["Check lookup in an empty table and lookup of a non-existing key"];
+empty(suite) -> [];
+empty(Config) when is_list(Config) ->
+ repeat_for_opts(empty_do).
+
+empty_do(Opts) ->
+ ?line EtsMem = etsmem(),
+ ?line Tab = ets:new(foo,Opts),
+ ?line [] = ets:lookup(Tab,key),
+ ?line true = ets:insert(Tab,{key2,val}),
+ ?line [] = ets:lookup(Tab,key),
+ ?line true = ets:delete(Tab),
+ ?line verify_etsmem(EtsMem).
+
+badinsert(doc) ->
+ ["Check proper return values for illegal insert operations."];
+badinsert(suite) -> [];
+badinsert(Config) when is_list(Config) ->
+ repeat_for_opts(badinsert_do).
+
+badinsert_do(Opts) ->
+ ?line EtsMem = etsmem(),
+ ?line {'EXIT',{badarg,_}} = (catch ets:insert(foo,{key,val})),
+
+ ?line Tab = ets:new(foo,Opts),
+ ?line {'EXIT',{badarg,_}} = (catch ets:insert(Tab,{})),
+
+ ?line Tab3 = ets:new(foo,[{keypos,3}| Opts]),
+ ?line {'EXIT',{badarg,_}} = (catch ets:insert(Tab3,{a,b})),
+
+ ?line {'EXIT',{badarg,_}} = (catch ets:insert(Tab,[key,val2])),
+ ?line true = ets:delete(Tab),
+ ?line true = ets:delete(Tab3),
+ ?line verify_etsmem(EtsMem).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+lookup(doc) -> ["Some tests for lookups (timing, bad lookups, etc.)."];
+lookup(suite) -> [time_lookup,badlookup,lookup_order].
+
+time_lookup(doc) -> ["Lookup timing."];
+time_lookup(suite) -> [];
+time_lookup(Config) when is_list(Config) ->
+ %% just for timing, really
+ ?line EtsMem = etsmem(),
+ Values = repeat_for_opts(time_lookup_do),
+ ?line verify_etsmem(EtsMem),
+ ?line {comment,lists:flatten(io_lib:format(
+ "~p ets lookups/s",[Values]))}.
+
+time_lookup_do(Opts) ->
+ ?line Tab = ets:new(foo,Opts),
+ ?line fill_tab(Tab,foo),
+ ?line ets:insert(Tab,{{a,key},foo}),
+ ?line {Time,_} = ?t:timecall(test_server,do_times,
+ [10000,ets,lookup,[Tab,{a,key}]]),
+ ?line true = ets:delete(Tab),
+ round(10000 / Time). % lookups/s
+
+badlookup(doc) ->
+ ["Check proper return values from bad lookups in existing/non existing "
+ " ets tables"];
+badlookup(suite) -> [];
+badlookup(Config) when is_list(Config) ->
+ ?line EtsMem = etsmem(),
+ ?line {'EXIT',{badarg,_}} = (catch ets:lookup(foo,key)),
+ ?line Tab = ets:new(foo,[]),
+ ?line ets:delete(Tab),
+ ?line {'EXIT',{badarg,_}} = (catch ets:lookup(Tab,key)),
+ ?line verify_etsmem(EtsMem).
+
+lookup_order(doc) -> ["Test that lookup returns objects in order of insertion for bag and dbag."];
+lookup_order(suite) -> [];
+lookup_order(Config) when is_list(Config) ->
+ EtsMem = etsmem(),
+ repeat_for_opts(lookup_order_do, [write_concurrency,[bag,duplicate_bag]]),
+ ?line verify_etsmem(EtsMem),
+ ok.
+
+lookup_order_do(Opts) ->
+ lookup_order_2(Opts, false),
+ lookup_order_2(Opts, true).
+
+lookup_order_2(Opts, Fixed) ->
+ io:format("Opts=~p Fixed=~p\n",[Opts,Fixed]),
+
+ A = 1, B = 2, C = 3,
+ ABC = [A,B,C],
+ Pair = [{A,B},{B,A},{A,C},{C,A},{B,C},{C,B}],
+ Combos = [{D1,D2,D3} || D1<-ABC, D2<-Pair, D3<-Pair],
+ lists:foreach(fun({D1,{D2a,D2b},{D3a,D3b}}) ->
+ T = ets:new(foo,Opts),
+ case Fixed of
+ true -> ets:safe_fixtable(T,true);
+ false -> ok
+ end,
+ S10 = {T,[],key},
+ S20 = check_insert(S10,A),
+ S30 = check_insert(S20,B),
+ S40 = check_insert(S30,C),
+ S50 = check_delete(S40,D1),
+ S55 = check_insert(S50,D1),
+ S60 = check_insert(S55,D1),
+ S70 = check_delete(S60,D2a),
+ S80 = check_delete(S70,D2b),
+ S90 = check_insert(S80,D2a),
+ SA0 = check_delete(S90,D3a),
+ SB0 = check_delete(SA0,D3b),
+ check_insert_new(SB0,D3b),
+
+ true = ets:delete(T)
+ end,
+ Combos).
+
+
+check_insert({T,List0,Key},Val) ->
+ %%io:format("insert ~p into ~p\n",[Val,List0]),
+ ets:insert(T,{Key,Val}),
+ List1 = case (ets:info(T,type) =:= bag andalso
+ lists:member({Key,Val},List0)) of
+ true -> List0;
+ false -> [{Key,Val} | List0]
+ end,
+ check_check({T,List1,Key}).
+
+check_insert_new({T,List0,Key},Val) ->
+ %%io:format("insert_new ~p into ~p\n",[Val,List0]),
+ Ret = ets:insert_new(T,{Key,Val}),
+ ?line Ret = (List0 =:= []),
+ List1 = case Ret of
+ true -> [{Key,Val}];
+ false -> List0
+ end,
+ check_check({T,List1,Key}).
+
+
+check_delete({T,List0,Key},Val) ->
+ %%io:format("delete ~p from ~p\n",[Val,List0]),
+ ets:delete_object(T,{Key,Val}),
+ List1 = lists:filter(fun(Obj) -> Obj =/= {Key,Val} end,
+ List0),
+ check_check({T,List1,Key}).
+
+check_check(S={T,List,Key}) ->
+ case lists:reverse(ets:lookup(T,Key)) of
+ List -> ok;
+ ETS -> io:format("check failed:\nETS: ~p\nCHK: ~p\n", [ETS,List]),
+ ?t:fail("Invalid return value from ets:lookup")
+ end,
+ ?line Items = ets:info(T,size),
+ ?line Items = length(List),
+ S.
+
+
+
+fill_tab(Tab,Val) ->
+ ?line ets:insert(Tab,{key,Val}),
+ ?line ets:insert(Tab,{{a,144},Val}),
+ ?line ets:insert(Tab,{{a,key2},Val}),
+ ?line ets:insert(Tab,{14,Val}),
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+lookup_element(doc) -> ["Some tests for lookup_element."];
+lookup_element(suite) -> [lookup_element_mult].
+
+lookup_element_mult(doc) -> ["Multiple return elements (OTP-2386)"];
+lookup_element_mult(suite) -> [];
+lookup_element_mult(Config) when is_list(Config) ->
+ repeat_for_opts(lookup_element_mult_do).
+
+lookup_element_mult_do(Opts) ->
+ ?line EtsMem = etsmem(),
+ ?line T = ets:new(service, [bag, {keypos, 2} | Opts]),
+ ?line D = lists:reverse(lem_data()),
+ ?line lists:foreach(fun(X) -> ets:insert(T, X) end, D),
+ ?line ok = lem_crash_3(T),
+ ?line true = ets:delete(T),
+ ?line verify_etsmem(EtsMem).
+
+lem_data() ->
+ [
+ {service,'eddie2@boromir',{150,236,14,103},httpd88,self()},
+ {service,'eddie2@boromir',{150,236,14,103},httpd80,self()},
+ {service,'eddie3@boromir',{150,236,14,107},httpd88,self()},
+ {service,'eddie3@boromir',{150,236,14,107},httpd80,self()},
+ {service,'eddie4@boromir',{150,236,14,108},httpd88,self()}
+ ].
+
+lem_crash(T) ->
+ L = ets:lookup_element(T, 'eddie2@boromir', 3),
+ {erlang:phash(L, 256), L}.
+
+lem_crash_3(T) ->
+ lem_crash(T),
+ io:format("Survived once~n"),
+ lem_crash(T),
+ io:format("Survived twice~n"),
+ lem_crash(T),
+ io:format("Survived all!~n"),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+delete(doc) ->
+ ["Check delete functionality (proper/improper deletes)"];
+delete(suite) ->
+ [delete_elem,delete_tab,delete_large_tab,delete_large_named_table,evil_delete,
+ table_leak,baddelete,match_delete,match_delete3].
+
+delete_elem(doc) ->
+ ["Check delete of an element inserted in a `filled' table."];
+delete_elem(suite) -> [];
+delete_elem(Config) when is_list(Config) ->
+ repeat_for_opts(delete_elem_do, [write_concurrency, all_types]).
+
+delete_elem_do(Opts) ->
+ ?line EtsMem = etsmem(),
+ ?line Tab = ets:new(foo,Opts),
+ ?line fill_tab(Tab,foo),
+ ?line ets:insert(Tab,{{b,key},foo}),
+ ?line ets:insert(Tab,{{c,key},foo}),
+ ?line true = ets:delete(Tab,{b,key}),
+ ?line [] = ets:lookup(Tab,{b,key}),
+ ?line [{{c,key},foo}] = ets:lookup(Tab,{c,key}),
+ ?line true = ets:delete(Tab),
+ ?line verify_etsmem(EtsMem).
+
+delete_tab(doc) ->
+ ["Check that ets:delete() works and releases the name of the deleted "
+ "table."];
+delete_tab(suite) -> [];
+delete_tab(Config) when is_list(Config) ->
+ repeat_for_opts(delete_tab_do,[write_concurrency,all_types]).
+
+delete_tab_do(Opts) ->
+ Name = foo,
+ ?line EtsMem = etsmem(),
+ ?line Name = ets:new(Name, [named_table | Opts]),
+ ?line true = ets:delete(foo),
+ %% The name should be available again.
+ ?line Name = ets:new(Name, [named_table | Opts]),
+ ?line true = ets:delete(Name),
+ ?line verify_etsmem(EtsMem).
+
+delete_large_tab(doc) ->
+ "Check that ets:delete/1 works and that other processes can run.";
+delete_large_tab(Config) when is_list(Config) ->
+ ?line Data = [{erlang:phash2(I, 16#ffffff),I} || I <- lists:seq(1, 500000)],
+ ?line EtsMem = etsmem(),
+ repeat_for_opts(fun(Opts) -> delete_large_tab_do(Opts,Data) end),
+ ?line verify_etsmem(EtsMem).
+
+delete_large_tab_do(Opts,Data) ->
+ ?line delete_large_tab_1(foo_hash, Opts, Data, false),
+ ?line delete_large_tab_1(foo_tree, [ordered_set | Opts], Data, false),
+ ?line delete_large_tab_1(foo_hash, Opts, Data, true).
+
+
+delete_large_tab_1(Name, Flags, Data, Fix) ->
+ ?line Tab = ets:new(Name, Flags),
+ ?line ets:insert(Tab, Data),
+
+ case Fix of
+ false -> ok;
+ true ->
+ ?line true = ets:safe_fixtable(Tab, true),
+ ?line lists:foreach(fun({K,_}) -> ets:delete(Tab, K) end, Data)
+ end,
+
+ {priority, Prio} = process_info(self(), priority),
+ ?line Deleter = self(),
+ ?line [SchedTracer]
+ = start_loopers(1,
+ Prio,
+ fun (SC) ->
+ receive
+ {trace, Deleter, out, _} ->
+ undefined = ets:info(Tab),
+ SC+1;
+ {trace,
+ Deleter,
+ register,
+ delete_large_tab_done_marker}->
+ Deleter ! {schedule_count, SC},
+ exit(normal);
+ _ ->
+ SC
+ end
+ end,
+ 0),
+ ?line Loopers = start_loopers(erlang:system_info(schedulers),
+ Prio,
+ fun (_) -> erlang:yield() end,
+ ok),
+ ?line erlang:yield(),
+ ?line 1 = erlang:trace(self(),true,[running,procs,{tracer,SchedTracer}]),
+ ?line true = ets:delete(Tab),
+ %% The register stuff is just a trace marker
+ ?line true = register(delete_large_tab_done_marker, self()),
+ ?line true = unregister(delete_large_tab_done_marker),
+ ?line undefined = ets:info(Tab),
+ ?line ok = stop_loopers(Loopers),
+ ?line receive
+ {schedule_count, N} ->
+ ?line io:format("~s: context switches: ~p", [Name,N]),
+ if
+ N >= 5 -> ?line ok;
+ true -> ?line ?t:fail()
+ end
+ end.
+
+delete_large_named_table(doc) ->
+ "Delete a large name table and try to create a new table with the same name in another process.";
+delete_large_named_table(Config) when is_list(Config) ->
+ ?line Data = [{erlang:phash2(I, 16#ffffff),I} || I <- lists:seq(1, 500000)],
+ ?line EtsMem = etsmem(),
+ repeat_for_opts(fun(Opts) -> delete_large_named_table_do(Opts,Data) end),
+ ?line verify_etsmem(EtsMem),
+ ok.
+
+delete_large_named_table_do(Opts,Data) ->
+ ?line delete_large_named_table_1(foo_hash, [named_table | Opts], Data, false),
+ ?line delete_large_named_table_1(foo_tree, [ordered_set,named_table | Opts], Data, false),
+ ?line delete_large_named_table_1(foo_hash, [named_table | Opts], Data, true).
+
+delete_large_named_table_1(Name, Flags, Data, Fix) ->
+ ?line Tab = ets:new(Name, Flags),
+ ?line ets:insert(Tab, Data),
+
+ case Fix of
+ false -> ok;
+ true ->
+ ?line true = ets:safe_fixtable(Tab, true),
+ ?line lists:foreach(fun({K,_}) -> ets:delete(Tab, K) end, Data)
+ end,
+ Parent = self(),
+ Pid = spawn_link(fun() ->
+ receive
+ {trace,Parent,call,_} ->
+ ets:new(Name, [named_table])
+ end
+ end),
+ ?line erlang:trace(self(), true, [call,{tracer,Pid}]),
+ ?line erlang:trace_pattern({ets,delete,1}, true, [global]),
+ ?line erlang:yield(), true = ets:delete(Tab),
+ ?line erlang:trace_pattern({ets,delete,1}, false, [global]),
+ ok.
+
+evil_delete(doc) ->
+ "Delete a large table, and kill the process during the delete.";
+evil_delete(Config) when is_list(Config) ->
+ ?line Data = [{I,I*I} || I <- lists:seq(1, 100000)],
+ repeat_for_opts(fun(Opts) -> evil_delete_do(Opts,Data) end).
+
+evil_delete_do(Opts,Data) ->
+ ?line EtsMem = etsmem(),
+ ?line evil_delete_owner(foo_hash, Opts, Data, false),
+ ?line verify_etsmem(EtsMem),
+ ?line evil_delete_owner(foo_hash, Opts, Data, true),
+ ?line verify_etsmem(EtsMem),
+ ?line evil_delete_owner(foo_tree, [ordered_set | Opts], Data, false),
+ ?line verify_etsmem(EtsMem),
+ ?line TabA = evil_delete_not_owner(foo_hash, Opts, Data, false),
+ ?line verify_etsmem(EtsMem),
+ ?line TabB = evil_delete_not_owner(foo_hash, Opts, Data, true),
+ ?line verify_etsmem(EtsMem),
+ ?line TabC = evil_delete_not_owner(foo_tree, [ordered_set | Opts], Data, false),
+ ?line verify_etsmem(EtsMem),
+ ?line lists:foreach(fun(T) -> undefined = ets:info(T) end,
+ [TabA,TabB,TabC]).
+
+evil_delete_not_owner(Name, Flags, Data, Fix) ->
+ io:format("Not owner: ~p, fix = ~p", [Name,Fix]),
+ ?line Tab = ets:new(Name, [public|Flags]),
+ ?line ets:insert(Tab, Data),
+ case Fix of
+ false -> ok;
+ true ->
+ ?line true = ets:safe_fixtable(Tab, true),
+ ?line lists:foreach(fun({K,_}) -> ets:delete(Tab, K) end, Data)
+ end,
+ ?line Pid = my_spawn(fun() ->
+ P = my_spawn_link(
+ fun() ->
+ receive kill -> ok end,
+ erlang:yield(),
+ exit(kill_linked_processes_now)
+ end),
+ erlang:yield(),
+ P ! kill,
+ true = ets:delete(Tab)
+ end),
+ ?line Ref = erlang:monitor(process, Pid),
+ ?line receive {'DOWN',Ref,_,_,_} -> ok end,
+ Tab.
+
+evil_delete_owner(Name, Flags, Data, Fix) ->
+ ?line Fun = fun() ->
+ ?line Tab = ets:new(Name, [public|Flags]),
+ ?line ets:insert(Tab, Data),
+ case Fix of
+ false -> ok;
+ true ->
+ ?line true = ets:safe_fixtable(Tab, true),
+ ?line lists:foreach(fun({K,_}) ->
+ ets:delete(Tab, K)
+ end, Data)
+ end,
+ erlang:yield(),
+ my_spawn_link(fun() ->
+ erlang:yield(),
+ exit(kill_linked_processes_now)
+ end),
+ true = ets:delete(Tab)
+ end,
+ ?line Pid = my_spawn(Fun),
+ ?line Ref = erlang:monitor(process, Pid),
+ ?line receive {'DOWN',Ref,_,_,_} -> ok end.
+
+
+exit_large_table_owner(doc) ->
+ [];
+exit_large_table_owner(suite) ->
+ [];
+exit_large_table_owner(Config) when is_list(Config) ->
+ ?line Data = [{erlang:phash2(I, 16#ffffff),I} || I <- lists:seq(1, 500000)],
+ ?line EtsMem = etsmem(),
+ repeat_for_opts(fun(Opts) -> exit_large_table_owner_do(Opts,Data,Config) end),
+ ?line verify_etsmem(EtsMem).
+
+exit_large_table_owner_do(Opts,Data,Config) ->
+ ?line verify_rescheduling_exit(Config, Data, [named_table | Opts], true, 1, 1),
+ ?line verify_rescheduling_exit(Config, Data, Opts, false, 1, 1).
+
+exit_many_large_table_owner(doc) -> [];
+exit_many_large_table_owner(suite) -> [];
+exit_many_large_table_owner(Config) when is_list(Config) ->
+ ?line Data = [{erlang:phash2(I, 16#ffffff),I} || I <- lists:seq(1, 500000)],
+ ?line EtsMem = etsmem(),
+ repeat_for_opts(fun(Opts) -> exit_many_large_table_owner_do(Opts,Data,Config) end),
+ ?line verify_etsmem(EtsMem).
+
+exit_many_large_table_owner_do(Opts,Data,Config) ->
+ ?line verify_rescheduling_exit(Config, Data, Opts, true, 1, 4),
+ ?line verify_rescheduling_exit(Config, Data, [named_table | Opts], false, 1, 4).
+
+exit_many_tables_owner(doc) -> [];
+exit_many_tables_owner(suite) -> [];
+exit_many_tables_owner(Config) when is_list(Config) ->
+ ?line EtsMem = etsmem(),
+ ?line verify_rescheduling_exit(Config, [], [named_table], false, 1000, 1),
+ ?line verify_rescheduling_exit(Config, [], [named_table,{write_concurrency,true}], false, 1000, 1),
+ ?line verify_etsmem(EtsMem).
+
+exit_many_many_tables_owner(doc) -> [];
+exit_many_many_tables_owner(suite) -> [];
+exit_many_many_tables_owner(Config) when is_list(Config) ->
+ ?line Data = [{erlang:phash2(I, 16#ffffff),I} || I <- lists:seq(1, 50)],
+ repeat_for_opts(fun(Opts) -> exit_many_many_tables_owner_do(Opts,Data,Config) end).
+
+exit_many_many_tables_owner_do(Opts,Data,Config) ->
+ ?line verify_rescheduling_exit(Config, Data, [named_table | Opts], true, 200, 5),
+ ?line verify_rescheduling_exit(Config, Data, Opts, false, 200, 5),
+ ?line wait_for_test_procs(),
+ ?line EtsMem = etsmem(),
+ ?line verify_rescheduling_exit(Config, Data, Opts, true, 200, 5),
+ ?line verify_rescheduling_exit(Config, Data, [named_table | Opts], false, 200, 5),
+ ?line verify_etsmem(EtsMem).
+
+
+count_exit_sched(TP) ->
+ receive
+ {trace, TP, in_exiting, 0} ->
+ count_exit_sched_out(TP, 1);
+ {trace, TP, out_exiting, 0} ->
+ count_exit_sched_in(TP, 1);
+ {trace, TP, out_exited, 0} ->
+ 0
+ end.
+
+count_exit_sched_in(TP, N) ->
+ receive
+ {trace, TP, in_exiting, 0} ->
+ count_exit_sched_out(TP, N);
+ {trace, TP, _, _} = Msg ->
+ exit({unexpected_trace_msg, Msg})
+ end.
+
+count_exit_sched_out(TP, N) ->
+ receive
+ {trace, TP, out_exiting, 0} ->
+ count_exit_sched_in(TP, N+1);
+ {trace, TP, out_exited, 0} ->
+ N;
+ {trace, TP, _, _} = Msg ->
+ exit({unexpected_trace_msg, Msg})
+ end.
+
+vre_fix_tables(Tab) ->
+ Parent = self(),
+ Go = make_ref(),
+ my_spawn_link(fun () ->
+ true = ets:safe_fixtable(Tab, true),
+ Parent ! Go,
+ receive infinity -> ok end
+ end),
+ receive Go -> ok end,
+ ok.
+
+verify_rescheduling_exit(Config, Data, Flags, Fix, NOTabs, NOProcs) ->
+ ?line NoFix = 5,
+ ?line TestCase = atom_to_list(?config(test_case, Config)),
+ ?line Parent = self(),
+ ?line KillMe = make_ref(),
+ ?line PFun =
+ fun () ->
+ repeat(
+ fun () ->
+ {A, B, C} = now(),
+ ?line Name = list_to_atom(
+ TestCase
+ ++ "-" ++ integer_to_list(A)
+ ++ "-" ++ integer_to_list(B)
+ ++ "-" ++ integer_to_list(C)),
+ Tab = ets:new(Name, Flags),
+ ets:insert(Tab, Data),
+ case Fix of
+ false -> ok;
+ true ->
+ lists:foreach(fun (_) ->
+ vre_fix_tables(Tab)
+ end,
+ lists:seq(1,NoFix)),
+ lists:foreach(fun({K,_}) ->
+ ets:delete(Tab, K)
+ end,
+ Data)
+ end
+ end,
+ NOTabs),
+ Parent ! {KillMe, self()},
+ receive after infinity -> ok end
+ end,
+ ?line TPs = lists:map(fun (_) ->
+ ?line TP = my_spawn_link(PFun),
+ ?line 1 = erlang:trace(TP, true, [exiting]),
+ TP
+ end,
+ lists:seq(1, NOProcs)),
+ ?line lists:foreach(fun (TP) ->
+ receive {KillMe, TP} -> ok end
+ end,
+ TPs),
+ ?line LPs = start_loopers(erlang:system_info(schedulers),
+ normal,
+ fun (_) ->
+ erlang:yield()
+ end,
+ ok),
+ ?line lists:foreach(fun (TP) ->
+ ?line unlink(TP),
+ ?line exit(TP, bang)
+ end,
+ TPs),
+ ?line lists:foreach(fun (TP) ->
+ ?line XScheds = count_exit_sched(TP),
+ ?line ?t:format("~p XScheds=~p~n",
+ [TP, XScheds]),
+ ?line true = XScheds >= 5
+ end,
+ TPs),
+ ?line stop_loopers(LPs),
+ ?line ok.
+
+
+
+table_leak(doc) ->
+ "Make sure that slots for ets tables are cleared properly.";
+table_leak(Config) when is_list(Config) ->
+ repeat_for_opts(fun(Opts) -> table_leak_1(Opts,20000) end).
+
+table_leak_1(_,0) -> ok;
+table_leak_1(Opts,N) ->
+ ?line T = ets:new(fooflarf, Opts),
+ ?line true = ets:delete(T),
+ table_leak_1(Opts,N-1).
+
+baddelete(doc) ->
+ ["Check proper return values for illegal delete operations."];
+baddelete(suite) -> [];
+baddelete(Config) when is_list(Config) ->
+ ?line EtsMem = etsmem(),
+ ?line {'EXIT',{badarg,_}} = (catch ets:delete(foo)),
+ ?line Tab = ets:new(foo,[]),
+ ?line true = ets:delete(Tab),
+ ?line {'EXIT',{badarg,_}} = (catch ets:delete(Tab)),
+ ?line verify_etsmem(EtsMem).
+
+match_delete(doc) ->
+ ["Check that match_delete works. Also tests tab2list function."];
+match_delete(suite) -> [];
+match_delete(Config) when is_list(Config) ->
+ ?line EtsMem = etsmem(),
+ repeat_for_opts(match_delete_do,[write_concurrency,all_types]),
+ ?line verify_etsmem(EtsMem).
+
+match_delete_do(Opts) ->
+ ?line EtsMem = etsmem(),
+ ?line Tab = ets:new(kad,Opts),
+ ?line fill_tab(Tab,foo),
+ ?line ets:insert(Tab,{{c,key},bar}),
+ ?line _ = ets:match_delete(Tab,{'_',foo}),
+ ?line [{{c,key},bar}] = ets:tab2list(Tab),
+ ?line _ = ets:match_delete(Tab,'_'),
+ ?line [] = ets:tab2list(Tab),
+ ?line true = ets:delete(Tab),
+ ?line verify_etsmem(EtsMem).
+
+match_delete3(doc) ->
+ ["OTP-3005: check match_delete with constant argument."];
+match_delete3(suite) -> [];
+match_delete3(Config) when is_list(Config) ->
+ repeat_for_opts(match_delete3_do).
+
+match_delete3_do(Opts) ->
+ ?line EtsMem = etsmem(),
+ T = make_table(test,
+ [duplicate_bag | Opts],
+ [{aa,17},
+ {cA,1000},
+ {cA,17},
+ {cA,1000},
+ {aa,17}]),
+ %% 'aa' and 'cA' have the same hash value in the current
+ %% implementation. This causes the aa's to precede the cA's, to make
+ %% the test more interesting.
+ [{cA,1000},{cA,1000}] = ets:match_object(T, {'_', 1000}),
+ ets:match_delete(T, {cA,1000}),
+ [] = ets:match_object(T, {'_', 1000}),
+ ets:delete(T),
+ ?line verify_etsmem(EtsMem).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+firstnext(doc) -> ["Tests ets:first/1 & ets:next/2."];
+firstnext(suite) -> [];
+firstnext(Config) when is_list(Config) ->
+ repeat_for_opts(firstnext_do).
+
+firstnext_do(Opts) ->
+ ?line EtsMem = etsmem(),
+ ?line Tab = ets:new(foo,Opts),
+ ?line [] = firstnext_collect(Tab,ets:first(Tab),[]),
+ ?line fill_tab(Tab,foo),
+ ?line Len = length(ets:tab2list(Tab)),
+ ?line Len = length(firstnext_collect(Tab,ets:first(Tab),[])),
+ ?line true = ets:delete(Tab),
+ ?line verify_etsmem(EtsMem).
+
+firstnext_collect(_Tab,'$end_of_table',List) ->
+ ?line List;
+firstnext_collect(Tab,Key,List) ->
+ ?line firstnext_collect(Tab,ets:next(Tab,Key),[Key|List]).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+firstnext_concurrent(doc) -> "Tests ets:first/1 & ets:next/2.";
+firstnext_concurrent(Config) when is_list(Config) ->
+ register(master, self()),
+ ets_init(?MODULE, 20),
+ [dynamic_go() || _ <- lists:seq(1, 2)],
+ receive
+ after 5000 -> ok
+ end.
+
+ets_init(Tab, N) ->
+ ets:new(Tab, [named_table,public,ordered_set]),
+ cycle(Tab, lists:seq(1,N+1)).
+
+cycle(_Tab, [H|T]) when H > length(T)-> ok;
+cycle(Tab, L) ->
+ ets:insert(Tab,list_to_tuple(L)),
+ cycle(Tab, tl(L)++[hd(L)]).
+
+dynamic_go() -> spawn_link(fun dynamic_init/0).
+
+dynamic_init() -> [dyn_lookup(?MODULE) || _ <- lists:seq(1, 10)].
+
+dyn_lookup(T) -> dyn_lookup(T, ets:first(T)).
+
+dyn_lookup(_T, '$end_of_table') -> [];
+dyn_lookup(T, K) ->
+ NextKey=ets:next(T,K),
+ case ets:next(T,K) of
+ NextKey ->
+ dyn_lookup(T, NextKey);
+ NK ->
+ io:fwrite("hmmm... ~p =/= ~p~n", [NextKey,NK]),
+ exit(failed)
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+slot(suite) -> [];
+slot(Config) when is_list(Config) ->
+ repeat_for_opts(slot_do).
+
+slot_do(Opts) ->
+ ?line EtsMem = etsmem(),
+ ?line Tab = ets:new(foo,Opts),
+ ?line fill_tab(Tab,foo),
+ ?line Elts = ets:info(Tab,size),
+ ?line Elts = slot_loop(Tab,0,0),
+ ?line true = ets:delete(Tab),
+ ?line verify_etsmem(EtsMem).
+
+slot_loop(Tab,SlotNo,EltsSoFar) ->
+ ?line case ets:slot(Tab,SlotNo) of
+ '$end_of_table' ->
+ ?line {'EXIT',{badarg,_}} =
+ (catch ets:slot(Tab,SlotNo+1)),
+ ?line EltsSoFar;
+ Elts ->
+ ?line slot_loop(Tab,SlotNo+1,EltsSoFar+length(Elts))
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+match(suite) -> [match1, match2, match_object, match_object2].
+
+match1(suite) -> [];
+match1(Config) when is_list(Config) ->
+ repeat_for_opts(match1_do).
+
+match1_do(Opts) ->
+ ?line EtsMem = etsmem(),
+ ?line Tab = ets:new(foo,Opts),
+ ?line fill_tab(Tab,foo),
+ ?line [] = ets:match(Tab,{}),
+ ?line ets:insert(Tab,{{one,4},4}),
+ ?line ets:insert(Tab,{{one,5},5}),
+ ?line ets:insert(Tab,{{two,4},4}),
+ ?line ets:insert(Tab,{{two,5},6}),
+ ?line case ets:match(Tab,{{one,'_'},'$0'}) of
+ [[4],[5]] -> ok;
+ [[5],[4]] -> ok
+ end,
+ ?line case ets:match(Tab,{{two,'$1'},'$0'}) of
+ [[4,4],[6,5]] -> ok;
+ [[6,5],[4,4]] -> ok
+ end,
+ ?line case ets:match(Tab,{{two,'$9'},'$4'}) of
+ [[4,4],[6,5]] -> ok;
+ [[6,5],[4,4]] -> ok
+ end,
+ ?line case ets:match(Tab,{{two,'$9'},'$22'}) of
+ [[4,4],[5,6]] -> ok;
+ [[5,6],[4,4]] -> ok
+ end,
+ ?line [[4]] = ets:match(Tab,{{two,'$0'},'$0'}),
+ ?line Len = length(ets:match(Tab,'$0')),
+ ?line Len = length(ets:match(Tab,'_')),
+ ?line if Len > 4 -> ok end,
+ ?line true = ets:delete(Tab),
+ ?line verify_etsmem(EtsMem).
+
+match2(doc) -> ["Tests match with specified keypos bag table."];
+match2(suite) -> [];
+match2(Config) when is_list(Config) ->
+ repeat_for_opts(match2_do).
+
+match2_do(Opts) ->
+ ?line EtsMem = etsmem(),
+ ?line Tab = make_table(foobar,
+ [bag, named_table, {keypos, 2} | Opts],
+ [{value1, key1},
+ {value2_1, key2},
+ {value2_2, key2},
+ {value3_1, key3},
+ {value3_2, key3},
+ {value2_1, key2_wannabe}]),
+ ?line case length(ets:match(Tab, '$1')) of
+ 6 -> ok;
+ _ -> ?t:fail("Length of matched list is wrong.")
+ end,
+ ?line [[value3_1],[value3_2]] = ets:match(Tab, {'$1', key3}),
+ ?line [[key1]] = ets:match(Tab, {value1, '$1'}),
+ ?line [[key2_wannabe],[key2]] = ets:match(Tab, {value2_1, '$2'}),
+ ?line [] = ets:match(Tab,{'$1',nosuchkey}),
+ ?line [] = ets:match(Tab,{'$1',kgY2}), % same hash as key2
+ ?line [] = ets:match(Tab,{nosuchvalue,'$1'}),
+ ?line true = ets:delete(Tab),
+ ?line verify_etsmem(EtsMem).
+
+match_object(doc) -> ["Some ets:match_object test."];
+match_object(suite) -> [];
+match_object(Config) when is_list(Config) ->
+ repeat_for_opts(match_object_do).
+
+match_object_do(Opts) ->
+ ?line EtsMem = etsmem(),
+ ?line Tab = ets:new(foobar, Opts),
+ ?line fill_tab(Tab, foo),
+ ?line ets:insert(Tab, {{one, 4}, 4}),
+ ?line ets:insert(Tab,{{one,5},5}),
+ ?line ets:insert(Tab,{{two,4},4}),
+ ?line ets:insert(Tab,{{two,5},6}),
+ ?line case ets:match_object(Tab, {{one, '_'}, '$0'}) of
+ [{{one,5},5},{{one,4},4}] -> ok;
+ [{{one,4},4},{{one,5},5}] -> ok;
+ _ -> ?t:fail("ets:match_object() returned something funny.")
+ end,
+ ?line case ets:match_object(Tab, {{two, '$1'}, '$0'}) of
+ [{{two,5},6},{{two,4},4}] -> ok;
+ [{{two,4},4},{{two,5},6}] -> ok;
+ _ -> ?t:fail("ets:match_object() returned something funny.")
+ end,
+ ?line case ets:match_object(Tab, {{two, '$9'}, '$4'}) of
+ [{{two,5},6},{{two,4},4}] -> ok;
+ [{{two,4},4},{{two,5},6}] -> ok;
+ _ -> ?t:fail("ets:match_object() returned something funny.")
+ end,
+ ?line case ets:match_object(Tab, {{two, '$9'}, '$22'}) of
+ [{{two,5},6},{{two,4},4}] -> ok;
+ [{{two,4},4},{{two,5},6}] -> ok;
+ _ -> ?t:fail("ets:match_object() returned something funny.")
+ end,
+ % Check that unsucessful match returns an empty list.
+ ?line [] = ets:match_object(Tab, {{three,'$0'}, '$92'}),
+ % Check that '$0' equals '_'.
+ Len = length(ets:match_object(Tab, '$0')),
+ Len = length(ets:match_object(Tab, '_')),
+ ?line if Len > 4 -> ok end,
+ ?line true = ets:delete(Tab),
+ ?line verify_etsmem(EtsMem).
+
+match_object2(suite) -> [];
+match_object2(doc) -> ["Tests that db_match_object does not generate "
+ "a `badarg' when resuming a search with no "
+ "previous matches."];
+match_object2(Config) when is_list(Config) ->
+ repeat_for_opts(match_object2_do).
+
+match_object2_do(Opts) ->
+ ?line EtsMem = etsmem(),
+ ?line Tab = ets:new(foo, [bag, {keypos, 2} | Opts]),
+ ?line fill_tab2(Tab, 0, 13005), % match_db_object does 1000
+ % elements per pass, might
+ % change in the future.
+ ?line case catch ets:match_object(Tab, {hej, '$1'}) of
+ {'EXIT', _} ->
+ ets:delete(Tab),
+ ?t:fail("match_object EXIT:ed");
+ [] ->
+ io:format("Nothing matched.");
+ List ->
+ io:format("Matched:~p~n",[List])
+ end,
+ ets:delete(Tab),
+ ?line verify_etsmem(EtsMem).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+misc(suite) -> [misc1, safe_fixtable, info, dups, tab2list].
+
+tab2list(doc) -> ["Tests tab2list (OTP-3319)"];
+tab2list(suite) -> [];
+tab2list(Config) when is_list(Config) ->
+ ?line EtsMem = etsmem(),
+ ?line Tab = make_table(foo,
+ [ordered_set],
+ [{a,b}, {c,b}, {b,b}, {a,c}]),
+ ?line [{a,c},{b,b},{c,b}] = ets:tab2list(Tab),
+ ?line true = ets:delete(Tab),
+ ?line verify_etsmem(EtsMem).
+
+misc1(doc) -> ["Simple general small test. ",
+ "If this fails, ets is in really bad shape."];
+misc1(suite) -> [];
+misc1(Config) when is_list(Config) ->
+ repeat_for_opts(misc1_do).
+
+misc1_do(Opts) ->
+ ?line EtsMem = etsmem(),
+ ?line Tab = ets:new(foo,Opts),
+ ?line true = lists:member(Tab,ets:all()),
+ ?line ets:delete(Tab),
+ ?line false = lists:member(Tab,ets:all()),
+ ?line case catch ets:delete(Tab) of
+ {'EXIT',_Reason} ->
+ ?line verify_etsmem(EtsMem);
+ true ->
+ ?t:fail("Delete of nonexisting table returned `true'.")
+ end,
+ ok.
+
+safe_fixtable(doc) -> ["Check the safe_fixtable function."];
+safe_fixtable(suite) -> [];
+safe_fixtable(Config) when is_list(Config) ->
+ repeat_for_opts(safe_fixtable_do).
+
+safe_fixtable_do(Opts) ->
+ ?line EtsMem = etsmem(),
+ ?line Tab = ets:new(foo, Opts),
+ ?line fill_tab(Tab, foobar),
+ ?line true = ets:safe_fixtable(Tab, true),
+ ?line receive after 1 -> ok end,
+ ?line true = ets:safe_fixtable(Tab, false),
+ ?line false = ets:info(Tab,safe_fixed),
+ ?line true = ets:safe_fixtable(Tab, true),
+ Self = self(),
+ ?line {{_,_,_},[{Self,1}]} = ets:info(Tab,safe_fixed),
+ %% Test that an unjustified 'unfix' is a no-op.
+ {Pid,MRef} = spawn_monitor(fun() -> true = ets:safe_fixtable(Tab,false) end),
+ {'DOWN', MRef, process, Pid, normal} = receive M -> M end,
+ ?line true = ets:info(Tab,fixed),
+ ?line {{_,_,_},[{Self,1}]} = ets:info(Tab,safe_fixed),
+ %% badarg's
+ ?line {'EXIT', {badarg, _}} = (catch ets:safe_fixtable(Tab, foobar)),
+ ?line true = ets:info(Tab,fixed),
+ ?line true = ets:safe_fixtable(Tab, false),
+ ?line false = ets:info(Tab,fixed),
+ ?line {'EXIT', {badarg, _}} = (catch ets:safe_fixtable(Tab, foobar)),
+ ?line false = ets:info(Tab,fixed),
+ ?line ets:delete(Tab),
+ ?line case catch ets:safe_fixtable(Tab, true) of
+ {'EXIT', _Reason} ->
+ ?line verify_etsmem(EtsMem);
+ _ ->
+ ?t:fail("Fixtable on nonexisting table returned `true'")
+ end,
+ ok.
+
+info(doc) -> ["Tests ets:info result for required tuples."];
+info(suite) -> [];
+info(Config) when is_list(Config) ->
+ repeat_for_opts(info_do).
+
+info_do(Opts) ->
+ ?line EtsMem = etsmem(),
+ ?line MeMyselfI=self(),
+ ?line ThisNode=node(),
+ ?line Tab = ets:new(foobar, [{keypos, 2} | Opts]),
+
+ %% Note: ets:info/1 used to return a tuple, but from R11B onwards it
+ %% returns a list.
+ ?line Res = ets:info(Tab),
+ ?line {value, {memory, _Mem}} = lists:keysearch(memory, 1, Res),
+ ?line {value, {owner, MeMyselfI}} = lists:keysearch(owner, 1, Res),
+ ?line {value, {name, foobar}} = lists:keysearch(name, 1, Res),
+ ?line {value, {size, 0}} = lists:keysearch(size, 1, Res),
+ ?line {value, {node, ThisNode}} = lists:keysearch(node, 1, Res),
+ ?line {value, {named_table, false}} = lists:keysearch(named_table, 1, Res),
+ ?line {value, {type, set}} = lists:keysearch(type, 1, Res),
+ ?line {value, {keypos, 2}} = lists:keysearch(keypos, 1, Res),
+ ?line {value, {protection, protected}} =
+ lists:keysearch(protection, 1, Res),
+ ?line true = ets:delete(Tab),
+ ?line undefined = ets:info(non_existing_table_xxyy),
+ ?line undefined = ets:info(non_existing_table_xxyy,type),
+ ?line undefined = ets:info(non_existing_table_xxyy,node),
+ ?line undefined = ets:info(non_existing_table_xxyy,named_table),
+ ?line undefined = ets:info(non_existing_table_xxyy,safe_fixed),
+ ?line verify_etsmem(EtsMem).
+
+dups(doc) -> ["Test various duplicate_bags stuff"];
+dups(suite) -> [];
+dups(Config) when is_list(Config) ->
+ repeat_for_opts(dups_do).
+
+dups_do(Opts) ->
+ ?line EtsMem = etsmem(),
+ ?line T = make_table(funky,
+ [duplicate_bag | Opts],
+ [{1, 2}, {1, 2}]),
+ ?line 2 = length(ets:tab2list(T)),
+ ?line ets:delete(T, 1),
+ ?line [] = ets:lookup(T, 1),
+
+ ?line ets:insert(T, {1, 2, 2}),
+ ?line ets:insert(T, {1, 2, 4}),
+ ?line ets:insert(T, {1, 2, 2}),
+ ?line ets:insert(T, {1, 2, 2}),
+ ?line ets:insert(T, {1, 2, 4}),
+
+ ?line 5 = length(ets:tab2list(T)),
+
+ ?line 5 = length(ets:match(T, {'$1', 2, '$2'})),
+ ?line 3 = length(ets:match(T, {'_', '$1', '$1'})),
+ ?line ets:match_delete(T, {'_', '$1', '$1'}),
+ ?line 0 = length(ets:match(T, {'_', '$1', '$1'})),
+ ?line ets:delete(T),
+ ?line verify_etsmem(EtsMem).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+files(suite) -> [tab2file, tab2file2, tab2file3, tabfile_ext1, tabfile_ext2,
+ tabfile_ext3, tabfile_ext4].
+
+tab2file(doc) -> ["Check the ets:tab2file function on an empty "
+ "ets table."];
+tab2file(suite) -> [];
+tab2file(Config) when is_list(Config) ->
+ %% Write an empty ets table to a file, read back and check properties.
+ ?line Tab = ets:new(ets_SUITE_foo_tab, [named_table, set, private,
+ {keypos, 2}]),
+ ?line FName = filename:join([?config(priv_dir, Config),"tab2file_case"]),
+ ?line ok = ets:tab2file(Tab, FName),
+ ?line true = ets:delete(Tab),
+ %
+ ?line EtsMem = etsmem(),
+ ?line {ok, Tab2} = ets:file2tab(FName),
+ ?line private = ets:info(Tab2, protection),
+ ?line true = ets:info(Tab2, named_table),
+ ?line 2 = ets:info(Tab2, keypos),
+ ?line set = ets:info(Tab2, type),
+ ?line true = ets:delete(Tab2),
+ ?line verify_etsmem(EtsMem).
+
+tab2file2(doc) -> ["Check the ets:tab2file function on a ",
+ "filled set type ets table."];
+tab2file2(suite) -> [];
+tab2file2(Config) when is_list(Config) ->
+ %% Try the same on a filled set table.
+ ?line EtsMem = etsmem(),
+ ?line Tab = ets:new(ets_SUITE_foo_tab, [named_table, set, private,
+ {keypos, 2}]),
+ ?line FName = filename:join([?config(priv_dir, Config),"tab2file2_case"]),
+ ?line ok = fill_tab2(Tab, 0, 10000), % Fill up the table (grucho mucho!)
+ ?line Len = length(ets:tab2list(Tab)),
+ ?line ok = ets:tab2file(Tab, FName),
+ ?line true = ets:delete(Tab),
+ %
+ ?line {ok, Tab2} = ets:file2tab(FName),
+ ?line private = ets:info(Tab2, protection),
+ ?line true = ets:info(Tab2, named_table),
+ ?line 2 = ets:info(Tab2, keypos),
+ ?line set = ets:info(Tab2, type),
+ ?line Len = length(ets:tab2list(Tab2)),
+ ?line true = ets:delete(Tab2),
+ ?line verify_etsmem(EtsMem).
+
+tab2file3(doc) -> ["Check the ets:tab2file function on a ",
+ "filled bag type ets table."];
+tab2file3(suite) -> [];
+tab2file3(Config) when is_list(Config) ->
+ %% Try the same on a filled bag table.
+ ?line EtsMem = etsmem(),
+ ?line Tab = ets:new(ets_SUITE_foo_tab, [named_table, bag, private,
+ {keypos, 2}]),
+ ?line FName = filename:join([?config(priv_dir, Config),"tab2file3_case"]),
+ ?line ok = fill_tab2(Tab, 0, 10000), % Fill up the table (grucho mucho!)
+ ?line Len = length(ets:tab2list(Tab)),
+ ?line Mem = ets:info(Tab, memory),
+ ?line ok = ets:tab2file(Tab, FName),
+ ?line true = ets:delete(Tab),
+
+ ?line {ok, Tab2} = ets:file2tab(FName),
+ ?line private = ets:info(Tab2, protection),
+ ?line true = ets:info(Tab2, named_table),
+ ?line 2 = ets:info(Tab2, keypos),
+ ?line bag = ets:info(Tab2, type),
+ ?line Len = length(ets:tab2list(Tab2)),
+ ?line Mem = ets:info(Tab2, memory),
+ ?line true = ets:delete(Tab2),
+ ?line verify_etsmem(EtsMem).
+
+-define(test_list, [8,5,4,1,58,125,255, 250, 245, 240, 235,
+ 230, Num rem 255, 255, 125, 130, 135, 140, 145,
+ 150, 134, 12, 54, Val rem 255, 12, 3, 6, 9, 126]).
+-define(big_test_list, [Num rem 256|lists:seq(1, 66)]).
+-define(test_integer, 2846287468+Num).
+-define(test_float, 187263.18236-Val).
+-define(test_atom, some_crazy_atom).
+-define(test_tuple, {just, 'Some', 'Tuple', 1, [list, item], Val+Num}).
+
+%% Insert different datatypes into a ets table.
+fill_tab2(_Tab, _Val, 0) ->
+ ok;
+fill_tab2(Tab, Val, Num) ->
+ ?line Item =
+ case Num rem 10 of
+ 0 -> "String";
+ 1 -> ?line ?test_atom;
+ 2 -> ?line ?test_tuple;
+ 3 -> ?line ?test_integer;
+ 4 -> ?line ?test_float;
+ 5 -> ?line list_to_binary(?test_list); %Heap binary
+ 6 -> ?line list_to_binary(?big_test_list); %Refc binary
+ 7 -> ?line make_sub_binary(?test_list, Num); %Sub binary
+ 8 -> ?line ?test_list;
+ 9 -> ?line fun(X) -> {Tab,Val,X*Num} end
+ end,
+ ?line true=ets:insert(Tab, {Item, Val}),
+ ?line fill_tab2(Tab, Val+1, Num-1),
+ ok.
+
+tabfile_ext1(suite) ->
+ [];
+tabfile_ext1(doc) ->
+ ["Tests verification of tables with object count extended_info"];
+tabfile_ext1(Config) when is_list(Config) ->
+ repeat_for_opts(fun(Opts) -> tabfile_ext1_do(Opts, Config) end).
+
+tabfile_ext1_do(Opts,Config) ->
+ ?line FName = filename:join([?config(priv_dir, Config),"nisse.dat"]),
+ ?line FName2 = filename:join([?config(priv_dir, Config),"countflip.dat"]),
+ L = lists:seq(1,10),
+ T = ets:new(x,Opts),
+ Name = make_ref(),
+ [ets:insert(T,{X,integer_to_list(X)}) || X <- L],
+ ok = ets:tab2file(T,FName,[{extended_info,[object_count]}]),
+ true = lists:sort(ets:tab2list(T)) =:=
+ lists:sort(ets:tab2list(element(2,ets:file2tab(FName)))),
+ true = lists:sort(ets:tab2list(T)) =:=
+ lists:sort(ets:tab2list(
+ element(2,ets:file2tab(FName,[{verify,true}])))),
+ {ok,Name} = disk_log:open([{name,Name},{file,FName}]),
+ {_,[H0|T0]} = disk_log:chunk(Name,start),
+ disk_log:close(Name),
+ LH0=tuple_to_list(H0),
+ {value,{size,N}}=lists:keysearch(size,1,LH0),
+ NewLH0 = lists:keyreplace(size,1,LH0,{size,N-1}),
+ NewH0 = list_to_tuple(NewLH0),
+ NewT0=lists:keydelete(8,1,T0),
+ file:delete(FName2),
+ disk_log:open([{name,Name},{file,FName2},{mode,read_write}]),
+ disk_log:log_terms(Name,[NewH0|NewT0]),
+ disk_log:close(Name),
+ 9 = length(ets:tab2list(element(2,ets:file2tab(FName2)))),
+ {error,invalid_object_count} = ets:file2tab(FName2,[{verify,true}]),
+ {ok, _} = ets:tabfile_info(FName2),
+ {ok, _} = ets:tabfile_info(FName),
+ file:delete(FName),
+ file:delete(FName2),
+ ok.
+
+tabfile_ext2(suite) ->
+ [];
+tabfile_ext2(doc) ->
+ ["Tests verification of tables with md5sum extended_info"];
+tabfile_ext2(Config) when is_list(Config) ->
+ repeat_for_opts(fun(Opts) -> tabfile_ext2_do(Opts,Config) end).
+
+tabfile_ext2_do(Opts,Config) ->
+ ?line FName = filename:join([?config(priv_dir, Config),"olle.dat"]),
+ ?line FName2 = filename:join([?config(priv_dir, Config),"bitflip.dat"]),
+ L = lists:seq(1,10),
+ T = ets:new(x,Opts),
+ Name = make_ref(),
+ [ets:insert(T,{X,integer_to_list(X)}) || X <- L],
+ ok = ets:tab2file(T,FName,[{extended_info,[md5sum]}]),
+ true = lists:sort(ets:tab2list(T)) =:=
+ lists:sort(ets:tab2list(element(2,ets:file2tab(FName)))),
+ true = lists:sort(ets:tab2list(T)) =:=
+ lists:sort(ets:tab2list(
+ element(2,ets:file2tab(FName,[{verify,true}])))),
+ {ok, Name} = disk_log:open([{name,Name},{file,FName}]),
+ {_,[H1|T1]} = disk_log:chunk(Name,start),
+ disk_log:close(Name),
+ NewT1=lists:keyreplace(8,1,T1,{8,"9"}),
+ file:delete(FName2),
+ disk_log:open([{name,Name},{file,FName2},{mode,read_write}]),
+ disk_log:log_terms(Name,[H1|NewT1]),
+ disk_log:close(Name),
+ {value,{8,"9"}} = lists:keysearch(8,1,
+ ets:tab2list(
+ element(2,ets:file2tab(FName2)))),
+ {error,checksum_error} = ets:file2tab(FName2,[{verify,true}]),
+ {value,{extended_info,[md5sum]}} =
+ lists:keysearch(extended_info,1,element(2,ets:tabfile_info(FName2))),
+ {value,{extended_info,[md5sum]}} =
+ lists:keysearch(extended_info,1,element(2,ets:tabfile_info(FName))),
+ file:delete(FName),
+ file:delete(FName2),
+ ok.
+
+tabfile_ext3(suite) ->
+ [];
+tabfile_ext3(doc) ->
+ ["Tests verification of (named) tables without extended info"];
+tabfile_ext3(Config) when is_list(Config) ->
+ ?line FName = filename:join([?config(priv_dir, Config),"namn.dat"]),
+ ?line FName2 = filename:join([?config(priv_dir, Config),"ncountflip.dat"]),
+ L = lists:seq(1,10),
+ Name = make_ref(),
+ ?MODULE = ets:new(?MODULE,[named_table]),
+ [ets:insert(?MODULE,{X,integer_to_list(X)}) || X <- L],
+ ets:tab2file(?MODULE,FName),
+ {error,cannot_create_table} = ets:file2tab(FName),
+ true = ets:delete(?MODULE),
+ {ok,?MODULE} = ets:file2tab(FName),
+ true = ets:delete(?MODULE),
+ disk_log:open([{name,Name},{file,FName}]),
+ {_,[H2|T2]} = disk_log:chunk(Name,start),
+ disk_log:close(Name),
+ NewT2=lists:keydelete(8,1,T2),
+ file:delete(FName2),
+ disk_log:open([{name,Name},{file,FName2},{mode,read_write}]),
+ disk_log:log_terms(Name,[H2|NewT2]),
+ disk_log:close(Name),
+ 9 = length(ets:tab2list(element(2,ets:file2tab(FName2)))),
+ true = ets:delete(?MODULE),
+ {error,invalid_object_count} = ets:file2tab(FName2,[{verify,true}]),
+ {'EXIT',_} = (catch ets:delete(?MODULE)),
+ {ok,_} = ets:tabfile_info(FName2),
+ {ok,_} = ets:tabfile_info(FName),
+ file:delete(FName),
+ file:delete(FName2),
+ ok.
+
+tabfile_ext4(suite) ->
+ [];
+tabfile_ext4(doc) ->
+ ["Tests verification of large table with md5 sum"];
+tabfile_ext4(Config) when is_list(Config) ->
+ ?line FName = filename:join([?config(priv_dir, Config),"bauta.dat"]),
+ LL = lists:seq(1,10000),
+ TL = ets:new(x,[]),
+ Name2 = make_ref(),
+ [ets:insert(TL,{X,integer_to_list(X)}) || X <- LL],
+ ok = ets:tab2file(TL,FName,[{extended_info,[md5sum]}]),
+ {ok, Name2} = disk_log:open([{name, Name2}, {file, FName},
+ {mode, read_only}]),
+ {C,[_|_]} = disk_log:chunk(Name2,start),
+ {_,[_|_]} = disk_log:chunk(Name2,C),
+ disk_log:close(Name2),
+ true = lists:sort(ets:tab2list(TL)) =:=
+ lists:sort(ets:tab2list(element(2,ets:file2tab(FName)))),
+ Res = [
+ begin
+ {ok,FD} = file:open(FName,[binary,read,write]),
+ {ok, Bin} = file:pread(FD,0,1000),
+ <<B1:N/binary,Ch:8,B2/binary>> = Bin,
+ Ch2 = (Ch + 1) rem 255,
+ Bin2 = <<B1/binary,Ch2:8,B2/binary>>,
+ ok = file:pwrite(FD,0,Bin2),
+ ok = file:close(FD),
+ X = case ets:file2tab(FName) of
+ {ok,TL2} ->
+ true = lists:sort(ets:tab2list(TL)) =/=
+ lists:sort(ets:tab2list(TL2));
+ _ ->
+ totally_broken
+ end,
+ {error,Y} = ets:file2tab(FName,[{verify,true}]),
+ ets:tab2file(TL,FName,[{extended_info,[md5sum]}]),
+ {X,Y}
+ end || N <- lists:seq(400,500) ],
+ io:format("~p~n",[Res]),
+ file:delete(FName),
+ ok.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+make_sub_binary(List, Num) when is_list(List) ->
+ N = Num rem 23,
+ Bin = list_to_binary([lists:seq(0, N)|List]),
+ {_,B} = split_binary(Bin, N+1),
+ B.
+
+heavy(suite) -> [heavy_lookup, heavy_lookup_element].
+
+%% Lookup stuff like crazy...
+heavy_lookup(doc) -> ["Performs multiple lookups for every key ",
+ "in a large table."];
+heavy_lookup(suite) -> [];
+heavy_lookup(Config) when is_list(Config) ->
+ repeat_for_opts(heavy_lookup_do).
+
+heavy_lookup_do(Opts) ->
+ ?line EtsMem = etsmem(),
+ ?line Tab = ets:new(foobar_table, [set, protected, {keypos, 2} | Opts]),
+ ?line ok = fill_tab2(Tab, 0, 7000),
+ ?line ?t:do_times(50, ?MODULE, do_lookup, [Tab, 6999]),
+ ?line true = ets:delete(Tab),
+ ?line verify_etsmem(EtsMem).
+
+do_lookup(_Tab, 0) -> ok;
+do_lookup(Tab, N) ->
+ case ets:lookup(Tab, N) of
+ [] -> ?t:format("Set #~p was reported as empty. Not valid.",
+ [N]),
+ exit('Invalid lookup');
+ _ -> do_lookup(Tab, N-1)
+ end.
+
+heavy_lookup_element(doc) -> ["Performs multiple lookups for ",
+ "every element in a large table."];
+heavy_lookup_element(suite) -> [];
+heavy_lookup_element(Config) when is_list(Config) ->
+ repeat_for_opts(heavy_lookup_element_do).
+
+heavy_lookup_element_do(Opts) ->
+ ?line EtsMem = etsmem(),
+ ?line Tab = ets:new(foobar_table, [set, protected, {keypos, 2} | Opts]),
+ ?line ok = fill_tab2(Tab, 0, 7000),
+ case os:type() of
+ vxworks ->
+ ?line ?t:do_times(5, ?MODULE, do_lookup_element,
+ [Tab, 6999, 1]);
+ % lookup ALL elements 5 times.
+ _ ->
+ ?line ?t:do_times(50, ?MODULE, do_lookup_element,
+ [Tab, 6999, 1])
+ % lookup ALL elements 50 times.
+ end,
+ ?line true = ets:delete(Tab),
+ ?line verify_etsmem(EtsMem).
+
+do_lookup_element(_Tab, 0, _) -> ok;
+do_lookup_element(Tab, N, M) ->
+ ?line case catch ets:lookup_element(Tab, N, M) of
+ {'EXIT', {badarg, _}} ->
+ case M of
+ 1 -> ?t:fail("Set #~p reported as empty. Not valid.",
+ [N]),
+ exit('Invalid lookup_element');
+ _ -> ?line do_lookup_element(Tab, N-1, 1)
+ end;
+ _ -> ?line do_lookup_element(Tab, N, M+1)
+ end.
+
+
+fold(suite) -> [foldl_ordered, foldr_ordered,
+ foldl, foldr,
+ fold_empty].
+
+fold_empty(doc) ->
+ [];
+fold_empty(suite) -> [];
+fold_empty(Config) when is_list(Config) ->
+ ?line EtsMem = etsmem(),
+ ?line Tab = make_table(a, [], []),
+ ?line [] = ets:foldl(fun(_X) -> exit(hej) end, [], Tab),
+ ?line [] = ets:foldr(fun(_X) -> exit(hej) end, [], Tab),
+ ?line true = ets:delete(Tab),
+ ?line verify_etsmem(EtsMem).
+
+foldl(doc) ->
+ [];
+foldl(suite) -> [];
+foldl(Config) when is_list(Config) ->
+ ?line EtsMem = etsmem(),
+ ?line L = [{a,1}, {c,3}, {b,2}],
+ ?line LS = lists:sort(L),
+ ?line Tab = make_table(a, [bag], L),
+ ?line LS = lists:sort(ets:foldl(fun(E,A) -> [E|A] end, [], Tab)),
+ ?line true = ets:delete(Tab),
+ ?line verify_etsmem(EtsMem).
+
+foldr(doc) ->
+ [];
+foldr(suite) -> [];
+foldr(Config) when is_list(Config) ->
+ ?line EtsMem = etsmem(),
+ ?line L = [{a,1}, {c,3}, {b,2}],
+ ?line LS = lists:sort(L),
+ ?line Tab = make_table(a, [bag], L),
+ ?line LS = lists:sort(ets:foldr(fun(E,A) -> [E|A] end, [], Tab)),
+ ?line true = ets:delete(Tab),
+ ?line verify_etsmem(EtsMem).
+
+foldl_ordered(doc) ->
+ [];
+foldl_ordered(suite) -> [];
+foldl_ordered(Config) when is_list(Config) ->
+ ?line EtsMem = etsmem(),
+ ?line L = [{a,1}, {c,3}, {b,2}],
+ ?line LS = lists:sort(L),
+ ?line Tab = make_table(a, [ordered_set], L),
+ ?line LS = lists:reverse(ets:foldl(fun(E,A) -> [E|A] end, [], Tab)),
+ ?line true = ets:delete(Tab),
+ ?line verify_etsmem(EtsMem).
+
+foldr_ordered(doc) ->
+ [];
+foldr_ordered(suite) -> [];
+foldr_ordered(Config) when is_list(Config) ->
+ ?line EtsMem = etsmem(),
+ ?line L = [{a,1}, {c,3}, {b,2}],
+ ?line LS = lists:sort(L),
+ ?line Tab = make_table(a, [ordered_set], L),
+ ?line LS = ets:foldr(fun(E,A) -> [E|A] end, [], Tab),
+ ?line true = ets:delete(Tab),
+ ?line verify_etsmem(EtsMem).
+
+member(suite) ->
+ [];
+member(doc) ->
+ ["Tests ets:member BIF"];
+member(Config) when is_list(Config) ->
+ repeat_for_opts(member_do, [write_concurrency, all_types]).
+
+member_do(Opts) ->
+ ?line EtsMem = etsmem(),
+ ?line T = ets:new(xxx, Opts),
+ ?line false = ets:member(T,hej),
+ ?line E = fun(0,_F)->ok;
+ (N,F) ->
+ ?line ets:insert(T,{N,N rem 10}),
+ F(N-1,F)
+ end,
+ ?line E(10000,E),
+ ?line false = ets:member(T,hej),
+ ?line true = ets:member(T,1),
+ ?line false = ets:member(T,20000),
+ ?line ets:delete(T,5),
+ ?line false = ets:member(T,5),
+ ?line ets:safe_fixtable(T,true),
+ ?line ets:delete(T,6),
+ ?line false = ets:member(T,6),
+ ?line ets:safe_fixtable(T,false),
+ ?line false = ets:member(T,6),
+ ?line ets:delete(T),
+ ?line {'EXIT',{badarg,_}} = (catch ets:member(finnsinte, 23)),
+ ?line {'EXIT',{badarg,_}} = (catch ets:member(T, 23)),
+ ?line verify_etsmem(EtsMem).
+
+
+build_table(L1,L2,Num) ->
+ T = ets:new(xxx, [ordered_set]
+ ),
+ lists:foreach(
+ fun(X1) ->
+ lists:foreach(
+ fun(X2) ->
+ F = fun(FF,N) ->
+ ets:insert(T,{{X1,X2,N},
+ X1, X2, N}),
+ case N of
+ 0 ->
+ ok;
+ _ ->
+ FF(FF,N-1)
+ end
+ end,
+ F(F,Num)
+ end, L2)
+ end, L1),
+ T.
+
+build_table2(L1,L2,Num) ->
+ T = ets:new(xxx, [ordered_set]
+ ),
+ lists:foreach(
+ fun(X1) ->
+ lists:foreach(
+ fun(X2) ->
+ F = fun(FF,N) ->
+ ets:insert(T,{{N,X1,X2},
+ N, X1, X2}),
+ case N of
+ 0 ->
+ ok;
+ _ ->
+ FF(FF,N-1)
+ end
+ end,
+ F(F,Num)
+ end, L2)
+ end, L1),
+ T.
+
+time_match_object(Tab,Match, Res) ->
+ T1 = erlang:now(),
+ Res = ets:match_object(Tab,Match),
+ T2 = erlang:now(),
+ nowdiff(T1,T2).
+
+time_match(Tab,Match) ->
+ T1 = erlang:now(),
+ ets:match(Tab,Match),
+ T2 = erlang:now(),
+ nowdiff(T1,T2).
+
+seventyfive_percent_success(_,S,Fa,0) ->
+ true = (S > ((S + Fa) * 0.75));
+
+seventyfive_percent_success({M,F,A},S,Fa,N) ->
+ case (catch apply(M,F,A)) of
+ {'EXIT', _} ->
+ seventyfive_percent_success({M,F,A},S,Fa+1,N-1);
+ _ ->
+ seventyfive_percent_success({M,F,A},S+1,Fa,N-1)
+ end.
+
+fifty_percent_success(_,S,Fa,0) ->
+ true = (S > ((S + Fa) * 0.5));
+
+fifty_percent_success({M,F,A},S,Fa,N) ->
+ case (catch apply(M,F,A)) of
+ {'EXIT', _} ->
+ fifty_percent_success({M,F,A},S,Fa+1,N-1);
+ _ ->
+ fifty_percent_success({M,F,A},S+1,Fa,N-1)
+ end.
+
+
+nowtonumber({Mega, Secs, Milli}) ->
+ Milli + Secs * 1000000 + Mega * 1000000000000.
+nowdiff(T1,T2) ->
+ nowtonumber(T2) - nowtonumber(T1).
+
+create_random_string(0) ->
+ [];
+
+create_random_string(OfLength) ->
+ C = case random:uniform(2) of
+ 1 ->
+ (random:uniform($Z - $A + 1) - 1) + $A;
+ _ ->
+ (random:uniform($z - $a + 1) - 1) + $a
+ end,
+ [C | create_random_string(OfLength - 1)].
+
+
+create_random_tuple(OfLength) ->
+ list_to_tuple(lists:map(fun(X) ->
+ list_to_atom([X])
+ end,create_random_string(OfLength))).
+
+create_partly_bound_tuple(OfLength) ->
+ case random:uniform(2) of
+ 1 ->
+ create_partly_bound_tuple1(OfLength);
+ _ ->
+ create_partly_bound_tuple3(OfLength)
+ end.
+
+create_partly_bound_tuple1(OfLength) ->
+ T0 = create_random_tuple(OfLength),
+ I = random:uniform(OfLength),
+ setelement(I,T0,'$1').
+
+
+set_n_random_elements(T0,0,_,_) ->
+ T0;
+set_n_random_elements(T0,N,OfLength,GenFun) ->
+ I = random:uniform(OfLength),
+ What = GenFun(I),
+ case element(I,T0) of
+ What ->
+ set_n_random_elements(T0,N,OfLength,GenFun);
+ _Else ->
+ set_n_random_elements(setelement(I,T0,What),
+ N-1,OfLength,GenFun)
+ end.
+
+make_dollar_atom(I) ->
+ list_to_atom([$$] ++ integer_to_list(I)).
+create_partly_bound_tuple2(OfLength) ->
+ T0 = create_random_tuple(OfLength),
+ I = random:uniform(OfLength - 1),
+ set_n_random_elements(T0,I,OfLength,fun make_dollar_atom/1).
+
+create_partly_bound_tuple3(OfLength) ->
+ T0 = create_random_tuple(OfLength),
+ I = random:uniform(OfLength - 1),
+ set_n_random_elements(T0,I,OfLength,fun(_) -> '_' end).
+
+do_n_times(_,0) ->
+ ok;
+do_n_times(Fun,N) ->
+ Fun(),
+ case N rem 1000 of
+ 0 ->
+ io:format(".");
+ _ ->
+ ok
+ end,
+ do_n_times(Fun,N-1).
+
+make_table(Name, Options, Elements) ->
+ T = ets:new(Name, Options),
+ lists:foreach(fun(E) -> ets:insert(T, E) end, Elements),
+ T.
+filltabint(Tab,0) ->
+ Tab;
+filltabint(Tab,N) ->
+ ets:insert(Tab,{N,integer_to_list(N)}),
+ filltabint(Tab,N-1).
+filltabint2(Tab,0) ->
+ Tab;
+filltabint2(Tab,N) ->
+ ets:insert(Tab,{N + N rem 2,integer_to_list(N)}),
+ filltabint2(Tab,N-1).
+filltabint3(Tab,0) ->
+ Tab;
+filltabint3(Tab,N) ->
+ ets:insert(Tab,{N + N rem 2,integer_to_list(N + N rem 2)}),
+ filltabint3(Tab,N-1).
+xfilltabint(Tab,N) ->
+ case ets:info(Tab,type) of
+ bag ->
+ filltabint2(Tab,N);
+ duplicate_bag ->
+ ets:select_delete(Tab,[{'_',[],[true]}]),
+ filltabint3(Tab,N);
+ _ ->
+ filltabint(Tab,N)
+ end.
+
+
+filltabstr(Tab,N) ->
+ filltabstr(Tab,0,N).
+filltabstr(Tab,N,N) ->
+ Tab;
+filltabstr(Tab,Floor,N) when N > Floor ->
+ ets:insert(Tab,{integer_to_list(N),N}),
+ filltabstr(Tab,Floor,N-1).
+
+filltabstr2(Tab,0) ->
+ Tab;
+filltabstr2(Tab,N) ->
+ ets:insert(Tab,{integer_to_list(N),N}),
+ ets:insert(Tab,{integer_to_list(N),N+1}),
+ filltabstr2(Tab,N-1).
+filltabstr3(Tab,0) ->
+ Tab;
+filltabstr3(Tab,N) ->
+ ets:insert(Tab,{integer_to_list(N),N}),
+ ets:insert(Tab,{integer_to_list(N),N}),
+ filltabstr3(Tab,N-1).
+xfilltabstr(Tab,N) ->
+ case ets:info(Tab,type) of
+ bag ->
+ filltabstr2(Tab,N);
+ duplicate_bag ->
+ ets:select_delete(Tab,[{'_',[],[true]}]),
+ filltabstr3(Tab,N);
+ _ ->
+ filltabstr(Tab,N)
+ end.
+
+fill_sets_int(N) ->
+ fill_sets_int(N,[]).
+fill_sets_int(N,Opts) ->
+ Tab1 = ets:new(xxx, [ordered_set|Opts]),
+ filltabint(Tab1,N),
+ Tab2 = ets:new(xxx, [set|Opts]),
+ filltabint(Tab2,N),
+ Tab3 = ets:new(xxx, [bag|Opts]),
+ filltabint2(Tab3,N),
+ Tab4 = ets:new(xxx, [duplicate_bag|Opts]),
+ filltabint3(Tab4,N),
+ [Tab1,Tab2,Tab3,Tab4].
+
+check_fun(_Tab,_Fun,'$end_of_table') ->
+ ok;
+check_fun(Tab,Fun,Item) ->
+ lists:foreach(fun(Obj) ->
+ true = Fun(Obj)
+ end,
+ ets:lookup(Tab,Item)),
+ check_fun(Tab,Fun,ets:next(Tab,Item)).
+
+check(Tab,Fun,N) ->
+ N = ets:info(Tab, size),
+ check_fun(Tab,Fun,ets:first(Tab)).
+
+
+
+del_one_by_one_set(T,N,N) ->
+ 0 = ets:info(T,size),
+ ok;
+del_one_by_one_set(T,From,To) ->
+ N = ets:info(T,size),
+ ets:delete_object(T,{From, integer_to_list(From)}),
+ N = (ets:info(T,size) + 1),
+ Next = if
+ From < To ->
+ From + 1;
+ true ->
+ From - 1
+ end,
+ del_one_by_one_set(T,Next,To).
+
+del_one_by_one_bag(T,N,N) ->
+ 0 = ets:info(T,size),
+ ok;
+del_one_by_one_bag(T,From,To) ->
+ N = ets:info(T,size),
+ ets:delete_object(T,{From + From rem 2, integer_to_list(From)}),
+ N = (ets:info(T,size) + 1),
+ Next = if
+ From < To ->
+ From + 1;
+ true ->
+ From - 1
+ end,
+ del_one_by_one_bag(T,Next,To).
+
+
+del_one_by_one_dbag_1(T,N,N) ->
+ 0 = ets:info(T,size),
+ ok;
+del_one_by_one_dbag_1(T,From,To) ->
+ N = ets:info(T,size),
+ ets:delete_object(T,{From, integer_to_list(From)}),
+ case From rem 2 of
+ 0 ->
+ N = (ets:info(T,size) + 2);
+ 1 ->
+ N = ets:info(T,size)
+ end,
+ Next = if
+ From < To ->
+ From + 1;
+ true ->
+ From - 1
+ end,
+ del_one_by_one_dbag_1(T,Next,To).
+
+del_one_by_one_dbag_2(T,N,N) ->
+ 0 = ets:info(T,size),
+ ok;
+del_one_by_one_dbag_2(T,From,To) ->
+ N = ets:info(T,size),
+ ets:delete_object(T,{From, integer_to_list(From)}),
+ case From rem 2 of
+ 0 ->
+ N = (ets:info(T,size) + 3);
+ 1 ->
+ N = (ets:info(T,size) + 1)
+ end,
+ Next = if
+ From < To ->
+ From + 1;
+ true ->
+ From - 1
+ end,
+ del_one_by_one_dbag_2(T,Next,To).
+
+del_one_by_one_dbag_3(T,N,N) ->
+ 0 = ets:info(T,size),
+ ok;
+del_one_by_one_dbag_3(T,From,To) ->
+ N = ets:info(T,size),
+ Obj = {From + From rem 2, integer_to_list(From)},
+ ets:delete_object(T,Obj),
+ case From rem 2 of
+ 0 ->
+ N = (ets:info(T,size) + 2);
+ 1 ->
+ N = (ets:info(T,size) + 1),
+ Obj2 = {From, integer_to_list(From)},
+ ets:delete_object(T,Obj2),
+ N = (ets:info(T,size) + 2)
+ end,
+ Next = if
+ From < To ->
+ From + 1;
+ true ->
+ From - 1
+ end,
+ del_one_by_one_dbag_3(T,Next,To).
+
+
+successive_delete(Table,From,To,Type) ->
+ successive_delete(Table,From,To,Type,ets:info(Table,type)).
+
+successive_delete(_Table,N,N,_,_) ->
+ ok;
+successive_delete(Table,From,To,Type,TType) ->
+ MS = case Type of
+ bound ->
+ [{{From,'_'},[],[true]}];
+ unbound ->
+ [{{'$1','_'},[],[{'==', '$1', From}]}]
+ end,
+ case TType of
+ X when X == bag; X == duplicate_bag ->
+ %erlang:display(From),
+ case From rem 2 of
+ 0 ->
+ 2 = ets:select_delete(Table,MS);
+ _ ->
+ 0 = ets:select_delete(Table,MS)
+ end;
+ _ ->
+ 1 = ets:select_delete(Table,MS)
+ end,
+ Next = if
+ From < To ->
+ From + 1;
+ true ->
+ From - 1
+ end,
+ successive_delete(Table, Next, To, Type,TType).
+
+gen_dets_filename(Config,N) ->
+ filename:join(?config(priv_dir,Config),
+ "testdets_" ++ integer_to_list(N) ++ ".dets").
+
+otp_6842_select_1000(Config) when is_list(Config) ->
+ ?line Tab = ets:new(xxx,[ordered_set]),
+ ?line [ets:insert(Tab,{X,X}) || X <- lists:seq(1,10000)],
+ ?line AllTrue = lists:duplicate(10,true),
+ ?line AllTrue =
+ [ length(
+ element(1,
+ ets:select(Tab,[{'_',[],['$_']}],X*1000))) =:=
+ X*1000 || X <- lists:seq(1,10) ],
+ ?line Sequences = [[1000,1000,1000,1000,1000,1000,1000,1000,1000,1000],
+ [2000,2000,2000,2000,2000],
+ [3000,3000,3000,1000],
+ [4000,4000,2000],
+ [5000,5000],
+ [6000,4000],
+ [7000,3000],
+ [8000,2000],
+ [9000,1000],
+ [10000]],
+ ?line AllTrue = [ check_seq(Tab, ets:select(Tab,[{'_',[],['$_']}],hd(L)),L) ||
+ L <- Sequences ],
+ ?line ets:delete(Tab),
+ ok.
+
+check_seq(_,'$end_of_table',[]) ->
+ true;
+check_seq(Tab,{L,C},[H|T]) when length(L) =:= H ->
+ check_seq(Tab, ets:select(C),T);
+check_seq(A,B,C) ->
+ erlang:display({A,B,C}),
+ false.
+
+otp_6338(Config) when is_list(Config) ->
+ L = binary_to_term(<<131,108,0,0,0,2,104,2,108,0,0,0,2,103,100,0,19,112,112,98,49,95,98,115,49,50,64,98,108,97,100,101,95,48,95,53,0,0,33,50,0,0,0,4,1,98,0,0,23,226,106,100,0,4,101,120,105,116,104,2,108,0,0,0,2,104,2,100,0,3,115,98,109,100,0,19,112,112,98,50,95,98,115,49,50,64,98,108,97,100,101,95,48,95,56,98,0,0,18,231,106,100,0,4,114,101,99,118,106>>),
+ T = ets:new(xxx,[ordered_set]),
+ lists:foreach(fun(X) -> ets:insert(T,X) end,L),
+ [[4839,recv]] = ets:match(T,{[{sbm,ppb2_bs12@blade_0_8},'$1'],'$2'}),
+ ets:delete(T).
+
+%% Elements could come in the wrong order in a bag if a rehash occurred.
+otp_5340(Config) when is_list(Config) ->
+ repeat_for_opts(otp_5340_do).
+
+otp_5340_do(Opts) ->
+ N = 3000,
+ T = ets:new(otp_5340, [bag,public | Opts]),
+ Ids = [1,2,3,4,5],
+ [w(T, N, Id) || Id <- Ids],
+ verify(T, Ids),
+ ets:delete(T).
+
+w(_,0, _) -> ok;
+w(T,N, Id) ->
+ ets:insert(T, {N, Id}),
+ w(T,N-1,Id).
+
+verify(T, Ids) ->
+ List = my_tab_to_list(T),
+ Errors = lists:filter(fun(Bucket) ->
+ verify2(Bucket, Ids)
+ end, List),
+ case Errors of
+ [] ->
+ ok;
+ _ ->
+ io:format("Failed:\n~p\n", [Errors]),
+ ?t:fail()
+ end.
+
+verify2([{_N,Id}|RL], [Id|R]) ->
+ verify2(RL,R);
+verify2([],[]) -> false;
+verify2(_Err, _) ->
+ true.
+
+otp_7665(doc) -> ["delete_object followed by delete on fixed bag failed to delete objects."];
+otp_7665(suite) -> [];
+otp_7665(Config) when is_list(Config) ->
+ repeat_for_opts(otp_7665_do).
+
+otp_7665_do(Opts) ->
+ Tab = ets:new(otp_7665,[bag | Opts]),
+ Min = 0,
+ Max = 10,
+ lists:foreach(fun(N)-> otp_7665_act(Tab,Min,Max,N) end,
+ lists:seq(Min,Max)),
+ ?line true = ets:delete(Tab).
+
+otp_7665_act(Tab,Min,Max,DelNr) ->
+ List1 = [{key,N} || N <- lists:seq(Min,Max)],
+ ?line true = ets:insert(Tab, List1),
+ ?line true = ets:safe_fixtable(Tab, true),
+ ?line true = ets:delete_object(Tab, {key,DelNr}),
+ List2 = lists:delete({key,DelNr}, List1),
+
+ %% Now verify that we find all remaining objects
+ ?line List2 = ets:lookup(Tab,key),
+ ?line EList2 = lists:map(fun({key,N})-> N end,
+ List2),
+ ?line EList2 = ets:lookup_element(Tab,key,2),
+ ?line true = ets:delete(Tab, key),
+ ?line [] = ets:lookup(Tab, key),
+ ?line true = ets:safe_fixtable(Tab, false),
+ ok.
+
+%% Whitebox testing of meta name table hashing.
+meta_wb(Config) when is_list(Config) ->
+ ?line EtsMem = etsmem(),
+ ?line erts_debug:set_internal_state(available_internal_state, true),
+ try
+ repeat_for_opts(meta_wb_do)
+ after
+ erts_debug:set_internal_state(available_internal_state, false)
+ end,
+ ?line verify_etsmem(EtsMem).
+
+
+meta_wb_do(Opts) ->
+ %% Do random new/delete/rename of colliding named tables
+ Names = [pioneer | colliding_names(pioneer)],
+ Len = length(Names),
+ OpFuns = {fun meta_wb_new/4, fun meta_wb_delete/4, fun meta_wb_rename/4},
+
+ io:format("Colliding names = ~p\n",[Names]),
+ F = fun(0,_,_) -> ok;
+ (N,Tabs,Me) -> Name1 = lists:nth(random:uniform(Len),Names),
+ Name2 = lists:nth(random:uniform(Len),Names),
+ Op = element(random:uniform(3),OpFuns),
+ NTabs = Op(Name1, Name2, Tabs, Opts),
+ Me(N-1,NTabs,Me)
+ end,
+ F(Len*100, [], F),
+
+ % cleanup
+ lists:foreach(fun(Name)->catch ets:delete(Name) end,
+ Names).
+
+meta_wb_new(Name, _, Tabs, Opts) ->
+ case (catch ets:new(Name,[named_table|Opts])) of
+ Name ->
+ ?line false = lists:member(Name, Tabs),
+ [Name | Tabs];
+ {'EXIT',{badarg,_}} ->
+ ?line true = lists:member(Name, Tabs),
+ Tabs
+ end.
+meta_wb_delete(Name, _, Tabs, _) ->
+ case (catch ets:delete(Name)) of
+ true ->
+ ?line true = lists:member(Name, Tabs),
+ lists:delete(Name, Tabs);
+ {'EXIT',{badarg,_}} ->
+ ?line false = lists:member(Name, Tabs),
+ Tabs
+ end.
+meta_wb_rename(Old, New, Tabs, _) ->
+ case (catch ets:rename(Old,New)) of
+ New ->
+ ?line true = lists:member(Old, Tabs)
+ andalso not lists:member(New, Tabs),
+ [New | lists:delete(Old, Tabs)];
+ {'EXIT',{badarg,_}} ->
+ ?line true = not lists:member(Old, Tabs)
+ orelse lists:member(New,Tabs),
+ Tabs
+ end.
+
+
+colliding_names(Name) ->
+ erts_debug:set_internal_state(colliding_names, {Name,5}).
+
+
+%% OTP_6913: Grow and shrink.
+
+grow_shrink(Config) when is_list(Config) ->
+ ?line EtsMem = etsmem(),
+ grow_shrink_0(lists:seq(3071, 5000), EtsMem).
+
+grow_shrink_0([N|Ns], EtsMem) ->
+ ?line grow_shrink_1(N, [set]),
+ ?line grow_shrink_1(N, [ordered_set]),
+ ?line verify_etsmem(EtsMem),
+ grow_shrink_0(Ns, EtsMem);
+grow_shrink_0([], _) -> ok.
+
+grow_shrink_1(N, Flags) ->
+ ?line T = ets:new(a, Flags),
+ ?line grow_shrink_2(N, N, T),
+ ?line ets:delete(T).
+
+grow_shrink_2(0, Orig, T) ->
+ List = [{I,a} || I <- lists:seq(1, Orig)],
+ List = lists:sort(ets:tab2list(T)),
+ grow_shrink_3(Orig, T);
+grow_shrink_2(N, Orig, T) ->
+ true = ets:insert(T, {N,a}),
+ grow_shrink_2(N-1, Orig, T).
+
+grow_shrink_3(0, T) ->
+ [] = ets:tab2list(T);
+grow_shrink_3(N, T) ->
+ true = ets:delete(T, N),
+ grow_shrink_3(N-1, T).
+
+grow_pseudo_deleted(doc) -> ["Grow a table that still contains pseudo-deleted objects"];
+grow_pseudo_deleted(suite) -> [];
+grow_pseudo_deleted(Config) when is_list(Config) ->
+ only_if_smp(fun() -> grow_pseudo_deleted_do() end).
+
+grow_pseudo_deleted_do() ->
+ lists:foreach(fun(Type) -> grow_pseudo_deleted_do(Type) end,
+ [set,bag,duplicate_bag]).
+
+grow_pseudo_deleted_do(Type) ->
+ process_flag(scheduler,1),
+ Self = self(),
+ ?line T = ets:new(kalle,[Type,public,{write_concurrency,true}]),
+ Mod = 7, Mult = 10000,
+ filltabint(T,Mod*Mult),
+ ?line true = ets:safe_fixtable(T,true),
+ ?line Mult = ets:select_delete(T,
+ [{{'$1', '_'},
+ [{'=:=', {'rem', '$1', Mod}, 0}],
+ [true]}]),
+ Left = Mult*(Mod-1),
+ ?line Left = ets:info(T,size),
+ ?line Mult = ets:info(T,kept_objects),
+ filltabstr(T,Mult),
+ spawn_opt(fun()-> ?line true = ets:info(T,fixed),
+ Self ! start,
+ io:format("Starting to filltabstr... ~p\n",[now()]),
+ filltabstr(T,Mult,Mult+10000),
+ io:format("Done with filltabstr. ~p\n",[now()]),
+ Self ! done
+ end, [link, {scheduler,2}]),
+ ?line start = receive_any(),
+ io:format("Unfixing table...~p nitems=~p\n",[now(),ets:info(T,size)]),
+ ?line true = ets:safe_fixtable(T,false),
+ io:format("Unfix table done. ~p nitems=~p\n",[now(),ets:info(T,size)]),
+ ?line false = ets:info(T,fixed),
+ ?line 0 = ets:info(T,kept_objects),
+ ?line done = receive_any(),
+ %%verify_table_load(T), % may fail if concurrency is poor (genny)
+ ets:delete(T),
+ process_flag(scheduler,0).
+
+shrink_pseudo_deleted(doc) -> ["Shrink a table that still contains pseudo-deleted objects"];
+shrink_pseudo_deleted(suite) -> [];
+shrink_pseudo_deleted(Config) when is_list(Config) ->
+ only_if_smp(fun()->shrink_pseudo_deleted_do() end).
+
+shrink_pseudo_deleted_do() ->
+ lists:foreach(fun(Type) -> shrink_pseudo_deleted_do(Type) end,
+ [set,bag,duplicate_bag]).
+
+shrink_pseudo_deleted_do(Type) ->
+ process_flag(scheduler,1),
+ Self = self(),
+ ?line T = ets:new(kalle,[Type,public,{write_concurrency,true}]),
+ Half = 10000,
+ filltabint(T,Half*2),
+ ?line true = ets:safe_fixtable(T,true),
+ ?line Half = ets:select_delete(T,
+ [{{'$1', '_'},
+ [{'>', '$1', Half}],
+ [true]}]),
+ ?line Half = ets:info(T,size),
+ ?line Half = ets:info(T,kept_objects),
+ spawn_opt(fun()-> ?line true = ets:info(T,fixed),
+ Self ! start,
+ io:format("Starting to delete... ~p\n",[now()]),
+ del_one_by_one_set(T,1,Half+1),
+ io:format("Done with delete. ~p\n",[now()]),
+ Self ! done
+ end, [link, {scheduler,2}]),
+ ?line start = receive_any(),
+ io:format("Unfixing table...~p nitems=~p\n",[now(),ets:info(T,size)]),
+ ?line true = ets:safe_fixtable(T,false),
+ io:format("Unfix table done. ~p nitems=~p\n",[now(),ets:info(T,size)]),
+ ?line false = ets:info(T,fixed),
+ ?line 0 = ets:info(T,kept_objects),
+ ?line done = receive_any(),
+ %%verify_table_load(T), % may fail if concurrency is poor (genny)
+ ets:delete(T),
+ process_flag(scheduler,0).
+
+
+meta_smp(suite) ->
+ [meta_lookup_unnamed_read,
+ meta_lookup_unnamed_write,
+ meta_lookup_named_read,
+ meta_lookup_named_write,
+ meta_newdel_unnamed,
+ meta_newdel_named].
+
+meta_lookup_unnamed_read(suite) -> [];
+meta_lookup_unnamed_read(Config) when is_list(Config) ->
+ InitF = fun(_) -> Tab = ets:new(unnamed,[]),
+ true = ets:insert(Tab,{key,data}),
+ Tab
+ end,
+ ExecF = fun(Tab) -> [{key,data}] = ets:lookup(Tab,key),
+ Tab
+ end,
+ FiniF = fun(Tab) -> true = ets:delete(Tab)
+ end,
+ run_workers(InitF,ExecF,FiniF,10000).
+
+meta_lookup_unnamed_write(suite) -> [];
+meta_lookup_unnamed_write(Config) when is_list(Config) ->
+ InitF = fun(_) -> Tab = ets:new(unnamed,[]),
+ {Tab,0}
+ end,
+ ExecF = fun({Tab,N}) -> true = ets:insert(Tab,{key,N}),
+ {Tab,N+1}
+ end,
+ FiniF = fun({Tab,_}) -> true = ets:delete(Tab)
+ end,
+ run_workers(InitF,ExecF,FiniF,10000).
+
+meta_lookup_named_read(suite) -> [];
+meta_lookup_named_read(Config) when is_list(Config) ->
+ InitF = fun([ProcN|_]) -> Name = list_to_atom(integer_to_list(ProcN)),
+ Tab = ets:new(Name,[named_table]),
+ true = ets:insert(Tab,{key,data}),
+ Tab
+ end,
+ ExecF = fun(Tab) -> [{key,data}] = ets:lookup(Tab,key),
+ Tab
+ end,
+ FiniF = fun(Tab) -> true = ets:delete(Tab)
+ end,
+ run_workers(InitF,ExecF,FiniF,10000).
+
+meta_lookup_named_write(suite) -> [];
+meta_lookup_named_write(Config) when is_list(Config) ->
+ InitF = fun([ProcN|_]) -> Name = list_to_atom(integer_to_list(ProcN)),
+ Tab = ets:new(Name,[named_table]),
+ {Tab,0}
+ end,
+ ExecF = fun({Tab,N}) -> true = ets:insert(Tab,{key,N}),
+ {Tab,N+1}
+ end,
+ FiniF = fun({Tab,_}) -> true = ets:delete(Tab)
+ end,
+ run_workers(InitF,ExecF,FiniF,10000).
+
+meta_newdel_unnamed(suite) -> [];
+meta_newdel_unnamed(Config) when is_list(Config) ->
+ InitF = fun(_) -> ok end,
+ ExecF = fun(_) -> Tab = ets:new(unnamed,[]),
+ true = ets:delete(Tab)
+ end,
+ FiniF = fun(_) -> ok end,
+ run_workers(InitF,ExecF,FiniF,10000).
+
+meta_newdel_named(suite) -> [];
+meta_newdel_named(Config) when is_list(Config) ->
+ InitF = fun([ProcN|_]) -> list_to_atom(integer_to_list(ProcN))
+ end,
+ ExecF = fun(Name) -> Name = ets:new(Name,[named_table]),
+ true = ets:delete(Name),
+ Name
+ end,
+ FiniF = fun(_) -> ok end,
+ run_workers(InitF,ExecF,FiniF,10000).
+
+smp_insert(doc) -> ["Concurrent insert's on same table"];
+smp_insert(suite) -> [];
+smp_insert(Config) when is_list(Config) ->
+ ets:new(smp_insert,[named_table,public,{write_concurrency,true}]),
+ InitF = fun(_) -> ok end,
+ ExecF = fun(_) -> true = ets:insert(smp_insert,{random:uniform(10000)})
+ end,
+ FiniF = fun(_) -> ok end,
+ run_workers(InitF,ExecF,FiniF,100000),
+ verify_table_load(smp_insert),
+ ets:delete(smp_insert).
+
+smp_fixed_delete(doc) -> ["Concurrent delete's on same fixated table"];
+smp_fixed_delete(suite) -> [];
+smp_fixed_delete(Config) when is_list(Config) ->
+ only_if_smp(fun()->smp_fixed_delete_do() end).
+
+smp_fixed_delete_do() ->
+ T = ets:new(foo,[public,{write_concurrency,true}]),
+ %%Mem = ets:info(T,memory),
+ NumOfObjs = 100000,
+ filltabint(T,NumOfObjs),
+ ets:safe_fixtable(T,true),
+ Buckets = num_of_buckets(T),
+ InitF = fun([ProcN,NumOfProcs|_]) -> {ProcN,NumOfProcs} end,
+ ExecF = fun({Key,_}) when Key > NumOfObjs ->
+ [end_of_work];
+ ({Key,Increment}) ->
+ true = ets:delete(T,Key),
+ {Key+Increment,Increment}
+ end,
+ FiniF = fun(_) -> ok end,
+ run_workers_do(InitF,ExecF,FiniF,NumOfObjs),
+ ?line 0 = ets:info(T,size),
+ ?line true = ets:info(T,fixed),
+ ?line Buckets = num_of_buckets(T),
+ ?line NumOfObjs = ets:info(T,kept_objects),
+ ets:safe_fixtable(T,false),
+ %% Will fail as unfix does not shrink the table:
+ %%?line Mem = ets:info(T,memory),
+ %%verify_table_load(T),
+ ets:delete(T).
+
+num_of_buckets(T) ->
+ ?line element(1,ets:info(T,stats)).
+
+smp_unfix_fix(doc) -> ["Fixate hash table while other process is busy doing unfix"];
+smp_unfix_fix(suite) -> [];
+smp_unfix_fix(Config) when is_list(Config) ->
+ only_if_smp(fun()-> smp_unfix_fix_do() end).
+
+smp_unfix_fix_do() ->
+ process_flag(scheduler,1),
+ Parent = self(),
+ T = ets:new(foo,[public,{write_concurrency,true}]),
+ %%Mem = ets:info(T,memory),
+ NumOfObjs = 100000,
+ Deleted = 50000,
+ filltabint(T,NumOfObjs),
+ ets:safe_fixtable(T,true),
+ Buckets = num_of_buckets(T),
+ ?line Deleted = ets:select_delete(T,[{{'$1', '_'},
+ [{'=<','$1', Deleted}],
+ [true]}]),
+ ?line Buckets = num_of_buckets(T),
+ Left = NumOfObjs - Deleted,
+ ?line Left = ets:info(T,size),
+ ?line true = ets:info(T,fixed),
+ ?line Deleted = ets:info(T,kept_objects),
+
+ {Child, Mref} =
+ spawn_opt(fun()-> ?line true = ets:info(T,fixed),
+ Parent ! start,
+ io:format("Child waiting for table to be unfixed... now=~p mem=~p\n",
+ [now(),ets:info(T,memory)]),
+ repeat_while(fun()-> ets:info(T,fixed) end),
+ io:format("Table unfixed. Child Fixating! now=~p mem=~p\n",
+ [now(),ets:info(T,memory)]),
+ ?line true = ets:safe_fixtable(T,true),
+ repeat_while(fun(Key) when Key =< NumOfObjs ->
+ ets:delete(T,Key), {true,Key+1};
+ (Key) -> {false,Key}
+ end,
+ Deleted),
+ ?line 0 = ets:info(T,size),
+ ?line true = ets:info(T,kept_objects) >= Left,
+ ?line done = receive_any()
+ end,
+ [link, monitor, {scheduler,2}]),
+
+ ?line start = receive_any(),
+ ?line true = ets:info(T,fixed),
+ io:format("Parent starting to unfix... ~p\n",[now()]),
+ ets:safe_fixtable(T,false),
+ io:format("Parent done with unfix. ~p\n",[now()]),
+ Child ! done,
+ {'DOWN', Mref, process, Child, normal} = receive_any(),
+ ?line false = ets:info(T,fixed),
+ ?line 0 = ets:info(T,kept_objects),
+ %%verify_table_load(T),
+ ets:delete(T),
+ process_flag(scheduler,0).
+
+otp_8166(doc) -> ["Unsafe unfix was done by trapping select/match"];
+otp_8166(suite) -> [];
+otp_8166(Config) when is_list(Config) ->
+ only_if_smp(3, fun()-> otp_8166_do(false),
+ otp_8166_do(true)
+ end).
+
+otp_8166_do(WC) ->
+ %% Bug scenario: One process segv while reading the table because another
+ %% process is doing unfix without write-lock at the end of a trapping match_object.
+ process_flag(scheduler,1),
+ T = ets:new(foo,[public, {write_concurrency,WC}]),
+ NumOfObjs = 3000, %% Need more than 1000 live objects for match_object to trap one time
+ Deleted = NumOfObjs div 2,
+ filltabint(T,NumOfObjs),
+ {ReaderPid, ReaderMref} =
+ spawn_opt(fun()-> otp_8166_reader(T,NumOfObjs) end,
+ [link, monitor, {scheduler,2}]),
+ {ZombieCrPid, ZombieCrMref} =
+ spawn_opt(fun()-> otp_8166_zombie_creator(T,Deleted) end,
+ [link, monitor, {scheduler,3}]),
+
+ repeat(fun() -> ZombieCrPid ! {loop, self()},
+ zombies_created = receive_any(),
+ otp_8166_trapper(T, 10, ZombieCrPid)
+ end,
+ 100),
+
+ ReaderPid ! quit,
+ {'DOWN', ReaderMref, process, ReaderPid, normal} = receive_any(),
+ ZombieCrPid ! quit,
+ {'DOWN', ZombieCrMref, process, ZombieCrPid, normal} = receive_any(),
+ ?line false = ets:info(T,fixed),
+ ?line 0 = ets:info(T,kept_objects),
+ %%verify_table_load(T),
+ ets:delete(T),
+ process_flag(scheduler,0).
+
+%% Keep reading the table
+otp_8166_reader(T, NumOfObjs) ->
+ repeat_while(fun(0) ->
+ receive quit -> {false,done}
+ after 0 -> {true,NumOfObjs}
+ end;
+ (Key) ->
+ ets:lookup(T,Key),
+ {true, Key-1}
+ end,
+ NumOfObjs).
+
+%% Do a match_object that will trap and thereby fixate and then unfixate the table
+otp_8166_trapper(T, Try, ZombieCrPid) ->
+ [] = ets:match_object(T,{'_',"Pink Unicorn"}),
+ case {ets:info(T,fixed),Try} of
+ {true,1} ->
+ io:format("failed to provoke unsafe unfix, give up...\n",[]),
+ ZombieCrPid ! unfix;
+ {true,_} ->
+ io:format("trapper too fast, trying again...\n",[]),
+ otp_8166_trapper(T, Try-1, ZombieCrPid);
+ {false,_} -> done
+ end.
+
+
+%% Fixate table and create some pseudo-deleted objects (zombies)
+%% Then wait for trapper to fixate before unfixing, as we want the trappers'
+%% unfix to be the one that purges the zombies.
+otp_8166_zombie_creator(T,Deleted) ->
+ case receive_any() of
+ quit -> done;
+
+ {loop,Pid} ->
+ filltabint(T,Deleted),
+ ets:safe_fixtable(T,true),
+ ?line Deleted = ets:select_delete(T,[{{'$1', '_'},
+ [{'=<','$1', Deleted}],
+ [true]}]),
+ Pid ! zombies_created,
+ repeat_while(fun() -> case ets:info(T,safe_fixed) of
+ {_,[_P1,_P2]} ->
+ false;
+ _ ->
+ receive unfix -> false
+ after 0 -> true
+ end
+ end
+ end),
+ ets:safe_fixtable(T,false),
+ otp_8166_zombie_creator(T,Deleted);
+
+ unfix ->
+ io:format("ignore unfix in outer loop?\n",[]),
+ otp_8166_zombie_creator(T,Deleted)
+ end.
+
+
+
+
+verify_table_load(T) ->
+ ?line Stats = ets:info(T,stats),
+ ?line {Buckets,AvgLen,StdDev,ExpSD,_MinLen,_MaxLen} = Stats,
+ ?line ok = if
+ AvgLen > 7 ->
+ io:format("Table overloaded: Stats=~p\n~p\n",
+ [Stats, ets:info(T)]),
+ false;
+
+ Buckets>256, AvgLen < 6 ->
+ io:format("Table underloaded: Stats=~p\n~p\n",
+ [Stats, ets:info(T)]),
+ false;
+
+ StdDev > ExpSD*2 ->
+ io:format("Too large standard deviation (poor hashing?),"
+ " stats=~p\n~p\n",[Stats, ets:info(T)]),
+ false;
+
+ true ->
+ io:format("Stats = ~p\n",[Stats]),
+ ok
+ end.
+
+
+
+
+
+smp_select_delete(suite) -> [];
+smp_select_delete(doc) ->
+ ["Run concurrent select_delete (and inserts) on same table."];
+smp_select_delete(Config) when is_list(Config) ->
+ T = ets:new(smp_select_delete,[named_table,public,{write_concurrency,true}]),
+ Mod = 17,
+ Zeros = erlang:make_tuple(Mod,0),
+ InitF = fun(_) -> Zeros end,
+ ExecF = fun(Diffs0) ->
+ case random:uniform(20) of
+ 1 ->
+ Mod = 17,
+ Eq = random:uniform(Mod) - 1,
+ Deleted = ets:select_delete(T,
+ [{{'_', '$1'},
+ [{'=:=', {'rem', '$1', Mod}, Eq}],
+ [true]}]),
+ Diffs1 = setelement(Eq+1, Diffs0,
+ element(Eq+1,Diffs0) - Deleted),
+ Diffs1;
+ _ ->
+ Key = random:uniform(10000),
+ Eq = Key rem Mod,
+ ?line case ets:insert_new(T,{Key,Key}) of
+ true ->
+ Diffs1 = setelement(Eq+1, Diffs0,
+ element(Eq+1,Diffs0)+1),
+ Diffs1;
+ false -> Diffs0
+ end
+ end
+ end,
+ FiniF = fun(Result) -> Result end,
+ Results = run_workers_do(InitF,ExecF,FiniF,20000),
+ ?line TotCnts = lists:foldl(fun(Diffs, Sum) -> add_lists(Sum,tuple_to_list(Diffs)) end,
+ lists:duplicate(Mod, 0), Results),
+ io:format("TotCnts = ~p\n",[TotCnts]),
+ ?line LeftInTab = lists:foldl(fun(N,Sum) -> Sum+N end,
+ 0, TotCnts),
+ io:format("LeftInTab = ~p\n",[LeftInTab]),
+ ?line LeftInTab = ets:info(T,size),
+ lists:foldl(fun(Cnt,Eq) ->
+ WasCnt = ets:select_count(T,
+ [{{'_', '$1'},
+ [{'=:=', {'rem', '$1', Mod}, Eq}],
+ [true]}]),
+ io:format("~p: ~p =?= ~p\n",[Eq,Cnt,WasCnt]),
+ ?line Cnt = WasCnt,
+ Eq+1
+ end,
+ 0, TotCnts),
+ verify_table_load(T),
+ ?line LeftInTab = ets:select_delete(T, [{{'$1','$1'}, [], [true]}]),
+ ?line 0 = ets:info(T,size),
+ ?line false = ets:info(T,fixed),
+ ets:delete(T).
+
+add_lists(L1,L2) ->
+ add_lists(L1,L2,[]).
+add_lists([],[],Acc) ->
+ lists:reverse(Acc);
+add_lists([E1|T1], [E2|T2], Acc) ->
+ add_lists(T1, T2, [E1+E2 | Acc]).
+
+run_workers(InitF,ExecF,FiniF,Laps) ->
+ case erlang:system_info(smp_support) of
+ true ->
+ run_workers_do(InitF,ExecF,FiniF,Laps);
+ false ->
+ {skipped,"No smp support"}
+ end.
+
+run_workers_do(InitF,ExecF,FiniF,Laps) ->
+ NumOfProcs = erlang:system_info(schedulers),
+ io:format("smp starting ~p workers\n",[NumOfProcs]),
+ Seeds = [{ProcN,random:uniform(9999)} || ProcN <- lists:seq(1,NumOfProcs)],
+ Parent = self(),
+ Pids = [spawn_link(fun()-> worker(Seed,InitF,ExecF,FiniF,Laps,Parent,NumOfProcs) end)
+ || Seed <- Seeds],
+ wait_pids(Pids).
+
+worker({ProcN,Seed}, InitF, ExecF, FiniF, Laps, Parent, NumOfProcs) ->
+ io:format("smp worker ~p, seed=~p~n",[self(),Seed]),
+ random:seed(Seed,Seed,Seed),
+ State1 = InitF([ProcN, NumOfProcs]),
+ State2 = worker_loop(Laps, ExecF, State1),
+ Result = FiniF(State2),
+ io:format("worker ~p done\n",[self()]),
+ Parent ! {self(), Result}.
+
+worker_loop(0, _, State) ->
+ State;
+worker_loop(_, _, [end_of_work|State]) ->
+ State;
+worker_loop(N, ExecF, State) ->
+ worker_loop(N-1,ExecF,ExecF(State)).
+
+wait_pids(Pids) ->
+ wait_pids(Pids,[]).
+wait_pids([],Acc) ->
+ Acc;
+wait_pids(Pids, Acc) ->
+ receive
+ {Pid,Result} ->
+ ?line true = lists:member(Pid,Pids),
+ Others = lists:delete(Pid,Pids),
+ io:format("wait_pid got ~p from ~p, still waiting for ~p\n",[Result,Pid,Others]),
+ wait_pids(Others,[Result | Acc])
+ end.
+
+
+
+
+my_tab_to_list(Ts) ->
+ Key = ets:first(Ts),
+ my_tab_to_list(Ts,ets:next(Ts,Key),[ets:lookup(Ts, Key)]).
+
+my_tab_to_list(_Ts,'$end_of_table', Acc) -> lists:reverse(Acc);
+my_tab_to_list(Ts,Key, Acc) ->
+ my_tab_to_list(Ts,ets:next(Ts,Key),[ets:lookup(Ts, Key)| Acc]).
+
+etsmem() ->
+ {try erlang:memory(ets) catch error:notsup -> notsup end,
+ case erlang:system_info({allocator,ets_alloc}) of
+ false -> undefined;
+ MemInfo ->
+ MSBCS = lists:foldl(
+ fun ({instance, _, L}, Acc) ->
+ {value,{_,MBCS}} = lists:keysearch(mbcs, 1, L),
+ {value,{_,SBCS}} = lists:keysearch(sbcs, 1, L),
+ [MBCS,SBCS | Acc]
+ end,
+ [],
+ MemInfo),
+ lists:foldl(
+ fun(L, {Bl0,BlSz0}) ->
+ {value,{_,Bl,_,_}} = lists:keysearch(blocks, 1, L),
+ {value,{_,BlSz,_,_}} = lists:keysearch(blocks_size, 1, L),
+ {Bl0+Bl,BlSz0+BlSz}
+ end, {0,0}, MSBCS)
+ end}.
+
+verify_etsmem(MemInfo) ->
+ wait_for_test_procs(),
+ case etsmem() of
+ MemInfo ->
+ io:format("Ets mem info: ~p", [MemInfo]),
+ case MemInfo of
+ {ErlMem,EtsAlloc} when ErlMem == notsup; EtsAlloc == undefined ->
+ %% Use 'erl +Mea max' to do more complete memory leak testing.
+ {comment,"Incomplete or no mem leak testing"};
+ _ ->
+ ok
+ end;
+ Other ->
+ io:format("Expected: ~p", [MemInfo]),
+ io:format("Actual: ~p", [Other]),
+ ?t:fail()
+ end.
+
+start_loopers(N, Prio, Fun, State) ->
+ lists:map(fun (_) ->
+ my_spawn_opt(fun () -> looper(Fun, State) end,
+ [{priority, Prio}, link])
+ end,
+ lists:seq(1, N)).
+
+stop_loopers(Loopers) ->
+ lists:foreach(fun (P) ->
+ unlink(P),
+ exit(P, bang)
+ end,
+ Loopers),
+ ok.
+
+looper(Fun, State) ->
+ looper(Fun, Fun(State)).
+
+spawn_logger(Procs) ->
+ receive
+ {new_test_proc, Proc} ->
+ spawn_logger([Proc|Procs]);
+ {sync_test_procs, Kill, From} ->
+ lists:foreach(fun (Proc) when From == Proc ->
+ ok;
+ (Proc) ->
+ Mon = erlang:monitor(process, Proc),
+ receive
+ {'DOWN', Mon, _, _, _} ->
+ ok
+ after 0 ->
+ case Kill of
+ true -> exit(Proc, kill);
+ _ -> ok
+ end,
+ receive
+ {'DOWN', Mon, _, _, _} ->
+ ok
+ end
+ end
+ end, Procs),
+ From ! test_procs_synced,
+ spawn_logger([From])
+ end.
+
+start_spawn_logger() ->
+ case whereis(ets_test_spawn_logger) of
+ Pid when is_pid(Pid) -> true;
+ _ -> register(ets_test_spawn_logger,
+ spawn_opt(fun () -> spawn_logger([]) end,
+ [{priority, max}]))
+ end.
+
+%% restart_spawn_logger() ->
+%% stop_spawn_logger(),
+%% start_spawn_logger().
+
+stop_spawn_logger() ->
+ Mon = erlang:monitor(process, ets_test_spawn_logger),
+ (catch exit(whereis(ets_test_spawn_logger), kill)),
+ receive {'DOWN', Mon, _, _, _} -> ok end,
+ ok.
+
+wait_for_test_procs() ->
+ wait_for_test_procs(false).
+
+wait_for_test_procs(Kill) ->
+ ets_test_spawn_logger ! {sync_test_procs, Kill, self()},
+ receive test_procs_synced -> ok end.
+
+log_test_proc(Proc) ->
+ ets_test_spawn_logger ! {new_test_proc, Proc},
+ Proc.
+
+my_spawn(Fun) -> log_test_proc(spawn(Fun)).
+%%my_spawn(M,F,A) -> log_test_proc(spawn(M,F,A)).
+%%my_spawn(N,M,F,A) -> log_test_proc(spawn(N,M,F,A)).
+
+my_spawn_link(Fun) -> log_test_proc(spawn_link(Fun)).
+my_spawn_link(M,F,A) -> log_test_proc(spawn_link(M,F,A)).
+%%my_spawn_link(N,M,F,A) -> log_test_proc(spawn_link(N,M,F,A)).
+
+my_spawn_opt(Fun,Opts) -> log_test_proc(spawn_opt(Fun,Opts)).
+%%my_spawn_opt(M,F,A,Opts) -> log_test_proc(spawn_opt(M,F,A,Opts)).
+%%my_spawn_opt(N,M,F,A,Opts) -> log_test_proc(spawn_opt(N,M,F,A,Opts)).
+
+repeat(_Fun, 0) ->
+ ok;
+repeat(Fun, N) ->
+ Fun(),
+ repeat(Fun, N-1).
+
+repeat_while(Fun) ->
+ case Fun() of
+ true -> repeat_while(Fun);
+ false -> false
+ end.
+
+repeat_while(Fun, Arg0) ->
+ case Fun(Arg0) of
+ {true,Arg1} -> repeat_while(Fun,Arg1);
+ {false,Ret} -> Ret
+ end.
+
+receive_any() ->
+ receive M ->
+ io:format("Process ~p got msg ~p\n", [self(),M]),
+ M
+ end.
+
+receive_any_spinning() ->
+ receive_any_spinning(1000000).
+receive_any_spinning(Loops) ->
+ receive_any_spinning(Loops,Loops,1).
+receive_any_spinning(Loops,0,Tries) ->
+ receive M ->
+ io:format("Spinning process ~p got msg ~p after ~p tries\n", [self(),M,Tries]),
+ M
+ after 0 ->
+ receive_any_spinning(Loops, Loops, Tries+1)
+ end;
+receive_any_spinning(Loops, N, Tries) when N>0 ->
+ receive_any_spinning(Loops, N-1, Tries).
+
+
+
+spawn_monitor_with_pid(Pid, Fun) when is_pid(Pid) ->
+ spawn_monitor_with_pid(Pid, Fun, 1, 10).
+
+spawn_monitor_with_pid(Pid, Fun, N, M) when N > M*10 ->
+ spawn_monitor_with_pid(Pid, Fun, N, M*10);
+spawn_monitor_with_pid(Pid, Fun, N, M) ->
+ ?line false = is_process_alive(Pid),
+ case spawn(fun()-> case self() of
+ Pid -> Fun();
+ _ -> die
+ end
+ end) of
+ Pid ->
+ {Pid, erlang:monitor(process, Pid)};
+ Other ->
+ case N rem M of
+ 0 -> io:format("Failed ~p times to get pid ~p (current = ~p)\n",[N,Pid,Other]);
+ _ -> ok
+ end,
+ spawn_monitor_with_pid(Pid,Fun,N+1,M)
+ end.
+
+
+only_if_smp(Func) ->
+ only_if_smp(2, Func).
+only_if_smp(Schedulers, Func) ->
+ case {erlang:system_info(smp_support),
+ erlang:system_info(schedulers_online)} of
+ {false,_} -> {skip,"No smp support"};
+ {true,N} when N < Schedulers -> {skip,"Too few schedulers online"};
+ {true,_} -> Func()
+ end.
+
+
+%% Repeat test function with different combination of table options
+%%
+repeat_for_opts(F) ->
+ repeat_for_opts(F, [write_concurrency]).
+
+repeat_for_opts(F, OptGenList) when is_atom(F) ->
+ repeat_for_opts(fun(Opts) -> ?MODULE:F(Opts) end, OptGenList);
+repeat_for_opts(F, OptGenList) ->
+ repeat_for_opts(F, OptGenList, []).
+
+repeat_for_opts(F, [], Acc) ->
+ lists:map(fun(Opts) ->
+ io:format("Calling with options ~p\n",[Opts]),
+ F(Opts)
+ end, Acc);
+repeat_for_opts(F, [OptList | Tail], []) when is_list(OptList) ->
+ repeat_for_opts(F, Tail, [[Opt] || Opt <- OptList]);
+repeat_for_opts(F, [OptList | Tail], AccList) when is_list(OptList) ->
+ repeat_for_opts(F, Tail, [[Opt|Acc] || Opt <- OptList, Acc <- AccList]);
+repeat_for_opts(F, [Atom | Tail], AccList) when is_atom(Atom) ->
+ repeat_for_opts(F, [repeat_for_opts_atom2list(Atom) | Tail ], AccList).
+
+repeat_for_opts_atom2list(all_types) -> [set,ordered_set,bag,duplicate_bag];
+repeat_for_opts_atom2list(write_concurrency) -> [{write_concurrency,false},{write_concurrency,true}].
+
+
diff --git a/lib/stdlib/test/ets_SUITE_data/dummy.txt b/lib/stdlib/test/ets_SUITE_data/dummy.txt
new file mode 100644
index 0000000000..2cdad292f7
--- /dev/null
+++ b/lib/stdlib/test/ets_SUITE_data/dummy.txt
@@ -0,0 +1 @@
+Dummy
diff --git a/lib/stdlib/test/ets_tough_SUITE.erl b/lib/stdlib/test/ets_tough_SUITE.erl
new file mode 100644
index 0000000000..e3d44d00b9
--- /dev/null
+++ b/lib/stdlib/test/ets_tough_SUITE.erl
@@ -0,0 +1,1093 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(ets_tough_SUITE).
+-export([all/1,ex1/1]).
+-export([init/1,terminate/2,handle_call/3,handle_info/2]).
+-export([init_per_testcase/2, fin_per_testcase/2]).
+-compile([export_all]).
+-include("test_server.hrl").
+
+all(suite) -> [ex1].
+
+
+-define(DEBUG(X),debug_disabled).
+%%-define(DEBUG(X),X).
+-define(GLOBAL_PARAMS,ets_tough_SUITE_global_params).
+
+init_per_testcase(_Func, Config) ->
+ Dog=test_server:timetrap(test_server:seconds(300)),
+ [{watchdog, Dog}|Config].
+
+fin_per_testcase(_Func, Config) ->
+ Dog=?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+ ets:delete(?GLOBAL_PARAMS).
+
+
+ex1(Config) when list(Config) ->
+ ?line ets:new(?GLOBAL_PARAMS,[named_table,public]),
+ ?line ets:insert(?GLOBAL_PARAMS,{a,set}),
+ ?line ets:insert(?GLOBAL_PARAMS,{b,set}),
+ ?line ex1_sub(Config),
+ ?line ets:insert(?GLOBAL_PARAMS,{a,ordered_set}),
+ ?line ets:insert(?GLOBAL_PARAMS,{b,set}),
+ ?line ex1_sub(Config),
+ ?line ets:insert(?GLOBAL_PARAMS,{a,ordered_set}),
+ ?line ets:insert(?GLOBAL_PARAMS,{b,ordered_set}),
+ ?line ex1_sub(Config).
+
+
+
+
+ex1_sub(Config) ->
+ {A,B} = prep(Config),
+ N =
+ case ?config(ets_tough_SUITE_iters,Config) of
+ undefined ->
+ 5000;
+ Other ->
+ Other
+ end,
+ {NewA,NewB} = run({A,B},N),
+ _Gurkor = lists:keysearch(gurka,1,ets:all()),
+ (catch stop(NewA)),
+ (catch stop(NewB)),
+ ok.
+
+prep(Config) ->
+ random:seed(),
+ put(dump_ticket,none),
+ DumpDir = filename:join(?config(priv_dir,Config), "ets_tough"),
+ file:make_dir(DumpDir),
+ put(dump_dir,DumpDir),
+ process_flag(trap_exit,true),
+ {ok, A} = start(a),
+ {ok, B} = start(b),
+ {A,B}.
+
+run({A,B},N) ->
+ run(A,B,0,N).
+
+run(A,B,N,N) ->
+ {A,B};
+run(A,B,N,M) ->
+ eat_msgs(),
+ Op = random_operation(),
+ ?DEBUG(io:format("~w: ",[N])),
+ case catch operate(Op,A,B) of
+ {'EXIT',Reason} ->
+ io:format("\nFAILURE on ~w: ~w, reason: ~w\n",[N,Op,Reason]),
+ exit(failed);
+ {new_a,NewA} ->
+ run(NewA,B,N+1,M);
+ _ ->
+ run(A,B,N+1,M)
+ end.
+
+eat_msgs() ->
+ receive
+ _Anything ->
+ eat_msgs()
+ after 0 ->
+ ok
+ end.
+
+operate(get,A,B) ->
+ case random_key() of
+ 1 ->
+ Class = random_class(),
+ AnsA = lists:sort(dget_class(A,Class,all)),
+ AnsB = lists:sort(dget_class(B,Class,all)),
+ ?DEBUG(io:format("get_class ~w (~w)\n",[Class,AnsA])),
+ AnsA = AnsB;
+ _Other ->
+ Class = random_class(),
+ Key = random_key(),
+ AnsA = dget(A,Class,Key),
+ AnsB = dget(B,Class,Key),
+ ?DEBUG(io:format("get ~w,~w (~w)\n",[Class,Key,AnsA])),
+ AnsA = AnsB
+ end;
+
+operate(put,A,B) ->
+ Class = random_class(),
+ Key = random_key(),
+ Value = random_value(),
+ AnsA = dput(A,Class,Key,Value),
+ AnsB = dput(B,Class,Key,Value),
+ ?DEBUG(io:format("put ~w,~w=~w (~w)\n",[Class,Key,Value,AnsA])),
+ AnsA = AnsB;
+
+operate(erase,A,B) ->
+ case random_key() of
+ 1 ->
+ Class = random_class(),
+ AnsA = derase_class(A,Class),
+ AnsB = derase_class(B,Class),
+ ?DEBUG(io:format("erase_class ~w\n",[Class])),
+ AnsA = AnsB;
+ _Other ->
+ Class = random_class(),
+ Key = random_key(),
+ AnsA = derase(A,Class,Key),
+ AnsB = derase(B,Class,Key),
+ ?DEBUG(io:format("erase ~w,~w (~w)\n",[Class,Key,AnsA])),
+ AnsA = AnsB
+ end;
+
+operate(dirty_get,A,_B) ->
+ Class = random_class(),
+ Key = random_key(),
+ %% only try dirty get on the b-side (which is never dumping)
+ AnsA = dget(A,Class,Key),
+ AnsB = dirty_dget(b,Class,Key),
+ ?DEBUG(io:format("dirty_get ~w,~w (~w)\n",[Class,Key,AnsA])),
+ AnsA = AnsB;
+
+operate(dump,A,_B) ->
+ case get(dump_ticket) of
+ {dump_more,Ticket} ->
+ Units = random_key(),
+ NewTicket = ddump_next(A,Units,Ticket),
+ put(dump_ticket,NewTicket),
+ _Result = case NewTicket of
+ done -> done;
+ _ -> dump_more
+ end,
+ ?DEBUG(io:format("dump ~w (~w)\n",[Units,_Result]));
+ _ ->
+ DumpDir = get(dump_dir),
+ case random_key() of
+ 1 ->
+ ?DEBUG(io:format("start_dump\n",[])),
+ NewTicket = ddump_first(A,DumpDir),
+ put(dump_ticket,NewTicket);
+ 2 ->
+ ?DEBUG(io:format("dump_and_restore\n",[])),
+ {dump_more,NewTicket} = ddump_first(A,DumpDir),
+ done = ddump_next(A,1000000,NewTicket),
+ stop(A),
+ {ok, NewA} = start(a,DumpDir),
+ {new_a,NewA};
+ _ ->
+ ?DEBUG(io:format("idle\n",[])),
+ ok
+ end
+ end.
+
+random_operation() ->
+ Ops = {get,put,erase,dirty_get,dump},
+ random_element(Ops).
+
+random_class() ->
+ Classes = {foo,bar,tomat,gurka},
+ random_element(Classes).
+
+random_key() ->
+ random:uniform(8).
+
+random_value() ->
+ case random:uniform(5) of
+ 1 -> ok;
+ 2 -> {data,random_key()};
+ 3 -> {foo,bar,random_class()};
+ 4 -> random:uniform(1000);
+ 5 -> {recursive,random_value()}
+ end.
+
+random_element(T) ->
+ I = random:uniform(tuple_size(T)),
+ element(I,T).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+show_table(N) ->
+ FileName = ["etsdump.",integer_to_list(N)],
+ case file:open(FileName,read) of
+ {ok,Fd} ->
+ show_entries(Fd);
+ _ ->
+ error
+ end.
+
+show_entries(Fd) ->
+ case phys_read_len(Fd) of
+ {ok,Len} ->
+ case phys_read_entry(Fd,Len) of
+ {ok,ok} ->
+ ok;
+ {ok,{Key,Val}} ->
+ io:format("~w\n",[{Key,Val}]),
+ show_entries(Fd);
+ _ ->
+ error
+ end;
+ _ ->
+ error
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%% DEFINITIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+-define(NAMED_TABLES,true).
+-define(DB_NAME_KEY, {'$db_name'}).
+-define(LIST_OF_CLASSES_KEY,{'$list_of_classes'}).
+-define(DUMPING_FLAG_KEY,{'$dumping_flag'}).
+-define(DUMP_DIRECTORY_KEY,{'$dump_directory'}).
+-define(ERASE_MARK(Key),{{{'$erased'},Key}}).
+-define(ets_new,ets:new).
+-define(ets_lookup,ets:lookup).
+-define(ets_insert,ets:insert). % erlang:db_put
+-define(ets_delete,ets:delete). % erlang:db_erase
+-define(ets_first,ets:first). % erlang:db_first
+-define(ets_next,ets:next). % erlang:db_next_key
+-define(ets_info,ets:info). % erlang:db_info
+
+%%% INTERFACE FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%% start(DbName) -> Pid | {error,Reason}
+%%%
+%%% Starts the ets table database with name DbName
+
+start(DbName) ->
+ case gen_server:start_link(ets_tough_SUITE,{DbName,no_dump_dir},[]) of
+ {ok,Pid} when pid(Pid) ->
+ {ok, Pid};
+ Other ->
+ Other
+ end.
+
+%%% start(DbName,DumpDir) -> Pid | {error,Reason}
+%%%
+%%% Starts the ets table database with name DbName, and reads a dump
+%%% from DumpDir when it starts.
+
+start(DbName,DumpDir) ->
+ case gen_server:start_link(ets_tough_SUITE,
+ {DbName,{dump_dir,DumpDir}},[]) of
+ {ok,Pid} when pid(Pid) ->
+ {ok, Pid};
+ Other ->
+ Other
+ end.
+
+%%% stop(ServerPid) -> {'EXIT',shutdown}
+%%%
+%%% Shuts down the ets table database
+
+stop(ServerPid) ->
+ gen_server:call(ServerPid,stop).
+
+%%% dget(ServerPid,Class,Key) -> {value,Value} | undefined
+%%%
+%%% Returns a value identified by Class,Key from the database, or
+%%% 'undefined' if there is no such value.
+
+dget(ServerPid,Class,Key) ->
+ gen_server:call(ServerPid,{handle_lookup,Class,Key}).
+
+%%% dirty_dget(DbName,Class,Key) -> {value,Value} | undefined
+%%%
+%%% This is looks up the value directly in the ets table
+%%% to avoid message passing. Several databases may be started,
+%%% so the admin table must be registered.
+
+dirty_dget(DbName,Class,Key) ->
+ Admin = admin_table_name(DbName),
+ case catch(?ets_lookup(Admin,Class)) of
+ [{_Class,[Tab|_Tabs]}] ->
+ case ?ets_lookup(Tab,Key) of
+ [{_Key,Value}] ->
+ {value,Value};
+ _ ->
+ undefined
+ end;
+ _ ->
+ undefined
+ end.
+
+%%% dput(ServerPid,Class,Key,Value) -> undefined | {value,OldValue}
+%%%
+%%% Inserts the given Value to be identified by Class,Key. Any prevoius
+%%% value is returned, or otherwise 'undefined'.
+
+dput(ServerPid,Class,Key,Value) ->
+ gen_server:call(ServerPid,{handle_insert,Class,Key,Value}).
+
+%%% derase(ServerPid,Class,Key) -> undefined | {value,OldValue}
+%%%
+%%% Erases any value identified by Class,Key
+
+derase(ServerPid,Class,Key) ->
+ gen_server:call(ServerPid,{handle_delete,Class,Key}).
+
+%%% dget_class(ServerPid,Class,Condition) -> KeyList
+%%%
+%%% Returns a list of keys where the instance match Condition.
+%%% Condition = 'all' returns all keys in the class.
+%%% The condition is supplied as Condition = {Mod, Fun, ExtraArgs},
+%%% where the instance will be prepended to ExtraArgs before each
+%%% call is made.
+
+dget_class(ServerPid,Class,Condition) ->
+ gen_server:call(ServerPid,
+ {handle_get_class,Class,Condition},infinity).
+
+%%% derase_class(ServerPid,Class) -> ok
+%%%
+%%% Erases a whole class, identified by Class
+
+derase_class(ServerPid,Class) ->
+ gen_server:call(ServerPid,{handle_delete_class,Class}, infinity).
+
+%%% dmodify(ServerPid,Application) -> ok
+%%%
+%%% Applies a function on every instance in the database.
+%%% The user provided function must always return one of the
+%%% terms {ok,NewItem}, true, or false.
+%%% Aug 96, this is only used to reset all timestamp values
+%%% in the database.
+%%% The function is supplied as Application = {Mod, Fun, ExtraArgs},
+%%% where the instance will be prepended to ExtraArgs before each
+%%% call is made.
+
+dmodify(ServerPid,Application) ->
+ gen_server:call(ServerPid,{handle_dmodify,Application}, infinity).
+
+%%% ddump_first(ServerPid,DumpDir) -> {dump_more,Ticket} | already_dumping
+%%%
+%%% Starts dumping the database. This call redirects all database updates
+%%% to temporary tables, so that exactly the same database image will be
+%%% written to disk as is in memory when this function is called.
+%%% The returned Ticket is to be used with ddump_next/2
+
+ddump_first(ServerPid,DumpDir) ->
+ gen_server:call(ServerPid,{handle_dump_first,DumpDir}, infinity).
+
+%%% ddump_next(ServerPid,Count,Ticket) -> {dump_more,Ticket} | done
+%%%
+%%% Dumps the database. This function performs Count units of dump work.
+%%% Higher value of Count makes the entire dump operation more efficient,
+%%% but blocks the database for longer periods of time.
+%%% If there is still more work to be done, a new Ticket is returned,
+%%% or 'done' otherwise.
+
+ddump_next(ServerPid,Count,Ticket) ->
+ gen_server:call(ServerPid,{handle_dump_next,Ticket,Count},150000).
+
+%%% PRIVATE HANDLER FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%% Admin
+%%% -----
+%%%
+%%% The database has a main administrative table Admin. It always contains
+%%% these four items:
+%%%
+%%% {{'$db_name'},Name}
+%%% {{'$list_of_classes'},ListOfClasses}
+%%% {{'$dumping_flag'},BoolDumping}
+%%% {{'$dump_directory'},Dir}
+%%%
+%%% The ListOfClasses is simply a list of all Classes that has ever been
+%%% inserted in the database. It's used to know which tables to dump.
+%%% The dump flag is 'true' while dump is in progress, to make it
+%%% impossible to start a new dump before an old dump is completed.
+%%%
+%%% For each class there is an entry of the form
+%%%
+%%% {Class,ListOfTables}
+%%%
+%%% Where the ListOfTables is the list of class tables (see below)
+%%%
+%%% Class Tables
+%%% ------------
+%%%
+%%% The class tables are common ets tables that have the actual user
+%%% data stored in them.
+%%%
+%%% Normally there is only one class table, Mtab (main table).
+%%% When dumping is initiated, each class is syncronously given a
+%%% temporary table, Ttab, where all updates are stored. Reads are
+%%% directed to the Ttab first, and only if not found there, Mtab is
+%%% consulted.
+%%%
+%%% Writes always go to the first table in the table sequence. This
+%%% ensures that the dump algorithm can enumerate the entries in the
+%%% other tables, without risk of being disrupted.
+%%%
+%%% When the dumping to disk is completed, it's time to write back
+%%% whatever updates that came into the Ttab to Mtab. To do this, a
+%%% third table is needed, Utab, to handle all updates while Ttab is
+%%% being copied to Mtab. When all of Ttab is copied, Ttab is thrown
+%%% away, and the whole process is repeated with Utab as Ttab until
+%%% eventually nobody wrote to Utab while Ttab was copied (clean run).
+%%%
+%%% There is no _guarantee_ that this will ever happen, but unless there
+%%% is a constant (and quite high frequency) stream of updates to a
+%%% particular class, this should work.
+%%%
+%%% (It is possible to make this failsafe, by copying the elements in
+%%% Mtab to Ttab. This is probably a lot more expensive, though)
+%%%
+%%% Erasure during dump
+%%% -------------------
+%%%
+%%% Erasing need special attention when a single class has several
+%%% tables. It really boils down to a number of cases:
+%%%
+%%% - element does not exist in Ttab.
+%%% A special erase record is written, {{{'$erased'},Key}} which
+%%% is hopefully different from all other keys used by the user.
+%%% - element exists in Ttab
+%%% The element is deleted, and erase record is written
+%%% - element does not exist in Ttab, but there is an erase record
+%%% fine, do nothing
+%%% - element exist in Ttab, and there is an erase record
+%%% This happens when a record is deleted from Ttab, then written
+%%% back again. Erase records are not looked for when inserting
+%%% new data (and that's not necessary)
+%%%
+%%% Then when Ttab should be copied to Mtab:
+%%%
+%%% - found an element
+%%% Usual case, just copy
+%%% - found erase record
+%%% Check if there is an element with the same key as the erase
+%%% record. If so it has been written later than the erasure, so
+%%% the erasure is obsolete. Otherwise erase the record from Mtab.
+%%%
+%%% Delete Class
+%%% ------------
+%%%
+%%% A slight problem is deleting an entire class while dumping is in
+%%% progress. For consitency, all user visible traces of the class must
+%%% be deleted, while dumping must not be affected. On top of that, the
+%%% deleted class may well be recreated while dumping is still going on,
+%%% and entries added.
+%%%
+%%% This is solved by having the dump algorithm keep track of the table
+%%% identifiers of the tables to dump, rather than asking the admin table
+%%% (since the class might be deleted there). The dump algorithm will
+%%% itself take care of deleting the tables used in the dumping, while the
+%%% normal database interface deletes the "first table", the table that is
+%%% currently accepting all write operations.
+
+
+init({DbName,DumpDir}) ->
+ case DumpDir of
+ no_dump_dir ->
+ Admin = make_admin_table(DbName),
+ ?ets_insert(Admin,{?LIST_OF_CLASSES_KEY,[]}),
+ init2(DbName,Admin);
+ {dump_dir,Dir} ->
+ case load_dump(DbName,Dir) of
+ {ok,Admin} ->
+ ?ets_insert(Admin,{?DUMP_DIRECTORY_KEY,Dir}),
+ init2(DbName,Admin);
+ _ ->
+ cant_load_dump
+ end
+ end.
+
+init2(DbName,Admin) ->
+ ?ets_insert(Admin,{?DUMPING_FLAG_KEY,false}),
+ ?ets_insert(Admin,{?DB_NAME_KEY,DbName}),
+ {ok, Admin}.
+
+terminate(_Reason,_Admin) ->
+ ok.
+
+handle_call({handle_lookup,Class,Key},_From,Admin) ->
+ %% Lookup tables to search in
+ Reply =
+ case ?ets_lookup(Admin,Class) of
+ [] ->
+ undefined; %% no such class => no such record
+ [{_,TabList}] ->
+ {_,Ans} = table_lookup(TabList, Key),
+ Ans
+ end,
+ {reply,Reply,Admin};
+
+handle_call({handle_insert,Class,Key,Value},_From,Admin) ->
+ %% Lookup in which table to write
+ Reply =
+ case ?ets_lookup(Admin,Class) of
+ [] ->
+ %% undefined class, let's create it
+ Mtab = make_db_table(db_name(Admin),Class),
+ ?ets_insert(Admin,{Class,[Mtab]}),
+ [{_,Classes}] = ?ets_lookup(Admin,?LIST_OF_CLASSES_KEY),
+ ?ets_insert(Admin,{?LIST_OF_CLASSES_KEY,[Class|Classes]}),
+ ?ets_insert(Mtab, {Key, Value}),
+ undefined;
+ [{_,[Tab|Tabs]}] ->
+ {_,Old} = table_lookup([Tab|Tabs], Key),
+ ?ets_insert(Tab, {Key, Value}),
+ Old
+ end,
+ {reply,Reply,Admin};
+
+handle_call({handle_delete,Class,Key},_From,Admin) ->
+ %% Lookup in which table to write
+ Reply =
+ case ?ets_lookup(Admin, Class) of
+ [] ->
+ undefined; %% no such class, but delete is happy anyway
+ [{_,[Tab]}] ->
+ %% When there is only one table, simply deleting is enough
+ {_,Old} = table_lookup(Tab,Key),
+ ?ets_delete(Tab,Key),
+ Old;
+ [{_,[Tab|Tabs]}] ->
+ %% When there are more tables, we have to write a delete
+ %% record into the first one, so that nobody goes looking
+ %% for this entry in some other table
+ {_,Old} = table_lookup([Tab|Tabs],Key),
+ ?ets_insert(Tab, {?ERASE_MARK(Key), erased}),
+ ?ets_delete(Tab,Key),
+ Old
+ end,
+ {reply,Reply,Admin};
+
+handle_call({handle_get_class,Class,Cond},_From,Admin) ->
+ Reply =
+ case ?ets_lookup(Admin,Class) of % Lookup tables to search in
+ [] ->
+ []; % no such class
+ [{_,TabList}] ->
+ table_lookup_batch(TabList, Class, Cond) % get class data
+ end,
+ {reply,Reply,Admin};
+
+handle_call({handle_delete_class,Class},_From,Admin) ->
+ Reply =
+ case ?ets_lookup(Admin, Class) of
+ [] ->
+ ok; % no such class, but delete_class is happy anyway
+ [{_,[Tab|_Tabs]}] ->
+ %% Always delete the first table (the one we're writing into)
+ %% In case we're dumping, the rest of the tables will be
+ %% taken care of by the dump algorithm.
+ ?ets_delete(Tab),
+ [{_, Classes}] = ?ets_lookup(Admin, ?LIST_OF_CLASSES_KEY),
+ NewClasses = lists:delete(Class, Classes),
+ ?ets_insert(Admin, {?LIST_OF_CLASSES_KEY, NewClasses}),
+ ?ets_delete(Admin, Class),
+ ok
+ end,
+ {reply,Reply,Admin};
+
+handle_call({handle_dmodify,Application},_From,Admin) ->
+ [{_, Classes}] = ?ets_lookup(Admin, ?LIST_OF_CLASSES_KEY),
+ modify(Application, Classes, Admin),
+ {reply,ok,Admin};
+
+handle_call({handle_dump_first,DumpDir},_From,Admin) ->
+ case ?ets_lookup(Admin,?DUMPING_FLAG_KEY) of
+ [{_,true}] ->
+ {reply,already_dumping,Admin};
+ _ ->
+ phys_remove_ok(DumpDir),
+ [{_,Classes}] = ?ets_lookup(Admin,?LIST_OF_CLASSES_KEY),
+ Tables = dump_prepare_classes(Classes,Admin),
+ ?ets_insert(Admin,{?DUMPING_FLAG_KEY,true}),
+ %% this is the new dir for dumping:
+ ?ets_insert(Admin,{?DUMP_DIRECTORY_KEY,DumpDir}),
+ handle_dump_next({[{admin,Classes}|Tables]},0,Admin)
+ end;
+
+%% All done, good work!
+handle_call({handle_dump_next,Ticket,Count},_From,Admin) ->
+ handle_dump_next(Ticket,Count,Admin);
+
+handle_call(stop,_From,Admin) ->
+ ?ets_delete(Admin), % Make sure table is gone before reply is sent.
+ {stop, normal, ok, []}.
+
+handle_info({'EXIT',_Pid,_Reason},Admin) ->
+ {stop,normal,Admin}.
+
+handle_delete(Class, Key, Admin) ->
+ handle_call({handle_delete,Class,Key},from,Admin).
+
+handle_insert(Class, Key, Value, Admin) ->
+ handle_call({handle_insert,Class,Key,Value},from,Admin).
+
+handle_lookup(Class, Key, Admin) ->
+ handle_call({handle_lookup,Class,Key},from,Admin).
+
+
+handle_dump_next({[]},_Count,Admin) ->
+ [{_Key,DumpDir}] = ?ets_lookup(Admin,?DUMP_DIRECTORY_KEY),
+ phys_ok_dump(DumpDir),
+ ?ets_insert(Admin,{?DUMPING_FLAG_KEY,false}),
+ {reply,done,Admin};
+
+%% No more operations, return to user asking for more
+handle_dump_next(Ticket,0,Admin) ->
+ {reply,{dump_more,Ticket},Admin};
+
+%% Dump the admin table. Costs one dump-work unit.
+handle_dump_next({[{admin,Classes}|Tables]},Count,Admin) ->
+ [{_Key,DumpDir}] = ?ets_lookup(Admin,?DUMP_DIRECTORY_KEY),
+ DumpData = phys_init_dump(admin,DumpDir,0),
+ phys_dump({?LIST_OF_CLASSES_KEY,Classes},DumpData),
+ phys_finish_dump(DumpData),
+ handle_dump_next({Tables},Count-1,Admin);
+
+%% Pick out a class and start dumping it
+handle_dump_next({[{Class,Mtab}|Tables]},Count,Admin) ->
+ ?DEBUG(io:format("DUMP CLASS ~w\n",[Class])),
+ [{_Key,DumpDir}] = ?ets_lookup(Admin,?DUMP_DIRECTORY_KEY),
+ DumpData = phys_init_dump(Class,DumpDir,length(Tables)+1),
+ First = ?ets_first(Mtab),
+ handle_dump_next({Class,Tables,Mtab,First,DumpData},Count,Admin);
+
+%% All keys in this class have been written to disk, now we have to
+%% copy all items from temporary Ttab to main Mtab
+handle_dump_next({Class,Tables,Stab,'$end_of_table',DumpData},Count,Admin) ->
+ phys_finish_dump(DumpData),
+ ?DEBUG(io:format("Cleaning up temporary table in ~p\n",[Class])),
+ case ?ets_lookup(Admin,Class) of
+ [{Key,[Utab,Mtab]}] ->
+ Ttab = make_db_table(db_name(Admin),Class),
+ ?ets_insert(Admin,{Key,[Ttab,Utab,Mtab]}),
+ First = ?ets_first(Utab),
+ handle_dump_next({3,Class,Tables,Utab,First,Mtab},Count,Admin);
+ _Other ->
+ %% Class deleted (and maybe recreated) while dumping, no need to
+ %% bring this one up to date. Just discard late additions.
+ ?ets_delete(Stab),
+ handle_dump_next({Tables},Count,Admin)
+ end;
+
+%% Dumping one key to disk. Costs one dump-work unit.
+handle_dump_next({Class,Tables,Tab,Key,DumpData},Count,Admin) ->
+ [KeyVal] = ?ets_lookup(Tab,Key),
+ phys_dump(KeyVal,DumpData),
+ NextKey = ?ets_next(Tab,Key),
+ handle_dump_next({Class,Tables,Tab,NextKey,DumpData},Count-1,Admin);
+
+%% Done copying elements from Ttab to Mtab
+%% check if Utab is empty and go on with next class, or
+%% make Utab the current Ttab, and run again
+%% ... will this ever end? ;-)
+handle_dump_next({3,Class,Tables,Stab,'$end_of_table',Dtab},Count,Admin) ->
+ case ?ets_lookup(Admin,Class) of
+ [{Key,[Ttab,Utab,Mtab]}] ->
+ case ?ets_info(Ttab,size) of
+ 0 ->
+ ?ets_insert(Admin,{Key,[Mtab]}),
+ ?ets_delete(Ttab),
+ ?ets_delete(Utab),
+ handle_dump_next({Tables},Count,Admin);
+ _Work ->
+ ?DEBUG(io:format("Switching direction in ~p\n",[Class])),
+ %% Which is faster, deleting all the entries
+ %% in a table, or deleting it and create a new?
+ ?ets_delete(Utab),
+ Ntab = make_db_table(db_name(Admin),Class),
+ ?ets_insert(Admin,{Key,[Ntab,Ttab,Mtab]}),
+ First = ?ets_first(Ttab),
+ handle_dump_next({3,Class,Tables,Ttab,First,Mtab},
+ Count,Admin)
+ end;
+ _Other ->
+ %% Class deleted (and maybe recreated) while dumping, no need to
+ %% bring this one up to date. Just discard late additions.
+ ?ets_delete(Stab),
+ ?ets_delete(Dtab),
+ handle_dump_next({Tables},Count,Admin)
+ end;
+
+%% Copy one key from Ttab to Mtab
+%% costs one dump-work unit
+handle_dump_next({3,Class,Tables,Stab,Key,Dtab},Count,Admin) ->
+ copy_dump_entry(Stab,Key,Dtab),
+ NextKey = ?ets_next(Stab,Key),
+ handle_dump_next({3,Class,Tables,Stab,NextKey,Dtab},Count-1,Admin).
+
+%%% INTERNAL HELPER FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%% admin_table_name(DbName) -> Name
+%%%
+%%% Returns the name of the admin table of the table DbName
+
+admin_table_name(DbName) ->
+ list_to_atom(lists:append(atom_to_list(DbName),"#admin")).
+
+%%% make_admin_table(DbName) -> EtsAdminTable
+%%%
+%%% Creates and registers an ETS Admin table
+
+make_admin_table(DbName) ->
+ ?ets_new(admin_table_name(DbName),[named_table,protected,db_type(DbName)]).
+
+%%% make_db_table(DbName,Name) -> EtsTable
+%%%
+%%% Creates an ETS database table
+
+make_db_table(DbName, Name) ->
+ ?ets_new(Name,[protected,db_type(DbName)]).
+
+db_name(Admin) ->
+ ets:lookup_element(Admin,?DB_NAME_KEY,2).
+
+db_type(DbName) ->
+ case ets:lookup(?GLOBAL_PARAMS, DbName) of
+ [] ->
+ set;
+ [{DbName,X}] ->
+ X
+ end.
+
+%%% table_lookup(Table,Key) ->
+%%% table_lookup(TableList,Key) ->
+%%% {def,{value,Value}} | {undef,undefined} | (erased,undefined}
+%%%
+%%% Looks up key in the table and returns it value, or undefined
+%%% if there is no such key.
+%%% If a list of tables is given, they are searched one after another
+%%% for a matching key, until one is found. The search is discontinued
+%%% if a record telling that the key was deleted is found.
+
+table_lookup([], _Key) ->
+ {undef,undefined};
+table_lookup([Table|Tables], Key) ->
+ case table_lookup(Table,Key) of
+ {_,undefined} ->
+ case ?ets_lookup(Table,?ERASE_MARK(Key)) of
+ [] ->
+ table_lookup(Tables,Key);
+ _Definition ->
+ %% The element has been deleted, don't look further!
+ %% Pretend we never saw anything..
+ {erased,undefined}
+ end;
+ Answer ->
+ Answer
+ end;
+table_lookup(Table, Key) ->
+ case ?ets_lookup(Table,Key) of
+ [] ->
+ {undef,undefined};
+ [{_Key,Value}] ->
+ {def,{value,Value}}
+ end.
+
+%%% table_lookup_batch(Tables, Class, Cond) -> KeyList
+%%%
+%%% Extract the keys from a table or a table group.
+%%% If a condition is supplied, it is on the form {Mod, Fun, ExtraArgs}
+%%% and returns {true,Key} or false when called using
+%%% apply(Mod, Fun, [Instance|ExtraArgs]).
+%%% Instance is, for historic reasons, {{Class, Key}, Value} when the function
+%%% is called. Cond = 'all' can be used to get all keys from a class.
+
+table_lookup_batch([],_Class,_Cond) ->
+ [];
+table_lookup_batch([Table|Tables],Class,Cond) ->
+ table_lookup_batch([],Tables,Table,ets:first(Table),Class,Cond,[]).
+
+table_lookup_batch(_Passed,[],_,'$end_of_table',_Class,_Cond,Ack) ->
+ Ack;
+table_lookup_batch(Passed,[NewTable|Tables],Table,'$end_of_table',
+ Class,Cond,Ack) ->
+ table_lookup_batch(lists:append(Passed,[Table]),Tables,
+ NewTable,ets:first(NewTable),Class,Cond,Ack);
+table_lookup_batch(Passed,Tables,Table,?ERASE_MARK(Key),Class,Cond,Ack) ->
+ table_lookup_batch(Passed,Tables,Table,?ets_next(Table,?ERASE_MARK(Key)),
+ Class,Cond,Ack);
+
+table_lookup_batch(Passed,Tables,Table,Key,Class,Cond,Ack) ->
+ NewAck =
+ case table_lookup(Passed,Key) of
+ {undef,undefined} ->
+ [{_Key,Value}] = ?ets_lookup(Table,Key),
+ case Cond of % are there any conditions?
+ all ->
+ [Key|Ack];
+ {M, F, A} ->
+ %% apply the condition test.
+ %% Applications need keys to consist of
+ %% {class, primkey}, so we make it that way
+ case apply(M, F, [{{Class, Key}, Value}|A]) of
+ {true, Key} -> [Key|Ack];
+ false -> Ack
+ end
+ end;
+ _Other ->
+ %% Already processed (or erased) key
+ %% {def,{value,Value}} ->
+ %% {erased,undefined} ->
+ Ack
+ end,
+ table_lookup_batch(Passed,Tables,Table,?ets_next(Table,Key),
+ Class,Cond,NewAck).
+
+%%% modify(Application, ClassList, Admin) -> ok.
+%%%
+%%% This function modifies each element of the classes
+
+modify(_Application, [], _Admin) ->
+ ok;
+modify(Application, [Class|Classes], Admin) ->
+ ?DEBUG(io:format("modifying class ~p\n", [Class])),
+ [{_,Tables}] = ?ets_lookup(Admin, Class),
+ modify_class(Application, Class, table_lookup_batch(Tables, Class, all),
+ Admin),
+ modify(Application, Classes, Admin).
+
+modify_class(_Application, _Class, [], _Admin) ->
+ ok;
+modify_class({Mod, Fun, ExtraArgs}, Class, [Key|Keys], Admin) ->
+ {ok, {{value, Value}, _Admin}} = handle_lookup(Class, Key, Admin),
+ %% The applications think that a key consists of {class, primkey},
+ %% so let them.
+ case apply(Mod,Fun,[{{Class, Key}, Value}|ExtraArgs]) of
+ {ok,{{NewClass, NewKey}, NewValue}} -> % The item is modified.
+ %% remove old instance, insert new
+ %% JALI could be optimized (we don't care about previous values),
+ %% but ets_delete/insert is *not* enough
+ handle_delete(Class, Key, Admin),
+ handle_insert(NewClass, NewKey, NewValue, Admin);
+ true -> % The item should be left as it is.
+ ok;
+ false -> % The item should be removed!
+ %% JALI could be optimized (we don't care about previous values),
+ %% but ets_delete is *not* enough
+ handle_delete(Class, Key, Admin)
+ end,
+ modify_class({Mod, Fun, ExtraArgs}, Class, Keys, Admin).
+
+%%% dump_prepare_classes(Classes,Admin) -> ok
+%%%
+%%% Create a Ttab for each class, and insert
+%%% the new table order in Admin
+
+dump_prepare_classes(Classes,Admin) ->
+ ?DEBUG(io:format("DUMP CLASSES ~w\n",[Classes])),
+ dump_prepare_classes(Classes,Admin,[]).
+
+dump_prepare_classes([],_Admin,Ack) ->
+ Ack;
+dump_prepare_classes([Class|Classes],Admin,Ack) ->
+ [{_Class,[Mtab]}] = ?ets_lookup(Admin,Class),
+ %% Only one table => we can prepare for dumping
+ %% In case there are several tables defined, dumping is
+ %% already (still) in progress for this class (database inconsistent)
+ Ttab = make_db_table(db_name(Admin),Class),
+ ?ets_insert(Admin,{Class,[Ttab,Mtab]}),
+ dump_prepare_classes(Classes,Admin,lists:append(Ack,[{Class,Mtab}])).
+
+%%% copy_dump_entry(SourceTable,Key,DestinationTable) -> NobodyCares
+%%%
+%%% Copies Key from SourceTable to DestinationTable.
+%%% If Key is an erase record, then the corresponding entry is deleted
+%%% from DestinationTable, if it should be (see Erasure during dump, above)
+
+copy_dump_entry(Stab,Key,Dtab) ->
+ ?DEBUG(io:format("Copying key ~p\n",[Key])),
+ case ?ets_lookup(Stab,Key) of
+ [{?ERASE_MARK(RealKey),_}] ->
+ %% Only erase if the entry RealKey hasn't been written again
+ case ?ets_lookup(Stab,RealKey) of
+ [] ->
+ %% No, it hasn't: we should delete
+ ?DEBUG(io:format("Erasing: ~p\n",[RealKey])),
+ ?ets_delete(Dtab,RealKey);
+ _Definition ->
+ %% It has, don't erase. In this case the new value
+ %% has already or will soon be written to Dtab
+ ok
+ end;
+ [KeyVal] ->
+ ?DEBUG(io:format("Forwarding: ~p\n",[KeyVal])),
+ ?ets_insert(Dtab,KeyVal)
+ end.
+
+%%% DUMP LOADING %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+load_dump(DbName,DumpDir) ->
+ case phys_load_dump_ok(DumpDir) of
+ ok ->
+ Admin = make_admin_table(DbName),
+ ?ets_insert(Admin,{?DB_NAME_KEY,DbName}),
+ case phys_load_table(DumpDir,0,Admin) of
+ ok ->
+ load_dump2(DumpDir,Admin);
+ Other ->
+ load_dump_failed(Admin,[]),
+ {error,{load_dump1,Other}}
+ end;
+ Other ->
+ {error,{load_dump2,Other}}
+ end.
+
+load_dump2(DumpDir,Admin) ->
+ case ?ets_lookup(Admin,?LIST_OF_CLASSES_KEY) of
+ [{_Key,Classes}] ->
+ case load_dump_tables(DumpDir,Admin,Classes) of
+ ok ->
+ {ok, Admin};
+ Other ->
+ io:format("Dumping failed: ~p\n",[Other]),
+ load_dump_failed(Admin,Classes)
+ end;
+ Other ->
+ io:format("Dumping failed2: ~p\n",[Other]),
+ load_dump_failed(Admin,[])
+ end.
+
+load_dump_failed(Admin,[]) ->
+ ?ets_delete(Admin),
+ {error,load_dump_failed};
+load_dump_failed(Admin,[Class|Classes]) ->
+ case ?ets_lookup(Admin,Class) of
+ [{_Key,[Tab]}] ->
+ ?ets_delete(Tab);
+ _ ->
+ ok
+ end,
+ load_dump_failed(Admin,Classes).
+
+load_dump_tables(_DumpDir,_Admin,[]) ->
+ ok;
+load_dump_tables(DumpDir,Admin,[Class|Classes]) ->
+ Mtab = make_db_table(db_name(Admin),Class),
+ ?ets_insert(Admin,{Class,[Mtab]}),
+ Num = length(Classes)+1,
+ case phys_load_table(DumpDir,Num,Mtab) of
+ ok ->
+ load_dump_tables(DumpDir,Admin,Classes);
+ Other ->
+ {error,{load_dump_failed,Other}}
+ end.
+
+%%% FILE ACCESS LAYER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%% phys_init_dump(Class,DumpDir) -> DumpData
+
+phys_init_dump(Class,DumpDir,Num) ->
+ ?DEBUG(io:format("Opened ~p for writing\n",[Class])),
+ FileName = [DumpDir,"/etsdump.",integer_to_list(Num)],
+ {tag1,{ok,Fd}} = {tag1,file:open(FileName,write)},
+ {Class,Fd}.
+
+%%% phys_finish_dump(DumpData) -> NobodyCares
+
+phys_finish_dump({_Class,Fd}) ->
+ ?DEBUG(io:format("Closed ~p\n",[_Class])),
+ phys_dump_term(Fd,ok),
+ file:close(Fd), % JALI: OTP P1D returns true instead of ok, so no check
+ ok.
+
+%%% phys_dump(KeyVal,DumpData) -> NobodyCares
+
+phys_dump({Key,Val},{_Class,Fd}) ->
+ ?DEBUG(io:format("To disk (~p.dump): {~p,~p}\n",[_Class,Key,Val])),
+ phys_dump_term(Fd,{Key,Val}),
+ ok.
+
+phys_dump_term(Fd,Term) ->
+ Bin = binary_to_list(term_to_binary(Term)),
+ {tag2,ok} = {tag2,io:put_chars(Fd,encode32(length(Bin)))},
+ {tag3,ok} = {tag3,io:put_chars(Fd,Bin)}.
+
+%%% phys_ok_dump(DumpDir) -> NobodyCares
+
+phys_ok_dump(DumpDir) ->
+ ?DEBUG(io:format("Ok:ing dump dir ~s\n",[DumpDir])),
+ FileName = [DumpDir,"/ok"],
+ {tag4,{ok,Fd}} = {tag4,file:open(FileName,write)},
+ {tag5,ok} = {tag5,io:format(Fd,"ok.\n",[])},
+ file:close(Fd), % JALI: OTP P1D returns true instead of ok, so no check
+ ok.
+
+phys_remove_ok(DumpDir) ->
+ ?DEBUG(io:format("Removing any Ok in dump dir ~s\n",[DumpDir])),
+ FileName = [DumpDir,"/ok"],
+ %% don't care if delete returns ok, file probably doesn't exist
+ file:delete(FileName),
+ ok.
+
+phys_load_dump_ok(DumpDir) ->
+ FileName = [DumpDir,"/ok"],
+ case file:consult(FileName) of
+ {ok,[ok]} ->
+ ok;
+ Other ->
+ {error,{consult_error,Other}}
+ end.
+
+phys_load_table(DumpDir,N,Tab) ->
+ ?DEBUG(io:format("LOAD TABLE ~w\n",[N])),
+ FileName = [DumpDir,"/etsdump.",integer_to_list(N)],
+ case file:open(FileName,read) of
+ {ok,Fd} ->
+ phys_load_entries(Fd,Tab);
+ Other ->
+ {error,{open_error,Other}}
+ end.
+
+phys_load_entries(Fd,Tab) ->
+ case phys_read_len(Fd) of
+ {ok,Len} ->
+ case phys_read_entry(Fd,Len) of
+ {ok,ok} ->
+ ok;
+ {ok,{Key,Val}} ->
+ ?ets_insert(Tab,{Key,Val}),
+ phys_load_entries(Fd,Tab);
+ Other ->
+ {error,{read_len,Other}}
+ end;
+ Other ->
+ {error,{read_len2,Other}}
+ end.
+
+phys_read_len(Fd) ->
+ case io:get_chars(Fd,'',4) of
+ [A,B,C,D] ->
+ {ok,decode32(A,B,C,D)};
+ Other ->
+ {error,{decode,Other}}
+ end.
+
+phys_read_entry(Fd,Len) ->
+ case io:get_chars(Fd,'',Len) of
+ L when list(L), length(L) == Len ->
+ {ok,binary_to_term(list_to_binary(L))};
+ Other ->
+ {error,{read_term,Other}}
+ end.
+
+encode32(N) ->
+ [(N bsr 24) band 255,
+ (N bsr 16) band 255,
+ (N bsr 8) band 255,
+ N band 255].
+
+decode32(A,B,C,D) ->
+ (A bsl 24) bor (B bsl 16) bor (C bsl 8) bor D.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/stdlib/test/file_sorter_SUITE.erl b/lib/stdlib/test/file_sorter_SUITE.erl
new file mode 100644
index 0000000000..c00ed91fe7
--- /dev/null
+++ b/lib/stdlib/test/file_sorter_SUITE.erl
@@ -0,0 +1,1345 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(file_sorter_SUITE).
+
+%-define(debug, true).
+
+-ifdef(debug).
+-define(format(S, A), io:format(S, A)).
+-define(line, put(line, ?LINE), ).
+-define(config(X,Y), foo).
+-define(t,test_server).
+-define(privdir(_), "./file_sorter_SUITE_priv").
+-else.
+-include("test_server.hrl").
+-define(format(S, A), ok).
+-define(privdir(Conf), ?config(priv_dir, Conf)).
+-endif.
+
+-export([all/1, basic/1, badarg/1,
+ term_sort/1, term_keysort/1,
+ binary_term_sort/1, binary_term_keysort/1,
+ binary_sort/1,
+ term_merge/1, term_keymerge/1,
+ binary_term_merge/1, binary_term_keymerge/1,
+ binary_merge/1,
+ term_check/1, term_keycheck/1,
+ binary_term_check/1, binary_term_keycheck/1,
+ binary_check/1,
+ inout/1, misc/1, many/1]).
+
+-export([init_per_testcase/2, fin_per_testcase/2]).
+
+init_per_testcase(_Case, Config) ->
+ Dog=?t:timetrap(?t:minutes(2)),
+ [{watchdog, Dog}|Config].
+
+fin_per_testcase(_Case, Config) ->
+ Dog=?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+all(suite) ->
+ {req,[stdlib,kernel],
+ [basic, badarg,
+ term_sort, term_keysort,
+ binary_term_sort, binary_term_keysort,
+ binary_sort,
+ term_merge, term_keymerge,
+ binary_term_merge, binary_term_keymerge,
+ binary_merge,
+ term_check, binary_term_keycheck,
+ binary_term_check, binary_term_keycheck,
+ binary_check,
+ inout, misc, many]}.
+
+basic(doc) ->
+ ["Basic test case."];
+basic(suite) ->
+ [];
+basic(Config) when is_list(Config) ->
+ Fmt = binary,
+ Arg = {format,Fmt},
+ Foo = outfile(foo, Config),
+ P0 = pps(),
+
+ ?line F1s = [F1] = to_files([[]], Fmt, Config),
+ ?line ok = file_sorter:sort(F1),
+ ?line [] = from_files(F1, Fmt),
+ ?line ok = file_sorter:keysort(17, F1),
+ ?line [] = from_files(F1, Fmt),
+ ?line ok = file_sorter:merge(F1s, Foo),
+ ?line [] = from_files(Foo, Fmt),
+ ?line delete_files(Foo),
+ ?line ok = file_sorter:keymerge(17, F1s, Foo),
+ ?line [] = from_files(Foo, Fmt),
+ ?line delete_files([Foo | F1s]),
+
+ ?line [F2] = to_files([[foo,bar]], Fmt, Config),
+ ?line ok = file_sorter:sort([F2], F2, Arg),
+ ?line [bar,foo] = from_files(F2, Fmt),
+ ?line delete_files(F2),
+
+ ?line Fs1 = to_files([[foo],[bar]], Fmt, Config),
+ ?line ok = file_sorter:sort(Fs1, Foo, Arg),
+ ?line [bar,foo] = from_files(Foo, Fmt),
+ ?line delete_files(Foo),
+ ?line ok = file_sorter:merge(Fs1, Foo, Arg),
+ ?line [bar,foo] = from_files(Foo, Fmt),
+ ?line delete_files([Foo | Fs1]),
+
+ ?line Fmt2 = binary_term,
+ ?line Arg2 = {format, Fmt2},
+ ?line [F3] = to_files([[{foo,1},{bar,2}]], Fmt2, Config),
+ ?line ok = file_sorter:keysort([2], [F3], F3, Arg2),
+ ?line [{foo,1},{bar,2}] = from_files(F3, Fmt2),
+ ?line delete_files(F3),
+
+ ?line Fs2 = to_files([[{foo,1}],[{bar,2}]], Fmt2, Config),
+ ?line ok = file_sorter:keysort(1, Fs2, Foo, Arg2),
+ ?line [{bar,2},{foo,1}] = from_files(Foo, Fmt2),
+ ?line delete_files(Foo),
+ ?line ok = file_sorter:keymerge(1, Fs2, Foo, Arg2),
+ ?line [{bar,2},{foo,1}] = from_files(Foo, Fmt2),
+ ?line delete_files([Foo | Fs2]),
+
+ ?line true = P0 =:= pps(),
+
+ ok.
+
+badarg(doc) ->
+ ["Call functions with bad arguments."];
+badarg(suite) ->
+ [];
+badarg(Config) when is_list(Config) ->
+ PrivDir = ?privdir(Config),
+ BadFile = filename:join(PrivDir, "not_a_file"),
+ ABadFile = filename:absname(BadFile),
+ ?line file:delete(BadFile),
+ ?line {error,{file_error,ABadFile,enoent}} =
+ file_sorter:sort(BadFile),
+ ?line {'EXIT', {{badarg, {flipp}}, _}} =
+ (catch file_sorter:sort({flipp})),
+ ?line {error,{file_error,ABadFile,enoent}} =
+ file_sorter:keysort(1, BadFile),
+ ?line {'EXIT', {{badarg, {flipp}}, _}} =
+ (catch file_sorter:keysort(1, {flipp})),
+
+ ?line {'EXIT', {{badarg, {flipp}}, _}} =
+ (catch file_sorter:merge([{flipp}],foo)),
+ ?line {error,{file_error,ABadFile,enoent}} =
+ file_sorter:keymerge(1,[BadFile],foo),
+ ?line {'EXIT', {{badarg, {flipp}}, _}} =
+ (catch file_sorter:keymerge(1,[{flipp}],foo)),
+ ?line {'EXIT', {{badarg, _}, _}} =
+ (catch file_sorter:merge(fun(X) -> X end, foo)),
+ ?line {'EXIT', {{badarg, _}, _}} =
+ (catch file_sorter:keymerge(1, fun(X) -> X end, foo)),
+
+ ?line {error,{file_error,ABadFile,enoent}} =
+ file_sorter:check(BadFile),
+ ?line {'EXIT', {{badarg, {flipp}}, _}} =
+ (catch file_sorter:check({flipp})),
+ ?line {error,{file_error,ABadFile,enoent}} =
+ file_sorter:keycheck(1, BadFile),
+ ?line {'EXIT', {{badarg, {flipp}}, _}} =
+ (catch file_sorter:keycheck(1, {flipp})),
+ ?line {'EXIT', {{badarg, {flipp}}, _}} =
+ (catch file_sorter:check([{flipp}],foo)),
+ ?line {'EXIT', {{badarg, {flipp}}, _}} =
+ (catch file_sorter:keycheck(1,[{flipp}],foo)),
+ ?line {'EXIT', {{badarg, _}, _}} =
+ (catch file_sorter:check(fun(X) -> X end, foo)),
+ ?line {'EXIT', {{badarg, _}, _}} =
+ (catch file_sorter:keycheck(1, fun(X) -> X end, foo)),
+
+ ?line Fs1 = to_files([[1,2,3]], binary_term, Config),
+ ?line {'EXIT', {{badarg, flipp}, _}} =
+ (catch file_sorter:check(Fs1 ++ flipp, [])),
+ [F1] = Fs1,
+ ?line {error,{file_error,_,_}} =
+ file_sorter:sort(Fs1, foo, [{tmpdir,F1},{size,0}]),
+ ?line delete_files(Fs1),
+ ?line Fs2 = to_files([[1,2,3]], binary_term, Config),
+ {error,{file_error,_,enoent}} =
+ file_sorter:sort(Fs2, foo, [{tmpdir,filename:absname(BadFile)},
+ {size,0}]),
+ ?line delete_files(Fs2),
+
+ ?line {'EXIT', {{badarg, bad}, _}} =
+ (catch file_sorter:check([], [{format,term} | bad])),
+ ?line {'EXIT', {{badarg, [{flipp}]}, _}} =
+ (catch file_sorter:check([{flipp}])),
+ ?line {'EXIT', {{badarg, {flipp}}, _}} =
+ (catch file_sorter:keycheck(1, {flipp})),
+ ?line {'EXIT', {{badarg, [{flipp}]}, _}} =
+ (catch file_sorter:keycheck(2, [{flipp}])),
+ ?line {error,{file_error,_,eisdir}} = file_sorter:keycheck(1, []),
+ ?line {'EXIT', {{badarg, kp}, _}} = (catch file_sorter:keycheck(kp, [])),
+ ?line {'EXIT', {{badarg, kp}, _}} =
+ (catch file_sorter:keycheck([1, kp], [])),
+ ?line {'EXIT', {{badarg, kp}, _}} =
+ (catch file_sorter:keycheck([1 | kp], [])),
+ ?line {'EXIT', {{badarg, []}, _}} = (catch file_sorter:keycheck([], [])),
+ ?line {'EXIT', {{badarg, {format, foo}}, _}} =
+ (catch file_sorter:check([], {format,foo})),
+ ?line {'EXIT', {{badarg, not_an_option}, _}} =
+ (catch file_sorter:keycheck(7, [], [not_an_option])),
+ ?line {'EXIT', {{badarg, format}, _}} =
+ (catch file_sorter:keycheck(1, [], [{format, binary}])),
+ ?line {'EXIT', {{badarg, order}, _}} =
+ (catch file_sorter:keycheck(1, [], [{order, fun compare/2}])),
+
+ ?line do_badarg(fun(I, O) -> file_sorter:sort(I, O) end,
+ fun(Kp, I, O) -> file_sorter:keysort(Kp, I, O) end,
+ BadFile),
+ ?line do_badarg_opt(fun(I, O, X) -> file_sorter:sort(I, O, X) end,
+ fun(Kp, I, O, X) -> file_sorter:keysort(Kp, I, O, X)
+ end),
+ ?line do_badarg(fun(I, O) -> file_sorter:merge(I, O) end,
+ fun(Kp, I, O) -> file_sorter:keymerge(Kp, I, O) end,
+ BadFile),
+ ?line do_badarg_opt(fun(I, O, X) -> file_sorter:merge(I, O, X) end,
+ fun(Kp, I, O, X) -> file_sorter:keymerge(Kp, I, O, X)
+ end).
+
+do_badarg(F, KF, BadFile) ->
+ [Char | _] = BadFile,
+ AFlipp = filename:absname(flipp),
+ ?line {error,{file_error,AFlipp,enoent}} = F([flipp | flopp], foo),
+ ?line {'EXIT', {{badarg, {foo,bar}}, _}} = (catch F([], {foo,bar})),
+ ?line {'EXIT', {{badarg, Char}, _}} = (catch F(BadFile, [])),
+ ?line {'EXIT', {{badarg, {flipp}}, _}} = (catch F({flipp}, [])),
+
+ ?line {'EXIT', {{badarg, Char}, _}} = (catch KF(1, BadFile, [])),
+ ?line {'EXIT', {{badarg, {flipp}}, _}} = (catch KF(1, {flipp}, [])),
+ ?line {error,{file_error,AFlipp,enoent}} =
+ KF(2, [flipp | flopp], foo),
+ ?line {'EXIT', {{badarg, {foo,bar}}, _}} = (catch KF(1, [], {foo,bar})),
+ ?line {'EXIT', {{badarg, kp}, _}} = (catch KF(kp, [], foo)),
+ ?line {'EXIT', {{badarg, kp}, _}} = (catch KF([1, kp], [], foo)),
+ ?line {'EXIT', {{badarg, kp}, _}} = (catch KF([1 | kp], [], foo)),
+ ?line {'EXIT', {{badarg, []}, _}} = (catch KF([], [], foo)),
+ ok.
+
+do_badarg_opt(F, KF) ->
+ AFlipp = filename:absname(flipp),
+ ?line {error,{file_error,AFlipp,enoent}} =
+ F([flipp | flopp], foo, []),
+ ?line {'EXIT', {{badarg, {flipp}}, _}} = (catch F([{flipp}], foo, [])),
+ ?line {'EXIT', {{badarg, {out,put}}, _}} = (catch F([], {out,put}, [])),
+ ?line {'EXIT', {{badarg, not_an_option}, _}} =
+ (catch F([], foo, [not_an_option])),
+ ?line {'EXIT', {{badarg, {format, foo}}, _}} =
+ (catch F([], foo, {format,foo})),
+ ?line {'EXIT', {{badarg, {size,foo}}, _}} = (catch F([], foo, {size,foo})),
+
+ ?line {'EXIT', {{badarg, {size, -1}}, _}} = (catch F([], foo, {size,-1})),
+ ?line {'EXIT', {{badarg, {no_files, foo}}, _}} =
+ (catch F([], foo, {no_files,foo})),
+ ?line {'EXIT', {{badarg, {no_files, 1}}, _}} =
+ (catch F([], foo, {no_files,1})),
+ ?line {'EXIT', {{badarg, 1}, _}} = (catch F([], foo, {tmpdir,1})),
+ ?line {'EXIT', {{badarg, {order,1}}, _}} = (catch F([], foo, {order,1})),
+ ?line {'EXIT', {{badarg, {compressed, flopp}}, _}} =
+ (catch F([], foo, {compressed,flopp})),
+ ?line {'EXIT', {{badarg, {unique,flopp}}, _}} =
+ (catch F([], foo, {unique,flopp})),
+ ?line {'EXIT', {{badarg, {header,foo}}, _}} =
+ (catch F([], foo, {header,foo})),
+ ?line {'EXIT', {{badarg, {header, 0}}, _}} =
+ (catch F([], foo, {header,0})),
+ ?line {'EXIT', {{badarg, {header, 1 bsl 35}}, _}} =
+ (catch F([], foo, {header,1 bsl 35})),
+ ?line {'EXIT', {{badarg, header}, _}} =
+ (catch F([], foo, [{header,1},{format,term}])),
+
+ ?line {'EXIT', {{badarg, not_an_option}, _}} =
+ (catch KF(7, [], foo, [not_an_option])),
+ ?line {'EXIT', {{badarg,format}, _}} =
+ (catch KF(1, [], foo, [{format, binary}])),
+ ?line {'EXIT', {{badarg, order}, _}} =
+ (catch KF(1, [], foo, [{order, fun compare/2}])),
+ ?line {'EXIT', {{badarg, {flipp}}, _}} =
+ (catch KF(2, [{flipp}], foo,[])),
+ ?line {error,{file_error,AFlipp,enoent}} =
+ KF(2, [flipp | flopp], foo,[]),
+ ?line {'EXIT', {{badarg, {out, put}}, _}} =
+ (catch KF(1, [], {out,put}, [])),
+ ?line {'EXIT', {{badarg, kp}, _}} = (catch KF(kp, [], foo, [])),
+ ?line {'EXIT', {{badarg, kp}, _}} = (catch KF([1, kp], [], foo, [])),
+ ?line {'EXIT', {{badarg, kp}, _}} = (catch KF([1 | kp], [], foo, [])),
+ ok.
+
+term_sort(doc) ->
+ ["Sort terms on files."];
+term_sort(suite) ->
+ [];
+term_sort(Config) when is_list(Config) ->
+ ?line sort(term, [{compressed,false}], Config),
+ ?line sort(term, [{order, fun compare/2}], Config),
+ ?line sort(term, [{order, ascending}, {compressed,true}], Config),
+ ?line sort(term, [{order, descending}], Config),
+ ok.
+
+term_keysort(doc) ->
+ ["Keysort terms on files."];
+term_keysort(suite) ->
+ [];
+term_keysort(Config) when is_list(Config) ->
+ ?line keysort(term, [{tmpdir, ""}], Config),
+ ?line keysort(term, [{order,descending}], Config),
+ ok.
+
+binary_term_sort(doc) ->
+ ["Sort binary terms on files."];
+binary_term_sort(suite) ->
+ [];
+binary_term_sort(Config) when is_list(Config) ->
+ PrivDir = ?privdir(Config),
+ ?line sort({2, binary_term}, [], Config),
+ ?line sort(binary_term, [{tmpdir, list_to_atom(PrivDir)}], Config),
+ ?line sort(binary_term, [{tmpdir,PrivDir}], Config),
+ ?line sort({3,binary_term}, [{order, fun compare/2}], Config),
+ ?line sort(binary_term, [{order, fun compare/2}], Config),
+ ?line sort(binary_term, [{order,descending}], Config),
+ ok.
+
+binary_term_keysort(doc) ->
+ ["Keysort binary terms on files."];
+binary_term_keysort(suite) ->
+ [];
+binary_term_keysort(Config) when is_list(Config) ->
+ ?line keysort({3, binary_term}, [], Config),
+ ?line keysort(binary_term, [], Config),
+ ?line keysort(binary_term, [{order,descending}], Config),
+ ok.
+
+binary_sort(doc) ->
+ ["Sort binaries on files."];
+binary_sort(suite) ->
+ [];
+binary_sort(Config) when is_list(Config) ->
+ PrivDir = ?privdir(Config),
+ ?line sort({2, binary}, [], Config),
+ ?line sort(binary, [{tmpdir, list_to_atom(PrivDir)}], Config),
+ ?line sort(binary, [{tmpdir,PrivDir}], Config),
+ ?line sort({3,binary}, [{order, fun compare/2}], Config),
+ ?line sort(binary, [{order, fun compare/2}], Config),
+ ?line sort(binary, [{order,descending}], Config),
+ ok.
+
+term_merge(doc) ->
+ ["Merge terms on files."];
+term_merge(suite) ->
+ [];
+term_merge(Config) when is_list(Config) ->
+ ?line merge(term, [{order, fun compare/2}], Config),
+ ?line merge(term, [{order, ascending}, {compressed,true}], Config),
+ ?line merge(term, [{order, descending}, {compressed,false}], Config),
+ ok.
+
+term_keymerge(doc) ->
+ ["Keymerge terms on files."];
+term_keymerge(suite) ->
+ [];
+term_keymerge(Config) when is_list(Config) ->
+ ?line keymerge(term, [], Config),
+ ?line keymerge(term, [{order, descending}], Config),
+ ?line funmerge(term, [], Config),
+ ok.
+
+binary_term_merge(doc) ->
+ ["Merge binary terms on files."];
+binary_term_merge(suite) ->
+ [];
+binary_term_merge(Config) when is_list(Config) ->
+ ?line merge(binary_term, [], Config),
+ ?line merge({7, binary_term}, [], Config),
+ ?line merge({3, binary_term}, [{order, fun compare/2}], Config),
+ ok.
+
+binary_term_keymerge(doc) ->
+ ["Keymerge binary terms on files."];
+binary_term_keymerge(suite) ->
+ [];
+binary_term_keymerge(Config) when is_list(Config) ->
+ ?line keymerge({3, binary_term}, [], Config),
+ ?line keymerge(binary_term, [], Config),
+ ?line funmerge({3, binary_term}, [], Config),
+ ?line funmerge(binary_term, [], Config),
+ ok.
+
+binary_merge(doc) ->
+ ["Merge binaries on files."];
+binary_merge(suite) ->
+ [];
+binary_merge(Config) when is_list(Config) ->
+ ?line merge(binary, [], Config),
+ ?line merge({7, binary}, [], Config),
+ ?line merge({3, binary}, [{order, fun compare/2}], Config),
+ ok.
+
+term_check(doc) ->
+ ["Check terms on files."];
+term_check(suite) ->
+ [];
+term_check(Config) when is_list(Config) ->
+ ?line check(term, Config),
+ ok.
+
+binary_term_check(doc) ->
+ ["Check binary terms on files."];
+binary_term_check(suite) ->
+ [];
+binary_term_check(Config) when is_list(Config) ->
+ ?line check(binary_term, Config),
+ ok.
+
+term_keycheck(doc) ->
+ ["Keycheck terms on files."];
+term_keycheck(suite) ->
+ [];
+term_keycheck(Config) when is_list(Config) ->
+ ?line keycheck(term, Config),
+ ok.
+
+binary_term_keycheck(doc) ->
+ ["Keycheck binary terms on files."];
+binary_term_keycheck(suite) ->
+ [];
+binary_term_keycheck(Config) when is_list(Config) ->
+ ?line keycheck(binary_term, Config),
+ ok.
+
+binary_check(doc) ->
+ ["Check binary terms on files."];
+binary_check(suite) ->
+ [];
+binary_check(Config) when is_list(Config) ->
+ ?line check(binary, Config),
+ ok.
+
+inout(doc) ->
+ ["Funs as input or output."];
+inout(suite) ->
+ [];
+inout(Config) when is_list(Config) ->
+ BTF = {format, binary_term},
+ Foo = outfile(foo, Config),
+
+ %% Input is fun.
+ End = fun(read) -> end_of_input end,
+
+ IF1 = fun(read) -> {[1,7,5], End} end,
+ ?line ok = file_sorter:sort(IF1, Foo, [{format, term}]),
+ %% 'close' is called, but the return value is caught and ignored.
+ IF2 = fun(read) -> {[1,2,3], fun(close) -> throw(ignored) end} end,
+ ?line {error, bad_object} = file_sorter:sort(IF2, Foo, BTF),
+
+ IF3 = fun(no_match) -> foo end,
+ ?line {'EXIT', {function_clause, _}} =
+ (catch file_sorter:sort(IF3, Foo)),
+ IF4 = fun(read) -> throw(my_message) end,
+ ?line my_message = (catch file_sorter:sort(IF4, Foo)),
+ IF5 = fun(read) -> {error, my_error} end,
+ ?line {error, my_error} = file_sorter:sort(IF5, Foo),
+
+ %% Output is fun.
+ ?line {error, bad_object} =
+ file_sorter:sort(IF2, fun(close) -> ignored end, BTF),
+ Args = [{format, term}],
+ ?line {error, bad_object} =
+ file_sorter:keysort(1, IF2, fun(close) -> ignored end, Args),
+ OF1 = fun(close) -> fine; (L) when is_list(L) -> fun(close) -> nice end end,
+ ?line nice = file_sorter:sort(IF1, OF1, Args),
+ OF2 = fun(_) -> my_return end,
+ ?line my_return = file_sorter:sort(IF1, OF2, Args),
+ OF3 = fun(_) -> throw(my_message) end,
+ ?line my_message = (catch file_sorter:sort(IF1, OF3, Args)),
+ OF4 = fun(no_match) -> foo end,
+ ?line {'EXIT', {function_clause, _}} =
+ (catch file_sorter:sort(IF1, OF4, Args)),
+
+ ?line P0 = pps(),
+ ?line Fs1 = to_files([[3,1,2,5,4], [8,3,10]], term, Config),
+ ?line error = file_sorter:sort(Fs1, fun(_) -> error end, Args),
+ ?line delete_files(Fs1),
+
+ ?line true = P0 =:= pps(),
+
+ %% Passing a value from the input functions to the output functions.
+ IFV1 = fun(read) -> {end_of_input, 17} end,
+ OFV1 = fun({value, Value}) -> ofv(Value, []) end,
+ ?line {17, []} = file_sorter:sort(IFV1, OFV1, Args),
+
+ %% Output is not a fun. The value returned by input funs is ignored.
+ %% OTP-5009.
+ ?line ok = file_sorter:sort(IFV1, Foo, [{format,term}]),
+ ?line [] = from_files(Foo, term),
+ ?line delete_files(Foo),
+
+ ok.
+
+ofv(Value, A) ->
+ fun(close) ->
+ {Value, lists:append(lists:reverse(A))};
+ (L) when is_list(L) ->
+ ofv(Value, [L | A])
+ end.
+
+many(doc) ->
+ ["Many temporary files."];
+many(suite) ->
+ [];
+many(Config) when is_list(Config) ->
+ Foo = outfile(foo, Config),
+ PrivDir = ?privdir(Config),
+ P0 = pps(),
+
+ Args = [{format, term}],
+ L1 = lists:map(fun(I) -> {one, two, three, I} end, lists:seq(1,1000)),
+ L2 = lists:map(fun(I) -> {four, five, six, I} end, lists:seq(1,1000)),
+ ?line Fs2 = to_files([L1, L2], term, Config),
+ ?line ok = file_sorter:sort(Fs2, Foo, [{size,1000} | Args]),
+ ?line R = lists:sort(L1++L2),
+ ?line R = from_files(Foo, term),
+ ?line 2000 = length(R),
+ ?line ok = file_sorter:sort(Fs2, Foo, [{no_files,4},{size,1000} | Args]),
+ ?line R = from_files(Foo, term),
+ ?line ok =
+ file_sorter:sort(Fs2, Foo,
+ [{no_files,4},{size,1000},{order,descending} | Args]),
+ ?line true = lists:reverse(R) =:= from_files(Foo, term),
+ ?line ok =
+ file_sorter:sort(Fs2, Foo,
+ [{no_files,4},{size,1000},
+ {order,fun compare/2} | Args]),
+ ?line R = from_files(Foo, term),
+ ?line ok = file_sorter:keysort(4, Fs2, Foo,
+ [{no_files,4},{size,1000} | Args]),
+ ?line RK = lists:keysort(4, L1++L2),
+ ?line RK = from_files(Foo, term),
+ ?line delete_files(Foo),
+ ?line ok =
+ file_sorter:keysort(4, Fs2, Foo,
+ [{no_files,4},{size,1000},{order,descending} | Args]),
+ ?line true = lists:reverse(RK) =:= from_files(Foo, term),
+ ?line delete_files(Foo),
+ ?line ok = file_sorter:keysort(4, Fs2, Foo,
+ [{size,500},{order,descending} | Args]),
+ ?line true = lists:reverse(RK) =:= from_files(Foo, term),
+ ?line delete_files(Foo),
+ ?line error = file_sorter:sort(Fs2, fun(_) -> error end,
+ [{tmpdir, PrivDir}, {no_files,3},
+ {size,10000} | Args]),
+
+ TmpDir = filename:join(PrivDir, "tmpdir"),
+ file:del_dir(TmpDir),
+ ?line ok = file:make_dir(TmpDir),
+ ?line case os:type() of
+ {unix, _} ->
+ ?line ok = file:change_mode(TmpDir, 8#0000),
+ ?line {error, {file_error, _,_}} =
+ file_sorter:sort(Fs2, fun(_M) -> foo end,
+ [{no_files,3},{size,10000},
+ {tmpdir,TmpDir} | Args]);
+ _ ->
+ true
+ end,
+ ?line ok = file:del_dir(TmpDir),
+ delete_files(Fs2),
+ ?line true = P0 =:= pps(),
+ ok.
+
+misc(doc) ->
+ ["Some other tests."];
+misc(suite) ->
+ [];
+misc(Config) when is_list(Config) ->
+ BTF = {format, binary_term},
+ Foo = outfile(foo, Config),
+ FFoo = filename:absname(Foo),
+ P0 = pps(),
+
+ ?line [File] = Fs1 = to_files([[1,3,2]], term, Config),
+ ?line ok = file:write_file(Foo,<<>>),
+ ?line case os:type() of
+ {unix, _} ->
+ ok = file:change_mode(Foo, 8#0000),
+ {error,{file_error,FFoo,eacces}} =
+ file_sorter:sort(Fs1, Foo, {format,term});
+ _ ->
+ true
+ end,
+ ?line file:delete(Foo),
+ ?line NoBytes = 16, % RAM memory will never get this big, or?
+ ?line ALot = (1 bsl (NoBytes*8)) - 1,
+ ?line ok = file:write_file(File, <<ALot:NoBytes/unit:8,"foobar">>),
+ FFile = filename:absname(File),
+ ?line {error, {bad_object,FFile}} =
+ file_sorter:sort(Fs1, Foo, [BTF, {header, 20}]),
+ ?line ok = file:write_file(File, <<30:32,"foobar">>),
+ ?line {error, {premature_eof, FFile}} = file_sorter:sort(Fs1, Foo, BTF),
+ ?line ok = file:write_file(File, <<6:32,"foobar">>),
+ ?line {error, {bad_object,FFile}} = file_sorter:sort(Fs1, Foo, BTF),
+ ?line case os:type() of
+ {unix, _} ->
+ ok = file:change_mode(File, 8#0000),
+ {error, {file_error,FFile,eacces}} =
+ file_sorter:sort(Fs1, Foo),
+ {error, {file_error,FFile,eacces}} =
+ file_sorter:sort(Fs1, Foo, {format, binary_term});
+ _ ->
+ true
+ end,
+ ?line delete_files(Fs1),
+ ?line true = P0 =:= pps(),
+
+ %% bigger than chunksize
+ ?line E1 = <<32000:32, 10:256000>>,
+ ?line E2 = <<32000:32, 5:256000>>,
+ ?line E3 = <<32000:32, 8:256000>>,
+ ?line ok = file:write_file(Foo, [E1, E2, E3]),
+ ?line ok = file_sorter:sort([Foo], Foo, [{format,binary},{size,10000}]),
+ ?line ok = file_sorter:sort([Foo], Foo, [{format,fun(X) -> X end},
+ {size,10000}]),
+ ?line Es = list_to_binary([E2,E3,E1]),
+ ?line {ok, Es} = file:read_file(Foo),
+ ?line delete_files(Foo),
+ ?line true = P0 =:= pps(),
+
+ %% keysort more than one element
+ L = [{c,1,a},{c,2,b},{c,3,c},{b,1,c},{b,2,b},{b,3,a},{a,1,a},{a,2,b},
+ {a,3,c}],
+ ?line Fs2 = to_files([L], binary_term, Config),
+ ?line ok = file_sorter:keysort([2,3], Fs2, Foo, {format, binary_term}),
+ ?line KS2_1 = from_files(Foo, binary_term),
+ ?line KS2_2 = lists:keysort(2,lists:keysort(3, L)),
+ ?line KS2_1 = KS2_2,
+ ?line ok = file_sorter:keysort([2,3], Fs2, Foo,
+ [{format, binary_term},{size,5}]),
+ ?line KS2_3 = from_files(Foo, binary_term),
+ ?line KS2_3 = KS2_2,
+ ?line ok = file_sorter:keysort([2,3,1], Fs2, Foo, {format, binary_term}),
+ ?line KS3_1 = from_files(Foo, binary_term),
+ ?line KS3_2 = lists:keysort(2, lists:keysort(3,lists:keysort(1, L))),
+ ?line KS3_1 = KS3_2,
+ ?line ok = file_sorter:keysort([2,3,1], Fs2, Foo,
+ [{format, binary_term},{size,5}]),
+ ?line KS3_3 = from_files(Foo, binary_term),
+ ?line KS3_3 = KS3_2,
+ ?line delete_files([Foo | Fs2]),
+ ?line true = P0 =:= pps(),
+
+ %% bigger than chunksize
+ %% Assumes that CHUNKSIZE = 16384. Illustrates that the Last argument
+ %% of merge_files/5 is necessary.
+ ?line EP1 = erlang:make_tuple(2728,foo),
+ ?line EP2 = lists:duplicate(2729,qqq),
+ ?line LL = [EP1, EP2, EP1, EP2, EP1, EP2],
+ ?line Fs3 = to_files([LL], binary, Config),
+ ?line ok = file_sorter:sort(Fs3, Foo, [{format,binary}, {unique,true}]),
+ ?line [EP1,EP2] = from_files(Foo, binary),
+ ?line delete_files(Foo),
+ ?line ok = file_sorter:sort(Fs3, Foo,
+ [{format,binary_term}, {unique,true},
+ {size,30000}]),
+ ?line [EP1,EP2] = from_files(Foo, binary_term),
+ ?line delete_files([Foo | Fs3]),
+
+ ?line true = P0 =:= pps(),
+
+ ?line BE1 = <<20000:32, 17:160000>>,
+ ?line BE2 = <<20000:32, 1717:160000>>,
+ ?line ok = file:write_file(Foo, [BE1,BE2,BE1,BE2]),
+ ?line ok = file_sorter:sort([Foo], Foo, [{format,binary},
+ {size,10000},
+ {unique,true}]),
+ ?line BEs = list_to_binary([BE1, BE2]),
+ ?line {ok, BEs} = file:read_file(Foo),
+ ?line delete_files(Foo),
+ ?line true = P0 =:= pps(),
+
+ ?line Fs4 = to_files([[7,4,1]], binary_term, Config),
+ ?line {error, {bad_term, _}} = file_sorter:sort(Fs4, Foo, {format, term}),
+ ?line delete_files([Foo | Fs4]),
+ ?line true = P0 =:= pps(),
+
+ ok.
+
+%%%
+%%% Utilities.
+%%%
+
+sort(Fmt, XArgs, Config) ->
+ Args = make_args(Fmt, [{size,5} | XArgs]),
+ TmpArgs = [{tmpdir,?privdir(Config)} | Args],
+ Foo = outfile(foo, Config),
+
+ %% Input is a fun. Output is a fun.
+ ?line [] = file_sorter:sort(input([], 2, Fmt), output([], Fmt), Args),
+ ?line L1 = [3,1,2,5,4],
+ ?line S1 = file_sorter:sort(input(L1, 2, Fmt), output([], Fmt), TmpArgs),
+ ?line S1 = rev(lists:sort(L1), TmpArgs),
+
+ %% Input is a file. Output is a fun.
+ ?line [] = file_sorter:sort([], output([], Fmt), Args),
+ ?line L2 = [3,1,2,5,4],
+ ?line Fs1 = to_files([L2], Fmt, Config),
+ ?line S2 = file_sorter:sort(Fs1, output([], Fmt), TmpArgs),
+ ?line S2 = rev(lists:sort(L2), TmpArgs),
+ ?line delete_files(Fs1),
+
+ %% Input is a file. Output is a file
+ ?line ok = file_sorter:sort([], Foo, Args),
+ ?line [] = from_files(Foo, Fmt),
+ ?line delete_files(Foo),
+ ?line ok = file_sorter:sort([], Foo, [{unique,true} | Args]),
+ ?line [] = from_files(Foo, Fmt),
+ ?line delete_files(Foo),
+ ?line L3 = [3,1,2,5,4,6],
+ ?line Fs2 = to_files([L3], Fmt, Config),
+ ?line ok = file_sorter:sort(Fs2, Foo, Args),
+ ?line true = rev(lists:sort(L3), Args) =:= from_files(Foo, Fmt),
+ ?line delete_files([Foo | Fs2]),
+ ?line L4 = [1,3,4,1,2,5,4,5,6],
+ ?line Fs3 = to_files([L4], Fmt, Config),
+ ?line ok = file_sorter:sort(Fs3, Foo, Args++[{unique,true},
+ {size,100000}]),
+ ?line true = rev(lists:usort(L4), Args) =:= from_files(Foo, Fmt),
+ ?line delete_files(Foo),
+ ?line ok = file_sorter:sort(Fs3, Foo, Args++[{unique,true}]),
+ ?line true = rev(lists:usort(L4), Args) =:= from_files(Foo, Fmt),
+ ?line delete_files([Foo | Fs3]),
+
+ %% Input is a fun. Output is a file.
+ ?line ok = file_sorter:sort(input([], 2, Fmt), Foo, Args),
+ ?line [] = from_files(Foo, Fmt),
+ ?line delete_files(Foo),
+ ?line L5 = [3,1,2,5,4,7],
+ ?line ok = file_sorter:sort(input(L5, 2, Fmt), Foo, Args),
+ ?line true = rev(lists:sort(L5), Args) =:= from_files(Foo, Fmt),
+ ?line delete_files(Foo),
+
+ %% Removing duplicate keys.
+ KFun = key_compare(2),
+ L6 = [{5,e},{2,b},{3,c},{1,a},{4,d}] ++ [{2,c},{1,b},{4,a}],
+ KUArgs = lists:keydelete(order, 1, Args) ++
+ [{unique, true}, {order, KFun},{size,100000}],
+ ?line ok = file_sorter:sort(input(L6, 2, Fmt), Foo, KUArgs),
+ ?line true = rev(lists:ukeysort(2, L6), KUArgs) =:= from_files(Foo, Fmt),
+ KArgs = lists:keydelete(unique, 1, KUArgs),
+ ?line ok = file_sorter:sort(input(L6, 2, Fmt), Foo, KArgs),
+ ?line true = rev(lists:keysort(2, L6), KArgs) =:= from_files(Foo, Fmt),
+
+ %% Removing duplicate keys. Again.
+ KUArgs2 = lists:keydelete(order, 1, Args) ++
+ [{unique, true}, {order, KFun},{size,5}],
+ ?line ok = file_sorter:sort(input(L6, 2, Fmt), Foo, KUArgs2),
+ ?line true = rev(lists:ukeysort(2, L6), KUArgs2) =:= from_files(Foo, Fmt),
+ KArgs2 = lists:keydelete(unique, 1, KUArgs2),
+ ?line ok = file_sorter:sort(input(L6, 2, Fmt), Foo, KArgs2),
+ ?line true = rev(lists:keysort(2, L6), KArgs2) =:= from_files(Foo, Fmt),
+ ?line delete_files(Foo),
+
+ ok.
+
+keysort(Fmt, XArgs, Config) ->
+ Args = make_args(Fmt, [{size,50}, {no_files, 2} | XArgs]),
+ TmpArgs = Args ++ [{tmpdir,?privdir(Config)}],
+ Foo = outfile(foo, Config),
+
+ %% Input is files. Output is a file.
+ ?line ok = file_sorter:keysort(2, [], Foo, Args),
+ ?line [] = from_files(Foo, Fmt),
+ ?line delete_files(Foo),
+ ?line ok = file_sorter:keysort(2, [], Foo, [{unique,true} | Args]),
+ ?line [] = from_files(Foo, Fmt),
+ ?line delete_files(Foo),
+ ?line L0 = [{a,2},{a,1},{a,2},{a,2},{a,1},{a,2},{a,2},{a,3}],
+ ?line Fs0 = to_files([L0], Fmt, Config),
+ ?line S = rev(lists:ukeysort(1, L0), Args),
+ ?line ok =
+ file_sorter:keysort(1, Fs0, Foo, Args ++ [{unique,true},
+ {size,100000}]),
+ ?line S = from_files(Foo, Fmt),
+ ?line ok =
+ file_sorter:keysort(1, Fs0, Foo, Args ++ [{unique,true},
+ {size,5}]),
+ ?line S = from_files(Foo, Fmt),
+ ?line ok = file_sorter:keysort(1, Fs0, Foo, Args ++ [{unique,true}]),
+ ?line S = from_files(Foo, Fmt),
+ ?line delete_files([Foo | Fs0]),
+ ?line L11 = [{a,1,x4},{b,2,x4},{c,3,x4}],
+ ?line L21 = [{a,1,x3},{b,2,x3},{c,3,x3}],
+ ?line L31 = [{a,1,x2},{b,2,x2},{c,3,x2}],
+ ?line L41 = [{a,1,x1},{b,2,x1},{c,3,x1}],
+ ?line All = [L11, L21, L31, L41],
+ ?line AllFlat = lists:append(All),
+ ?line Sorted = rev(lists:keysort(2, AllFlat), Args),
+ ?line Fs1 = to_files(All, Fmt, Config),
+ ?line ok = file_sorter:keysort(2, Fs1, Foo, Args),
+ ?line Sorted = from_files(Foo, Fmt),
+ ?line delete_files(Foo),
+
+ %% Input is files. Output is a fun.
+ ?line [] = file_sorter:keysort(2, [], output([], Fmt), Args),
+ ?line KS1 = file_sorter:keysort(2, Fs1, output([], Fmt), TmpArgs),
+ ?line Sorted = KS1,
+ ?line delete_files(Fs1),
+
+ %% Input is a fun. Output is a file.
+ ?line ok = file_sorter:keysort(2, input([], 2, Fmt), Foo, Args),
+ ?line [] = from_files(Foo, Fmt),
+ ?line delete_files(Foo),
+ ?line ok = file_sorter:keysort(2, input(AllFlat, 4, Fmt), Foo, Args),
+ ?line Sorted = from_files(Foo, Fmt),
+ ?line delete_files(Foo),
+
+ %% Input is a fun. Output is a fun.
+ ?line [] = file_sorter:keysort(2, input([], 2, Fmt), output([], Fmt),Args),
+ ?line KS2 =
+ file_sorter:keysort(2, input(AllFlat, 4, Fmt), output([], Fmt),
+ TmpArgs),
+ ?line Sorted = KS2,
+ ok.
+
+merge(Fmt, XArgs, Config) ->
+ Args = make_args(Fmt, [{size,5} | XArgs]),
+ Foo = outfile(foo, Config),
+
+ %% Input is a file. Output is a fun.
+ ?line [] = file_sorter:merge([], output([], Fmt), Args),
+ ?line L2 = [[1,3,5],[2,4,5]],
+ ?line Fs1 = to_files(L2, Fmt, Config),
+ ?line S2 = file_sorter:sort(Fs1, output([], Fmt), Args),
+ ?line S2 = rev(lists:sort(lists:append(L2)), Args),
+ ?line delete_files(Fs1),
+
+ %% Input is a file. Output is a file
+ ?line ok = file_sorter:merge([], Foo, Args),
+ ?line [] = from_files(Foo, Fmt),
+ ?line delete_files(Foo),
+ ?line ok = file_sorter:merge([], Foo, [{unique,true} | Args]),
+ ?line [] = from_files(Foo, Fmt),
+ ?line delete_files(Foo),
+ ?line L31 = [1,2,3],
+ ?line L32 = [2,3,4],
+ ?line L33 = [4,5,6],
+ ?line L3r = [L31, L32, L33],
+ ?line L3 = [rev(L31,Args), rev(L32,Args), rev(L33,Args)],
+ ?line Fs2 = to_files(L3, Fmt, Config),
+ ?line ok = file_sorter:merge(Fs2, Foo, Args),
+ ?line true = rev(lists:merge(L3r), Args) =:= from_files(Foo, Fmt),
+ ?line ok = file_sorter:merge(Fs2, Foo, Args++[{unique,true},
+ {size,100000}]),
+ ?line true = rev(lists:umerge(L3r), Args) =:= from_files(Foo, Fmt),
+ ?line delete_files(Foo),
+ ?line ok = file_sorter:merge(Fs2, Foo, Args++[{unique,true}]),
+ ?line true = rev(lists:umerge(L3r), Args) =:= from_files(Foo, Fmt),
+ ?line delete_files([Foo | Fs2]),
+
+ ok.
+
+keymerge(Fmt, XArgs, Config) ->
+ Args = make_args(Fmt, [{size,50}, {no_files, 2} | XArgs]),
+ Foo = outfile(foo, Config),
+
+ %% Input is files. Output is a file.
+ ?line ok = file_sorter:keymerge(2, [], Foo, Args),
+ ?line [] = from_files(Foo, Fmt),
+ ?line delete_files(Foo),
+ ?line ok = file_sorter:keymerge(2, [], Foo, [{unique,true} | Args]),
+ ?line [] = from_files(Foo, Fmt),
+ ?line delete_files(Foo),
+ ?line L0 = [rev([{a,1},{a,2}], Args), rev([{a,2},{a,1},{a,3}], Args)],
+ ?line Fs0 = to_files(L0, Fmt, Config),
+ ?line delete_files(Foo),
+ ?line ok = file_sorter:keymerge(1, Fs0, Foo, Args ++ [{unique,false}]),
+ ?line S2 = rev([{a,1},{a,2},{a,2},{a,1},{a,3}], Args),
+ ?line S2 = from_files(Foo, Fmt),
+ ?line delete_files([Foo | Fs0]),
+ ?line L11 = [{a,1,x4},{b,2,x4},{c,3,x4}],
+ ?line L21 = [{a,1,x3},{b,2,x3},{c,3,x3}],
+ ?line L31 = [{a,1,x2},{b,2,x2},{c,3,x2}],
+ ?line L41 = [{a,1,x1},{b,2,x1},{c,3,x1}],
+ ?line All =
+ [rev(L11, Args), rev(L21, Args), rev(L31, Args), rev(L41, Args)],
+ ?line Merged1 = lists:keymerge(2, L11, L21),
+ ?line Merged2 = lists:keymerge(2, L31, L41),
+ ?line Merged = rev(lists:keymerge(2, Merged1, Merged2), Args),
+ ?line Fs1 = to_files(All, Fmt, Config),
+ ?line ok = file_sorter:keymerge(2, Fs1, Foo, Args),
+ ?line Merged = from_files(Foo, Fmt),
+
+ fun() ->
+ UArgs = [{unique,true} | Args],
+ ?line UMerged1 = lists:ukeymerge(2, L11, L21),
+ ?line UMerged2 = lists:ukeymerge(2, L31, L41),
+ ?line UMerged = rev(lists:ukeymerge(2, UMerged1, UMerged2), Args),
+ ?line ok = file_sorter:keymerge(2, Fs1, Foo, UArgs),
+ ?line UMerged = from_files(Foo, Fmt),
+ UArgs2 = make_args(Fmt, [{unique,true}, {size,50} | XArgs]),
+ ?line ok = file_sorter:keymerge(2, Fs1, Foo, UArgs2),
+ ?line UMerged = from_files(Foo, Fmt),
+ ?line List = rev([{a,1,x4},{b,2,x4},{c,3,x4}], Args),
+ ?line FsL = to_files([List], Fmt, Config),
+ ?line ok = file_sorter:keymerge(2, FsL, Foo, UArgs),
+ ?line List = from_files(Foo, Fmt),
+ ?line List1 = [{a,1,x4},{b,2,x4},{c,3,x4}],
+ ?line List2 = [{a,3,x4},{b,4,x4},{c,5,x4}],
+ ?line FsLL = to_files([rev(List1, Args), rev(List2, Args)], Fmt, Config),
+ ?line ok = file_sorter:keymerge(2, FsLL, Foo, UArgs),
+ ?line List1_2 = rev(lists:ukeymerge(2, List1, List2), Args),
+ ?line List1_2 = from_files(Foo, Fmt),
+ ?line delete_files(Foo)
+ end(),
+
+ %% Input is files. Output is a fun.
+ ?line Fs3 = to_files(All, Fmt, Config),
+ ?line [] = file_sorter:keysort(2, [], output([], Fmt), Args),
+ ?line KS1 = file_sorter:keymerge(2, Fs3, output([], Fmt), Args),
+ ?line Merged = KS1,
+ ?line delete_files([Foo | Fs3]),
+
+ ?line L2 = [[{a,1}],[{a,2}],[{a,3}],[{a,4}],[{a,5}],[{a,6}],[{a,7}]],
+ ?line Fs2 = to_files(L2, Fmt, Config),
+ ?line M = file_sorter:keymerge(1, Fs2, output([], Fmt), Args),
+ ?line M = rev(lists:append(L2), Args),
+ ?line delete_files(Fs2),
+
+ ?line LL1 = [{d,4},{e,5},{f,6}],
+ ?line LL2 = [{a,1},{b,2},{c,3}],
+ ?line LL3 = [{j,10},{k,11},{l,12}],
+ ?line LL4 = [{g,7},{h,8},{i,9}],
+ ?line LL5 = [{p,16},{q,17},{r,18}],
+ ?line LL6 = [{m,13},{n,14},{o,15}],
+ ?line LLAll = [rev(LL1, Args),rev(LL2, Args),rev(LL3, Args),
+ rev(LL4, Args),rev(LL5, Args),rev(LL6, Args)],
+ ?line FsLL6 = to_files(LLAll, Fmt, Config),
+ ?line LL = rev(lists:sort(lists:append(LLAll)), Args),
+ ?line ok = file_sorter:keymerge(1, FsLL6, Foo, Args),
+ ?line LL = from_files(Foo, Fmt),
+ ?line ok = file_sorter:keymerge(1, FsLL6, Foo, [{unique,true} | Args]),
+ ?line LL = from_files(Foo, Fmt),
+ ?line delete_files([Foo | FsLL6]),
+
+ ok.
+
+funmerge(Fmt, XArgs, Config) ->
+ KComp = key_compare(2),
+ Args = make_args(Fmt, [{order,KComp},{size,5}, {no_files, 5} | XArgs]),
+ UArgs = [{unique,true} | Args],
+ Foo = outfile(foo, Config),
+
+ ?line EFs = to_files([[]], Fmt, Config),
+ ?line ok = file_sorter:merge(EFs, Foo, UArgs),
+ ?line [] = from_files(Foo, Fmt),
+ delete_files([Foo | EFs]),
+
+ ?line L11 = [{a,1,x4},{b,2,x4},{c,3,x4}],
+ ?line L21 = [{a,1,x3},{b,2,x3},{c,3,x3}],
+ ?line L31 = [{a,1,x2},{b,2,x2},{c,3,x2}],
+ ?line L41 = [{a,1,x1},{b,2,x1},{c,3,x1}],
+ ?line CAll = [L11, L21, L31, L41],
+ ?line CMerged1 = lists:merge(KComp, L11, L21),
+ ?line CMerged2 = lists:merge(KComp, L31, L41),
+ ?line CMerged = lists:merge(KComp, CMerged1, CMerged2),
+ ?line CFs1 = to_files(CAll, Fmt, Config),
+ ?line ok = file_sorter:merge(CFs1, Foo, Args),
+ ?line CMerged = from_files(Foo, Fmt),
+
+ Args4 = make_args(Fmt, [{size,50} | XArgs]),
+ ?line ok = file_sorter:merge(CFs1, Foo, [{order,KComp} | Args4]),
+ ?line CMerged = from_files(Foo, Fmt),
+
+ ?line UMerged1 = lists:umerge(KComp, L11, L21),
+ ?line UMerged2 = lists:umerge(KComp, L31, L41),
+ ?line UMerged = lists:umerge(KComp, UMerged1, UMerged2),
+ ?line ok = file_sorter:merge(CFs1, Foo, [{order,KComp} | UArgs]),
+ ?line UMerged = from_files(Foo, Fmt),
+ UArgs2 =
+ lists:keydelete(order, 1,
+ make_args(Fmt, [{unique,true}, {size,50} | XArgs])),
+ ?line ok = file_sorter:merge(CFs1, Foo, [{order,KComp} | UArgs2]),
+ ?line UMerged = from_files(Foo, Fmt),
+ ?line delete_files(Foo),
+
+ ?line List1 = [{a,1,x4},{b,2,x4},{c,3,x4}],
+ ?line List2 = [{a,3,x4},{b,4,x4},{c,5,x4}],
+ ?line List3 = [{a,5,x4},{b,6,x4},{c,7,x4}],
+ ?line FsLL = to_files([List1, List2, List3], Fmt, Config),
+ ?line ok = file_sorter:merge(FsLL, Foo, Args),
+ ?line List1_2 = lists:merge(KComp,lists:merge(KComp,List1,List2),List3),
+ ?line List1_2 = from_files(Foo, Fmt),
+ ?line ok = file_sorter:merge(FsLL, Foo, [{order,KComp} | UArgs]),
+ ?line UList1_2 =
+ lists:umerge(KComp,lists:umerge(KComp, List1, List2),List3),
+ ?line UList1_2 = from_files(Foo, Fmt),
+ ?line delete_files([Foo | CFs1]),
+
+ fun() ->
+ ?line LL1 = [{d,4},{e,5},{f,6}],
+ ?line LL2 = [{a,1},{b,2},{c,3}],
+ ?line LL3 = [{j,10},{k,11},{l,12}],
+ ?line LL4 = [{g,7},{h,8},{i,9}],
+ ?line LL5 = [{p,16},{q,17},{r,18}],
+ ?line LL6 = [{m,13},{n,14},{o,15}],
+ ?line LLAll = [LL1,LL2,LL3,LL4,LL5,LL6],
+ ?line FsLL6 = to_files(LLAll, Fmt, Config),
+ ?line LL = lists:sort(lists:append(LLAll)),
+ ?line ok = file_sorter:merge(FsLL6, Foo, Args),
+ ?line LL = from_files(Foo, Fmt),
+ ?line ok = file_sorter:merge(FsLL6, Foo, UArgs),
+ ?line LL = from_files(Foo, Fmt),
+ ?line delete_files([Foo | FsLL6])
+ end(),
+
+ fun() ->
+ ?line RLL1 = [{b,2},{h,8},{n,14}],
+ ?line RLL2 = [{a,1},{g,7},{m,13}],
+ ?line RLL3 = [{d,4},{j,10},{p,16}],
+ ?line RLL4 = [{c,3},{i,9},{o,15}],
+ ?line RLL5 = [{f,6},{l,12},{r,18}],
+ ?line RLL6 = [{e,5},{k,11},{q,17}],
+ ?line RLLAll = [RLL1,RLL2,RLL3,RLL4,RLL5,RLL6],
+ ?line RFsLL6 = to_files(RLLAll, Fmt, Config),
+ ?line RLL = lists:sort(lists:append(RLLAll)),
+ ?line ok = file_sorter:merge(RFsLL6, Foo, Args),
+ ?line RLL = from_files(Foo, Fmt),
+ ?line ok = file_sorter:merge(RFsLL6, Foo, UArgs),
+ ?line RLL = from_files(Foo, Fmt),
+ ?line delete_files([Foo | RFsLL6])
+ end(),
+
+ ok.
+
+check(Fmt, Config) ->
+ Args0 = make_args(Fmt, [{size,5}]),
+ Args = Args0 ++ [{tmpdir,?privdir(Config)}],
+
+ Fun = fun compare/2,
+
+ L1 = [3,1,2,5,4],
+ [F1_0] = Fs1 = to_files([L1], Fmt, Config),
+ F1 = filename:absname(F1_0),
+ ?line {ok, [{F1,2,1}]} = file_sorter:check(Fs1, Args),
+ ?line {ok, [{F1,2,1}]} = file_sorter:check(Fs1, [{order,Fun} | Args]),
+ ?line {ok, [{F1,2,1}]} = file_sorter:check(Fs1, [{unique,true} | Args]),
+ ?line {ok, [{F1,2,1}]} =
+ file_sorter:check(Fs1, [{order,Fun},{unique,true} | Args]),
+ ?line {ok, [{F1,3,2}]} =
+ file_sorter:check(Fs1, [{order,descending} | Args]),
+ ?line {ok, [{F1,3,2}]} =
+ file_sorter:check(Fs1, [{unique,true},{order,descending} | Args]),
+ ?line delete_files(Fs1),
+
+ L2 = [[1,2,2,3,3,4,5,5],[5,5,4,3,3,2,2,1]],
+ [F2_0,F3_0] = Fs2 = to_files(L2, Fmt, Config),
+ F2 = filename:absname(F2_0),
+ F3 = filename:absname(F3_0),
+ ?line {ok, [{F3,3,4}]} = file_sorter:check(Fs2, Args),
+ ?line {ok, [{F3,3,4}]} = file_sorter:check(Fs2, [{order,Fun} | Args]),
+ ?line {ok, [{F2,3,2},{F3,2,5}]} =
+ file_sorter:check(Fs2, [{unique, true} | Args]),
+ ?line {ok, [{F2,3,2},{F3,2,5}]} =
+ file_sorter:check(Fs2, [{order,Fun},{unique, true} | Args]),
+ ?line {ok, [{F2,2,2}]} =
+ file_sorter:check(Fs2, [{order,descending} | Args]),
+ ?line {ok, [{F2,2,2},{F3,2,5}]} =
+ file_sorter:check(Fs2, [{unique,true},{order,descending} | Args]),
+ ?line delete_files(Fs2),
+
+ L3 = [1,2,3,4],
+ ?line Fs3 = to_files([L3], Fmt, Config),
+ ?line {ok, []} = file_sorter:check(Fs3, [{unique,true} | Args]),
+ ?line {ok, []} =
+ file_sorter:check(Fs3, [{unique,true},{order,Fun} | Args]),
+ ?line delete_files(Fs3),
+
+ %% big objects
+ ?line T1 = erlang:make_tuple(10000,foo),
+ ?line T2 = erlang:make_tuple(10000,bar),
+ ?line L4 = [T1,T2],
+ ?line [FF_0] = Fs4 = to_files([L4], Fmt, Config),
+ FF = filename:absname(FF_0),
+ ?line {ok, [{FF,2,T2}]} = file_sorter:check(Fs4, [{unique,true} | Args]),
+ ?line delete_files(Fs4),
+
+ CFun = key_compare(2),
+ L10 = [[{1,a},{2,b},T10_1={1,b},{3,c}], [{1,b},T10_2={2,a}]],
+ [F10_0,F11_0] = Fs10 = to_files(L10, Fmt, Config),
+ F10_1 = filename:absname(F10_0),
+ F11_1 = filename:absname(F11_0),
+ ?line {ok, [{F10_1,3,T10_1},{F11_1,2,T10_2}]} =
+ file_sorter:check(Fs10, [{unique,true},{order,CFun} | Args]),
+ ?line delete_files(Fs10),
+
+ ok.
+
+keycheck(Fmt, Config) ->
+ Args0 = make_args(Fmt, [{size,5}]),
+ Args = Args0 ++ [{tmpdir,?privdir(Config)}],
+
+ ?line L1 = [[{a,1},{b,2}], [{c,2},{b,1},{a,3}]],
+ ?line [F1_0,F2_0] = Fs1 = to_files(L1, Fmt, Config),
+ F1 = filename:absname(F1_0),
+ F2 = filename:absname(F2_0),
+ ?line {ok, [{F2,2,{b,1}}]} = file_sorter:keycheck(1, Fs1, Args),
+ ?line {ok, [{F2,2,{b,1}}]} =
+ file_sorter:keycheck(1, Fs1, [{unique,true} | Args]),
+ ?line {ok, [{F1,2,{b,2}}]} =
+ file_sorter:keycheck(1, Fs1, [{order,descending},{unique,true} | Args]),
+ ?line delete_files(Fs1),
+
+ L2 = [[{a,1},{a,2},{a,2},{b,2}], [{c,2},{b,1},{b,2},{b,2},{a,3}]],
+ ?line [F3_0,F4_0] = Fs2 = to_files(L2, Fmt, Config),
+ F3 = filename:absname(F3_0),
+ F4 = filename:absname(F4_0),
+ ?line {ok, [{F4,2,{b,1}}]} = file_sorter:keycheck(1, Fs2, Args),
+ ?line {ok, [{F3,2,{a,2}},{F4,2,{b,1}}]} =
+ file_sorter:keycheck(1, Fs2, [{unique,true} | Args]),
+ ?line {ok, [{F3,4,{b,2}}]} =
+ file_sorter:keycheck(1, Fs2, [{order,descending} | Args]),
+ ?line {ok, [{F3,2,{a,2}},{F4,3,{b,2}}]} =
+ file_sorter:keycheck(1, Fs2,
+ [{order,descending},{unique,true} | Args]),
+ ?line delete_files(Fs2),
+
+ ok.
+
+rev(L, Args) ->
+ case lists:member({order, descending}, Args) of
+ true ->
+ lists:reverse(L);
+ false ->
+ L
+ end.
+
+make_args({HL, Fmt}, Args) ->
+ make_args(Fmt, [{header, HL} | Args]);
+make_args(Fmt, Args) ->
+ [{format, Fmt} | Args].
+
+compare(X, Y) ->
+ X =< Y.
+
+key_compare(I) ->
+ fun(X, Y) ->
+ element(I, bin_to_term(X)) =< element(I, bin_to_term(Y))
+ end.
+
+bin_to_term(B) when is_binary(B) -> binary_to_term(B);
+bin_to_term(T) -> T.
+
+-define(CHUNKSIZE, 8096).
+
+pps() ->
+ erlang:ports().
+
+input(L, N, term) ->
+ input(L, N);
+input(L, N, {_HL, Format}) when Format =:= binary_term; Format =:= binary ->
+ binput(L, N);
+input(L, N, Format) when Format =:= binary_term; Format =:= binary ->
+ binput(L, N).
+
+binput(L, N) ->
+ Bs = lists:map(fun(T) -> term_to_binary(T) end, L),
+ input(Bs, N).
+
+input(L, N) ->
+ fun(close) ->
+ ok;
+ (read) ->
+ case L of
+ [] -> end_of_input;
+ _ ->
+ R = lists:sublist(L, N),
+ NL = lists:nthtail(length(R), L),
+ {R, input(NL, N)}
+ end
+ end.
+
+output(L, term) ->
+ output(L);
+output(L, {_HL, Format}) when Format =:= binary_term; Format =:= binary ->
+ boutput(L);
+output(L, Format) when Format =:= binary_term; Format =:= binary ->
+ boutput(L).
+
+output(A) ->
+ fun(close) ->
+ lists:append(lists:reverse(A));
+ (L) when is_list(L) ->
+ output([L | A])
+ end.
+
+boutput(A) ->
+ fun(close) ->
+ Bs = lists:append(lists:reverse(A)),
+ lists:map(fun(B) -> binary_to_term(B) end, Bs);
+ (L) when is_list(L) ->
+ boutput([L | A])
+ end.
+
+outfile(Name, Config) ->
+ list_to_atom(filename:join(?privdir(Config), Name)).
+
+%% [[term()]] -> [filename()]
+to_files(Lists, term, Config) ->
+ terms_to_files(Lists, Config);
+to_files(Lists, Format, Config) when Format =:= binary_term;
+ Format =:= binary ->
+ bins_to_files(Lists, 4, Config);
+to_files(Lists, {HL, Format}, Config) when Format =:= binary_term;
+ Format =:= binary ->
+ bins_to_files(Lists, HL, Config).
+
+%% [[term()]] -> [filename()]
+terms_to_files(Lists, Config) ->
+ PrivDir = ?privdir(Config),
+ terms_to_files(Lists, PrivDir, 1).
+
+terms_to_files([L | Ls], PrivDir, N) ->
+ F = lists:concat([?MODULE, '_', N]),
+ File = filename:join(PrivDir, F),
+ {ok, Fd} = file:open(File, [write]),
+ write_terms(Fd, L),
+ file:close(Fd),
+ [list_to_atom(File) | terms_to_files(Ls, PrivDir, N+1)];
+terms_to_files([], _PrivDir, _N) ->
+ [].
+
+write_terms(Fd, [T | Ts]) ->
+ io:format(Fd, "~p.~n", [T]),
+ write_terms(Fd, Ts);
+write_terms(_Fd, []) ->
+ ok.
+
+%% [[term()]] -> [filename()]
+bins_to_files(Lists, HL, Config) ->
+ PrivDir = ?privdir(Config),
+ bins_to_files(Lists, PrivDir, 1, HL).
+
+bins_to_files([L | Fs], PrivDir, N, HL) ->
+ F = lists:concat([?MODULE, '_', N]),
+ File = filename:join(PrivDir, F),
+ {ok, Fd} = file:open(File, [raw,binary,write]),
+ write_bins(Fd, L, HL),
+ file:close(Fd),
+ [list_to_atom(File) | bins_to_files(Fs, PrivDir, N+1, HL)];
+bins_to_files([], _PrivDir, _N, _HL) ->
+ [].
+
+write_bins(Fd, [T | Ts], HL) ->
+ B = term_to_binary(T),
+ Sz = byte_size(B),
+ ok = file:write(Fd, [<<Sz:HL/unit:8>>, B]),
+ write_bins(Fd, Ts, HL);
+write_bins(_Fd, [], _HL) ->
+ ok.
+
+%% [filename()] -> [[term()]] or filename() -> [term()]
+from_files(Files, term) ->
+ terms_from_files(Files);
+from_files(Files, Format) when Format =:= binary_term; Format =:= binary ->
+ bins_from_files(Files, 4);
+from_files(Files, {HL, Format}) when Format =:= binary_term;
+ Format =:= binary ->
+ bins_from_files(Files, HL).
+
+%% [filename()] -> [[term()]] or filename() -> [term()]
+terms_from_files(File) when is_atom(File) ->
+ [Terms] = terms_from_files([File]),
+ Terms;
+terms_from_files(Files) ->
+ lists:map(fun(F) -> terms_from_file(F) end, Files).
+
+terms_from_file(File) ->
+ {ok, Fd} = file:open(File, [read,compressed]),
+ terms_from_file(Fd, []).
+
+terms_from_file(Fd, L) ->
+ case io:read(Fd, '') of
+ {ok, Term} ->
+ terms_from_file(Fd, [Term | L]);
+ eof ->
+ file:close(Fd),
+ lists:reverse(L)
+ end.
+
+%% [filename()] -> [[term()]]
+bins_from_files(File, HL) when is_atom(File) ->
+ [Bins] = bins_from_files([File], HL),
+ Bins;
+bins_from_files(Files, HL) ->
+ lists:map(fun(F) -> collect(F, HL) end, Files).
+
+delete_files(File) when is_atom(File) ->
+ file:delete(File);
+delete_files(Files) ->
+ lists:foreach(fun(F) -> file:delete(F) end, Files).
+
+%%%
+%%% Collects binaries converted to terms in a list. Not very efficient.
+%%%
+collect(F, HL) ->
+ {ok, Fd} = file:open(F, [read, binary, raw, compressed]),
+ R = (catch c(Fd, <<>>, 0, ?CHUNKSIZE, HL, [])),
+ file:close(Fd),
+ R.
+
+c(Fd, Bin0, Size0, NoBytes, HL, L) ->
+ case file:read(Fd, NoBytes) of
+ {ok, Bin} ->
+ Size = Size0 + byte_size(Bin),
+ NBin = list_to_binary([Bin0, Bin]),
+ c1(Fd, NBin, Size, HL, L);
+ eof when Size0 =:= 0 ->
+ lists:reverse(L);
+ eof ->
+ test_server:fail({error, premature_eof});
+ Error ->
+ test_server:fail(Error)
+ end.
+
+c1(Fd, B, BinSize, HL, L) ->
+ case B of
+ <<Size:HL/unit:8, Bin/binary>> ->
+ if
+ Size > BinSize - HL, Size > ?CHUNKSIZE ->
+ c(Fd, B, BinSize, Size + HL, HL, L);
+ Size > BinSize - HL ->
+ c(Fd, B, BinSize, ?CHUNKSIZE, HL, L);
+ true ->
+ <<BinTerm:Size/binary, R/binary>> = Bin,
+ E = case catch binary_to_term(BinTerm) of
+ {'EXIT', _} ->
+ test_server:fail({error, bad_object});
+ Term ->
+ Term
+ end,
+ NBinSize = BinSize - HL - Size,
+ c1(Fd, R, NBinSize, HL, [E | L])
+ end;
+ _ ->
+ c(Fd, B, BinSize, ?CHUNKSIZE, HL, L)
+ end.
diff --git a/lib/stdlib/test/filelib_SUITE.erl b/lib/stdlib/test/filelib_SUITE.erl
new file mode 100644
index 0000000000..c9c6054f7b
--- /dev/null
+++ b/lib/stdlib/test/filelib_SUITE.erl
@@ -0,0 +1,241 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(filelib_SUITE).
+
+-export([all/1,init_per_testcase/2,fin_per_testcase/2,
+ wildcard_one/1,wildcard_two/1,wildcard_errors/1,
+ fold_files/1,otp_5960/1]).
+
+-import(lists, [foreach/2]).
+
+-include("test_server.hrl").
+-include_lib("kernel/include/file.hrl").
+
+init_per_testcase(_Case, Config) ->
+ ?line Dog = ?t:timetrap(?t:minutes(5)),
+ [{watchdog,Dog}|Config].
+
+fin_per_testcase(_Case, Config) ->
+ Dog = ?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+all(suite) ->
+ [wildcard_one,wildcard_two,wildcard_errors,fold_files,otp_5960].
+
+wildcard_one(Config) when is_list(Config) ->
+ ?line {ok,OldCwd} = file:get_cwd(),
+ ?line Dir = filename:join(?config(priv_dir, Config), "wildcard_one"),
+ ?line ok = file:make_dir(Dir),
+ ?line file:set_cwd(Dir),
+ ?line do_wildcard_1(Dir, fun(Wc) -> filelib:wildcard(Wc) end),
+ ?line file:set_cwd(OldCwd),
+ ?line ok = file:del_dir(Dir),
+ ok.
+
+wildcard_two(Config) when is_list(Config) ->
+ ?line Dir = filename:join(?config(priv_dir, Config), "wildcard_two"),
+ ?line ok = file:make_dir(Dir),
+ ?line do_wildcard_1(Dir, fun(Wc) -> filelib:wildcard(Wc, Dir) end),
+ ?line do_wildcard_1(Dir, fun(Wc) -> filelib:wildcard(Wc, Dir++"/") end),
+ case os:type() of
+ {win32,_} ->
+ ok;
+ _ ->
+ ?line do_wildcard_1(Dir, fun(Wc) -> filelib:wildcard(Wc, "//"++Dir) end)
+ end,
+ ?line ok = file:del_dir(Dir),
+ ok.
+
+wildcard_errors(Config) when is_list(Config) ->
+ ?line wcc("{", missing_delimiter),
+ ?line wcc("{a", missing_delimiter),
+ ?line wcc("{a,", missing_delimiter),
+ ?line wcc("{a,b", missing_delimiter),
+ ok.
+
+wcc(Wc, Error) ->
+ {'EXIT',{{badpattern,Error},
+ [{filelib,compile_wildcard,1}|_]}} = (catch filelib:compile_wildcard(Wc)),
+ {'EXIT',{{badpattern,Error},
+ [{filelib,wildcard,1}|_]}} = (catch filelib:wildcard(Wc)),
+ {'EXIT',{{badpattern,Error},
+ [{filelib,wildcard,2}|_]}} = (catch filelib:wildcard(Wc, ".")).
+
+do_wildcard_1(Dir, Wcf0) ->
+ do_wildcard_2(Dir, Wcf0),
+ Wcf = fun(Wc0) ->
+ Wc = filename:join(Dir, Wc0),
+ L = Wcf0(Wc),
+ [subtract_dir(N, Dir) || N <- L]
+ end,
+ do_wildcard_2(Dir, Wcf).
+
+subtract_dir([C|Cs], [C|Dir]) -> subtract_dir(Cs, Dir);
+subtract_dir("/"++Cs, []) -> Cs.
+
+do_wildcard_2(Dir, Wcf) ->
+ %% Basic wildcards.
+ All = ["abc","abcdef","glurf"],
+ ?line Files = mkfiles(lists:reverse(All), Dir),
+ ?line All = Wcf("*"),
+ ?line ["abc","abcdef"] = Wcf("a*"),
+ ?line ["abc","abcdef"] = Wcf("abc*"),
+ ?line ["abcdef"] = Wcf("abc???"),
+ ?line ["abcdef"] = Wcf("abcd*"),
+ ?line ["abcdef"] = Wcf("*def"),
+ ?line ["abcdef","glurf"] = Wcf("{*def,gl*}"),
+ ?line ["abc","abcdef"] = Wcf("a*{def,}"),
+ ?line ["abc","abcdef"] = Wcf("a*{,def}"),
+
+ %% Negative tests.
+ ?line [] = Wcf("b*"),
+ ?line [] = Wcf("bufflig"),
+
+ ?line del(Files),
+ do_wildcard_3(Dir, Wcf).
+
+do_wildcard_3(Dir, Wcf) ->
+ %% Some character sets.
+ All = ["a01","a02","a03","b00","c02","d19"],
+ ?line Files = mkfiles(lists:reverse(All), Dir),
+ ?line All = Wcf("[a-z]*"),
+ ?line All = Wcf("[a-d]*"),
+ ?line All = Wcf("[adbc]*"),
+ ?line All = Wcf("?[0-9][0-9]"),
+ ?line All = Wcf("?[0-1][0-39]"),
+ ?line All = Wcf("[abcdefgh][10][01239]"),
+ ?line ["a01","a02","a03","b00","c02"] = Wcf("[a-z]0[0-3]"),
+ ?line [] = Wcf("?[a-z][0-39]"),
+ ?line del(Files),
+ do_wildcard_4(Dir, Wcf).
+
+do_wildcard_4(Dir, Wcf) ->
+ %% More character sets: tricky characters.
+ All = ["a-","aA","aB","aC","a[","a]"],
+ ?line Files = mkfiles(lists:reverse(All), Dir),
+ ?line All = Wcf("a[][A-C-]"),
+ ?line del(Files),
+ do_wildcard_5(Dir, Wcf).
+
+do_wildcard_5(Dir, Wcf) ->
+ Dirs = ["xa","blurf","yyy"],
+ ?line foreach(fun(D) -> ok = file:make_dir(filename:join(Dir, D)) end, Dirs),
+ All = ["blurf/nisse","xa/arne","xa/kalle","yyy/arne"],
+ ?line Files = mkfiles(lists:reverse(All), Dir),
+
+ %% Test.
+ ?line All = Wcf("*/*"),
+ ?line ["blurf/nisse","xa/arne","xa/kalle"] = Wcf("{blurf,xa}/*"),
+ ?line ["xa/arne","yyy/arne"] = Wcf("*/arne"),
+ ?line ["blurf/nisse"] = Wcf("*/nisse"),
+ ?line [] = Wcf("mountain/*"),
+ ?line [] = Wcf("xa/gurka"),
+
+ %% Cleanup
+ ?line del(Files),
+ ?line foreach(fun(D) -> ok = file:del_dir(filename:join(Dir, D)) end, Dirs).
+
+
+
+fold_files(Config) when is_list(Config) ->
+ ?line Dir = filename:join(?config(priv_dir, Config), "fold_files"),
+ ?line ok = file:make_dir(Dir),
+ ?line Dirs = [filename:join(Dir, D) || D <- ["blurf","blurf/blarf"]],
+ ?line foreach(fun(D) -> ok = file:make_dir(D) end, Dirs),
+ All = ["fb.txt","ko.txt",
+ "blurf/nisse.text","blurf/blarf/aaa.txt","blurf/blarf/urfa.txt"],
+ ?line Files = mkfiles(lists:reverse(All), Dir),
+
+ %% Test.
+ ?line Files0 = filelib:fold_files(Dir, "^", false,
+ fun(H, T) -> [H|T] end, []),
+ ?line same_lists(["fb.txt","ko.txt"], Files0, Dir),
+
+ ?line Files1 = filelib:fold_files(Dir, "^", true,
+ fun(H, T) -> [H|T] end, []),
+ ?line same_lists(All, Files1, Dir),
+
+ ?line Files2 = filelib:fold_files(Dir, "[.]text$", true,
+ fun(H, T) -> [H|T] end, []),
+ ?line same_lists(["blurf/nisse.text"], Files2, Dir),
+
+
+ ?line Files3 = filelib:fold_files(Dir, "^..[.]", true,
+ fun(H, T) -> [H|T] end, []),
+ ?line same_lists(["fb.txt","ko.txt"], Files3, Dir),
+
+ ?line Files4 = filelib:fold_files(Dir, "^ko[.]txt$", true,
+ fun(H, T) -> [H|T] end, []),
+ ?line same_lists(["ko.txt"], Files4, Dir),
+ ?line Files4 = filelib:fold_files(Dir, "^ko[.]txt$", false,
+ fun(H, T) -> [H|T] end, []),
+
+ ?line [] = filelib:fold_files(Dir, "^$", true,
+ fun(H, T) -> [H|T] end, []),
+
+ %% Cleanup
+ ?line del(Files),
+ ?line foreach(fun(D) -> ok = file:del_dir(D) end, lists:reverse(Dirs)),
+ ?line ok = file:del_dir(Dir).
+
+same_lists(Expected0, Actual0, BaseDir) ->
+ Expected = [filename:absname(N, BaseDir) || N <- lists:sort(Expected0)],
+ Actual = lists:sort(Actual0),
+ Expected = Actual.
+
+mkfiles([H|T], Dir) ->
+ Name = filename:join(Dir, H),
+ Garbage = [31+random:uniform(95) || _ <- lists:seq(1, random:uniform(1024))],
+ file:write_file(Name, Garbage),
+ [Name|mkfiles(T, Dir)];
+mkfiles([], _) -> [].
+
+del([H|T]) ->
+ ok = file:delete(H),
+ del(T);
+del([]) -> ok.
+
+otp_5960(suite) ->
+ [];
+otp_5960(doc) ->
+ ["Test that filelib:ensure_dir/1 returns ok or {error,Reason}"];
+otp_5960(Config) when is_list(Config) ->
+ ?line PrivDir = ?config(priv_dir, Config),
+ ?line Dir = filename:join(PrivDir, otp_5960_dir),
+ ?line Name1 = filename:join(Dir, name1),
+ ?line Name2 = filename:join(Dir, name2),
+ ?line ok = filelib:ensure_dir(Name1), % parent is created
+ ?line ok = filelib:ensure_dir(Name2), % parent already exists
+ ?line Name3 = filename:join(Name1, name3),
+ ?line {ok, FileInfo} = file:read_file_info(Dir),
+ case os:type() of
+ {win32,_} ->
+ %% Not possibly to write protect directories on Windows
+ %% (at least not using file:write_file_info/2).
+ ok;
+ _ ->
+ ?line Mode = FileInfo#file_info.mode,
+ ?line NoWriteMode = Mode - 8#00200 - 8#00020 - 8#00002,
+ ?line ok = file:write_file_info(Dir, #file_info{mode=NoWriteMode}),
+ ?line {error, _} = filelib:ensure_dir(Name3),
+ ?line ok = file:write_file_info(Dir, #file_info{mode=Mode}),
+ ok
+ end.
diff --git a/lib/stdlib/test/filename_SUITE.erl b/lib/stdlib/test/filename_SUITE.erl
new file mode 100644
index 0000000000..ab6521f37b
--- /dev/null
+++ b/lib/stdlib/test/filename_SUITE.erl
@@ -0,0 +1,459 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(filename_SUITE).
+-export([all/1]).
+-export([absname/1, absname_2/1,
+ basename_1/1, basename_2/1,
+ dirname/1, extension/1, join/1, t_nativename/1]).
+-export([pathtype/1,rootname/1,split/1,find_src/1]).
+-include("test_server.hrl").
+
+all(suite) ->
+ [absname, absname_2, basename_1, basename_2, dirname,
+ extension,
+ join, pathtype, rootname, split, t_nativename, find_src].
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+absname(Config) when is_list(Config) ->
+ case os:type() of
+ {win32, _} ->
+ ?line [Drive|_] = ?config(priv_dir, Config),
+ ?line Temp = filename:join([Drive|":/"], "temp"),
+ ?line case file:make_dir(Temp) of
+ ok -> ok;
+ {error,eexist} -> ok
+ end,
+ ?line {ok,Cwd} = file:get_cwd(),
+ ?line ok = file:set_cwd(Temp),
+ ?line [Drive|":/temp/foo"] = filename:absname(foo),
+ ?line [Drive|":/temp/foo"] = filename:absname("foo"),
+ ?line [Drive|":/temp/../ebin"] = filename:absname("../ebin"),
+ ?line [Drive|":/erlang"] = filename:absname("/erlang"),
+ ?line [Drive|":/erlang/src"] = filename:absname("/erlang/src"),
+ ?line [Drive|":/erlang/src"] = filename:absname("\\erlang\\src"),
+ ?line [Drive|":/temp/erlang"] = filename:absname([Drive|":erlang"]),
+ ?line [Drive|":/temp/erlang/src"] =
+ filename:absname([Drive|":erlang/src"]),
+ ?line [Drive|":/temp/erlang/src"] =
+ filename:absname([Drive|":erlang\\src\\"]),
+ ?line "a:/erlang" = filename:absname("a:erlang"),
+
+ ?line file:set_cwd([Drive|":/"]),
+ ?line [Drive|":/foo"] = filename:absname(foo),
+ ?line [Drive|":/foo"] = filename:absname("foo"),
+ ?line [Drive|":/../ebin"] = filename:absname("../ebin"),
+ ?line [Drive|":/erlang"] = filename:absname("/erlang"),
+ ?line [Drive|":/erlang/src"] = filename:absname("/erlang/src"),
+ ?line [Drive|":/erlang/src"] = filename:absname(["/erlang",'/src']),
+ ?line [Drive|":/erlang/src"] = filename:absname("\\erlang\\\\src"),
+ ?line [Drive|":/erlang"] = filename:absname([Drive|":erlang"]),
+ ?line [Drive|":/erlang/src"] = filename:absname([Drive|":erlang/src"]),
+ ?line "a:/erlang" = filename:absname("a:erlang"),
+
+ ?line file:set_cwd(Cwd),
+ ok;
+ {unix, _} ->
+ ?line ok = file:set_cwd("/usr"),
+ ?line "/usr/foo" = filename:absname(foo),
+ ?line "/usr/foo" = filename:absname("foo"),
+ ?line "/usr/../ebin" = filename:absname("../ebin"),
+
+ ?line file:set_cwd("/"),
+ ?line "/foo" = filename:absname(foo),
+ ?line "/foo" = filename:absname("foo"),
+ ?line "/../ebin" = filename:absname("../ebin"),
+ ?line "/erlang" = filename:absname("/erlang"),
+ ?line "/erlang/src" = filename:absname("/erlang/src"),
+ ?line "/erlang/src" = filename:absname(["/erl",'ang/s',"rc"]),
+ ?line "/erlang/src" = filename:absname(["/erl",'a','ng',"/",'s',"rc"]),
+ ?line "/erlang/src" = filename:absname("/erlang///src"),
+ ?line "/file_sorter.erl" = filename:absname([file_sorter|'.erl']),
+ ok;
+ vxworks ->
+ Test_dir = ?config(priv_dir, Config),
+ Test1 = Test_dir ++ "/foo",
+ Test2 = Test_dir ++ "/ebin",
+ ?line ok = file:set_cwd(Test_dir),
+ ?line Test1 = filename:absname(foo),
+ ?line Test1= filename:absname("foo"),
+ ?line Test2 = filename:absname("foo/../ebin"),
+ ?line "/erlang" = filename:absname("/erlang"),
+ ?line "/erlang/src" = filename:absname("/erlang/src"),
+ ?line "/erlang/src" = filename:absname(["/erlan",'g/s',"rc"]),
+ ?line "/erlang/src" = filename:absname("/erlang///src"),
+ ok
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+absname_2(Config) when is_list(Config) ->
+ case os:type() of
+ {win32, _} ->
+ ?line [Drive|_] = ?config(priv_dir, Config),
+ ?line [Drive|":/temp/foo"] = filename:absname(foo, [Drive|":/temp"]),
+ ?line [Drive|":/temp/foo"] = filename:absname("foo", [Drive|":/temp"]),
+ ?line [Drive|":/temp/../ebin"] = filename:absname("../ebin",
+ [Drive|":/temp"]),
+ ?line [Drive|":/erlang"] = filename:absname("/erlang", [Drive|":/temp"]),
+ ?line [Drive|":/erlang/src"] = filename:absname("/erlang/src",
+ [Drive|":/temp"]),
+ ?line [Drive|":/erlang/src"] = filename:absname("\\erlang\\src",
+ [Drive|":/temp"]),
+ ?line [Drive|":/temp/erlang"] = filename:absname([Drive|":erlang"],
+ [Drive|":/temp"]),
+ ?line [Drive|":/temp/erlang/src"] = filename:absname([Drive|":erlang/src"],
+ [Drive|":/temp"]),
+ ?line [Drive|":/temp/erlang/src"] =
+ filename:absname([Drive|":erlang\\src\\"], [Drive|":/temp"]),
+ ?line "a:/erlang" = filename:absname("a:erlang", [Drive|":/temp"]),
+
+ ?line file:set_cwd([Drive|":/"]),
+ ?line [Drive|":/foo"] = filename:absname(foo, [Drive|":/"]),
+ ?line [Drive|":/foo"] = filename:absname("foo", [Drive|":/"]),
+ ?line [Drive|":/../ebin"] = filename:absname("../ebin", [Drive|":/"]),
+ ?line [Drive|":/erlang"] = filename:absname("/erlang", [Drive|":/"]),
+ ?line [Drive|":/erlang/src"] = filename:absname("/erlang/src",
+ [Drive|":/"]),
+ ?line [Drive|":/erlang/src"] = filename:absname("\\erlang\\\\src",
+ [Drive|":/"]),
+ ?line [Drive|":/erlang"] = filename:absname([Drive|":erlang"],
+ [Drive|":/"]),
+ ?line [Drive|":/erlang/src"] = filename:absname([Drive|":erlang/src"],
+ [Drive|":/"]),
+ ?line "a:/erlang" = filename:absname("a:erlang", [Drive|":/"]),
+
+ ok;
+ {unix, _} ->
+ ?line "/usr/foo" = filename:absname(foo, "/usr"),
+ ?line "/usr/foo" = filename:absname("foo", "/usr"),
+ ?line "/usr/../ebin" = filename:absname("../ebin", "/usr"),
+
+ ?line "/foo" = filename:absname(foo, "/"),
+ ?line "/foo" = filename:absname("foo", "/"),
+ ?line "/../ebin" = filename:absname("../ebin", "/"),
+ ?line "/erlang" = filename:absname("/erlang", "/"),
+ ?line "/erlang/src" = filename:absname("/erlang/src", "/"),
+ ?line "/erlang/src" = filename:absname("/erlang///src", "/"),
+ ok;
+ vxworks ->
+ ?line "/usr/foo" = filename:absname(foo, "/usr"),
+ ?line "/usr/foo" = filename:absname("foo", "/usr"),
+ ?line "/usr/ebin" = filename:absname("../ebin", "/usr"),
+ ?line "/usr/ebin" = filename:absname("../ebin", "/usr/src"),
+ ?line "/erlang" = filename:absname("/erlang", "/usr"),
+ ?line "/erlang/src" = filename:absname("/erlang/src", "/usr"),
+ ?line "/erlang/src" = filename:absname("/erlang///src", "/usr"),
+ ok
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+basename_1(Config) when is_list(Config) ->
+ ?line Dog = test_server:timetrap(test_server:seconds(10)),
+ ?line "." = filename:basename("."),
+ ?line "foo" = filename:basename("foo"),
+ ?line "foo" = filename:basename("/usr/foo"),
+ ?line "foo.erl" = filename:basename("A:usr/foo.erl"),
+ ?line "foo" = filename:basename('/usr/foo'),
+ ?line "foo" = filename:basename(["/usr","/","f","o","o"]),
+ ?line "foo" = filename:basename(["/usr/",foo]),
+ ?line "foo" = filename:basename(["/usr/f",oo]),
+ ?line "foo" = filename:basename(["usr/", "foo"]),
+ ?line "foo" = filename:basename(["usr/"|foo]),
+ ?line "foo" = filename:basename(["usr/foo/"]),
+ ?line case os:type() of
+ {win32, _} ->
+ ?line "foo" = filename:basename(["usr\\foo\\"]),
+ ?line "foo" = filename:basename("A:\\usr\\foo"),
+ ?line "foo" = filename:basename("A:foo");
+ {unix, _} ->
+ ?line "strange\\but\\true" =
+ filename:basename("strange\\but\\true");
+ vxworks ->
+ ?line "foo" = filename:basename(["usr\\foo\\"]),
+ ?line "foo" = filename:basename("elrond:usr\\foo\\"),
+ ?line "foo" = filename:basename("disk:/foo")
+ end,
+ ?line test_server:timetrap_cancel(Dog),
+ ok.
+
+basename_2(Config) when is_list(Config) ->
+ ?line Dog = test_server:timetrap(test_server:seconds(10)),
+ ?line "." = filename:basename(".", ".erl"),
+ ?line "foo" = filename:basename("foo.erl", ".erl"),
+ ?line "foo" = filename:basename('foo.erl', ".erl"),
+ ?line "foo" = filename:basename("foo.erl", '.erl'),
+ ?line "foo" = filename:basename(["/usr","/","f","oo"], ".erl"),
+ ?line "foo.erl" = filename:basename("/usr/foo.erl", ".hrl"),
+ ?line "foo.erl" = filename:basename("/usr.hrl/foo.erl", ".hrl"),
+ ?line "foo" = filename:basename("/usr.hrl/foo", ".hrl"),
+ ?line "foo" = filename:basename("usr/foo/", ".erl"),
+ ?line "foo.erl" = filename:basename("usr/foo.erl/", ".erl"),
+ ?line "foo.erl" = filename:basename("usr/foo.erl/", '.erl'),
+ ?line "foo" = filename:basename(["/usr",'/','f','oo'], ".erl"),
+ ?line "foo.erl" = filename:basename(["usr/foo.e",'rl/'], ".erl"),
+ ?line case os:type() of
+ {win32, _} ->
+ ?line "foo" = filename:basename("A:foo", ".erl"),
+ ?line "foo.erl" = filename:basename("a:\\usr\\foo.erl",
+ ".hrl"),
+ ?line "foo.erl" = filename:basename("c:\\usr.hrl\\foo.erl",
+ ".hrl"),
+ ?line "foo" = filename:basename("A:\\usr\\foo", ".hrl");
+ {unix, _} ->
+ ?line "strange\\but\\true" =
+ filename:basename("strange\\but\\true.erl", ".erl"),
+ ?line "strange\\but\\true" =
+ filename:basename("strange\\but\\true", ".erl");
+ vxworks ->
+ ?line "foo" = filename:basename("net:foo", ".erl"),
+ ?line "foo.erl" = filename:basename("net:\\usr\\foo.erl",
+ ".hrl"),
+ ?line "foo.erl" =
+ filename:basename("/disk0:\\usr.hrl\\foo.erl",
+ ".hrl"),
+ ?line "foo" = filename:basename("/home\\usr\\foo", ".hrl")
+ end,
+ ?line test_server:timetrap_cancel(Dog),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+dirname(Config) when is_list(Config) ->
+ case os:type() of
+ {win32,_} ->
+ ?line "A:/usr" = filename:dirname("A:/usr/foo.erl"),
+ ?line "A:usr" = filename:dirname("A:usr/foo.erl"),
+ ?line "/usr" = filename:dirname("\\usr\\foo.erl"),
+ ?line "/" = filename:dirname("\\usr"),
+ ?line "A:" = filename:dirname("A:");
+ vxworks ->
+ ?line "net:/usr" = filename:dirname("net:/usr/foo.erl"),
+ ?line "/disk0:/usr" = filename:dirname("/disk0:/usr/foo.erl"),
+ ?line "/usr" = filename:dirname("\\usr\\foo.erl"),
+ ?line "/usr" = filename:dirname("\\usr"),
+ ?line "net:" = filename:dirname("net:");
+ _ -> true
+ end,
+ ?line "usr" = filename:dirname("usr///foo.erl"),
+ ?line "." = filename:dirname("foo.erl"),
+ ?line "." = filename:dirname("."),
+ ?line "usr" = filename:dirname('usr/foo.erl'),
+ ?line "usr" = filename:dirname(['usr','/foo.erl']),
+ ?line "usr" = filename:dirname(['us','r/foo.erl']),
+ ?line "usr" = filename:dirname(['usr/','/foo.erl']),
+ ?line "usr" = filename:dirname(['usr/','foo.erl']),
+ ?line "usr" = filename:dirname(['usr/'|'foo.erl']),
+ ?line "usr" = filename:dirname(['usr/f','oo.erl']),
+ case os:type() of
+ vxworks ->
+ ?line "/" = filename:dirname("/"),
+ ?line "/usr" = filename:dirname("/usr");
+ _ ->
+ ?line "/" = filename:dirname("/"),
+ ?line "/" = filename:dirname("/usr")
+ end,
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+extension(Config) when is_list(Config) ->
+ ?line ".erl" = filename:extension("A:/usr/foo.erl"),
+ ?line ".erl" = filename:extension("A:/usr/foo.nisse.erl"),
+ ?line ".erl" = filename:extension(["A:/usr/", 'foo.ni', "sse.erl"]),
+ ?line ".erl" = filename:extension(["A:/usr/", 'foo.ni', "sse.e", 'rl']),
+ ?line ".erl" = filename:extension(["A:/usr/", 'foo.ni', "sse.e"|'rl']),
+ ?line ".erl" = filename:extension("A:/usr.bar/foo.nisse.erl"),
+ ?line "" = filename:extension("A:/usr.bar/foo"),
+ ?line "" = filename:extension("A:/usr/foo"),
+ ?line case os:type() of
+ {win32, _} ->
+ ?line "" = filename:extension("A:\\usr\\foo"),
+ ?line ".erl" =
+ filename:extension("A:/usr.bar/foo.nisse.erl"),
+ ?line "" = filename:extension("A:/usr.bar/foo"),
+ ok;
+ vxworks ->
+ ?line "" = filename:extension("/disk0:\\usr\\foo"),
+ ?line ".erl" =
+ filename:extension("net:/usr.bar/foo.nisse.erl"),
+ ?line "" = filename:extension("net:/usr.bar/foo"),
+ ok;
+ _ -> ok
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+join(Config) when is_list(Config) ->
+ ?line "/" = filename:join(["/"]),
+ ?line "/" = filename:join(["//"]),
+ ?line "usr/foo.erl" = filename:join("usr","foo.erl"),
+ ?line "/src/foo.erl" = filename:join(usr, "/src/foo.erl"),
+ ?line "/src/foo.erl" = filename:join(["/src/",'foo.erl']),
+ ?line "/src/foo.erl" = filename:join(usr, ["/sr", 'c/foo.erl']),
+ ?line "/src/foo.erl" = filename:join("usr", "/src/foo.erl"),
+
+ %% Make sure that redundant slashes work too.
+ ?line "a/b/c/d/e/f/g" = filename:join(["a//b/c/////d//e/f/g"]),
+ ?line "a/b/c/d/e/f/g" = filename:join(["a//b/c/", "d//e/f/g"]),
+ ?line "a/b/c/d/e/f/g" = filename:join(["a//b/c", "d//e/f/g"]),
+ ?line "/d/e/f/g" = filename:join(["a//b/c", "/d//e/f/g"]),
+ ?line "/d/e/f/g" = filename:join(["a//b/c", "//d//e/f/g"]),
+
+ ?line "foo/bar" = filename:join([$f,$o,$o,$/,[]], "bar"),
+
+ ?line case os:type() of
+ {win32, _} ->
+ ?line "d:/" = filename:join(["D:/"]),
+ ?line "d:/" = filename:join(["D:\\"]),
+ ?line "d:/abc" = filename:join(["D:/", "abc"]),
+ ?line "d:abc" = filename:join(["D:", "abc"]),
+ ?line "a/b/c/d/e/f/g" =
+ filename:join(["a//b\\c//\\/\\d/\\e/f\\g"]),
+ ?line "a:usr/foo.erl" =
+ filename:join(["A:","usr","foo.erl"]),
+ ?line "/usr/foo.erl" =
+ filename:join(["A:","/usr","foo.erl"]),
+ ?line "c:usr" = filename:join("A:","C:usr"),
+ ?line "a:usr" = filename:join("A:","usr"),
+ ?line "c:/usr" = filename:join("A:", "C:/usr"),
+ ?line "c:/usr/foo.erl" =
+ filename:join(["A:","C:/usr","foo.erl"]),
+ ?line "c:usr/foo.erl" =
+ filename:join(["A:","C:usr","foo.erl"]),
+ ?line "d:/foo" = filename:join([$D, $:, $/, []], "foo"),
+ ok;
+ vxworks ->
+ ?line "Net:" = filename:join(["Net:/"]),
+ ?line "net:" = filename:join(["net:\\"]),
+ ?line "net:/abc" = filename:join(["net:/", "abc"]),
+ ?line "net:/abc" = filename:join(["net:", "abc"]),
+ ?line "a/b/c/d/e/f/g" =
+ filename:join(["a//b\\c//\\/\\d/\\e/f\\g"]),
+ ?line "net:/usr/foo.erl" =
+ filename:join(["net:","usr","foo.erl"]),
+ ?line "/usr/foo.erl" =
+ filename:join(["net:","/usr","foo.erl"]),
+ ?line "/target:usr" = filename:join("net:","/target:usr"),
+ ?line "kernel:/usr" = filename:join("net:", "kernel:/usr"),
+ ?line "foo:/usr/foo.erl" =
+ filename:join(["A:","foo:/usr","foo.erl"]),
+ ?line "/disk0:usr/foo.erl" =
+ filename:join(["kalle:","/disk0:usr","foo.erl"]),
+ ?line "D:/foo" = filename:join([$D, $:, $/, []], "foo"),
+ ok;
+ {unix, _} ->
+ ok
+ end.
+
+pathtype(Config) when is_list(Config) ->
+ ?line relative = filename:pathtype(".."),
+ ?line relative = filename:pathtype("foo"),
+ ?line relative = filename:pathtype("foo/bar"),
+ ?line relative = filename:pathtype('foo/bar'),
+ ?line relative = filename:pathtype(['f','oo',"/bar"]),
+ case os:type() of
+ {win32, _} ->
+ ?line volumerelative = filename:pathtype("/usr/local/bin"),
+ ?line volumerelative = filename:pathtype("A:usr/local/bin"),
+ ok;
+ {unix, _} ->
+ ?line absolute = filename:pathtype("/"),
+ ?line absolute = filename:pathtype("/usr/local/bin"),
+ ok;
+ vxworks ->
+ ?line absolute = filename:pathtype("/usr/local/bin"),
+ ?line absolute = filename:pathtype("net:usr/local/bin"),
+ ok
+ end.
+
+rootname(Config) when is_list(Config) ->
+ ?line "/jam.src/kalle" = filename:rootname("/jam.src/kalle"),
+ ?line "/jam.src/foo" = filename:rootname("/jam.src/foo.erl"),
+ ?line "/jam.src/foo" = filename:rootname(["/ja",'m.sr',"c/foo.erl"]),
+ ?line "/jam.src/foo" = filename:rootname("/jam.src/foo.erl", ".erl"),
+ ?line "/jam.src/foo.jam" = filename:rootname("/jam.src/foo.jam", ".erl"),
+ ?line "/jam.src/foo.jam" = filename:rootname(["/jam.sr",'c/foo.j',"am"],".erl"),
+ ?line "/jam.src/foo.jam" = filename:rootname(["/jam.sr",'c/foo.j'|am],".erl"),
+ ok.
+
+split(Config) when is_list(Config) ->
+ case os:type() of
+ vxworks ->
+ ?line ["/usr","local","bin"] = filename:split("/usr/local/bin");
+ _ ->
+ ?line ["/","usr","local","bin"] = filename:split("/usr/local/bin")
+ end,
+ ?line ["foo","bar"]= filename:split("foo/bar"),
+ ?line ["foo", "bar", "hello"]= filename:split("foo////bar//hello"),
+ ?line ["foo", "bar", "hello"]= filename:split(["foo//",'//bar//h',"ello"]),
+ ?line ["foo", "bar", "hello"]= filename:split(["foo//",'//bar//h'|ello]),
+ case os:type() of
+ {win32,_} ->
+ ?line ["a:/","msdev","include"] =
+ filename:split("a:/msdev/include"),
+ ?line ["a:/","msdev","include"] =
+ filename:split("A:/msdev/include"),
+ ?line ["msdev","include"] =
+ filename:split("msdev\\include"),
+ ?line ["a:/","msdev","include"] =
+ filename:split("a:\\msdev\\include"),
+ ?line ["a:","msdev","include"] =
+ filename:split("a:msdev\\include"),
+ ok;
+ vxworks ->
+ ?line ["net:","msdev","include"] =
+ filename:split("net:/msdev/include"),
+ ?line ["Target:","msdev","include"] =
+ filename:split("Target:/msdev/include"),
+ ?line ["msdev","include"] =
+ filename:split("msdev\\include"),
+ ?line ["/disk0:","msdev","include"] =
+ filename:split("/disk0:\\msdev\\include"),
+ ?line ["a:","msdev","include"] =
+ filename:split("a:msdev\\include"),
+ ok;
+ _ ->
+ ok
+ end.
+
+t_nativename(Config) when is_list(Config) ->
+ ?line "abcedf" = filename:nativename(abcedf),
+ ?line "abcedf" = filename:nativename(["abc", "edf"]),
+ ?line "abcgluff" = filename:nativename(["abc", gluff]),
+ case os:type() of
+ {win32, _} ->
+ ?line "a:\\temp\\arne.exe" =
+ filename:nativename("A:/temp//arne.exe/");
+ _ ->
+ ?line "/usr/tmp/arne" =
+ filename:nativename("/usr/tmp//arne/")
+ end.
+
+find_src(Config) when is_list(Config) ->
+ ?line {Source,_} = filename:find_src(file),
+ ?line ["file"|_] = lists:reverse(filename:split(Source)),
+ ?line {_,_} = filename:find_src(init, [{".","."}, {"ebin","src"}]),
+
+ %% Try to find the source for a preloaded module.
+ ?line {error,{preloaded,init}} = filename:find_src(init),
+ ok.
diff --git a/lib/stdlib/test/fixtable_SUITE.erl b/lib/stdlib/test/fixtable_SUITE.erl
new file mode 100644
index 0000000000..9f21308ad4
--- /dev/null
+++ b/lib/stdlib/test/fixtable_SUITE.erl
@@ -0,0 +1,414 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%%----------------------------------------------------------------------
+%%% Purpose : Tests the safe_fixtable functions in both ets and dets.
+%%%----------------------------------------------------------------------
+
+-module(fixtable_SUITE).
+-export([all/1]).
+%%% Test cases
+-export([multiple_fixes/1, multiple_processes/1,
+ other_process_deletes/1, owner_dies/1,
+ other_process_closes/1,insert_same_key/1]).
+-export([fixbag/1]).
+-export([init_per_testcase/2, fin_per_testcase/2]).
+%%% Internal exports
+-export([command_loop/0,start_commander/0]).
+
+all(suite) -> {req, [stdlib],
+ [multiple_fixes, multiple_processes,
+ other_process_deletes, owner_dies,
+ other_process_closes,insert_same_key,fixbag]}.
+
+-include("test_server.hrl").
+
+%%% I wrote this thinking I would use more than one temporary at a time, but
+%%% I wasn't... Well, maybe in the future...
+-define(DETS_TEMPORARIES, [tmp1]).
+-define(ETS_TEMPORARIES, [gurksmetsmedaljong]).
+-define(DETS_TMP1,hd(?DETS_TEMPORARIES)).
+-define(ETS_TMP1,hd(?ETS_TEMPORARIES)).
+
+-define(HELPER_NODE, (atom_to_list(?MODULE) ++ "_helper1")).
+
+init_per_testcase(_Func, Config) ->
+ PrivDir = ?config(priv_dir,Config),
+ file:make_dir(PrivDir),
+ Dog=test_server:timetrap(test_server:seconds(60)),
+ [{watchdog, Dog}|Config].
+
+fin_per_testcase(_Func, Config) ->
+ Dog=?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+ lists:foreach(fun(X) ->
+ (catch dets:close(X)),
+ (catch file:delete(dets_filename(X,Config)))
+ end,
+ ?DETS_TEMPORARIES),
+ lists:foreach(fun(X) ->
+ (catch ets:delete(X))
+ end,
+ ?ETS_TEMPORARIES).
+
+
+-ifdef(DEBUG).
+-define(LOG(X), show(X,?LINE)).
+
+show(Term, Line) ->
+ io:format("~p: ~p~n", [Line,Term]),
+ Term.
+-else.
+-define(LOG(X),X).
+-endif.
+
+
+fixbag(doc) ->
+ ["Check for bug OTP-5087, safe_fixtable for bags could give "
+ "incorrect lookups"];
+fixbag(suite) ->
+ [];
+fixbag(Config) when list(Config) ->
+ ?line T = ets:new(x,[bag]),
+ ?line ets:insert(T,{a,1}),
+ ?line ets:insert(T,{a,2}),
+ ?line ets:safe_fixtable(T,true),
+ ?line ets:match_delete(T,{a,2}),
+ ?line ets:insert(T,{a,3}),
+ ?line Res = ets:lookup(T,a),
+ ?line ets:safe_fixtable(T,false),
+ ?line Res = ets:lookup(T,a),
+ ok.
+
+
+
+insert_same_key(doc) ->
+ ["Check correct behaviour if a key is deleted and reinserted during fixation."];
+insert_same_key(suite) ->
+ [];
+insert_same_key(Config) when list(Config) ->
+ ?line {ok,Dets1} = dets:open_file(?DETS_TMP1,
+ [{file, dets_filename(?DETS_TMP1,Config)}]),
+ ?line Ets1 = ets:new(ets,[]),
+ ?line insert_same_key(Dets1,dets,Config),
+ ?line insert_same_key(Ets1,ets,Config),
+ ?line ets:insert(Ets1,{1,2}),
+ ?line 1 = ets:info(Ets1,size),
+ ?line dets:insert(Dets1,{1,2}),
+ ?line 1 = dets:info(Dets1,size),
+ ?line dets:close(Dets1),
+ ?line (catch file:delete(dets_filename(Dets1,Config))),
+ ?line ets:delete(Ets1),
+ ?line {ok,Dets2} = dets:open_file(?DETS_TMP1,
+ [{type,bag},{file, dets_filename(?DETS_TMP1,Config)}]),
+ ?line Ets2 = ets:new(ets,[bag]),
+ ?line insert_same_key(Dets2,dets,Config),
+ ?line insert_same_key(Ets2,ets,Config),
+ ?line ets:insert(Ets2,{1,2}),
+ ?line 2 = ets:info(Ets2,size),
+ ?line ets:insert(Ets2,{1,2}),
+ ?line 2 = ets:info(Ets2,size),
+ ?line dets:insert(Dets2,{1,2}),
+ ?line 2 = dets:info(Dets2,size),
+ ?line dets:insert(Dets2,{1,2}),
+ ?line 2 = dets:info(Dets2,size),
+ ?line dets:close(Dets2),
+ ?line (catch file:delete(dets_filename(Dets2,Config))),
+ ?line ets:delete(Ets2),
+ ?line {ok,Dets3} = dets:open_file(?DETS_TMP1,
+ [{type,duplicate_bag},
+ {file, dets_filename(?DETS_TMP1,Config)}]),
+ ?line Ets3 = ets:new(ets,[duplicate_bag]),
+ ?line insert_same_key(Dets3,dets,Config),
+ ?line insert_same_key(Ets3,ets,Config),
+ ?line ets:insert(Ets3,{1,2}),
+ ?line 2 = ets:info(Ets3,size),
+ ?line ets:insert(Ets3,{1,2}),
+ ?line 3 = ets:info(Ets3,size),
+ ?line dets:insert(Dets3,{1,2}),
+ ?line 2 = dets:info(Dets3,size),
+ ?line dets:insert(Dets3,{1,2}),
+ ?line 3 = dets:info(Dets3,size),
+ ?line dets:close(Dets3),
+ ?line (catch file:delete(dets_filename(Dets3,Config))),
+ ?line ets:delete(Ets3),
+ ok.
+
+insert_same_key(Tab,Mod,_Config) ->
+ ?line Mod:insert(Tab,{1,1}),
+ ?line Mod:insert(Tab,{1,2}),
+ ?line Mod:insert(Tab,{2,2}),
+ ?line Mod:insert(Tab,{2,2}),
+ ?line Mod:safe_fixtable(Tab,true),
+ ?line Mod:delete(Tab,1),
+ ?line Mod:insert(Tab,{1,1}),
+ ?line Expect = case Mod:info(Tab,type) of
+ bag ->
+ Mod:insert(Tab,{1,2}),
+ 2;
+ _ ->
+ 1
+ end,
+ ?line Mod:delete(Tab,2),
+ ?line Mod:safe_fixtable(Tab,false),
+ ?line case Mod:info(Tab,size) of
+ Expect ->
+ ok;
+ _ ->
+ exit({size_field_wrong,{Mod,Mod:info(Tab)}})
+ end.
+
+
+
+
+owner_dies(doc) ->
+ ["Check correct behaviour if the table owner dies."];
+owner_dies(suite) ->
+ [];
+owner_dies(Config) when list(Config) ->
+ ?line P1 = start_commander(),
+ ?line Ets1 = command(P1,{ets,new,[ets,[]]}),
+ ?line command(P1,{ets,safe_fixtable,[Ets1,true]}),
+ ?line {_,[{P1,1}]} = ets:info(Ets1, safe_fixed),
+ ?line stop_commander(P1),
+ ?line undefined = ets:info(Ets1, safe_fixed),
+ ?line P2 = start_commander(),
+ ?line Ets2 = command(P2,{ets,new,[ets,[public]]}),
+ ?line command(P2,{ets,safe_fixtable,[Ets2,true]}),
+ ?line ets:safe_fixtable(Ets2,true),
+ ?line true = ets:info(Ets2, fixed),
+ ?line {_,[{_,1},{_,1}]} = ets:info(Ets2, safe_fixed),
+ ?line stop_commander(P2),
+ ?line undefined = ets:info(Ets2, safe_fixed),
+ ?line undefined = ets:info(Ets2, fixed),
+ ?line P3 = start_commander(),
+ ?line {ok,Dets} = ?LOG(command(P3, {dets, open_file,
+ [?DETS_TMP1,
+ [{file,
+ dets_filename(?DETS_TMP1,
+ Config)}]]})),
+ ?line command(P3, {dets, safe_fixtable, [Dets, true]}),
+ ?line {_,[{P3,1}]} = dets:info(Dets, safe_fixed),
+ ?line true = dets:info(Dets, fixed),
+ ?line stop_commander(P3),
+ ?line undefined = dets:info(Dets, safe_fixed),
+ ?line undefined = dets:info(Dets, fixed),
+ ?line P4 = start_commander(),
+ ?line {ok,Dets} = command(P4, {dets, open_file,
+ [?DETS_TMP1,
+ [{file, dets_filename(?DETS_TMP1,Config)}]]}),
+ ?line {ok,Dets} = dets:open_file(?DETS_TMP1,
+ [{file, dets_filename(?DETS_TMP1,Config)}]),
+ ?line false = dets:info(Dets, safe_fixed),
+ ?line command(P4, {dets, safe_fixtable, [Dets, true]}),
+ ?line dets:safe_fixtable(Dets, true),
+ ?line {_,[{_,1},{_,1}]} = dets:info(Dets, safe_fixed),
+ ?line dets:safe_fixtable(Dets, true),
+ ?line stop_commander(P4),
+ ?line S = self(),
+ ?line {_,[{S,2}]} = dets:info(Dets, safe_fixed),
+ ?line true = dets:info(Dets, fixed),
+ ?line dets:close(Dets),
+ ?line undefined = dets:info(Dets, fixed),
+ ?line undefined = dets:info(Dets, safe_fixed),
+ ok.
+
+
+other_process_closes(doc) ->
+ ["When another process closes an dets table, different "
+ "things should happen depending on if it has opened it before."];
+
+other_process_closes(suite) ->
+ [];
+
+other_process_closes(Config) when list(Config) ->
+ ?line {ok,Dets} = dets:open_file(?DETS_TMP1,
+ [{file, dets_filename(tmp1,Config)}]),
+ ?line P2 = start_commander(),
+ ?line dets:safe_fixtable(Dets,true),
+ ?line S = self(),
+ ?line {_,[{S,1}]} = dets:info(Dets, safe_fixed),
+ ?line command(P2,{dets, safe_fixtable, [Dets, true]}),
+ ?line {_,[_,_]} = dets:info(Dets, safe_fixed),
+ ?line {error, not_owner} = command(P2,{dets, close, [Dets]}),
+ ?line {_,[_,_]} = dets:info(Dets, safe_fixed),
+ ?line command(P2,{dets, open_file,[?DETS_TMP1,
+ [{file,
+ dets_filename(?DETS_TMP1, Config)}]]}),
+ ?line {_,[_,_]} = dets:info(Dets, safe_fixed),
+ ?line command(P2,{dets, close, [Dets]}),
+ ?line stop_commander(P2),
+ ?line {_,[{S,1}]} = dets:info(Dets, safe_fixed),
+ ?line true = dets:info(Dets,fixed),
+ ?line dets:close(Dets),
+ ?line undefined = dets:info(Dets,fixed),
+ ?line undefined = dets:info(Dets, safe_fixed),
+ ok.
+
+other_process_deletes(doc) ->
+ ["Check that fixtable structures are cleaned up if another process "
+ "deletes an ets table"];
+other_process_deletes(suite) ->
+ [];
+other_process_deletes(Config) when list(Config) ->
+ ?line Ets = ets:new(ets,[public]),
+ ?line P = start_commander(),
+ ?line ets:safe_fixtable(Ets,true),
+ ?line ets:safe_fixtable(Ets,true),
+ ?line true = ets:info(Ets, fixed),
+ ?line {_,_} = ets:info(Ets, safe_fixed),
+ ?line command(P,{ets,delete,[Ets]}),
+ ?line stop_commander(P),
+ ?line undefined = ets:info(Ets, fixed),
+ ?line undefined = ets:info(Ets, safe_fixed),
+ ok.
+
+multiple_fixes(doc) ->
+ ["Check that multiple safe_fixtable keeps the reference counter."];
+multiple_fixes(suite) ->
+ [];
+multiple_fixes(Config) when list(Config) ->
+ ?line {ok,Dets} = dets:open_file(?DETS_TMP1,
+ [{file, dets_filename(?DETS_TMP1,Config)}]),
+ ?line Ets = ets:new(ets,[]),
+ ?line multiple_fixes(Dets,dets),
+ ?line multiple_fixes(Ets,ets),
+ ?line dets:close(Dets),
+ ok.
+
+multiple_fixes(Tab, Mod) ->
+ ?line false = Mod:info(Tab,fixed),
+ ?line false = Mod:info(Tab, safe_fixed),
+ ?line Mod:safe_fixtable(Tab, true),
+ ?line true = Mod:info(Tab,fixed),
+ ?line S = self(),
+ ?line {_,[{S,1}]} = Mod:info(Tab, safe_fixed),
+ ?line Mod:safe_fixtable(Tab, true),
+ ?line Mod:safe_fixtable(Tab, true),
+ ?line {_,[{S,3}]} = Mod:info(Tab, safe_fixed),
+ ?line true = Mod:info(Tab,fixed),
+ ?line Mod:safe_fixtable(Tab, false),
+ ?line {_,[{S,2}]} = Mod:info(Tab, safe_fixed),
+ ?line true = Mod:info(Tab,fixed),
+ ?line Mod:safe_fixtable(Tab, false),
+ ?line {_,[{S,1}]} = Mod:info(Tab, safe_fixed),
+ ?line true = Mod:info(Tab,fixed),
+ ?line Mod:safe_fixtable(Tab, false),
+ ?line false = Mod:info(Tab, safe_fixed),
+ ?line false = Mod:info(Tab,fixed).
+
+multiple_processes(doc) ->
+ ["Check that multiple safe_fixtable across processes are reference "
+ "counted OK"];
+multiple_processes(suite) ->
+ [];
+multiple_processes(Config) when list(Config) ->
+ ?line {ok,Dets} = dets:open_file(?DETS_TMP1,[{file,
+ dets_filename(?DETS_TMP1,
+ Config)}]),
+ ?line Ets = ets:new(ets,[public]),
+ ?line multiple_processes(Dets,dets),
+ ?line multiple_processes(Ets,ets),
+ ok.
+
+multiple_processes(Tab, Mod) ->
+ ?line io:format("Mod = ~p\n", [Mod]),
+ ?line P1 = start_commander(),
+ ?line P2 = start_commander(),
+ ?line false = Mod:info(Tab,fixed),
+ ?line false = Mod:info(Tab, safe_fixed),
+ ?line command(P1, {Mod, safe_fixtable, [Tab,true]}),
+ ?line true = Mod:info(Tab,fixed),
+ ?line {_,[{P1,1}]} = Mod:info(Tab, safe_fixed),
+ ?line command(P2, {Mod, safe_fixtable, [Tab,true]}),
+ ?line true = Mod:info(Tab,fixed),
+ ?line {_,L} = Mod:info(Tab,safe_fixed),
+ ?line true = (lists:sort(L) == lists:sort([{P1,1},{P2,1}])),
+ ?line command(P2, {Mod, safe_fixtable, [Tab,true]}),
+ ?line {_,L2} = Mod:info(Tab,safe_fixed),
+ ?line true = (lists:sort(L2) == lists:sort([{P1,1},{P2,2}])),
+ ?line command(P2, {Mod, safe_fixtable, [Tab,false]}),
+ ?line true = Mod:info(Tab,fixed),
+ ?line {_,L3} = Mod:info(Tab,safe_fixed),
+ ?line true = (lists:sort(L3) == lists:sort([{P1,1},{P2,1}])),
+ ?line command(P2, {Mod, safe_fixtable, [Tab,false]}),
+ ?line true = Mod:info(Tab,fixed),
+ ?line {_,[{P1,1}]} = Mod:info(Tab, safe_fixed),
+ ?line stop_commander(P1),
+ ?line receive after 1000 -> ok end,
+ ?line false = Mod:info(Tab,fixed),
+ ?line false = Mod:info(Tab, safe_fixed),
+ ?line command(P2, {Mod, safe_fixtable, [Tab,true]}),
+ ?line true = Mod:info(Tab,fixed),
+ ?line {_,[{P2,1}]} = Mod:info(Tab, safe_fixed),
+ case Mod of
+ dets ->
+ ?line dets:close(Tab);
+ ets ->
+ ?line ets:delete(Tab)
+ end,
+ ?line stop_commander(P2),
+ ?line receive after 1000 -> ok end,
+ ?line undefined = Mod:info(Tab, safe_fixed),
+ ok.
+
+
+
+%%% Helpers
+dets_filename(Base, Config) when atom(Base) ->
+ dets_filename(atom_to_list(Base) ++ ".dat", Config);
+dets_filename(Basename, Config) ->
+ PrivDir = ?config(priv_dir,Config),
+ filename:join(PrivDir, Basename).
+
+command_loop() ->
+ receive
+ {From, command, {M,F,A}} ->
+ Res = (catch apply(M, F, A)),
+ From ! {self(), Res},
+ command_loop();
+ die ->
+ ok
+ end.
+
+start_commander() ->
+ spawn(?MODULE, command_loop, []).
+
+stop_commander(Pid) ->
+ process_flag(trap_exit, true),
+ link(Pid),
+ Pid ! die,
+ receive
+ {'EXIT',Pid,_} ->
+ timer:sleep(1), % let other processes handle the signal as well
+ true
+ after 5000 ->
+ exit(stop_timeout)
+ end.
+
+command(Pid,MFA) ->
+ Pid ! {self(), command, MFA},
+ receive
+ {Pid, Res} ->
+ Res
+ after 20000 ->
+ exit(command_timeout)
+ end.
+
+
+
diff --git a/lib/stdlib/test/format_SUITE.erl b/lib/stdlib/test/format_SUITE.erl
new file mode 100644
index 0000000000..2c415894f4
--- /dev/null
+++ b/lib/stdlib/test/format_SUITE.erl
@@ -0,0 +1,51 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1998-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(format_SUITE).
+-export([all/1]).
+
+-export([hang_1/1]).
+
+-export([init_per_testcase/2, fin_per_testcase/2]).
+
+-include("test_server.hrl").
+
+% Default timetrap timeout (set in init_per_testcase).
+-define(default_timeout, ?t:minutes(1)).
+
+init_per_testcase(_Case, Config) ->
+ ?line Dog = ?t:timetrap(?default_timeout),
+ [{watchdog, Dog} | Config].
+fin_per_testcase(_Case, Config) ->
+ Dog = ?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+all(doc) ->
+ ["Test cases for io:format/[2,3]."];
+all(suite) ->
+ [hang_1].
+
+hang_1(doc) ->
+ ["Bad args can hang (OTP-2400)"];
+hang_1(suite) ->
+ [];
+hang_1(Config) when list(Config) ->
+ ?line _ = (catch io:format(a, "", [])),
+ ?line _ = (catch io:format({}, "", [])),
+ ok.
diff --git a/lib/stdlib/test/gen_event_SUITE.erl b/lib/stdlib/test/gen_event_SUITE.erl
new file mode 100644
index 0000000000..dc5ddebf53
--- /dev/null
+++ b/lib/stdlib/test/gen_event_SUITE.erl
@@ -0,0 +1,846 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(gen_event_SUITE).
+
+-include("test_server.hrl").
+
+-export([all/1]).
+-export([start/1, test_all/1, add_handler/1, add_sup_handler/1,
+ delete_handler/1, swap_handler/1, swap_sup_handler/1,
+ notify/1, sync_notify/1, call/1, info/1, hibernate/1]).
+
+all(suite) -> {req, [stdlib], [start, test_all, hibernate]}.
+
+%% --------------------------------------
+%% Start an event manager.
+%% --------------------------------------
+
+start(doc) -> [];
+start(suite) -> [];
+start(Config) when list(Config) ->
+ OldFl = process_flag(trap_exit, true),
+
+ ?line {ok, Pid0} = gen_event:start(), %anonymous
+ ?line [] = gen_event:which_handlers(Pid0),
+ ?line ok = gen_event:stop(Pid0),
+
+ ?line {ok, Pid1} = gen_event:start_link(), %anonymous
+ ?line [] = gen_event:which_handlers(Pid1),
+ ?line ok = gen_event:stop(Pid1),
+
+ ?line {ok, Pid2} = gen_event:start({local, my_dummy_name}),
+ ?line [] = gen_event:which_handlers(my_dummy_name),
+ ?line [] = gen_event:which_handlers(Pid2),
+ ?line ok = gen_event:stop(my_dummy_name),
+
+ ?line {ok, Pid3} = gen_event:start_link({local, my_dummy_name}),
+ ?line [] = gen_event:which_handlers(my_dummy_name),
+ ?line [] = gen_event:which_handlers(Pid3),
+ ?line ok = gen_event:stop(my_dummy_name),
+
+ ?line {ok, Pid4} = gen_event:start_link({global, my_dummy_name}),
+ ?line [] = gen_event:which_handlers({global, my_dummy_name}),
+ ?line [] = gen_event:which_handlers(Pid4),
+ ?line ok = gen_event:stop({global, my_dummy_name}),
+
+ ?line {ok, _} = gen_event:start_link({local, my_dummy_name}),
+ ?line {error, {already_started, _}} =
+ gen_event:start_link({local, my_dummy_name}),
+ ?line {error, {already_started, _}} =
+ gen_event:start({local, my_dummy_name}),
+ ?line ok = gen_event:stop(my_dummy_name),
+
+ ?line {ok, Pid5} = gen_event:start_link({global, my_dummy_name}),
+ ?line {error, {already_started, _}} =
+ gen_event:start_link({global, my_dummy_name}),
+ ?line {error, {already_started, _}} =
+ gen_event:start({global, my_dummy_name}),
+
+ exit(Pid5, shutdown),
+ receive
+ {'EXIT', Pid5, shutdown} -> ok
+ after 10000 ->
+ ?t:fail(exit_gen_event)
+ end,
+
+ ?t:messages_get(),
+ process_flag(trap_exit, OldFl),
+ ok.
+
+
+hibernate(suite) -> [];
+hibernate(Config) when is_list(Config) ->
+ ?line {ok,Pid} = gen_event:start({local, my_dummy_handler}),
+ ?line ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
+ ?line [dummy_h] = gen_event:which_handlers(my_dummy_handler),
+ ?line true = gen_event:call(my_dummy_handler, dummy_h, hibernate),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} = erlang:process_info(Pid,current_function),
+ ?line Pid ! wake,
+ ?line receive after 1000 -> ok end,
+ ?line true = ({current_function,{erlang,hibernate,3}} =/=
+ erlang:process_info(Pid,current_function)),
+ ?line later = gen_event:call(my_dummy_handler, dummy_h, hibernate_later),
+ ?line true = ({current_function,{erlang,hibernate,3}} =/=
+ erlang:process_info(Pid,current_function)),
+ ?line receive after 2000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} = erlang:process_info(Pid,current_function),
+ ?line Pid ! wake,
+ ?line receive after 1000 -> ok end,
+ ?line true = ({current_function,{erlang,hibernate,3}} =/=
+ erlang:process_info(Pid,current_function)),
+ ?line gen_event:notify(my_dummy_handler,hibernate),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} = erlang:process_info(Pid,current_function),
+ ?line gen_event:notify(my_dummy_handler,wakeup),
+ ?line receive after 1000 -> ok end,
+ ?line true = ({current_function,{erlang,hibernate,3}} =/=
+ erlang:process_info(Pid,current_function)),
+ ?line gen_event:notify(my_dummy_handler,hibernate),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} = erlang:process_info(Pid,current_function),
+ ?line gen_event:sync_notify(my_dummy_handler,wakeup),
+ ?line true = ({current_function,{erlang,hibernate,3}} =/=
+ erlang:process_info(Pid,current_function)),
+ ?line ok = gen_event:sync_notify(my_dummy_handler,hibernate),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} = erlang:process_info(Pid,current_function),
+ ?line Pid ! wake,
+ ?line receive after 1000 -> ok end,
+ ?line true = ({current_function,{erlang,hibernate,3}} =/=
+ erlang:process_info(Pid,current_function)),
+ ?line ok = gen_event:add_handler(my_dummy_handler, dummy1_h, [self()]),
+ ?line [_,_] = gen_event:which_handlers(my_dummy_handler),
+ ?line gen_event:notify(my_dummy_handler,hibernate),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} = erlang:process_info(Pid,current_function),
+ ?line gen_event:notify(my_dummy_handler,wakeup),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} = erlang:process_info(Pid,current_function),
+ ?line Pid ! wake,
+ ?line receive after 1000 -> ok end,
+ ?line true = ({current_function,{erlang,hibernate,3}} =/=
+ erlang:process_info(Pid,current_function)),
+ ?line Pid ! gnurf,
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} = erlang:process_info(Pid,current_function),
+ ?line Pid ! sleep,
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} = erlang:process_info(Pid,current_function),
+ ?line Pid ! wake,
+ ?line receive after 1000 -> ok end,
+ ?line true = ({current_function,{erlang,hibernate,3}} =/=
+ erlang:process_info(Pid,current_function)),
+ ?line ok = gen_event:stop(my_dummy_handler),
+ ?line {ok,Pid2} = gen_event:start({local, my_dummy_handler}),
+ ?line ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self(),hibernate]),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} = erlang:process_info(Pid2,current_function),
+ ?line sys:suspend(my_dummy_handler),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} = erlang:process_info(Pid2,current_function),
+ ?line sys:resume(my_dummy_handler),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} = erlang:process_info(Pid2,current_function),
+ ?line Pid2 ! wake,
+ ?line receive after 1000 -> ok end,
+ ?line true = ({current_function,{erlang,hibernate,3}} =/=
+ erlang:process_info(Pid2,current_function)),
+
+
+ ?line ok = gen_event:stop(my_dummy_handler),
+
+ ok.
+
+
+test_all(suite) -> [add_handler, add_sup_handler, delete_handler,
+ swap_handler, swap_sup_handler, notify,
+ sync_notify, call, info].
+
+add_handler(doc) -> [];
+add_handler(suite) -> [];
+add_handler(Config) when list(Config) ->
+ ?line {ok,_} = gen_event:start({local, my_dummy_handler}),
+ ?line {error, my_error} =
+ gen_event:add_handler(my_dummy_handler, dummy_h, make_error),
+ ?line [] = gen_event:which_handlers(my_dummy_handler),
+ ?line ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
+ ?line [dummy_h] = gen_event:which_handlers(my_dummy_handler),
+
+ ?line {error, my_error} =
+ gen_event:add_handler(my_dummy_handler, {dummy_h, self()}, make_error),
+ ?line [dummy_h] = gen_event:which_handlers(my_dummy_handler),
+ ?line ok = gen_event:add_handler(my_dummy_handler, {dummy_h,self()},
+ [self()]),
+ Self = self(),
+ ?line [{dummy_h, Self}, dummy_h] =
+ gen_event:which_handlers(my_dummy_handler),
+ ?line ok = gen_event:stop(my_dummy_handler),
+ ok.
+
+add_sup_handler(doc) -> [];
+add_sup_handler(suite) -> [];
+add_sup_handler(Config) when list(Config) ->
+ ?line {ok,Pid} = gen_event:start({local, my_dummy_handler}),
+ ?line {error, my_error} =
+ gen_event:add_sup_handler(my_dummy_handler, dummy_h, make_error),
+ ?line [] = gen_event:which_handlers(my_dummy_handler),
+ ?line ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
+ ?line [dummy_h] = gen_event:which_handlers(my_dummy_handler),
+ ?line exit(Pid, sup_died),
+ ?t:sleep(1000),
+ ?line [] = gen_event:which_handlers(my_dummy_handler),
+
+ ?line ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
+ ?line [dummy_h] = gen_event:which_handlers(my_dummy_handler),
+
+ ?line {error, my_error} =
+ gen_event:add_handler(my_dummy_handler, {dummy_h, self()}, make_error),
+ ?line [dummy_h] = gen_event:which_handlers(my_dummy_handler),
+ ?line ok = gen_event:add_sup_handler(my_dummy_handler, {dummy_h,self()},
+ [self()]),
+ Self = self(),
+ ?line [{dummy_h, Self}, dummy_h] =
+ gen_event:which_handlers(my_dummy_handler),
+ ?line ok = gen_event:stop(my_dummy_handler),
+
+ ?line receive
+ {gen_event_EXIT, dummy_h, shutdown} ->
+ ok
+ after 1000 ->
+ ?t:fail({no,{gen_event_EXIT, dummy_h, shutdown}})
+ end,
+
+ ?line receive
+ {gen_event_EXIT, {dummy_h,Self}, shutdown} ->
+ ok
+ after 1000 ->
+ ?t:fail({no,{gen_event_EXIT, {dummy_h,Self},
+ shutdown}})
+ end,
+ ok.
+
+delete_handler(doc) -> [];
+delete_handler(suite) -> [];
+delete_handler(Config) when list(Config) ->
+ ?line {ok,_} = gen_event:start({local, my_dummy_handler}),
+ ?line ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
+ ?line {error, module_not_found} =
+ gen_event:delete_handler(my_dummy_handler, duuuuuuuuumy, []),
+ ?line return_hej =
+ gen_event:delete_handler(my_dummy_handler, dummy_h, return_hej),
+ ?line [] = gen_event:which_handlers(my_dummy_handler),
+ ?line ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
+ ?line ok =
+ gen_event:delete_handler(my_dummy_handler, dummy_h, []),
+ ?line [] = gen_event:which_handlers(my_dummy_handler),
+
+ ?line ok = gen_event:add_handler(my_dummy_handler, {dummy_h,1}, [self()]),
+ ?line ok = gen_event:add_handler(my_dummy_handler, {dummy_h,2}, [self()]),
+ ?line {error, module_not_found} =
+ gen_event:delete_handler(my_dummy_handler, {duuuuuuuuumy,1}, []),
+ ?line return_hej =
+ gen_event:delete_handler(my_dummy_handler, {dummy_h,1}, return_hej),
+ ?line return_hej =
+ gen_event:delete_handler(my_dummy_handler, {dummy_h,2}, return_hej),
+ ?line [] = gen_event:which_handlers(my_dummy_handler),
+ ?line ok = gen_event:add_handler(my_dummy_handler, {dummy_h,2}, [self()]),
+ ?line ok =
+ gen_event:delete_handler(my_dummy_handler, {dummy_h,2}, []),
+ ?line [] = gen_event:which_handlers(my_dummy_handler),
+
+ ?line ok = gen_event:stop(my_dummy_handler),
+ ok.
+
+swap_handler(doc) -> [];
+swap_handler(suite) -> [];
+swap_handler(Config) when list(Config) ->
+ ?line {ok,_} = gen_event:start({local, my_dummy_handler}),
+ ?line ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
+ ?line {error, non_existing} =
+ gen_event:swap_handler(my_dummy_handler, {faulty_h, swap},
+ {dummy1_h, []}),
+ ?line ok =
+ gen_event:swap_handler(my_dummy_handler, {dummy_h, swap},
+ {dummy1_h, swap}),
+ ?line [dummy1_h] = gen_event:which_handlers(my_dummy_handler),
+
+ ?line ok = gen_event:delete_handler(my_dummy_handler, dummy1_h, []),
+
+ ?line ok = gen_event:add_handler(my_dummy_handler, {dummy_h,3}, [self()]),
+ ?line {error, non_existing} =
+ gen_event:swap_handler(my_dummy_handler, {faulty_h, swap},
+ {dummy1_h, []}),
+ ?line ok =
+ gen_event:swap_handler(my_dummy_handler, {{dummy_h,3}, swap},
+ {{dummy1_h,4}, swap}),
+ ?line [{dummy1_h,4}] = gen_event:which_handlers(my_dummy_handler),
+
+ ?line ok = gen_event:delete_handler(my_dummy_handler, {dummy1_h,4}, []),
+
+ ?line ok = gen_event:stop(my_dummy_handler),
+ ok.
+
+swap_sup_handler(doc) -> [];
+swap_sup_handler(suite) -> [];
+swap_sup_handler(Config) when list(Config) ->
+ ?line {ok,_} = gen_event:start({local, my_dummy_handler}),
+ ?line ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
+ ?line {error, non_existing} =
+ gen_event:swap_handler(my_dummy_handler, {faulty_h, swap},
+ {dummy1_h, []}),
+ ?line ok =
+ gen_event:swap_handler(my_dummy_handler, {dummy_h, swap},
+ {dummy1_h, swap}),
+ ?line [dummy1_h] = gen_event:which_handlers(my_dummy_handler),
+
+ ?line ok = gen_event:delete_handler(my_dummy_handler, dummy1_h, []),
+ ?line receive
+ {gen_event_EXIT, dummy1_h, normal} ->
+ ok
+ after 1000 ->
+ ?t:fail({no,{gen_event_EXIT, dummy1_h, normal}})
+ end,
+
+ ?line ok = gen_event:add_sup_handler(my_dummy_handler, {dummy_h,3},
+ [self()]),
+ ?line {error, non_existing} =
+ gen_event:swap_sup_handler(my_dummy_handler, {faulty_h, swap},
+ {dummy1_h, []}),
+ ?line ok =
+ gen_event:swap_sup_handler(my_dummy_handler, {{dummy_h,3}, swap},
+ {{dummy1_h,4}, swap}),
+ ?line [{dummy1_h,4}] = gen_event:which_handlers(my_dummy_handler),
+
+ ?line ok = gen_event:delete_handler(my_dummy_handler, {dummy1_h,4}, []),
+ ?line receive
+ {gen_event_EXIT, {dummy1_h,4}, normal} ->
+ ok
+ after 1000 ->
+ ?t:fail({no,{gen_event_EXIT, {dummy1_h,4}, normal}})
+ end,
+
+ ?line ok = gen_event:stop(my_dummy_handler),
+ ok.
+
+notify(doc) -> [];
+notify(suite) -> [];
+notify(Config) when list(Config) ->
+ ?line {ok,_} = gen_event:start({local, my_dummy_handler}),
+ ?line ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
+ Event = {event, self()},
+ ?line [dummy_h] = gen_event:which_handlers(my_dummy_handler),
+ ?line ok = gen_event:notify(my_dummy_handler, Event),
+ ?line receive
+ {dummy_h, Event} ->
+ ok
+ end,
+ ?line ok = gen_event:notify(my_dummy_handler, {swap_event,dummy1_h,swap}),
+ ?t:sleep(1000),
+ ?line [dummy1_h] = gen_event:which_handlers(my_dummy_handler),
+ ?line ok = gen_event:notify(my_dummy_handler, Event),
+ ?line receive
+ {dummy1_h, Event} ->
+ ok
+ end,
+ ?line ok = gen_event:notify(my_dummy_handler, delete_event),
+ ?line receive
+ {dummy1_h, removed} ->
+ ok
+ end,
+ ?line [] = gen_event:which_handlers(my_dummy_handler),
+ ?line ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
+
+ ?line ok = gen_event:notify(my_dummy_handler, error_event),
+ ?line receive
+ {dummy_h, returned_error} ->
+ ok
+ end,
+ ?line [] = gen_event:which_handlers(my_dummy_handler),
+
+ %% Handler with id, {Mod,Id}
+
+ ?line ok = gen_event:add_handler(my_dummy_handler, {dummy_h,5}, [self()]),
+ ?line [{dummy_h,5}] = gen_event:which_handlers(my_dummy_handler),
+ ?line ok = gen_event:notify(my_dummy_handler, Event),
+ ?line receive
+ {dummy_h, Event} ->
+ ok
+ end,
+ ?line ok = gen_event:notify(my_dummy_handler,
+ {swap_event, {dummy1_h, 9}, swap}),
+ ?t:sleep(1000),
+ ?line [{dummy1_h,9}] = gen_event:which_handlers(my_dummy_handler),
+ ?line ok = gen_event:notify(my_dummy_handler, Event),
+ ?line receive
+ {dummy1_h, Event} ->
+ ok
+ end,
+ ?line ok = gen_event:notify(my_dummy_handler, delete_event),
+ ?line receive
+ {dummy1_h, removed} ->
+ ok
+ end,
+ ?line [] = gen_event:which_handlers(my_dummy_handler),
+ ?line ok = gen_event:add_handler(my_dummy_handler, {dummy_h,a}, [self()]),
+
+ ?line ok = gen_event:notify(my_dummy_handler, error_event),
+ ?line receive
+ {dummy_h, returned_error} ->
+ ok
+ end,
+ ?line [] = gen_event:which_handlers(my_dummy_handler),
+
+ %% Supervised handler.
+
+ ?line ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
+ ?line [dummy_h] = gen_event:which_handlers(my_dummy_handler),
+ ?line ok = gen_event:notify(my_dummy_handler, Event),
+ ?line receive
+ {dummy_h, Event} ->
+ ok
+ end,
+
+ ?line ok = gen_event:notify(my_dummy_handler, do_crash),
+ ?line receive
+ {gen_event_EXIT, dummy_h, {'EXIT',_}} ->
+ ok
+ end,
+
+ ?line ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
+ ?line ok = gen_event:notify(my_dummy_handler, {swap_event,dummy1_h,swap}),
+ ?t:sleep(1000),
+ ?line [dummy1_h] = gen_event:which_handlers(my_dummy_handler),
+
+ ?line ok = gen_event:notify(my_dummy_handler, do_crash),
+ ?line receive
+ {gen_event_EXIT, dummy1_h, {'EXIT',_}} ->
+ ok
+ end,
+
+ ?line ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
+ ?line ok = gen_event:notify(my_dummy_handler, {swap_event,dummy1_h,swap}),
+ ?t:sleep(1000),
+ ?line [dummy1_h] = gen_event:which_handlers(my_dummy_handler),
+
+ ?line ok = gen_event:notify(my_dummy_handler, delete_event),
+ ?line receive
+ {dummy1_h, removed} ->
+ ok
+ end,
+
+ ?line receive
+ {gen_event_EXIT, dummy1_h, normal} ->
+ ok
+ end,
+
+ ?line [] = gen_event:which_handlers(my_dummy_handler),
+
+ ?line ok = gen_event:stop(my_dummy_handler),
+ ok.
+
+sync_notify(doc) -> [];
+sync_notify(suite) -> [];
+sync_notify(Config) when list(Config) ->
+ ?line {ok,_} = gen_event:start({local, my_dummy_handler}),
+ ?line ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
+ Event = {event, self()},
+ ?line [dummy_h] = gen_event:which_handlers(my_dummy_handler),
+ ?line ok = gen_event:sync_notify(my_dummy_handler, Event),
+ ?line receive
+ {dummy_h, Event} ->
+ ok
+ end,
+ ?line ok = gen_event:sync_notify(my_dummy_handler,
+ {swap_event, dummy1_h, swap}),
+ ?t:sleep(1000),
+ ?line [dummy1_h] = gen_event:which_handlers(my_dummy_handler),
+ ?line ok = gen_event:sync_notify(my_dummy_handler, Event),
+ ?line receive
+ {dummy1_h, Event} ->
+ ok
+ end,
+ ?line ok = gen_event:sync_notify(my_dummy_handler, delete_event),
+ ?line receive
+ {dummy1_h, removed} ->
+ ok
+ end,
+ ?line [] = gen_event:which_handlers(my_dummy_handler),
+ ?line ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
+
+ ?line ok = gen_event:sync_notify(my_dummy_handler, error_event),
+ ?line receive
+ {dummy_h, returned_error} ->
+ ok
+ end,
+ ?line [] = gen_event:which_handlers(my_dummy_handler),
+
+ %% Handler with id, {Mod,Id}
+
+ ?line ok = gen_event:add_handler(my_dummy_handler, {dummy_h,5}, [self()]),
+ ?line [{dummy_h,5}] = gen_event:which_handlers(my_dummy_handler),
+ ?line ok = gen_event:sync_notify(my_dummy_handler, Event),
+ ?line receive
+ {dummy_h, Event} ->
+ ok
+ end,
+ ?line ok = gen_event:sync_notify(my_dummy_handler,
+ {swap_event, {dummy1_h, 9}, swap}),
+ ?t:sleep(1000),
+ ?line [{dummy1_h,9}] = gen_event:which_handlers(my_dummy_handler),
+ ?line ok = gen_event:sync_notify(my_dummy_handler, Event),
+ ?line receive
+ {dummy1_h, Event} ->
+ ok
+ end,
+ ?line ok = gen_event:sync_notify(my_dummy_handler, delete_event),
+ ?line receive
+ {dummy1_h, removed} ->
+ ok
+ end,
+ ?line [] = gen_event:which_handlers(my_dummy_handler),
+ ?line ok = gen_event:add_handler(my_dummy_handler, {dummy_h,a}, [self()]),
+
+ ?line ok = gen_event:sync_notify(my_dummy_handler, error_event),
+ ?line receive
+ {dummy_h, returned_error} ->
+ ok
+ end,
+ ?line [] = gen_event:which_handlers(my_dummy_handler),
+
+ %% Supervised handler.
+
+ ?line ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
+ ?line [dummy_h] = gen_event:which_handlers(my_dummy_handler),
+ ?line ok = gen_event:sync_notify(my_dummy_handler, Event),
+ ?line receive
+ {dummy_h, Event} ->
+ ok
+ end,
+
+ ?line ok = gen_event:sync_notify(my_dummy_handler, do_crash),
+ ?line receive
+ {gen_event_EXIT, dummy_h, {'EXIT',_}} ->
+ ok
+ end,
+
+ ?line ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
+ ?line ok = gen_event:sync_notify(my_dummy_handler,
+ {swap_event,dummy1_h,swap}),
+ ?t:sleep(1000),
+ ?line [dummy1_h] = gen_event:which_handlers(my_dummy_handler),
+
+ ?line ok = gen_event:sync_notify(my_dummy_handler, do_crash),
+ ?line receive
+ {gen_event_EXIT, dummy1_h, {'EXIT',_}} ->
+ ok
+ end,
+
+ ?line ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
+ ?line ok = gen_event:sync_notify(my_dummy_handler,
+ {swap_event,dummy1_h,swap}),
+ ?t:sleep(1000),
+ ?line [dummy1_h] = gen_event:which_handlers(my_dummy_handler),
+
+ ?line ok = gen_event:sync_notify(my_dummy_handler, delete_event),
+ ?line receive
+ {dummy1_h, removed} ->
+ ok
+ end,
+
+ ?line receive
+ {gen_event_EXIT, dummy1_h, normal} ->
+ ok
+ end,
+
+ ?line [] = gen_event:which_handlers(my_dummy_handler),
+
+ ?line ok = gen_event:stop(my_dummy_handler),
+ ok.
+
+call(doc) -> [];
+call(suite) -> [];
+call(Config) when list(Config) ->
+ ?line {ok,_} = gen_event:start({local, my_dummy_handler}),
+ ?line ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
+ ?line ok = gen_event:add_handler(my_dummy_handler, {dummy_h, 1}, [self()]),
+ ?line [{dummy_h, 1}, dummy_h] = gen_event:which_handlers(my_dummy_handler),
+ ?line {'EXIT',_} = (catch gen_event:call(non_exist, dummy_h, hejsan)),
+ ?line {error, bad_module} =
+ gen_event:call(my_dummy_handler, bad_h, hejsan),
+ ?line {ok, hejhopp} = gen_event:call(my_dummy_handler, dummy_h, hejsan),
+ ?line {ok, hejhopp} = gen_event:call(my_dummy_handler, {dummy_h, 1},
+ hejsan),
+ ?line {ok, hejhopp} = gen_event:call(my_dummy_handler, dummy_h, hejsan,
+ 10000),
+ ?line {'EXIT', {timeout, _}} =
+ (catch gen_event:call(my_dummy_handler, dummy_h, hejsan, 0)),
+ flush(),
+ ?line ok = gen_event:delete_handler(my_dummy_handler, {dummy_h, 1}, []),
+ ?line {ok, swapped} = gen_event:call(my_dummy_handler, dummy_h,
+ {swap_call,dummy1_h,swap}),
+ ?line [dummy1_h] = gen_event:which_handlers(my_dummy_handler),
+ ?line {error, bad_module} =
+ gen_event:call(my_dummy_handler, dummy_h, hejsan),
+ ?line ok = gen_event:call(my_dummy_handler, dummy1_h, delete_call),
+ ?line receive
+ {dummy1_h, removed} ->
+ ok
+ end,
+ ?line [] = gen_event:which_handlers(my_dummy_handler),
+ ?line ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
+
+ ?line {error, {return, faulty}} =
+ gen_event:call(my_dummy_handler, dummy_h, error_call),
+ ?line receive
+ {dummy_h, returned_error} ->
+ ok
+ end,
+ ?line [] = gen_event:which_handlers(my_dummy_handler),
+ ?line ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
+
+ ?line {error, {'EXIT', _}} =
+ gen_event:call(my_dummy_handler, dummy_h, exit_call),
+
+ ?line [] = gen_event:which_handlers(my_dummy_handler),
+
+ %% Handler with id, {Mod,Id}
+
+ ?line ok = gen_event:add_handler(my_dummy_handler, {dummy_h,1}, [self()]),
+ ?line [{dummy_h,1}] = gen_event:which_handlers(my_dummy_handler),
+ ?line {error, bad_module} =
+ gen_event:call(my_dummy_handler, bad_h, hejsan),
+ ?line {ok, hejhopp} = gen_event:call(my_dummy_handler, {dummy_h,1},
+ hejsan),
+ ?line {ok, swapped} = gen_event:call(my_dummy_handler, {dummy_h,1},
+ {swap_call,{dummy1_h,2},swap}),
+ ?line [{dummy1_h,2}] = gen_event:which_handlers(my_dummy_handler),
+ ?line {error, bad_module} =
+ gen_event:call(my_dummy_handler, dummy_h, hejsan),
+ ?line ok = gen_event:call(my_dummy_handler, {dummy1_h,2}, delete_call),
+ ?line receive
+ {dummy1_h, removed} ->
+ ok
+ end,
+ ?line [] = gen_event:which_handlers(my_dummy_handler),
+ ?line ok = gen_event:add_handler(my_dummy_handler, {dummy_h,3}, [self()]),
+
+ ?line {error, {return, faulty}} =
+ gen_event:call(my_dummy_handler, {dummy_h,3}, error_call),
+ ?line receive
+ {dummy_h, returned_error} ->
+ ok
+ end,
+ ?line [] = gen_event:which_handlers(my_dummy_handler),
+ ?line ok = gen_event:add_handler(my_dummy_handler, {dummy_h,4}, [self()]),
+
+ ?line {error, {'EXIT', _}} =
+ gen_event:call(my_dummy_handler, {dummy_h,4}, exit_call),
+
+ ?line [] = gen_event:which_handlers(my_dummy_handler),
+
+ %% Supervised handler.
+
+ ?line ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
+ ?line [dummy_h] = gen_event:which_handlers(my_dummy_handler),
+ ?line {error, bad_module} =
+ gen_event:call(my_dummy_handler, bad_h, hejsan),
+ ?line {ok, hejhopp} = gen_event:call(my_dummy_handler, dummy_h, hejsan),
+ ?line {ok, swapped} = gen_event:call(my_dummy_handler, dummy_h,
+ {swap_call,dummy1_h,swap}),
+ ?line [dummy1_h] = gen_event:which_handlers(my_dummy_handler),
+ ?line {error, bad_module} =
+ gen_event:call(my_dummy_handler, dummy_h, hejsan),
+ ?line ok = gen_event:call(my_dummy_handler, dummy1_h, delete_call),
+ ?line receive
+ {dummy1_h, removed} ->
+ ok
+ end,
+
+ ?line receive
+ {gen_event_EXIT, dummy1_h, normal} ->
+ ok
+ end,
+
+ ?line [] = gen_event:which_handlers(my_dummy_handler),
+ ?line ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
+
+ ?line {error, {return, faulty}} =
+ gen_event:call(my_dummy_handler, dummy_h, error_call),
+ ?line receive
+ {dummy_h, returned_error} ->
+ ok
+ end,
+
+ ?line receive
+ {gen_event_EXIT, dummy_h, {return,faulty}} ->
+ ok
+ after 1000 ->
+ ?t:fail({no, {gen_event_EXIT, dummy_h, {return,faulty}}})
+ end,
+
+ ?line [] = gen_event:which_handlers(my_dummy_handler),
+ ?line ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
+
+ ?line {error, {'EXIT', _}} =
+ gen_event:call(my_dummy_handler, dummy_h, exit_call),
+
+ ?line receive
+ {gen_event_EXIT, dummy_h, {'EXIT',_}} ->
+ ok
+ after 1000 ->
+ ?t:fail({no, {gen_event_EXIT, dummy_h, {'EXIT','_'}}})
+ end,
+
+ ?line [] = gen_event:which_handlers(my_dummy_handler),
+
+ ?line ok = gen_event:stop(my_dummy_handler),
+ ok.
+
+flush() ->
+ receive _ -> flush() after 0 -> ok end.
+
+info(doc) -> [];
+info(suite) -> [];
+info(Config) when list(Config) ->
+ ?line {ok,_} = gen_event:start({local, my_dummy_handler}),
+ ?line ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
+ Info = {info, self()},
+ ?line [dummy_h] = gen_event:which_handlers(my_dummy_handler),
+ ?line my_dummy_handler ! Info,
+ ?line receive
+ {dummy_h, Info} ->
+ ok
+ end,
+ ?line my_dummy_handler ! {swap_info,dummy1_h,swap},
+ ?t:sleep(1000),
+ ?line [dummy1_h] = gen_event:which_handlers(my_dummy_handler),
+ ?line my_dummy_handler ! Info,
+ ?line receive
+ {dummy1_h, Info} ->
+ ok
+ end,
+ ?line my_dummy_handler ! delete_info,
+ ?line receive
+ {dummy1_h, removed} ->
+ ok
+ end,
+ ?line [] = gen_event:which_handlers(my_dummy_handler),
+ ?line ok = gen_event:add_handler(my_dummy_handler, dummy_h, [self()]),
+
+ ?line my_dummy_handler ! error_info,
+ ?line receive
+ {dummy_h, returned_error} ->
+ ok
+ end,
+ ?line [] = gen_event:which_handlers(my_dummy_handler),
+
+ %% Handler with id, {Mod,Id}
+
+ ?line ok = gen_event:add_handler(my_dummy_handler, {dummy_h,1}, [self()]),
+ ?line [{dummy_h,1}] = gen_event:which_handlers(my_dummy_handler),
+ ?line my_dummy_handler ! Info,
+ ?line receive
+ {dummy_h, Info} ->
+ ok
+ end,
+ ?line my_dummy_handler ! {swap_info,{dummy1_h,2},swap},
+ ?t:sleep(1000),
+ ?line [{dummy1_h,2}] = gen_event:which_handlers(my_dummy_handler),
+ ?line my_dummy_handler ! Info,
+ ?line receive
+ {dummy1_h, Info} ->
+ ok
+ end,
+ ?line my_dummy_handler ! delete_info,
+ ?line receive
+ {dummy1_h, removed} ->
+ ok
+ end,
+ ?line [] = gen_event:which_handlers(my_dummy_handler),
+ ?line ok = gen_event:add_handler(my_dummy_handler, {dummy_h,3}, [self()]),
+
+ ?line my_dummy_handler ! error_info,
+ ?line receive
+ {dummy_h, returned_error} ->
+ ok
+ end,
+ ?line [] = gen_event:which_handlers(my_dummy_handler),
+
+ %% Supervised handler
+
+ ?line ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
+ ?line [dummy_h] = gen_event:which_handlers(my_dummy_handler),
+ ?line my_dummy_handler ! Info,
+ ?line receive
+ {dummy_h, Info} ->
+ ok
+ end,
+ ?line my_dummy_handler ! {swap_info,dummy1_h,swap},
+ ?t:sleep(1000),
+ ?line [dummy1_h] = gen_event:which_handlers(my_dummy_handler),
+ ?line my_dummy_handler ! Info,
+ ?line receive
+ {dummy1_h, Info} ->
+ ok
+ end,
+ ?line my_dummy_handler ! delete_info,
+ ?line receive
+ {dummy1_h, removed} ->
+ ok
+ end,
+
+ ?line receive
+ {gen_event_EXIT, dummy1_h, normal} ->
+ ok
+ after 1000 ->
+ ?t:fail({no, {gen_event_EXIT, dummy1_h, normal}})
+ end,
+
+ ?line [] = gen_event:which_handlers(my_dummy_handler),
+
+ ?line ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
+
+ ?line my_dummy_handler ! error_info,
+ ?line receive
+ {dummy_h, returned_error} ->
+ ok
+ end,
+
+ ?line receive
+ {gen_event_EXIT, dummy_h, {return,faulty}} ->
+ ok
+ after 1000 ->
+ ?t:fail({no, {gen_event_EXIT, dummy_h, {return,faulty}}})
+ end,
+
+ ?line ok = gen_event:add_sup_handler(my_dummy_handler, dummy_h, [self()]),
+ ?line my_dummy_handler ! do_crash,
+
+ ?line receive
+ {gen_event_EXIT, dummy_h, {'EXIT',_}} ->
+ ok
+ after 1000 ->
+ ?t:fail({no, {gen_event_EXIT, dummy_h, {'EXIT','_'}}})
+ end,
+
+ ?line [] = gen_event:which_handlers(my_dummy_handler),
+
+ ?line ok = gen_event:stop(my_dummy_handler),
+ ok.
diff --git a/lib/stdlib/test/gen_fsm_SUITE.erl b/lib/stdlib/test/gen_fsm_SUITE.erl
new file mode 100644
index 0000000000..62f8b2f9dd
--- /dev/null
+++ b/lib/stdlib/test/gen_fsm_SUITE.erl
@@ -0,0 +1,838 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(gen_fsm_SUITE).
+
+-include("test_server.hrl").
+
+%% Test cases
+-export([all/1]).
+
+-export([start/1, start1/1, start2/1, start3/1, start4/1 , start5/1, start6/1,
+ start7/1, start8/1, start9/1, start10/1, start11/1]).
+
+-export([abnormal/1, abnormal1/1, abnormal2/1]).
+
+-export([shutdown/1]).
+
+-export([sys/1, sys1/1]).
+
+-export([hibernate/1,hiber_idle/3,hiber_wakeup/3,hiber_idle/2,hiber_wakeup/2]).
+
+-export([enter_loop/1]).
+
+%% Exports for apply
+-export([do_msg/1, do_sync_msg/1]).
+-export([enter_loop/2]).
+
+% The gen_fsm behaviour
+-export([init/1, handle_event/3, handle_sync_event/4, terminate/3,
+ handle_info/3]).
+-export([idle/2, idle/3,
+ timeout/2,
+ wfor_conf/2, wfor_conf/3,
+ connected/2, connected/3]).
+-export([state0/3]).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+all(suite) ->
+ [start, abnormal, shutdown, sys, hibernate, enter_loop].
+
+
+
+start(suite) -> [start1, start2, start3, start4, start5, start6, start7,
+ start8, start9, start10, start11].
+
+%% anonymous
+start1(Config) when is_list(Config) ->
+ %%OldFl = process_flag(trap_exit, true),
+
+ ?line {ok, Pid0} = gen_fsm:start_link(gen_fsm_SUITE, [], []),
+ ?line ok = do_func_test(Pid0),
+ ?line ok = do_sync_func_test(Pid0),
+ stop_it(Pid0),
+%% ?line stopped = gen_fsm:sync_send_all_state_event(Pid0, stop),
+%% ?line {'EXIT', {timeout,_}} =
+%% (catch gen_fsm:sync_send_event(Pid0, hej)),
+
+ ?line test_server:messages_get(),
+ %%process_flag(trap_exit, OldFl),
+ ok.
+
+%% anonymous w. shutdown
+start2(Config) when is_list(Config) ->
+ %% Dont link when shutdown
+ ?line {ok, Pid0} = gen_fsm:start(gen_fsm_SUITE, [], []),
+ ?line ok = do_func_test(Pid0),
+ ?line ok = do_sync_func_test(Pid0),
+ ?line shutdown_stopped =
+ gen_fsm:sync_send_all_state_event(Pid0, stop_shutdown),
+ ?line {'EXIT', {noproc,_}} =
+ (catch gen_fsm:sync_send_event(Pid0, hej)),
+
+ ?line test_server:messages_get(),
+ ok.
+
+%% anonymous with timeout
+start3(Config) when is_list(Config) ->
+ %%OldFl = process_flag(trap_exit, true),
+
+ ?line {ok, Pid0} = gen_fsm:start(gen_fsm_SUITE, [], [{timeout,5}]),
+ ?line ok = do_func_test(Pid0),
+ ?line ok = do_sync_func_test(Pid0),
+ ?line stop_it(Pid0),
+
+ ?line {error, timeout} = gen_fsm:start(gen_fsm_SUITE, sleep,
+ [{timeout,5}]),
+
+ test_server:messages_get(),
+ %%process_flag(trap_exit, OldFl),
+ ok.
+
+%% anonymous with ignore
+start4(suite) -> [];
+start4(Config) when is_list(Config) ->
+ OldFl = process_flag(trap_exit, true),
+
+ ?line ignore = gen_fsm:start(gen_fsm_SUITE, ignore, []),
+
+ test_server:messages_get(),
+ process_flag(trap_exit, OldFl),
+ ok.
+
+%% anonymous with stop
+start5(suite) -> [];
+start5(Config) when is_list(Config) ->
+ OldFl = process_flag(trap_exit, true),
+
+ ?line {error, stopped} = gen_fsm:start(gen_fsm_SUITE, stop, []),
+
+ test_server:messages_get(),
+ process_flag(trap_exit, OldFl),
+ ok.
+
+%% anonymous linked
+start6(Config) when is_list(Config) ->
+ ?line {ok, Pid} = gen_fsm:start_link(gen_fsm_SUITE, [], []),
+ ?line ok = do_func_test(Pid),
+ ?line ok = do_sync_func_test(Pid),
+ ?line stop_it(Pid),
+
+ test_server:messages_get(),
+
+ ok.
+
+%% global register linked
+start7(Config) when is_list(Config) ->
+ ?line {ok, Pid} =
+ gen_fsm:start_link({global, my_fsm}, gen_fsm_SUITE, [], []),
+ ?line {error, {already_started, Pid}} =
+ gen_fsm:start_link({global, my_fsm}, gen_fsm_SUITE, [], []),
+ ?line {error, {already_started, Pid}} =
+ gen_fsm:start({global, my_fsm}, gen_fsm_SUITE, [], []),
+
+ ?line ok = do_func_test(Pid),
+ ?line ok = do_sync_func_test(Pid),
+ ?line ok = do_func_test({global, my_fsm}),
+ ?line ok = do_sync_func_test({global, my_fsm}),
+ ?line stop_it({global, my_fsm}),
+
+ test_server:messages_get(),
+ ok.
+
+
+%% local register
+start8(Config) when is_list(Config) ->
+ %%OldFl = process_flag(trap_exit, true),
+
+ ?line {ok, Pid} =
+ gen_fsm:start({local, my_fsm}, gen_fsm_SUITE, [], []),
+ ?line {error, {already_started, Pid}} =
+ gen_fsm:start({local, my_fsm}, gen_fsm_SUITE, [], []),
+
+ ?line ok = do_func_test(Pid),
+ ?line ok = do_sync_func_test(Pid),
+ ?line ok = do_func_test(my_fsm),
+ ?line ok = do_sync_func_test(my_fsm),
+ ?line stop_it(Pid),
+
+ test_server:messages_get(),
+ %%process_flag(trap_exit, OldFl),
+ ok.
+
+%% local register linked
+start9(Config) when is_list(Config) ->
+ %%OldFl = process_flag(trap_exit, true),
+
+ ?line {ok, Pid} =
+ gen_fsm:start_link({local, my_fsm}, gen_fsm_SUITE, [], []),
+ ?line {error, {already_started, Pid}} =
+ gen_fsm:start({local, my_fsm}, gen_fsm_SUITE, [], []),
+
+ ?line ok = do_func_test(Pid),
+ ?line ok = do_sync_func_test(Pid),
+ ?line ok = do_func_test(my_fsm),
+ ?line ok = do_sync_func_test(my_fsm),
+ ?line stop_it(Pid),
+
+ test_server:messages_get(),
+ %%process_flag(trap_exit, OldFl),
+ ok.
+
+%% global register
+start10(Config) when is_list(Config) ->
+ ?line {ok, Pid} =
+ gen_fsm:start({global, my_fsm}, gen_fsm_SUITE, [], []),
+ ?line {error, {already_started, Pid}} =
+ gen_fsm:start({global, my_fsm}, gen_fsm_SUITE, [], []),
+ ?line {error, {already_started, Pid}} =
+ gen_fsm:start_link({global, my_fsm}, gen_fsm_SUITE, [], []),
+
+ ?line ok = do_func_test(Pid),
+ ?line ok = do_sync_func_test(Pid),
+ ?line ok = do_func_test({global, my_fsm}),
+ ?line ok = do_sync_func_test({global, my_fsm}),
+ ?line stop_it({global, my_fsm}),
+
+ test_server:messages_get(),
+ ok.
+
+
+%% Stop registered processes
+start11(Config) when is_list(Config) ->
+ ?line {ok, Pid} =
+ gen_fsm:start_link({local, my_fsm}, gen_fsm_SUITE, [], []),
+ ?line stop_it(Pid),
+
+ ?line {ok, _Pid1} =
+ gen_fsm:start_link({local, my_fsm}, gen_fsm_SUITE, [], []),
+ ?line stop_it(my_fsm),
+
+ ?line {ok, Pid2} =
+ gen_fsm:start({global, my_fsm}, gen_fsm_SUITE, [], []),
+ ?line stop_it(Pid2),
+ receive after 1 -> true end,
+ ?line Result =
+ gen_fsm:start({global, my_fsm}, gen_fsm_SUITE, [], []),
+ io:format("Result = ~p~n",[Result]),
+ ?line {ok, _Pid3} = Result,
+ ?line stop_it({global, my_fsm}),
+
+ test_server:messages_get(),
+ ok.
+
+abnormal(suite) -> [abnormal1, abnormal2].
+
+%% Check that time outs in calls work
+abnormal1(suite) -> [];
+abnormal1(Config) when is_list(Config) ->
+ ?line {ok, _Pid} =
+ gen_fsm:start({local, my_fsm}, gen_fsm_SUITE, [], []),
+
+ %% timeout call.
+ case os:type() of
+ vxworks ->
+ %% timeout call for VxWorks must be in 16ms increments.
+ ?line delayed = gen_fsm:sync_send_event(my_fsm, {delayed_answer,1}, 17),
+ ?line {'EXIT',{timeout,_}} =
+ (catch gen_fsm:sync_send_event(my_fsm, {delayed_answer,17}, 1));
+ _ ->
+ ?line delayed = gen_fsm:sync_send_event(my_fsm, {delayed_answer,1}, 100),
+ ?line {'EXIT',{timeout,_}} =
+ (catch gen_fsm:sync_send_event(my_fsm, {delayed_answer,10}, 1))
+ end,
+ test_server:messages_get(),
+ ok.
+
+%% Check that bad return values makes the fsm crash. Note that we must
+%% trap exit since we must link to get the real bad_return_ error
+abnormal2(suite) -> [];
+abnormal2(Config) when is_list(Config) ->
+ OldFl = process_flag(trap_exit, true),
+ ?line {ok, Pid} =
+ gen_fsm:start_link(gen_fsm_SUITE, [], []),
+
+ %% bad return value in the gen_fsm loop
+ ?line {'EXIT',{{bad_return_value, badreturn},_}} =
+ (catch gen_fsm:sync_send_event(Pid, badreturn)),
+
+ test_server:messages_get(),
+ process_flag(trap_exit, OldFl),
+ ok.
+
+shutdown(Config) when is_list(Config) ->
+ ?line error_logger_forwarder:register(),
+
+ process_flag(trap_exit, true),
+
+ ?line {ok,Pid0} = gen_fsm:start_link(gen_fsm_SUITE, [], []),
+ ?line ok = do_func_test(Pid0),
+ ?line ok = do_sync_func_test(Pid0),
+ ?line {shutdown,reason} =
+ gen_fsm:sync_send_all_state_event(Pid0, stop_shutdown_reason),
+ receive {'EXIT',Pid0,{shutdown,reason}} -> ok end,
+ process_flag(trap_exit, false),
+
+ ?line {'EXIT', {noproc,_}} =
+ (catch gen_fsm:sync_send_event(Pid0, hej)),
+
+ receive
+ Any ->
+ ?line io:format("Unexpected: ~p", [Any]),
+ ?line ?t:fail()
+ after 500 ->
+ ok
+ end,
+
+ ok.
+
+
+sys(suite) -> [sys1].
+
+sys1(Config) when is_list(Config) ->
+ ?line {ok, Pid} =
+ gen_fsm:start(gen_fsm_SUITE, [], []),
+ ?line {status, Pid, {module,gen_fsm}, _} = sys:get_status(Pid),
+ ?line sys:suspend(Pid),
+ ?line {'EXIT', {timeout,_}} =
+ (catch gen_fsm:sync_send_event(Pid, hej)),
+ ?line sys:resume(Pid),
+ ?line stop_it(Pid).
+
+
+%% Hibernation
+hibernate(suite) -> [];
+hibernate(Config) when is_list(Config) ->
+ OldFl = process_flag(trap_exit, true),
+
+ ?line {ok, Pid0} = gen_fsm:start_link(?MODULE, hiber_now, []),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} =
+ erlang:process_info(Pid0,current_function),
+ ?line stop_it(Pid0),
+ test_server:messages_get(),
+
+
+ ?line {ok, Pid} = gen_fsm:start_link(?MODULE, hiber, []),
+ ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
+ ?line hibernating = gen_fsm:sync_send_event(Pid,hibernate_sync),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} =
+ erlang:process_info(Pid,current_function),
+ ?line good_morning = gen_fsm:sync_send_event(Pid,wakeup_sync),
+ ?line receive after 1000 -> ok end,
+ ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
+ ?line hibernating = gen_fsm:sync_send_event(Pid,hibernate_sync),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} =
+ erlang:process_info(Pid,current_function),
+ ?line five_more = gen_fsm:sync_send_event(Pid,snooze_sync),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} =
+ erlang:process_info(Pid,current_function),
+ ?line good_morning = gen_fsm:sync_send_event(Pid,wakeup_sync),
+ ?line receive after 1000 -> ok end,
+ ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
+ ?line ok = gen_fsm:send_event(Pid,hibernate_async),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} =
+ erlang:process_info(Pid,current_function),
+ ?line ok = gen_fsm:send_event(Pid,wakeup_async),
+ ?line receive after 1000 -> ok end,
+ ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
+ ?line ok = gen_fsm:send_event(Pid,hibernate_async),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} =
+ erlang:process_info(Pid,current_function),
+ ?line ok = gen_fsm:send_event(Pid,snooze_async),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} =
+ erlang:process_info(Pid,current_function),
+ ?line ok = gen_fsm:send_event(Pid,wakeup_async),
+ ?line receive after 1000 -> ok end,
+ ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
+ ?line Pid ! hibernate_later,
+ ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
+ ?line receive after 2000 -> ok end,
+ ?line ({current_function,{erlang,hibernate,3}} = erlang:process_info(Pid,current_function)),
+ ?line 'alive!' = gen_fsm:sync_send_event(Pid,'alive?'),
+ ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
+ ?line Pid ! hibernate_now,
+ ?line receive after 1000 -> ok end,
+ ?line ({current_function,{erlang,hibernate,3}} = erlang:process_info(Pid,current_function)),
+ ?line 'alive!' = gen_fsm:sync_send_event(Pid,'alive?'),
+ ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
+
+
+ ?line hibernating = gen_fsm:sync_send_all_state_event(Pid,hibernate_sync),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} =
+ erlang:process_info(Pid,current_function),
+ ?line good_morning = gen_fsm:sync_send_all_state_event(Pid,wakeup_sync),
+ ?line receive after 1000 -> ok end,
+ ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
+ ?line hibernating = gen_fsm:sync_send_all_state_event(Pid,hibernate_sync),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} =
+ erlang:process_info(Pid,current_function),
+ ?line five_more = gen_fsm:sync_send_all_state_event(Pid,snooze_sync),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} =
+ erlang:process_info(Pid,current_function),
+ ?line good_morning = gen_fsm:sync_send_all_state_event(Pid,wakeup_sync),
+ ?line receive after 1000 -> ok end,
+ ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
+ ?line ok = gen_fsm:send_all_state_event(Pid,hibernate_async),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} =
+ erlang:process_info(Pid,current_function),
+ ?line ok = gen_fsm:send_all_state_event(Pid,wakeup_async),
+ ?line receive after 1000 -> ok end,
+ ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
+ ?line ok = gen_fsm:send_all_state_event(Pid,hibernate_async),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} =
+ erlang:process_info(Pid,current_function),
+ ?line ok = gen_fsm:send_all_state_event(Pid,snooze_async),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} =
+ erlang:process_info(Pid,current_function),
+ ?line ok = gen_fsm:send_all_state_event(Pid,wakeup_async),
+ ?line receive after 1000 -> ok end,
+ ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
+
+ ?line hibernating = gen_fsm:sync_send_all_state_event(Pid,hibernate_sync),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} =
+ erlang:process_info(Pid,current_function),
+ ?line sys:suspend(Pid),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} = erlang:process_info(Pid,current_function),
+ ?line sys:resume(Pid),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} = erlang:process_info(Pid,current_function),
+
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} =
+ erlang:process_info(Pid,current_function),
+ ?line good_morning = gen_fsm:sync_send_all_state_event(Pid,wakeup_sync),
+ ?line receive after 1000 -> ok end,
+ ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
+ ?line stop_it(Pid),
+ test_server:messages_get(),
+ process_flag(trap_exit, OldFl),
+ ok.
+
+
+
+%%sys1(suite) -> [];
+%%sys1(_) ->
+
+enter_loop(suite) ->
+ [];
+enter_loop(doc) ->
+ ["Test gen_fsm:enter_loop/4,5,6"];
+enter_loop(Config) when is_list(Config) ->
+ OldFlag = process_flag(trap_exit, true),
+
+ %% Locally registered process + {local, Name}
+ ?line {ok, Pid1a} =
+ proc_lib:start_link(?MODULE, enter_loop, [local, local]),
+ ?line yes = gen_fsm:sync_send_event(Pid1a, 'alive?'),
+ ?line stopped = gen_fsm:sync_send_event(Pid1a, stop),
+ receive
+ {'EXIT', Pid1a, normal} ->
+ ok
+ after 5000 ->
+ ?line test_server:fail(gen_fsm_did_not_die)
+ end,
+
+ %% Unregistered process + {local, Name}
+ ?line {ok, Pid1b} =
+ proc_lib:start_link(?MODULE, enter_loop, [anon, local]),
+ receive
+ {'EXIT', Pid1b, process_not_registered} ->
+ ok
+ after 5000 ->
+ ?line test_server:fail(gen_fsm_did_not_die)
+ end,
+
+ %% Globally registered process + {global, Name}
+ ?line {ok, Pid2a} =
+ proc_lib:start_link(?MODULE, enter_loop, [global, global]),
+ ?line yes = gen_fsm:sync_send_event(Pid2a, 'alive?'),
+ ?line stopped = gen_fsm:sync_send_event(Pid2a, stop),
+ receive
+ {'EXIT', Pid2a, normal} ->
+ ok
+ after 5000 ->
+ ?line test_server:fail(gen_fsm_did_not_die)
+ end,
+
+ %% Unregistered process + {global, Name}
+ ?line {ok, Pid2b} =
+ proc_lib:start_link(?MODULE, enter_loop, [anon, global]),
+ receive
+ {'EXIT', Pid2b, process_not_registered_globally} ->
+ ok
+ after 5000 ->
+ ?line test_server:fail(gen_fsm_did_not_die)
+ end,
+
+ %% Unregistered process + no name
+ ?line {ok, Pid3} =
+ proc_lib:start_link(?MODULE, enter_loop, [anon, anon]),
+ ?line yes = gen_fsm:sync_send_event(Pid3, 'alive?'),
+ ?line stopped = gen_fsm:sync_send_event(Pid3, stop),
+ receive
+ {'EXIT', Pid3, normal} ->
+ ok
+ after 5000 ->
+ ?line test_server:fail(gen_fsm_did_not_die)
+ end,
+
+ %% Process not started using proc_lib
+ ?line Pid4 =
+ spawn_link(gen_fsm, enter_loop, [?MODULE, [], state0, []]),
+ receive
+ {'EXIT', Pid4, process_was_not_started_by_proc_lib} ->
+ ok
+ after 5000 ->
+ ?line test_server:fail(gen_fsm_did_not_die)
+ end,
+
+ %% Make sure I am the parent, ie that ordering a shutdown will
+ %% result in the process terminating with Reason==shutdown
+ ?line {ok, Pid5} =
+ proc_lib:start_link(?MODULE, enter_loop, [anon, anon]),
+ ?line yes = gen_fsm:sync_send_event(Pid5, 'alive?'),
+ ?line exit(Pid5, shutdown),
+ receive
+ {'EXIT', Pid5, shutdown} ->
+ ok
+ after 5000 ->
+ ?line test_server:fail(gen_fsm_did_not_die)
+ end,
+
+ %% Make sure gen_fsm:enter_loop does not accept {local,Name}
+ %% when it's another process than the calling one which is
+ %% registered under that name
+ register(armitage, self()),
+ ?line {ok, Pid6a} =
+ proc_lib:start_link(?MODULE, enter_loop, [anon, local]),
+ receive
+ {'EXIT', Pid6a, process_not_registered} ->
+ ok
+ after 1000 ->
+ ?line test_server:fail(gen_fsm_started)
+ end,
+ unregister(armitage),
+
+ %% Make sure gen_fsm:enter_loop does not accept {global,Name}
+ %% when it's another process than the calling one which is
+ %% registered under that name
+ global:register_name(armitage, self()),
+ ?line {ok, Pid6b} =
+ proc_lib:start_link(?MODULE, enter_loop, [anon, global]),
+ receive
+ {'EXIT', Pid6b, process_not_registered_globally} ->
+ ok
+ after 1000 ->
+ ?line test_server:fail(gen_server_started)
+ end,
+ global:unregister_name(armitage),
+
+ process_flag(trap_exit, OldFlag),
+ ok.
+
+enter_loop(Reg1, Reg2) ->
+ process_flag(trap_exit, true),
+ case Reg1 of
+ local -> register(armitage, self());
+ global -> global:register_name(armitage, self());
+ anon -> ignore
+ end,
+ proc_lib:init_ack({ok, self()}),
+ case Reg2 of
+ local ->
+ gen_fsm:enter_loop(?MODULE, [], state0, [], {local,armitage});
+ global ->
+ gen_fsm:enter_loop(?MODULE, [], state0, [], {global,armitage});
+ anon ->
+ gen_fsm:enter_loop(?MODULE, [], state0, [])
+ end.
+
+%%
+%% Functionality check
+%%
+
+wfor(Msg) ->
+ receive
+ Msg -> ok
+ after 5000 ->
+ throw(timeout)
+ end.
+
+
+stop_it(FSM) ->
+ ?line stopped = gen_fsm:sync_send_all_state_event(FSM, stop),
+ ?line {'EXIT',_} = (catch gen_fsm:sync_send_event(FSM, hej)),
+ ok.
+
+
+
+do_func_test(FSM) ->
+ ok = gen_fsm:send_all_state_event(FSM, {'alive?', self()}),
+ wfor(yes),
+ ok = do_connect(FSM),
+ ok = gen_fsm:send_all_state_event(FSM, {'alive?', self()}),
+ wfor(yes),
+ test_server:do_times(3, ?MODULE, do_msg, [FSM]),
+ ok = gen_fsm:send_all_state_event(FSM, {'alive?', self()}),
+ wfor(yes),
+ ok = do_disconnect(FSM),
+ ok = gen_fsm:send_all_state_event(FSM, {'alive?', self()}),
+ wfor(yes),
+ ok.
+
+
+do_connect(FSM) ->
+ check_state(FSM, idle),
+ gen_fsm:send_event(FSM, {connect, self()}),
+ wfor(accept),
+ check_state(FSM, wfor_conf),
+ gen_fsm:send_event(FSM, confirmation),
+ check_state(FSM, connected),
+ ok.
+
+do_msg(FSM) ->
+ check_state(FSM, connected),
+ R = make_ref(),
+ ok = gen_fsm:send_event(FSM, {msg, R, self(), hej_pa_dig_quasimodo}),
+ wfor({ak, R}).
+
+
+do_disconnect(FSM) ->
+ ok = gen_fsm:send_event(FSM, disconnect),
+ check_state(FSM, idle).
+
+check_state(FSM, State) ->
+ case gen_fsm:sync_send_all_state_event(FSM, {get, self()}) of
+ {state, State, _} -> ok
+ end.
+
+do_sync_func_test(FSM) ->
+ yes = gen_fsm:sync_send_all_state_event(FSM, 'alive?'),
+ ok = do_sync_connect(FSM),
+ yes = gen_fsm:sync_send_all_state_event(FSM, 'alive?'),
+ test_server:do_times(3, ?MODULE, do_sync_msg, [FSM]),
+ yes = gen_fsm:sync_send_all_state_event(FSM, 'alive?'),
+ ok = do_sync_disconnect(FSM),
+ yes = gen_fsm:sync_send_all_state_event(FSM, 'alive?'),
+ check_state(FSM, idle),
+ ok = gen_fsm:sync_send_event(FSM, {timeout,200}),
+ yes = gen_fsm:sync_send_all_state_event(FSM, 'alive?'),
+ check_state(FSM, idle),
+ ok.
+
+
+do_sync_connect(FSM) ->
+ check_state(FSM, idle),
+ accept = gen_fsm:sync_send_event(FSM, {connect, self()}),
+ check_state(FSM, wfor_conf),
+ yes = gen_fsm:sync_send_event(FSM, confirmation),
+ check_state(FSM, connected),
+ ok.
+
+do_sync_msg(FSM) ->
+ check_state(FSM, connected),
+ R = make_ref(),
+ Res = gen_fsm:sync_send_event(FSM, {msg, R, self(), hej_pa_dig_quasimodo}),
+ if Res == {ak, R} ->
+ ok
+ end.
+
+do_sync_disconnect(FSM) ->
+ yes = gen_fsm:sync_send_event(FSM, disconnect),
+ check_state(FSM, idle).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
+%% The Finite State Machine
+%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+init(ignore) ->
+ ignore;
+init(stop) ->
+ {stop, stopped};
+init(stop_shutdown) ->
+ {stop, shutdown};
+init(sleep) ->
+ test_server:sleep(1000),
+ {ok, idle, data};
+init({timeout, T}) ->
+ {ok, idle, state, T};
+init(hiber) ->
+ {ok, hiber_idle, []};
+init(hiber_now) ->
+ {ok, hiber_idle, [], hibernate};
+init(_) ->
+ {ok, idle, state_data}.
+
+
+terminate({From, stopped}, State, _Data) ->
+ From ! {self(), {stopped, State}},
+ ok;
+terminate(_Reason, _State, _Data) ->
+ ok.
+
+
+idle({connect, Pid}, Data) ->
+ Pid ! accept,
+ {next_state, wfor_conf, Data};
+idle(badreturn, _Data) ->
+ badreturn;
+idle(_, Data) ->
+ {next_state, idle, Data}.
+
+idle({connect, _Pid}, _From, Data) ->
+ {reply, accept, wfor_conf, Data};
+idle({delayed_answer, T}, _From, Data) ->
+ test_server:sleep(T),
+ {reply, delayed, idle, Data};
+idle(badreturn, _From, _Data) ->
+ badreturn;
+idle({timeout,Time}, From, _Data) ->
+ gen_fsm:send_event_after(Time, {timeout,Time}),
+ {next_state, timeout, From};
+idle(_, _From, Data) ->
+ {reply, 'eh?', idle, Data}.
+
+timeout({timeout,Time}, From) ->
+ Ref = gen_fsm:start_timer(Time, {timeout,Time}),
+ {next_state, timeout, {From,Ref}};
+timeout({timeout,Ref,{timeout,Time}}, {From,Ref}) ->
+ Ref2 = gen_fsm:start_timer(Time, ok),
+ Cref = gen_fsm:start_timer(Time, cancel),
+ Time4 = Time*4,
+ receive after Time4 -> ok end,
+ gen_fsm:cancel_timer(Cref),
+ {next_state, timeout, {From,Ref2}};
+timeout({timeout,Ref2,ok},{From,Ref2}) ->
+ gen_fsm:reply(From, ok),
+ {next_state, idle, state}.
+
+wfor_conf(confirmation, Data) ->
+ {next_state, connected, Data};
+wfor_conf(_, Data) ->
+ {next_state, idle, Data}.
+
+wfor_conf(confirmation, _From, Data) ->
+ {reply, yes, connected, Data};
+wfor_conf(_, _From, Data) ->
+ {reply, 'eh?', idle, Data}.
+
+connected({msg, Ref, From, _Msg}, Data) ->
+ From ! {ak, Ref},
+ {next_state, connected, Data};
+connected(disconnect, Data) ->
+ {next_state, idle, Data};
+connected(_, Data) ->
+ {next_state, connected, Data}.
+
+connected({msg, Ref, _From, _Msg}, _, Data) ->
+ {reply, {ak, Ref}, connected, Data};
+connected(disconnect, _From, Data) ->
+ {reply, yes, idle, Data};
+connected(_, _, Data) ->
+ {reply, 'eh?', connected, Data}.
+
+state0('alive?', _From, Data) ->
+ {reply, yes, state0, Data};
+state0(stop, _From, Data) ->
+ {stop, normal, stopped, Data}.
+
+hiber_idle('alive?', _From, Data) ->
+ {reply, 'alive!', hiber_idle, Data};
+hiber_idle(hibernate_sync, _From, Data) ->
+ {reply, hibernating, hiber_wakeup, Data,hibernate}.
+hiber_idle(timeout, hibernate_me) -> % Arrive here from
+ % handle_info(hibernate_later,...)
+ {next_state, hiber_idle, [], hibernate};
+hiber_idle(hibernate_async, Data) ->
+ {next_state,hiber_wakeup, Data, hibernate}.
+
+hiber_wakeup(wakeup_sync,_From,Data) ->
+ {reply,good_morning,hiber_idle,Data};
+hiber_wakeup(snooze_sync,_From,Data) ->
+ {reply,five_more,hiber_wakeup,Data,hibernate}.
+hiber_wakeup(wakeup_async,Data) ->
+ {next_state,hiber_idle,Data};
+hiber_wakeup(snooze_async,Data) ->
+ {next_state,hiber_wakeup,Data,hibernate}.
+
+
+handle_info(hibernate_now, _SName, _State) -> % Arrive here from by direct ! from testcase
+ {next_state, hiber_idle, [], hibernate};
+handle_info(hibernate_later, _SName, _State) ->
+ {next_state, hiber_idle, hibernate_me, 1000};
+
+handle_info(Info, _State, Data) ->
+ {stop, {unexpected,Info}, Data}.
+
+handle_event(hibernate_async, hiber_idle, Data) ->
+ {next_state,hiber_wakeup, Data, hibernate};
+handle_event(wakeup_async,hiber_wakeup,Data) ->
+ {next_state,hiber_idle,Data};
+handle_event(snooze_async,hiber_wakeup,Data) ->
+ {next_state,hiber_wakeup,Data,hibernate};
+handle_event({get, Pid}, State, Data) ->
+ Pid ! {state, State, Data},
+ {next_state, State, Data};
+handle_event(stop, _State, Data) ->
+ {stop, normal, Data};
+handle_event(stop_shutdown, _State, Data) ->
+ {stop, shutdown, Data};
+handle_event(stop_shutdown_reason, _State, Data) ->
+ {stop, shutdown, Data};
+handle_event({'alive?', Pid}, State, Data) ->
+ Pid ! yes,
+ {next_state, State, Data}.
+
+handle_sync_event(hibernate_sync, _From, hiber_idle, Data) ->
+ {reply, hibernating, hiber_wakeup, Data, hibernate};
+handle_sync_event(wakeup_sync,_From,hiber_wakeup, Data) ->
+ {reply,good_morning,hiber_idle,Data};
+handle_sync_event(snooze_sync,_From,hiber_wakeup,Data) ->
+ {reply,five_more,hiber_wakeup,Data,hibernate};
+handle_sync_event('alive?', _From, State, Data) ->
+ {reply, yes, State, Data};
+handle_sync_event(stop, _From, _State, Data) ->
+ {stop, normal, stopped, Data};
+handle_sync_event(stop_shutdown, _From, _State, Data) ->
+ {stop, shutdown, shutdown_stopped, Data};
+handle_sync_event(stop_shutdown_reason, _From, _State, Data) ->
+ {stop, {shutdown,reason}, {shutdown,reason}, Data};
+handle_sync_event({get, _Pid}, _From, State, Data) ->
+ {reply, {state, State, Data}, State, Data}.
diff --git a/lib/stdlib/test/gen_server_SUITE.erl b/lib/stdlib/test/gen_server_SUITE.erl
new file mode 100644
index 0000000000..86a5a65ba3
--- /dev/null
+++ b/lib/stdlib/test/gen_server_SUITE.erl
@@ -0,0 +1,1049 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(gen_server_SUITE).
+
+-include("test_server.hrl").
+-include_lib("kernel/include/inet.hrl").
+
+-export([init_per_testcase/2, fin_per_testcase/2]).
+
+-export([all/1]).
+-export([start/1, crash/1, call/1, cast/1, cast_fast/1,
+ info/1, abcast/1, multicall/1, multicall_down/1,
+ call_remote1/1, call_remote2/1, call_remote3/1,
+ call_remote_n1/1, call_remote_n2/1, call_remote_n3/1, spec_init/1,
+ spec_init_local_registered_parent/1,
+ spec_init_global_registered_parent/1,
+ otp_5854/1, hibernate/1, otp_7669/1
+ ]).
+
+% spawn export
+-export([spec_init_local/2, spec_init_global/2,
+ spec_init_default_timeout/2, spec_init_anonymous/1,
+ spec_init_anonymous_default_timeout/1,
+ spec_init_not_proc_lib/1, cast_fast_messup/0]).
+
+
+% The gen_server behaviour
+-export([init/1, handle_call/3, handle_cast/2,
+ handle_info/2, terminate/2]).
+
+all(suite) ->
+ [start, crash, call, cast, cast_fast, info,
+ abcast, multicall, multicall_down, call_remote1,
+ call_remote2, call_remote3, call_remote_n1,
+ call_remote_n2, call_remote_n3, spec_init,
+ spec_init_local_registered_parent,
+ spec_init_global_registered_parent,
+ otp_5854,hibernate,otp_7669].
+
+-define(default_timeout, ?t:minutes(1)).
+
+init_per_testcase(_Case, Config) ->
+ ?line Dog = ?t:timetrap(?default_timeout),
+ [{watchdog, Dog} | Config].
+fin_per_testcase(_Case, Config) ->
+ Dog = ?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+
+%% --------------------------------------
+%% Start and stop a gen_server.
+%% --------------------------------------
+
+start(suite) -> [];
+start(Config) when is_list(Config) ->
+ OldFl = process_flag(trap_exit, true),
+
+ %% anonymous
+ ?line {ok, Pid0} = gen_server:start(gen_server_SUITE, [], []),
+ ?line ok = gen_server:call(Pid0, started_p),
+ ?line ok = gen_server:call(Pid0, stop),
+ ?line busy_wait_for_process(Pid0,600),
+ ?line {'EXIT', {noproc,_}} = (catch gen_server:call(Pid0, started_p, 1)),
+
+ %% anonymous with timeout
+ ?line {ok, Pid00} = gen_server:start(gen_server_SUITE, [],
+ [{timeout,1000}]),
+ ?line ok = gen_server:call(Pid00, started_p),
+ ?line ok = gen_server:call(Pid00, stop),
+ ?line {error, timeout} = gen_server:start(gen_server_SUITE, sleep,
+ [{timeout,100}]),
+
+ %% anonymous with ignore
+ ?line ignore = gen_server:start(gen_server_SUITE, ignore, []),
+
+ %% anonymous with stop
+ ?line {error, stopped} = gen_server:start(gen_server_SUITE, stop, []),
+
+ %% anonymous linked
+ ?line {ok, Pid1} =
+ gen_server:start_link(gen_server_SUITE, [], []),
+ ?line ok = gen_server:call(Pid1, started_p),
+ ?line ok = gen_server:call(Pid1, stop),
+ ?line receive
+ {'EXIT', Pid1, stopped} ->
+ ok
+ after 5000 ->
+ test_server:fail(not_stopped)
+ end,
+
+ %% local register
+ ?line {ok, Pid2} =
+ gen_server:start({local, my_test_name},
+ gen_server_SUITE, [], []),
+ ?line ok = gen_server:call(my_test_name, started_p),
+ ?line {error, {already_started, Pid2}} =
+ gen_server:start({local, my_test_name},
+ gen_server_SUITE, [], []),
+ ?line ok = gen_server:call(my_test_name, stop),
+
+ ?line busy_wait_for_process(Pid2,600),
+
+ ?line {'EXIT', {noproc,_}} = (catch gen_server:call(Pid2, started_p, 10)),
+
+ %% local register linked
+ ?line {ok, Pid3} =
+ gen_server:start_link({local, my_test_name},
+ gen_server_SUITE, [], []),
+ ?line ok = gen_server:call(my_test_name, started_p),
+ ?line {error, {already_started, Pid3}} =
+ gen_server:start({local, my_test_name},
+ gen_server_SUITE, [], []),
+ ?line ok = gen_server:call(my_test_name, stop),
+ ?line receive
+ {'EXIT', Pid3, stopped} ->
+ ok
+ after 5000 ->
+ test_server:fail(not_stopped)
+ end,
+
+ %% global register
+ ?line {ok, Pid4} =
+ gen_server:start({global, my_test_name},
+ gen_server_SUITE, [], []),
+ ?line ok = gen_server:call({global, my_test_name}, started_p),
+ ?line {error, {already_started, Pid4}} =
+ gen_server:start({global, my_test_name},
+ gen_server_SUITE, [], []),
+ ?line ok = gen_server:call({global, my_test_name}, stop),
+ test_server:sleep(1),
+ ?line {'EXIT', {noproc,_}} = (catch gen_server:call(Pid4, started_p, 10)),
+
+ %% global register linked
+ ?line {ok, Pid5} =
+ gen_server:start_link({global, my_test_name},
+ gen_server_SUITE, [], []),
+ ?line ok = gen_server:call({global, my_test_name}, started_p),
+ ?line {error, {already_started, Pid5}} =
+ gen_server:start({global, my_test_name},
+ gen_server_SUITE, [], []),
+ ?line ok = gen_server:call({global, my_test_name}, stop),
+ ?line receive
+ {'EXIT', Pid5, stopped} ->
+ ok
+ after 5000 ->
+ test_server:fail(not_stopped)
+ end,
+
+ test_server:messages_get(),
+
+ %% Must wait for all error messages before going to next test.
+ %% (otherwise it interferes too much with real time characteristics).
+ case os:type() of
+ vxworks ->
+ receive after 5000 -> ok end;
+ _ ->
+ ok
+ end,
+ process_flag(trap_exit, OldFl),
+ ok.
+
+crash(Config) when is_list(Config) ->
+ ?line error_logger_forwarder:register(),
+
+ process_flag(trap_exit, true),
+
+ %% This crash should not generate a crash report.
+ ?line {ok,Pid0} = gen_server:start_link(?MODULE, [], []),
+ ?line {'EXIT',{{shutdown,reason},_}} =
+ (catch gen_server:call(Pid0, shutdown_reason)),
+ receive {'EXIT',Pid0,{shutdown,reason}} -> ok end,
+
+ %% This crash should not generate a crash report.
+ ?line {ok,Pid1} = gen_server:start_link(?MODULE, {state,state1}, []),
+ ?line {'EXIT',{{shutdown,stop_reason},_}} =
+ (catch gen_server:call(Pid1, stop_shutdown_reason)),
+ receive {'EXIT',Pid1,{shutdown,stop_reason}} -> ok end,
+
+ %% This crash should not generate a crash report.
+ ?line {ok,Pid2} = gen_server:start_link(?MODULE, [], []),
+ ?line {'EXIT',{shutdown,_}} =
+ (catch gen_server:call(Pid2, exit_shutdown)),
+ receive {'EXIT',Pid2,shutdown} -> ok end,
+
+ %% This crash should not generate a crash report.
+ ?line {ok,Pid3} = gen_server:start_link(?MODULE, {state,state3}, []),
+ ?line {'EXIT',{shutdown,_}} =
+ (catch gen_server:call(Pid3, stop_shutdown)),
+ receive {'EXIT',Pid3,shutdown} -> ok end,
+
+ process_flag(trap_exit, false),
+
+ %% This crash should generate a crash report and a report
+ %% from gen_server.
+ ?line {ok,Pid4} = gen_server:start(?MODULE, {state,state4}, []),
+ ?line {'EXIT',{crashed,_}} = (catch gen_server:call(Pid4, crash)),
+ receive
+ {error,_GroupLeader4,{Pid4,
+ "** Generic server"++_,
+ [Pid4,crash,state4,crashed]}} ->
+ ok;
+ Other4a ->
+ ?line io:format("Unexpected: ~p", [Other4a]),
+ ?line ?t:fail()
+ end,
+ receive
+ {error_report,_,{Pid4,crash_report,[List4|_]}} ->
+ {exit,crashed,_} = proplists:get_value(error_info, List4),
+ Pid4 = proplists:get_value(pid, List4);
+ Other4 ->
+ ?line io:format("Unexpected: ~p", [Other4]),
+ ?line ?t:fail()
+ end,
+
+ receive
+ Any ->
+ ?line io:format("Unexpected: ~p", [Any]),
+ ?line ?t:fail()
+ after 500 ->
+ ok
+ end,
+
+ ok.
+
+%% --------------------------------------
+%% Test gen_server:call and handle_call.
+%% Test all different return values from
+%% handle_call.
+%% --------------------------------------
+
+call(suite) -> [];
+call(Config) when is_list(Config) ->
+ OldFl = process_flag(trap_exit, true),
+
+ ?line {ok, _Pid} =
+ gen_server:start_link({local, my_test_name},
+ gen_server_SUITE, [], []),
+
+ ?line ok = gen_server:call(my_test_name, started_p),
+ ?line delayed = gen_server:call(my_test_name, {delayed_answer,1}),
+
+ %% two requests within a specified time.
+ ?line ok = gen_server:call(my_test_name, {call_within, 1000}),
+ test_server:sleep(500),
+ ?line ok = gen_server:call(my_test_name, next_call),
+ ?line ok = gen_server:call(my_test_name, {call_within, 1000}),
+ test_server:sleep(1500),
+ ?line false = gen_server:call(my_test_name, next_call),
+
+ %% timeout call.
+ ?line delayed = gen_server:call(my_test_name, {delayed_answer,1}, 30),
+ ?line {'EXIT',{timeout,_}} =
+ (catch gen_server:call(my_test_name, {delayed_answer,30}, 1)),
+
+ %% bad return value in the gen_server loop from handle_call.
+ ?line {'EXIT',{{bad_return_value, badreturn},_}} =
+ (catch gen_server:call(my_test_name, badreturn)),
+
+ process_flag(trap_exit, OldFl),
+ ok.
+
+%% --------------------------------------
+%% Test call to nonexisting processes on remote nodes
+%% --------------------------------------
+
+start_node(Name) ->
+ ?line Pa = filename:dirname(code:which(?MODULE)),
+ ?line N = test_server:start_node(Name, slave, [{args, " -pa " ++ Pa}]),
+ %% After starting a slave, it takes a little while until global knows
+ %% about it, even if nodes() includes it, so we make sure that global
+ %% knows about it before registering something on all nodes.
+ global:sync(),
+ N.
+
+call_remote1(suite) -> [];
+call_remote1(Config) when is_list(Config) ->
+ ?line N = hubba,
+ ?line {ok, Node} = start_node(N),
+ ?line {ok, Pid} = rpc:call(Node, gen_server, start,
+ [{global, N}, ?MODULE, [], []]),
+ ?line ok = (catch gen_server:call({global, N}, started_p, infinity)),
+ ?line exit(Pid, boom),
+ ?line {'EXIT', {Reason, _}} = (catch gen_server:call({global, N},
+ started_p, infinity)),
+ ?line true = (Reason == noproc) orelse (Reason == boom),
+ ok.
+
+call_remote2(suite) -> [];
+call_remote2(Config) when is_list(Config) ->
+ ?line N = hubba,
+ ?line {ok, Node} = start_node(N),
+
+ ?line {ok, Pid} = rpc:call(Node, gen_server, start,
+ [{global, N}, ?MODULE, [], []]),
+ ?line ok = (catch gen_server:call(Pid, started_p, infinity)),
+ ?line exit(Pid, boom),
+ ?line {'EXIT', {Reason, _}} = (catch gen_server:call(Pid,
+ started_p, infinity)),
+ ?line true = (Reason == noproc) orelse (Reason == boom),
+ ok.
+
+call_remote3(suite) -> [];
+call_remote3(Config) when is_list(Config) ->
+ ?line N = hubba,
+ ?line {ok, Node} = start_node(N),
+
+ ?line {ok, Pid} = rpc:call(Node, gen_server, start,
+ [{local, piller}, ?MODULE, [], []]),
+ ?line ok = (catch gen_server:call({piller, Node}, started_p, infinity)),
+ ?line exit(Pid, boom),
+ ?line {'EXIT', {Reason, _}} = (catch gen_server:call({piller, Node},
+ started_p, infinity)),
+ ?line true = (Reason == noproc) orelse (Reason == boom),
+ ok.
+
+%% --------------------------------------
+%% Test call to nonexisting node
+%% --------------------------------------
+
+call_remote_n1(suite) -> [];
+call_remote_n1(Config) when is_list(Config) ->
+ ?line N = hubba,
+ ?line {ok, Node} = start_node(N),
+ ?line {ok, _Pid} = rpc:call(Node, gen_server, start,
+ [{global, N}, ?MODULE, [], []]),
+ ?line _ = test_server:stop_node(Node),
+ ?line {'EXIT', {noproc, _}} =
+ (catch gen_server:call({global, N}, started_p, infinity)),
+
+ ok.
+
+call_remote_n2(suite) -> [];
+call_remote_n2(Config) when is_list(Config) ->
+ ?line N = hubba,
+ ?line {ok, Node} = start_node(N),
+
+ ?line {ok, Pid} = rpc:call(Node, gen_server, start,
+ [{global, N}, ?MODULE, [], []]),
+ ?line _ = test_server:stop_node(Node),
+ ?line {'EXIT', {{nodedown, Node}, _}} = (catch gen_server:call(Pid,
+ started_p, infinity)),
+
+ ok.
+
+call_remote_n3(suite) -> [];
+call_remote_n3(Config) when is_list(Config) ->
+ ?line N = hubba,
+ ?line {ok, Node} = start_node(N),
+
+ ?line {ok, _Pid} = rpc:call(Node, gen_server, start,
+ [{local, piller}, ?MODULE, [], []]),
+ ?line _ = test_server:stop_node(Node),
+ ?line {'EXIT', {{nodedown, Node}, _}} = (catch gen_server:call({piller, Node},
+ started_p, infinity)),
+
+ ok.
+
+%% --------------------------------------
+%% Test gen_server:cast and handle_cast.
+%% Test all different return values from
+%% handle_cast.
+%% --------------------------------------
+
+cast(suite) -> [];
+cast(Config) when is_list(Config) ->
+ ?line {ok, Pid} =
+ gen_server:start({local, my_test_name},
+ gen_server_SUITE, [], []),
+
+ ?line ok = gen_server:call(my_test_name, started_p),
+
+ ?line ok = gen_server:cast(my_test_name, {self(),handle_cast}),
+ ?line receive
+ {Pid, handled_cast} ->
+ ok
+ after 1000 ->
+ test_server:fail(handle_cast)
+ end,
+
+ ?line ok = gen_server:cast(my_test_name, {self(),delayed_cast,1}),
+ ?line receive
+ {Pid, delayed} ->
+ ok
+ after 1000 ->
+ test_server:fail(delayed_cast)
+ end,
+
+ ?line ok = gen_server:cast(my_test_name, {self(),stop}),
+ ?line receive
+ {Pid, stopped} ->
+ ok
+ after 1000 ->
+ test_server:fail(stop)
+ end,
+ ok.
+
+cast_fast(suite) -> [];
+cast_fast(doc) -> ["Test that cast really return immediately"];
+cast_fast(Config) when is_list(Config) ->
+ ?line {ok,Node} = start_node(hubba),
+ ?line {_,"@"++Host} = lists:splitwith(fun ($@) -> false; (_) -> true end,
+ atom_to_list(Node)),
+ ?line FalseNode = list_to_atom("hopp@"++Host),
+ ?line true = rpc:cast(Node, ?MODULE, cast_fast_messup, []),
+% ?line io:format("Nodes ~p~n", [rpc:call(N, ?MODULE, cast_fast_messup, [])]),
+ ?line test_server:sleep(1000),
+ ?line [Node] = nodes(),
+ ?line {Time,ok} = test_server:timecall(gen_server, cast,
+ [{hopp,FalseNode},hopp]),
+ ?line true = test_server:stop_node(Node),
+ ?line if Time > 1.0 -> % Default listen timeout is about 7.0 s
+ test_server:fail(hanging_cast);
+ true ->
+ ok
+ end.
+
+cast_fast_messup() ->
+ %% Register a false node: hopp@hostname
+ unregister(erl_epmd),
+ erl_epmd:start_link(),
+ {ok,S} = gen_tcp:listen(0, []),
+ {ok,P} = inet:port(S),
+ {ok,_Creation} = erl_epmd:register_node(hopp, P),
+ receive after infinity -> ok end.
+
+%% --------------------------------------
+%% Test handle_info.
+%% --------------------------------------
+
+info(suite) -> [];
+info(Config) when is_list(Config) ->
+ ?line {ok, Pid} =
+ gen_server:start({local, my_test_name},
+ gen_server_SUITE, [], []),
+
+ ?line ok = gen_server:call(my_test_name, started_p),
+
+ ?line Pid ! {self(),handle_info},
+ ?line receive
+ {Pid, handled_info} ->
+ ok
+ after 1000 ->
+ test_server:fail(handle_info)
+ end,
+
+ ?line Pid ! {self(),delayed_info,1},
+ ?line receive
+ {Pid, delayed_info} ->
+ ok
+ after 1000 ->
+ test_server:fail(delayed_info)
+ end,
+
+ ?line Pid ! {self(),stop},
+ ?line receive
+ {Pid, stopped_info} ->
+ ok
+ after 1000 ->
+ test_server:fail(stop_info)
+ end,
+ ok.
+
+hibernate(suite) -> [];
+hibernate(Config) when is_list(Config) ->
+ OldFl = process_flag(trap_exit, true),
+ ?line {ok, Pid0} =
+ gen_server:start_link({local, my_test_name_hibernate0},
+ gen_server_SUITE, hibernate, []),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} = erlang:process_info(Pid0,current_function),
+ ?line ok = gen_server:call(my_test_name_hibernate0, stop),
+ receive
+ {'EXIT', Pid0, stopped} ->
+ ok
+ after 5000 ->
+ test_server:fail(gen_server_did_not_die)
+ end,
+
+ ?line {ok, Pid} =
+ gen_server:start_link({local, my_test_name_hibernate},
+ gen_server_SUITE, [], []),
+
+ ?line ok = gen_server:call(my_test_name_hibernate, started_p),
+ ?line true = gen_server:call(my_test_name_hibernate, hibernate),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} = erlang:process_info(Pid,current_function),
+ ?line Parent = self(),
+ Fun = fun() ->
+ receive
+ go ->
+ ok
+ end,
+ receive
+ after 1000 ->
+ ok
+ end,
+ X = erlang:process_info(Pid,current_function),
+ Pid ! continue,
+ Parent ! {result,X}
+ end,
+ ?line Pid2 = spawn_link(Fun),
+ ?line true = gen_server:call(my_test_name_hibernate, {hibernate_noreply,Pid2}),
+
+ ?line gen_server:cast(my_test_name_hibernate, hibernate_later),
+ ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
+ ?line receive after 2000 -> ok end,
+ ?line ({current_function,{erlang,hibernate,3}} = erlang:process_info(Pid,current_function)),
+ ?line ok = gen_server:call(my_test_name_hibernate, started_p),
+ ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
+ ?line gen_server:cast(my_test_name_hibernate, hibernate_now),
+ ?line receive after 1000 -> ok end,
+ ?line ({current_function,{erlang,hibernate,3}} = erlang:process_info(Pid,current_function)),
+ ?line ok = gen_server:call(my_test_name_hibernate, started_p),
+ ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
+ ?line Pid ! hibernate_later,
+ ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
+ ?line receive after 2000 -> ok end,
+ ?line ({current_function,{erlang,hibernate,3}} = erlang:process_info(Pid,current_function)),
+ ?line ok = gen_server:call(my_test_name_hibernate, started_p),
+ ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
+ ?line Pid ! hibernate_now,
+ ?line receive after 1000 -> ok end,
+ ?line ({current_function,{erlang,hibernate,3}} = erlang:process_info(Pid,current_function)),
+ ?line ok = gen_server:call(my_test_name_hibernate, started_p),
+ ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
+ ?line receive
+ {result,R} ->
+ ?line {current_function,{erlang,hibernate,3}} = R
+ end,
+ ?line true = gen_server:call(my_test_name_hibernate, hibernate),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} = erlang:process_info(Pid,current_function),
+ ?line sys:suspend(my_test_name_hibernate),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} = erlang:process_info(Pid,current_function),
+ ?line sys:resume(my_test_name_hibernate),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} = erlang:process_info(Pid,current_function),
+ ?line ok = gen_server:call(my_test_name_hibernate, started_p),
+ ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
+
+ ?line ok = gen_server:call(my_test_name_hibernate, stop),
+ receive
+ {'EXIT', Pid, stopped} ->
+ ok
+ after 5000 ->
+ test_server:fail(gen_server_did_not_die)
+ end,
+ process_flag(trap_exit, OldFl),
+ ok.
+
+%% --------------------------------------
+%% Test gen_server:abcast and handle_cast.
+%% Test all different return values from
+%% handle_cast.
+%% --------------------------------------
+
+abcast(suite) -> [];
+abcast(Config) when is_list(Config) ->
+ ?line {ok, Pid} =
+ gen_server:start({local, my_test_name},
+ gen_server_SUITE, [], []),
+
+ ?line ok = gen_server:call(my_test_name, started_p),
+
+ ?line abcast = gen_server:abcast(my_test_name, {self(),handle_cast}),
+ ?line receive
+ {Pid, handled_cast} ->
+ ok
+ after 1000 ->
+ test_server:fail(abcast)
+ end,
+
+ ?line abcast = gen_server:abcast([node()], my_test_name,
+ {self(),delayed_cast,1}),
+ ?line receive
+ {Pid, delayed} ->
+ ok
+ after 1000 ->
+ test_server:fail(delayed_abcast)
+ end,
+
+ ?line abcast = gen_server:abcast(my_test_name, {self(),stop}),
+ ?line receive
+ {Pid, stopped} ->
+ ok
+ after 1000 ->
+ test_server:fail(abcast_stop)
+ end,
+ ok.
+
+%% --------------------------------------
+%% Test gen_server:multicall and handle_call.
+%% Test all different return values from
+%% handle_call.
+%% --------------------------------------
+
+multicall(suite) -> [];
+multicall(Config) when is_list(Config) ->
+ OldFl = process_flag(trap_exit, true),
+
+ ?line {ok, Pid} =
+ gen_server:start_link({local, my_test_name},
+ gen_server_SUITE, [], []),
+
+ ?line ok = gen_server:call(my_test_name, started_p),
+ Nodes = nodes(),
+ Node = node(),
+ ?line {[{Node,delayed}],Nodes} =
+ gen_server:multi_call(my_test_name, {delayed_answer,1}),
+
+ %% two requests within a specified time.
+ ?line {[{Node,ok}],[]} =
+ gen_server:multi_call([Node], my_test_name, {call_within, 1000}),
+ test_server:sleep(500),
+ ?line {[{Node,ok}],[]} =
+ gen_server:multi_call([Node], my_test_name, next_call),
+ ?line {[{Node,ok}],[]} =
+ gen_server:multi_call([Node], my_test_name, {call_within, 1000}),
+ test_server:sleep(1500),
+ ?line {[{Node,false}],[]} =
+ gen_server:multi_call([Node],my_test_name, next_call),
+
+ %% Stop the server.
+ ?line {[{Node,ok}],[]} =
+ gen_server:multi_call([Node],my_test_name, stop),
+ receive
+ {'EXIT', Pid, stopped} -> ok
+ after 1000 ->
+ test_server:fail(multicall_stop)
+ end,
+
+ process_flag(trap_exit, OldFl),
+
+ ok.
+
+%% OTP-3587
+multicall_down(suite) -> [];
+multicall_down(Config) when is_list(Config) ->
+ %% We need a named host which is inaccessible.
+ ?line Name = node@test01,
+
+ %% We use 'global' as a gen_server to call.
+ ?line {Good, Bad} = gen_server:multi_call([Name, node()],
+ global_name_server,
+ {whereis, gurkburk},
+ 3000),
+ io:format("good = ~p, bad = ~p~n", [Good, Bad]),
+ ?line [Name] = Bad,
+ ok.
+
+busy_wait_for_process(Pid,N) ->
+ case erlang:is_process_alive(Pid) of
+ true ->
+ receive
+ after 100 ->
+ ok
+ end,
+ busy_wait_for_process(Pid,N-1);
+ _ ->
+ ok
+ end.
+%%--------------------------------------------------------------
+spec_init(doc) ->
+ ["Test gen_server:enter_loop/[3,4,5]. Used when you want to write "
+ "your own special init-phase."];
+spec_init(suite) ->
+ [];
+spec_init(Config) when is_list(Config) ->
+
+ OldFlag = process_flag(trap_exit, true),
+
+ ?line {ok, Pid0} = start_link(spec_init_local, [{ok, my_server}, []]),
+ ?line ok = gen_server:call(Pid0, started_p),
+ ?line ok = gen_server:call(Pid0, stop),
+ receive
+ {'EXIT', Pid0, stopped} ->
+ ok
+ after 5000 ->
+ test_server:fail(gen_server_did_not_die)
+ end,
+
+ ?line {ok, Pid01} = start_link(spec_init_local, [{not_ok, my_server}, []]),
+ receive
+ {'EXIT', Pid01, process_not_registered} ->
+ ok
+ after 5000 ->
+ test_server:fail(gen_server_did_not_die)
+ end,
+
+ ?line {ok, Pid1} = start_link(spec_init_global, [{ok, my_server}, []]),
+ ?line ok = gen_server:call(Pid1, started_p),
+ ?line ok = gen_server:call(Pid1, stop),
+ receive
+ {'EXIT', Pid1, stopped} ->
+ ok
+ after 5000 ->
+ test_server:fail(gen_server_did_not_die)
+ end,
+
+ ?line {ok, Pid11} =
+ start_link(spec_init_global, [{not_ok, my_server}, []]),
+
+ receive
+ {'EXIT', Pid11, process_not_registered_globally} ->
+ ok
+ after 5000 ->
+ test_server:fail(gen_server_did_not_die)
+ end,
+
+ ?line {ok, Pid2} = start_link(spec_init_anonymous, [[]]),
+ ?line ok = gen_server:call(Pid2, started_p),
+ ?line ok = gen_server:call(Pid2, stop),
+ receive
+ {'EXIT', Pid2, stopped} ->
+ ok
+ after 5000 ->
+ test_server:fail(gen_server_did_not_die)
+ end,
+
+ ?line {ok, Pid3} = start_link(spec_init_anonymous_default_timeout, [[]]),
+ ?line ok = gen_server:call(Pid3, started_p),
+ ?line ok = gen_server:call(Pid3, stop),
+ receive
+ {'EXIT', Pid3, stopped} ->
+ ok
+ after 5000 ->
+ test_server:fail(gen_server_did_not_die)
+ end,
+
+ ?line {ok, Pid4} =
+ start_link(spec_init_default_timeout, [{ok, my_server}, []]),
+ ?line ok = gen_server:call(Pid4, started_p),
+ ?line ok = gen_server:call(Pid4, stop),
+ receive
+ {'EXIT', Pid4, stopped} ->
+ ok
+ after 5000 ->
+ test_server:fail(gen_server_did_not_die)
+ end,
+
+ ?line Pid5 =
+ erlang:spawn_link(?MODULE, spec_init_not_proc_lib, [[]]),
+ receive
+ {'EXIT', Pid5, process_was_not_started_by_proc_lib} ->
+ ok
+ after 5000 ->
+ test_server:fail(gen_server_did_not_die)
+ end,
+ process_flag(trap_exit, OldFlag),
+ ok.
+
+%%--------------------------------------------------------------
+spec_init_local_registered_parent(doc) ->
+ ["Test that terminate is run when the parent is a locally registered "
+ "process OTP-4820"];
+spec_init_local_registered_parent(suite) -> [];
+spec_init_local_registered_parent(Config) when is_list(Config) ->
+
+ register(foobar, self()),
+ process_flag(trap_exit, true),
+
+ ?line {ok, Pid} = start_link(spec_init_local, [{ok, my_server}, []]),
+
+ ?line ok = gen_server:cast(my_server, {self(),stop}),
+ ?line receive
+ {Pid, stopped} ->
+ ok
+ after 1000 ->
+ test_server:fail(stop)
+ end,
+ unregister(foobar),
+ ok.
+%%--------------------------------------------------------------
+spec_init_global_registered_parent(doc) ->
+ ["Test that terminate is run when the parent is a global registered "
+ "process OTP-4820"];
+spec_init_global_registered_parent(suite) -> [];
+spec_init_global_registered_parent(Config) when is_list(Config) ->
+
+ global:register_name(foobar, self()),
+ process_flag(trap_exit, true),
+
+ ?line {ok, Pid} = start_link(spec_init_global, [{ok, my_server}, []]),
+
+ ?line ok = gen_server:call(Pid, started_p),
+ ?line ok = gen_server:cast(Pid, {self(),stop}),
+
+ ?line receive
+ {Pid, stopped} ->
+ ok
+ after 1000 ->
+ test_server:fail(stop)
+ end,
+ global:unregister_name(foobar),
+ ok.
+%%--------------------------------------------------------------
+otp_5854(suite) ->
+ [];
+otp_5854(doc) ->
+ ["Test check for registered name in enter_loop/3,4,5"];
+otp_5854(Config) when is_list(Config) ->
+ OldFlag = process_flag(trap_exit, true),
+
+ %% Make sure gen_server:enter_loop does not accept {local,Name}
+ %% when it's another process than the calling one which is
+ %% registered under that name
+ register(armitage, self()),
+ ?line {ok, Pid1} =
+ start_link(spec_init_local, [{not_ok, armitage}, []]),
+ receive
+ {'EXIT', Pid1, process_not_registered} ->
+ ok
+ after 1000 ->
+ ?line test_server:fail(gen_server_started)
+ end,
+ unregister(armitage),
+
+ %% Make sure gen_server:enter_loop does not accept {global,Name}
+ %% when it's another process than the calling one which is
+ %% registered under that name
+ global:register_name(armitage, self()),
+ ?line {ok, Pid2} =
+ start_link(spec_init_global, [{not_ok, armitage}, []]),
+ receive
+ {'EXIT', Pid2, process_not_registered_globally} ->
+ ok
+ after 1000 ->
+ ?line test_server:fail(gen_server_started)
+ end,
+ global:unregister_name(armitage),
+
+ process_flag(trap_exit, OldFlag),
+ ok.
+
+%% If initialization fails (with ignore or {stop,Reason}),
+%% make sure that the process is not registered when gen_sever:start()
+%% returns.
+
+otp_7669(Config) when is_list(Config) ->
+ ?line ?t:do_times(100, fun do_otp_7669_local_ignore/0),
+ ?line ?t:do_times(100, fun do_otp_7669_global_ignore/0),
+ ?line ?t:do_times(10, fun do_otp_7669_stop/0),
+ ok.
+
+do_otp_7669_local_ignore() ->
+ %% The name should never be registered after the return
+ %% from gen_server:start/3.
+ ?line ignore = gen_server:start({local,?MODULE}, ?MODULE, ignore, []),
+ ?line undefined = whereis(?MODULE),
+ ?line ignore = gen_server:start({local,?MODULE}, ?MODULE, ignore, []),
+ ?line undefined = whereis(?MODULE),
+ ?line ignore = gen_server:start_link({local,?MODULE}, ?MODULE, ignore, []),
+ ?line undefined = whereis(?MODULE).
+
+do_otp_7669_global_ignore() ->
+ ?line ignore = gen_server:start({global,?MODULE}, ?MODULE, ignore, []),
+ ?line undefined = global:whereis_name(?MODULE),
+ ?line ignore = gen_server:start_link({global,?MODULE}, ?MODULE, ignore, []),
+ ?line undefined = global:whereis_name(?MODULE).
+
+do_otp_7669_stop() ->
+ %% The name should never be registered after the return
+ %% from gen_server:start/3.
+ ?line {error,stopped} = gen_server:start({local,?MODULE},
+ ?MODULE, stop, []),
+ ?line undefined = whereis(?MODULE),
+
+ ?line {error,stopped} = gen_server:start({global,?MODULE},
+ ?MODULE, stop, []),
+ ?line undefined = global:whereis_name(?MODULE).
+
+%%--------------------------------------------------------------
+%% Help functions to spec_init_*
+start_link(Init, Options) ->
+ proc_lib:start_link(?MODULE, Init, Options).
+
+spec_init_local({ok, Name}, Options) ->
+ process_flag(trap_exit, true),
+ register(Name, self()),
+ proc_lib:init_ack({ok, self()}),
+ %% Supervised init can occur here ...
+ gen_server:enter_loop(?MODULE, Options, {}, {local, Name}, infinity);
+
+spec_init_local({not_ok, Name}, Options) ->
+ process_flag(trap_exit, true),
+ proc_lib:init_ack({ok, self()}),
+ %% Supervised init can occur here ...
+ gen_server:enter_loop(?MODULE, Options, {}, {local, Name}, infinity).
+
+spec_init_global({ok, Name}, Options) ->
+ process_flag(trap_exit, true),
+ global:register_name(Name, self()),
+ proc_lib:init_ack({ok, self()}),
+ %% Supervised init can occur here ...
+ gen_server:enter_loop(?MODULE, Options, {}, {global, Name}, infinity);
+
+spec_init_global({not_ok, Name}, Options) ->
+ process_flag(trap_exit, true),
+ proc_lib:init_ack({ok, self()}),
+ %% Supervised init can occur here ...
+ gen_server:enter_loop(?MODULE, Options, {}, {global, Name}, infinity).
+
+spec_init_default_timeout({ok, Name}, Options) ->
+ process_flag(trap_exit, true),
+ register(Name, self()),
+ proc_lib:init_ack({ok, self()}),
+ %% Supervised init can occur here ...
+ gen_server:enter_loop(?MODULE, Options, {}, {local, Name}).
+
+spec_init_anonymous(Options) ->
+ process_flag(trap_exit, true),
+ proc_lib:init_ack({ok, self()}),
+ %% Supervised init can occur here ...
+ gen_server:enter_loop(?MODULE, Options, {}, infinity).
+
+spec_init_anonymous_default_timeout(Options) ->
+ process_flag(trap_exit, true),
+ proc_lib:init_ack({ok, self()}),
+ %% Supervised init can occur here ...
+ gen_server:enter_loop(?MODULE, Options, {}).
+
+spec_init_not_proc_lib(Options) ->
+ gen_server:enter_loop(?MODULE, Options, {}, infinity).
+
+%%% --------------------------------------------------------
+%%% Here is the tested gen_server behaviour.
+%%% --------------------------------------------------------
+
+init([]) ->
+ {ok, []};
+init(ignore) ->
+ ignore;
+init(stop) ->
+ {stop, stopped};
+init(hibernate) ->
+ {ok,[],hibernate};
+init(sleep) ->
+ test_server:sleep(1000),
+ {ok, []};
+init({state,State}) ->
+ {ok, State}.
+
+handle_call(started_p, _From, State) ->
+ io:format("FROZ"),
+ {reply,ok,State};
+handle_call({delayed_answer, T}, From, _State) ->
+ {noreply,{reply_to,From},T};
+handle_call({call_within, T}, _From, _) ->
+ {reply,ok,call_within,T};
+handle_call(next_call, _From, call_within) ->
+ {reply,ok,[]};
+handle_call(next_call, _From, State) ->
+ {reply,false,State};
+handle_call(badreturn, _From, _State) ->
+ badreturn;
+handle_call(hibernate, _From, _State) ->
+ {reply,true,[],hibernate};
+handle_call({hibernate_noreply,Pid}, From, _State) ->
+ Pid ! go,
+ {noreply,From,hibernate};
+handle_call(stop, _From, State) ->
+ {stop,stopped,ok,State};
+handle_call(crash, _From, _State) ->
+ exit(crashed);
+handle_call(exit_shutdown, _From, _State) ->
+ exit(shutdown);
+handle_call(stop_shutdown, _From, State) ->
+ {stop,shutdown,State};
+handle_call(shutdown_reason, _From, _State) ->
+ exit({shutdown,reason});
+handle_call(stop_shutdown_reason, _From, State) ->
+ {stop,{shutdown,stop_reason},State}.
+
+handle_cast({From,handle_cast}, State) ->
+ From ! {self(), handled_cast},
+ {noreply, State};
+handle_cast({From,delayed_cast,T}, _State) ->
+ {noreply, {delayed_cast,From}, T};
+handle_cast(hibernate_now, _State) ->
+ {noreply, [], hibernate};
+handle_cast(hibernate_later, _State) ->
+ timer:send_after(1000,self(),hibernate_now),
+ {noreply, []};
+handle_cast({From, stop}, State) ->
+ io:format("BAZ"),
+ {stop, {From,stopped}, State}.
+
+handle_info(timeout, {reply_to, From}) ->
+ gen_server:reply(From, delayed),
+ {noreply, []};
+handle_info(timeout, hibernate_me) -> % Arrive here from
+ % handle_info(hibernate_later,...)
+ {noreply, [], hibernate};
+handle_info(hibernate_now, _State) -> % Arrive here from
+ % handle_cast({_,hibernate_later},...)
+ % and by direct ! from testcase
+ {noreply, [], hibernate};
+handle_info(hibernate_later, _State) ->
+ {noreply, hibernate_me, 1000};
+handle_info(timeout, call_within) ->
+ {noreply, []};
+handle_info(timeout, {delayed_cast, From}) ->
+ From ! {self(), delayed},
+ {noreply, []};
+handle_info(timeout, {delayed_info, From}) ->
+ From ! {self(), delayed_info},
+ {noreply, []};
+handle_info({From, handle_info}, _State) ->
+ From ! {self(), handled_info},
+ {noreply, []};
+handle_info({From, delayed_info, T}, _State) ->
+ {noreply, {delayed_info, From}, T};
+handle_info(continue, From) ->
+ gen_server:reply(From,true),
+ {noreply, []};
+handle_info({From, stop}, State) ->
+ {stop, {From,stopped_info}, State};
+handle_info(_Info, State) ->
+ {noreply, State}.
+
+terminate({From, stopped}, _State) ->
+ io:format("FOOBAR"),
+ From ! {self(), stopped},
+ ok;
+terminate({From, stopped_info}, _State) ->
+ From ! {self(), stopped_info},
+ ok;
+terminate(_Reason, _State) ->
+ ok.
+
+
diff --git a/lib/stdlib/test/id_transform_SUITE.erl b/lib/stdlib/test/id_transform_SUITE.erl
new file mode 100644
index 0000000000..95ee509833
--- /dev/null
+++ b/lib/stdlib/test/id_transform_SUITE.erl
@@ -0,0 +1,398 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(id_transform_SUITE).
+-author('[email protected]').
+
+-include_lib("kernel/include/file.hrl").
+
+-export([all/1,
+ id_transform/1]).
+
+-export([check/2,check2/1,g/0,f/1,t/1,t1/1,t2/1,t3/1,t4/1,
+ t5/1,t6/1,apa/1,new_fun/0]).
+
+% Serves as test...
+-hej(hopp).
+-include("test_server.hrl").
+
+all(suite) -> [id_transform].
+
+id_transform(doc) -> "Test erl_id_trans.";
+id_transform(Config) when is_list(Config) ->
+ ?line File=filename:join([code:lib_dir(stdlib),"examples",
+ "erl_id_trans.erl"]),
+ ?line {ok,erl_id_trans,Bin}=compile:file(File,[binary]),
+ ?line {module,erl_id_trans}=code:load_binary(erl_id_trans,File,Bin),
+ ?line case test_server:purify_is_running() of
+ false ->
+ Dog = ?t:timetrap(?t:hours(1)),
+ ?line Res = run_in_test_suite(),
+ ?t:timetrap_cancel(Dog),
+ Res;
+ true ->
+ {skip,"Purify (too slow)"}
+ end.
+
+run_in_test_suite() ->
+ LibDir = code:lib_dir(),
+ SuperDir = filename:dirname(filename:dirname(code:which(?MODULE))),
+ TestDirs = filelib:wildcard(filename:join([SuperDir,"*_test"])),
+ {All,Res} = case LibDir of
+ "/clearcase/otp/erts/lib" ->
+ %% Only test_suites 'cause clearcase is too slow...
+ {false,run_list(TestDirs)};
+ _ ->
+ {true,run_codepath_and(TestDirs)}
+ end,
+ Comment0 = case All of
+ true -> [];
+ false -> "Only testsuite directories traversed"
+ end,
+ case Res of
+ {error,Reason} when Comment0 =/= [] ->
+ {failed,Comment0++"; "++Reason};
+ {error,Reason} ->
+ {failed,Reason};
+ ok ->
+ {comment,Comment0}
+ end.
+
+run_codepath_and(DirList) ->
+ AbsDirs = [filename:absname(X) || X <- code:get_path()],
+ run_list(ordsets:from_list([X || X <- AbsDirs] ++ DirList)).
+
+run_list(PathL) ->
+ io:format("Where to search for beam files:\n~p\n", [PathL]),
+ io:format("Searching for beam files ...~n",[]),
+ Beams = collect_beams(PathL, []),
+ io:format("~p beam files\n", [length(Beams)]),
+ io:format("Applying erl_id_trans to found beam files...~n",[]),
+ Res = [do_trans(X) || X <- Beams],
+ io:format("...done~n",[]),
+ Successes = [X || {ok,X} <- Res],
+ SevereFailures = [{F,E} || {failed,{F,{transform,E}}} <- Res],
+ BeamLib = [{F,E} || {failed,{F,{beam_lib,E}}} <- Res],
+ io:format("~p files processed", [length(Res)]),
+ io:format("~p files successfully transformed", [length(Successes)]),
+ case length(SevereFailures) of
+ 0 -> ok;
+ SevLen ->
+ io:format("\n~p severe failures:\n~p",
+ [SevLen,SevereFailures])
+ end,
+ case BeamLib of
+ [] -> ok;
+ _ -> io:format("\nbeam_lib failures:\n~p", [BeamLib])
+ end,
+ case length(SevereFailures) of
+ 0 -> ok;
+ Len -> {error,integer_to_list(Len)++" failures"}
+ end.
+
+
+collect_beams([P0|Ps], Acc) ->
+ Wc = filename:join(filename:absname(P0), "*.beam"),
+ collect_beams(Ps, filelib:wildcard(Wc)++Acc);
+collect_beams([], Acc) -> Acc.
+
+do_trans(Beam) ->
+ case beam_lib:chunks(Beam, [abstract_code]) of
+ {ok,{_Mod,[{abstract_code,no_abstract_code}]}} ->
+ {failed,{Beam,{beam_lib,no_debug_info}}};
+ {ok,{_Mod,[{abstract_code,{raw_abstract_v1,Abst}}]}} ->
+ do_trans_1(Beam, Abst);
+ {ok,{_Mod,[{abstract_code,{Tag,_}}]}} ->
+ {failed,{Beam,{beam_lib,{wrong_type_of_debug_info,Tag}}}};
+ {ok,{_Mod,[{abstract_code,_}]}} ->
+ {failed,{Beam,{beam_lib,unknown_type_of_debug_info}}};
+ {error,beam_lib,{missing_chunk,_,_}} ->
+ {failed,{Beam,{beam_lib,no_debug_info}}};
+ Error ->
+ {failed,{Beam,{beam_lib,Error}}}
+ end.
+
+do_trans_1(File, Tree0) ->
+ case catch erl_id_trans:parse_transform(Tree0, []) of
+ Tree0 when is_list(Tree0) ->
+ {ok,File};
+ Tree when is_list(Tree) ->
+ {failed,{File,{transform,output_not_same_as_input}}};
+ {'EXIT', Reason} ->
+ {failed,{File,{transform,{crash,Reason}}}};
+ Else ->
+ {failed,{File,{transform,{unknown,Else}}}}
+ end.
+
+% From here on there's only fake code to serve as test cases
+% for the id_transform.
+% They need to be exported.
+
+check(X,_Y) when X ->
+ true;
+check(A,_) when atom(A) ->
+ atom;
+check(A,_) when erlang:is_list(A) ->
+ list;
+check(A,B) when erlang:'+'(A,B) ->
+ atom;
+check(_,_) ->
+ false.
+
+check2(A) ->
+ case A of
+ "hej" ++ "hopp" ->
+ a;
+ [$l,$e,$k] ++ "hopp" ->
+ a;
+ [1] ++ [2] ->
+ b
+ end.
+
+-record(x,{x,y}).
+-record(y,{x=1,y=0}).
+
+g() ->
+ #y.y.
+
+f(#y.y) ->
+ vansinne;
+
+f(X) when X =:= #y.y ->
+ {#y.y,_Y} = {X,hej};
+f(#x{_='_'}) ->
+ hopp;
+f(#x{x=true,y=true}) ->
+ babba;
+f(A) when A == #x{x=true,y=true} ->
+ true;
+f(A) when A#x.x == 4 ->
+ #x{x = 1, _ = 2};
+f(X) ->
+ if X#x.y ->
+ ok;
+ element(3,X) ->
+ banan;
+ true ->
+ nok
+ end.
+
+% Stolen from erl_lint_SUITE.erl
+-record(apa, {}).
+
+t(A) when atom(A) ->
+ atom;
+t(A) when binary(A) ->
+ binary;
+t(A) when float(A) ->
+ float;
+t(A) when function(A) ->
+ function;
+t(A) when integer(A) ->
+ integer;
+t(A) when is_atom(A) ->
+ is_atom;
+t(A) when is_binary(A) ->
+ is_binary;
+t(A) when is_float(A) ->
+ is_float;
+t(A) when is_function(A) ->
+ is_function;
+t(A) when is_integer(A) ->
+ is_integer;
+t(A) when is_list(A) ->
+ is_list;
+t(A) when is_number(A) ->
+ is_number;
+t(A) when is_pid(A) ->
+ is_pid;
+t(A) when is_port(A) ->
+ is_port;
+t(A) when is_record(A, apa) ->
+ is_record;
+t(A) when is_reference(A) ->
+ is_reference;
+t(A) when is_tuple(A) ->
+ is_tuple;
+t(A) when list(A) ->
+ list;
+t(A) when number(A) ->
+ number;
+t(A) when pid(A) ->
+ pid;
+t(A) when port(A) ->
+ port;
+t(A) when record(A, apa) ->
+ record;
+t(A) when reference(A) ->
+ reference;
+t(A) when tuple(A) ->
+ tuple.
+
+t1(A) when atom(A), atom(A) ->
+ atom;
+t1(A) when binary(A), binary(A) ->
+ binary;
+t1(A) when float(A), float(A) ->
+ float;
+t1(A) when function(A), function(A) ->
+ function;
+t1(A) when integer(A), integer(A) ->
+ integer;
+t1(A) when is_atom(A), is_atom(A) ->
+ is_atom;
+t1(A) when is_binary(A), is_binary(A) ->
+ is_binary;
+t1(A) when is_float(A), is_float(A) ->
+ is_float;
+t1(A) when is_function(A), is_function(A) ->
+ is_function;
+t1(A) when is_integer(A), is_integer(A) ->
+ is_integer;
+t1(A) when is_list(A), is_list(A) ->
+ is_list;
+t1(A) when is_number(A), is_number(A) ->
+ is_number;
+t1(A) when is_pid(A), is_pid(A) ->
+ is_pid;
+t1(A) when is_port(A), is_port(A) ->
+ is_port;
+t1(A) when is_record(A, apa), is_record(A, apa) ->
+ is_record;
+t1(A) when is_reference(A), is_reference(A) ->
+ is_reference;
+t1(A) when is_tuple(A), is_tuple(A) ->
+ is_tuple;
+t1(A) when list(A), list(A) ->
+ list;
+t1(A) when number(A), number(A) ->
+ number;
+t1(A) when pid(A), pid(A) ->
+ pid;
+t1(A) when port(A), port(A) ->
+ port;
+t1(A) when record(A, apa), record(A, apa) ->
+ record;
+t1(A) when reference(A), reference(A) ->
+ reference;
+t1(A) when tuple(A), tuple(A) ->
+ tuple.
+
+t2(A) when atom(A); atom(A) ->
+ atom;
+t2(A) when binary(A); binary(A) ->
+ binary;
+t2(A) when float(A); float(A) ->
+ float;
+t2(A) when function(A); function(A) ->
+ function;
+t2(A) when integer(A); integer(A) ->
+ integer;
+t2(A) when is_atom(A); is_atom(A) ->
+ is_atom;
+t2(A) when is_binary(A); is_binary(A) ->
+ is_binary;
+t2(A) when is_float(A); is_float(A) ->
+ is_float;
+t2(A) when is_function(A); is_function(A) ->
+ is_function;
+t2(A) when is_integer(A); is_integer(A) ->
+ is_integer;
+t2(A) when is_list(A); is_list(A) ->
+ is_list;
+t2(A) when is_number(A); is_number(A) ->
+ is_number;
+t2(A) when is_pid(A); is_pid(A) ->
+ is_pid;
+t2(A) when is_port(A); is_port(A) ->
+ is_port;
+t2(A) when is_record(A, apa); is_record(A, apa) ->
+ is_record;
+t2(A) when is_reference(A); is_reference(A) ->
+ is_reference;
+t2(A) when is_tuple(A); is_tuple(A) ->
+ is_tuple;
+t2(A) when list(A); list(A) ->
+ list;
+t2(A) when number(A); number(A) ->
+ number;
+t2(A) when pid(A); pid(A) ->
+ pid;
+t2(A) when port(A); port(A) ->
+ port;
+t2(A) when record(A, apa); record(A, apa) ->
+ record;
+t2(A) when reference(A); reference(A) ->
+ reference;
+t2(A) when tuple(A); tuple(A) ->
+ tuple.
+
+t3(A) when is_atom(A) or is_atom(A) ->
+ is_atom;
+t3(A) when is_binary(A) or is_binary(A) ->
+ is_binary;
+t3(A) when is_float(A) or is_float(A) ->
+ is_float;
+t3(A) when is_function(A) or is_function(A) ->
+ is_function;
+t3(A) when is_integer(A) or is_integer(A) ->
+ is_integer;
+t3(A) when is_list(A) or is_list(A) ->
+ is_list;
+t3(A) when is_number(A) or is_number(A) ->
+ is_number;
+t3(A) when is_pid(A) or is_pid(A) ->
+ is_pid;
+t3(A) when is_port(A) or is_port(A) ->
+ is_port;
+t3(A) when is_record(A, apa) or is_record(A, apa) ->
+ is_record;
+t3(A) when is_reference(A) or is_reference(A) ->
+ is_reference;
+t3(A) when is_tuple(A) or is_tuple(A) ->
+ is_tuple;
+t3(A) when record(A, apa) ->
+ foo;
+t3(A) when {erlang,is_record}(A, apa) ->
+ foo;
+t3(A) when erlang:is_record(A, apa) ->
+ foo;
+t3(A) when is_record(A, apa) ->
+ foo;
+t3(A) when record({apa}, apa) ->
+ {A,foo}.
+
+t4(_) when {erlang,is_record}({apa}, apa) ->
+ foo.
+
+t5(A) when erlang:is_record({apa}, apa) ->
+ {A,foo}.
+
+t6(A) when is_record({apa}, apa) ->
+ {A,foo}.
+
+-record(apa2,{a=a,b=foo:bar()}).
+apa(1) ->
+ [X || X <- [], #apa2{a = a} == {r,X,foo}];
+apa(2) ->
+ [X || X <- [], #apa2{b = b} == {r,X,foo}];
+apa(3) ->
+ [X || X <- [], 3 == X#apa2.a].
+
+new_fun() ->
+ lists:map(fun erlang:abs/1, [-1,3,4]).
diff --git a/lib/stdlib/test/id_transform_SUITE_data/External.hrl b/lib/stdlib/test/id_transform_SUITE_data/External.hrl
new file mode 100644
index 0000000000..c0cd9e68ac
--- /dev/null
+++ b/lib/stdlib/test/id_transform_SUITE_data/External.hrl
@@ -0,0 +1,41 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%% Generated by the Erlang ASN.1 compiler version:0.8.1
+%% Purpose: Erlang record definitions for each named and unnamed
+%% SEQUENCE and SET in module External
+
+-record('XSeq1',{bool1, int1, seq1}).
+-record('XSeqIn',{boolIn, intIn}).
+-record('XSet1',{bool1, int1, set1}).
+-record('XSetIn',{boolIn, intIn}).
+-record('XSetExt1',{asn1_EXT}).
+-record('XSetExt2',{bool, int, asn1_EXT}).
+-record('XSetExt3',{asn1_EXT, bool, int}).
+-record('XSetExt4',{bool, asn1_EXT, int}).
+-record('XSeqExt1',{asn1_EXT}).
+-record('XSeqExt2',{bool, int, asn1_EXT}).
+-record('XSeqExt3',{asn1_EXT, bool, int}).
+-record('XSeqExt4',{bool, asn1_EXT, int}).
+-record('XSetNT',{os, bool}).
+-record('XSetImp',{os, bool}).
+-record('XSetExp',{os, bool}).
+-record('XSeqNT',{os, bool}).
+-record('XSeqImp',{os, bool}).
+-record('XSeqExp',{os, bool}).
+
diff --git a/lib/stdlib/test/id_transform_SUITE_data/m.hrl b/lib/stdlib/test/id_transform_SUITE_data/m.hrl
new file mode 100644
index 0000000000..ed485e24be
--- /dev/null
+++ b/lib/stdlib/test/id_transform_SUITE_data/m.hrl
@@ -0,0 +1,30 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+
+-ifndef(M_HRL).
+-define(M_HRL, true).
+
+
+-record(m_NotAnInteger, {'OE_ID'="IDL:m/NotAnInteger:1.0"}).
+
+
+-endif.
+
+
diff --git a/lib/stdlib/test/id_transform_SUITE_data/m_i.hrl b/lib/stdlib/test/id_transform_SUITE_data/m_i.hrl
new file mode 100644
index 0000000000..53a279999e
--- /dev/null
+++ b/lib/stdlib/test/id_transform_SUITE_data/m_i.hrl
@@ -0,0 +1,29 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+
+-ifndef(M_I_HRL).
+-define(M_I_HRL, true).
+
+
+
+
+-endif.
+
+
diff --git a/lib/stdlib/test/id_transform_SUITE_data/oe_ex.hrl b/lib/stdlib/test/id_transform_SUITE_data/oe_ex.hrl
new file mode 100644
index 0000000000..72a12908df
--- /dev/null
+++ b/lib/stdlib/test/id_transform_SUITE_data/oe_ex.hrl
@@ -0,0 +1,29 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+
+-ifndef(OE_EX_HRL).
+-define(OE_EX_HRL, true).
+
+
+
+
+-endif.
+
+
diff --git a/lib/stdlib/test/io_SUITE.erl b/lib/stdlib/test/io_SUITE.erl
new file mode 100644
index 0000000000..73efeb004a
--- /dev/null
+++ b/lib/stdlib/test/io_SUITE.erl
@@ -0,0 +1,1900 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(io_SUITE).
+
+-export([all/1]).
+
+-export([init_per_testcase/2, fin_per_testcase/2]).
+
+-export([error_1/1, float_g/1, otp_5403/1, otp_5813/1, otp_6230/1,
+ otp_6282/1, otp_6354/1, otp_6495/1, otp_6517/1, otp_6502/1,
+ manpage/1, otp_6708/1, otp_7084/1, otp_7421/1,
+ io_lib_collect_line_3_wb/1, cr_whitespace_in_string/1,
+ io_fread_newlines/1]).
+
+%-define(debug, true).
+
+-ifdef(debug).
+-define(format(S, A), io:format(S, A)).
+-define(line, put(line, ?LINE), ).
+-define(config(X,Y), foo).
+-define(t, test_server).
+-define(privdir(_), "./io_SUITE_priv").
+-else.
+-include("test_server.hrl").
+-define(format(S, A), ok).
+-define(privdir(Conf), ?config(priv_dir, Conf)).
+-endif.
+
+
+% Default timetrap timeout (set in init_per_testcase).
+-define(default_timeout, ?t:minutes(1)).
+
+init_per_testcase(_Case, Config) ->
+ ?line Dog = ?t:timetrap(?default_timeout),
+ [{watchdog, Dog} | Config].
+fin_per_testcase(_Case, _Config) ->
+ Dog = ?config(watchdog, _Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+all(doc) ->
+ ["Test cases for io."];
+all(suite) ->
+ [error_1,float_g,otp_5403,otp_5813,otp_6230,otp_6282,otp_6354,otp_6495,
+ otp_6517,otp_6502,manpage,otp_6708,otp_7084,otp_7421,
+ io_lib_collect_line_3_wb,cr_whitespace_in_string,io_fread_newlines].
+
+error_1(doc) ->
+ ["Error cases for output"];
+error_1(suite) ->
+ [];
+error_1(Config) when is_list(Config) ->
+ %% We don't do erroneous output on stdout - the test server
+ %% seems to catch that somehow.
+ ?line PrivDir = ?privdir(Config),
+ ?line File = filename:join(PrivDir, "slask"),
+ ?line {ok, F1} = file:open(File, [write]),
+ ?line {'EXIT', _} = (catch io:format(muttru, "hej", [])),
+ ?line {'EXIT', _} = (catch io:format(F1, pelle, "hej")),
+ ?line {'EXIT', _} = (catch io:format(F1, 1, "hej")),
+ ?line {'EXIT', _} = (catch io:format(F1, "~p~", [kaka])),
+ ?line {'EXIT', _} = (catch io:format(F1, "~m~n", [kaka])),
+
+ %% This causes the file process to die, and it is linked to us,
+ %% so we can't catch the error this easily.
+% ?line {'EXIT', _} = (catch io:put_chars(F1, 666)),
+
+ ?line file:close(F1),
+ ?line {'EXIT', _} = (catch io:format(F1, "~p", ["hej"])),
+ ok.
+
+float_g(Config) when is_list(Config) ->
+ ?line ["5.00000e-2",
+ "0.500000",
+ "5.00000",
+ "50.0000",
+ "500.000",
+ "5000.00",
+ "5.00000e+4",
+ "5.00000e+5"] = float_g_1("~g", 5.0, -2, 5),
+
+ ?line ["-5.0000e-2",
+ "-0.50000",
+ "-5.0000",
+ "-50.000",
+ "-500.00",
+ "-5000.0",
+ "-5.0000e+4",
+ "-5.0000e+5"] = float_g_1("~.5g", -5.0, -2, 5),
+
+ ?line ["5.000e-2",
+ "0.5000",
+ "5.000",
+ "50.00",
+ "500.0",
+ "5.000e+3",
+ "5.000e+4",
+ "5.000e+5"] = float_g_1("~.4g", 5.0, -2, 5),
+
+ ?line ["-5.00e-2",
+ "-0.500",
+ "-5.00",
+ "-50.0",
+ "-5.00e+2",
+ "-5.00e+3",
+ "-5.00e+4",
+ "-5.00e+5"] = float_g_1("~.3g", -5.0, -2, 5),
+
+ ?line ["5.0e-2",
+ "0.50",
+ "5.0",
+ "5.0e+1",
+ "5.0e+2",
+ "5.0e+3",
+ "5.0e+4",
+ "5.0e+5"] = float_g_1("~.2g", 5.0, -2, 5),
+
+ ?line
+ case catch fmt("~.1g", [0.5]) of
+ "0.5" ->
+ ?line
+ ["5.0e-2",
+ "0.5",
+ "5.0e+0",
+ "5.0e+1",
+ "5.0e+2",
+ "5.0e+3",
+ "5.0e+4",
+ "5.0e+5"] = float_g_1("~.1g", 5.0, -2, 5);
+ {'EXIT',_} -> ok
+ end,
+
+ ?line ["4.99999e-2",
+ "0.499999",
+ "4.99999",
+ "49.9999",
+ "499.999",
+ "4999.99",
+ "4.99999e+4",
+ "4.99999e+5"] = float_g_1("~g", 4.9999949999, -2, 5),
+
+ ?line ["-5.00000e-2",
+ "-0.500000",
+ "-5.00000",
+ "-50.0000",
+ "-500.000",
+ "-5000.00",
+ "-5.00000e+4",
+ "-5.00000e+5"] = float_g_1("~g", -4.9999950001, -2, 5),
+ ok.
+
+float_g_1(Fmt, V, Min, Max) ->
+ [fmt(Fmt, [V*math:pow(10, E)]) || E <- lists:seq(Min, Max)].
+
+otp_5403(doc) ->
+ ["OTP-5403. ~s formats I/O lists and a single binary."];
+otp_5403(suite) ->
+ [];
+otp_5403(Config) when is_list(Config) ->
+ ?line "atom" = fmt("~s", [atom]),
+ ?line "binary" = fmt("~s", [<<"binary">>]),
+ ?line "atail" = fmt("~s", [["a" | <<"tail">>]]),
+ ?line "deepcharlist" = fmt("~s", [["deep",["char",["list"]]]]),
+ ?line "somebinaries" = fmt("~s", [[<<"some">>,[<<"binaries">>]]]),
+ ok.
+
+otp_5813(doc) ->
+ ["OTP-5813. read/3 is new."];
+otp_5813(suite) ->
+ [];
+otp_5813(Config) when is_list(Config) ->
+ ?line PrivDir = ?privdir(Config),
+ ?line File = filename:join(PrivDir, "test"),
+
+ ?line ok = file:write_file(File, <<"a. ">>),
+ ?line {ok, Fd} = file:open(File, [read]),
+ ?line {ok, a, 1} = io:read(Fd, '', 1),
+ ?line {eof,1} = io:read(Fd, '', 1),
+ ok = file:close(Fd),
+
+ ?line ok = file:write_file(File, <<"[}.">>),
+ ?line {ok, Fd2} = file:open(File, [read]),
+ ?line {error,{1,_,_},1} = io:read(Fd2, '', 1),
+ ?line ok = file:close(Fd),
+
+ file:delete(File),
+ ok.
+
+otp_6230(doc) ->
+ ["OTP-6230. ~p and ~P with (huge) binaries."];
+otp_6230(suite) ->
+ [];
+otp_6230(Config) when is_list(Config) ->
+ %% The problem is actually huge binaries, but the small tests here
+ %% just run through most of the modified code.
+ ?line "<<>>" = fmt("~P", [<<"">>,-1]),
+ ?line "<<\"hej\">>" = fmt("~P", [<<"hej">>,-1]),
+ ?line "{hej,...}" = fmt("~P", [{hej,<<"hej">>},2]),
+ ?line "{hej,<<...>>}" = fmt("~P", [{hej,<<"hej">>},3]),
+ ?line "{hej,<<\"hejs\"...>>}" = fmt("~P", [{hej,<<"hejsan">>},4]),
+ ?line "{hej,<<\"hej\">>}" = fmt("~P", [{hej,<<"hej">>},6]),
+ ?line "<<...>>" = fmt("~P", [<<"hej">>,1]),
+ ?line "<<\"hejs\"...>>" = fmt("~P", [<<"hejsan">>,2]),
+ ?line "<<\"hej\">>" = fmt("~P", [<<"hej">>,4]),
+ ?line "{hej,<<127,...>>}" =
+ fmt("~P", [{hej,<<127:8,<<"hej">>/binary>>},4]),
+ ?line "{hej,<<127,104,101,...>>}" =
+ fmt("~P", [{hej,<<127:8,<<"hej">>/binary>>},6]),
+
+ B = list_to_binary(lists:duplicate(30000, $a)),
+ ?line "<<\"aaaa"++_ = fmt("~P", [B, 20000]),
+ ok.
+
+otp_6282(doc) ->
+ ["OTP-6282. ~p truncates strings (like binaries) depending on depth."];
+otp_6282(suite) ->
+ [];
+otp_6282(Config) when is_list(Config) ->
+ ?line "[]" = p("", 1, 20, 1),
+ ?line "[]" = p("", 1, 20, -1),
+ ?line "[...]" = p("a", 1, 20, 1),
+ ?line "\"a\"" = p("a", 1, 20, 2),
+ ?line "\"aa\"" = p("aa", 1, 20, 2),
+ ?line "\"aaa\"" = p("aaa", 1, 20, 2),
+ ?line "\"aaaa\"" = p("aaaa", 1, 20, 2),
+ % ?line "\"aaaa\"..." = p("aaaaaa", 1, 20, 2),
+ ?line "\"a\"" = p("a", 1, 20, -1),
+ % ?line "\"aa\"..." = p([$a,$a,1000], 1, 20, 2),
+ % ?line "\"aa\"..." = p([$a,$a,1000], 1, 20, 3),
+ ?line "[97,97,1000]" = p([$a,$a,1000], 1, 20, 4),
+ S1 = lists:duplicate(200,$a),
+ ?line "[...]" = p(S1, 1, 20, 1),
+ % ?line "\"aaaaaaaaaaaaaaaa\"\n \"aaaaaaaaaaaaaaaa\"\n \"aaaa\"..." =
+ % ?line "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"..." =
+ % p(S1, 1, 20, 10),
+ ?line true = "\"" ++ S1 ++ "\"" =:= p(S1, 1, 205, -1),
+ ?line "[97,97,1000|...]" = p([$a,$a,1000,1000], 1, 20, 4),
+
+ ?line "[[]]" = p([""], 1, 20, 2),
+ ?line "[[]]" = p([""], 1, 20, -1),
+ ?line "[[...]]" = p(["a"], 1, 20, 2),
+ ?line "[\"a\"]" = p(["a"], 1, 20, 3),
+ ?line "[\"aa\"]" = p(["aa"], 1, 20, 3),
+ ?line "[\"aaa\"]" = p(["aaa"], 1, 20, 3),
+ ?line "[\"a\"]" = p(["a"], 1, 20, -1),
+ % ?line "[\"aa\"...]" = p([[$a,$a,1000]], 1, 20, 3),
+ % ?line "[\"aa\"...]" = p([[$a,$a,1000]], 1, 20, 4),
+ ?line "[[97,97,1000]]" = p([[$a,$a,1000]], 1, 20, 5),
+ ?line "[[...]]" = p([S1], 1, 20, 2),
+ % ?line "[\"aaaaaaaaaaaaaa\"\n \"aaaaaaaaaaaaaa\"\n \"aaaaaaaa\"...]" =
+ % ?line "[\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"...]" =
+ % p([S1], 1, 20, 11),
+ ?line true = "[\"" ++ S1 ++ "\"]" =:= p([S1], 1, 210, -1),
+ ?line "[[97,97,1000|...]]" = p([[$a,$a,1000,1000]], 1, 20, 5),
+
+ % ?line "[\"aaaa\"...]" = p(["aaaaa"], 1, 10, 3),
+ ?line "[\"aaaaa\"]" = p(["aaaaa"], 1, 10, 6),
+
+ ok.
+
+otp_6354(doc) ->
+ ["OTP-6354. io_lib_pretty rewritten."];
+otp_6354(suite) ->
+ [];
+otp_6354(Config) when is_list(Config) ->
+ %% A few tuples:
+ ?line "{}" = p({}, 1, 20, -1),
+ ?line "..." = p({}, 1, 20, 0),
+ ?line "{}" = p({}, 1, 20, 1),
+ ?line "{}" = p({}, 1, 20, 2),
+ ?line "{a}" = p({a}, 1, 20, -1),
+ ?line "..." = p({a}, 1, 20, 0),
+ ?line "{...}" = p({a}, 1, 20, 1),
+ ?line "{a}" = p({a}, 1, 20, 2),
+ ?line "{a,b}" = p({a,b}, 1, 20, -1),
+ ?line "..." = p({a,b}, 1, 20, 0),
+ ?line "{...}" = p({a,b}, 1, 20, 1),
+ ?line "{a,...}" = p({a,b}, 1, 20, 2),
+ ?line "{a,b}" = p({a,b}, 1, 20, 3),
+ ?line "{}" = p({}, 1, 1, -1),
+ ?line "..." = p({}, 1, 1, 0),
+ ?line "{}" = p({}, 1, 1, 1),
+ ?line "{}" = p({}, 1, 1, 2),
+ ?line "{a}" = p({a}, 1, 1, -1),
+ ?line "..." = p({a}, 1, 1, 0),
+ ?line "{...}" = p({a}, 1, 1, 1),
+ ?line "{a}" = p({a}, 1, 1, 2),
+ ?line "{a,\n b}" = p({a,b}, 1, 1, -1),
+ ?line "{1,\n b}" = p({1,b}, 1, 1, -1),
+ ?line "..." = p({a,b}, 1, 1, 0),
+ ?line "{...}" = p({a,b}, 1, 1, 1),
+ ?line "{a,...}" = p({a,b}, 1, 1, 2),
+ ?line "{a,\n b}" = p({a,b}, 1, 1, 3),
+ ?line "{{}}" = p({{}}, 1, 1, 2),
+ ?line "{[]}" = p({[]}, 1, 1, 2),
+ ?line bt(<<"{1,2,a,b,{sfdsf,sdfdsfs},[sfsdf,sdfsdf]}">>,
+ p({1,2,a,b,{sfdsf,sdfdsfs},[sfsdf,sdfsdf]}, -1)),
+ ?line bt(<<"{abcd,ddddd,\n ddddd}">>,
+ p({abcd,ddddd,ddddd}, 1,16, -1)),
+ ?line bt(<<"{1,2,a,b,\n {sfdsf,sdfdsfs},\n [sfsdf,sdfsdf]}">>,
+ p({1,2,a,b,{sfdsf,sdfdsfs},[sfsdf,sdfsdf]}, 1, 35, 100)),
+ % With other terms than atomic ones on the same line:
+% ?line bt(<<"{1,2,a,b,{sfdsf,sdfdsfs},\n [sfsdf,sdfsdf]}">>,
+% p({1,2,a,b,{sfdsf,sdfdsfs},[sfsdf,sdfsdf]}, 1, 35, 100)),
+ % With line breaks:
+% ?line bt(<<"{1,\n"
+% " 2,\n"
+% " a,\n"
+% " b,\n"
+% " {sfdsf,sdfdsfs},\n"
+% " [sfsdf,sdfsdf]}">>,
+% p({1,2,a,b,{sfdsf,sdfdsfs},[sfsdf,sdfsdf]}, 1, 35, 100)),
+ ?line "{1,{1,{2,3}}}" = p({1,{1,{2,3}}}, 1, 80, 100),
+
+ ?line bt(<<"{wwwww,{wwwww,{wwwww,{wwwww,{wwwww,lkjsldfj,klsdjfjklds,\n"
+ " sdkfjdsl,sdakfjdsklj,sdkljfsdj}}}}}">>,
+ p({wwwww,{wwwww,{wwwww,{wwwww,{wwwww,lkjsldfj,klsdjfjklds,
+ sdkfjdsl,sdakfjdsklj,sdkljfsdj}}}}}, -1)),
+
+ % With no restriction on number of characters per line:
+% ?line bt(<<"{wwwww,{wwwww,{wwwww,{wwwww,{wwwww,lkjsldfj,klsdjfjklds,"
+% "sdkfjdsl,sdakfjdsklj,\n"
+% " sdkljfsdj}}}}}">>,
+% p({wwwww,{wwwww,{wwwww,{wwwww,{wwwww,lkjsldfj,klsdjfjklds,
+% sdkfjdsl,sdakfjdsklj,sdkljfsdj}}}}}, -1)),
+
+ % With line breaks:
+% ?line bt(<<"{wwwww,{wwwww,{wwwww,{wwwww,{wwwww,lkjsldfj,\n"
+% " klsdjfjklds,\n"
+% " sdkfjdsl,\n"
+% " sdakfjdsklj,\n"
+% " sdkljfsdj}}}}}">>,
+% p({wwwww,{wwwww,{wwwww,{wwwww,{wwwww,lkjsldfj,klsdjfjklds,
+% sdkfjdsl,sdakfjdsklj,sdkljfsdj}}}}}, -1)),
+ ?line bt(<<"{wwwww,\n"
+ " {wwwww,\n"
+ " {wwwww,\n"
+ " {wwwww,\n"
+ " {wwwww,\n"
+ " {lkjsldfj,\n"
+ " {klsdjfjklds,\n"
+ " {klajsljls,\n"
+ " #aaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaa{}}}}}}}}}">>,
+ p({wwwww,{wwwww,{wwwww,{wwwww,{wwwww,{lkjsldfj,
+ {klsdjfjklds,{klajsljls,
+ {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}}}}}}}}},
+ -1)),
+ ?line "{{...},...}" = p({{a,b},{a,b,c},{d,e,f}},1,8,2),
+ %% Closing brackets and parentheses count:
+ ?line "{{a,b,c},\n {{1,2,\n 3}}}" = p({{a,b,c},{{1,2,3}}},1,11,-1),
+ % With line breaks:
+% ?line "{{a,b,c},\n {{1,\n 2,\n 3}}}" = p({{a,b,c},{{1,2,3}}},1,11,-1),
+ ?line "{{a,b,c},\n [1,2,\n 3]}" = p({{a,b,c},[1,2,3]},1,10,-1),
+ % With line breaks:
+% ?line "{{a,b,c},\n [1,\n 2,\n 3]}" = p({{a,b,c},[1,2,3]},1,10,-1),
+ ?line "[{{a,b,c},\n {1,2,\n 3}}]" = p([{{a,b,c},{1,2,3}}],1,12,-1),
+ % With line breaks:
+% ?line "[{{a,b,c},\n {1,\n 2,\n 3}}]" = p([{{a,b,c},{1,2,3}}],1,12,-1),
+
+ %% A few lists:
+ ?line "[]" = p([], 1, 20, -1),
+ ?line "..." = p([], 1, 20, 0),
+ ?line "[]" = p([], 1, 20, 1),
+ ?line "[]" = p([], 1, 20, 2),
+ ?line "[a]" = p([a], 1, 20, -1),
+ ?line "..." = p([a], 1, 20, 0),
+ ?line "[...]" = p([a], 1, 20, 1),
+ ?line "[a]" = p([a], 1, 20, 2),
+ ?line "[a,b]" = p([a,b], 1, 20, -1),
+ ?line "..." = p([a,b], 1, 20, 0),
+ ?line "[...]" = p([a,b], 1, 20, 1),
+ ?line "[a|...]" = p([a,b], 1, 20, 2),
+ ?line "[a,b]" = p([a,b], 1, 20, 3),
+ ?line "[a|b]" = p([a|b], 1, 20, -1),
+ ?line "..." = p([a|b], 1, 20, 0),
+ ?line "[...]" = p([a|b], 1, 20, 1),
+ ?line "[a|...]" = p([a|b], 1, 20, 2),
+ ?line "[a|b]" = p([a|b], 1, 20, 3),
+ ?line "[]" = p([], 1, 1, -1),
+ ?line "..." = p([], 1, 1, 0),
+ ?line "[]" = p([], 1, 1, 1),
+ ?line "[]" = p([], 1, 1, 2),
+ ?line "[a]" = p([a], 1, 1, -1),
+ ?line "..." = p([a], 1, 1, 0),
+ ?line "[...]" = p([a], 1, 1, 1),
+ ?line "[a]" = p([a], 1, 1, 2),
+ ?line "[a,\n b]" = p([a,b], 1, 1, -1),
+ ?line "..." = p([a,b], 1, 1, 0),
+ ?line "[...]" = p([a,b], 1, 1, 1),
+ ?line "[a|...]" = p([a,b], 1, 1, 2),
+ ?line "[a,\n b]" = p([a,b], 1, 1, 3),
+ ?line "[a|\n b]" = p([a|b], 1, 1, -1),
+ ?line "..." = p([a|b], 1, 1, 0),
+ ?line "[...]" = p([a|b], 1, 1, 1),
+ ?line "[a|...]" = p([a|b], 1, 1, 2),
+ ?line "[a|\n b]" = p([a|b], 1, 1, 3),
+ ?line "[{}]" = p([{}], 1, 1, 2),
+ ?line "[[]]" = p([[]], 1, 1, 2),
+ ?line bt(<<"[1,2,a,b,{sfdsf,sdfdsfs},[sfsdf,sdfsdf]]">>,
+ p([1,2,a,b,{sfdsf,sdfdsfs},[sfsdf,sdfsdf]], -1)),
+ ?line bt(<<"[1,2,a,b,\n {sfdsf,sdfdsfs},\n [sfsdf,sdfsdf]]">>,
+ p([1,2,a,b,{sfdsf,sdfdsfs},[sfsdf,sdfsdf]], 1, 35, 100)),
+ % With other terms than atomic ones on the same line:
+% ?line bt(<<"[1,2,a,b,{sfdsf,sdfdsfs},\n [sfsdf,sdfsdf]]">>,
+% p([1,2,a,b,{sfdsf,sdfdsfs},[sfsdf,sdfsdf]], 1, 35, 100)),
+ % With line breaks:
+% ?line bt(<<"[1,\n"
+% " 2,\n"
+% " a,\n"
+% " b,\n"
+% " {sfdsf,sdfdsfs},\n"
+% " [sfsdf,sdfsdf]]">>,
+% p([1,2,a,b,{sfdsf,sdfdsfs},[sfsdf,sdfsdf]], 1, 35, 100)),
+ %% Element #8 is not printable:
+ ?line "[49," ++ _ = p("1234567"++[3,4,5,6,7], 1, 100, 9),
+ % ?line "\"1234567\"..." = p("1234567"++[3,4,5,6,7], 1, 100, 8),
+
+ %% A few records:
+ %% -record(a, {}).
+ %% -record(a, {}).
+ ?line "..." = p({a}, 0),
+ ?line "{...}" = p({a}, 1),
+ ?line "#a{}" = p({a}, 2),
+ ?line "#a{}" = p({a}, -1),
+ %% -record(b, {f}).
+ ?line "{...}" = p({b}, 1),
+ ?line "..." = p({b,c}, 0),
+ ?line "{...}" = p({b,c}, 1),
+ ?line "#b{...}" = p({b,c}, 2),
+ ?line "#b{f = c}" = p({b,c}, 3),
+ ?line "#b{f = c}" = p({b,c}, -1),
+ ?line "..." = p({b,{c,d}}, 0),
+ ?line "{...}" = p({b,{c,d}}, 1),
+ ?line "#b{...}" = p({b,{c,d}}, 2),
+ ?line "#b{f = {...}}" = p({b,{c,d}}, 3),
+ ?line "#b{f = {c,...}}" = p({b,{c,d}}, 4),
+ ?line "#b{f = {c,d}}" = p({b,{c,d}}, 5),
+ ?line "#b{f = {...}}" = p({b,{b,c}}, 3),
+ ?line "#b{f = #b{...}}" = p({b,{b,c}}, 4),
+ ?line "#b{f = #b{f = c}}" = p({b,{b,c}}, 5),
+ %% -record(c, {f1, f2}).
+ ?line "#c{f1 = d,f2 = e}" = p({c,d,e}, -1),
+ ?line "..." = p({c,d,e}, 0),
+ ?line "{...}" = p({c,d,e}, 1),
+ ?line "#c{...}" = p({c,d,e}, 2),
+ ?line "#c{f1 = d,...}" = p({c,d,e}, 3),
+ ?line "#c{f1 = d,f2 = e}" = p({c,d,e}, 4),
+ %% -record(d, {a..., b..., c.., d...}).
+ ?line bt(<<"#d{aaaaaaaaaaaaaaaaaaaa = 1,bbbbbbbbbbbbbbbbbbbb = 2,\n"
+ " cccccccccccccccccccc = 3,dddddddddddddddddddd = 4,\n"
+ " eeeeeeeeeeeeeeeeeeee = 5}">>,
+ p({d,1,2,3,4,5}, -1)),
+ % With no restriction on number of characters per line:
+% ?line bt(<<"#d{aaaaaaaaaaaaaaaaaaaa = 1,bbbbbbbbbbbbbbbbbbbb = 2,"
+% "cccccccccccccccccccc = 3,\n dddddddddddddddddddd = 4,"
+% "eeeeeeeeeeeeeeeeeeee = 5}">>,
+% p({d,1,2,3,4,5}, -1)),
+ % With line breaks:
+% ?line bt(<<"#d{aaaaaaaaaaaaaaaaaaaa = 1,\n"
+% " bbbbbbbbbbbbbbbbbbbb = 2,\n"
+% " cccccccccccccccccccc = 3,\n"
+% " dddddddddddddddddddd = 4,\n"
+% " eeeeeeeeeeeeeeeeeeee = 5}">>,
+% p({d,1,2,3,4,5}, -1)),
+ ?line "..." = p({d,1,2,3,4,5}, 0),
+ ?line "{...}" = p({d,1,2,3,4,5}, 1),
+ ?line "#d{...}" = p({d,1,2,3,4,5}, 2),
+ ?line "#d{aaaaaaaaaaaaaaaaaaaa = 1,...}" = p({d,1,2,3,4,5}, 3),
+ ?line bt(<<"#d{aaaaaaaaaaaaaaaaaaaa = 1,bbbbbbbbbbbbbbbbbbbb = 2,...}">>,
+ p({d,1,2,3,4,5}, 4)),
+ ?line bt(<<"#d{aaaaaaaaaaaaaaaaaaaa = 1,bbbbbbbbbbbbbbbbbbbb = 2,\n"
+ " cccccccccccccccccccc = 3,...}">>,
+ p({d,1,2,3,4,5}, 5)), % longer than 80 characters...
+ % With no restriction on number of characters per line:
+% ?line bt(<<"#d{aaaaaaaaaaaaaaaaaaaa = 1,bbbbbbbbbbbbbbbbbbbb = 2,"
+% "cccccccccccccccccccc = 3,...}">>,
+% p({d,1,2,3,4,5}, 5)), % longer than 80 characters...
+ % With line breaks:
+% ?line bt(<<"#d{aaaaaaaaaaaaaaaaaaaa = 1,\n"
+% " bbbbbbbbbbbbbbbbbbbb = 2,\n"
+% " cccccccccccccccccccc = 3,...}">>,
+% p({d,1,2,3,4,5}, 5)),
+ ?line bt(<<"#d{aaaaaaaaaaaaaaaaaaaa = 1,bbbbbbbbbbbbbbbbbbbb = 2,\n"
+ " cccccccccccccccccccc = 3,dddddddddddddddddddd = 4,...}">>,
+ p({d,1,2,3,4,5}, 6)),
+ % With no restriction on number of characters per line:
+% ?line bt(<<"#d{aaaaaaaaaaaaaaaaaaaa = 1,bbbbbbbbbbbbbbbbbbbb = 2,"
+% "cccccccccccccccccccc = 3,\n dddddddddddddddddddd = 4,...}">>,
+% p({d,1,2,3,4,5}, 6)),
+ % With line breaks:
+% ?line bt(<<"#d{aaaaaaaaaaaaaaaaaaaa = 1,\n"
+% " bbbbbbbbbbbbbbbbbbbb = 2,\n"
+% " cccccccccccccccccccc = 3,\n"
+% " dddddddddddddddddddd = 4,...}">>,
+% p({d,1,2,3,4,5}, 6)),
+ ?line bt(<<"#d{aaaaaaaaaaaaaaaaaaaa = 1,bbbbbbbbbbbbbbbbbbbb = 2,\n"
+ " cccccccccccccccccccc = 3,dddddddddddddddddddd = 4,\n"
+ " eeeeeeeeeeeeeeeeeeee = 5}">>,
+ p({d,1,2,3,4,5}, 7)),
+ % With no restriction on number of characters per line:
+% ?line bt(<<"#d{aaaaaaaaaaaaaaaaaaaa = 1,bbbbbbbbbbbbbbbbbbbb = 2,"
+% "cccccccccccccccccccc = 3,\n dddddddddddddddddddd = 4,"
+% "eeeeeeeeeeeeeeeeeeee = 5}">>,
+% p({d,1,2,3,4,5}, 7)),
+ % With line breaks:
+% ?line bt(<<"#d{aaaaaaaaaaaaaaaaaaaa = 1,\n"
+% " bbbbbbbbbbbbbbbbbbbb = 2,\n"
+% " cccccccccccccccccccc = 3,\n"
+% " dddddddddddddddddddd = 4,\n"
+% " eeeeeeeeeeeeeeeeeeee = 5}">>,
+% p({d,1,2,3,4,5}, 7)),
+ ?line bt(<<"#rrrrr{\n"
+ " f1 = 1,\n"
+ " f2 = #rrrrr{f1 = a,f2 = b,f3 = c},\n"
+ " f3 = \n"
+ " #rrrrr{\n"
+ " f1 = h,f2 = i,\n"
+ " f3 = \n"
+ " #rrrrr{\n"
+ " f1 = aa,\n"
+ " f2 = \n"
+ " #rrrrr{\n"
+ " f1 = #rrrrr{f1 = a,f2 = b,f3 = c},\n"
+ " f2 = 2,f3 = 3},\n"
+ " f3 = bb}}}">>,
+ p({rrrrr,1,{rrrrr,a,b,c},{rrrrr,h,i,
+ {rrrrr,aa,{rrrrr,{rrrrr,a,b,c},
+ 2,3},bb}}},
+ -1)),
+ % With other terms than atomic ones on the same line:
+% ?line bt(<<"#rrrrr{\n"
+% " f1 = 1,f2 = #rrrrr{f1 = a,f2 = b,f3 = c},\n"
+% " f3 = \n"
+% " #rrrrr{\n"
+% " f1 = h,f2 = i,\n"
+% " f3 = \n"
+% " #rrrrr{\n"
+% " f1 = aa,\n"
+% " f2 = \n"
+% " #rrrrr{\n"
+% " f1 = #rrrrr{f1 = a,f2 = b,"
+% "f3 = c},f2 = 2,f3 = 3},\n"
+% " f3 = bb}}}">>,
+% p({rrrrr,1,{rrrrr,a,b,c},{rrrrr,h,i,
+% {rrrrr,aa,{rrrrr,{rrrrr,a,b,c},
+% 2,3},bb}}},
+% -1)),
+ % With line breaks:
+% ?line bt(<<"#rrrrr{\n"
+% " f1 = 1,\n"
+% " f2 = #rrrrr{f1 = a,f2 = b,f3 = c},\n"
+% " f3 = \n"
+% " #rrrrr{\n"
+% " f1 = h,\n"
+% " f2 = i,\n"
+% " f3 = \n"
+% " #rrrrr{\n"
+% " f1 = aa,\n"
+% " f2 = \n"
+% " #rrrrr{\n"
+% " f1 = #rrrrr{f1 = a,f2 = b,"
+% "f3 = c},\n"
+% " f2 = 2,\n"
+% " f3 = 3},\n"
+% " f3 = bb}}}">>,
+% p({rrrrr,1,{rrrrr,a,b,c},{rrrrr,h,i,
+% {rrrrr,aa,{rrrrr,{rrrrr,a,b,c},
+% 2,3},bb}}},
+% -1)),
+ ?line bt(<<"#d{aaaaaaaaaaaaaaaaaaaa = 1,\n"
+ " bbbbbbbbbbbbbbbbbbbb = \n"
+ " #d{aaaaaaaaaaaaaaaaaaaa = a,bbbbbbbbbbbbbbbbbbbb = b,\n"
+ " cccccccccccccccccccc = c,dddddddddddddddddddd = d,\n"
+ " eeeeeeeeeeeeeeeeeeee = e},\n"
+ " cccccccccccccccccccc = 3,\n"
+ " dddddddddddddddddddd = \n"
+ " #d{aaaaaaaaaaaaaaaaaaaa = h,bbbbbbbbbbbbbbbbbbbb = i,\n"
+ " cccccccccccccccccccc = \n"
+ " #d{aaaaaaaaaaaaaaaaaaaa = aa,"
+ "bbbbbbbbbbbbbbbbbbbb = bb,\n"
+ " cccccccccccccccccccc = \n"
+ " #d{aaaaaaaaaaaaaaaaaaaa = 1,"
+ "bbbbbbbbbbbbbbbbbbbb = 2,\n"
+ " cccccccccccccccccccc = 3,"
+ "dddddddddddddddddddd = 4,\n"
+ " eeeeeeeeeeeeeeeeeeee = 5},\n"
+ " dddddddddddddddddddd = dd,"
+ "eeeeeeeeeeeeeeeeeeee = ee},\n"
+ " dddddddddddddddddddd = k,"
+ "eeeeeeeeeeeeeeeeeeee = l},\n"
+ " eeeeeeeeeeeeeeeeeeee = 5}">>,
+ p({d,1,{d,a,b,c,d,e},3,{d,h,i,{d,aa,bb,{d,1,2,3,4,5},dd,ee},
+ k,l},5}, -1)),
+ % With line breaks:
+% ?line bt(<<"#d{aaaaaaaaaaaaaaaaaaaa = 1,\n"
+% " bbbbbbbbbbbbbbbbbbbb = \n"
+% " #d{aaaaaaaaaaaaaaaaaaaa = a,\n"
+% " bbbbbbbbbbbbbbbbbbbb = b,\n"
+% " cccccccccccccccccccc = c,\n"
+% " dddddddddddddddddddd = d,\n"
+% " eeeeeeeeeeeeeeeeeeee = e},\n"
+% " cccccccccccccccccccc = 3,\n"
+% " dddddddddddddddddddd = \n"
+% " #d{aaaaaaaaaaaaaaaaaaaa = h,\n"
+% " bbbbbbbbbbbbbbbbbbbb = i,\n"
+% " cccccccccccccccccccc = \n"
+% " #d{aaaaaaaaaaaaaaaaaaaa = aa,\n"
+% " bbbbbbbbbbbbbbbbbbbb = bb,\n"
+% " cccccccccccccccccccc = \n"
+% " #d{aaaaaaaaaaaaaaaaaaaa = 1,\n"
+% " bbbbbbbbbbbbbbbbbbbb = 2,\n"
+% " cccccccccccccccccccc = 3,\n"
+% " dddddddddddddddddddd = 4,\n"
+% " eeeeeeeeeeeeeeeeeeee = 5},\n"
+% " dddddddddddddddddddd = dd,\n"
+% " eeeeeeeeeeeeeeeeeeee = ee},\n"
+% " dddddddddddddddddddd = k,\n"
+% " eeeeeeeeeeeeeeeeeeee = l},\n"
+% " eeeeeeeeeeeeeeeeeeee = 5}">>,
+% p({d,1,{d,a,b,c,d,e},3,{d,h,i,{d,aa,bb,{d,1,2,3,4,5},dd,ee},
+% k,l},5}, -1)),
+
+ A = aaaaaaaaaaaaa,
+ %% Print the record with dots at the end of the line (Ll = 80).
+ ?line "{aaaaaaa" ++ _ =
+ p({A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,
+ {A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,
+ {A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,
+ {A,{A,{ggg,{hhh,{ii,{jj,{kk,{ll,{mm,{nn,{oo,{d,1,2,3,4,5}
+ }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
+ }}}}}}}}}}}}}}}}, 146),
+ ?line "{aaaaaaa" ++ _ =
+ p({A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,
+ {A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,
+ {A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,
+ {A,{A,{A,{A,{A,{ggg,{hhh,{ii,{jj,{kk,{ll,{mm,{nn,{oo,{a}
+ }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
+ }}}}}}}}}}}}}}}}}}}, 152),
+
+ ?line bt(<<"{aaaaaaaaaaaaa,\n"
+ " {aaaaaaaaaaaaa,\n"
+ " {aaaaaaaaaaaaa,\n"
+ " {aaaaaaaaaaaaa,\n"
+ " {aaaaaaaaaaaaa,\n"
+ " {aaaaaaaaaaaaa,\n"
+ " {g,{h,{i,{j,{k,{l,{m,{n,{o,#"
+ "d{...}}}}}}}}}}}}}}}}">>,
+ p({A,{A,{A,{A,{A,{A,
+ {g,{h,{i,{j,{k,{l,{m,{n,{o,{d,1,2,3,4,5}}}}}}}}}}}}}}}}, 32)),
+ ?line bt(<<"{a,#b{f = {c,{d,{e,{f,...}}}}}}">>,
+ p({a,{b,{c,{d,{e,{f,g}}}}}}, 12)),
+ ?line bt(<<"{aaaaaaaaaaaaa,\n"
+ " {aaaaaaaaaaaaa,\n"
+ " {aaaaaaaaaaaaa,\n"
+ " {aaaaaaaaaaaaa,\n"
+ " {aaaaaaaaaaaaa,\n"
+ " {aaaaaaaaaaaaa,\n"
+ " {aaaaaaaaaaaaa,\n"
+ " {aaaaaaaaaaaaa,\n"
+ " {aaaaaaaaaaaaa,#c{f1 = ddd,"
+ "f2 = eee}}}}}}}}}}">>,
+ p({A,{A,{A,{A,{A,{A,{A,{A,{A,{c,ddd,eee}}}}}}}}}}, 100)),
+ ?line bt(<<"{aaaaaaaaaaaaa,\n"
+ " {aaaaaaaaaaaaa,{aaaaaaaaaaaaa,{aaaaaaaaaaaaa,...}}}}">>,
+ p({A,{A,{A,{A,{b}}}}}, 8)),
+ % With no restriction on number of characters per line:
+% ?line bt(<<"{aaaaaaaaaaaaa,{aaaaaaaaaaaaa,{aaaaaaaaaaaaa,"
+% "{aaaaaaaaaaaaa,...}}}}">>,
+% p({A,{A,{A,{A,{b}}}}}, 8)),
+ ?line bt(<<"{aaaaaaaaaaaaa,\n"
+ " {aaaaaaaaaaaaa,\n"
+ " {aaaaaaaaaaaaa,{aaaaaaaaaaaaa,{aaaaaaaaaaaaa,...}}}}}">>,
+ p({A,{A,{A,{A,{A,{b}}}}}}, 10)),
+ % With no restriction on number of characters per line:
+% ?line bt(<<"{aaaaaaaaaaaaa,\n"
+% " {aaaaaaaaaaaaa,{aaaaaaaaaaaaa,{aaaaaaaaaaaaa,"
+% "{aaaaaaaaaaaaa,...}}}}}">>,
+% p({A,{A,{A,{A,{A,{b}}}}}}, 10)),
+ ?line bt(<<"{aaaaaaaaaaaaa,\n"
+ " {aaaaaaaaaaaaa,\n"
+ " {aaaaaaaaaaaaa,\n"
+ " {aaaaaaaaaaaaa,\n"
+ " {aaaaaaaaaaaaa,\n"
+ " {aaaaaaaaaaaaa,\n"
+ " {aaaaaaaaaaaaa,\n"
+ " {aaaaaaaaaaaaa,\n"
+ " {aaaaaaaaaaaaa,"
+ "{aaaaaaaaaaaaa,#a{}}}}}}}}}}}">>,
+ p({A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{a}}}}}}}}}}}, 23)),
+ ?line bt(<<"{aaaaaaaaaaaaa,\n"
+ " {aaaaaaaaaaaaa,\n"
+ " {aaaaaaaaaaaaa,\n",
+ " #rrrrr{\n"
+ " f1 = kljlkjlksfdgkljlsdkjf,"
+ "f2 = kljkljsdaflkjlkjsdf,...}}}}">>,
+ p({A,{A,{A,{rrrrr, kljlkjlksfdgkljlsdkjf,
+ kljkljsdaflkjlkjsdf,
+ asdfkldsjfklkljsdklfds}}}}, 10)),
+ % With no restriction on number of characters per line:
+% ?line bt(<<"{aaaaaaaaaaaaa,\n"
+% " {aaaaaaaaaaaaa,\n"
+% " {aaaaaaaaaaaaa,\n",
+% " #rrrrr{f1 = kljlkjlksfdgkljlsdkjf,f2 = "
+% "kljkljsdaflkjlkjsdf,...}}}}">>,
+% p({A,{A,{A,{rrrrr, kljlkjlksfdgkljlsdkjf,
+% kljkljsdaflkjlkjsdf,
+% asdfkldsjfklkljsdklfds}}}}, 10)),
+ ?line bt(<<"{aaaaaaaaaaaaa,\n"
+ " {aaaaaaaaaaaaa,\n"
+ " {aaaaaaaaaaaaa,\n"
+ " {aaaaaaaaaaaaa,\n"
+ " {aaaaaaaaaaaaa,\n"
+ " {aaaaaaaaaaaaa,\n"
+ " {aaaaaaaaaaaaa,\n"
+ " {g,{h,{i,{j,{k,{l,{m,{n,"
+ "{o,#a{}}}}}}}}}}}}}}}}}">>,
+ p({A,{A,{A,{A,{A,{A,{A,
+ {g,{h,{i,{j,{k,{l,{m,{n,{o,{a}}}}}}}}}}}}}}}}}, 100)),
+ ?line bt(<<"#c{\n"
+ " f1 = \n"
+ " #c{\n"
+ " f1 = \n"
+ " #c{\n"
+ " f1 = \n"
+ " #c{\n"
+ " f1 = \n"
+ " #c{\n"
+ " f1 = \n"
+ " #c{\n"
+ " f1 = \n"
+ " #c{\n"
+ " f1 = \n"
+ " #c{\n"
+ " f1 = \n"
+ " #c{\n"
+ " f1 = #c{f1 = #c{f1 = #c{f1 = a,"
+ "f2 = b},f2 = b},f2 = b},\n"
+ " f2 = b},\n"
+ " f2 = b},\n"
+ " f2 = b},\n"
+ " f2 = b},\n"
+ " f2 = b},\n"
+ " f2 = b},\n"
+ " f2 = b},\n"
+ " f2 = b},\n"
+ " f2 = b}">>,
+ p({c,{c,{c,{c,{c,{c,{c,{c,{c,{c,{c,{c,a,b},b},b},b},b},b},
+ b},b},b},b},b},b}, -1)),
+ ?line bt(<<"#rrrrr{\n"
+ " f1 = \n"
+ " #rrrrr{\n"
+ " f1 = \n"
+ " #rrrrr{\n"
+ " f1 = \n"
+ " #rrrrr{\n"
+ " f1 = \n"
+ " {rrrrr,{rrrrr,a,#rrrrr{f1 = {rrrrr,1,2},f2 = a,"
+ "f3 = b}},b},\n"
+ " f2 = {rrrrr,c,d},\n"
+ " f3 = {rrrrr,1,2}},\n"
+ " f2 = 1,f3 = 2},\n"
+ " f2 = 3,f3 = 4},\n"
+ " f2 = 5,f3 = 6}">>,
+ p({rrrrr,{rrrrr,{rrrrr,{rrrrr,{rrrrr,{rrrrr,a,{rrrrr,
+ {rrrrr,1,2},a,b}},b},{rrrrr,c,d},{rrrrr,1,2}},
+ 1,2},3,4},5,6}, -1)),
+ % With other terms than atomic ones on the same line:
+% ?line bt(<<"#rrrrr{\n"
+% " f1 = \n"
+% " #rrrrr{\n"
+% " f1 = \n"
+% " #rrrrr{\n"
+% " f1 = \n"
+% " #rrrrr{\n"
+% " f1 = \n"
+% " {rrrrr,{rrrrr,a,#rrrrr{f1 = {rrrrr,1,2},f2 = a,"
+% "f3 = b}},b},\n"
+% " f2 = {rrrrr,c,d},f3 = {rrrrr,1,2}},\n"
+% " f2 = 1,f3 = 2},\n"
+% " f2 = 3,f3 = 4},\n"
+% " f2 = 5,f3 = 6}">>,
+% p({rrrrr,{rrrrr,{rrrrr,{rrrrr,{rrrrr,{rrrrr,a,{rrrrr,
+% {rrrrr,1,2},a,b}},b},{rrrrr,c,d},{rrrrr,1,2}},
+% 1,2},3,4},5,6}, -1)),
+ % With no restriction on number of characters per line:
+% ?line bt(<<"#rrrrr{\n"
+% " f1 = \n"
+% " #rrrrr{\n"
+% " f1 = \n"
+% " #rrrrr{\n"
+% " f1 = \n"
+% " #rrrrr{\n"
+% " f1 = {rrrrr,{rrrrr,a,#rrrrr{f1 = {rrrrr,1,2},f2 = a,"
+% "f3 = b}},b},\n"
+% " f2 = {rrrrr,c,d},f3 = {rrrrr,1,2}},\n"
+% " f2 = 1,f3 = 2},\n"
+% " f2 = 3,f3 = 4},\n"
+% " f2 = 5,f3 = 6}">>,
+% p({rrrrr,{rrrrr,{rrrrr,{rrrrr,{rrrrr,{rrrrr,a,{rrrrr,
+% {rrrrr,1,2},a,b}},b},{rrrrr,c,d},{rrrrr,1,2}},
+% 1,2},3,4},5,6}, -1)),
+ % With line breaks:
+% ?line bt(<<"#rrrrr{\n"
+% " f1 = \n"
+% " #rrrrr{\n"
+% " f1 = \n"
+% " #rrrrr{\n"
+% " f1 = \n"
+% " #rrrrr{\n"
+% " f1 = {rrrrr,{rrrrr,a,#rrrrr{f1 = {rrrrr,1,2},f2 = a,"
+% "f3 = b}},b},\n"
+% " f2 = {rrrrr,c,d},\n"
+% " f3 = {rrrrr,1,2}},\n"
+% " f2 = 1,\n"
+% " f3 = 2},\n"
+% " f2 = 3,\n"
+% " f3 = 4},\n"
+% " f2 = 5,\n"
+% " f3 = 6}">>,
+% p({rrrrr,{rrrrr,{rrrrr,{rrrrr,{rrrrr,{rrrrr,a,{rrrrr,
+% {rrrrr,1,2},a,b}},b},{rrrrr,c,d},{rrrrr,1,2}},
+% 1,2},3,4},5,6}, -1)),
+ ?line "{aaa,\n {aaa," ++ _ =
+ p({aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,
+ {aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,
+ {aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,
+ {aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,
+ {aaa,a}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},
+ 1, 80, -1),
+
+ %% A few other cases...
+ ?line "{a,#Fun<" ++ _ = lists:flatten(io_lib_pretty:print({a,fun fmt/2})),
+ ?line "#Fun<" ++ _ = io_lib_pretty:print(fun() -> foo end),
+ % ?line "[<<\"foobar\">>|<<\"barf\"...>>]" =
+ % p([<<"foobar">>|<<"barfoo">>], 1, 30, 4),
+ %% No support for negative columns any more:
+ ?line "[a,\n [b,\n c,\n d,\n [e,\n f]],\n c]" =
+ p([a,[b,c,d,[e,f]],c], -1, 2, 10),
+ ?line "[a,\n [b,\n c,\n d,\n [e,\n f]],\n c]" =
+ p([a,[b,c,d,[e,f]],c], 0, 2, 10),
+ %% 20 bytes are tried first, then the rest. Try 21 bytes:
+ L = lists:duplicate(20, $a),
+ % ?line bt(<<"<<\"aaaaaa\"\n \"aaaaaa\"\n \"aaaaaa\"\n \"aaa\">>">>,
+ ?line bt(<<"<<\"aaaaaaaaaaaaaaaaaaaaa\">>">>,
+ p(list_to_binary([$a | L]), 1, 10, -1)),
+ ?line "<<97," ++ _ = p(list_to_binary(L ++ [3]), 1, 10, -1),
+ % ?line "<<\"aaaa\"...>>" = p(list_to_binary(L ++ [3]), 1, 10, 2),
+ % ?line "<<\"aaaaaa\"\n \"aa\"...>>" =
+ % ?line "<<\"aaaaaaaa\"...>>" =
+ % p(list_to_binary(L ++ [3]), 1, 10, 3),
+ % ?line "<<\"aaaaaa\"\n \"aaaaaa\"\n \"aaaaaa\"\n \"aa\"...>>" =
+ % ?line "<<\"aaaaaaaaaaaaaaaaaaaa\"...>>" =
+ % p(list_to_binary(L ++ [3]), 1, 10, 21),
+ ?line "<<97," ++ _ = p(list_to_binary(L ++ [3]), 1, 10, 22),
+
+ ?line "\"\\b\\t\\n\\v\\f\\r\\e\250\"" =
+ p([8,9,10,11,12,13,27,168], 1, 40, -1),
+ % ?line "\"\\b\\t\\n\"\n \"\\v\\f\\r\"\n \"\\e\250\"" =
+ ?line "\"\\b\\t\\n\\v\\f\\r\\e�\"" =
+ p([8,9,10,11,12,13,27,168], 1, 10, -1),
+ ?line "\"\\b\\t\\n\\v\\f\\r\\e\250\"" =
+ p([8,9,10,11,12,13,27,168], 1, 40, 100),
+ % ?line "\"\\e\\t\\nab\"\n \"cd\"" =
+ ?line "\"\\e\\t\\nabcd\"" =
+ p("\e\t\nabcd", 1, 12, -1),
+
+ %% DEL (127) is special...
+ ?line "[127]" = p("\d", 1, 10, -1),
+ ?line "[127]" = p([127], 1, 10, 100),
+
+ ?line "<<\"\\b\\t\\n\\v\\f\\r\\e\250\">>" =
+ p(<<8,9,10,11,12,13,27,168>>, 1, 40, -1),
+ ?line "<<\"\\b\\t\\n\\v\\f\\r\\e\250\">>" =
+ p(<<8,9,10,11,12,13,27,168>>, 1, 10, -1),
+ ?line "<<127>>" = p(<<127>>, 1, 10, 100),
+
+ %% "Partial" string binaries:
+ ?line "<<\"he\"...>>" = p(list_to_binary("he"++[3]), 1, 80, 2),
+ ?line "<<\"he\"...>>" = p(list_to_binary("he"++[3]), 1, 80, 3),
+ ?line "<<104,101,3>>" = p(list_to_binary("he"++[3]), 1, 80, 4),
+ ?line "<<...>>" = p(list_to_binary([3] ++ "he"), 1, 80, 1),
+ ?line "<<3,...>>" = p(list_to_binary([3] ++ "he"), 1, 80, 2),
+ ?line "<<3,104,...>>" = p(list_to_binary([3] ++ "he"), 1, 80, 3),
+
+ ?line "<<\"12345678901234567890\"...>>" =
+ p(list_to_binary("12345678901234567890"++[3]), 1, 80, 8),
+ ?line "<<\"12345678901234567890\"...>>" =
+ p(list_to_binary("12345678901234567890"++[3]), 1, 80, 21),
+ ?line "<<49," ++ _ =
+ p(list_to_binary("12345678901234567890"++[3]), 1, 80, 22),
+
+ ?line "{sdfsdfj,\n 23" ++ _ =
+ p({sdfsdfj,23423423342.23432423}, 1, 17, -1),
+
+ ?line bt(<<"kljkljlksdjjlf kljalkjlsdajafasjdfj [kjljklasdf,kjlljsfd,sdfsdkjfsd,kjjsdf,jl,
+ lkjjlajsfd|jsdf]">>,
+ fmt("~w ~w ~p",
+ [kljkljlksdjjlf,
+ kljalkjlsdajafasjdfj,
+ [kjljklasdf,kjlljsfd,sdfsdkjfsd,kjjsdf,jl,lkjjlajsfd |
+ jsdf]])),
+
+ %% Binaries are split as well:
+ ?line bt(<<"<<80,100,0,55,55,55,55,55,55,55,55,55,\n "
+ "55,55,55,55,55,55,55,...>>">>,
+ p(<<80,100,0,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,
+ 55,55,55,55,55,55,55,55,55,55,55,55>>,1,40,20)),
+ ?line bt(<<"<<80,100,0,55,55,55,55,55,55,55,55,55,\n "
+ "55,55,55,55,55,55,55,55,55,55,55,55,\n 55,55,55,55,55,55>>">>,
+ p(<<80,100,0,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,
+ 55,55,55,55,55,55,55,55,55,55,55,55>>,1,40,-1)),
+ ?line "<<0,0,0,\n ...>>" = p(<<0,0,0,0,0>>, 1, 10, 4),
+
+ %% ~W now uses ",..." when printing tuples
+ ?line "[a,b|...]" = fmt("~W", [[a,b,c,d,e], 3]),
+ ?line "{a,b,...}" = fmt("~W", [{a,b,c,d,e}, 3]),
+ ok.
+
+otp_6495(doc) ->
+ ["OTP-6495. io_lib_pretty bugfix."];
+otp_6495(suite) ->
+ [];
+otp_6495(Config) when is_list(Config) ->
+ ?line bt(<<"[120,120,120,120,120,120,120,120,120,120,120,120,120,120,"
+ "120,120,120,120,120]<<1>>">>,
+ fmt("~w~p", ["xxxxxxxxxxxxxxxxxxx", <<1>>])),
+ ok.
+
+otp_6517(doc) ->
+ ["OTP-6517. The Format argument of fwrite can be a binary."];
+otp_6517(suite) ->
+ [];
+otp_6517(Config) when is_list(Config) ->
+ ?line "string" = fmt(<<"~s">>, [<<"string">>]),
+ ok.
+
+otp_6502(doc) ->
+ ["OTP-6502. Bits."];
+otp_6502(suite) ->
+ [];
+otp_6502(Config) when is_list(Config) ->
+ ?line bt(<<
+ "[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]"
+ "<<0,0,8,\n"
+ " "
+ " 1:1>>">>,
+ fmt("~w~p", [lists:seq(0, 25), <<17:25>>])),
+ ok.
+
+otp_7421(doc) ->
+ ["OTP-7421. Soft limit of 60 chars removed when pretty printing."];
+otp_7421(suite) ->
+ [];
+otp_7421(Config) when is_list(Config) ->
+ bt(<<"{aa,bb,\n"
+ " c,dd,\n"
+ " eee,\n"
+ " fff}">>,
+ rp({aa,bb,c,dd,eee,fff}, 1, 80, -1, 5, none)),
+ bt(<<"{aa,bb,\n"
+ " c,\n"
+ " dd,\n"
+ " eee,\n"
+ " fff}">>,
+ rp({aa,bb,c,dd,eee,fff}, 1, 80, -1, 4, none)),
+ ok.
+
+bt(Bin, R) ->
+ R = binary_to_list(Bin).
+
+p(Term, D) ->
+ rp(Term, 1, 80, D).
+
+p(Term, Col, Ll, D) ->
+ rp(Term, Col, Ll, D, no_fun).
+
+rp(Term, Col, Ll, D) ->
+ rp(Term, Col, Ll, D, fun rfd/2).
+
+-define(MAXCS, 60).
+
+rp(Term, Col, Ll, D, RF) ->
+ rp(Term, Col, Ll, D, ?MAXCS, RF).
+
+rp(Term, Col, Ll, D, M, RF) ->
+ %% io:format("~n~n*** Col = ~p Ll = ~p D = ~p~n~p~n-->~n",
+ %% [Col, Ll, D, Term]),
+ R = io_lib_pretty:print(Term, Col, Ll, D, M, RF),
+ %% io:format("~s~n<--~n", [R]),
+ lists:flatten(io_lib:format("~s", [R])).
+
+fmt(Fmt, Args) ->
+ lists:flatten(io_lib:format(Fmt, Args)).
+
+rfd(a, 0) ->
+ [];
+rfd(b, 1) ->
+ [f];
+rfd(c, 2) ->
+ [f1, f2];
+rfd(e, 3) ->
+ [f, g, h];
+rfd(d, 5) ->
+ [aaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbb,
+ cccccccccccccccccccc, dddddddddddddddddddd,
+ eeeeeeeeeeeeeeeeeeee];
+rfd(rrrrr, 3) ->
+ [f1, f2, f3];
+rfd(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, 0) ->
+ [];
+rfd(_, _) ->
+ no.
+
+manpage(doc) ->
+ ["The examples in io(3) and io_lib(3)."];
+manpage(suite) ->
+ [];
+manpage(Config) when is_list(Config) ->
+ %% The examples that write or print only, not the ones that read...
+
+ ?line bt(<<"Hello world!\n">>,
+ fmt("Hello world!~n", [])),
+ ?line bt(<<"| aaaaa|bbbbb |ccccc|\n">>, % bugfix
+ fmt("|~10.5c|~-10.5c|~5c|~n", [$a, $b, $c])),
+ ?line bt(<<"|**********|\n">>,
+ fmt("|~10w|~n", [{hey, hey, hey}])),
+ ?line bt(<<"|{hey,hey,h|\n">>,
+ fmt("|~10s|~n", [io_lib:write({hey, hey, hey})])),
+
+ T = [{attributes,[[{id,age,1.50000},{mode,explicit},
+ {typename,"INTEGER"}], [{id,cho},{mode,explicit},{typename,'Cho'}]]},
+ {typename,'Person'},{tag,{'PRIVATE',3}},{mode,implicit}],
+ ?line bt(<<"[{attributes,[[{id,age,1.5},{mode,explicit},{typename,"
+ "[73,78,84,69,71,69,82]}],[{id,cho},{mode,explicit},"
+ "{typename,'Cho'}]]},{typename,'Person'},{tag,{'PRIVATE',3}},"
+ "{mode,implicit}]\n">>,
+ fmt("~w~n", [T])),
+ ?line bt(<<"[{attributes,[[{id,age,1.5},\n"
+ " {mode,explicit},\n"
+ " {typename,\"INTEGER\"}],\n"
+ " [{id,cho},{mode,explicit},{typename,'Cho'}]]},\n"
+ " {typename,'Person'},\n"
+ " {tag,{'PRIVATE',3}},\n"
+ " {mode,implicit}]\n">>,
+ fmt("~62p~n", [T])),
+ ?line bt(<<"Here T = [{attributes,[[{id,age,1.5},\n"
+ " {mode,explicit},\n"
+ " {typename,\"INTEGER\"}],\n"
+ " [{id,cho},\n"
+ " {mode,explicit},\n"
+ " {typename,'Cho'}]]},\n"
+ " {typename,'Person'},\n"
+ " {tag,{'PRIVATE',3}},\n"
+ " {mode,implicit}]\n">>,
+ fmt("Here T = ~62p~n", [T])),
+ ?line bt(<<"[{attributes,[[{id,age,1.5},{mode,explicit},"
+ "{typename,...}],[{id,cho},{mode,...},{...}]]},"
+ "{typename,'Person'},{tag,{'PRIVATE',3}},{mode,implicit}]\n">>,
+ fmt("~W~n", [T,9])),
+ ?line bt(<<"[{attributes,[[{id,age,1.5},{mode,explicit},{typename,...}],"
+ "\n "
+ "[{id,cho},{mode,...},{...}]]},\n {typename,'Person'},\n "
+ "{tag,{'PRIVATE',3}},\n {mode,implicit}]\n">>,
+ fmt("~62P~n", [T,9])),
+
+ ?line "1F\n" = fmt("~.16B~n", [31]),
+ ?line "-10011\n" = fmt("~.2B~n", [-19]),
+ ?line "5Z\n" = fmt("~.36B~n", [5*36+35]),
+ ?line "10#31\n" = fmt("~X~n", [31,"10#"]),
+ ?line "-0x1F\n" = fmt("~.16X~n", [-31,"0x"]),
+ ?line "10#31\n" = fmt("~.10#~n", [31]),
+ ?line "-16#1F\n" = fmt("~.16#~n", [-31]),
+ ?line "abc def 'abc def' {foo,1} A \n" =
+ fmt("~s ~w ~i ~w ~c ~n",
+ ['abc def', 'abc def', {foo, 1},{foo, 1}, 65]),
+ % fmt("~s", [65]),
+
+ %% io_lib(3)
+ ?line bt(<<"{1,[2],[3],[...],...}">>,
+ lists:flatten(io_lib:write({1,[2],[3],[4,5],6,7,8,9}, 5))),
+ ok.
+
+otp_6708(doc) ->
+ ["OTP-6708. Fewer newlines when pretty-printing."];
+otp_6708(suite) ->
+ [];
+otp_6708(Config) when is_list(Config) ->
+ ?line bt(<<"[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,\n"
+ " 23,24,25,26,27,28,29|...]">>,
+ p(lists:seq(1,1000), 30)),
+ ?line bt(<<"{lkjasklfjsdak,mlkasjdflksj,klasdjfklasd,jklasdfjkl,\n"
+ " jklsdjfklsd,masdfjkkl}">>,
+ p({lkjasklfjsdak,mlkasjdflksj,klasdjfklasd,jklasdfjkl,
+ jklsdjfklsd, masdfjkkl}, -1)),
+ ?line bt(<<"#b{f = {lkjljalksdf,jklaskfjd,kljasdlf,kljasdf,kljsdlkf,\n"
+ " kjdd}}">>,
+ p({b, {lkjljalksdf,jklaskfjd,kljasdlf,kljasdf,kljsdlkf,kjdd}},
+ -1)),
+ ?line bt(<<"#b{f = {lkjljalksdf,jklaskfjd,kljasdlf,kljasdf,kljsdlkf,\n"
+ " kdd}}">>,
+ p({b, {lkjljalksdf,jklaskfjd,kljasdlf,kljasdf,kljsdlkf,kdd}},
+ -1)),
+ ?line bt(<<"#e{f = undefined,g = undefined,\n"
+ " h = #e{f = 11,g = 22,h = 333}}">>,
+ p({e,undefined,undefined,{e,11,22,333}}, -1)),
+ ?line bt(<<"[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21|\n"
+ " apa11]">>,
+ p(lists:seq(1,21) ++ apa11, -1)),
+ ?line bt(<<"[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,\n"
+ " 23,\n"
+ " {{abadalkjlasdjflksdajfksdklfsdjlkfdlskjflsdj"
+ "flsdjfldsdsdddd}}]">>,
+ p(lists:seq(1,23) ++
+ [{{abadalkjlasdjflksdajfksdklfsdjlkfdlskjflsdjflsdjfldsdsdddd}}],
+ -1)),
+ ?line bt(<<"{lkjasdf,\n"
+ " {kjkjsd,\n"
+ " {kjsd,\n"
+ " {kljsdf,\n"
+ " {kjlsd,{dkjsdf,{kjlds,{kljsd,{kljs,"
+ "{kljlkjsd}}}}}}}}}}">>,
+ p({lkjasdf,{kjkjsd,{kjsd,
+ {kljsdf,
+ {kjlsd,
+ {dkjsdf,{kjlds,
+ {kljsd,{kljs,{kljlkjsd}}}}}}}}}},
+ -1)),
+ ?line bt(<<"{lkjasdf,\n"
+ " {kjkjsd,\n"
+ " {kjsd,{kljsdf,{kjlsd,{dkjsdf,{kjlds,"
+ "{kljsd,{kljs}}}}}}}}}">>,
+ p({lkjasdf,{kjkjsd,{kjsd,
+ {kljsdf,{kjlsd,{dkjsdf,
+ {kjlds,{kljsd,{kljs}}}}}}}}},
+ -1)),
+ ?line bt(<<"<<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,\n"
+ " 22,23>>">>,
+ p(list_to_binary(lists:seq(1,23)), -1)),
+ ?line bt(<<"<<100,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,\n"
+ " 27>>">>,
+ p(list_to_binary([100|lists:seq(10,27)]), -1)),
+ ?line bt(<<"<<100,101,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,\n"
+ " 26>>">>,
+ p(list_to_binary([100,101|lists:seq(10,26)]), -1)),
+ ?line bt(<<"{{<<100,101,102,10,11,12,13,14,15,16,17,18,19,20,21,22,\n"
+ " 23>>}}">>,
+ p({{list_to_binary([100,101,102|lists:seq(10,23)])}}, -1)),
+ ?line bt(<<"[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22|\n"
+ " ap]">>,
+ p(lists:seq(1,22) ++ ap, -1)),
+ ?line bt(<<"[1,2,3,4,5,6,7,8,9,10,{},[],\n <<>>,11,12,13,14,15]">>,
+ p(lists:seq(1,10) ++ [{},[],<<>>] ++ lists:seq(11,15),1,30,-1)),
+ ?line bt(<<"[ddd,ddd,\n"
+ " {1},\n"
+ " [1,2],\n"
+ " ddd,kdfd,\n"
+ " [[1,2],a,b,c],\n"
+ " <<\"foo\">>,<<\"bar\">>,1,\n"
+ " {2}]">>,
+ p([ddd,ddd,{1},[1,2],ddd,kdfd,[[1,2],a,b,c],<<"foo">>,<<"bar">>,
+ 1,{2}],1,50,-1)),
+
+ ?line bt(<<"{dskljsadfkjsdlkjflksdjflksdjfklsdjklfjsdklfjlsdjfkl,jksd,\n"
+ " "
+ "lkjsdf,kljsdf,kljsf,kljsdf,kljsdf,jkldf,jklsdf,kljsdf,\n"
+ " "
+ "kljsdf,jklsdf,lkjfd,lkjsdf,kljsdf,kljsdf,lkjsdf,kljsdf,\n"
+ " "
+ "lkjsdfsd,kljsdf,kjsfj}">>,
+ p({dskljsadfkjsdlkjflksdjflksdjfklsdjklfjsdklfjlsdjfkl,jksd,
+ lkjsdf,kljsdf,kljsf,kljsdf,kljsdf,jkldf,jklsdf,kljsdf,
+ kljsdf,jklsdf,lkjfd,lkjsdf,kljsdf,kljsdf,lkjsdf,kljsdf,
+ lkjsdfsd,kljsdf,kjsfj}, 1, 110, -1)),
+ ?line bt(<<"{dskljsadfkjsdlkjflksdjflksdjfklsdjklfjsdklfjlsdjfkl,"
+ "#d{aaaaaaaaaaaaaaaaaaaa = 1,\n"
+ " "
+ "bbbbbbbbbbbbbbbbbbbb = 2,cccccccccccccccccccc = 3,\n"
+ " "
+ "dddddddddddddddddddd = 4,eeeeeeeeeeeeeeeeeeee = 5}}">>,
+ rp({dskljsadfkjsdlkjflksdjflksdjfklsdjklfjsdklfjlsdjfkl,
+ {d,1,2,3,4,5}},1,200,-1)),
+ ok.
+
+-define(ONE(N), ((1 bsl N) - 1)).
+-define(ALL_ONES, ((1 bsl 52) - 1)).
+
+otp_7084(doc) ->
+ ["OTP-7084. Printing floating point numbers nicely."];
+otp_7084(suite) ->
+ [];
+otp_7084(Config) when is_list(Config) ->
+ OldDog=?config(watchdog, Config),
+ test_server:timetrap_cancel(OldDog),
+ Timeout = 180,
+ ?line Dog = test_server:timetrap({seconds,Timeout}),
+ L = [{g_warm_up, fun g_warm_up/0},
+ {g_big_pos_float, fun g_big_pos_float/0},
+ {g_small_neg_float, fun g_small_neg_float/0},
+ {g_close_to_zero, fun g_close_to_zero/0},
+ {g_denormalized, fun g_denormalized/0},
+ {g_normalized, fun g_normalized/0},
+ {g_choice, fun g_choice/0},
+ {g_misc, fun g_misc/0}],
+ F = fun({M,T}) -> io:format("~p~n", [M]), T() end,
+ R = try
+ lists:foreach(fun(T) -> F(T) end, L),
+ ok
+ catch throw:Reason ->
+ Reason
+ end,
+ ?line test_server:timetrap_cancel(Dog),
+ R.
+
+g_warm_up() ->
+ g_t(0.5),
+ g_t(-0.5),
+ g_t((1 bsl 55) * 0.5),
+ g_t(-(1 bsl 55) * 0.5),
+ g_t(1.6799127650033296e+308),
+ g_t(pack(1, 0, 2#1010101010001100101000010111100101000000101100110001)),
+ g_t(pack(1, 0, 2#0001010000001001110100000101010101001110010001010110)),
+ g_t(234324324.23432432432432),
+ ok.
+
+g_big_pos_float() ->
+ %% The greatest positive float:
+ ft({{0,2046,?ONE(52)}, 100, 0}),
+ ok.
+
+g_small_neg_float() ->
+ %% The least negative float:
+ ft({{1,2046,?ONE(52)}, 0, 100}),
+ ok.
+
+g_close_to_zero() ->
+ %% A few denormalized floats close to zero:
+ ft({{0,0,0}, 100, 100}),
+ g_t(pack(1, 0, 0)), % -0.0
+ ok.
+
+g_denormalized() ->
+ %% Denormalized floats (mantissa carry):
+% D = 5,
+ %% Faster:
+ D = 1,
+ [ft({{S,0,?ONE(N)},D,D}) || S <- [0,1], N <- lists:seq(0, 52)],
+ ok.
+
+g_normalized() ->
+ %% Normalized floats (exponent carry):
+% D = 5,
+ %% Faster:
+ D = 1,
+ [ft({{S,E,?ONE(52)},D,D}) || S <- [0,1], E <- lists:seq(0, 2045)],
+ ok.
+
+g_choice() ->
+ %% Exponent should be used when and only when the string is shorter.
+ %% (g_misc/0 checks this too, and probably more throughly).
+ L = [0.0003, 3.0e-5, 3.3e-5, 3.3e-4,
+ 314.0, 314.1, 310.0, 3.1e6, -100.0,
+ 3.34e4, 3.0e3, 3.34333e9, 3.3433323e10, 33433323700.0,
+ 0.00197963, 1.97963e-4],
+ lists:foreach(fun(V) -> g_t(V) end, L),
+ ok.
+
+g_misc() ->
+ L_0_308 = lists:seq(0, 308),
+ L_0_307 = lists:seq(0, 307),
+% L_1_9 = lists:seq(1, 9),
+% L_0_9 = lists:seq(0, 9),
+ %% Faster:
+ L_1_9 = [1,5,9],
+ L_0_9 = [0,1,5,9],
+
+ %% 1.0,10.0, ... 2.0,20.0, ... 9.0,90.0, ... -1,-10, ... -2.0,-20.0...
+ [g_t(S*T*pow10(N)) || S <- [1.0, -1.0], T <- L_1_9, N <- L_0_307],
+
+ %% 1.0,1.0/10,1.0/100,... 2.0,2.0/10,2.0/100, ... 9.0,9.0/10,9.0/100,
+ %% -1.0,-1.0/10,... -9.0,-9.0/10...
+ [g_t(S*T/pow10(N)) || S <- [1.0, -1.0], T <- L_1_9, N <- L_0_308],
+
+ %% 0.0,1.0,2.0,...,9.0, 0.0,10.0,20.0,...,90.0,...
+ %% 0.0,-1.0,-2.0,...,-9.0, 0.0,-10.0,-20.0,...,-90.0,...
+ [g_t(S*list_to_float([D+$0]++lists:duplicate(N, $0)++".0")) ||
+ S <- [1.0,-1.0], N <- lists:seq(0, 300), D <- L_0_9],
+
+ %% 0.0,0.1,0.2,...0,9, 0.0,0.01,0.02,...,0.09,
+ %% 0.0,-0.1,-0.2,...-0,9, 0.0,-0.01,-0.02,...,-0.09,
+ [g_t(S*list_to_float("0."++lists:duplicate(N, $0)++[D+$0])) ||
+ S <- [1.0,-1.0], N <- lists:seq(0, 300), D <- L_0_9],
+ ok.
+
+ft({{S,E,M}, L, G}) ->
+ ft({pack(S, E, M), L, G});
+ft({V, Less, Greater}) when is_float(V) ->
+ _ = g_t(V),
+ ft(V, fun inc/1, Greater),
+ ft(V, fun dec/1, Less).
+
+ft(V0, F, I) when I > 0, is_float(V0) ->
+ V = F(V0),
+ _ = g_t(V),
+ ft(V, F, I - 1);
+ft(V, _F, 0) when is_float(V) ->
+ ok.
+
+g_t(V) when is_float(V) ->
+ %% io:format("Testing ~.17g~n", [V]),
+ Io = io_lib:format("~p", [V]),
+ Sv = binary_to_list(iolist_to_binary(Io)),
+ ok = g_t(V, Sv),
+ Sv.
+
+%% -> ok | THROW
+
+%% Checks that Sv is the shortest, correctly rounded string that
+%% converts to V when read back with list_to_float/1.
+%% Note: in a few cases the least significant digit has been
+%% incremented by one, namely when the correctly rounded string
+%% converts to another floating point number.
+g_t(0.0, "0.0") ->
+ ok;
+g_t(V, Sv) ->
+ try
+ g_t_1(V, Sv)
+ catch throw:Reason ->
+ throw({Reason, V, Sv})
+ end.
+
+g_t_1(V, Sv) ->
+ %% Check that the least significant digit is correct.
+ %% If Sv is "3.14" then Sv- is "3.13" and Sv+ is "3.15".
+ %% Check that |V - Sv| =< (V - Sv-) and
+ %% that |V - Sv| =< (Sv+ - V)
+ Times = least_significant_digit(Sv),
+ case Times of
+ 0 -> throw(least_significant_digit_is_zero);
+ _ -> ok
+ end,
+ S = if V < 0 -> -1; true -> 1 end,
+ SvMinus = incr_lsd(Sv, -S),
+ SvPlus = incr_lsd(Sv, S),
+ Svr = s2r(Sv),
+ Svminusr = s2r(SvMinus),
+ Svplusr = s2r(SvPlus),
+ Vr = f2r(V),
+
+ Abs_Sv_Vr = rat_abs(rat_minus(Svr, Vr)),
+ Svminus_Vr = rat_minus(Vr, Svminusr),
+ Svplus_Vr = rat_minus(Svplusr, Vr),
+ %% The are 45 (negative) floats where SvMinus (SvPlus) is closer
+ %% to V than Sv, but such that when reading SvMinus (SvPlus) wrong
+ %% float would be returned.
+ case rat_lte(Abs_Sv_Vr, Svminus_Vr) of
+ true ->
+ ok;
+ false ->
+ case list_to_float(SvMinus) of
+ V -> throw(vsminus_too_close_to_v);
+ _Vminus -> ok
+ end
+ end,
+ case rat_lte(Abs_Sv_Vr, Svplus_Vr) of
+ true ->
+ ok;
+ false ->
+ case list_to_float(SvPlus) of
+ V -> throw(vsplus_too_close_to_v);
+ _Vplus -> ok
+ end
+ end,
+
+ %% Check that Sv is closer to V than to V- and V+.
+ %% Check that |V - Sv| =< (V - V-) and
+ %% that |V - Sv| =< (V+ - V)
+ %% (An alternative is V- + V =< 2*Sv =< V + V+.)
+ case inc(V) of
+ inf ->
+ ok;
+ Vplus ->
+ Vplusr = f2r(Vplus),
+ V_Vplusr = rat_minus(Vplusr, Vr),
+ case rat_lte(Abs_Sv_Vr, V_Vplusr) of
+ true -> ok;
+ false -> throw(vplus_too_close_to_sv)
+ end
+ end,
+ case dec(V) of
+ '-inf' ->
+ ok;
+ Vminus ->
+ Vminusr = f2r(Vminus),
+ V_Vminusr = rat_minus(Vr, Vminusr),
+ case rat_lte(Abs_Sv_Vr, V_Vminusr) of
+ true -> ok;
+ false -> throw(vminus_too_close_to_sv)
+ end
+ end,
+
+ %% Check that no prefix of Sv yields V.
+ %% If Sv is "3.14" then Svlow is "3.1" and Svhigh is "3.2".
+ %%
+ %% This is just one way of getting Svlow and Svhigh:
+ if
+ V < 0 ->
+ SvHigh = step_lsd(Sv, -Times),
+ SvLow = step_lsd(Sv, 10 - Times);
+ true ->
+ SvHigh = step_lsd(Sv, 10 - Times),
+ SvLow = step_lsd(Sv, -Times)
+ end,
+
+ case catch list_to_float(SvLow) of
+ V -> throw(low_is_v);
+ _ -> ok
+ end,
+
+ case catch list_to_float(SvHigh) of
+ V -> throw(high_is_v);
+ _ -> ok
+ end,
+
+ %% Check that Sv has enough digits.
+ case list_to_float(Sv) of
+ V -> ok;
+ _ -> throw(wrong_float) % cannot happen
+ end,
+
+ g_choice(Sv),
+
+ ok.
+
+%%% In "123450000.0", '5' is the lsd;
+%%% in "1234.0000", (the last) '0' is the lsd;
+%%% in "1234.0", '4' is the lsd (the Erlang syntax requires the final zero).
+
+%% Trailing zeroes are not significant ("3.0", "5.0e-324", "232000.0").
+least_significant_digit("-"++Ds) ->
+ least_significant_digit(Ds);
+least_significant_digit("+"++Ds) ->
+ least_significant_digit(Ds);
+least_significant_digit(Ds) ->
+ [MS|_E] = string:tokens(Ds, "eE"),
+ lsd0(lists:reverse(MS))-$0.
+
+lsd0("0."++Ds) ->
+ lsd1(Ds);
+lsd0([D | _Ds]) ->
+ D.
+
+lsd1("0"++Ds) ->
+ lsd1(Ds);
+lsd1([D | _Ds]) ->
+ D.
+
+step_lsd(Ds, 0) ->
+ Ds;
+step_lsd(Ds, N) when N > 0 ->
+ NDs = incr_lsd(Ds, 1),
+ step_lsd(NDs, N - 1);
+step_lsd(Ds, N) when N < 0 ->
+ NDs = incr_lsd(Ds, -1),
+ step_lsd(NDs, N + 1).
+
+%% Assumes Ds represents some other number than zero.
+%% Increments or decrements the least significant digit.
+incr_lsd("-"++Ds, I) ->
+ "-"++incr_lsd(Ds, I);
+incr_lsd(Ds, I) when I =:= 1; I =:= -1 ->
+ [MS|E] = string:tokens(Ds, "eE"),
+ X = ["e" || true <- [E =/= []]],
+ lists:flatten([incr_lsd0(lists:reverse(MS), I, []), X, E]).
+
+incr_lsd0("0."++Ds, C, L) ->
+ incr_lsd1(Ds, C, [$., $0 | L]);
+incr_lsd0(Ds, C, L) ->
+ incr_lsd2(Ds, C, L).
+
+incr_lsd1("0"++Ds, C, L) ->
+ incr_lsd1(Ds, C, [$0 | L]);
+incr_lsd1(Ds, C, L) ->
+ incr_lsd2(Ds, C, L).
+
+incr_lsd2([], C, L) ->
+ [C + $0 | L];
+incr_lsd2("."++Ds, C, L) ->
+ incr_lsd2(Ds, C, [$. | L]);
+incr_lsd2("9"++Ds, 1=C, L) ->
+ incr_lsd2(Ds, C, [$0 | L]);
+incr_lsd2("0"++Ds, -1=C, L) ->
+ incr_lsd2(Ds, C, [$9 | L]);
+incr_lsd2([D | Ds], C, L) ->
+ lists:reverse(Ds, [D + C | L]).
+
+s2r(S) when is_list(S) ->
+ case string:tokens(S, "eE") of
+ [MS] ->
+ s10(MS);
+ [MS, ES] ->
+ Mr = s10(MS),
+ E = list_to_integer(ES),
+ if
+ E < 0 ->
+ rat_multiply(Mr, {1,pow10(-E)});
+ true ->
+ rat_multiply(Mr, {pow10(E), 1})
+ end
+ end.
+
+s10("-"++S) ->
+ rat_multiply({-1,1},s10(S));
+s10(S) ->
+ [AS, BS] = string:tokens(S, "."),
+ Sc = length(BS),
+ A = list_to_integer(AS),
+ B = list_to_integer(BS),
+ F = pow10(Sc),
+ rat_multiply({1,1}, {A*F + B, F}).
+
+pow10(X) ->
+ int_pow(10, X).
+
+int_pow(X, 0) when is_integer(X) ->
+ 1;
+int_pow(X, N) when is_integer(X), is_integer(N), N > 0 ->
+ int_pow(X, N, 1).
+
+int_pow(X, N, R) when N < 2 ->
+ R * X;
+int_pow(X, N, R) ->
+ int_pow(X * X, N bsr 1, case N band 1 of 1 -> R * X; 0 -> R end).
+
+dec(F) when is_float(F) ->
+ <<S:1, BE:11, M:52>> = <<F:64/float>>,
+ dec({S,BE,M});
+dec({1,2046,?ALL_ONES}) ->
+ '-inf';
+dec({S,BE,M}) when 0 =< S, S =< 1,
+ 0 =< BE, BE =< 2046,
+ 0 =< M, M =< ?ALL_ONES ->
+ {S1,BE1,M1} = dec1(S, BE, M),
+ <<F:64/float>> = <<S:1, BE:11, M:52>>,
+ <<F1:64/float>> = <<S1:1, BE1:11, M1:52>>,
+ true = F1 < F,
+ F1.
+
+
+dec1(0, 0, 0) ->
+ dec1(1, 0, 0);
+dec1(0, BE, 0) ->
+ {0,BE-1,?ALL_ONES};
+dec1(0, BE, M) ->
+ {0,BE,M-1};
+dec1(1, BE, ?ALL_ONES) ->
+ {1,BE+1,0};
+dec1(1, BE, M) ->
+ {1,BE,M+1}.
+
+inc(F) when is_float(F) ->
+ <<S:1, BE:11, M:52>> = <<F:64/float>>,
+ inc({S,BE,M});
+inc({0,2046,?ALL_ONES}) ->
+ inf;
+inc({S,BE,M}) when 0 =< S, S =< 1,
+ 0 =< BE, BE =< 2046,
+ 0 =< M, M =< ?ALL_ONES ->
+ {S1,BE1,M1} = inc1(S, BE, M),
+ <<F:64/float>> = <<S:1, BE:11, M:52>>,
+ <<F1:64/float>> = <<S1:1, BE1:11, M1:52>>,
+ true = F1 > F,
+ F1.
+
+inc1(0, BE, ?ALL_ONES) ->
+ {0,BE+1,0};
+inc1(0, BE, M) ->
+ {0,BE,M+1};
+inc1(1, 0, 0) ->
+ inc1(0, 0, 0);
+inc1(1, BE, 0) ->
+ {1,BE-1,?ALL_ONES};
+inc1(1, BE, M) ->
+ {1,BE,M-1}.
+
+f2r(F) when is_float(F) ->
+ <<S:1, BE:11, M:52>> = <<F:64/float>>,
+ f2r({S,BE,M});
+f2r({S,BE,M}) when 0 =< S, S =< 1,
+ 0 =< BE, BE =< 2046,
+ 0 =< M, M =< ?ALL_ONES ->
+ Vr = {T,N} = f2r1(S, BE, M),
+ <<F:64/float>> = <<S:1, BE:11, M:52>>,
+ case catch T/N of
+ {'EXIT', _} -> ok;
+ TN -> true = F =:= TN
+ end,
+ Vr.
+
+f2r1(S, 0, M) ->
+ rat_multiply({sign(S),1}, {M, 1 bsl 1074});
+f2r1(S, BE, M) when BE - 1075 >= 0 ->
+ rat_multiply({sign(S),1}, {((1 bsl 52)+M) * (1 bsl (BE-1075)),1});
+f2r1(S, BE, M) ->
+ rat_multiply({sign(S),1}, {(1 bsl 52)+M, 1 bsl (1075-BE)}).
+
+sign(0) ->
+ 1;
+sign(1) ->
+ -1.
+
+%%% Rational numbers (very scetchy).
+
+rat_abs({A,B}) when A < 0 ->
+ {-A,B};
+rat_abs({A,B}) ->
+ {A,B}.
+
+-ifdef(not_used).
+rat_equal(R1, R2) ->
+ R1 =:= R2.
+
+rat_negate({A,B}) ->
+ {-A,B}.
+
+rat_divide({A,B},{C,D}) ->
+ rat_multiply({A,B},{D,C}).
+-endif.
+
+rat_lte({A,B}, {C,D}) when B =/= 0, D =/= 0 ->
+ A*D =< C*B.
+
+rat_minus({A,B}, {C,D}) ->
+ rat_plus({A,B}, {-C,D}).
+
+rat_plus({A,B}, {C,D}) when B =/= 0, D =/= 0 ->
+ rat_normalize({A*D+B*C, B*D}).
+
+rat_multiply({A,B}, {C,D}) when B =/= 0, D =/= 0 ->
+ rat_normalize({A * C, B * D}).
+
+rat_normalize({T,N}) when N =/= 0 ->
+ G = gcd(T, N),
+ T2 = T div G,
+ N2 = N div G,
+ if
+ T2 < 0 ->
+ if
+ N2 < 0 -> {-T2,-N2};
+ true -> {T2,N2}
+ end;
+ true ->
+ if
+ N2 < 0 -> {-T2,-N2};
+ true -> {T2,N2}
+ end
+ end.
+
+gcd(A, 0) -> A;
+gcd(A, B) -> gcd(B, A rem B).
+
+%%% End of rational numbers.
+
+%% Check that there is an exponent if and only if characters are
+%% saved. Note: this assumes floating point numbers "Erlang style"
+%% (with a single zero before and after the dot, and no extra leading
+%% zero in the exponent).
+g_choice(S) when is_list(S) ->
+ [MS | ES0] = string:tokens(S, "eE"),
+ [IS, FS] = string:tokens(MS, "."),
+ Il = length(IS),
+ Fl = length(FS),
+ Pre = z(MS),
+ Post = z(lists:reverse(MS)),
+ ES = lists:append(ES0),
+ El = length(ES),
+ I = list_to_integer(IS),
+ if
+ El =/= 0, ((I > 9) or (I < -9)) ->
+ throw(too_many_digits_before_the_dot);
+ El =/= 0, I =:= 0 ->
+ throw(zero_before_the_dot);
+ Pre =:= 0, Post > 0, El =:= 0 -> % DDDD0000.0
+ Saving = if
+ I < 0, Il =:= Post + 2 ->
+ Post;
+ I > 0, Il =:= Post + 1 ->
+ Post;
+ I =/= 0, true ->
+ Post + 1
+ end,
+ Cost = 1 + length(integer_to_list(Il - 1)),
+ if
+ Cost < Saving ->
+ throw(with_exponent_is_shorter);
+ true ->
+ ok
+ end;
+ Pre > 0, Post =:= 0, El =:= 0 -> % 0.000DDDD
+ Saving = if
+ Fl =:= Pre + 1 ->
+ Pre;
+ true ->
+ Pre + 1
+ end,
+ Cost = 2 + length(integer_to_list(Pre + 1)),
+ if
+ Cost < Saving ->
+ throw(with_exponent_is_shorter);
+ true ->
+ ok
+ end;
+ Pre =:= 0, Post =:= 0, El > 0 -> % D.DDDeDD
+ E = list_to_integer(ES),
+ if
+ E >= 0 ->
+ Cost = E - (Fl - 1);
+ E < 0 ->
+ Cost = -E
+ end,
+ Saving = length(ES) + 1,
+ if
+ Cost =:= Saving ->
+ throw(draw_but_choose_form_without_exponent);
+ Cost < Saving ->
+ throw(without_exponent_is_shorter);
+ true ->
+ ok
+ end;
+ Pre =:= 0, Post =:= 0, El =:= 0 -> % DDD.DDD
+ ok;
+ true ->
+ throw(badly_formed_floating_point_string)
+ end.
+
+z("0."++Ds) ->
+ length(lists:takewhile(fun(D) -> D =:= $0 end, Ds));
+z(_Ds) ->
+ 0.
+
+pack(Sign, Exp, Frac) ->
+ <<Float:64/float>> = <<Sign:1, Exp:11, Frac:52>>,
+ Float.
+
+%% Whitebox test of io_lib:collect_line/3.
+io_lib_collect_line_3_wb(Config) when is_list(Config) ->
+ ?line do_collect_line(binary, "\n"),
+ ?line do_collect_line(binary, "\r\n"),
+ ?line do_collect_line(list, "\n"),
+ ?line do_collect_line(list, "\r\n"),
+ ok.
+
+do_collect_line(Mode, Eol) ->
+ First = "abcde",
+ FirstNL = First++"\n",
+ Second = "unterminated line",
+ Data0 = First ++ Eol ++ Second,
+ {Data1,Result0} = do_collect_line_combine(Mode, Data0, FirstNL, Second),
+ do_collect_line_1(Mode, Data1, Result0, []),
+
+ {Data,Result} = do_collect_line_combine(Mode, "unterm", "unterm", eof),
+ do_collect_line_1(Mode, Data, Result, []).
+
+do_collect_line_combine(binary, Data0, FirstNL, eof) ->
+ {list_to_binary(Data0),
+ {stop,list_to_binary(FirstNL),eof}};
+do_collect_line_combine(binary, Data0, FirstNL, Second) ->
+ {list_to_binary(Data0),
+ {stop,list_to_binary(FirstNL),list_to_binary(Second)}};
+do_collect_line_combine(list, Data0, FirstNL, Second) ->
+ {Data0,{stop,FirstNL,Second}}.
+
+do_collect_line_1(Mode, [H|T], Result, Acc0) ->
+ Acc = [H|Acc0],
+ Result = do_collect_line_2(lists:reverse(Acc), T),
+ do_collect_line_1(Mode, T, Result, Acc);
+do_collect_line_1(Mode, <<H,T/binary>>, Result, Acc0) ->
+ Acc = [H|Acc0],
+ Result = do_collect_line_2(list_to_binary(lists:reverse(Acc)), T),
+ do_collect_line_1(Mode, T, Result, Acc);
+do_collect_line_1(_Mode, [], _Result, _Acc) ->
+ ok;
+do_collect_line_1(_Mode, <<>>, _Result, _Acc) ->
+ ok.
+
+do_collect_line_2(Part1, Part2) ->
+ Dummy = make_ref(),
+ do_collect_line_3(start, [Part1,Part2,eof], Dummy).
+
+do_collect_line_3(State0, [H|T], Dummy) ->
+ case io_lib:collect_line(State0, H, Dummy) of
+ {stop,Line,Rest} ->
+ {stop,Line,do_collect_line_adjust_rest(Rest, T)};
+ State ->
+ do_collect_line_3(State, T, Dummy)
+ end.
+
+do_collect_line_adjust_rest(eof, []) -> eof;
+do_collect_line_adjust_rest(eof, <<>>) -> eof;
+do_collect_line_adjust_rest(Rest, [eof]) -> Rest;
+do_collect_line_adjust_rest(Rest, [Bin|T]) when is_binary(Bin) ->
+ do_collect_line_adjust_rest(<<Rest/binary,Bin/binary>>, T);
+do_collect_line_adjust_rest(Rest, [List|T]) when is_list(List) ->
+ do_collect_line_adjust_rest(Rest++List, T).
+
+
+
+cr_whitespace_in_string(Config) when is_list(Config) ->
+ ?line {ok,["abc"],[]} = io_lib:fread("~s", "\rabc").
+
+
+
+io_fread_newlines(Config) when is_list(Config) ->
+ ?line PrivDir = ?privdir(Config),
+ ?line Fname = filename:join(PrivDir, "io_fread_newlines.txt"),
+ ?line F0 = [[0,1,2,3,4,5,6,7,8,9]],
+ ?line F1 = [[0,1,2,3,4,5,6,7,8],[9]],
+ ?line F2 = [[0,1,2,3,4,5,6,7],[8,9]],
+ ?line F3 = [[0,1,2,3,4,5,6],[7,8,9]],
+ ?line F4 = [[0,1,2,3,4,5],[6,7,8,9]],
+ ?line F5 = [[0,1,2,3,4],[5,6,7,8,9]],
+ ?line F6 = [[0,1,2,3],[4,5,6,7],[8,9]],
+ ?line F7 = [[0,1,2],[3,4,5],[6,7,8],[9]],
+ ?line F8 = [[0,1],[2,3],[4,5],[6,7],[8,9]],
+ ?line F9 = [[0],[1],[2],[3],[4],[5],[6],[7],[8],[9]],
+ ?line Newlines = ["\n", "\r\n", "\r"],
+ try
+ ?line io_fread_newlines_1([F0,F1,F2,F3,F4,F5,F6,F7,F8,F9],
+ Fname, Newlines)
+ after
+ file:delete(Fname)
+ end.
+
+io_fread_newlines_1(Fs, Fname, [Newline|Newlines]) ->
+ ?line ok = io_fread_newlines_2(Fs, Fname, Newline),
+ ?line io_fread_newlines_1(Fs, Fname, Newlines);
+io_fread_newlines_1(_, _, []) -> ok.
+
+io_fread_newlines_2([F|Fs], Fname, Newline) ->
+ ?line N1 = write_newlines_file(Fname, F, Newline),
+ ?line {F2,N2} = read_newlines_file(Fname),
+ ?line io:format("~w ~p ~w~n~n", [N1,F,N2]),
+ ?line F2 = lists:flatten(F),
+ %% Intermediate newlines are not counted
+ ?line N2 = N1 - (length(F) - 1)*length(Newline),
+ ?line io_fread_newlines_2(Fs, Fname, Newline);
+io_fread_newlines_2([], _, _) -> ok.
+
+
+write_newlines_file(Fname, F, Newline) ->
+ Bytes = list_to_binary(digit_lines(F, Newline)),
+ io:format("Data: ~w~n~w~n", [Newline,Bytes]),
+ ok = file:write_file(Fname, Bytes),
+ size(Bytes).
+
+digit_lines([L], _) ->
+ digit_line(L);
+digit_lines([L|Ls], Newline) ->
+ [digit_line(L),Newline|digit_lines(Ls, Newline)].
+
+digit_line([D]) ->
+ integer_to_list(D);
+digit_line([D|Ds]) ->
+ [integer_to_list(D), " ", digit_line(Ds)].
+
+read_newlines_file(Fname) ->
+ {ok,Fd} = file:open(Fname, [read]),
+ try {L, N0} = R0 = read_newlines(Fd, [], 0),
+ case io:fread(Fd, "", "~*s~l") of
+ eof -> R0;
+ {ok,[N]} -> {L,N0+N}
+ end
+ after
+ file:close(Fd)
+ end.
+
+
+read_newlines(Fd, Acc, N0) ->
+ case io:fread(Fd, "", "~d~l") of
+ {ok,[D,N]} ->
+ read_newlines(Fd, [D|Acc], N0+N);
+ eof ->
+ {lists:reverse(Acc),N0}
+ end.
diff --git a/lib/stdlib/test/io_proto_SUITE.erl b/lib/stdlib/test/io_proto_SUITE.erl
new file mode 100644
index 0000000000..46407193d7
--- /dev/null
+++ b/lib/stdlib/test/io_proto_SUITE.erl
@@ -0,0 +1,1824 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(io_proto_SUITE).
+
+-export([all/1]).
+
+-export([init_per_testcase/2, fin_per_testcase/2]).
+
+-export([setopts_getopts/1,unicode_options/1,unicode_options_gen/1, binary_options/1, bc_with_r12/1,
+ bc_with_r12_gl/1, read_modes_gl/1,bc_with_r12_ogl/1, read_modes_ogl/1, broken_unicode/1,eof_on_pipe/1]).
+
+
+-export([io_server_proxy/1,start_io_server_proxy/0, proxy_getall/1, proxy_setnext/2, proxy_quit/1]).
+%% For spawn
+-export([toerl_server/3,hold_the_line/3,answering_machine1/3,
+ answering_machine2/3]).
+
+%-define(without_test_server, true).
+
+-ifdef(without_test_server).
+-define(line, put(line, ?LINE), ).
+-define(config(X,Y), foo).
+-define(t, test_server).
+-define(privdir(_), "./io_SUITE_priv").
+-else.
+-include("test_server.hrl").
+-define(privdir(Conf), ?config(priv_dir, Conf)).
+-endif.
+
+%-define(debug, true).
+
+-ifdef(debug).
+-define(format(S, A), io:format(S, A)).
+-define(dbg(Data),io:format(standard_error, "DBG: ~p\r\n",[Data])).
+-else.
+-define(format(S, A), ok).
+-define(dbg(Data),noop).
+-endif.
+
+
+% Default timetrap timeout (set in init_per_testcase).
+-define(default_timeout, ?t:minutes(20)).
+
+init_per_testcase(_Case, Config) ->
+ ?line Dog = ?t:timetrap(?default_timeout),
+ Term = case os:getenv("TERM") of
+ List when is_list(List) ->
+ List;
+ _ ->
+ "dumb"
+ end,
+ os:putenv("TERM","vt100"),
+ [{watchdog, Dog}, {term, Term} | Config].
+fin_per_testcase(_Case, Config) ->
+ Dog = ?config(watchdog, Config),
+ Term = ?config(term,Config),
+ os:putenv("TERM",Term),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+all(doc) ->
+ ["Test cases for the io_protocol."];
+all(suite) ->
+ [setopts_getopts, unicode_options, unicode_options_gen, binary_options, bc_with_r12,
+ bc_with_r12_gl,bc_with_r12_ogl, read_modes_gl, read_modes_ogl,
+ broken_unicode,eof_on_pipe].
+
+
+-record(state, {
+ q = [],
+ nxt = eof,
+ mode = list
+ }).
+
+setopts_getopts(suite) ->
+ [];
+setopts_getopts(doc) ->
+ ["Check io:setopts and io:getopts functions"];
+setopts_getopts(Config) when is_list(Config) ->
+ ?line FileName = filename:join([?config(priv_dir,Config),
+ "io_proto_SUITE_setopts_getopts.dat"]),
+ ?line {ok,WFile} = file:open(FileName,[write]),
+ ?line Server = start_io_server_proxy(),
+ ?line [{binary, false}] = io:getopts(Server),
+ ?line [getopts] = proxy_getall(Server),
+ ?line [{binary,false},{encoding,latin1}] = lists:sort(io:getopts(WFile)),
+ ?line proxy_setnext(Server,"Hej"),
+ ?line "Hej" = io:get_line(Server,''),
+ ?line proxy_setnext(Server,"Hej"++[532]),
+ ?line [$H,$e,$j,532] = io:get_line(Server,''),
+ ?line ok = io:setopts(Server,[{binary,true}]),
+ ?line proxy_setnext(Server,"Hej"),
+ ?line <<"Hej">> = io:get_line(Server,''),
+ ?line proxy_setnext(Server,"Hej"++[532]),
+ ?line <<72,101,106,200,148>> = io:get_line(Server,''),
+ ?line [$H,$e,$j,532] = lists:flatten(io_lib:format("~ts",[<<72,101,106,200,148>>])),
+ ?line file:write(WFile,<<"HejA">>),
+ ?line file:write(WFile,unicode:characters_to_binary("Hej"++[532],unicode,unicode)),
+ ?line file:write(WFile,unicode:characters_to_binary("Hej"++[532],unicode,{utf16,big})),
+ ?line file:write(WFile,unicode:characters_to_binary("Hej"++[532],unicode,{utf16,little})),
+ ?line file:write(WFile,unicode:characters_to_binary("Hej"++[532],unicode,{utf32,big})),
+ ?line file:write(WFile,unicode:characters_to_binary("Hej"++[532],unicode,{utf32,little})),
+ ?line file:close(WFile),
+ ?line {ok,RFile} = file:open(FileName,[read]),
+ ?line [{binary,false},{encoding,latin1}] = lists:sort(io:getopts(RFile)),
+ ?line [$H,$e,$j,$A] = io:get_chars(RFile,'',4),
+ ?line io:setopts(RFile,[{encoding,unicode}]),
+ ?line [$H,$e,$j,532] = io:get_chars(RFile,'',4),
+ ?line [{binary,false},{encoding,unicode}] = lists:sort(io:getopts(RFile)),
+ ?line io:setopts(RFile,[{encoding,{utf16,big}}]),
+ ?line [$H,$e,$j,532] = io:get_chars(RFile,'',4),
+ ?line [{binary,false},{encoding,{utf16,big}}] =
+ lists:sort(io:getopts(RFile)),
+ ?line io:setopts(RFile,[{encoding,{utf16,little}}]),
+ ?line [$H,$e,$j,532] = io:get_chars(RFile,'',4),
+ ?line [{binary,false},{encoding,{utf16,little}}] =
+ lists:sort(io:getopts(RFile)),
+ ?line io:setopts(RFile,[{encoding,{utf32,big}}]),
+ ?line [$H,$e,$j,532] = io:get_chars(RFile,'',4),
+ ?line [{binary,false},{encoding,{utf32,big}}] =
+ lists:sort(io:getopts(RFile)),
+ ?line io:setopts(RFile,[{encoding,{utf32,little}}]),
+ ?line [$H,$e,$j,532] = io:get_chars(RFile,'',4),
+ ?line [{binary,false},{encoding,{utf32,little}}] =
+ lists:sort(io:getopts(RFile)),
+ ?line eof = io:get_line(RFile,''),
+ ?line file:position(RFile,0),
+ ?line io:setopts(RFile,[{binary,true},{encoding,latin1}]),
+ ?line <<$H,$e,$j,$A>> = io:get_chars(RFile,'',4),
+ ?line [{binary,true},{encoding,latin1}] = lists:sort(io:getopts(RFile)),
+ ?line io:setopts(RFile,[{encoding,unicode}]),
+ ?line <<$H,$e,$j,532/utf8>> = io:get_chars(RFile,'',4),
+ ?line [{binary,true},{encoding,unicode}] = lists:sort(io:getopts(RFile)),
+ ?line io:setopts(RFile,[{encoding,{utf16,big}}]),
+ ?line <<$H,$e,$j,532/utf8>> = io:get_chars(RFile,'',4),
+ ?line [{binary,true},{encoding,{utf16,big}}] =
+ lists:sort(io:getopts(RFile)),
+ ?line io:setopts(RFile,[{encoding,{utf16,little}}]),
+ ?line <<$H,$e,$j,532/utf8>> = io:get_chars(RFile,'',4),
+ ?line [{binary,true},{encoding,{utf16,little}}] =
+ lists:sort(io:getopts(RFile)),
+ ?line io:setopts(RFile,[{encoding,{utf32,big}}]),
+ ?line <<$H,$e,$j,532/utf8>> = io:get_chars(RFile,'',4),
+ ?line [{binary,true},{encoding,{utf32,big}}] =
+ lists:sort(io:getopts(RFile)),
+ ?line io:setopts(RFile,[{encoding,{utf32,little}}]),
+ ?line <<$H,$e,$j,532/utf8>> = io:get_chars(RFile,'',4),
+ ?line [{binary,true},{encoding,{utf32,little}}] =
+ lists:sort(io:getopts(RFile)),
+ ?line eof = io:get_line(RFile,''),
+ ?line file:close(RFile),
+ %% So, lets test another node with new interactive shell
+ ?line rtnode([{putline,""},
+ {putline, "2."},
+ {getline, "2"},
+ {putline, "lists:keyfind(binary,1,io:getopts())."},
+ {getline, "{binary,false}"},
+ {putline, "io:get_line('')."},
+ {putline, "hej"},
+ {getline, "\"hej\\n\""},
+ {putline, "io:setopts([{binary,true}])."},
+ {getline, "ok"},
+ {putline, "io:get_line('')."},
+ {putline, "hej"},
+ {getline, "<<\"hej\\n\">>"}
+ ],[]),
+ %% And one with oldshell
+ ?line rtnode([{putline,""},
+ {putline, "2."},
+ {getline_re, ".*2."},
+ {getline, "2"},
+ {putline, "lists:keyfind(binary,1,io:getopts())."},
+ {getline_re, ".*{binary,false}"},
+ {putline, "io:get_line('')."},
+ {putline, "hej"},
+ {getline_re, ".*\"hej\\\\n\""},
+ {putline, "io:setopts([{binary,true}])."},
+ {getline_re, ".*ok"},
+ {putline, "io:get_line('')."},
+ {putline, "hej"},
+ {getline_re, ".*<<\"hej\\\\n\">>"}
+ ],[],[],"-oldshell"),
+ ok.
+
+unicode_options(suite) ->
+ [];
+unicode_options(doc) ->
+ ["Tests various unicode options"];
+unicode_options(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir,Config),
+ PrivDir = ?config(priv_dir,Config),
+ %% A string in both russian and greek characters, which is present
+ %% in all the internal test files (but in different formats of course)...
+ TestData = [1090,1093,1077,32,1073,1080,1075,32,
+ 1088,1077,1076,32,1092,1086,1100,32,1093,
+ 1072,1089,32,1089,1086,1100,32,932,951,949,
+ 32,946,953,947,32,961,949,948,32,
+ 963,959,967,32,945,961,949,32,966,959,967,949,963],
+ %% Testdata from Chinese open source customer, that triggered OTP-7974
+ TestData2 = [46,46,46,12411,12370,12411,12370,44,12411,12370,12411,12370,44,
+ 12411,12370,12411,12370,44,12411,12370,12411,12370,44,12411,12370,
+ 12411,12370,44,44,44,12411,12370,12411,12370,44,44,12411,12370,12411,
+ 12370,44,12411,12370,12411,12370,44,12411,12370,12411,12370,44,12411,
+ 12370,12411,12370,44,12411,12370,12411,12370,44,44,44,10],
+
+ %% The external test files are generated with a BOM writing
+ %% text editor. A shorter line is written (with two characters
+ %% larger than 127).
+ ExternalTestData = [197,116,101,114,101,114,246,118,114,97],
+ InternalBomFiles = ["testdata_utf8_bom.dat",
+ "testdata_utf16_big_bom.dat",
+ "testdata_utf16_little_bom.dat",
+ "testdata_utf32_big_bom.dat",
+ "testdata_utf32_little_bom.dat"],
+ AllNoBom = [{utf8,"testdata_utf8.dat"},
+ {utf16,"testdata_utf16_big.dat"},
+ {{utf16,big},"testdata_utf16_big.dat"},
+ {{utf16,little},"testdata_utf16_little.dat"},
+ {utf32,"testdata_utf32_big.dat"},
+ {{utf32,big},"testdata_utf32_big.dat"},
+ {{utf32,little},"testdata_utf32_little.dat"}],
+ ExternalBomFiles = ["external_utf8_bom.dat",
+ "external_utf16_little_bom.dat",
+ "external_utf16_big_bom.dat"],
+ ReadBomFile = fun(File,Dir) ->
+ %io:format(standard_error,"~s\r\n",[filename:join([Dir,File])]),
+ {ok,F} = file:open(filename:join([Dir,File]),
+ [read,binary]),
+ {ok,Bin} = file:read(F,4),
+ {Type,Bytes} = unicode:bom_to_encoding(Bin),
+ %io:format(standard_error,"~p\r\n",[{Type,Bytes}]),
+
+ file:position(F,Bytes),
+ io:setopts(F,[{encoding,Type}]),
+ R = unicode:characters_to_list(
+ io:get_chars(F,'',length(TestData)),unicode),
+ file:close(F),
+ R
+ end,
+ ReadBomlessFile = fun({Type,File},DataLen,Dir) ->
+ {ok,F} = file:open(filename:join([Dir,File]),
+ [read,binary,
+ {encoding,Type}]),
+ R = unicode:characters_to_list(
+ io:get_chars(F,'',DataLen),unicode),
+ file:close(F),
+ R
+ end,
+ ReadBomlessFileList = fun({Type,File},DataLen,Dir) ->
+ {ok,F} = file:open(filename:join([Dir,File]),
+ [read,
+ {encoding,Type}]),
+ R = io:get_chars(F,'',DataLen),
+ file:close(F),
+ R
+ end,
+ ReadBomlessFileListLine = fun({Type,File},Dir) ->
+ {ok,F} = file:open(filename:join([Dir,File]),
+ [read,
+ {encoding,Type}]),
+ R = io:get_line(F,''),
+ file:close(F),
+ R
+ end,
+ ?line [TestData = ReadBomFile(F,DataDir) || F <- InternalBomFiles ],
+ ?line [ExternalTestData = ReadBomFile(F,DataDir) || F <- ExternalBomFiles ],
+ ?line [TestData = ReadBomlessFile(F,length(TestData),DataDir) || F <- AllNoBom ],
+ ?line [TestData = ReadBomlessFileList(F,length(TestData),DataDir) || F <- AllNoBom ],
+ ?line [TestData = ReadBomlessFileListLine(F,DataDir) || F <- AllNoBom ],
+
+ BomDir = filename:join([PrivDir,"BOMDATA"]),
+ BomlessDir = filename:join([PrivDir,"BOMLESSDATA"]),
+ file:make_dir(BomDir),
+ file:make_dir(BomlessDir),
+
+ WriteBomFile = fun({Enc,File},Dir) ->
+ {ok,F} = file:open(filename:join([Dir,File]),
+ [write,binary]),
+ file:write(F,unicode:encoding_to_bom(Enc)),
+ io:setopts(F,[{encoding,Enc}]),
+ io:put_chars(F,TestData),
+ file:close(F),
+ ok
+ end,
+ ?line [ ok = WriteBomFile(F,BomDir) || F <- AllNoBom ],
+ ?line [TestData = ReadBomFile(F,BomDir) || {_,F} <- AllNoBom ],
+ WriteBomlessFile = fun({Enc,File},TData,Dir) ->
+ {ok,F} = file:open(
+ filename:join([Dir,File]),
+ [write,binary,{encoding,Enc}]),
+ io:put_chars(F,TData),
+ file:close(F),
+ ok
+ end,
+ ?line [ ok = WriteBomlessFile(F,TestData,BomlessDir) || F <- AllNoBom ],
+ ?line [TestData = ReadBomlessFile(F,length(TestData),BomlessDir) || F <- AllNoBom ],
+ ?line [TestData = ReadBomlessFileList(F,length(TestData),BomlessDir) || F <- AllNoBom ],
+ ?line [TestData = ReadBomlessFileListLine(F,BomlessDir) || F <- AllNoBom ],
+
+ CannotReadFile = fun({Enc,File},Dir) ->
+ %io:format(standard_error,"~s\r\n",[filename:join([Dir,File])]),
+ {ok,F} = file:open(
+ filename:join([Dir,File]),
+ [read,binary,{encoding,Enc}]),
+ Enc2 = case Enc of
+ utf8 ->
+ unicode;
+ Tpl when is_tuple(Tpl) ->
+ Tpl;
+ Atom when is_atom(Atom) ->
+ {Atom, big}
+ end,
+ {error, {no_translation,Enc2,latin1}} =
+ file:read(F,10),
+ {error,terminated} = io:get_chars(F,'',10),
+ ok
+ end,
+ ?line [ ok = CannotReadFile(F,DataDir) || F <- AllNoBom ],
+ ?line [ ok = CannotReadFile(F,BomlessDir) || F <- AllNoBom ],
+ ?line [ ok = CannotReadFile(F,BomDir) || F <- AllNoBom ],
+
+ ?line [ ok = WriteBomlessFile(F,TestData2,BomlessDir) || F <- AllNoBom ],
+ ?line [TestData2 = ReadBomlessFile(F,length(TestData2),BomlessDir) || F <- AllNoBom ],
+ ?line [TestData2 = ReadBomlessFileList(F,length(TestData2),BomlessDir) || F <- AllNoBom ],
+ ?line [TestData2 = ReadBomlessFileListLine(F,BomlessDir) || F <- AllNoBom ],
+
+
+ FailDir = filename:join([PrivDir,"FAIL"]),
+ file:make_dir(FailDir),
+
+ CannotWriteFile = fun({_Enc,File},Dir) ->
+ {ok,F} = file:open(
+ filename:join([Dir,File]),
+ [write,binary]),
+ ?line {'EXIT', {no_translation,_}} =
+ (catch io:put_chars(F,TestData)),
+ ?line {'EXIT', {terminated,_}} = (catch io:put_chars(F,TestData)),
+ ok
+ end,
+ ?line [ ok = CannotWriteFile(F,FailDir) || F <- AllNoBom ],
+
+ %% OK, time for the group_leaders...
+ ?line rtnode([{putline,""},
+ {putline, "2."},
+ {getline, "2"},
+ {putline, "lists:keyfind(encoding,1,io:getopts())."},
+ {getline, "{encoding,latin1}"},
+ {putline, "io:format(\"~ts~n\",[[1024]])."},
+ {getline, "\\x{400}"},
+ {putline, "io:setopts([unicode])."},
+ {getline, "ok"},
+ {putline, "io:format(\"~ts~n\",[[1024]])."},
+ {getline,
+ binary_to_list(unicode:characters_to_binary(
+ [1024],unicode,utf8))}
+ ],[],"LC_CTYPE=\"ISO-8859-1\"; export LC_CTYPE; "),
+ ?line rtnode([{putline,""},
+ {putline, "2."},
+ {getline_re, ".*2."},
+ {getline, "2"},
+ {putline, "lists:keyfind(encoding,1,io:getopts())."},
+ {getline_re, ".*{encoding,latin1}"},
+ {putline, "io:format(\"~ts~n\",[[1024]])."},
+ {getline_re, ".*\\\\x{400\\}"},
+ {putline, "io:setopts([{encoding,unicode}])."},
+ {getline_re, ".*ok"},
+ {putline, "io:format(\"~ts~n\",[[1024]])."},
+ {getline_re,
+ ".*"++binary_to_list(unicode:characters_to_binary(
+ [1024],unicode,utf8))}
+ ],[],"LC_CTYPE=\"ISO-8859-1\"; export LC_CTYPE; ",
+ " -oldshell "),
+
+ ok.
+
+unicode_options_gen(suite) ->
+ [];
+unicode_options_gen(doc) ->
+ ["Tests various unicode options on random generated files"];
+unicode_options_gen(Config) when is_list(Config) ->
+ ?line random:seed(1240,900586,553728),
+ ?line PrivDir = ?config(priv_dir,Config),
+ ?line AllModes = [utf8,utf16,{utf16,big},{utf16,little},utf32,{utf32,big},{utf32,little}],
+ ?line FSize = 17*1024,
+ ?line NumItersRead = 2,
+ ?line NumItersWrite = 2,
+ ?line Dir = filename:join([PrivDir,"GENDATA1"]),
+ ?line file:make_dir(Dir),
+
+ %dbg:tracer(process,{fun(A,_) -> erlang:display(A) end,true}),
+ %dbg:tpl(file_io_server,x),
+ %dbg:ctpl(file_io_server,cafu),
+ %dbg:tp(unicode,x),
+
+ DoOneFile1 = fun(Encoding,N,M) ->
+ ?dbg({Encoding,M,N}),
+ io:format("Read test: Encoding ~p, Chunk size ~p, Iteration ~p~n",[Encoding,M,N]),
+ io:format(standard_error,"Read test: Encoding ~p, Chunk size ~p, Iteration ~p\r\n",[Encoding,M,N]),
+ ?line Fname = filename:join([Dir,"genfile_"++enc2str(Encoding)++"_"++integer_to_list(N)]),
+ ?dbg(?LINE),
+ ?line Ulist = random_unicode(FSize),
+ ?dbg(?LINE),
+ ?line my_write_file(Fname,Ulist,Encoding),
+ ?dbg(?LINE),
+ ?line {ok,F1} = file:open(Fname,[read,{encoding,Encoding}]),
+
+ ?dbg(?LINE),
+ ?line Res1 = read_whole_file(fun(FD) -> io:get_line(FD,'') end,F1),
+ ?dbg(?LINE),
+ ?line Ulist = unicode:characters_to_list(Res1,unicode),
+ ?dbg(?LINE),
+ ?line file:close(F1),
+ ?line {ok,F2} = file:open(Fname, [read,binary,{encoding,Encoding}]),
+ ?line Res2 = read_whole_file(fun(FD) -> io:get_chars(FD,'',M) end,F2),
+ ?line Ulist = unicode:characters_to_list(Res2,unicode),
+ ?dbg(?LINE),
+ ?line file:close(F2),
+ ?line {ok,F3} = file:open(Fname, [read,binary,{encoding,Encoding}]),
+ ?dbg(?LINE),
+%% case {Encoding,M,N} of
+%% {{utf16,little},10,2} ->
+%% dbg:p(F3,call);
+%% _ ->
+%% ok
+%% end,
+
+ ?line Res3 = read_whole_file(fun(FD) -> case io:fread(FD,'',"~ts") of {ok,D} -> D; O -> O end end, F3),
+ ?dbg(?LINE),
+ ?line Ulist2 = [ X || X <- Ulist,
+ X =/= $\n, X =/= $ ],
+ ?dbg(?LINE),
+ ?line Ulist2 = unicode:characters_to_list(Res3,unicode),
+ ?dbg(?LINE),
+ ?line file:close(F3),
+ ?line {ok,F4} = file:open(Fname, [read,{encoding,Encoding}]),
+ ?line Res4 = read_whole_file(fun(FD) -> case io:fread(FD,'',"~tc") of {ok,D} -> D; O -> O end end,F4),
+ ?line Ulist3 = [ X || X <- Ulist,
+ X =/= $\n ],
+ ?line Ulist3 = unicode:characters_to_list(Res4,unicode),
+ ?dbg(?LINE),
+ ?line file:close(F4),
+ ?line file:delete(Fname)
+ end,
+
+ [ [ [ DoOneFile1(E,N,M) || E <- AllModes ] || M <- [10,1000,128,1024,8192,8193] ] || N <- lists:seq(1,NumItersRead)],
+ DoOneFile2 = fun(Encoding,N,M) ->
+ ?dbg({Encoding,M,N}),
+ io:format("Write test: Encoding ~p, Chunk size ~p, Iteration ~p~n",[Encoding,M,N]),
+ io:format(standard_error,"Write test: Encoding ~p, Chunk size ~p, Iteration ~p\r\n",[Encoding,M,N]),
+ ?line Fname = filename:join([Dir,"genfile_"++enc2str(Encoding)++"_"++integer_to_list(N)]),
+ ?dbg(?LINE),
+ ?line Ulist = random_unicode(FSize),
+ ?dbg(?LINE),
+ ?line {ok,F1} = file:open(Fname,[write,{encoding,Encoding}]),
+ ?line io:put_chars(F1,Ulist),
+ ?line file:close(F1),
+ ?line Ulist = my_read_file(Fname,Encoding),
+ ?line file:delete(Fname),
+ ?line {ok,F2} = file:open(Fname,[write,binary,{encoding,Encoding}]),
+ ?line io:put_chars(F2,Ulist),
+ ?line file:close(F2),
+ ?line Ulist = my_read_file(Fname,Encoding),
+ ?line file:delete(Fname),
+ ?line {ok,F3} = file:open(Fname,[write,{encoding,Encoding}]),
+ ?line LL = string:tokens(Ulist,"\n"),
+ ?line Ulist2 = lists:flatten(LL),
+ ?line [ io:format(F3,"~ts",[L]) || L <- LL ],
+ ?line file:close(F3),
+ ?line Ulist2 = my_read_file(Fname,Encoding),
+ ?line file:delete(Fname),
+ ?line {ok,F4} = file:open(Fname,[write,{encoding,Encoding}]),
+ ?line [ io:format(F4,"~tc",[C]) || C <- Ulist ],
+ ?line file:close(F4),
+ ?line Ulist = my_read_file(Fname,Encoding),
+ ?line file:delete(Fname),
+ ?line {ok,F5} = file:open(Fname,[write,{encoding,Encoding}]),
+ ?line io:put_chars(F5,unicode:characters_to_binary(Ulist)),
+ ?line file:close(F5),
+ ?line Ulist = my_read_file(Fname,Encoding),
+ ?line file:delete(Fname),
+ ok
+ end,
+ [ [ [ DoOneFile2(E,N,M) || E <- AllModes ] || M <- [10,1000,128,1024,8192,8193] ] || N <- lists:seq(1,NumItersWrite)],
+ ok.
+
+
+
+
+read_whole_file(Fun,F) ->
+ case Fun(F) of
+ eof ->
+ [];
+ {error,Error} ->
+ ?dbg(Error),
+ receive after 10000 -> ok end,
+ exit(Error);
+ Other ->
+ %?dbg(Other),
+ [Other | read_whole_file(Fun,F)]
+ end.
+
+
+enc2str(Atom) when is_atom(Atom) ->
+ atom_to_list(Atom);
+enc2str({A1,A2}) when is_atom(A1), is_atom(A2) ->
+ atom_to_list(A1)++"_"++atom_to_list(A2).
+
+
+
+
+my_write_file(Filename,UniList,Encoding) ->
+ Bin = unicode:characters_to_binary(UniList,utf8,Encoding),
+ file:write_file(Filename,Bin).
+
+my_read_file(Filename,Encoding) ->
+ {ok,Bin} = file:read_file(Filename),
+ unicode:characters_to_list(Bin,Encoding).
+
+random_unicode(0) ->
+ [];
+random_unicode(N) ->
+ % Favour large unicode and make linebreaks
+ X = case random:uniform(20) of
+ A when A =< 1 -> $\n;
+ A0 when A0 =< 3 -> random:uniform(16#10FFFF);
+ A1 when A1 =< 6 -> random:uniform(16#10FFFF - 16#7F) + 16#7F;
+ A2 when A2 =< 12 -> random:uniform(16#10FFFF - 16#7FF) + 16#7FF;
+ _ -> random:uniform(16#10FFFF - 16#FFFF) + 16#FFFF
+ end,
+ case X of
+ Inv1 when Inv1 >= 16#D800, Inv1 =< 16#DFFF;
+ Inv1 =:= 16#FFFE;
+ Inv1 =:= 16#FFFF ->
+ random_unicode(N);
+ _ ->
+ [X | random_unicode(N-1)]
+ end.
+
+
+binary_options(suite) ->
+ [];
+binary_options(doc) ->
+ ["Tests variants with binary option"];
+binary_options(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir,Config),
+ PrivDir = ?config(priv_dir,Config),
+ TestData = unicode:characters_to_binary(
+ [1090,1093,1077,32,1073,1080,1075,32,
+ 1088,1077,1076,32,1092,1086,1100,32,1093,
+ 1072,1089,32,1089,1086,1100,32,932,951,949,
+ 32,946,953,947,32,961,949,948,32,
+ 963,959,967,32,945,961,949,32,966,959,967,949,963]),
+ <<First10:10/binary,Second10:10/binary,_/binary>> = TestData,
+ First10List = binary_to_list(First10),
+ Second10List = binary_to_list(Second10),
+ TestFile = filename:join([DataDir, "testdata_utf8.dat"]),
+ ?line {ok, F} = file:open(TestFile,[read]),
+ ?line {ok, First10List} = file:read(F,10),
+ ?line io:setopts(F,[binary]),
+ ?line {ok, Second10} = file:read(F,10),
+ ?line file:close(F),
+ ?line {ok, F2} = file:open(TestFile,[read,binary]),
+ ?line {ok, First10} = file:read(F2,10),
+ ?line io:setopts(F2,[list]),
+ ?line {ok, Second10List} = file:read(F2,10),
+ ?line file:position(F2,0),
+ %dbg:tracer(),dbg:p(F2,call),dbg:tpl(file_io_server,x),
+ ?line First10List = io:get_chars(F2,'',10),
+ ?line io:setopts(F2,[binary]),
+ ?line Second10 = unicode:characters_to_binary(io:get_chars(F2,'',10),unicode,latin1),
+ ?line file:close(F2),
+ ?line LineBreakFileName = filename:join([PrivDir, "testdata.dat"]),
+ ?line LineBreakTestData = <<TestData/binary,$\n>>,
+ ?line LineBreakTestDataList = binary_to_list(LineBreakTestData),
+ ?line file:write_file(LineBreakFileName,[LineBreakTestData,LineBreakTestData,LineBreakTestData,TestData]),
+ ?line {ok, F3} = file:open(LineBreakFileName,[read]),
+ ?line LineBreakTestDataList = io:get_line(F3,''),
+ ?line io:setopts(F3,[binary]),
+ ?line LineBreakTestData = unicode:characters_to_binary(io:get_line(F3,''),unicode,latin1),
+ ?line io:setopts(F3,[list]),
+ ?line LineBreakTestDataList = io:get_line(F3,''),
+ ?line io:setopts(F3,[binary]),
+ %ok = io:format(standard_error,"TestData = ~w~n",[TestData]),
+ ?line TestData = unicode:characters_to_binary(io:get_line(F3,''),unicode,latin1),
+ ?line eof = io:get_line(F3,''),
+ ?line file:close(F3),
+ %% OK, time for the group_leaders...
+ %% io:format(standard_error,"Hmmm:~w~n",["<<\""++binary_to_list(<<"\345\344\366"/utf8>>)++"\\n\">>"]),
+ ?line rtnode([{putline,""},
+ {putline, "2."},
+ {getline, "2"},
+ {putline, "lists:keyfind(binary,1,io:getopts())."},
+ {getline, "{binary,false}"},
+ {putline, "io:get_line('')."},
+ {putline, "hej"},
+ {getline, "\"hej\\n\""},
+ {putline, "io:setopts([{binary,true},unicode])."},
+ {getline, "ok"},
+ {putline, "io:get_line('')."},
+ {putline, "hej"},
+ {getline, "<<\"hej\\n\">>"},
+ {putline, "io:get_line('')."},
+ {putline, binary_to_list(<<"\345\344\366"/utf8>>)},
+ {getline, "<<\""++binary_to_list(unicode:characters_to_binary(<<"\345\344\366"/utf8>>,latin1,utf8))++"\\n\">>"}
+ ],[]),
+ %% And one with oldshell
+ ?line rtnode([{putline,""},
+ {putline, "2."},
+ {getline_re, ".*2."},
+ {getline, "2"},
+ {putline, "lists:keyfind(binary,1,io:getopts())."},
+ {getline_re, ".*{binary,false}"},
+ {putline, "io:get_line('')."},
+ {putline, "hej"},
+ {getline_re, ".*\"hej\\\\n\""},
+ {putline, "io:setopts([{binary,true},unicode])."},
+ {getline_re, ".*ok"},
+ {putline, "io:get_line('')."},
+ {putline, "hej"},
+ {getline_re, ".*<<\"hej\\\\n\">>"},
+ {putline, "io:get_line('')."},
+ {putline, binary_to_list(<<"\345\344\366"/utf8>>)},
+ {getline_re, ".*<<\""++binary_to_list(unicode:characters_to_binary(<<"\345\344\366"/utf8>>,latin1,utf8))++"\\\\n\">>"}
+ ],[],[],"-oldshell"),
+ ok.
+
+bc_with_r12(suite) ->
+ [];
+bc_with_r12(doc) ->
+ ["Test io protocol compatibility with R12 nodes"];
+bc_with_r12(Config) when is_list(Config) ->
+ case ?t:is_release_available("r12b") of
+ true -> bc_with_r12_1(Config);
+ false -> {skip,"No R12B found"}
+ end.
+
+bc_with_r12_1(Config) ->
+ PA = filename:dirname(code:which(?MODULE)),
+ Name1 = io_proto_r12_1,
+ ?line N1 = list_to_atom(atom_to_list(Name1) ++ "@" ++ hostname()),
+ ?line ?t:start_node(Name1, peer, [{args, "-pz "++PA},{erl,[{release,"r12b"}]}]),
+ DataDir = ?config(data_dir,Config),
+ %PrivDir = ?config(priv_dir,Config),
+ FileName1 = filename:join([DataDir,"testdata_latin1.dat"]),
+ TestDataLine1 = [229,228,246],
+ TestDataLine2 = [197,196,214],
+ ?line SPid1 = rpc:call(N1,erlang,spawn,[?MODULE,hold_the_line,[self(),FileName1,[read]]]),
+ ?line {ok,F1} = receive
+ {SPid1,Res1} ->
+ Res1
+ after 5000 ->
+ exit(timeout)
+ end,
+ ?line TestDataLine1 = chomp(io:get_line(F1,'')),
+ ?line SPid1 ! die,
+ receive after 1000 -> ok end,
+ ?line SPid2 = rpc:call(N1,erlang,spawn,[?MODULE,hold_the_line,[self(),FileName1,[read,binary]]]),
+ ?line {ok,F2} = receive
+ {SPid2,Res2} ->
+ Res2
+ after 5000 ->
+ exit(timeout)
+ end,
+ TestDataLine1BinUtf = unicode:characters_to_binary(TestDataLine1),
+ TestDataLine1BinLatin = list_to_binary(TestDataLine1),
+ TestDataLine2BinUtf = unicode:characters_to_binary(TestDataLine2),
+ TestDataLine2BinLatin = list_to_binary(TestDataLine2),
+ ?line TestDataLine1BinUtf = chomp(io:get_line(F2,'')),
+ ?line TestDataLine2BinUtf = chomp(io:get_line(F2,'')),
+ %io:format(standard_error,"Exec:~s\r\n",[rpc:call(N1,os,find_executable,["erl"])]),
+ %io:format(standard_error,"Io:~s\r\n",[rpc:call(N1,code,which,[io])]),
+ %io:format(standard_error,"File_io_server:~s\r\n",[rpc:call(N1,code,which,[file_io_server])]),
+ ?line file:position(F2,0),
+ ?line TestDataLine1BinLatin = chomp(rpc:call(N1,io,get_line,[F2,''])),
+ ?line TestDataLine2BinUtf = chomp(io:get_line(F2,'')),
+ ?line file:position(F2,0),
+ ?line TestDataLine1BinUtf = chomp(io:get_line(F2,'')),
+ ?line TestDataLine2BinLatin = chomp(rpc:call(N1,io,get_line,[F2,''])),
+ ?line eof = chomp(rpc:call(N1,io,get_line,[F2,''])),
+ ?line file:position(F2,0),
+ ?line TestDataLine1BinLatin = rpc:call(N1,io,get_chars,[F2,'',3]),
+ io:get_chars(F2,'',1),
+ ?line TestDataLine2BinLatin = chomp(rpc:call(N1,io,get_line,[F2,''])),
+ ?line file:position(F2,0),
+ ?line {ok,[TestDataLine1]} = io:fread(F2,'',"~s"),
+ ?line {ok,[TestDataLine2]} = rpc:call(N1,io,fread,[F2,'',"~s"]),
+
+ ?line DataLen1 = length(TestDataLine1),
+ ?line DataLen2 = length(TestDataLine2),
+
+ ?line file:position(F2,0),
+ ?line {ok,TestDataLine1BinLatin} = file:read(F2,DataLen1),
+ ?line {ok,_} = file:read(F2,1),
+ ?line {ok,TestDataLine2BinLatin} = rpc:call(N1,file,read,[F2,DataLen2]),
+ ?line {ok,_} = file:read(F2,1),
+ ?line eof = rpc:call(N1,file,read,[F2,1]),
+ %% As r12 has a bug when setting options with setopts, we need
+ %% to reopen the file...
+ ?line SPid2 ! die,
+ receive after 1000 -> ok end,
+ ?line SPid3 = rpc:call(N1,erlang,spawn,[?MODULE,hold_the_line,[self(),FileName1,[read]]]),
+ ?line {ok,F3} = receive
+ {SPid3,Res3} ->
+ Res3
+ after 5000 ->
+ exit(timeout)
+ end,
+
+ ?line file:position(F3,0),
+ ?line {ok,[TestDataLine1]} = io:fread(F3,'',"~s"),
+ ?line {ok,[TestDataLine2]} = rpc:call(N1,io,fread,[F3,'',"~s"]),
+
+
+ ?line file:position(F3,0),
+ ?line {ok,TestDataLine1} = file:read(F3,DataLen1),
+ ?line {ok,_} = file:read(F3,1),
+ ?line {ok,TestDataLine2} = rpc:call(N1,file,read,[F3,DataLen2]),
+ ?line {ok,_} = file:read(F3,1),
+ ?line eof = rpc:call(N1,file,read,[F3,1]),
+
+
+ %% So, lets do it all again, but the other way around
+ {ok,F4} = file:open(FileName1,[read]),
+ ?line TestDataLine1 = chomp(io:get_line(F4,'')),
+ ?line file:position(F4,0),
+ ?line io:setopts(F4,[binary]),
+ ?line TestDataLine1BinUtf = chomp(io:get_line(F4,'')),
+ ?line TestDataLine2BinUtf = chomp(io:get_line(F4,'')),
+ ?line file:position(F4,0),
+ ?line TestDataLine1BinUtf = chomp(io:get_line(F4,'')),
+ ?line TestDataLine2BinUtf = chomp(io:get_line(F4,'')),
+ ?line file:position(F4,0),
+ %dbg:tracer(),dbg:p(F4,[call,m]),dbg:tpl(file_io_server,x),dbg:tpl(io_lib,x),
+ ?line TestDataLine1BinUtf = chomp(io:get_line(F4,'')),
+ ?line TestDataLine2BinLatin = chomp(rpc:call(N1,io,get_line,[F4,''])),
+ ?line file:position(F4,0),
+ ?line TestDataLine1BinLatin = chomp(rpc:call(N1,io,get_line,[F4,''])),
+ ?line TestDataLine2BinUtf = chomp(io:get_line(F4,'')),
+ ?line eof = chomp(rpc:call(N1,io,get_line,[F4,''])),
+ ?line file:position(F4,0),
+ ?line TestDataLine1BinLatin = rpc:call(N1,io,get_chars,[F4,'',3]),
+ io:get_chars(F4,'',1),
+ ?line TestDataLine2BinLatin = chomp(rpc:call(N1,io,get_line,[F4,''])),
+ ?line file:position(F4,0),
+ ?line {ok,[TestDataLine1]} = io:fread(F4,'',"~s"),
+ ?line {ok,[TestDataLine2]} = rpc:call(N1,io,fread,[F4,'',"~s"]),
+ ?line file:position(F4,0),
+ ?line {ok,TestDataLine1BinLatin} = file:read(F4,DataLen1),
+ ?line {ok,_} = file:read(F4,1),
+ ?line {ok,TestDataLine2BinLatin} = rpc:call(N1,file,read,[F4,DataLen2]),
+ ?line {ok,_} = file:read(F4,1),
+ ?line eof = rpc:call(N1,file,read,[F4,1]),
+ ?line io:setopts(F4,[list]),
+
+ ?line file:position(F4,0),
+ ?line {ok,[TestDataLine1]} = io:fread(F4,'',"~s"),
+ ?line {ok,[TestDataLine2]} = rpc:call(N1,io,fread,[F4,'',"~s"]),
+
+
+ ?line file:position(F4,0),
+ ?line {ok,TestDataLine1} = file:read(F4,DataLen1),
+ ?line {ok,_} = file:read(F4,1),
+ ?line {ok,TestDataLine2} = rpc:call(N1,file,read,[F4,DataLen2]),
+ ?line {ok,_} = file:read(F4,1),
+ ?line eof = rpc:call(N1,file,read,[F4,1]),
+
+ file:close(F4),
+ ?t:stop_node(N1),
+ ok.
+
+hold_the_line(Parent,Filename,Options) ->
+ Parent ! {self(), file:open(Filename,Options)},
+ receive
+ die ->
+ ok
+ end.
+
+
+bc_with_r12_gl(suite) ->
+ [];
+bc_with_r12_gl(doc) ->
+ ["Test io protocol compatibility with R12 nodes (terminals)"];
+bc_with_r12_gl(Config) when is_list(Config) ->
+ case ?t:is_release_available("r12b") of
+ true ->
+ case get_progs() of
+ {error,Reason} ->
+ {skip, Reason};
+ _ ->
+ bc_with_r12_gl_1(Config,answering_machine1)
+ end;
+ false ->
+ {skip,"No R12B found"}
+ end.
+
+bc_with_r12_ogl(suite) ->
+ [];
+bc_with_r12_ogl(doc) ->
+ ["Test io protocol compatibility with R12 nodes (oldshell)"];
+bc_with_r12_ogl(Config) when is_list(Config) ->
+ case ?t:is_release_available("r12b") of
+ true ->
+ case get_progs() of
+ {error,Reason} ->
+ {skip, Reason};
+ _ ->
+ bc_with_r12_gl_1(Config,answering_machine2)
+ end;
+ false ->
+ {skip,"No R12B found"}
+ end.
+
+bc_with_r12_gl_1(_Config,Machine) ->
+ PA = filename:dirname(code:which(?MODULE)),
+ Name1 = io_proto_r12_gl_1,
+ ?line N1 = list_to_atom(atom_to_list(Name1) ++ "@" ++ hostname()),
+ ?line ?t:start_node(Name1, peer, [{args, "-pz "++PA},{erl,[{release,"r12b"}]}]),
+ TestDataLine1 = [229,228,246],
+ TestDataLine1BinUtf = unicode:characters_to_binary(TestDataLine1),
+ TestDataLine1BinLatin = list_to_binary(TestDataLine1),
+
+ N2List = create_nodename(),
+ MyNodeList = atom_to_list(node()),
+ register(io_proto_suite,self()),
+ AM1 = spawn(?MODULE,Machine,
+ [MyNodeList, "io_proto_suite", N2List]),
+
+ ?line GL = receive X when is_pid(X) -> X end,
+ %% get_line
+ ?line "Hej\n" = rpc:call(N1,io,get_line,[GL,"Prompt\n"]),
+ ?line io:setopts(GL,[binary]),
+ ?line io:format(GL,"Okej~n",[]),
+ ?line <<"Hej\n">> = rpc:call(N1,io,get_line,[GL,"Prompt\n"]),
+ ?line io:setopts(GL,[{encoding,latin1}]),
+ ?line io:format(GL,"Okej~n",[]),
+ ?line TestDataLine1BinLatin = chomp(rpc:call(N1,io,get_line,[GL,"Prompt\n"])),
+ ?line io:format(GL,"Okej~n",[]),
+ ?line TestDataLine1BinUtf = chomp(io:get_line(GL,"Prompt\n")),
+ ?line io:setopts(GL,[{encoding,unicode}]),
+
+ ?line io:format(GL,"Okej~n",[]),
+ ?line TestDataLine1BinLatin = chomp(rpc:call(N1,io,get_line,[GL,"Prompt\n"])),
+ ?line io:format(GL,"Okej~n",[]),
+ ?line TestDataLine1BinUtf = chomp(io:get_line(GL,"Prompt\n")),
+ ?line io:setopts(GL,[list]),
+ ?line io:format(GL,"Okej~n",[]),
+
+ %%get_chars
+ ?line "Hej" = rpc:call(N1,io,get_chars,[GL,"Prompt\n",3]),
+ ?line io:setopts(GL,[binary]),
+ ?line io:format(GL,"Okej~n",[]),
+ ?line <<"Hej">> = rpc:call(N1,io,get_chars,[GL,"Prompt\n",3]),
+ ?line io:setopts(GL,[{encoding,latin1}]),
+ ?line io:format(GL,"Okej~n",[]),
+ ?line TestDataLine1BinLatin = rpc:call(N1,io,get_chars,[GL,"Prompt\n",3]),
+ ?line io:format(GL,"Okej~n",[]),
+ ?line TestDataLine1BinUtf = io:get_chars(GL,"Prompt\n",3),
+ ?line io:setopts(GL,[{encoding,unicode}]),
+
+ ?line io:format(GL,"Okej~n",[]),
+ ?line TestDataLine1BinLatin = rpc:call(N1,io,get_chars,[GL,"Prompt\n",3]),
+ ?line io:format(GL,"Okej~n",[]),
+ ?line TestDataLine1BinUtf = io:get_chars(GL,"Prompt\n",3),
+ ?line io:setopts(GL,[list]),
+ ?line io:format(GL,"Okej~n",[]),
+ %%fread
+ ?line {ok,["Hej"]} = rpc:call(N1,io,fread,[GL,"Prompt\n","~s"]),
+ ?line io:setopts(GL,[binary]),
+ ?line io:format(GL,"Okej~n",[]),
+ ?line {ok,["Hej"]} = rpc:call(N1,io,fread,[GL,"Prompt\n","~s"]),
+ ?line io:setopts(GL,[{encoding,latin1}]),
+ ?line io:format(GL,"Okej~n",[]),
+ ?line {ok,[TestDataLine1]} = rpc:call(N1,io,fread,[GL,"Prompt\n","~s"]),
+ ?line io:format(GL,"Okej~n",[]),
+ ?line {ok,[TestDataLine1]} = io:fread(GL,"Prompt\n","~s"),
+ ?line io:setopts(GL,[{encoding,unicode}]),
+ ?line io:format(GL,"Okej~n",[]),
+ ?line {ok,[TestDataLine1]} = rpc:call(N1,io,fread,[GL,"Prompt\n","~s"]),
+ ?line io:format(GL,"Okej~n",[]),
+ ?line {ok,[TestDataLine1]} = io:fread(GL,"Prompt\n","~s"),
+ ?line io:setopts(GL,[list]),
+ ?line io:format(GL,"Okej~n",[]),
+
+
+ ?line receive
+ {AM1,done} ->
+ ok
+ after 5000 ->
+ exit(timeout)
+ end,
+ ?t:stop_node(N1),
+ ok.
+
+
+answering_machine1(OthNode,OthReg,Me) ->
+ TestDataLine1 = [229,228,246],
+ TestDataUtf = binary_to_list(unicode:characters_to_binary(TestDataLine1)),
+ ?line rtnode([{putline,""},
+ {putline, "2."},
+ {getline, "2"},
+ {putline, "{"++OthReg++","++OthNode++"} ! group_leader()."},
+ {getline, "<"},
+ % get_line
+ {getline_re, ".*Prompt"},
+ {putline, "Hej"},
+ {getline_re, ".*Okej"},
+ {getline_re, ".*Prompt"},
+ {putline, "Hej"},
+ {getline_re, ".*Okej"},
+ {getline_re, ".*Prompt"},
+ {putline, TestDataLine1},
+ {getline_re, ".*Okej"},
+ {getline_re, ".*Prompt"},
+ {putline, TestDataLine1},
+ {getline_re, ".*Okej"},
+ {getline_re, ".*Prompt"},
+ {putline, TestDataUtf},
+ {getline_re, ".*Okej"},
+ {getline_re, ".*Prompt"},
+ {putline, TestDataUtf},
+ {getline_re, ".*Okej"},
+ % get_chars
+ {getline_re, ".*Prompt"},
+ {putline, "Hej"},
+ {getline_re, ".*Okej"},
+ {getline_re, ".*Prompt"},
+ {putline, "Hej"},
+ {getline_re, ".*Okej"},
+ {getline_re, ".*Prompt"},
+ {putline, TestDataLine1},
+ {getline_re, ".*Okej"},
+ {getline_re, ".*Prompt"},
+ {putline, TestDataLine1},
+ {getline_re, ".*Okej"},
+ {getline_re, ".*Prompt"},
+ {putline, TestDataUtf},
+ {getline_re, ".*Okej"},
+ {getline_re, ".*Prompt"},
+ {putline, TestDataUtf},
+ {getline_re, ".*Okej"},
+ % fread
+ {getline_re, ".*Prompt"},
+ {putline, "Hej"},
+ {getline_re, ".*Okej"},
+ {getline_re, ".*Prompt"},
+ {putline, "Hej"},
+ {getline_re, ".*Okej"},
+ {getline_re, ".*Prompt"},
+ {putline, TestDataLine1},
+ {getline_re, ".*Okej"},
+ {getline_re, ".*Prompt"},
+ {putline, TestDataLine1},
+ {getline_re, ".*Okej"},
+ {getline_re, ".*Prompt"},
+ {putline, TestDataUtf},
+ {getline_re, ".*Okej"},
+ {getline_re, ".*Prompt"},
+ {putline, TestDataUtf},
+ {getline_re, ".*Okej"}
+
+ ],Me,"LC_CTYPE=\"ISO-8859-1\"; export LC_CTYPE; "),
+ O = list_to_atom(OthReg),
+ O ! {self(),done},
+ ok.
+
+answering_machine2(OthNode,OthReg,Me) ->
+ TestDataLine1 = [229,228,246],
+ TestDataUtf = binary_to_list(unicode:characters_to_binary(TestDataLine1)),
+ ?line rtnode([{putline,""},
+ {putline, "2."},
+ {getline, "2"},
+ {putline, "{"++OthReg++","++OthNode++"} ! group_leader()."},
+ {getline_re, ".*<[0-9].*"},
+ % get_line
+ {getline_re, ".*Prompt"},
+ {putline, "Hej"},
+ {getline_re, ".*Okej"},
+ {getline_re, ".*Prompt"},
+ {putline, "Hej"},
+ {getline_re, ".*Okej"},
+ {getline_re, ".*Prompt"},
+ {putline, TestDataLine1},
+ {getline_re, ".*Okej"},
+ {getline_re, ".*Prompt"},
+ {putline, TestDataLine1},
+ {getline_re, ".*Okej"},
+ {getline_re, ".*Prompt"},
+ {putline, TestDataUtf},
+ {getline_re, ".*Okej"},
+ {getline_re, ".*Prompt"},
+ {putline, TestDataUtf},
+ {getline_re, ".*Okej"},
+ % get_chars
+ {getline_re, ".*Prompt"},
+ {putline, "Hej"},
+ {getline_re, ".*Okej"},
+ {getline_re, ".*Prompt"},
+ {putline, "Hej"},
+ {getline_re, ".*Okej"},
+ {getline_re, ".*Prompt"},
+ {putline, TestDataLine1},
+ {getline_re, ".*Okej"},
+ {getline_re, ".*Prompt"},
+ {putline, TestDataLine1},
+ {getline_re, ".*Okej"},
+ {getline_re, ".*Prompt"},
+ {putline, TestDataUtf},
+ {getline_re, ".*Okej"},
+ {getline_re, ".*Prompt"},
+ {putline, TestDataUtf},
+ {getline_re, ".*Okej"},
+ % fread
+ {getline_re, ".*Prompt"},
+ {putline, "Hej"},
+ {getline_re, ".*Okej"},
+ {getline_re, ".*Prompt"},
+ {putline, "Hej"},
+ {getline_re, ".*Okej"},
+ {getline_re, ".*Prompt"},
+ {putline, TestDataLine1},
+ {getline_re, ".*Okej"},
+ {getline_re, ".*Prompt"},
+ {putline, TestDataLine1},
+ {getline_re, ".*Okej"},
+ {getline_re, ".*Prompt"},
+ {putline, TestDataUtf},
+ {getline_re, ".*Okej"},
+ {getline_re, ".*Prompt"},
+ {putline, TestDataUtf},
+ {getline_re, ".*Okej"}
+
+ ],Me,"LC_CTYPE=\"ISO-8859-1\"; export LC_CTYPE; "," -oldshell "),
+ O = list_to_atom(OthReg),
+ O ! {self(),done},
+ ok.
+
+
+read_modes_ogl(suite) ->
+ [];
+read_modes_ogl(doc) ->
+ ["Test various modes when reading from the group leade from another machine"];
+read_modes_ogl(Config) when is_list(Config) ->
+ case get_progs() of
+ {error,Reason} ->
+ {skipped,Reason};
+ _ ->
+ read_modes_gl_1(Config,answering_machine2)
+ end.
+
+read_modes_gl(suite) ->
+ [];
+read_modes_gl(doc) ->
+ ["Test various modes when reading from the group leade from another machine"];
+read_modes_gl(Config) when is_list(Config) ->
+ case get_progs() of
+ {error,Reason} ->
+ {skipped,Reason};
+ _ ->
+ read_modes_gl_1(Config,answering_machine1)
+ end.
+
+read_modes_gl_1(_Config,Machine) ->
+ TestDataLine1 = [229,228,246],
+ TestDataLine1BinUtf = unicode:characters_to_binary(TestDataLine1),
+ TestDataLine1BinLatin = list_to_binary(TestDataLine1),
+
+ N2List = create_nodename(),
+ MyNodeList = atom_to_list(node()),
+ register(io_proto_suite,self()),
+ AM1 = spawn(?MODULE,Machine,
+ [MyNodeList, "io_proto_suite", N2List]),
+
+ ?line GL = receive X when is_pid(X) -> X end,
+ %% get_line
+ ?line "Hej\n" = io:get_line(GL,"Prompt\n"),
+ ?line io:setopts(GL,[binary]),
+ ?line io:format(GL,"Okej~n",[]),
+ ?line <<"Hej\n">> = io:get_line(GL,"Prompt\n"),
+ ?line io:setopts(GL,[{encoding,latin1}]),
+ ?line io:format(GL,"Okej~n",[]),
+ ?line TestDataLine1BinLatin = chomp(io:request(GL,{get_line,latin1,"Prompt\n"})),
+ ?line io:format(GL,"Okej~n",[]),
+ ?line TestDataLine1BinUtf = chomp(io:get_line(GL,"Prompt\n")),
+ ?line io:setopts(GL,[{encoding,unicode}]),
+
+ ?line io:format(GL,"Okej~n",[]),
+ ?line TestDataLine1BinLatin = chomp(io:request(GL,{get_line,latin1,"Prompt\n"})),
+ ?line io:format(GL,"Okej~n",[]),
+ ?line TestDataLine1BinUtf = chomp(io:get_line(GL,"Prompt\n")),
+ ?line io:setopts(GL,[list]),
+ ?line io:format(GL,"Okej~n",[]),
+
+ %%get_chars
+ ?line "Hej" = io:get_chars(GL,"Prompt\n",3),
+ ?line io:setopts(GL,[binary]),
+ ?line io:format(GL,"Okej~n",[]),
+ ?line <<"Hej">> = io:get_chars(GL,"Prompt\n",3),
+ ?line io:setopts(GL,[{encoding,latin1}]),
+ ?line io:format(GL,"Okej~n",[]),
+ ?line TestDataLine1BinLatin = io:request(GL,{get_chars,latin1,"Prompt\n",3}),
+ ?line io:format(GL,"Okej~n",[]),
+ ?line TestDataLine1BinUtf = io:get_chars(GL,"Prompt\n",3),
+ ?line io:setopts(GL,[{encoding,unicode}]),
+
+ ?line io:format(GL,"Okej~n",[]),
+ ?line TestDataLine1BinLatin = io:request(GL,{get_chars,latin1,"Prompt\n",3}),
+ ?line io:format(GL,"Okej~n",[]),
+ ?line TestDataLine1BinUtf = io:get_chars(GL,"Prompt\n",3),
+ ?line io:setopts(GL,[list]),
+ ?line io:format(GL,"Okej~n",[]),
+ %%fread
+ ?line {ok,["Hej"]} = io:fread(GL,"Prompt\n","~s"),
+ ?line io:setopts(GL,[binary]),
+ ?line io:format(GL,"Okej~n",[]),
+ ?line {ok,["Hej"]} = io:fread(GL,"Prompt\n","~s"),
+ ?line io:setopts(GL,[{encoding,latin1}]),
+ ?line io:format(GL,"Okej~n",[]),
+ ?line {ok,[TestDataLine1]} = io:fread(GL,"Prompt\n","~s"),
+ ?line io:format(GL,"Okej~n",[]),
+ ?line {ok,[TestDataLine1]} = io:fread(GL,"Prompt\n","~s"),
+ ?line io:setopts(GL,[{encoding,unicode}]),
+ ?line io:format(GL,"Okej~n",[]),
+ ?line {ok,[TestDataLine1]} = io:fread(GL,"Prompt\n","~s"),
+ ?line io:format(GL,"Okej~n",[]),
+ ?line {ok,[TestDataLine1]} = io:fread(GL,"Prompt\n","~s"),
+ ?line io:setopts(GL,[list]),
+ ?line io:format(GL,"Okej~n",[]),
+
+
+ ?line receive
+ {AM1,done} ->
+ ok
+ after 5000 ->
+ exit(timeout)
+ end,
+ ok.
+
+
+broken_unicode(suite) ->
+ [];
+broken_unicode(doc) ->
+ ["Test behaviour when reading broken Unicode files"];
+broken_unicode(Config) when is_list(Config) ->
+ Dir = ?config(priv_dir,Config),
+ Latin1Name = filename:join([Dir,"latin1_data_file.dat"]),
+ Utf8Name = filename:join([Dir,"utf8_data_file.dat"]),
+ Latin1Data = iolist_to_binary(lists:duplicate(10,lists:seq(0,255)++[255,255,255])),
+ Utf8Data = unicode:characters_to_binary(
+ lists:duplicate(10,lists:seq(0,255))),
+ file:write_file(Latin1Name,Latin1Data),
+ file:write_file(Utf8Name,Utf8Data),
+ ?line [ latin1 = heuristic_encoding_file2(Latin1Name,N,utf8) || N <- lists:seq(1,100)++[1024,2048,10000]],
+ ?line [ utf8 = heuristic_encoding_file2(Utf8Name,N,utf8) || N <- lists:seq(1,100)++[1024,2048,10000]],
+ ?line [ latin1 = heuristic_encoding_file2(Latin1Name,N,utf16) || N <- lists:seq(1,100)++[1024,2048,10000]],
+ ?line [ latin1 = heuristic_encoding_file2(Latin1Name,N,utf32) || N <- lists:seq(1,100)++[1024,2048,10000]],
+ ok.
+
+
+%%
+%% From the cookbook, more or less
+heuristic_encoding_file2(FileName,Chunk,Enc) ->
+ {ok,F} = file:open(FileName,[read,binary,{encoding,Enc}]),
+ loop_through_file2(F,io:get_chars(F,'',Chunk),Chunk,Enc).
+
+loop_through_file2(_,eof,_,Enc) ->
+ Enc;
+loop_through_file2(_,{error,_Err},_,_) ->
+ latin1;
+loop_through_file2(F,Bin,Chunk,Enc) when is_binary(Bin) ->
+ loop_through_file2(F,io:get_chars(F,'',Chunk),Chunk,Enc).
+
+
+
+eof_on_pipe(suite) ->
+ [];
+eof_on_pipe(doc) ->
+ ["tests eof before newline on stdin when erlang is in pipe"];
+eof_on_pipe(Config) when is_list(Config) ->
+ case {get_progs(),os:type()} of
+ {{error,Reason},_} ->
+ {skipped,Reason};
+ {{_,_,Erl},{unix,linux}} ->
+ %% Not even Linux is reliable - echo can be both styles
+ try
+ EchoLine = case os:cmd("echo -ne \"test\\ntest\"") of
+ "test\ntest" ->
+ "echo -ne \"a\\nbu\" | ";
+ _ ->
+ case os:cmd("echo \"test\\ntest\\c\"") of
+ "test\ntest" ->
+ "echo \"a\\nbu\\c\" | ";
+ _ ->
+ throw(skip)
+ end
+ end,
+ CommandLine1 = EchoLine ++
+ Erl++" -noshell -eval "
+ "'io:format(\"~p\",[io:get_line(\"\")]),"
+ "io:format(\"~p\",[io:get_line(\"\")]),"
+ "io:format(\"~p\",[io:get_line(\"\")]).' -run init stop",
+ case os:cmd(CommandLine1) of
+ "\"a\\n\"\"bu\"eof" ->
+ ok;
+ Other1 ->
+ exit({unexpected1,Other1})
+ end,
+ CommandLine2 = EchoLine ++
+ Erl++" -noshell -eval "
+ "'io:setopts([binary]),io:format(\"~p\",[io:get_line(\"\")]),"
+ "io:format(\"~p\",[io:get_line(\"\")]),"
+ "io:format(\"~p\",[io:get_line(\"\")]).' -run init stop",
+ case os:cmd(CommandLine2) of
+ "<<\"a\\n\">><<\"bu\">>eof" ->
+ ok;
+ Other2 ->
+ exit({unexpected2,Other2})
+ end
+ catch
+ throw:skip ->
+ {skipped,"unsupported echo program"}
+ end;
+ {_,_} ->
+ {skipped,"Only on linux"}
+ end.
+
+
+%%
+%% Tool for running interactive shell (stolen from the kernel
+%% test suite interactive_shell_SUITE)
+%%
+-undef(line).
+-define(line,).
+rtnode(C,N) ->
+ rtnode(C,N,[]).
+rtnode(Commands,Nodename,ErlPrefix) ->
+ rtnode(Commands,Nodename,ErlPrefix,[]).
+rtnode(Commands,Nodename,ErlPrefix,Extra) ->
+ ?line case get_progs() of
+ {error,_Reason} ->
+ ?line {skip,"No runerl present"};
+ {RunErl,ToErl,Erl} ->
+ ?line case create_tempdir() of
+ {error, Reason2} ->
+ ?line {skip, Reason2};
+ Tempdir ->
+ ?line SPid =
+ start_runerl_node(RunErl,ErlPrefix++Erl,
+ Tempdir,Nodename, Extra),
+ ?line CPid = start_toerl_server(ToErl,Tempdir),
+ ?line erase(getline_skipped),
+ ?line Res =
+ (catch get_and_put(CPid, Commands,1)),
+ ?line case stop_runerl_node(CPid) of
+ {error,_} ->
+ ?line CPid2 =
+ start_toerl_server
+ (ToErl,Tempdir),
+ ?line erase(getline_skipped),
+ ?line ok = get_and_put
+ (CPid2,
+ [{putline,[7]},
+ {sleep,
+ timeout(short)},
+ {putline,""},
+ {getline," -->"},
+ {putline,"s"},
+ {putline,"c"},
+ {putline,""}],1),
+ ?line stop_runerl_node(CPid2);
+ _ ->
+ ?line ok
+ end,
+ ?line wait_for_runerl_server(SPid),
+ ?line ok = rm_rf(Tempdir),
+ ?line ok = Res
+ end
+ end.
+
+timeout(long) ->
+ 2 * timeout(normal);
+timeout(short) ->
+ timeout(normal) div 10;
+timeout(normal) ->
+ 10000 * test_server:timetrap_scale_factor().
+
+
+%% start_noshell_node(Name) ->
+%% PADir = filename:dirname(code:which(?MODULE)),
+%% {ok, Node} = test_server:start_node(Name,slave,[{args," -noshell -pa "++
+%% PADir++" "}]),
+%% Node.
+%% stop_noshell_node(Node) ->
+%% test_server:stop_node(Node).
+
+
+rm_rf(Dir) ->
+ try
+ {ok,List} = file:list_dir(Dir),
+ Files = [filename:join([Dir,X]) || X <- List],
+ [case file:list_dir(Y) of
+ {error, enotdir} ->
+ ok = file:delete(Y);
+ _ ->
+ ok = rm_rf(Y)
+ end || Y <- Files],
+ ok = file:del_dir(Dir),
+ ok
+ catch
+ _:Exception -> {error, {Exception,Dir}}
+ end.
+
+
+get_and_put(_CPid,[],_) ->
+ ok;
+get_and_put(CPid, [{sleep, X}|T],N) ->
+ ?dbg({sleep, X}),
+ receive
+ after X ->
+ get_and_put(CPid,T,N+1)
+ end;
+get_and_put(CPid, [{getline, Match}|T],N) ->
+ ?dbg({getline, Match}),
+ CPid ! {self(), {get_line, timeout(normal)}},
+ receive
+ {get_line, timeout} ->
+ error_logger:error_msg("~p: getline timeout waiting for \"~s\" "
+ "(command number ~p, skipped: ~p)~n",
+ [?MODULE, Match,N,get(getline_skipped)]),
+ {error, timeout};
+ {get_line, Data} ->
+ ?dbg({data,Data}),
+ case lists:prefix(Match, Data) of
+ true ->
+ erase(getline_skipped),
+ get_and_put(CPid, T,N+1);
+ false ->
+ case get(getline_skipped) of
+ undefined ->
+ put(getline_skipped,[Data]);
+ List ->
+ put(getline_skipped,List ++ [Data])
+ end,
+ get_and_put(CPid, [{getline, Match}|T],N)
+ end
+ end;
+get_and_put(CPid, [{getline_re, Match}|T],N) ->
+ ?dbg({getline_re, Match}),
+ CPid ! {self(), {get_line, timeout(normal)}},
+ receive
+ {get_line, timeout} ->
+ error_logger:error_msg("~p: getline_re timeout waiting for \"~s\" "
+ "(command number ~p, skipped: ~p)~n",
+ [?MODULE, Match,N,get(getline_skipped)]),
+ {error, timeout};
+ {get_line, Data} ->
+ ?dbg({data,Data}),
+ case re:run(Data, Match,[{capture,none}]) of
+ match ->
+ erase(getline_skipped),
+ get_and_put(CPid, T,N+1);
+ _ ->
+ case get(getline_skipped) of
+ undefined ->
+ put(getline_skipped,[Data]);
+ List ->
+ put(getline_skipped,List ++ [Data])
+ end,
+ get_and_put(CPid, [{getline_re, Match}|T],N)
+ end
+ end;
+
+get_and_put(CPid, [{putline_raw, Line}|T],N) ->
+ ?dbg({putline_raw, Line}),
+ CPid ! {self(), {send_line, Line}},
+ Timeout = timeout(normal),
+ receive
+ {send_line, ok} ->
+ get_and_put(CPid, T,N+1)
+ after Timeout ->
+ error_logger:error_msg("~p: putline_raw timeout (~p) sending "
+ "\"~s\" (command number ~p)~n",
+ [?MODULE, Timeout, Line, N]),
+ {error, timeout}
+ end;
+
+get_and_put(CPid, [{putline, Line}|T],N) ->
+ ?dbg({putline, Line}),
+ CPid ! {self(), {send_line, Line}},
+ Timeout = timeout(normal),
+ receive
+ {send_line, ok} ->
+ get_and_put(CPid, [{getline, []}|T],N)
+ after Timeout ->
+ error_logger:error_msg("~p: putline timeout (~p) sending "
+ "\"~s\" (command number ~p)~n[~p]~n",
+ [?MODULE, Timeout, Line, N,get()]),
+ {error, timeout}
+ end.
+
+wait_for_runerl_server(SPid) ->
+ Ref = erlang:monitor(process, SPid),
+ Timeout = timeout(long),
+ receive
+ {'DOWN', Ref, process, SPid, _} ->
+ ok
+ after Timeout ->
+ {error, timeout}
+ end.
+
+
+
+stop_runerl_node(CPid) ->
+ Ref = erlang:monitor(process, CPid),
+ CPid ! {self(), kill_emulator},
+ Timeout = timeout(long),
+ receive
+ {'DOWN', Ref, process, CPid, noproc} ->
+ ok;
+ {'DOWN', Ref, process, CPid, normal} ->
+ ok;
+ {'DOWN', Ref, process, CPid, {error, Reason}} ->
+ {error, Reason}
+ after Timeout ->
+ {error, timeout}
+ end.
+
+get_progs() ->
+ case os:type() of
+ {unix,freebsd} ->
+ {error,"cant use run_erl on freebsd"};
+ {unix,openbsd} ->
+ {error,"cant use run_erl on openbsd"};
+ {unix,_} ->
+ case os:find_executable("run_erl") of
+ RE when is_list(RE) ->
+ case os:find_executable("to_erl") of
+ TE when is_list(TE) ->
+ case os:find_executable("erl") of
+ E when is_list(E) ->
+ {RE,TE,E};
+ _ ->
+ {error, "Could not find erl command"}
+ end;
+ _ ->
+ {error, "Could not find to_erl command"}
+ end;
+ _ ->
+ {error, "Could not find run_erl command"}
+ end;
+ _ ->
+ {error, "Not a unix OS"}
+ end.
+
+create_tempdir() ->
+ create_tempdir(filename:join(["/tmp","rtnode"++os:getpid()]),$A).
+
+create_tempdir(Dir,X) when X > $Z, X < $a ->
+ create_tempdir(Dir,$a);
+create_tempdir(Dir,X) when X > $z ->
+ Estr = lists:flatten(
+ io_lib:format("Unable to create ~s, reason eexist",
+ [Dir++[$z]])),
+ {error, Estr};
+create_tempdir(Dir0, Ch) ->
+ % Expect fairly standard unix.
+ Dir = Dir0++[Ch],
+ case file:make_dir(Dir) of
+ {error, eexist} ->
+ create_tempdir(Dir0, Ch+1);
+ {error, Reason} ->
+ Estr = lists:flatten(
+ io_lib:format("Unable to create ~s, reason ~p",
+ [Dir,Reason])),
+ {error,Estr};
+ ok ->
+ Dir
+ end.
+
+create_nodename() ->
+ create_nodename($A).
+
+create_nodename(X) when X > $Z, X < $a ->
+ create_nodename($a);
+create_nodename(X) when X > $z ->
+ {error,out_of_nodenames};
+create_nodename(X) ->
+ NN = "rtnode"++os:getpid()++[X],
+ case file:read_file_info(filename:join(["/tmp",NN])) of
+ {error,enoent} ->
+ Host = lists:nth(2,string:tokens(atom_to_list(node()),"@")),
+ NN++"@"++Host;
+ _ ->
+ create_nodename(X+1)
+ end.
+
+
+start_runerl_node(RunErl,Erl,Tempdir,Nodename,Extra) ->
+ XArg = case Nodename of
+ [] ->
+ [];
+ _ ->
+ " -sname "++(if is_atom(Nodename) -> atom_to_list(Nodename);
+ true -> Nodename
+ end)++
+ " -setcookie "++atom_to_list(erlang:get_cookie())
+ end,
+ XXArg = case Extra of
+ [] ->
+ [];
+ _ ->
+ " "++Extra
+ end,
+ spawn(fun() ->
+ os:cmd(RunErl++" "++Tempdir++"/ "++Tempdir++" \""++
+ Erl++XArg++XXArg++"\"")
+ end).
+
+start_toerl_server(ToErl,Tempdir) ->
+ Pid = spawn(?MODULE,toerl_server,[self(),ToErl,Tempdir]),
+ receive
+ {Pid,started} ->
+ Pid;
+ {Pid,error,Reason} ->
+ {error,Reason}
+ end.
+
+try_to_erl(_Command, 0) ->
+ {error, cannot_to_erl};
+try_to_erl(Command, N) ->
+ ?dbg({?LINE,N}),
+ Port = open_port({spawn, Command},[eof,{line,1000}]),
+ Timeout = timeout(normal) div 2,
+ receive
+ {Port, eof} ->
+ receive after Timeout ->
+ ok
+ end,
+ try_to_erl(Command, N-1)
+ after Timeout ->
+ ?dbg(Port),
+ Port
+ end.
+
+toerl_server(Parent,ToErl,Tempdir) ->
+ Port = try_to_erl(ToErl++" "++Tempdir++"/ 2>/dev/null",8),
+ case Port of
+ P when is_port(P) ->
+ Parent ! {self(),started};
+ {error,Other} ->
+ Parent ! {self(),error,Other},
+ exit(Other)
+ end,
+ case toerl_loop(Port,[]) of
+ normal ->
+ ok;
+ {error, Reason} ->
+ error_logger:error_msg("toerl_server exit with reason ~p~n",
+ [Reason]),
+ exit(Reason)
+ end.
+
+toerl_loop(Port,Acc) ->
+ ?dbg({toerl_loop, Port, Acc}),
+ receive
+ {Port,{data,{Tag0,Data}}} when is_port(Port) ->
+ ?dbg({?LINE,Port,{data,{Tag0,Data}}}),
+ case Acc of
+ [{noeol,Data0}|T0] ->
+ toerl_loop(Port,[{Tag0, Data0++Data}|T0]);
+ _ ->
+ toerl_loop(Port,[{Tag0,Data}|Acc])
+ end;
+ {Pid,{get_line,Timeout}} ->
+ case Acc of
+ [] ->
+ case get_data_within(Port,Timeout,[]) of
+ timeout ->
+ Pid ! {get_line, timeout},
+ toerl_loop(Port,[]);
+ {noeol,Data1} ->
+ Pid ! {get_line, timeout},
+ toerl_loop(Port,[{noeol,Data1}]);
+ {eol,Data2} ->
+ Pid ! {get_line, Data2},
+ toerl_loop(Port,[])
+ end;
+ [{noeol,Data3}] ->
+ case get_data_within(Port,Timeout,Data3) of
+ timeout ->
+ Pid ! {get_line, timeout},
+ toerl_loop(Port,Acc);
+ {noeol,Data4} ->
+ Pid ! {get_line, timeout},
+ toerl_loop(Port,[{noeol,Data4}]);
+ {eol,Data5} ->
+ Pid ! {get_line, Data5},
+ toerl_loop(Port,[])
+ end;
+ List ->
+ {NewAcc,[{eol,Data6}]} = lists:split(length(List)-1,List),
+ Pid ! {get_line,Data6},
+ toerl_loop(Port,NewAcc)
+ end;
+ {Pid, {send_line, Data7}} ->
+ Port ! {self(),{command, Data7++"\n"}},
+ Pid ! {send_line, ok},
+ toerl_loop(Port,Acc);
+ {_Pid, kill_emulator} ->
+ Port ! {self(),{command, "init:stop().\n"}},
+ Timeout1 = timeout(long),
+ receive
+ {Port,eof} ->
+ normal
+ after Timeout1 ->
+ {error, kill_timeout}
+ end;
+ {Port, eof} ->
+ {error, unexpected_eof};
+ Other ->
+ {error, {unexpected, Other}}
+ end.
+
+millistamp() ->
+ {Mega, Secs, Micros} = erlang:now(),
+ (Micros div 1000) + Secs * 1000 + Mega * 1000000000.
+
+get_data_within(Port, X, Acc) when X =< 0 ->
+ ?dbg({get_data_within, X, Acc, ?LINE}),
+ receive
+ {Port,{data,{Tag0,Data}}} ->
+ ?dbg({?LINE,Port,{data,{Tag0,Data}}}),
+ {Tag0, Acc++Data}
+ after 0 ->
+ case Acc of
+ [] ->
+ timeout;
+ Noeol ->
+ {noeol,Noeol}
+ end
+ end;
+
+
+get_data_within(Port, Timeout, Acc) ->
+ ?dbg({get_data_within, Timeout, Acc, ?LINE}),
+ T1 = millistamp(),
+ receive
+ {Port,{data,{noeol,Data}}} ->
+ ?dbg({?LINE,Port,{data,{noeol,Data}}}),
+ Elapsed = millistamp() - T1 + 1,
+ get_data_within(Port, Timeout - Elapsed, Acc ++ Data);
+ {Port,{data,{eol,Data1}}} ->
+ ?dbg({?LINE,Port,{data,{eol,Data1}}}),
+ {eol, Acc ++ Data1}
+ after Timeout ->
+ timeout
+ end.
+
+%%
+%% Test I/O-server
+%%
+
+start_io_server_proxy() ->
+ spawn_link(?MODULE,io_server_proxy,[#state{}]).
+
+proxy_getall(Pid) ->
+ req(Pid,{self(),getall}).
+proxy_setnext(Pid,Data) when is_list(Data) ->
+ req(Pid,{self(),next,Data}).
+proxy_quit(Pid) ->
+ req(Pid,{self(),quit}).
+
+req(Pid,Mess) ->
+ Pid ! Mess,
+ receive
+ {Pid, Answer} ->
+ Answer
+ after 5000 ->
+ exit(timeout)
+ end.
+
+io_server_proxy(State) ->
+ receive
+ {io_request, From, ReplyAs, Request} ->
+ case request(Request,State) of
+ {Tag, Reply, NewState} when Tag =:= ok; Tag =:= error ->
+ reply(From, ReplyAs, Reply),
+ io_server_proxy(NewState);
+ {stop, Reply, _NewState} ->
+ reply(From, ReplyAs, Reply),
+ exit(Reply)
+ end;
+ %% Private message
+ {From, next, Data} ->
+ From ! {self(), ok},
+ io_server_proxy(State#state{nxt = Data});
+ {From, getall} ->
+ From ! {self(), lists:reverse(State#state.q)},
+ io_server_proxy(State#state{q=[]});
+ {From, quit} ->
+ From ! {self(), lists:reverse(State#state.q)},
+ ok;
+ _Unknown ->
+ io_server_proxy(State)
+ end.
+
+reply(From, ReplyAs, Reply) ->
+ From ! {io_reply, ReplyAs, Reply}.
+
+request({put_chars, Encoding, Chars}, State) ->
+ {ok, ok, State#state{q=[{put_chars, Encoding, Chars} | State#state.q ]}};
+request({put_chars, Encoding, Module, Function, Args}, State) ->
+ {ok, ok, State#state{q=[{put_chars, Encoding, Module, Function, Args} |
+ State#state.q ]}};
+request({put_chars,Chars}, State) ->
+ {ok, ok, State#state{q=[{put_chars, Chars} | State#state.q ]}};
+request({put_chars,M,F,As}, State) ->
+ {ok, ok, State#state{q=[{put_chars, M,F,As} | State#state.q ]}};
+request({get_until, Encoding, Prompt, M, F, As}, State) ->
+ {ok, convert(State#state.nxt, Encoding, State#state.mode), State#state{nxt = eof, q = [{get_until, Encoding, Prompt, M, F, As} | State#state.q]}};
+request({get_chars, Encoding, Prompt, N}, State) ->
+ {ok, convert(State#state.nxt, Encoding, State#state.mode), State#state{nxt = eof,
+ q = [{get_chars, Encoding, Prompt, N} |
+ State#state.q]}};
+request({get_line, Encoding, Prompt}, State) ->
+ {ok, convert(State#state.nxt, Encoding, State#state.mode),
+ State#state{nxt = eof,
+ q = [{get_line, Encoding, Prompt} |
+ State#state.q]}};
+request({get_until, Prompt, M, F, As}, State) ->
+ {ok, convert(State#state.nxt, latin1, State#state.mode),
+ State#state{nxt = eof,
+ q = [{get_until, Prompt, M, F, As} | State#state.q]}};
+request({get_chars, Prompt, N}, State) ->
+ {ok, convert(State#state.nxt, latin1, State#state.mode),
+ State#state{nxt = eof,
+ q = [{get_chars, Prompt, N} |
+ State#state.q]}};
+request({get_line, Prompt}, State) ->
+ {ok, convert(State#state.nxt, latin1, State#state.mode),
+ State#state{nxt = eof,
+ q = [{get_line, Prompt} |
+ State#state.q]}};
+request({get_geomentry,_}, State) ->
+ {error, {error,enotsup}, State};
+request({setopts, Opts}, State) when Opts =:= [{binary, false}]; Opts =:= [list] ->
+ {ok, ok, State#state{q=[{setopts, Opts} | State#state.q ], mode = list}};
+request({setopts, Opts}, State) when Opts =:= [{binary, true}]; Opts =:= [binary] ->
+ {ok, ok, State#state{q=[{setopts, Opts} | State#state.q ], mode = binary}};
+request(getopts, State) ->
+ {ok, case State#state.mode of
+ list -> [{binary,false}];
+ binary -> [{binary, true}]
+ end, State#state{q=[getopts | State#state.q ]}};
+request({requests, Reqs}, State) ->
+ multi_request(Reqs, {ok, ok, State}).
+
+multi_request([R|Rs], {ok, _Res, State}) ->
+ multi_request(Rs, request(R, State));
+multi_request([_|_], Error) ->
+ Error;
+multi_request([], State) ->
+ State.
+
+convert(Atom,_,_) when is_atom(Atom) ->
+ Atom;
+convert(Data, unicode, list) ->
+ unicode:characters_to_list(Data,unicode);
+convert(Data, latin1, list) ->
+ try
+ L = unicode:characters_to_list(Data, unicode),
+ [ true = Ch =< 255 || Ch <- L ],
+ L
+ catch
+ _:_ ->
+ {error, {cannot_convert, unicode, latin1}}
+ end;
+convert(Data, unicode, binary) ->
+ unicode:characters_to_binary(Data,unicode,unicode);
+convert(Data, latin1, binary) ->
+ case unicode:characters_to_binary(Data, unicode, latin1) of
+ Bin when is_binary(Bin) ->
+ Bin;
+ _ ->
+ {error, {cannot_convert, unicode, latin1}}
+ end.
+
+hostname() ->
+ from($@, atom_to_list(node())).
+
+from(H, [H | T]) -> T;
+from(H, [_ | T]) -> from(H, T);
+from(_, []) -> [].
+
+chomp([]) ->
+ [];
+chomp([$\n]) ->
+ [];
+chomp([H|T]) ->
+ [H|chomp(T)];
+chomp(<<>>) ->
+ <<>>;
+chomp(<<$\n>>) ->
+ <<>>;
+chomp(<<Ch,Rest/binary>>) ->
+ X = chomp(Rest),
+ <<Ch,X/binary>>;
+chomp(Atom) ->
+ Atom.
diff --git a/lib/stdlib/test/io_proto_SUITE_data/external_utf16_big_bom.dat b/lib/stdlib/test/io_proto_SUITE_data/external_utf16_big_bom.dat
new file mode 100644
index 0000000000..82f99cbded
--- /dev/null
+++ b/lib/stdlib/test/io_proto_SUITE_data/external_utf16_big_bom.dat
Binary files differ
diff --git a/lib/stdlib/test/io_proto_SUITE_data/external_utf16_little_bom.dat b/lib/stdlib/test/io_proto_SUITE_data/external_utf16_little_bom.dat
new file mode 100644
index 0000000000..99b3970950
--- /dev/null
+++ b/lib/stdlib/test/io_proto_SUITE_data/external_utf16_little_bom.dat
Binary files differ
diff --git a/lib/stdlib/test/io_proto_SUITE_data/external_utf8_bom.dat b/lib/stdlib/test/io_proto_SUITE_data/external_utf8_bom.dat
new file mode 100644
index 0000000000..3c87ce519e
--- /dev/null
+++ b/lib/stdlib/test/io_proto_SUITE_data/external_utf8_bom.dat
@@ -0,0 +1 @@
+Återerövra \ No newline at end of file
diff --git a/lib/stdlib/test/io_proto_SUITE_data/testdata_latin1.dat b/lib/stdlib/test/io_proto_SUITE_data/testdata_latin1.dat
new file mode 100644
index 0000000000..a9ce7d28e1
--- /dev/null
+++ b/lib/stdlib/test/io_proto_SUITE_data/testdata_latin1.dat
@@ -0,0 +1,2 @@
+���
+���
diff --git a/lib/stdlib/test/io_proto_SUITE_data/testdata_utf16_big.dat b/lib/stdlib/test/io_proto_SUITE_data/testdata_utf16_big.dat
new file mode 100644
index 0000000000..c611508766
--- /dev/null
+++ b/lib/stdlib/test/io_proto_SUITE_data/testdata_utf16_big.dat
Binary files differ
diff --git a/lib/stdlib/test/io_proto_SUITE_data/testdata_utf16_big_bom.dat b/lib/stdlib/test/io_proto_SUITE_data/testdata_utf16_big_bom.dat
new file mode 100644
index 0000000000..e35436aa97
--- /dev/null
+++ b/lib/stdlib/test/io_proto_SUITE_data/testdata_utf16_big_bom.dat
Binary files differ
diff --git a/lib/stdlib/test/io_proto_SUITE_data/testdata_utf16_little.dat b/lib/stdlib/test/io_proto_SUITE_data/testdata_utf16_little.dat
new file mode 100644
index 0000000000..4e2bdfa7cd
--- /dev/null
+++ b/lib/stdlib/test/io_proto_SUITE_data/testdata_utf16_little.dat
Binary files differ
diff --git a/lib/stdlib/test/io_proto_SUITE_data/testdata_utf16_little_bom.dat b/lib/stdlib/test/io_proto_SUITE_data/testdata_utf16_little_bom.dat
new file mode 100644
index 0000000000..e1960d2261
--- /dev/null
+++ b/lib/stdlib/test/io_proto_SUITE_data/testdata_utf16_little_bom.dat
Binary files differ
diff --git a/lib/stdlib/test/io_proto_SUITE_data/testdata_utf32_big.dat b/lib/stdlib/test/io_proto_SUITE_data/testdata_utf32_big.dat
new file mode 100644
index 0000000000..c9170fba93
--- /dev/null
+++ b/lib/stdlib/test/io_proto_SUITE_data/testdata_utf32_big.dat
Binary files differ
diff --git a/lib/stdlib/test/io_proto_SUITE_data/testdata_utf32_big_bom.dat b/lib/stdlib/test/io_proto_SUITE_data/testdata_utf32_big_bom.dat
new file mode 100644
index 0000000000..e95dcec297
--- /dev/null
+++ b/lib/stdlib/test/io_proto_SUITE_data/testdata_utf32_big_bom.dat
Binary files differ
diff --git a/lib/stdlib/test/io_proto_SUITE_data/testdata_utf32_little.dat b/lib/stdlib/test/io_proto_SUITE_data/testdata_utf32_little.dat
new file mode 100644
index 0000000000..8eb6eb43bb
--- /dev/null
+++ b/lib/stdlib/test/io_proto_SUITE_data/testdata_utf32_little.dat
Binary files differ
diff --git a/lib/stdlib/test/io_proto_SUITE_data/testdata_utf32_little_bom.dat b/lib/stdlib/test/io_proto_SUITE_data/testdata_utf32_little_bom.dat
new file mode 100644
index 0000000000..816f19c0ba
--- /dev/null
+++ b/lib/stdlib/test/io_proto_SUITE_data/testdata_utf32_little_bom.dat
Binary files differ
diff --git a/lib/stdlib/test/io_proto_SUITE_data/testdata_utf8.dat b/lib/stdlib/test/io_proto_SUITE_data/testdata_utf8.dat
new file mode 100644
index 0000000000..1fcb997763
--- /dev/null
+++ b/lib/stdlib/test/io_proto_SUITE_data/testdata_utf8.dat
@@ -0,0 +1 @@
+тхе биг ред фоь хас соь Τηε βιγ ρεδ σοχ αρε φοχεσ \ No newline at end of file
diff --git a/lib/stdlib/test/io_proto_SUITE_data/testdata_utf8_bom.dat b/lib/stdlib/test/io_proto_SUITE_data/testdata_utf8_bom.dat
new file mode 100644
index 0000000000..5a38c1519e
--- /dev/null
+++ b/lib/stdlib/test/io_proto_SUITE_data/testdata_utf8_bom.dat
@@ -0,0 +1 @@
+тхе биг ред фоь хас соь Τηε βιγ ρεδ σοχ αρε φοχεσ \ No newline at end of file
diff --git a/lib/stdlib/test/lists_SUITE.erl b/lib/stdlib/test/lists_SUITE.erl
new file mode 100644
index 0000000000..0089e874c8
--- /dev/null
+++ b/lib/stdlib/test/lists_SUITE.erl
@@ -0,0 +1,2657 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%%----------------------------------------------------------------
+%%% Purpose: Test suite for the 'lists' module.
+%%%-----------------------------------------------------------------
+
+-module(lists_SUITE).
+-include("test_server.hrl").
+
+
+% Default timetrap timeout (set in init_per_testcase).
+% This should be set relatively high (10-15 times the expected
+% max testcasetime).
+-define(default_timeout, ?t:minutes(4)).
+
+% Test server specific exports
+-export([all/1]).
+-export([init_per_testcase/2, fin_per_testcase/2]).
+
+% Test cases must be exported.
+-export([member/1, reverse/1,
+ keymember/1, keysearch_keyfind/1,
+ keystore/1, keytake/1,
+ append/1, append_1/1, append_2/1,
+ seq/1, seq_loop/1, seq_2/1, seq_3/1, seq_2_e/1, seq_3_e/1,
+ sublist/1, flatten/1,
+ sublist_2/1, sublist_3/1, sublist_2_e/1, sublist_3_e/1,
+ flatten_1/1, flatten_2/1, flatten_1_e/1, flatten_2_e/1,
+ dropwhile/1,
+ sort/1, sort_1/1, sort_stable/1, merge/1, rmerge/1, sort_rand/1,
+ usort/1, usort_1/1, usort_stable/1, umerge/1, rumerge/1,usort_rand/1,
+ keymerge/1, rkeymerge/1,
+ keysort/1, keysort_1/1, keysort_i/1, keysort_stable/1,
+ keysort_rand/1, keysort_error/1,
+ ukeymerge/1, rukeymerge/1,
+ ukeysort/1, ukeysort_1/1, ukeysort_i/1, ukeysort_stable/1,
+ ukeysort_rand/1, ukeysort_error/1,
+ funmerge/1, rfunmerge/1,
+ funsort/1, funsort_1/1, funsort_stable/1, funsort_rand/1,
+ funsort_error/1,
+ ufunmerge/1, rufunmerge/1,
+ ufunsort/1, ufunsort_1/1, ufunsort_stable/1, ufunsort_rand/1,
+ ufunsort_error/1,
+ zip_unzip/1, zip_unzip3/1, zipwith/1, zipwith3/1,
+ filter_partition/1,
+ tickets/1, otp_5939/1, otp_6023/1, otp_6606/1, otp_7230/1,
+ suffix/1, subtract/1]).
+
+%% Sort randomized lists until stopped.
+%%
+%% If you update some of the sort or merge functions, you should
+%% definitely let sort_loop work for a couple of hours or days. Try
+%% both sort_loop/0 and sort_loop/1 with a small argument (30-50 say).
+
+-export([sort_loop/0, sort_loop/1, sloop/1]).
+
+%% Internal export.
+-export([make_fun/1]).
+
+%%
+%% all/1
+%%
+all(doc) ->
+ [];
+all(suite) ->
+ [append, reverse, member, keymember, keysearch_keyfind, keystore, keytake,
+ dropwhile,
+ sort, usort, keysort, ukeysort,
+ funsort, ufunsort, sublist, flatten, seq,
+ zip_unzip, zip_unzip3, zipwith, zipwith3,
+ filter_partition, tickets, suffix, subtract].
+
+init_per_testcase(_Case, Config) ->
+ ?line Dog=test_server:timetrap(?default_timeout),
+ [{watchdog, Dog}|Config].
+
+fin_per_testcase(_Case, Config) ->
+ Dog=?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+%
+% Test cases starts here.
+%
+append(doc) ->
+ ["Tests lists:append/1 & lists:append/2"];
+append(suite) ->
+ [append_1, append_2].
+
+append_1(doc) -> [];
+append_1(suite) -> [];
+append_1(Config) when is_list(Config) ->
+ ?line "abcdef"=lists:append(["abc","def"]),
+ ?line [hej, du,[glade, [bagare]]]=
+ lists:append([[hej], [du], [[glade, [bagare]]]]),
+ ?line [10, [elem]]=lists:append([[10], [[elem]]]),
+ ok.
+
+append_2(doc) -> [];
+append_2(suite) -> [];
+append_2(Config) when is_list(Config) ->
+ ?line "abcdef"=lists:append("abc", "def"),
+ ?line [hej, du]=lists:append([hej], [du]),
+ ?line [10, [elem]]=lists:append([10], [[elem]]),
+ ok.
+
+reverse(suite) ->
+ [];
+reverse(doc) ->
+ ["Tests the lists:reverse() implementation. The function is "
+ "`non-blocking', and only processes a fixed number of elements "
+ "at a time."];
+reverse(Config) when is_list(Config) ->
+ ?line reverse_test(0),
+ ?line reverse_test(1),
+ ?line reverse_test(2),
+ ?line reverse_test(128),
+ ?line reverse_test(256),
+ ?line reverse_test(1000),
+ ?line reverse_test(1998),
+ ?line reverse_test(1999),
+ ?line reverse_test(2000),
+ ?line reverse_test(2001),
+ ?line reverse_test(3998),
+ ?line reverse_test(3999),
+ ?line reverse_test(4000),
+ ?line reverse_test(4001),
+ ?line reverse_test(60001),
+ ?line reverse_test(100007),
+ ok.
+
+reverse_test(0) ->
+ case lists:reverse([]) of
+ [] ->
+ ok;
+ _Other ->
+ error
+ end;
+reverse_test(Num) ->
+ List0 = ['The Element'|lists:duplicate(Num, 'Ele')],
+ List = lists:reverse(List0),
+ ['Ele'|_] = List,
+ 'The Element' = lists:last(List),
+ List0 = lists:reverse(List),
+ ok.
+
+member(doc) ->
+ ["Tests the lists:member() implementation."
+ "This test case depends on lists:reverse() to work, "
+ "wich is tested in a separate test case."];
+member(Config) when is_list(Config) ->
+ ?line {'EXIT',{badarg,_}} = (catch lists:member(45, {a,b,c})),
+ ?line {'EXIT',{badarg,_}} = (catch lists:member(45, [0|non_list_tail])),
+ ?line false = lists:member(4233, []),
+ ?line member_test(1),
+ ?line member_test(100),
+ ?line member_test(256),
+ ?line member_test(1000),
+ ?line member_test(1998),
+ ?line member_test(1999),
+ ?line member_test(2000),
+ ?line member_test(2001),
+ ?line member_test(3998),
+ ?line member_test(3999),
+ ?line member_test(4000),
+ ?line member_test(4001),
+ ?line member_test(100008),
+ ok.
+
+member_test(Num) ->
+ List0 = ['The Element'|lists:duplicate(Num, 'Elem')],
+ true = lists:member('The Element', List0),
+ true = lists:member('Elem', List0),
+ false = lists:member(arne_anka, List0),
+ false = lists:member({a,b,c}, List0),
+ List = lists:reverse(List0),
+ true = lists:member('The Element', List),
+ true = lists:member('Elem', List),
+ false = lists:member(arne_anka, List),
+ false = lists:member({a,b,c}, List).
+
+keymember(Config) when is_list(Config) ->
+ ?line false = lists:keymember(anything_goes, 1, []),
+ ?line {'EXIT',{badarg,_}} = (catch lists:keymember(anything_goes, -1, [])),
+ ?line {'EXIT',{badarg,_}} = (catch lists:keymember(anything_goes, 0, [])),
+ ?line {'EXIT',{badarg,_}} = (catch lists:keymember(anything_goes, 1, {1,2,3})),
+ List = [{52.0,a},{-19,b,c},{37.5,d},an_atom,42.0,{39},{45,{x,y,z}}],
+
+ ?line false = lists:keymember(333, 5, List),
+ ?line false = lists:keymember(333, 999, List),
+ ?line false = lists:keymember(37, 1, List),
+
+ ?line true = lists:keymember(52.0, 1, List),
+ ?line true = lists:keymember(52, 1, List),
+ ?line true = lists:keymember(-19, 1, List),
+ ?line true = lists:keymember(-19.0, 1, List),
+ ?line true = lists:keymember(37.5, 1, List),
+ ?line true = lists:keymember(39, 1, List),
+ ?line true = lists:keymember(39.0, 1, List),
+ ?line true = lists:keymember(45, 1, List),
+ ?line true = lists:keymember(45.0, 1, List),
+
+ ?line true = lists:keymember(a, 2, List),
+ ?line true = lists:keymember(b, 2, List),
+ ?line true = lists:keymember(c, 3, List),
+ ?line true = lists:keymember(d, 2, List),
+ ?line true = lists:keymember({x,y,z}, 2, List),
+
+ ?line Long0 = lists:seq(1, 100007),
+ ?line false = lists:keymember(kalle, 1, Long0),
+ ?line Long = lists:foldl(fun(E, A) -> [{1/E,E}|A] end, [], Long0),
+ ?line true = lists:keymember(1, 2, Long),
+ ?line true = lists:keymember(2, 2, Long),
+ ?line true = lists:keymember(1.0, 2, Long),
+ ?line true = lists:keymember(2.0, 2, Long),
+ ?line true = lists:keymember(100006, 2, Long),
+ ok.
+
+keysearch_keyfind(Config) when is_list(Config) ->
+ ?line false = key_search_find(anything_goes, 1, []),
+ ?line {'EXIT',{badarg,_}} = (catch key_search_find(anything_goes, -1, [])),
+ ?line {'EXIT',{badarg,_}} = (catch key_search_find(anything_goes, 0, [])),
+ ?line {'EXIT',{badarg,_}} = (catch key_search_find(anything_goes, 1, {1,2,3})),
+
+ First = {x,42.0},
+ Second = {y,-77},
+ Third = {z,[a,b,c],{5.0}},
+ List = [First,Second,Third],
+
+ ?line false = key_search_find(333, 1, []),
+ ?line false = key_search_find(333, 5, List),
+ ?line false = key_search_find(333, 999, List),
+ ?line false = key_search_find(37, 1, List),
+
+ ?line {value,First} = key_search_find(42, 2, List),
+ ?line {value,First} = key_search_find(42.0, 2, List),
+
+ ?line {value,Second} = key_search_find(-77, 2, List),
+ ?line {value,Second} = key_search_find(-77.0, 2, List),
+
+ ?line {value,Third} = key_search_find(z, 1, List),
+ ?line {value,Third} = key_search_find([a,b,c], 2, List),
+ ?line {value,Third} = key_search_find({5}, 3, List),
+ ?line {value,Third} = key_search_find({5.0}, 3, List),
+
+ ?line Long0 = lists:seq(1, 100007),
+ ?line false = key_search_find(kalle, 1, Long0),
+ ?line Long = lists:foldl(fun(E, A) -> [{1/E,float(E)}|A] end, [], Long0),
+ ?line {value,{_,1.0}} = key_search_find(1, 2, Long),
+ ?line {value,{_,1.0}} = key_search_find(1.0, 2, Long),
+ ?line {value,{_,2.0}} = key_search_find(2, 2, Long),
+ ?line {value,{_,2.0}} = key_search_find(2.0, 2, Long),
+ ?line {value,{_,33988.0}} = key_search_find(33988, 2, Long),
+ ?line {value,{_,33988.0}} = key_search_find(33988.0, 2, Long),
+ ok.
+
+%% Test both lists:keysearch/3 and lists:keyfind/3. The only
+%% difference between these two functions is that lists:keysearch/3
+%% wraps a successfully returned tuple in a value tuple.
+%%
+key_search_find(Key, Pos, List) ->
+ case lists:keyfind(Key, Pos, List) of
+ false ->
+ false = lists:keysearch(Key, Pos, List);
+ Tuple when is_tuple(Tuple) ->
+ {value,Tuple} = lists:keysearch(Key, Pos, List)
+ end.
+
+dropwhile(Config) when is_list(Config) ->
+ ?line F = fun(C) -> C =:= $@ end,
+
+ ?line [] = lists:dropwhile(F, []),
+ ?line [a] = lists:dropwhile(F, [a]),
+ ?line [a,b] = lists:dropwhile(F, [a,b]),
+ ?line [a,b,c] = lists:dropwhile(F, [a,b,c]),
+
+ ?line [] = lists:dropwhile(F, [$@]),
+ ?line [] = lists:dropwhile(F, [$@,$@]),
+ ?line [a,$@] = lists:dropwhile(F, [$@,a,$@]),
+
+ ?line [$k] = lists:dropwhile(F, [$@,$k]),
+ ?line [$k,$l] = lists:dropwhile(F, [$@,$@,$k,$l]),
+ ?line [a] = lists:dropwhile(F, [$@,$@,$@,a]),
+
+ ?line [a,$@,b] = lists:dropwhile(F, [$@,a,$@,b]),
+ ?line [a,$@,b] = lists:dropwhile(F, [$@,$@,a,$@,b]),
+ ?line [a,$@,b] = lists:dropwhile(F, [$@,$@,$@,a,$@,b]),
+
+ Long = lists:seq(1, 1024),
+ Shorter = lists:seq(800, 1024),
+
+ ?line Shorter = lists:dropwhile(fun(E) -> E < 800 end, Long),
+
+ ok.
+
+keystore(doc) ->
+ ["OTP-XXX."];
+keystore(suite) -> [];
+keystore(Config) when is_list(Config) ->
+ ?line {'EXIT',_} = (catch lists:keystore(key, 0, [], {1})),
+ ?line {'EXIT',_} = (catch lists:keystore(key, 1, {}, {})),
+ ?line {'EXIT',_} = (catch lists:keystore(key, 1, {a,b}, {})),
+ ?line {'EXIT', _} = (catch lists:keystore(a, 2, [{1,a}], b)),
+ T = {k,17},
+ ?line [T] = lists:keystore(a, 2, [], T),
+ ?line [{1,a},{2,b},{k,17}] = lists:keystore(c, 2, [{1,a},{2,b}],T),
+ L = [{1,a},{2,b},{3,c}],
+ ?line [{k,17},{2,b},{3,c}] = lists:keystore(a, 2, L, T),
+ ?line [{1,a},{k,17},{3,c}] = lists:keystore(b, 2, L, T),
+ ?line [{1,a},{2,b},{k,17}] = lists:keystore(c, 2, L, T),
+ ?line [{2,b}] = lists:keystore(a, 2, [{1,a}], {2,b}),
+ ?line [{1,a}] = lists:keystore(foo, 1, [], {1,a}),
+ ok.
+
+keytake(doc) ->
+ ["OTP-XXX."];
+keytake(suite) -> [];
+keytake(Config) when is_list(Config) ->
+ ?line {'EXIT',_} = (catch lists:keytake(key, 0, [])),
+ ?line {'EXIT',_} = (catch lists:keytake(key, 1, {})),
+ ?line {'EXIT',_} = (catch lists:keytake(key, 1, {a,b})),
+ ?line false = lists:keytake(key, 2, [{a}]),
+ ?line false = lists:keytake(key, 1, [a]),
+ ?line false = lists:keytake(k, 1, []),
+ ?line false = lists:keytake(k, 1, [{a},{b},{c}]),
+ L = [{a,1},{b,2},{c,3}],
+ ?line {value,{a,1},[{b,2},{c,3}]} = lists:keytake(1, 2, L),
+ ?line {value,{b,2},[{a,1},{c,3}]} = lists:keytake(2, 2, L),
+ ?line {value,{c,3},[{a,1},{b,2}]} = lists:keytake(3, 2, L),
+ ?line false = lists:keytake(4, 2, L),
+ ok.
+
+sort(doc) ->
+ ["Tests merge functions and lists:sort/1"];
+sort(suite) ->
+ %% [merge, rmerge, sort_1, sort_rand, sort_stable].
+ [merge, rmerge, sort_1, sort_rand].
+
+merge(doc) -> ["merge functions"];
+merge(suite) -> [];
+merge(Config) when is_list(Config) ->
+
+ %% merge list of lists
+ ?line [] = lists:merge([]),
+ ?line [] = lists:merge([[]]),
+ ?line [] = lists:merge([[],[]]),
+ ?line [] = lists:merge([[],[],[]]),
+ ?line [1] = lists:merge([[1]]),
+ ?line [1,1,2,2] = lists:merge([[1,2],[1,2]]),
+ ?line [1] = lists:merge([[1],[],[]]),
+ ?line [1] = lists:merge([[],[1],[]]),
+ ?line [1] = lists:merge([[],[],[1]]),
+ ?line [1,2] = lists:merge([[1],[2],[]]),
+ ?line [1,2] = lists:merge([[1],[],[2]]),
+ ?line [1,2] = lists:merge([[],[1],[2]]),
+ ?line [1,2,3,4,5,6] = lists:merge([[1,2],[],[5,6],[],[3,4],[]]),
+ ?line [1,2,3,4] = lists:merge([[4],[3],[2],[1]]),
+ ?line [1,2,3,4,5] = lists:merge([[1],[2],[3],[4],[5]]),
+ ?line [1,2,3,4,5,6] = lists:merge([[1],[2],[3],[4],[5],[6]]),
+ ?line [1,2,3,4,5,6,7,8,9] =
+ lists:merge([[1],[2],[3],[4],[5],[6],[7],[8],[9]]),
+ Seq = lists:seq(1,100),
+ ?line true = Seq == lists:merge(lists:map(fun(E) -> [E] end, Seq)),
+
+ Two = [1,2],
+ Six = [1,2,3,4,5,6],
+
+ %% 2-way merge
+ ?line [] = lists:merge([], []),
+ ?line Two = lists:merge(Two, []),
+ ?line Two = lists:merge([], Two),
+ ?line Six = lists:merge([1,3,5], [2,4,6]),
+ ?line Six = lists:merge([2,4,6], [1,3,5]),
+ ?line Six = lists:merge([1,2,3], [4,5,6]),
+ ?line Six = lists:merge([4,5,6], [1,2,3]),
+ ?line Six = lists:merge([1,2,5],[3,4,6]),
+ ?line [1,2,3,5,7] = lists:merge([1,3,5,7], [2]),
+ ?line [1,2,3,4,5,7] = lists:merge([1,3,5,7], [2,4]),
+ ?line [1,2,3,4,5,6,7] = lists:merge([1,3,5,7], [2,4,6]),
+ ?line [1,2,3,5,7] = lists:merge([2], [1,3,5,7]),
+ ?line [1,2,3,4,5,7] = lists:merge([2,4], [1,3,5,7]),
+ ?line [1,2,3,4,5,6,7] = lists:merge([2,4,6], [1,3,5,7]),
+
+ %% 3-way merge
+ ?line [] = lists:merge3([], [], []),
+ ?line Two = lists:merge3([], [], Two),
+ ?line Two = lists:merge3([], Two, []),
+ ?line Two = lists:merge3(Two, [], []),
+ ?line Six = lists:merge3([], [1,3,5], [2,4,6]),
+ ?line Six = lists:merge3([1,3,5], [], [2,4,6]),
+ ?line Six = lists:merge3([1,3,5], [2,4,6], []),
+ ?line Nine = lists:merge3([1,4,7],[2,5,8],[3,6,9]),
+ ?line Nine = lists:merge3([1,4,7],[3,6,9],[2,5,8]),
+ ?line Nine = lists:merge3([3,6,9],[1,4,7],[2,5,8]),
+ ?line Nine = lists:merge3([4,5,6],[1,2,3],[7,8,9]),
+ ?line Nine = lists:merge3([1,2,3],[4,5,6],[7,8,9]),
+ ?line Nine = lists:merge3([7,8,9],[4,5,6],[1,2,3]),
+ ?line Nine = lists:merge3([4,5,6],[7,8,9],[1,2,3]),
+
+ ok.
+
+rmerge(doc) -> ["reverse merge functions"];
+rmerge(suite) -> [];
+rmerge(Config) when is_list(Config) ->
+
+ Two = [2,1],
+ Six = [6,5,4,3,2,1],
+
+ %% 2-way reversed merge
+ ?line [] = lists:rmerge([], []),
+ ?line Two = lists:rmerge(Two, []),
+ ?line Two = lists:rmerge([], Two),
+ ?line Six = lists:rmerge([5,3,1], [6,4,2]),
+ ?line Six = lists:rmerge([6,4,2], [5,3,1]),
+ ?line Six = lists:rmerge([3,2,1], [6,5,4]),
+ ?line Six = lists:rmerge([6,5,4], [3,2,1]),
+ ?line Six = lists:rmerge([4,3,2],[6,5,1]),
+ ?line [7,6,5,3,1] = lists:rmerge([7,5,3,1], [6]),
+ ?line [7,6,5,4,3,1] = lists:rmerge([7,5,3,1], [6,4]),
+ ?line [7,6,5,4,3,2,1] = lists:rmerge([7,5,3,1], [6,4,2]),
+ ?line [7,5,3,2,1] = lists:rmerge([2], [7,5,3,1]),
+ ?line [7,5,4,3,2,1] = lists:rmerge([4,2], [7,5,3,1]),
+ ?line [7,6,5,4,3,2,1] = lists:rmerge([6,4,2], [7,5,3,1]),
+
+ Nine = [9,8,7,6,5,4,3,2,1],
+
+ %% 3-way reversed merge
+ ?line [] = lists:rmerge3([], [], []),
+ ?line Two = lists:rmerge3([], [], Two),
+ ?line Two = lists:rmerge3([], Two, []),
+ ?line Two = lists:rmerge3(Two, [], []),
+ ?line Six = lists:rmerge3([], [5,3,1], [6,4,2]),
+ ?line Six = lists:rmerge3([5,3,1], [], [6,4,2]),
+ ?line Six = lists:rmerge3([5,3,1], [6,4,2], []),
+ ?line Nine = lists:rmerge3([7,4,1],[8,5,2],[9,6,3]),
+ ?line Nine = lists:rmerge3([7,4,1],[9,6,3],[8,5,2]),
+ ?line Nine = lists:rmerge3([9,6,3],[7,4,1],[8,5,2]),
+ ?line Nine = lists:rmerge3([6,5,4],[3,2,1],[9,8,7]),
+ ?line Nine = lists:rmerge3([3,2,1],[6,5,4],[9,8,7]),
+ ?line Nine = lists:rmerge3([9,8,7],[6,5,4],[3,2,1]),
+ ?line Nine = lists:rmerge3([6,5,4],[9,8,7],[3,2,1]),
+
+ ok.
+
+sort_1(doc) -> ["sort/1"];
+sort_1(suite) -> [];
+sort_1(Config) when is_list(Config) ->
+ ?line [] = lists:sort([]),
+ ?line [a] = lists:sort([a]),
+ ?line [a,a] = lists:sort([a,a]),
+ ?line [a,b] = lists:sort([a,b]),
+ ?line [a,b] = lists:sort([b,a]),
+ ?line [1,1] = lists:sort([1,1]),
+ ?line [1,1,2,3] = lists:sort([1,1,3,2]),
+ ?line [1,2,3,3] = lists:sort([3,3,1,2]),
+ ?line [1,1,1,1] = lists:sort([1,1,1,1]),
+ ?line [1,1,1,2,2,2,3,3,3] = lists:sort([3,3,3,2,2,2,1,1,1]),
+ ?line [1,1,1,2,2,2,3,3,3] = lists:sort([1,1,1,2,2,2,3,3,3]),
+
+ ?line lists:foreach(fun check/1, perms([1,2,3])),
+ ?line lists:foreach(fun check/1, perms([1,2,3,4,5,6,7,8])),
+ ok.
+
+sort_rand(doc) -> ["sort/1 on big randomized lists"];
+sort_rand(suite) -> [];
+sort_rand(Config) when is_list(Config) ->
+ ?line ok = check(biglist(10)),
+ ?line ok = check(biglist(100)),
+ ?line ok = check(biglist(1000)),
+ ?line ok = check(biglist(10000)),
+ ok.
+
+%% sort/1 was really stable for a while - the order of equal elements
+%% was kept - but since the performance suffered a bit, this "feature"
+%% was removed.
+sort_stable(doc) -> ["sort/1 should be stable for equal terms."];
+sort_stable(suite) -> [];
+sort_stable(Config) when is_list(Config) ->
+ ?line ok = check_stability(bigfunlist(10)),
+ ?line ok = check_stability(bigfunlist(100)),
+ ?line ok = check_stability(bigfunlist(1000)),
+ ?line case erlang:system_info(modified_timing_level) of
+ undefined -> ok = check_stability(bigfunlist(10000));
+ _ -> ok
+ end,
+ ok.
+
+check([]) ->
+ ok;
+check(L) ->
+ S = lists:sort(L),
+ case {length(L) == length(S), check(hd(S), tl(S))} of
+ {true,ok} ->
+ ok;
+ _ ->
+ io:format("~w~n", [L]),
+ erlang:error(check)
+ end.
+
+check(_A, []) ->
+ ok;
+check(A, [B | L]) when A =< B ->
+ check(B, L);
+check(_A, _L) ->
+ no.
+
+%% The check that sort/1 is stable is no longer used.
+%% Equal elements are no longer always kept in order.
+check_stability(L) ->
+ S = lists:sort(L),
+ LP = explicit_pid(L),
+ SP = explicit_pid(S),
+ check_sorted(1, 2, LP, SP).
+
+explicit_pid(L) ->
+ lists:reverse(expl_pid(L, [])).
+
+expl_pid([{I,F} | T], L) when is_function(F) ->
+ expl_pid(T, [{I,fun_pid(F)} | L]);
+expl_pid([], L) ->
+ L.
+
+usort(doc) ->
+ ["Tests unique merge functions and lists:usort/1"];
+usort(suite) ->
+ [umerge, rumerge, usort_1, usort_rand, usort_stable].
+
+usort_1(suite) -> [];
+usort_1(doc) -> [""];
+usort_1(Conf) when is_list(Conf) ->
+ ?line [] = lists:usort([]),
+ ?line [1] = lists:usort([1]),
+ ?line [1] = lists:usort([1,1]),
+ ?line [1] = lists:usort([1,1,1,1,1]),
+ ?line [1,2] = lists:usort([1,2]),
+ ?line [1,2] = lists:usort([1,2,1]),
+ ?line [1,2] = lists:usort([1,2,2]),
+ ?line [1,2,3] = lists:usort([1,3,2]),
+ ?line [1,3] = lists:usort([3,1,3]),
+ ?line [0,1,3] = lists:usort([3,1,0]),
+ ?line [1,2,3] = lists:usort([3,1,2]),
+ ?line [1,2] = lists:usort([2,1,1]),
+ ?line [1,2] = lists:usort([2,1]),
+ ?line [0,3,4,8,9] = lists:usort([3,8,9,0,9,4]),
+
+ ?line lists:foreach(fun ucheck/1, perms([1,2,3])),
+ ?line lists:foreach(fun ucheck/1, perms([1,2,3,4,5,6,2,1])),
+
+ ok.
+
+umerge(suite) -> [];
+umerge(doc) -> [""];
+umerge(Conf) when is_list(Conf) ->
+ %% merge list of lists
+ ?line [] = lists:umerge([]),
+ ?line [] = lists:umerge([[]]),
+ ?line [] = lists:umerge([[],[]]),
+ ?line [] = lists:umerge([[],[],[]]),
+ ?line [1] = lists:umerge([[1]]),
+ ?line [1,2] = lists:umerge([[1,2],[1,2]]),
+ ?line [1] = lists:umerge([[1],[],[]]),
+ ?line [1] = lists:umerge([[],[1],[]]),
+ ?line [1] = lists:umerge([[],[],[1]]),
+ ?line [1,2] = lists:umerge([[1],[2],[]]),
+ ?line [1,2] = lists:umerge([[1],[],[2]]),
+ ?line [1,2] = lists:umerge([[],[1],[2]]),
+ ?line [1,2,3,4,5,6] = lists:umerge([[1,2],[],[5,6],[],[3,4],[]]),
+ ?line [1,2,3,4] = lists:umerge([[4],[3],[2],[1]]),
+ ?line [1,2,3,4,5] = lists:umerge([[1],[2],[3],[4],[5]]),
+ ?line [1,2,3,4,5,6] = lists:umerge([[1],[2],[3],[4],[5],[6]]),
+ ?line [1,2,3,4,5,6,7,8,9] =
+ lists:umerge([[1],[2],[3],[4],[5],[6],[7],[8],[9]]),
+ ?line [1,2,4,6,8] = lists:umerge([[1,2],[2,4,6,8]]),
+ Seq = lists:seq(1,100),
+ ?line true = Seq == lists:umerge(lists:map(fun(E) -> [E] end, Seq)),
+
+ Two = [1,2],
+ Six = [1,2,3,4,5,6],
+
+ %% 2-way unique merge
+ ?line [] = lists:umerge([], []),
+ ?line Two = lists:umerge(Two, []),
+ ?line Two = lists:umerge([], Two),
+ ?line Six = lists:umerge([1,3,5], [2,4,6]),
+ ?line Six = lists:umerge([2,4,6], [1,3,5]),
+ ?line Six = lists:umerge([1,2,3], [4,5,6]),
+ ?line Six = lists:umerge([4,5,6], [1,2,3]),
+ ?line Six = lists:umerge([1,2,5],[3,4,6]),
+ ?line [1,2,3,5,7] = lists:umerge([1,3,5,7], [2]),
+ ?line [1,2,3,4,5,7] = lists:umerge([1,3,5,7], [2,4]),
+ ?line [1,2,3,4,5,6,7] = lists:umerge([1,3,5,7], [2,4,6]),
+ ?line [1,2,3,5,7] = lists:umerge([2], [1,3,5,7]),
+ ?line [1,2,3,4,5,7] = lists:umerge([2,4], [1,3,5,7]),
+ ?line [1,2,3,4,5,6,7] = lists:umerge([2,4,6], [1,3,5,7]),
+
+ ?line [1,2,3,5,7] = lists:umerge([1,2,3,5,7], [2]),
+ ?line [1,2,3,4,5,7] = lists:umerge([1,2,3,4,5,7], [2,4]),
+ ?line [1,2,3,4,5,6,7] = lists:umerge([1,2,3,4,5,6,7], [2,4,6]),
+ ?line [1,2,3,5,7] = lists:umerge([2], [1,2,3,5,7]),
+ ?line [1,2,3,4,5,7] = lists:umerge([2,4], [1,2,3,4,5,7]),
+ ?line [1,2,3,4,5,6,7] = lists:umerge([2,4,6], [1,2,3,4,5,6,7]),
+
+ %% 3-way unique merge
+ ?line [] = lists:umerge3([], [], []),
+ ?line Two = lists:umerge3([], [], Two),
+ ?line Two = lists:umerge3([], Two, []),
+ ?line Two = lists:umerge3(Two, [], []),
+ ?line Six = lists:umerge3([], [1,3,5], [2,4,6]),
+ ?line Six = lists:umerge3([1,3,5], [], [2,4,6]),
+ ?line Six = lists:umerge3([1,3,5], [2,4,6], []),
+ ?line Nine = lists:umerge3([1,4,7],[2,5,8],[3,6,9]),
+ ?line Nine = lists:umerge3([1,4,7],[3,6,9],[2,5,8]),
+ ?line Nine = lists:umerge3([3,6,9],[1,4,7],[2,5,8]),
+ ?line Nine = lists:umerge3([4,5,6],[1,2,3],[7,8,9]),
+ ?line Nine = lists:umerge3([1,2,3],[4,5,6],[7,8,9]),
+ ?line Nine = lists:umerge3([7,8,9],[4,5,6],[1,2,3]),
+ ?line Nine = lists:umerge3([4,5,6],[7,8,9],[1,2,3]),
+
+ ?line [1,2,3] = lists:umerge3([1,2,3],[1,2,3],[1,2,3]),
+ ?line [1,2,3,4] = lists:umerge3([2,3,4],[1,2,3],[2,3,4]),
+ ?line [1,2,3] = lists:umerge3([1,2,3],[2,3],[1,2,3]),
+ ?line [1,2,3,4] = lists:umerge3([2,3,4],[3,4],[1,2,3]),
+
+ ok.
+
+rumerge(suite) -> [];
+rumerge(doc) -> [""];
+rumerge(Conf) when is_list(Conf) ->
+ Two = [2,1],
+ Six = [6,5,4,3,2,1],
+
+ %% 2-way reversed unique merge
+ ?line [] = lists:rumerge([], []),
+ ?line Two = lists:rumerge(Two, []),
+ ?line Two = lists:rumerge([], Two),
+ ?line Six = lists:rumerge([5,3,1], [6,4,2]),
+ ?line Six = lists:rumerge([6,4,2], [5,3,1]),
+ ?line Six = lists:rumerge([3,2,1], [6,5,4]),
+ ?line Six = lists:rumerge([6,5,4], [3,2,1]),
+ ?line Six = lists:rumerge([4,3,2],[6,5,1]),
+ ?line [7,6,5,3,1] = lists:rumerge([7,5,3,1], [6]),
+ ?line [7,6,5,4,3,1] = lists:rumerge([7,5,3,1], [6,4]),
+ ?line [7,6,5,4,3,2,1] = lists:rumerge([7,5,3,1], [6,4,2]),
+ ?line [7,5,3,2,1] = lists:rumerge([2], [7,5,3,1]),
+ ?line [7,5,4,3,2,1] = lists:rumerge([4,2], [7,5,3,1]),
+ ?line [7,6,5,4,3,2,1] = lists:rumerge([6,4,2], [7,5,3,1]),
+
+ ?line [7,6,5,3,1] = lists:rumerge([7,6,5,3,1], [6]),
+ ?line [7,6,5,4,3,1] = lists:rumerge([7,6,5,4,3,1], [6,4]),
+ ?line [7,6,5,4,3,2,1] = lists:rumerge([7,6,5,4,3,2,1], [6,4,2]),
+ ?line [7,5,3,2,1] = lists:rumerge([2], [7,5,3,2,1]),
+ ?line [7,5,4,3,2,1] = lists:rumerge([4,2], [7,5,4,3,2,1]),
+ ?line [7,6,5,4,3,2,1] = lists:rumerge([6,4,2], [7,6,5,4,3,2,1]),
+
+ Nine = [9,8,7,6,5,4,3,2,1],
+
+ %% 3-way reversed unique merge
+ ?line [] = lists:rumerge3([], [], []),
+ ?line Two = lists:rumerge3([], [], Two),
+ ?line Two = lists:rumerge3([], Two, []),
+ ?line Two = lists:rumerge3(Two, [], []),
+ ?line Six = lists:rumerge3([], [5,3,1], [6,4,2]),
+ ?line Six = lists:rumerge3([5,3,1], [], [6,4,2]),
+ ?line Six = lists:rumerge3([5,3,1], [6,4,2], []),
+ ?line Nine = lists:rumerge3([7,4,1],[8,5,2],[9,6,3]),
+ ?line Nine = lists:rumerge3([7,4,1],[9,6,3],[8,5,2]),
+ ?line Nine = lists:rumerge3([9,6,3],[7,4,1],[8,5,2]),
+ ?line Nine = lists:rumerge3([6,5,4],[3,2,1],[9,8,7]),
+ ?line Nine = lists:rumerge3([3,2,1],[6,5,4],[9,8,7]),
+ ?line Nine = lists:rumerge3([9,8,7],[6,5,4],[3,2,1]),
+ ?line Nine = lists:rumerge3([6,5,4],[9,8,7],[3,2,1]),
+
+ ?line [3,2,1] = lists:rumerge3([3,2,1],[3,2,1],[3,2,1]),
+ ?line [4,3,2,1] = lists:rumerge3([4,3,2],[3,2,1],[3,2,1]),
+ ?line [5,4,3,2,1] = lists:rumerge3([4,3,2],[5,4,3,2],[5,4,3,2,1]),
+ ?line [6,5,4,3,2] = lists:rumerge3([4,3,2],[5,4,3,2],[6,5,4,3]),
+
+ L1 = [c,d,e],
+ L2 = [b,c,d],
+ ?line true =
+ lists:umerge(L1, L2) ==
+ lists:reverse(lists:rumerge(lists:reverse(L1), lists:reverse(L2))),
+ ok.
+
+usort_rand(doc) -> ["usort/1 on big randomized lists"];
+usort_rand(suite) -> [];
+usort_rand(Config) when is_list(Config) ->
+ ?line ok = ucheck(biglist(10)),
+ ?line ok = ucheck(biglist(100)),
+ ?line ok = ucheck(biglist(1000)),
+ ?line ok = ucheck(biglist(10000)),
+
+ ?line ok = ucheck(ubiglist(10)),
+ ?line ok = ucheck(ubiglist(100)),
+ ?line ok = ucheck(ubiglist(1000)),
+ ?line ok = ucheck(ubiglist(10000)),
+ ok.
+
+usort_stable(doc) -> ["usort/1 should keep the first duplicate."];
+usort_stable(suite) -> [];
+usort_stable(Config) when is_list(Config) ->
+ ?line ok = ucheck_stability(bigfunlist(3)),
+ ?line ok = ucheck_stability(bigfunlist(10)),
+ ?line ok = ucheck_stability(bigfunlist(100)),
+ ?line ok = ucheck_stability(bigfunlist(1000)),
+ ?line case erlang:system_info(modified_timing_level) of
+ undefined -> ok = ucheck_stability(bigfunlist(10000));
+ _ -> ok
+ end,
+ ok.
+
+ucheck([]) ->
+ ok;
+ucheck(L) ->
+ S = lists:usort(L),
+ case ucheck(hd(S), tl(S)) of
+ ok ->
+ ok;
+ _ ->
+ io:format("~w~n", [L]),
+ erlang:error(ucheck)
+ end.
+
+ucheck(_A, []) ->
+ ok;
+ucheck(A, [B | L]) when A < B ->
+ ucheck(B, L);
+ucheck(_A, _L) ->
+ no.
+
+%% Check that usort/1 is stable and correct relative ukeysort/2.
+ucheck_stability(L) ->
+ S = no_dups(lsort(L)),
+ U = lists:usort(L),
+ check_stab(L, U, S, "usort/1", "ukeysort/2").
+
+keysort(doc) ->
+ ["Tests lists:keysort/2"];
+keysort(suite) ->
+ [keymerge, rkeymerge,
+ keysort_1, keysort_rand, keysort_i, keysort_stable, keysort_error].
+
+keymerge(doc) -> ["Key merge two lists."];
+keymerge(suite) -> [];
+keymerge(Config) when is_list(Config) ->
+
+ Two = [{1,a},{2,b}],
+ Six = [{1,a},{2,b},{3,c},{4,d},{5,e},{6,f}],
+
+ %% 2-way keymerge
+ ?line [] = lists:keymerge(1, [], []),
+ ?line Two = lists:keymerge(1, Two, []),
+ ?line Two = lists:keymerge(1, [], Two),
+ ?line Six = lists:keymerge(1, [{1,a},{3,c},{5,e}], [{2,b},{4,d},{6,f}]),
+ ?line Six = lists:keymerge(1, [{2,b},{4,d},{6,f}], [{1,a},{3,c},{5,e}]),
+ ?line Six = lists:keymerge(1, [{1,a},{2,b},{3,c}], [{4,d},{5,e},{6,f}]),
+ ?line Six = lists:keymerge(1, [{4,d},{5,e},{6,f}], [{1,a},{2,b},{3,c}]),
+ ?line Six = lists:keymerge(1, [{1,a},{2,b},{5,e}],[{3,c},{4,d},{6,f}]),
+ ?line [{1,a},{2,b},{3,c},{5,e},{7,g}] =
+ lists:keymerge(1, [{1,a},{3,c},{5,e},{7,g}], [{2,b}]),
+ ?line [{1,a},{2,b},{3,c},{4,d},{5,e},{7,g}] =
+ lists:keymerge(1, [{1,a},{3,c},{5,e},{7,g}], [{2,b},{4,d}]),
+ ?line [{1,a},{2,b},{3,c},{4,d},{5,e},{6,f},{7,g}] =
+ lists:keymerge(1, [{1,a},{3,c},{5,e},{7,g}], [{2,b},{4,d},{6,f}]),
+ ?line [{1,a},{2,b},{3,c},{5,e},{7,g}] =
+ lists:keymerge(1, [{2,b}], [{1,a},{3,c},{5,e},{7,g}]),
+ ?line [{1,a},{2,b},{3,c},{4,d},{5,e},{7,g}] =
+ lists:keymerge(1, [{2,b},{4,d}], [{1,a},{3,c},{5,e},{7,g}]),
+ ?line [{1,a},{2,b},{3,c},{4,d},{5,e},{6,f},{7,g}] =
+ lists:keymerge(1, [{2,b},{4,d},{6,f}], [{1,a},{3,c},{5,e},{7,g}]),
+
+ ?line [{b,2},{c,11},{c,12},{c,21},{c,22},{e,5}] =
+ lists:keymerge(1,[{c,11},{c,12},{e,5}], [{b,2},{c,21},{c,22}]),
+
+ ok.
+
+rkeymerge(doc) -> ["Reverse key merge two lists."];
+rkeymerge(suite) -> [];
+rkeymerge(Config) when is_list(Config) ->
+
+ Two = [{2,b},{1,a}],
+ Six = [{6,f},{5,e},{4,d},{3,c},{2,b},{1,a}],
+
+ %% 2-way reversed keymerge
+ ?line [] = lists:rkeymerge(1, [], []),
+ ?line Two = lists:rkeymerge(1, Two, []),
+ ?line Two = lists:rkeymerge(1, [], Two),
+ ?line Six = lists:rkeymerge(1, [{5,e},{3,c},{1,a}], [{6,f},{4,d},{2,b}]),
+ ?line Six = lists:rkeymerge(1, [{6,f},{4,d},{2,b}], [{5,e},{3,c},{1,a}]),
+ ?line Six = lists:rkeymerge(1, [{3,c},{2,b},{1,a}], [{6,f},{5,e},{4,d}]),
+ ?line Six = lists:rkeymerge(1, [{6,f},{5,e},{4,d}], [{3,c},{2,b},{1,a}]),
+ ?line Six = lists:rkeymerge(1, [{4,d},{3,c},{2,b}],[{6,f},{5,e},{1,a}]),
+ ?line [{7,g},{6,f},{5,e},{3,c},{1,a}] =
+ lists:rkeymerge(1, [{7,g},{5,e},{3,c},{1,a}], [{6,f}]),
+ ?line [{7,g},{6,f},{5,e},{4,d},{3,c},{1,a}] =
+ lists:rkeymerge(1, [{7,g},{5,e},{3,c},{1,a}], [{6,f},{4,d}]),
+ ?line [{7,g},{6,f},{5,e},{4,d},{3,c},{2,b},{1,a}] =
+ lists:rkeymerge(1, [{7,g},{5,e},{3,c},{1,a}], [{6,f},{4,d},{2,b}]),
+ ?line [{7,g},{5,e},{3,c},{2,b},{1,a}] =
+ lists:rkeymerge(1, [{2,b}], [{7,g},{5,e},{3,c},{1,a}]),
+ ?line [{7,g},{5,e},{4,d},{3,c},{2,b},{1,a}] =
+ lists:rkeymerge(1, [{4,d},{2,b}], [{7,g},{5,e},{3,c},{1,a}]),
+ ?line [{7,g},{6,f},{5,e},{4,d},{3,c},{2,b},{1,a}] =
+ lists:rkeymerge(1, [{6,f},{4,d},{2,b}], [{7,g},{5,e},{3,c},{1,a}]),
+
+ L1 = [{c,11},{c,12},{e,5}],
+ L2 = [{b,2},{c,21},{c,22}],
+ ?line true =
+ lists:keymerge(1, L1, L2) ==
+ lists:reverse(lists:rkeymerge(1,lists:reverse(L1),
+ lists:reverse(L2))),
+
+ ok.
+
+keysort_1(doc) -> ["keysort"];
+keysort_1(suite) -> [];
+keysort_1(Config) when is_list(Config) ->
+ ?line ok = keysort_check(1, [], []),
+ ?line ok = keysort_check(1, [{a,b}], [{a,b}]),
+ ?line ok = keysort_check(1, [{a,b},{a,b}], [{a,b},{a,b}]),
+ ?line ok = keysort_check(1, [{a,b},{b,c}], [{a,b},{b,c}]),
+ ?line ok = keysort_check(1, [{b,c},{a,b}], [{a,b},{b,c}]),
+ ?line ok = keysort_check(1,
+ [{1,e},{3,f},{2,y},{0,z},{x,14}],
+ [{0,z},{1,e},{2,y},{3,f},{x,14}]),
+ ?line ok = keysort_check(1,
+ [{1,a},{1,a},{1,a},{1,a}],
+ [{1,a},{1,a},{1,a},{1,a}]),
+
+ ?line [{b,1},{c,1}] = lists:keysort(1, [{c,1},{b,1}]),
+ ?line [{a,0},{b,2},{c,3},{d,4}] =
+ lists:keysort(1, [{d,4},{c,3},{b,2},{a,0}]),
+ ?line [{a,0},{b,1},{b,2},{c,1}] =
+ lists:keysort(1, [{c,1},{b,1},{b,2},{a,0}]),
+ ?line [{a,0},{b,1},{b,2},{c,1},{d,4}] =
+ lists:keysort(1, [{c,1},{b,1},{b,2},{a,0},{d,4}]),
+
+ SFun = fun(L) -> fun(X) -> keysort_check(1, X, L) end end,
+ L1 = [{1,a},{2,b},{3,c}],
+ ?line lists:foreach(SFun(L1), perms(L1)),
+ L2 = [{1,a},{1,a},{2,b}],
+ ?line lists:foreach(SFun(L2), perms(L2)),
+ L3 = [{1,a},{1,a},{1,a},{2,b}],
+ ?line lists:foreach(SFun(L3), perms(L3)),
+ L4 = [{a,1},{a,1},{b,2},{b,2},{c,3},{d,4},{e,5},{f,6}],
+ ?line lists:foreach(SFun(L4), perms(L4)),
+
+ ok.
+
+keysort_stable(doc) -> ["keysort should be stable"];
+keysort_stable(suite) -> [];
+keysort_stable(Config) when is_list(Config) ->
+ ?line ok = keysort_check(1, [{1,b},{1,c}], [{1,b},{1,c}]),
+ ?line ok = keysort_check(1, [{1,c},{1,b}], [{1,c},{1,b}]),
+ ?line ok = keysort_check(1,
+ [{1,c},{1,b},{2,x},{3,p},{2,a}],
+ [{1,c},{1,b},{2,x},{2,a},{3,p}]),
+ ?line ok = keysort_check(1,
+ [{1,a},{1,b},{1,a},{1,a}],
+ [{1,a},{1,b},{1,a},{1,a}]),
+ ok.
+
+keysort_error(doc) -> ["keysort should exit when given bad arguments"];
+keysort_error(suite) -> [];
+keysort_error(Config) when is_list(Config) ->
+ ?line {'EXIT', _} = (catch lists:keysort(0, [{1,b},{1,c}])),
+ ?line {'EXIT', _} = (catch lists:keysort(3, [{1,b},{1,c}])),
+ ?line {'EXIT', _} = (catch lists:keysort(1.5, [{1,b},{1,c}])),
+ ?line {'EXIT', _} = (catch lists:keysort(x, [{1,b},{1,c}])),
+ ?line {'EXIT', _} = (catch lists:keysort(x, [])),
+ ?line {'EXIT', _} = (catch lists:keysort(x, [{1,b}])),
+ ?line {'EXIT', _} = (catch lists:keysort(1, [a,b])),
+ ?line {'EXIT', _} = (catch lists:keysort(1, [{1,b} | {1,c}])),
+ ok.
+
+keysort_i(doc) -> ["keysort with other key than first element"];
+keysort_i(suite) -> [];
+keysort_i(Config) when is_list(Config) ->
+ ?line ok = keysort_check(2, [{a,2},{b,1},{c,3}], [{b,1},{a,2},{c,3}]),
+ ok.
+
+keysort_rand(doc) -> ["keysort on big randomized lists"];
+keysort_rand(suite) -> [];
+keysort_rand(Config) when is_list(Config) ->
+ ?line ok = keysort_check3(1, biglist(10)),
+ ?line ok = keysort_check3(1, biglist(100)),
+ ?line ok = keysort_check3(1, biglist(1000)),
+ ?line ok = keysort_check3(1, biglist(10000)),
+
+ ?line ok = keysort_check3(2, biglist(10)),
+ ?line ok = keysort_check3(2, biglist(100)),
+ ?line ok = keysort_check3(2, biglist(1000)),
+ ?line ok = keysort_check3(2, biglist(10000)),
+ ok.
+
+%%% Keysort a list, check that the returned list is what we expected,
+%%% and that it is actually sorted.
+keysort_check(I, Input, Expected) ->
+ ?line Expected = lists:keysort(I, Input),
+ check_sorted(I, Input, Expected).
+
+keysort_check3(I, Input) ->
+ check_sorted(I, 3, Input, lists:keysort(I, Input)).
+
+check_sorted(I, Input, L) ->
+ check_sorted(I, I, Input, L).
+
+%%% Check that a list is keysorted by element I. Elements comparing equal
+%%% should be sorted according to element J.
+check_sorted(_I, _J, _Input, []) ->
+ ok;
+check_sorted(I, J, Input, [A | Rest]) ->
+ case catch check_sorted1(I, J, A, Rest) of
+ {'EXIT', _} ->
+ io:format("~w~n", [Input]),
+ erlang:error(check_sorted);
+ Reply ->
+ Reply
+ end.
+
+check_sorted1(_I, _J, _A, []) ->
+ ok;
+check_sorted1(I, J, A, [B | Rest]) ->
+ ok = keycompare(I, J, A, B),
+ check_sorted1(I, J, B, Rest).
+
+keycompare(I, _J, A, B) when element(I, A) < element(I, B) ->
+ ok;
+keycompare(I, J, A, B) when element(I, A) == element(I, B),
+ element(J, A) =< element(J, B) ->
+ ok.
+
+ukeysort(doc) ->
+ ["Tests lists:ukeysort/2"];
+ukeysort(suite) ->
+ [ukeymerge, rukeymerge,
+ ukeysort_1, ukeysort_rand, ukeysort_i, ukeysort_stable, ukeysort_error].
+
+ukeymerge(suite) -> [];
+ukeymerge(doc) -> ["Merge two lists while removing duplicates."];
+ukeymerge(Conf) when is_list(Conf) ->
+
+ Two = [{1,a},{2,b}],
+ Six = [{1,a},{2,b},{3,c},{4,d},{5,e},{6,f}],
+
+ %% 2-way unique keymerge
+ ?line [] = lists:ukeymerge(1, [], []),
+ ?line Two = lists:ukeymerge(1, Two, []),
+ ?line Two = lists:ukeymerge(1, [], Two),
+ ?line [] = lists:ukeymerge(1, [], []),
+ ?line Two = lists:ukeymerge(1, Two, []),
+ ?line Two = lists:ukeymerge(1, [], Two),
+ ?line Six = lists:ukeymerge(1, [{1,a},{3,c},{5,e}], [{2,b},{4,d},{6,f}]),
+ ?line Six = lists:ukeymerge(1, [{2,b},{4,d},{6,f}], [{1,a},{3,c},{5,e}]),
+ ?line Six = lists:ukeymerge(1, [{1,a},{2,b},{3,c}], [{4,d},{5,e},{6,f}]),
+ ?line Six = lists:ukeymerge(1, [{4,d},{5,e},{6,f}], [{1,a},{2,b},{3,c}]),
+ ?line Six = lists:ukeymerge(1, [{1,a},{2,b},{5,e}],[{3,c},{4,d},{6,f}]),
+ ?line [{1,a},{2,b},{3,c},{5,e},{7,g}] =
+ lists:ukeymerge(1, [{1,a},{3,c},{5,e},{7,g}], [{2,b}]),
+ ?line [{1,a},{2,b},{3,c},{4,d},{5,e},{7,g}] =
+ lists:ukeymerge(1, [{1,a},{3,c},{5,e},{7,g}], [{2,b},{4,d}]),
+ ?line [{1,a},{2,b},{3,c},{4,d},{5,e},{6,f},{7,g}] =
+ lists:ukeymerge(1, [{1,a},{3,c},{5,e},{7,g}], [{2,b},{4,d},{6,f}]),
+ ?line [{1,a},{2,b},{3,c},{5,e},{7,g}] =
+ lists:ukeymerge(1, [{2,b}], [{1,a},{3,c},{5,e},{7,g}]),
+ ?line [{1,a},{2,b},{3,c},{4,d},{5,e},{7,g}] =
+ lists:ukeymerge(1, [{2,b},{4,d}], [{1,a},{3,c},{5,e},{7,g}]),
+ ?line [{1,a},{2,b},{3,c},{4,d},{5,e},{6,f},{7,g}] =
+ lists:ukeymerge(1, [{2,b},{4,d},{6,f}], [{1,a},{3,c},{5,e},{7,g}]),
+
+ ?line [{1,a},{2,b},{3,c},{5,e},{7,g}] =
+ lists:ukeymerge(1, [{1,a},{2,b},{3,c},{5,e},{7,g}], [{2,b}]),
+ ?line [{1,a},{2,b},{3,c},{4,d},{5,e},{7,g}] =
+ lists:ukeymerge(1, [{1,a},{2,b},{3,c},{4,d},{5,e},{7,g}],
+ [{2,b},{4,d}]),
+ ?line [{1,a},{2,b},{3,c},{4,d},{5,e},{6,f},{7,g}] =
+ lists:ukeymerge(1, [{1,a},{3,c},{5,e},{6,f},{7,g}],
+ [{2,b},{4,d},{6,f}]),
+ ?line [{1,a},{2,b},{3,c},{5,e},{7,g}] =
+ lists:ukeymerge(1, [{2,b}], [{1,a},{2,b},{3,c},{5,e},{7,g}]),
+ ?line [{1,a},{2,b},{3,c},{4,d},{5,e},{7,g}] =
+ lists:ukeymerge(1, [{2,b},{4,d}],
+ [{1,a},{2,b},{3,c},{4,d},{5,e},{7,g}]),
+ ?line [{1,a},{2,b},{3,c},{4,d},{5,e},{6,f},{7,g}] =
+ lists:ukeymerge(1, [{2,b},{4,d},{6,f}],
+ [{1,a},{2,b},{3,c},{4,d},{5,e},{6,f},{7,g}]),
+
+ L1 = [{a,1},{a,3},{a,5},{a,7}],
+ L2 = [{b,1},{b,3},{b,5},{b,7}],
+ ?line L1 = lists:ukeymerge(2, L1, L2),
+
+ ok.
+
+rukeymerge(suite) -> [];
+rukeymerge(doc) ->
+ ["Reverse merge two lists while removing duplicates."];
+rukeymerge(Conf) when is_list(Conf) ->
+
+ Two = [{2,b},{1,a}],
+ Six = [{6,f},{5,e},{4,d},{3,c},{2,b},{1,a}],
+
+ %% 2-way reversed unique keymerge
+ ?line [] = lists:rukeymerge(1, [], []),
+ ?line Two = lists:rukeymerge(1, Two, []),
+ ?line Two = lists:rukeymerge(1, [], Two),
+ ?line Six = lists:rukeymerge(1, [{5,e},{3,c},{1,a}], [{6,f},{4,d},{2,b}]),
+ ?line Six = lists:rukeymerge(1, [{6,f},{4,d},{2,b}], [{5,e},{3,c},{1,a}]),
+ ?line Six = lists:rukeymerge(1, [{3,c},{2,b},{1,a}], [{6,f},{5,e},{4,d}]),
+ ?line Six = lists:rukeymerge(1, [{6,f},{5,e},{4,d}], [{3,c},{2,b},{1,a}]),
+ ?line Six = lists:rukeymerge(1, [{4,d},{3,c},{2,b}],[{6,f},{5,e},{1,a}]),
+ ?line [{7,g},{6,f},{5,e},{3,c},{1,a}] =
+ lists:rukeymerge(1, [{7,g},{5,e},{3,c},{1,a}], [{6,f}]),
+ ?line [{7,g},{6,f},{5,e},{4,d},{3,c},{1,a}] =
+ lists:rukeymerge(1, [{7,g},{5,e},{3,c},{1,a}], [{6,f},{4,d}]),
+ ?line [{7,g},{6,f},{5,e},{4,d},{3,c},{2,b},{1,a}] =
+ lists:rukeymerge(1, [{7,g},{5,e},{3,c},{1,a}], [{6,f},{4,d},{2,b}]),
+ ?line [{7,g},{5,e},{3,c},{2,b},{1,a}] =
+ lists:rukeymerge(1, [{2,b}], [{7,g},{5,e},{3,c},{1,a}]),
+ ?line [{7,g},{5,e},{4,d},{3,c},{2,b},{1,a}] =
+ lists:rukeymerge(1, [{4,d},{2,b}], [{7,g},{5,e},{3,c},{1,a}]),
+ ?line [{7,g},{6,f},{5,e},{4,d},{3,c},{2,b},{1,a}] =
+ lists:rukeymerge(1, [{6,f},{4,d},{2,b}], [{7,g},{5,e},{3,c},{1,a}]),
+
+ ?line [{7,g},{6,f},{5,e},{3,c},{1,a}] =
+ lists:rukeymerge(1, [{7,g},{6,f},{5,e},{3,c},{1,a}], [{6,f}]),
+ ?line [{7,g},{6,f},{5,e},{4,d},{3,c},{1,a}] =
+ lists:rukeymerge(1, [{7,g},{6,f},{5,e},{4,d},{3,c},{1,a}],
+ [{6,f},{4,d}]),
+ ?line [{7,g},{6,f},{5,e},{4,d},{3,c},{2,b},{1,a}] =
+ lists:rukeymerge(1, [{7,g},{6,f},{5,e},{4,d},{3,c},{2,b},{1,a}],
+ [{6,f},{4,d},{2,b}]),
+ ?line [{7,g},{5,e},{3,c},{2,b},{1,a}] =
+ lists:rukeymerge(1, [{2,b}], [{7,g},{5,e},{3,c},{2,b},{1,a}]),
+ ?line [{7,g},{5,e},{4,d},{3,c},{2,b},{1,a}] =
+ lists:rukeymerge(1, [{4,d},{2,b}],
+ [{7,g},{5,e},{4,d},{3,c},{2,b},{1,a}]),
+ ?line [{7,g},{6,f},{5,e},{4,d},{3,c},{2,b},{1,a}] =
+ lists:rukeymerge(1, [{6,f},{4,d},{2,b}],
+ [{7,g},{6,f},{5,e},{4,d},{3,c},{2,b},{1,a}]),
+
+ L1 = [{a,1},{a,3},{a,5},{a,7}],
+ L2 = [{b,1},{b,3},{b,5},{b,7}],
+ ?line true =
+ lists:ukeymerge(2, L1, L2) ==
+ lists:reverse(lists:rukeymerge(2, lists:reverse(L1),
+ lists:reverse(L2))),
+
+ ok.
+
+ukeysort_1(doc) -> ["ukeysort"];
+ukeysort_1(suite) -> [];
+ukeysort_1(Config) when is_list(Config) ->
+ ?line ok = ukeysort_check(1, [], []),
+ ?line ok = ukeysort_check(1, [{a,b}], [{a,b}]),
+ ?line ok = ukeysort_check(1, [{a,b},{a,b}], [{a,b}]),
+ ?line ok = ukeysort_check(1, [{a,b},{b,c}], [{a,b},{b,c}]),
+ ?line ok = ukeysort_check(1, [{b,c},{a,b}], [{a,b},{b,c}]),
+ ?line ok = ukeysort_check(1,
+ [{1,e},{3,f},{2,y},{0,z},{x,14}],
+ [{0,z},{1,e},{2,y},{3,f},{x,14}]),
+ ?line ok = ukeysort_check(1, [{1,a},{1,a},{1,a},{1,a}], [{1,a}]),
+
+ L1 = [{1,a},{1,b},{1,a}],
+ L1u = lists:ukeysort(1, L1),
+ L2 = [{1,a},{1,b},{1,a}],
+ L2u = lists:ukeysort(1, L2),
+ ?line ok = ukeysort_check(1, lists:keymerge(1, L1, L2),
+ lists:ukeymerge(1, L1u, L2u)),
+ L3 = [{1,a},{1,b},{1,a},{2,a}],
+ L3u = lists:ukeysort(1, L3),
+ ?line ok = ukeysort_check(1, lists:keymerge(1, L3, L2),
+ lists:ukeymerge(1, L3u, L2u)),
+ L4 = [{1,b},{1,a}],
+ L4u = lists:ukeysort(1, L4),
+ ?line ok = ukeysort_check(1, lists:keymerge(1, L1, L4),
+ lists:ukeymerge(1, L1u, L4u)),
+ L5 = [{1,a},{1,b},{1,a},{2,a}],
+ L5u = lists:ukeysort(1, L5),
+ ?line ok = ukeysort_check(1, lists:keymerge(1, [], L5),
+ lists:ukeymerge(1, [], L5u)),
+ ?line ok = ukeysort_check(1, lists:keymerge(1, L5, []),
+ lists:ukeymerge(1, L5u, [])),
+ L6 = [{3,a}],
+ L6u = lists:ukeysort(1, L6),
+ ?line ok = ukeysort_check(1, lists:keymerge(1, L5, L6),
+ lists:ukeymerge(1, L5u, L6u)),
+
+ ?line [{b,1},{c,1}] = lists:ukeysort(1, [{c,1},{c,1},{c,1},{c,1},{b,1}]),
+ ?line [{a,0},{b,2},{c,3},{d,4}] =
+ lists:ukeysort(1, [{d,4},{c,3},{b,2},{b,2},{a,0}]),
+ ?line [{a,0},{b,1},{c,1}] =
+ lists:ukeysort(1, [{c,1},{b,1},{b,1},{b,2},{b,2},{a,0}]),
+ ?line [{a,0},{b,1},{c,1},{d,4}] =
+ lists:ukeysort(1, [{c,1},{b,1},{b,2},{a,0},{a,0},{d,4},{d,4}]),
+
+ SFun = fun(L) -> fun(X) -> ukeysort_check(2, X, L) end end,
+ PL = [{a,1},{b,2},{c,3},{d,4},{e,5},{f,6}],
+ Ps = perms([{a,1},{b,2},{c,3},{d,4},{e,5},{f,6},{b,2},{a,1}]),
+ ?line lists:foreach(SFun(PL), Ps),
+
+ M1L = [{1,a},{1,a},{2,b}],
+ M1s = [{1,a},{2,b}],
+ ?line lists:foreach(SFun(M1s), perms(M1L)),
+ M2L = [{1,a},{2,b},{2,b}],
+ M2s = [{1,a},{2,b}],
+ ?line lists:foreach(SFun(M2s), perms(M2L)),
+ M3 = [{1,a},{2,b},{3,c}],
+ ?line lists:foreach(SFun(M3), perms(M3)),
+
+ ok.
+
+ukeysort_stable(doc) -> ["ukeysort should keep the first duplicate"];
+ukeysort_stable(suite) -> [];
+ukeysort_stable(Config) when is_list(Config) ->
+ ?line ok = ukeysort_check(1, [{1,b},{1,c}], [{1,b}]),
+ ?line ok = ukeysort_check(1, [{1,c},{1,b}], [{1,c}]),
+ ?line ok = ukeysort_check(1,
+ [{1,c},{1,b},{2,x},{3,p},{2,a}],
+ [{1,c},{2,x},{3,p}]),
+
+ ?line ok = ukeysort_check(1, [{1,a},{1,b},{1,b}], [{1,a}]),
+ ?line ok = ukeysort_check(1, [{2,a},{1,b},{2,a}], [{1,b},{2,a}]),
+
+ ?line ok = ukeysort_check_stability(bigfunlist(3)),
+ ?line ok = ukeysort_check_stability(bigfunlist(10)),
+ ?line ok = ukeysort_check_stability(bigfunlist(100)),
+ ?line ok = ukeysort_check_stability(bigfunlist(1000)),
+ ?line case erlang:system_info(modified_timing_level) of
+ undefined -> ok = ukeysort_check_stability(bigfunlist(10000));
+ _ -> ok
+ end,
+ ok.
+
+ukeysort_error(doc) -> ["ukeysort should exit when given bad arguments"];
+ukeysort_error(suite) -> [];
+ukeysort_error(Config) when is_list(Config) ->
+ ?line {'EXIT', _} = (catch lists:ukeysort(0, [{1,b},{1,c}])),
+ ?line {'EXIT', _} = (catch lists:ukeysort(3, [{1,b},{1,c}])),
+ ?line {'EXIT', _} = (catch lists:ukeysort(1.5, [{1,b},{1,c}])),
+ ?line {'EXIT', _} = (catch lists:ukeysort(x, [{1,b},{1,c}])),
+ ?line {'EXIT', _} = (catch lists:ukeysort(x, [])),
+ ?line {'EXIT', _} = (catch lists:ukeysort(x, [{1,b}])),
+ ?line {'EXIT', _} = (catch lists:ukeysort(1, [a,b])),
+ ?line {'EXIT', _} = (catch lists:ukeysort(1, [{1,b} | {1,c}])),
+ ok.
+
+ukeysort_i(doc) -> ["ukeysort with other key than first element"];
+ukeysort_i(suite) -> [];
+ukeysort_i(Config) when is_list(Config) ->
+ ?line ok = ukeysort_check(2, [{a,2},{b,1},{c,3}], [{b,1},{a,2},{c,3}]),
+ ok.
+
+ukeysort_rand(doc) -> ["ukeysort on big randomized lists"];
+ukeysort_rand(suite) -> [];
+ukeysort_rand(Config) when is_list(Config) ->
+ ?line ok = ukeysort_check3(2, biglist(10)),
+ ?line ok = ukeysort_check3(2, biglist(100)),
+ ?line ok = ukeysort_check3(2, biglist(1000)),
+ ?line ok = ukeysort_check3(2, biglist(10000)),
+
+ ?line ok = gen_ukeysort_check(1, ubiglist(10)),
+ ?line ok = gen_ukeysort_check(1, ubiglist(100)),
+ ?line ok = gen_ukeysort_check(1, ubiglist(1000)),
+ ?line ok = gen_ukeysort_check(1, ubiglist(10000)),
+ ok.
+
+%% Check that ukeysort/2 is stable and correct relative keysort/2.
+%% (this is not affected by the fact that keysort/2 is no longer really
+%% stable; ucheck_stability/1 checks ukeysort/2 (and usort/1, of course))
+gen_ukeysort_check(I, Input) ->
+ U = lists:ukeysort(I, Input),
+ S = lists:keysort(I, Input),
+ case U == no_dups_keys(S, I) of
+ true ->
+ ok;
+ false ->
+ io:format("~w~n", [Input]),
+ erlang:error(gen_ukeysort_check)
+ end.
+
+%% Used for checking that the first copy is kept.
+ukeysort_check_stability(L) ->
+ I = 1,
+ U = lists:ukeysort(I, L),
+ S = no_dups_keys(lkeysort(I, L), I),
+ check_stab(L, U, S, "ukeysort/2", "usort/2").
+
+%%% Uniquely keysort a list, check that the returned list is what we
+%%% expected, and that it is actually sorted.
+ukeysort_check(I, Input, Expected) ->
+ ?line Expected = lists:ukeysort(I, Input),
+ ucheck_sorted(I, Input, Expected).
+
+ukeysort_check3(I, Input) ->
+ ucheck_sorted(I, 3, Input, lists:ukeysort(I, Input)).
+
+ucheck_sorted(I, Input, L) ->
+ ucheck_sorted(I, I, Input, L).
+
+%%% Check that a list is ukeysorted by element I. Elements comparing
+%%% equal should be sorted according to element J.
+ucheck_sorted(_I, _J, _Input, []) ->
+ ok;
+ucheck_sorted(I, J, Input, [A | Rest]) ->
+ case catch ucheck_sorted1(I, J, A, Rest) of
+ {'EXIT', _} ->
+ io:format("~w~n", [Input]),
+ erlang:error(ucheck_sorted);
+ Reply ->
+ Reply
+ end.
+
+ucheck_sorted1(_I, _J, _A, []) ->
+ ok;
+ucheck_sorted1(I, J, A, [B | Rest]) ->
+ ok = ukeycompare(I, J, A, B),
+ ucheck_sorted1(I, J, B, Rest).
+
+ukeycompare(I, _J, A, B) when element(I, A) < element(I, B) ->
+ ok;
+ukeycompare(I, J, A, B) when A =/= B,
+ element(I, A) == element(I, B),
+ element(J, A) =< element(J, B) ->
+ ok.
+
+
+funsort(doc) ->
+ ["Tests lists:sort/2"];
+funsort(suite) ->
+ [funmerge, rfunmerge,
+ funsort_1, funsort_stable, funsort_error, funsort_rand].
+
+funmerge(doc) -> ["Merge two lists using a fun."];
+funmerge(suite) -> [];
+funmerge(Config) when is_list(Config) ->
+
+ Two = [1,2],
+ Six = [1,2,3,4,5,6],
+ F = fun(X, Y) -> X =< Y end,
+
+ %% 2-way merge
+ ?line [] = lists:merge(F, [], []),
+ ?line Two = lists:merge(F, Two, []),
+ ?line Two = lists:merge(F, [], Two),
+ ?line Six = lists:merge(F, [1,3,5], [2,4,6]),
+ ?line Six = lists:merge(F, [2,4,6], [1,3,5]),
+ ?line Six = lists:merge(F, [1,2,3], [4,5,6]),
+ ?line Six = lists:merge(F, [4,5,6], [1,2,3]),
+ ?line Six = lists:merge(F, [1,2,5],[3,4,6]),
+ ?line [1,2,3,5,7] = lists:merge(F, [1,3,5,7], [2]),
+ ?line [1,2,3,4,5,7] = lists:merge(F, [1,3,5,7], [2,4]),
+ ?line [1,2,3,4,5,6,7] = lists:merge(F, [1,3,5,7], [2,4,6]),
+ ?line [1,2,3,5,7] = lists:merge(F, [2], [1,3,5,7]),
+ ?line [1,2,3,4,5,7] = lists:merge(F, [2,4], [1,3,5,7]),
+ ?line [1,2,3,4,5,6,7] = lists:merge(F, [2,4,6], [1,3,5,7]),
+
+ F2 = fun(X,Y) -> element(1,X) =< element(1,Y) end,
+ ?line [{b,2},{c,11},{c,12},{c,21},{c,22},{e,5}] =
+ lists:merge(F2,[{c,11},{c,12},{e,5}], [{b,2},{c,21},{c,22}]),
+
+ ok.
+
+rfunmerge(doc) -> ["Reverse merge two lists using a fun."];
+rfunmerge(suite) -> [];
+rfunmerge(Config) when is_list(Config) ->
+
+ Two = [2,1],
+ Six = [6,5,4,3,2,1],
+ F = fun(X, Y) -> X =< Y end,
+
+ %% 2-way reversed merge
+ ?line [] = lists:rmerge(F, [], []),
+ ?line Two = lists:rmerge(F, Two, []),
+ ?line Two = lists:rmerge(F, [], Two),
+ ?line Six = lists:rmerge(F, [5,3,1], [6,4,2]),
+ ?line Six = lists:rmerge(F, [6,4,2], [5,3,1]),
+ ?line Six = lists:rmerge(F, [3,2,1], [6,5,4]),
+ ?line Six = lists:rmerge(F, [6,5,4], [3,2,1]),
+ ?line Six = lists:rmerge(F, [4,3,2],[6,5,1]),
+ ?line [7,6,5,3,1] = lists:rmerge(F, [7,5,3,1], [6]),
+ ?line [7,6,5,4,3,1] = lists:rmerge(F, [7,5,3,1], [6,4]),
+ ?line [7,6,5,4,3,2,1] = lists:rmerge(F, [7,5,3,1], [6,4,2]),
+ ?line [7,5,3,2,1] = lists:rmerge(F, [2], [7,5,3,1]),
+ ?line [7,5,4,3,2,1] = lists:rmerge(F, [4,2], [7,5,3,1]),
+ ?line [7,6,5,4,3,2,1] = lists:rmerge(F, [6,4,2], [7,5,3,1]),
+
+ F2 = fun(X,Y) -> element(1,X) =< element(1,Y) end,
+ L1 = [{c,11},{c,12},{e,5}],
+ L2 = [{b,2},{c,21},{c,22}],
+ ?line true =
+ lists:merge(F2, L1, L2) ==
+ lists:reverse(lists:rmerge(F2,lists:reverse(L1), lists:reverse(L2))),
+
+ ok.
+
+
+funsort_1(doc) -> ["sort/2"];
+funsort_1(suite) -> [];
+funsort_1(Config) when is_list(Config) ->
+ ?line ok = funsort_check(1, [], []),
+ ?line ok = funsort_check(1, [{a,b}], [{a,b}]),
+ ?line ok = funsort_check(1, [{a,b},{a,b}], [{a,b},{a,b}]),
+ ?line ok = funsort_check(1, [{a,b},{b,c}], [{a,b},{b,c}]),
+ ?line ok = funsort_check(1, [{b,c},{a,b}], [{a,b},{b,c}]),
+ ?line ok = funsort_check(1,
+ [{1,e},{3,f},{2,y},{0,z},{x,14}],
+ [{0,z},{1,e},{2,y},{3,f},{x,14}]),
+ F = funsort_fun(1),
+
+ ?line [{b,1},{c,1}] = lists:sort(F, [{c,1},{b,1}]),
+ ?line [{a,0},{b,2},{c,3},{d,4}] =
+ lists:sort(F, [{d,4},{c,3},{b,2},{a,0}]),
+ ?line [{a,0},{b,1},{b,2},{c,1}] =
+ lists:sort(F, [{c,1},{b,1},{b,2},{a,0}]),
+ ?line [{a,0},{b,1},{b,2},{c,1},{d,4}] =
+ lists:sort(F, [{c,1},{b,1},{b,2},{a,0},{d,4}]),
+
+ SFun = fun(L) -> fun(X) -> funsort_check(1, X, L) end end,
+ L1 = [{1,a},{1,a},{2,b},{2,b},{3,c},{4,d},{5,e},{6,f}],
+ ?line lists:foreach(SFun(L1), perms(L1)),
+
+ ok.
+
+funsort_stable(doc) -> ["sort/2 should be stable"];
+funsort_stable(suite) -> [];
+funsort_stable(Config) when is_list(Config) ->
+ ?line ok = funsort_check(1, [{1,b},{1,c}], [{1,b},{1,c}]),
+ ?line ok = funsort_check(1, [{1,c},{1,b}], [{1,c},{1,b}]),
+ ?line ok = funsort_check(1,
+ [{1,c},{1,b},{2,x},{3,p},{2,a}],
+ [{1,c},{1,b},{2,x},{2,a},{3,p}]),
+ ok.
+
+funsort_error(doc) -> ["sort/2 should exit when given bad arguments"];
+funsort_error(suite) -> [];
+funsort_error(Config) when is_list(Config) ->
+ ?line {'EXIT', _} = (catch lists:sort(1, [{1,b} , {1,c}])),
+ ?line {'EXIT', _} = (catch lists:sort(fun(X,Y) -> X =< Y end,
+ [{1,b} | {1,c}])),
+ ok.
+
+funsort_rand(doc) -> ["sort/2 on big randomized lists"];
+funsort_rand(suite) -> [];
+funsort_rand(Config) when is_list(Config) ->
+ ?line ok = funsort_check3(1, biglist(10)),
+ ?line ok = funsort_check3(1, biglist(100)),
+ ?line ok = funsort_check3(1, biglist(1000)),
+ ?line ok = funsort_check3(1, biglist(10000)),
+ ok.
+
+% Do a keysort
+funsort(I, L) ->
+ lists:sort(funsort_fun(I), L).
+
+funsort_check3(I, Input) ->
+ check_sorted(I, 3, Input, funsort(I, Input)).
+
+%%% Keysort a list, check that the returned list is what we expected,
+%%% and that it is actually sorted.
+funsort_check(I, Input, Expected) ->
+ ?line Expected = funsort(I, Input),
+ check_sorted(I, Input, Expected).
+
+ufunsort(doc) ->
+ ["Tests lists:usort/2"];
+ufunsort(suite) ->
+ [ufunmerge, rufunmerge,
+ ufunsort_1, ufunsort_stable, ufunsort_error, ufunsort_rand].
+
+ufunmerge(suite) -> [];
+ufunmerge(doc) -> ["Merge two lists while removing duplicates using a fun."];
+ufunmerge(Conf) when is_list(Conf) ->
+
+ Two = [1,2],
+ Six = [1,2,3,4,5,6],
+ F = fun(X, Y) -> X =< Y end,
+
+ %% 2-way unique merge
+ ?line [] = lists:umerge(F, [], []),
+ ?line Two = lists:umerge(F, Two, []),
+ ?line Two = lists:umerge(F, [], Two),
+ ?line Six = lists:umerge(F, [1,3,5], [2,4,6]),
+ ?line Six = lists:umerge(F, [2,4,6], [1,3,5]),
+ ?line Six = lists:umerge(F, [1,2,3], [4,5,6]),
+ ?line Six = lists:umerge(F, [4,5,6], [1,2,3]),
+ ?line Six = lists:umerge(F, [1,2,5],[3,4,6]),
+ ?line [1,2,3,5,7] = lists:umerge(F, [1,3,5,7], [2]),
+ ?line [1,2,3,4,5,7] = lists:umerge(F, [1,3,5,7], [2,4]),
+ ?line [1,2,3,4,5,6,7] = lists:umerge(F, [1,3,5,7], [2,4,6]),
+ ?line [1,2,3,5,7] = lists:umerge(F, [2], [1,3,5,7]),
+ ?line [1,2,3,4,5,7] = lists:umerge(F, [2,4], [1,3,5,7]),
+ ?line [1,2,3,4,5,6,7] = lists:umerge(F, [2,4,6], [1,3,5,7]),
+
+ ?line [1,2,3,5,7] = lists:umerge(F, [1,2,3,5,7], [2]),
+ ?line [1,2,3,4,5,7] = lists:umerge(F, [1,2,3,4,5,7], [2,4]),
+ ?line [1,2,3,4,5,6,7] = lists:umerge(F, [1,3,5,6,7], [2,4,6]),
+ ?line [1,2,3,5,7] = lists:umerge(F, [2], [1,2,3,5,7]),
+ ?line [1,2,3,4,5,7] = lists:umerge(F, [2,4], [1,2,3,4,5,7]),
+ ?line [1,2,3,4,5,6,7] = lists:umerge(F, [2,4,6], [1,2,3,4,5,6,7]),
+
+ L1 = [{a,1},{a,3},{a,5},{a,7}],
+ L2 = [{b,1},{b,3},{b,5},{b,7}],
+ F2 = fun(X,Y) -> element(2,X) =< element(2,Y) end,
+ ?line L1 = lists:umerge(F2, L1, L2),
+ ?line [{b,2},{e,5},{c,11},{c,12},{c,21},{c,22}] =
+ lists:umerge(F2, [{e,5},{c,11},{c,12}], [{b,2},{c,21},{c,22}]),
+
+ ok.
+
+rufunmerge(suite) -> [];
+rufunmerge(doc) ->
+ ["Reverse merge two lists while removing duplicates using a fun."];
+rufunmerge(Conf) when is_list(Conf) ->
+ Two = [2,1],
+ Six = [6,5,4,3,2,1],
+ F = fun(X, Y) -> X =< Y end,
+
+ %% 2-way reversed unique merge
+ ?line [] = lists:rumerge(F, [], []),
+ ?line Two = lists:rumerge(F, Two, []),
+ ?line Two = lists:rumerge(F, [], Two),
+ ?line Six = lists:rumerge(F, [5,3,1], [6,4,2]),
+ ?line Six = lists:rumerge(F, [6,4,2], [5,3,1]),
+ ?line Six = lists:rumerge(F, [3,2,1], [6,5,4]),
+ ?line Six = lists:rumerge(F, [6,5,4], [3,2,1]),
+ ?line Six = lists:rumerge(F, [4,3,2],[6,5,1]),
+ ?line [7,6,5,3,1] = lists:rumerge(F, [7,5,3,1], [6]),
+ ?line [7,6,5,4,3,1] = lists:rumerge(F, [7,5,3,1], [6,4]),
+ ?line [7,6,5,4,3,2,1] = lists:rumerge(F, [7,5,3,1], [6,4,2]),
+ ?line [7,5,3,2,1] = lists:rumerge(F, [2], [7,5,3,1]),
+ ?line [7,5,4,3,2,1] = lists:rumerge(F, [4,2], [7,5,3,1]),
+ ?line [7,6,5,4,3,2,1] = lists:rumerge(F, [6,4,2], [7,5,3,1]),
+
+ ?line [7,6,5,3,1] = lists:rumerge(F, [7,6,5,3,1], [6]),
+ ?line [7,6,5,4,3,1] = lists:rumerge(F, [7,6,5,4,3,1], [6,4]),
+ ?line [7,6,5,4,3,2,1] = lists:rumerge(F, [7,6,5,4,3,2,1], [6,4,2]),
+ ?line [7,5,3,2,1] = lists:rumerge(F, [2], [7,5,3,2,1]),
+ ?line [7,5,4,3,2,1] = lists:rumerge(F, [4,2], [7,5,4,3,2,1]),
+ ?line [7,6,5,4,3,2,1] = lists:rumerge(F, [6,4,2], [7,6,5,4,3,2,1]),
+
+ F2 = fun(X,Y) -> element(1,X) =< element(1,Y) end,
+ L1 = [{1,a},{1,b},{1,a}],
+ L2 = [{1,a},{1,b},{1,a}],
+ ?line true = lists:umerge(F2, L1, L2) ==
+ lists:reverse(lists:rumerge(F, lists:reverse(L2), lists:reverse(L1))),
+
+ L3 = [{c,11},{c,12},{e,5}],
+ L4 = [{b,2},{c,21},{c,22}],
+ ?line true =
+ lists:umerge(F2, L3, L4) ==
+ lists:reverse(lists:rumerge(F2,lists:reverse(L3), lists:reverse(L4))),
+
+ ok.
+
+ufunsort_1(doc) -> ["usort/2"];
+ufunsort_1(suite) -> [];
+ufunsort_1(Config) when is_list(Config) ->
+ ?line ok = ufunsort_check(1, [], []),
+ ?line ok = ufunsort_check(1, [{a,b}], [{a,b}]),
+ ?line ok = ufunsort_check(1, [{a,b},{a,b}], [{a,b}]),
+ ?line ok = ufunsort_check(1, [{a,b},{b,c}], [{a,b},{b,c}]),
+ ?line ok = ufunsort_check(1, [{b,c},{a,b}], [{a,b},{b,c}]),
+ ?line ok = ufunsort_check(1,
+ [{1,e},{3,f},{2,y},{0,z},{x,14}],
+ [{0,z},{1,e},{2,y},{3,f},{x,14}]),
+ ?line ok = ufunsort_check(1,
+ [{1,a},{2,b},{3,c},{2,b},{1,a},{2,b},{3,c},
+ {2,b},{1,a}],
+ [{1,a},{2,b},{3,c}]),
+ ?line ok = ufunsort_check(1,
+ [{1,a},{1,a},{1,b},{1,b},{1,a},{2,a}],
+ [{1,a},{2,a}]),
+
+ F = funsort_fun(1),
+ L1 = [{1,a},{1,b},{1,a}],
+ L2 = [{1,a},{1,b},{1,a}],
+ ?line ok = ufunsort_check(1, lists:keymerge(1, L1, L2),
+ lists:umerge(F, lists:usort(F, L1),
+ lists:usort(F, L2))),
+ L3 = [{1,a},{1,b},{1,a},{2,a}],
+ ?line ok = ufunsort_check(1, lists:keymerge(1, L3, L2),
+ lists:umerge(F, lists:usort(F, L3),
+ lists:usort(F, L2))),
+ L4 = [{1,b},{1,a}],
+ ?line ok = ufunsort_check(1, lists:keymerge(1, L1, L4),
+ lists:umerge(F, lists:usort(F, L1),
+ lists:usort(F, L4))),
+ L5 = [{1,a},{1,b},{1,a},{2,a}],
+ ?line ok = ufunsort_check(1, lists:keymerge(1, L5, []),
+ lists:umerge(F, lists:usort(F, L5), [])),
+ L6 = [{3,a}],
+ ?line ok = ufunsort_check(1, lists:keymerge(1, L5, L6),
+ lists:umerge(F, lists:usort(F, L5),
+ lists:usort(F, L6))),
+
+ ?line [{b,1},{c,1}] = lists:usort(F, [{c,1},{c,1},{b,1}]),
+ ?line [{a,0},{b,2},{c,3},{d,4}] =
+ lists:usort(F, [{d,4},{c,3},{b,2},{b,2},{a,0}]),
+ ?line [{a,0},{b,1},{c,1}] =
+ lists:usort(F, [{c,1},{b,1},{b,1},{b,2},{b,2},{a,0}]),
+ ?line [{a,0},{b,1},{c,1},{d,4}] =
+ lists:usort(F, [{c,1},{b,1},{b,2},{a,0},{a,0},{d,4},{d,4}]),
+
+ SFun = fun(L) -> fun(X) -> ufunsort_check(1, X, L) end end,
+ PL = [{1,a},{2,b},{3,c},{4,d},{5,e},{6,f}],
+ Ps = perms([{1,a},{2,b},{3,c},{4,d},{5,e},{6,f},{2,b},{1,a}]),
+ ?line lists:foreach(SFun(PL), Ps),
+
+ ok.
+
+ufunsort_stable(doc) -> ["usort/2 should be stable"];
+ufunsort_stable(suite) -> [];
+ufunsort_stable(Config) when is_list(Config) ->
+ ?line ok = ufunsort_check(1, [{1,b},{1,c}], [{1,b}]),
+ ?line ok = ufunsort_check(1, [{1,c},{1,b}], [{1,c}]),
+ ?line ok = ufunsort_check(1,
+ [{1,c},{1,b},{2,x},{3,p},{2,a}],
+ [{1,c},{2,x},{3,p}]),
+
+ ?line ok = ufunsort_check_stability(bigfunlist(10)),
+ ?line ok = ufunsort_check_stability(bigfunlist(100)),
+ ?line ok = ufunsort_check_stability(bigfunlist(1000)),
+ ?line case erlang:system_info(modified_timing_level) of
+ undefined -> ok = ufunsort_check_stability(bigfunlist(10000));
+ _ -> ok
+ end,
+ ok.
+
+ufunsort_error(doc) -> ["usort/2 should exit when given bad arguments"];
+ufunsort_error(suite) -> [];
+ufunsort_error(Config) when is_list(Config) ->
+ ?line {'EXIT', _} = (catch lists:usort(1, [{1,b} , {1,c}])),
+ ?line {'EXIT', _} = (catch lists:usort(fun(X,Y) -> X =< Y end,
+ [{1,b} | {1,c}])),
+ ok.
+
+ufunsort_rand(doc) -> ["usort/2 on big randomized lists"];
+ufunsort_rand(suite) -> [];
+ufunsort_rand(Config) when is_list(Config) ->
+ ?line ok = ufunsort_check3(1, biglist(10)),
+ ?line ok = ufunsort_check3(1, biglist(100)),
+ ?line ok = ufunsort_check3(1, biglist(1000)),
+ ?line ok = ufunsort_check3(1, biglist(10000)),
+
+ ?line ok = gen_ufunsort_check(1, ubiglist(100)),
+ ?line ok = gen_ufunsort_check(1, ubiglist(1000)),
+ ?line ok = gen_ufunsort_check(1, ubiglist(10000)),
+ ok.
+
+%% Check that usort/2 is stable and correct relative sort/2.
+gen_ufunsort_check(I, Input) ->
+ U = ufunsort(I, Input),
+ S = funsort(I, Input),
+ case U == no_dups_keys(S, I) of
+ true ->
+ ok;
+ false ->
+ io:format("~w~n", [Input]),
+ erlang:error(gen_ufunsort_check)
+ end.
+
+%% Used for checking that the first copy is kept.
+ufunsort_check_stability(L) ->
+ I = 1,
+ U = ufunsort(I, L),
+ S = no_dups(funsort(I, L)),
+ check_stab(L, U, S, "usort/2", "sort/2").
+
+ufunsort_check3(I, Input) ->
+ ucheck_sorted(I, 3, Input, ufunsort(I, Input)).
+
+%%% Keysort a list, check that the returned list is what we expected,
+%%% and that it is actually sorted.
+ufunsort_check(I, Input, Expected) ->
+ ?line Expected = ufunsort(I, Input),
+ ucheck_sorted(I, Input, Expected).
+
+% Do a keysort
+ufunsort(I, L) ->
+ lists:usort(funsort_fun(I), L).
+
+funsort_fun(I) ->
+ fun(A, B) when tuple_size(A) >= I, tuple_size(B) >= I ->
+ element(I, A) =< element(I, B)
+ end.
+
+check_stab(L, U, S, US, SS) ->
+ UP = explicit_pid(U),
+ SP = explicit_pid(S),
+ case UP == SP of
+ true ->
+ ok;
+ false ->
+ io:format("In: ~w~n", [explicit_pid(L)]),
+ io:format("~s: ~w~n", [US, UP]),
+ io:format("~s: ~w~n", [SS, SP]),
+ erlang:error(unstable)
+ end.
+
+%%%------------------------------------------------------------
+%%% Generate lists of given length, containing 3-tuples with
+%%% random integer elements in the range 0..44 as elements 1 and 2.
+%%% Element 3 in the tuple is the position of the tuple in the list.
+
+biglist(N) ->
+ {A, B, C} = get_seed(),
+ random:seed(A, B, C),
+ biglist(N, []).
+
+biglist(0, L) ->
+ L;
+biglist(N, L) ->
+ E = random_tuple(45, N),
+ biglist(N-1, [E|L]).
+
+%%%------------------------------------------------------------
+%%% Generate lists of given length, containing 2-tuples with
+%%% random integer elements in the range 0..10 as element 1.
+%%% Element 2 in the tuple is a random integer in the range 0..5.
+%%% No sequence number.
+
+ubiglist(N) ->
+ {A, B, C} = get_seed(),
+ random:seed(A, B, C),
+ ubiglist(N, []).
+
+ubiglist(0, L) ->
+ L;
+ubiglist(N, L) ->
+ E = urandom_tuple(11, 6),
+ ubiglist(N-1, [E|L]).
+
+urandom_tuple(N, I) ->
+ R1 = randint(N),
+ R2 = randint(I),
+ {R1, R2}.
+
+%%%------------------------------------------------------------
+%%% Generate lists of given length, containing 2-tuples with random
+%%% integer elements in the range 0..10 as elements 1. All tuples have
+%%% the same function as element 2, but every function is created in a
+%%% unique process. ==/2 will return 'true' for any pair of functions,
+%%% but erlang:fun_info(Fun, pid) can be used for distinguishing
+%%% functions created in different processes. The pid acts like a
+%%% sequence number.
+
+bigfunlist(N) ->
+ {A, B, C} = get_seed(),
+ random:seed(A, B, C),
+ bigfunlist_1(N).
+
+bigfunlist_1(N) when N < 30000 -> % Now (R8) max 32000 different pids.
+ case catch bigfunlist(N, 0, []) of
+ {'EXIT', _} ->
+ bigfunlist_1(N);
+ Reply ->
+ Reply
+ end.
+
+bigfunlist(0, _P, L) ->
+ lists:reverse(L);
+bigfunlist(N, P, L) ->
+ {E, NP} = random_funtuple(P, 11),
+ bigfunlist(N-1, NP, [E | L]).
+
+random_funtuple(P, N) ->
+ R = randint(N),
+ F = make_fun(),
+ NP = fun_pid(F),
+ true = NP > P,
+ {{R, F}, NP}.
+
+make_fun() ->
+ Pid = spawn(?MODULE, make_fun, [self()]),
+ receive {Pid, Fun} -> Fun end.
+
+make_fun(Pid) ->
+ Pid ! {self(), fun make_fun/1}.
+
+fun_pid(Fun) ->
+ erlang:fun_info(Fun, pid).
+
+get_seed() ->
+ case random:seed() of
+ undefined ->
+ now();
+ Tuple ->
+ Tuple
+ end.
+
+random_tuple(N, Seq) ->
+ R1 = randint(N),
+ R2 = randint(N),
+ {R1, R2, Seq}.
+
+randint(N) ->
+ trunc(random:uniform() * N).
+
+%% The first "duplicate" is kept.
+no_dups([]) ->
+ [];
+no_dups([H | T]) ->
+ no_dups(H, T, []).
+
+no_dups(H, [H1 | T], L) when H == H1 ->
+ no_dups(H, T, L);
+no_dups(H, [H1 | T], L) ->
+ no_dups(H1, T, [H | L]);
+no_dups(H, [], L) ->
+ lists:reverse([H | L]).
+
+%% The first "duplicate" is kept.
+no_dups_keys([], _I) ->
+ [];
+no_dups_keys([H | T], I) ->
+ no_dups_keys(H, T, [], I).
+
+no_dups_keys(H, [H1 | T], L, I) when element(I, H) == element(I, H1) ->
+ no_dups_keys(H, T, L, I);
+no_dups_keys(H, [H1 | T], L, I) ->
+ no_dups_keys(H1, T, [H | L], I);
+no_dups_keys(H, [], L, _I) ->
+ lists:reverse([H | L]).
+
+perms([]) ->
+ [[]];
+perms(L) ->
+ [[H|T] || H <- L, T <- perms(L--[H])].
+
+%%%------------------------------------------------------------
+%%% Test the sort routines with randomly generated lists.
+
+-record(state, {sort = 0, usort = 0, stable = 0}).
+
+%% Run it interactively. 'stop' or 'info' recognized commands.
+sort_loop() ->
+ sort_loop(5000).
+
+sort_loop(N) when is_integer(N), N > 0 ->
+ Pid = spawn_link(?MODULE, sloop, [N]),
+ sort_loop_1(Pid).
+
+sort_loop_1(Pid) ->
+ case io:get_line('? ') of
+ eof ->
+ ok;
+ "stop\n" ->
+ Pid ! {self(), stop},
+ receive {Pid, S} -> display_state(S) end;
+ "info\n" ->
+ Pid ! {self(), info},
+ receive {Pid, S} -> display_state(S) end,
+ sort_loop_1(Pid);
+ _Other ->
+ sort_loop_1(Pid)
+ end.
+
+sloop(N) ->
+ {A, B, C} = get_seed(),
+ random:seed(A, B, C),
+ sloop(N, #state{}).
+
+sloop(N, S) ->
+ receive
+ {From, stop} ->
+ From ! {self(), S};
+ {From, info} ->
+ From ! {self(), S},
+ sloop(N, S)
+ after 0 ->
+ Len = randint(N),
+ NS = case randint(3) of
+ 0 ->
+ BL = biglist(Len, []),
+ ok = check(BL),
+ ok = keysort_check3(1, BL),
+ ok = funsort_check3(1, BL),
+ S#state{sort = S#state.sort + 1};
+ 1 ->
+ BL = ubiglist(Len, []),
+ ok = ucheck(BL),
+ ok = gen_ukeysort_check(1, BL),
+ ok = gen_ufunsort_check(1, BL),
+ S#state{usort = S#state.usort + 1};
+ 2 ->
+ BL = bigfunlist(Len),
+ %% ok = check_stability(BL),
+ ok = ucheck_stability(BL),
+ ok = ukeysort_check_stability(BL),
+ ok = ufunsort_check_stability(BL),
+ S#state{stable = S#state.stable + 1}
+ end,
+ sloop(N, NS)
+ end.
+
+display_state(S) ->
+ io:format("sort: ~p~n", [S#state.sort]),
+ io:format("usort: ~p~n", [S#state.usort]),
+ io:format("stable: ~p~n", [S#state.stable]).
+
+%% This version of sort/1 is really stable; the order of equal
+%% elements is kept. It is used for checking the current
+%% implementation of usort/1 etc.
+
+lsort([X, Y | L] = L0) when X =< Y ->
+ case L of
+ [] ->
+ L0;
+ [Z] when Y =< Z ->
+ L0;
+ [Z] when X =< Z ->
+ [X, Z, Y];
+ [Z] ->
+ [Z, X, Y];
+ _ ->
+ split_1(X, Y, L, [], [])
+ end;
+lsort([X, Y | L]) ->
+ case L of
+ [] ->
+ [Y, X];
+ [Z] when X =< Z ->
+ [Y, X | L];
+ [Z] when Y =< Z ->
+ [Y, Z, X];
+ [Z] ->
+ [Z, Y, X];
+ _ ->
+ split_2(X, Y, L, [], [])
+ end;
+lsort([_] = L) ->
+ L;
+lsort([] = L) ->
+ L.
+
+split_1(X, Y, [Z | L], R, Rs) when Z >= Y ->
+ split_1(Y, Z, L, [X | R], Rs);
+split_1(X, Y, [Z | L], R, Rs) when Z >= X ->
+ split_1(Z, Y, L, [X | R], Rs);
+split_1(X, Y, [Z | L], [], Rs) ->
+ split_1(X, Y, L, [Z], Rs);
+split_1(X, Y, [Z | L], R, Rs) ->
+ split_1_1(X, Y, L, R, Rs, Z);
+split_1(X, Y, [], R, Rs) ->
+ rmergel([[Y, X | R] | Rs], [], asc).
+
+split_1_1(X, Y, [Z | L], R, Rs, S) when Z >= Y ->
+ split_1_1(Y, Z, L, [X | R], Rs, S);
+split_1_1(X, Y, [Z | L], R, Rs, S) when Z >= X ->
+ split_1_1(Z, Y, L, [X | R], Rs, S);
+split_1_1(X, Y, [Z | L], R, Rs, S) when S =< Z ->
+ split_1(S, Z, L, [], [[Y, X | R] | Rs]);
+split_1_1(X, Y, [Z | L], R, Rs, S) ->
+ split_1(Z, S, L, [], [[Y, X | R] | Rs]);
+split_1_1(X, Y, [], R, Rs, S) ->
+ rmergel([[S], [Y, X | R] | Rs], [], asc).
+
+split_2(X, Y, [Z | L], R, Rs) when Z < Y ->
+ split_2(Y, Z, L, [X | R], Rs);
+split_2(X, Y, [Z | L], R, Rs) when Z < X ->
+ split_2(Z, Y, L, [X | R], Rs);
+split_2(X, Y, [Z | L], [], Rs) ->
+ split_2(X, Y, L, [Z], Rs);
+split_2(X, Y, [Z | L], R, Rs) ->
+ split_2_1(X, Y, L, R, Rs, Z);
+split_2(X, Y, [], R, Rs) ->
+ mergel([[Y, X | R] | Rs], [], desc).
+
+split_2_1(X, Y, [Z | L], R, Rs, S) when Z < Y ->
+ split_2_1(Y, Z, L, [X | R], Rs, S);
+split_2_1(X, Y, [Z | L], R, Rs, S) when Z < X ->
+ split_2_1(Z, Y, L, [X | R], Rs, S);
+split_2_1(X, Y, [Z | L], R, Rs, S) when S > Z ->
+ split_2(S, Z, L, [], [[Y, X | R] | Rs]);
+split_2_1(X, Y, [Z | L], R, Rs, S) ->
+ split_2(Z, S, L, [], [[Y, X | R] | Rs]);
+split_2_1(X, Y, [], R, Rs, S) ->
+ mergel([[S], [Y, X | R] | Rs], [], desc).
+
+mergel([[] | L], Acc, O) ->
+ mergel(L, Acc, O);
+mergel([T1, [H2 | T2] | L], Acc, asc) ->
+ mergel(L, [merge2_1(T1, H2, T2, []) | Acc], asc);
+mergel([[H2 | T2], T1 | L], Acc, desc) ->
+ mergel(L, [merge2_1(T1, H2, T2, []) | Acc], desc);
+mergel([L], [], _O) ->
+ L;
+mergel([L], Acc, O) ->
+ rmergel([lists:reverse(L, []) | Acc], [], O);
+mergel([], [], _O) ->
+ [];
+mergel([], Acc, O) ->
+ rmergel(Acc, [], O);
+mergel([A, [] | L], Acc, O) ->
+ mergel([A | L], Acc, O);
+mergel([A, B, [] | L], Acc, O) ->
+ mergel([A, B | L], Acc, O).
+
+rmergel([[H2 | T2], T1 | L], Acc, asc) ->
+ rmergel(L, [rmerge2_1(T1, H2, T2, []) | Acc], asc);
+rmergel([T1, [H2 | T2] | L], Acc, desc) ->
+ rmergel(L, [rmerge2_1(T1, H2, T2, []) | Acc], desc);
+rmergel([L], Acc, O) ->
+ mergel([lists:reverse(L, []) | Acc], [], O);
+rmergel([], Acc, O) ->
+ mergel(Acc, [], O).
+
+merge2_1([H1 | T1], H2, T2, M) when H1 =< H2 ->
+ merge2_1(T1, H2, T2, [H1 | M]);
+merge2_1([H1 | T1], H2, T2, M) ->
+ merge2_2(T1, H1, T2, [H2 | M]);
+merge2_1([], H2, T2, M) ->
+ lists:reverse(T2, [H2 | M]).
+
+merge2_2(T1, H1, [H2 | T2], M) when H1 =< H2 ->
+ merge2_1(T1, H2, T2, [H1 | M]);
+merge2_2(T1, H1, [H2 | T2], M) ->
+ merge2_2(T1, H1, T2, [H2 | M]);
+merge2_2(T1, H1, [], M) ->
+ lists:reverse(T1, [H1 | M]).
+
+rmerge2_1([H1 | T1], H2, T2, M) when H1 =< H2 ->
+ rmerge2_2(T1, H1, T2, [H2 | M]);
+rmerge2_1([H1 | T1], H2, T2, M) ->
+ rmerge2_1(T1, H2, T2, [H1 | M]);
+rmerge2_1([], H2, T2, M) ->
+ lists:reverse(T2, [H2 | M]).
+
+rmerge2_2(T1, H1, [H2 | T2], M) when H1 =< H2 ->
+ rmerge2_2(T1, H1, T2, [H2 | M]);
+rmerge2_2(T1, H1, [H2 | T2], M) ->
+ rmerge2_1(T1, H2, T2, [H1 | M]);
+rmerge2_2(T1, H1, [], M) ->
+ lists:reverse(T1, [H1 | M]).
+
+
+
+%% This version of keysort/2 is really stable; the order of equal
+%% elements is kept. It is used for checking the current
+%% implementation of ukeysort/2 etc.
+
+lkeysort(Index, L) when is_integer(Index), Index > 0 ->
+ case L of
+ [] -> L;
+ [_] -> L;
+ [X, Y | T] ->
+ EX = element(Index, X),
+ EY = element(Index, Y),
+ if
+ EX =< EY ->
+ keysplit_1(Index, X, EX, Y, EY, T, [], []);
+ true ->
+ keysplit_2(Index, Y, EY, T, [X])
+ end
+ end.
+
+keysplit_1(I, X, EX, Y, EY, [Z | L], R, Rs) ->
+ EZ = element(I, Z),
+ if
+ EY =< EZ ->
+ keysplit_1(I, Y, EY, Z, EZ, L, [X | R], Rs);
+ EX =< EZ ->
+ keysplit_1(I, Z, EZ, Y, EY, L, [X | R], Rs);
+ true, R == [] ->
+ keysplit_1(I, X, EX, Y, EY, L, [Z], Rs);
+ true ->
+ keysplit_1_1(I, X, EX, Y, EY, L, R, Rs, Z, EZ)
+ end;
+keysplit_1(I, X, _EX, Y, _EY, [], R, Rs) ->
+ rkeymergel(I, [[Y, X | R] | Rs], []).
+
+%% One out-of-order element, S.
+keysplit_1_1(I, X, EX, Y, EY, [Z | L], R, Rs, S, ES) ->
+ EZ = element(I, Z),
+ if
+ EY =< EZ ->
+ keysplit_1_1(I, Y, EY, Z, EZ, L, [X | R], Rs, S, ES);
+ EX =< EZ ->
+ keysplit_1_1(I, Z, EZ, Y, EY, L, [X | R], Rs, S, ES);
+ ES =< EZ ->
+ keysplit_1(I, S, ES, Z, EZ, L, [], [[Y, X | R] | Rs]);
+ true ->
+ keysplit_1(I, Z, EZ, S, ES, L, [], [[Y, X | R] | Rs])
+ end;
+keysplit_1_1(I, X, _EX, Y, _EY, [], R, Rs, S, _ES) ->
+ rkeymergel(I, [[S], [Y, X | R] | Rs], []).
+
+%% Descending.
+keysplit_2(I, Y, EY, [Z | L], R) ->
+ EZ = element(I, Z),
+ if
+ EY =< EZ ->
+ keysplit_1(I, Y, EY, Z, EZ, L, [], [lists:reverse(R, [])]);
+ true ->
+ keysplit_2(I, Z, EZ, L, [Y | R])
+ end;
+keysplit_2(_I, Y, _EY, [], R) ->
+ [Y | R].
+
+keymergel(I, [T1, [H2 | T2] | L], Acc) ->
+ keymergel(I, L, [keymerge2_1(I, T1, element(I, H2), H2, T2, []) | Acc]);
+keymergel(_I, [L], []) ->
+ L;
+keymergel(I, [L], Acc) ->
+ rkeymergel(I, [lists:reverse(L, []) | Acc], []);
+keymergel(I, [], Acc) ->
+ rkeymergel(I, Acc, []).
+
+rkeymergel(I, [[H2 | T2], T1 | L], Acc) ->
+ rkeymergel(I, L, [rkeymerge2_1(I, T1, element(I, H2), H2, T2, []) | Acc]);
+rkeymergel(I, [L], Acc) ->
+ keymergel(I, [lists:reverse(L, []) | Acc], []);
+rkeymergel(I, [], Acc) ->
+ keymergel(I, Acc, []).
+
+keymerge2_1(I, [H1 | T1], E2, H2, T2, M) ->
+ E1 = element(I, H1),
+ if
+ E1 =< E2 ->
+ keymerge2_1(I, T1, E2, H2, T2, [H1 | M]);
+ true ->
+ keymerge2_2(I, T1, E1, H1, T2, [H2 | M])
+ end;
+keymerge2_1(_I, [], _E2, H2, T2, M) ->
+ lists:reverse(T2, [H2 | M]).
+
+keymerge2_2(I, T1, E1, H1, [H2 | T2], M) ->
+ E2 = element(I, H2),
+ if
+ E1 =< E2 ->
+ keymerge2_1(I, T1, E2, H2, T2, [H1 | M]);
+ true ->
+ keymerge2_2(I, T1, E1, H1, T2, [H2 | M])
+ end;
+keymerge2_2(_I, T1, _E1, H1, [], M) ->
+ lists:reverse(T1, [H1 | M]).
+
+rkeymerge2_1(I, [H1 | T1], E2, H2, T2, M) ->
+ E1 = element(I, H1),
+ if
+ E1 =< E2 ->
+ rkeymerge2_2(I, T1, E1, T2, [H2 | M], H1);
+ true ->
+ rkeymerge2_1(I, T1, E2, H2, T2, [H1 | M])
+ end;
+rkeymerge2_1(_I, [], _E2, H2, T2, M) ->
+ lists:reverse(T2, [H2 | M]).
+
+rkeymerge2_2(I, T1, E1, [H2 | T2], M, H1) ->
+ E2 = element(I, H2),
+ if
+ E1 =< E2 ->
+ rkeymerge2_2(I, T1, E1, T2, [H2 | M], H1);
+ true ->
+ rkeymerge2_1(I, T1, E2, H2, T2, [H1 | M])
+ end;
+rkeymerge2_2(_I, T1, _E1, [], M, H1) ->
+ lists:reverse(T1, [H1 | M]).
+
+
+%%%------------------------------------------------------------
+
+seq(doc) ->
+ ["Tests lists:seq/3"];
+seq(suite) ->
+ [
+ seq_loop,
+ seq_2, seq_3, seq_2_e, seq_3_e].
+
+seq_loop(doc) ->
+ ["Test for infinite loop (OTP-2404)."];
+seq_loop(suite) ->
+ [];
+seq_loop(Config) when is_list(Config) ->
+ ?line _ = (catch lists:seq(1, 5, -1)),
+ ok.
+
+seq_2(doc) ->
+ ["Non-error cases for seq/2"];
+seq_2(suite) ->
+ [];
+seq_2(Config) when is_list(Config) ->
+ ?line [1,2,3] = lists:seq(1,3),
+ ?line [1] = lists:seq(1,1),
+ ?line Big = 748274827583793785928592859,
+ ?line Big1 = Big+1,
+ ?line Big2 = Big+2,
+ ?line [Big, Big1, Big2] = lists:seq(Big, Big+2),
+ ok.
+
+seq_2_e(doc) ->
+ ["Error cases for seq/2"];
+seq_2_e(suite) ->
+ [];
+seq_2_e(Config) when is_list(Config) ->
+ ?line seq_error([4, 2]),
+ ?line seq_error([1, a]),
+ ?line seq_error([1.0, 2.0]),
+ ok.
+
+seq_error(Args) ->
+ {'EXIT', _} = (catch apply(lists, seq, Args)).
+
+seq_3(doc) ->
+ ["Non-error cases for seq/3"];
+seq_3(suite) ->
+ [];
+seq_3(Config) when is_list(Config) ->
+ ?line [1,2,3] = lists:seq(1,3,1),
+ ?line [1] = lists:seq(1,1,1),
+ ?line Big = 748274827583793785928592859,
+ ?line Big1 = Big+1,
+ ?line Big2 = Big+2,
+ ?line [Big, Big1, Big2] = lists:seq(Big, Big+2,1),
+
+ ?line [3,2,1] = lists:seq(3,1,-1),
+ ?line [1] = lists:seq(1,1,-1),
+
+ ?line [3,1] = lists:seq(3,1,-2),
+ ?line [1] = lists:seq(1, 10, 10),
+ ?line [1, 4, 7, 10, 13, 16, 19] = lists:seq(1, 19, 3),
+ ?line [1, 4, 7, 10, 13, 16, 19] = lists:seq(1, 20, 3),
+ ?line [1, 4, 7, 10, 13, 16, 19] = lists:seq(1, 21, 3),
+
+ ?line [1] = lists:seq(1, 1, 0), %OTP-2613
+ ok.
+
+seq_3_e(doc) ->
+ ["Error cases for seq/3"];
+seq_3_e(suite) ->
+ [];
+seq_3_e(Config) when is_list(Config) ->
+ ?line seq_error([4, 2, 1]),
+ ?line seq_error([3, 5, -1]),
+ ?line seq_error([1, a, 1]),
+ ?line seq_error([1.0, 2.0, 1]),
+
+ ?line seq_error([1, 3, 1.0]),
+ ?line seq_error([1, 3, a]),
+ ?line seq_error([1, 3, 0]),
+
+ ?line seq_error([a, a, 0]),
+ ok.
+
+otp_7230(doc) ->
+ ["OTP-7230. seq/1,2 returns the empty list"];
+otp_7230(suite) ->
+ [];
+otp_7230(Config) when is_list(Config) ->
+ From = -10,
+ To = 10,
+ StepFrom = -10,
+ StepTo = 10,
+
+ L = lists:seq(From, To),
+ SL = lists:seq(StepFrom, StepTo),
+ ?line [] =
+ [{F, T, S} ||
+ F <- L, T <- L, S <- SL,
+ not check_seq(F, T, S, catch lists:seq(F, T, S))
+ orelse
+ S =:= 1 andalso not check_seq(F, T, S, catch lists:seq(F, T))
+ ].
+
+check_seq(From, To, 0, R) ->
+ From =:= To andalso R =:= [From]
+ orelse
+ From =/= To andalso is_tuple(R) andalso element(1, R) =:= 'EXIT';
+check_seq(From, To, Step, []) when Step =/= 0 ->
+ 0 =:= property(From, To, Step)
+ andalso
+ (
+ Step > 0 andalso To < From andalso From-To =< Step
+ orelse
+ Step < 0 andalso To > From andalso To-From =< -Step
+ );
+check_seq(From, To, Step, R) when R =/= [], To < From, Step > 0 ->
+ is_tuple(R) andalso element(1, R) =:= 'EXIT';
+check_seq(From, To, Step, R) when R =/= [], To > From, Step < 0 ->
+ is_tuple(R) andalso element(1, R) =:= 'EXIT';
+check_seq(From, To, Step, L) when is_list(L), L =/= [], Step =/= 0 ->
+ First = hd(L),
+ Last = lists:last(L),
+ Min = lists:min(L),
+ Max = lists:max(L),
+
+ [] =:= [E || E <- L, not is_integer(E)]
+ andalso
+ %% The difference between two consecutive elements is Step:
+ begin
+ LS = [First-Step]++L,
+ LR = L++[Last+Step],
+ [Step] =:= lists:usort([B-A || {A,B} <- lists:zip(LS, LR)])
+ end
+ andalso
+ %% The first element of L is From:
+ From =:= First
+ andalso
+ %% No element outside the given interval:
+ Min >= lists:min([From, To])
+ andalso
+ Max =< lists:max([From, To])
+ andalso
+ %% All elements are present:
+ abs(To-Last) < abs(Step)
+ andalso
+ length(L) =:= property(From, To, Step);
+check_seq(_From, _To, _Step, _R) ->
+ false.
+
+property(From, To, Step) ->
+ ((To-From+Step) div Step).
+
+%%%------------------------------------------------------------
+
+sublist(doc) ->
+ ["Tests lists:sublist/[2,3]"];
+sublist(suite) ->
+ [sublist_2, sublist_3, sublist_2_e, sublist_3_e].
+
+-define(sublist_error2(X,Y), ?line {'EXIT', _} = (catch lists:sublist(X,Y))).
+-define(sublist_error3(X,Y,Z), ?line {'EXIT', _} = (catch lists:sublist(X,Y,Z))).
+
+sublist_2(doc) -> ["sublist/2"];
+sublist_2(suite) -> [];
+sublist_2(Config) when is_list(Config) ->
+ ?line [] = lists:sublist([], 0),
+ ?line [] = lists:sublist([], 1),
+ ?line [] = lists:sublist([a], 0),
+ ?line [a] = lists:sublist([a], 1),
+ ?line [a] = lists:sublist([a], 2),
+ ?line [a] = lists:sublist([a|b], 1),
+
+ ?line [a,b] = lists:sublist([a,b|c], 2),
+
+ ok.
+
+sublist_2_e(doc) -> ["sublist/2 error cases"];
+sublist_2_e(suite) -> [];
+sublist_2_e(Config) when is_list(Config) ->
+ ?sublist_error2([], -1),
+ ?sublist_error2(a, -1),
+ ?sublist_error2(a, 0),
+ ?sublist_error2([a|b], 2),
+ ?sublist_error2([a], x),
+ ?sublist_error2([a], 1.5),
+ ?sublist_error2([], x),
+ ?sublist_error2([], 1.5),
+ ok.
+
+sublist_3(doc) -> ["sublist/3"];
+sublist_3(suite) -> [];
+sublist_3(Config) when is_list(Config) ->
+ ?line [] = lists:sublist([], 1, 0),
+ ?line [] = lists:sublist([], 1, 1),
+ ?line [] = lists:sublist([a], 1, 0),
+ ?line [a] = lists:sublist([a], 1, 1),
+ ?line [a] = lists:sublist([a], 1, 2),
+ ?line [a] = lists:sublist([a|b], 1, 1),
+
+ ?line [] = lists:sublist([], 1, 0),
+ ?line [] = lists:sublist([], 1, 1),
+ ?line [] = lists:sublist([a], 1, 0),
+ ?line [a] = lists:sublist([a], 1, 1),
+ ?line [a] = lists:sublist([a], 1, 2),
+ ?line [] = lists:sublist([a], 2, 1),
+ ?line [] = lists:sublist([a], 2, 2),
+ ?line [] = lists:sublist([a], 2, 79),
+ ?line [] = lists:sublist([a,b|c], 1, 0),
+ ?line [] = lists:sublist([a,b|c], 2, 0),
+ ?line [a] = lists:sublist([a,b|c], 1, 1),
+ ?line [b] = lists:sublist([a,b|c], 2, 1),
+ ?line [a,b] = lists:sublist([a,b|c], 1, 2),
+
+ ?line [] = lists:sublist([a], 2, 0),
+
+ ok.
+
+sublist_3_e(doc) -> ["sublist/3 error cases"];
+sublist_3_e(suite) -> [];
+sublist_3_e(Config) when is_list(Config) ->
+ ?sublist_error3([], 1, -1),
+ ?sublist_error3(a, 1, -1),
+ ?sublist_error3(a, 1, 0),
+ ?sublist_error3([a|b], 1, 2),
+ ?sublist_error3([a], 1, x),
+ ?sublist_error3([a], 1, 1.5),
+ ?sublist_error3([], 1, x),
+ ?sublist_error3([], 1, 1.5),
+
+ ?sublist_error3([], -1, 0),
+ ?sublist_error3(a, x, -1),
+ ?sublist_error3([a,b], 0.5, 1),
+ ?sublist_error3([a,b], 1.5, 1),
+ ?sublist_error3([a], 1, x),
+ ?sublist_error3([a], 1, 1.5),
+ ?sublist_error3([], 1, x),
+ ?sublist_error3([], 1, 1.5),
+
+ ?sublist_error3([a], 0, -1),
+ ?sublist_error3([a], 1, -1),
+ ?sublist_error3([a], 2, -1),
+ ?sublist_error3([a], 0, 0),
+ ?sublist_error3([a], 0, 1),
+
+ ?sublist_error3([a,b|c], 2, 2),
+ ?sublist_error3([a,b|c], 3, 0),
+ ?sublist_error3([a,b|c], 3, 1),
+ ok.
+
+%%%------------------------------------------------------------
+
+flatten(doc) ->
+ ["Tests lists:flatten/[1,2]"];
+flatten(suite) ->
+ [flatten_1, flatten_2, flatten_1_e, flatten_2_e].
+
+-define(flatten_error1(X), ?line {'EXIT', _} = (catch lists:flatten(X))).
+-define(flatten_error2(X,Y), ?line {'EXIT', _} = (catch lists:flatten(X,Y))).
+
+flatten_1(doc) -> ["flatten/1"];
+flatten_1(suite) -> [];
+flatten_1(Config) when is_list(Config) ->
+ ?line [] = lists:flatten([]),
+ ?line [1,2] = lists:flatten([1,2]),
+ ?line [1,2] = lists:flatten([1,[2]]),
+ ?line [1,2] = lists:flatten([[1],2]),
+ ?line [1,2] = lists:flatten([[1],[2]]),
+ ?line [1,2] = lists:flatten([[1,2]]),
+ ?line [a,b,c,d] = lists:flatten([[a],[b,c,[d]]]),
+
+ ok.
+
+flatten_1_e(doc) -> ["flatten/1 error cases"];
+flatten_1_e(suite) -> [];
+flatten_1_e(Config) when is_list(Config) ->
+ ?flatten_error1(a),
+ ?flatten_error1([a|b]),
+ ?flatten_error1([[a],[b|c],[d]]),
+ ok.
+
+%%% [arndt] What if second arg isn't a proper list? This issue isn't
+%%% clear-cut. Right now, I think that any term should be allowed.
+%%% But I also wish this function didn't exist at all.
+
+flatten_2(doc) -> ["flatten/2"];
+flatten_2(suite) -> [];
+flatten_2(Config) when is_list(Config) ->
+ ?line [] = lists:flatten([]),
+ ?line [a] = lists:flatten([a]),
+ ok.
+
+flatten_2_e(doc) -> ["flatten/2 error cases"];
+flatten_2_e(suite) -> [];
+flatten_2_e(Config) when is_list(Config) ->
+ ok.
+
+%% Test lists:zip/2, lists:unzip/1.
+zip_unzip(Config) when is_list(Config) ->
+ ?line [] = lists:zip([], []),
+ ?line [{a,b}] = lists:zip([a], [b]),
+ ?line [{42.0,{kalle,nisse}},{a,b}] = lists:zip([42.0,a], [{kalle,nisse},b]),
+
+ %% Longer lists.
+ ?line SeqA = lists:seq(45, 200),
+ ?line SeqB = [A*A || A <- SeqA],
+ ?line AB = lists:zip(SeqA, SeqB),
+ ?line SeqA = [A || {A,_} <- AB],
+ ?line SeqB = [B || {_,B} <- AB],
+ ?line {SeqA,SeqB} = lists:unzip(AB),
+
+ %% Some more unzip/1.
+ ?line {[],[]} = lists:unzip([]),
+ ?line {[a],[b]} = lists:unzip([{a,b}]),
+ ?line {[a,c],[b,d]} = lists:unzip([{a,b},{c,d}]),
+
+ %% Error cases.
+ ?line {'EXIT',{function_clause,_}} = (catch lists:zip([], [b])),
+ ?line {'EXIT',{function_clause,_}} = (catch lists:zip([a], [])),
+ ?line {'EXIT',{function_clause,_}} = (catch lists:zip([a], [b,c])),
+ ?line {'EXIT',{function_clause,_}} = (catch lists:zip([a], [b,c])),
+ ok.
+
+%% Test lists:zip3/3, lists:unzip3/1.
+zip_unzip3(Config) when is_list(Config) ->
+ ?line [] = lists:zip3([], [], []),
+ ?line [{a,b,c}] = lists:zip3([a], [b], [c]),
+
+ %% Longer lists.
+ ?line SeqA = lists:seq(45, 200),
+ ?line SeqB = [2*A || A <- SeqA],
+ ?line SeqC = [A*A || A <- SeqA],
+ ?line ABC = lists:zip3(SeqA, SeqB, SeqC),
+ ?line SeqA = [A || {A,_,_} <- ABC],
+ ?line SeqB = [B || {_,B,_} <- ABC],
+ ?line SeqC = [C || {_,_,C} <- ABC],
+ ?line {SeqA,SeqB,SeqC} = lists:unzip3(ABC),
+
+ %% Some more unzip3/1.
+ ?line {[],[],[]} = lists:unzip3([]),
+ ?line {[a],[b],[c]} = lists:unzip3([{a,b,c}]),
+
+ %% Error cases.
+ ?line {'EXIT',{function_clause,_}} = (catch lists:zip3([], [], [c])),
+ ?line {'EXIT',{function_clause,_}} = (catch lists:zip3([], [b], [])),
+ ?line {'EXIT',{function_clause,_}} = (catch lists:zip3([a], [], [])),
+
+ ok.
+
+%% Test lists:zipwith/3.
+zipwith(Config) when is_list(Config) ->
+ Zip = fun(A, B) -> [A|B] end,
+
+ ?line [] = lists:zipwith(Zip, [], []),
+ ?line [[a|b]] = lists:zipwith(Zip, [a], [b]),
+
+ %% Longer lists.
+ ?line SeqA = lists:seq(77, 300),
+ ?line SeqB = [A*A || A <- SeqA],
+ ?line AB = lists:zipwith(Zip, SeqA, SeqB),
+ ?line SeqA = [A || [A|_] <- AB],
+ ?line SeqB = [B || [_|B] <- AB],
+
+ %% Error cases.
+ ?line {'EXIT',{function_clause,_}} = (catch lists:zipwith(badfun, [], [])),
+ ?line {'EXIT',{function_clause,_}} = (catch lists:zipwith(Zip, [], [b])),
+ ?line {'EXIT',{function_clause,_}} = (catch lists:zipwith(Zip, [a], [])),
+ ?line {'EXIT',{function_clause,_}} = (catch lists:zipwith(Zip, [a], [b,c])),
+ ?line {'EXIT',{function_clause,_}} = (catch lists:zipwith(Zip, [a], [b,c])),
+ ok.
+
+%% Test lists:zipwith3/4.
+zipwith3(Config) when is_list(Config) ->
+ Zip = fun(A, B, C) -> [A,B,C] end,
+
+ ?line [] = lists:zipwith3(Zip, [], [], []),
+ ?line [[a,b,c]] = lists:zipwith3(Zip, [a], [b], [c]),
+
+ %% Longer lists.
+ ?line SeqA = lists:seq(45, 200),
+ ?line SeqB = [2*A || A <- SeqA],
+ ?line SeqC = [A*A || A <- SeqA],
+ ?line ABC = lists:zipwith3(Zip, SeqA, SeqB, SeqC),
+ ?line SeqA = [A || [A,_,_] <- ABC],
+ ?line SeqB = [B || [_,B,_] <- ABC],
+ ?line SeqC = [C || [_,_,C] <- ABC],
+
+ %% Error cases.
+ ?line {'EXIT',{function_clause,_}} = (catch lists:zipwith3(badfun, [], [], [])),
+ ?line {'EXIT',{function_clause,_}} = (catch lists:zipwith3(Zip, [], [], [c])),
+ ?line {'EXIT',{function_clause,_}} = (catch lists:zipwith3(Zip, [], [b], [])),
+ ?line {'EXIT',{function_clause,_}} = (catch lists:zipwith3(Zip, [a], [], [])),
+
+ ok.
+
+%% Test lists:filter/2, lists:partition/2.
+filter_partition(Config) when is_list(Config) ->
+ F = fun(I) -> I rem 2 =:= 0 end,
+ ?line filpart(F, [], []),
+ ?line filpart(F, [1], []),
+ ?line filpart(F, [1,3,17], []),
+ ?line filpart(F, [1,2,3,17], [2]),
+ ?line filpart(F, [6,8,1,2,3,17], [6,8,2]),
+ ?line filpart(F, [6,8,1,2,42,3,17], [6,8,2,42]),
+
+ %% Error cases.
+ ?line {'EXIT',{function_clause,_}} = (catch lists:filter(badfun, [])),
+ ?line {'EXIT',{function_clause,_}} = (catch lists:partition(badfun, [])),
+ ok.
+
+filpart(F, All, Exp) ->
+ Exp = lists:filter(F, All),
+ Other = lists:filter(fun(E) -> not F(E) end, All),
+ {Exp,Other} = lists:partition(F, All).
+
+tickets(doc) ->
+ ["Ticktes."];
+tickets(suite) ->
+ [otp_5939, otp_6023, otp_6606, otp_7230].
+
+otp_5939(doc) -> ["OTP-5939. Guard tests added."];
+otp_5939(suite) -> [];
+otp_5939(Config) when is_list(Config) ->
+ Fun1 = fun(A) -> A end,
+ Fun2 = fun(A, B) -> {A,B} end,
+ Fun3 = fun(A, B, C) -> {A,B,C} end,
+ Pred = fun(_A) -> true end,
+ Fold = fun(_E, A) -> A end,
+ MapFold = fun(E, A) -> {E,A} end,
+
+ ?line {'EXIT', _} = (catch lists:usort( [asd], [qwe])),
+
+ ?line {'EXIT', _} = (catch lists:zipwith(func, [], [])),
+ ?line [] = lists:zipwith(Fun2, [], []),
+ ?line {'EXIT', _} = (catch lists:zipwith3(func, [], [], [])),
+ ?line [] = lists:zipwith3(Fun3, [], [], []),
+ ?line {'EXIT', _} = (catch lists:keymap(func, 1, [])),
+ ?line {'EXIT', _} = (catch lists:keymap(Fun1, 0, [])),
+ ?line [] = lists:keymap(Fun1, 1, []),
+ ?line {'EXIT', _} = (catch lists:merge(func, [], [1])),
+ ?line {'EXIT', _} = (catch lists:merge(func, [1], [])),
+ ?line [] = lists:merge(Fun2, [], []),
+ ?line {'EXIT', _} = (catch lists:rmerge(func, [], [1])),
+ ?line {'EXIT', _} = (catch lists:rmerge(func, [1], [])),
+ ?line [] = lists:rmerge(Fun2, [], []),
+ ?line {'EXIT', _} = (catch lists:usort(func, [])),
+ ?line {'EXIT', _} = (catch lists:usort(func, [a])),
+ ?line {'EXIT', _} = (catch lists:usort(func, [a, b])),
+ ?line [] = lists:usort(Fun2, []),
+ ?line {'EXIT', _} = (catch lists:umerge(func, [], [1])),
+ ?line {'EXIT', _} = (catch lists:merge(func, [1], [])),
+ ?line [] = lists:umerge(Fun2, [], []),
+ ?line {'EXIT', _} = (catch lists:rumerge(func, [], [1])),
+ ?line {'EXIT', _} = (catch lists:rumerge(func, [1], [])),
+ ?line [] = lists:rumerge(Fun2, [], []),
+ ?line {'EXIT', _} = (catch lists:all(func, [])),
+ ?line true = lists:all(Pred, []),
+ ?line {'EXIT', _} = (catch lists:any(func, [])),
+ ?line false = lists:any(Pred, []),
+ ?line {'EXIT', _} = (catch lists:map(func, [])),
+ ?line [] = lists:map(Fun1, []),
+ ?line {'EXIT', _} = (catch lists:flatmap(func, [])),
+ ?line [] = lists:flatmap(Fun1, []),
+ ?line {'EXIT', _} = (catch lists:foldl(func, [], [])),
+ ?line [] = lists:foldl(Fold, [], []),
+ ?line {'EXIT', _} = (catch lists:foldr(func, [], [])),
+ ?line [] = lists:foldr(Fold, [], []),
+ ?line {'EXIT', _} = (catch lists:filter(func, [])),
+ ?line [] = lists:filter(Pred, []),
+ ?line {'EXIT', _} = (catch lists:partition(func, [])),
+ ?line {[],[]} = lists:partition(Pred, []),
+ ?line {'EXIT', _} = (catch lists:zf(func, [])),
+ ?line [] = lists:zf(Fun1, []),
+ ?line {'EXIT', _} = (catch lists:foreach(func, [])),
+ ?line ok = lists:foreach(Fun1, []),
+ ?line {'EXIT', _} = (catch lists:mapfoldl(func, [], [])),
+ ?line {[],[]} = lists:mapfoldl(MapFold, [], []),
+ ?line {'EXIT', _} = (catch lists:mapfoldr(func, [], [])),
+ ?line {[],[]} = lists:mapfoldr(MapFold, [], []),
+ ?line {'EXIT', _} = (catch lists:takewhile(func, [])),
+ ?line [] = lists:takewhile(Pred, []),
+ ?line {'EXIT', _} = (catch lists:dropwhile(func, [])),
+ ?line [] = lists:dropwhile(Pred, []),
+ ?line {'EXIT', _} = (catch lists:splitwith(func, [])),
+ ?line {[],[]} = lists:splitwith(Pred, []),
+
+ ok.
+
+otp_6023(doc) -> ["OTP-6023. lists:keyreplace/4, a typecheck."];
+otp_6023(suite) -> [];
+otp_6023(Config) when is_list(Config) ->
+ ?line {'EXIT', _} = (catch lists:keyreplace(a, 2, [{1,a}], b)),
+ ?line [{2,b}] = lists:keyreplace(a, 2, [{1,a}], {2,b}),
+
+ ok.
+
+otp_6606(doc) -> ["OTP-6606. sort and keysort bug"];
+otp_6606(suite) -> [];
+otp_6606(Config) when is_list(Config) ->
+ I = 1,
+ F = float(1),
+ L1 = [{F,I},{F,F},{I,I},{I,F}],
+ ?line L1 = lists:keysort(1, L1),
+ ?line L1 = lists:sort(L1),
+ L2 = [{I,I},{I,F},{F,I},{F,F}],
+ ?line L2 = lists:keysort(1, L2),
+ ?line L2 = lists:sort(L2),
+ ok.
+
+%% Test lists:suffix/2.
+suffix(Config) when is_list(Config) ->
+ ?line true = lists:suffix([], []),
+ ?line true = lists:suffix([], [a]),
+ ?line true = lists:suffix([], [a,b]),
+ ?line true = lists:suffix([], [a,b,c]),
+ ?line true = lists:suffix([a], lists:duplicate(200000, a)),
+ ?line true = lists:suffix(lists:seq(1, 1024),
+ lists:seq(2, 64000) ++ lists:seq(1, 1024)),
+ ?line true = lists:suffix(lists:duplicate(20000, a),
+ lists:duplicate(200000, a)),
+ ?line true = lists:suffix([2.0,3.0], [1.0,2.0,3.0]),
+
+ %% False cases.
+ ?line false = lists:suffix([a], []),
+ ?line false = lists:suffix([a,b,c], []),
+ ?line false = lists:suffix([a,b,c], [b,c]),
+ ?line false = lists:suffix([a,b,c], [a,b,c,a,b]),
+ ?line false = lists:suffix(lists:duplicate(199999, a)++[b],
+ lists:duplicate(200000, a)),
+ ?line false = lists:suffix([2.0,3.0], [1,2,3]),
+
+ %% Error cases.
+ ?line {'EXIT',_} = (catch lists:suffix({a,b,c}, [])),
+ ?line {'EXIT',_} = (catch lists:suffix([], {a,b})),
+ ?line {'EXIT',_} = (catch lists:suffix([a|b], [])),
+ ?line {'EXIT',_} = (catch lists:suffix([a,b|c], [a|b])),
+ ?line {'EXIT',_} = (catch lists:suffix([a|b], [a,b|c])),
+ ?line {'EXIT',_} = (catch lists:suffix([a|b], [a|b])),
+
+ ok.
+
+%% Test lists:subtract/2 and the '--' operator.
+subtract(Config) when is_list(Config) ->
+ ?line [] = sub([], []),
+ ?line [] = sub([], [a]),
+ ?line [] = sub([], lists:seq(1, 1024)),
+ ?line sub_non_matching([a], []),
+ ?line sub_non_matching([1,2], [make_ref()]),
+ ?line sub_non_matching(lists:seq(1, 1024), [make_ref(),make_ref()]),
+
+ %% Matching subtracts.
+ ?line [] = sub([a], [a]),
+ ?line [a] = sub([a,b], [b]),
+ ?line [a] = sub([a,b], [b,c]),
+ ?line [a] = sub([a,b,c], [b,c]),
+ ?line [a] = sub([a,b,c], [b,c]),
+ ?line [d,a,a] = sub([a,b,c,d,a,a], [a,b,c]),
+ ?line [d,x,a] = sub([a,b,c,d,a,x,a], [a,b,c,a]),
+ ?line [1,2,3,4,5,6,7,8,9,9999,10000,20,21,22] =
+ sub(lists:seq(1, 10000)++[20,21,22], lists:seq(10, 9998)),
+
+ %% Floats/integers.
+ ?line [42.0,42.0] = sub([42.0,42,42.0], [42,42,42]),
+ ?line [1,2,3,4,43.0] = sub([1,2,3,4,5,42.0,43.0], [42.0,5]),
+
+ %% Crashing subtracts.
+ ?line {'EXIT',_} = (catch sub([], [a|b])),
+ ?line {'EXIT',_} = (catch sub([a], [a|b])),
+ ?line {'EXIT',_} = (catch sub([a|b], [])),
+ ?line {'EXIT',_} = (catch sub([a|b], [])),
+ ?line {'EXIT',_} = (catch sub([a|b], [a])),
+
+ ok.
+
+sub_non_matching(A, B) ->
+ A = sub(A, B).
+
+sub(A, B) ->
+ Res = A -- B,
+ Res = lists:subtract(A, B).
+
diff --git a/lib/stdlib/test/log_mf_h_SUITE.erl b/lib/stdlib/test/log_mf_h_SUITE.erl
new file mode 100644
index 0000000000..640261f665
--- /dev/null
+++ b/lib/stdlib/test/log_mf_h_SUITE.erl
@@ -0,0 +1,92 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(log_mf_h_SUITE).
+
+-include("test_server.hrl").
+-include_lib("kernel/include/file.hrl").
+
+-export([all/1, test/1]).
+
+all(suite) -> [test].
+
+
+%%-----------------------------------------------------------------
+%% This is actually very basic tests, maybe we could test some more
+%% in the future...
+%%-----------------------------------------------------------------
+
+test(Config) when is_list(Config) ->
+ ?line {ok, Pid} = gen_event:start_link(),
+ ?line PrivDir = ?config(priv_dir, Config),
+ Log1 = PrivDir ++ "/log1",
+ ?line ok = file:make_dir(Log1),
+ Args1 = log_mf_h:init(Log1, 500, 3),
+ gen_event:add_handler(Pid, log_mf_h, Args1),
+ generate(Pid, 200),
+ {ok, Files} = file:list_dir(Log1),
+ ?line true = lists:member("1", Files),
+ ?line true = lists:member("index", Files),
+ ?line false = lists:member("2", Files),
+ generate(Pid, 2500),
+ %% The documentation doesn't guarantee that syncing one request
+ %% causes all previous ones to be finished too, but that seems to
+ %% be the case. We need to be sure that the files exist when we
+ %% look for them with 'list_dir'.
+ gen_event:sync_notify(Pid, "end"),
+ {ok, Files2} = file:list_dir(Log1),
+ ?line true = lists:member("1", Files2),
+ ?line true = lists:member("2", Files2),
+ ?line true = lists:member("3", Files2),
+ ?line false = lists:member("4", Files2),
+ ?line true = lists:member("index", Files2),
+ ?line {ok, #file_info{size=Size1,type=regular}} = file:read_file_info(Log1 ++ "/1"),
+ ?line if Size1 > 500 -> test_server:fail({too_big, Size1});
+ true -> ok end,
+ ?line {ok, #file_info{size=Size2,type=regular}} = file:read_file_info(Log1 ++ "/2"),
+ ?line if Size2 > 500 -> test_server:fail({too_big, Size2});
+ true -> ok end,
+ ?line {ok, #file_info{size=Size3,type=regular}} = file:read_file_info(Log1 ++ "/3"),
+ ?line if Size3 > 500 -> test_server:fail({too_big, Size3});
+ true -> ok end,
+ gen_event:delete_handler(Pid, log_mf_h, []),
+ ?line {ok, Index} = read_index_file(Log1),
+ gen_event:add_handler(Pid, log_mf_h, Args1),
+ X = if Index == 3 -> 1; true -> Index + 1 end,
+ ?line {ok, X} = read_index_file(Log1).
+
+
+generate(Pid, Bytes) when Bytes > 32 ->
+ gen_event:notify(Pid, make_list(32, [])),
+ generate(Pid, Bytes - 32);
+generate(_, _) -> ok.
+
+make_list(0, Res) -> Res;
+make_list(N, Res) -> make_list(N-1, [67 | Res]).
+
+
+read_index_file(Dir) ->
+ case file:open(Dir ++ "/index", [read,raw]) of
+ {ok, Fd} ->
+ case catch file:read(Fd, 1) of
+ {ok, [Index]} -> {ok, Index};
+ _ -> error
+ end;
+ _ -> error
+ end.
+
diff --git a/lib/stdlib/test/ms_transform_SUITE.erl b/lib/stdlib/test/ms_transform_SUITE.erl
new file mode 100644
index 0000000000..cf0926b7fa
--- /dev/null
+++ b/lib/stdlib/test/ms_transform_SUITE.erl
@@ -0,0 +1,730 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(ms_transform_SUITE).
+-author('[email protected]').
+
+-include("test_server.hrl").
+
+-export([all/1]).
+-export([basic_ets/1]).
+-export([basic_dbg/1]).
+-export([from_shell/1]).
+-export([records/1]).
+-export([record_index/1]).
+-export([multipass/1]).
+-export([top_match/1]).
+-export([old_guards/1]).
+-export([autoimported/1]).
+-export([semicolon/1]).
+-export([bitsyntax/1]).
+-export([record_defaults/1]).
+-export([andalso_orelse/1]).
+-export([float_1_function/1]).
+-export([action_function/1]).
+-export([init_per_testcase/2, fin_per_testcase/2]).
+
+init_per_testcase(_Func, Config) ->
+ Dog=test_server:timetrap(test_server:seconds(360)),
+ [{watchdog, Dog}|Config].
+
+fin_per_testcase(_Func, Config) ->
+ Dog=?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog).
+
+all(suite) -> [from_shell,basic_ets,basic_dbg,records,record_index,multipass,
+ bitsyntax, record_defaults, andalso_orelse,
+ float_1_function, action_function,
+ top_match, old_guards, autoimported, semicolon].
+
+andalso_orelse(suite) ->
+ [];
+andalso_orelse(doc) ->
+ ["Tests that andalso and orelse are allowed in guards."];
+andalso_orelse(Config) when list(Config) ->
+ ?line setup(Config),
+ ?line [{{'$1','$2'},
+ [{'and',{is_integer,'$1'},{'>',{'+','$1',5},'$2'}}],
+ [{'andalso','$1','$2'}]}] =
+ compile_and_run(<<"ets:fun2ms(fun({A,B}) "
+ " when is_integer(A) and (A+5 > B) -> "
+ " A andalso B "
+ " end)">>),
+ ?line [{{'$1','$2'},
+ [{'or',{is_atom,'$1'},{'>',{'+','$1',5},'$2'}}],
+ [{'orelse','$1','$2'}]}] =
+ compile_and_run(<<"ets:fun2ms(fun({A,B}) "
+ " when is_atom(A) or (A+5 > B) -> "
+ " A orelse B "
+ " end)">>),
+ ?line [{{'$1','$2'},
+ [{'andalso',{is_integer,'$1'},{'>',{'+','$1',5},'$2'}}],
+ ['$1']}] =
+ compile_and_run(
+ <<"ets:fun2ms(fun({A,B}) when is_integer(A) andalso (A+5 > B) ->"
+ " A "
+ " end)">>),
+ ?line [{{'$1','$2'},
+ [{'orelse',{is_atom,'$1'},{'>',{'+','$1',5},'$2'}}],
+ ['$1']}] =
+ compile_and_run(
+ <<"ets:fun2ms(fun({A,B}) when is_atom(A) orelse (A+5 > B) -> "
+ " A "
+ " end)">>),
+ ok.
+
+
+bitsyntax(suite) ->
+ [];
+bitsyntax(doc) ->
+ ["Tests that bitsyntax works and does not work where appropriate"];
+bitsyntax(Config) when list(Config) ->
+ ?line setup(Config),
+ ?line [{'_',[],
+ [<<0,27,0,27>>]}] =
+ compile_and_run(<<"A = 27, "
+ "ets:fun2ms(fun(_) -> <<A:16,27:16>> end)">>),
+ ?line [{{<<15,47>>,
+ '$1',
+ '$2'},
+ [{'=:=','$1',
+ <<0,27>>},
+ {'=:=','$2',
+ <<27,28,19>>}],
+ [<<188,0,13>>]}] =
+ compile_and_run(<<"A = 27, "
+ "ets:fun2ms("
+ " fun({<<15,47>>,B,C}) "
+ " when B =:= <<A:16>>, C =:= <<27,28,19>> -> "
+ " <<A:4,12:4,13:16>> "
+ " end)">>),
+ ?line expect_failure(
+ <<>>,
+ <<"ets:fun2ms(fun({<<15,47>>,B,C}) "
+ " when B =:= <<16>>, C =:= <<27,28,19>> -> "
+ " <<B:4,12:4,13:16>> "
+ " end)">>),
+ ?line expect_failure(
+ <<>>,
+ <<"ets:fun2ms(fun({<<A:15,47>>,B,C}) "
+ " when B =:= <<16>>, C =:= <<27,28,19>> -> "
+ " <<B:4,12:4,13:16>> "
+ " end)">>),
+ ok.
+
+record_defaults(suite) ->
+ [];
+record_defaults(doc) ->
+ ["Tests that record defaults works"];
+record_defaults(Config) when list(Config) ->
+ ?line setup(Config),
+ ?line [{{<<27>>,{a,5,'$1',hej,hej}},
+ [],
+ [{{a,hej,{'*','$1',2},flurp,flurp}}]}] =
+ compile_and_run(<<"-record(a,{a,b,c,d=foppa}).">>,
+ <<"ets:fun2ms(fun({<<27>>,#a{a=5, b=B,_=hej}}) -> "
+ "#a{a=hej,b=B*2,_=flurp} "
+ "end)">>),
+ ok.
+
+basic_ets(suite) ->
+ [];
+basic_ets(doc) ->
+ ["Tests basic ets:fun2ms"];
+basic_ets(Config) when list(Config) ->
+ ?line setup(Config),
+ ?line [{{a,b},[],[true]}] = compile_and_run(
+ <<"ets:fun2ms(fun({a,b}) -> true end)">>),
+ ?line [{{'$1',foo},[{is_list,'$1'}],[{{{hd,'$1'},'$_'}}]},
+ {{'$1','$1'},[{is_tuple,'$1'}],[{{{element,1,'$1'},'$*'}}]}] =
+ compile_and_run(<<"ets:fun2ms(fun({X,foo}) when is_list(X) -> ",
+ "{hd(X),object()};",
+ "({X,X}) when is_tuple(X) ->",
+ "{element(1,X),bindings()}",
+ "end)">>),
+ ?line [{{'$1','$2'},[],[{{'$2','$1'}}]}] =
+ compile_and_run(<<"ets:fun2ms(fun({A,B}) -> {B,A} end)">>),
+ ?line [{{'$1','$2'},[],[['$2','$1']]}] =
+ compile_and_run(<<"ets:fun2ms(fun({A,B}) -> [B,A] end)">>),
+ ok.
+
+basic_dbg(suite) ->
+ [];
+basic_dbg(doc) ->
+ ["Tests basic ets:fun2ms"];
+basic_dbg(Config) when list(Config) ->
+ ?line setup(Config),
+ ?line [{[a,b],[],[{message,banan},{return_trace}]}] =
+ compile_and_run(<<"dbg:fun2ms(fun([a,b]) -> message(banan), ",
+ "return_trace() end)">>),
+ ?line [{['$1','$2'],[],[{{'$2','$1'}}]}] =
+ compile_and_run(<<"dbg:fun2ms(fun([A,B]) -> {B,A} end)">>),
+ ?line [{['$1','$2'],[],[['$2','$1']]}] =
+ compile_and_run(<<"dbg:fun2ms(fun([A,B]) -> [B,A] end)">>),
+ ?line [{['$1','$2'],[],['$*']}] =
+ compile_and_run(<<"dbg:fun2ms(fun([A,B]) -> bindings() end)">>),
+ ?line [{['$1','$2'],[],['$_']}] =
+ compile_and_run(<<"dbg:fun2ms(fun([A,B]) -> object() end)">>),
+ ok.
+
+from_shell(suite) ->
+ [];
+from_shell(doc) ->
+ ["Test calling of ets/dbg:fun2ms from the shell"];
+from_shell(Config) when list(Config) ->
+ ?line setup(Config),
+ ?line Fun = do_eval("fun({a,b}) -> true end"),
+ ?line [{{a,b},[],[true]}] = apply(ets,fun2ms,[Fun]),
+ ?line [{{a,b},[],[true]}] = do_eval("ets:fun2ms(fun({a,b}) -> true end)"),
+ ?line Fun2 = do_eval("fun([a,b]) -> message(banan), return_trace() end"),
+ ?line [{[a,b],[],[{message,banan},{return_trace}]}]
+ = apply(dbg,fun2ms,[Fun2]),
+ ?line [{[a,b],[],[{message,banan},{return_trace}]}] =
+ do_eval(
+ "dbg:fun2ms(fun([a,b]) -> message(banan), return_trace() end)"),
+ ok.
+
+records(suite) ->
+ [];
+records(doc) ->
+ ["Tests expansion of records in fun2ms"];
+records(Config) when list(Config) ->
+ ?line setup(Config),
+ ?line RD = <<"-record(t, {"
+ "t1 = [],"
+ "t2 = foo,"
+ "t3,"
+ "t4"
+ "}).">>,
+ ?line [{{t,'$1','$2',foo,'_'},[{is_list,'$1'}],[{{{hd,'$1'},'$_'}}]},
+ {{t,'_','_','_','_'},[{'==',{element,2,'$_'},nisse}],[{{'$*'}}]}] =
+ compile_and_run(RD,<<
+ "ets:fun2ms(fun(#t{t1 = X, t2 = Y, t3 = foo}) when is_list(X) ->
+ {hd(X),object()};
+ (#t{}) when (object())#t.t1 == nisse ->
+ {bindings()}
+ end)">>),
+ ?line [{{t,'$1','$2','_',foo},
+ [{'==',{element,4,'$_'},7},{is_list,'$1'}],
+ [{{{hd,'$1'},'$_'}}]},
+ {'$1',[{is_record,'$1',t,5}],
+ [{{{element,2,'$1'},
+ {{t,'$1',foo,undefined,undefined}},
+ {{t,{element,2,'$1'},{element,3,'$1'},{element,4,'$1'},boooo}}}}]}] =
+ compile_and_run(RD,<<
+ "ets:fun2ms(fun(#t{t1 = X, t2 = Y, t4 = foo}) when
+ (object())#t.t3==7,is_list(X) ->
+ {hd(X),object()};
+ (A) when is_record(A,t) ->
+ {A#t.t1
+ ,#t{t1=A}
+ ,A#t{t4=boooo}
+ }
+ end)"
+ >>),
+ ?line [{[{t,'$1','$2',foo,'_'}],[{is_list,'$1'}],[{{{hd,'$1'},'$_'}}]},
+ {[{t,'_','_','_','_'}],[{'==',{element,2,{hd,'$_'}},nisse}],[{{'$*'}}]}]=
+ compile_and_run(RD,<<
+ "dbg:fun2ms(fun([#t{t1 = X, t2 = Y, t3 = foo}]) when is_list(X) ->
+ {hd(X),object()};
+ ([#t{}]) when (hd(object()))#t.t1 == nisse ->
+ {bindings()}
+ end)"
+ >>),
+ ok.
+
+
+record_index(suite) ->
+ [];
+record_index(doc) ->
+ ["Tests expansion of records in fun2ms, part 2"];
+record_index(Config) when list(Config) ->
+ ?line setup(Config),
+ ?line RD = <<"-record(a,{a,b}).">>,
+ ?line [{{2},[],[true]}] = compile_and_run(RD,
+ <<"ets:fun2ms(fun({#a.a}) -> true end)">>),
+ ?line [{{2},[],[2]}] = compile_and_run(RD,
+ <<"ets:fun2ms(fun({#a.a}) -> #a.a end)">>),
+ ?line [{{2,'$1'},[{'>','$1',2}],[2]}] = compile_and_run(RD,
+ <<"ets:fun2ms(fun({#a.a,A}) when A > #a.a -> #a.a end)">>),
+ ok.
+
+top_match(suite) ->
+ [];
+top_match(doc) ->
+ ["Tests matching on top level in head to give alias for object()"];
+top_match(Config) when list(Config) ->
+ ?line setup(Config),
+ ?line RD = <<"-record(a,{a,b}).">>,
+ ?line [{{a,3,'_'},[],['$_']}] =
+ compile_and_run(RD,
+ <<"ets:fun2ms(fun(A = #a{a=3}) -> A end)">>),
+ ?line [{{a,3,'_'},[],['$_']}] =
+ compile_and_run(RD,
+ <<"ets:fun2ms(fun(#a{a=3} = A) -> A end)">>),
+ ?line [{[a,b],[],['$_']}] =
+ compile_and_run(RD,
+ <<"dbg:fun2ms(fun(A = [a,b]) -> A end)">>),
+ ?line [{[a,b],[],['$_']}] =
+ compile_and_run(RD,
+ <<"dbg:fun2ms(fun([a,b] = A) -> A end)">>),
+ ?line expect_failure(RD,
+ <<"ets:fun2ms(fun({a,A = {_,b}}) -> A end)">>),
+ ?line expect_failure(RD,
+ <<"dbg:fun2ms(fun([a,A = {_,b}]) -> A end)">>),
+ ?line expect_failure(RD,
+ <<"ets:fun2ms(fun(A#a{a = 2}) -> A end)">>),
+ ok.
+
+multipass(suite) ->
+ [];
+multipass(doc) ->
+ ["Tests that multi-defined fields in records give errors."];
+multipass(Config) when list(Config) ->
+ ?line setup(Config),
+ ?line RD = <<"-record(a,{a,b}).">>,
+ ?line expect_failure(RD,<<"ets:fun2ms(fun(A) -> #a{a=2,a=3} end)">>),
+ ?line expect_failure(RD,<<"ets:fun2ms(fun(A) -> A#a{a=2,a=3} end)">>),
+ ?line expect_failure(RD,<<"ets:fun2ms(fun(A) when A =:= #a{a=2,a=3} ->",
+ " true end)">>),
+ ?line expect_failure(RD,<<"ets:fun2ms(fun({A,B})when A =:= B#a{a=2,a=3}->",
+ "true end)">>),
+ ?line expect_failure(RD,<<"ets:fun2ms(fun(#a{a=3,a=3}) -> true end)">>),
+ ?line compile_and_run(RD,<<"ets:fun2ms(fun(A) -> #a{a=2,b=3} end)">>),
+ ?line compile_and_run(RD,<<"ets:fun2ms(fun(A) -> A#a{a=2,b=3} end)">>),
+ ?line compile_and_run(RD,<<"ets:fun2ms(fun(A) when A =:= #a{a=2,b=3} ->",
+ " true end)">>),
+ ?line compile_and_run(RD,<<"ets:fun2ms(fun({A,B})when A=:= B#a{a=2,b=3}->",
+ "true end)">>),
+ ?line compile_and_run(RD,<<"ets:fun2ms(fun(#a{a=3,b=3}) -> true end)">>),
+ ok.
+
+
+old_guards(suite) ->
+ [];
+old_guards(doc) ->
+ ["Tests that old type tests in guards are translated"];
+old_guards(Config) when list(Config) ->
+ ?line setup(Config),
+ Tests = [
+ {atom,is_atom},
+ {constant,is_constant},
+ {float,is_float},
+ {integer,is_integer},
+ {list,is_list},
+ {number,is_number},
+ {pid,is_pid},
+ {port,is_port},
+ {reference,is_reference},
+ {tuple,is_tuple},
+ {binary,is_binary},
+ {function,is_function}],
+ ?line lists:foreach(
+ fun({Old,New}) ->
+ Bin = list_to_binary([<<"ets:fun2ms(fun(X) when ">>,
+ atom_to_list(Old),
+ <<"(X) -> true end)">>]),
+ case compile_and_run(Bin) of
+ [{'$1',[{New,'$1'}],[true]}] ->
+ ok;
+ _ ->
+ exit({bad_result_for, binary_to_list(Bin)})
+ end
+ end,
+ Tests),
+ ?line RD = <<"-record(a,{a,b}).">>,
+ ?line [{'$1',[{is_record,'$1',a,3}],[true]}] =
+ compile_and_run(RD,
+ <<"ets:fun2ms(fun(X) when record(X,a) -> true end)">>),
+ ?line expect_failure
+ (RD,
+ <<"ets:fun2ms(fun(X) when integer(X) and constant(X) -> "
+ "true end)">>),
+ ?line [{'$1',[{is_integer,'$1'},
+ {is_float,'$1'},
+ {is_atom,'$1'},
+ {is_constant,'$1'},
+ {is_list,'$1'},
+ {is_number,'$1'},
+ {is_pid,'$1'},
+ {is_port,'$1'},
+ {is_reference,'$1'},
+ {is_tuple,'$1'},
+ {is_binary,'$1'},
+ {is_record,'$1',a,3}],
+ [true]}] =
+ compile_and_run(RD, <<
+ "ets:fun2ms(fun(X) when integer(X),"
+ "float(X), atom(X), constant(X),"
+ "list(X), number(X), pid(X),"
+ "port(X), reference(X), tuple(X),"
+ "binary(X), record(X,a) -> true end)"
+ >>),
+ ok.
+
+autoimported(suite) ->
+ [];
+autoimported(doc) ->
+ ["Tests use of autoimported bif's used like erlang:'+'(A,B) in guards"
+ " and body."];
+autoimported(Config) when list(Config) ->
+ ?line setup(Config),
+ Allowed = [
+ {abs,1},
+ {element,2},
+ {hd,1},
+ {length,1},
+ {node,0},
+ {node,1},
+ {round,1},
+ {size,1},
+ {tl,1},
+ {trunc,1},
+ {self,0},
+ %{float,1}, see float_1_function/1
+ {is_atom,1},
+ {is_constant,1},
+ {is_float,1},
+ {is_integer,1},
+ {is_list,1},
+ {is_number,1},
+ {is_pid,1},
+ {is_port,1},
+ {is_reference,1},
+ {is_tuple,1},
+ {is_binary,1},
+ {is_function,1},
+ {is_record,2,magic},
+ {'and',2,infix},
+ {'or',2,infix},
+ {'xor',2,infix},
+ {'not',1},
+ %{'andalso',2,infix},
+ %{'orelse',2,infix},
+ {'+',1},
+ {'+',2,infix},
+ {'-',1},
+ {'-',2,infix},
+ {'*',2,infix},
+ {'/',2,infix},
+ {'div',2,infix},
+ {'rem',2,infix},
+ {'band',2,infix},
+ {'bor',2,infix},
+ {'bxor',2,infix},
+ {'bnot',1},
+ {'bsl',2,infix},
+ {'bsr',2,infix},
+ {'>',2,infix},
+ {'>=',2,infix},
+ {'<',2,infix},
+ {'=<',2,infix},
+ {'==',2,infix},
+ {'=:=',2,infix},
+ {'/=',2,infix},
+ {'=/=',2,infix}],
+ ?line RD = <<"-record(a,{a,b}).">>,
+ ?line lists:foreach(
+ fun({A,0}) ->
+ L = atom_to_list(A),
+ Bin1 = list_to_binary(
+ [
+ <<"ets:fun2ms(fun(X) when ">>,
+ L,<<"() -> ">>,
+ L,<<"() end)">>
+ ]),
+ Bin2 = list_to_binary(
+ [
+ <<"ets:fun2ms(fun(X) when erlang:'">>,
+ L,<<"'() -> erlang:'">>,
+ L,<<"'() end)">>
+ ]),
+ Res1 = compile_and_run(Bin1),
+ Res2 = compile_and_run(Bin2),
+ case Res1 =:= Res2 of
+ true ->
+ ok;
+ false ->
+ exit({not_equal,{Res1,Res2,A}})
+ end;
+ ({A,1}) ->
+ L = atom_to_list(A),
+ Bin1 = list_to_binary(
+ [
+ <<"ets:fun2ms(fun(X) when ">>,
+ L,<<"(X) -> ">>,
+ L,<<"(X) end)">>
+ ]),
+ Bin2 = list_to_binary(
+ [
+ <<"ets:fun2ms(fun(X) when erlang:'">>,
+ L,<<"'(X) -> erlang:'">>,
+ L,<<"'(X) end)">>
+ ]),
+ Res1 = compile_and_run(Bin1),
+ Res2 = compile_and_run(Bin2),
+ case Res1 =:= Res2 of
+ true ->
+ ok;
+ false ->
+ exit({not_equal,{Res1,Res2,A}})
+ end;
+ ({A,2}) ->
+ L = atom_to_list(A),
+ Bin1 = list_to_binary(
+ [
+ <<"ets:fun2ms(fun({X,Y}) when ">>,
+ L,<<"(X,Y) -> ">>,
+ L,<<"(X,Y) end)">>
+ ]),
+ Bin2 = list_to_binary(
+ [
+ <<"ets:fun2ms(fun({X,Y}) when erlang:'">>,
+ L,<<"'(X,Y) -> erlang:'">>,
+ L,<<"'(X,Y) end)">>
+ ]),
+ Res1 = compile_and_run(Bin1),
+ Res2 = compile_and_run(Bin2),
+ case Res1 =:= Res2 of
+ true ->
+ ok;
+ false ->
+ exit({not_equal,{Res1,Res2,A}})
+ end;
+ ({A,2,infix}) ->
+ L = atom_to_list(A),
+ Bin1 = list_to_binary(
+ [
+ <<"ets:fun2ms(fun({X,Y}) when X ">>,
+ L,<<" Y -> X ">>,
+ L,<<" Y end)">>
+ ]),
+ Bin2 = list_to_binary(
+ [
+ <<"ets:fun2ms(fun({X,Y}) when erlang:'">>,
+ L,<<"'(X,Y) -> erlang:'">>,
+ L,<<"'(X,Y) end)">>
+ ]),
+ Res1 = compile_and_run(Bin1),
+ Res2 = compile_and_run(Bin2),
+ case Res1 =:= Res2 of
+ true ->
+ ok;
+ false ->
+ exit({not_equal,{Res1,Res2,A}})
+ end;
+ ({A,2,magic}) -> %is_record
+ L = atom_to_list(A),
+ Bin1 = list_to_binary(
+ [
+ <<"ets:fun2ms(fun(X) when ">>,
+ L,<<"(X,a) -> ">>,
+ L,<<"(X,a) end)">>
+ ]),
+ Bin2 = list_to_binary(
+ [
+ <<"ets:fun2ms(fun(X) when erlang:'">>,
+ L,<<"'(X,a) -> erlang:'">>,
+ L,<<"'(X,a) end)">>
+ ]),
+ Res1 = compile_and_run(RD,Bin1),
+ Res2 = compile_and_run(RD,Bin2),
+ case Res1 =:= Res2 of
+ true ->
+ ok;
+ false ->
+ exit({not_equal,{Res1,Res2,A}})
+ end
+ end,
+ Allowed),
+ ok.
+
+semicolon(suite) ->
+ [];
+semicolon(doc) ->
+ ["Tests semicolon in guards of match_specs."];
+semicolon(Config) when is_list(Config) ->
+ ?line setup(Config),
+ ?line Res01 = compile_and_run
+ (<<"ets:fun2ms(fun(X) when is_integer(X); "
+ "is_float(X) -> true end)">>),
+ ?line Res02 = compile_and_run
+ (<<"ets:fun2ms(fun(X) when is_integer(X) -> true; "
+ "(X) when is_float(X) -> true end)">>),
+ ?line Res01 = Res02,
+ ?line Res11 = compile_and_run
+ (<<"ets:fun2ms(fun(X) when is_integer(X); "
+ "is_float(X); atom(X) -> true end)">>),
+ ?line Res12 = compile_and_run
+ (<<"ets:fun2ms(fun(X) when is_integer(X) -> true; "
+ "(X) when is_float(X) -> true; "
+ "(X) when is_atom(X) -> true end)">>),
+ ?line Res11 = Res12,
+ ok.
+
+
+float_1_function(suite) ->
+ [];
+float_1_function(doc) ->
+ ["OTP-5297. The function float/1."];
+float_1_function(Config) when list(Config) ->
+ ?line setup(Config),
+ RunMS = fun(L, MS) ->
+ ets:match_spec_run(L, ets:match_spec_compile(MS))
+ end,
+ ?line MS1 = compile_and_run
+ (<<"ets:fun2ms(fun(X) -> float(X) end)">>),
+ ?line [F1] = RunMS([3], MS1),
+ ?line true = is_float(F1) and (F1 == 3),
+
+ ?line MS1b = compile_and_run
+ (<<"dbg:fun2ms(fun(X) -> float(X) end)">>),
+ ?line [F2] = RunMS([3], MS1b),
+ ?line true = is_float(F2) and (F2 == 3),
+
+ ?line MS2 = compile_and_run
+ (<<"ets:fun2ms(fun(X) when is_pid(X) or float(X) -> true end)">>),
+ ?line [] = RunMS([3.0], MS2),
+
+ ?line MS3 = compile_and_run
+ (<<"dbg:fun2ms(fun(X) when is_pid(X); float(X) -> true end)">>),
+ ?line [true] = RunMS([3.0], MS3),
+
+ ?line MS4 = compile_and_run
+ (<<"ets:fun2ms(fun(X) when erlang:float(X) > 1 -> big;"
+ " (_) -> small end)">>),
+ ?line [small,big] = RunMS([1.0, 3.0], MS4),
+
+ ?line MS5 = compile_and_run
+ (<<"ets:fun2ms(fun(X) when float(X) > 1 -> big;"
+ " (_) -> small end)">>),
+ ?line [small,big] = RunMS([1.0, 3.0], MS5),
+
+ %% This is the test from autoimported/1.
+ ?line [{'$1',[{is_float,'$1'}],[{float,'$1'}]}] =
+ compile_and_run
+ (<<"ets:fun2ms(fun(X) when float(X) -> float(X) end)">>),
+ ?line [{'$1',[{float,'$1'}],[{float,'$1'}]}] =
+ compile_and_run
+ (<<"ets:fun2ms(fun(X) when erlang:'float'(X) -> "
+ "erlang:'float'(X) end)">>),
+ ok.
+
+
+action_function(suite) ->
+ [];
+action_function(doc) ->
+ ["Test all 'action functions'."];
+action_function(Config) when is_list(Config) ->
+ ?line setup(Config),
+ ?line [{['$1','$2'],[],
+ [{set_seq_token,label,0},
+ {get_seq_token},
+ {message,'$1'},
+ {return_trace},
+ {exception_trace}]}] =
+ compile_and_run
+ (<<"dbg:fun2ms(fun([X,Y]) -> "
+ "set_seq_token(label, 0), "
+ "get_seq_token(), "
+ "message(X), "
+ "return_trace(), "
+ "exception_trace() end)">>),
+ ?line [{['$1','$2'],[],
+ [{process_dump},
+ {enable_trace,send},
+ {enable_trace,'$2',send},
+ {disable_trace,procs},
+ {disable_trace,'$2',procs}]}] =
+ compile_and_run
+ (<<"dbg:fun2ms(fun([X,Y]) -> "
+ "process_dump(), "
+ "enable_trace(send), "
+ "enable_trace(Y, send), "
+ "disable_trace(procs), "
+ "disable_trace(Y, procs) end)">>),
+ ?line [{['$1','$2'],
+ [],
+ [{display,'$1'},
+ {caller},
+ {set_tcw,{const,16}},
+ {silent,true},
+ {trace,[send],[procs]},
+ {trace,'$2',[procs],[send]}]}] =
+ compile_and_run
+ (<<"A = 16, dbg:fun2ms(fun([X,Y]) -> "
+ "display(X), "
+ "caller(), "
+ "set_tcw(A), "
+ "silent(true), "
+ "trace([send], [procs]), "
+ "trace(Y, [procs], [send]) end)">>),
+ ok.
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Helpers
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+setup(Config) ->
+ put(mts_config,Config),
+ put(mts_tf_counter,0).
+
+temp_name() ->
+ Conf = get(mts_config),
+ C = get(mts_tf_counter),
+ put(mts_tf_counter,C+1),
+ filename:join([?config(priv_dir,Conf),
+ "tempfile"++integer_to_list(C)++".tmp"]).
+
+
+expect_failure(Recs,Code) ->
+ case (catch compile_and_run(Recs,Code)) of
+ {'EXIT',_Foo} ->
+ %erlang:display(_Foo),
+ ok;
+ Other ->
+ exit({expected,failure,got,Other})
+ end.
+
+compile_and_run(Expr) ->
+ compile_and_run(<<>>,Expr).
+compile_and_run(Records,Expr) ->
+ Prog = <<
+ "-module(tmp).\n",
+ "-include_lib(\"stdlib/include/ms_transform.hrl\").\n",
+ "-export([tmp/0]).\n",
+ Records/binary,"\n",
+ "tmp() ->\n",
+ Expr/binary,".\n">>,
+ FN=temp_name(),
+ file:write_file(FN,Prog),
+ {ok,Forms} = epp:parse_file(FN,"",""),
+ {ok,tmp,Bin} = compile:forms(Forms),
+ code:load_binary(tmp,FN,Bin),
+ tmp:tmp().
+
+do_eval(String) ->
+ {done,{ok,T,_},[]} = erl_scan:tokens(
+ [],
+ String++".\n",1),
+ {ok,Tree} = erl_parse:parse_exprs(T),
+ {value,Res,[]} = erl_eval:exprs(Tree,[]),
+ Res.
diff --git a/lib/stdlib/test/naughty_child.erl b/lib/stdlib/test/naughty_child.erl
new file mode 100644
index 0000000000..b56130929c
--- /dev/null
+++ b/lib/stdlib/test/naughty_child.erl
@@ -0,0 +1,101 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2002-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%% DESCRIPTION: Implements a naughty child process that does unlink
+%%% from its supervisor. Used by the supervisor test suite.
+
+-module(naughty_child).
+
+-behaviour(gen_server).
+%%--------------------------------------------------------------------
+%% Include files
+%%--------------------------------------------------------------------
+
+%%--------------------------------------------------------------------
+%% External exports
+-export([start_link/1]).
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
+ code_change/3]).
+
+-record(state, {}).
+
+%%====================================================================
+%% External functions
+%%====================================================================
+%%--------------------------------------------------------------------
+%% Function: start_link/0
+%% Description: Starts the server
+%%--------------------------------------------------------------------
+start_link(Pid) ->
+ gen_server:start_link({local, naughty_foo}, ?MODULE, [Pid], []).
+
+%%====================================================================
+%% Server functions
+%%====================================================================
+
+%%--------------------------------------------------------------------
+%% Function: init/1
+%% Description: Initiates the server
+%%--------------------------------------------------------------------
+init([Pid]) ->
+ unlink(Pid),
+ {ok, #state{}}.
+
+%%--------------------------------------------------------------------
+%% Function: handle_call/3
+%% Description: Handling call messages
+%%--------------------------------------------------------------------
+handle_call(_Request, _From, State) ->
+ Reply = ok,
+ {reply, Reply, State}.
+
+%%--------------------------------------------------------------------
+%% Function: handle_cast/2
+%% Description: Handling cast messages
+%%--------------------------------------------------------------------
+handle_cast(_Msg, State) ->
+ {noreply, State}.
+
+%%--------------------------------------------------------------------
+%% Function: handle_info/2
+%% Description: Handling all non call/cast messages
+%%--------------------------------------------------------------------
+handle_info(_Info, State) ->
+ {noreply, State}.
+
+%%--------------------------------------------------------------------
+%% Function: terminate/2
+%% Description: Shutdown the server
+%%--------------------------------------------------------------------
+terminate(_Reason, _State) ->
+ ok.
+
+%%--------------------------------------------------------------------
+%% Func: code_change/3
+%% Purpose: Convert process state when code is changed
+%%--------------------------------------------------------------------
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+%%--------------------------------------------------------------------
+%%% Internal functions
+%%--------------------------------------------------------------------
+
diff --git a/lib/stdlib/test/proc_lib_SUITE.erl b/lib/stdlib/test/proc_lib_SUITE.erl
new file mode 100644
index 0000000000..2fd7725335
--- /dev/null
+++ b/lib/stdlib/test/proc_lib_SUITE.erl
@@ -0,0 +1,344 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(proc_lib_SUITE).
+
+%%
+%% Define to run outside of test server
+%%
+%%-define(STANDALONE,1).
+
+-export([all/1, crash/1, sync_start/1, sync_start_nolink/1, sync_start_link/1,
+ spawn_opt/1, sp1/0, sp2/0, sp3/1, sp4/2, sp5/1,
+ hibernate/1]).
+-export([tickets/1, otp_6345/1]).
+
+-export([hib_loop/1, awaken/1]).
+
+-export([init/1,
+ handle_event/2, handle_call/2, handle_info/2,
+ terminate/2]).
+
+-export([otp_6345_init/1]).
+
+
+-ifdef(STANDALONE).
+-define(line, noop, ).
+-else.
+-include("test_server.hrl").
+-endif.
+
+all(suite) -> [crash, sync_start, spawn_opt, hibernate, tickets].
+
+tickets(suite) -> [otp_6345].
+
+%%-----------------------------------------------------------------
+%% We don't have to test that spwn and spawn_link actually spawns
+%% new processes - if they don't we can't run this suite!
+%% But we want to test that start and start_link really is
+%% synchronous, and we want to test that the crash report is ok.
+%%-----------------------------------------------------------------
+crash(Config) when is_list(Config) ->
+ error_logger:add_report_handler(?MODULE, self()),
+
+ Pid = proc_lib:spawn(?MODULE, sp1, []),
+ Pid ! die,
+ ?line Report = receive
+ {crash_report, Pid, Report0} -> Report0
+ after 2000 -> test_server:fail(no_crash_report)
+ end,
+ ?line proc_lib:format(Report),
+ ?line [PidRep, []] = Report,
+ ?line {value, {initial_call,{?MODULE,sp1,[]}}} =
+ lists:keysearch(initial_call, 1, PidRep),
+ Self = self(),
+ ?line {value, {ancestors,[Self]}} =
+ lists:keysearch(ancestors, 1, PidRep),
+ ?line {value, {error_info,{exit,die,_StackTrace1}}} =
+ lists:keysearch(error_info, 1, PidRep),
+
+ F = fun sp1/0,
+ Pid1 = proc_lib:spawn(node(), F),
+ Pid1 ! die,
+ ?line [PidRep1, []] = receive
+ {crash_report, Pid1, Report1} -> Report1
+ after 2000 -> test_server:fail(no_crash_report)
+ end,
+ ?line {value, {initial_call,{Fmod,Fname,[]}}} =
+ lists:keysearch(initial_call, 1, PidRep1),
+ ?line {module,Fmod} = erlang:fun_info(F, module),
+ ?line {name,Fname} = erlang:fun_info(F, name),
+ ?line {value, {ancestors,[Self]}} =
+ lists:keysearch(ancestors, 1, PidRep1),
+ ?line {value, {error_info,{exit,die,_StackTrace2}}} =
+ lists:keysearch(error_info, 1, PidRep1),
+
+ Pid2 = proc_lib:spawn(?MODULE, sp2, []),
+ test_server:sleep(100),
+ ?line {?MODULE,sp2,[]} = proc_lib:initial_call(Pid2),
+ ?line {?MODULE,sp2,0} = proc_lib:translate_initial_call(Pid2),
+ Pid2 ! die,
+ ?line [Pid2Rep, [{neighbour, LinkRep}]] =
+ receive
+ {crash_report, Pid2, Report2} -> Report2
+ after 2000 -> test_server:fail(no_crash_report)
+ end,
+ ?line {value, {initial_call,{?MODULE,sp2,[]}}} =
+ lists:keysearch(initial_call, 1, Pid2Rep),
+ ?line {value, {ancestors,[Self]}} =
+ lists:keysearch(ancestors, 1, Pid2Rep),
+ ?line {value, {error_info,{exit,die,_StackTrace3}}} =
+ lists:keysearch(error_info, 1, Pid2Rep),
+ ?line {value, {initial_call,{?MODULE,sp1,[]}}} =
+ lists:keysearch(initial_call, 1, LinkRep),
+
+ %% Make sure that we don't get a crash report if a process
+ %% terminates with reason 'shutdown' or reason {shutdown,Reason}.
+ ?line process_flag(trap_exit, true),
+ ?line Pid3 = proc_lib:spawn_link(erlang, apply,
+ [fun() -> exit(shutdown) end,[]]),
+
+ ?line Pid4 = proc_lib:spawn_link(erlang, apply,
+ [fun() -> exit({shutdown,{a,b,c}}) end,[]]),
+
+ ?line receive {'EXIT',Pid3,shutdown} -> ok end,
+ ?line receive {'EXIT',Pid4,{shutdown,{a,b,c}}} -> ok end,
+ ?line process_flag(trap_exit, false),
+
+ receive
+ Any ->
+ ?line ?t:fail({unexpected_message,Any})
+ after 2000 ->
+ ok
+ end.
+
+sync_start(suite) -> [sync_start_nolink, sync_start_link].
+
+sync_start_nolink(Config) when is_list(Config) ->
+ _Pid = spawn_link(?MODULE, sp5, [self()]),
+ receive
+ {sync_started, F} ->
+ exit(F, kill),
+ test_server:fail(async_start)
+ after 1000 -> ok
+ end,
+ receive
+ {Pid2, init} ->
+ Pid2 ! go_on
+ end,
+ receive
+ {sync_started, _} -> ok
+ after 1000 ->
+ exit(Pid2, kill),
+ test_server:fail(no_sync_start)
+ end,
+ ok.
+
+sync_start_link(Config) when is_list(Config) ->
+ _Pid = spawn_link(?MODULE, sp3, [self()]),
+ receive
+ {sync_started, _} -> test_server:fail(async_start)
+ after 1000 -> ok
+ end,
+ receive
+ {Pid2, init} ->
+ Pid2 ! go_on
+ end,
+ receive
+ {sync_started, _} -> ok
+ after 1000 -> test_server:fail(no_sync_start)
+ end,
+ ok.
+
+spawn_opt(Config) when is_list(Config) ->
+ F = fun sp1/0,
+ {name,Fname} = erlang:fun_info(F, name),
+ FunMFArgs = {?MODULE,Fname,[]},
+ FunMFArity = {?MODULE,Fname,0},
+ ?line Pid1 = proc_lib:spawn_opt(node(), F, [{priority,low}]),
+ ?line Pid = proc_lib:spawn_opt(F, [{priority,low}]),
+ ?line test_server:sleep(100),
+ ?line FunMFArgs = proc_lib:initial_call(Pid),
+ ?line FunMFArity = proc_lib:translate_initial_call(Pid),
+ ?line Pid ! die,
+ ?line FunMFArgs = proc_lib:initial_call(Pid1),
+ ?line FunMFArity = proc_lib:translate_initial_call(Pid1),
+ ?line Pid1 ! die,
+ ok.
+
+
+sp1() ->
+ receive
+ die -> exit(die);
+ _ -> sp1()
+ end.
+
+sp2() ->
+ _Pid = proc_lib:spawn_link(?MODULE, sp1, []),
+ receive
+ die -> exit(die);
+ _ -> sp1()
+ end.
+
+sp3(Tester) ->
+ Pid = proc_lib:start_link(?MODULE, sp4, [self(), Tester]),
+ Tester ! {sync_started, Pid}.
+
+sp5(Tester) ->
+ Pid = proc_lib:start(?MODULE, sp4, [self(), Tester]),
+ Tester ! {sync_started, Pid}.
+
+sp4(Parent, Tester) ->
+ Tester ! {self(), init},
+ receive
+ go_on -> ok
+ end,
+ proc_lib:init_ack(Parent, self()).
+
+hibernate(Config) when is_list(Config) ->
+ Ref = make_ref(),
+ Self = self(),
+ LoopData = {Ref,Self},
+ ?line Pid = proc_lib:spawn_link(?MODULE, hib_loop, [LoopData]),
+
+ %% Just check that the child process can process and answer messages.
+ ?line Pid ! {Self,loop_data},
+ receive
+ {loop_data,LoopData} -> ok;
+ Unexpected0 ->
+ ?line io:format("Unexpected: ~p\n", [Unexpected0]),
+ ?line ?t:fail()
+ after 1000 ->
+ ?line io:format("Timeout"),
+ ?line ?t:fail()
+ end,
+
+ %% Hibernate the process.
+ ?line Pid ! hibernate,
+ erlang:yield(),
+ io:format("~p\n", [process_info(Pid, heap_size)]),
+
+
+ %% Send a message to the process...
+
+ ?line Pid ! {Self,loop_data},
+
+ %% ... expect first a wake up message from the process...
+ receive
+ {awaken,LoopData} -> ok;
+ Unexpected1 ->
+ ?line io:format("Unexpected: ~p\n", [Unexpected1]),
+ ?line ?t:fail()
+ after 1000 ->
+ ?line io:format("Timeout"),
+ ?line ?t:fail()
+ end,
+
+ %% ... followed by the answer to the actual request.
+ receive
+ {loop_data,LoopData} -> ok;
+ Unexpected2 ->
+ ?line io:format("Unexpected: ~p\n", [Unexpected2]),
+ ?line ?t:fail()
+ after 1000 ->
+ ?line io:format("Timeout"),
+ ?line ?t:fail()
+ end,
+
+ %% Test that errors are handled correctly after wake up from hibernation...
+
+ ?line process_flag(trap_exit, true),
+ ?line error_logger:add_report_handler(?MODULE, self()),
+ ?line Pid ! crash,
+
+ %% We should receive two messages. Especially in the SMP emulator,
+ %% we can't be sure of the message order, so sort the messages before
+ %% matching.
+
+ Messages = lists:sort(hib_receive_messages(2)),
+ io:format("~p", [Messages]),
+ ?line [{'EXIT',Pid,i_crashed},{crash_report,Pid,[Report,[]]}] = Messages,
+
+ %% Check that the initial_call has the expected format.
+ ?line {value,{initial_call,{?MODULE,hib_loop,[_]}}} =
+ lists:keysearch(initial_call, 1, Report),
+
+ ok.
+
+hib_loop(LoopData) ->
+ receive
+ hibernate ->
+ proc_lib:hibernate(?MODULE, awaken, [LoopData]);
+ {Pid,loop_data} ->
+ Pid ! {loop_data,LoopData};
+ crash ->
+ exit(i_crashed)
+ end,
+ hib_loop(LoopData).
+
+awaken({_,Parent}=LoopData) ->
+ Parent ! {awaken,LoopData},
+ hib_loop(LoopData).
+
+hib_receive_messages(0) -> [];
+hib_receive_messages(N) ->
+ receive
+ Any -> [Any|hib_receive_messages(N-1)]
+ end.
+
+otp_6345(suite) ->
+ [];
+otp_6345(doc) ->
+ ["'monitor' spawn_opt option"];
+otp_6345(Config) when is_list(Config) ->
+ Opts = [link,monitor],
+ {'EXIT', {badarg,[{proc_lib,check_for_monitor,_}|_Stack]}} =
+ (catch proc_lib:start(?MODULE, otp_6345_init, [self()],
+ 1000, Opts)),
+ ok.
+
+otp_6345_init(Parent) ->
+ proc_lib:init_ack(Parent, {ok, self()}),
+ otp_6345_loop().
+
+otp_6345_loop() ->
+ receive
+ _Msg ->
+ otp_6345_loop()
+ end.
+
+%%-----------------------------------------------------------------
+%% The error_logger handler used.
+%%-----------------------------------------------------------------
+init(Tester) ->
+ {ok, Tester}.
+
+handle_event({error_report, _GL, {Pid, crash_report, Report}}, Tester) ->
+ io:format("~s\n", [proc_lib:format(Report)]),
+ Tester ! {crash_report, Pid, Report},
+ {ok, Tester};
+handle_event(_Event, State) ->
+ {ok, State}.
+
+handle_info(_, State) ->
+ {ok, State}.
+
+handle_call(_Query, State) -> {ok, {error, bad_query}, State}.
+
+terminate(_Reason, State) ->
+ State.
diff --git a/lib/stdlib/test/qlc_SUITE.erl b/lib/stdlib/test/qlc_SUITE.erl
new file mode 100644
index 0000000000..ff11ebc6bf
--- /dev/null
+++ b/lib/stdlib/test/qlc_SUITE.erl
@@ -0,0 +1,8179 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%%----------------------------------------------------------------
+%%% Purpose:Test Suite for the 'qlc' module.
+%%%-----------------------------------------------------------------
+-module(qlc_SUITE).
+
+-define(QLC, qlc).
+-define(QLCs, "qlc").
+
+%-define(debug, true).
+
+%% There are often many tests per testcase. Most tests are copied to a
+%% module, a file. The file is compiled and the test run. Should the
+%% test fail, the module file is not removed from ?privdir, but is
+%% kept for inspection. The name of the file is
+%% ?privdir/qlc_test_CASE.erl.
+-define(TESTMODULE, qlc_test).
+-define(TESTCASE, testcase_name).
+
+-ifdef(debug).
+-define(line, put(line, ?LINE), ).
+-define(config(X,Y), foo).
+-define(datadir, ?QLCs ++ "_SUITE_data").
+-define(privdir, ?QLCs ++ "_SUITE_priv").
+-define(testcase, current_testcase). % don't know
+-define(t, test_server).
+-else.
+-include("test_server.hrl").
+-define(datadir, ?config(data_dir, Config)).
+-define(privdir, ?config(priv_dir, Config)).
+-define(testcase, ?config(?TESTCASE, Config)).
+-endif.
+
+-include_lib("stdlib/include/ms_transform.hrl").
+
+-export([all/1, init_per_testcase/2, fin_per_testcase/2]).
+
+-export([parse_transform/1,
+ badarg/1, nested_qlc/1, unused_var/1, lc/1, fun_clauses/1,
+ filter_var/1, single/1, exported_var/1, generator_vars/1,
+ nomatch/1, errors/1, pattern/1,
+
+ evaluation/1,
+ eval/1, cursor/1, fold/1, eval_unique/1, eval_cache/1, append/1,
+ evaluator/1, string_to_handle/1, table/1, process_dies/1,
+ sort/1, keysort/1, filesort/1, cache/1, cache_list/1, filter/1,
+ info/1, nested_info/1, lookup1/1, lookup2/1, lookup_rec/1,
+ indices/1, pre_fun/1, skip_filters/1,
+
+ table_impls/1,
+ ets/1, dets/1,
+
+ join/1,
+ join_option/1, join_filter/1, join_lookup/1, join_merge/1,
+ join_sort/1, join_complex/1,
+
+ tickets/1,
+ otp_5644/1, otp_5195/1, otp_6038_bug/1, otp_6359/1, otp_6562/1,
+ otp_6590/1, otp_6673/1, otp_6964/1, otp_7114/1, otp_7238/1,
+ otp_7232/1, otp_7552/1, otp_6674/1, otp_7714/1,
+
+ manpage/1,
+
+ compat/1,
+ backward/1, forward/1]).
+
+%% Internal exports.
+-export([bad_table_throw/1, bad_table_exit/1, default_table/1, bad_table/1,
+ bad_table_format/1, bad_table_format_arity/1, bad_table_traverse/1,
+ bad_table_post/1, bad_table_lookup/1, bad_table_max_lookup/1,
+ bad_table_info_arity/1, bad_table_info_fun_n_objects/1,
+ bad_table_info_fun_indices/1, bad_table_info_fun_keypos/1,
+ bad_table_key_equality/1]).
+-export([evaluator_2/2]).
+-export([prep_scratchdir/1, truncate_tmpfile/2, crash/2, crash_tmpfile/2]).
+-export([etsc/2, etsc/3, create_ets/2, lookup_keys/1]).
+-export([strip_qlc_call/1, join_info/1, join_info_count/1]).
+-export([i/1, i/2, format_info/2]).
+
+-export([table_kill_parent/2, table_parent_throws/2,
+ table_parent_exits/2, table_bad_parent_fun/2]).
+-export([table/2, table/3, stop_list/2, table_error/2, table_error/3,
+ table_lookup_error/1]).
+
+%% error_logger
+-export([install_error_logger/0, uninstall_error_logger/0,
+ read_error_logger/0]).
+-export([init/1,
+ handle_event/2, handle_call/2, handle_info/2,
+ terminate/2]).
+
+% Default timetrap timeout (set in init_per_testcase).
+-define(default_timeout, ?t:minutes(5)).
+
+init_per_testcase(Case, Config) ->
+ ?line Dog = ?t:timetrap(?default_timeout),
+ [{?TESTCASE, Case}, {watchdog, Dog} | Config].
+
+fin_per_testcase(_Case, _Config) ->
+ Dog = ?config(watchdog, _Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+all(suite) ->
+ [parse_transform, evaluation, table_impls, join, tickets, manpage, compat].
+
+parse_transform(suite) ->
+ [badarg, nested_qlc, unused_var, lc, fun_clauses, filter_var,
+ single, exported_var, generator_vars, nomatch, errors, pattern].
+
+badarg(doc) ->
+ "Badarg.";
+badarg(suite) -> [];
+badarg(Config) when is_list(Config) ->
+ Ts =
+ [{badarg,
+ <<"-import(qlc, [q/1, q/2]).
+ q(_, _, _) -> ok.
+
+ badarg() ->
+ qlc:q(foo),
+ qlc:q(foo, cache_all),
+ qlc:q(foo, cache_all, extra),
+ q(bar),
+ q(bar, cache_all),
+ q(bar, cache_all, extra).
+ ">>,
+ [],
+ {errors,[{5,?QLC,not_a_query_list_comprehension},
+ {6,?QLC,not_a_query_list_comprehension},
+ {8,?QLC,not_a_query_list_comprehension},
+ {9,?QLC,not_a_query_list_comprehension}],
+ []}}],
+ ?line [] = compile(Config, Ts),
+ ok.
+
+nested_qlc(doc) ->
+ "Nested qlc expressions.";
+nested_qlc(suite) -> [];
+nested_qlc(Config) when is_list(Config) ->
+ %% Nested QLC expressions. X is bound before the first one; Z and X
+ %% before the second one.
+ Ts =
+ [{nested_qlc1,
+ <<"nested_qlc() ->
+ X = 3, % X unused
+ Q = qlc:q([Y ||
+ X <- % X shadowed
+ begin Z = 3,
+ qlc:q([Y ||
+ Y <- [Z],
+ X <- [1,2,3], % X shadowed
+ X < Y])
+ end,
+ Y <-
+ [y],
+ Y > X]),
+ [y, y] = qlc:e(Q),
+ ok.
+ ">>,
+ [warn_unused_vars],
+ {warnings,[{{2,15},erl_lint,{unused_var,'X'}},
+ {{4,29},erl_lint,{shadowed_var,'X',generate}},
+ {{8,49},erl_lint,{shadowed_var,'X',generate}}]}},
+
+ {nested_qlc2,
+ <<"nested_qlc() ->
+ H0 = qlc:append([a,b], [c,d]),
+ qlc:q([{X,Y} ||
+ X <- H0,
+ Y <- qlc:q([{X,Y} ||
+ X <- H0, % X shadowed
+ Y <- H0])]),
+ ok.
+ ">>,
+ [warn_unused_vars],
+ {warnings,[{{6,39},erl_lint,{shadowed_var,'X',generate}}]}}
+ ],
+ ?line [] = compile(Config, Ts),
+ ok.
+
+unused_var(doc) ->
+ "Unused variable with a name that should not be introduced.";
+unused_var(suite) -> [];
+unused_var(Config) when is_list(Config) ->
+ Ts =
+ [{unused_var,
+ <<"unused_var() ->
+ qlc:q([X || begin Y1 = 3, true end, % Y1 unused
+ Y <- [1,2,3],
+ X <- [a,b,c],
+ X < Y]).
+ ">>,
+ [warn_unused_vars],
+ {warnings,[{{2,33},erl_lint,{unused_var,'Y1'}}]}}],
+ ?line [] = compile(Config, Ts),
+ ok.
+
+lc(doc) ->
+ "Ordinary LC expression.";
+lc(suite) -> [];
+lc(Config) when is_list(Config) ->
+ Ts =
+ [{lc,
+ <<"lc() ->
+ [X || X <- [], X <- X]. % X shadowed
+ ">>,
+ [],
+ {warnings,[{{2,30},erl_lint,{shadowed_var,'X',generate}}]}}],
+ ?line [] = compile(Config, Ts),
+ ok.
+
+fun_clauses(doc) ->
+ "Fun with several clauses.";
+fun_clauses(suite) -> [];
+fun_clauses(Config) when is_list(Config) ->
+ Ts =
+ [{fun_clauses,
+ <<"fun_clauses() ->
+ {X,X1,X2} = {1,2,3},
+ F = fun({X}) -> qlc:q([X || X <- X]); % X shadowed (fun, generate)
+ ([X]) -> qlc:q([X || X <- X]) % X shadowed (fun, generate)
+ end,
+ {F,X,X1,X2}.
+ ">>,
+ [],
+ {warnings,[{{3,22},erl_lint,{shadowed_var,'X','fun'}},
+ {{3,41},erl_lint,{shadowed_var,'X',generate}},
+ {{4,22},erl_lint,{shadowed_var,'X','fun'}},
+ {{4,41},erl_lint,{shadowed_var,'X',generate}}]}}],
+ ?line [] = compile(Config, Ts),
+ ok.
+
+filter_var(doc) ->
+ "Variable introduced in filter.";
+filter_var(suite) -> [];
+filter_var(Config) when is_list(Config) ->
+ Ts =
+ [{filter_var,
+ <<"filter_var() ->
+ qlc:q([X ||
+ Y <- [X ||
+ X <- [1,2,3]],
+ begin X = Y, true end]).
+ ">>,
+ [],
+ []},
+
+ {unsafe_filter_var,
+ <<"unsafe_filter_var() ->
+ qlc:q([{X,V} || X <- [1,2],
+ case {a} of
+ {_} ->
+ true;
+ V ->
+ V
+ end]).
+ ">>,
+ [],
+ {errors,[{{2,25},erl_lint,{unsafe_var,'V',{'case',{3,19}}}}],[]}}],
+ ?line [] = compile(Config, Ts),
+ ok.
+
+
+single(doc) ->
+ "Unused pattern variable.";
+single(suite) -> [];
+single(Config) when is_list(Config) ->
+ Ts =
+ [{single,
+ <<"single() ->
+ qlc:q([X || {X,Y} <- [{1,2}]]), % Y unused
+ qlc:q([[] || [] <- [[]]]).
+ ">>,
+ [warn_unused_vars],
+ {warnings,[{{2,30},erl_lint,{unused_var,'Y'}}]}}],
+ ?line [] = compile(Config, Ts),
+ ok.
+
+exported_var(doc) ->
+ "Exported variable in list expression (rhs of generator).";
+exported_var(suite) -> [];
+exported_var(Config) when is_list(Config) ->
+ Ts =
+ [{exported_var,
+ <<"exported() ->
+ qlc:q([X || X <- begin
+ case foo:bar() of
+ 1 -> Z = a;
+ 2 -> Z = b
+ end,
+ [Z = 3, Z = 3] % Z exported (twice...)
+ end
+ ]).
+ ">>,
+ [warn_export_vars],
+ {warnings,[{{7,37},erl_lint,{exported_var,'Z',{'case',{3,36}}}},
+ {{7,44},erl_lint,{exported_var,'Z',{'case',{3,36}}}}]}}],
+ ?line [] = compile(Config, Ts),
+ ok.
+
+generator_vars(doc) ->
+ "Errors for generator variable used in list expression.";
+generator_vars(suite) -> [];
+generator_vars(Config) when is_list(Config) ->
+ Ts =
+ [{generator_vars,
+ <<"generator_vars() ->
+ qlc:q([X ||
+ Z <- [1,2],
+ X <- begin
+ case 1 of
+ 1 -> Z = a; % used_generator_variable
+ 2 -> Z = b % used_generator_variable
+ end,
+ [Z = 3, Z = 3] % used_generator_variable (2)
+ end
+ ]).
+ ">>,
+ [],
+ {errors,[{{6,41},?QLC,{used_generator_variable,'Z'}},
+ {{7,41},?QLC,{used_generator_variable,'Z'}},
+ {{9,33},?QLC,{used_generator_variable,'Z'}},
+ {{9,40},?QLC,{used_generator_variable,'Z'}}],
+ []}}],
+ ?line [] = compile(Config, Ts),
+ ok.
+
+nomatch(doc) ->
+ "Unreachable clauses also found when compiling.";
+nomatch(suite) -> [];
+nomatch(Config) when is_list(Config) ->
+ Ts =
+ [{unreachable1,
+ <<"unreachable1() ->
+ qlc:q([X || X <- [1,2],
+ case X of
+ true -> false;
+ true -> true % clause cannot match
+ end]).
+ ">>,
+ [],
+ {warnings,[{5,v3_kernel,{nomatch_shadow,4}}]}},
+
+ {nomatch1,
+ <<"generator1() ->
+ qlc:q([3 || {3=4} <- []]).
+ ">>,
+ [],
+ {warnings,[{{2,27},qlc,nomatch_pattern}]}},
+
+ {nomatch2,
+ <<"nomatch() ->
+ etsc(fun(E) ->
+ Q = qlc:q([3 || {3=4} <- ets:table(E)]),
+ [] = qlc:eval(Q),
+ false = lookup_keys(Q)
+ end, [{1},{2}]).
+ ">>,
+ [],
+ {warnings,[{{3,33},qlc,nomatch_pattern}]}},
+
+ {nomatch3,
+ <<"nomatch() ->
+ etsc(fun(E) ->
+ Q = qlc:q([{A,B,C,D} || A=B={C=D}={_,_} <-
+ ets:table(E)]),
+ [] = qlc:eval(Q),
+ false = lookup_keys(Q)
+ end, [{1,2},{2,3}]).
+ ">>,
+ [],
+ {warnings,[{{3,52},qlc,nomatch_pattern}]}},
+
+ {nomatch4,
+ <<"nomatch() ->
+ etsc(fun(E) ->
+ Q = qlc:q([{X,Y} || {<<X>>} = {<<Y>>} <-
+ ets:table(E)]),
+ [] = qlc:eval(Q),
+ false = lookup_keys(Q)
+ end, [{<<34>>},{<<40>>}]).
+ ">>,
+ [],
+ {errors,[{{3,48},erl_lint,illegal_bin_pattern}],[]}},
+
+ {nomatch5,
+ <<"nomatch() ->
+ etsc(fun(E) ->
+ Q = qlc:q([t || {\"a\"++\"b\"} = {\"ac\"} <-
+ ets:table(E)]),
+ [t] = qlc:eval(Q),
+ [\"ab\"] = lookup_keys(Q)
+ end, [{\"ab\"}]).
+ ">>,
+ [],
+ {warnings,[{3,v3_core,nomatch}]}}
+
+ ],
+ ?line [] = compile(Config, Ts),
+ ok.
+
+
+errors(doc) ->
+ "Errors within qlc expressions also found when compiling.";
+errors(suite) -> [];
+errors(Config) when is_list(Config) ->
+ Ts =
+ [{errors1,
+ <<"errors1() ->
+ qlc:q([X || X <- A]). % A unbound
+ ">>,
+ [],
+ {errors,[{{2,33},erl_lint,{unbound_var,'A'}}],[]}}],
+ ?line [] = compile(Config, Ts),
+ ok.
+
+pattern(doc) ->
+ "Patterns.";
+pattern(suite) -> [];
+pattern(Config) when is_list(Config) ->
+ Ts = [
+ <<"%% Records in patterns. No lookup.
+ L = [#a{k=#k{v=91}}],
+ H = qlc:q([Q || Q = #a{k=#k{v=91}} <- qlc_SUITE:table(L, 2, [])]),
+ {qlc,_,[{generate,_,{table,{call,_,_,_}}}], []} = i(H),
+ L = qlc:e(H),
+ {call, _, _q, [{lc,_,{var,_,'Q'},
+ [{generate,_,
+ {match,_,_,_},
+ {call,_,_,_}}]}]}
+ = i(H, {format,abstract_code})">>,
+
+ <<"%% No matchspec since there is a binary in the pattern.
+ etsc(fun(E) ->
+ Q = qlc:q([A || {<<A:3/unit:8>>} <- ets:table(E)]),
+ [_] = qlc:eval(Q),
+ {qlc,_,[{generate,_,{table,_}}], []} = i(Q)
+ end, [{<<\"hej\">>}])">>
+
+ ],
+ ?line run(Config, <<"-record(a, {k,v}).
+ -record(k, {t,v}).\n">>, Ts),
+ ok.
+
+evaluation(suite) ->
+ [eval, cursor, fold, eval_unique, eval_cache, append, evaluator,
+ string_to_handle, table, process_dies, sort, keysort, filesort, cache,
+ cache_list, filter, info, nested_info, lookup1, lookup2, lookup_rec,
+ indices, pre_fun, skip_filters].
+
+eval(doc) ->
+ "eval/2";
+eval(suite) -> [];
+eval(Config) when is_list(Config) ->
+ ScratchDir = filename:join([?privdir, "scratch","."]),
+
+ Ts = [<<"{'EXIT',{badarg,_}} = (catch qlc:eval(not_a_qlc)),
+ H = qlc:q([X || X <- [1,2]]),
+ {'EXIT',{{unsupported_qlc_handle,{qlc_handle,foo}},_}}=
+ (catch qlc:e({qlc_handle,foo})),
+ {'EXIT',{badarg,_}} = (catch qlc:eval(H, [{unique_all,badarg}])),
+ {'EXIT',{badarg,_}} =
+ (catch qlc:eval(H, [{spawn_options,badarg}])),
+ {'EXIT',{badarg,_}} =
+ (catch qlc:eval(H, [{unique_all,true},{bad,arg}])),
+ {throw,t} =
+ (catch {any_term,qlc:e(qlc:q([X || X <- throw({throw,t})]))}),
+ M = qlc,
+ {'EXIT',{badarg,_}} = (catch M:q(bad))">>,
+
+ [<<"Dir = \"">>,ScratchDir,<<"\",
+ qlc_SUITE:prep_scratchdir(Dir),
+
+ E = ets:new(foo, []),
+ [true || I <- lists:seq(1, 50000), not ets:insert(E, {I, I})],
+ H = qlc:q([{X,Y} || Y <- [1,2],
+ X <- qlc:sort(ets:table(E),{tmpdir,Dir}),
+ qlc_SUITE:truncate_tmpfile(Dir, 0)]),
+ R = qlc:eval(H),
+ ets:delete(E),
+ {error,_,{bad_object,_}} = R,
+ \"the tempo\" ++ _ = lists:flatten(qlc:format_error(R))">>],
+
+ [<<"Dir = \"">>,ScratchDir,<<"\",
+ qlc_SUITE:prep_scratchdir(Dir),
+
+ E = ets:new(foo, []),
+ Bin = term_to_binary(lists:seq(1,20000)),
+ [true || I <- lists:seq(1, 10), not ets:insert(E, {I, I, Bin})],
+ H = qlc:q([{X,Y} || Y <- [1,2],
+ X <- qlc:sort(ets:table(E),{tmpdir,Dir}),
+ qlc_SUITE:crash_tmpfile(Dir, 5)]),
+ R = qlc:eval(H),
+ ets:delete(E),
+ {error,_,{bad_object,_}} = R">>],
+
+ <<"E = ets:new(test, []),
+ H = qlc:q([{X,Y} || X <- qlc_SUITE:bad_table_throw(E),
+ Y <- ets:table(E)]),
+ R1 = (catch {any_term,qlc:eval(H, {unique_all,false})}),
+ R2 = (catch {any_term,qlc:eval(H, {unique_all,true})}),
+ ets:delete(E),
+ true = {throw,bad_pre_fun} == R1,
+ true = {throw,bad_pre_fun} == R2">>,
+
+ <<"E = ets:new(test, []),
+ H = qlc:q([{X,Y} || X <- qlc_SUITE:bad_table_exit(E),
+ Y <- ets:table(E)]),
+ R1 = (catch qlc:eval(H, {unique_all,false})),
+ R2 = (catch qlc:eval(H, {unique_all,true})),
+ ets:delete(E),
+ {'EXIT',{bad_pre_fun,_}} = R1,
+ {'EXIT',{bad_pre_fun,_}} = R2">>,
+
+ <<"Q = qlc:q([X || X <- [4,3,2,1,0,-1], begin 3/X > 0 end]),
+ {'EXIT',{badarith,_}} = (catch qlc:eval(Q, {unique_all,false})),
+ {'EXIT',{badarith,_}} = (catch qlc:eval(Q, {unique_all,true}))
+ ">>,
+
+ <<"[1,2] = qlc:eval(qlc:q([X || X <- [1,2]])),
+ [1,2,3,4] = qlc:eval(qlc:append([1,2],[3,4])),
+ [1,2] = qlc:eval(qlc:sort([2,1])),
+ E = ets:new(foo, []),
+ ets:insert(E, [{1},{2}]),
+ [{1},{2}] = lists:sort(qlc:eval(ets:table(E))),
+ true = ets:delete(E)">>,
+
+ <<"H = qlc:q([X || X <- [1,2],
+ begin F = fun() ->
+ qlc:e(qlc:q([Y || Y <- [1,2]])) end,
+ F() == (fun f/0)() end]),
+ [1,2] = qlc:e(H),
+ ok.
+
+ f() -> [1,2].
+ foo() -> bar">>,
+
+ <<"C1_0_1 = [1,2],
+ %% The PT cannot rename C to C1_0_1; another name is chosen.
+ [1,2] = qlc:eval(qlc:q([C || C <- C1_0_1]))">>,
+
+ <<"H = qlc:q([X || {X,X} <- [{1,a},{2,2},{b,b},{3,4}]]),
+ [2,b] = qlc:e(H),
+ H1 = qlc:q([3 || {X,X} <- [{1,a},{2,2},{b,b},{3,4}]]),
+ [3,3] = qlc:e(H1)">>,
+
+ %% Just to cover a certain line in qlc.erl (avoids returning [])
+ <<"E = ets:new(foo, []),
+ Bin = term_to_binary(lists:seq(1,20000)),
+ [true || I <- lists:seq(1, 10), not ets:insert(E, {I, I, Bin})],
+ H = qlc:q([{X,Y} || Y <- [1,2], X <- qlc:sort(ets:table(E))]),
+ R = qlc:eval(H),
+ ets:delete(E),
+ 20 = length(R)">>,
+
+ <<"H = qlc:q([{A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W} ||
+ {A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W} <-
+ [{a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w}]]),
+ [_] = qlc:e(H)">>,
+
+ <<"H = qlc:q([Y || Y <- [1,2]],
+ {unique, begin [T] = qlc:e(qlc:q([X || X <- [true]],
+ cache)),
+ T end}),
+ [1,2] = qlc:e(H)">>
+
+ ],
+
+ ?line run(Config, Ts),
+ ok.
+
+cursor(doc) ->
+ "cursor/2";
+cursor(suite) -> [];
+cursor(Config) when is_list(Config) ->
+ ScratchDir = filename:join([?privdir, "scratch","."]),
+ Ts = [<<"{'EXIT',{badarg,_}} =
+ (catch qlc:cursor(fun() -> not_a_cursor end)),
+ H0 = qlc:q([X || X <- throw({throw,t})]),
+ {throw,t} = (catch {any_term,qlc:cursor(H0)}),
+ H = qlc:q([X || X <- [1,2]]),
+ {'EXIT',{badarg,_}} =
+ (catch qlc:cursor(H,{spawn_options, [a|b]})),
+ {'EXIT',{badarg,_}} =
+ (catch qlc:cursor(H,{bad_option,true}))">>,
+
+ <<"{'EXIT',{badarg,_}} = (catch qlc:delete_cursor(not_a_cursor))">>,
+
+ [<<"Dir = \"">>,ScratchDir,<<"\",
+ qlc_SUITE:prep_scratchdir(Dir), % kludge
+ E = ets:new(foo, []),
+ [true || I <- lists:seq(1, 50000), not ets:insert(E, {I, I})],
+ H = qlc:q([{X,Y} || begin put('$qlc_tmpdir', true), true end,
+ Y <- [1,2],
+ X <- qlc:sort(ets:table(E),{tmpdir,Dir}),
+ qlc_SUITE:truncate_tmpfile(Dir, 0)]),
+ C = qlc:cursor(H),
+ R = qlc:next_answers(C, all_remaining),
+ qlc:delete_cursor(C),
+ erase('$qlc_tmpdir'),
+ ets:delete(E),
+ {error,_,{bad_object,_}} = R">>],
+
+ <<"H1 = qlc:q([X || X <- [1,2]]),
+ C1 = qlc:cursor(H1),
+ [1,2] = qlc:next_answers(C1, all_remaining),
+ [] = qlc:next_answers(C1),
+ [] = qlc:next_answers(C1),
+ ok = qlc:delete_cursor(C1),
+
+ H2 = qlc:append([1,2],[3,4]),
+ C2 = qlc:cursor(H2),
+ [1,2,3,4] = qlc:next_answers(C2, all_remaining),
+ ok = qlc:delete_cursor(C2),
+
+ H3 = qlc:sort([2,1]),
+ C3 = qlc:cursor(H3),
+ [1,2] = qlc:next_answers(C3, all_remaining),
+ ok = qlc:delete_cursor(C3),
+
+ E = ets:new(foo, []),
+ ets:insert(E, [{1},{2}]),
+ H4 = ets:table(E),
+ C4 = qlc:cursor(H4),
+ [{1},{2}] = lists:sort(qlc:next_answers(C4, all_remaining)),
+ ok = qlc:delete_cursor(C4),
+ true = ets:delete(E)">>,
+
+ <<"H = qlc:q([{X,Y} || X <- [1,2], Y <- [a,b]]),
+ C = qlc:cursor(H, []),
+ [{1,a},{1,b}] = qlc:next_answers(C, 2),
+ [{2,a}] = qlc:next_answers(C, 1),
+ [{2,b}] = qlc:next_answers(C, all_remaining),
+ {'EXIT',{badarg,_}} = (catch qlc:next_answers(C, -1)),
+ P = self(),
+ Pid1 = spawn_link(fun() ->
+ {'EXIT',{not_cursor_owner,_}} =
+ (catch qlc:delete_cursor(C)),
+ P ! {self(), done} end),
+ Pid2 = spawn_link(fun() ->
+ {'EXIT',{not_cursor_owner,_}} =
+ (catch qlc:next_answers(C)),
+ P ! {self(), done} end),
+ receive {Pid1, done} -> ok end,
+ receive {Pid2, done} -> ok end,
+ ok = qlc:delete_cursor(C),
+ {'EXIT',{badarg,_}} = (catch qlc:next_answers(not_a_cursor)),
+ ok = qlc:delete_cursor(C)">>,
+
+ <<"Q = qlc:q([X || X <- [1,2,1,2,1]]),
+ C1 = qlc:cursor(Q, [{unique_all,true}]),
+ [1,2] = qlc:next_answers(C1, all_remaining),
+ ok = qlc:delete_cursor(C1),
+ C2 = qlc:cursor(Q, [{unique_all,true}]),
+ [1,2] = qlc:next_answers(C2, all_remaining),
+ ok = qlc:delete_cursor(C2)">>,
+
+ <<"Q = qlc:q([X || X <- [1,2,1,2,1]]),
+ C1 = qlc:cursor(Q, [{unique_all,true},{spawn_options, []}]),
+ [1,2] = qlc:next_answers(C1, all_remaining),
+ ok = qlc:delete_cursor(C1),
+ C2 = qlc:cursor(Q, [{unique_all,true},{spawn_options, default}]),
+ [1,2] = qlc:next_answers(C2, all_remaining),
+ ok = qlc:delete_cursor(C2)">>,
+
+ <<"Q = qlc:q([X || X <- [1,2,1,2,1]]),
+ C1 = qlc:cursor(Q, [{unique_all,false},{spawn_options, []}]),
+ [1,2,1,2,1] = qlc:next_answers(C1, all_remaining),
+ ok = qlc:delete_cursor(C1),
+ C2 = qlc:cursor(Q, [{unique_all,false},{spawn_options, []}]),
+ [1,2,1,2,1] = qlc:next_answers(C2, all_remaining),
+ ok = qlc:delete_cursor(C2)">>,
+
+ <<"Q = qlc:q([X || X <- [1,2,1,2,1]]),
+ C1 = qlc:cursor(Q, [{unique_all,false}]),
+ [1,2,1,2,1] = qlc:next_answers(C1, all_remaining),
+ ok = qlc:delete_cursor(C1),
+ C2 = qlc:cursor(Q, [{unique_all,false}]),
+ [1,2,1,2,1] = qlc:next_answers(C2, all_remaining),
+ ok = qlc:delete_cursor(C2)">>
+
+ ],
+ ?line run(Config, Ts),
+ ok.
+
+fold(doc) ->
+ "fold/4";
+fold(suite) -> [];
+fold(Config) when is_list(Config) ->
+ ScratchDir = filename:join([?privdir, "scratch","."]),
+ Ts = [<<"Q = qlc:q([X || X <- [1,2,1,2,1]]),
+ F = fun(Obj, A) -> A++[Obj] end,
+ {'EXIT',{badarg,_}} = (catch qlc:fold(F, [], Q, {bad,arg})),
+ {'EXIT',{badarg,_}} = (catch qlc:fold(F, [], badarg)),
+ {'EXIT',{badarg,_}} =
+ (catch qlc:fold(F, [], {spawn_options, [a|b]})),
+ H = qlc:q([X || X <- throw({throw,t})]),
+ {throw,t} = (catch {any_term,qlc:fold(F, [], H)}),
+ [1,2] = qlc:fold(F, [], Q, {unique_all,true}),
+ {'EXIT',{badarg,_}} =
+ (catch qlc:fold(F, [], Q, [{unique_all,bad}])),
+ [1,2,1,2,1] =
+ qlc:fold(F, [], Q, [{unique_all,false}])">>,
+
+ [<<"Dir = \"">>,ScratchDir,<<"\",
+ qlc_SUITE:prep_scratchdir(Dir),
+
+ E = ets:new(foo, []),
+ [true || I <- lists:seq(1, 50000), not ets:insert(E, {I, I})],
+ H = qlc:q([{X,Y} || Y <- [1,2],
+ X <- qlc:sort(ets:table(E),{tmpdir,Dir}),
+ qlc_SUITE:truncate_tmpfile(Dir, 0)]),
+ F = fun(Obj, A) -> A++[Obj] end,
+ R = qlc:fold(F, [], H),
+ ets:delete(E),
+ {error,_,{bad_object,_}} = R">>],
+
+ <<"E = ets:new(test, []),
+ H = qlc:q([{X,Y} || X <- qlc_SUITE:bad_table_throw(E),
+ Y <- ets:table(E)]),
+ F = fun(Obj, A) -> A++[Obj] end,
+ R1 = (catch {any_term,qlc:fold(F, [], H, {unique_all,false})}),
+ R2 = (catch {any_term,qlc:fold(F, [], H, {unique_all,true})}),
+ ets:delete(E),
+ true = {throw,bad_pre_fun} == R1,
+ true = {throw,bad_pre_fun} == R2">>,
+
+ <<"E = ets:new(test, []),
+ H = qlc:q([{X,Y} || X <- qlc_SUITE:bad_table_exit(E),
+ Y <- ets:table(E)]),
+ F = fun(Obj, A) -> A++[Obj] end,
+ R1 = (catch qlc:fold(F, [], H, {unique_all,false})),
+ R2 = (catch qlc:fold(F, [], H, {unique_all,true})),
+ ets:delete(E),
+ {'EXIT',{bad_pre_fun,_}} = R1,
+ {'EXIT',{bad_pre_fun,_}} = R2">>,
+
+ <<"F = fun(Obj, A) -> A++[Obj] end,
+ Q = qlc:q([X || X <- [1,2,1,2,1], throw({throw,wrong})]),
+ {throw,wrong} =
+ (catch {any_term,qlc:fold(F, [], Q, {unique_all,true})}),
+ {throw,wrong} =
+ (catch {any_term,qlc:fold(F, [], Q)})">>,
+
+ <<"F = fun(Obj, A) -> A++[Obj] end,
+ Q = qlc:q([X || X <- [4,3,2,1,0,-1], begin 3/X > 0 end]),
+ {'EXIT',{badarith,_}} =
+ (catch qlc:fold(F, [], Q, {unique_all,true})),
+ {'EXIT',{badarith,_}} =
+ (catch qlc:fold(F, [], Q, [{unique_all,false}]))
+ ">>,
+
+ <<"F = fun(Obj, A) -> A++[Obj] end,
+ [1,2] = qlc:fold(F, [], qlc:q([X || X <- [1,2]])),
+ [1,2,3,4] = qlc:fold(F, [], qlc:append([1,2],[3,4])),
+ [1,2] = qlc:fold(F, [], qlc:sort([2,1])),
+ E = ets:new(foo, []),
+ ets:insert(E, [{1},{2}]),
+ [{1},{2}] = lists:sort(qlc:fold(F, [], ets:table(E))),
+ true = ets:delete(E)">>,
+
+ <<"F = fun(_Obj, _A) -> throw({throw,fatal}) end,
+ Q = qlc:q([X || X <- [4,3,2]]),
+ {throw,fatal} =
+ (catch {any_term,qlc:fold(F, [], Q, {unique_all,true})}),
+ {throw,fatal} =
+ (catch {any_term,qlc:fold(F, [], Q, [{unique_all,false}])})">>,
+
+ <<"G = fun(_Obj, _A, D) -> 17/D end,
+ F = fun(Obj, A) -> G(Obj, A, 0) end,
+ Q = qlc:q([X || X <- [4,3,2]]),
+ {'EXIT',{badarith,_}} =
+ (catch qlc:fold(F, [], Q, {unique_all,true})),
+ {'EXIT',{badarith,_}} =
+ (catch qlc:fold(F, [], Q, [{unique_all,false}]))
+ ">>
+ ],
+ ?line run(Config, Ts),
+ ok.
+
+eval_unique(doc) ->
+ "Test the unique_all option of eval.";
+eval_unique(suite) -> [];
+eval_unique(Config) when is_list(Config) ->
+ Ts = [<<"QLC1 = qlc:q([X || X <- qlc:append([[1,1,2], [1,2,3,2,3]])]),
+ [1,2,3] = qlc:eval(QLC1, {unique_all,true}),
+ QLC2 = qlc:q([X || X <- [1,2,1,2,1,2,1]]),
+ [1,2] = qlc:e(QLC2, {unique_all,true})">>,
+
+ <<"E = ets:new(test, []),
+ true = ets:insert(E, [{1,a},{2,b},{3,c}]),
+ H = qlc:q([X || X <- qlc:append([ets:table(E), ets:table(E)])]),
+ R1 = qlc:e(H, {unique_all,false}),
+ R2 = qlc:e(H, {unique_all,true}),
+ ets:delete(E),
+ true = lists:sort(R1) == [{1,a},{1,a},{2,b},{2,b},{3,c},{3,c}],
+ true = lists:sort(R2) == [{1,a},{2,b},{3,c}]
+ ">>,
+
+ <<"Q1 = qlc:q([{X,make_ref()} || X <- [1,2,1,2]]),
+ [_,_] = qlc:e(Q1, {unique_all,true}),
+ [_,_,_,_] = qlc:e(Q1, {unique_all,false}),
+ [_,_] = qlc:e(Q1, [{unique_all,true}]),
+ Q2 = qlc:q([{X,make_ref()} || X <- qlc:append([[1,2,1,2]])]),
+ [_,_] = qlc:e(Q2, {unique_all,true}),
+ [_,_,_,_] = qlc:e(Q2, {unique_all,false}),
+ [_,_] = qlc:e(Q2, [{unique_all,true}])
+ ">>,
+
+ <<"Q = qlc:q([{X,make_ref()} || X <- qlc:sort([1,2,1,2])]),
+ [_, _] = qlc:e(Q, {unique_all,true}),
+ Q1 = qlc:q([X || X <- [1,2,1,2]]),
+ Q2 = qlc:q([{X,make_ref()} || X <- qlc:sort(Q1)]),
+ [_, _] = qlc:e(Q2, {unique_all,true})
+ ">>,
+
+ <<"E = ets:new(test, []),
+ true = ets:insert(E, [{1,a},{2,b},{3,c}]),
+ H = qlc:q([X || X <- qlc:append([[1,2,1,2]])]),
+ [1,2,1,2] = qlc:e(H, {unique_all,false}),
+ [1,2] = qlc:e(H, {unique_all,true}),
+ ets:delete(E)">>,
+
+ <<"E = ets:new(foo, [duplicate_bag]),
+ true = ets:insert(E, [{1,a},{1,a},{2,b},{3,c},{4,c},{4,d}]),
+ Q1 = qlc:q([{X,make_ref()} || {_, X} <- ets:table(E)]),
+ true = length(qlc:eval(Q1, {unique_all, true})) =:= 5,
+ Q2 = qlc:q([X || {_, X} <- ets:table(E)]),
+ true = length(qlc:eval(Q2, {unique_all, true})) =:= 4,
+ Q3 = qlc:q([element(2, X) || X <- ets:table(E)]),
+ true = length(qlc:eval(Q3, {unique_all, true})) =:= 4,
+ Q4 = qlc:q([1 || _X <- ets:table(E)]),
+ true = length(qlc:eval(Q4, {unique_all, true})) =:= 1,
+ true = ets:delete(E)
+ ">>,
+
+ <<"Q1 = qlc:q([X || X <- qlc:append([[1], [2,1]])]),
+ Q2 = qlc:q([X || X <- qlc:append([[2,1], [2]])]),
+ Q3 = qlc:q([{X,Y} || X <- Q1, Y <- Q2]),
+ [{1,2},{1,1},{2,2},{2,1}] = qlc:e(Q3, {unique_all,true}),
+ Q4 = qlc:q([{X,Y,make_ref()} || X <- Q1, Y <- Q2]),
+ [{1,2,_},{1,1,_},{2,2,_},{2,1,_}] = qlc:e(Q4, {unique_all,true})
+ ">>,
+
+ <<"Q1 = qlc:q([X || X <- [1,2,1]]),
+ Q2 = qlc:q([X || X <- [2,1,2]]),
+ Q3 = qlc:q([{X,Y} || X <- Q1, Y <- Q2]),
+ [{1,2},{1,1},{2,2},{2,1}] = qlc:e(Q3,{unique_all,true}),
+ Q4 = qlc:q([{X,Y,make_ref()} || X <- Q1, Y <- Q2]),
+ [{1,2,_},{1,1,_},{2,2,_},{2,1,_}] = qlc:e(Q4, {unique_all,true})
+ ">>,
+
+ <<"Q1 = qlc:q([X || {X,_} <- [{1,a},{1,b}]]),
+ [1] = qlc:e(Q1, {unique_all, true}),
+ Q2 = qlc:q([a || _ <- [{1,a},{1,b}]]),
+ [a] = qlc:e(Q2, {unique_all, true})
+ ">>,
+
+ <<"Q = qlc:q([SQV || SQV <- qlc:q([X || X <- [1,2,1]],unique)],
+ unique),
+ {call,_,_,[{lc,_,{var,_,'X'},[{generate,_,{var,_,'X'},_}]},_]} =
+ qlc:info(Q, [{format,abstract_code},unique_all]),
+ [1,2] = qlc:e(Q)">>,
+
+ <<"Q = qlc:q([X || X <- [1,2,1]]),
+ {call,_,_,[{lc,_,{var,_,'X'},[{generate,_,{var,_,'X'},_}]},_]} =
+ qlc:info(Q, [{format,abstract_code},unique_all]),
+ [1,2] = qlc:e(Q, unique_all)">>,
+
+ <<"Q1 = qlc:sort([{1},{2},{3},{1}], [{unique,true}]),
+ Q = qlc:sort(Q1,[{unique,true}]),
+ {sort,{sort,{list,_},[{unique,true}]},[]} = i(Q)">>
+
+ ],
+ ?line run(Config, Ts),
+ ok.
+
+eval_cache(doc) ->
+ "Test the cache_all and unique_all options of eval.";
+eval_cache(suite) -> [];
+eval_cache(Config) when is_list(Config) ->
+ Ts = [
+ <<"E = ets:new(apa, [ordered_set]),
+ ets:insert(E, [{1},{2}]),
+ H = qlc:q([X || Y <- [3,4],
+ ets:insert(E, {Y}),
+ X <- ets:table(E)]), % already unique, no cache...
+ {qlc, _,
+ [{generate, _, {qlc, _,
+ [{generate, _, {list, [3,4]}}],
+ [{unique,true}]}},
+ _,
+ {generate, _, {table,_}}],
+ [{unique,true}]} = i(H, [cache_all, unique_all]),
+ [{1},{2},{3},{4}] = qlc:e(H, [cache_all, unique_all]),
+ ets:delete(E)">>,
+
+ <<"E = ets:new(apa, [ordered_set]),
+ ets:insert(E, [{1},{2}]),
+ H = qlc:q([X || Y <- [3,4],
+ ets:insert(E, {Y}),
+ X <- ets:table(E)]), % no cache...
+ {qlc, _,
+ [{generate, _,{list, [3,4]}},
+ _,
+ {generate, _, {table,_}}],
+ []} = i(H, cache_all),
+ [{1},{2},{3},{1},{2},{3},{4}] = qlc:e(H, [cache_all]),
+ ets:delete(E)">>,
+
+ <<"E = ets:new(apa, [ordered_set]),
+ ets:insert(E, [{1},{2}]),
+ H = qlc:q([X || Y <- [3,4],
+ ets:insert(E, {Y}),
+ X <- qlc:q([X || X <- ets:table(E)], cache)]),
+ {qlc, _,
+ [{generate, _, {list, [3,4]}},
+ _,
+ {generate, _, {qlc, _,
+ [{generate, _, {table,_}}],
+ [{cache,ets}]}}],
+ []} = i(H, cache_all),
+ [{1},{2},{3},{1},{2},{3}] = qlc:e(H, [cache_all]),
+ ets:delete(E)">>,
+
+ <<"%% {cache_all,no} does not override {cache,true}.
+ E = ets:new(apa, [ordered_set]),
+ ets:insert(E, [{1},{2}]),
+ H = qlc:q([X || Y <- [3,4],
+ ets:insert(E, {Y}),
+ X <- qlc:q([X || X <- ets:table(E)], cache)]),
+ {qlc, _,
+ [{generate, _, {list, [3,4]}},
+ _,
+ {generate, _, {qlc, _,
+ [{generate, _, {table,_}}],
+ [{cache,ets}]}}],
+ []} = i(H, {cache_all,no}),
+ [{1},{2},{3},{1},{2},{3}] = qlc:e(H, [cache_all]),
+ ets:delete(E)">>,
+
+ <<"E = ets:new(apa, [ordered_set]),
+ ets:insert(E, [{1},{2}]),
+ H = qlc:q([X || Y <- [3,4],
+ ets:insert(E, {Y}),
+ X <- ets:table(E)]),
+ {qlc, _,
+ [{generate, _, {qlc, _, [{generate, _,{list, [3,4]}}],
+ [{unique,true}]}},
+ _,
+ {generate, _,{table,_}}],
+ [{unique,true}]} = i(H, unique_all),
+ [{1},{2},{3},{4}] = qlc:e(H, [unique_all]),
+ ets:delete(E)">>,
+
+ %% cache_all is ignored
+ <<"E = ets:new(apa, [ordered_set]),
+ ets:insert(E, [{1},{2},{0}]),
+ H = qlc:q([X || X <- qlc:sort(ets:table(E))]),
+ {sort,_Table,[]} = i(H, cache_all),
+ [{0},{1},{2}] = qlc:e(H, cache_all),
+ ets:delete(E)">>,
+
+ <<"F = fun(Obj, A) -> A++[Obj] end,
+ E = ets:new(apa, [duplicate_bag]),
+ true = ets:insert(E, [{1,a},{2,b},{1,a}]),
+ Q = qlc:q([X || X <- ets:table(E)], cache),
+ {table, _} = i(Q, []),
+ R = qlc:fold(F, [], Q, []),
+ ets:delete(E),
+ true = [{1,a},{1,a},{2,b}] == lists:sort(R)">>,
+
+ <<"E = ets:new(apa, [ordered_set]),
+ ets:insert(E, [{1},{2},{0}]),
+ H = qlc:q([X || X <- ets:table(E)], cache),
+ {table, _} = i(H, cache_all),
+ [{0},{1},{2}]= qlc:e(H, cache_all),
+ ets:delete(E)">>,
+
+ <<"E = ets:new(foo, []),
+ true = ets:insert(E, [{1}, {2}]),
+ Q1 = qlc:q([{X} || X <- ets:table(E)]),
+ Q2 = qlc:q([{X,Y} || {X} <- Q1, {Y} <- Q1]),
+ {qlc, _, [{generate, _, {table, _}},
+ {generate, _, {qlc, _, [{generate, _, {table, _}}],
+ [{cache,ets}]}}],
+ []} = i(Q2, cache_all),
+ [{{1},{1}},{{1},{2}},{{2},{1}},{{2},{2}}] =
+ lists:sort(qlc:e(Q2, cache_all)),
+ ets:delete(E)">>,
+
+ <<"L1 = [1,2,3],
+ L2 = [4,5,6],
+ Q1 = qlc:append(L1, L2),
+ Q2 = qlc:q([{X} || X <- Q1]),
+ {qlc, _,[{generate, _,{append, [{list, L1}, {list, L2}]}}], []} =
+ i(Q2, [cache_all]),
+ [{1},{2},{3},{4},{5},{6}] = qlc:e(Q2, [cache_all])">>,
+
+ <<"H = qlc:sort(qlc:q([1 || _ <- [a,b]])),
+ {sort, {qlc, _, [{generate, _, {qlc, _, [{generate, _,
+ {list, [a,b]}}],
+ [{unique,true}]}}],
+ [{unique,true}]},
+ []} = i(H, unique_all),
+ [1] = qlc:e(H, unique_all)">>
+
+ ],
+ ?line run(Config, Ts),
+ ok.
+
+append(doc) ->
+ "Test the append function.";
+append(suite) -> [];
+append(Config) when is_list(Config) ->
+ Ts = [<<"C = qlc:cursor(qlc:q([X || X <- [0,1,2,3], begin 10/X > 0.0 end])),
+ R = (catch qlc:next_answers(C)),
+ {'EXIT',{badarith,_}} = R">>,
+
+ <<"C = qlc:cursor(qlc:q([X || X <- [0 | fun() -> exit(bad) end]])),
+ R = (catch qlc:next_answers(C)),
+ {'EXIT',bad} = R">>,
+
+ <<"{'EXIT',{badarg,_}} = (catch qlc:append([a], a)),
+ {'EXIT',{badarg,_}} = (catch qlc:append([[a],a]))">>,
+
+ <<"C = qlc:cursor(qlc:q([X || X <- [0,1,2,3],
+ begin throw({throw,wrong}), true end])),
+ {throw,wrong} = (catch {any_term,qlc:next_answers(C)})">>,
+
+ <<"QLC = qlc:q([X || X <- [0,1,2,3],
+ begin throw({throw,wrong}), true end]),
+ {throw,wrong} = (catch {any_term,qlc:eval(QLC)}),
+ {throw,wrong} =
+ (catch {any_term,qlc:e(QLC, {unique_all,true})})">>,
+
+ <<"H1 = qlc:q([X || X <- [1,2,3]]),
+ H2 = qlc:q([X || X <- [4,5,6]]),
+ R = qlc:e(qlc:q([X || X <- qlc:append([H1, H2])])),
+ true = R == [1,2,3,4,5,6]">>,
+
+ <<"H1 = [1,2,3],
+ H2 = qlc:q([X || X <- [4,5,6]]),
+ R = qlc:e(qlc:q([X || X <- qlc:append(H1, H2)])),
+ true = R == [1,2,3,4,5,6]">>,
+
+ <<"H1 = qlc:q([X || X <- [1,2,3]]),
+ H2 = qlc:q([X || X <- [4,5,6]]),
+ R = qlc:e(qlc:q([X || X <- qlc:append(qlc:e(H1), H2)])),
+ true = R == [1,2,3,4,5,6]">>,
+
+ <<"H1 = qlc:q([X || X <- [1,2,3]]),
+ H2 = [4,5,6],
+ R = qlc:e(qlc:q([X || X <- qlc:append(H1, H2)])),
+ true = R == [1,2,3,4,5,6]">>,
+
+ <<"H1 = qlc:q([X || X <- [1,2,3]]),
+ H2 = qlc:q([X || X <- [4,5,6]]),
+ R = qlc:e(qlc:q([X || X <- qlc:append([H1, H2, H1]), X < 5])),
+ true = R == [1,2,3,4,1,2,3]">>,
+
+ <<"R = qlc:e(qlc:q([X || X <- qlc:append([lista(), anrop()])])),
+ true = R == [a,b,1,2],
+ ok.
+
+ lista() ->
+ [a,b].
+
+ anrop() ->
+ qlc:q([X || X <- [1,2]]).
+ foo() -> bar">>,
+
+ %% Used to work up to R11B.
+ % <<"apa = qlc:e(qlc:q([X || X <- qlc:append([[1,2,3], ugly()])])),
+ % ok.
+ %
+ % ugly() ->
+ % [a | apa].
+ % foo() -> bar">>,
+
+
+ %% Maybe this one should fail.
+ <<"[a|b] = qlc:e(qlc:q([X || X <- qlc:append([[a|b]])])),
+ ok">>,
+
+ <<"17 = qlc:e(qlc:q([X || X <- qlc:append([[1,2,3],ugly2()])])),
+ ok.
+
+ ugly2() ->
+ [a | fun() -> 17 end].
+ foo() -> bar">>,
+
+ <<"E = ets:new(test, []),
+ true = ets:insert(E, [{1,a},{2,b},{3,c}]),
+ H = qlc:q([X || X <- qlc:append([ets:table(E), apa])]),
+ {'EXIT',{badarg,_}} = (catch qlc:e(H)),
+ false = ets:info(E, safe_fixed),
+ {'EXIT',{badarg,_}} = (catch qlc:e(H)),
+ false = ets:info(E, safe_fixed),
+ {'EXIT',{badarg,_}} = (catch qlc:cursor(H)),
+ false = ets:info(E, safe_fixed),
+ F = fun(Obj, A) -> A++[Obj] end,
+ {'EXIT',{badarg,_}} = (catch qlc:fold(F, [], H)),
+ false = ets:info(E, safe_fixed),
+ ets:delete(E)">>,
+
+ <<"H1 = qlc:q([X || X <- [1,2,3]]),
+ H2 = qlc:q([X || X <- [a,b,c]]),
+ R = qlc:e(qlc:q([X || X <- qlc:append(H1,qlc:append(H1,H2))])),
+ true = R == [1,2,3,1,2,3,a,b,c]">>,
+
+ <<"H = qlc:q([X || X <- qlc:append([],qlc:append([[], []]))]),
+ [] = qlc:e(H)">>,
+
+ <<"Q1 = qlc:q([X || X <- [3,4,4]]),
+ Q2 = qlc:q([X || X <- qlc:sort(qlc:append([[1,2], Q1]))]),
+ [1,2,3,4,4] = qlc:e(Q2),
+ [1,2,3,4] = qlc:e(Q2, {unique_all,true})">>,
+
+ <<"[] = qlc:e(qlc:q([X || X <- qlc:append([])]))">>,
+
+ <<"Q1 = qlc:q([X || X <- [a,b]]),
+ Q2 = qlc:q([X || X <- [1,2]]),
+ Q3 = qlc:append([Q1, Q2, qlc:sort([2,1])]),
+ Q = qlc:q([X || X <- Q3]),
+ {append, [{list, [a,b]},
+ {list, [1,2]},
+ {sort,{list, [2,1]},[]}]} = i(Q),
+ [a,b,1,2,1,2] = qlc:e(Q)">>
+
+ ],
+ ?line run(Config, Ts),
+ ok.
+
+evaluator(doc) ->
+ "Simple call from evaluator.";
+evaluator(suite) -> [];
+evaluator(Config) when is_list(Config) ->
+ ?line true = is_alive(),
+ evaluator_2(Config, []),
+ ?line {ok, Node} = start_node(qlc_SUITE_evaluator),
+ ?line ok = rpc:call(Node, ?MODULE, evaluator_2, [Config, [compiler]]),
+ ?line ?t:stop_node(Node),
+ ok.
+
+evaluator_2(Config, Apps) ->
+ ?line lists:foreach(fun(App) -> true = code:del_path(App) end, Apps),
+ FileName = filename:join(?privdir, "eval"),
+ ?line ok = file:write_file(FileName,
+ <<"H = qlc:q([X || X <- L]),
+ [1,2,3] = qlc:e(H).">>),
+ ?line Bs = erl_eval:add_binding('L', [1,2,3], erl_eval:new_bindings()),
+ ?line ok = file:eval(FileName, Bs),
+
+ %% The error message is "handled" a bit too much...
+ %% (no trace of erl_lint left)
+ ?line ok = file:write_file(FileName,
+ <<"H = qlc:q([X || X <- L]), qlc:e(H).">>),
+ ?line {error,_} = file:eval(FileName),
+
+ %% Ugly error message; badarg is caught by file.erl.
+ ?line ok = file:write_file(FileName,
+ <<"H = qlc:q([Z || {X,Y} <- [{a,2}], Z <- [Y]]), qlc:e(H).">>),
+ ?line {error,_} = file:eval(FileName),
+
+ _ = file:delete(FileName),
+ ok.
+
+start_node(Name) ->
+ ?line PA = filename:dirname(code:which(?MODULE)),
+ ?t:start_node(Name, slave, [{args, "-pa " ++ PA}]).
+
+string_to_handle(doc) ->
+ "string_to_handle/1,2.";
+string_to_handle(suite) -> [];
+string_to_handle(Config) when is_list(Config) ->
+ ?line {'EXIT',{badarg,_}} = (catch qlc:string_to_handle(14)),
+ ?line {'EXIT',{badarg,_}} =
+ (catch qlc:string_to_handle("[X || X <- [a].", unique_all)),
+ ?line R1 = {error, _, {_,erl_scan,_}} = qlc:string_to_handle("'"),
+ ?line "1: unterminated " ++ _ = lists:flatten(qlc:format_error(R1)),
+ ?line {error, _, {_,erl_parse,_}} = qlc:string_to_handle("foo"),
+ ?line {'EXIT',{badarg,_}} = (catch qlc:string_to_handle("foo, bar.")),
+ ?line R3 = {error, _, {_,?QLC,not_a_query_list_comprehension}} =
+ qlc:string_to_handle("bad."),
+ ?line "1: argument is not" ++ _ = lists:flatten(qlc:format_error(R3)),
+ ?line R4 = {error, _, {_,?QLC,{used_generator_variable,'Y'}}} =
+ qlc:string_to_handle("[X || begin Y = [1,2], true end, X <- Y]."),
+ ?line "1: generated variable 'Y'" ++ _ =
+ lists:flatten(qlc:format_error(R4)),
+ ?line {error, _, {_,erl_lint,_}} = qlc:string_to_handle("[X || X <- A]."),
+ ?line H1 = qlc:string_to_handle("[X || X <- [1,2]]."),
+ ?line [1,2] = qlc:e(H1),
+ ?line H2 = qlc:string_to_handle("[X || X <- qlc:append([a,b],"
+ "qlc:e(qlc:q([X || X <- [c,d,e]])))]."),
+ ?line [a,b,c,d,e] = qlc:e(H2),
+ %% The generated fun has many arguments (erl_eval has a maximum of 20).
+ ?line H3 = qlc:string_to_handle(
+ "[{A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W} ||"
+ " {A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W} <- []]."),
+ ?line [] = qlc:e(H3),
+ ?line Bs1 = erl_eval:add_binding('L', [1,2,3], erl_eval:new_bindings()),
+ ?line H4 = qlc:string_to_handle("[X || X <- L].", [], Bs1),
+ ?line [1,2,3] = qlc:e(H4),
+ ?line H5 = qlc:string_to_handle("[X || X <- [1,2,1,2]].", [unique, cache]),
+ ?line [1,2] = qlc:e(H5),
+
+ ?line Ets = ets:new(test, []),
+ ?line true = ets:insert(Ets, [{1}]),
+ ?line Bs2 = erl_eval:add_binding('E', Ets, erl_eval:new_bindings()),
+ ?line Q = "[X || {X} <- ets:table(E)].",
+ ?line [1] = qlc:e(qlc:string_to_handle(Q, [], Bs2)),
+ ?line [1] = qlc:e(qlc:string_to_handle(Q, {max_lookup,1000}, Bs2)),
+ ?line [1] = qlc:e(qlc:string_to_handle(Q, {max_lookup,infinity}, Bs2)),
+ ?line {'EXIT',{badarg,_}} =
+ (catch qlc:string_to_handle(Q, {max_lookup,-1}, Bs2)),
+ ?line {'EXIT', {no_lookup_to_carry_out, _}} =
+ (catch qlc:e(qlc:string_to_handle(Q, {lookup,true}, Bs2))),
+ ?line ets:delete(Ets),
+ ok.
+
+table(doc) ->
+ "table";
+table(suite) -> [];
+table(Config) when is_list(Config) ->
+ dets:start(),
+ Ts = [
+ <<"E = ets:new(test, []),
+ {'EXIT',{badarg,_}} =
+ (catch qlc:e(qlc:q([X || X <- ets:table(E, [badarg])]))),
+ [] = qlc:e(qlc:q([X || X <- ets:table(E)])),
+ ets:delete(E)">>,
+
+ <<"{'EXIT',{badarg,_}} = (catch qlc:table(not_a_fun, []))">>,
+
+ <<"E = ets:new(test, []),
+ true = ets:insert(E, [{1,a},{2,b},{3,c}]),
+ H = qlc:q([{X,Y} || X <- ets:table(E), Y <- ets:table(E)]),
+ R = qlc:e(H),
+ ets:delete(E),
+ [{{1,a},{1,a}},{{1,a},{2,b}},{{1,a},{3,c}},
+ {{2,b},{1,a}},{{2,b},{2,b}},{{2,b},{3,c}},
+
+ {{3,c},{1,a}},{{3,c},{2,b}},{{3,c},{3,c}}] = lists:sort(R)">>,
+
+ <<"E = ets:new(test, []),
+ true = ets:insert(E, [{1,a},{2,b},{3,c}]),
+ H = qlc:q([X || X <- qlc:append([ets:table(E), [a,b,c],
+ ets:table(E)])]),
+ R = qlc:e(H),
+ ets:delete(E),
+ [a,b,c,{1,a},{1,a},{2,b},{2,b},{3,c},{3,c}] = lists:sort(R)">>,
+
+ <<"E = ets:new(test, []),
+ true = ets:insert(E, [{1,a},{2,b},{3,c}]),
+ false = ets:info(E, safe_fixed),
+ H = qlc:q([{X,Y} || X <- ets:table(E, {n_objects, default}),
+ Y <- ets:table(E, {n_objects, 2}),
+ false =/= ets:info(E, safe_fixed),
+ throw({throw,apa})]),
+ {throw,apa} = (catch {any_term,qlc:e(H)}),
+ false = ets:info(E, safe_fixed),
+ ets:delete(E)">>,
+
+ <<"E = ets:new(test, []),
+ true = ets:insert(E, [{1,a},{2,b},{3,c}]),
+ false = ets:info(E, safe_fixed),
+ H = qlc:q([{X,Y} || X <- ets:table(E), Y <- ets:table(E),
+ false =/= ets:info(E, safe_fixed), exit(apa)]),
+ {'EXIT',apa} = (catch {any_term,qlc:e(H)}),
+ false = ets:info(E, safe_fixed),
+ ets:delete(E)">>,
+
+ <<"E = ets:new(test, []),
+ true = ets:insert(E, [{1,a},{2,b},{3,c}]),
+ H = qlc:q([{X,Y} || X <- qlc_SUITE:bad_table_throw(E),
+ Y <- ets:table(E)]),
+ R = (catch {any_term,qlc:cursor(H)}),
+ false = ets:info(E, safe_fixed),
+ ets:delete(E),
+ {throw,bad_pre_fun} = R">>,
+
+ <<"E = ets:new(test, []),
+ true = ets:insert(E, [{1,a},{2,b},{3,c}]),
+ H = qlc:q([{X,Y} || X <- qlc_SUITE:bad_table_exit(E),
+ Y <- ets:table(E)]),
+ R = (catch {any_term,qlc:cursor(H)}),
+ false = ets:info(E, safe_fixed),
+ ets:delete(E),
+ {'EXIT',{bad_pre_fun,_}} = R">>,
+
+ <<"E = ets:new(test, [ordered_set]),
+ true = ets:insert(E, [{1,a},{2,b},{3,c}]),
+ H = qlc:q([X || X <- qlc_SUITE:default_table(E)]),
+ R = qlc:e(H),
+ ets:delete(E),
+ [{1,a},{2,b},{3,c}] = R">>,
+
+ <<"E = ets:new(test, [ordered_set]),
+ true = ets:insert(E, [{1,a},{2,b},{3,c}]),
+ H = qlc:q([X || X <- qlc_SUITE:bad_table(E)]),
+ {'EXIT', {badarg, _}} = (catch qlc:e(H)),
+ ets:delete(E)">>,
+
+ %% The info tag num_of_objects is currently not used.
+% <<"E = ets:new(test, [ordered_set]),
+% true = ets:insert(E, [{1,a},{2,b},{3,c}]),
+% H = qlc:q([X || X <- qlc_SUITE:bad_table_info_fun_n_objects(E)]),
+% {'EXIT', finito} = (catch {any_term,qlc:e(H)}),
+% ets:delete(E)">>,
+
+ <<"E = ets:new(test, [ordered_set]),
+ true = ets:insert(E, [{1,a},{2,b},{3,c}]),
+ H = qlc:q([Y || {X,Y} <- qlc_SUITE:bad_table_info_fun_indices(E),
+ X =:= a]),
+ %% This is due to lookup. If the table were traversed there
+ %% would be no failure.
+ {throw, apa} = (catch {any_term,qlc:e(H)}),
+ ets:delete(E)">>,
+
+ <<"E = ets:new(test, [ordered_set]),
+ true = ets:insert(E, [{1,a},{2,b},{3,c}]),
+ H = qlc:q([Y || {X,Y} <- qlc_SUITE:bad_table_info_fun_keypos(E),
+ X =:= a]),
+ {'EXIT',{keypos,_}} = (catch {any_term,qlc:info(H)}),
+ {'EXIT',{keypos,_}} = (catch {any_term,qlc:e(H)}),
+ ets:delete(E)">>,
+
+ begin
+ MS = ets:fun2ms(fun(X) when element(1, X) > 1 -> X end),
+ [<<"E = ets:new(test, []),
+ true = ets:insert(E, [{1,a},{2,b},{3,c}]),
+ MS = ">>, io_lib:format("~w", [MS]), <<",
+ H = qlc:q([{X,Y} || X <- ets:table(E,{traverse,{select, MS}}),
+ Y <- ets:table(E)]),
+ R = qlc:e(H),
+ ets:delete(E),
+ [{{2,b},{1,a}},{{2,b},{2,b}},{{2,b},{3,c}},
+ {{3,c},{1,a}},{{3,c},{2,b}},{{3,c},{3,c}}] = lists:sort(R)">>]
+ end,
+
+ begin % a short table
+ MS = ets:fun2ms(fun(X) when element(1, X) > 1 -> X end),
+ [<<"E = ets:new(test, []),
+ true = ets:insert(E, [{0,b}]),
+ MS = ">>, io_lib:format("~w", [MS]), <<",
+ H1 = qlc:q([X || X <- ets:table(E)]),
+ R1 = qlc:e(H1),
+ H2 = qlc:q([X || X <- ets:table(E, {traverse, {select, MS}})]),
+ R2 = qlc:e(H2),
+ ets:delete(E),
+ [_] = R1,
+ [] = R2">>]
+ end,
+
+ begin
+ File = filename:join(?privdir, "detsfile"),
+ _ = file:delete(File),
+ [<<"{ok, Tab} = dets:open_file(apa, [{file,\"">>, File, <<"\"},
+ {type,bag}]),
+ ok = dets:insert(Tab, [{1,a},{1,b}]),
+ R = qlc:e(qlc:q([X || X <- dets:table(Tab)])),
+ dets:close(Tab),
+ file:delete(\"">>, File, <<"\"),
+ R">>]
+ end,
+
+ %% [T || P <- Table, F] turned into a match spec.
+ <<"E = ets:new(apa, [duplicate_bag]),
+ true = ets:insert(E, [{1,a},{2,b},{3,c},{4,d}]),
+ QH = qlc:q([X || {X,_} <- ets:table(E), X > 2], unique),
+ {qlc, _, [{generate, _, {table, _}}], [{unique,true}]} = i(QH),
+ [3,4] = lists:sort(qlc:e(QH)),
+ ets:delete(E)">>,
+
+ <<"E = ets:new(apa, []),
+ true = ets:insert(E, [{1,a},{2,b}]),
+ {'EXIT', {badarg, _}} = (catch qlc_SUITE:bad_table_format(E)),
+ ets:delete(E)">>,
+
+ <<"E = ets:new(apa, []),
+ true = ets:insert(E, [{1,a},{2,b}]),
+ {'EXIT', {badarg, _}} = (catch qlc_SUITE:bad_table_format_arity(E)),
+ ets:delete(E)">>,
+
+ <<"E = ets:new(apa, []),
+ true = ets:insert(E, [{1,a},{2,b}]),
+ {'EXIT', {badarg, _}} = (catch qlc_SUITE:bad_table_info_arity(E)),
+ ets:delete(E)">>,
+
+ <<"E = ets:new(apa, []),
+ true = ets:insert(E, [{1,a},{2,b}]),
+ {'EXIT', {badarg, _}} = (catch qlc_SUITE:bad_table_traverse(E)),
+ ets:delete(E)">>,
+
+ <<"E = ets:new(apa, []),
+ true = ets:insert(E, [{1,a},{2,b}]),
+ {'EXIT', {badarg, _}} = (catch qlc_SUITE:bad_table_post(E)),
+ ets:delete(E)">>,
+
+ <<"E = ets:new(apa, []),
+ true = ets:insert(E, [{1,a},{2,b}]),
+ {'EXIT', {badarg, _}} = (catch qlc_SUITE:bad_table_max_lookup(E)),
+ ets:delete(E)">>,
+
+ <<"E = ets:new(apa, []),
+ true = ets:insert(E, [{1,a},{2,b}]),
+ {'EXIT', {badarg, _}} = (catch qlc_SUITE:bad_table_lookup(E)),
+ ets:delete(E)">>,
+
+ <<"L = [{1,a},{2,b},{3,c}],
+ QH = qlc:q([element(2, X) || X <- qlc_SUITE:table(L, [2]),
+ (element(1, X) =:= 1)
+ or (2 =:= element(1, X))]),
+ [a,b] = lists:sort(qlc:e(QH))">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([{A,B} || {A,B} <-
+ qlc:q([{B,A} || {A,B} <- ets:table(E),
+ (A =:= 1) or (A =:= 2),
+ math:sqrt(B) < A])]),
+ [{2,2}] = qlc:eval(Q),
+ [1,2] = lookup_keys(Q)
+ end, [{1,1},{2,2}])">>
+ ],
+ ?line run(Config, Ts),
+
+ Ts2 = [
+ %% [T || P <- Table, F] turned into a match spec. Records needed.
+ <<"E = ets:new(foo, [bag]),
+ ets:insert(E, [{a,1,2},#a{b=3,c=4},{a,3}]),
+ QH = qlc:q([X || X <- ets:table(E), is_record(X, a)]),
+ {list,{table,_}, _} = i(QH),
+ [{a,1,2},{a,3,4}] = lists:sort(qlc:eval(QH)),
+ ets:delete(E)">>
+ ],
+ ?line run(Config, <<"-record(a, {b,c}).\n">>, Ts2),
+
+ ok.
+
+process_dies(doc) ->
+ "Caller or cursor process dies.";
+process_dies(suite) -> [];
+process_dies(Config) when is_list(Config) ->
+ Ts = [
+ <<"E = ets:new(test, []),
+ true = ets:insert(E, [{1,a},{2,b},{3,c}]),
+ false = ets:info(E, safe_fixed),
+ Parent = self(),
+ F = fun() ->
+ H = qlc:q([X || X <- ets:table(E)]),
+ qlc:cursor(H),
+ Parent ! {self(),ok}
+ end,
+ Pid = spawn_link(F),
+ receive {Pid,ok} -> ok end,
+ timer:sleep(10),
+ false = ets:info(E, safe_fixed),
+ ets:delete(E)">>,
+
+ <<"%% This is not nice. The cursor's monitor kicks in.
+ E = ets:new(test, []),
+ true = ets:insert(E, [{1,a},{2,b},{3,c}]),
+ false = ets:info(E, safe_fixed),
+ Parent = self(),
+ F = fun() ->
+ H = qlc:q([X || begin
+ process_flag(trap_exit, false),
+ {links, [Pid]} =
+ process_info(self(), links),
+ unlink(Pid),
+ timer:sleep(1),
+ {links, []} =
+ process_info(self(), links),
+ true
+ end,
+ X <- ets:table(E)]),
+ C = qlc:cursor(H),
+ qlc:next_answers(C),
+ Parent ! {self(),ok}
+ end,
+ Pid = spawn_link(F),
+ receive {Pid,ok} -> ok end,
+ timer:sleep(10),
+ false = ets:info(E, safe_fixed),
+ ets:delete(E)">>,
+
+ <<"H = qlc:q([X || X <- [1,2]]),
+ {qlc_cursor, Term} = C = qlc:cursor(H),
+ PF = process_flag(trap_exit, true),
+ F = fun(T) -> not is_pid(T) end,
+ [Pid|_] = lists:dropwhile(F, tuple_to_list(Term)),
+ exit(Pid, kill),
+ timer:sleep(1),
+ {'EXIT', {{qlc_cursor_pid_no_longer_exists, Pid}, _}} =
+ (catch qlc:next_answers(C)),
+ process_flag(trap_exit, PF)">>,
+ <<"H = qlc:q([X || begin process_flag(trap_exit, true), true end,
+ X <- [1,2]]),
+ {qlc_cursor, Term} = C = qlc:cursor(H),
+ PF = process_flag(trap_exit, true),
+ F = fun(T) -> not is_pid(T) end,
+ [Pid|_] = lists:dropwhile(F, tuple_to_list(Term)),
+ [1] = qlc:next_answers(C, 1),
+ exit(Pid, stop),
+ timer:sleep(1),
+ {'EXIT', {{qlc_cursor_pid_no_longer_exists, Pid}, _}} =
+ (catch qlc:next_answers(C)),
+ process_flag(trap_exit, PF)">>,
+ <<"%% This is not nice. No cleanup is done...
+ H = qlc:q([X || begin process_flag(trap_exit, false), true end,
+ X <- [1,2]]),
+ {qlc_cursor, Term} = C = qlc:cursor(H),
+ PF = process_flag(trap_exit, true),
+ F = fun(T) -> not is_pid(T) end,
+ [Pid|_] = lists:dropwhile(F, tuple_to_list(Term)),
+ [1] = qlc:next_answers(C, 1),
+ exit(Pid, stop),
+ timer:sleep(1),
+ {'EXIT', {{qlc_cursor_pid_no_longer_exists, Pid}, _}} =
+ (catch qlc:next_answers(C)),
+ process_flag(trap_exit, PF)">>,
+
+ <<"PF = process_flag(trap_exit, true),
+ E = ets:new(test, []),
+ %% Hard kill. No cleanup will be done.
+ H = qlc:q([X || begin exit(self(), kill), true end,
+ X <- ets:table(E)]),
+ C = qlc:cursor(H),
+ {'EXIT', {{qlc_cursor_pid_no_longer_exists, _}, _}} =
+ (catch qlc:next_answers(C)),
+ false = ets:info(E, safe_fixed), % - but Ets cleans up anyway.
+ true = ets:delete(E),
+ process_flag(trap_exit, PF)">>,
+
+ <<"E = ets:new(test, []),
+ true = ets:insert(E, [{1,a}]),
+ %% The signal is caught by trap_exit. No process dies...
+ H = qlc:q([X || begin exit(self(), normal), true end,
+ X <- ets:table(E)]),
+ C = qlc:cursor(H, {spawn_options, []}),
+ [{1,a}] = qlc:next_answers(C),
+ qlc:delete_cursor(C),
+ false = ets:info(E, safe_fixed),
+ true = ets:delete(E)">>,
+ <<"E = ets:new(test, []),
+ true = ets:insert(E, [{1,a}]),
+ %% The same as last example.
+ H = qlc:q([X || begin
+ process_flag(trap_exit, true),
+ exit(self(), normal), true
+ end,
+ X <- ets:table(E)]),
+ C = qlc:cursor(H, {spawn_options, []}),
+ [{1,a}] = qlc:next_answers(C),
+ qlc:delete_cursor(C),
+ false = ets:info(E, safe_fixed),
+ true = ets:delete(E), ok">>,
+ <<"E = ets:new(test, []),
+ true = ets:insert(E, [{1,a}]),
+ H = qlc:q([X || X <- ets:table(E)]),
+ SpawnOpts = [link, monitor], % monitor is ignored
+ {qlc_cursor, Term} = C = qlc:cursor(H, {spawn_options, SpawnOpts}),
+ F = fun(T) -> not is_pid(T) end,
+ [Pid|_] = lists:dropwhile(F, tuple_to_list(Term)),
+ Me = self(),
+ qlc_SUITE:install_error_logger(),
+ Tuple = {this, tuple, is, writton, onto, the, error_logger},
+ SP = spawn(fun() ->
+ Pid ! Tuple,
+ Me ! {self(), done}
+ end),
+ receive {SP, done} -> ok end,
+ [{1,a}] = qlc:next_answers(C),
+ qlc:delete_cursor(C),
+ {error, _Pid, Tuple} = qlc_SUITE:read_error_logger(),
+ qlc_SUITE:uninstall_error_logger(),
+ false = ets:info(E, safe_fixed),
+ true = ets:delete(E), ok">>
+
+ ],
+ ?line run(Config, Ts),
+ ok.
+
+sort(doc) ->
+ "The sort option.";
+sort(suite) -> [];
+sort(Config) when is_list(Config) ->
+ Ts = [
+ <<"H = qlc:q([X || X <- qlc:sort([1,2,3,2], {unique,true})]),
+ [1,2,3] = qlc:e(H),
+ C1 = qlc:cursor(H),
+ [1,2,3] = qlc:next_answers(C1, all_remaining),
+ qlc:delete_cursor(C1)">>,
+
+ <<"H = qlc:q([{X,Y} || X <- qlc:sort(qlc:q([X || X <- [1,2,3,2]]),
+ {unique,true}),
+ Y <- [a,b]]),
+ [{1,a},{1,b},{2,a},{2,b},{3,a},{3,b}] = qlc:e(H),
+ C = qlc:cursor(H),
+ [{1,a},{1,b},{2,a},{2,b},{3,a},{3,b}] =
+ qlc:next_answers(C, all_remaining),
+ qlc:delete_cursor(C)">>,
+
+ <<"H = qlc:q([X || X <- qlc:sort(qlc:q([X || X <- apa]))]),
+ {'EXIT',{badarg,_}} = (catch qlc:e(H))">>,
+
+ %% An example with a side effect. The result may vary...
+ <<"E = ets:new(test, [duplicate_bag]),
+ true = ets:insert(E, [{1,17},{1,a}]),
+ H_1 = qlc:q([X || X <- ets:table(E)]),
+ H = qlc:q([X || X <- [1,2,3], ets:insert(E, {1,-X}),
+ {_,Y} <- H_1,
+ X > Y]),
+ true = lists:sort(qlc:e(H)) == [1,2,2,3,3,3],
+ true = ets:delete(E)">>,
+
+ <<"E = ets:new(test, [duplicate_bag]),
+ true = ets:insert(E, [{1,17}]),
+ H_1 = qlc:q([X || X <- qlc:sort(ets:tab2list(E))]),
+ %% Note: side effect in filter!
+ H = qlc:q([X || X <- [1,2,3], ets:insert(E, {1,-X}),
+ {_,Y} <- H_1, X > Y]),
+ [] = qlc:e(H),
+ true = ets:delete(E)">>,
+
+ <<"H = qlc:q([X || X <- qlc:sort([1,2,3], {fopp,la})]),
+ {'EXIT',{badarg,_}} = (catch qlc:e(H)),
+ {'EXIT',{badarg,_}} = (catch qlc:cursor(H)),
+ F = fun(Obj, A) -> A++[Obj] end,
+ {'EXIT',{badarg,_}} = (catch qlc:fold(F, [], H))">>,
+
+ <<"Q1 = qlc:q([X || X <- [1,2]]),
+ AL = [Q1, [1,2,3]],
+ Q2 = qlc:q([X || X <- qlc:sort(qlc:append(AL))]),
+ [1,1,2,2,3] = qlc:e(Q2)">>,
+
+ <<"H = qlc:q([{X,Y} || X <- qlc:sort(qlc:q([X || X <- [1,2,3,2]]),
+ {unique,true}),
+ Y <- [a,b]]),
+ {qlc, _,
+ [{generate, _, {sort, {qlc, _, [{generate, _, {list, [1,2,3,2]}}],
+ [{unique,true}]},
+ []}},
+ {generate, _, {qlc, _, [{generate, _, {list, [a,b]}}],
+ [{unique,true}]}}],
+ [{unique,true}]} = i(H, unique_all),
+ [{1,a},{1,b},{2,a},{2,b},{3,a},{3,b}] = qlc:e(H, unique_all)">>,
+
+ <<"L = [1,2,1,3,4,3,1],
+ true = lists:sort(L) == qlc:e(qlc:q([X || X <- qlc:sort(L)])),
+ true = lists:usort(L) ==
+ qlc:e(qlc:q([X || X <- qlc:sort(L, {unique,true})])),
+ true = lists:reverse(lists:sort(L)) ==
+ qlc:e(qlc:q([X || X <- qlc:sort(L, {order, descending})])),
+ true = lists:reverse(lists:usort(L)) ==
+ qlc:e(qlc:q([X || X <- qlc:sort(L, [{order, descending},
+ {unique, true}])])),
+ CF = fun(X, Y) -> X =< Y end,
+ true = lists:sort(L) ==
+ qlc:e(qlc:q([X || X <- qlc:sort(L, {order, CF})])),
+ true = lists:usort(L) ==
+ qlc:e(qlc:q([X || X <- qlc:sort(L, [{order, CF},
+ {unique, true}])]))">>,
+
+ <<"E = ets:new(foo, []),
+ [true || I <- lists:seq(1, 50000), not ets:insert(E, {I, I})],
+ H = qlc:q([{X,Y} || X <- [a,b], Y <- qlc:sort(ets:table(E))]),
+ 100000 = length(qlc:e(H)),
+ ets:delete(E)">>,
+
+ begin
+ TmpDir = ?privdir,
+ [<<"TE = process_flag(trap_exit, true),
+ E = ets:new(foo, []),
+ [true || I <- lists:seq(1, 50000), not ets:insert(E, {I, I})],
+ Ports = erlang:ports(),
+ H = qlc:q([{X,Y} || X <- [a,b],
+ begin
+ [P] = erlang:ports() -- Ports,
+ exit(P, port_exit),
+ true
+ end,
+ Y <- qlc:sort(ets:table(E),
+ [{tmpdir,\"">>,
+ TmpDir, <<"\"}])]),
+ {error, qlc, {file_error, _, _}} = (catch qlc:e(H)),
+ receive {'EXIT', _, port_exit} -> ok end,
+ ets:delete(E),
+ process_flag(trap_exit, TE)">>]
+ end
+
+ ],
+ ?line run(Config, Ts),
+ ok.
+
+keysort(doc) ->
+ "The sort option.";
+keysort(suite) -> [];
+keysort(Config) when is_list(Config) ->
+
+ Ts = [
+ <<"OF = fun(X, Y) -> X =< Y end,
+ F = fun(Obj, A) -> A++[Obj] end,
+ H = qlc:q([X || X <- qlc:keysort(1, [{2,a},{1,b}], {order,OF})]),
+ {'EXIT',{{badarg,order},_}} = (catch qlc:e(H)),
+ {'EXIT',{{badarg,order},_}} = (catch qlc:fold(F, [], H)),
+ {'EXIT',{{badarg,order},_}} = (catch qlc:cursor(H))">>,
+
+ <<"E = create_ets(1, 2),
+ H = qlc:q([X || X <- qlc:keysort([1], ets:table(E),
+ [{size,1},{tmpdir,\"/a/b/c\"}])]),
+ H1 = qlc:q([X || {X,_} <- qlc:e(H), X < 4]),
+ {error,_,{file_error,_,_}} = qlc:info(H1),
+ {error,_,{file_error,_,_}} = qlc:e(H1),
+ ets:delete(E)">>,
+
+ <<"L = [{1,a},{2,b},{3,c},{2,b}],
+ H = qlc:q([{X,Y} || {X,_} <- qlc:keysort(1, qlc:q([X || X <- L]),
+ {unique,true}),
+ Y <- [a,b]]),
+ [{1,a},{1,b},{2,a},{2,b},{3,a},{3,b}] = qlc:e(H),
+ C = qlc:cursor(H),
+ [{1,a},{1,b},{2,a},{2,b},{3,a},{3,b}] =
+ qlc:next_answers(C, all_remaining),
+ qlc:delete_cursor(C)">>,
+
+ <<"H1 = qlc:q([X || X <- qlc:keysort(0, [])]),
+ {'EXIT',{badarg,_}} = (catch qlc:e(H1)),
+ H2 = qlc:q([X || X <- qlc:keysort(1, [], {bad,arg})]),
+ {'EXIT',{badarg,_}} = (catch qlc:e(H2)),
+ H3 = qlc:q([X || X <- qlc:keysort([], [])]),
+ {'EXIT',{badarg,_}} = (catch qlc:e(H3))">>,
+
+ <<"H = qlc:q([X || X <- qlc:keysort(1, [{1,a},{2,b}],
+ [{order,descending},
+ {compressed,true}])]),
+ [{2,b},{1,a}] = qlc:e(H),
+ H2 = qlc:q([X || X <- qlc:keysort(1, [{1},{2}], compressed)]),
+ {'EXIT', {badarg, _}} = (catch qlc:e(H2))">>,
+
+ <<"H = qlc:q([X || X <- qlc:keysort(1, [{1,a},{2,b}], {compressed,false})]),
+ [{1,a},{2,b}] = qlc:e(H)">>,
+
+ <<"E = create_ets(1, 2),
+ H = qlc:q([X || X <- qlc:keysort([1], ets:table(E),
+ [{size,1},{tmpdir,\"/a/b/c\"}])]),
+ F = fun(Obj, A) -> A++[Obj] end,
+ {error,_,{file_error,_,_}} = qlc:e(H),
+ \" \\\"no such\" ++ _ = lists:dropwhile(fun(A) -> A =/= $\s end,
+ lists:flatten(qlc:format_error(qlc:e(H)))),
+ {error,_,{file_error,_,_}} = qlc:e(H, {unique_all,true}),
+ {error,_,{file_error,_,_}} = qlc:cursor(H),
+ {error,_,{file_error,_,_}} = qlc:cursor(H, {unique_all,true}),
+ {error,_,{file_error,_,_}} = qlc:cursor(H, {spawn_options, []}),
+ {error,_,{file_error,_,_}} = qlc:cursor(H, {spawn_options,default}),
+ {error,_,{file_error,_,_}} =
+ qlc:cursor(H, [{unique_all,true},{spawn_options, []}]),
+ {error,_,{file_error,_,_}} = qlc:fold(F, [], H),
+ {error,_,{file_error,_,_}} = qlc:fold(F, [],H, {unique_all,true}),
+ ets:delete(E)">>,
+
+ <<"L = [{1,b,a},{1,b,b},{1,a,a}],
+ H = qlc:q([X || X <- qlc:keysort([4,1], L)]),
+ {error,_,bad_object} = qlc:e(H),
+ \"the keys\" ++ _ = qlc:format_error(qlc:e(H))">>,
+
+ begin
+ File = filename:join(?privdir, "afile"),
+ ok = file:write_file(File, <<>>),
+ [<<"H = qlc:q([X || X <- qlc:keysort([1], [{1},{2},{1}],
+ [{tmpdir,\"">>, File, <<"\"},
+ {size,1}])]),
+ {error,_,{file_error,_,_}} = qlc:e(H),
+ file:delete(\"">>, File, <<"\")">>]
+ end,
+
+ <<"H0 = qlc:q([X || X <- [1,2,3]]),
+ H = qlc:q([X || X <- qlc:sort(H0,{tmpdir,\".\"})]),
+ [1,2,3] = qlc:e(H)">>,
+
+ %% The global option 'tmpdir' takes precedence.
+ begin
+ PrivDir = ?privdir,
+ [<<"L = [{1,a},{2,b}],
+ H = qlc:q([X || X <- qlc:keysort([1], L, {tmpdir,\"/a/b/c\"})]),
+ H1 = qlc:q([X || X <- H, X > 3]),
+ Dir = \"">>, PrivDir, <<"\",
+ Options = [{tmpdir, Dir}],
+ {qlc,_,[{generate,_,{keysort,{list,L},[1],[{tmpdir,Dir}]}},_],[]} =
+ i(H1, Options),
+ [{1,a},{2,b}] = qlc:e(H1, Options)">>] % no check of "/a/b/c"
+ end,
+
+ <<"L = [{2,c},{1,b},{1,a},{3,a},{1,c},{2,b}],
+ true = lists:sort(L) ==
+ qlc:e(qlc:q([X || X <- qlc:keysort([1,2], L)]))">>,
+
+ <<"L = [{1,b},{2,c},{1,a},{3,e},{4,f},{3,d}],
+ true = lists:keysort(1, L) ==
+ qlc:e(qlc:q([X || X <- qlc:keysort(1,L)])),
+ true = lists:ukeysort(1, L) ==
+ qlc:e(qlc:q([X || X <- qlc:keysort(1, L, {unique,true})])),
+ true = lists:reverse(lists:keysort(1, L)) ==
+ qlc:e(qlc:q([X || X <- qlc:keysort(1,L,
+ {order, descending})])),
+ true = lists:reverse(lists:ukeysort(1, L)) ==
+ qlc:e(qlc:q([X || X <- qlc:keysort(1, L, [{unique,true},
+ {order, descending}])]))">>,
+
+ <<"L = [{X} || X <- lists:seq(1,100000)],
+ H1 = qlc:append([L,[{1,2},{2,3},{3,4}]]),
+ H = qlc:keysort([1], qlc:keysort([1], H1, [{compressed,true}])),
+ R = qlc:e(H),
+ 100003 = length(R)">>
+
+ ],
+ ?line run(Config, Ts),
+
+ ok.
+
+filesort(doc) ->
+ "keysort/1,2, using a file.";
+filesort(suite) -> [];
+filesort(Config) when is_list(Config) ->
+ Ts = [
+ <<"Q = qlc:q([X || X <- [{3},{1},{2}]]),
+ Opts = [{size,10},{no_files,3}],
+ Q2 = qlc:q([{X,Y} || Y <- [1,2], X <- qlc:keysort([1],Q,Opts)]),
+ [{{1},1},{{2},1},{{3},1},{{1},2},{{2},2},{{3},2}] = qlc:e(Q2)">>
+ ],
+ ?line run(Config, Ts),
+ ok.
+
+
+cache(doc) ->
+ "The cache option.";
+cache(suite) -> [];
+cache(Config) when is_list(Config) ->
+ Ts = [
+ <<"{'EXIT', {badarg, _}} = (catch qlc:q([X || X <- [1,2]], badarg))">>,
+
+ <<"Q1 = qlc:q([X || X <- [1,2,1,2,1]], {unique,true}),
+ [1,2] = qlc:e(Q1),
+ [1,2] = qlc:e(Q1, {unique_all,true}),
+ Q2 = qlc:q([X || X <- qlc:q([X || X <- [1,2,1,2,1]],
+ {unique,true})]),
+ [1,2] = qlc:e(Q2),
+ [1,2] = qlc:e(Q2, {unique_all,true}),
+ Q3 = qlc:q([X || X <- qlc:append([[1,2,3], [4,5,6]])]),
+ [1,2,3,4,5,6] = qlc:e(Q3)">>,
+
+ <<"Q1 = qlc:q([X || {X,_} <- [{1,a},{2,a},{1,b},{2,b}]]),
+ Q2 = qlc:q([{X,make_ref()} || X <- Q1]),
+ [{1,_},{2,_},{1,_},{2,_}] = qlc:e(Q2, {unique_all,false}),
+ [{1,_},{2,_}] = qlc:e(Q2, {unique_all,true})">>,
+
+ <<"E = ets:new(test, [duplicate_bag]),
+ true = ets:insert(E, [{1,a},{2,a},{1,b},{2,b}]),
+ Q1 = qlc:q([X || {X,_} <- ets:table(E)]),
+ Q2 = qlc:q([{X,make_ref()} || X <- Q1]),
+ [{1,_},{1,_},{2,_},{2,_}] = lists:sort(qlc:e(Q2, {unique_all,false})),
+ [{1,_},{2,_}] = lists:sort(qlc:e(Q2, {unique_all,true})),
+ ets:delete(E)">>,
+
+ <<"Q1 = qlc:q([X || {X,_} <- [{1,a},{2,a},{1,b},{2,b}]]),
+ Q2 = qlc:q([{X,make_ref()} || X <- qlc:append([Q1, Q1])]),
+ [{1,_},{2,_},{1,_},{2,_},{1,_},{2,_},{1,_},{2,_}] =
+ qlc:e(Q2, {unique_all,false}),
+ [{1,_},{2,_}] = qlc:e(Q2, {unique_all,true})">>,
+
+ <<"[] = qlc:e(qlc:q([X || X <- []], {unique, true})),
+ [] = qlc:e(qlc:q([X || X <- qlc:q([X || X <- qlc:append([])],
+ {unique,true})]))">>,
+
+ <<"Q1 = qlc:q([{X,make_ref()} || {X,_} <- [{1,a},{1,b}]]),
+ [{1,_},{1,_}] = qlc:e(Q1, {unique_all, true}),
+ Q2 = qlc:q([Y || {X,_} <- [{1,a},{1,b}],
+ begin Y = {X,make_ref()}, true end]),
+ [{1,_},{1,_}] = qlc:e(Q2, {unique_all,true}),
+ Q3 = qlc:q([Y || X <- [{1,a},{2,a}],
+ begin {_,Z} = X, Y = {Z,make_ref()}, true end]),
+ [{a,_},{a,_}] = qlc:e(Q3, {unique_all, true})">>,
+
+ <<"E = ets:new(apa, [duplicate_bag]),
+ ets:insert(E, [{1,a},{2,a},{1,a}]),
+ H1 = qlc:q([X || X <- qlc:append(ets:table(E),[7,3,5])],
+ {cache, true}),
+ [{_,a},{_,a},{_,a},7,3,5] = qlc:e(H1),
+ ets:delete(E)">>,
+
+ <<"F = fun(Obj, A) -> A++[Obj] end,
+ H = qlc:q([X || X <- [1,3,2,4]], cache),
+ Q = qlc:q([X || X <- H]),
+ [1,3,2,4] = qlc:fold(F, [], Q, [])">>,
+
+ <<"F = fun(Obj, A) -> A++[Obj] end,
+ E = ets:new(apa, [duplicate_bag]),
+ true = ets:insert(E, [{1,a},{2,b},{1,a}]),
+ Q1 = qlc:q([X || X <- ets:table(E)], [cache, unique]),
+ Q = qlc:q([X || X <- Q1], [cache, unique]),
+ {qlc, _, [{generate, _,{table,_}}], [{unique,true}]} = i(Q),
+ R = qlc:fold(F, [], Q, []),
+ ets:delete(E),
+ true = [{1,a},{2,b}] == lists:sort(R)">>,
+
+ <<"E = ets:new(apa, [duplicate_bag]),
+ ets:insert(E, [{1,a},{2,b},{1,a}]),
+ H1 = qlc:q([X || X <- qlc:append(ets:table(E),[7,3])], cache),
+ H2 = qlc:q([{Y,X} || Y <- [2,1,3], X <- H1]),
+ [{2,_},{2,_},{2,_},{2,7},{2,3},
+ {1,_},{1,_},{1,_},{1,7},{1,3},
+ {3,_},{3,_},{3,_},{3,7},{3,3}] = qlc:e(H2),
+ ets:delete(E)">>,
+
+ %% This case is not 100 percent determined. An Ets table
+ %% is updated in a filter and later used in a generator.
+ <<"E = ets:new(apa, [bag]),
+ true = ets:insert(E, [{1,a},{2,b}]),
+ H1 = qlc:q([Y || Y <- ets:table(E)],
+ [{cache, no}, {unique, true}]),
+ H = qlc:q([{X,Y} || X <- [{1,a},{2,d},{3,e}],
+ ets:insert(E, X),
+ Y <- H1]),
+ [{{1,a},_}, {{1,a},_}, {{2,d},_}, {{2,d},_}, {{2,d},_},
+ {{3,e},_}, {{3,e},_}, {{3,e},_}, {{3,e},_}] = qlc:e(H),
+ ets:delete(E)">>,
+
+ %% This case is not 100 percent determined. An Ets table
+ %% is updated in a filter and later used in a generator.
+ <<"E = ets:new(apa, [bag]),
+ true = ets:insert(E, [{1,a},{2,b}]),
+ H1 = qlc:q([Y || Y <- ets:table(E)],
+ [{cache, true}, {unique, true}]),
+ H = qlc:q([{X,Y} || X <- [{1,a},{2,d},{3,e}],
+ ets:insert(E, X),
+ Y <- H1]),
+ [{{1,a},_}, {{1,a},_}, {{2,d},_}, {{2,d},_}, {{3,e},_}, {{3,e},_}] =
+ qlc:e(H),
+ ets:delete(E)">>,
+
+ <<"%% {5979} and {5549} are both hashed to 28244 by phash2/1
+ E = ets:new(apa, [duplicate_bag]),
+ true = ets:insert(E, [{5979},{5549},{5979},{5549},{0}]),
+ H1 = qlc:q([X || X <- ets:table(E)],
+ [{cache, true}, {unique, true}]),
+ H = qlc:q([Y || _ <- [1,2], Y <- H1]),
+ {qlc, _, [{generate, _, {list, [1,2]}},
+ {generate, _, {qlc, _, [{generate, _, {table,_}}],
+ [{cache,ets},{unique,true}]}}],
+ []} = i(H),
+ [{0},{0},{5549},{5549},{5979},{5979}] = lists:sort(qlc:e(H)),
+ ets:delete(E)">>,
+
+ <<"E = ets:new(apa, [ordered_set]),
+ ets:insert(E, [{1},{2}]),
+ H1 = qlc:q([X || X <- ets:table(E)], [cache, unique]),
+ H2 = qlc:q([X || Y <- [3,4], ets:insert(E, {Y}), X <- H1]),
+ {qlc, _, [{generate, _, {list, [3,4]}}, _,
+ {generate, _, {qlc, _, [{generate, _,
+ {table, _}}],
+ [{cache, ets}]}}],
+ []} = i(H2),
+ [{1},{2},{3},{1},{2},{3}] = qlc:e(H2),
+ ets:delete(E)">>,
+
+ <<"E = ets:new(apa, [ordered_set]),
+ ets:insert(E, [{1},{2}]),
+ H1 = qlc:q([X || X <- ets:table(E)], [unique]),
+ H2 = qlc:q([X || Y <- [3,4], ets:insert(E, {Y}), X <- H1]),
+ [{1},{2},{3},{1},{2},{3},{4}] = qlc:e(H2),
+ ets:delete(E)">>,
+
+ <<"H0 = qlc:append([a,b], [c,d]),
+ H = qlc:q([{X,Y} ||
+ X <- H0,
+ Y <- qlc:q([{X1,Y} ||
+ X1 <- H0,
+ Y <- qlc:q([{X2,Y} ||
+ X2 <- H0,
+ Y <- H0])])]),
+ {qlc, _,
+ [{generate, _,{append, [{list, [a,b]}, {list, [c,d]}]}},
+ {generate, _,
+ {qlc, _,
+ [{generate, _, {append,[{list, [a,b]},{list, [c,d]}]}},
+ {generate, _,
+ {qlc, _,
+ [{generate, _,{append,[{list, [a,b]}, {list, [c,d]}]}},
+ {generate, _,{append,[{list, [a,b]}, {list, [c,d]}]}}],
+ [{cache,ets}]}}],
+ [{cache,ets}]}}],
+ []} = i(H, cache_all)">>
+
+ ],
+ ?line run(Config, Ts),
+ ok.
+
+cache_list(doc) ->
+ "OTP-6038. The {cache,list} option.";
+cache_list(suite) -> [];
+cache_list(Config) when is_list(Config) ->
+ Ts = [
+ begin
+ PrivDir = ?privdir,
+ [<<"%% unique, cache list. A simple qlc.
+ Options = [{cache,list}, unique],
+ L0 = [1,2,3,4,1,2,3,4],
+ L = qlc_SUITE:table(L0, []),
+ Q1 = qlc:q([X || X <- L], Options),
+ Q = qlc:q([{X,Y} || X <- [a,b], Y <- Q1]),
+ GOptions = [{tmpdir,\"">>, PrivDir, <<"\"}],
+ {qlc,_,[{generate,_,{list,[a,b]}},
+ {generate,_,{qlc,_,
+ [{generate,_,{table,_}}],
+ [{cache,list},{unique,true}]}}],
+ []} = i(Q, GOptions),
+ true = [{X,Y} || X <- [a,b], Y <- [1,2,3,4]] =:=
+ qlc:e(Q, GOptions)">>]
+ end,
+
+ begin
+ MS = ets:fun2ms(fun({X,_}) when X > 1 -> X end),
+ [<<"%% No cache, even if explicit match specification.
+ etsc(fun(E) ->
+ MS = ">>, io_lib:format("~w", [MS]), <<",
+ Options = [{cache,list}, unique],
+ Q = qlc:q([{X,Y} ||
+ X <- ets:table(E, {traverse, {select, MS}}),
+ Y <- [1,2,3]],
+ Options),
+ {qlc,_,[{generate,_,{table,{ets,table,_}}},
+ {generate,_,{list,[1,2,3]}}],
+ [{unique,true}]} = i(Q),
+ true = [{X,Y} || X <- lists:seq(2,10), Y <- [1,2,3]] =:=
+ lists:sort(qlc:e(Q))
+ end, [{keypos,1}], [{I,a} || I <- lists:seq(1, 10)])">>]
+ end,
+
+ <<"%% Temporary files.
+ %% Remove list expression caches when possible. (no visible effect)
+ T = lists:seq(1, 100000), % Huge terms on file
+ F = fun(C) ->
+ Q0 = qlc:q([{X} || X <- [T,T,T], begin X > 0 end],
+ {cache,C}),
+ Q1 = qlc:q([{X,Y,Z} ||
+ X <- Q0,
+ Y <- Q0,
+ Z <- Q0],
+ {cache,C}),
+ qlc:q([{X, Y} || Y <- [1], X <- Q1])
+ end,
+ Ql = F(list),
+ Rl = qlc:e(Ql, {max_list_size, 64*1024}),
+ Qe = F(ets),
+ Re = qlc:e(Qe),
+ Qf = F(no),
+ Rf = qlc:e(Qf),
+ Ri = qlc:e(Ql, {max_list_size, 1 bsl 35}), % heavy
+ {27,27,27,27,true,true,true} =
+ {length(Rl), length(Re), length(Rf), length(Ri),
+ Rl =:= Re, Re =:= Rf, Rf =:= Ri}">>,
+
+ <<"%% File sorter.
+ T = lists:seq(1, 10000),
+ F = fun(C) ->
+ Q0 = qlc:q([{X} || X <- [T,T,T], begin X > 0 end],
+ [{cache,C},unique]),
+ Q1 = qlc:q([{X,Y,Z} ||
+ X <- Q0,
+ Y <- Q0,
+ Z <- Q0],
+ [{cache,C},unique]),
+ qlc:q([{X, Y} || Y <- [1], X <- Q1])
+ end,
+ GOpt = [{max_list_size, 10000}],
+ Ql = F(list),
+ Rl = qlc:e(Ql, GOpt),
+ Qe = F(ets),
+ Re = qlc:e(Qe, GOpt),
+ Qf = F(no),
+ Rf = qlc:e(Qf, GOpt),
+ {1,1,1,true,true} =
+ {length(Rl), length(Re), length(Rf), Rl =:= Re, Re =:= Rf}">>,
+
+ <<"%% Remove list expression caches when possible. (no visible effect)
+ Q0 = qlc:q([{X} || X <- [1,2,3], begin X > 0 end], {cache,list}),
+ Q1 = qlc:q([{X,Y,Z} ||
+ X <- Q0,
+ Y <- Q0,
+ Z <- Q0],
+ {cache,list}),
+ Q = qlc:q([{X, Y} || Y <- [1], X <- Q1]),
+ R = qlc:e(Q),
+ L0 = [{X} || X <- [1,2,3], begin X > 0 end],
+ L1 = [{X,Y,Z} ||
+ X <- L0,
+ Y <- L0,
+ Z <- L0],
+ L = [{X, Y} || Y <- [1], X <- L1],
+ true = R =:= L">>,
+
+ <<"%% No temporary file.
+ L = [{I,a} || I <- lists:seq(1, 10)],
+ Q0 = qlc:q([X || X <- qlc_SUITE:table_error(L, 1, err),
+ begin element(1, X) > 5 end],
+ {cache,list}),
+ Q = qlc:q([{X, element(1,Y)} ||
+ X <- lists:seq(1, 5),
+ Y <- Q0]),
+ err = qlc:e(Q)">>,
+
+ <<"%% Sort internally.
+ L = [{I,a} || I <- lists:seq(1, 10)],
+ Q0 = qlc:q([X || X <- qlc_SUITE:table_error(L, 1, err),
+ begin element(1, X) > 5 end],
+ [unique,{cache,list}]),
+ Q = qlc:q([{X, element(1,Y)} ||
+ X <- lists:seq(1, 5),
+ Y <- Q0]),
+ err = qlc:e(Q, {max_list_size,0})">>,
+
+ <<"%% No temporary file.
+ etsc(fun(E) ->
+ Q0 = qlc:q([X || X <- ets:table(E),
+ begin element(1, X) > 5 end],
+ {cache,list}),
+ Q = qlc:q([{X, element(1,Y)} || X <- lists:seq(1, 5),
+ Y <- Q0]),
+ R = [{X,Y} || X <- lists:seq(1, 5),
+ Y <- lists:seq(6, 10)],
+ R = lists:sort(qlc:e(Q))
+ end, [{keypos,1}], [{I,a} || I <- lists:seq(1, 10)])">>,
+
+ <<"%% Sort internally
+ etsc(fun(E) ->
+ Q0 = qlc:q([X || X <- ets:table(E),
+ begin element(1, X) > 5 end],
+ [{cache,list},unique]),
+ Q = qlc:q([{X, element(1,Y)} || X <- lists:seq(1, 5),
+ Y <- Q0]),
+ R = [{X,Y} || X <- lists:seq(1, 5),
+ Y <- lists:seq(6, 10)],
+ R = lists:sort(qlc:e(Q))
+ end, [{keypos,1}], [{I,a} || I <- lists:seq(1, 10)])">>,
+
+ <<"%% A few more tests of unique and {cache,list}.
+ F = fun(CU) ->
+ H1 = qlc:q([{X,Y} ||
+ Y <- [a,b],
+ X <- [1,2]],
+ CU),
+ qlc:q([{X,Y,Z} || X <- [3,4], {Y,Z} <- H1])
+ end,
+ Q1 = F([]),
+ Q2 = F([{cache,list}, unique]),
+ R1 = qlc:e(Q1),
+ R2 = qlc:e(Q2),
+ R3 = qlc:e(Q2, {max_list_size, 0}), % still in RAM
+ true = R1 =:= R2,
+ true = R2 =:= R3">>,
+
+ <<"E = ets:new(t, [duplicate_bag]),
+ true = ets:insert(E, [{2},{1},{2}]),
+ H1 = qlc:q([{X,Y} ||
+ Y <- [a,b],
+ {X} <- ets:table(E)],
+ [{cache,list}, unique]),
+ H2 = qlc:q([{X,Y,Z} || X <- [3,4], {Y,Z} <- H1]),
+ {qlc,_,[{generate,_,{list,[3,4]}},
+ {generate,_,{qlc,_,
+ [{generate,_,{list,[a,b]}},
+ {generate,_,
+ {qlc,_,[{generate,_,{table,{ets,table,_}}}],
+ [{cache,list},{unique,true}]}}],
+ [{cache,list},{unique,true}]}}], []} = i(H2),
+ L1s = [[{X,Y} || Y <- [a,b], X <- Xs] || Xs <- [[1,2], [2,1]]],
+ L2s = [[{X,Y,Z} || X <- [3,4], {Y,Z} <- L1] || L1 <- L1s],
+ R1 = qlc:e(H2),
+ R2 = qlc:e(H2, {max_list_size, 0}), % on temporary file
+ ets:delete(E),
+ true = lists:member(R1, L2s),
+ true = R1 =:= R2">>,
+
+ <<"E = ets:new(t, [duplicate_bag]),
+ true = ets:insert(E, [{2},{1},{2}]),
+ H1 = qlc:q([{X,Y} ||
+ Y <- [a,b],
+ {X} <- ets:table(E)],
+ [{cache,list}]),
+ H2 = qlc:q([{X,Y,Z} || X <- [3,4], {Y,Z} <- H1]),
+ L1s = [[{X,Y} || Y <- [a,b], X <- Xs] || Xs <- [[1,2,2], [2,2,1]]],
+ L2s = [[{X,Y,Z} || X <- [3,4], {Y,Z} <- L1] || L1 <- L1s],
+ R1 = qlc:e(H2),
+ R2 = qlc:e(H2, {max_list_size, 0}), % on temporary file
+ ets:delete(E),
+ true = lists:member(R1, L2s),
+ true = R1 =:= R2">>,
+
+ <<"Q1 = qlc:q([{X,Y} ||
+ Y <- [a,b],
+ {X,_} <- qlc_SUITE:table_error([{a,1}], 2, err)],
+ [{cache,list}, unique]),
+ Q = qlc:q([{X,Y,Z} || X <- [3,4], {Y,Z} <- Q1]),
+ {qlc,_,[{generate,_,{list,[3,4]}},
+ {generate,_,{qlc,_,
+ [{generate,_,{list,[a,b]}},
+ {generate,_,{table,_}}],
+ [{cache,list},{unique,true}]}}],
+ []} = i(Q),
+ err = qlc:e(Q,{max_list_size,0})">>,
+
+ begin
+ Privdir = ?privdir,
+ [<<"
+ E = ets:new(t, [duplicate_bag]),
+ N = 17000,
+ true = ets:insert(E, [{X,X} || X <- lists:seq(1, N)]),
+ N = ets:info(E, size),
+ RF = fun(GOpts) ->
+ F = fun(CU) ->
+ H1 = qlc:q([{X,Y} ||
+ Y <- [a,b],
+ {X,_} <- ets:table(E)],
+ CU),
+ qlc:q([{X,Y,Z} || X <- [3,4], {Y,Z} <- H1])
+ end,
+ Q1 = F([{cache,list}, unique]),
+ _ = qlc:info(Q1, GOpts),
+ R1 = qlc:e(Q1, GOpts),
+ Q2 = F([unique]),
+ R2 = qlc:e(Q2, GOpts),
+ true = lists:sort(R1) =:= lists:sort(R2)
+ end,
+ GOpts = [{tmpdir,\"">>,Privdir,<<"\"}],
+ RF([{max_list_size, 1 bsl 35} | GOpts]),
+ RF(GOpts),
+ RF([{max_list_size, 40000} | GOpts]),
+ true = ets:insert(E, [{X,X} || X <- lists:seq(1, N)]),
+ true = N+N =:= ets:info(E, size),
+ RF([{max_list_size, 1 bsl 30} | GOpts]),
+ RF(GOpts),
+ RF([{max_list_size, 40000} | GOpts]),
+ ets:delete(E)">>]
+ end,
+
+ <<"%% Temporary file employed.
+ etsc(fun(E) ->
+ Q0 = qlc:q([X || X <- ets:table(E),
+ begin element(1, X) > 5 end],
+ {cache,list}),
+ Q = qlc:q([{X, element(1,Y)} || X <- lists:seq(1, 5),
+ Y <- Q0]),
+ R = [{X,Y} || X <- lists:seq(1, 5),
+ Y <- lists:seq(6, 10)],
+ R = lists:sort(qlc:e(Q, {max_list_size, 100*1024}))
+ end, [{keypos,1}], [{I,a,lists:duplicate(100000,1)} ||
+ I <- lists:seq(1, 10)])">>,
+
+ <<"%% Temporary file employed. The file is removed after error.
+ L = [{I,a,lists:duplicate(100000,1)} || I <- lists:seq(1, 10)],
+ Q0 = qlc:q([X || X <- qlc_SUITE:table_error(L, 1, err),
+ begin element(1, X) > 5 end],
+ {cache,list}),
+ Q = qlc:q([{X, element(1,Y)} ||
+ X <- lists:seq(1, 5),
+ Y <- Q0]),
+ err = qlc:e(Q)">>,
+
+ <<"%% Temporary file employed. The file is removed after error.
+ L = [{I,a,lists:duplicate(100000,1)} || I <- lists:seq(1, 10)],
+ Q0 = qlc:q([X || X <- qlc_SUITE:table(L, 1, []),
+ begin element(1, X) > 5 end],
+ {cache,list}),
+ Q = qlc:q([{X, element(1,Y)} ||
+ X <- lists:seq(1, 5),
+ Y <- Q0]),
+ {error, _, {file_error,_,_}} = qlc:e(Q, {tmpdir, \"/a/b/c\"})">>,
+
+ <<"Q = qlc:q([X || X <- [1,2]]),
+ {'EXIT', {badarg, _}} = (catch qlc:e(Q, {max_list_size, -1}))">>,
+
+ <<"Q = qlc:q([X || X <- [1,2]]),
+ {'EXIT', {badarg, _}} = (catch qlc:e(Q, {max_list_size, foo}))">>
+
+ ],
+ ?line run(Config, Ts),
+ ok.
+
+filter(doc) ->
+ "Filters and match specs.";
+filter(suite) -> [];
+filter(Config) when is_list(Config) ->
+ Ts = [
+ <<"L = [1,2,3,4,5],
+ QH1 = qlc:q([X || X <- L, X > 1, X < 4]),
+ [2,3] = qlc:e(QH1),
+ {list,{list,L},_MS} = i(QH1)
+ ">>,
+
+ <<"L = [1,2,3,4,5],
+ QH2 = qlc:q([X || X <- L, X > 1, X < 4, X > 2]),
+ [3] = qlc:e(QH2),
+ {list,{list,L},_MS} = i(QH2)
+ ">>,
+
+ %% "X > 1" is skipped since the matchspec does the job
+ <<"QH3 = qlc:q([X || X <- [1,2,3,4,5], X > 1, begin X < 4 end]),
+ [2,3] = qlc:e(QH3),
+ {qlc,_,[{generate,_,{list,{list,[1,2,3,4,5]},_MS}},_],[]} = i(QH3)
+ ">>,
+
+ <<"QH4 = qlc:q([{X,Y} || X <- [1,2], Y <- [1,2]]),
+ [{1,1},{1,2},{2,1},{2,2}] = qlc:e(QH4),
+ {qlc,_,[{generate,_,{list,[1,2]}},{generate,_,{list,[1,2]}}],[]} =
+ i(QH4)">>,
+
+ %% "X > 1" is skipped since the matchspec does the job
+ <<"QH5 = qlc:q([{X,Y} || X <- [1,2], X > 1, Y <- [1,2]]),
+ [{2,1},{2,2}] = qlc:e(QH5),
+ {qlc,_,[{generate,_,{list,{list,[1,2]},_MS}},
+ {generate,_,{list,[1,2]}}],[]} =
+ i(QH5)">>,
+
+ <<"%% Binaries are not handled at all when trying to find lookup values
+ etsc(fun(E) ->
+ A = 2,
+ Q = qlc:q([X || {X} <- ets:table(E), <<A>> =:= <<X>>]),
+ [2] = lists:sort(qlc:e(Q)),
+ false = lookup_keys(Q)
+ end, [{1},{2},{3}])">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {X,_} <- ets:table(E),
+ qlc:e(qlc:q([Y || {Y,_} <- ets:table(E),
+ Y > X])) == []]),
+ [3] = qlc:e(Q)
+ end, [{1,a},{2,b},{3,c}])">>,
+
+ <<"Q = qlc:q([X || {X} <- [], (false or (X/0 > 3))]),
+ \"[]\" = qlc:info(Q),
+ [] = qlc:e(Q)">>,
+
+ <<"%% match spec
+ [] = qlc:e(qlc:q([X || {X} <- [{1},{2}],
+ (false orelse (X/0 > 3))])),
+ %% generated code
+ {'EXIT', {badarith, _}} =
+ (catch qlc:e(qlc:q([X || {X} <- [{1}],
+ begin (false orelse (X/0 > 3)) end])))">>,
+
+ <<"%% Partial evaluation in filter.
+ etsc(fun(E) ->
+ QH = qlc:q([{X+1,Y} || {X,Y} <- ets:table(E),
+ X =:= 1-1+1+(+1)]),
+ [{3,2}] = qlc:e(QH),
+ [2] = lookup_keys(QH)
+ end, [{1,1},{2,2},{3,3}])">>,
+
+ <<"%% =/2 in filters must not be recognized when 'badmatch' is
+ %% possible.
+ etsc(fun(E) ->
+ QH = qlc:q([{X,Y} || {X,Y} <- ets:table(E),
+ ((Y = X) =:= 3)]),
+ {'EXIT', {{badmatch,4},_}} = (catch qlc:e(QH)),
+ false = lookup_keys(QH)
+ end, [{3,3},{4,true}])">>,
+
+ <<"%% One more of the same kind.
+ etsc(fun(E) ->
+ QH = qlc:q([{X,Y} || {X,_} <- ets:table(E),
+ (Y=X) =:= (Y=1+1)]),
+ {'EXIT', {{badmatch,2},_}} = (catch qlc:e(QH)),
+ false = lookup_keys(QH)
+ end, [{1,1},{2,2},{3,3}])">>,
+
+ <<"%% OTP-5195. Used to return a value, but badarith is correct.
+ etsc(fun(E) ->
+ QH = qlc:q([X || {X,_} <- ets:table(E),
+ (X =:= 1) and
+ if X =:= 1 -> true;
+ true -> X/0
+ end]),
+ {'EXIT',{badarith,_}} = (catch qlc:e(QH)),
+ false = lookup_keys(QH)
+ end, [{1,1},{2,2},{3,3}])">>,
+
+ <<"fun(Z) ->
+ Q = qlc:q([X || Z < 2, X <- [1,2,3]]),
+ [] = qlc:e(Q)
+ end(3)">>,
+
+ <<"H = qlc:q([{P1,A,P2,B,P3,C} ||
+ P1={A,_} <- [{1,a},{2,b}],
+ {_,B}=P2 <- [{1,a},{2,b}],
+ C=P3 <- [1],
+ {[X,_],{_,X}} <- [{[1,2],{3,1}}, {[a,b],{3,4}}],
+ A > 0,
+ B =/= c,
+ C > 0]),
+ L = [{{1,a},1,{1,a},a,1,1}, {{1,a},1,{2,b},b,1,1},
+ {{2,b},2,{1,a},a,1,1}, {{2,b},2,{2,b},b,1,1}],
+ L = qlc:e(H)">>,
+
+ <<"H = qlc:q([{X,Y} ||
+ X = _ <- [1,2,3],
+ _ = Y <- [a,b,c],
+ _ = _ <- [foo],
+ X > 1,
+ Y =/= a]),
+ [{2,b},{2,c},{3,b},{3,c}] = qlc:e(H)">>
+
+ ],
+ ?line run(Config, Ts),
+ ok.
+
+info(doc) ->
+ "info/2.";
+info(suite) -> [];
+info(Config) when is_list(Config) ->
+ Ts = [
+ <<"{list, [1,2]} = i(qlc:q([X || X <- [1,2]])),
+ {append,[{list, [1,2]}, {list, [3,4]}]} =
+ i(qlc:append([1,2],[3,4])),
+ {sort,{list, [1,2]},[]} = i(qlc:sort([1,2])),
+ E = ets:new(foo, []),
+ ets:insert(E, [{1},{2}]),
+ {table, _} = i(ets:table(E)),
+ true = ets:delete(E),
+ {list, [1,2]} = i([1,2]),
+ {append, [{list, [1,2]}, {list, [3,4]}]} =
+ i(qlc:q([X || X <- qlc:append([1,2],[3,4])])),
+
+ H0 = qlc:q([X || X <- throw({throw,t})]),
+ {throw,t} = (catch {any_term,qlc:info(H0)}),
+ {'EXIT', {badarg, _}} =
+ (catch qlc:info(foobar)),
+ {'EXIT', {badarg, _}} =
+ (catch qlc:info(qlc:q([X || X <- [1,2]]), badarg))">>,
+
+ <<"{'EXIT', {badarg, _}} =
+ (catch qlc:info([X || {X} <- []], {n_elements, 0})),
+ L = lists:seq(1, 1000),
+ \"[1,2,3,4,5,6,7,8,9,10|'...']\" = qlc:info(L, {n_elements, 10}),
+ {cons,1,{integer,1,1},{atom,1,'...'}} =
+ qlc:info(L, [{n_elements, 1},{format,abstract_code}]),
+ Q = qlc:q([{X} || X <- [a,b,c,d,e,f]]),
+ {call,_,_,[{cons,_,{atom,_,a},{cons,_,{atom,_,b},{cons,_,{atom,_,c},
+ {atom,_,'...'}}}},
+ {call,_,_,_}]} =
+ qlc:info(Q, [{n_elements, 3},{format,abstract_code}]),
+ \"ets:match_spec_run([a,b,c,d,e,f],\n\"
+ \" ets:match_spec_compile([{'$1',[true],\"
+ \"[{{'$1'}}]}]))\" =
+ qlc:info(Q, [{n_elements, infinity}])">>,
+
+ <<"Q1 = qlc:q([{X} || X <- qlc:q([X || X <- [1,2]])]),
+ {qlc, _, [{generate, _, {list, [1,2]}}],[]} = i(Q1),
+ Q2 = qlc:q([X || X <- qlc:q([{X} || X <- [1,2]])]),
+ {list,{list,[1,2]},_} = i(Q2),
+ [{1},{2}] = qlc:eval(Q2),
+ Q3 = qlc:q([{X,Y} || X <- qlc:q([X || X <- [a,b]]),
+ Y <- qlc:q([Z || Z <- [a,b]])]),
+ {qlc, _, [{generate, _, {list, [a,b]}},
+ {generate, _, {list, [a,b]}}], []} = i(Q3),
+ Q4 = qlc:q([X || X <- [a]]),
+ {list, [a]} = i(Q4),
+ Q5 = qlc:q([X || X <- qlc:q([Y || Y <- [a,b]], unique)]),
+ {qlc, _, [{generate, _, {list, [a,b]}}], [{unique,true}]} =
+ i(Q5)">>,
+
+ <<"H = qlc:q([X || X <- qlc:append([qlc:q([X || X <- [1,2]]),[1,2]])]),
+ {append, [{list, [1,2]},{list, [1,2]}]} = i(H),
+ [1,2,1,2] = qlc:e(H)">>,
+
+ <<"H = qlc:q([{X} || X <- [], X > 1]),
+ {list, []} = i(H),
+ [] = qlc:e(H)">>,
+
+ <<"H1 = qlc:q([{X} || X <- [], X > 1]),
+ H = qlc:q([{X} || X <- H1, X < 10]),
+ {list, []} = i(H),
+ [] = qlc:e(H)">>,
+
+ <<"L = [1,2,3],
+ QH1 = qlc:q([{X} || X <- L, X > 1]),
+ QH2 = qlc:q([{X} || X <- QH1]),
+ [{{2}},{{3}}] = qlc:e(QH2),
+ {list,{list,{list,L},_},_} = i(QH2)">>,
+
+ <<"H = qlc:q([X || X <- qlc:q([Y || Y <- qlc:q([Z || Z <-[1,2,1]])])]),
+ {list, [1,2,1]} = i(H),
+ [1,2,1] = qlc:eval(H)">>,
+
+ <<"%% Used to replace empty ETS tables with [], but that won't work.
+ E = ets:new(apa,[]),
+ QH1 = qlc:q([{X} || X <- ets:table(E), X > 1]),
+ QH2 = qlc:q([{X} || X <- QH1], cache),
+ [] = qlc:e(QH2),
+ {qlc,_,[{generate,_,{table,{ets,table,_}}}],[]} = i(QH2),
+ ets:delete(E)">>,
+
+ <<"Q1 = qlc:q([W || W <- [a,b]]),
+ Q2 = qlc:q([Z || Z <- qlc:sort([1,2,300])], unique),
+ Q3 = qlc:q([{X,Y} || X <- qlc:keysort([2], [{1,a}]),
+ Y <- qlc:append([Q1, Q2]),
+ X > Y]),
+ {qlc, T1,
+ [{generate, P1, {list, [{1,a}]}},
+ {generate, P2, {append, [{list, [a,b]},
+ {qlc, T2, [{generate, P3,
+ {sort, {list,[1,2,300]},[]}}],
+ [{cache,ets},{unique,true}]}]}},F],
+ []} = i(Q3, cache_all),
+ {tuple, _, [{var,_,'X'}, {var,_,'Y'}]} = binary_to_term(T1),
+ {var, _, 'X'} = binary_to_term(P1),
+ {var, _, 'Y'} = binary_to_term(P2),
+ {var, _, 'Z'} = binary_to_term(P3),
+ {var, _, 'Z'} = binary_to_term(T2),
+ {op, _, '>', {var, _, 'X'}, {var, _, 'Y'}} = binary_to_term(F),
+ true = binary_to_list(<<
+ \"beginV1=qlc:q([Z||Z<-qlc:sort([1,2,300],[])],[{unique,true}]),\"
+ \"qlc:q([{X,Y}||X<-[{1,a}],Y<-qlc:append([[a,b],V1]),X>Y])end\"
+ >>) == format_info(Q3, true)">>,
+
+ <<"Q1 = qlc:q([{X} || X <- qlc:q([X || X <- [a,b]])]),
+ {qlc, _, [{generate, _, {list, [a,b]}}], []} = i(Q1),
+ Q2 = qlc:q([X || X <- qlc:q([{X} || X <- [a,b]])]),
+ {list,{list,[a,b]},_} = i(Q2),
+ [{a},{b}] = qlc:eval(Q2)">>,
+
+ <<"Q = qlc:keysort(2, [{1,a,b},{2,b,c},{3,4,c}]),
+ {keysort,{list,[{1,a,b},{2,b,c},{3,4,c}]},2,[]} = i(Q),
+ true = binary_to_list(<<
+ \"qlc:keysort(2,[{1,a,b},{2,b,c},{3,4,c}],[])\">>)
+ == format_info(Q, true),
+ [{3,4,c},{1,a,b},{2,b,c}] = qlc:e(Q)">>,
+
+ <<"E = ets:new(foo, []),
+ ets:insert(E, [{1},{2}]),
+ Q = qlc_SUITE:default_table(E),
+ {table,{'$MOD','$FUN',[]}} = i(Q),
+ true = binary_to_list(<<\"'$MOD':'$FUN'()\">>)
+ == format_info(Q, true),
+ true = ets:delete(E)">>,
+
+ <<"\"[]\" = qlc:info([], flat),
+ \"[]\" = qlc:info([]),
+ \"[]\" = qlc:info([], {flat, true})">>,
+
+ <<"H = qlc:q([{X} || X <- [a,b]]),
+ \"ets:match_spec_run([a,b],ets:match_spec_compile(\" ++ _ =
+ format_info(H, true),
+ \"ets:match_spec_run([a,b],ets:match_spec_compile(\" ++ _ =
+ format_info(H, false)">>,
+
+ <<"H = qlc:q([{X} || X <- [a,b], begin true end]),
+ true = binary_to_list(<<\"qlc:q([{X}||X<-[a,b],begintrueend])\">>)
+ == format_info(H, true),
+ true = binary_to_list(<<\"qlc:q([{X}||X<-[a,b],begintrueend])\">>)
+ == format_info(H, false)">>,
+
+ <<"H = qlc:q([A || {A} <- [{1},{2}], (A =:= 2) andalso true]),
+ {call,_,{remote,_,{atom,_,ets},{atom,_,match_spec_run}},_} =
+ qlc:info(H, {format,abstract_code})">>,
+
+ <<"H = qlc:q([{X} || X <- qlc:q([{X} || X <- [a,b], begin true end],
+ unique),
+ begin true end]),
+ true = binary_to_list(<<
+ \"beginV1=qlc:q([{X}||X<-[a,b],begintrueend],[{unique,true}]),\"
+ \"qlc:q([{X}||X<-V1,begintrueend])end\">>) ==
+ format_info(H, true),
+ true = binary_to_list(<<
+ \"qlc:q([{X}||X<-qlc:q([{X}||X<-[a,b],begintrueend],\"
+ \"[{unique,true}]),begintrueend])\">>) == format_info(H, false)">>,
+
+ <<"H0 = qlc:q([{V3} || V3 <- qlc:q([{V1} || V1 <- [a,b],
+ begin true end], unique),
+ begin true end]),
+ H = qlc:sort(H0),
+ true = binary_to_list(<<
+ \"qlc:sort(qlc:q([{V3}||V3<-qlc:q([{V1}||\"
+ \"V1<-[a,b],begintrueend],[{unique,true}]),begintrueend]),[])\">>)
+ == format_info(H, false),
+ true = binary_to_list(<<
+ \"beginV2=qlc:q([{V1}||V1<-[a,b],begintrueend],[{unique,true}]),\"
+ \"V4=qlc:q([{V3}||V3<-V2,begintrueend]),qlc:sort(V4,[])end\">>)
+ == format_info(H, true)">>,
+
+ <<"H0 = qlc:q([X || X <- [true], begin true end]),
+ H1 = qlc:q([{X} || X <- [a,b], begin true end],
+ [{unique,begin [T] = qlc:e(H0), T end}]),
+ {call,_,{remote,_,{atom,_,qlc},{atom,_,q}},
+ [{lc,_,{tuple,_,[{var,_,'X'}]},
+ [{generate,_,{var,_,'X'},
+ {cons,_,{atom,_,a},_}},
+ {block, _, [{atom, _, true}]}]},
+ {cons,_,_,_}]} = i(H1, {format, abstract_code})">>,
+
+ <<"E = ets:new(apa, [duplicate_bag]),
+ true = ets:insert(E, [{1,a},{2,b},{3,c},{4,d}]),
+ QH = qlc:q([X || {X,_} <- ets:tab2list(E), X > 2], unique),
+ {qlc, _, [{generate, _, {list, _, _MS}}], [{unique, true}]} =
+ i(QH),
+ [3,4] = lists:sort(qlc:e(QH)),
+ ets:delete(E)">>,
+
+ %% "Imported" variable.
+ <<"F = fun(U) -> qlc:q([{X} || X <- [1,2,3,4,5,6], X > U]) end,
+ QH = F(4),
+ {call, _ ,
+ {remote, _, {atom, _, ets},{atom, _, match_spec_run}},
+ [{string, _, [1,2,3,4,5,6]},
+ {call, _,
+ _compile,
+ [{cons, _,
+ {tuple, _,
+ [{atom, _,'$1'},
+ {cons, _,
+ {tuple,
+ _,
+ [{atom, _,'>'},
+ {atom, _,'$1'},
+ {tuple,
+ _,
+ [{atom, _,const},
+ {integer, _,4}]}]},
+ _},
+ {cons, _, _, _}]},
+ {nil,_}}]}]} = i(QH, {format, abstract_code}),
+ [{5},{6}] = qlc:e(QH),
+ [{4},{5},{6}] = qlc:e(F(3))">>
+
+ ],
+ ?line run(Config, Ts),
+ ok.
+
+nested_info(doc) ->
+ "Nested QLC expressions. QLC expressions in filter and template.";
+nested_info(suite) -> [];
+nested_info(Config) when is_list(Config) ->
+ Ts = [
+ <<"L = [{1,a},{2,b},{3,c}],
+ Q = qlc:q(
+ [{X,R} ||
+ {X,_} <- qlc_SUITE:table(L, []),
+ begin % X imported
+ R = qlc:e(qlc:q([{X,Y} || {Y,_}
+ <- qlc_SUITE:table(L, []),
+ Y > X])),
+ true
+ end]),
+ true = binary_to_list(<<
+ \"qlc:q([{X,R}||{X,_}<-qlc_SUITE:the_list([{1,a},{2,b},{3,c}]),\"
+ \"beginR=qlc:e(qlc:q([{X,Y}||{Y,_}<-qlc_SUITE:table(L,[]),Y>X]))\"
+ \",trueend])\">>) == format_info(Q, true),
+ [{1,[{1,2},{1,3}]},{2,[{2,3}]},{3,[]}] = qlc:e(Q)">>,
+
+ <<"L = [{1,a},{2,b},{3,c}],
+ Q = qlc:q( % X imported
+ [{X,qlc:e(qlc:q([{X,Y} || {Y,_} <- qlc_SUITE:table(L, []),
+ Y > X]))} ||
+ {X,_} <- qlc_SUITE:table(L, [])]),
+ true = binary_to_list(<<
+ \"qlc:q([{X,qlc:e(qlc:q([{X,Y}||{Y,_}<-qlc_SUITE:table(L,[]),\"
+ \"Y>X]))}||{X,_}<-qlc_SUITE:the_list([{1,a},{2,b},{3,c}])])\">>)
+ == format_info(Q, true),
+ [{1,[{1,2},{1,3}]},{2,[{2,3}]},{3,[]}] = qlc:e(Q)">>,
+
+ <<"L = [{1,a},{2,b},{3,c}],
+ Q = qlc:q(
+ [{X,R} ||
+ {X,_} <- qlc_SUITE:table(L, []),
+ begin % X imported
+ R = qlc:e(qlc:q([{X,Y} || {Y,_}
+ <- qlc_SUITE:table(L, []),
+ Y =:= X])),
+ true
+ end]),
+ true = binary_to_list(<<
+ \"qlc:q([{X,R}||{X,_}<-qlc_SUITE:the_list([{1,a},{2,b},{3,c}]),\"
+ \"beginR=qlc:e(qlc:q([{X,Y}||{Y,_}<-qlc_SUITE:table(L,[]),\"
+ \"Y=:=X])),trueend])\">>) == format_info(Q, true),
+ [{1,[{1,1}]},{2,[{2,2}]},{3,[{3,3}]}] = qlc:e(Q)">>,
+
+ <<"L = [{1,a},{2,b},{3,c}],
+ Q = qlc:q(
+ [{X, % X imported
+ qlc:e(qlc:q([{X,Y} || {Y,_} <- qlc_SUITE:table(L, []),
+ Y =:= X]))} ||
+ {X,_} <- qlc_SUITE:table(L, [])]),
+ true = binary_to_list(<<
+ \"qlc:q([{X,qlc:e(qlc:q([{X,Y}||{Y,_}<-qlc_SUITE:table(L,[]),\"
+ \"Y=:=X]))}||{X,_}<-qlc_SUITE:the_list([{1,a},{2,b},{3,c}])])\">>)
+ == format_info(Q, true),
+ [{1,[{1,1}]},{2,[{2,2}]},{3,[{3,3}]}] = qlc:e(Q)">>,
+
+ <<"L = [{1,a},{2,b},{3,c}],
+ Q = qlc:q(
+ [{X,R} ||
+ {X,_} <- qlc_SUITE:table(L, []),
+ begin
+ R = qlc:e(qlc:q([Y || Y <- [X]])),
+ true
+ end]),
+ true = binary_to_list(<<
+ \"qlc:q([{X,R}||{X,_}<-qlc_SUITE:the_list([{1,a},{2,b},{3,c}]),\"
+ \"beginR=qlc:e(qlc:q([Y||Y<-[X]])),trueend])\">>)
+ == format_info(Q, true),
+ [{1,[1]},{2,[2]},{3,[3]}] = qlc:e(Q)">>,
+
+ <<"L = [{1,a},{2,b},{3,c}],
+ Q = qlc:q(
+ [{X,qlc:e(qlc:q([Y || Y <- [X]]))} ||
+ {X,_} <- qlc_SUITE:table(L, [])]),
+ true = binary_to_list(<<
+ \"qlc:q([{X,qlc:e(qlc:q([Y||Y<-[X]]))}||{X,_}<-qlc_SUITE:\"
+ \"the_list([{1,a},{2,b},{3,c}])])\">>) == format_info(Q, true),
+ [{1,[1]},{2,[2]},{3,[3]}] = qlc:e(Q)">>,
+
+ <<"L = [{1,a},{2,b}],
+ Q = qlc:q(
+ [{X,Y} ||
+ {X,_} <- qlc_SUITE:table(L, []),
+ {Y,_} <- qlc:q(
+ [{Z,V} ||
+ {Z,_} <- qlc_SUITE:table(L, []),
+ {V} <- qlc:q(
+ [{W} || W
+ <- qlc_SUITE:table(L, [])])
+ ])
+ ]),
+ true = binary_to_list(<<
+ \"beginV1=qlc:q([{W}||W<-qlc_SUITE:the_list([{1,a},{2,b}])]),\"
+ \"V2=qlc:q([{Z,V}||{Z,_}<-qlc_SUITE:the_list([{1,a},{2,b}]),\"
+ \"{V}<-V1]),qlc:q([{X,Y}||{X,_}<-qlc_SUITE:the_list([{1,a},\"
+ \"{2,b}]),{Y,_}<-V2])end\">>) == format_info(Q, true),
+ [{1,1},{1,1},{1,2},{1,2},{2,1},{2,1},{2,2},{2,2}] = qlc:e(Q)">>
+
+ ],
+ ?line run(Config, Ts),
+ ok.
+
+
+lookup1(doc) ->
+ "Lookup keys. Mostly test of patterns.";
+lookup1(suite) -> [];
+lookup1(Config) when is_list(Config) ->
+ Ts = [
+ <<"etsc(fun(E) ->
+ Q = qlc:q([A || {A=3} <- ets:table(E)]),
+ [3] = qlc:eval(Q),
+ [3] = lookup_keys(Q)
+ end, [{1},{2},{3},{4}])">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([A || {A=3} <- ets:table(E)],{max_lookup,0}),
+ [3] = qlc:eval(Q),
+ false = lookup_keys(Q)
+ end, [{1},{2},{3},{4}])">>,
+
+ <<"%% The lookup and max_lookup options interact.
+ etsc(fun(E) ->
+ Q = qlc:q([X || {X} <- ets:table(E),
+ (X =:= 1) or (X =:= 2)],
+ [{lookup,true},{max_lookup,1}]),
+ {'EXIT', {no_lookup_to_carry_out, _}} = (catch qlc:e(Q))
+ end, [{1},{2}])">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([{A,B,C,D} || {A,B}={C,D} <- ets:table(E)]),
+ [{1,2,1,2},{3,4,3,4}] = lists:sort(qlc:eval(Q)),
+ false = lookup_keys(Q)
+ end, [{1,2},{3,4}])">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([{A,B,D} || {A,B}={D,A} <- ets:table(E)]),
+ [{1,1,1},{2,2,2}] = lists:sort(qlc:eval(Q)),
+ false = lookup_keys(Q)
+ end, [{1,2},{2,2},{1,1}])">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([{A,B,D} || {A,B}={D,A} <- ets:table(E),
+ (D =:= 2) or (B =:= 1)],
+ {max_lookup,infinity}),
+ [{1,1,1},{2,2,2}] = qlc:eval(Q),
+ [1,2] = lookup_keys(Q)
+ end, [{1,2},{2,2},{1,1}])">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([{A,B,D} || {A,B}={D,A} <- ets:table(E),
+ (D =:= 2) xor (B =:= 1)]),
+ [{1,1,1},{2,2,2}] = qlc:eval(Q),
+ [1,2] = lookup_keys(Q)
+ end, [{1,2},{2,2},{1,1}])">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([3 || {{[3,4],apa}} <- ets:table(E)]),
+ [3] = qlc:e(Q),
+ [{[3,4],apa}] = lookup_keys(Q)
+ end, [{{[4,3],foo}},{{[3,4],apa}}])">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([3 || {3} <- ets:table(E)]),
+ [3] = qlc:e(Q),
+ [3] = lookup_keys(Q)
+ end, [{2},{3},{4}])">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([{X,Y,Z} || {{X,_},Y,Y={_,Z},X,Y} <- ets:table(E)]),
+ [] = qlc:e(Q),
+ false = lookup_keys(Q)
+ end, [{{1,1},1,{1,1},1,1}])">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {X,X=2} <- ets:table(E)]),
+ [2] = qlc:e(Q),
+ [2] = lookup_keys(Q)
+ end, [{2,2},{3,3}])">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {{_,3}={4,_}=X} <- ets:table(E)]),
+ [{4,3}] = qlc:e(Q),
+ [{4,3}] = lookup_keys(Q)
+ end, [{{2,3}},{{4,3}}])">>,
+
+ <<"U = 17.0,
+ etsc(fun(E) ->
+ Q = qlc:q([X || {_=X=_} <- ets:table(E)]),
+ [U] = qlc:e(Q),
+ false = lookup_keys(Q)
+ end, [{U},{U+U,U}])">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([{X,Y,Z,W} || {X=Y}=Z={V=W} <- ets:table(E),
+ V == {h,g}]),
+ [{{h,g},{h,g},{{h,g}},{h,g}}] = qlc:e(Q),
+ [{h,g}] = lookup_keys(Q)
+ end, [{h,g},{{h,g}}])">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([{C,Y,Z,X} || {{X=Y}=Z}={{A=B}=C} <- ets:table(E),
+ A == a, B =/= c]),
+ [{{a},a,{a},a}] = qlc:e(Q),
+ [{a}] = lookup_keys(Q)
+ end, [{{1}},{{a}}])">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([{A,D,Y,X} ||
+ {{A={B=C}},{D={C}}} = {X,Y} <- ets:table(E),
+ [] == B]),
+ [{{[]},{[]},{{[]}},{{[]}}}] = qlc:e(Q),
+ [{{[]}}] = lookup_keys(Q)
+ end, [{{{[]}},{{[]}}}])">>,
+
+ {cres,
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {X}=X <- ets:table(E)]),
+ [] = qlc:e(Q),
+ false = lookup_keys(Q)
+ end, [{1},{a}])">>,
+ {warnings,[{{2,37},qlc,nomatch_pattern}]}},
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {X=X,Y=Y}={Y=Y,X=X} <- ets:table(E),
+ {} == X]),
+ [{}] = qlc:e(Q),
+ [{}] = lookup_keys(Q)
+ end, [{{},{}},{[],[]}])">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {3+4=7,X} <- ets:table(E),
+ X =:= 3+997]),
+ [1000] = qlc:e(Q),
+ [7] = lookup_keys(Q)
+ end, [{7,1000},{8,1000}])">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([{X, Y} || [X]=[Y] <- ets:table(E)]),
+ [] = qlc:eval(Q),
+ false = lookup_keys(Q)
+ end, [{a}])">>,
+
+ {cres,
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || X={1,2,3,X,5} <- ets:table(E)]),
+ [] = qlc:e(Q),
+ false = lookup_keys(Q)
+ end, [{a},{b}])">>,
+ {warnings,[{{2,35},qlc,nomatch_pattern}]}},
+
+ {cres,
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || X=[1,2,3,X,5] <- ets:table(E)]),
+ [] = qlc:e(Q),
+ false = lookup_keys(Q)
+ end, [{a},{b}])">>,
+ {warnings,[{{2,35},qlc,nomatch_pattern}]}},
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || X = <<X>> <- ets:table(E)]),
+ [] = qlc:e(Q),
+ false = lookup_keys(Q)
+ end, [{a},{b}])">>,
+
+ <<"Tre = 3.0,
+ etsc(fun(E) ->
+ Q = qlc:q([{A,B} || {A,B}={{a,C},{a,C}} <- ets:table(E),
+ C =:= Tre]),
+ [] = qlc:e(Q),
+ [{a,Tre}] = lookup_keys(Q)
+ end, [{a,b}])">>,
+
+ <<"A = 3,
+ etsc(fun(E) ->
+ Q = qlc:q([X || X <- ets:table(E), A =:= element(1, X)]),
+ [{3,3}] = qlc:e(Q),
+ [3] = lookup_keys(Q)
+ end, [{1,a},{3,3}])">>,
+
+ <<"A = 3,
+ etsc(fun(E) ->
+ Q = qlc:q([X || X <- ets:table(E), A =:= erlang:element(1, X)]),
+ [{3,3}] = qlc:e(Q),
+ [3] = lookup_keys(Q)
+ end, [{1,a},{3,3}])">>,
+
+ <<"A = 3,
+ etsc(fun(E) ->
+ Q = qlc:q([X || X <- ets:table(E), A =:= {erlang,element}(1, X)]),
+ [{3,3}] = qlc:e(Q),
+ [3] = lookup_keys(Q)
+ end, [{1,a},{3,3}])">>,
+
+ <<"etsc(fun(E) ->
+ A = 3,
+ Q = qlc:q([X || X <- ets:table(E),
+ A == element(1,X),
+ element(1,X) =:= a]),
+ [] = qlc:e(Q),
+ [a] = lookup_keys(Q)
+ end, [{a},{b},{c}])">>,
+
+ {cres,
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {X = {[a,Z]},
+ Z = [foo, {[Y]}],
+ Y = {{foo,[X]}}} <- ets:table(E)]),
+ [] = qlc:e(Q),
+ false = lookup_keys(Q)
+ end, [{a,b,c},{d,e,f}])">>,
+ {warnings,[{{2,34},qlc,nomatch_pattern}]}}
+
+ ],
+ ?line run(Config, Ts),
+ ok.
+
+lookup2(doc) ->
+ "Lookup keys. Mostly test of filters.";
+lookup2(suite) -> [];
+lookup2(Config) when is_list(Config) ->
+ Ts = [
+ <<"%% Only guards are inspected. No lookup.
+ etsc(fun(E) ->
+ Q = qlc:q([{X,Y} || {X,Y} <- ets:table(E),
+ ((Y = X) =:= 3)]),
+ {'EXIT', {{badmatch,4},_}} = (catch qlc:e(Q))
+ end, [{3,3},{4,true}])">>,
+
+ <<"%% Only guards are inspected. No lookup.
+ etsc(fun(E) ->
+ Q = qlc:q([{X,Y} || {X,Y} <- ets:table(E),
+ Y = (X =:= 3)]),
+ {'EXIT', {{badmatch,false},_}} = (catch qlc:e(Q))
+ end, [{false,3},{true,3}])">>,
+
+ <<"%% Only guards are inspected. No lookup.
+ etsc(fun(E) ->
+ Q = qlc:q([{X,Y} || {X,Y} <- ets:table(E),
+ Y = (X =:= 3)]),
+ {'EXIT', {{badmatch,false},_}} = (catch qlc:e(Q))
+ end, [{3,true},{4,true}])">>,
+
+ <<"%% Only guards are inspected. No lookup.
+ E1 = create_ets(1, 10),
+ E2 = ets:new(join, []),
+ true = ets:insert(E2, [{true,1},{false,2}]),
+ Q = qlc:q([{X,Z} || {_,X} <- ets:table(E1),
+ {Y,Z} <- ets:table(E2),
+ Y = (X =:= 3)]),
+ {'EXIT', {{badmatch,false},_}} = (catch qlc:e(Q)),
+ ets:delete(E1),
+ ets:delete(E2)">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([{A,B,D} || {A,B}={D,A} <- ets:table(E),
+ (A =:= 3) or (4 =:= D)]),
+ [{3,3,3},{4,4,4}] = lists:sort(qlc:e(Q)),
+ [3,4] = lookup_keys(Q)
+ end, [{2,2},{3,3},{4,4}])">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {X,U} <- ets:table(E), X =:= U]),
+ [1] = qlc:e(Q),
+ false = lookup_keys(Q)
+ end, [{1,1}])">>,
+
+ {cres,
+ <<"etsc(fun(E) ->
+ Q = qlc:q([{X,Y} || {X=Y} <- ets:table(E),
+ {[X],4} =:= {[3],X}]),
+ [] = qlc:e(Q),
+ false = lookup_keys(Q)
+ end, [{1}, {2}])">>,
+ {warnings,[{{3,46},qlc,nomatch_filter}]}},
+
+ {cres,
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {X} <- ets:table(E),
+ X == 1, X =:= 2]),
+ [] = qlc:e(Q),
+ false = lookup_keys(Q)
+ end, [{1}, {2}])">>,
+ {warnings,[{{3,43},qlc,nomatch_filter}]}},
+
+ {cres,
+ <<"etsc(fun(E) ->
+ Q = qlc:q([{X,Y} || {X=Y} <- ets:table(E),
+ {[X,Y],4} =:= {[3,X],X}]),
+ [] = qlc:e(Q),
+ false = lookup_keys(Q)
+ end, [{1}, {2}])">>,
+ {warnings,[{{3,48},qlc,nomatch_filter}]}},
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([{X,Y} || {X,Y} <- ets:table(E),
+ ({X,3} =:= {Y,Y}) or (X =:= 4)]),
+ [{3,3},{4,4}] = lists:sort(qlc:e(Q)),
+ [3,4] = lookup_keys(Q)
+ end, [{2,2},{3,3},{4,4},{5,5}])">>,
+
+ {cres,
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {X} <- ets:table(E), {[X]} =:= {[3,4]}]),
+ [] = qlc:e(Q),
+ false = lookup_keys(Q)
+ end, [{[3]},{[3,4]}])">>,
+ {warnings,[{{2,61},qlc,nomatch_filter}]}},
+
+ <<"etsc(fun(E) ->
+ U = 18,
+ Q = qlc:q([{X,Y} || {X=Y} <- ets:table(E), [X|a] =:= [3|U]]),
+ [] = qlc:e(Q),
+ [3] = lookup_keys(Q)
+ end, [{2}, {3}])">>,
+
+ <<"etsc(fun(E) ->
+ U = 18, V = 19,
+ Q = qlc:q([{X,Y} || {X=Y} <- ets:table(E),
+ [X|V] =:= [3|U+1]]),
+ [{3,3}] = qlc:e(Q),
+ [3] = lookup_keys(Q)
+ end, [{2},{3}])">>,
+
+ <<"%% Blocks are not handled.
+ etsc(fun(E) ->
+ Q = qlc:q([X || {X} <- ets:table(E), begin X == a end]),
+ [a] = qlc:e(Q),
+ false = lookup_keys(Q)
+ end, [{a},{b}])">>,
+
+ {cres,
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {X} <- ets:table(E),
+ (3 =:= X) or (X =:= 12),
+ (8 =:= X) or (X =:= 10)]),
+ [] = lists:sort(qlc:e(Q)),
+ false = lookup_keys(Q)
+ end, [{2},{3},{4},{8}])">>,
+ {warnings,[{{4,44},qlc,nomatch_filter}]}},
+
+ {cres,
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {X} <- ets:table(E),
+ ((3 =:= X) or (X =:= 12))
+ and ((8 =:= X) or (X =:= 10))]),
+ [] = lists:sort(qlc:e(Q)),
+ false = lookup_keys(Q)
+ end, [{2},{3},{4},{8}])">>,
+ {warnings,[{{4,35},qlc,nomatch_filter}]}},
+
+ <<"F = fun(U) ->
+ Q = qlc:q([X || {X} <- [a,b,c],
+ X =:= if U -> true; true -> false end]),
+ [] = qlc:eval(Q),
+ false = lookup_keys(Q)
+ end,
+ F(apa)">>,
+
+ {cres,
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {X=1,X} <- ets:table(E), X =:= 2]),
+ [] = qlc:e(Q),
+ false = lookup_keys(Q)
+ end, [{1,1},{2,1}])">>,
+ {warnings,[{{2,61},qlc,nomatch_filter}]}},
+
+ <<"Two = 2.0,
+ etsc(fun(E) ->
+ Q = qlc:q([X || {X} <- ets:table(E), X =:= Two]),
+ [Two] = qlc:e(Q),
+ [Two] = lookup_keys(Q)
+ end, [{2.0},{2}])">>,
+
+ <<"etsc(fun(E) ->
+ %% This float is equal (==) to an integer. Not a constant!
+ Q = qlc:q([X || {X} <- ets:table(E), X == {a,b,c,[2.0]}]),
+ [_,_] = qlc:e(Q),
+ false = lookup_keys(Q)
+ end, [{{a,b,c,[2]}},{{a,b,c,[2.0]}}])">>,
+
+ <<"%% Must _not_ regard floats as constants. Check imported variables
+ %% in runtime.
+ etsc(fun(E) ->
+ U = 3.0,
+ QH = qlc:q([X || {X,_} <- ets:table(E), X =:= U]),
+ [] = qlc:e(QH),
+ [U] = lookup_keys(QH)
+ end, [{1,a},{2,b},{3,c},{4,d}])">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {X} <- ets:table(E),
+ length(X) =:= 1]),
+ [[1]] = qlc:e(Q),
+ false = lookup_keys(Q)
+ end, [{[1]},{[2,3]}])">>,
+
+ <<"etsc(fun(E) ->
+ A=3,
+ Q = qlc:q([X || {X,Y} <- ets:table(E), X =:= A, Y =:= 3]),
+ [3] = qlc:e(Q),
+ [3] = lookup_keys(Q)
+ end, [{3,3},{4,3}])">>,
+
+ <<"etsc(fun(E) ->
+ A = 1,
+ Q = qlc:q([X || {X} <- ets:table(E),
+ X =:= 1, <<X>> =:= <<A>>]),
+ [1] = qlc:e(Q),
+ [1] = lookup_keys(Q)
+ end, [{1},{2}])">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {X} <- ets:table(E), X == a]),
+ [a] = qlc:e(Q),
+ [a] = lookup_keys(Q)
+ end, [{a},{b},{c}])">>,
+
+ {cres,
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {X}=Y <- ets:table(E),
+ element(2, Y) == b,
+ X =:= 1]),
+ [] = qlc:e(Q),
+ false = lookup_keys(Q)
+ end, [{1,b},{2,3}])">>,
+ {warnings,[{{3,48},qlc,nomatch_filter}]}},
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {X} <- ets:table(E), element(1,{X}) =:= 1]),
+ [1] = qlc:e(Q),
+ [1] = lookup_keys(Q)
+ end, [{1}, {2}])">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {X} <- ets:table(E), 1 =:= element(1,{X})]),
+ [1] = qlc:e(Q),
+ [1] = lookup_keys(Q)
+ end, [{1}, {2}])">>,
+
+ {cres,
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {X} <- ets:table(E),
+ X =:= {1},
+ element(1,X) =:= 2]),
+ [] = qlc:e(Q),
+ false = lookup_keys(Q)
+ end, [{{1}},{{2}}])">>,
+ {warnings,[{{4,47},qlc,nomatch_filter}]}},
+
+ {cres,
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {X} <- ets:table(E),
+ X =:= {1},
+ element(1,X) =:= element(1, {2})]),
+ [] = qlc:e(Q),
+ false = lookup_keys(Q)
+ end, [{{1}},{{2}}])">>,
+ {warnings,[{{4,47},qlc,nomatch_filter}]}},
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {X} <- ets:table(E),
+ element(1,X) =:= 1, X =:= {1}]),
+ [{1}] = qlc:e(Q),
+ [{1}] = lookup_keys(Q)
+ end, [{{1}},{{2}}])">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {X} <- ets:table(E),
+ {{element(1,element(1,{{1}}))}} =:= {X}]),
+ [{1}] = qlc:e(Q),
+ [{1}] = lookup_keys(Q)
+ end, [{{1}},{{2}}])">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || X <- ets:table(E),
+ {element(1,element(1, {{1}}))} =:=
+ {element(1,X)}]),
+ [{1}] = qlc:e(Q),
+ [1] = lookup_keys(Q)
+ end, [{1},{2}])">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {{X,Y}} <- ets:table(E),
+ (X =:= 1) and (Y =:= 2)
+ or (X =:= 3) and (Y =:= 4)]),
+ [1,3] = lists:sort(qlc:e(Q)),
+ [{1,2}, {3,4}] = lookup_keys(Q)
+ end, [{{1,2}}, {{3,4}}, {{2,3}}])">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {{X,a}} <- ets:table(E), X =:= 3]),
+ [3] = qlc:e(Q),
+ [{3,a}] = lookup_keys(Q)
+ end, [{{3,a}},{{3,b}}])">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {{X,Y},_Z} <- ets:table(E),
+ X =:= 3, Y =:= a]),
+ [3] = qlc:e(Q),
+ [{3,a}] = lookup_keys(Q)
+ end, [{{3,a},3}, {{4,a},3}])">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {{X,Y},_Z} <- ets:table(E),
+ (X =:= 3) and (Y =:= a)
+ or (X =:= 4) and (Y =:= a)]),
+ [3,4] = qlc:e(Q),
+ [{3,a}, {4,a}] = lookup_keys(Q)
+ end, [{{3,a},3}, {{4,a},3}])">>,
+
+ {cres,
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {X} <- ets:table(E),
+ (X =:= 3) and (X =:= a)]),
+ [] = qlc:e(Q),
+ false = lookup_keys(Q)
+ end, [{3}, {4}])">>,
+ {warnings,[{{3,44},qlc,nomatch_filter}]}},
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {{X,Y}} <- ets:table(E),
+ X =:= 3, ((Y =:= a) or (Y =:= b))]),
+ [3,3] = qlc:e(Q),
+ [{3,a},{3,b}] = lists:sort(lookup_keys(Q))
+ end, [{{3,a}},{{2,b}},{{3,b}}])">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {X,Y} <- ets:table(E),
+ ((X =:= 3) or (Y =:= 4)) and (X == a)]),
+ [a] = qlc:e(Q),
+ [a] = lookup_keys(Q)
+ end, [{a,4},{3,3}])">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {X,Y} <- ets:table(E),
+ (X =:= 3) or ((Y =:= 4) and (X == a))]),
+ [3,a] = lists:sort(qlc:e(Q)),
+ [3,a] = lookup_keys(Q)
+ end, [{a,4},{3,3}])">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {{X,Y}} <- ets:table(E),
+ (X =:= 3) or ((Y =:= 4) and (X == a))]),
+ [3,a] = lists:sort(qlc:e(Q)),
+ false = lookup_keys(Q)
+ end, [{{3,a}},{{2,b}},{{a,4}}])">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {{X,Y}} <- ets:table(E),
+ ((X =:= 3) or (Y =:= 4)) and (X == a)]),
+ [a] = lists:sort(qlc:e(Q)),
+ [{a,4}] = lookup_keys(Q)
+ end, [{{3,a}},{{2,b}},{{a,4}}])">>,
+
+ <<"etsc(fun(E) ->
+ NoAnswers = 3*3*3+2*2*2,
+ Q = qlc:q([{X,Y,Z} ||
+ {{X,Y,Z}} <- ets:table(E),
+ (((X =:= 4) or (X =:= 5)) and
+ ((Y =:= 4) or (Y =:= 5)) and
+ ((Z =:= 4) or (Z =:= 5))) or
+ (((X =:= 1) or (X =:= 2) or (X =:= 3)) and
+ ((Y =:= 1) or (Y =:= 2) or (Y =:= 3)) and
+ ((Z =:= 1) or (Z =:= 2) or (Z =:= 3)))],
+ {max_lookup, NoAnswers}),
+ {list, {table, _}, _} = i(Q),
+ [{1,1,1},{2,2,2},{3,3,3}] = lists:sort(qlc:e(Q)),
+ true = NoAnswers =:= length(lookup_keys(Q))
+ end, [{{1,1,1}},{{2,2,2}},{{3,3,3}},{{3,3,4}},{{4,1,1}}])">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([{X,Y,Z} ||
+ {{X,Y,Z}} <- ets:table(E),
+ (((X =:= 4) or (X =:= 5)) and
+ ((Y =:= 4) or (Y =:= 5)) and
+ ((Z =:= 4) or (Z =:= 5))) or
+ (((X =:= 1) or (X =:= 2) or (X =:= 3)) and
+ ((Y =:= 1) or (Y =:= 2) or (Y =:= 3)) and
+ ((Z =:= 1) or (Z =:= 2) or (Z =:= 3)))],
+ {max_lookup, 10}),
+ [{1,1,1},{2,2,2},{3,3,3}] = lists:sort(qlc:e(Q)),
+ {table,{ets,table,[_,[{traverse,{select,_}}]]}} = i(Q)
+ end, [{{1,1,1}},{{2,2,2}},{{3,3,3}},{{3,3,4}},{{4,1,1}}])">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || X={_,_,_} <- ets:table(E),
+ element(1, X) =:= 3, element(2, X) == a]),
+ [{3,a,s}] = qlc:e(Q),
+ [3] = lookup_keys(Q)
+ end, [{1,c,q},{2,b,r},{3,a,s}])">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || X <- ets:table(E),
+ element(0, X) =:= 3]),
+ [] = qlc:e(Q),
+ false = lookup_keys(Q)
+ end, [{1},{2}])">>,
+
+ <<"etsc(fun(E) ->
+ F = fun(_) -> 3 end,
+ %% No occurs check; X =:= F(X) is ignored.
+ Q = qlc:q([X || {X} <- ets:table(E),
+ X =:= 3, X =:= F(X)]),
+ {qlc,_,[{generate,_,{list,{table,_},_}},_],[]} = i(Q),
+ [3] = lists:sort(qlc:e(Q)),
+ [3] = lookup_keys(Q)
+ end, [{2},{3},{4}])">>,
+
+ <<"etsc(fun(E) ->
+ A = a, B = a,
+ Q = qlc:q([X || {{X,Y}} <- ets:table(E),
+ ((X =:= A) and (Y =:= B))
+ or ((X =:= B) and (Y =:= A))]),
+ [a] = qlc:e(Q),
+ %% keys are usorted, duplicate removed:
+ [{a,a}] = lookup_keys(Q)
+ end, [{{a,a}},{{b,b}}])">>,
+
+ <<"etsc(fun(E) ->
+ A = a, B = b,
+ Q = qlc:q([X || {{X,Y}} <- ets:table(E),
+ ((X =:= A) and (Y =:= B))
+ or ((X =:= B) and (Y =:= A))]),
+ [a,b] = lists:sort(qlc:e(Q)),
+ [{a,b},{b,a}] = lookup_keys(Q)
+ end, [{{a,b}},{{b,a}},{{c,a}},{{d,b}}])">>,
+
+ %% The atom 'fail' is recognized - lookup.
+ <<"etsc(fun(E) ->
+ Q = qlc:q([A || {A} <- ets:table(E),
+ (A =:= 2)
+ orelse fail
+ ]),
+ [2] = lists:sort(qlc:e(Q)),
+ [2] = lookup_keys(Q)
+ end, [{1},{2}])">>
+
+ ],
+ ?line run(Config, Ts),
+
+ TsR = [
+ %% is_record/2,3:
+ <<"etsc(fun(E) ->
+ Q = qlc:q([element(1, X) || X <- ets:table(E),
+ erlang:is_record(X, r, 2)]),
+ [r] = qlc:e(Q),
+ [r] = lookup_keys(Q)
+ end, [{keypos,1}], [#r{}])">>,
+ <<"etsc(fun(E) ->
+ Q = qlc:q([element(1, X) || X <- ets:table(E),
+ is_record(X, r, 2)]),
+ [r] = qlc:e(Q),
+ [r] = lookup_keys(Q)
+ end, [{keypos,1}], [#r{}])">>,
+ <<"etsc(fun(E) ->
+ Q = qlc:q([element(1, X) || X <- ets:table(E),
+ {erlang,is_record}(X, r, 2)]),
+ [r] = qlc:e(Q),
+ [r] = lookup_keys(Q)
+ end, [{keypos,1}], [#r{}])">>,
+ {cres,
+ <<"etsc(fun(E) ->
+ Q = qlc:q([element(1, X) || X <- ets:table(E),
+ record(X, r)]),
+ [r] = qlc:e(Q),
+ [r] = lookup_keys(Q)
+ end, [{keypos,1}], [#r{}])">>,
+ {warnings,[{{4,45},erl_lint,{obsolete_guard,{record,2}}}]}},
+ <<"etsc(fun(E) ->
+ Q = qlc:q([element(1, X) || X <- ets:table(E),
+ erlang:is_record(X, r)]),
+ [r] = qlc:e(Q),
+ [r] = lookup_keys(Q)
+ end, [{keypos,1}], [#r{}])">>,
+ <<"etsc(fun(E) ->
+ Q = qlc:q([element(1, X) || X <- ets:table(E),
+ is_record(X, r)]),
+ [r] = qlc:e(Q),
+ [r] = lookup_keys(Q)
+ end, [{keypos,1}], [#r{}])">>,
+ <<"etsc(fun(E) ->
+ Q = qlc:q([element(1, X) || X <- ets:table(E),
+ {erlang,is_record}(X, r)]),
+ [r] = qlc:e(Q),
+ [r] = lookup_keys(Q)
+ end, [{keypos,1}], [#r{}])">>
+
+ ],
+ ?line run(Config, <<"-record(r, {a}).\n">>, TsR),
+
+ Ts2 = [
+ <<"etsc(fun(E) ->
+ Q0 = qlc:q([X ||
+ X <- ets:table(E),
+ (element(1, X) =:= 1) or
+ (element(1, X) =:= 2)],
+ {cache,ets}),
+ Q = qlc:q([{X,Y} ||
+ X <- [1,2],
+ Y <- Q0]),
+ {qlc,_,[{generate,_,{list,[1,2]}},
+ {generate,_,{table,_}}], []} = i(Q),
+ [{1,{1}},{1,{2}},{2,{1}},{2,{2}}] = lists:sort(qlc:e(Q)),
+ [1,2] = lookup_keys(Q)
+ end, [{keypos,1}], [{1},{2}])">>,
+
+ <<"etsc(fun(E) ->
+ Q0 = qlc:q([X ||
+ X <- ets:table(E),
+ (element(1, X) =:= 1) or
+ (element(1, X) =:= 2)]),
+ Q = qlc:q([{X,Y} ||
+ X <- [1,2],
+ Y <- Q0],
+ {cache,true}),
+ {qlc,_,[{generate,_,{list,[1,2]}},
+ {generate,_,{table,_}}],[]} = i(Q),
+ [1,2] = lookup_keys(Q)
+ end, [{keypos,1}], [{1},{2}])">>,
+
+ %% One introduced QLC expression (join, ms), and the cache option.
+ <<"%% Match spec and lookup. The lookup is done twice, which might
+ %% be confusing...
+ etsc(fun(E) ->
+ Q = qlc:q([{X,Y} ||
+ X <- [1,2],
+ {Y} <- ets:table(E),
+ (Y =:= 1) or (Y =:= 2)],
+ []),
+ [{1,1},{1,2},{2,1},{2,2}] = qlc:e(Q),
+ {qlc,_,[{generate,_,{list,[1,2]}},
+ {generate,_,{list,{table,_},_}}],[]} = i(Q),
+ [1,2] = lookup_keys(Q)
+ end, [{keypos,1}], [{1},{2},{3}])">>,
+ <<"%% The same as last example, but with cache.
+ %% No cache needed (always one lookup only).
+ etsc(fun(E) ->
+ Q = qlc:q([{X,Y} ||
+ X <- [1,2],
+ {Y} <- ets:table(E),
+ (Y =:= 1) or (Y =:= 2)],
+ [cache]),
+ [{1,1},{1,2},{2,1},{2,2}] = qlc:e(Q),
+ {qlc,_,[{generate,_,{list,[1,2]}},
+ {generate,_,{list,{table,_},_}}],[]} = i(Q),
+ [1,2] = lookup_keys(Q)
+ end, [{keypos,1}], [{1},{2},{3}])">>,
+
+ <<"%% And again, this time only lookup, no mach spec.
+ etsc(fun(E) ->
+ Q = qlc:q([{X,Y} ||
+ X <- [1,2],
+ Y <- ets:table(E),
+ (element(1, Y) =:= 1)
+ or (element(1, Y) =:= 2)],
+ []),
+ [{1,{1}},{1,{2}},{2,{1}},{2,{2}}] = qlc:e(Q),
+ {qlc,_,[{generate,_,{list,[1,2]}},
+ {generate,_,{table,_}}],[]} = i(Q),
+ [1,2] = lookup_keys(Q)
+ end, [{keypos,1}], [{1},{2},{3}])">>,
+ <<"%% As last one, but with cache.
+ %% No cache needed (always one lookup only).
+ etsc(fun(E) ->
+ Q = qlc:q([{X,Y} ||
+ X <- [1,2],
+ Y <- ets:table(E),
+ (element(1, Y) =:= 1)
+ or (element(1, Y) =:= 2)],
+ [cache]),
+ {qlc,_,[{generate,_,{list,[1,2]}},
+ {generate,_,{table,_}}],[]} = i(Q),
+ [{1,{1}},{1,{2}},{2,{1}},{2,{2}}] = qlc:e(Q),
+ [1,2] = lookup_keys(Q)
+ end, [{keypos,1}], [{1},{2},{3}])">>,
+
+ <<"%% Lookup only. No cache.
+ etsc(fun(E) ->
+ Q = qlc:q([{X,Y} ||
+ X <- [1,2],
+ {Y=2} <- ets:table(E)],
+ []),
+ {qlc,_,[{generate,_,{list,[1,2]}},
+ {generate,_,{table,_}}],[]} = i(Q),
+ [{1,2},{2,2}] = qlc:e(Q),
+ [2] = lookup_keys(Q)
+ end, [{keypos,1}], [{1},{2},{3}])">>,
+ <<"%% Lookup only. No cache.
+ etsc(fun(E) ->
+ Q = qlc:q([{X,Y} ||
+ X <- [1,2],
+ {Y=2} <- ets:table(E)],
+ [cache]),
+ {qlc,_,[{generate,_,{list,[1,2]}},
+ {generate,_,{table,_}}],[]} = i(Q),
+ [{1,2},{2,2}] = qlc:e(Q),
+ [2] = lookup_keys(Q)
+ end, [{keypos,1}], [{1},{2},{3}])">>,
+
+ <<"%% Matchspec only. No cache.
+ etsc(fun(E) ->
+ Q = qlc:q([{X,Y} ||
+ X <- [1,2],
+ {Y} <- ets:table(E),
+ Y > 1],
+ []),
+ {qlc,_,[{generate,_,{list,[1,2]}},
+ {generate,_,
+ {table,{ets,_,[_,[{traverse,_}]]}}}],[]} =
+ i(Q),
+ [{1,2},{1,3},{2,2},{2,3}] = qlc:e(Q),
+ false = lookup_keys(Q)
+ end, [{keypos,1}], [{1},{2},{3}])">>,
+ <<"%% Matchspec only. Cache
+ etsc(fun(E) ->
+ Q = qlc:q([{X,Y} ||
+ X <- [1,2],
+ {Y} <- ets:table(E),
+ Y > 1],
+ [cache]),
+ {qlc,_,[{generate,_,{list,[1,2]}},
+ {generate,_,{qlc,_,
+ [{generate,_,{table,{ets,_,[_,[{traverse,_}]]}}}],
+ [{cache,ets}]}}],[]} = i(Q),
+ [{1,2},{1,3},{2,2},{2,3}] = qlc:e(Q),
+ false = lookup_keys(Q)
+ end, [{keypos,1}], [{1},{2},{3}])">>,
+ <<"%% An empty list. Always unique and cached.
+ Q = qlc:q([X || {X} <- [], X =:= 1, begin X > 0 end],
+ [{cache,true},{unique,true}]),
+ {qlc,_,[{generate,_,{list,[]}},_],[{unique,true}]} = i(Q),
+ _ = qlc:info(Q),
+ [] = qlc:e(Q)">>,
+ <<"%% A list is always cached.
+ Q = qlc:q([{X,Y} || Y <- [1,2], X <- [2,1,2]],
+ [cache]),
+ {qlc,_,[{generate,_,{list,[1,2]}},
+ {generate,_,{list,[2,1,2]}}],[]} = i(Q),
+ [{2,1},{1,1},{2,1},{2,2},{1,2},{2,2}] = qlc:e(Q)">>,
+ <<"%% But a processed list is never cached.
+ Q = qlc:q([{X,Y} || Y <- [1,2], X <- [2,1,2], X > 1],
+ [cache]),
+ {qlc,_,[{generate,_, {list,[1,2]}},
+ {generate,_,{qlc,_,
+ [{generate,_,{list,{list,[2,1,2]},_}}],
+ [{cache,ets}]}}],[]} = i(Q),
+ [{2,1},{2,1},{2,2},{2,2}] = qlc:e(Q)">>,
+ <<"%% A bug fixed in R11B-2: coalescing simple_qlc:s works now.
+ Q0 = qlc:q([X || {X} <- [{1},{2},{3}]], {cache, ets}),
+ Q1 = qlc:q([X || X <- Q0], {cache, list}),
+ Q = qlc:q([{Y,X} || Y <- [1,2], X <- Q1, X < 2], {cache, list}),
+ {qlc,_,[{generate,_,{list,_}},
+ {generate,_,{qlc,_,[{generate,_,{list,{list,_},_}}],
+ [{cache,ets}]}},_],[]} = i(Q),
+ [{1,1},{2,1}] = qlc:e(Q)">>,
+ <<"Q = qlc:q([{X,Y} || Y <- [1,2], X <- [1,2], X > 1],
+ [cache,unique]),
+ {qlc,_,[{generate,_,{list,[1,2]}},
+ {generate,_,{qlc,_,
+ [{generate,_,{list,{list,[1,2]},_}}],
+ [{cache,ets},{unique,true}]}}],
+ [{unique,true}]} = i(Q),
+ [{2,1},{2,2}] = qlc:e(Q)">>,
+ <<"L = [1,2,3],
+ QH1 = qlc:q([{X} || X <- L, X > 1]),
+ QH2 = qlc:q([{X} || X <- QH1, X > 0], [cache]),
+ [{{2}},{{3}}] = qlc:e(QH2),
+ {list,{list,{list,L},_},_} = i(QH2)">>,
+ <<"L = [1,2,3,1,2,3],
+ QH1 = qlc:q([{X} || X <- L, X > 1]),
+ QH2 = qlc:q([{X} || X <- QH1, X > 0], [cache,unique]),
+ [{{2}},{{3}}] = qlc:e(QH2),
+ {qlc,_,[{generate,_,{list,{list,{list,L},_},_}}],
+ [{unique,true}]} = i(QH2)">>
+
+ ],
+
+ ?line run(Config, Ts2),
+
+ LTs = [
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || X <- ets:table(E),
+ element(1, X) =:= 1],
+ {lookup,true}),
+ {table,L} = i(Q),
+ true = is_list(L),
+ [{1,a}] = qlc:e(Q),
+ [1] = lookup_keys(Q)
+ end, [{1,a},{2,b}])">>,
+ <<"%% No lookup, use the match spec for traversal instead.
+ etsc(fun(E) ->
+ Q = qlc:q([X || X <- ets:table(E),
+ element(1, X) =:= 1],
+ {lookup,false}),
+ {table,{ets,table,_}} = i(Q),
+ [{1,a}] = qlc:e(Q),
+ false = lookup_keys(Q)
+ end, [{1,a},{2,b}])">>,
+ <<"%% As last one. {max_lookup,0} has the same effect.
+ etsc(fun(E) ->
+ Q = qlc:q([X || X <- ets:table(E),
+ element(1, X) =:= 1],
+ {max_lookup,0}),
+ {table,{ets,table,_}} = i(Q),
+ [{1,a}] = qlc:e(Q),
+ false = lookup_keys(Q)
+ end, [{1,a},{2,b}])">>
+
+ ],
+ ?line run(Config, LTs),
+
+ ok.
+
+lookup_rec(doc) ->
+ "Lookup keys. With records.";
+lookup_rec(suite) -> [];
+lookup_rec(Config) when is_list(Config) ->
+ Ts = [
+ <<"etsc(fun(E) ->
+ Q = qlc:q([A || #r{a = A} <- ets:table(E),
+ (A =:= 3) or (4 =:= A)]),
+ [3] = qlc:e(Q),
+ [3,4] = lookup_keys(Q)
+ end, [{keypos,2}], [#r{a = a}, #r{a = 3}, #r{a = 5}])">>,
+
+ {cres,
+ <<"etsc(fun(E) ->
+ Q = qlc:q([A || #r{a = 17 = A} <- ets:table(E),
+ (A =:= 3) or (4 =:= A)]),
+ [] = qlc:e(Q),
+ false = lookup_keys(Q)
+ end, [{keypos,2}], [#r{a = 17}, #r{a = 3}, #r{a = 5}])">>,
+ {warnings,[{{4,44},qlc,nomatch_filter}]}},
+
+ <<"%% Compares an integer and a float.
+ etsc(fun(E) ->
+ Q = qlc:q([A || #r{a = 17 = A} <- ets:table(E),
+ (A == 17) or (17.0 == A)]),
+ [_] = qlc:e(Q),
+ [_] = lookup_keys(Q)
+ end, [{keypos,2}], [#r{a = 17}, #r{a = 3}, #r{a = 5}])">>,
+
+ <<"%% Compares an integer and a float.
+ %% There is a test in qlc_pt.erl (Op =:= '=:=', C1 =:= C2), but
+ %% that case is handled in an earlier clause (unify ... E, E).
+ etsc(fun(E) ->
+ Q = qlc:q([A || #r{a = 17.0 = A} <- ets:table(E),
+ (A =:= 17) or (17.0 =:= A)]),
+ [_] = qlc:e(Q),
+ [_] = lookup_keys(Q)
+ end, [{keypos,2}], [#r{a = 17.0}, #r{a = 3}, #r{a = 5}])">>,
+
+ <<"%% Matches an integer and a float.
+ etsc(fun(E) ->
+ Q = qlc:q([A || #r{a = 17 = A} <- ets:table(E),
+ (A =:= 17) or (17.0 =:= A)]),
+ [_] = qlc:e(Q),
+ [_] = lookup_keys(Q)
+ end, [{keypos,2}], [#r{a = 17}, #r{a = 3}, #r{a = 5}])">>,
+
+ <<"etsc(fun(E) ->
+ F = fun(_) -> 17 end,
+ Q = qlc:q([A || #r{a = A} <- ets:table(E),
+ (F(A) =:= 3) and (A =:= 4)]),
+ [] = qlc:e(Q),
+ false = lookup_keys(Q) % F(A) could fail
+ end, [{keypos,2}], [#r{a = 4}, #r{a = 3}, #r{a = 5}])">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {X} <- ets:table(E),
+ #r{} == X]),
+ [#r{}] = lists:sort(qlc:e(Q)),
+ {call,_,_,[_,_]} = i(Q, {format, abstract_code}),
+ [#r{}] = lookup_keys(Q)
+ end, [{#r{}},{#r{a=foo}}])">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([R#r.a || R <- ets:table(E), R#r.a =:= foo]),
+ [foo] = qlc:e(Q),
+ [_] = lookup_keys(Q)
+ end, [{keypos,2}], [#r{a=foo}])">>
+ ],
+ ?line run(Config, <<"-record(r, {a}).\n">>, Ts),
+ ok.
+
+indices(doc) ->
+ "Using indices for lookup.";
+indices(suite) -> [];
+indices(Config) when is_list(Config) ->
+ Ts = [
+ <<"L = [{1,a},{2,b},{3,c}],
+ QH = qlc:q([element(1, X) || X <- qlc_SUITE:table(L, [2]),
+ (element(2, X) =:= a)
+ or (b =:= element(2, X))]),
+ {list, {table,{qlc_SUITE,list_keys,[[a,b],2,L]}}, _MS} = i(QH),
+ [1,2] = qlc:eval(QH)">>,
+
+ <<"L = [{1,a},{2,b},{3,c}],
+ QH = qlc:q([element(1, X) || X <- qlc_SUITE:table(L, [2]),
+ begin (element(2, X) =:= a)
+ or (b =:= element(2, X)) end]),
+ {qlc,_,[{generate,_,{table,{call,_,
+ {remote,_,_,{atom,_,the_list}},_}}},_],[]}
+ = i(QH),
+ [1,2] = qlc:eval(QH)">>,
+
+ <<"L = [{1,a,q},{2,b,r},{3,c,s}],
+ QH = qlc:q([element(1, X) || X <- qlc_SUITE:table(L, [2,3]),
+ (element(3, X) =:= q)
+ or (r =:= element(3, X))]),
+ {list, {table,{qlc_SUITE,list_keys, [[q,r],3,L]}}, _MS} = i(QH),
+ [1,2] = qlc:eval(QH)">>,
+
+ <<"L = [{1,a,q},{2,b,r},{3,c,s}],
+ QH = qlc:q([element(1, X) || X <- qlc_SUITE:table(L, 1, [2]),
+ (element(3, X) =:= q)
+ or (r =:= element(3, X))]),
+ {qlc,_,[{generate,_,{table,{call,_,_,_}}},
+ _],[]} = i(QH),
+ [1,2] = qlc:eval(QH)">>,
+
+ <<"L = [{a,1},{b,2},{c,3}],
+ QH = qlc:q([E || {K,I}=E <- qlc_SUITE:table(L, 1, [2]),
+ ((K =:= a) or (K =:= b) or (K =:= c))
+ and ((I =:= 1) or (I =:= 2))],
+ {max_lookup, 3}),
+ {list, {table,{qlc_SUITE,list_keys,[[a,b,c],1,L]}}, _MS} = i(QH),
+ [{a,1},{b,2}] = qlc:eval(QH)">>,
+
+ <<"L = [{a,1},{b,2},{c,3}],
+ QH = qlc:q([E || {K,I}=E <- qlc_SUITE:table(L, 1, [2]),
+ ((K =:= a) or (K =:= b) or (K =:= c))
+ and ((I =:= 1) or (I =:= 2))],
+ {max_lookup, 2}),
+ {list, {table,{qlc_SUITE,list_keys, [[1,2],2,L]}}, _MS} = i(QH),
+ [{a,1},{b,2}] = qlc:eval(QH)">>,
+
+ <<"L = [{a,1,x,u},{b,2,y,v},{c,3,z,w}],
+ QH = qlc:q([E || {K,I1,I2,I3}=E <- qlc_SUITE:table(L, 1, [2,3,4]),
+ ((K =/= a) or (K =/= b) or (K =/= c))
+ and ((I1 =:= 1) or (I1 =:= 2) or
+ (I1 =:= 3) or (I1 =:= 4))
+ and ((I2 =:= x) or (I2 =:= z))
+ and ((I3 =:= v) or (I3 =:= w))],
+ {max_lookup, 5}),
+ {list, {table,{qlc_SUITE,list_keys, [[x,z],3,L]}}, _MS} = i(QH),
+ [{c,3,z,w}] = qlc:eval(QH)">>
+
+ ],
+ ?line run(Config, <<"-record(r, {a}).\n">>, Ts),
+ ok.
+
+pre_fun(doc) ->
+ "Test the table/2 callback functions parent_fun and stop_fun.";
+pre_fun(suite) -> [];
+pre_fun(Config) when is_list(Config) ->
+ Ts = [
+ <<"PF = process_flag(trap_exit, true),
+ %% cursor: table killing parent
+ L = [{1,a},{2,b},{3,c}],
+ F1 = fun() ->
+ QH = qlc:q([element(1, X) ||
+ X <- qlc_SUITE:table_kill_parent(L, [2]),
+ (element(2, X) =:= a)
+ or (b =:= element(2, X))]),
+ _ = qlc:info(QH),
+ _ = qlc:cursor(QH)
+ end,
+ Pid1 = spawn_link(F1),
+ receive {'EXIT', Pid1, killed} ->
+ ok
+ end,
+ timer:sleep(1),
+ process_flag(trap_exit, PF)">>,
+
+ <<"PF = process_flag(trap_exit, true),
+ %% eval without cursor: table killing parent
+ L = [{1,a},{2,b},{3,c}],
+ F2 = fun() ->
+ QH = qlc:q([element(1, X) ||
+ X <- qlc_SUITE:table_kill_parent(L, [2]),
+ (element(2, X) =:= a)
+ or (b =:= element(2, X))]),
+ _ = qlc:eval(QH)
+ end,
+ Pid2 = spawn_link(F2),
+ receive {'EXIT', Pid2, killed} ->
+ ok
+ end,
+ process_flag(trap_exit, PF)">>,
+
+ <<"L = [{1,a},{2,b},{3,c}],
+ QH = qlc:q([element(1, X) ||
+ X <- qlc_SUITE:table_parent_throws(L, [2]),
+ (element(2, X) =:= a)
+ or (b =:= element(2, X))]),
+ _ = qlc:info(QH),
+ {throw,thrown} = (catch {any_term,qlc:cursor(QH)}),
+ {throw,thrown} = (catch {any_term,qlc:eval(QH)})">>,
+
+ <<"L = [{1,a},{2,b},{3,c}],
+ QH = qlc:q([element(1, X) ||
+ X <- qlc_SUITE:table_parent_exits(L, [2]),
+ (element(2, X) =:= a)
+ or (b =:= element(2, X))]),
+ _ = qlc:info(QH),
+ {'EXIT', {badarith,_}} = (catch qlc:cursor(QH)),
+ {'EXIT', {badarith,_}} = (catch qlc:eval(QH))">>,
+
+ <<"L = [{1,a},{2,b},{3,c}],
+ QH = qlc:q([element(1, X) ||
+ X <- qlc_SUITE:table_bad_parent_fun(L, [2]),
+ (element(2, X) =:= a)
+ or (b =:= element(2, X))]),
+ {'EXIT', {badarg,_}} = (catch qlc:cursor(QH)),
+ {'EXIT', {badarg,_}} = (catch qlc:eval(QH))">>,
+
+ <<"%% Very simple test of stop_fun.
+ Ets = ets:new(apa, [public]),
+ L = [{1,a},{2,b},{3,c}],
+ H = qlc:q([X || {X,_} <- qlc_SUITE:stop_list(L, Ets)]),
+ C = qlc:cursor(H),
+ [{stop_fun,StopFun}] = ets:lookup(Ets, stop_fun),
+ StopFun(),
+ {'EXIT', {{qlc_cursor_pid_no_longer_exists, _}, _}} =
+ (catch qlc:next_answers(C, all_remaining)),
+ ets:delete(Ets)">>
+
+ ],
+
+ ?line run(Config, Ts),
+ ok.
+
+skip_filters(doc) ->
+ "Lookup keys. With records.";
+skip_filters(suite) -> [];
+skip_filters(Config) when is_list(Config) ->
+ %% Skipped filters
+ TsS = [
+ %% Cannot skip the filter.
+ <<"etsc(fun(E) ->
+ H = qlc:q([X || X <- ets:table(E),
+ (element(1, X) =:= 1) xor (element(1, X) =:= 1)]),
+ [] = qlc:eval(H),
+ [1] = lookup_keys(H)
+ end, [{keypos,1}], [{1},{2}])">>,
+
+ %% The filter can be skipped. Just a lookup remains.
+ <<"etsc(fun(E) ->
+ H = qlc:q([X || X <- ets:table(E),
+ (element(1, X) =:= 1) or (element(1, X) =:= 1)]),
+ [{1}] = qlc:eval(H),
+ {table, _} = i(H),
+ [1] = lookup_keys(H)
+ end, [{keypos,1}], [{1},{2}])">>,
+
+ %% safe_unify fails on 3 and <<X:32>>
+ <<"etsc(fun(E) ->
+ H = qlc:q([X || X <- ets:table(E),
+ (element(1, X) =:= 1) and (3 =:= <<X:32>>)]),
+ [] = qlc:eval(H),
+ [1] = lookup_keys(H)
+ end, [{keypos,1}], [{1},{2}])">>,
+
+ %% Two filters are skipped.
+ <<"etsc(fun(E) ->
+ Q = qlc:q([{B,C,D} || {A={C},B} <- ets:table(E),
+ (A =:= {1}) or (A =:= {2}),
+ (C =:= 1) or (C =:= 2),
+ D <- [1,2]]),
+ {qlc,_,[{generate,_,{table,_}},{generate,_,{list,[1,2]}}],[]}
+ = i(Q),
+ [{1,1,1},{1,1,2},{2,2,1},{2,2,2}] = lists:sort(qlc:eval(Q)),
+ [{1},{2}] = lookup_keys(Q)
+ end, [{{1},1},{{2},2},{{3},3}])">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([{B,C} || {A={C},B} <- ets:table(E),
+ (A =:= {1}) or (A =:= {2}),
+ (C =:= 1) or (C =:= 2)]),
+ {qlc,_,[{generate,_,{table,_}}],[]} = i(Q),
+ [{1,1},{2,2}] = lists:sort(qlc:eval(Q)),
+ [{1},{2}] = lookup_keys(Q)
+ end, [{{1},1},{{2},2},{{3},3}])">>,
+
+ %% Lookup. No match spec, no filter.
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || X <- ets:table(E),
+ element(1, X) =:= 1]),
+ {table, _} = i(Q),
+ [{1}] = qlc:e(Q),
+ [1] = lookup_keys(Q)
+ end, [{1},{2}])">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([{X,Y} || X <- ets:table(E),
+ element(1, X) =:= 1,
+ Y <- [1,2]]),
+ {qlc,_,[{generate,_,{table,_}},{generate,_,{list,_}}],[]}
+ = i(Q),
+ [{{1},1},{{1},2}] = lists:sort(qlc:e(Q)),
+ [1] = lookup_keys(Q)
+ end, [{1},{2}])">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {X,Y} <- ets:table(E),
+ X =:= a,
+ X =:= Y]),
+ {list,{table,_},_} = i(Q),
+ [a] = qlc:e(Q),
+ [a] = lookup_keys(Q)
+ end, [{a,a},{b,c},{c,a}])">>,
+
+ %% The imported variable (A) is never looked up in the current
+ %% implementation. This means that the first filter cannot be skipped;
+ %% the constant 'a' is looked up, and then the first filter evaluates
+ %% to false.
+ <<"etsc(fun(E) ->
+ A = 3,
+ Q = qlc:q([X || X <- ets:table(E),
+ A == element(1,X),
+ element(1,X) =:= a]),
+ [] = qlc:e(Q),
+ [a] = lookup_keys(Q)
+ end, [{a},{b},{c}])">>,
+
+ %% No lookup.
+ {cres,
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {X} <- ets:table(E),
+ X =:= 1,
+ X =:= 2]),
+ {table, _} = i(Q),
+ [] = qlc:e(Q),
+ false = lookup_keys(Q)
+ end, [{1,1},{2,0}])">>,
+ {warnings,[{{4,37},qlc,nomatch_filter}]}},
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([{A,B,C} ||
+ {A} <- ets:table(E),
+ A =:= 1,
+ {B} <- ets:table(E),
+ B =:= 2,
+ {C} <- ets:table(E),
+ C =:= 3]),
+ {qlc,_,[{generate,_,{list,{table,_},_}},
+ {generate,_,{list,{table,_},_}},
+ {generate,_,{list,{table,_},_}}],[]} = i(Q),
+ [{1,2,3}] = qlc:e(Q),
+ [1,2,3] = lookup_keys(Q)
+ end, [{0},{1},{2},{3},{4}])">>
+
+ ],
+ ?line run(Config, TsS),
+
+ Ts = [
+ <<"etsc(fun(E) ->
+ H = qlc:q([X || {X,_} <- ets:table(E),
+ X =:= 2]),
+ {list,{table,_},_} = i(H),
+ [2] = qlc:e(H)
+ end, [{1,a},{2,b}])">>,
+
+ <<"etsc(fun(E) ->
+ H = qlc:q([X || {X,_} <- ets:table(E),
+ ((X =:= 2) or (X =:= 1)) and (X > 1)]),
+ {list,{table,_},_} = i(H),
+ [2] = qlc:e(H)
+ end, [{1,a},{2,b}])">>,
+
+ <<"etsc(fun(E) ->
+ H = qlc:q([X || {X,Y} <- ets:table(E),
+ (X =:= 2) and (Y =:= b)]),
+ {list,{table,_},_} = i(H),
+ [2] = qlc:e(H)
+ end, [{1,a},{2,b}])">>,
+
+ <<"etsc(fun(E) ->
+ H = qlc:q([X || X <- ets:table(E),
+ (element(1,X) =:= 2) and (X =:= {2,b})]),
+ {list,{table,_},_} = i(H),
+ [{2,b}] = qlc:e(H)
+ end, [{1,a},{2,b}])">>,
+
+ <<"etsc(fun(E) ->
+ H = qlc:q([{X,Y,Z,W} ||
+ {X,Y} <- ets:table(E),
+ {Z,W} <- ets:table(E),
+ (Y =:= 3) or (Y =:= 4)]),
+ {qlc,_,[{generate,_,{table,{ets,table,_}}},
+ {generate,_,{table,{ets,table,_}}}],[]} = i(H),
+ [{a,3,a,3},{a,3,b,5}] = lists:sort(qlc:e(H))
+ end, [{a,3},{b,5}])">>,
+
+ <<"etsc(fun(E) ->
+ H = qlc:q([{X,Y} ||
+ {X,Y=3} <- ets:table(E), % no matchspec
+ %% Two columns restricted, but lookup anyway
+ (X =:= a)]),
+ {qlc,_,[{generate,_,{table,_}}],[]} = i(H),
+ [{a,3}] = qlc:e(H)
+ end, [{a,3},{b,4}])">>,
+
+ <<"etsc(fun(E) ->
+ V = 3,
+ H = qlc:q([{X,Y} ||
+ {X,Y} <- ets:table(E),
+ (Y =:= V)]), % imported variable, no lookup
+ {table,{ets,table,_}} = i(H),
+ [{a,3}] = qlc:e(H)
+ end, [{a,3},{b,4}])">>,
+
+ <<"etsc(fun(E) ->
+ V = b,
+ H = qlc:q([{X,Y} ||
+ {X,Y} <- ets:table(E),
+ (X =:= V)]), % imported variable, lookup
+ {list,{table,_},_} = i(H),
+ [{b,4}] = qlc:e(H)
+ end, [{a,3},{b,4}])">>,
+
+ <<"H = qlc:q([{A,B} || {{A,B}} <- [{{1,a}},{{2,b}}],
+ A =:= 1,
+ B =:= a]),
+ {list,{list,[_,_]},_} = i(H),
+ [{1,a}] = qlc:e(H)">>,
+
+ <<"etsc(fun(E) ->
+ H = qlc:q([{A,B} || {{A,B}} <- ets:table(E),
+ A =:= 1,
+ B =:= a]),
+ {list,{table,_},_} = i(H),
+ [{1,a}] = qlc:e(H)
+ end, [{{1,a}},{{2,b}}])">>,
+
+ %% The filters are skipped, and the guards of the match specifications
+ %% are skipped as well. Only the transformations of the matchspecs
+ %% are kept.
+ <<"etsc(fun(E1) ->
+ etsc(fun(E2) ->
+ H = qlc:q([{X,Y,Z,W} ||
+ {X,_}=Z <- ets:table(E1),
+ W={Y} <- ets:table(E2),
+ (X =:= 1) or (X =:= 2),
+ (Y =:= a) or (Y =:= b)]
+ ,{lookup,true}
+ ),
+ {qlc,_,[{generate,_,{list,{table,_},
+ [{{'$1','_'},[],['$_']}]}},
+ {generate,_,{list,{table,_},
+ [{{'$1'},[],['$_']}]}}],[]}
+ = i(H),
+ [{1,a,{1,a},{a}},
+ {1,b,{1,a},{b}},
+ {2,a,{2,b},{a}},
+ {2,b,{2,b},{b}}] = qlc:e(H)
+ end, [{a},{b}])
+ end, [{1,a},{2,b}])">>,
+
+ %% The same example again, but this time no match specs are run.
+ <<"fun(Z) ->
+ etsc(fun(E1) ->
+ etsc(fun(E2) ->
+ H = qlc:q([{X,Y} ||
+ Z > 2,
+ X <- ets:table(E1),
+ Y <- ets:table(E2),
+ (element(1, X) =:= 1) or
+ (element(1, X) =:= 2),
+ (element(1, Y) =:= a) or
+ (element(1, Y) =:= b)]
+ ,{lookup,true}
+ ),
+ {qlc,_,[_,{generate,_,{table,_}},
+ {generate,_,{table,_}}],[]} = i(H),
+ [{{1,a},{a}},
+ {{1,a},{b}},
+ {{2,b},{a}},
+ {{2,b},{b}}] = qlc:e(H)
+ end, [{a},{b}])
+ end, [{1,a},{2,b}])
+ end(4)">>,
+
+ %% Once again, this time with a join.
+ <<"etsc(fun(E1) ->
+ etsc(fun(E2) ->
+ H = qlc:q([{X,Y,Z,W} ||
+ {X,V}=Z <- ets:table(E1),
+ W={Y} <- ets:table(E2),
+ (X =:= 1) or (X =:= 2),
+ (Y =:= a) or (Y =:= b),
+ Y =:= V]
+ ,[{lookup,true},{join,merge}]
+ ),
+ {qlc,_,[{generate,_,{qlc,_,
+ [{generate,_,{qlc,_,[{generate,_,
+ {keysort,{list,{table,_},_},2,[]}},
+ _C1,_C2],[]}},
+ {generate,_,
+ {qlc,_,[{generate, _,
+ {keysort,{list,{table,_},_},1,[]}},
+ _C3],
+ []}},
+ _],
+ [{join,merge}]}},_],[]} = i(H),
+ [{1,a,{1,a},{a}},{2,b,{2,b},{b}}] =
+ lists:sort(qlc:e(H))
+ end, [{a},{b}])
+ end, [{1,a},{2,b}])">>,
+
+ %% Filters 2 and 3 are not skipped.
+ %% (Only one filter at a time is tried by the parse transform.)
+ <<"etsc(fun(E) ->
+ H = qlc:q([X || {{A,B}=X,Y} <- ets:table(E), % no matchspec
+ Y =:= 3,
+ A =:= 1,
+ B =:= a]),
+
+ {qlc,_,[{generate,_,{table,_}},_,_,_],[]}= i(H),
+ [{1,a}] = qlc:e(H)
+ end, [{{1,a},3},{{2,b},4}])">>,
+
+ <<"etsc(fun(E) ->
+ H = qlc:q([X || {X=_,_} <- ets:table(E), % no matchspec
+ (X =:= 3) and (X > 3)]),
+ {qlc,_,[{generate,_,{table,_}},_],[]} = i(H),
+ [] = qlc:e(H)
+ end, [{3,a},{4,b}])">>,
+
+ <<"etsc(fun(E) ->
+ H = qlc:q([X || {X=_,_} <- ets:table(E), % no matchspec
+ (X =:= 3) or true]),
+ {qlc,_,[{generate,_,{table,{ets,table,_}}},_],[]} = i(H),
+ [3,4] = lists:sort(qlc:e(H))
+ end, [{3,a},{4,b}])">>,
+
+ <<"etsc(fun(E) ->
+ H = qlc:q([X || {X=_,_} <- ets:table(E), % no matchspec
+ (X =:= 3) or false]),
+ {qlc,_,[{generate,_,{table,_}}],[]} = i(H),
+ [3] = lists:sort(qlc:e(H))
+ end, [{3,a},{4,b}])">>,
+
+ <<"etsc(fun(E) ->
+ H = qlc:q([X || {X=_,_} <- ets:table(E), % no matchspec
+ (X =:= X) and (X =:= 3)]),
+ {qlc,_,[{generate,_,{table,_}}],[]} = i(H),
+ [3] = lists:sort(qlc:e(H))
+ end, [{3,a},{4,b}])">>,
+
+ %% The order of filters matters. A guard filter cannot be used
+ %% unless there are no non-guard filter placed before the guard
+ %% filter that uses the guard filter's generator. There is
+ %% more examples in join_filter().
+ <<"etsc(fun(E) ->
+ %% Lookup.
+ Q = qlc:q([{A,B,A} ||
+ {A=_,B} <- ets:table(E), % no match spec
+ A =:= 1,
+ begin 1/B > 0 end]),
+ [{1,1,1}] = lists:sort(qlc:e(Q))
+ end, [{1,1},{2,0}])">>,
+ <<"etsc(fun(E) ->
+ %% No lookup.
+ Q = qlc:q([{A,B,A} ||
+ {A=_,B} <- ets:table(E), % no match spec
+ begin 1/B > 0 end,
+ A =:= 1]),
+ {'EXIT', _} = (catch qlc:e(Q))
+ end, [{1,1},{2,0}])">>,
+ %% The same thing, with a match specification.
+ <<"etsc(fun(E) ->
+ Q = qlc:q([{A,B,A} ||
+ {A,B} <- ets:table(E), % match spec
+ A < 2,
+ begin 1/B > 0 end]),
+ [{1,1,1}] = lists:sort(qlc:e(Q))
+ end, [{1,1},{2,0}])">>,
+ <<"etsc(fun(E) ->
+ Q = qlc:q([{A,B,A} ||
+ {A,B} <- ets:table(E), % match spec
+ begin 1/B > 0 end,
+ A < 2]),
+ {'EXIT', _} = (catch qlc:e(Q))
+ end, [{1,1},{2,0}])">>,
+ %% More examples, this time two tables.
+ <<"etsc(fun(E) ->
+ Q = qlc:q([{A,B,C,D} ||
+ {A,B} <- ets:table(E), % match spec
+ A < 2,
+ {C,D} <- ets:table(E),
+ begin 1/B > 0 end, %\"invalidates\" next filter
+ C =:= 1,
+ begin 1/D > 0 end]),
+ {qlc,_,[{generate,_,{table,{ets,table,_}}},
+ {generate,_,{table,{ets,table,_}}},
+ _,_,_],[]} = i(Q),
+ [{1,1,1,1}] = lists:sort(qlc:e(Q))
+ end, [{1,1},{2,0}])">>,
+ <<"etsc(fun(E) ->
+ Q = qlc:q([{A,B,C,D} ||
+ {A,B} <- ets:table(E),
+ {C,D} <- ets:table(E),
+ begin 1/B > 0 end, % \"invalidates\" two filters
+ A < 2,
+ C =:= 1,
+ begin 1/D > 0 end]),
+ {qlc,_,[{generate,_,{table,{ets,table,_}}},
+ {generate,_,{table,{ets,table,_}}},_,_,_,_],[]} = i(Q),
+ {'EXIT', _} = (catch qlc:e(Q))
+ end, [{1,1},{2,0}])">>,
+ <<"%% There are objects in the ETS table, but none passes the filter.
+ %% F() would not be run if it did not \"invalidate\" the following
+ %% guards.
+ etsc(fun(E) ->
+ F = fun() -> [foo || A <- [0], 1/A] end,
+ Q1 = qlc:q([X || {X} <- ets:table(E),
+ F(), % \"invalidates\" next guard
+ X =:= 17]),
+ {'EXIT', _} = (catch qlc:e(Q1))
+ end, [{1},{2},{3}])">>,
+ <<"%% The last example works just like this one:
+ etsc(fun(E) ->
+ F = fun() -> [foo || A <- [0], 1/A] end,
+ Q1 = qlc:q([X || {X} <- ets:table(E),
+ F(),
+ begin X =:= 17 end]),
+ {'EXIT', _} = (catch qlc:e(Q1))
+ end, [{1},{2},{3}])">>
+
+ ],
+ ?line run(Config, Ts),
+
+ ok.
+
+table_impls(suite) ->
+ [ets, dets].
+
+ets(doc) ->
+ "ets:table/1,2.";
+ets(suite) -> [];
+ets(Config) when is_list(Config) ->
+ Ts = [
+ <<"E = ets:new(t, [ordered_set]),
+ true = ets:insert(E, [{1},{2}]),
+ {'EXIT', _} =
+ (catch qlc:e(qlc:q([X || {X} <- ets:table(E, bad_option)]))),
+ {'EXIT', _} =
+ (catch qlc:e(qlc:q([X || {X} <- ets:table(E,{traverse,bad})]))),
+ All = [{'$1',[],['$1']}],
+ TravAll = {traverse,{select,All}},
+ [_, _] = qlc:e(qlc:q([X || {X} <- ets:table(E, TravAll)])),
+ [_, _] = qlc:e(qlc:q([X || {X} <- ets:table(E,{traverse,select})])),
+ [1,2] =
+ qlc:e(qlc:q([X || {X} <- ets:table(E, {traverse, first_next})])),
+ [2,1] =
+ qlc:e(qlc:q([X || {X} <- ets:table(E, {traverse, last_prev})])),
+ {table,{ets,table,[_,[{traverse,{select,_}},{n_objects,1}]]}} =
+ i(qlc:q([X || {X} <- ets:table(E, {n_objects,1})])),
+ {qlc,_,[{generate,_,{table,{ets,table,[_,{n_objects,1}]}}},_],[]} =
+ i(qlc:q([X || {X} <- ets:table(E,{n_objects,1}),
+ begin (X >= 1) or (X < 1) end])),
+ {qlc,_,[{generate,_,{table,{ets,table,[_]}}},_],[]} =
+ i(qlc:q([X || {X} <- ets:table(E),
+ begin (X >= 1) or (X < 1) end])),
+ ets:delete(E)">>,
+
+ begin
+ MS = ets:fun2ms(fun({X,Y}) when X > 1 -> {X,Y} end),
+ [<<"E = ets:new(apa,[]),
+ true = ets:insert(E, [{1,a},{2,b},{3,c}]),
+ MS = ">>, io_lib:format("~w", [MS]), <<",
+ Q = qlc:q([X || {X,_} <- ets:table(E, {traverse, {select, MS}}),
+ X =:= 1]),
+ R = qlc:e(Q),
+ ets:delete(E),
+ [] = R">>]
+ end
+
+ ],
+
+ ?line run(Config, Ts),
+ ok.
+
+dets(doc) ->
+ "dets:table/1,2.";
+dets(suite) -> [];
+dets(Config) when is_list(Config) ->
+ dets:start(),
+ T = t,
+ Fname = filename(T, Config),
+ Ts = [
+ [<<"T = t, Fname = \"">>, Fname, <<"\",
+ file:delete(Fname),
+ {ok, _} = dets:open_file(T, [{file,Fname}]),
+ ok = dets:insert(T, [{1},{2}]),
+ {'EXIT', _} =
+ (catch qlc:e(qlc:q([X || {X} <- dets:table(T, bad_option)]))),
+ {'EXIT', _} =
+ (catch qlc:e(qlc:q([X || {X} <- dets:table(T,{traverse,bad})]))),
+ {'EXIT', _} =
+ (catch
+ qlc:e(qlc:q([X || {X} <- dets:table(T,{traverse,last_prev})]))),
+ All = [{'$1',[],['$1']}],
+ TravAll = {traverse,{select,All}},
+ [_,_] = qlc:e(qlc:q([X || {X} <- dets:table(T, TravAll)])),
+ [_,_] = qlc:e(qlc:q([X || {X} <- dets:table(T,{traverse,select})])),
+ [_,_] =
+ qlc:e(qlc:q([X || {X} <- dets:table(T, {traverse, first_next})])),
+ {table,{dets,table,[T,[{traverse,{select,_}},{n_objects,1}]]}} =
+ i(qlc:q([X || {X} <- dets:table(T, {n_objects,1})])),
+ {qlc,_,[{generate,_,{table,{dets,table,[t,{n_objects,1}]}}},_],[]}=
+ i(qlc:q([X || {X} <- dets:table(T,{n_objects,1}),
+ begin (X >= 1) or (X < 1) end])),
+ {qlc,_,[{generate,_,{table,{dets,table,[_]}}},_],[]} =
+ i(qlc:q([X || {X} <- dets:table(T),
+ begin (X >= 1) or (X < 1) end])),
+ H = qlc:q([X || {X} <- dets:table(T, {n_objects, default}),
+ begin (X =:= 1) or (X =:= 2) or (X =:= 3) end]),
+ [1,2] = lists:sort(qlc:e(H)),
+ {qlc,_,[{generate,_,{table,_}},_],[]} = i(H),
+
+ H2 = qlc:q([X || {X} <- dets:table(T), (X =:= 1) or (X =:= 2)]),
+ [1,2] = lists:sort(qlc:e(H2)),
+ {list,{table,_},_} = i(H2),
+ true = binary_to_list(<<
+ \"ets:match_spec_run(lists:flatmap(fun(V)->dets:lookup(t,V)end,\"
+ \"[1,2]),ets:match_spec_compile([{{'$1'},[],['$1']}]))\">>)
+ == format_info(H2, true),
+
+ H3 = qlc:q([X || {X} <- dets:table(T), (X =:= 1)]),
+ [1] = qlc:e(H3),
+ {list,{table,_},_} = i(H3),
+
+ ok = dets:close(T),
+ file:delete(\"">>, Fname, <<"\"),
+ ok">>],
+
+ begin
+ MS = ets:fun2ms(fun({X,Y}) when X > 1 -> {X,Y} end),
+ [<<"T = t, Fname = \"">>, Fname, <<"\",
+ {ok, _} = dets:open_file(T, [{file,Fname}]),
+ MS = ">>, io_lib:format("~w", [MS]), <<",
+ ok = dets:insert(T, [{1,a},{2,b},{3,c}]),
+ Q = qlc:q([X || {X,_} <- dets:table(T, {traverse, {select, MS}}),
+ X =:= 1]),
+ R = qlc:e(Q),
+ ok = dets:close(T),
+ file:delete(\"">>, Fname, <<"\"),
+ [] = R">>]
+ end,
+
+ [<<"T = t, Fname = \"">>, Fname, <<"\",
+ {ok, _} = dets:open_file(T, [{file,Fname}]),
+ Objs = [{X} || X <- lists:seq(1,10)],
+ ok = dets:insert(T, Objs),
+ {ok, Where} = dets:where(T, {2}),
+ ok = dets:close(T),
+ qlc_SUITE:crash(Fname, Where),
+
+ {ok, _} = dets:open_file(T, [{file,Fname}]),
+ HT = qlc:q([X || {X} <- dets:table(T, {traverse, first_next})]),
+ {'EXIT',{error,{{bad_object,_},_}}} = (catch qlc:e(HT)),
+ _ = dets:close(T),
+
+ {ok, _} = dets:open_file(T, [{file,Fname}]),
+ HMS = qlc:q([X || {X} <- dets:table(T, {traverse, select})]),
+ {error,{{bad_object,_},_}} = qlc:e(HMS),
+ _ = dets:close(T),
+
+ {ok, _} = dets:open_file(T, [{file,Fname}]),
+ HLU = qlc:q([X || {X} <- dets:table(T), X =:= 2]),
+ {error,{{bad_object,_},_}} = qlc:e(HLU),
+ _ = dets:close(T),
+
+ file:delete(Fname)">>]
+
+ ],
+
+ ?line run(Config, Ts),
+ _ = file:delete(Fname),
+ ok.
+
+join(suite) ->
+ [join_option, join_filter, join_lookup, join_merge,
+ join_sort, join_complex].
+
+join_option(doc) ->
+ "The 'join' option (any, lookup, merge, nested_loop). Also cache/unique.";
+join_option(suite) -> [];
+join_option(Config) when is_list(Config) ->
+ Ts = [
+ <<"Q1 = qlc:q([X || X <- [1,2,3]],{join,merge}),
+ {'EXIT', {no_join_to_carry_out,_}} = (catch {foo, qlc:info(Q1)}),
+ {'EXIT', {no_join_to_carry_out,_}} = (catch {foo, qlc:e(Q1)}),
+
+ Q2 = qlc:q([X || X <- [1,2,3], X > 1],{join,merge}),
+ {'EXIT', {no_join_to_carry_out,_}} = (catch {foo, qlc:info(Q2)}),
+ {'EXIT', {no_join_to_carry_out,_}} = (catch {foo, qlc:e(Q2)}),
+
+ Q3 = qlc:q([{X,Y} ||
+ {X} <- [{1},{2},{3}],
+ {Y} <- [{a},{b},{c}],
+ X =:= Y],
+ {join, merge}),
+
+ {1,0,0,2} = join_info(Q3),
+ [] = qlc:e(Q3),
+
+ Q4 = qlc:q([{X,Y} ||
+ {X} <- [{1},{2},{3}],
+ {Y} <- [{a},{b},{c}],
+ X > Y],
+ {join, lookup}),
+ {'EXIT', {no_join_to_carry_out, _}} = (catch {foo, qlc:info(Q4)}),
+ {'EXIT', {no_join_to_carry_out, _}} = (catch {foo, qlc:e(Q4)}),
+
+ Q5 = qlc:q([{X,Y} ||
+ {X} <- [{1},{2},{3}],
+ {Y} <- [{3},{4},{5}],
+ X == Y],
+ {join, merge}),
+ [{3,3}] = qlc:e(Q5),
+
+ Q6 = qlc:q([{X,Y} ||
+ {X} <- [{1},{2},{3}],
+ {Y} <- [{3},{4},{5}],
+ X == Y],
+ {join, lookup}),
+ {'EXIT', {cannot_carry_out_join, _}} = (catch {foo, qlc:info(Q6)}),
+ {'EXIT', {cannot_carry_out_join, _}} = (catch {foo, qlc:e(Q6)}),
+
+ Q7 = qlc:q([{X,Y} ||
+ {X} <- [{1},{2},{3}],
+ {Y} <- [{3},{4},{5}],
+ X == Y],
+ {join, nested_loop}),
+ {0,0,1,0} = join_info(Q7),
+ [{3,3}] = qlc:e(Q7),
+
+ Q8 = qlc:q([{X,Y} ||
+ {X} <- [{1},{2},{3}],
+ {Y} <- [{3},{4},{5}],
+ X =:= Y],
+ {join, nested_loop}),
+ {0,0,1,0} = join_info(Q8),
+ [{3,3}] = qlc:e(Q8),
+
+ %% Only guards are inspected...
+ Q9 = qlc:q([{X,Y} ||
+ {X} <- [{1},{2},{3}],
+ {Y} <- [{3},{4},{5}],
+ begin X =:= Y end],
+ {join, nested_loop}),
+ {'EXIT', {no_join_to_carry_out, _}} = (catch {foo, qlc:info(Q9)}),
+ {'EXIT', {no_join_to_carry_out, _}} = (catch {foo, qlc:e(Q9)}),
+
+ Q10 = qlc:q([{X,Y} ||
+ {X} <- [{1},{2},{3}],
+ {Y} <- [{3},{4},{5}],
+ X < Y],
+ {join, nested_loop}),
+ {'EXIT', {no_join_to_carry_out, _}} = (catch {foo, qlc:info(Q10)}),
+ {'EXIT', {no_join_to_carry_out, _}} = (catch {foo, qlc:e(Q10)}),
+
+ F = fun(J) -> qlc:q([X || X <- [1,2]], {join,J}) end,
+ {'EXIT', {no_join_to_carry_out, _}} =
+ (catch {foo, qlc:e(F(merge))}),
+ {'EXIT', {no_join_to_carry_out, _}} =
+ (catch {foo, qlc:e(F(lookup))}),
+ {'EXIT', {no_join_to_carry_out, _}} =
+ (catch {foo, qlc:e(F(nested_loop))}),
+ [1,2] = qlc:e(F(any)),
+
+ %% No join of columns in the same table.
+ Q11 = qlc:q([{X,Y} || {a = X, X = Y} <- [{a,1},{a,a},{a,3},{a,a}]],
+ {join,merge}),
+ {'EXIT', {no_join_to_carry_out, _}} = (catch qlc:e(Q11)),
+ Q12 = qlc:q([{X,Y} || {X = a, X = Y} <- [{a,1},{a,a},{a,3},{a,a}]],
+ {join,merge}),
+ {'EXIT', {no_join_to_carry_out, _}} = (catch qlc:e(Q12)),
+ %% X and Y are \"equal\" (same constants), but must not be joined.
+ Q13 = qlc:q([{X,Y} || {X,_Z} <- [{a,1},{a,2},{b,1},{b,2}],
+ {Y} <- [{a}],
+ (X =:= a) and (Y =:= b) or
+ (X =:= b) and (Y =:= a)],
+ {join,merge}),
+ {'EXIT', {no_join_to_carry_out, _}} = (catch qlc:e(Q13))
+
+">>,
+
+ <<"Q1 = qlc:q([X || X <- [1,2,3]], {lookup,true}),
+ {'EXIT', {no_lookup_to_carry_out, _}} = (catch {foo, qlc:info(Q1)}),
+ {'EXIT', {no_lookup_to_carry_out, _}} = (catch {foo, qlc:e(Q1)}),
+ Q2 = qlc:q([{X,Y} || X <- [1,2,3], Y <- [x,y,z]], lookup),
+ {'EXIT', {no_lookup_to_carry_out, _}} = (catch {foo, qlc:info(Q2)}),
+ {'EXIT', {no_lookup_to_carry_out, _}} = (catch {foo, qlc:e(Q2)}),
+ Q3 = qlc:q([X || {X} <- [{1},{2},{3}]], {lookup,true}),
+ {'EXIT', {no_lookup_to_carry_out, _}} = (catch {foo, qlc:e(Q3)}),
+ {'EXIT', {no_lookup_to_carry_out, _}} = (catch {foo, qlc:info(Q3)}),
+
+ E1 = create_ets(1, 10),
+ Q4 = qlc:q([{X,Y} || {X,Y} <- ets:table(E1), X =:= 3], lookup),
+ {match_spec, _} = strip_qlc_call(Q4),
+ [{3,3}] = qlc:e(Q4),
+ Q5 = qlc:q([{X,Y} || {X,Y} <- ets:table(E1), X =:= 3], {lookup,false}),
+ {table, ets, _} = strip_qlc_call(Q5),
+ [{3,3}] = qlc:e(Q5),
+ Q6 = qlc:q([{X,Y} || {X,Y} <- ets:table(E1), X =:= 3], {lookup,any}),
+ {match_spec, _} = strip_qlc_call(Q6),
+ [{3,3}] = qlc:e(Q6),
+ ets:delete(E1)">>
+
+ ],
+ ?line run(Config, Ts),
+
+ %% The 'cache' and 'unique' options of qlc/2 affects join.
+ CUTs = [
+ <<"L1 = [1,2],
+ L2 = [{1,a},{2,b}],
+ L3 = [{a,1},{b,2}],
+ Q = qlc:q([{X,Y,Z} ||
+ Z <- L1,
+ {X,_} <- L2,
+ {_,Y} <- L3,
+ X =:= Y],
+ [cache, unique]),
+ {qlc,_,
+ [{generate,_,{list,L1}},
+ {generate,_,{qlc,_,[{generate,_,
+ {qlc,_,[{generate,_,{keysort,{list,L2},1,[]}}],[]}},
+ {generate,_,{qlc,_,
+ [{generate,_,{keysort,{list,L3},2,[]}}],[]}},_],
+ [{join,merge},{cache,ets},{unique,true}]}},_],
+ [{unique,true}]} = i(Q),
+ [{1,1,1},{2,2,1},{1,1,2},{2,2,2}] = qlc:e(Q)">>,
+ <<"L1 = [1,2],
+ L2 = [{1,a},{2,b}],
+ L3 = [{a,1},{b,2}],
+ Q = qlc:q([{X,Y,Z} ||
+ Z <- L1,
+ {X,_} <- L2,
+ {_,Y} <- L3,
+ X =:= Y],
+ []),
+ Options = [{cache_all,ets}, unique_all],
+ {qlc,_,[{generate,_,{qlc,_,[{generate,_,{list,L1}}],
+ [{unique,true}]}},
+ {generate,_,{qlc,_,
+ [{generate,_,{qlc,_,[{generate,_,
+ {keysort,{qlc,_,[{generate,_,{list,L2}}],
+ [{cache,ets},{unique,true}]},
+ 1,[]}}],[]}},
+ {generate,_,{qlc,_,
+ [{generate,_,{keysort,
+ {qlc,_,[{generate,_,{list,L3}}],
+ [{cache,ets},{unique,true}]},
+ 2,[]}}],[]}},_],
+ [{join,merge},{cache,ets},{unique,true}]}},
+ _],[{unique,true}]} = i(Q, Options),
+ [{1,1,1},{2,2,1},{1,1,2},{2,2,2}] = qlc:e(Q, Options)">>
+ ],
+ ?line run(Config, CUTs),
+
+ ok.
+
+join_filter(doc) ->
+ "Various aspects of filters and join.";
+join_filter(suite) -> [];
+join_filter(Config) when is_list(Config) ->
+ Ts = [
+ <<"E1 = create_ets(1, 10),
+ Q = qlc:q([X || {X,_} <- ets:table(E1),
+ begin A = X * X end, % ej true (?)
+ X >= A]),
+ {'EXIT', _} = (catch qlc:e(Q)),
+ ets:delete(E1)">>,
+
+ %% The order of filters matters. See also skip_filters().
+ <<"Q = qlc:q([{X,Y} || {X,Y} <- [{a,1},{b,2}],
+ {Z,W} <- [{a,1},{c,0}],
+ X =:= Z,
+ begin Y/W > 0 end]),
+ [{a,1}] = qlc:e(Q)">>,
+ <<"Q = qlc:q([{X,Y} || {X,Y} <- [{a,1},{b,2}],
+ {Z,W} <- [{a,1},{c,0}],
+ begin Y/W > 0 end,
+ X =:= Z]),
+ {'EXIT', _} = (catch qlc:e(Q))">>,
+
+ <<"etsc(fun(E1) ->
+ etsc(fun(E2) ->
+ F = fun() -> [foo || A <- [0], 1/A] end,
+ Q1 = qlc:q([X || {X} <- ets:table(E1),
+ {Y} <- ets:table(E2),
+ F(), % invalidates next filter
+ X =:= Y]),
+ {qlc,_,[{generate,_,{table,{ets,table,_}}},
+ {generate,_,{table,{ets,table,_}}},_,_],
+ []} = i(Q1),
+ {'EXIT', _} = (catch qlc:e(Q1))
+ end, [{1},{2},{3}])
+ end, [{a},{b},{c}])">>
+
+ ],
+ ?line run(Config, Ts),
+ ok.
+
+join_lookup(doc) ->
+ "Lookup join.";
+join_lookup(suite) -> [];
+join_lookup(Config) when is_list(Config) ->
+ Ts = [
+ <<"E1 = create_ets(1, 10),
+ E2 = create_ets(5, 15),
+ Q = qlc:q([{X,Y} || {_,Y} <- ets:table(E2),
+ {X,_} <- ets:table(E1),
+ X =:= Y], [{join,lookup}]),
+ {0,1,0,0} = join_info_count(Q),
+ R = qlc:e(Q),
+ ets:delete(E1),
+ ets:delete(E2),
+ [{5,5},{6,6},{7,7},{8,8},{9,9},{10,10}] = lists:sort(R)">>,
+
+ <<"E1 = create_ets(1, 10),
+ E2 = create_ets(5, 15),
+ F = fun(J) -> qlc:q([{X,Y} || {X,_} <- ets:table(E1),
+ {_,Y} <- ets:table(E2),
+ X =:= Y], {join, J})
+ end,
+ Q = F(lookup),
+ {0,1,0,0} = join_info_count(Q),
+ R = qlc:e(Q),
+ ets:delete(E1),
+ ets:delete(E2),
+ [{5,5},{6,6},{7,7},{8,8},{9,9},{10,10}] = lists:sort(R)">>,
+
+ <<"etsc(fun(E1) ->
+ E2 = qlc_SUITE:table([{1,a},{a},{1,b},{b}], 2, []),
+ Q = qlc:q([{X,Y} || {X,Y} <- ets:table(E1), % (1)
+ {_,Z} <- E2, % (2)
+ (Z =:= Y) and (X =:= a)
+ or
+ (Z =:= Y) and (X =:= b)]),
+ %% Cannot look up in (1) (X is keypos). Can look up (2).
+ %% Lookup-join: traverse (1), look up in (2).
+ {0,1,0,0} = join_info_count(Q),
+ [{a,a},{b,a}] = qlc:e(Q)
+ end, [{a,a},{b,a},{c,3},{d,4}])">>,
+
+ <<"%% The pattern {X,_} is used to filter out looked up objects.
+ etsc(fun(E) ->
+ Q = qlc:q([X || {X,_} <- ets:table(E),
+ Y <- [{a,b},{c,d},{1,2},{3,4}],
+ X =:= element(1, Y)]),
+ {0,1,0,0} = join_info_count(Q),
+ [1] = qlc:e(Q)
+ end, [{1,2},{3}])">>,
+
+ <<"E = ets:new(e, [bag,{keypos,2}]),
+ L = lists:sort([{a,1},{b,1},{c,1},{d,1},
+ {aa,2},{bb,2},{cc,2},{dd,2}]),
+ true = ets:insert(E, L ++ [{aaa,1,1},{bbb,2,2},{ccc,3,3}]),
+ Q = qlc:q([Z || {_,Y}=Z <- ets:table(E),
+ {X} <- [{X} || X <- lists:seq(0, 10)],
+ X =:= Y]),
+ {0,1,0,0} = join_info_count(Q),
+ R = qlc:e(Q),
+ ets:delete(E),
+ L = lists:sort(R)">>,
+
+ <<"E = ets:new(e, [bag,{keypos,2}]),
+ L = lists:sort([{a,1},{b,1},{c,1},{d,1},
+ {aa,2},{bb,2},{cc,2},{dd,2}]),
+ true = ets:insert(E, L ++ [{aaa,1,1},{bbb,2,2},{ccc,3,3}]),
+ Q = qlc:q([Z || {X} <- [{X} || X <- lists:seq(0, 10)],
+ {_,Y}=Z <- ets:table(E),
+ X =:= Y]),
+ {0,1,0,0} = join_info_count(Q),
+ R = qlc:e(Q),
+ ets:delete(E),
+ L = lists:sort(R)">>,
+
+ <<"Q = qlc:q([{XX,YY} ||
+ {XX,X} <- [{b,1},{c,3}],
+ {Y,YY} <- qlc_SUITE:table_lookup_error([{1,a}]),
+ X =:= Y],
+ {join,lookup}),
+ {error, lookup, failed} = qlc:e(Q)">>,
+
+ <<"E = create_ets(1, 10),
+ Q = qlc:q([{X,Y} ||
+ {X,_} <- ets:table(E),
+ {_,Y} <- qlc_SUITE:table_error([{a,1}], 1, err),
+ X =:= Y]),
+ {0,1,0,0} = join_info_count(Q),
+ err = qlc:e(Q),
+ ets:delete(E)">>
+
+ ],
+ ?line run(Config, Ts),
+ ok.
+
+join_merge(doc) ->
+ "Merge join.";
+join_merge(suite) -> [];
+join_merge(Config) when is_list(Config) ->
+ Ts = [
+ <<"Q = qlc:q([{X,Y} || {X} <- [], {Y} <- [{1}], X =:= Y],
+ {join,merge}),
+ [] = qlc:e(Q)
+ ">>,
+
+ <<"Q = qlc:q([{X,Y} || {X} <- [{1}], {Y} <- [], X =:= Y],
+ {join,merge}),
+ [] = qlc:e(Q)
+ ">>,
+
+ <<"Q = qlc:q([{X,Y} || {X} <- [{1},{1},{1}],
+ {Y} <- [{1},{1},{1}], X =:= Y],
+ {join,merge}),
+ 9 = length(qlc:e(Q))
+ ">>,
+
+ <<"%% Two merge joins possible.
+ Q = qlc:q([{X,Y,Z,W} || {X,Y} <- [{1,a},{1,b},{1,c}],
+ {Z,W} <- [{1,a},{1,b},{1,c}],
+ X =:= Z,
+ Y =:= W]),
+ {qlc,_,[{generate,_,
+ {qlc,_,
+ [{generate,_,
+ {qlc,_,[{generate,_,{keysort,{list,_},C,[]}}],[]}},
+ {generate,_,
+ {qlc,_,[{generate,_,{keysort,{list,_},C,[]}}],[]}},
+ _],
+ [{join,merge}]}},
+ _,_],[]} = qlc:info(Q, {format,debug}),
+ [{1,a,1,a},{1,b,1,b},{1,c,1,c}] = qlc:e(Q)">>,
+
+ <<"%% As the last one, but comparison.
+ Q = qlc:q([{X,Y,Z,W} || {X,Y} <- [{1,a},{1,b},{1,c}],
+ {Z,W} <- [{1,a},{1,b},{1,c}],
+ X == Z, % skipped
+ Y =:= W]),
+ {qlc,_,[{generate,_,
+ {qlc,_,
+ [{generate,_,
+ {qlc,_,[{generate,_,{keysort,{list,_},1,[]}}],[]}},
+ {generate,_,
+ {qlc,_,[{generate,_,{keysort,{list,_},1,[]}}],[]}},
+ _],
+ [{join,merge}]}},
+ _],[]} = qlc:info(Q, {format,debug}),
+ [{1,a,1,a},{1,b,1,b},{1,c,1,c}] = qlc:e(Q)">>,
+
+ <<"%% This is no join.
+ Q = qlc:q([{X,Y,Z,W} || {X,Y} <- [], {Z,W} <- [],
+ X =:= Y, Z =:= W]),
+ {0,0,0,0} = join_info_count(Q)">>,
+
+ <<"%% Used to replace empty ETS tables with [], but that won't work.
+ E1 = ets:new(e1, []),
+ E2 = ets:new(e2, []),
+ Q = qlc:q([{X,Z,W} ||
+ {X, Z} <- ets:table(E1),
+ {W, Y} <- ets:table(E2),
+ X =:= Y],
+ {join, lookup}),
+ [] = qlc:e(Q),
+ ets:delete(E1),
+ ets:delete(E2)">>,
+
+ <<"Q = qlc:q([{X,Y} || {X} <- [{3},{1},{0}],
+ {Y} <- [{1},{2},{3}],
+ X =:= Y]),
+ {1,0,0,2} = join_info_count(Q),
+ [{1,1},{3,3}] = qlc:e(Q)">>,
+
+ <<"QH = qlc:q([{X,Y,Z,W} || {X,Y} <- [{3,c},{2,b},{1,a}],
+ {Z,W} <- [{2,b},{4,d},{5,e},{3,c}],
+ X =:= Z,
+ Y =:= W]),
+ {1,0,0,2} = join_info_count(QH),
+ [{2,b,2,b},{3,c,3,c}] = qlc:e(QH)">>,
+
+ <<"%% QLC finds no join column at run time...
+ QH = qlc:q([1 || X <- [{1,2,3},{4,5,6}],
+ Y <- [{1,2},{3,4}],
+ X =:= Y]),
+ {0,0,0,0} = join_info_count(QH),
+ [] = qlc:e(QH)">>,
+
+ <<"QH = qlc:q([X || X <- [{1,2,3},{4,5,6}],
+ Y <- [{1,2},{3,4}],
+ element(1, X) =:= element(2, Y)]),
+ {1,0,0,2} = join_info_count(QH),
+ [{4,5,6}] = qlc:e(QH)">>,
+
+ <<"Q = qlc:q([{A,X,Z,W} ||
+ A <- [a,b,c],
+ {X,Z} <- [{a,1},{b,4},{c,6}],
+ {W,Y} <- [{2,a},{3,b},{4,c}],
+ X =:= Y],
+ {cache, list}),
+ _ = qlc:info(Q),
+ [{a,a,1,2},{a,b,4,3},{a,c,6,4},{b,a,1,2},{b,b,4,3},
+ {b,c,6,4},{c,a,1,2},{c,b,4,3},{c,c,6,4}] = qlc:e(Q)">>,
+
+ <<"Q = qlc:q([{X,Y} ||
+ {X,Z} <- [{a,1},{b,4},{c,6}],
+ {W,Y} <- [{2,a},{3,b},{4,c}],
+ Z > W,
+ X =:= Y],
+ {join,merge}),
+ {qlc,_,[{generate,_,{qlc,_,
+ [{generate,_,
+ {qlc,_,[{generate,_,{keysort,_,1,[]}}],[]}},
+ {generate,_,
+ {qlc,_,[{generate,_,{keysort,_,2,[]}}],
+ []}},_],[{join,merge}]}},
+ _,_],[]} = i(Q),
+ [{b,b},{c,c}] = qlc:e(Q)">>,
+
+ <<"E1 = create_ets(1, 10),
+ E2 = create_ets(5, 15),
+ %% A match spec.; Q does not see Q1 and Q2 as lookup-tables.
+ Q1 = qlc:q([X || X <- ets:table(E1)]),
+ Q2 = qlc:q([X || X <- ets:table(E2)]),
+ F = fun(J) -> qlc:q([{X,Y} || X <- Q1,
+ Y <- Q2,
+ element(1,X) =:= element(1,Y)],
+ [{join,J}])
+ end,
+ {'EXIT',{cannot_carry_out_join,_}} = (catch qlc:e(F(lookup))),
+ Q = F(merge),
+ {1,0,0,2} = join_info(Q),
+ R = lists:sort(qlc:e(Q)),
+ ets:delete(E1),
+ ets:delete(E2),
+ true = [{Y,Y} || X <- lists:seq(5, 10), {} =/= (Y = {X,X})] =:= R
+ ">>,
+
+ <<"E1 = create_ets(1, 10),
+ E2 = create_ets(5, 15),
+ Q = qlc:q([{X,Y} || X <- ets:table(E1),
+ Y <- ets:table(E2),
+ element(1,X) =:= element(1,Y)],
+ [{join,merge}]),
+ {1,0,0,2} = join_info(Q),
+ R = lists:sort(qlc:e(Q)),
+ ets:delete(E1),
+ ets:delete(E2),
+ true = [{Y,Y} || X <- lists:seq(5, 10), {} =/= (Y = {X,X})] =:= R
+ ">>,
+
+ <<"E1 = create_ets(1, 10),
+ E2 = create_ets(5, 15),
+ Q1 = qlc:q([Y || X <- ets:table(E1), begin Y = {X}, true end]),
+ %% A match spec.; Q does not see Q2 as a lookup-table.
+ %%
+ %% OTP-6673: lookup join is considered but since there is no
+ %% filter that can do the job of Q2, lookup join is not an option..
+ Q2 = qlc:q([{X} || X <- ets:table(E2)]),
+ F = fun(J) ->
+ qlc:q([{X,Y} || X <- Q1,
+ Y <- Q2,
+ element(1,X) =:= element(1,Y)],
+ [{join,J}])
+ end,
+ {'EXIT',{cannot_carry_out_join,_}} = (catch qlc:e(F(lookup))),
+ Q = F(any),
+ {1,0,0,2} = join_info(Q),
+ R = lists:sort(qlc:e(Q)),
+ ets:delete(E1),
+ ets:delete(E2),
+ true = [{Y,Y} || X <- lists:seq(5, 10), {} =/= (Y = {{X,X}})] =:= R
+ ">>,
+
+ <<"L1 = [{1,a},{2,a},{1,b},{2,b},{1,c},{2,c}],
+ L2 = [{b,Y} || Y <- lists:seq(1, 10000)],
+ F = fun(J) ->
+ Q = qlc:q([{XX,YY} ||
+ {X,XX} <- L1,
+ {YY,Y} <- L2,
+ X == Y],
+ {join,J}),
+ qlc:q([{XX1,YY1,XX2,YY2} ||
+ {XX1,YY1} <- Q,
+ {XX2,YY2} <- Q])
+ end,
+ Qm = F(merge),
+ Qn = F(nested_loop),
+ true = lists:sort(qlc:e(Qm)) =:= lists:sort(qlc:e(Qn))">>,
+
+ <<"L1 = [{{1,a},2},{{3,c},4}],
+ L2 = [{a,{1,a}},{c,{4,d}}],
+ Q = qlc:q([{X,Y} || {X,_} <- L1,
+ {_,{Y,Z}} <- L2,
+ X == {Y,Z}
+ ]),
+ {qlc,_,[{generate,_,{qlc,_,
+ [{generate,_,
+ {qlc,_,[{generate,_,{keysort,{list,L1},1,[]}}],[]}},
+ {generate,_,
+ {qlc,_,[{generate,_,{keysort,{list,L2},2,[]}}],[]}},
+ _],
+ [{join,merge}]}}],[]} = i(Q),
+ [{{1,a},1}] = qlc:e(Q)">>,
+
+ <<"etsc(fun(E1) ->
+ etsc(fun(E2) ->
+ Q = qlc:q([{X,Y} || {X,Y} <- ets:table(E1), % (1)
+ {Z} <- ets:table(E2), % (2)
+ (Z =:= X) and
+ (Y =:= a) and
+ (X =:= Y) or
+ (Y =:= b) and
+ (Z =:= Y)]),
+ %% Cannot look up in (1) (X is keypos). Can look up (2).
+ %% Lookup join not possible (cannot look up in (1)).
+ %% Merge join is possible (after lookup in (2)).
+ {1,0,0,2} = join_info_count(Q),
+ {qlc,_,
+ [{generate,_,
+ {qlc,_,[{generate,_,
+ {qlc,_,[{generate,_,
+ {keysort,
+ {table,{ets,table,_}},
+ 2,[]}},_C1],[]}},
+ {generate,_,
+ {qlc,_,[{generate,_,
+ {keysort,{table,_},1,[]}},_C2],
+ []}},
+ _],[{join,merge}]}},_],[]} = i(Q),
+ [{a,a}] = qlc:e(Q)
+ end, [{a}])
+ end, [{a,1},{a,a},{b,1},{b,2}])">>,
+
+ <<"Q = qlc:q([{G1,G2} ||
+ G1<- [{1}],
+ G2 <- [{1}],
+ element(1, G1) =:= element(1, G2)]),
+ {1,0,0,2} = join_info(Q),
+ [{{1},{1}}] = qlc:e(Q)">>,
+
+ <<"Q = qlc:q([{X,Y} ||
+ X <- [{1}],
+ Y <- [{1}],
+ element(1, X) =:= element(1, Y)],
+ {join,merge}),
+ {1,0,0,2} = join_info(Q),
+ [{{1},{1}}] = qlc:e(Q)">>,
+
+ <<"%% Generator after the join-filter.
+ Q = qlc:q([Z ||
+ {X} <- [{1},{2},{3}],
+ {Y} <- [{2},{3},{4}],
+ X =:= Y,
+ Z <- [1,2]]),
+ {qlc,_,
+ [{generate,_,{qlc,_,
+ [{generate,_,{qlc,_,
+ [{generate,_,{keysort,{list,[{1},{2},{3}]},1,[]}}],[]}},
+ {generate,_,{qlc,_,
+ [{generate,_,{keysort,{list,_},1,[]}}],[]}},_],
+ [{join,merge}]}}, _,{generate,_,{list,_}}],[]} = i(Q),
+ [1,2,1,2] = qlc:e(Q)">>,
+
+ <<"%% X and W occur twice in the pattern of the extra join handle.
+ Q = qlc:q([{Z,W} ||
+ {X,Z,X} <- [{1,2,1},{1,2,2}],
+ {W,Y,W} <- [{a,1,a}],
+ X =:= Y]),
+ [{2,a}] = qlc:e(Q)">>
+
+ ],
+ ?line run(Config, Ts),
+
+ %% Small examples. Returning an error term.
+ ETs = [
+ <<"F = fun(M) ->
+ qlc:q([{XX,YY} ||
+ {XX,X} <- [{a,1},{b,2},{bb,2},{c,3},{cc,3}],
+ {Y,YY} <- [{0,a},{1,a},{1,aa},{2,b},{2,bb},{2,bbb},
+ {3,c},{3,cc}],
+ X =:= Y],
+ {join,M})
+ end,
+ R = qlc:e(F(nested_loop)),
+ R = qlc:e(F(merge))">>,
+
+ <<"F = fun(M) ->
+ qlc:q([{XX,YY} ||
+ {XX,X} <- [{a,1},{b,2},{bb,2},{c,3},{cc,3}],
+ {Y,YY} <- [{0,a},{1,a},{1,aa},{2,b},{2,bb},{2,bbb},
+ {4,d}],
+ X =:= Y],
+ {join,M})
+ end,
+ R = qlc:e(F(nested_loop)),
+ R = qlc:e(F(merge))">>,
+
+ <<"Q = qlc:q([{XX,YY} ||
+ {XX,X} <- [{b,1},{c,3}],
+ {Y,YY} <- [{1,a}],
+ X =:= Y],
+ {join,merge}),
+ [{b,a}] = qlc:e(Q)">>,
+
+ <<"Q = qlc:q([{XX,YY} ||
+ {XX,X} <- [{b,1},{c,3}],
+ {Y,YY} <- qlc_SUITE:table_error([{1,a}], 1, err),
+ X =:= Y],
+ {join,merge}),
+ err = qlc:e(Q)">>,
+
+ <<"Q = qlc:q([{XX,YY} ||
+ {XX,X} <- [{a,1},{aa,1}],
+ {Y,YY} <- [{1,a}],
+ X =:= Y],
+ {join,merge}),
+ [{a,a},{aa,a}] = qlc:e(Q)">>,
+
+ <<"Q = qlc:q([{XX,YY} ||
+ {XX,X} <- qlc_SUITE:table_error([{a,1},{aa,1}],
+ 2, err),
+ {Y,YY} <- [{1,a}],
+ X =:= Y],
+ {join,merge}),
+ err = qlc:e(Q)">>,
+
+ <<"Q = qlc:q([{XX,YY} ||
+ {XX,X} <- [{a,1}],
+ {Y,YY} <- [{1,a},{1,aa}],
+ X =:= Y],
+ {join,merge}),
+ [{a,a},{a,aa}]= qlc:e(Q)">>,
+
+ <<"Q = qlc:q([{XX,YY} ||
+ {XX,X} <- qlc_SUITE:table_error([{a,1}], 2, err),
+ {Y,YY} <- [{1,a},{1,aa}],
+ X =:= Y],
+ {join,merge}),
+ C = qlc:cursor(Q),
+ [{a,a}] = qlc:next_answers(C, 1),
+ qlc:delete_cursor(C),
+ err = qlc:e(Q)">>,
+
+ <<"F = fun(M) ->
+ qlc:q([{XX,YY} ||
+ {XX,X} <- [{a,1},{b,2},{bb,2},{c,3},{cc,3}],
+ {Y,YY} <- [{0,a},{1,a},{1,aa},{2,b},
+ {2,bb},{2,bbb}],
+ X =:= Y],
+ {join,M})
+ end,
+ %% [{a,a},{a,aa},{b,b},{b,bb},{b,bbb},{bb,b},{bb,bb},{bb,bbb}]
+ R = qlc:e(F(nested_loop)),
+ R = qlc:e(F(merge))">>,
+
+
+ <<"F = fun(M) ->
+ qlc:q([{XX,YY} ||
+ {XX,X} <- [{a,1},{b,2},{bb,2},{c,3},{cc,3}],
+ {Y,YY} <- qlc_SUITE:table_error([{0,a},{1,a},{1,aa},
+ {2,b},{2,bb},
+ {2,bbb}],
+ 1, err),
+ X =:= Y],
+ {join,M})
+ end,
+ %% [{a,a},{a,aa},{b,b},{b,bb},{b,bbb},{bb,b},{bb,bb},{bb,bbb}]
+ err = qlc:e(F(nested_loop)),
+ err = qlc:e(F(merge))">>,
+
+ <<"Q = qlc:q([{XX,YY} ||
+ {XX,X} <- qlc_SUITE:table_error([], 2, err),
+ {Y,YY} <- [{2,b},{3,c}],
+ X =:= Y],
+ {join,merge}),
+ err = qlc:e(Q)">>,
+
+ <<"Q = qlc:q([{XX,YY} ||
+ {XX,X} <- [{a,1},{c,3}],
+ {Y,YY} <- [{2,b},{3,c}],
+ X =:= Y],
+ {join,merge}),
+ [{c,c}] = qlc:e(Q)">>,
+
+ <<"Q = qlc:q([{XX,YY} ||
+ {XX,X} <- [{a,1},{aa,1}],
+ {Y,YY} <- [{1,a},{1,aa}],
+ X =:= Y],
+ {join,merge}),
+ [{a,a},{a,aa},{aa,a},{aa,aa}] = qlc:e(Q)">>,
+
+ <<"Q = qlc:q([{XX,YY} ||
+ {XX,X} <- [{a,1},{b,2}],
+ {Y,YY} <- [{1,a},{1,aa}],
+ X =:= Y],
+ {join,merge}),
+ [{a,a},{a,aa}] = qlc:e(Q)">>,
+
+ <<"Q = qlc:q([{XX,YY} ||
+ {XX,X} <- [{a,1},{b,2}],
+ {Y,YY} <- qlc_SUITE:table_error([{1,a},{1,aa}],
+ 1, err),
+ X =:= Y],
+ {join,merge}),
+ err = qlc:e(Q)">>,
+
+ <<"Q = qlc:q([{XX,YY} ||
+ {XX,X} <- [{a,1},{b,2}],
+ {Y,YY} <- [{1,a},{1,aa},{1,aaa},{1,aaaa}],
+ X =:= Y],
+ {join,merge}),
+ [{a,a},{a,aa},{a,aaa},{a,aaaa}]= qlc:e(Q)">>,
+
+ <<"Q = qlc:q([{element(1, X), element(2, Y)} ||
+ X <- [{a,1},{aa,1}],
+ Y <- [{1,a},{1,aa}],
+ element(2, X) =:= element(1, Y)],
+ {join,merge}),
+ [{a,a},{a,aa},{aa,a},{aa,aa}] = qlc:e(Q)">>,
+
+ <<"Q = qlc:q([{element(1, X), element(2, Y)} ||
+ X <- [{a,1},{aa,1}],
+ Y <- qlc_SUITE:table_error([], 1, err),
+ element(2, X) =:= element(1, Y)],
+ {join,merge}),
+ err = qlc:e(Q)">>,
+
+ <<"Q = qlc:q([{element(1, X), element(2, Y)} ||
+ X <- qlc_SUITE:table_error([{a,1}], 2, err),
+ Y <- [{2,b}],
+ element(2, X) =:= element(1, Y)],
+ {join,merge}),
+ err = qlc:e(Q)">>,
+
+ <<"Q = qlc:q([{XX,YY} ||
+ {XX,X} <- [{1,a},{'1b',b},{2,b}],
+ {Y,YY} <- [{a,1},{b,'1b'},{c,1}],
+ X == Y],
+ {join,merge}),
+ [{1,1},{'1b','1b'},{2,'1b'}] = qlc:e(Q)">>,
+
+ <<"Q = qlc:q([{XX,YY} ||
+ {XX,X} <- qlc_SUITE:table_error([{1,a},{'1b',b},{2,b}],
+ 2, err),
+ {Y,YY} <- [{a,1},{b,'1b'},{c,1}],
+ X == Y],
+ {join,merge}),
+ err = qlc:e(Q)">>
+
+ ],
+ ?line run(Config, ETs),
+
+ %% Mostly examples where temporary files are needed while merging.
+ FTs = [
+ <<"L1 = [{Y,a} || Y <- lists:seq(1, 2)],
+ L2 = [{a,Y} || Y <- lists:seq(1, 10000)],
+ F = fun(J) ->
+ qlc:q([{XX,YY} ||
+ {XX,X} <- L1,
+ {Y,YY} <- L2,
+ X == Y],
+ {join,J})
+ end,
+ Qm = F(merge),
+ Qn = F(nested_loop),
+ true = qlc:e(Qm,{max_list_size, 0}) =:= qlc:e(Qn)">>,
+
+ <<"L1 = [{Y,a} || Y <- lists:seq(1, 2)],
+ L2 = [{a,Y} || Y <- lists:seq(1, 10000)],
+ Q = qlc:q([{XX,YY} ||
+ {XX,X} <- L1,
+ {Y,YY} <- L2,
+ X == Y],
+ {join,merge}),
+ {error,_,{file_error,_,_}} =
+ qlc:e(Q, [{max_list_size,64*1024},{tmpdir,\"/a/b/c\"}])">>,
+
+ <<"L1 = qlc_SUITE:table_error([{1,a},{2,a}], 2, err),
+ L2 = [{a,Y} || Y <- lists:seq(1, 10000)],
+ F = fun(J) ->
+ qlc:q([{XX,YY} ||
+ {XX,X} <- L1,
+ {Y,YY} <- L2,
+ X == Y],
+ {join,J})
+ end,
+ Qm = F(merge),
+ Qn = F(nested_loop),
+ err = qlc:e(Qm, {max_list_size,64*1024}),
+ err = qlc:e(Qn)">>,
+
+ <<"L1 = [{Y,a} || Y <- lists:seq(1, 2)],
+ L2 = qlc_SUITE:table_error([{a,Y} || Y <- lists:seq(1, 10000)],
+ 1, err),
+ F = fun(J) ->
+ qlc:q([{XX,YY} ||
+ {XX,X} <- L1,
+ {Y,YY} <- L2,
+ X == Y],
+ {join,J})
+ end,
+ Qm = F(merge),
+ Qn = F(nested_loop),
+ err = qlc:e(Qm, {max_list_size,64*1024}),
+ err = qlc:e(Qn)">>,
+
+ <<"L1 = [{Y,a} || Y <- lists:seq(1, 2)] ++
+ [{'1b',b},{2,b}] ++ [{Y,d} || Y <- lists:seq(1, 2)],
+ L2 = [{a,Y} || Y <- lists:seq(1, 10000)] ++
+ [{b,'1b'}] ++ [{c,1}] ++ [{d,Y} || Y <- lists:seq(1, 10000)],
+ F = fun(J) ->
+ qlc:q([{XX,YY} ||
+ {XX,X} <- L1,
+ {Y,YY} <- L2,
+ X == Y],
+ {join,J})
+ end,
+ Qm = F(merge),
+ Qn = F(nested_loop),
+ true = lists:sort(qlc:e(Qm, {max_list_size,64*1024})) =:=
+ lists:sort(qlc:e(Qn))">>,
+
+ <<"F = fun(J) ->
+ qlc:q([{XX,YY} ||
+ {XX,X} <- [{Y,a} || Y <- lists:seq(1, 2)],
+ {Y,YY} <- [{a,Y} || Y <- lists:seq(1,100000)],
+ X == Y],
+ {join,J})
+ end,
+ Qm = F(merge),
+ Qn = F(nested_loop),
+ true = qlc:e(Qm, {max_list_size,64*1024}) =:= qlc:e(Qn)">>,
+
+ %% More than one join in one QLC expression.
+ <<"L1 = [{Y,a} || Y <- lists:seq(1, 2)],
+ L2 = [{a,Y} || Y <- lists:seq(1, 10000)],
+ F = fun(J) ->
+ Q = qlc:q([{XX,YY} ||
+ {XX,X} <- L1,
+ {Y,YY} <- L2,
+ X == Y,
+ begin XX > 1 end,
+ begin YY > 9999 end],
+ {join,J}),
+ qlc:q([{XX1,YY1,XX2,YY2} ||
+ {XX1,YY1} <- Q,
+ {XX2,YY2} <- Q])
+ end,
+ Qm = F(merge),
+ Qn = F(nested_loop),
+ R1 = lists:sort(qlc:e(Qm, {max_list_size,64*1024})),
+ R2 = lists:sort(qlc:e(Qm, {max_list_size,1 bsl 31})),
+ true = R1 =:= lists:sort(qlc:e(Qn)),
+ true = R1 =:= R2">>,
+
+ <<"L1 = [{Y,a} || Y <- lists:seq(1, 2)],
+ L2 = [{a,Y} || Y <- lists:seq(1, 10000)],
+ F = fun(J) ->
+ Q = qlc:q([{XX,YY} ||
+ {XX,X} <- L1,
+ {Y,YY} <- L2,
+ X == Y,
+ begin XX > 1 end,
+ begin YY > 9999 end],
+ {join,J}),
+ qlc:q([{XX1,YY1,XX2,YY2} ||
+ {XX1,YY1} <- Q,
+ {XX2,YY2} <- Q,
+ throw(thrown)])
+ end,
+ Qm = F(merge),
+ thrown = (catch {any_term, qlc:e(Qm, {max_list_size,64*1024})})">>,
+
+ <<"%% Bigger than 64*1024.
+ T1 = {1, lists:seq(1, 20000)},
+ L1 = [{a,T1},{b,T1}],
+ L2 = [{T1,a},{T1,b}],
+ F = fun(J) ->
+ qlc:q([{XX,YY} ||
+ {XX,X} <- L1,
+ {Y,YY} <- L2,
+ X == Y],
+ {join,J})
+ end,
+ Qm = F(merge),
+ Qn = F(nested_loop),
+ R = [{a,a},{a,b},{b,a},{b,b}],
+ R = qlc:e(Qm, {max_list_size,64*1024}),
+ R = qlc:e(Qn)">>,
+
+ <<"%% Bigger than 64*1024. No temporary files.
+ T1 = {1, lists:seq(1, 20000)},
+ L1 = [{a,T1},{b,T1}],
+ L2 = [{T1,a},{T1,b}],
+ F = fun(J) ->
+ qlc:q([{XX,YY} ||
+ {XX,X} <- L1,
+ {Y,YY} <- L2,
+ X == Y],
+ {join,J})
+ end,
+ Qm = F(merge),
+ Qn = F(nested_loop),
+ R = [{a,a},{a,b},{b,a},{b,b}],
+ R = qlc:e(Qm, {max_list_size,1 bsl 31}),
+ R = qlc:e(Qn)">>
+
+
+ ],
+ ?line run(Config, FTs),
+
+ ok.
+
+join_sort(doc) ->
+ "Merge join optimizations (avoid unnecessary sorting).";
+join_sort(suite) -> [];
+join_sort(Config) when is_list(Config) ->
+ Ts = [
+ <<"H1_1 = qlc:keysort(1, [{1,2,3},{4,5,6}]),
+ H1 = qlc:q([X || X <- H1_1], unique),
+ H2 = qlc:keysort(2, [{1,2},{3,4}]),
+ H3 = qlc:q([{X,Y} || {X,_,_} <- H1,
+ {_,Y} <- H2,
+ X =:= Y]),
+ {1,0,0,2} = join_info(H3),
+ [{4,4}] = qlc:e(H3)">>,
+
+ <<"H1_1 = qlc:keysort(1, [{1,2,3},{4,5,6}]),
+ H1 = qlc:q([X || X <- H1_1], unique), % keeps the order
+ H2 = qlc:keysort(2, [{1,2},{3,4}]),
+ H3 = qlc:q([{X,Y} || {X,_,_} <- H1, % no extra keysort
+ {Y,_} <- H2, % an extra keysort
+ X =:= Y]),
+ {1,0,0,3} = join_info(H3),
+ [{1,1}] = qlc:e(H3)">>,
+
+ <<"H1_1 = qlc:keysort(1, [{1,2,3},{4,5,6}], {tmpdir,\"\"}),
+ H1 = qlc:q([X || X <- H1_1], unique),
+ H2 = qlc:keysort(2, [{1,2},{3,4}]),
+ H3 = qlc:q([{X,Y} || {_,X,_} <- H1,
+ {_,Y} <- H2,
+ X =:= Y]),
+ {1,0,0,3} = join_info(H3),
+ [{2,2}] = qlc:e(H3)">>,
+
+ <<"H1_1 = qlc:keysort(1, [{1,2,3},{4,5,6}], {tmpdir,\"\"}),
+ H1 = qlc:q([X || X <- H1_1], unique),
+ H2 = qlc:keysort(2, [{1,2},{3,4}]),
+ H3 = qlc:q([{X,Y} || {_,X,_} <- H1,
+ {_,Y} <- H2,
+ X =:= Y]),
+ {1,0,0,3} = join_info(H3),
+ [{2,2}] = qlc:e(H3)">>,
+
+ <<"H1 = qlc:sort([{1,a},{2,b},{3,c}]),
+ %% Since H1 is sorted it is also keysorted on the first column.
+ Q = qlc:q([{X, Y} || {X,_} <- H1,
+ {Y} <- [{0},{1},{2}],
+ X == Y]),
+ {1,0,0,1} = join_info(Q),
+ [{1,1},{2,2}] = qlc:e(Q)">>,
+
+ <<"H1 = qlc:sort([{r,a,1},{r,b,2},{r,c,3}]),
+ Q = qlc:q([{X, Y} || {r,_,X} <- H1, % needs keysort(3)
+ {Y} <- [{0},{1},{2}],
+ X == Y]),
+ {1,0,0,2} = join_info(Q),
+ [{1,1},{2,2}] = qlc:e(Q)">>,
+
+ <<"QH = qlc:q([X || X <- [{1,2,3},{4,5,6}],
+ Y <- qlc:sort([{1,2},{3,4}]),
+ element(1, X) =:= element(2, Y)]),
+ {1,0,0,2} = join_info_count(QH),
+ [{4,5,6}] = qlc:e(QH)">>,
+
+ <<"H1_1 = qlc:keysort(1, [{1,2,3},{4,5,6},{1,2,3}]),
+ H1 = qlc:q([X || X <- H1_1], unique),
+ H2 = qlc:keysort(2, [{2,1},{3,4}]),
+ H3 = qlc:q([{X,Y} || {X,_,_} <- H1,
+ {_,Y} <- H2,
+ X =:= Y]),
+ H4 = qlc:keysort(1, [{1,2},{3,4},{4,a}]),
+ H5 = qlc:q([{X,Y} || {X,_} <- H4,
+ {_,Y} <- H3,
+ X =:= Y]),
+ {2,0,0,3} = join_info_count(H5),
+ [{1,1},{4,4}]= qlc:e(H5)">>,
+
+ <<"
+ H1 = qlc:keysort(2, [{1,a,u},{2,b,k},{3,c,l}]),
+ H2 = qlc:q([{a,X,Y,a} || {1,X,u} <- H1,
+ {2,Y,k} <- H1]),
+ %% Neither H1 nor H2 need to be key-sorted
+ %% (the columns are constant).
+ H3 = qlc:q([{A,B,C,D,E,F,G,H} ||
+ {A,B,C,D} <- H2,
+ {E,F,G,H} <- H2,
+ A =:= H],
+ {join,merge}),
+ {1,0,0,4} = join_info_count(H3),
+ [{a,a,b,a,a,a,b,a}] = qlc:e(H3)">>,
+
+ <<"%% Q1 is sorted on X or Y.
+ Q1 = qlc:q([{X,Y} ||
+ {X,_} <- qlc:keysort(1, [{1,a},{2,b}]),
+ {_,Y} <- qlc:keysort(2, [{aa,11},{bb,22}]),
+ X < Y]),
+ [{1,11},{1,22},{2,11},{2,22}] = qlc:e(Q1),
+ Q = qlc:q([{X,Y} ||
+ {X,_} <- Q1, % no need to sort Q1
+ {Y} <- [{0},{1},{2},{3}],
+ X =:= Y]),
+ {1,0,0,3} = join_info_count(Q),
+ [{1,1},{1,1},{2,2},{2,2}] = qlc:e(Q)">>,
+
+ <<"H1 = qlc:keysort([2], [{r,1},{r,2},{r,3}]),
+ %% H1 is actually sorted, but this info is not captured.
+ Q = qlc:q([{X, Y} || {r,X} <- H1,
+ {Y} <- [{0},{1},{2}],
+ X == Y]),
+ {1,0,0,2} = join_info_count(Q),
+ [{1,1},{2,2}] = qlc:e(Q)">>,
+
+ <<"%% Two leading constants columns and sorted objects
+ %% implies keysorted on column 3.
+ H1 = qlc:sort(qlc:q([{a,X,Y} || {X,Y} <- [{1,2},{2,3},{3,3}]])),
+ H2 = qlc:q([{X,Y} ||
+ {a,3,X} <- H1,
+ {a,2,Y} <- H1,
+ X =:= Y]),
+ {1,0,0,0} = join_info_count(H2),
+ [{3,3}] = qlc:e(H2)">>,
+
+ <<"QH = qlc:q([{X,Y} || {X,Y} <- [{1,4},{1,3}],
+ {Z} <- [{1}],
+ X =:= Z, (Y =:= 3) or (Y =:= 4)]),
+ {1,0,0,1} = join_info_count(QH),
+ [{1,4},{1,3}] = qlc:e(QH)">>,
+
+ <<"E = ets:new(join, [ordered_set]),
+ true = ets:insert(E, [{1,a},{2,b},{3,c}]),
+ Q = qlc:q([{X, Y} || {X,_} <- ets:table(E), % no need to sort
+ {Y} <- [{0},{1},{2}],
+ X == Y], {join,merge}),
+ {1,0,0,1} = join_info(Q),
+ [{1,1},{2,2}] = qlc:e(Q),
+ ets:delete(E)">>,
+
+ <<"H1 = qlc:sort([{r,1,a},{r,2,b},{r,3,c}]),
+ Q = qlc:q([{X, Y} || {r,X,_} <- H1, % does not need keysort(3)
+ {Y} <- [{0},{1},{2}],
+ X == Y]),
+ {1,0,0,1} = join_info(Q),
+ [{1,1},{2,2}] = qlc:e(Q)">>,
+
+ <<"H1 = qlc:keysort(2,[{r,1},{r,2},{r,3}]),
+ H2 = [{a},{b}],
+ %% Several columns in different qualifiers have initial
+ %% constant columns.
+ H3 = qlc:keysort(1,[{c1,c2,1},{foo,bar,2},{c1,c2,3},{c1,c2,2}]),
+ Q = qlc:q([{r,X,Y,Z} || {r,X} <- H1,
+ {Y} <- H2,
+ {c1,c2,Z} <- H3,
+ X =:= Z], {join,merge}),
+ {1,0,0,3} = join_info(Q),
+ [{r,1,a,1},{r,1,b,1},{r,2,a,2},{r,2,b,2},{r,3,a,3},{r,3,b,3}] =
+ qlc:e(Q)">>,
+
+ <<"H1 = qlc:keysort(2,[{r,1},{r,2},{r,3}]),
+ H2 = [{a},{b}],
+ %% As the last one, but one keysort less.
+ H3 = qlc:keysort(3,[{c1,c2,1},{foo,bar,2},{c1,c2,3},{c1,c2,2}]),
+ Q = qlc:q([{r,X,Y,Z} || {r,X} <- H1,
+ {Y} <- H2,
+ {c1,c2,Z} <- H3,
+ X =:= Z], {join,merge}),
+ {1,0,0,2} = join_info(Q),
+ [{r,1,a,1},{r,1,b,1},{r,2,a,2},{r,2,b,2},{r,3,a,3},{r,3,b,3}] =
+ qlc:e(Q)">>,
+
+ <<"H1 = qlc:keysort(2,[{r,1},{r,2},{r,3}]),
+ H2 = [{a},{b}],
+ H3 = qlc:keysort(1,[{c1,c2,1},{foo,bar,2},{c1,c2,3},{c1,c2,2}]),
+ %% One generator before the joined generators.
+ Q = qlc:q([{r,X,Y,Z} || {Y} <- H2,
+ {r,X} <- H1,
+ {c1,c2,Z} <- H3,
+ X =:= Z], {join,merge}),
+ {1,0,0,3} = join_info(Q),
+ [{r,1,a,1},{r,2,a,2},{r,3,a,3},{r,1,b,1},{r,2,b,2},{r,3,b,3}] =
+ qlc:e(Q)">>,
+
+ <<"H1 = [{a,1},{b,2},{c,3},{d,4}],
+ H2 = [{a},{b}],
+ H3 = [{c1,c2,a},{foo,bar,b},{c1,c2,c},{c1,c2,d}],
+ %% A couple of \"extra\" filters and generators.
+ Q = qlc:q([{X,Y,Z} || {X,_} <- H1,
+ {Y} <- H2,
+ X > Y,
+ {c1,c2,Z} <- H3,
+ {W} <- [{a},{b}],
+ W > a,
+ X =:= Z]),
+ {1,0,0,2} = join_info(Q),
+ [{c,a,c},{c,b,c},{d,a,d},{d,b,d}] = qlc:e(Q)">>,
+
+ <<"H1 = qlc:keysort(2,[{r,1},{r,2},{r,3}]),
+ H2 = qlc:sort([{c1,c2,1},{foo,bar,2},{c1,c2,3},{c1,c2,2}]),
+ %% H2 is sorted, no keysort necessary.
+ %% This example shows that the 'filter-part' of the pattern
+ %% ({c1,c2,Z}) should be evaluated _before_ the join.
+ %% Otherwise the objects cannot be assumed to be keysort:ed on the
+ %% third column (if merge join), and lookup-join would lookup
+ %% more keys than necessary.
+ Q = qlc:q([{r,X,Z} || {r,X} <- H1,
+ {c1,c2,Z} <- H2,
+ X =:= Z] ,{join,merge}),
+ {1,0,0,1} = join_info(Q),
+ [{r,1,1},{r,2,2},{r,3,3}] = qlc:e(Q)">>,
+
+ <<"H1 = [{1,a},{2,b},{3,c}],
+ H2 = [{0,0},{1,1},{2,2}],
+ H3 = qlc:q([{A,C,D} ||
+ {A,_B} <- H1,
+ {C,D} <- H2,
+ A == D, C == D]),
+ H4 = [{1,1},{2,2},{3,3}],
+ H5 = qlc:q([{X,Y} ||
+ {X,_,_} <- H3, % no need to sort this one (merge join)
+ {_,Y} <- H4,
+ X == Y]),
+ Q = qlc:q([{X,Y} ||
+ {X,_} <- H5, % no need to sort this one
+ {Y,_} <- H4,
+ X == Y]),
+ {{3,0,0,4},{3,0,0,6}} = join_info(Q),
+ [{1,1},{2,2}] = qlc:e(Q)">>,
+
+ <<"%% There is an extra test (_C1, element(1, X) =:= 1) that is not
+ %% necessary since the match spec does the same check. This can be
+ %% improved upon.
+ Q = qlc:q([{X,Y} ||
+ X <- [{2},{1}],
+ element(1, X) =:= 1,
+ Y=_ <- [{2},{1}],
+ element(1, X) =:= element(1, Y)]),
+ {qlc,_,
+ [{generate,_,{qlc,_,
+ [{generate,_,{qlc,_,
+ [{generate,_,{list,{list,_},_}},
+ _C1],[]}},
+ {generate,_,{qlc,_,
+ [{generate,_,{list,[{2},{1}]}},
+ _C2],[]}},_],
+ [{join,merge}]}},_],[]} = i(Q),
+ {1,0,0,0} = join_info_count(Q),
+ [{{1},{1}}] = qlc:e(Q)">>,
+
+ <<"etsc(fun(E) ->
+ L = [{a,b,a},{c,d,b},{1,2,a},{3,4,b}],
+ Q = qlc:q([P1 || {X,2,Z}=P1 <- ets:table(E),
+ Y <- L,
+ X =:= 1,
+ Z =:= a,
+ P1 =:= Y,
+ X =:= element(1, Y)]),
+ {1,0,0,0} = join_info_count(Q),
+ [{1,2,a}] = qlc:e(Q)
+ end, [{1,2,a},{3,4,b}])">>,
+
+ %% Merge join on Z and element(3, Y). No need to sort!
+ <<"etsc(fun(E) ->
+ L = [{a,b,a},{c,d,b},{1,2,a},{3,4,b}],
+ Q = qlc:q([P1 || {X,2,Z}=P1 <- ets:table(E),
+ Y <- L,
+ (X =:= 1) or (X =:= 2),
+ Z =:= a,
+ P1 =:= Y,
+ X =:= element(1, Y)]),
+ {1,0,0,0} = join_info_count(Q),
+ [{1,2,a}] = qlc:e(Q)
+ end, [{1,2,a},{3,4,b}])">>,
+
+ <<"%% Y is constant as well as X. No keysort, which means that
+ %% Y must be filtered before merge join.
+ etsc(fun(E) ->
+ Q = qlc:q([X || {1,2}=X <- ets:table(E),
+ Y <- [{a,b},{c,d},{1,2},{3,4}],
+ X =:= Y,
+ element(1, X) =:= element(1, Y)]),
+ {1,0,0,0} = join_info_count(Q),
+ [{1,2}] = qlc:e(Q)
+ end, [{1,2},{3,4}])">>
+
+ ],
+ ?line run(Config, Ts),
+ ok.
+
+join_complex(doc) ->
+ "Join of more than two columns.";
+join_complex(suite) -> [];
+join_complex(Config) when is_list(Config) ->
+ Ts = [{three,
+ <<"three() ->
+ L = [],
+ Q = qlc:q([{X,Y,Z} || {X,_} <- L,
+ {_,Y} <- L,
+ {Z,_} <- L,
+ X =:= Y, Y == Z
+ ]),
+ qlc:e(Q).">>,
+ [],
+ {warnings,[{3,qlc,too_complex_join}]}},
+
+ {two,
+ <<"two() ->
+ Q = qlc:q([{X,Y,Z,W} ||
+ {X} <- [],
+ {Y} <- [],
+ {Z} <- [],
+ {W} <- [],
+ X =:= Y,
+ Z =:= W],{join,merge}),
+ qlc:e(Q).">>,
+ [],
+ {warnings,[{2,qlc,too_many_joins}]}}
+ ],
+
+ ?line compile(Config, Ts),
+
+ Ts2 = [{three,
+ <<"three() ->
+ L = [],
+ Q = qlc:q([{X,Y,Z} || {X,_} <- L,
+ {_,Y} <- L,
+ {Z,_} <- L,
+ X =:= Y, Y == Z
+ ]),
+ qlc:e(Q).">>,
+ [],
+ {[],
+ ["cannot handle join of three or more generators efficiently"]}},
+
+ {two,
+ <<"two() ->
+ Q = qlc:q([{X,Y,Z,W} ||
+ {X} <- [],
+ {Y} <- [],
+ {Z} <- [],
+ {W} <- [],
+ X =:= Y,
+ Z =:= W],{join,merge}),
+ qlc:e(Q).">>,
+ [],
+ {[],["cannot handle more than one join efficiently"]}}
+ ],
+
+ ?line compile_format(Config, Ts2),
+
+ ok.
+
+tickets(suite) ->
+ [otp_5644, otp_5195, otp_6038_bug, otp_6359, otp_6562, otp_6590,
+ otp_6673, otp_6964, otp_7114, otp_7232, otp_7238, otp_7552, otp_6674,
+ otp_7714].
+
+otp_5644(doc) ->
+ "OTP-5644. Handle the new language element M:F/A.";
+otp_5644(suite) -> [];
+otp_5644(Config) when is_list(Config) ->
+ Ts = [
+ <<"Q = qlc:q([fun modul:mfa/0 || _ <- [1,2],
+ is_function(fun modul:mfa/0, 0)]),
+ [_,_] = qlc:eval(Q)">>
+ ],
+
+ ?line run(Config, Ts),
+ ok.
+
+otp_5195(doc) ->
+ "OTP-5195. Allow traverse functions returning terms.";
+otp_5195(suite) -> [];
+otp_5195(Config) when is_list(Config) ->
+ %% Several minor improvements have been implemented in OTP-5195.
+ %% The test cases are spread all over... except these.
+ %%
+ %% Traverse functions returning terms.
+
+ Ts = [<<"L = [1,2,3],
+ Err = {error,modul,err},
+ H = qlc:q([X || X <- qlc_SUITE:table_error(L, Err)]),
+ Err = qlc:e(H)">>,
+
+ <<"Err = {error,modul,err},
+ TravFun = fun() -> Err end,
+ H1 = qlc:sort(qlc:q([X || X <- qlc:table(TravFun, [])])),
+ H = qlc:q([{X} || X <- H1]),
+ Err = qlc:e(H)">>,
+
+ <<"L = [1,2,3],
+ Err = {error,modul,err},
+ H = qlc:q([X || X <- qlc_SUITE:table_error(L, Err)]),
+ C = qlc:cursor(H),
+ R = qlc:next_answers(C, all_remaining),
+ qlc:delete_cursor(C),
+ Err = R">>,
+
+ <<"L = [1,2,3],
+ Err = {error,modul,err},
+ H = qlc:q([X || X <- qlc_SUITE:table_error(L, Err)]),
+ F = fun(Obj, A) -> A++[Obj] end,
+ Err = qlc:fold(F, [], H)">>,
+
+ <<"Err = {error,modul,err},
+ TravFun = fun() -> Err end,
+ H1 = qlc:sort(qlc:q([X || X <- qlc:table(TravFun, [])])),
+ H = qlc:q([{X} || X <- H1]),
+ F = fun(Obj, A) -> A++[Obj] end,
+ Err = qlc:fold(F, [], H)">>,
+
+ <<"Q1 = qlc:append([qlc:append([ugly()]),[3]]),
+ Q = qlc:q([X || X <- Q1]),
+ 42 = qlc:e(Q),
+ ok.
+
+ ugly() ->
+ [apa | fun() -> 42 end].
+ foo() -> bar">>,
+
+ <<"L = [1,2,3],
+ Err = {error,modul,err},
+ H = qlc:q([X || X <- qlc_SUITE:table_error(L, Err)]),
+ H1 = qlc:q([X || X <- H], unique),
+ Err = qlc:e(H1)">>,
+
+ <<"Err = {error, module, err},
+ L = [1,2,3],
+ H1 = qlc:q([{X} || X <- qlc_SUITE:table_error(L, Err)]),
+ H = qlc:q([{X,Y,Z} || X <- H1, Y <- H1, Z <- L], cache),
+ qlc:e(H, cache_all)">>,
+
+ <<"Err = {error, module, err},
+ L = [1,2,3],
+ H1 = qlc:q([X || X <- qlc_SUITE:table_error(L, Err)]),
+ H = qlc:q([{X,Y,Z} || X <- H1, Y <- H1, Z <- L], cache),
+ qlc:e(H, [cache_all,unique_all])">>,
+
+ <<"L = [{1},{2},{3}],
+ H = qlc:q([X || {X} <- qlc_SUITE:table_lookup_error(L),
+ X =:= 2]),
+ {error, lookup, failed} = qlc:e(H)">>,
+
+ %% The traverse function can return any value, but it must not
+ %% return an improper list. Improper lists must not be given anyway.
+ <<"{'EXIT', {{badfun,a},_}} =
+ (catch qlc:e(qlc:q([{X} || X <- [1 | a], begin true end])))">>
+
+ ],
+
+ ?line run(Config, Ts),
+
+ Ts2 = [<<"Q = qlc:q([{X,Y} || {X} <- [{1},{2},{3}],
+ begin
+ %% Used to generate a badly formed file
+ Y = 3, true
+ end,
+ X =:= Y]),
+ [{3,3}] = qlc:e(Q)">>],
+ ?line run(Config, Ts2),
+
+ ok.
+
+otp_6038_bug(doc) ->
+ "OTP-6038. Bug fixes: unique and keysort; cache.";
+otp_6038_bug(suite) -> [];
+otp_6038_bug(Config) when is_list(Config) ->
+ %% The 'unique' option can no longer be merged with the keysort options.
+ %% This used to return [{1,a},{1,c},{2,b},{2,d}], but since
+ %% file_sorter:keysort now removes duplicates based on keys, the
+ %% correct return value is [{1,a},{2,b}].
+ Ts = [<<"H1 = qlc:q([X || X <- [{1,a},{2,b},{1,c},{2,d}]], unique),
+ H2 = qlc:keysort(1, H1, [{unique,true}]),
+ [{1,a},{2,b}] = qlc:e(H2)">>],
+
+ ?line run(Config, Ts),
+
+ %% Sometimes the cache options did not empty the correct tables.
+ CTs = [
+ <<"Options = [cache,unique],
+ V1 = qlc:q([{X,Y} || X <- [1,2], Y <- [3]], Options),
+ V2 = qlc:q([{X,Y} || X <- [a,b], Y <- V1]),
+ V3 = qlc:q([{X,Y} || X <- [5,6], Y <- [7]], Options),
+ Q = qlc:q([{X,Y} || X <- V2, Y <- V3]),
+ R = qlc:e(Q),
+ L1 = [{X,Y} || X <- [1,2], Y <- [3]],
+ L2 = [{X,Y} || X <- [a,b], Y <- L1],
+ L3 = [{X,Y} || X <- [5,6], Y <- [7]],
+ L = [{X,Y} || X <- L2, Y <- L3],
+ true = R =:= L">>,
+ <<"Options = [cache,unique],
+ V1 = qlc:q([{X,Y} || X <- [1,2], Y <- [3]], Options),
+ V2 = qlc:q([{X,Y} || X <- [a,b], Y <- V1]),
+ V3 = qlc:q([{X,Y} || X <- [5,6], Y <- [7]], Options),
+ V4 = qlc:q([{X,Y} || X <- V2, Y <- V3], Options),
+ Q = qlc:q([{X,Y} || X <- [1,2], Y <- V4]),
+ R = qlc:e(Q),
+ L1 = [{X,Y} || X <- [1,2], Y <- [3]],
+ L2 = [{X,Y} || X <- [a,b], Y <- L1],
+ L3 = [{X,Y} || X <- [5,6], Y <- [7]],
+ L4 = [{X,Y} || X <- L2, Y <- L3],
+ L = [{X,Y} || X <- [1,2], Y <- L4],
+ true = R =:= L">>
+ ],
+ ?line run(Config, CTs),
+
+ ok.
+
+otp_6359(doc) ->
+ "OTP-6359. dets:select() never returns the empty list.";
+otp_6359(suite) -> [];
+otp_6359(Config) when is_list(Config) ->
+ dets:start(),
+ T = luna,
+ Fname = filename(T, Config),
+
+ Ts = [
+ [<<"T = luna, Fname = \"">>, Fname, <<"\",
+ {ok, _} = dets:open_file(T, [{file,Fname}]),
+ Q = qlc:q([F ||
+ F <- dets:table(T),
+ (F band ((1 bsl 0)) =/= 0),
+ true]),
+ [] = qlc:eval(Q),
+ ok = dets:close(T),
+ file:delete(\"">>, Fname, <<"\"),
+ ok">>]
+ ],
+
+ ?line run(Config, Ts),
+ ok.
+
+otp_6562(doc) ->
+ "OTP-6562. compressed = false (should be []) when sorting before join.";
+otp_6562(suite) -> [];
+otp_6562(Config) when is_list(Config) ->
+ Bug = [
+ %% This example uses a file to sort E2 on the second column. It is
+ %% not easy to verify that this happens; the file_sorter module's
+ %% size option cannot be set in this case. But it is not likely
+ %% that the default size (512 KiB) will ever change, so it should
+ %% be future safe.
+ <<"E1 = create_ets(1, 10),
+ E2 = create_ets(5, 150000),
+ Q = qlc:q([{XX,YY} ||
+ {X,XX} <- ets:table(E1),
+ {YY,Y} <- ets:table(E2),
+ X == Y],
+ {join,merge}),
+ [{5,5},{6,6},{7,7},{8,8},{9,9},{10,10}] = qlc:e(Q),
+ ets:delete(E1),
+ ets:delete(E2)">>
+ ],
+ ?line run(Config, Bug),
+
+ Bits = [
+ {otp_6562_1,
+ <<"otp_6562_1() ->
+ Q = qlc:q([X || <<X:8>> <= <<\"hej\">>]),
+ qlc:info(Q).
+ ">>,
+ [],
+ {errors,[{2,qlc,binary_generator}],
+ []}}
+ ],
+ ?line [] = compile(Config, Bits),
+
+ ?line R1 = {error,qlc,{1,qlc,binary_generator}}
+ = qlc:string_to_handle("[X || <<X:8>> <= <<\"hej\">>]."),
+ ?line "1: cannot handle binary generators\n" =
+ lists:flatten(qlc:format_error(R1)),
+
+ ok.
+
+otp_6590(doc) ->
+ "OTP-6590. Bug fix (join info).";
+otp_6590(suite) -> [];
+otp_6590(Config) when is_list(Config) ->
+ Ts = [<<"fun(Tab1Value) ->
+ Q = qlc:q([T1#tab1.id || T1 <- [#tab1{id = id1,
+ value = v,
+ tab2_id = id}],
+ T2 <- [#tab2{id = id}],
+ T1#tab1.value =:= Tab1Value,
+ T1#tab1.tab2_id =:= T2#tab2.id]),
+ [id1] = qlc:e(Q)
+ end(v)">>],
+
+ ?line run(Config, <<"-record(tab1, {id, tab2_id, value}).
+ -record(tab2, {id, value}).\n">>, Ts),
+ ok.
+
+otp_6673(doc) ->
+ "OTP-6673. Optimizations and fixes.";
+otp_6673(suite) -> [];
+otp_6673(Config) when is_list(Config) ->
+ Ts_PT =
+ [<<"etsc(fun(E1) ->
+ etsc(fun(E2) ->
+ Q = qlc:q([{A,B,C,D} ||
+ {A,B} <- ets:table(E1),
+ {C,D} <- ets:table(E2),
+ A =:= 2, % lookup
+ B =:= D, % join
+ C =:= g]), % lookup invalidated by join
+ {qlc,_,[{generate,_,
+ {qlc,_,
+ [{generate,_,
+ {qlc,_,[{generate,_,
+ {keysort,
+ {list,{table,_},
+ [{{'$1','$2'},[],['$_']}]},
+ 2,[]}},_],[]}},
+ {generate,_,{qlc,_,
+ [{generate,_,
+ {keysort,{table,_},2,[]}}],
+ []}},_],
+ [{join,merge}]}},_,_],[]} = i(Q),
+ [{2,y,g,y}] = qlc:e(Q)
+ end, [{f,x},{g,y},{h,z}])
+ end,
+ [{1,x},{2,y},{3,z}])">>,
+ <<"etsc(fun(E1) ->
+ etsc(fun(E2) ->
+ Q = qlc:q([{A,B,C,D} ||
+ {A,B} <- ets:table(E1),
+ {C,D} <- ets:table(E2),
+ A =:= 2, % lookup
+ C =:= g, % lookup
+ B =:= D]), % join
+ {qlc,_,[{generate,_,
+ {qlc,_,
+ [{generate,_,
+ {qlc,_,[{generate,_,
+ {keysort,
+ {list,{table,_},
+ [{{'$1','$2'},[],['$_']}]},
+ 2,[]}},_],[]}},
+ {generate,_,{qlc,_,
+ [{generate,_,
+ {keysort,
+ {list,{table,_},
+ [{{'$1','$2'},[],['$_']}]},
+ 2,[]}},_],[]}},_],
+ [{join,merge}]}},_],[]} = i(Q),
+ [{2,y,g,y}] = qlc:e(Q)
+ end, [{f,x},{g,y},{h,z}])
+ end,
+ [{1,x},{2,y},{3,z}])">>],
+
+ ?line run(Config, Ts_PT),
+
+ MS = ets:fun2ms(fun({X,_Y}=T) when X > 1 -> T end),
+ Ts_RT = [
+ [<<"%% Explicit match-spec. ets:table() ensures there is no lookup
+ %% function, which means that lookup join will not be considered.
+ MS = ">>, io_lib:format("~w", [MS]), <<",
+ etsc(fun(E) ->
+ F = fun(J) ->
+ qlc:q([{X,W} ||
+ {X,_Y} <-
+ ets:table(E,{traverse,
+ {select,MS}}),
+ {Z,W} <- [{1,1},{2,2},{3,3}],
+ X =:= Z], {join,J})
+ end,
+ Qm = F(any),
+ [{2,2},{3,3}] = qlc:e(Qm),
+ {'EXIT',{cannot_carry_out_join,_}} =
+ (catch qlc:e(F(lookup)))
+ end, [{1,a},{2,b},{3,c}])">>],
+
+ <<"%% The filter 'A =< y' can be evaluated by traversing E1 using a
+ %% match specification, but then lookup join cannot use E1 for
+ %% looking up keys. This example shows that the filter is kept if
+ %% lookup join is employed (otherwise it is optimized away since
+ %% the match spec is used).
+ etsc(fun(E1) ->
+ Q = qlc:q([{A,B,C,D} ||
+ {A,B} <- ets:table(E1),
+ {C,D} <- [{x,f},{y,g},{z,h}],
+ A =< y, % kept
+ A =:= C], {join,lookup}),
+ [{x,1,x,f},{y,2,y,g}] = lists:sort(qlc:e(Q))
+ end, [{x,1},{y,2},{z,3}])">>
+
+ ],
+ ?line run(Config, Ts_RT),
+
+ %% Ulf Wiger provided a patch that makes QLC work with packages:
+ Dir = filename:join(?privdir, "p"),
+ ?line ok = filelib:ensure_dir(filename:join(Dir, ".")),
+ File = filename:join(Dir, "p.erl"),
+ ?line ok = file:write_file(File,
+ <<"-module(p.p).\n"
+ "-export([q/0]).\n"
+ "-include_lib(\"stdlib/include/qlc.hrl\").\n"
+ "q() ->\n"
+ " .qlc:q([X || X <- [1,2]]).">>),
+ ?line {ok, 'p.p'} = compile:file(File, [{outdir,Dir}]),
+ ?line code:purge('p.p'),
+ ?line {module, 'p.p'} = code:load_abs(filename:rootname(File), 'p.p'),
+ ?line [1,2] = qlc:e(p.p:q()),
+
+ ok.
+
+otp_6964(doc) ->
+ "OTP-6964. New option 'tmpdir_usage'.";
+otp_6964(suite) -> [];
+otp_6964(Config) when is_list(Config) ->
+ T1 = [
+ <<"Q1 = qlc:q([{X} || X <- [1,2]]),
+ {'EXIT', {badarg,_}} = (catch qlc:e(Q1, {tmpdir_usage,bad})),
+ %% merge join
+ F = fun(Use) ->
+ L1 = [{Y,a} || Y <- lists:seq(1, 2)],
+ L2 = [{a,Y} || Y <- lists:seq(1, 10000)],
+ Q = qlc:q([{XX,YY} ||
+ {XX,X} <- L1,
+ {Y,YY} <- L2,
+ X == Y],
+ {join,merge}),
+ qlc:e(Q, [{max_list_size,64*1024},{tmpdir_usage,Use}])
+ end,
+ D = erlang:system_flag(backtrace_depth, 0),
+ 20000 = length(F(allowed)),
+ ErrReply = F(not_allowed),
+ {error, qlc, {tmpdir_usage,joining}} = ErrReply,
+ \"temporary file was needed for joining\n\" =
+ lists:flatten(qlc:format_error(ErrReply)),
+ qlc_SUITE:install_error_logger(),
+ 20000 = length(F(warning_msg)),
+ {error, joining} = qlc_SUITE:read_error_logger(),
+ 20000 = length(F(info_msg)),
+ {info, joining} = qlc_SUITE:read_error_logger(),
+ 20000 = length(F(error_msg)),
+ {error, joining} = qlc_SUITE:read_error_logger(),
+ _ = erlang:system_flag(backtrace_depth, D),
+ qlc_SUITE:uninstall_error_logger()">>],
+ ?line run(Config, T1),
+
+ T2 = [
+ <<"%% File sorter.
+ T = lists:seq(1, 10000),
+ Q0 = qlc:q([{X} || X <- [T,T,T], begin X > 0 end],
+ [{cache,list},unique]),
+ Q1 = qlc:q([{X,Y,Z} ||
+ X <- Q0,
+ Y <- Q0,
+ Z <- Q0],
+ [{cache,list},unique]),
+ Q = qlc:q([{X, Y} || Y <- [1], X <- Q1]),
+ F = fun(Use) ->
+ qlc:e(Q, [{max_list_size,10000},{tmpdir_usage,Use}])
+ end,
+ 1 = length(F(allowed)),
+ ErrReply = F(not_allowed),
+ {error, qlc, {tmpdir_usage,caching}} = ErrReply,
+ \"temporary file was needed for caching\n\" =
+ lists:flatten(qlc:format_error(ErrReply)),
+ qlc_SUITE:install_error_logger(),
+ 1 = length(F(error_msg)),
+ {error, caching} = qlc_SUITE:read_error_logger(),
+ {error, caching} = qlc_SUITE:read_error_logger(),
+ 1 = length(F(warning_msg)),
+ {error, caching} = qlc_SUITE:read_error_logger(),
+ {error, caching} = qlc_SUITE:read_error_logger(),
+ 1 = length(F(info_msg)),
+ {info, caching} = qlc_SUITE:read_error_logger(),
+ {info, caching} = qlc_SUITE:read_error_logger(),
+ qlc_SUITE:uninstall_error_logger()">>],
+
+ ?line run(Config, T2),
+
+ T3 = [
+ <<"%% sort/keysort
+ E1 = create_ets(1, 10),
+ E2 = create_ets(5, 50000),
+ Q = qlc:q([{XX,YY} ||
+ {X,XX} <- ets:table(E1),
+ {YY,Y} <- ets:table(E2),
+ X == Y],
+ {join,merge}),
+ F = fun(Use) ->
+ qlc:e(Q, {tmpdir_usage,Use})
+ end,
+ ErrReply = F(not_allowed),
+ {error,qlc,{tmpdir_usage,sorting}} = ErrReply,
+ \"temporary file was needed for sorting\n\" =
+ lists:flatten(qlc:format_error(ErrReply)),
+ qlc_SUITE:install_error_logger(),
+ L = [{5,5},{6,6},{7,7},{8,8},{9,9},{10,10}],
+ L = F(allowed),
+ L = F(error_msg),
+ {error, sorting} = qlc_SUITE:read_error_logger(),
+ L = F(info_msg),
+ {info, sorting} = qlc_SUITE:read_error_logger(),
+ L = F(warning_msg),
+ {error, sorting} = qlc_SUITE:read_error_logger(),
+ qlc_SUITE:uninstall_error_logger(),
+ ets:delete(E1),
+ ets:delete(E2)">>],
+ ?line run(Config, T3),
+
+ T4 = [
+ <<"%% cache list
+ etsc(fun(E) ->
+ Q0 = qlc:q([X || X <- ets:table(E),
+ begin element(1, X) > 5 end],
+ {cache,list}),
+ Q = qlc:q([{X, element(1,Y)} || X <- lists:seq(1, 5),
+ Y <- Q0]),
+ R = [{X,Y} || X <- lists:seq(1, 5),
+ Y <- lists:seq(6, 10)],
+ F = fun(Use) ->
+ qlc:e(Q, [{max_list_size, 100*1024},
+ {tmpdir_usage, Use}])
+ end,
+ R = lists:sort(F(allowed)),
+ qlc_SUITE:install_error_logger(),
+ R = lists:sort(F(info_msg)),
+ {info, caching} = qlc_SUITE:read_error_logger(),
+ R = lists:sort(F(error_msg)),
+ {error, caching} = qlc_SUITE:read_error_logger(),
+ R = lists:sort(F(warning_msg)),
+ {error, caching} = qlc_SUITE:read_error_logger(),
+ qlc_SUITE:uninstall_error_logger(),
+ ErrReply = F(not_allowed),
+ {error,qlc,{tmpdir_usage,caching}} = ErrReply,
+ \"temporary file was needed for caching\n\" =
+ lists:flatten(qlc:format_error(ErrReply))
+ end, [{keypos,1}], [{I,a,lists:duplicate(100000,1)} ||
+ I <- lists:seq(1, 10)])">>],
+ ?line run(Config, T4),
+ ok.
+
+otp_7238(doc) ->
+ "OTP-7238. info-option 'depth', &c.";
+otp_7238(suite) -> [];
+otp_7238(Config) when is_list(Config) ->
+ dets:start(),
+ T = otp_7238,
+ Fname = filename(T, Config),
+
+ ?line ok = compile_gb_table(Config),
+
+ %% A few more warnings.
+ T1 = [
+ %% The same error message string, but with different tags
+ %% (the strings are not compared :-(
+ {nomatch_1,
+ <<"nomatch_1() ->
+ {qlc:q([X || X={X} <- []]), [t || \"a\"=\"b\" <- []]}.">>,
+ [],
+ {warnings,[{{2,30},qlc,nomatch_pattern},
+ {{2,44},v3_core,nomatch}]}},
+
+ %% Not found by qlc...
+ {nomatch_2,
+ <<"nomatch_2() ->
+ qlc:q([t || {\"a\"++\"b\"} = {\"ac\"} <- []]).">>,
+ [],
+ {warnings,[{{2,22},v3_core,nomatch}]}},
+
+ {nomatch_3,
+ <<"nomatch_3() ->
+ qlc:q([t || [$a, $b] = \"ba\" <- []]).">>,
+ [],
+ {warnings,[{{2,37},qlc,nomatch_pattern}]}},
+
+ %% Not found by qlc...
+ {nomatch_4,
+ <<"nomatch_4() ->
+ qlc:q([t || \"a\"++_=\"b\" <- []]).">>,
+ [],
+ {warnings,[{{2,22},v3_core,nomatch}]}},
+
+ %% Found neither by the compiler nor by qlc...
+ {nomatch_5,
+ <<"nomatch_5() ->
+ qlc:q([X || X = <<X>> <- [3]]).">>,
+ [],
+ []},
+
+ {nomatch_6,
+ <<"nomatch_6() ->
+ qlc:q([X || X <- [],
+ X =:= {X}]).">>,
+ [],
+ {warnings,[{{3,30},qlc,nomatch_filter}]}},
+
+ {nomatch_7,
+ <<"nomatch_7() ->
+ qlc:q([X || {X=Y,{Y}=X} <- []]).">>,
+ [],
+ {warnings,[{{2,28},qlc,nomatch_pattern}]}},
+
+ {nomatch_8,
+ <<"nomatch_8() ->
+ qlc:q([X || {X={},X=[]} <- []]).">>,
+ [],
+ {warnings,[{{2,28},qlc,nomatch_pattern}]}},
+
+ {nomatch_9,
+ <<"nomatch_9() ->
+ qlc:q([X || X <- [], X =:= {}, X =:= []]).">>,
+ [],
+ {warnings,[{{2,49},qlc,nomatch_filter}]}},
+
+ {nomatch_10,
+ <<"nomatch_10() ->
+ qlc:q([X || X <- [],
+ ((X =:= 1) or (X =:= 2)) and (X =:= 3)]).">>,
+ [],
+ {warnings,[{{3,53},qlc,nomatch_filter}]}},
+
+ {nomatch_11,
+ <<"nomatch_11() ->
+ qlc:q([X || X <- [], x =:= []]).">>,
+ [],
+ {warnings,[{{2,39},qlc,nomatch_filter}]}},
+
+ {nomatch_12,
+ <<"nomatch_12() ->
+ qlc:q([X || X={} <- [], X =:= []]).">>,
+ [],
+ {warnings,[{{2,42},qlc,nomatch_filter}]}},
+
+ {nomatch_13,
+ <<"nomatch_13() ->
+ qlc:q([Z || Z <- [],
+ X={X} <- [],
+ Y={Y} <- []]).">>,
+ [],
+ {warnings,[{{3,29},qlc,nomatch_pattern},
+ {{4,29},qlc,nomatch_pattern}]}},
+
+ {nomatch_14,
+ <<"nomatch_14() ->
+ qlc:q([X || X={X} <- [],
+ 1 > 0,
+ 1 > X]).">>,
+ [],
+ {warnings,[{{2,29},qlc,nomatch_pattern}]}},
+
+ {nomatch_15,
+ <<"nomatch_15() ->
+ qlc:q([{X,Y} || X={X} <- [1],
+ Y <- [1],
+ 1 > 0,
+ 1 > X]).">>,
+ [],
+ {warnings,[{{2,32},qlc,nomatch_pattern}]}},
+
+ %% Template warning.
+ {nomatch_template1,
+ <<"nomatch_template1() ->
+ qlc:q([{X} = {} || X <- []]).">>,
+ [],
+ {warnings,[{2,sys_core_fold,no_clause_match}]}}
+ ],
+ ?line [] = compile(Config, T1),
+
+ %% 'depth' is a new option used by info()
+ T2 = [
+ %% Firstly: lists
+ <<"L = [[a,b,c],{a,b,c},[],<<\"foobar\">>],
+ Q = qlc:q([{X} || X <- L]),
+ {call, _,
+ {remote,_,{atom,_,ets},{atom,_,match_spec_run}},
+ [{cons,_,{atom,_,'...'},
+ {cons,_,{atom,_,'...'},
+ {cons,_,{nil,_},{cons,_,{atom,_,'...'},{nil,_}}}}},
+ _]} = qlc:info(Q, [{format,abstract_code},{depth,0}]),
+
+ {call,_,_,
+ [{cons,_,{cons,_,{atom,_,'...'},{nil,_}},
+ {cons,_,
+ {tuple,_,[{atom,_,'...'}]},
+ {cons,_,{nil,_},
+ {cons,_,
+ {bin,_,
+ [{_,_,{_,_,$.},_,_},
+ {_,_,{_,_,$.},_,_},
+ {_,_,{_,_,$.},_,_}]},
+ {nil,_}}}}},
+ _]} = qlc:info(Q, [{format,abstract_code},{depth,1}]),
+
+ {call,_,
+ _,
+ [{cons,_,{cons,_,{atom,_,a},{atom,_,'...'}},
+ {cons,_,
+ {tuple,_,[{atom,_,a},{atom,_,'...'}]},
+ {cons,_,{nil,_},
+ {cons,_,
+ {bin,_,
+ [{_,_,{_,_,$f},_,_},
+ {_,_,{_,_,$.},_,_},
+ {_,_,{_,_,$.},_,_},
+ {_,_,{_,_,$.},_,_}]},
+ {nil,_}}}}},
+ _]} = qlc:info(Q, [{format,abstract_code},{depth,2}]),
+
+ {call,_,_,
+ [{cons,_,
+ {cons,_,{atom,_,a},{cons,_,{atom,_,b},{atom,_,'...'}}},
+ {cons,_,
+ {tuple,_,[{atom,_,a},{atom,_,b},{atom,_,'...'}]},
+ {cons,_,{nil,_},
+ {cons,_,
+ {bin,_,
+ [{_,_,{_,_,$f},_,_},
+ {_,_,{_,_,$o},_,_},_,_,_]},
+ {nil,_}}}}},
+ _]} = qlc:info(Q, [{format,abstract_code},{depth,3}]),
+
+ {call,_,_,
+ [{cons,_,
+ {cons,_,
+ {atom,_,a},{cons,_,{atom,_,b},{cons,_,{atom,_,c},{nil,_}}}},
+ {cons,_,
+ {tuple,_,[{atom,_,a},{atom,_,b},{atom,_,c}]},
+ {cons,_,{nil,_},
+ {cons,_,
+ {bin,_,
+ [{_,_,{_,_,$f},_,_},
+ {_,_,{_,_,$o},_,_},
+ {_,_,{_,_,$o},_,_},
+ {_,_,{_,_,$b},_,_},
+ {_,_,{_,_,$a},_,_},
+ {_,_,{_,_,$r},_,_}]},
+ {nil,_}}}}},
+ _]} = qlc:info(Q, [{format,abstract_code},{depth,10}]),
+
+ {call,_,_,
+ [{cons,_,
+ {cons,_,
+ {atom,_,a},{cons,_,{atom,_,b},{cons,_,{atom,_,c},{nil,_}}}},
+ {cons,_,
+ {tuple,_,[{atom,_,a},{atom,_,b},{atom,_,c}]},
+ {cons,_,{nil,_},
+ {cons,_,
+ {bin,_,
+ [{_,_,{_,_,$f},_,_},
+ {_,_,{_,_,$o},_,_},
+ {_,_,{_,_,$o},_,_},
+ {_,_,{_,_,$b},_,_},
+ {_,_,{_,_,$a},_,_},
+ {_,_,{_,_,$r},_,_}]},
+ {nil,_}}}}},
+ _]} = qlc:info(Q, [{format,abstract_code},{depth,infinity}])">>,
+
+ %% Secondly: looked up keys
+ <<"F = fun(D) ->
+ etsc(fun(E) ->
+ Q = qlc:q([C || {N,C} <- ets:table(E),
+ (N =:= {2,2}) or (N =:= {3,3})]),
+ F = qlc:info(Q, [{format,abstract_code},{depth,D}]),
+ {call,_,_,[{call,_,_,[_Fun,Values]},_]} = F,
+ [b,c] = lists:sort(qlc:eval(Q)),
+ Values
+ end, [{{1,1},a},{{2,2},b},{{3,3},c},{{4,4},d}])
+ end,
+
+ [{cons,_,{atom,_,'...'},{cons,_,{atom,_,'...'},{nil,_}}},
+ {cons,_,
+ {tuple,_,[{atom,_,'...'}]},
+ {cons,_,{tuple,_,[{atom,_,'...'}]},{nil,_}}},
+ {cons,_,
+ {tuple,_,[{integer,_,2},{atom,_,'...'}]},
+ {cons,_,{tuple,_,[{integer,_,3},{atom,_,'...'}]},{nil,_}}},
+ {cons,_,
+ {tuple,_,[{integer,_,2},{integer,_,2}]},
+ {cons,_,{tuple,_,[{integer,_,3},{integer,_,3}]},{nil,_}}},
+ {cons,_,
+ {tuple,_,[{integer,_,2},{integer,_,2}]},
+ {cons,_,{tuple,_,[{integer,_,3},{integer,_,3}]},{nil,_}}}] =
+ lists:map(F, [0,1,2,3,infinity])">>,
+ [<<"T = otp_7238, Fname = \"">>, Fname, <<"\",
+ {ok, _} = dets:open_file(T, [{file,Fname}]),
+ ok = dets:insert(T, [{{1,1},a},{{2,2},b},{{3,3},c},{{4,4},d}]),
+ Q = qlc:q([C || {N,C} <- dets:table(T),
+ (N =:= {2,2}) or (N =:= {3,3})]),
+ F = qlc:info(Q, [{format,abstract_code},{depth,1}]),
+ [b,c] = lists:sort(qlc:eval(Q)),
+ {call,_,_,
+ [{call,_,_,
+ [_,
+ {cons,_,
+ {tuple,_,[{atom,_,'...'}]},
+ {cons,_,{tuple,_,[{atom,_,'...'}]},{nil,_}}}]},
+ _]} = F,
+ ok = dets:close(T),
+ file:delete(\"">>, Fname, <<"\")">>],
+
+ %% Thirdly: format_fun has been extended (in particular: gb_table)
+ <<"T = gb_trees:from_orddict([{{1,a},w},{{2,b},v},{{3,c},u}]),
+ QH = qlc:q([X || {{X,Y},_} <- gb_table:table(T),
+ ((X =:= 1) or (X =:= 2)),
+ ((Y =:= a) or (Y =:= b) or (Y =:= c))]),
+ {call,_,_,
+ [{call,_,_,
+ [{'fun',_,
+ {clauses,
+ [{clause,_,_,[],
+ [{'case',_,
+ {call,_,_,
+ [_,
+ {call,_,_,
+ [{cons,_,
+ {tuple,_,[{atom,_,'...'}]},
+ {cons,_,
+ {tuple,_,[{atom,_,'...'}]},
+ {cons,_,{tuple,_,[{atom,_,'...'}]},{nil,_}}}}]}]},
+ [_,_]}]}]}},
+ {cons,_,
+ {tuple,_,[{atom,_,'...'}]},
+ {cons,_,
+ {tuple,_,[{atom,_,'...'}]},
+ {cons,_,
+ {tuple,_,[{atom,_,'...'}]},
+ {cons,_,
+ {tuple,_,[{atom,_,'...'}]},
+ {cons,_,
+ {tuple,_,[{atom,_,'...'}]},
+ {cons,_,{tuple,_,[{atom,_,'...'}]},{nil,_}}}}}}}]},
+ {call,_,_,
+ [{cons,_,{tuple,_,[{atom,_,'...'}]},{nil,_}}]}]} =
+ qlc:info(QH, [{format,abstract_code},{depth,1}])">>,
+ <<"T1 = [{1,1,a},{2,2,b},{3,3,c},{4,4,d}],
+ T2 = [{x,1},{y,1},{z,2}],
+ QH1 = T1,
+ T = gb_trees:from_orddict(T2),
+ QH2 = qlc:q([X || {_,X} <- gb_table:table(T)], cache),
+ Q = qlc:q([{X1,X2,X3} || {X1,X2,X3} <- QH1,
+ Y2 <- QH2,
+ X2 =:= Y2]),
+ {block,_,
+ [{match,_,_,
+ {call,_,_,
+ [{lc,_,_,
+ [{generate,_,_,
+ {call,_,_,
+ [{call,_,_,
+ [{cons,_,
+ {tuple,_,[{atom,_,'...'}]},
+ {atom,_,'...'}}]}]}}]},
+ _]}},
+ {call,_,_,
+ [{lc,_,_,
+ [{generate,_,_,
+ {cons,_,{tuple,_,[{atom,_,'...'}]},{atom,_,'...'}}},
+ _,_]}]}]} =
+ qlc:info(Q, [{format,abstract_code},{depth, 1},
+ {n_elements,1}])">>,
+ <<"L = [{{key,1},a},{{key,2},b},{{key,3},c}],
+ T = gb_trees:from_orddict(orddict:from_list(L)),
+ Q = qlc:q([K || {K,_} <- gb_table:table(T),
+ (K =:= {key,1}) or (K =:= {key,2})]),
+{call,_,_,
+ [{call,_,_,
+ [{'fun',_,
+ {clauses,
+ [{clause,_,_,[],
+ [{'case',_,
+ {call,_,_,
+ [_,
+ {call,_,_,
+ [{cons,_,
+ {tuple,_,[{tuple,_,[{atom,_,'...'}]},{atom,_,'...'}]},
+ {cons,_,
+ {tuple,_,[{tuple,_,[{atom,_,'...'}]},{atom,_,'...'}]},
+ {cons,_,
+ {tuple,_,[{tuple,_,[{atom,_,'...'}]},{atom,_,'...'}]},
+ {nil,_}}}}]}]},
+ _}]}]}},
+ {cons,_,
+ {tuple,_,[{atom,_,key},{atom,_,'...'}]},
+ {cons,_,{tuple,_,[{atom,_,key},{atom,_,'...'}]},{nil,_}}}]},
+ {call,_,
+ {remote,_,{atom,_,ets},{atom,_,match_spec_compile}},
+ [{cons,_,
+ {tuple,_,[{tuple,_,[{atom,_,'...'}]},{atom,_,'...'}]},
+ {nil,_}}]}]} =
+ qlc:info(Q, [{format,abstract_code},{depth, 2}])">>
+
+ ],
+ ?line run(Config, T2),
+
+ T3 = [
+ {nomatch_6,
+ <<"nomatch_6() ->
+ qlc:q([X || X <- [],
+ X =:= {X}]).">>,
+ [],
+ {[],["filter evaluates to 'false'"]}},
+
+ {nomatch_7,
+ <<"nomatch_7() ->
+ qlc:q([X || {X=Y,{Y}=X} <- []]).">>,
+ [],
+ {[],["pattern cannot possibly match"]}}],
+ ?line compile_format(Config, T3),
+
+ %% *Very* simple test - just check that it doesn't crash.
+ Type = [{cres,
+ <<"Q = qlc:q([X || {X} <- []]),
+ {'EXIT',{{badfun,_},_}} = (catch qlc:e(Q))">>,
+ [type_checker],
+ []}],
+ ?line run(Config, Type),
+
+ ok.
+
+otp_7114(doc) ->
+ "OTP-7114. Match spec, table and duplicated objects..";
+otp_7114(suite) -> [];
+otp_7114(Config) when is_list(Config) ->
+ Ts = [<<"T = ets:new(t, [bag]),
+ [ets:insert(T, {t, I, I div 2}) || I <- lists:seq(1,10)],
+ Q1 = qlc:q([element(3, E) || E <- ets:table(T)]),
+ [0,1,1,2,2,3,3,4,4,5] = lists:sort(qlc:e(Q1)),
+ [0,1,2,3,4,5] = qlc:e(Q1, unique_all),
+ [0,1,2,3,4,5] = qlc:e(qlc:sort(Q1), unique_all),
+ [0,1,2,3,4,5] = qlc:e(qlc:sort(qlc:e(Q1)), unique_all),
+ ets:delete(T),
+ ok">>],
+ ?line run(Config, Ts).
+
+otp_7232(doc) ->
+ "OTP-7232. qlc:info() bug (pids, ports, refs, funs).";
+otp_7232(suite) -> [];
+otp_7232(Config) when is_list(Config) ->
+ Ts = [<<"L = [fun math:sqrt/1, list_to_pid(\"<0.4.1>\"),
+ erlang:make_ref()],
+ \"[fun math:sqrt/1,<0.4.1>,#Ref<\" ++ _ = qlc:info(L),
+ {call,_,
+ {remote,_,{atom,_,qlc},{atom,_,sort}},
+ [{cons,_,
+ {'fun',_,{function,math,sqrt,_}},
+ {cons,_,
+ {string,_,\"<0.4.1>\"}, % could use list_to_pid..
+ {cons,_,{string,_,\"#Ref<\"++_},{nil,_}}}},
+ {nil,_}]} =
+ qlc:info(qlc:sort(L),{format,abstract_code})">>,
+
+ <<"Q1 = qlc:q([X || X <- [1000,2000]]),
+ Q = qlc:sort(Q1, {order, fun(A,B)-> A>B end}),
+ \"qlc:sort([1000,2000],[{order,fun'-function/0-fun-2-'/2}])\" =
+ format_info(Q, true),
+ AC = qlc:info(Q, {format, abstract_code}),
+ \"qlc:sort([1000,2000], [{order,fun '-function/0-fun-2-'/2}])\" =
+ binary_to_list(iolist_to_binary(erl_pp:expr(AC)))">>,
+
+ %% OTP-7234. erl_parse:abstract() handles bit strings
+ <<"Q = qlc:sort([<<17:9>>]),
+ \"[<<8,1:1>>]\" = qlc:info(Q)">>
+
+ ],
+ ?line run(Config, Ts).
+
+otp_7552(doc) ->
+ "OTP-7552. Merge join bug.";
+otp_7552(suite) -> [];
+otp_7552(Config) when is_list(Config) ->
+ %% The poor performance cannot be observed unless the
+ %% (redundant) join filter is skipped.
+ Ts = [<<"Few = lists:seq(1, 2),
+ Many = lists:seq(1, 10),
+ S = [d,e],
+ L1 = [{Y,a} || Y <- Few] ++ [{'1b',b},{2,b}] ++
+ [{Y,X} || X <- S, Y <- Few],
+ L2 = [{a,Y} || Y <- Many] ++
+ [{b,'1b'}] ++ [{c,1}] ++
+ [{X,Y} || X <- S, Y <- Many],
+ F = fun(J) ->
+ qlc:q([{XX,YY} ||
+ {XX,X} <- L1,
+ {Y,YY} <- L2,
+ X == Y],
+ {join,J})
+ end,
+ Qm = F(merge),
+ Qn = F(nested_loop),
+ true = lists:sort(qlc:e(Qm, {max_list_size,20})) =:=
+ lists:sort(qlc:e(Qn))">>],
+ ?line run(Config, Ts).
+
+otp_7714(doc) ->
+ "OTP-7714. Merge join bug.";
+otp_7714(suite) -> [];
+otp_7714(Config) when is_list(Config) ->
+ %% The original example uses Mnesia. This one does not.
+ Ts = [<<"E1 = ets:new(set,[]),
+ true = ets:insert(E1, {a,1}),
+ E2 = ets:new(set,[]),
+ _ = [true = ets:insert(E2, {I, 1}) ||
+ I <- lists:seq(1, 3)],
+ Q = qlc:q([{A,B} ||
+ {A,I1} <- ets:table(E1),
+ {B,I2} <- ets:table(E2),
+ I1 =:= I2],{join,merge}),
+ [{a,1},{a,2},{a,3}] = qlc:e(Q),
+ ets:delete(E1),
+ ets:delete(E2)">>],
+ ?line run(Config, Ts).
+
+otp_6674(doc) ->
+ "OTP-6674. match/comparison.";
+otp_6674(suite) -> [];
+otp_6674(Config) when is_list(Config) ->
+
+ ?line ok = compile_gb_table(Config),
+
+ Ts = [%% lookup join
+ <<"E = ets:new(join, [ordered_set]),
+ true = ets:insert(E, [{1,a},{2,b},{3,c}]),
+ Q = qlc:q([{X, Y} || {X,_} <- ets:table(E),
+ {Y} <- [{0},{1},{2}],
+ X == Y]),
+ {0,1,0,0} = join_info(Q),
+ [{1,1},{2,2}] = qlc:e(Q),
+ ets:delete(E)">>,
+
+ <<"E = ets:new(join, [ordered_set]),
+ true = ets:insert(E, [{1,a},{2,b},{3,c}]),
+ Q = qlc:q([{X, Y} || {X,_} <- ets:table(E),
+ {Y} <- [{0},{1},{2}],
+ X =:= Y]),
+ {0,1,0,0} = join_info(Q),
+ {block,_,
+ [_,
+ {match,_,_,
+ {call,_,_,
+ [{lc,_,_,
+ [_,_,{op,_,'==',_,_}]},
+ {cons,_,
+ {tuple,_,[{atom,_,join},{atom,_,lookup}]},_}]}},
+ _]} = qlc:info(Q, {format, abstract_code}),
+ [{1,1},{2,2}] = qlc:e(Q),
+ ets:delete(E)">>,
+
+ <<"E = ets:new(join, [set]),
+ Q = qlc:q([{X, Y} || {X,_} <- ets:table(E),
+ {Y} <- [{0},{1},{2}],
+ X == Y], {join, lookup}),
+ {'EXIT',{cannot_carry_out_join,_}} = (catch qlc:e(Q)),
+ ets:delete(E)">>,
+
+ %% Lookup join possible in both directions.
+ <<"E1 = ets:new(join, [ordered_set]),
+ E2 = ets:new(join, [set]),
+ true = ets:insert(E1, [{1.0,a},{2,b},{3,c}]),
+ true = ets:insert(E2, [{0},{1},{2}]),
+ Q = qlc:q([{X, Y} || {X,_} <- ets:table(E1),
+ {Y} <- ets:table(E2),
+ X == Y],{join,lookup}), % skipped
+ {qlc,_,
+ [{generate,_,
+ {qlc,_,
+ [{generate,_,
+ {qlc,_,[{generate,_,{table,{ets,table,[_]}}}],[]}},
+ {generate,_,{table,{ets,table,[_]}}},
+ _],
+ [{join,lookup}]}}],
+ []} = qlc:info(Q, {format,debug}),
+ {0,1,0,0} = join_info(Q),
+ [{1.0,1},{2,2}] = qlc:e(Q),
+ ets:delete(E1),
+ ets:delete(E2)">>,
+ <<"E1 = ets:new(join, [ordered_set]),
+ E2 = ets:new(join, [set]),
+ true = ets:insert(E1, [{1.0,a},{2,b},{3,c}]),
+ true = ets:insert(E2, [{0},{1},{2}]),
+ Q = qlc:q([{X, Y} || {X,_} <- ets:table(E1),
+ {Y} <- ets:table(E2),
+ X =:= Y],{join,merge}), % not skipped
+ {1,0,0,1} = join_info(Q),
+ [{2,2}] = qlc:e(Q),
+ ets:delete(E1),
+ ets:delete(E2)">>,
+ <<"E1 = ets:new(join, [ordered_set]),
+ E2 = ets:new(join, [set]),
+ true = ets:insert(E1, [{1.0,a},{2,b},{3,c}]),
+ true = ets:insert(E2, [{0},{1},{2}]),
+ Q = qlc:q([{X, Y} || {X,_} <- ets:table(E1),
+ {Y} <- ets:table(E2),
+ X =:= Y],{join,lookup}), % skipped
+ {qlc,_,
+ [{generate,_,
+ {qlc,_,
+ [{generate,_,
+ {qlc,_,
+ [{generate,_,{table,{ets,table,[_]}}}],
+ []}},
+ {generate,_,{table,{ets,table,[_]}}},
+ _],
+ [{join,lookup}]}}],
+ []} = qlc:info(Q, {format,debug}),
+ {0,1,0,0} = join_info(Q),
+ [{2,2}] = qlc:e(Q),
+ ets:delete(E1),
+ ets:delete(E2)">>,
+ <<"E1 = ets:new(join, [ordered_set]),
+ E2 = ets:new(join, [set]),
+ true = ets:insert(E1, [{1.0,a},{2,b},{3,c}]),
+ true = ets:insert(E2, [{0},{1},{2}]),
+ Q = qlc:q([{X, Y} || {X,_} <- ets:table(E1),
+ {Y} <- ets:table(E2),
+ %% Independent of term comparison:
+ X =:= Y, X == Y]),
+ {0,1,0,0} = join_info(Q),
+ [{2,2}] = qlc:e(Q),
+ ets:delete(E1),
+ ets:delete(E2)">>,
+
+ <<"E = ets:new(join, [ordered_set]),
+ true = ets:insert(E, [{1,1},{2,2},{3,c}]),
+ Q = qlc:q([{X, Y} || {X,Z} <- ets:table(E),
+ {Y} <- [{0},{1},{2}],
+ X == Z, Y == Z]), % cannot skip (yet)
+ {qlc,_,
+ [{generate,_,
+ {qlc,_,[_,_,_],[{join,lookup}]}},
+ _,_],[]} = qlc:info(Q,{format,debug}),
+ {0,1,0,0} = join_info(Q),
+ [{1,1},{2,2}] = qlc:e(Q),
+ ets:delete(E)">>,
+
+ %% The following moved here from skip_filters. It was buggy!
+ <<"etsc(fun(E) ->
+ A = 3,
+ Q = qlc:q([X || X <- ets:table(E),
+ A == element(1,X)]),
+ {table, _} = i(Q),
+ case qlc:e(Q) of
+ [{3},{3.0}] -> ok;
+ [{3.0},{3}] -> ok
+ end,
+ false = lookup_keys(Q)
+ end, [{3},{3.0},{c}])">>,
+ <<"H1 = qlc:sort([{{192,192.0},1,a},{{192.0,192.0},2,b},{{192,192.0},3,c}]),
+ Q = qlc:q([{X, Y} || {{A,B},X,_} <- H1, % does not need keysort(3)
+ A == 192, B =:= 192.0,
+ {Y} <- [{0},{1},{2}],
+ X == Y]),
+ {block,0,
+ [{match,_,_,
+ {call,_,_,
+ [{lc,_,_,
+ [_,
+ %% Has to compare extra constant:
+ {op,_,'==',
+ {tuple,_,[{integer,_,192},{float,_,192.0}]},
+ {call,_,{atom,_,element},[{integer,_,1},{var,_,'P0'}]}}]}]}},
+ _,_,
+ {call,_,_,
+ [{lc,_,_,
+ [_,
+ %% The join filter has been skipped.
+ {op,_,'==',{var,_,'A'},{integer,_,192}},
+ {op,_,'=:=',{var,_,'B'},{float,_,192.0}}]}]}]}
+ = qlc:info(Q, {format,abstract_code}),
+ {1,0,0,1} = join_info(Q),
+ [{1,1},{2,2}] = qlc:e(Q)">>,
+
+ %% Does not handle more than one lookup value (conjunctive).
+ <<"T = gb_trees:from_orddict([{1,a},{2,b}]),
+ H = qlc:q([X || {X,_} <- gb_table:table(T),
+ X =:= 1 andalso X == 1.0]),
+ false = lookup_keys(H),
+ [1] = qlc:e(H)">>,
+
+ %% EqualConstants...
+ <<"etsc(fun(E) ->
+ Q = qlc:q([{X,Y} || {X} <- ets:table(E),
+ {Y} <- [{{1}},{{2}},{{1.0}},{{2.0}}],
+ X =:= {1}, X == {1.0},
+ X == Y], {join, merge}),
+ [{{1},{1}},{{1},{1.0}}] = lists:sort(qlc:e(Q)),
+ false = lookup_keys(Q)
+ end, [{{1}}, {{2}}])">>,
+
+ <<"T = gb_trees:from_orddict([{foo,{1}}, {bar,{2}}]),
+ Q = qlc:q([{X,Y} || {_,X} <- gb_table:table(T),
+ {Y} <- [{{1}},{{2}},{{1.0}},{{2.0}}],
+ (X =:= {1}) or (X == {2}),
+ (X == {1.0}) or (X =:= {2.0}),
+ X == Y], {join, merge}),
+ [{{1},{1}},{{1},{1.0}}] = qlc:e(Q)">>,
+
+ %% Compare key
+ <<"T = gb_trees:from_orddict([{1,a},{2,b}]),
+ H = qlc:q([X || {X,_} <- gb_table:table(T),
+ X == 1]),
+ [1] = lookup_keys(H),
+ [1] = qlc:e(H)">>,
+ <<"T = gb_trees:from_orddict([{1,a},{2,b}]),
+ H = qlc:q([X || {X,_} <- gb_table:table(T),
+ X == 1.0]),
+ [1.0] = lookup_keys(H), % this is how gb_table works...
+ [1.0] = qlc:e(H)">>,
+ <<"etsc(fun(E) ->
+ H = qlc:q([X || {X,_} <- ets:table(E),
+ X == 1.0]),
+ [1] = qlc:e(H), % and this is how ETS works.
+ [1.0] = lookup_keys(H)
+ end, [ordered_set], [{1,a},{2,b}])">>,
+
+ <<"T = gb_trees:from_orddict([{1,a},{2,b}]),
+ H = qlc:q([X || {X,_} <- gb_table:table(T),
+ X =:= 2]),
+ [2] = lookup_keys(H),
+ %% Cannot (generally) remove the matching filter (the table
+ %% compares the key). But note that gb_table returns the given
+ %% term as key, so in this case the filter _could_ have been removed.
+ %% However, there is no callback to inform qlc about that.
+ {call,_,_,
+ [_,{call,_,_,
+ [{cons,_,{tuple,_,
+ [_,{cons,_,
+ {tuple,_,[{atom,_,'=:='},{atom,_,'$1'},{integer,_,2}]},
+ _},_]},_}]}]} = qlc:info(H, {format,abstract_code}),
+ [2] = qlc:e(H)">>,
+ <<"T = gb_trees:from_orddict([{1,a},{2,b}]),
+ H = qlc:q([X || {X,_} <- gb_table:table(T),
+ X =:= 2.0]),
+ %% Just shows that the term (not the key) is returned.
+ [2.0] = lookup_keys(H),
+ [2.0] = qlc:e(H)">>,
+
+ <<"I = 1,
+ T = gb_trees:from_orddict([{1,a},{2,b}]),
+ H = qlc:q([X || {X,_} <- gb_table:table(T),
+ X == I]), % imported variable
+ [1] = lookup_keys(H),
+ {call,_,_,
+ [_,{call,_,_,
+ [{cons,_,
+ {tuple,_,
+ [{tuple,_,[{atom,_,'$1'},{atom,_,'_'}]},
+ {nil,_}, % the filter has been skipped
+ {cons,_,{atom,_,'$1'},_}]},
+ _}]}]} = qlc:info(H, {format, abstract_code}),
+ [1] = qlc:e(H)">>,
+ <<"I = 2,
+ T = gb_trees:from_orddict([{1,a},{2,b}]),
+ H = qlc:q([X || {X,_} <- gb_table:table(T),
+ X =:= I]),
+ [2] = lookup_keys(H),
+ {call,_,_,
+ [_,{call,_,_,
+ [{cons,_,{tuple,_,
+ [_,{cons,_,
+ {tuple,_,
+ [{atom,_,'=:='},
+ {atom,_,'$1'},
+ {tuple,_,[{atom,_,const},{integer,_,2}]}]},
+ _},_]},
+ _}]}]} = qlc:info(H, {format, abstract_code}),
+ [2] = qlc:e(H)">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {X,_} <- ets:table(E),
+ X =:= a]), % skipped
+ [a] = qlc:e(Q),
+ {list,{table,_},_} = i(Q),
+ [a] = lookup_keys(Q)
+ end, [ordered_set], [{a,1},{b,2},{3,c}])">>,
+
+ %% Does not find that if for instance X =:= {1} then the filter
+ %% X == {1} can be removed.
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {X} <- ets:table(E),
+ X =:= {1}, X == {1.0}]),
+ [{1}] = qlc:e(Q),
+ [{1}] = lookup_keys(Q)
+ end, [{{1}}, {{2}}])">>,
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {X} <- ets:table(E),
+ X =:= {1}, X == {1.0}]),
+ [{1}] = qlc:e(Q),
+ false = lookup_keys(Q)
+ end, [ordered_set], [{{1}}, {{2}}])">>,
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {X} <- ets:table(E),
+ X == {1.0}, X =:= {1}]),
+ [{1}] = qlc:e(Q),
+ [{1}] = lookup_keys(Q)
+ end, [{{1}}, {{2}}])">>,
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {X} <- ets:table(E),
+ X == {1.0}, X =:= {1}]),
+ [{1}] = qlc:e(Q),
+ false = lookup_keys(Q)
+ end, [ordered_set], [{{1}}, {{2}}])">>,
+
+ <<"E = ets:new(apa, []),
+ true = ets:insert(E, [{1,a},{2,b}]),
+ {'EXIT', {badarg, _}} =
+ (catch qlc_SUITE:bad_table_key_equality(E)),
+ ets:delete(E)">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {X} <- ets:table(E),
+ X =:= 1, X =:= is_integer(X)]),
+ [] = qlc:e(Q),
+ [1] = lookup_keys(Q)
+ end, [{1}, {2}])">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {X=1} <- ets:table(E),
+ X =:= is_integer(X)]),
+ {call,_,_,
+ [{lc,_,_,
+ [_,
+ {op,_,'=:=',
+ {var,_,'X'},
+ {call,_,
+ {atom,_,is_integer},
+ [{var,_,'X'}]}}]}]} =
+ qlc:info(Q, {format, abstract_code}),
+ [] = qlc:e(Q),
+ [1] = lookup_keys(Q)
+ end, [{1}, {2}])">>,
+
+ <<"T = gb_trees:from_orddict([{1,a},{2,b}]),
+ H = qlc:q([X || {X,Y} <- gb_table:table(T),
+ Y =:= a, true, X =:= 1]),
+ [1] = lookup_keys(H),
+ [1] = qlc:e(H)">>,
+
+ <<"T = gb_trees:from_orddict([{{1.0,1},a},{{2.0,2},b}]),
+ H = qlc:q([X || {{1.0,B}=X,_} <- gb_table:table(T),
+ B == 1]), % skipped
+ [{1.0, 1}] = qlc:e(H),
+ {qlc,_,[{generate,_,{table,_}}], []} = qlc:info(H, {format,debug})">>,
+ <<"T = gb_trees:from_orddict([{{1.0,1},a},{{2.0,2},b}]),
+ H = qlc:q([X || {{1.0,B}=X,_} <- gb_table:table(T),
+ B == 1.0]), % skipped
+ [{1.0, 1.0}] = qlc:e(H), % this is how gb_table works...
+ {qlc,_,[{generate,_,{table,_}}], []} = qlc:info(H, {format,debug})">>,
+ <<"T = gb_trees:from_orddict([{{1.0,1},a},{{2.0,2},b}]),
+ H = qlc:q([X || {{1.0,B}=X,_} <- gb_table:table(T),
+ B =:= 1.0]), % not skipped
+ [{1.0, 1.0}] = qlc:e(H),
+ {qlc,_,[{generate,_,{table,_}},_], []} = qlc:info(H,{format,debug})">>,
+ <<"T = gb_trees:from_orddict([{{1.0,1},a},{{2.0,2},b}]),
+ H = qlc:q([X || {{1.0,B}=X,_} <- gb_table:table(T),
+ B =:= 1]), % not skipped
+ [{1.0, 1}] = qlc:e(H),
+ {qlc,_,[{generate,_,{table,_}},_], []} = qlc:info(H,{format,debug})">>,
+
+ <<"%% The imported variables do not interfere with join.
+ E = ets:new(join, [ordered_set]),
+ {A, B} = {1,1},
+ true = ets:insert(E, [{1,a},{2,b},{3,c}]),
+ Q = qlc:q([{X, Y} || {X,_Z} <- ets:table(E),
+ {Y} <- [{0},{1},{2}],
+ X =:= A, Y =:= B,
+ Y == X], % skipped
+ {join, merge}),
+ [{1,1}] = qlc:e(Q),
+ {qlc,_,
+ [{generate,_,
+ {qlc,_,
+ [{generate,_,
+ {qlc,_,[{generate,_,{list,{table,_},_}},_],[]}},
+ {generate,_,
+ {qlc,_,[{generate,_,{list,_,_}},_],[]}},
+ _],
+ [{join,merge}]}}],
+ []} = qlc:info(Q, {format, debug}),
+ ets:delete(E)">>,
+
+ <<"% An old bug: usort() should not be used when matching values
+ etsc(fun(E) ->
+ I = 1,
+ H = qlc:q([X || {X,_} <- ets:table(E),
+ X =:= 1.0 orelse X =:= I]),
+ [1] = qlc:e(H),
+ [1.0] = lookup_keys(H) % do not look up twice
+ end, [set], [{1,a},{2,b}])">>,
+ <<"etsc(fun(E) ->
+ H = qlc:q([X || {X,_} <- ets:table(E),
+ X =:= 1.0 orelse X == 1]),
+ [1] = qlc:e(H),
+ false = lookup_keys(H) % doesn't handle this case
+ end, [ordered_set], [{1,a},{2,b}])">>,
+
+ <<"etsc(fun(E) ->
+ I1 = 1, I2 = 1,
+ H = qlc:q([X || {X,_} <- ets:table(E),
+ X =:= I1 orelse X == I2]),
+ [1] = qlc:e(H), % do not look up twice
+ [1] = lookup_keys(H)
+ end, [ordered_set], [{1,a},{2,b}])">>,
+
+ <<"etsc(fun(E) ->
+ I1 = 1, I2 = 1, I3 = 1,
+ H = qlc:q([X || {X,_} <- ets:table(E),
+ I1 == I2, I1 =:= I3, I3 == I2, I2 =:= I3,
+ X =:= I1 orelse X == I2
+ ]),
+ [1] = qlc:e(H),
+ [1] = lookup_keys(H)
+ end, [ordered_set], [{1,a},{2,b}])">>,
+
+ <<"E = ets:new(join, [ordered_set]),
+ true = ets:insert(E, [{1,a},{2,b,x},{3,c}]),
+ Q = qlc:q([P || P <- ets:table(E),
+ P =:= {1,a} orelse P =:= {2,b,x}]),
+ [{1,a},{2,b,x}] = qlc:e(Q),
+ ets:delete(E)">>,
+
+ <<"etsc(fun(E) ->
+ Q = qlc:q([X || {X,Y} <- ets:table(E),
+ ((X =:= 3) or (Y =:= 4)) and (X == a)]),
+ {list,{table,_},_} = i(Q),
+ [] = qlc:e(Q), % a is not an answer
+ [a] = lookup_keys(Q)
+ end, [{keypos,1},ordered_set], [{a,3},{b,4}])">>,
+
+ <<"Q = qlc:q([{X,Y} ||
+ {X} <- [{<<3:4>>}],
+ {Y} <- [{<<3:4>>}],
+ X =:= <<1:3,1:1>>, % <<3:4>>
+ Y =:= <<0:2,1:1,1:1>>, % <<3:4>>
+ X =:= Y]),
+ [{<<3:4>>,<<3:4>>}] = qlc:e(Q)">>
+
+
+ ],
+
+ ?line run(Config, Ts).
+
+manpage(doc) ->
+ "Examples from qlc(3).";
+manpage(suite) -> [];
+manpage(Config) when is_list(Config) ->
+
+ ?line ok = compile_gb_table(Config),
+
+ Ts = [
+ <<"QH = qlc:q([{X,Y} || X <- [a,b], Y <- [1,2]]),
+ QC = qlc:cursor(QH),
+ [{a,1}] = qlc:next_answers(QC, 1),
+ [{a,2}] = qlc:next_answers(QC, 1),
+ [{b,1},{b,2}] = qlc:next_answers(QC, all_remaining),
+ ok = qlc:delete_cursor(QC)">>,
+
+ <<"QH = qlc:q([{X,Y} || X <- [a,b], Y <- [1,2]]),
+ [{a,1},{a,2},{b,1},{b,2}] = qlc:eval(QH)">>,
+
+ <<"QH = [1,2,3,4,5,6],
+ 21 = qlc:fold(fun(X, Sum) -> X + Sum end, 0, QH)">>,
+
+ <<"QH = qlc:q([{X,Y} || X <- [x,y], Y <- [a,b]]),
+ B = \"begin\n\"
+ \" V1 =\n\"
+ \" qlc:q([ \n\"
+ \" SQV ||\n\"
+ \" SQV <- [x,y]\n\"
+ \" ],\n\"
+ \" [{unique,true}]),\n\"
+ \" V2 =\n\"
+ \" qlc:q([ \n\"
+ \" SQV ||\n\"
+ \" SQV <- [a,b]\n\"
+ \" ],\n\"
+ \" [{unique,true}]),\n\"
+ \" qlc:q([ \n\"
+ \" {X,Y} ||\n\"
+ \" X <- V1,\n\"
+ \" Y <- V2\n\"
+ \" ],\n\"
+ \" [{unique,true}])\n\"
+ \"end\",
+ true = B =:= qlc:info(QH, unique_all)">>,
+
+ <<"E1 = ets:new(e1, []),
+ E2 = ets:new(e2, []),
+ true = ets:insert(E1, [{1,a},{2,b}]),
+ true = ets:insert(E2, [{a,1},{b,2}]),
+ Q = qlc:q([{X,Z,W} ||
+ {X, Z} <- ets:table(E1),
+ {W, Y} <- ets:table(E2),
+ X =:= Y]),
+ L = \"begin\n\"
+ \" V1 =\n\"
+ \" qlc:q([ \n\"
+ \" P0 ||\n\"
+ \" P0 = {W,Y} <- ets:table(_)\n\"
+ \" ]),\n\"
+ \" V2 =\n\"
+ \" qlc:q([ \n\"
+ \" [G1|G2] ||\n\"
+ \" G2 <- V1,\n\"
+ \" G1 <- ets:table(_),\n\"
+ \" element(2, G1) =:= element(1, G2)\n\"
+ \" ],\n\"
+ \" [{join,lookup}]),\n\"
+ \" qlc:q([ \n\"
+ \" {X,Z,W} ||\n\"
+ \" [{X,Z}|{W,Y}] <- V2\n\"
+ \" ])\n\"
+ \"end\",
+ Info =
+ re:replace(qlc:info(Q),
+ \"table\\\\(-*[0-9]*\",
+ \"table(_\", [{return,list},global]),
+ L = Info,
+ ets:delete(E1),
+ ets:delete(E2)">>,
+
+ <<"Q = qlc:q([{A,X,Z,W} ||
+ A <- [a,b,c],
+ {X,Z} <- [{a,1},{b,4},{c,6}],
+ {W,Y} <- [{2,a},{3,b},{4,c}],
+ X =:= Y],
+ {cache, list}),
+ L =
+ \"begin\n\"
+ \" V1 =\n\"
+ \" qlc:q([ \n\"
+ \" P0 ||\n\"
+ \" P0 = {X,Z} <- qlc:keysort(1, [{a,1},{b,4},{c,6}], [])\n\"
+ \" ]),\n\"
+ \" V2 =\n\"
+ \" qlc:q([ \n\"
+ \" P0 ||\n\"
+ \" P0 = {W,Y} <- qlc:keysort(2, [{2,a},{3,b},{4,c}], [])\n\"
+ \" ]),\n\"
+ \" V3 =\n\"
+ \" qlc:q([ \n\"
+ \" [G1|G2] ||\n\"
+ \" G1 <- V1,\n\"
+ \" G2 <- V2,\n\"
+ \" element(1, G1) == element(2, G2)\n\"
+ \" ],\n\"
+ \" [{join,merge},{cache,list}]),\n\"
+ \" qlc:q([ \n\"
+ \" {A,X,Z,W} ||\n\"
+ \" A <- [a,b,c],\n\"
+ \" [{X,Z}|{W,Y}] <- V3,\n\"
+ \" X =:= Y\n\"
+ \" ])\n\"
+ \"end\",
+ L = qlc:info(Q)">>,
+
+ <<"E1 = ets:new(t, [set]), % uses =:=/2
+ Q1 = qlc:q([K ||
+ {K} <- ets:table(E1),
+ K == 2.71 orelse K == a]),
+ {list,{table,_}, [{{'$1'},[],['$1']}]} = i(Q1),
+ true = ets:delete(E1)">>,
+
+ <<"F = fun(E, I) ->
+ qlc:q([V || {K,V} <- ets:table(E), K == I])
+ end,
+ E2 = ets:new(t, [set]),
+ true = ets:insert(E2, [{{2,2},a},{{2,2.0},b},{{2.0,2},c}]),
+ Q2 = F(E2, {2,2}),
+ {table,{ets,table,[_,
+ [{traverse,{select,[{{'$1','$2'},
+ [{'==','$1',{const,{2,2}}}],
+ ['$2']}]}}]]}} = i(Q2),
+ [a,b,c] = lists:sort(qlc:e(Q2)),
+ true = ets:delete(E2),
+
+ E3 = ets:new(t, [ordered_set]), % uses ==/2
+ true = ets:insert(E3, [{{2,2.0},b}]),
+ Q3 = F(E3,{2,2}),
+ {list,{table,_},[{{'$1','$2'},[],['$2']}]} = i(Q3),
+ [b] = qlc:e(Q3),
+ true = ets:delete(E3)">>,
+
+ <<"T = gb_trees:empty(),
+ QH = qlc:q([X || {{X,Y},_} <- gb_table:table(T),
+ ((X == 1) or (X == 2)) andalso
+ ((Y == a) or (Y == b) or (Y == c))]),
+ L = \"ets:match_spec_run(lists:flatmap(fun(K) ->
+ case
+ gb_trees:lookup(K,
+ gb_trees:from_orddict([]))
+ of
+ {value,V} ->
+ [{K,V}];
+ none ->
+ []
+ end
+ end,
+ [{1,a},{1,b},{1,c},{2,a},{2,b},{2,c}]),
+ ets:match_spec_compile([{{{'$1','$2'},'_'},[],['$1']}]))\",
+ L = qlc:info(QH)">>
+ ],
+ ?line run(Config, Ts),
+
+ L = [1,2,3],
+ Bs = erl_eval:add_binding('L', L, erl_eval:new_bindings()),
+ QH = qlc:string_to_handle("[X+1 || X <- L].", [], Bs),
+ [2,3,4] = qlc:eval(QH),
+
+ %% ets(3)
+ MS = ets:fun2ms(fun({X,Y}) when (X > 1) or (X < 5) -> {Y} end),
+ ETs = [
+ [<<"true = ets:insert(Tab = ets:new(t, []),[{1,a},{2,b},{3,c},{4,d}]),
+ MS = ">>, io_lib:format("~w", [MS]), <<",
+ QH1 = ets:table(Tab, [{traverse, {select, MS}}]),
+
+ QH2 = qlc:q([{Y} || {X,Y} <- ets:table(Tab), (X > 1) or (X < 5)]),
+
+ true = qlc:info(QH1) =:= qlc:info(QH2),
+ true = ets:delete(Tab)">>]],
+ ?line run(Config, ETs),
+
+ %% dets(3)
+ DTs = [
+ [<<"{ok, T} = dets:open_file(t, []),
+ ok = dets:insert(T, [{1,a},{2,b},{3,c},{4,d}]),
+ MS = ">>, io_lib:format("~w", [MS]), <<",
+ QH1 = dets:table(T, [{traverse, {select, MS}}]),
+
+ QH2 = qlc:q([{Y} || {X,Y} <- dets:table(t), (X > 1) or (X < 5)]),
+
+ true = qlc:info(QH1) =:= qlc:info(QH2),
+ ok = dets:close(T)">>]],
+ ?line run(Config, DTs),
+
+ ok.
+
+compile_gb_table(Config) ->
+ GB_table_file = filename("gb_table.erl", Config),
+ ?line ok = file:write_file(GB_table_file, gb_table()),
+ ?line {ok, gb_table} = compile:file(GB_table_file, [{outdir,?privdir}]),
+ ?line code:purge(gb_table),
+ ?line {module, gb_table} =
+ code:load_abs(filename:rootname(GB_table_file)),
+ ok.
+
+gb_table() ->
+ <<"
+-module(gb_table).
+
+-export([table/1]).
+
+table(T) ->
+ TF = fun() -> qlc_next(gb_trees:next(gb_trees:iterator(T))) end,
+ InfoFun = fun(num_of_objects) -> gb_trees:size(T);
+ (keypos) -> 1;
+ (is_sorted_key) -> true;
+ (is_unique_objects) -> true;
+ (_) -> undefined
+ end,
+ LookupFun =
+ fun(1, Ks) ->
+ lists:flatmap(fun(K) ->
+ case gb_trees:lookup(K, T) of
+ {value, V} -> [{K,V}];
+ none -> []
+ end
+ end, Ks)
+ end,
+ FormatFun =
+ fun({all, NElements, ElementFun}) ->
+ ValsS = io_lib:format(\"gb_trees:from_orddict(~w)\",
+ [gb_nodes(T, NElements, ElementFun)]),
+ io_lib:format(\"gb_table:table(~s)\", [ValsS]);
+ ({lookup, 1, KeyValues, _NElements, ElementFun}) ->
+ ValsS = io_lib:format(\"gb_trees:from_orddict(~w)\",
+ [gb_nodes(T, infinity, ElementFun)]),
+ io_lib:format(\"lists:flatmap(fun(K) -> \"
+ \"case gb_trees:lookup(K, ~s) of \"
+ \"{value, V} -> [{K,V}];none -> [] end \"
+ \"end, ~w)\",
+ [ValsS, [ElementFun(KV) || KV <- KeyValues]])
+ end,
+ qlc:table(TF, [{info_fun, InfoFun}, {format_fun, FormatFun},
+ {lookup_fun, LookupFun},{key_equality,'=='}]).
+
+qlc_next({X, V, S}) ->
+ [{X,V} | fun() -> qlc_next(gb_trees:next(S)) end];
+qlc_next(none) ->
+ [].
+
+gb_nodes(T, infinity, ElementFun) ->
+ gb_nodes(T, -1, ElementFun);
+gb_nodes(T, NElements, ElementFun) ->
+ gb_iter(gb_trees:iterator(T), NElements, ElementFun).
+
+gb_iter(_I, 0, _EFun) ->
+ '...';
+gb_iter(I0, N, EFun) ->
+ case gb_trees:next(I0) of
+ {X, V, I} ->
+ [EFun({X,V}) | gb_iter(I, N-1, EFun)];
+ none ->
+ []
+ end.
+ ">>.
+
+compat(suite) ->
+ [backward, forward].
+
+backward(doc) ->
+ "OTP-6674. Join info and extra constants.";
+backward(suite) -> [];
+backward(Config) when is_list(Config) ->
+ case try_old_join_info(Config) of
+ ok ->
+ ok;
+ Reply ->
+ Reply
+ end.
+
+-ifdef(debug).
+try_old_join_info(_Config) ->
+ ok.
+-else.
+try_old_join_info(Config) ->
+ case ?t:is_release_available("r12b") of
+ true ->
+ %% Check join info for handlers of extra constants. Start R12B-0.
+ ?line {ok, R12} = start_node_rel(r12, r12b, slave),
+ File = filename("handle.erl", Config),
+ ?line file:write_file(File,
+ <<"-module(handle).\n"
+ "-export([create_handle/0, lookup_handle/0]).\n"
+ "-include_lib(\"stdlib/include/qlc.hrl\").\n"
+ "create_handle() ->\n"
+ " H1 = qlc:sort([{192.0,1,a},{192.0,2,b},{192.0,3,c}]),\n"
+ " qlc:q([{X, Y} || {B,X,_} <- H1,\n"
+ " B =:= 192.0,\n"
+ " {Y} <- [{0},{1},{2}],\n"
+ " X == Y]).\n",
+ "\n",
+ "lookup_handle() ->\n"
+ " E = qlc_SUITE:table([{1,a},{2,b},{3,c}], 1, [1]),\n"
+ " qlc:q([{X, Y} || {X,_} <- E,\n"
+ " {Y} <- [{0},{1},{2}],\n"
+ " X =:= Y]).\n">>),
+ ?line {ok, handle} = rpc:call(R12, compile, file,
+ [File, [{outdir,?privdir}]]),
+ ?line {module, handle} = rpc:call(R12, code, load_abs,
+ [filename:rootname(File)]),
+ ?line H = rpc:call(R12, handle, create_handle, []),
+ ?line {module, handle} = code:load_abs(filename:rootname(File)),
+ ?line {block,0,
+ [{match,_,_,
+ {call,_,_,
+ [{lc,_,_,
+ [_,
+ {op,_,'=:=',
+ {float,_,192.0},
+ {call,_,{atom,_,element},[{integer,_,1},_]}}]}]}},
+ _,_,
+ {call,_,_,
+ [{lc,_,_,
+ [_,
+ {op,_,'=:=',{var,_,'B'},{float,_,192.0}},
+ {op,_,'==',{var,_,'X'},{var,_,'Y'}}]}]}]}
+ = qlc:info(H,{format,abstract_code}),
+ ?line [{1,1},{2,2}] = qlc:e(H),
+ ?line H2 = rpc:call(R12, handle, lookup_handle, []),
+ ?line {qlc,_,[{generate,_,{qlc,_,_,[{join,lookup}]}},_],[]} =
+ qlc:info(H2, {format,debug}),
+ ?line [{1,1},{2,2}] = qlc:e(H2),
+ stop_node(R12);
+ false ->
+ ?line {skipped, "No support for old node"}
+ end.
+-endif.
+
+forward(doc) ->
+ "";
+forward(suite) -> [];
+forward(Config) when is_list(Config) ->
+ Ts = [
+ %% LC_fun() returns something unknown.
+ <<"FakeH = {qlc_handle,{qlc_lc,fun() -> {foo,bar} end,
+ {qlc_opt,false,false,-1,any,[],any,524288}}},
+ {'EXIT', {{unsupported_qlc_handle,_},_}} = (catch qlc:e(FakeH))">>,
+
+%% 'f1' should be used for new stuff that does not interfer with old behavior
+% %% The unused element 'f1' of #qlc_table seems to be used.
+% <<"DF = fun() -> foo end,
+% FakeH = {qlc_handle,{qlc_table,DF,
+% true,DF,DF,DF,DF,DF,
+% undefined,not_undefined,undefined,no_match_spec}},
+% {'EXIT', {{unsupported_qlc_handle,_},_}} = (catch qlc:e(FakeH))">>,
+
+ %% #qlc_opt has changed.
+ <<"H = qlc:q([X || X <- []]),
+ {qlc_handle, {qlc_lc, Fun, _Opt}} = H,
+ FakeH = {qlc_handle, {qlc_lc, Fun, {new_qlc_opt, a,b,c}}},
+ {'EXIT', {{unsupported_qlc_handle,_},_}} = (catch qlc:e(FakeH))">>
+
+ ],
+ ?line run(Config, Ts),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bad_table_throw(Tab) ->
+ Limit = 1,
+ Select = fun(MS) -> cb(ets:select(Tab, MS, Limit)) end,
+ PreFun = fun(_) -> throw({throw,bad_pre_fun}) end,
+ PostFun = fun() -> throw({throw,bad_post_fun}) end,
+ InfoFun = fun(Tag) -> info(Tab, Tag) end,
+ qlc:table(Select, [{pre_fun,PreFun}, {post_fun, PostFun},
+ {info_fun, InfoFun}]).
+
+bad_table_exit(Tab) ->
+ Limit = 1,
+ Select = fun(MS) -> cb(ets:select(Tab, MS, Limit)) end,
+ PreFun = fun(_) -> erlang:error(bad_pre_fun) end,
+ PostFun = fun() -> erlang:error(bad_post_fun) end,
+ InfoFun = fun(Tag) -> info(Tab, Tag) end,
+ qlc:table(Select, [{pre_fun,PreFun}, {post_fun, PostFun},
+ {info_fun, InfoFun}]).
+
+info(_Tab, is_unique_objects) ->
+ false;
+info(Tab, Tag) ->
+ try ets:info(Tab, Tag) catch _:_ -> undefined end.
+
+create_ets(S, E) ->
+ create_ets(lists:seq(S, E)).
+
+create_ets(L) ->
+ E1 = ets:new(e, []),
+ true = ets:insert(E1, [{X,X} || X <- L]),
+ E1.
+
+etsc(F, Objs) ->
+ etsc(F, [{keypos,1}], Objs).
+
+etsc(F, Opts, Objs) ->
+ E = ets:new(test, Opts),
+ true = ets:insert(E, Objs),
+ V = F(E),
+ ets:delete(E),
+ V.
+
+join_info(H) ->
+ {qlc, S, Options} = strip_qlc_call(H),
+ %% "Hide" the call to qlc_pt from the test in run_test().
+ LoadedPT = code:is_loaded(qlc_pt),
+ QH = qlc:string_to_handle(S, Options),
+ _ = [unload_pt() || false <- [LoadedPT]], % doesn't take long...
+ case {join_info_count(H), join_info_count(QH)} of
+ {N, N} ->
+ N;
+ Ns ->
+ Ns
+ end.
+
+strip_qlc_call(H) ->
+ S = qlc:info(H, {flat, false}),
+ {ok, Tokens, _EndLine} = erl_scan:string(S++"."),
+ {ok, [Expr]} = erl_parse:parse_exprs(Tokens),
+ case Expr of
+ {call,_,{remote,_,{atom,_,qlc},{atom,_,q}},[LC]} ->
+ {qlc, lists:flatten([erl_pp:expr(LC), "."]), []};
+ {call,_,{remote,_,{atom,_,qlc},{atom,_,q}},[LC, Opts]} ->
+ {qlc, lists:flatten([erl_pp:expr(LC), "."]),
+ erl_parse:normalise(Opts)};
+ {call,_,{remote,_,{atom,_,ets},{atom,_,match_spec_run}},_} ->
+ {match_spec, Expr};
+ {call,_,{remote,_,{atom,_,M},{atom,_,table}},_} ->
+ {table, M, Expr};
+ _ ->
+ []
+ end.
+
+-record(ji, {nmerge = 0, nlookup = 0, nnested_loop = 0, nkeysort = 0}).
+
+%% Counts join options and (all) calls to qlc:keysort().
+join_info_count(H) ->
+ S = qlc:info(H, {flat, false}),
+ {ok, Tokens, _EndLine} = erl_scan:string(S++"."),
+ {ok, [Expr]} = erl_parse:parse_exprs(Tokens),
+ #ji{nmerge = Nmerge, nlookup = Nlookup,
+ nkeysort = NKeysort, nnested_loop = Nnested_loop} =
+ ji(Expr, #ji{}),
+ {Nmerge, Nlookup, Nnested_loop, NKeysort}.
+
+ji({call,_,{remote,_,{atom,_,qlc},{atom,_,q}},[LC,Options]}, JI) ->
+ NJI = case lists:keysearch(join, 1, erl_parse:normalise(Options)) of
+ {value, {join, merge}} ->
+ JI#ji{nmerge = JI#ji.nmerge + 1};
+ {value, {join, lookup}} ->
+ JI#ji{nlookup = JI#ji.nlookup + 1};
+ {value, {join, nested_loop}} ->
+ JI#ji{nnested_loop = JI#ji.nnested_loop + 1};
+ _ ->
+ JI
+ end,
+ ji(LC, NJI);
+ji({call,_,{remote,_,{atom,_,qlc},{atom,_,keysort}},[_KP,H,_Options]}, JI) ->
+ ji(H, JI#ji{nkeysort = JI#ji.nkeysort + 1});
+ji(T, JI) when is_tuple(T) ->
+ ji(tuple_to_list(T), JI);
+ji([E | Es], JI) ->
+ ji(Es, ji(E, JI));
+ji(_, JI) ->
+ JI.
+
+%% Designed for ETS' and gb_table's format funs.
+lookup_keys(Q) ->
+ case lists:flatten(lookup_keys(i(Q), [])) of
+ [] -> false;
+ L -> lists:usort(L)
+ end.
+
+lookup_keys([Q | Qs], L) ->
+ lookup_keys(Qs, lookup_keys(Q, L));
+lookup_keys({qlc,_,Quals,_}, L) ->
+ lookup_keys(Quals, L);
+lookup_keys({list,Q,_}, L) ->
+ lookup_keys(Q, L);
+lookup_keys({generate,_,Q}, L) ->
+ lookup_keys(Q, L);
+lookup_keys({table,Chars}, L) when is_list(Chars) ->
+ {ok, Tokens, _} = erl_scan:string(lists:flatten(Chars++".")),
+ {ok, [Expr]} = erl_parse:parse_exprs(Tokens),
+ case Expr of
+ {call,_,_,[_fun,AKs]} ->
+ case erl_parse:normalise(AKs) of
+ Ks when is_list(Ks) ->
+ [lists:sort(Ks) | L];
+ K -> % assume keys are never lists (ets only)
+ [K | L]
+ end;
+ _ -> % gb_table
+ L
+ end;
+lookup_keys(_Q, L) ->
+ L.
+
+bad_table_format(Tab) ->
+ Limit = 1,
+ SelectFun = fun(MS) -> cb(ets:select(Tab, MS, Limit)) end,
+ FormatFun = {is, no, good},
+ qlc:table(SelectFun, [{format_fun, FormatFun}]).
+
+bad_table_format_arity(Tab) ->
+ Limit = 1,
+ SelectFun = fun(MS) -> cb(ets:select(Tab, MS, Limit)) end,
+ FormatFun = fun() -> {?MODULE, bad_table_format_arity, [Tab]} end,
+ qlc:table(SelectFun, [{format_fun, FormatFun}]).
+
+bad_table_traverse(Tab) ->
+ Limit = 1,
+ Select = fun(MS, _) -> cb(ets:select(Tab, MS, Limit)) end,
+ qlc:table(Select, []).
+
+bad_table_post(Tab) ->
+ Limit = 1,
+ SelectFun = fun(MS) -> cb(ets:select(Tab, MS, Limit)) end,
+ qlc:table(SelectFun, [{pre_fun,undefined},
+ {post_fun, fun(X) -> X end},
+ {info_fun, undefined}]).
+
+bad_table_lookup(Tab) ->
+ Limit = 1,
+ SelectFun = fun(MS) -> cb(ets:select(Tab, MS, Limit)) end,
+ qlc:table(SelectFun, {lookup_fun, fun(X) -> X end}).
+
+bad_table_max_lookup(Tab) ->
+ Limit = 1,
+ SelectFun = fun(MS) -> cb(ets:select(Tab, MS, Limit)) end,
+ qlc:table(SelectFun, {max_lookup, -2}).
+
+bad_table_info_arity(Tab) ->
+ Limit = 1,
+ SelectFun = fun(MS) -> cb(ets:select(Tab, MS, Limit)) end,
+ InfoFun = fun() -> {?MODULE, bad_table_info_arity, [Tab]} end,
+ qlc:table(SelectFun, [{info_fun, InfoFun}]).
+
+default_table(Tab) ->
+ Limit = 1,
+ SelectFun = fun(MS) -> cb(ets:select(Tab, MS, Limit)) end,
+ qlc:table(SelectFun, [{format_fun, undefined},
+ {info_fun, undefined},
+ {lookup_fun, undefined},
+ {parent_fun, undefined},
+ {pre_fun,undefined},
+ {post_fun, undefined}]).
+
+bad_table(Tab) ->
+ Limit = 1,
+ SelectFun = fun(MS) -> cb(ets:select(Tab, MS, Limit)) end,
+ qlc:table(SelectFun, [{info, fun() -> ok end}]).
+
+bad_table_info_fun_n_objects(Tab) ->
+ Limit = 1,
+ SelectFun = fun(MS) -> cb(ets:select(Tab, MS, Limit)) end,
+ LookupFun = fun(_Pos, Ks) ->
+ lists:flatmap(fun(K) -> ets:lookup(Tab, K) end, Ks)
+ end,
+ InfoFun = fun(num_of_objects) -> exit(finito);
+ (_) -> undefined
+ end,
+ qlc:table(SelectFun, [{info_fun, InfoFun}, {lookup_fun, LookupFun}]).
+
+bad_table_info_fun_indices(Tab) ->
+ Limit = 1,
+ SelectFun = fun(MS) -> cb(ets:select(Tab, MS, Limit)) end,
+ LookupFun = fun(_Pos, Ks) ->
+ lists:flatmap(fun(K) -> ets:lookup(Tab, K) end, Ks)
+ end,
+ InfoFun = fun(indices) -> throw({throw,apa});
+ (_) -> undefined
+ end,
+ qlc:table(SelectFun, [{info_fun, InfoFun}, {lookup_fun, LookupFun}]).
+
+bad_table_info_fun_keypos(Tab) ->
+ Limit = 1,
+ SelectFun = fun(MS) -> cb(ets:select(Tab, MS, Limit)) end,
+ LookupFun = fun(_Pos, Ks) ->
+ lists:flatmap(fun(K) -> ets:lookup(Tab, K) end, Ks)
+ end,
+ InfoFun = fun(indices) -> erlang:error(keypos);
+ (_) -> undefined
+ end,
+ qlc:table(SelectFun, [{info_fun, InfoFun}, {lookup_fun, LookupFun}]).
+
+bad_table_key_equality(Tab) ->
+ Limit = 1,
+ SelectFun = fun(MS) -> cb(ets:select(Tab, MS, Limit)) end,
+ LookupFun = fun(_Pos, Ks) ->
+ lists:flatmap(fun(K) -> ets:lookup(Tab, K) end, Ks)
+ end,
+ qlc:table(SelectFun, [{lookup_fun, LookupFun},{key_equality,'=/='}]).
+
+cb('$end_of_table') ->
+ [];
+cb({Objects,Cont}) ->
+ Objects ++ fun() -> cb(ets:select(Cont)) end.
+
+i(H) ->
+ i(H, []).
+
+i(H, Options) when is_list(Options) ->
+ case has_format(Options) of
+ true -> qlc:info(H, Options);
+ false -> qlc:info(H, [{format, debug} | Options])
+ end;
+i(H, Option) ->
+ i(H, [Option]).
+
+has_format({format,_}) ->
+ true;
+has_format([E | Es]) ->
+ has_format(E) or has_format(Es);
+has_format(_) ->
+ false.
+
+format_info(H, Flat) ->
+ L = qlc:info(H, [{flat, Flat}, {format,string}]),
+ re:replace(L, "\s|\n|\t|\f|\r|\v", "", [{return,list},global]).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% A list turned into a table...
+
+table_kill_parent(List, Indices) ->
+ ParentFun = fun() -> exit(self(), kill) end,
+ table_i(List, Indices, ParentFun).
+
+table_parent_throws(List, Indices) ->
+ ParentFun = fun() -> throw({throw,thrown}) end,
+ table_i(List, Indices, ParentFun).
+
+table_parent_exits(List, Indices) ->
+ ParentFun = fun() -> 1 + Indices end,
+ table_i(List, Indices, ParentFun).
+
+table_bad_parent_fun(List, Indices) ->
+ ParentFun = fun(X) -> X end, % parent_fun should be nullary
+ table_i(List, Indices, ParentFun).
+
+table(List, Indices) ->
+ ParentFun = fun() -> self() end,
+ table_i(List, Indices, ParentFun).
+
+table(List, KeyPos, Indices) ->
+ ParentFun = fun() -> self() end,
+ table(List, Indices, KeyPos, ParentFun).
+
+table_i(List, Indices, ParentFun) ->
+ table(List, Indices, undefined, ParentFun).
+
+table(List, Indices, KeyPos, ParentFun) ->
+ TraverseFun = fun() -> list_traverse(List) end,
+ PreFun = fun(PreArgs) ->
+ {value, {parent_value, Pid}} =
+ lists:keysearch(parent_value, 1, PreArgs),
+ true = is_pid(Pid)
+ end,
+ PostFun = fun() -> ok end,
+ InfoFun = fun(indices) ->
+ Indices;
+ (is_unique_objects) ->
+ undefined;
+ (keypos) ->
+ KeyPos;
+ (num_of_objects) ->
+ undefined;
+ (_) ->
+ undefined
+ end,
+ LookupFun =
+ fun(Column, Values) ->
+ lists:flatmap(fun(V) ->
+ case lists:keysearch(V, Column, List) of
+ false -> [];
+ {value,Val} -> [Val]
+ end
+ end, Values)
+
+ end,
+ FormatFun = fun(all) ->
+ L = 17,
+ {call,L,{remote,L,{atom,1,?MODULE},{atom,L,the_list}},
+ [erl_parse:abstract(List, 17)]};
+ ({lookup, Column, Values}) ->
+ {?MODULE, list_keys, [Values, Column, List]}
+ end,
+ qlc:table(TraverseFun, [{info_fun,InfoFun}, {pre_fun, PreFun},
+ {post_fun, PostFun}, {lookup_fun, LookupFun},
+ {format_fun, FormatFun},
+ {parent_fun, ParentFun}]).
+
+stop_list(List, Ets) ->
+ Traverse = fun() -> list_traverse(List) end,
+ PV = a_sample_parent_value,
+ ParentFun = fun() -> PV end,
+ Pre = fun(PreArgs) ->
+ {value, {parent_value, PV}} =
+ lists:keysearch(parent_value, 1, PreArgs),
+ {value, {stop_fun, Fun}} =
+ lists:keysearch(stop_fun, 1, PreArgs),
+ true = ets:insert(Ets, {stop_fun, Fun})
+ end,
+ qlc:table(Traverse, [{pre_fun, Pre}, {parent_fun, ParentFun}]).
+
+list_traverse([]) ->
+ [];
+list_traverse([E | Es]) ->
+ [E | fun() -> list_traverse(Es) end].
+
+table_error(List, Error) ->
+ table_error(List, undefined, Error).
+
+table_error(List, KeyPos, Error) ->
+ TraverseFun = fun() -> list_traverse2(lists:sort(List), Error) end,
+ InfoFun = fun(is_sorted_key) -> true;
+ (keypos) -> KeyPos;
+ (_) -> undefined
+ end,
+ qlc:table(TraverseFun, [{info_fun,InfoFun}]).
+
+list_traverse2([], Err) ->
+ Err;
+list_traverse2([E | Es], Err) ->
+ [E | fun() -> list_traverse2(Es, Err) end].
+
+table_lookup_error(List) ->
+ TraverseFun = fun() -> list_traverse(List) end,
+ LookupFun = fun(_Column, _Values) -> {error,lookup,failed} end,
+ InfoFun = fun(keypos) -> 1;
+ (_) -> undefined
+ end,
+ qlc:table(TraverseFun, [{lookup_fun,LookupFun},{info_fun,InfoFun}]).
+
+prep_scratchdir(Dir) ->
+ put('$qlc_tmpdir', true),
+ _ = filelib:ensure_dir(Dir),
+ lists:foreach(fun(F) -> file:delete(F)
+ end, filelib:wildcard(filename:join(Dir, "*"))),
+ true.
+
+%% Truncate just once.
+truncate_tmpfile(Dir, Where) ->
+ case get('$qlc_tmpdir') of
+ true ->
+ {ok, [TmpFile0 | _]} = file:list_dir(Dir),
+ TmpFile = filename:join(Dir, TmpFile0),
+ truncate(TmpFile, Where),
+ erase('$qlc_tmpdir');
+ _ ->
+ true
+ end.
+
+truncate(File, Where) ->
+ {ok, Fd} = file:open(File, [read, write]),
+ {ok, _} = file:position(Fd, Where),
+ ok = file:truncate(Fd),
+ ok = file:close(Fd).
+
+%% Crash just once.
+crash_tmpfile(Dir, Where) ->
+ case get('$qlc_tmpdir') of
+ true ->
+ {ok, [TmpFile0 | _]} = file:list_dir(Dir),
+ TmpFile = filename:join(Dir, TmpFile0),
+ crash(TmpFile, Where),
+ erase('$qlc_tmpdir');
+ _ ->
+ true
+ end.
+
+crash(File, Where) ->
+ {ok, Fd} = file:open(File, [read, write]),
+ {ok, _} = file:position(Fd, Where),
+ ok = file:write(Fd, [10]),
+ ok = file:close(Fd).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+run(Config, Tests) ->
+ run(Config, [], Tests).
+
+run(Config, Extra, Tests) ->
+ lists:foreach(fun(Body) -> run_test(Config, Extra, Body) end, Tests).
+
+run_test(Config, Extra, {cres, Body, ExpectedCompileReturn}) ->
+ run_test(Config, Extra, {cres, Body, _Opts = [], ExpectedCompileReturn});
+run_test(Config, Extra, {cres, Body, Opts, ExpectedCompileReturn}) ->
+ {SourceFile, Mod} = compile_file_mod(Config),
+ P = [Extra,<<"function() -> ">>, Body, <<", ok. ">>],
+ CompileReturn = compile_file(Config, P, Opts),
+ case comp_compare(ExpectedCompileReturn, CompileReturn) of
+ true -> ok;
+ false -> expected(ExpectedCompileReturn, CompileReturn, SourceFile)
+ end,
+ AbsFile = filename:rootname(SourceFile, ".erl"),
+ _ = code:purge(Mod),
+ {module, _} = code:load_abs(AbsFile, Mod),
+
+ Ms0 = erlang:process_info(self(),messages),
+ Before = {get(), pps(), ets:all(), Ms0},
+
+ %% Prepare the check that the qlc module does not call qlc_pt.
+ _ = [unload_pt() || {file, Name} <- [code:is_loaded(qlc_pt)],
+ Name =/= cover_compiled],
+
+ R = case catch Mod:function() of
+ {'EXIT', _Reason} = Error ->
+ ?t:format("failed, got ~p~n", [Error]),
+ fail(SourceFile);
+ Reply ->
+ Reply
+ end,
+
+ %% Check that the qlc module does not call qlc_pt:
+ case code:is_loaded(qlc_pt) of
+ {file, cover_compiled} ->
+ ok;
+ {file, _} ->
+ ?t:format("qlc_pt was loaded in runtime~n", []),
+ fail(SourceFile);
+ false ->
+ ok
+ end,
+
+ Ms = erlang:process_info(self(),messages),
+ After = {get(), pps(), ets:all(), Ms},
+ code:purge(Mod),
+ case {R, After} of
+ {ok, Before} -> ok;
+ _ -> expected({ok,Before}, {R,After}, SourceFile)
+ end;
+run_test(Config, Extra, Body) ->
+ run_test(Config, Extra, {cres,Body,[]}).
+
+unload_pt() ->
+ erlang:garbage_collect(), % get rid of references to qlc_pt...
+ _ = code:purge(qlc_pt),
+ _ = code:delete(qlc_pt).
+
+compile_format(Config, Tests) ->
+ Fun = fun(Test, Opts) ->
+ Return = compile_file(Config, Test, Opts),
+ format_messages(Return)
+ end,
+ compile(Config, Tests, Fun).
+
+format_messages({warnings,Ws}) ->
+ format_messages({errors,[],Ws});
+format_messages({errors,Es,Ws}) ->
+ {[format_msg(E, Mod) || {_Line,Mod,E} <- Es],
+ [format_msg(W, Mod) || {_Line,Mod,W} <- Ws]}.
+
+format_msg(Msg, Mod) ->
+ IOlist = Mod:format_error(Msg),
+ binary_to_list(iolist_to_binary(IOlist)).
+
+compile(Config, Tests) ->
+ Fun = fun(Test, Opts) -> catch compile_file(Config, Test, Opts) end,
+ compile(Config, Tests, Fun).
+
+compile(Config, Tests, Fun) ->
+ F = fun({TestName,Test,Opts,Expected}, BadL) ->
+ Return = Fun(Test, Opts),
+ case comp_compare(Expected, Return) of
+ true ->
+ BadL;
+ false ->
+ {File, _Mod} = compile_file_mod(Config),
+ expected(TestName, Expected, Return, File)
+ end
+ end,
+ lists:foldl(F, [], Tests).
+
+%% Compiles a test module and returns the list of errors and warnings.
+
+compile_file(Config, Test0, Opts0) ->
+ {File, Mod} = compile_file_mod(Config),
+ Test = list_to_binary(["-module(", atom_to_list(Mod), "). "
+ "-compile(export_all). "
+ "-import(qlc_SUITE, [i/1,i/2,format_info/2]). "
+ "-import(qlc_SUITE, [etsc/2, etsc/3]). "
+ "-import(qlc_SUITE, [create_ets/2]). "
+ "-import(qlc_SUITE, [strip_qlc_call/1]). "
+ "-import(qlc_SUITE, [join_info/1]). "
+ "-import(qlc_SUITE, [join_info_count/1]). "
+ "-import(qlc_SUITE, [lookup_keys/1]). "
+ "-include_lib(\"stdlib/include/qlc.hrl\"). ",
+ Test0]),
+ Opts = [export_all,return,nowarn_unused_record,{outdir,?privdir}|Opts0],
+ ok = file:write_file(File, Test),
+ case compile:file(File, Opts) of
+ {ok, _M, Ws} -> warnings(File, Ws);
+ {error, [{File,Es}], []} -> {errors, Es, []};
+ {error, [{File,Es}], [{File,Ws}]} -> {error, Es, Ws}
+ end.
+
+comp_compare(T, T) ->
+ true;
+comp_compare(T1, T2_0) ->
+ T2 = wskip(T2_0),
+ T1 =:= T2
+ %% This clause should eventually be removed.
+ orelse ln(T1) =:= T2 orelse T1 =:= ln(T2).
+
+wskip([]) ->
+ [];
+wskip([{_,sys_core_fold,{eval_failure,badarg}}|L]) ->
+ wskip(L);
+wskip([{{L,_C},sys_core_fold,M}|L]) ->
+ [{L,sys_core_fold,M}|wskip(L)];
+wskip({T,L}) ->
+ {T,wskip(L)};
+wskip([M|L]) ->
+ [M|wskip(L)];
+wskip(T) ->
+ T.
+
+%% Replaces locations like {Line,Column} with Line.
+ln({warnings,L}) ->
+ {warnings,ln0(L)};
+ln({errors,EL,WL}) ->
+ {errors,ln0(EL),ln0(WL)};
+ln(L) ->
+ ln0(L).
+
+ln0(L) ->
+ lists:sort(ln1(L)).
+
+ln1([]) ->
+ [];
+ln1([{File,Ms}|MsL]) when is_list(File) ->
+ [{File,ln0(Ms)}|ln1(MsL)];
+ln1([{{L,_C},Mod,Mess0}|Ms]) ->
+ Mess = case Mess0 of
+ {exported_var,V,{Where,{L1,_C1}}} ->
+ {exported_var,V,{Where,L1}};
+ {unsafe_var,V,{Where,{L1,_C1}}} ->
+ {unsafe_var,V,{Where,L1}};
+ %% There are more...
+ M ->
+ M
+ end,
+ [{L,Mod,Mess}|ln1(Ms)];
+ln1([M|Ms]) ->
+ [M|ln1(Ms)].
+
+%% -> {FileName, Module}; {string(), atom()}
+compile_file_mod(Config) ->
+ NameL = lists:concat([?TESTMODULE, "_", ?testcase]),
+ Name = list_to_atom(NameL),
+ File = filename(NameL ++ ".erl", Config),
+ {File, Name}.
+
+filename(Name, Config) when is_atom(Name) ->
+ filename(atom_to_list(Name), Config);
+filename(Name, Config) ->
+ filename:join(?privdir, Name).
+
+pps() ->
+ {port_list(), process_list()}.
+
+port_list() ->
+ [{P,safe_second_element(erlang:port_info(P, name))} ||
+ P <- erlang:ports()].
+
+process_list() ->
+ [{P,process_info(P, registered_name),
+ safe_second_element(process_info(P, initial_call))} ||
+ P <- processes(), is_process_alive(P)].
+
+safe_second_element({_,Info}) -> Info;
+safe_second_element(Other) -> Other.
+
+warnings(File, Ws) ->
+ case lists:append([W || {F, W} <- Ws, F =:= File]) of
+ [] -> [];
+ L -> {warnings, L}
+ end.
+
+expected(Test, Expected, Got, File) ->
+ ?t:format("~nTest ~p failed. ", [Test]),
+ expected(Expected, Got, File).
+
+expected(Expected, Got, File) ->
+ ?t:format("Expected~n ~p~n, but got~n ~p~n", [Expected, Got]),
+ fail(File).
+
+fail(Source) ->
+ io:format("failed~n"),
+ ?t:fail({failed,testcase,on,Source}).
+
+%% Copied from global_SUITE.erl.
+
+start_node_rel(Name, Rel, How) ->
+ {Release, Compat} = case Rel of
+ this ->
+ {[this], "+R8"};
+ Rel when is_atom(Rel) ->
+ {[{release, atom_to_list(Rel)}], ""};
+ RelList ->
+ {RelList, ""}
+ end,
+ ?line Pa = filename:dirname(code:which(?MODULE)),
+ ?line Res = test_server:start_node(Name, How,
+ [{args,
+ Compat ++
+ " -kernel net_setuptime 100 "
+ " -pa " ++ Pa},
+ {erl, Release}]),
+ Res.
+
+stop_node(Node) ->
+ ?line ?t:stop_node(Node).
+
+install_error_logger() ->
+ error_logger:add_report_handler(?MODULE, self()).
+
+uninstall_error_logger() ->
+ error_logger:delete_report_handler(?MODULE).
+
+read_error_logger() ->
+ receive
+ {error, Why} ->
+ {error, Why};
+ {info, Why} ->
+ {info, Why};
+ {error, Pid, Tuple} ->
+ {error, Pid, Tuple}
+ after 1000 ->
+ ?line io:format("No reply after 1 s\n", []),
+ ?line ?t:fail()
+ end.
+
+%%-----------------------------------------------------------------
+%% The error_logger handler used.
+%% (Copied from stdlib/test/proc_lib_SUITE.erl.)
+%%-----------------------------------------------------------------
+init(Tester) ->
+ {ok, Tester}.
+
+handle_event({error, _GL, {_Pid, _Msg, [Why, _]}}, Tester)
+ when is_atom(Why) ->
+ Tester ! {error, Why},
+ {ok, Tester};
+handle_event({error, _GL, {_Pid, _Msg, [P, T]}}, Tester) when is_pid(P) ->
+ Tester ! {error, P, T},
+ {ok, Tester};
+handle_event({info_msg, _GL, {_Pid, _Msg, [Why, _]}}, Tester) ->
+ Tester ! {info, Why},
+ {ok, Tester};
+handle_event(_Event, State) ->
+ {ok, State}.
+
+handle_info(_, State) ->
+ {ok, State}.
+
+handle_call(_Query, State) -> {ok, {error, bad_query}, State}.
+
+terminate(_Reason, State) ->
+ State.
diff --git a/lib/stdlib/test/queue_SUITE.erl b/lib/stdlib/test/queue_SUITE.erl
new file mode 100644
index 0000000000..ec3080baa0
--- /dev/null
+++ b/lib/stdlib/test/queue_SUITE.erl
@@ -0,0 +1,604 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(queue_SUITE).
+-export([all/1]).
+
+-export([do/1, to_list/1, io_test/1, op_test/1, error/1, oops/1]).
+
+-export([init_per_testcase/2, fin_per_testcase/2]).
+
+-include("test_server.hrl").
+
+% Default timetrap timeout (set in init_per_testcase).
+-define(default_timeout, ?t:minutes(1)).
+
+init_per_testcase(_Case, Config) ->
+ ?line Dog = ?t:timetrap(?default_timeout),
+ [{watchdog, Dog} | Config].
+fin_per_testcase(_Case, Config) ->
+ Dog = ?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+all(doc) ->
+ ["Test cases for queue."];
+all(suite) ->
+ [do, to_list, io_test, op_test, error, oops].
+
+do(doc) ->
+ [""];
+do(suite) ->
+ [];
+do(Config) when list(Config) ->
+ ?line L = [{in, 1},
+ {in, 2},
+ {out, {value, 1}},
+ {in, 3},
+ {out, {value, 2}},
+ {out, {value, 3}},
+ {out, empty}
+ ],
+
+ ?line E = queue:new(),
+ ?line [] = queue:to_list(E),
+ ?line Q = do_queue(E, L),
+ ?line true = queue:is_empty(Q),
+ ?line 0 = queue:len(Q),
+ ok.
+
+to_list(doc) ->
+ ["OTP-2701"];
+to_list(suite) ->
+ [];
+to_list(Config) when list(Config) ->
+ ?line E = queue:new(),
+ ?line Q = do_queue(E, [{in, 1},
+ {in, 2},
+ {in, 3},
+ {out, {value, 1}},
+ {in, 4},
+ {in, 5}]),
+ ?line true = queue:is_queue(Q),
+ ?line 4 = queue:len(Q),
+ ?line case queue:to_list(Q) of
+ [2,3,4,5] ->
+ ok;
+ Other1 ->
+ test_server:fail(Other1)
+ end,
+ ok.
+
+do_queue(Q, []) ->
+ Q;
+do_queue(Q, [E | Rest]) ->
+ do_queue(do_queue_1(E, Q), Rest).
+
+do_queue_1({in, E}, Q) ->
+ queue:in(E, Q);
+do_queue_1({out, E}, Q) ->
+ case queue:out(Q) of
+ {E, Q1} ->
+ Q1;
+ Other ->
+ test_server:fail({"out failed", E, Q, Other})
+ end.
+
+
+io_test(doc) ->
+ "Test input and output";
+io_test(suite) ->
+ [];
+io_test(Config) when list(Config) ->
+ E = queue:new(),
+ do_io_test(E),
+ ok.
+
+do_io_test(E) ->
+ ?line [4,3,5] =
+ io([snoc,snoc,head,head,head,cons,cons,snoc], E, 1),
+ ?line [5,3,4] =
+ io([cons,cons,daeh,daeh,daeh,snoc,snoc,cons], E, 1),
+ ?line [4,3,5] =
+ io([in,in,out,out,out,in_r,in_r,in], E, 1),
+ ?line [5,3,4] =
+ io([in_r,in_r,out_r,out_r,out_r,in,in,in_r], E, 1),
+ %%
+ ?line [] =
+ io([snoc,snoc,head,snoc,snoc,head,head,snoc,head,head], E, 1),
+ ?line [] =
+ io([cons,cons,daeh,cons,cons,daeh,daeh,cons,daeh,daeh], E, 1),
+ ?line [] =
+ io([in,in,out,in,in,out,out,in,out,out], E, 1),
+ ?line [] =
+ io([in_r,in_r,out_r,in_r,in_r,out_r,out_r,in_r,out_r,out_r],
+ E, 1),
+ %%
+ ?line [5,6] =
+ io([snoc,snoc,snoc,head,head,snoc,snoc,snoc,head,head], E, 1),
+ ?line [6,5] =
+ io([cons,cons,cons,daeh,daeh,cons,cons,cons,daeh,daeh], E, 1),
+ ?line [5,6] =
+ io([in,in,in,out,out,in,in,in,out,out], E, 1),
+ ?line [6,5] =
+ io([in_r,in_r,in_r,out_r,out_r,in_r,in_r,in_r,out_r,out_r],
+ E, 1),
+ %%
+ ?line [5] =
+ io([snoc,head,head,snoc,head,snoc,head,snoc,head,snoc], E, 1),
+ ?line [5] =
+ io([cons,daeh,daeh,cons,daeh,cons,daeh,cons,daeh,cons], E, 1),
+ ?line [5] =
+ io([in,out,out,in,out,in,out,in,out,in], E, 1),
+ ?line [5] =
+ io([in_r,out_r,out_r,in_r,out_r,in_r,out_r,in_r,out_r,in_r],
+ E, 1),
+ %%
+ ?line [] =
+ io([snoc,head,snoc,snoc,head,head,snoc,snoc,snoc,head,head,head],
+ E, 1),
+ ?line [] =
+ io([cons,daeh,cons,cons,daeh,daeh,cons,cons,cons,daeh,daeh,daeh],
+ E, 1),
+ ?line [] =
+ io([in,out,in,in,out,out,in,in,in,out,out,out],
+ E, 1),
+ ?line [] =
+ io([in_r,out_r,in_r,in_r,out_r,out_r,in_r,in_r,in_r,out_r,out_r,out_r],
+ E, 1),
+ %%
+ ?line [3] = io([cons,cons,cons,snoc,daeh,daeh,daeh], E, 1),
+ ?line [3] = io([snoc,snoc,snoc,cons,head,head,head], E, 1),
+ ?line [3] = io([in,in,in,in_r,out,out,out], E, 1),
+ ?line [3] = io([in_r,in_r,in_r,in,out_r,out_r,out_r], E, 1),
+ %%
+ ?line Q2 = queue:join(queue:cons(1, E),queue:cons(2, E)),
+ ?line Q1 = queue:reverse(Q2),
+ ?line [1] = io([head], Q1, 3),
+ ?line [1] = io([out], Q1, 3),
+ ?line [1] = io([daeh], Q2, 3),
+ ?line [1] = io([out_r], Q2, 3),
+% ?line [2] = io([cons,cons,snoc,daeh,daeh], [], 1),
+% ?line [2] = io([snoc,snoc,cons,head,head], [], 1),
+% ?line [2] = io([in,in,in_r,out,out], [], 1),
+% ?line [2] = io([in_r,in_r,in,out_r,out_r], [], 1),
+ %%
+ ?line [2] =
+ io([in,peek,peek_r,drop,in_r,peek,peek_r,in,peek,peek_r,drop_r], E, 1),
+ %% Malformed queues UGLY-GUTS-ALL-OVER-THE-PLACE
+ ?line [2,1] = io([peek], {[1,2],[]}, 1),
+ ?line [1,2] = io([peek_r], {[],[1,2]}, 1),
+ %%
+ ok.
+
+%% Perform a list of operations to a queue.
+%% Keep a reference queue on the side; just a list.
+%% Compare the read values between the queues.
+%% Return the resulting queue as a list.
+%% Inserted values are increments of the previously inserted.
+io(Ops, Q, X) ->
+ io(Ops, Q, queue:to_list(Q), X).
+
+io([head | Tail], Q, [], X) ->
+ true = queue:is_empty(Q),
+ {'EXIT',{empty,_}} = (catch {ok,queue:head(Q)}),
+ {'EXIT',{empty,_}} = (catch {ok,queue:tail(Q)}),
+ io(Tail, Q, [], X);
+io([head | Tail], Q, [H | T], X) ->
+ H = queue:head(Q),
+ false = queue:is_empty(Q),
+ io(Tail, queue:tail(Q), T, X);
+io([daeh | Tail], Q, [], X) ->
+ true = queue:is_empty(Q),
+ {'EXIT',{empty,_}} = (catch {ok,queue:daeh(Q)}),
+ {'EXIT',{empty,_}} = (catch {ok,queue:liat(Q)}),
+ {'EXIT',{empty,_}} = (catch {ok,queue:lait(Q)}),
+ io(Tail, Q, [], X);
+io([daeh | Tail], Q, QQ, X) ->
+ H = queue:daeh(Q),
+ false = queue:is_empty(Q),
+ [H | T] = lists:reverse(QQ),
+ io(Tail, queue:liat(Q), lists:reverse(T), X);
+io([out | Tail], Q, [], X) ->
+ {empty, Q1} = queue:out(Q),
+ io(Tail, Q1, [], X);
+io([out | Tail], Q, [H | T], X) ->
+ {{value,H}, Q1} = queue:out(Q),
+ io(Tail, Q1, T, X);
+io([out_r | Tail], Q, [], X) ->
+ {empty, Q1} = queue:out_r(Q),
+ io(Tail, Q1, [], X);
+io([out_r | Tail], Q, QQ, X) ->
+ {{value,H}, Q1} = queue:out_r(Q),
+ [H | T] = lists:reverse(QQ),
+ io(Tail, Q1, lists:reverse(T), X);
+io([cons | Tail], Q, QQ, X) ->
+ io(Tail, queue:cons(X,Q), [X|QQ], X+1);
+io([snoc | Tail], Q, QQ, X) ->
+ io(Tail, queue:snoc(Q,X), QQ++[X], X+1);
+io([in_r | Tail], Q, QQ, X) ->
+ io(Tail, queue:in_r(X,Q), [X|QQ], X+1);
+io([in | Tail], Q, QQ, X) ->
+ io(Tail, queue:in(X,Q), QQ++[X], X+1);
+io([peek | Tail], Q, [], X) ->
+ empty = queue:peek(Q),
+ io(Tail, Q, [], X);
+io([peek | Tail], Q, [H|_]=Q0, X) ->
+ {value,H} = queue:peek(Q),
+ io(Tail, Q, Q0, X);
+io([peek_r | Tail], Q, [], X) ->
+ empty = queue:peek_r(Q),
+ io(Tail, Q, [], X);
+io([peek_r | Tail], Q, Q0, X) ->
+ E = lists:last(Q0),
+ {value,E} = queue:peek_r(Q),
+ io(Tail, Q, Q0, X);
+io([drop | Tail], Q, [], X) ->
+ try queue:drop(Q) of
+ V ->
+ test_server:fail({?MODULE,?LINE,V})
+ catch
+ error:empty ->
+ io(Tail, Q, [], X)
+ end;
+io([drop | Tail], Q, [_ | T], X) ->
+ Q1 = queue:drop(Q),
+ io(Tail, Q1, T, X);
+io([drop_r | Tail], Q, [], X) ->
+ try queue:drop_r(Q) of
+ V ->
+ test_server:fail({?MODULE,?LINE,V})
+ catch
+ error:empty ->
+ io(Tail, Q, [], X)
+ end;
+io([drop_r | Tail], Q, L, X) ->
+ io:format("~p~n", [{drop_r,Tail,Q,L,X}]),
+ Q1 = queue:drop_r(Q),
+ [_ | T] = lists:reverse(L),
+ io:format("~p~n", [{drop_r,Q1,T}]),
+ io(Tail, Q1, lists:reverse(T), X);
+io([], Q, QQ, _X) ->
+ QQ = queue:to_list(Q),
+ Length = length(QQ),
+ Length = queue:len(Q),
+ QQ.
+
+
+op_test(doc) ->
+ "Test operations on whole queues";
+op_test(suite) ->
+ [];
+op_test(Config) when list(Config) ->
+ do_op_test(fun id/1),
+ ok.
+
+do_op_test(F) ->
+ ?line Len = 50,
+ ?line Len2 = 2*Len,
+ ?line L1 = lists:seq(1, Len),
+ ?line L1r = lists:reverse(L1),
+ ?line L2 = lists:seq(Len+1, Len2),
+ ?line L2r = lists:reverse(L2),
+ ?line L3 = L1++L2,
+ ?line L3r = L2r++L1r,
+ ?line Q0 = F(queue:new()),
+ ?line [] = queue:to_list(Q0),
+ ?line Q0 = F(queue:from_list([])),
+ ?line Q1 = F(queue:from_list(L1)),
+ ?line Q2 = F(queue:from_list(L2)),
+ ?line Q3 = F(queue:from_list(L3)),
+ ?line Len = queue:len(Q1),
+ ?line Len = queue:len(Q2),
+ ?line Len2 = queue:len(Q3),
+ ?line L1 = queue:to_list(Q1),
+ ?line L2 = queue:to_list(Q2),
+ ?line L3 = queue:to_list(Q3),
+ ?line Q3b = queue:join(Q0, queue:join(queue:join(Q1, Q2), Q0)),
+ ?line L3 = queue:to_list(Q3b),
+ ?line {Q0, Q3New1} = queue:split(0, Q3),
+ ?line L3 = queue:to_list(Q3New1),
+ ?line {Q3New2, Q0} = queue:split(Len2, Q3),
+ ?line L3 = queue:to_list(Q3New2),
+ ?line {Q1a, Q2a} = queue:split(Len, Q3),
+ ?line L1 = queue:to_list(Q1a),
+ ?line L2 = queue:to_list(Q2a),
+ ?line {Q3c, Q3d} = queue:split(2, Q3),
+ ?line L3 = queue:to_list(Q3c) ++ queue:to_list(Q3d),
+ ?line {Q1b, Q2b} = queue:split(Len, Q3b),
+ ?line L1 = queue:to_list(Q1b),
+ ?line L2 = queue:to_list(Q2b),
+ ?line Len = queue:len(Q1b),
+ ?line Len = queue:len(Q2b),
+ ?line Len2 = queue:len(Q3b),
+ ?line Q1r = queue:reverse(Q1),
+ ?line Q2r = queue:reverse(Q2),
+ ?line Q1ar = queue:reverse(Q1a),
+ ?line Q2ar = queue:reverse(Q2a),
+ ?line Q1br = queue:reverse(Q1b),
+ ?line Q2br = queue:reverse(Q2b),
+ ?line Q3br = queue:reverse(Q3b),
+ ?line L1r = queue:to_list(Q1r),
+ ?line L1r = queue:to_list(Q1ar),
+ ?line L1r = queue:to_list(Q1br),
+ ?line L2r = queue:to_list(Q2r),
+ ?line L2r = queue:to_list(Q2ar),
+ ?line L2r = queue:to_list(Q2br),
+ ?line L3r = queue:to_list(Q3br),
+ ?line Len = queue:len(Q1br),
+ ?line Len = queue:len(Q2br),
+ ?line Len2 = queue:len(Q3br),
+ ?line false = queue:member([], Q0),
+ ?line false = queue:member(0, Q0),
+ ?line false = queue:member(0, Q1),
+ ?line false = queue:member([], Q1),
+ ?line true = queue:member(1, Q1),
+ ?line false = queue:member(1.0, Q1),
+ ?line true = queue:member(Len, Q1),
+ %%
+ %% Additional coverage.
+ ?line {MyL1r,MyL2r} = lists:split(Len-2, L1r),
+ ?line MyQ0r = queue:reverse(F(queue:from_list(L1))),
+ ?line {MyQ1r,MyQ2r} = queue:split(Len-2, MyQ0r),
+ ?line MyL1r = queue:to_list(MyQ1r),
+ ?line MyL2r = queue:to_list(MyQ2r),
+ ?line MyQ3r = queue:filter(
+ fun (X) when X rem 4 >= 2 -> false;
+ (X) when X rem 8 == 0 -> [float(X),{X}];
+ (X) when X rem 2 >= 1 -> [{X}];
+ (_) -> true
+ end, MyQ1r),
+ ?line MyL3r = lists:flatten(
+ [if X rem 8 == 0 -> [float(X),{X}];
+ X rem 2 >= 1 -> {X};
+ true -> X
+ end || X <- MyL1r,
+ X rem 4 < 2]),
+ ?line MyL3r = queue:to_list(MyQ3r),
+ ?line MyQ4 = F(queue:from_list([11,22,33,44])),
+ ?line [11,22] = queue:to_list(queue:filter(fun(X) when X < 27 -> true;
+ (_) -> [] end, MyQ4)),
+ ?line [33,44] = queue:to_list(queue:filter(fun(X) when X < 27 -> false;
+ (X) -> [X] end, MyQ4)),
+ %%
+ ok.
+
+error(doc) ->
+ "Test queue errors";
+error(suite) ->
+ [];
+error(Config) when list(Config) ->
+ do_error(fun id/1, illegal_queue),
+ do_error(fun id/1, {[],illegal_queue}),
+ do_error(fun id/1, {illegal_queue,[17]}),
+ ok.
+
+trycatch(F, Args) ->
+ trycatch(queue, F, Args).
+
+trycatch(M, F, Args) ->
+ try apply(M, F, Args) of
+ V -> {value,V}
+ catch
+ C:R -> {C,R}
+ end.
+
+do_error(F, IQ) ->
+ ?line io:format("Illegal Queue: ~p~n", [IQ]),
+ %%
+ ?line {error,badarg} = trycatch(in, [1, IQ]),
+ ?line {error,badarg} = trycatch(out, [IQ]),
+ ?line {error,badarg} = trycatch(in_r ,[1, IQ]),
+ ?line {error,badarg} = trycatch(out_r ,[IQ]),
+ ?line {error,badarg} = trycatch(to_list ,[IQ]),
+ %%
+ ?line {error,badarg} = trycatch(from_list, [no_list]),
+ ?line {error,badarg} = trycatch(is_empty, [IQ]),
+ ?line {error,badarg} = trycatch(len, [IQ]),
+ %%
+ ?line {error,badarg} = trycatch(cons, [1, IQ]),
+ ?line {error,badarg} = trycatch(head, [IQ]),
+ ?line {error,badarg} = trycatch(tail, [IQ]),
+ %%
+ ?line {error,badarg} = trycatch(snoc, [IQ, 1]),
+ ?line {error,badarg} = trycatch(last, [IQ]),
+ ?line {error,badarg} = trycatch(daeh, [IQ]),
+ ?line {error,badarg} = trycatch(liat, [IQ]),
+ ?line {error,badarg} = trycatch(lait, [IQ]),
+ ?line {error,badarg} = trycatch(init, [IQ]),
+ %%
+ ?line {error,badarg} = trycatch(reverse, [IQ]),
+ ?line {error,badarg} = trycatch(join, [F(queue:new()), IQ]),
+ ?line {error,badarg} = trycatch(join, [IQ, F(queue:new())]),
+ ?line {error,badarg} = trycatch(split, [17, IQ]),
+ ?line {error,badarg} = trycatch(head, [IQ]),
+ %%
+ ?line Q0 = F(queue:new()),
+ ?line {error,badarg} = trycatch(split, [1, Q0]),
+ ?line {error,badarg} = trycatch(split, [2, queue:snoc(Q0, 1)]),
+ %%
+ ?line {value,false} = trycatch(is_queue, [IQ]),
+ ?line {error,badarg} = trycatch(get, [IQ]),
+ ?line {error,badarg} = trycatch(peek, [IQ]),
+ ?line {error,badarg} = trycatch(peek_r, [IQ]),
+ ?line {error,badarg} = trycatch(filter, [fun id/1, IQ]),
+ ?line {error,badarg} = trycatch(filter, [no_fun, Q0]),
+ %%
+ ?line {error,badarg} = trycatch(member, [1, IQ]),
+ ok.
+
+id(X) ->
+ X.
+
+oops(doc) ->
+ "Test queue errors";
+oops(suite) ->
+ [];
+oops(Config) when list(Config) ->
+ ?line N = 3142,
+ ?line Optab = optab(),
+ ?line Seed0 = random:seed0(),
+ ?line {Is,Seed} = random_list(N, tuple_size(Optab), Seed0, []),
+ ?line io:format("~p ", [Is]),
+ ?line QA = queue:new(),
+ ?line QB = {[]},
+ ?line emul([QA], [QB], Seed, [element(I, Optab) || I <- Is]).
+
+optab() ->
+ {{new,[], q, fun () -> {[]} end},
+ {is_queue,[q], v, fun (_) -> true end},
+ {is_empty,[q], v, fun (Q) ->
+ case Q of
+ {[]} -> true;
+ _ -> false
+ end end},
+ {len,[q], v, fun ({L}) -> length(L) end},
+ {to_list,[q], v, fun ({L}) -> L end},
+ {from_list,[l], q, fun (L) -> {L} end},
+ {in,[t,q], q, fun (X,{L}) -> {L++[X]} end},
+ {in_r,[t,q], q, fun (X,{L}) -> {[X|L]} end},
+ {out,[q], {v,q}, fun ({L}=Q) ->
+ case L of
+ [] -> {empty,Q};
+ [X|T] -> {{value,X},{T}}
+ end
+ end},
+ {out_r,[q], {v,q}, fun ({L}=Q) ->
+ case L of
+ [] -> {empty,Q};
+ _ ->
+ [X|R] = lists:reverse(L),
+ T = lists:reverse(R),
+ {{value,X},{T}}
+ end
+ end},
+ {get,[q], v, fun ({[]}) -> erlang:error(empty);
+ ({[H|_]}) -> H
+ end},
+ {get_r,[q], v, fun ({[]}) -> erlang:error(empty);
+ ({L}) -> lists:last(L)
+ end},
+ {peek,[q], v, fun ({[]}) -> empty;
+ ({[H|_]}) -> {value,H}
+ end},
+ {peek_r,[q], v, fun ({[]}) -> empty;
+ ({L}) -> {value,lists:last(L)}
+ end},
+ {drop,[q], q, fun ({[]}) -> erlang:error(empty);
+ ({[_|T]}) -> {T}
+ end},
+ {drop_r,[q], q, fun ({[]}) -> erlang:error(empty);
+ ({L}) -> [_|R] = lists:reverse(L),
+ {lists:reverse(R)}
+ end},
+ {reverse,[q], q, fun ({L}) -> {lists:reverse(L)} end},
+ {join,[q,q], q, fun ({L1}, {L2}) -> {L1++L2} end},
+ {split,[n,q], {q,q}, fun (N, {L}) -> {L1,L2} = lists:split(N, L),
+ {{L1},{L2}} end},
+ {member,[t,q], v, fun (X, {L}) -> lists:member(X, L) end}
+ }.
+
+emul(_, _, _, []) ->
+ ok;
+emul(QsA0, QsB0, Seed0, [{Op,Ts,S,Fun}|Ops]) ->
+ {AsA,Seed} = args(Ts, QsA0, Seed0, []),
+ {AsB,Seed} = args(Ts, QsB0, Seed0, []),
+ io:format("~n% ~w % ~p ", [Op,AsA]),
+ io:format("% ~p :", [AsB]),
+ XX = call({queue,Op}, AsA),
+ YY = call(Fun, AsB),
+ case {XX,YY} of
+ {{value,X},{value,Y}} ->
+ {[Qa|_]=QsA,[{Lb}|_]=QsB} = chk(QsA0, QsB0, S, X, Y),
+ case queue:to_list(Qa) of
+ Lb ->
+ io:format("|~p| ", [Lb]),
+ emul(QsA, QsB, Seed, Ops);
+ La ->
+ throw({to_list,[XX,YY,Op,AsA,AsB,La,Lb]})
+ end;
+ {Exception,Exception} ->
+ io:format("!~p! ", [Exception]),
+ emul(QsA0, QsB0, Seed, Ops);
+ _ ->
+ throw({diff,[XX,YY,Op,AsA,AsB]})
+ end.
+
+args([], _, Seed, R) ->
+ {lists:reverse(R),Seed};
+args([q|Ts], [Q|Qs]=Qss, Seed, R) ->
+ args(Ts, if Qs =:= [] -> Qss; true -> Qs end, Seed, [Q|R]);
+args([l|Ts], Qs, Seed0, R) ->
+ {N,Seed1} = random:uniform_s(17, Seed0),
+ {L,Seed} = random_list(N, 4711, Seed1, []),
+ args(Ts, Qs, Seed, [L|R]);
+args([t|Ts], Qs, Seed0, R) ->
+ {T,Seed} = random:uniform_s(4711, Seed0),
+ args(Ts, Qs, Seed, [T|R]);
+args([n|Ts], Qs, Seed0, R) ->
+ {N,Seed} = random:uniform_s(17, Seed0),
+ args(Ts, Qs, Seed, [N|R]).
+
+random_list(0, _, Seed, R) ->
+ {R,Seed};
+random_list(N, M, Seed0, R) ->
+ {X,Seed} = random:uniform_s(M, Seed0),
+ random_list(N-1, M, Seed, [X|R]).
+
+call(Func, As) ->
+ try case Func of
+ {M,F} -> apply(M, F, As);
+ _ -> apply(Func, As)
+ end of
+ V ->
+ {value,V}
+ catch
+ Class:Reason ->
+ {Class,Reason}
+ end.
+
+chk(QsA, QsB, v, X, X) ->
+ io:format("<~p> ", [X]),
+ {QsA,QsB};
+chk(_, _, v, X, Y) ->
+ throw({diff,v,[X,Y]});
+chk(QsA, QsB, q, Qa, {Lb}=Qb) ->
+ case queue:to_list(Qa) of
+ Lb ->
+ io:format("|~p| ", [Lb]),
+ {[Qa|QsA],[Qb|QsB]};
+ La ->
+ throw({diff,q,[Qa,La,Lb]})
+ end;
+chk(QsA, QsB, T, X, Y)
+ when tuple_size(T) =:= tuple_size(X), tuple_size(T) =:= tuple_size(Y) ->
+ io:format("{"),
+ try
+ chk_tuple(QsA, QsB, T, X, Y, 1)
+ after
+ io:format("}")
+ end;
+chk(_, _, T, X, Y)
+ when is_tuple(T), is_tuple(X), is_tuple(Y) ->
+ throw({diff,T,[X,Y]}).
+
+chk_tuple(QsA, QsB, T, _, _, N) when N > tuple_size(T) ->
+ {QsA,QsB};
+chk_tuple(QsA0, QsB0, T, X, Y, N) ->
+ {QsA,QsB} = chk(QsA0, QsB0, element(N, T), element(N, X), element(N, Y)),
+ chk_tuple(QsA, QsB, T, X, Y, N+1).
diff --git a/lib/stdlib/test/random_SUITE.erl b/lib/stdlib/test/random_SUITE.erl
new file mode 100644
index 0000000000..8f1c304705
--- /dev/null
+++ b/lib/stdlib/test/random_SUITE.erl
@@ -0,0 +1,110 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+
+-module(random_SUITE).
+-export([all/1]).
+
+-export([interval_1/1, seed0/1, seed/1]).
+
+-export([init_per_testcase/2, fin_per_testcase/2]).
+
+-include("test_server.hrl").
+
+% Default timetrap timeout (set in init_per_testcase).
+-define(default_timeout, ?t:minutes(1)).
+
+init_per_testcase(_Case, Config) ->
+ ?line Dog = ?t:timetrap(?default_timeout),
+ [{watchdog, Dog} | Config].
+fin_per_testcase(_Case, Config) ->
+ Dog = ?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+all(doc) ->
+ ["Test cases for random."];
+all(suite) ->
+ [interval_1, seed0, seed].
+
+seed0(doc) ->
+ ["Test that seed is set implicitly, and always the same."];
+seed0(suite) ->
+ [];
+seed0(Config) when is_list(Config) ->
+ ?line Self = self(),
+ ?line _ = spawn(fun() -> Self ! random:uniform() end),
+ ?line F1 = receive
+ Fa -> Fa
+ end,
+ ?line _ = spawn(fun() -> random:seed(),
+ Self ! random:uniform() end),
+ ?line F2 = receive
+ Fb -> Fb
+ end,
+ ?line F1 = F2,
+ ok.
+
+seed(doc) ->
+ ["Test that seed/1 and seed/3 is equivalent."];
+seed(suite) ->
+ [];
+seed(Config) when is_list(Config) ->
+ ?line Self = self(),
+ ?line Seed = {S1, S2, S3} = now(),
+ ?line _ = spawn(fun() ->
+ random:seed(S1,S2,S3),
+ Rands = lists:foldl(fun
+ (_, Out) -> [random:uniform(10000)|Out]
+ end, [], lists:seq(1,100)),
+ Self ! {seed_test, Rands}
+ end),
+ ?line Rands1 = receive {seed_test, R1s} -> R1s end,
+ ?line _ = spawn(fun() ->
+ random:seed(Seed),
+ Rands = lists:foldl(fun
+ (_, Out) -> [random:uniform(10000)|Out]
+ end, [], lists:seq(1,100)),
+ Self ! {seed_test, Rands}
+ end),
+ ?line Rands2 = receive {seed_test, R2s} -> R2s end,
+ ?line Rands1 = Rands2,
+ ok.
+
+
+interval_1(doc) ->
+ ["Check that uniform/1 returns values within the proper interval."];
+interval_1(suite) ->
+ [];
+interval_1(Config) when is_list(Config) ->
+ ?line Top = 7,
+ ?line N = 10,
+ ?line check_interval(N, Top),
+ ok.
+
+check_interval(0, _) -> ok;
+check_interval(N, Top) ->
+ X = random:uniform(Top),
+ if
+ X < 1 ->
+ test_server:fail(too_small);
+ X > Top ->
+ test_server:fail(too_large);
+ true ->
+ ok
+ end,
+ check_interval(N-1, Top).
diff --git a/lib/stdlib/test/random_iolist.erl b/lib/stdlib/test/random_iolist.erl
new file mode 100644
index 0000000000..4bce347d9a
--- /dev/null
+++ b/lib/stdlib/test/random_iolist.erl
@@ -0,0 +1,195 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%% Generate random iolists to be used by crypto_SUITE.erl
+%%
+
+-module(random_iolist).
+
+-export([run/3, run2/3, standard_seed/0, compare/3, compare2/3,
+ random_iolist/1]).
+
+run(Iter,Fun1,Fun2) ->
+ standard_seed(),
+ compare(Iter,Fun1,Fun2).
+
+run2(Iter,Fun1,Fun2) ->
+ standard_seed(),
+ compare2(Iter,Fun1,Fun2).
+
+random_byte() ->
+ random:uniform(256) - 1.
+
+random_list(0,Acc) ->
+ Acc;
+random_list(N,Acc) ->
+ random_list(N-1,[random_byte() | Acc]).
+
+random_binary(N) ->
+ B = list_to_binary(random_list(N,[])),
+ case {random:uniform(2),size(B)} of
+ {2,M} when M > 1 ->
+ S = M-1,
+ <<_:3,C:S/binary,_:5>> = B,
+ C;
+ _ ->
+ B
+ end.
+random_list(N) ->
+ random_list(N,[]).
+
+front() ->
+ case random:uniform(10) of
+ 10 ->
+ false;
+ _ ->
+ true
+ end.
+
+any_type() ->
+ case random:uniform(10) of
+ 1 ->
+ list;
+ 2 ->
+ binary;
+ 3 ->
+ iolist;
+ _ ->
+ byte
+ end.
+
+tail_type() ->
+ case random:uniform(5) of
+ 1 ->
+ list;
+ 2 ->
+ iolist;
+ _ ->
+ binary
+ end.
+
+random_length(N) ->
+ UpperLimit = 255,
+ case N of
+ M when M > UpperLimit ->
+ random:uniform(UpperLimit+1) - 1;
+ _ ->
+ random:uniform(N+1) - 1
+ end.
+
+random_iolist(0,Acc) ->
+ Acc;
+random_iolist(N,Acc) ->
+ case front() of
+ true ->
+ case any_type() of
+ list ->
+ X = random_length(N),
+ L = random_list(X),
+ random_iolist(N-X,[L|Acc]);
+ binary ->
+ X = random_length(N),
+ B = random_binary(X),
+ random_iolist(N-X,[B|Acc]);
+ iolist ->
+ X = random_length(N),
+ B = random_iolist(X),
+ random_iolist(N-X,[B|Acc]);
+ byte ->
+ C = random_byte(),
+ random_iolist(N-1,[C|Acc])
+ end;
+ false ->
+ case tail_type() of
+ list ->
+ X = random_length(N),
+ L = random_list(X),
+ random_iolist(N-X,[Acc|L]);
+ binary ->
+ X = random_length(N),
+ B = random_binary(X),
+ random_iolist(N-X,[Acc|B]);
+ iolist ->
+ X = random_length(N),
+ B = random_iolist(X),
+ random_iolist(N-X,[Acc|B])
+ end
+ end.
+
+random_iolist(N) ->
+ random_iolist(N,[]).
+
+
+standard_seed() ->
+ random:seed(1201,855653,380975).
+
+do_comp(List,F1,F2) ->
+ X = F1(List),
+ Y = F2(List),
+ case X =:= Y of
+ false ->
+ exit({not_matching,List,X,Y});
+ _ ->
+ true
+ end.
+
+do_comp(List,List2,F1,F2) ->
+ X = F1(List,List2),
+ Y = F2(List,List2),
+ case X =:= Y of
+ false ->
+ exit({not_matching,List,List2,X,Y});
+ _ ->
+ true
+ end.
+
+compare(0,Fun1,Fun2) ->
+ do_comp(<<>>,Fun1,Fun2),
+ do_comp([],Fun1,Fun2),
+ do_comp([[]|<<>>],Fun1,Fun2),
+ do_comp([<<>>,[]|<<>>],Fun1,Fun2),
+ true;
+
+compare(N,Fun1,Fun2) ->
+ L = random_iolist(N),
+ do_comp(L,Fun1,Fun2),
+ compare(N-1,Fun1,Fun2).
+
+compare2(0,Fun1,Fun2) ->
+ L = random_iolist(100),
+ do_comp(<<>>,L,Fun1,Fun2),
+ do_comp(L,<<>>,Fun1,Fun2),
+ do_comp(<<>>,<<>>,Fun1,Fun2),
+ do_comp([],L,Fun1,Fun2),
+ do_comp(L,[],Fun1,Fun2),
+ do_comp([],[],Fun1,Fun2),
+ do_comp([[]|<<>>],L,Fun1,Fun2),
+ do_comp(L,[[]|<<>>],Fun1,Fun2),
+ do_comp([[]|<<>>],[[]|<<>>],Fun1,Fun2),
+ do_comp([<<>>,[]|<<>>],L,Fun1,Fun2),
+ do_comp(L,[<<>>,[]|<<>>],Fun1,Fun2),
+ do_comp([<<>>,[]|<<>>],[<<>>,[]|<<>>],Fun1,Fun2),
+ true;
+
+compare2(N,Fun1,Fun2) ->
+ L = random_iolist(N),
+ L2 = random_iolist(N),
+ do_comp(L,L2,Fun1,Fun2),
+ compare2(N-1,Fun1,Fun2).
diff --git a/lib/stdlib/test/random_unicode_list.erl b/lib/stdlib/test/random_unicode_list.erl
new file mode 100644
index 0000000000..3e83383b08
--- /dev/null
+++ b/lib/stdlib/test/random_unicode_list.erl
@@ -0,0 +1,270 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%% Generate random iolists to be used by crypto_SUITE.erl
+%%
+
+-module(random_unicode_list).
+
+-export([run/3, run/4, run2/3, standard_seed/0, compare/4, compare2/3,
+ random_unicode_list/2]).
+
+run(I,F1,F2) ->
+ run(I,F1,F2,utf8).
+run(Iter,Fun1,Fun2,Enc) ->
+ standard_seed(),
+ compare(Iter,Fun1,Fun2,Enc).
+
+run2(Iter,Fun1,Fun2) ->
+ standard_seed(),
+ compare2(Iter,Fun1,Fun2).
+
+int_to_utf8(I) when I =< 16#7F ->
+ <<I>>;
+int_to_utf8(I) when I =< 16#7FF ->
+ B2 = I,
+ B1 = (I bsr 6),
+ <<1:1,1:1,0:1,B1:5,1:1,0:1,B2:6>>;
+int_to_utf8(I) when I =< 16#FFFF ->
+ B3 = I,
+ B2 = (I bsr 6),
+ B1 = (I bsr 12),
+ <<1:1,1:1,1:1,0:1,B1:4,1:1,0:1,B2:6,1:1,0:1,B3:6>>;
+int_to_utf8(I) when I =< 16#3FFFFF ->
+ B4 = I,
+ B3 = (I bsr 6),
+ B2 = (I bsr 12),
+ B1 = (I bsr 18),
+ <<1:1,1:1,1:1,1:1,0:1,B1:3,1:1,0:1,B2:6,1:1,0:1,B3:6,1:1,0:1,B4:6>>;
+int_to_utf8(I) when I =< 16#3FFFFFF ->
+ B5 = I,
+ B4 = (I bsr 6),
+ B3 = (I bsr 12),
+ B2 = (I bsr 18),
+ B1 = (I bsr 24),
+ <<1:1,1:1,1:1,1:1,1:1,0:1,B1:2,1:1,0:1,B2:6,1:1,0:1,B3:6,1:1,0:1,B4:6,
+ 1:1,0:1,B5:6>>.
+
+int_to_utf16_big(I) when I < 16#10000 ->
+ <<I:16/big>>;
+int_to_utf16_big(I) ->
+ I2 = I - 16#10000,
+ B1 = 16#D800 bor (I2 bsr 10),
+ B2 = 16#DC00 bor (I2 band 16#3FF),
+ <<B1:16/big,B2:16/big>>.
+int_to_utf16_little(I) when I < 16#10000 ->
+ <<I:16/little>>;
+int_to_utf16_little(I) ->
+ I2 = I - 16#10000,
+ B1 = 16#D800 bor (I2 bsr 10),
+ B2 = 16#DC00 bor (I2 band 16#3FF),
+ <<B1:16/little,B2:16/little>>.
+int_to_utf32_big(I) ->
+ <<I:32/big>>.
+int_to_utf32_little(I) ->
+ <<I:32/little>>.
+
+id(I) -> I.
+
+random_char() ->
+ case random:uniform(16#10FFFF+1) - 1 of
+ X when X >= 16#D800,
+ X =< 16#DFFF ->
+ random_char();
+ Y ->
+ Y
+ end.
+
+random_list(0,Acc) ->
+ Acc;
+random_list(N,Acc) ->
+ random_list(N-1,[random_char() | Acc]).
+
+int_to(utf8,X) ->
+ int_to_utf8(X);
+int_to({utf16,big},X) ->
+ int_to_utf16_big(X);
+int_to({utf16,little},X) ->
+ int_to_utf16_little(X);
+int_to({utf32,big},X) ->
+ int_to_utf32_big(X);
+int_to({utf32,little},X) ->
+ int_to_utf32_little(X).
+
+
+random_binary(N,Enc) ->
+ L = random_list(N,[]),
+ B = iolist_to_binary(lists:map(fun(X) ->
+ int_to(Enc,X)
+ end,
+ L)),
+ case {random:uniform(3),size(B)} of
+ {2,M} when M > 1 ->
+ B2 = id(<<1:3,B/binary,1:5>>),
+ <<_:3,C:M/binary,_:5>> = B2,
+ C;
+ {3,M} when M > 1 ->
+ X = random:uniform(M+1)-1,
+ <<B1:X/binary,B2/binary>> = B,
+ [B1,B2];
+ _ ->
+ B
+ end.
+random_list(N) ->
+ random_list(N,[]).
+
+front() ->
+ case random:uniform(10) of
+ 10 ->
+ false;
+ _ ->
+ true
+ end.
+
+any_type() ->
+ case random:uniform(10) of
+ 1 ->
+ list;
+ 2 ->
+ binary;
+ 3 ->
+ iolist;
+ _ ->
+ char
+ end.
+
+tail_type() ->
+ case random:uniform(5) of
+ 1 ->
+ list;
+ 2 ->
+ iolist;
+ _ ->
+ binary
+ end.
+
+random_length(N) ->
+ UpperLimit = 255,
+ case N of
+ M when M > UpperLimit ->
+ random:uniform(UpperLimit+1) - 1;
+ _ ->
+ random:uniform(N+1) - 1
+ end.
+
+random_unicode_list(0,Acc,_Enc) ->
+ Acc;
+random_unicode_list(N,Acc,Enc) ->
+ case front() of
+ true ->
+ case any_type() of
+ list ->
+ X = random_length(N),
+ L = random_list(X),
+ random_unicode_list(N-X,[L|Acc],Enc);
+ binary ->
+ X = random_length(N),
+ B = random_binary(X,Enc),
+ random_unicode_list(N-X,[B|Acc],Enc);
+ iolist ->
+ X = random_length(N),
+ B = random_unicode_list(X,Enc),
+ random_unicode_list(N-X,[B|Acc],Enc);
+ char ->
+ C = random_char(),
+ random_unicode_list(N-1,[C|Acc],Enc)
+ end;
+ false ->
+ case tail_type() of
+ list ->
+ X = random_length(N),
+ L = random_list(X),
+ random_unicode_list(N-X,[Acc|L],Enc);
+ binary ->
+ X = random_length(N),
+ B = random_binary(X,Enc),
+ random_unicode_list(N-X,[Acc|B],Enc);
+ iolist ->
+ X = random_length(N),
+ B = random_unicode_list(X,Enc),
+ random_unicode_list(N-X,[Acc|B],Enc)
+ end
+ end.
+
+random_unicode_list(N,Enc) ->
+ random_unicode_list(N,[],Enc).
+
+
+standard_seed() ->
+ random:seed(1201,855653,380975).
+
+do_comp(List,F1,F2) ->
+ X = F1(List),
+ Y = F2(List),
+ case X =:= Y of
+ false ->
+ exit({not_matching,List,X,Y});
+ _ ->
+ true
+ end.
+
+do_comp(List,List2,F1,F2) ->
+ X = F1(List,List2),
+ Y = F2(List,List2),
+ case X =:= Y of
+ false ->
+ exit({not_matching,List,List2,X,Y});
+ _ ->
+ true
+ end.
+
+compare(0,Fun1,Fun2,_Enc) ->
+ do_comp(<<>>,Fun1,Fun2),
+ do_comp([],Fun1,Fun2),
+ do_comp([[]|<<>>],Fun1,Fun2),
+ do_comp([<<>>,[]|<<>>],Fun1,Fun2),
+ true;
+
+compare(N,Fun1,Fun2,Enc) ->
+ L = random_unicode_list(N,Enc),
+ do_comp(L,Fun1,Fun2),
+ compare(N-1,Fun1,Fun2,Enc).
+
+compare2(0,Fun1,Fun2) ->
+ L = random_unicode_list(100,utf8),
+ do_comp(<<>>,L,Fun1,Fun2),
+ do_comp(L,<<>>,Fun1,Fun2),
+ do_comp(<<>>,<<>>,Fun1,Fun2),
+ do_comp([],L,Fun1,Fun2),
+ do_comp(L,[],Fun1,Fun2),
+ do_comp([],[],Fun1,Fun2),
+ do_comp([[]|<<>>],L,Fun1,Fun2),
+ do_comp(L,[[]|<<>>],Fun1,Fun2),
+ do_comp([[]|<<>>],[[]|<<>>],Fun1,Fun2),
+ do_comp([<<>>,[]|<<>>],L,Fun1,Fun2),
+ do_comp(L,[<<>>,[]|<<>>],Fun1,Fun2),
+ do_comp([<<>>,[]|<<>>],[<<>>,[]|<<>>],Fun1,Fun2),
+ true;
+
+compare2(N,Fun1,Fun2) ->
+ L = random_unicode_list(N,utf8),
+ L2 = random_unicode_list(N,utf8),
+ do_comp(L,L2,Fun1,Fun2),
+ compare2(N-1,Fun1,Fun2).
diff --git a/lib/stdlib/test/re_SUITE.erl b/lib/stdlib/test/re_SUITE.erl
new file mode 100644
index 0000000000..98eb66d1fb
--- /dev/null
+++ b/lib/stdlib/test/re_SUITE.erl
@@ -0,0 +1,526 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(re_SUITE).
+
+-export([all/1, pcre/1,compile_options/1,run_options/1,combined_options/1,replace_autogen/1,global_capture/1,replace_return/1,split_autogen/1,split_options/1,split_specials/1,error_handling/1]).
+
+-include("test_server.hrl").
+-include_lib("kernel/include/file.hrl").
+
+all(suite) -> [pcre,compile_options,run_options,combined_options,replace_autogen,global_capture,replace_return,split_autogen,split_options,split_specials,error_handling].
+
+pcre(doc) ->
+ ["Run all applicable tests from the PCRE testsuites."];
+pcre(Config) when is_list(Config) ->
+ Dog = ?t:timetrap(?t:minutes(3)),
+ RootDir = ?config(data_dir, Config),
+ Res = run_pcre_tests:test(RootDir),
+ 0 = lists:sum([ X || {X,_,_} <- Res ]),
+ ?t:timetrap_cancel(Dog),
+ {comment,Res}.
+
+compile_options(doc) ->
+ ["Test all documented compile options"];
+compile_options(Config) when is_list(Config) ->
+ ?line ok = ctest("ABDabcdABCD","abcd",[],true,{match,[{3,4}]}),
+ ?line ok = ctest("ABDabcdABCD","abcd",[anchored],true,nomatch),
+ ?line ok = ctest("ABDabcdABCD",".*abcd",[anchored],true,{match,[{0,7}]}),
+ ?line ok = ctest("ABCabcdABC","ABCD",[],true,nomatch),
+ ?line ok = ctest("ABCabcdABC","ABCD",[caseless],true,{match,[{3,4}]}),
+ ?line ok = ctest("abcdABC\n","ABC$",[],true,{match,[{4,3}]}),
+ ?line ok = ctest("abcdABC\n","ABC$",[dollar_endonly],true,nomatch),
+ ?line ok = ctest("abcdABC\n","ABC.",[],true,nomatch),
+ ?line ok = ctest("abcdABC\n","ABC.",[dotall],true,{match,[{4,4}]}),
+ ?line ok = ctest("abcdABCD","ABC .",[],true,nomatch),
+ ?line ok = ctest("abcdABCD","ABC .",[extended],true,{match,[{4,4}]}),
+ ?line ok = ctest("abcd\nABCD","ABC",[],true,{match,[{5,3}]}),
+ ?line ok = ctest("abcd\nABCD","ABC",[firstline],true,nomatch),
+ ?line ok = ctest("abcd\nABCD","^ABC",[],true,nomatch),
+ ?line ok = ctest("abcd\nABCD","^ABC",[multiline],true,{match,[{5,3}]}),
+ ?line ok = ctest("abcdABCD","(ABC)",[],true,{match,[{4,3},{4,3}]}),
+ ?line ok = ctest("abcdABCD","(ABC)",[no_auto_capture],true,{match,[{4,3}]}),
+ ?line ok = ctest(notused,"(?<FOO>ABC)|(?<FOO>DEF)",[],false,notused),
+ ?line ok = ctest("abcdABCD","(?<FOO>ABC)|(?<FOO>DEF)",[dupnames],true,{match,[{4,3},{4,3}]}),
+ ?line ok = ctest("abcdABCDabcABCD","abcd.*D",[],true,{match,[{0,15}]}),
+ ?line ok = ctest("abcdABCDabcABCD","abcd.*D",[ungreedy],true,{match,[{0,8}]}),
+ ?line ok = ctest("abcdABCabcABC\nD","abcd.*D",[],true,nomatch),
+ ?line ok = ctest("abcdABCabcABC\nD","abcd.*D",[{newline,cr}],true,{match,[{0,15}]}),
+ ?line ok = ctest("abcdABCabcABC\rD","abcd.*D",[],true,{match,[{0,15}]}),
+ ?line ok = ctest("abcdABCabcABC\rD","abcd.*D",[{newline,lf}],true,{match,[{0,15}]}),
+ ?line ok = ctest("abcdABCabcd\r\n","abcd$",[{newline,lf}],true,nomatch),
+ ?line ok = ctest("abcdABCabcd\r\n","abcd$",[{newline,cr}],true,nomatch),
+ ?line ok = ctest("abcdABCabcd\r\n","abcd$",[{newline,crlf}],true,{match,[{7,4}]}),
+
+ ?line ok = ctest("abcdABCabcd\r","abcd$",[{newline,crlf}],true,nomatch),
+ ?line ok = ctest("abcdABCabcd\n","abcd$",[{newline,crlf}],true,nomatch),
+ ?line ok = ctest("abcdABCabcd\r\n","abcd$",[{newline,anycrlf}],true,{match,[{7,4}]}),
+
+ ?line ok = ctest("abcdABCabcd\r","abcd$",[{newline,anycrlf}],true,{match,[{7,4}]}),
+ ?line ok = ctest("abcdABCabcd\n","abcd$",[{newline,anycrlf}],true,{match,[{7,4}]}),
+ ok.
+
+run_options(doc) ->
+ ["Test all documented run specific options"];
+run_options(Config) when is_list(Config) ->
+ ?line rtest("ABCabcdABC","abc",[],[],true),
+ ?line rtest("ABCabcdABC","abc",[anchored],[],false),
+ % Anchored in run overrides unanchored in compilation
+ ?line rtest("ABCabcdABC","abc",[],[anchored],false),
+
+ ?line rtest("","a?b?",[],[],true),
+ ?line rtest("","a?b?",[],[notempty],false),
+
+ ?line rtest("abc","^a",[],[],true),
+ ?line rtest("abc","^a",[],[notbol],false),
+ ?line rtest("ab\nc","^a",[multiline],[],true),
+ ?line rtest("ab\nc","^a",[multiline],[notbol],false),
+ ?line rtest("ab\nc","^c",[multiline],[notbol],true),
+
+ ?line rtest("abc","c$",[],[],true),
+ ?line rtest("abc","c$",[],[noteol],false),
+
+ ?line rtest("ab\nc","b$",[multiline],[],true),
+ ?line rtest("ab\nc","c$",[multiline],[],true),
+ ?line rtest("ab\nc","b$",[multiline],[noteol],true),
+ ?line rtest("ab\nc","c$",[multiline],[noteol],false),
+
+ ?line rtest("abc","ab",[],[{offset,0}],true),
+ ?line rtest("abc","ab",[],[{offset,1}],false),
+
+ ?line rtest("abcdABCabcABC\nD","abcd.*D",[],[],false),
+ ?line rtest("abcdABCabcABC\nD","abcd.*D",[],[{newline,cr}],true),
+ ?line rtest("abcdABCabcABC\rD","abcd.*D",[],[],true),
+ ?line rtest("abcdABCabcABC\rD","abcd.*D",[{newline,cr}],[{newline,lf}],true),
+ ?line rtest("abcdABCabcd\r\n","abcd$",[],[{newline,lf}],false),
+ ?line rtest("abcdABCabcd\r\n","abcd$",[],[{newline,cr}],false),
+ ?line rtest("abcdABCabcd\r\n","abcd$",[],[{newline,crlf}],true),
+
+ ?line rtest("abcdABCabcd\r","abcd$",[],[{newline,crlf}],false),
+ ?line rtest("abcdABCabcd\n","abcd$",[],[{newline,crlf}],false),
+ ?line rtest("abcdABCabcd\r\n","abcd$",[],[{newline,anycrlf}],true),
+
+ ?line rtest("abcdABCabcd\r","abcd$",[],[{newline,anycrlf}],true),
+ ?line rtest("abcdABCabcd\n","abcd$",[],[{newline,anycrlf}],true),
+
+ ?line {ok,MP} = re:compile(".*(abcd).*"),
+ ?line {match,[{0,10},{3,4}]} = re:run("ABCabcdABC",MP,[]),
+ ?line {match,[{0,10},{3,4}]} = re:run("ABCabcdABC",MP,[{capture,all}]),
+ ?line {match,[{0,10},{3,4}]} = re:run("ABCabcdABC",MP,[{capture,all,index}]),
+ ?line {match,["ABCabcdABC","abcd"]} = re:run("ABCabcdABC",MP,[{capture,all,list}]),
+ ?line {match,[<<"ABCabcdABC">>,<<"abcd">>]} = re:run("ABCabcdABC",MP,[{capture,all,binary}]),
+ ?line {match,[{0,10}]} = re:run("ABCabcdABC",MP,[{capture,first}]),
+ ?line {match,[{0,10}]} = re:run("ABCabcdABC",MP,[{capture,first,index}]), ?line {match,["ABCabcdABC"]} = re:run("ABCabcdABC",MP,[{capture,first,list}]),
+ ?line {match,[<<"ABCabcdABC">>]} = re:run("ABCabcdABC",MP,[{capture,first,binary}]),
+
+ ?line {match,[{3,4}]} = re:run("ABCabcdABC",MP,[{capture,all_but_first}]),
+ ?line {match,[{3,4}]} = re:run("ABCabcdABC",MP,[{capture,all_but_first,index}]),
+ ?line {match,["abcd"]} = re:run("ABCabcdABC",MP,[{capture,all_but_first,list}]),
+ ?line {match,[<<"abcd">>]} = re:run("ABCabcdABC",MP,[{capture,all_but_first,binary}]),
+
+ ?line match = re:run("ABCabcdABC",MP,[{capture,none}]),
+ ?line match = re:run("ABCabcdABC",MP,[{capture,none,index}]),
+ ?line match = re:run("ABCabcdABC",MP,[{capture,none,list}]),
+ ?line match = re:run("ABCabcdABC",MP,[{capture,none,binary}]),
+
+ ?line {ok,MP2} = re:compile(".*(?<FOO>abcd).*"),
+ ?line {match,[{3,4}]} = re:run("ABCabcdABC",MP2,[{capture,[1]}]),
+ ?line {match,[{3,4}]} = re:run("ABCabcdABC",MP2,[{capture,['FOO']}]),
+ ?line {match,[{3,4}]} = re:run("ABCabcdABC",MP2,[{capture,["FOO"]}]),
+ ?line {match,["abcd"]} = re:run("ABCabcdABC",MP2,[{capture,["FOO"],list}]),
+ ?line {match,[<<"abcd">>]} = re:run("ABCabcdABC",MP2,[{capture,["FOO"],binary}]),
+
+ ?line {match,[{-1,0}]} = re:run("ABCabcdABC",MP2,[{capture,[200]}]),
+ ?line {match,[{-1,0}]} = re:run("ABCabcdABC",MP2,[{capture,['BAR']}]),
+ ?line {match,[""]} = re:run("ABCabcdABC",MP2,[{capture,[200],list}]),
+ ?line {match,[""]} = re:run("ABCabcdABC",MP2,[{capture,['BAR'],list}]),
+ ?line {match,[<<>>]} = re:run("ABCabcdABC",MP2,[{capture,[200],binary}]),
+ ?line {match,[<<>>]} = re:run("ABCabcdABC",MP2,[{capture,['BAR'],binary}]),
+
+ ?line {ok, MP3} = re:compile(".*((?<FOO>abdd)|a(..d)).*"),
+ ?line {match,[{0,10},{3,4},{-1,0},{4,3}]} = re:run("ABCabcdABC",MP3,[]),
+ ?line {match,[{0,10},{3,4},{-1,0},{4,3}]} = re:run("ABCabcdABC",MP3,[{capture,all,index}]),
+ ?line {match,[<<"ABCabcdABC">>,<<"abcd">>,<<>>,<<"bcd">>]} = re:run("ABCabcdABC",MP3,[{capture,all,binary}]),
+ ?line {match,["ABCabcdABC","abcd",[],"bcd"]} = re:run("ABCabcdABC",MP3,[{capture,all,list}]),
+ ok.
+
+
+
+combined_options(doc) ->
+ ["Test compile options given directly to run"];
+combined_options(Config) when is_list(Config) ->
+ ?line ok = crtest("ABDabcdABCD","abcd",[],true,{match,[{3,4}]}),
+ ?line ok = crtest("ABDabcdABCD","abcd",[anchored],true,nomatch),
+ ?line ok = crtest("ABDabcdABCD",".*abcd",[anchored],true,{match,[{0,7}]}),
+ ?line ok = crtest("ABCabcdABC","ABCD",[],true,nomatch),
+ ?line ok = crtest("ABCabcdABC","ABCD",[caseless],true,{match,[{3,4}]}),
+ ?line ok = crtest("abcdABC\n","ABC$",[],true,{match,[{4,3}]}),
+ ?line ok = crtest("abcdABC\n","ABC$",[dollar_endonly],true,nomatch),
+ ?line ok = crtest("abcdABC\n","ABC.",[],true,nomatch),
+ ?line ok = crtest("abcdABC\n","ABC.",[dotall],true,{match,[{4,4}]}),
+ ?line ok = crtest("abcdABCD","ABC .",[],true,nomatch),
+ ?line ok = crtest("abcdABCD","ABC .",[extended],true,{match,[{4,4}]}),
+ ?line ok = crtest("abcd\nABCD","ABC",[],true,{match,[{5,3}]}),
+ ?line ok = crtest("abcd\nABCD","ABC",[firstline],true,nomatch),
+ ?line ok = crtest("abcd\nABCD","^ABC",[],true,nomatch),
+ ?line ok = crtest("abcd\nABCD","^ABC",[multiline],true,{match,[{5,3}]}),
+ ?line ok = crtest("abcdABCD","(ABC)",[],true,{match,[{4,3},{4,3}]}),
+ ?line ok = crtest("abcdABCD","(ABC)",[no_auto_capture],true,{match,[{4,3}]}),
+ ?line ok = crtest(notused,"(?<FOO>ABC)|(?<FOO>DEF)",[],false,notused),
+ ?line ok = crtest("abcdABCD","(?<FOO>ABC)|(?<FOO>DEF)",[dupnames],true,{match,[{4,3},{4,3}]}),
+ ?line ok = crtest("abcdABCDabcABCD","abcd.*D",[],true,{match,[{0,15}]}),
+ ?line ok = crtest("abcdABCDabcABCD","abcd.*D",[ungreedy],true,{match,[{0,8}]}),
+ ?line ok = ctest("abcdABCabcABC\nD","abcd.*D",[],true,nomatch),
+ ?line ok = crtest("abcdABCabcABC\nD","abcd.*D",[{newline,cr}],true,{match,[{0,15}]}),
+ ?line ok = crtest("abcdABCabcABC\rD","abcd.*D",[],true,{match,[{0,15}]}),
+ ?line ok = crtest("abcdABCabcABC\rD","abcd.*D",[{newline,lf}],true,{match,[{0,15}]}),
+ ?line ok = crtest("abcdABCabcd\r\n","abcd$",[{newline,lf}],true,nomatch),
+ ?line ok = crtest("abcdABCabcd\r\n","abcd$",[{newline,cr}],true,nomatch),
+ ?line ok = crtest("abcdABCabcd\r\n","abcd$",[{newline,crlf}],true,{match,[{7,4}]}),
+
+ ?line ok = crtest("abcdABCabcd\r","abcd$",[{newline,crlf}],true,nomatch),
+ ?line ok = crtest("abcdABCabcd\n","abcd$",[{newline,crlf}],true,nomatch),
+ ?line ok = crtest("abcdABCabcd\r\n","abcd$",[{newline,anycrlf}],true,{match,[{7,4}]}),
+
+ ?line ok = crtest("abcdABCabcd\r","abcd$",[{newline,anycrlf}],true,{match,[{7,4}]}),
+ ?line ok = crtest("abcdABCabcd\n","abcd$",[{newline,anycrlf}],true,{match,[{7,4}]}),
+
+ ?line ok = crtest("abcdABCabcd\r\n","abcd$",[{newline,anycrlf},{capture,all,list}],true,{match,["abcd"]}),
+
+ ?line ok = crtest("abcdABCabcd\r","abcd$",[{newline,anycrlf},{capture,all,list}],true,{match,["abcd"]}),
+
+ ?line ok = crtest("abcdABCabcd\n","abcd$",[{newline,anycrlf},{capture,all,list}],true,{match,["abcd"]}),
+
+ ?line ok = crtest("abcdABCabcd\r\n","abcd$",[{newline,anycrlf},{capture,all,binary}],true,{match,[<<"abcd">>]}),
+
+ ?line ok = crtest("abcdABCabcd\r","abcd$",[{newline,anycrlf},{capture,all,binary}],true,{match,[<<"abcd">>]}),
+ ?line ok = crtest("abcdABCabcd\n","abcd$",[{newline,anycrlf},{capture,all,binary}],true,{match,[<<"abcd">>]}),
+
+ % Check that unique run-options fail in compile only case:
+ ?line {'EXIT',{badarg,_}} = (catch re:compile("abcd$",[{newline,anycrlf},{capture,all,binary}])),
+ ?line {'EXIT',{badarg,_}} = (catch re:compile("abcd$",[{newline,anycrlf},{offset,3}])),
+ ?line {'EXIT',{badarg,_}} = (catch re:compile("abcd$",[{newline,anycrlf},notempty])),
+ ?line {'EXIT',{badarg,_}} = (catch re:compile("abcd$",[{newline,anycrlf},notbol])),
+ ?line {'EXIT',{badarg,_}} = (catch re:compile("abcd$",[{newline,anycrlf},noteol])),
+
+
+ ?line {match,_} = re:run("abcdABCabcd\r\n","abcd$",[{newline,crlf}]),
+ ?line nomatch = re:run("abcdABCabcd\r\nefgh","abcd$",[{newline,crlf}]),
+ ?line {match,_} = re:run("abcdABCabcd\r\nefgh","abcd$",[{newline,crlf},multiline]),
+ ?line nomatch = re:run("abcdABCabcd\r\nefgh","efgh$",[{newline,crlf},multiline,noteol]),
+ ?line {match,_} = re:run("abcdABCabcd\r\nefgh","abcd$",[{newline,crlf},multiline,noteol]),
+ ?line {match,_} = re:run("abcdABCabcd\r\nefgh","^abcd",[{newline,crlf},multiline,noteol]),
+ ?line nomatch = re:run("abcdABCabcd\r\nefgh","^abcd",[{newline,crlf},multiline,notbol]),
+ ?line {match,_} = re:run("abcdABCabcd\r\nefgh","^efgh",[{newline,crlf},multiline,notbol]),
+ ?line {match,_} = re:run("ABC\nD","[a-z]*",[{newline,crlf}]),
+ ?line nomatch = re:run("ABC\nD","[a-z]*",[{newline,crlf},notempty]),
+ ok.
+
+replace_autogen(doc) ->
+ ["Test replace with autogenerated erlang module"];
+replace_autogen(Config) when is_list(Config) ->
+ Dog = ?t:timetrap(?t:minutes(3)),
+ re_testoutput1_replacement_test:run(),
+ ?t:timetrap_cancel(Dog),
+ ok.
+
+global_capture(doc) ->
+ ["Tests capture options together with global searching"];
+global_capture(Config) when is_list(Config) ->
+ Dog = ?t:timetrap(?t:minutes(3)),
+ ?line {match,[{3,4}]} = re:run("ABCabcdABC",".*(?<FOO>abcd).*",[{capture,[1]}]),
+ ?line {match,[{10,4}]} = re:run("ABCabcdABCabcdA",".*(?<FOO>abcd).*",[{capture,[1]}]),
+ ?line {match,[[{10,4}]]} = re:run("ABCabcdABCabcdA",".*(?<FOO>abcd).*",[global,{capture,[1]}]),
+ ?line {match,[{3,4}]} = re:run("ABCabcdABC",".*(?<FOO>abcd).*",[{capture,['FOO']}]),
+ ?line {match,[{10,4}]} = re:run("ABCabcdABCabcdA",".*(?<FOO>abcd).*",[{capture,['FOO']}]),
+ ?line {match,[[{10,4}]]} = re:run("ABCabcdABCabcdA",".*(?<FOO>abcd).*",[global,{capture,['FOO']}]),
+ ?line {match,[[{3,4},{3,4}],[{10,4},{10,4}]]} = re:run("ABCabcdABCabcdA","(?<FOO>abcd)",[global]),
+ ?line {match,[[{3,4},{3,4}],[{10,4},{10,4}]]} = re:run("ABCabcdABCabcdA","(?<FOO>abcd)",[global,{capture,all}]),
+ ?line {match,[[{3,4},{3,4}],[{10,4},{10,4}]]} = re:run("ABCabcdABCabcdA","(?<FOO>abcd)",[global,{capture,all,index}]),
+ ?line {match,[[{3,4}],[{10,4}]]} = re:run("ABCabcdABCabcdA","(?<FOO>abcd)",[global,{capture,first}]),
+ ?line {match,[[{3,4}],[{10,4}]]} = re:run("ABCabcdABCabcdA","(?<FOO>abcd)",[global,{capture,all_but_first}]),
+ ?line {match,[[<<"bcd">>],[<<"bcd">>]]} = re:run("ABCabcdABCabcdA","a(?<FOO>bcd)",[global,{capture,all_but_first,binary}]),
+ ?line {match,[["bcd"],["bcd"]]} = re:run("ABCabcdABCabcdA","a(?<FOO>bcd)",[global,{capture,all_but_first,list}]),
+ ?line {match,[["abcd","bcd"],["abcd","bcd"]]} = re:run("ABCabcdABCabcdA","a(?<FOO>bcd)",[global,{capture,all,list}]),
+ ?line {match,[[<<"abcd">>,<<"bcd">>],[<<"abcd">>,<<"bcd">>]]} = re:run("ABCabcdABCabcdA","a(?<FOO>bcd)",[global,{capture,all,binary}]),
+ ?line {match,[[{3,4},{4,3}],[{10,4},{11,3}]]} = re:run("ABCabcdABCabcdA","a(?<FOO>bcd)",[global,{capture,all,index}]),
+ ?line match = re:run("ABCabcdABCabcdA","a(?<FOO>bcd)",[global,{capture,none,index}]),
+ ?line match = re:run("ABCabcdABCabcdA","a(?<FOO>bcd)",[global,{capture,none,binary}]),
+ ?line match = re:run("ABCabcdABCabcdA","a(?<FOO>bcd)",[global,{capture,none,list}]),
+ ?line {match,[[<<195,133,98,99,100>>,<<"bcd">>],[<<"abcd">>,<<"bcd">>]]} = re:run("ABC�bcdABCabcdA",".(?<FOO>bcd)",[global,{capture,all,binary},unicode]),
+ ?line {match,[["�bcd","bcd"],["abcd","bcd"]]} = re:run(<<"ABC",8#303,8#205,"bcdABCabcdA">>,".(?<FOO>bcd)",[global,{capture,all,list},unicode]),
+ ?line {match,[["�bcd","bcd"],["abcd","bcd"]]} = re:run("ABC�bcdABCabcdA",".(?<FOO>bcd)",[global,{capture,all,list},unicode]),
+ ?line {match,[[{3,5},{5,3}],[{11,4},{12,3}]]} = re:run("ABC�bcdABCabcdA",".(?<FOO>bcd)",[global,{capture,all,index},unicode]),
+ ?t:timetrap_cancel(Dog),
+ ok.
+
+replace_return(doc) ->
+ ["Tests return options of replace together with global searching"];
+replace_return(Config) when is_list(Config) ->
+ Dog = ?t:timetrap(?t:minutes(3)),
+ ?line {'EXIT',{badarg,_}} = (catch re:replace("na","(a","")),
+ ?line <<"nasse">> = re:replace(<<"nisse">>,"i","a",[{return,binary}]),
+ ?line <<"ABC�XABCXA">> = re:replace("ABC\305abcdABCabcdA","a(?<FOO>bcd)","X",[global,{return,binary}]),
+
+ ?line [<<"ABC�">>,
+ <<"X">>,
+ <<"ABC">>,
+ <<"X">> |
+ <<"A">> ] =
+ re:replace("ABC�abcdABCabcdA","a(?<FOO>bcd)","X",[global,{return,iodata}]),
+ ?line "ABC�XABCXA" = re:replace("ABC�abcdABCabcdA","a(?<FOO>bcd)","X",[global,{return,list},unicode]),
+ ?line <<65,66,67,195,133,88,65,66,67,88,65>> = re:replace("ABC�abcdABCabcdA","a(?<FOO>bcd)","X",[global,{return,binary},unicode]),
+ ?line <<65,66,67,195,133,88,65,66,67,97,98,99,100,65>> = re:replace("ABC�abcdABCabcdA","a(?<FOO>bcd)","X",[{return,binary},unicode]),
+ ?line <<"iXk">> = re:replace("abcdefghijk","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\9X",[{return,binary}]),
+ ?line <<"jXk">> = re:replace("abcdefghijk","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\10X",[{return,binary}]),
+ ?line <<"Xk">> = re:replace("abcdefghijk","(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)","\\11X",[{return,binary}]),
+ ?t:timetrap_cancel(Dog),
+ ok.
+
+rtest(Subj, RE, Copt, Ropt, true) ->
+ {ok,MP} = re:compile(RE,Copt),
+ {match,_} = re:run(Subj,MP,Ropt),
+ ok;
+rtest(Subj, RE, Copt, Ropt, false) ->
+ {ok,MP} = re:compile(RE,Copt),
+ nomatch = re:run(Subj,MP,Ropt),
+ ok.
+
+ctest(_,RE,Options,false,_) ->
+ case re:compile(RE,Options) of
+ {ok,_} ->
+ error;
+ {error,_} ->
+ ok
+ end;
+ctest(Subject,RE,Options,true,Result) ->
+ try
+ {ok, Prog} = re:compile(RE,Options),
+ Result = re:run(Subject,Prog,[]),
+ ok
+ catch
+ _:_ ->
+ error
+ end.
+crtest(_,RE,Options,false,_) ->
+ case (catch re:run("",RE,Options)) of
+ {'EXIT',{badarg,_}} ->
+ ok;
+ _ ->
+ error
+ end;
+crtest(Subject,RE,Options,true,Result) ->
+ try
+ Result = re:run(Subject,RE,Options),
+ ok
+ catch
+ _:_ ->
+ error
+ end.
+
+split_autogen(doc) ->
+ ["Test split with autogenerated erlang module"];
+split_autogen(Config) when is_list(Config) ->
+ Dog = ?t:timetrap(?t:minutes(3)),
+ re_testoutput1_split_test:run(),
+ ?t:timetrap_cancel(Dog),
+ ok.
+
+split_options(doc) ->
+ ["Test special options to split."];
+split_options(Config) when is_list(Config) ->
+ Dog = ?t:timetrap(?t:minutes(1)),
+ ?line [[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],[<<"c">>,<<" ">>]] = re:split("a b c ","( )",[group,trim]),
+ ?line [[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],[<<"c">>,<<" ">>]] = re:split("a b c ","( )",[group,{parts,0}]),
+ ?line [[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],[<<"c">>,<<" ">>],[<<>>]] =
+ re:split("a b c ","( )",[{parts,infinity},group]),
+ ?line [[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],[<<"c">>,<<" ">>],[<<>>]] =
+ re:split("a b c ","( )",[group]),
+ ?line [[<<>>,<<" ">>],[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],
+ [<<"c">>,<<" ">>],[<<"d">>,<<" ">>]] =
+ re:split(" a b c d ","( +)",[group,trim]),
+ ?line [[<<>>,<<" ">>],[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],
+ [<<"c">>,<<" ">>],[<<"d">>,<<" ">>]] =
+ re:split(" a b c d ","( +)",[{parts,0},group]),
+ ?line [[<<>>,<<" ">>],[<<"a">>,<<" ">>],[<<"b">>,<<" ">>],
+ [<<"c">>,<<" ">>],[<<"d">>,<<" ">>],[<<>>]] =
+ re:split(" a b c d ","( +)",[{parts,infinity},group]),
+ ?line [[<<"a">>,<<" ">>],[<<"b c d">>]] =
+ re:split("a b c d","( +)",[{parts,2},group]),
+ ?line [[[967]," "],["b c d"]] =
+ re:split([967]++" b c d","( +)",
+ [{parts,2},group,{return,list},unicode]),
+ ?line [[<<207,135>>,<<" ">>],[<<"b c d">>]] =
+ re:split([967]++" b c d","( +)",
+ [{parts,2},group,{return,binary},unicode]),
+ ?line {'EXIT',{badarg,_}} =
+ (catch re:split([967]++" b c d","( +)",
+ [{parts,2},group,{return,binary}])),
+ ?line {'EXIT',{badarg,_}} =
+ (catch re:split("a b c d","( +)",[{parts,-2}])),
+ ?line {'EXIT',{badarg,_}} =
+ (catch re:split("a b c d","( +)",[{parts,banan}])),
+ ?line {'EXIT',{badarg,_}} =
+ (catch re:split("a b c d","( +)",[{capture,all}])),
+ ?line {'EXIT',{badarg,_}} =
+ (catch re:split("a b c d","( +)",[{capture,[],binary}])),
+ % Parts 0 is equal to no parts specification (implicit strip)
+ ?line ["a"," ","b"," ","c"," ","d"] =
+ re:split("a b c d","( *)",[{parts,0},{return,list}]),
+ ?t:timetrap_cancel(Dog),
+ ok.
+
+join([]) -> [];
+join([A]) -> [A];
+join([H|T]) -> [H,<<":">>|join(T)].
+
+split_specials(doc) ->
+ ["Some special cases of split that are easy to get wrong."];
+split_specials(Config) when is_list(Config) ->
+ %% More or less just to remember these icky cases
+ Dog = ?t:timetrap(?t:minutes(1)),
+ ?line <<"::abd:f">> =
+ iolist_to_binary(join(re:split("abdf","^(?!(ab)de|x)(abd)(f)",[trim]))),
+ ?line <<":abc2xyzabc3">> =
+ iolist_to_binary(join(re:split("abc1abc2xyzabc3","\\Aabc.",[trim]))),
+ ?t:timetrap_cancel(Dog),
+ ok.
+
+
+error_handling(doc) ->
+ ["Test that errors are handled correctly by the erlang code."];
+error_handling(Config) when is_list(Config) ->
+ % This test checks the exception tuples manufactured in the erlang
+ % code to hide the trapping from the user at least when it comes to errors
+ Dog = ?t:timetrap(?t:minutes(1)),
+ % The malformed precomiled RE is detected after
+ % the trap to re:grun from grun, in the grun function clause
+ % that handles precompiled expressions
+ ?line {'EXIT',{badarg,[{re,run,["apa",{1,2,3,4},[global]]},
+ {?MODULE, error_handling,1} | _]}} =
+ (catch re:run("apa",{1,2,3,4},[global])),
+ % An invalid capture list will also cause a badarg late,
+ % but with a non pre compiled RE, the exception should be thrown by the
+ % grun function clause that handles RE's compiled implicitly by
+ % the run/3 BIF before trapping.
+ ?line {'EXIT',{badarg,[{re,run,["apa","p",[{capture,[1,{a}]},global]]},
+ {?MODULE, error_handling,1} | _]}} =
+ (catch re:run("apa","p",[{capture,[1,{a}]},global])),
+ % And so the case of a precompiled expression together with
+ % a compile-option (binary and list subject):
+ ?line {ok,RE} = re:compile("(p)"),
+ ?line {match,[[{1,1},{1,1}]]} = re:run(<<"apa">>,RE,[global]),
+ ?line {match,[[{1,1},{1,1}]]} = re:run("apa",RE,[global]),
+ {'EXIT',{badarg,[{re,run,
+ [<<"apa">>,
+ {re_pattern,1,0,_},
+ [global,unicode]]},
+ {?MODULE, error_handling,1} | _]}} =
+ (catch re:run(<<"apa">>,RE,[global,unicode])),
+ {'EXIT',{badarg,[{re,run,
+ ["apa",
+ {re_pattern,1,0,_},
+ [global,unicode]]},
+ {?MODULE, error_handling,1} | _]}} =
+ (catch re:run("apa",RE,[global,unicode])),
+ ?line {'EXIT',{badarg,_}} = (catch re:run("apa","(p",[])),
+ ?line {'EXIT',{badarg,_}} = (catch re:run("apa","(p",[global])),
+ % The replace errors:
+ ?line {'EXIT',{badarg,[{re,replace,["apa",{1,2,3,4},"X",[]]},
+ {?MODULE, error_handling,1} | _]}} =
+ (catch re:replace("apa",{1,2,3,4},"X",[])),
+ ?line {'EXIT',{badarg,[{re,replace,["apa",{1,2,3,4},"X",[global]]},
+ {?MODULE, error_handling,1} | _]}} =
+ (catch re:replace("apa",{1,2,3,4},"X",[global])),
+ ?line {'EXIT',{badarg,[{re,replace,
+ ["apa",
+ {re_pattern,1,0,_},
+ "X",
+ [unicode]]},
+ {?MODULE, error_handling,1} | _]}} =
+ (catch re:replace("apa",RE,"X",[unicode])),
+ ?line <<"aXa">> = iolist_to_binary(re:replace("apa","p","X",[])),
+ ?line {'EXIT',{badarg,[{re,replace,
+ ["apa","p","X",[{capture,all,binary}]]},
+ {?MODULE, error_handling,1} | _]}} =
+ (catch iolist_to_binary(re:replace("apa","p","X",
+ [{capture,all,binary}]))),
+ ?line {'EXIT',{badarg,[{re,replace,
+ ["apa","p","X",[{capture,all}]]},
+ {?MODULE, error_handling,1} | _]}} =
+ (catch iolist_to_binary(re:replace("apa","p","X",
+ [{capture,all}]))),
+ ?line {'EXIT',{badarg,[{re,replace,
+ ["apa","p","X",[{return,banana}]]},
+ {?MODULE, error_handling,1} | _]}} =
+ (catch iolist_to_binary(re:replace("apa","p","X",
+ [{return,banana}]))),
+ ?line {'EXIT',{badarg,_}} = (catch re:replace("apa","(p","X",[])),
+ % Badarg, not compile error.
+ ?line {'EXIT',{badarg,[{re,replace,
+ ["apa","(p","X",[{return,banana}]]},
+ {?MODULE, error_handling,1} | _]}} =
+ (catch iolist_to_binary(re:replace("apa","(p","X",
+ [{return,banana}]))),
+ % And the split errors:
+ ?line [<<"a">>,<<"a">>] = (catch re:split("apa","p",[])),
+ ?line [<<"a">>,<<"p">>,<<"a">>] = (catch re:split("apa",RE,[])),
+ ?line {'EXIT',{badarg,[{re,split,["apa","p",[global]]},
+ {?MODULE, error_handling,1} | _]}} =
+ (catch re:split("apa","p",[global])),
+ ?line {'EXIT',{badarg,[{re,split,["apa","p",[{capture,all}]]},
+ {?MODULE, error_handling,1} | _]}} =
+ (catch re:split("apa","p",[{capture,all}])),
+ ?line {'EXIT',{badarg,[{re,split,["apa","p",[{capture,all,binary}]]},
+ {?MODULE, error_handling,1} | _]}} =
+ (catch re:split("apa","p",[{capture,all,binary}])),
+ ?line {'EXIT',{badarg,[{re,split,["apa",{1,2,3,4},[]]},
+ {?MODULE, error_handling,1} | _]}} =
+ (catch re:split("apa",{1,2,3,4})),
+ ?line {'EXIT',{badarg,[{re,split,["apa",{1,2,3,4},[]]},
+ {?MODULE, error_handling,1} | _]}} =
+ (catch re:split("apa",{1,2,3,4},[])),
+ ?line {'EXIT',{badarg,[{re,split,
+ ["apa",
+ RE,
+ [unicode]]},
+ {?MODULE, error_handling,1} | _]}} =
+ (catch re:split("apa",RE,[unicode])),
+ ?line {'EXIT',{badarg,[{re,split,
+ ["apa",
+ RE,
+ [{return,banana}]]},
+ {?MODULE, error_handling,1} | _]}} =
+ (catch re:split("apa",RE,[{return,banana}])),
+ ?line {'EXIT',{badarg,[{re,split,
+ ["apa",
+ RE,
+ [banana]]},
+ {?MODULE, error_handling,1} | _]}} =
+ (catch re:split("apa",RE,[banana])),
+ ?line {'EXIT',{badarg,_}} = (catch re:split("apa","(p")),
+ %Exception on bad argument, not compilation error
+ ?line {'EXIT',{badarg,[{re,split,
+ ["apa",
+ "(p",
+ [banana]]},
+ {?MODULE, error_handling,1} | _]}} =
+ (catch re:split("apa","(p",[banana])),
+ ?t:timetrap_cancel(Dog),
+ ok.
+
diff --git a/lib/stdlib/test/re_SUITE_data/testoutput1 b/lib/stdlib/test/re_SUITE_data/testoutput1
new file mode 100644
index 0000000000..3bf4ffbeee
--- /dev/null
+++ b/lib/stdlib/test/re_SUITE_data/testoutput1
@@ -0,0 +1,6608 @@
+/the quick brown fox/
+ the quick brown fox
+ 0: the quick brown fox
+ The quick brown FOX
+No match
+ What do you know about the quick brown fox?
+ 0: the quick brown fox
+ What do you know about THE QUICK BROWN FOX?
+No match
+
+/The quick brown fox/i
+ the quick brown fox
+ 0: the quick brown fox
+ The quick brown FOX
+ 0: The quick brown FOX
+ What do you know about the quick brown fox?
+ 0: the quick brown fox
+ What do you know about THE QUICK BROWN FOX?
+ 0: THE QUICK BROWN FOX
+
+/abcd\t\n\r\f\a\e\071\x3b\$\\\?caxyz/
+ abcd\t\n\r\f\a\e9;\$\\?caxyz
+ 0: abcd\x09\x0a\x0d\x0c\x07\x1b9;$\?caxyz
+
+/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/
+ abxyzpqrrrabbxyyyypqAzz
+ 0: abxyzpqrrrabbxyyyypqAzz
+ abxyzpqrrrabbxyyyypqAzz
+ 0: abxyzpqrrrabbxyyyypqAzz
+ aabxyzpqrrrabbxyyyypqAzz
+ 0: aabxyzpqrrrabbxyyyypqAzz
+ aaabxyzpqrrrabbxyyyypqAzz
+ 0: aaabxyzpqrrrabbxyyyypqAzz
+ aaaabxyzpqrrrabbxyyyypqAzz
+ 0: aaaabxyzpqrrrabbxyyyypqAzz
+ abcxyzpqrrrabbxyyyypqAzz
+ 0: abcxyzpqrrrabbxyyyypqAzz
+ aabcxyzpqrrrabbxyyyypqAzz
+ 0: aabcxyzpqrrrabbxyyyypqAzz
+ aaabcxyzpqrrrabbxyyyypAzz
+ 0: aaabcxyzpqrrrabbxyyyypAzz
+ aaabcxyzpqrrrabbxyyyypqAzz
+ 0: aaabcxyzpqrrrabbxyyyypqAzz
+ aaabcxyzpqrrrabbxyyyypqqAzz
+ 0: aaabcxyzpqrrrabbxyyyypqqAzz
+ aaabcxyzpqrrrabbxyyyypqqqAzz
+ 0: aaabcxyzpqrrrabbxyyyypqqqAzz
+ aaabcxyzpqrrrabbxyyyypqqqqAzz
+ 0: aaabcxyzpqrrrabbxyyyypqqqqAzz
+ aaabcxyzpqrrrabbxyyyypqqqqqAzz
+ 0: aaabcxyzpqrrrabbxyyyypqqqqqAzz
+ aaabcxyzpqrrrabbxyyyypqqqqqqAzz
+ 0: aaabcxyzpqrrrabbxyyyypqqqqqqAzz
+ aaaabcxyzpqrrrabbxyyyypqAzz
+ 0: aaaabcxyzpqrrrabbxyyyypqAzz
+ abxyzzpqrrrabbxyyyypqAzz
+ 0: abxyzzpqrrrabbxyyyypqAzz
+ aabxyzzzpqrrrabbxyyyypqAzz
+ 0: aabxyzzzpqrrrabbxyyyypqAzz
+ aaabxyzzzzpqrrrabbxyyyypqAzz
+ 0: aaabxyzzzzpqrrrabbxyyyypqAzz
+ aaaabxyzzzzpqrrrabbxyyyypqAzz
+ 0: aaaabxyzzzzpqrrrabbxyyyypqAzz
+ abcxyzzpqrrrabbxyyyypqAzz
+ 0: abcxyzzpqrrrabbxyyyypqAzz
+ aabcxyzzzpqrrrabbxyyyypqAzz
+ 0: aabcxyzzzpqrrrabbxyyyypqAzz
+ aaabcxyzzzzpqrrrabbxyyyypqAzz
+ 0: aaabcxyzzzzpqrrrabbxyyyypqAzz
+ aaaabcxyzzzzpqrrrabbxyyyypqAzz
+ 0: aaaabcxyzzzzpqrrrabbxyyyypqAzz
+ aaaabcxyzzzzpqrrrabbbxyyyypqAzz
+ 0: aaaabcxyzzzzpqrrrabbbxyyyypqAzz
+ aaaabcxyzzzzpqrrrabbbxyyyyypqAzz
+ 0: aaaabcxyzzzzpqrrrabbbxyyyyypqAzz
+ aaabcxyzpqrrrabbxyyyypABzz
+ 0: aaabcxyzpqrrrabbxyyyypABzz
+ aaabcxyzpqrrrabbxyyyypABBzz
+ 0: aaabcxyzpqrrrabbxyyyypABBzz
+ >>>aaabxyzpqrrrabbxyyyypqAzz
+ 0: aaabxyzpqrrrabbxyyyypqAzz
+ >aaaabxyzpqrrrabbxyyyypqAzz
+ 0: aaaabxyzpqrrrabbxyyyypqAzz
+ >>>>abcxyzpqrrrabbxyyyypqAzz
+ 0: abcxyzpqrrrabbxyyyypqAzz
+ *** Failers
+No match
+ abxyzpqrrabbxyyyypqAzz
+No match
+ abxyzpqrrrrabbxyyyypqAzz
+No match
+ abxyzpqrrrabxyyyypqAzz
+No match
+ aaaabcxyzzzzpqrrrabbbxyyyyyypqAzz
+No match
+ aaaabcxyzzzzpqrrrabbbxyyypqAzz
+No match
+ aaabcxyzpqrrrabbxyyyypqqqqqqqAzz
+No match
+
+/^(abc){1,2}zz/
+ abczz
+ 0: abczz
+ 1: abc
+ abcabczz
+ 0: abcabczz
+ 1: abc
+ *** Failers
+No match
+ zz
+No match
+ abcabcabczz
+No match
+ >>abczz
+No match
+
+/^(b+?|a){1,2}?c/
+ bc
+ 0: bc
+ 1: b
+ bbc
+ 0: bbc
+ 1: b
+ bbbc
+ 0: bbbc
+ 1: bb
+ bac
+ 0: bac
+ 1: a
+ bbac
+ 0: bbac
+ 1: a
+ aac
+ 0: aac
+ 1: a
+ abbbbbbbbbbbc
+ 0: abbbbbbbbbbbc
+ 1: bbbbbbbbbbb
+ bbbbbbbbbbbac
+ 0: bbbbbbbbbbbac
+ 1: a
+ *** Failers
+No match
+ aaac
+No match
+ abbbbbbbbbbbac
+No match
+
+/^(b+|a){1,2}c/
+ bc
+ 0: bc
+ 1: b
+ bbc
+ 0: bbc
+ 1: bb
+ bbbc
+ 0: bbbc
+ 1: bbb
+ bac
+ 0: bac
+ 1: a
+ bbac
+ 0: bbac
+ 1: a
+ aac
+ 0: aac
+ 1: a
+ abbbbbbbbbbbc
+ 0: abbbbbbbbbbbc
+ 1: bbbbbbbbbbb
+ bbbbbbbbbbbac
+ 0: bbbbbbbbbbbac
+ 1: a
+ *** Failers
+No match
+ aaac
+No match
+ abbbbbbbbbbbac
+No match
+
+/^(b+|a){1,2}?bc/
+ bbc
+ 0: bbc
+ 1: b
+
+/^(b*|ba){1,2}?bc/
+ babc
+ 0: babc
+ 1: ba
+ bbabc
+ 0: bbabc
+ 1: ba
+ bababc
+ 0: bababc
+ 1: ba
+ *** Failers
+No match
+ bababbc
+No match
+ babababc
+No match
+
+/^(ba|b*){1,2}?bc/
+ babc
+ 0: babc
+ 1: ba
+ bbabc
+ 0: bbabc
+ 1: ba
+ bababc
+ 0: bababc
+ 1: ba
+ *** Failers
+No match
+ bababbc
+No match
+ babababc
+No match
+
+/^\ca\cA\c[\c{\c:/
+ \x01\x01\e;z
+ 0: \x01\x01\x1b;z
+
+/^[ab\]cde]/
+ athing
+ 0: a
+ bthing
+ 0: b
+ ]thing
+ 0: ]
+ cthing
+ 0: c
+ dthing
+ 0: d
+ ething
+ 0: e
+ *** Failers
+No match
+ fthing
+No match
+ [thing
+No match
+ \\thing
+No match
+
+/^[]cde]/
+ ]thing
+ 0: ]
+ cthing
+ 0: c
+ dthing
+ 0: d
+ ething
+ 0: e
+ *** Failers
+No match
+ athing
+No match
+ fthing
+No match
+
+/^[^ab\]cde]/
+ fthing
+ 0: f
+ [thing
+ 0: [
+ \\thing
+ 0: \
+ *** Failers
+ 0: *
+ athing
+No match
+ bthing
+No match
+ ]thing
+No match
+ cthing
+No match
+ dthing
+No match
+ ething
+No match
+
+/^[^]cde]/
+ athing
+ 0: a
+ fthing
+ 0: f
+ *** Failers
+ 0: *
+ ]thing
+No match
+ cthing
+No match
+ dthing
+No match
+ ething
+No match
+
+/^\�/
+ �
+ 0: \x81
+
+/^�/
+ �
+ 0: \xff
+
+/^[0-9]+$/
+ 0
+ 0: 0
+ 1
+ 0: 1
+ 2
+ 0: 2
+ 3
+ 0: 3
+ 4
+ 0: 4
+ 5
+ 0: 5
+ 6
+ 0: 6
+ 7
+ 0: 7
+ 8
+ 0: 8
+ 9
+ 0: 9
+ 10
+ 0: 10
+ 100
+ 0: 100
+ *** Failers
+No match
+ abc
+No match
+
+/^.*nter/
+ enter
+ 0: enter
+ inter
+ 0: inter
+ uponter
+ 0: uponter
+
+/^xxx[0-9]+$/
+ xxx0
+ 0: xxx0
+ xxx1234
+ 0: xxx1234
+ *** Failers
+No match
+ xxx
+No match
+
+/^.+[0-9][0-9][0-9]$/
+ x123
+ 0: x123
+ xx123
+ 0: xx123
+ 123456
+ 0: 123456
+ *** Failers
+No match
+ 123
+No match
+ x1234
+ 0: x1234
+
+/^.+?[0-9][0-9][0-9]$/
+ x123
+ 0: x123
+ xx123
+ 0: xx123
+ 123456
+ 0: 123456
+ *** Failers
+No match
+ 123
+No match
+ x1234
+ 0: x1234
+
+/^([^!]+)!(.+)=apquxz\.ixr\.zzz\.ac\.uk$/
+ abc!pqr=apquxz.ixr.zzz.ac.uk
+ 0: abc!pqr=apquxz.ixr.zzz.ac.uk
+ 1: abc
+ 2: pqr
+ *** Failers
+No match
+ !pqr=apquxz.ixr.zzz.ac.uk
+No match
+ abc!=apquxz.ixr.zzz.ac.uk
+No match
+ abc!pqr=apquxz:ixr.zzz.ac.uk
+No match
+ abc!pqr=apquxz.ixr.zzz.ac.ukk
+No match
+
+/:/
+ Well, we need a colon: somewhere
+ 0: :
+ *** Fail if we don't
+No match
+
+/([\da-f:]+)$/i
+ 0abc
+ 0: 0abc
+ 1: 0abc
+ abc
+ 0: abc
+ 1: abc
+ fed
+ 0: fed
+ 1: fed
+ E
+ 0: E
+ 1: E
+ ::
+ 0: ::
+ 1: ::
+ 5f03:12C0::932e
+ 0: 5f03:12C0::932e
+ 1: 5f03:12C0::932e
+ fed def
+ 0: def
+ 1: def
+ Any old stuff
+ 0: ff
+ 1: ff
+ *** Failers
+No match
+ 0zzz
+No match
+ gzzz
+No match
+ fed\x20
+No match
+ Any old rubbish
+No match
+
+/^.*\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/
+ .1.2.3
+ 0: .1.2.3
+ 1: 1
+ 2: 2
+ 3: 3
+ A.12.123.0
+ 0: A.12.123.0
+ 1: 12
+ 2: 123
+ 3: 0
+ *** Failers
+No match
+ .1.2.3333
+No match
+ 1.2.3
+No match
+ 1234.2.3
+No match
+
+/^(\d+)\s+IN\s+SOA\s+(\S+)\s+(\S+)\s*\(\s*$/
+ 1 IN SOA non-sp1 non-sp2(
+ 0: 1 IN SOA non-sp1 non-sp2(
+ 1: 1
+ 2: non-sp1
+ 3: non-sp2
+ 1 IN SOA non-sp1 non-sp2 (
+ 0: 1 IN SOA non-sp1 non-sp2 (
+ 1: 1
+ 2: non-sp1
+ 3: non-sp2
+ *** Failers
+No match
+ 1IN SOA non-sp1 non-sp2(
+No match
+
+/^[a-zA-Z\d][a-zA-Z\d\-]*(\.[a-zA-Z\d][a-zA-z\d\-]*)*\.$/
+ a.
+ 0: a.
+ Z.
+ 0: Z.
+ 2.
+ 0: 2.
+ ab-c.pq-r.
+ 0: ab-c.pq-r.
+ 1: .pq-r
+ sxk.zzz.ac.uk.
+ 0: sxk.zzz.ac.uk.
+ 1: .uk
+ x-.y-.
+ 0: x-.y-.
+ 1: .y-
+ *** Failers
+No match
+ -abc.peq.
+No match
+
+/^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$/
+ *.a
+ 0: *.a
+ *.b0-a
+ 0: *.b0-a
+ 1: 0-a
+ *.c3-b.c
+ 0: *.c3-b.c
+ 1: 3-b
+ 2: .c
+ *.c-a.b-c
+ 0: *.c-a.b-c
+ 1: -a
+ 2: .b-c
+ 3: -c
+ *** Failers
+No match
+ *.0
+No match
+ *.a-
+No match
+ *.a-b.c-
+No match
+ *.c-a.0-c
+No match
+
+/^(?=ab(de))(abd)(e)/
+ abde
+ 0: abde
+ 1: de
+ 2: abd
+ 3: e
+
+/^(?!(ab)de|x)(abd)(f)/
+ abdf
+ 0: abdf
+ 1: <unset>
+ 2: abd
+ 3: f
+
+/^(?=(ab(cd)))(ab)/
+ abcd
+ 0: ab
+ 1: abcd
+ 2: cd
+ 3: ab
+
+/^[\da-f](\.[\da-f])*$/i
+ a.b.c.d
+ 0: a.b.c.d
+ 1: .d
+ A.B.C.D
+ 0: A.B.C.D
+ 1: .D
+ a.b.c.1.2.3.C
+ 0: a.b.c.1.2.3.C
+ 1: .C
+
+/^\".*\"\s*(;.*)?$/
+ \"1234\"
+ 0: "1234"
+ \"abcd\" ;
+ 0: "abcd" ;
+ 1: ;
+ \"\" ; rhubarb
+ 0: "" ; rhubarb
+ 1: ; rhubarb
+ *** Failers
+No match
+ \"1234\" : things
+No match
+
+/^$/
+ \
+ 0:
+ *** Failers
+No match
+
+/ ^ a (?# begins with a) b\sc (?# then b c) $ (?# then end)/x
+ ab c
+ 0: ab c
+ *** Failers
+No match
+ abc
+No match
+ ab cde
+No match
+
+/(?x) ^ a (?# begins with a) b\sc (?# then b c) $ (?# then end)/
+ ab c
+ 0: ab c
+ *** Failers
+No match
+ abc
+No match
+ ab cde
+No match
+
+/^ a\ b[c ]d $/x
+ a bcd
+ 0: a bcd
+ a b d
+ 0: a b d
+ *** Failers
+No match
+ abcd
+No match
+ ab d
+No match
+
+/^(a(b(c)))(d(e(f)))(h(i(j)))(k(l(m)))$/
+ abcdefhijklm
+ 0: abcdefhijklm
+ 1: abc
+ 2: bc
+ 3: c
+ 4: def
+ 5: ef
+ 6: f
+ 7: hij
+ 8: ij
+ 9: j
+10: klm
+11: lm
+12: m
+
+/^(?:a(b(c)))(?:d(e(f)))(?:h(i(j)))(?:k(l(m)))$/
+ abcdefhijklm
+ 0: abcdefhijklm
+ 1: bc
+ 2: c
+ 3: ef
+ 4: f
+ 5: ij
+ 6: j
+ 7: lm
+ 8: m
+
+/^[\w][\W][\s][\S][\d][\D][\b][\n][\c]][\022]/
+ a+ Z0+\x08\n\x1d\x12
+ 0: a+ Z0+\x08\x0a\x1d\x12
+
+/^[.^$|()*+?{,}]+/
+ .^\$(*+)|{?,?}
+ 0: .^$(*+)|{?,?}
+
+/^a*\w/
+ z
+ 0: z
+ az
+ 0: az
+ aaaz
+ 0: aaaz
+ a
+ 0: a
+ aa
+ 0: aa
+ aaaa
+ 0: aaaa
+ a+
+ 0: a
+ aa+
+ 0: aa
+
+/^a*?\w/
+ z
+ 0: z
+ az
+ 0: a
+ aaaz
+ 0: a
+ a
+ 0: a
+ aa
+ 0: a
+ aaaa
+ 0: a
+ a+
+ 0: a
+ aa+
+ 0: a
+
+/^a+\w/
+ az
+ 0: az
+ aaaz
+ 0: aaaz
+ aa
+ 0: aa
+ aaaa
+ 0: aaaa
+ aa+
+ 0: aa
+
+/^a+?\w/
+ az
+ 0: az
+ aaaz
+ 0: aa
+ aa
+ 0: aa
+ aaaa
+ 0: aa
+ aa+
+ 0: aa
+
+/^\d{8}\w{2,}/
+ 1234567890
+ 0: 1234567890
+ 12345678ab
+ 0: 12345678ab
+ 12345678__
+ 0: 12345678__
+ *** Failers
+No match
+ 1234567
+No match
+
+/^[aeiou\d]{4,5}$/
+ uoie
+ 0: uoie
+ 1234
+ 0: 1234
+ 12345
+ 0: 12345
+ aaaaa
+ 0: aaaaa
+ *** Failers
+No match
+ 123456
+No match
+
+/^[aeiou\d]{4,5}?/
+ uoie
+ 0: uoie
+ 1234
+ 0: 1234
+ 12345
+ 0: 1234
+ aaaaa
+ 0: aaaa
+ 123456
+ 0: 1234
+
+/\A(abc|def)=(\1){2,3}\Z/
+ abc=abcabc
+ 0: abc=abcabc
+ 1: abc
+ 2: abc
+ def=defdefdef
+ 0: def=defdefdef
+ 1: def
+ 2: def
+ *** Failers
+No match
+ abc=defdef
+No match
+
+/^(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\11*(\3\4)\1(?#)2$/
+ abcdefghijkcda2
+ 0: abcdefghijkcda2
+ 1: a
+ 2: b
+ 3: c
+ 4: d
+ 5: e
+ 6: f
+ 7: g
+ 8: h
+ 9: i
+10: j
+11: k
+12: cd
+ abcdefghijkkkkcda2
+ 0: abcdefghijkkkkcda2
+ 1: a
+ 2: b
+ 3: c
+ 4: d
+ 5: e
+ 6: f
+ 7: g
+ 8: h
+ 9: i
+10: j
+11: k
+12: cd
+
+/(cat(a(ract|tonic)|erpillar)) \1()2(3)/
+ cataract cataract23
+ 0: cataract cataract23
+ 1: cataract
+ 2: aract
+ 3: ract
+ 4:
+ 5: 3
+ catatonic catatonic23
+ 0: catatonic catatonic23
+ 1: catatonic
+ 2: atonic
+ 3: tonic
+ 4:
+ 5: 3
+ caterpillar caterpillar23
+ 0: caterpillar caterpillar23
+ 1: caterpillar
+ 2: erpillar
+ 3: <unset>
+ 4:
+ 5: 3
+
+
+/^From +([^ ]+) +[a-zA-Z][a-zA-Z][a-zA-Z] +[a-zA-Z][a-zA-Z][a-zA-Z] +[0-9]?[0-9] +[0-9][0-9]:[0-9][0-9]/
+ From abcd Mon Sep 01 12:33:02 1997
+ 0: From abcd Mon Sep 01 12:33
+ 1: abcd
+
+/^From\s+\S+\s+([a-zA-Z]{3}\s+){2}\d{1,2}\s+\d\d:\d\d/
+ From abcd Mon Sep 01 12:33:02 1997
+ 0: From abcd Mon Sep 01 12:33
+ 1: Sep
+ From abcd Mon Sep 1 12:33:02 1997
+ 0: From abcd Mon Sep 1 12:33
+ 1: Sep
+ *** Failers
+No match
+ From abcd Sep 01 12:33:02 1997
+No match
+
+/^12.34/s
+ 12\n34
+ 0: 12\x0a34
+ 12\r34
+ 0: 12\x0d34
+
+/\w+(?=\t)/
+ the quick brown\t fox
+ 0: brown
+
+/foo(?!bar)(.*)/
+ foobar is foolish see?
+ 0: foolish see?
+ 1: lish see?
+
+/(?:(?!foo)...|^.{0,2})bar(.*)/
+ foobar crowbar etc
+ 0: rowbar etc
+ 1: etc
+ barrel
+ 0: barrel
+ 1: rel
+ 2barrel
+ 0: 2barrel
+ 1: rel
+ A barrel
+ 0: A barrel
+ 1: rel
+
+/^(\D*)(?=\d)(?!123)/
+ abc456
+ 0: abc
+ 1: abc
+ *** Failers
+No match
+ abc123
+No match
+
+/^1234(?# test newlines
+ inside)/
+ 1234
+ 0: 1234
+
+/^1234 #comment in extended re
+ /x
+ 1234
+ 0: 1234
+
+/#rhubarb
+ abcd/x
+ abcd
+ 0: abcd
+
+/^abcd#rhubarb/x
+ abcd
+ 0: abcd
+
+/^(a)\1{2,3}(.)/
+ aaab
+ 0: aaab
+ 1: a
+ 2: b
+ aaaab
+ 0: aaaab
+ 1: a
+ 2: b
+ aaaaab
+ 0: aaaaa
+ 1: a
+ 2: a
+ aaaaaab
+ 0: aaaaa
+ 1: a
+ 2: a
+
+/(?!^)abc/
+ the abc
+ 0: abc
+ *** Failers
+No match
+ abc
+No match
+
+/(?=^)abc/
+ abc
+ 0: abc
+ *** Failers
+No match
+ the abc
+No match
+
+/^[ab]{1,3}(ab*|b)/
+ aabbbbb
+ 0: aabb
+ 1: b
+
+/^[ab]{1,3}?(ab*|b)/
+ aabbbbb
+ 0: aabbbbb
+ 1: abbbbb
+
+/^[ab]{1,3}?(ab*?|b)/
+ aabbbbb
+ 0: aa
+ 1: a
+
+/^[ab]{1,3}(ab*?|b)/
+ aabbbbb
+ 0: aabb
+ 1: b
+
+/ (?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* # optional leading comment
+(?: (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+" (?: # opening quote...
+[^\\\x80-\xff\n\015"] # Anything except backslash and quote
+| # or
+\\ [^\x80-\xff] # Escaped something (something != CR)
+)* " # closing quote
+) # initial word
+(?: (?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* \. (?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+" (?: # opening quote...
+[^\\\x80-\xff\n\015"] # Anything except backslash and quote
+| # or
+\\ [^\x80-\xff] # Escaped something (something != CR)
+)* " # closing quote
+) )* # further okay, if led by a period
+(?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* @ (?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+| \[ # [
+(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff
+\] # ]
+) # initial subdomain
+(?: #
+(?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* \. # if led by a period...
+(?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+| \[ # [
+(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff
+\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+" (?: # opening quote...
+[^\\\x80-\xff\n\015"] # Anything except backslash and quote
+| # or
+\\ [^\x80-\xff] # Escaped something (something != CR)
+)* " # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] | # atom and space parts, or...
+\(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) | # comments, or...
+
+" (?: # opening quote...
+[^\\\x80-\xff\n\015"] # Anything except backslash and quote
+| # or
+\\ [^\x80-\xff] # Escaped something (something != CR)
+)* " # closing quote
+# quoted strings
+)*
+< (?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* # leading <
+(?: @ (?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+| \[ # [
+(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff
+\] # ]
+) # initial subdomain
+(?: #
+(?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* \. # if led by a period...
+(?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+| \[ # [
+(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff
+\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* , (?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* @ (?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+| \[ # [
+(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff
+\] # ]
+) # initial subdomain
+(?: #
+(?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* \. # if led by a period...
+(?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+| \[ # [
+(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff
+\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* )? # optional route
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+" (?: # opening quote...
+[^\\\x80-\xff\n\015"] # Anything except backslash and quote
+| # or
+\\ [^\x80-\xff] # Escaped something (something != CR)
+)* " # closing quote
+) # initial word
+(?: (?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* \. (?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+" (?: # opening quote...
+[^\\\x80-\xff\n\015"] # Anything except backslash and quote
+| # or
+\\ [^\x80-\xff] # Escaped something (something != CR)
+)* " # closing quote
+) )* # further okay, if led by a period
+(?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* @ (?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+| \[ # [
+(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff
+\] # ]
+) # initial subdomain
+(?: #
+(?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* \. # if led by a period...
+(?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+| \[ # [
+(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff
+\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* > # trailing >
+# name and address
+) (?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* # optional trailing comment
+/x
+ Alan Other <user\@dom.ain>
+ 0: Alan Other <[email protected]>
+ <user\@dom.ain>
+ user\@dom.ain
+ \"A. Other\" <user.1234\@dom.ain> (a comment)
+ 0: "A. Other" <[email protected]> (a comment)
+ A. Other <user.1234\@dom.ain> (a comment)
+ 0: Other <[email protected]> (a comment)
+ \"/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/\"\@x400-re.lay
+ 0: "/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/"@x400-re.lay
+ A missing angle <user\@some.where
+ *** Failers
+No match
+ The quick brown fox
+No match
+
+/[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+" # "
+[^\\\x80-\xff\n\015"] * # normal
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )*
+" # "
+# Quoted string
+)
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+(?:
+\.
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+" # "
+[^\\\x80-\xff\n\015"] * # normal
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )*
+" # "
+# Quoted string
+)
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+\[ # [
+(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff
+\] # ]
+)
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\.
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+\[ # [
+(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff
+\] # ]
+)
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+" # "
+[^\\\x80-\xff\n\015"] * # normal
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )*
+" # "
+# Quoted string
+)
+# leading word
+[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # "normal" atoms and or spaces
+(?:
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+|
+" # "
+[^\\\x80-\xff\n\015"] * # normal
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )*
+" # "
+) # "special" comment or quoted string
+[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # more "normal"
+)*
+<
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+\[ # [
+(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff
+\] # ]
+)
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\.
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+\[ # [
+(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff
+\] # ]
+)
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+@
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+\[ # [
+(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff
+\] # ]
+)
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\.
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+\[ # [
+(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff
+\] # ]
+)
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+" # "
+[^\\\x80-\xff\n\015"] * # normal
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )*
+" # "
+# Quoted string
+)
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+(?:
+\.
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+" # "
+[^\\\x80-\xff\n\015"] * # normal
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )*
+" # "
+# Quoted string
+)
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+\[ # [
+(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff
+\] # ]
+)
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\.
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+\[ # [
+(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff
+\] # ]
+)
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)
+/x
+ Alan Other <user\@dom.ain>
+ 0: Alan Other <[email protected]>
+ <user\@dom.ain>
+ user\@dom.ain
+ \"A. Other\" <user.1234\@dom.ain> (a comment)
+ 0: "A. Other" <[email protected]>
+ A. Other <user.1234\@dom.ain> (a comment)
+ 0: Other <[email protected]>
+ \"/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/\"\@x400-re.lay
+ 0: "/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/"@x400-re.lay
+ A missing angle <user\@some.where
+ *** Failers
+No match
+ The quick brown fox
+No match
+
+/abc\0def\00pqr\000xyz\0000AB/
+ abc\0def\00pqr\000xyz\0000AB
+ 0: abc\x00def\x00pqr\x00xyz\x000AB
+ abc456 abc\0def\00pqr\000xyz\0000ABCDE
+ 0: abc\x00def\x00pqr\x00xyz\x000AB
+
+/abc\x0def\x00pqr\x000xyz\x0000AB/
+ abc\x0def\x00pqr\x000xyz\x0000AB
+ 0: abc\x0def\x00pqr\x000xyz\x0000AB
+ abc456 abc\x0def\x00pqr\x000xyz\x0000ABCDE
+ 0: abc\x0def\x00pqr\x000xyz\x0000AB
+
+/^[\000-\037]/
+ \0A
+ 0: \x00
+ \01B
+ 0: \x01
+ \037C
+ 0: \x1f
+
+/\0*/
+ \0\0\0\0
+ 0: \x00\x00\x00\x00
+
+/A\x0{2,3}Z/
+ The A\x0\x0Z
+ 0: A\x00\x00Z
+ An A\0\x0\0Z
+ 0: A\x00\x00\x00Z
+ *** Failers
+No match
+ A\0Z
+No match
+ A\0\x0\0\x0Z
+No match
+
+/^(cow|)\1(bell)/
+ cowcowbell
+ 0: cowcowbell
+ 1: cow
+ 2: bell
+ bell
+ 0: bell
+ 1:
+ 2: bell
+ *** Failers
+No match
+ cowbell
+No match
+
+/^\s/
+ \040abc
+ 0:
+ \x0cabc
+ 0: \x0c
+ \nabc
+ 0: \x0a
+ \rabc
+ 0: \x0d
+ \tabc
+ 0: \x09
+ *** Failers
+No match
+ abc
+No match
+
+/^a b
+ c/x
+ abc
+ 0: abc
+
+/^(a|)\1*b/
+ ab
+ 0: ab
+ 1: a
+ aaaab
+ 0: aaaab
+ 1: a
+ b
+ 0: b
+ 1:
+ *** Failers
+No match
+ acb
+No match
+
+/^(a|)\1+b/
+ aab
+ 0: aab
+ 1: a
+ aaaab
+ 0: aaaab
+ 1: a
+ b
+ 0: b
+ 1:
+ *** Failers
+No match
+ ab
+No match
+
+/^(a|)\1?b/
+ ab
+ 0: ab
+ 1: a
+ aab
+ 0: aab
+ 1: a
+ b
+ 0: b
+ 1:
+ *** Failers
+No match
+ acb
+No match
+
+/^(a|)\1{2}b/
+ aaab
+ 0: aaab
+ 1: a
+ b
+ 0: b
+ 1:
+ *** Failers
+No match
+ ab
+No match
+ aab
+No match
+ aaaab
+No match
+
+/^(a|)\1{2,3}b/
+ aaab
+ 0: aaab
+ 1: a
+ aaaab
+ 0: aaaab
+ 1: a
+ b
+ 0: b
+ 1:
+ *** Failers
+No match
+ ab
+No match
+ aab
+No match
+ aaaaab
+No match
+
+/ab{1,3}bc/
+ abbbbc
+ 0: abbbbc
+ abbbc
+ 0: abbbc
+ abbc
+ 0: abbc
+ *** Failers
+No match
+ abc
+No match
+ abbbbbc
+No match
+
+/([^.]*)\.([^:]*):[T ]+(.*)/
+ track1.title:TBlah blah blah
+ 0: track1.title:TBlah blah blah
+ 1: track1
+ 2: title
+ 3: Blah blah blah
+
+/([^.]*)\.([^:]*):[T ]+(.*)/i
+ track1.title:TBlah blah blah
+ 0: track1.title:TBlah blah blah
+ 1: track1
+ 2: title
+ 3: Blah blah blah
+
+/([^.]*)\.([^:]*):[t ]+(.*)/i
+ track1.title:TBlah blah blah
+ 0: track1.title:TBlah blah blah
+ 1: track1
+ 2: title
+ 3: Blah blah blah
+
+/^[W-c]+$/
+ WXY_^abc
+ 0: WXY_^abc
+ *** Failers
+No match
+ wxy
+No match
+
+/^[W-c]+$/i
+ WXY_^abc
+ 0: WXY_^abc
+ wxy_^ABC
+ 0: wxy_^ABC
+
+/^[\x3f-\x5F]+$/i
+ WXY_^abc
+ 0: WXY_^abc
+ wxy_^ABC
+ 0: wxy_^ABC
+
+/^abc$/m
+ abc
+ 0: abc
+ qqq\nabc
+ 0: abc
+ abc\nzzz
+ 0: abc
+ qqq\nabc\nzzz
+ 0: abc
+
+/^abc$/
+ abc
+ 0: abc
+ *** Failers
+No match
+ qqq\nabc
+No match
+ abc\nzzz
+No match
+ qqq\nabc\nzzz
+No match
+
+/\Aabc\Z/m
+ abc
+ 0: abc
+ abc\n
+ 0: abc
+ *** Failers
+No match
+ qqq\nabc
+No match
+ abc\nzzz
+No match
+ qqq\nabc\nzzz
+No match
+
+/\A(.)*\Z/s
+ abc\ndef
+ 0: abc\x0adef
+ 1: f
+
+/\A(.)*\Z/m
+ *** Failers
+ 0: *** Failers
+ 1: s
+ abc\ndef
+No match
+
+/(?:b)|(?::+)/
+ b::c
+ 0: b
+ c::b
+ 0: ::
+
+/[-az]+/
+ az-
+ 0: az-
+ *** Failers
+ 0: a
+ b
+No match
+
+/[az-]+/
+ za-
+ 0: za-
+ *** Failers
+ 0: a
+ b
+No match
+
+/[a\-z]+/
+ a-z
+ 0: a-z
+ *** Failers
+ 0: a
+ b
+No match
+
+/[a-z]+/
+ abcdxyz
+ 0: abcdxyz
+
+/[\d-]+/
+ 12-34
+ 0: 12-34
+ *** Failers
+No match
+ aaa
+No match
+
+/[\d-z]+/
+ 12-34z
+ 0: 12-34z
+ *** Failers
+No match
+ aaa
+No match
+
+/\x5c/
+ \\
+ 0: \
+
+/\x20Z/
+ the Zoo
+ 0: Z
+ *** Failers
+No match
+ Zulu
+No match
+
+/(abc)\1/i
+ abcabc
+ 0: abcabc
+ 1: abc
+ ABCabc
+ 0: ABCabc
+ 1: ABC
+ abcABC
+ 0: abcABC
+ 1: abc
+
+/ab{3cd/
+ ab{3cd
+ 0: ab{3cd
+
+/ab{3,cd/
+ ab{3,cd
+ 0: ab{3,cd
+
+/ab{3,4a}cd/
+ ab{3,4a}cd
+ 0: ab{3,4a}cd
+
+/{4,5a}bc/
+ {4,5a}bc
+ 0: {4,5a}bc
+
+/abc$/
+ abc
+ 0: abc
+ abc\n
+ 0: abc
+ *** Failers
+No match
+ abc\ndef
+No match
+
+/(abc)\123/
+ abc\x53
+ 0: abcS
+ 1: abc
+
+/(abc)\223/
+ abc\x93
+ 0: abc\x93
+ 1: abc
+
+/(abc)\323/
+ abc\xd3
+ 0: abc\xd3
+ 1: abc
+
+/(abc)\100/
+ abc\x40
+ 0: abc@
+ 1: abc
+ abc\100
+ 0: abc@
+ 1: abc
+
+/(abc)\1000/
+ abc\x400
+ 0: abc@0
+ 1: abc
+ abc\x40\x30
+ 0: abc@0
+ 1: abc
+ abc\1000
+ 0: abc@0
+ 1: abc
+ abc\100\x30
+ 0: abc@0
+ 1: abc
+ abc\100\060
+ 0: abc@0
+ 1: abc
+ abc\100\60
+ 0: abc@0
+ 1: abc
+
+/abc\81/
+ abc\081
+ 0: abc\x0081
+ abc\0\x38\x31
+ 0: abc\x0081
+
+/abc\91/
+ abc\091
+ 0: abc\x0091
+ abc\0\x39\x31
+ 0: abc\x0091
+
+/(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)\12\123/
+ abcdefghijkllS
+ 0: abcdefghijkllS
+ 1: a
+ 2: b
+ 3: c
+ 4: d
+ 5: e
+ 6: f
+ 7: g
+ 8: h
+ 9: i
+10: j
+11: k
+12: l
+
+/(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\12\123/
+ abcdefghijk\12S
+ 0: abcdefghijk\x0aS
+ 1: a
+ 2: b
+ 3: c
+ 4: d
+ 5: e
+ 6: f
+ 7: g
+ 8: h
+ 9: i
+10: j
+11: k
+
+/ab\idef/
+ abidef
+ 0: abidef
+
+/a{0}bc/
+ bc
+ 0: bc
+
+/(a|(bc)){0,0}?xyz/
+ xyz
+ 0: xyz
+
+/abc[\10]de/
+ abc\010de
+ 0: abc\x08de
+
+/abc[\1]de/
+ abc\1de
+ 0: abc\x01de
+
+/(abc)[\1]de/
+ abc\1de
+ 0: abc\x01de
+ 1: abc
+
+/(?s)a.b/
+ a\nb
+ 0: a\x0ab
+
+/^([^a])([^\b])([^c]*)([^d]{3,4})/
+ baNOTccccd
+ 0: baNOTcccc
+ 1: b
+ 2: a
+ 3: NOT
+ 4: cccc
+ baNOTcccd
+ 0: baNOTccc
+ 1: b
+ 2: a
+ 3: NOT
+ 4: ccc
+ baNOTccd
+ 0: baNOTcc
+ 1: b
+ 2: a
+ 3: NO
+ 4: Tcc
+ bacccd
+ 0: baccc
+ 1: b
+ 2: a
+ 3:
+ 4: ccc
+ *** Failers
+ 0: *** Failers
+ 1: *
+ 2: *
+ 3: * Fail
+ 4: ers
+ anything
+No match
+ b\bc
+No match
+ baccd
+No match
+
+/[^a]/
+ Abc
+ 0: A
+
+/[^a]/i
+ Abc
+ 0: b
+
+/[^a]+/
+ AAAaAbc
+ 0: AAA
+
+/[^a]+/i
+ AAAaAbc
+ 0: bc
+
+/[^a]+/
+ bbb\nccc
+ 0: bbb\x0accc
+
+/[^k]$/
+ abc
+ 0: c
+ *** Failers
+ 0: s
+ abk
+No match
+
+/[^k]{2,3}$/
+ abc
+ 0: abc
+ kbc
+ 0: bc
+ kabc
+ 0: abc
+ *** Failers
+ 0: ers
+ abk
+No match
+ akb
+No match
+ akk
+No match
+
+/^\d{8,}\@.+[^k]$/
+ 12345678\@a.b.c.d
+ 123456789\@x.y.z
+ *** Failers
+No match
+ 12345678\@x.y.uk
+No match
+ 1234567\@a.b.c.d
+No match
+
+/(a)\1{8,}/
+ aaaaaaaaa
+ 0: aaaaaaaaa
+ 1: a
+ aaaaaaaaaa
+ 0: aaaaaaaaaa
+ 1: a
+ *** Failers
+No match
+ aaaaaaa
+No match
+
+/[^a]/
+ aaaabcd
+ 0: b
+ aaAabcd
+ 0: A
+
+/[^a]/i
+ aaaabcd
+ 0: b
+ aaAabcd
+ 0: b
+
+/[^az]/
+ aaaabcd
+ 0: b
+ aaAabcd
+ 0: A
+
+/[^az]/i
+ aaaabcd
+ 0: b
+ aaAabcd
+ 0: b
+
+/\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377/
+ \000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377
+ 0: \x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff
+
+/P[^*]TAIRE[^*]{1,6}?LL/
+ xxxxxxxxxxxPSTAIREISLLxxxxxxxxx
+ 0: PSTAIREISLL
+
+/P[^*]TAIRE[^*]{1,}?LL/
+ xxxxxxxxxxxPSTAIREISLLxxxxxxxxx
+ 0: PSTAIREISLL
+
+/(\.\d\d[1-9]?)\d+/
+ 1.230003938
+ 0: .230003938
+ 1: .23
+ 1.875000282
+ 0: .875000282
+ 1: .875
+ 1.235
+ 0: .235
+ 1: .23
+
+/(\.\d\d((?=0)|\d(?=\d)))/
+ 1.230003938
+ 0: .23
+ 1: .23
+ 2:
+ 1.875000282
+ 0: .875
+ 1: .875
+ 2: 5
+ *** Failers
+No match
+ 1.235
+No match
+
+/a(?)b/
+ ab
+ 0: ab
+
+/\b(foo)\s+(\w+)/i
+ Food is on the foo table
+ 0: foo table
+ 1: foo
+ 2: table
+
+/foo(.*)bar/
+ The food is under the bar in the barn.
+ 0: food is under the bar in the bar
+ 1: d is under the bar in the
+
+/foo(.*?)bar/
+ The food is under the bar in the barn.
+ 0: food is under the bar
+ 1: d is under the
+
+/(.*)(\d*)/
+ I have 2 numbers: 53147
+ 0: I have 2 numbers: 53147
+ 1: I have 2 numbers: 53147
+ 2:
+
+/(.*)(\d+)/
+ I have 2 numbers: 53147
+ 0: I have 2 numbers: 53147
+ 1: I have 2 numbers: 5314
+ 2: 7
+
+/(.*?)(\d*)/
+ I have 2 numbers: 53147
+ 0:
+ 1:
+ 2:
+
+/(.*?)(\d+)/
+ I have 2 numbers: 53147
+ 0: I have 2
+ 1: I have
+ 2: 2
+
+/(.*)(\d+)$/
+ I have 2 numbers: 53147
+ 0: I have 2 numbers: 53147
+ 1: I have 2 numbers: 5314
+ 2: 7
+
+/(.*?)(\d+)$/
+ I have 2 numbers: 53147
+ 0: I have 2 numbers: 53147
+ 1: I have 2 numbers:
+ 2: 53147
+
+/(.*)\b(\d+)$/
+ I have 2 numbers: 53147
+ 0: I have 2 numbers: 53147
+ 1: I have 2 numbers:
+ 2: 53147
+
+/(.*\D)(\d+)$/
+ I have 2 numbers: 53147
+ 0: I have 2 numbers: 53147
+ 1: I have 2 numbers:
+ 2: 53147
+
+/^\D*(?!123)/
+ ABC123
+ 0: AB
+
+/^(\D*)(?=\d)(?!123)/
+ ABC445
+ 0: ABC
+ 1: ABC
+ *** Failers
+No match
+ ABC123
+No match
+
+/^[W-]46]/
+ W46]789
+ 0: W46]
+ -46]789
+ 0: -46]
+ *** Failers
+No match
+ Wall
+No match
+ Zebra
+No match
+ 42
+No match
+ [abcd]
+No match
+ ]abcd[
+No match
+
+/^[W-\]46]/
+ W46]789
+ 0: W
+ Wall
+ 0: W
+ Zebra
+ 0: Z
+ Xylophone
+ 0: X
+ 42
+ 0: 4
+ [abcd]
+ 0: [
+ ]abcd[
+ 0: ]
+ \\backslash
+ 0: \
+ *** Failers
+No match
+ -46]789
+No match
+ well
+No match
+
+/\d\d\/\d\d\/\d\d\d\d/
+ 01/01/2000
+ 0: 01/01/2000
+
+/word (?:[a-zA-Z0-9]+ ){0,10}otherword/
+ word cat dog elephant mussel cow horse canary baboon snake shark otherword
+ 0: word cat dog elephant mussel cow horse canary baboon snake shark otherword
+ word cat dog elephant mussel cow horse canary baboon snake shark
+No match
+
+/word (?:[a-zA-Z0-9]+ ){0,300}otherword/
+ word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope
+No match
+
+/^(a){0,0}/
+ bcd
+ 0:
+ abc
+ 0:
+ aab
+ 0:
+
+/^(a){0,1}/
+ bcd
+ 0:
+ abc
+ 0: a
+ 1: a
+ aab
+ 0: a
+ 1: a
+
+/^(a){0,2}/
+ bcd
+ 0:
+ abc
+ 0: a
+ 1: a
+ aab
+ 0: aa
+ 1: a
+
+/^(a){0,3}/
+ bcd
+ 0:
+ abc
+ 0: a
+ 1: a
+ aab
+ 0: aa
+ 1: a
+ aaa
+ 0: aaa
+ 1: a
+
+/^(a){0,}/
+ bcd
+ 0:
+ abc
+ 0: a
+ 1: a
+ aab
+ 0: aa
+ 1: a
+ aaa
+ 0: aaa
+ 1: a
+ aaaaaaaa
+ 0: aaaaaaaa
+ 1: a
+
+/^(a){1,1}/
+ bcd
+No match
+ abc
+ 0: a
+ 1: a
+ aab
+ 0: a
+ 1: a
+
+/^(a){1,2}/
+ bcd
+No match
+ abc
+ 0: a
+ 1: a
+ aab
+ 0: aa
+ 1: a
+
+/^(a){1,3}/
+ bcd
+No match
+ abc
+ 0: a
+ 1: a
+ aab
+ 0: aa
+ 1: a
+ aaa
+ 0: aaa
+ 1: a
+
+/^(a){1,}/
+ bcd
+No match
+ abc
+ 0: a
+ 1: a
+ aab
+ 0: aa
+ 1: a
+ aaa
+ 0: aaa
+ 1: a
+ aaaaaaaa
+ 0: aaaaaaaa
+ 1: a
+
+/.*\.gif/
+ borfle\nbib.gif\nno
+ 0: bib.gif
+
+/.{0,}\.gif/
+ borfle\nbib.gif\nno
+ 0: bib.gif
+
+/.*\.gif/m
+ borfle\nbib.gif\nno
+ 0: bib.gif
+
+/.*\.gif/s
+ borfle\nbib.gif\nno
+ 0: borfle\x0abib.gif
+
+/.*\.gif/ms
+ borfle\nbib.gif\nno
+ 0: borfle\x0abib.gif
+
+/.*$/
+ borfle\nbib.gif\nno
+ 0: no
+
+/.*$/m
+ borfle\nbib.gif\nno
+ 0: borfle
+
+/.*$/s
+ borfle\nbib.gif\nno
+ 0: borfle\x0abib.gif\x0ano
+
+/.*$/ms
+ borfle\nbib.gif\nno
+ 0: borfle\x0abib.gif\x0ano
+
+/.*$/
+ borfle\nbib.gif\nno\n
+ 0: no
+
+/.*$/m
+ borfle\nbib.gif\nno\n
+ 0: borfle
+
+/.*$/s
+ borfle\nbib.gif\nno\n
+ 0: borfle\x0abib.gif\x0ano\x0a
+
+/.*$/ms
+ borfle\nbib.gif\nno\n
+ 0: borfle\x0abib.gif\x0ano\x0a
+
+/(.*X|^B)/
+ abcde\n1234Xyz
+ 0: 1234X
+ 1: 1234X
+ BarFoo
+ 0: B
+ 1: B
+ *** Failers
+No match
+ abcde\nBar
+No match
+
+/(.*X|^B)/m
+ abcde\n1234Xyz
+ 0: 1234X
+ 1: 1234X
+ BarFoo
+ 0: B
+ 1: B
+ abcde\nBar
+ 0: B
+ 1: B
+
+/(.*X|^B)/s
+ abcde\n1234Xyz
+ 0: abcde\x0a1234X
+ 1: abcde\x0a1234X
+ BarFoo
+ 0: B
+ 1: B
+ *** Failers
+No match
+ abcde\nBar
+No match
+
+/(.*X|^B)/ms
+ abcde\n1234Xyz
+ 0: abcde\x0a1234X
+ 1: abcde\x0a1234X
+ BarFoo
+ 0: B
+ 1: B
+ abcde\nBar
+ 0: B
+ 1: B
+
+/(?s)(.*X|^B)/
+ abcde\n1234Xyz
+ 0: abcde\x0a1234X
+ 1: abcde\x0a1234X
+ BarFoo
+ 0: B
+ 1: B
+ *** Failers
+No match
+ abcde\nBar
+No match
+
+/(?s:.*X|^B)/
+ abcde\n1234Xyz
+ 0: abcde\x0a1234X
+ BarFoo
+ 0: B
+ *** Failers
+No match
+ abcde\nBar
+No match
+
+/^.*B/
+ **** Failers
+No match
+ abc\nB
+No match
+
+/(?s)^.*B/
+ abc\nB
+ 0: abc\x0aB
+
+/(?m)^.*B/
+ abc\nB
+ 0: B
+
+/(?ms)^.*B/
+ abc\nB
+ 0: abc\x0aB
+
+/(?ms)^B/
+ abc\nB
+ 0: B
+
+/(?s)B$/
+ B\n
+ 0: B
+
+/^[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]/
+ 123456654321
+ 0: 123456654321
+
+/^\d\d\d\d\d\d\d\d\d\d\d\d/
+ 123456654321
+ 0: 123456654321
+
+/^[\d][\d][\d][\d][\d][\d][\d][\d][\d][\d][\d][\d]/
+ 123456654321
+ 0: 123456654321
+
+/^[abc]{12}/
+ abcabcabcabc
+ 0: abcabcabcabc
+
+/^[a-c]{12}/
+ abcabcabcabc
+ 0: abcabcabcabc
+
+/^(a|b|c){12}/
+ abcabcabcabc
+ 0: abcabcabcabc
+ 1: c
+
+/^[abcdefghijklmnopqrstuvwxy0123456789]/
+ n
+ 0: n
+ *** Failers
+No match
+ z
+No match
+
+/abcde{0,0}/
+ abcd
+ 0: abcd
+ *** Failers
+No match
+ abce
+No match
+
+/ab[cd]{0,0}e/
+ abe
+ 0: abe
+ *** Failers
+No match
+ abcde
+No match
+
+/ab(c){0,0}d/
+ abd
+ 0: abd
+ *** Failers
+No match
+ abcd
+No match
+
+/a(b*)/
+ a
+ 0: a
+ 1:
+ ab
+ 0: ab
+ 1: b
+ abbbb
+ 0: abbbb
+ 1: bbbb
+ *** Failers
+ 0: a
+ 1:
+ bbbbb
+No match
+
+/ab\d{0}e/
+ abe
+ 0: abe
+ *** Failers
+No match
+ ab1e
+No match
+
+/"([^\\"]+|\\.)*"/
+ the \"quick\" brown fox
+ 0: "quick"
+ 1: quick
+ \"the \\\"quick\\\" brown fox\"
+ 0: "the \"quick\" brown fox"
+ 1: brown fox
+
+/.*?/g+
+ abc
+ 0:
+ 0+ abc
+ 0: a
+ 0+ bc
+ 0:
+ 0+ bc
+ 0: b
+ 0+ c
+ 0:
+ 0+ c
+ 0: c
+ 0+
+ 0:
+ 0+
+
+/\b/g+
+ abc
+ 0:
+ 0+ abc
+ 0:
+ 0+
+
+/\b/+g
+ abc
+ 0:
+ 0+ abc
+ 0:
+ 0+
+
+//g
+ abc
+ 0:
+ 0:
+ 0:
+ 0:
+
+/<tr([\w\W\s\d][^<>]{0,})><TD([\w\W\s\d][^<>]{0,})>([\d]{0,}\.)(.*)((<BR>([\w\W\s\d][^<>]{0,})|[\s]{0,}))<\/a><\/TD><TD([\w\W\s\d][^<>]{0,})>([\w\W\s\d][^<>]{0,})<\/TD><TD([\w\W\s\d][^<>]{0,})>([\w\W\s\d][^<>]{0,})<\/TD><\/TR>/is
+ <TR BGCOLOR='#DBE9E9'><TD align=left valign=top>43.<a href='joblist.cfm?JobID=94 6735&Keyword='>Word Processor<BR>(N-1286)</a></TD><TD align=left valign=top>Lega lstaff.com</TD><TD align=left valign=top>CA - Statewide</TD></TR>
+ 0: <TR BGCOLOR='#DBE9E9'><TD align=left valign=top>43.<a href='joblist.cfm?JobID=94 6735&Keyword='>Word Processor<BR>(N-1286)</a></TD><TD align=left valign=top>Lega lstaff.com</TD><TD align=left valign=top>CA - Statewide</TD></TR>
+ 1: BGCOLOR='#DBE9E9'
+ 2: align=left valign=top
+ 3: 43.
+ 4: <a href='joblist.cfm?JobID=94 6735&Keyword='>Word Processor<BR>(N-1286)
+ 5:
+ 6:
+ 7: <unset>
+ 8: align=left valign=top
+ 9: Lega lstaff.com
+10: align=left valign=top
+11: CA - Statewide
+
+/a[^a]b/
+ acb
+ 0: acb
+ a\nb
+ 0: a\x0ab
+
+/a.b/
+ acb
+ 0: acb
+ *** Failers
+No match
+ a\nb
+No match
+
+/a[^a]b/s
+ acb
+ 0: acb
+ a\nb
+ 0: a\x0ab
+
+/a.b/s
+ acb
+ 0: acb
+ a\nb
+ 0: a\x0ab
+
+/^(b+?|a){1,2}?c/
+ bac
+ 0: bac
+ 1: a
+ bbac
+ 0: bbac
+ 1: a
+ bbbac
+ 0: bbbac
+ 1: a
+ bbbbac
+ 0: bbbbac
+ 1: a
+ bbbbbac
+ 0: bbbbbac
+ 1: a
+
+/^(b+|a){1,2}?c/
+ bac
+ 0: bac
+ 1: a
+ bbac
+ 0: bbac
+ 1: a
+ bbbac
+ 0: bbbac
+ 1: a
+ bbbbac
+ 0: bbbbac
+ 1: a
+ bbbbbac
+ 0: bbbbbac
+ 1: a
+
+/(?!\A)x/m
+ x\nb\n
+No match
+ a\bx\n
+ 0: x
+
+/\x0{ab}/
+ \0{ab}
+ 0: \x00{ab}
+
+/(A|B)*?CD/
+ CD
+ 0: CD
+
+/(A|B)*CD/
+ CD
+ 0: CD
+
+/(AB)*?\1/
+ ABABAB
+ 0: ABAB
+ 1: AB
+
+/(AB)*\1/
+ ABABAB
+ 0: ABABAB
+ 1: AB
+
+/(?<!bar)foo/
+ foo
+ 0: foo
+ catfood
+ 0: foo
+ arfootle
+ 0: foo
+ rfoosh
+ 0: foo
+ *** Failers
+No match
+ barfoo
+No match
+ towbarfoo
+No match
+
+/\w{3}(?<!bar)foo/
+ catfood
+ 0: catfoo
+ *** Failers
+No match
+ foo
+No match
+ barfoo
+No match
+ towbarfoo
+No match
+
+/(?<=(foo)a)bar/
+ fooabar
+ 0: bar
+ 1: foo
+ *** Failers
+No match
+ bar
+No match
+ foobbar
+No match
+
+/\Aabc\z/m
+ abc
+ 0: abc
+ *** Failers
+No match
+ abc\n
+No match
+ qqq\nabc
+No match
+ abc\nzzz
+No match
+ qqq\nabc\nzzz
+No match
+
+"(?>.*/)foo"
+ /this/is/a/very/long/line/in/deed/with/very/many/slashes/in/it/you/see/
+No match
+
+"(?>.*/)foo"
+ /this/is/a/very/long/line/in/deed/with/very/many/slashes/in/and/foo
+ 0: /this/is/a/very/long/line/in/deed/with/very/many/slashes/in/and/foo
+
+/(?>(\.\d\d[1-9]?))\d+/
+ 1.230003938
+ 0: .230003938
+ 1: .23
+ 1.875000282
+ 0: .875000282
+ 1: .875
+ *** Failers
+No match
+ 1.235
+No match
+
+/^((?>\w+)|(?>\s+))*$/
+ now is the time for all good men to come to the aid of the party
+ 0: now is the time for all good men to come to the aid of the party
+ 1: party
+ *** Failers
+No match
+ this is not a line with only words and spaces!
+No match
+
+/(\d+)(\w)/
+ 12345a
+ 0: 12345a
+ 1: 12345
+ 2: a
+ 12345+
+ 0: 12345
+ 1: 1234
+ 2: 5
+
+/((?>\d+))(\w)/
+ 12345a
+ 0: 12345a
+ 1: 12345
+ 2: a
+ *** Failers
+No match
+ 12345+
+No match
+
+/(?>a+)b/
+ aaab
+ 0: aaab
+
+/((?>a+)b)/
+ aaab
+ 0: aaab
+ 1: aaab
+
+/(?>(a+))b/
+ aaab
+ 0: aaab
+ 1: aaa
+
+/(?>b)+/
+ aaabbbccc
+ 0: bbb
+
+/(?>a+|b+|c+)*c/
+ aaabbbbccccd
+ 0: aaabbbbc
+
+/((?>[^()]+)|\([^()]*\))+/
+ ((abc(ade)ufh()()x
+ 0: abc(ade)ufh()()x
+ 1: x
+
+/\(((?>[^()]+)|\([^()]+\))+\)/
+ (abc)
+ 0: (abc)
+ 1: abc
+ (abc(def)xyz)
+ 0: (abc(def)xyz)
+ 1: xyz
+ *** Failers
+No match
+ ((()aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+No match
+
+/a(?-i)b/i
+ ab
+ 0: ab
+ Ab
+ 0: Ab
+ *** Failers
+No match
+ aB
+No match
+ AB
+No match
+
+/(a (?x)b c)d e/
+ a bcd e
+ 0: a bcd e
+ 1: a bc
+ *** Failers
+No match
+ a b cd e
+No match
+ abcd e
+No match
+ a bcde
+No match
+
+/(a b(?x)c d (?-x)e f)/
+ a bcde f
+ 0: a bcde f
+ 1: a bcde f
+ *** Failers
+No match
+ abcdef
+No match
+
+/(a(?i)b)c/
+ abc
+ 0: abc
+ 1: ab
+ aBc
+ 0: aBc
+ 1: aB
+ *** Failers
+No match
+ abC
+No match
+ aBC
+No match
+ Abc
+No match
+ ABc
+No match
+ ABC
+No match
+ AbC
+No match
+
+/a(?i:b)c/
+ abc
+ 0: abc
+ aBc
+ 0: aBc
+ *** Failers
+No match
+ ABC
+No match
+ abC
+No match
+ aBC
+No match
+
+/a(?i:b)*c/
+ aBc
+ 0: aBc
+ aBBc
+ 0: aBBc
+ *** Failers
+No match
+ aBC
+No match
+ aBBC
+No match
+
+/a(?=b(?i)c)\w\wd/
+ abcd
+ 0: abcd
+ abCd
+ 0: abCd
+ *** Failers
+No match
+ aBCd
+No match
+ abcD
+No match
+
+/(?s-i:more.*than).*million/i
+ more than million
+ 0: more than million
+ more than MILLION
+ 0: more than MILLION
+ more \n than Million
+ 0: more \x0a than Million
+ *** Failers
+No match
+ MORE THAN MILLION
+No match
+ more \n than \n million
+No match
+
+/(?:(?s-i)more.*than).*million/i
+ more than million
+ 0: more than million
+ more than MILLION
+ 0: more than MILLION
+ more \n than Million
+ 0: more \x0a than Million
+ *** Failers
+No match
+ MORE THAN MILLION
+No match
+ more \n than \n million
+No match
+
+/(?>a(?i)b+)+c/
+ abc
+ 0: abc
+ aBbc
+ 0: aBbc
+ aBBc
+ 0: aBBc
+ *** Failers
+No match
+ Abc
+No match
+ abAb
+No match
+ abbC
+No match
+
+/(?=a(?i)b)\w\wc/
+ abc
+ 0: abc
+ aBc
+ 0: aBc
+ *** Failers
+No match
+ Ab
+No match
+ abC
+No match
+ aBC
+No match
+
+/(?<=a(?i)b)(\w\w)c/
+ abxxc
+ 0: xxc
+ 1: xx
+ aBxxc
+ 0: xxc
+ 1: xx
+ *** Failers
+No match
+ Abxxc
+No match
+ ABxxc
+No match
+ abxxC
+No match
+
+/(?:(a)|b)(?(1)A|B)/
+ aA
+ 0: aA
+ 1: a
+ bB
+ 0: bB
+ *** Failers
+No match
+ aB
+No match
+ bA
+No match
+
+/^(a)?(?(1)a|b)+$/
+ aa
+ 0: aa
+ 1: a
+ b
+ 0: b
+ bb
+ 0: bb
+ *** Failers
+No match
+ ab
+No match
+
+/^(?(?=abc)\w{3}:|\d\d)$/
+ abc:
+ 0: abc:
+ 12
+ 0: 12
+ *** Failers
+No match
+ 123
+No match
+ xyz
+No match
+
+/^(?(?!abc)\d\d|\w{3}:)$/
+ abc:
+ 0: abc:
+ 12
+ 0: 12
+ *** Failers
+No match
+ 123
+No match
+ xyz
+No match
+
+/(?(?<=foo)bar|cat)/
+ foobar
+ 0: bar
+ cat
+ 0: cat
+ fcat
+ 0: cat
+ focat
+ 0: cat
+ *** Failers
+No match
+ foocat
+No match
+
+/(?(?<!foo)cat|bar)/
+ foobar
+ 0: bar
+ cat
+ 0: cat
+ fcat
+ 0: cat
+ focat
+ 0: cat
+ *** Failers
+No match
+ foocat
+No match
+
+/( \( )? [^()]+ (?(1) \) |) /x
+ abcd
+ 0: abcd
+ (abcd)
+ 0: (abcd)
+ 1: (
+ the quick (abcd) fox
+ 0: the quick
+ (abcd
+ 0: abcd
+
+/( \( )? [^()]+ (?(1) \) ) /x
+ abcd
+ 0: abcd
+ (abcd)
+ 0: (abcd)
+ 1: (
+ the quick (abcd) fox
+ 0: the quick
+ (abcd
+ 0: abcd
+
+/^(?(2)a|(1)(2))+$/
+ 12
+ 0: 12
+ 1: 1
+ 2: 2
+ 12a
+ 0: 12a
+ 1: 1
+ 2: 2
+ 12aa
+ 0: 12aa
+ 1: 1
+ 2: 2
+ *** Failers
+No match
+ 1234
+No match
+
+/((?i)blah)\s+\1/
+ blah blah
+ 0: blah blah
+ 1: blah
+ BLAH BLAH
+ 0: BLAH BLAH
+ 1: BLAH
+ Blah Blah
+ 0: Blah Blah
+ 1: Blah
+ blaH blaH
+ 0: blaH blaH
+ 1: blaH
+ *** Failers
+No match
+ blah BLAH
+No match
+ Blah blah
+No match
+ blaH blah
+No match
+
+/((?i)blah)\s+(?i:\1)/
+ blah blah
+ 0: blah blah
+ 1: blah
+ BLAH BLAH
+ 0: BLAH BLAH
+ 1: BLAH
+ Blah Blah
+ 0: Blah Blah
+ 1: Blah
+ blaH blaH
+ 0: blaH blaH
+ 1: blaH
+ blah BLAH
+ 0: blah BLAH
+ 1: blah
+ Blah blah
+ 0: Blah blah
+ 1: Blah
+ blaH blah
+ 0: blaH blah
+ 1: blaH
+
+/(?>a*)*/
+ a
+ 0: a
+ aa
+ 0: aa
+ aaaa
+ 0: aaaa
+
+/(abc|)+/
+ abc
+ 0: abc
+ 1:
+ abcabc
+ 0: abcabc
+ 1:
+ abcabcabc
+ 0: abcabcabc
+ 1:
+ xyz
+ 0:
+ 1:
+
+/([a]*)*/
+ a
+ 0: a
+ 1:
+ aaaaa
+ 0: aaaaa
+ 1:
+
+/([ab]*)*/
+ a
+ 0: a
+ 1:
+ b
+ 0: b
+ 1:
+ ababab
+ 0: ababab
+ 1:
+ aaaabcde
+ 0: aaaab
+ 1:
+ bbbb
+ 0: bbbb
+ 1:
+
+/([^a]*)*/
+ b
+ 0: b
+ 1:
+ bbbb
+ 0: bbbb
+ 1:
+ aaa
+ 0:
+ 1:
+
+/([^ab]*)*/
+ cccc
+ 0: cccc
+ 1:
+ abab
+ 0:
+ 1:
+
+/([a]*?)*/
+ a
+ 0:
+ 1:
+ aaaa
+ 0:
+ 1:
+
+/([ab]*?)*/
+ a
+ 0:
+ 1:
+ b
+ 0:
+ 1:
+ abab
+ 0:
+ 1:
+ baba
+ 0:
+ 1:
+
+/([^a]*?)*/
+ b
+ 0:
+ 1:
+ bbbb
+ 0:
+ 1:
+ aaa
+ 0:
+ 1:
+
+/([^ab]*?)*/
+ c
+ 0:
+ 1:
+ cccc
+ 0:
+ 1:
+ baba
+ 0:
+ 1:
+
+/(?>a*)*/
+ a
+ 0: a
+ aaabcde
+ 0: aaa
+
+/((?>a*))*/
+ aaaaa
+ 0: aaaaa
+ 1:
+ aabbaa
+ 0: aa
+ 1:
+
+/((?>a*?))*/
+ aaaaa
+ 0:
+ 1:
+ aabbaa
+ 0:
+ 1:
+
+/(?(?=[^a-z]+[a-z]) \d{2}-[a-z]{3}-\d{2} | \d{2}-\d{2}-\d{2} ) /x
+ 12-sep-98
+ 0: 12-sep-98
+ 12-09-98
+ 0: 12-09-98
+ *** Failers
+No match
+ sep-12-98
+No match
+
+/(?<=(foo))bar\1/
+ foobarfoo
+ 0: barfoo
+ 1: foo
+ foobarfootling
+ 0: barfoo
+ 1: foo
+ *** Failers
+No match
+ foobar
+No match
+ barfoo
+No match
+
+/(?i:saturday|sunday)/
+ saturday
+ 0: saturday
+ sunday
+ 0: sunday
+ Saturday
+ 0: Saturday
+ Sunday
+ 0: Sunday
+ SATURDAY
+ 0: SATURDAY
+ SUNDAY
+ 0: SUNDAY
+ SunDay
+ 0: SunDay
+
+/(a(?i)bc|BB)x/
+ abcx
+ 0: abcx
+ 1: abc
+ aBCx
+ 0: aBCx
+ 1: aBC
+ bbx
+ 0: bbx
+ 1: bb
+ BBx
+ 0: BBx
+ 1: BB
+ *** Failers
+No match
+ abcX
+No match
+ aBCX
+No match
+ bbX
+No match
+ BBX
+No match
+
+/^([ab](?i)[cd]|[ef])/
+ ac
+ 0: ac
+ 1: ac
+ aC
+ 0: aC
+ 1: aC
+ bD
+ 0: bD
+ 1: bD
+ elephant
+ 0: e
+ 1: e
+ Europe
+ 0: E
+ 1: E
+ frog
+ 0: f
+ 1: f
+ France
+ 0: F
+ 1: F
+ *** Failers
+No match
+ Africa
+No match
+
+/^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)/
+ ab
+ 0: ab
+ 1: ab
+ aBd
+ 0: aBd
+ 1: aBd
+ xy
+ 0: xy
+ 1: xy
+ xY
+ 0: xY
+ 1: xY
+ zebra
+ 0: z
+ 1: z
+ Zambesi
+ 0: Z
+ 1: Z
+ *** Failers
+No match
+ aCD
+No match
+ XY
+No match
+
+/(?<=foo\n)^bar/m
+ foo\nbar
+ 0: bar
+ *** Failers
+No match
+ bar
+No match
+ baz\nbar
+No match
+
+/(?<=(?<!foo)bar)baz/
+ barbaz
+ 0: baz
+ barbarbaz
+ 0: baz
+ koobarbaz
+ 0: baz
+ *** Failers
+No match
+ baz
+No match
+ foobarbaz
+No match
+
+/The case of aaaaaa is missed out below because I think Perl 5.005_02 gets/
+/it wrong; it sets $1 to aaa rather than aa. Compare the following test,/
+No match
+/where it does set $1 to aa when matching aaaaaa./
+No match
+
+/^(a\1?){4}$/
+ a
+No match
+ aa
+No match
+ aaa
+No match
+ aaaa
+ 0: aaaa
+ 1: a
+ aaaaa
+ 0: aaaaa
+ 1: a
+ aaaaaaa
+ 0: aaaaaaa
+ 1: a
+ aaaaaaaa
+No match
+ aaaaaaaaa
+No match
+ aaaaaaaaaa
+ 0: aaaaaaaaaa
+ 1: aaaa
+ aaaaaaaaaaa
+No match
+ aaaaaaaaaaaa
+No match
+ aaaaaaaaaaaaa
+No match
+ aaaaaaaaaaaaaa
+No match
+ aaaaaaaaaaaaaaa
+No match
+ aaaaaaaaaaaaaaaa
+No match
+
+/^(a\1?)(a\1?)(a\2?)(a\3?)$/
+ a
+No match
+ aa
+No match
+ aaa
+No match
+ aaaa
+ 0: aaaa
+ 1: a
+ 2: a
+ 3: a
+ 4: a
+ aaaaa
+ 0: aaaaa
+ 1: a
+ 2: aa
+ 3: a
+ 4: a
+ aaaaaa
+ 0: aaaaaa
+ 1: a
+ 2: aa
+ 3: a
+ 4: aa
+ aaaaaaa
+ 0: aaaaaaa
+ 1: a
+ 2: aa
+ 3: aaa
+ 4: a
+ aaaaaaaa
+No match
+ aaaaaaaaa
+No match
+ aaaaaaaaaa
+ 0: aaaaaaaaaa
+ 1: a
+ 2: aa
+ 3: aaa
+ 4: aaaa
+ aaaaaaaaaaa
+No match
+ aaaaaaaaaaaa
+No match
+ aaaaaaaaaaaaa
+No match
+ aaaaaaaaaaaaaa
+No match
+ aaaaaaaaaaaaaaa
+No match
+ aaaaaaaaaaaaaaaa
+No match
+
+/The following tests are taken from the Perl 5.005 test suite; some of them/
+/are compatible with 5.004, but I'd rather not have to sort them out./
+No match
+
+/abc/
+ abc
+ 0: abc
+ xabcy
+ 0: abc
+ ababc
+ 0: abc
+ *** Failers
+No match
+ xbc
+No match
+ axc
+No match
+ abx
+No match
+
+/ab*c/
+ abc
+ 0: abc
+
+/ab*bc/
+ abc
+ 0: abc
+ abbc
+ 0: abbc
+ abbbbc
+ 0: abbbbc
+
+/.{1}/
+ abbbbc
+ 0: a
+
+/.{3,4}/
+ abbbbc
+ 0: abbb
+
+/ab{0,}bc/
+ abbbbc
+ 0: abbbbc
+
+/ab+bc/
+ abbc
+ 0: abbc
+ *** Failers
+No match
+ abc
+No match
+ abq
+No match
+
+/ab{1,}bc/
+
+/ab+bc/
+ abbbbc
+ 0: abbbbc
+
+/ab{1,}bc/
+ abbbbc
+ 0: abbbbc
+
+/ab{1,3}bc/
+ abbbbc
+ 0: abbbbc
+
+/ab{3,4}bc/
+ abbbbc
+ 0: abbbbc
+
+/ab{4,5}bc/
+ *** Failers
+No match
+ abq
+No match
+ abbbbc
+No match
+
+/ab?bc/
+ abbc
+ 0: abbc
+ abc
+ 0: abc
+
+/ab{0,1}bc/
+ abc
+ 0: abc
+
+/ab?bc/
+
+/ab?c/
+ abc
+ 0: abc
+
+/ab{0,1}c/
+ abc
+ 0: abc
+
+/^abc$/
+ abc
+ 0: abc
+ *** Failers
+No match
+ abbbbc
+No match
+ abcc
+No match
+
+/^abc/
+ abcc
+ 0: abc
+
+/^abc$/
+
+/abc$/
+ aabc
+ 0: abc
+ *** Failers
+No match
+ aabc
+ 0: abc
+ aabcd
+No match
+
+/^/
+ abc
+ 0:
+
+/$/
+ abc
+ 0:
+
+/a.c/
+ abc
+ 0: abc
+ axc
+ 0: axc
+
+/a.*c/
+ axyzc
+ 0: axyzc
+
+/a[bc]d/
+ abd
+ 0: abd
+ *** Failers
+No match
+ axyzd
+No match
+ abc
+No match
+
+/a[b-d]e/
+ ace
+ 0: ace
+
+/a[b-d]/
+ aac
+ 0: ac
+
+/a[-b]/
+ a-
+ 0: a-
+
+/a[b-]/
+ a-
+ 0: a-
+
+/a]/
+ a]
+ 0: a]
+
+/a[]]b/
+ a]b
+ 0: a]b
+
+/a[^bc]d/
+ aed
+ 0: aed
+ *** Failers
+No match
+ abd
+No match
+ abd
+No match
+
+/a[^-b]c/
+ adc
+ 0: adc
+
+/a[^]b]c/
+ adc
+ 0: adc
+ *** Failers
+No match
+ a-c
+ 0: a-c
+ a]c
+No match
+
+/\ba\b/
+ a-
+ 0: a
+ -a
+ 0: a
+ -a-
+ 0: a
+
+/\by\b/
+ *** Failers
+No match
+ xy
+No match
+ yz
+No match
+ xyz
+No match
+
+/\Ba\B/
+ *** Failers
+ 0: a
+ a-
+No match
+ -a
+No match
+ -a-
+No match
+
+/\By\b/
+ xy
+ 0: y
+
+/\by\B/
+ yz
+ 0: y
+
+/\By\B/
+ xyz
+ 0: y
+
+/\w/
+ a
+ 0: a
+
+/\W/
+ -
+ 0: -
+ *** Failers
+ 0: *
+ -
+ 0: -
+ a
+No match
+
+/a\sb/
+ a b
+ 0: a b
+
+/a\Sb/
+ a-b
+ 0: a-b
+ *** Failers
+No match
+ a-b
+ 0: a-b
+ a b
+No match
+
+/\d/
+ 1
+ 0: 1
+
+/\D/
+ -
+ 0: -
+ *** Failers
+ 0: *
+ -
+ 0: -
+ 1
+No match
+
+/[\w]/
+ a
+ 0: a
+
+/[\W]/
+ -
+ 0: -
+ *** Failers
+ 0: *
+ -
+ 0: -
+ a
+No match
+
+/a[\s]b/
+ a b
+ 0: a b
+
+/a[\S]b/
+ a-b
+ 0: a-b
+ *** Failers
+No match
+ a-b
+ 0: a-b
+ a b
+No match
+
+/[\d]/
+ 1
+ 0: 1
+
+/[\D]/
+ -
+ 0: -
+ *** Failers
+ 0: *
+ -
+ 0: -
+ 1
+No match
+
+/ab|cd/
+ abc
+ 0: ab
+ abcd
+ 0: ab
+
+/()ef/
+ def
+ 0: ef
+ 1:
+
+/$b/
+
+/a\(b/
+ a(b
+ 0: a(b
+
+/a\(*b/
+ ab
+ 0: ab
+ a((b
+ 0: a((b
+
+/a\\b/
+ a\b
+No match
+
+/((a))/
+ abc
+ 0: a
+ 1: a
+ 2: a
+
+/(a)b(c)/
+ abc
+ 0: abc
+ 1: a
+ 2: c
+
+/a+b+c/
+ aabbabc
+ 0: abc
+
+/a{1,}b{1,}c/
+ aabbabc
+ 0: abc
+
+/a.+?c/
+ abcabc
+ 0: abc
+
+/(a+|b)*/
+ ab
+ 0: ab
+ 1: b
+
+/(a+|b){0,}/
+ ab
+ 0: ab
+ 1: b
+
+/(a+|b)+/
+ ab
+ 0: ab
+ 1: b
+
+/(a+|b){1,}/
+ ab
+ 0: ab
+ 1: b
+
+/(a+|b)?/
+ ab
+ 0: a
+ 1: a
+
+/(a+|b){0,1}/
+ ab
+ 0: a
+ 1: a
+
+/[^ab]*/
+ cde
+ 0: cde
+
+/abc/
+ *** Failers
+No match
+ b
+No match
+
+
+/a*/
+
+
+/([abc])*d/
+ abbbcd
+ 0: abbbcd
+ 1: c
+
+/([abc])*bcd/
+ abcd
+ 0: abcd
+ 1: a
+
+/a|b|c|d|e/
+ e
+ 0: e
+
+/(a|b|c|d|e)f/
+ ef
+ 0: ef
+ 1: e
+
+/abcd*efg/
+ abcdefg
+ 0: abcdefg
+
+/ab*/
+ xabyabbbz
+ 0: ab
+ xayabbbz
+ 0: a
+
+/(ab|cd)e/
+ abcde
+ 0: cde
+ 1: cd
+
+/[abhgefdc]ij/
+ hij
+ 0: hij
+
+/^(ab|cd)e/
+
+/(abc|)ef/
+ abcdef
+ 0: ef
+ 1:
+
+/(a|b)c*d/
+ abcd
+ 0: bcd
+ 1: b
+
+/(ab|ab*)bc/
+ abc
+ 0: abc
+ 1: a
+
+/a([bc]*)c*/
+ abc
+ 0: abc
+ 1: bc
+
+/a([bc]*)(c*d)/
+ abcd
+ 0: abcd
+ 1: bc
+ 2: d
+
+/a([bc]+)(c*d)/
+ abcd
+ 0: abcd
+ 1: bc
+ 2: d
+
+/a([bc]*)(c+d)/
+ abcd
+ 0: abcd
+ 1: b
+ 2: cd
+
+/a[bcd]*dcdcde/
+ adcdcde
+ 0: adcdcde
+
+/a[bcd]+dcdcde/
+ *** Failers
+No match
+ abcde
+No match
+ adcdcde
+No match
+
+/(ab|a)b*c/
+ abc
+ 0: abc
+ 1: ab
+
+/((a)(b)c)(d)/
+ abcd
+ 0: abcd
+ 1: abc
+ 2: a
+ 3: b
+ 4: d
+
+/[a-zA-Z_][a-zA-Z0-9_]*/
+ alpha
+ 0: alpha
+
+/^a(bc+|b[eh])g|.h$/
+ abh
+ 0: bh
+
+/(bc+d$|ef*g.|h?i(j|k))/
+ effgz
+ 0: effgz
+ 1: effgz
+ ij
+ 0: ij
+ 1: ij
+ 2: j
+ reffgz
+ 0: effgz
+ 1: effgz
+ *** Failers
+No match
+ effg
+No match
+ bcdd
+No match
+
+/((((((((((a))))))))))/
+ a
+ 0: a
+ 1: a
+ 2: a
+ 3: a
+ 4: a
+ 5: a
+ 6: a
+ 7: a
+ 8: a
+ 9: a
+10: a
+
+/((((((((((a))))))))))\10/
+ aa
+ 0: aa
+ 1: a
+ 2: a
+ 3: a
+ 4: a
+ 5: a
+ 6: a
+ 7: a
+ 8: a
+ 9: a
+10: a
+
+/(((((((((a)))))))))/
+ a
+ 0: a
+ 1: a
+ 2: a
+ 3: a
+ 4: a
+ 5: a
+ 6: a
+ 7: a
+ 8: a
+ 9: a
+
+/multiple words of text/
+ *** Failers
+No match
+ aa
+No match
+ uh-uh
+No match
+
+/multiple words/
+ multiple words, yeah
+ 0: multiple words
+
+/(.*)c(.*)/
+ abcde
+ 0: abcde
+ 1: ab
+ 2: de
+
+/\((.*), (.*)\)/
+ (a, b)
+ 0: (a, b)
+ 1: a
+ 2: b
+
+/[k]/
+
+/abcd/
+ abcd
+ 0: abcd
+
+/a(bc)d/
+ abcd
+ 0: abcd
+ 1: bc
+
+/a[-]?c/
+ ac
+ 0: ac
+
+/(abc)\1/
+ abcabc
+ 0: abcabc
+ 1: abc
+
+/([a-c]*)\1/
+ abcabc
+ 0: abcabc
+ 1: abc
+
+/(a)|\1/
+ a
+ 0: a
+ 1: a
+ *** Failers
+ 0: a
+ 1: a
+ ab
+ 0: a
+ 1: a
+ x
+No match
+
+/(([a-c])b*?\2)*/
+ ababbbcbc
+ 0: ababb
+ 1: bb
+ 2: b
+
+/(([a-c])b*?\2){3}/
+ ababbbcbc
+ 0: ababbbcbc
+ 1: cbc
+ 2: c
+
+/((\3|b)\2(a)x)+/
+ aaaxabaxbaaxbbax
+ 0: bbax
+ 1: bbax
+ 2: b
+ 3: a
+
+/((\3|b)\2(a)){2,}/
+ bbaababbabaaaaabbaaaabba
+ 0: bbaaaabba
+ 1: bba
+ 2: b
+ 3: a
+
+/abc/i
+ ABC
+ 0: ABC
+ XABCY
+ 0: ABC
+ ABABC
+ 0: ABC
+ *** Failers
+No match
+ aaxabxbaxbbx
+No match
+ XBC
+No match
+ AXC
+No match
+ ABX
+No match
+
+/ab*c/i
+ ABC
+ 0: ABC
+
+/ab*bc/i
+ ABC
+ 0: ABC
+ ABBC
+ 0: ABBC
+
+/ab*?bc/i
+ ABBBBC
+ 0: ABBBBC
+
+/ab{0,}?bc/i
+ ABBBBC
+ 0: ABBBBC
+
+/ab+?bc/i
+ ABBC
+ 0: ABBC
+
+/ab+bc/i
+ *** Failers
+No match
+ ABC
+No match
+ ABQ
+No match
+
+/ab{1,}bc/i
+
+/ab+bc/i
+ ABBBBC
+ 0: ABBBBC
+
+/ab{1,}?bc/i
+ ABBBBC
+ 0: ABBBBC
+
+/ab{1,3}?bc/i
+ ABBBBC
+ 0: ABBBBC
+
+/ab{3,4}?bc/i
+ ABBBBC
+ 0: ABBBBC
+
+/ab{4,5}?bc/i
+ *** Failers
+No match
+ ABQ
+No match
+ ABBBBC
+No match
+
+/ab??bc/i
+ ABBC
+ 0: ABBC
+ ABC
+ 0: ABC
+
+/ab{0,1}?bc/i
+ ABC
+ 0: ABC
+
+/ab??bc/i
+
+/ab??c/i
+ ABC
+ 0: ABC
+
+/ab{0,1}?c/i
+ ABC
+ 0: ABC
+
+/^abc$/i
+ ABC
+ 0: ABC
+ *** Failers
+No match
+ ABBBBC
+No match
+ ABCC
+No match
+
+/^abc/i
+ ABCC
+ 0: ABC
+
+/^abc$/i
+
+/abc$/i
+ AABC
+ 0: ABC
+
+/^/i
+ ABC
+ 0:
+
+/$/i
+ ABC
+ 0:
+
+/a.c/i
+ ABC
+ 0: ABC
+ AXC
+ 0: AXC
+
+/a.*?c/i
+ AXYZC
+ 0: AXYZC
+
+/a.*c/i
+ *** Failers
+No match
+ AABC
+ 0: AABC
+ AXYZD
+No match
+
+/a[bc]d/i
+ ABD
+ 0: ABD
+
+/a[b-d]e/i
+ ACE
+ 0: ACE
+ *** Failers
+No match
+ ABC
+No match
+ ABD
+No match
+
+/a[b-d]/i
+ AAC
+ 0: AC
+
+/a[-b]/i
+ A-
+ 0: A-
+
+/a[b-]/i
+ A-
+ 0: A-
+
+/a]/i
+ A]
+ 0: A]
+
+/a[]]b/i
+ A]B
+ 0: A]B
+
+/a[^bc]d/i
+ AED
+ 0: AED
+
+/a[^-b]c/i
+ ADC
+ 0: ADC
+ *** Failers
+No match
+ ABD
+No match
+ A-C
+No match
+
+/a[^]b]c/i
+ ADC
+ 0: ADC
+
+/ab|cd/i
+ ABC
+ 0: AB
+ ABCD
+ 0: AB
+
+/()ef/i
+ DEF
+ 0: EF
+ 1:
+
+/$b/i
+ *** Failers
+No match
+ A]C
+No match
+ B
+No match
+
+/a\(b/i
+ A(B
+ 0: A(B
+
+/a\(*b/i
+ AB
+ 0: AB
+ A((B
+ 0: A((B
+
+/a\\b/i
+ A\B
+No match
+
+/((a))/i
+ ABC
+ 0: A
+ 1: A
+ 2: A
+
+/(a)b(c)/i
+ ABC
+ 0: ABC
+ 1: A
+ 2: C
+
+/a+b+c/i
+ AABBABC
+ 0: ABC
+
+/a{1,}b{1,}c/i
+ AABBABC
+ 0: ABC
+
+/a.+?c/i
+ ABCABC
+ 0: ABC
+
+/a.*?c/i
+ ABCABC
+ 0: ABC
+
+/a.{0,5}?c/i
+ ABCABC
+ 0: ABC
+
+/(a+|b)*/i
+ AB
+ 0: AB
+ 1: B
+
+/(a+|b){0,}/i
+ AB
+ 0: AB
+ 1: B
+
+/(a+|b)+/i
+ AB
+ 0: AB
+ 1: B
+
+/(a+|b){1,}/i
+ AB
+ 0: AB
+ 1: B
+
+/(a+|b)?/i
+ AB
+ 0: A
+ 1: A
+
+/(a+|b){0,1}/i
+ AB
+ 0: A
+ 1: A
+
+/(a+|b){0,1}?/i
+ AB
+ 0:
+
+/[^ab]*/i
+ CDE
+ 0: CDE
+
+/abc/i
+
+/a*/i
+
+
+/([abc])*d/i
+ ABBBCD
+ 0: ABBBCD
+ 1: C
+
+/([abc])*bcd/i
+ ABCD
+ 0: ABCD
+ 1: A
+
+/a|b|c|d|e/i
+ E
+ 0: E
+
+/(a|b|c|d|e)f/i
+ EF
+ 0: EF
+ 1: E
+
+/abcd*efg/i
+ ABCDEFG
+ 0: ABCDEFG
+
+/ab*/i
+ XABYABBBZ
+ 0: AB
+ XAYABBBZ
+ 0: A
+
+/(ab|cd)e/i
+ ABCDE
+ 0: CDE
+ 1: CD
+
+/[abhgefdc]ij/i
+ HIJ
+ 0: HIJ
+
+/^(ab|cd)e/i
+ ABCDE
+No match
+
+/(abc|)ef/i
+ ABCDEF
+ 0: EF
+ 1:
+
+/(a|b)c*d/i
+ ABCD
+ 0: BCD
+ 1: B
+
+/(ab|ab*)bc/i
+ ABC
+ 0: ABC
+ 1: A
+
+/a([bc]*)c*/i
+ ABC
+ 0: ABC
+ 1: BC
+
+/a([bc]*)(c*d)/i
+ ABCD
+ 0: ABCD
+ 1: BC
+ 2: D
+
+/a([bc]+)(c*d)/i
+ ABCD
+ 0: ABCD
+ 1: BC
+ 2: D
+
+/a([bc]*)(c+d)/i
+ ABCD
+ 0: ABCD
+ 1: B
+ 2: CD
+
+/a[bcd]*dcdcde/i
+ ADCDCDE
+ 0: ADCDCDE
+
+/a[bcd]+dcdcde/i
+
+/(ab|a)b*c/i
+ ABC
+ 0: ABC
+ 1: AB
+
+/((a)(b)c)(d)/i
+ ABCD
+ 0: ABCD
+ 1: ABC
+ 2: A
+ 3: B
+ 4: D
+
+/[a-zA-Z_][a-zA-Z0-9_]*/i
+ ALPHA
+ 0: ALPHA
+
+/^a(bc+|b[eh])g|.h$/i
+ ABH
+ 0: BH
+
+/(bc+d$|ef*g.|h?i(j|k))/i
+ EFFGZ
+ 0: EFFGZ
+ 1: EFFGZ
+ IJ
+ 0: IJ
+ 1: IJ
+ 2: J
+ REFFGZ
+ 0: EFFGZ
+ 1: EFFGZ
+ *** Failers
+No match
+ ADCDCDE
+No match
+ EFFG
+No match
+ BCDD
+No match
+
+/((((((((((a))))))))))/i
+ A
+ 0: A
+ 1: A
+ 2: A
+ 3: A
+ 4: A
+ 5: A
+ 6: A
+ 7: A
+ 8: A
+ 9: A
+10: A
+
+/((((((((((a))))))))))\10/i
+ AA
+ 0: AA
+ 1: A
+ 2: A
+ 3: A
+ 4: A
+ 5: A
+ 6: A
+ 7: A
+ 8: A
+ 9: A
+10: A
+
+/(((((((((a)))))))))/i
+ A
+ 0: A
+ 1: A
+ 2: A
+ 3: A
+ 4: A
+ 5: A
+ 6: A
+ 7: A
+ 8: A
+ 9: A
+
+/(?:(?:(?:(?:(?:(?:(?:(?:(?:(a))))))))))/i
+ A
+ 0: A
+ 1: A
+
+/(?:(?:(?:(?:(?:(?:(?:(?:(?:(a|b|c))))))))))/i
+ C
+ 0: C
+ 1: C
+
+/multiple words of text/i
+ *** Failers
+No match
+ AA
+No match
+ UH-UH
+No match
+
+/multiple words/i
+ MULTIPLE WORDS, YEAH
+ 0: MULTIPLE WORDS
+
+/(.*)c(.*)/i
+ ABCDE
+ 0: ABCDE
+ 1: AB
+ 2: DE
+
+/\((.*), (.*)\)/i
+ (A, B)
+ 0: (A, B)
+ 1: A
+ 2: B
+
+/[k]/i
+
+/abcd/i
+ ABCD
+ 0: ABCD
+
+/a(bc)d/i
+ ABCD
+ 0: ABCD
+ 1: BC
+
+/a[-]?c/i
+ AC
+ 0: AC
+
+/(abc)\1/i
+ ABCABC
+ 0: ABCABC
+ 1: ABC
+
+/([a-c]*)\1/i
+ ABCABC
+ 0: ABCABC
+ 1: ABC
+
+/a(?!b)./
+ abad
+ 0: ad
+
+/a(?=d)./
+ abad
+ 0: ad
+
+/a(?=c|d)./
+ abad
+ 0: ad
+
+/a(?:b|c|d)(.)/
+ ace
+ 0: ace
+ 1: e
+
+/a(?:b|c|d)*(.)/
+ ace
+ 0: ace
+ 1: e
+
+/a(?:b|c|d)+?(.)/
+ ace
+ 0: ace
+ 1: e
+ acdbcdbe
+ 0: acd
+ 1: d
+
+/a(?:b|c|d)+(.)/
+ acdbcdbe
+ 0: acdbcdbe
+ 1: e
+
+/a(?:b|c|d){2}(.)/
+ acdbcdbe
+ 0: acdb
+ 1: b
+
+/a(?:b|c|d){4,5}(.)/
+ acdbcdbe
+ 0: acdbcdb
+ 1: b
+
+/a(?:b|c|d){4,5}?(.)/
+ acdbcdbe
+ 0: acdbcd
+ 1: d
+
+/((foo)|(bar))*/
+ foobar
+ 0: foobar
+ 1: bar
+ 2: foo
+ 3: bar
+
+/a(?:b|c|d){6,7}(.)/
+ acdbcdbe
+ 0: acdbcdbe
+ 1: e
+
+/a(?:b|c|d){6,7}?(.)/
+ acdbcdbe
+ 0: acdbcdbe
+ 1: e
+
+/a(?:b|c|d){5,6}(.)/
+ acdbcdbe
+ 0: acdbcdbe
+ 1: e
+
+/a(?:b|c|d){5,6}?(.)/
+ acdbcdbe
+ 0: acdbcdb
+ 1: b
+
+/a(?:b|c|d){5,7}(.)/
+ acdbcdbe
+ 0: acdbcdbe
+ 1: e
+
+/a(?:b|c|d){5,7}?(.)/
+ acdbcdbe
+ 0: acdbcdb
+ 1: b
+
+/a(?:b|(c|e){1,2}?|d)+?(.)/
+ ace
+ 0: ace
+ 1: c
+ 2: e
+
+/^(.+)?B/
+ AB
+ 0: AB
+ 1: A
+
+/^([^a-z])|(\^)$/
+ .
+ 0: .
+ 1: .
+
+/^[<>]&/
+ <&OUT
+ 0: <&
+
+/^(a\1?){4}$/
+ aaaaaaaaaa
+ 0: aaaaaaaaaa
+ 1: aaaa
+ *** Failers
+No match
+ AB
+No match
+ aaaaaaaaa
+No match
+ aaaaaaaaaaa
+No match
+
+/^(a(?(1)\1)){4}$/
+ aaaaaaaaaa
+ 0: aaaaaaaaaa
+ 1: aaaa
+ *** Failers
+No match
+ aaaaaaaaa
+No match
+ aaaaaaaaaaa
+No match
+
+/(?:(f)(o)(o)|(b)(a)(r))*/
+ foobar
+ 0: foobar
+ 1: f
+ 2: o
+ 3: o
+ 4: b
+ 5: a
+ 6: r
+
+/(?<=a)b/
+ ab
+ 0: b
+ *** Failers
+No match
+ cb
+No match
+ b
+No match
+
+/(?<!c)b/
+ ab
+ 0: b
+ b
+ 0: b
+ b
+ 0: b
+
+/(?:..)*a/
+ aba
+ 0: aba
+
+/(?:..)*?a/
+ aba
+ 0: a
+
+/^(?:b|a(?=(.)))*\1/
+ abc
+ 0: ab
+ 1: b
+
+/^(){3,5}/
+ abc
+ 0:
+ 1:
+
+/^(a+)*ax/
+ aax
+ 0: aax
+ 1: a
+
+/^((a|b)+)*ax/
+ aax
+ 0: aax
+ 1: a
+ 2: a
+
+/^((a|bc)+)*ax/
+ aax
+ 0: aax
+ 1: a
+ 2: a
+
+/(a|x)*ab/
+ cab
+ 0: ab
+
+/(a)*ab/
+ cab
+ 0: ab
+
+/(?:(?i)a)b/
+ ab
+ 0: ab
+
+/((?i)a)b/
+ ab
+ 0: ab
+ 1: a
+
+/(?:(?i)a)b/
+ Ab
+ 0: Ab
+
+/((?i)a)b/
+ Ab
+ 0: Ab
+ 1: A
+
+/(?:(?i)a)b/
+ *** Failers
+No match
+ cb
+No match
+ aB
+No match
+
+/((?i)a)b/
+
+/(?i:a)b/
+ ab
+ 0: ab
+
+/((?i:a))b/
+ ab
+ 0: ab
+ 1: a
+
+/(?i:a)b/
+ Ab
+ 0: Ab
+
+/((?i:a))b/
+ Ab
+ 0: Ab
+ 1: A
+
+/(?i:a)b/
+ *** Failers
+No match
+ aB
+No match
+ aB
+No match
+
+/((?i:a))b/
+
+/(?:(?-i)a)b/i
+ ab
+ 0: ab
+
+/((?-i)a)b/i
+ ab
+ 0: ab
+ 1: a
+
+/(?:(?-i)a)b/i
+ aB
+ 0: aB
+
+/((?-i)a)b/i
+ aB
+ 0: aB
+ 1: a
+
+/(?:(?-i)a)b/i
+ *** Failers
+No match
+ aB
+ 0: aB
+ Ab
+No match
+
+/((?-i)a)b/i
+
+/(?:(?-i)a)b/i
+ aB
+ 0: aB
+
+/((?-i)a)b/i
+ aB
+ 0: aB
+ 1: a
+
+/(?:(?-i)a)b/i
+ *** Failers
+No match
+ Ab
+No match
+ AB
+No match
+
+/((?-i)a)b/i
+
+/(?-i:a)b/i
+ ab
+ 0: ab
+
+/((?-i:a))b/i
+ ab
+ 0: ab
+ 1: a
+
+/(?-i:a)b/i
+ aB
+ 0: aB
+
+/((?-i:a))b/i
+ aB
+ 0: aB
+ 1: a
+
+/(?-i:a)b/i
+ *** Failers
+No match
+ AB
+No match
+ Ab
+No match
+
+/((?-i:a))b/i
+
+/(?-i:a)b/i
+ aB
+ 0: aB
+
+/((?-i:a))b/i
+ aB
+ 0: aB
+ 1: a
+
+/(?-i:a)b/i
+ *** Failers
+No match
+ Ab
+No match
+ AB
+No match
+
+/((?-i:a))b/i
+
+/((?-i:a.))b/i
+ *** Failers
+No match
+ AB
+No match
+ a\nB
+No match
+
+/((?s-i:a.))b/i
+ a\nB
+ 0: a\x0aB
+ 1: a\x0a
+
+/(?:c|d)(?:)(?:a(?:)(?:b)(?:b(?:))(?:b(?:)(?:b)))/
+ cabbbb
+ 0: cabbbb
+
+/(?:c|d)(?:)(?:aaaaaaaa(?:)(?:bbbbbbbb)(?:bbbbbbbb(?:))(?:bbbbbbbb(?:)(?:bbbbbbbb)))/
+ caaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+ 0: caaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+
+/(ab)\d\1/i
+ Ab4ab
+ 0: Ab4ab
+ 1: Ab
+ ab4Ab
+ 0: ab4Ab
+ 1: ab
+
+/foo\w*\d{4}baz/
+ foobar1234baz
+ 0: foobar1234baz
+
+/x(~~)*(?:(?:F)?)?/
+ x~~
+ 0: x~~
+ 1: ~~
+
+/^a(?#xxx){3}c/
+ aaac
+ 0: aaac
+
+/^a (?#xxx) (?#yyy) {3}c/x
+ aaac
+ 0: aaac
+
+/(?<![cd])b/
+ *** Failers
+No match
+ B\nB
+No match
+ dbcb
+No match
+
+/(?<![cd])[ab]/
+ dbaacb
+ 0: a
+
+/(?<!(c|d))b/
+
+/(?<!(c|d))[ab]/
+ dbaacb
+ 0: a
+
+/(?<!cd)[ab]/
+ cdaccb
+ 0: b
+
+/^(?:a?b?)*$/
+ \
+ 0:
+ a
+ 0: a
+ ab
+ 0: ab
+ aaa
+ 0: aaa
+ *** Failers
+No match
+ dbcb
+No match
+ a--
+No match
+ aa--
+No match
+
+/((?s)^a(.))((?m)^b$)/
+ a\nb\nc\n
+ 0: a\x0ab
+ 1: a\x0a
+ 2: \x0a
+ 3: b
+
+/((?m)^b$)/
+ a\nb\nc\n
+ 0: b
+ 1: b
+
+/(?m)^b/
+ a\nb\n
+ 0: b
+
+/(?m)^(b)/
+ a\nb\n
+ 0: b
+ 1: b
+
+/((?m)^b)/
+ a\nb\n
+ 0: b
+ 1: b
+
+/\n((?m)^b)/
+ a\nb\n
+ 0: \x0ab
+ 1: b
+
+/((?s).)c(?!.)/
+ a\nb\nc\n
+ 0: \x0ac
+ 1: \x0a
+ a\nb\nc\n
+ 0: \x0ac
+ 1: \x0a
+
+/((?s)b.)c(?!.)/
+ a\nb\nc\n
+ 0: b\x0ac
+ 1: b\x0a
+ a\nb\nc\n
+ 0: b\x0ac
+ 1: b\x0a
+
+/^b/
+
+/()^b/
+ *** Failers
+No match
+ a\nb\nc\n
+No match
+ a\nb\nc\n
+No match
+
+/((?m)^b)/
+ a\nb\nc\n
+ 0: b
+ 1: b
+
+/(x)?(?(1)a|b)/
+ *** Failers
+No match
+ a
+No match
+ a
+No match
+
+/(x)?(?(1)b|a)/
+ a
+ 0: a
+
+/()?(?(1)b|a)/
+ a
+ 0: a
+
+/()(?(1)b|a)/
+
+/()?(?(1)a|b)/
+ a
+ 0: a
+ 1:
+
+/^(\()?blah(?(1)(\)))$/
+ (blah)
+ 0: (blah)
+ 1: (
+ 2: )
+ blah
+ 0: blah
+ *** Failers
+No match
+ a
+No match
+ blah)
+No match
+ (blah
+No match
+
+/^(\(+)?blah(?(1)(\)))$/
+ (blah)
+ 0: (blah)
+ 1: (
+ 2: )
+ blah
+ 0: blah
+ *** Failers
+No match
+ blah)
+No match
+ (blah
+No match
+
+/(?(?!a)a|b)/
+
+/(?(?!a)b|a)/
+ a
+ 0: a
+
+/(?(?=a)b|a)/
+ *** Failers
+No match
+ a
+No match
+ a
+No match
+
+/(?(?=a)a|b)/
+ a
+ 0: a
+
+/(?=(a+?))(\1ab)/
+ aaab
+ 0: aab
+ 1: a
+ 2: aab
+
+/^(?=(a+?))\1ab/
+
+/(\w+:)+/
+ one:
+ 0: one:
+ 1: one:
+
+/$(?<=^(a))/
+ a
+ 0:
+ 1: a
+
+/(?=(a+?))(\1ab)/
+ aaab
+ 0: aab
+ 1: a
+ 2: aab
+
+/^(?=(a+?))\1ab/
+ *** Failers
+No match
+ aaab
+No match
+ aaab
+No match
+
+/([\w:]+::)?(\w+)$/
+ abcd
+ 0: abcd
+ 1: <unset>
+ 2: abcd
+ xy:z:::abcd
+ 0: xy:z:::abcd
+ 1: xy:z:::
+ 2: abcd
+
+/^[^bcd]*(c+)/
+ aexycd
+ 0: aexyc
+ 1: c
+
+/(a*)b+/
+ caab
+ 0: aab
+ 1: aa
+
+/([\w:]+::)?(\w+)$/
+ abcd
+ 0: abcd
+ 1: <unset>
+ 2: abcd
+ xy:z:::abcd
+ 0: xy:z:::abcd
+ 1: xy:z:::
+ 2: abcd
+ *** Failers
+ 0: Failers
+ 1: <unset>
+ 2: Failers
+ abcd:
+No match
+ abcd:
+No match
+
+/^[^bcd]*(c+)/
+ aexycd
+ 0: aexyc
+ 1: c
+
+/(>a+)ab/
+
+/(?>a+)b/
+ aaab
+ 0: aaab
+
+/([[:]+)/
+ a:[b]:
+ 0: :[
+ 1: :[
+
+/([[=]+)/
+ a=[b]=
+ 0: =[
+ 1: =[
+
+/([[.]+)/
+ a.[b].
+ 0: .[
+ 1: .[
+
+/((?>a+)b)/
+ aaab
+ 0: aaab
+ 1: aaab
+
+/(?>(a+))b/
+ aaab
+ 0: aaab
+ 1: aaa
+
+/((?>[^()]+)|\([^()]*\))+/
+ ((abc(ade)ufh()()x
+ 0: abc(ade)ufh()()x
+ 1: x
+
+/a\Z/
+ *** Failers
+No match
+ aaab
+No match
+ a\nb\n
+No match
+
+/b\Z/
+ a\nb\n
+ 0: b
+
+/b\z/
+
+/b\Z/
+ a\nb
+ 0: b
+
+/b\z/
+ a\nb
+ 0: b
+ *** Failers
+No match
+
+/^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$/
+ a
+ 0: a
+ 1:
+ abc
+ 0: abc
+ 1:
+ a-b
+ 0: a-b
+ 1:
+ 0-9
+ 0: 0-9
+ 1:
+ a.b
+ 0: a.b
+ 1:
+ 5.6.7
+ 0: 5.6.7
+ 1:
+ the.quick.brown.fox
+ 0: the.quick.brown.fox
+ 1:
+ a100.b200.300c
+ 0: a100.b200.300c
+ 1:
+ 12-ab.1245
+ 0: 12-ab.1245
+ 1:
+ *** Failers
+No match
+ \
+No match
+ .a
+No match
+ -a
+No match
+ a-
+No match
+ a.
+No match
+ a_b
+No match
+ a.-
+No match
+ a..
+No match
+ ab..bc
+No match
+ the.quick.brown.fox-
+No match
+ the.quick.brown.fox.
+No match
+ the.quick.brown.fox_
+No match
+ the.quick.brown.fox+
+No match
+
+/(?>.*)(?<=(abcd|wxyz))/
+ alphabetabcd
+ 0: alphabetabcd
+ 1: abcd
+ endingwxyz
+ 0: endingwxyz
+ 1: wxyz
+ *** Failers
+No match
+ a rather long string that doesn't end with one of them
+No match
+
+/word (?>(?:(?!otherword)[a-zA-Z0-9]+ ){0,30})otherword/
+ word cat dog elephant mussel cow horse canary baboon snake shark otherword
+ 0: word cat dog elephant mussel cow horse canary baboon snake shark otherword
+ word cat dog elephant mussel cow horse canary baboon snake shark
+No match
+
+/word (?>[a-zA-Z0-9]+ ){0,30}otherword/
+ word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope
+No match
+
+/(?<=\d{3}(?!999))foo/
+ 999foo
+ 0: foo
+ 123999foo
+ 0: foo
+ *** Failers
+No match
+ 123abcfoo
+No match
+
+/(?<=(?!...999)\d{3})foo/
+ 999foo
+ 0: foo
+ 123999foo
+ 0: foo
+ *** Failers
+No match
+ 123abcfoo
+No match
+
+/(?<=\d{3}(?!999)...)foo/
+ 123abcfoo
+ 0: foo
+ 123456foo
+ 0: foo
+ *** Failers
+No match
+ 123999foo
+No match
+
+/(?<=\d{3}...)(?<!999)foo/
+ 123abcfoo
+ 0: foo
+ 123456foo
+ 0: foo
+ *** Failers
+No match
+ 123999foo
+No match
+
+/<a[\s]+href[\s]*=[\s]* # find <a href=
+ ([\"\'])? # find single or double quote
+ (?(1) (.*?)\1 | ([^\s]+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space
+/isx
+ <a href=abcd xyz
+ 0: <a href=abcd
+ 1: <unset>
+ 2: <unset>
+ 3: abcd
+ <a href=\"abcd xyz pqr\" cats
+ 0: <a href="abcd xyz pqr"
+ 1: "
+ 2: abcd xyz pqr
+ <a href=\'abcd xyz pqr\' cats
+ 0: <a href='abcd xyz pqr'
+ 1: '
+ 2: abcd xyz pqr
+
+/<a\s+href\s*=\s* # find <a href=
+ (["'])? # find single or double quote
+ (?(1) (.*?)\1 | (\S+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space
+/isx
+ <a href=abcd xyz
+ 0: <a href=abcd
+ 1: <unset>
+ 2: <unset>
+ 3: abcd
+ <a href=\"abcd xyz pqr\" cats
+ 0: <a href="abcd xyz pqr"
+ 1: "
+ 2: abcd xyz pqr
+ <a href = \'abcd xyz pqr\' cats
+ 0: <a href = 'abcd xyz pqr'
+ 1: '
+ 2: abcd xyz pqr
+
+/<a\s+href(?>\s*)=(?>\s*) # find <a href=
+ (["'])? # find single or double quote
+ (?(1) (.*?)\1 | (\S+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space
+/isx
+ <a href=abcd xyz
+ 0: <a href=abcd
+ 1: <unset>
+ 2: <unset>
+ 3: abcd
+ <a href=\"abcd xyz pqr\" cats
+ 0: <a href="abcd xyz pqr"
+ 1: "
+ 2: abcd xyz pqr
+ <a href = \'abcd xyz pqr\' cats
+ 0: <a href = 'abcd xyz pqr'
+ 1: '
+ 2: abcd xyz pqr
+
+/((Z)+|A)*/
+ ZABCDEFG
+ 0: ZA
+ 1: A
+ 2: Z
+
+/(Z()|A)*/
+ ZABCDEFG
+ 0: ZA
+ 1: A
+ 2:
+
+/(Z(())|A)*/
+ ZABCDEFG
+ 0: ZA
+ 1: A
+ 2:
+ 3:
+
+/((?>Z)+|A)*/
+ ZABCDEFG
+ 0: ZA
+ 1: A
+
+/((?>)+|A)*/
+ ZABCDEFG
+ 0:
+ 1:
+
+/a*/g
+ abbab
+ 0: a
+ 0:
+ 0:
+ 0: a
+ 0:
+ 0:
+
+/^[a-\d]/
+ abcde
+ 0: a
+ -things
+ 0: -
+ 0digit
+ 0: 0
+ *** Failers
+No match
+ bcdef
+No match
+
+/^[\d-a]/
+ abcde
+ 0: a
+ -things
+ 0: -
+ 0digit
+ 0: 0
+ *** Failers
+No match
+ bcdef
+No match
+
+/[[:space:]]+/
+ > \x09\x0a\x0c\x0d\x0b<
+ 0: \x09\x0a\x0c\x0d\x0b
+
+/[[:blank:]]+/
+ > \x09\x0a\x0c\x0d\x0b<
+ 0: \x09
+
+/[\s]+/
+ > \x09\x0a\x0c\x0d\x0b<
+ 0: \x09\x0a\x0c\x0d
+
+/\s+/
+ > \x09\x0a\x0c\x0d\x0b<
+ 0: \x09\x0a\x0c\x0d
+
+/a b/x
+ ab
+No match
+
+/(?!\A)x/m
+ a\nxb\n
+ 0: x
+
+/(?!^)x/m
+ a\nxb\n
+No match
+
+/abc\Qabc\Eabc/
+ abcabcabc
+ 0: abcabcabc
+
+/abc\Q(*+|\Eabc/
+ abc(*+|abc
+ 0: abc(*+|abc
+
+/ abc\Q abc\Eabc/x
+ abc abcabc
+ 0: abc abcabc
+ *** Failers
+No match
+ abcabcabc
+No match
+
+/abc#comment
+ \Q#not comment
+ literal\E/x
+ abc#not comment\n literal
+ 0: abc#not comment\x0a literal
+
+/abc#comment
+ \Q#not comment
+ literal/x
+ abc#not comment\n literal
+ 0: abc#not comment\x0a literal
+
+/abc#comment
+ \Q#not comment
+ literal\E #more comment
+ /x
+ abc#not comment\n literal
+ 0: abc#not comment\x0a literal
+
+/abc#comment
+ \Q#not comment
+ literal\E #more comment/x
+ abc#not comment\n literal
+ 0: abc#not comment\x0a literal
+
+/\Qabc\$xyz\E/
+ abc\\\$xyz
+ 0: abc\$xyz
+
+/\Qabc\E\$\Qxyz\E/
+ abc\$xyz
+ 0: abc$xyz
+
+/\Gabc/
+ abc
+ 0: abc
+ *** Failers
+No match
+ xyzabc
+No match
+
+/\Gabc./g
+ abc1abc2xyzabc3
+ 0: abc1
+ 0: abc2
+
+/abc./g
+ abc1abc2xyzabc3
+ 0: abc1
+ 0: abc2
+ 0: abc3
+
+/a(?x: b c )d/
+ XabcdY
+ 0: abcd
+ *** Failers
+No match
+ Xa b c d Y
+No match
+
+/((?x)x y z | a b c)/
+ XabcY
+ 0: abc
+ 1: abc
+ AxyzB
+ 0: xyz
+ 1: xyz
+
+/(?i)AB(?-i)C/
+ XabCY
+ 0: abC
+ *** Failers
+No match
+ XabcY
+No match
+
+/((?i)AB(?-i)C|D)E/
+ abCE
+ 0: abCE
+ 1: abC
+ DE
+ 0: DE
+ 1: D
+ *** Failers
+No match
+ abcE
+No match
+ abCe
+No match
+ dE
+No match
+ De
+No match
+
+/(.*)\d+\1/
+ abc123abc
+ 0: abc123abc
+ 1: abc
+ abc123bc
+ 0: bc123bc
+ 1: bc
+
+/(.*)\d+\1/s
+ abc123abc
+ 0: abc123abc
+ 1: abc
+ abc123bc
+ 0: bc123bc
+ 1: bc
+
+/((.*))\d+\1/
+ abc123abc
+ 0: abc123abc
+ 1: abc
+ 2: abc
+ abc123bc
+ 0: bc123bc
+ 1: bc
+ 2: bc
+
+/-- This tests for an IPv6 address in the form where it can have up to --/
+/-- eight components, one and only one of which is empty. This must be --/
+No match
+/-- an internal component. --/
+No match
+
+/^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ /xi
+ a123::a123
+ 0: a123::a123
+ 1:
+ a123:b342::abcd
+ 0: a123:b342::abcd
+ 1:
+ a123:b342::324e:abcd
+ 0: a123:b342::324e:abcd
+ 1:
+ a123:ddde:b342::324e:abcd
+ 0: a123:ddde:b342::324e:abcd
+ 1:
+ a123:ddde:b342::324e:dcba:abcd
+ 0: a123:ddde:b342::324e:dcba:abcd
+ 1:
+ a123:ddde:9999:b342::324e:dcba:abcd
+ 0: a123:ddde:9999:b342::324e:dcba:abcd
+ 1:
+ *** Failers
+No match
+ 1:2:3:4:5:6:7:8
+No match
+ a123:bce:ddde:9999:b342::324e:dcba:abcd
+No match
+ a123::9999:b342::324e:dcba:abcd
+No match
+ abcde:2:3:4:5:6:7:8
+No match
+ ::1
+No match
+ abcd:fee0:123::
+No match
+ :1
+No match
+ 1:
+No match
+
+/[z\Qa-d]\E]/
+ z
+ 0: z
+ a
+ 0: a
+ -
+ 0: -
+ d
+ 0: d
+ ]
+ 0: ]
+ *** Failers
+ 0: a
+ b
+No match
+
+/[\z\C]/
+ z
+ 0: z
+ C
+ 0: C
+
+/\M/
+ M
+ 0: M
+
+/(a+)*b/
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+No match
+
+/(?i)reg(?:ul(?:[a�]|ae)r|ex)/
+ REGular
+ 0: REGular
+ regulaer
+ 0: regulaer
+ Regex
+ 0: Regex
+ regul�r
+ 0: regul\xe4r
+
+/����[�-��-�]+/
+ �����
+ 0: \xc5\xe6\xe5\xe4\xe0
+ �����
+ 0: \xc5\xe6\xe5\xe4\xff
+ �����
+ 0: \xc5\xe6\xe5\xe4\xc0
+ �����
+ 0: \xc5\xe6\xe5\xe4\xdf
+
+/(?<=Z)X./
+ \x84XAZXB
+ 0: XB
+
+/ab cd (?x) de fg/
+ ab cd defg
+ 0: ab cd defg
+
+/ab cd(?x) de fg/
+ ab cddefg
+ 0: ab cddefg
+ ** Failers
+No match
+ abcddefg
+No match
+
+/(?<![^f]oo)(bar)/
+ foobarX
+ 0: bar
+ 1: bar
+ ** Failers
+No match
+ boobarX
+No match
+
+/(?<![^f])X/
+ offX
+ 0: X
+ ** Failers
+No match
+ onyX
+No match
+
+/(?<=[^f])X/
+ onyX
+ 0: X
+ ** Failers
+No match
+ offX
+No match
+
+/^/mg
+ a\nb\nc\n
+ 0:
+ 0:
+ 0:
+ \
+ 0:
+
+/(?<=C\n)^/mg
+ A\nC\nC\n
+ 0:
+
+/(?:(?(1)a|b)(X))+/
+ bXaX
+ 0: bXaX
+ 1: X
+
+/(?:(?(1)\1a|b)(X|Y))+/
+ bXXaYYaY
+ 0: bXXaYYaY
+ 1: Y
+ bXYaXXaX
+ 0: bX
+ 1: X
+
+/()()()()()()()()()(?:(?(10)\10a|b)(X|Y))+/
+ bXXaYYaY
+ 0: bX
+ 1:
+ 2:
+ 3:
+ 4:
+ 5:
+ 6:
+ 7:
+ 8:
+ 9:
+10: X
+
+/[[,abc,]+]/
+ abc]
+ 0: abc]
+ a,b]
+ 0: a,b]
+ [a,b,c]
+ 0: [a,b,c]
+
+/(?-x: )/x
+ A\x20B
+ 0:
+
+"(?x)(?-x: \s*#\s*)"
+ A # B
+ 0: #
+ ** Failers
+No match
+ #
+No match
+
+"(?x-is)(?:(?-ixs) \s*#\s*) include"
+ A #include
+ 0: #include
+ ** Failers
+No match
+ A#include
+No match
+ A #Include
+No match
+
+/a*b*\w/
+ aaabbbb
+ 0: aaabbbb
+ aaaa
+ 0: aaaa
+ a
+ 0: a
+
+/a*b?\w/
+ aaabbbb
+ 0: aaabb
+ aaaa
+ 0: aaaa
+ a
+ 0: a
+
+/a*b{0,4}\w/
+ aaabbbb
+ 0: aaabbbb
+ aaaa
+ 0: aaaa
+ a
+ 0: a
+
+/a*b{0,}\w/
+ aaabbbb
+ 0: aaabbbb
+ aaaa
+ 0: aaaa
+ a
+ 0: a
+
+/a*\d*\w/
+ 0a
+ 0: 0a
+ a
+ 0: a
+
+/a*b *\w/x
+ a
+ 0: a
+
+/a*b#comment
+ *\w/x
+ a
+ 0: a
+
+/a* b *\w/x
+ a
+ 0: a
+
+/^\w+=.*(\\\n.*)*/
+ abc=xyz\\\npqr
+ 0: abc=xyz\
+
+/(?=(\w+))\1:/
+ abcd:
+ 0: abcd:
+ 1: abcd
+
+/^(?=(\w+))\1:/
+ abcd:
+ 0: abcd:
+ 1: abcd
+
+/^\Eabc/
+ abc
+ 0: abc
+
+/^[\Eabc]/
+ a
+ 0: a
+ ** Failers
+No match
+ E
+No match
+
+/^[a-\Ec]/
+ b
+ 0: b
+ ** Failers
+No match
+ -
+No match
+ E
+No match
+
+/^[a\E\E-\Ec]/
+ b
+ 0: b
+ ** Failers
+No match
+ -
+No match
+ E
+No match
+
+/^[\E\Qa\E-\Qz\E]+/
+ b
+ 0: b
+ ** Failers
+No match
+ -
+No match
+
+/^[a\Q]bc\E]/
+ a
+ 0: a
+ ]
+ 0: ]
+ c
+ 0: c
+
+/^[a-\Q\E]/
+ a
+ 0: a
+ -
+ 0: -
+
+/^(a()*)*/
+ aaaa
+ 0: aaaa
+ 1: a
+ 2:
+
+/^(?:a(?:(?:))*)*/
+ aaaa
+ 0: aaaa
+
+/^(a()+)+/
+ aaaa
+ 0: aaaa
+ 1: a
+ 2:
+
+/^(?:a(?:(?:))+)+/
+ aaaa
+ 0: aaaa
+
+/(a){0,3}(?(1)b|(c|))*D/
+ abbD
+ 0: abbD
+ 1: a
+ ccccD
+ 0: ccccD
+ 1: <unset>
+ 2:
+ D
+ 0: D
+ 1: <unset>
+ 2:
+
+/(a|)*\d/
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+No match
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4
+ 0: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4
+ 1:
+
+/(?>a|)*\d/
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+No match
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4
+ 0: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4
+
+/(?:a|)*\d/
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+No match
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4
+ 0: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4
+
+/\Z/g
+ abc\n
+ 0:
+ 0:
+
+/^(?s)(?>.*)(?<!\n)/
+ abc
+ 0: abc
+ abc\n
+No match
+
+/^(?![^\n]*\n\z)/
+ abc
+ 0:
+ abc\n
+No match
+
+/\z(?<!\n)/
+ abc
+ 0:
+ abc\n
+No match
+
+/(.*(.)?)*/
+ abcd
+ 0: abcd
+ 1:
+
+/( (A | (?(1)0|) )* )/x
+ abcd
+ 0:
+ 1:
+ 2:
+
+/( ( (?(1)0|) )* )/x
+ abcd
+ 0:
+ 1:
+ 2:
+
+/( (?(1)0|)* )/x
+ abcd
+ 0:
+ 1:
+
+/[[:abcd:xyz]]/
+ a]
+ 0: a]
+ :]
+ 0: :]
+
+/[abc[:x\]pqr]/
+ a
+ 0: a
+ [
+ 0: [
+ :
+ 0: :
+ ]
+ 0: ]
+ p
+ 0: p
+
+/ End of testinput1 /
diff --git a/lib/stdlib/test/re_SUITE_data/testoutput10 b/lib/stdlib/test/re_SUITE_data/testoutput10
new file mode 100644
index 0000000000..dbd59241ad
--- /dev/null
+++ b/lib/stdlib/test/re_SUITE_data/testoutput10
@@ -0,0 +1,669 @@
+/-- These are a few representative patterns whose lengths and offsets are to be
+shown when the link size is 2. This is just a doublecheck test to ensure the
+sizes don't go horribly wrong when something is changed. The pattern contents
+are all themselves checked in other tests. --/
+
+/((?i)b)/BM
+Memory allocation (code space): 21
+------------------------------------------------------------------
+ 0 17 Bra
+ 3 9 CBra 1
+ 8 01 Opt
+ 10 NC b
+ 12 9 Ket
+ 15 00 Opt
+ 17 17 Ket
+ 20 End
+------------------------------------------------------------------
+
+/(?s)(.*X|^B)/BM
+Memory allocation (code space): 25
+------------------------------------------------------------------
+ 0 21 Bra
+ 3 9 CBra 1
+ 8 Any*
+ 10 X
+ 12 6 Alt
+ 15 ^
+ 16 B
+ 18 15 Ket
+ 21 21 Ket
+ 24 End
+------------------------------------------------------------------
+
+/(?s:.*X|^B)/BM
+Memory allocation (code space): 29
+------------------------------------------------------------------
+ 0 25 Bra
+ 3 9 Bra
+ 6 04 Opt
+ 8 Any*
+ 10 X
+ 12 8 Alt
+ 15 04 Opt
+ 17 ^
+ 18 B
+ 20 17 Ket
+ 23 00 Opt
+ 25 25 Ket
+ 28 End
+------------------------------------------------------------------
+
+/^[[:alnum:]]/BM
+Memory allocation (code space): 41
+------------------------------------------------------------------
+ 0 37 Bra
+ 3 ^
+ 4 [0-9A-Za-z]
+ 37 37 Ket
+ 40 End
+------------------------------------------------------------------
+
+/#/IxMD
+Memory allocation (code space): 7
+------------------------------------------------------------------
+ 0 3 Bra
+ 3 3 Ket
+ 6 End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: extended
+No first char
+No need char
+
+/a#/IxMD
+Memory allocation (code space): 9
+------------------------------------------------------------------
+ 0 5 Bra
+ 3 a
+ 5 5 Ket
+ 8 End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: extended
+First char = 'a'
+No need char
+
+/x?+/BM
+Memory allocation (code space): 9
+------------------------------------------------------------------
+ 0 5 Bra
+ 3 x?+
+ 5 5 Ket
+ 8 End
+------------------------------------------------------------------
+
+/x++/BM
+Memory allocation (code space): 9
+------------------------------------------------------------------
+ 0 5 Bra
+ 3 x++
+ 5 5 Ket
+ 8 End
+------------------------------------------------------------------
+
+/x{1,3}+/BM
+Memory allocation (code space): 19
+------------------------------------------------------------------
+ 0 15 Bra
+ 3 9 Once
+ 6 x
+ 8 x{0,2}
+ 12 9 Ket
+ 15 15 Ket
+ 18 End
+------------------------------------------------------------------
+
+/(x)*+/BM
+Memory allocation (code space): 24
+------------------------------------------------------------------
+ 0 20 Bra
+ 3 14 Once
+ 6 Brazero
+ 7 7 CBra 1
+ 12 x
+ 14 7 KetRmax
+ 17 14 Ket
+ 20 20 Ket
+ 23 End
+------------------------------------------------------------------
+
+/^((a+)(?U)([ab]+)(?-U)([bc]+)(\w*))/BM
+Memory allocation (code space): 120
+------------------------------------------------------------------
+ 0 116 Bra
+ 3 ^
+ 4 109 CBra 1
+ 9 7 CBra 2
+ 14 a+
+ 16 7 Ket
+ 19 39 CBra 3
+ 24 [ab]+?
+ 58 39 Ket
+ 61 39 CBra 4
+ 66 [bc]+
+100 39 Ket
+103 7 CBra 5
+108 \w*
+110 7 Ket
+113 109 Ket
+116 116 Ket
+119 End
+------------------------------------------------------------------
+
+|8J\$WE\<\.rX\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\<EjmhUZ\?\.akp2dF\>qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b|BM
+Memory allocation (code space): 826
+------------------------------------------------------------------
+ 0 822 Bra
+ 3 8J$WE<.rX+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDD<EjmhUZ?.akp2dF>qmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X
+821 \b
+822 822 Ket
+825 End
+------------------------------------------------------------------
+
+|\$\<\.X\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\<EjmhUZ\?\.akp2dF\>qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b|BM
+Memory allocation (code space): 816
+------------------------------------------------------------------
+ 0 812 Bra
+ 3 $<.X+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDD<EjmhUZ?.akp2dF>qmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X
+811 \b
+812 812 Ket
+815 End
+------------------------------------------------------------------
+
+/(a(?1)b)/BM
+Memory allocation (code space): 28
+------------------------------------------------------------------
+ 0 24 Bra
+ 3 18 CBra 1
+ 8 a
+ 10 6 Once
+ 13 3 Recurse
+ 16 6 Ket
+ 19 b
+ 21 18 Ket
+ 24 24 Ket
+ 27 End
+------------------------------------------------------------------
+
+/(a(?1)+b)/BM
+Memory allocation (code space): 28
+------------------------------------------------------------------
+ 0 24 Bra
+ 3 18 CBra 1
+ 8 a
+ 10 6 Once
+ 13 3 Recurse
+ 16 6 KetRmax
+ 19 b
+ 21 18 Ket
+ 24 24 Ket
+ 27 End
+------------------------------------------------------------------
+
+/a(?P<name1>b|c)d(?P<longername2>e)/BM
+Memory allocation (code space): 42
+------------------------------------------------------------------
+ 0 32 Bra
+ 3 a
+ 5 7 CBra 1
+ 10 b
+ 12 5 Alt
+ 15 c
+ 17 12 Ket
+ 20 d
+ 22 7 CBra 2
+ 27 e
+ 29 7 Ket
+ 32 32 Ket
+ 35 End
+------------------------------------------------------------------
+
+/(?:a(?P<c>c(?P<d>d)))(?P<a>a)/BM
+Memory allocation (code space): 54
+------------------------------------------------------------------
+ 0 41 Bra
+ 3 25 Bra
+ 6 a
+ 8 17 CBra 1
+ 13 c
+ 15 7 CBra 2
+ 20 d
+ 22 7 Ket
+ 25 17 Ket
+ 28 25 Ket
+ 31 7 CBra 3
+ 36 a
+ 38 7 Ket
+ 41 41 Ket
+ 44 End
+------------------------------------------------------------------
+
+/(?P<a>a)...(?P=a)bbb(?P>a)d/BM
+Memory allocation (code space): 43
+------------------------------------------------------------------
+ 0 36 Bra
+ 3 7 CBra 1
+ 8 a
+ 10 7 Ket
+ 13 Any
+ 14 Any
+ 15 Any
+ 16 \1
+ 19 bbb
+ 25 6 Once
+ 28 3 Recurse
+ 31 6 Ket
+ 34 d
+ 36 36 Ket
+ 39 End
+------------------------------------------------------------------
+
+/abc(?C255)de(?C)f/BM
+Memory allocation (code space): 31
+------------------------------------------------------------------
+ 0 27 Bra
+ 3 abc
+ 9 Callout 255 10 1
+ 15 de
+ 19 Callout 0 16 1
+ 25 f
+ 27 27 Ket
+ 30 End
+------------------------------------------------------------------
+
+/abcde/CBM
+Memory allocation (code space): 53
+------------------------------------------------------------------
+ 0 49 Bra
+ 3 Callout 255 0 1
+ 9 a
+ 11 Callout 255 1 1
+ 17 b
+ 19 Callout 255 2 1
+ 25 c
+ 27 Callout 255 3 1
+ 33 d
+ 35 Callout 255 4 1
+ 41 e
+ 43 Callout 255 5 0
+ 49 49 Ket
+ 52 End
+------------------------------------------------------------------
+
+/\x{100}/8BM
+Memory allocation (code space): 10
+------------------------------------------------------------------
+ 0 6 Bra
+ 3 \x{100}
+ 6 6 Ket
+ 9 End
+------------------------------------------------------------------
+
+/\x{1000}/8BM
+Memory allocation (code space): 11
+------------------------------------------------------------------
+ 0 7 Bra
+ 3 \x{1000}
+ 7 7 Ket
+ 10 End
+------------------------------------------------------------------
+
+/\x{10000}/8BM
+Memory allocation (code space): 12
+------------------------------------------------------------------
+ 0 8 Bra
+ 3 \x{10000}
+ 8 8 Ket
+ 11 End
+------------------------------------------------------------------
+
+/\x{100000}/8BM
+Memory allocation (code space): 12
+------------------------------------------------------------------
+ 0 8 Bra
+ 3 \x{100000}
+ 8 8 Ket
+ 11 End
+------------------------------------------------------------------
+
+/\x{1000000}/8BM
+Memory allocation (code space): 13
+------------------------------------------------------------------
+ 0 9 Bra
+ 3 \x{1000000}
+ 9 9 Ket
+ 12 End
+------------------------------------------------------------------
+
+/\x{4000000}/8BM
+Memory allocation (code space): 14
+------------------------------------------------------------------
+ 0 10 Bra
+ 3 \x{4000000}
+ 10 10 Ket
+ 13 End
+------------------------------------------------------------------
+
+/\x{7fffFFFF}/8BM
+Memory allocation (code space): 14
+------------------------------------------------------------------
+ 0 10 Bra
+ 3 \x{7fffffff}
+ 10 10 Ket
+ 13 End
+------------------------------------------------------------------
+
+/[\x{ff}]/8BM
+Memory allocation (code space): 10
+------------------------------------------------------------------
+ 0 6 Bra
+ 3 \x{ff}
+ 6 6 Ket
+ 9 End
+------------------------------------------------------------------
+
+/[\x{100}]/8BM
+Memory allocation (code space): 15
+------------------------------------------------------------------
+ 0 11 Bra
+ 3 [\x{100}]
+ 11 11 Ket
+ 14 End
+------------------------------------------------------------------
+
+/\x80/8BM
+Memory allocation (code space): 10
+------------------------------------------------------------------
+ 0 6 Bra
+ 3 \x{80}
+ 6 6 Ket
+ 9 End
+------------------------------------------------------------------
+
+/\xff/8BM
+Memory allocation (code space): 10
+------------------------------------------------------------------
+ 0 6 Bra
+ 3 \x{ff}
+ 6 6 Ket
+ 9 End
+------------------------------------------------------------------
+
+/\x{0041}\x{2262}\x{0391}\x{002e}/D8M
+Memory allocation (code space): 18
+------------------------------------------------------------------
+ 0 14 Bra
+ 3 A\x{2262}\x{391}.
+ 14 14 Ket
+ 17 End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 'A'
+Need char = '.'
+
+/\x{D55c}\x{ad6d}\x{C5B4}/D8M
+Memory allocation (code space): 19
+------------------------------------------------------------------
+ 0 15 Bra
+ 3 \x{d55c}\x{ad6d}\x{c5b4}
+ 15 15 Ket
+ 18 End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 237
+Need char = 180
+
+/\x{65e5}\x{672c}\x{8a9e}/D8M
+Memory allocation (code space): 19
+------------------------------------------------------------------
+ 0 15 Bra
+ 3 \x{65e5}\x{672c}\x{8a9e}
+ 15 15 Ket
+ 18 End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 230
+Need char = 158
+
+/[\x{100}]/8BM
+Memory allocation (code space): 15
+------------------------------------------------------------------
+ 0 11 Bra
+ 3 [\x{100}]
+ 11 11 Ket
+ 14 End
+------------------------------------------------------------------
+
+/[Z\x{100}]/8BM
+Memory allocation (code space): 47
+------------------------------------------------------------------
+ 0 43 Bra
+ 3 [Z\x{100}]
+ 43 43 Ket
+ 46 End
+------------------------------------------------------------------
+
+/^[\x{100}\E-\Q\E\x{150}]/B8M
+Memory allocation (code space): 18
+------------------------------------------------------------------
+ 0 14 Bra
+ 3 ^
+ 4 [\x{100}-\x{150}]
+ 14 14 Ket
+ 17 End
+------------------------------------------------------------------
+
+/^[\QĀ\E-\QŐ\E]/B8M
+Memory allocation (code space): 18
+------------------------------------------------------------------
+ 0 14 Bra
+ 3 ^
+ 4 [\x{100}-\x{150}]
+ 14 14 Ket
+ 17 End
+------------------------------------------------------------------
+
+/^[\QĀ\E-\QŐ\E/B8M
+Failed: missing terminating ] for character class at offset 15
+
+/[\p{L}]/BM
+Memory allocation (code space): 15
+------------------------------------------------------------------
+ 0 11 Bra
+ 3 [\p{L}]
+ 11 11 Ket
+ 14 End
+------------------------------------------------------------------
+
+/[\p{^L}]/BM
+Memory allocation (code space): 15
+------------------------------------------------------------------
+ 0 11 Bra
+ 3 [\P{L}]
+ 11 11 Ket
+ 14 End
+------------------------------------------------------------------
+
+/[\P{L}]/BM
+Memory allocation (code space): 15
+------------------------------------------------------------------
+ 0 11 Bra
+ 3 [\P{L}]
+ 11 11 Ket
+ 14 End
+------------------------------------------------------------------
+
+/[\P{^L}]/BM
+Memory allocation (code space): 15
+------------------------------------------------------------------
+ 0 11 Bra
+ 3 [\p{L}]
+ 11 11 Ket
+ 14 End
+------------------------------------------------------------------
+
+/[abc\p{L}\x{0660}]/8BM
+Memory allocation (code space): 50
+------------------------------------------------------------------
+ 0 46 Bra
+ 3 [a-c\p{L}\x{660}]
+ 46 46 Ket
+ 49 End
+------------------------------------------------------------------
+
+/[\p{Nd}]/8BM
+Memory allocation (code space): 15
+------------------------------------------------------------------
+ 0 11 Bra
+ 3 [\p{Nd}]
+ 11 11 Ket
+ 14 End
+------------------------------------------------------------------
+
+/[\p{Nd}+-]+/8BM
+Memory allocation (code space): 48
+------------------------------------------------------------------
+ 0 44 Bra
+ 3 [+\-\p{Nd}]+
+ 44 44 Ket
+ 47 End
+------------------------------------------------------------------
+
+/A\x{391}\x{10427}\x{ff3a}\x{1fb0}/8iBM
+Memory allocation (code space): 25
+------------------------------------------------------------------
+ 0 21 Bra
+ 3 NC A\x{391}\x{10427}\x{ff3a}\x{1fb0}
+ 21 21 Ket
+ 24 End
+------------------------------------------------------------------
+
+/A\x{391}\x{10427}\x{ff3a}\x{1fb0}/8BM
+Memory allocation (code space): 25
+------------------------------------------------------------------
+ 0 21 Bra
+ 3 A\x{391}\x{10427}\x{ff3a}\x{1fb0}
+ 21 21 Ket
+ 24 End
+------------------------------------------------------------------
+
+/[\x{105}-\x{109}]/8iBM
+Memory allocation (code space): 17
+------------------------------------------------------------------
+ 0 13 Bra
+ 3 [\x{104}-\x{109}]
+ 13 13 Ket
+ 16 End
+------------------------------------------------------------------
+
+/( ( (?(1)0|) )* )/xBM
+Memory allocation (code space): 38
+------------------------------------------------------------------
+ 0 34 Bra
+ 3 28 CBra 1
+ 8 Brazero
+ 9 19 SCBra 2
+ 14 8 Cond
+ 17 1 Cond ref
+ 20 0
+ 22 3 Alt
+ 25 11 Ket
+ 28 19 KetRmax
+ 31 28 Ket
+ 34 34 Ket
+ 37 End
+------------------------------------------------------------------
+
+/( (?(1)0|)* )/xBM
+Memory allocation (code space): 30
+------------------------------------------------------------------
+ 0 26 Bra
+ 3 20 CBra 1
+ 8 Brazero
+ 9 8 SCond
+ 12 1 Cond ref
+ 15 0
+ 17 3 Alt
+ 20 11 KetRmax
+ 23 20 Ket
+ 26 26 Ket
+ 29 End
+------------------------------------------------------------------
+
+/[a]/BM
+Memory allocation (code space): 9
+------------------------------------------------------------------
+ 0 5 Bra
+ 3 a
+ 5 5 Ket
+ 8 End
+------------------------------------------------------------------
+
+/[a]/8BM
+Memory allocation (code space): 9
+------------------------------------------------------------------
+ 0 5 Bra
+ 3 a
+ 5 5 Ket
+ 8 End
+------------------------------------------------------------------
+
+/[\xaa]/BM
+Memory allocation (code space): 9
+------------------------------------------------------------------
+ 0 5 Bra
+ 3 \xaa
+ 5 5 Ket
+ 8 End
+------------------------------------------------------------------
+
+/[\xaa]/8BM
+Memory allocation (code space): 10
+------------------------------------------------------------------
+ 0 6 Bra
+ 3 \x{aa}
+ 6 6 Ket
+ 9 End
+------------------------------------------------------------------
+
+/[^a]/BM
+Memory allocation (code space): 9
+------------------------------------------------------------------
+ 0 5 Bra
+ 3 [^a]
+ 5 5 Ket
+ 8 End
+------------------------------------------------------------------
+
+/[^a]/8BM
+Memory allocation (code space): 9
+------------------------------------------------------------------
+ 0 5 Bra
+ 3 [^a]
+ 5 5 Ket
+ 8 End
+------------------------------------------------------------------
+
+/[^\xaa]/BM
+Memory allocation (code space): 9
+------------------------------------------------------------------
+ 0 5 Bra
+ 3 [^\xaa]
+ 5 5 Ket
+ 8 End
+------------------------------------------------------------------
+
+/[^\xaa]/8BM
+Memory allocation (code space): 40
+------------------------------------------------------------------
+ 0 36 Bra
+ 3 [\x00-\xa9\xab-\xff] (neg)
+ 36 36 Ket
+ 39 End
+------------------------------------------------------------------
+
+/ End of testinput10 /
diff --git a/lib/stdlib/test/re_SUITE_data/testoutput2 b/lib/stdlib/test/re_SUITE_data/testoutput2
new file mode 100644
index 0000000000..dba227f503
--- /dev/null
+++ b/lib/stdlib/test/re_SUITE_data/testoutput2
@@ -0,0 +1,9388 @@
+/(a)b|/I
+Capturing subpattern count = 1
+No options
+No first char
+No need char
+
+/abc/I
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'c'
+ abc
+ 0: abc
+ defabc
+ 0: abc
+ \Aabc
+ 0: abc
+ *** Failers
+No match
+ \Adefabc
+No match
+ ABC
+No match
+
+/^abc/I
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+ abc
+ 0: abc
+ \Aabc
+ 0: abc
+ *** Failers
+No match
+ defabc
+No match
+ \Adefabc
+No match
+
+/a+bc/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = 'a'
+Need char = 'c'
+
+/a*bc/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+No first char
+Need char = 'c'
+
+/a{3}bc/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = 'a'
+Need char = 'c'
+
+/(abc|a+z)/I
+Capturing subpattern count = 1
+Partial matching not supported
+No options
+First char = 'a'
+No need char
+
+/^abc$/I
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+ abc
+ 0: abc
+ *** Failers
+No match
+ def\nabc
+No match
+
+/ab\idef/X
+Failed: unrecognized character follows \ at offset 3
+
+/(?X)ab\idef/X
+Failed: unrecognized character follows \ at offset 7
+
+/x{5,4}/
+Failed: numbers out of order in {} quantifier at offset 5
+
+/z{65536}/
+Failed: number too big in {} quantifier at offset 7
+
+/[abcd/
+Failed: missing terminating ] for character class at offset 5
+
+/(?X)[\B]/
+Failed: invalid escape sequence in character class at offset 6
+
+/[z-a]/
+Failed: range out of order in character class at offset 3
+
+/^*/
+Failed: nothing to repeat at offset 1
+
+/(abc/
+Failed: missing ) at offset 4
+
+/(?# abc/
+Failed: missing ) after comment at offset 7
+
+/(?z)abc/
+Failed: unrecognized character after (? or (?- at offset 2
+
+/.*b/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char at start or follows newline
+Need char = 'b'
+
+/.*?b/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char at start or follows newline
+Need char = 'b'
+
+/cat|dog|elephant/I
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+ this sentence eventually mentions a cat
+ 0: cat
+ this sentences rambles on and on for a while and then reaches elephant
+ 0: elephant
+
+/cat|dog|elephant/IS
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+Starting byte set: c d e
+ this sentence eventually mentions a cat
+ 0: cat
+ this sentences rambles on and on for a while and then reaches elephant
+ 0: elephant
+
+/cat|dog|elephant/IiS
+Capturing subpattern count = 0
+Options: caseless
+No first char
+No need char
+Starting byte set: C D E c d e
+ this sentence eventually mentions a CAT cat
+ 0: CAT
+ this sentences rambles on and on for a while to elephant ElePhant
+ 0: elephant
+
+/a|[bcd]/IS
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+Starting byte set: a b c d
+
+/(a|[^\dZ])/IS
+Capturing subpattern count = 1
+No options
+No first char
+No need char
+Starting byte set: \x00 \x01 \x02 \x03 \x04 \x05 \x06 \x07 \x08 \x09 \x0a
+ \x0b \x0c \x0d \x0e \x0f \x10 \x11 \x12 \x13 \x14 \x15 \x16 \x17 \x18 \x19
+ \x1a \x1b \x1c \x1d \x1e \x1f \x20 ! " # $ % & ' ( ) * + , - . / : ; < = >
+ ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y [ \ ] ^ _ ` a b c d
+ e f g h i j k l m n o p q r s t u v w x y z { | } ~ \x7f \x80 \x81 \x82 \x83
+ \x84 \x85 \x86 \x87 \x88 \x89 \x8a \x8b \x8c \x8d \x8e \x8f \x90 \x91 \x92
+ \x93 \x94 \x95 \x96 \x97 \x98 \x99 \x9a \x9b \x9c \x9d \x9e \x9f \xa0 \xa1
+ \xa2 \xa3 \xa4 \xa5 \xa6 \xa7 \xa8 \xa9 \xaa \xab \xac \xad \xae \xaf \xb0
+ \xb1 \xb2 \xb3 \xb4 \xb5 \xb6 \xb7 \xb8 \xb9 \xba \xbb \xbc \xbd \xbe \xbf
+ \xc0 \xc1 \xc2 \xc3 \xc4 \xc5 \xc6 \xc7 \xc8 \xc9 \xca \xcb \xcc \xcd \xce
+ \xcf \xd0 \xd1 \xd2 \xd3 \xd4 \xd5 \xd6 \xd7 \xd8 \xd9 \xda \xdb \xdc \xdd
+ \xde \xdf \xe0 \xe1 \xe2 \xe3 \xe4 \xe5 \xe6 \xe7 \xe8 \xe9 \xea \xeb \xec
+ \xed \xee \xef \xf0 \xf1 \xf2 \xf3 \xf4 \xf5 \xf6 \xf7 \xf8 \xf9 \xfa \xfb
+ \xfc \xfd \xfe \xff
+
+/(a|b)*[\s]/IS
+Capturing subpattern count = 1
+No options
+No first char
+No need char
+Starting byte set: \x09 \x0a \x0c \x0d \x20 a b
+
+/(ab\2)/
+Failed: reference to non-existent subpattern at offset 6
+
+/{4,5}abc/
+Failed: nothing to repeat at offset 4
+
+/(a)(b)(c)\2/I
+Capturing subpattern count = 3
+Max back reference = 2
+No options
+First char = 'a'
+Need char = 'c'
+ abcb
+ 0: abcb
+ 1: a
+ 2: b
+ 3: c
+ \O0abcb
+Matched, but too many substrings
+ \O3abcb
+Matched, but too many substrings
+ 0: abcb
+ \O6abcb
+Matched, but too many substrings
+ 0: abcb
+ 1: a
+ \O9abcb
+Matched, but too many substrings
+ 0: abcb
+ 1: a
+ 2: b
+ \O12abcb
+ 0: abcb
+ 1: a
+ 2: b
+ 3: c
+
+/(a)bc|(a)(b)\2/I
+Capturing subpattern count = 3
+Max back reference = 2
+No options
+First char = 'a'
+No need char
+ abc
+ 0: abc
+ 1: a
+ \O0abc
+Matched, but too many substrings
+ \O3abc
+Matched, but too many substrings
+ 0: abc
+ \O6abc
+ 0: abc
+ 1: a
+ aba
+ 0: aba
+ 1: <unset>
+ 2: a
+ 3: b
+ \O0aba
+Matched, but too many substrings
+ \O3aba
+Matched, but too many substrings
+ 0: aba
+ \O6aba
+Matched, but too many substrings
+ 0: aba
+ 1: <unset>
+ \O9aba
+Matched, but too many substrings
+ 0: aba
+ 1: <unset>
+ 2: a
+ \O12aba
+ 0: aba
+ 1: <unset>
+ 2: a
+ 3: b
+
+/abc$/IE
+Capturing subpattern count = 0
+Options: dollar_endonly
+First char = 'a'
+Need char = 'c'
+ abc
+ 0: abc
+ *** Failers
+No match
+ abc\n
+No match
+ abc\ndef
+No match
+
+/(a)(b)(c)(d)(e)\6/
+Failed: reference to non-existent subpattern at offset 17
+
+/the quick brown fox/I
+Capturing subpattern count = 0
+No options
+First char = 't'
+Need char = 'x'
+ the quick brown fox
+ 0: the quick brown fox
+ this is a line with the quick brown fox
+ 0: the quick brown fox
+
+/the quick brown fox/IA
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+ the quick brown fox
+ 0: the quick brown fox
+ *** Failers
+No match
+ this is a line with the quick brown fox
+No match
+
+/ab(?z)cd/
+Failed: unrecognized character after (? or (?- at offset 4
+
+/^abc|def/I
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+ abcdef
+ 0: abc
+ abcdef\B
+ 0: def
+
+/.*((abc)$|(def))/I
+Capturing subpattern count = 3
+Partial matching not supported
+No options
+First char at start or follows newline
+No need char
+ defabc
+ 0: defabc
+ 1: abc
+ 2: abc
+ \Zdefabc
+ 0: def
+ 1: def
+ 2: <unset>
+ 3: def
+
+/abc/IP
+ abc
+ 0: abc
+ *** Failers
+No match: POSIX code 17: match failed
+
+/^abc|def/IP
+ abcdef
+ 0: abc
+ abcdef\B
+ 0: def
+
+/.*((abc)$|(def))/IP
+ defabc
+ 0: defabc
+ 1: abc
+ 2: abc
+ \Zdefabc
+ 0: def
+ 1: def
+ 3: def
+
+/the quick brown fox/IP
+ the quick brown fox
+ 0: the quick brown fox
+ *** Failers
+No match: POSIX code 17: match failed
+ The Quick Brown Fox
+No match: POSIX code 17: match failed
+
+/the quick brown fox/IPi
+ the quick brown fox
+ 0: the quick brown fox
+ The Quick Brown Fox
+ 0: The Quick Brown Fox
+
+/abc.def/IP
+ *** Failers
+No match: POSIX code 17: match failed
+ abc\ndef
+No match: POSIX code 17: match failed
+
+/abc$/IP
+ abc
+ 0: abc
+ abc\n
+ 0: abc
+
+/(abc)\2/IP
+Failed: POSIX code 15: bad back reference at offset 7
+
+/(abc\1)/IP
+ abc
+No match: POSIX code 17: match failed
+
+/)/
+Failed: unmatched parentheses at offset 0
+
+/a[]b/
+Failed: missing terminating ] for character class at offset 4
+
+/[^aeiou ]{3,}/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+No first char
+No need char
+ co-processors, and for
+ 0: -pr
+
+/<.*>/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = '<'
+Need char = '>'
+ abc<def>ghi<klm>nop
+ 0: <def>ghi<klm>
+
+/<.*?>/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = '<'
+Need char = '>'
+ abc<def>ghi<klm>nop
+ 0: <def>
+
+/<.*>/IU
+Capturing subpattern count = 0
+Partial matching not supported
+Options: ungreedy
+First char = '<'
+Need char = '>'
+ abc<def>ghi<klm>nop
+ 0: <def>
+
+/(?U)<.*>/I
+Capturing subpattern count = 0
+Partial matching not supported
+Options: ungreedy
+First char = '<'
+Need char = '>'
+ abc<def>ghi<klm>nop
+ 0: <def>
+
+/<.*?>/IU
+Capturing subpattern count = 0
+Partial matching not supported
+Options: ungreedy
+First char = '<'
+Need char = '>'
+ abc<def>ghi<klm>nop
+ 0: <def>ghi<klm>
+
+/={3,}/IU
+Capturing subpattern count = 0
+Partial matching not supported
+Options: ungreedy
+First char = '='
+Need char = '='
+ abc========def
+ 0: ===
+
+/(?U)={3,}?/I
+Capturing subpattern count = 0
+Partial matching not supported
+Options: ungreedy
+First char = '='
+Need char = '='
+ abc========def
+ 0: ========
+
+/(?<!bar|cattle)foo/I
+Capturing subpattern count = 0
+No options
+First char = 'f'
+Need char = 'o'
+ foo
+ 0: foo
+ catfoo
+ 0: foo
+ *** Failers
+No match
+ the barfoo
+No match
+ and cattlefoo
+No match
+
+/(?<=a+)b/
+Failed: lookbehind assertion is not fixed length at offset 6
+
+/(?<=aaa|b{0,3})b/
+Failed: lookbehind assertion is not fixed length at offset 14
+
+/(?<!(foo)a\1)bar/
+Failed: lookbehind assertion is not fixed length at offset 12
+
+/(?i)abc/I
+Capturing subpattern count = 0
+Options: caseless
+First char = 'a' (caseless)
+Need char = 'c' (caseless)
+
+/(a|(?m)a)/I
+Capturing subpattern count = 1
+No options
+First char = 'a'
+No need char
+
+/(?i)^1234/I
+Capturing subpattern count = 0
+Options: anchored caseless
+No first char
+No need char
+
+/(^b|(?i)^d)/I
+Capturing subpattern count = 1
+Options: anchored
+No first char
+No need char
+
+/(?s).*/I
+Capturing subpattern count = 0
+Partial matching not supported
+Options: anchored dotall
+No first char
+No need char
+
+/[abcd]/IS
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+Starting byte set: a b c d
+
+/(?i)[abcd]/IS
+Capturing subpattern count = 0
+Options: caseless
+No first char
+No need char
+Starting byte set: A B C D a b c d
+
+/(?m)[xy]|(b|c)/IS
+Capturing subpattern count = 1
+Options: multiline
+No first char
+No need char
+Starting byte set: b c x y
+
+/(^a|^b)/Im
+Capturing subpattern count = 1
+Options: multiline
+First char at start or follows newline
+No need char
+
+/(?i)(^a|^b)/Im
+Capturing subpattern count = 1
+Options: caseless multiline
+First char at start or follows newline
+No need char
+
+/(a)(?(1)a|b|c)/
+Failed: conditional group contains more than two branches at offset 13
+
+/(?(?=a)a|b|c)/
+Failed: conditional group contains more than two branches at offset 12
+
+/(?(1a)/
+Failed: missing ) at offset 6
+
+/(?(1a))/
+Failed: reference to non-existent subpattern at offset 6
+
+/(?(?i))/
+Failed: assertion expected after (?( at offset 3
+
+/(?(abc))/
+Failed: reference to non-existent subpattern at offset 7
+
+/(?(?<ab))/
+Failed: syntax error in subpattern name (missing terminator) at offset 7
+
+/((?s)blah)\s+\1/I
+Capturing subpattern count = 1
+Max back reference = 1
+Partial matching not supported
+No options
+First char = 'b'
+Need char = 'h'
+
+/((?i)blah)\s+\1/I
+Capturing subpattern count = 1
+Max back reference = 1
+Partial matching not supported
+No options
+First char = 'b' (caseless)
+Need char = 'h' (caseless)
+
+/((?i)b)/IDZS
+------------------------------------------------------------------
+ Bra
+ CBra 1
+ 01 Opt
+ NC b
+ Ket
+ 00 Opt
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+No options
+First char = 'b' (caseless)
+No need char
+Study returned NULL
+
+/(a*b|(?i:c*(?-i)d))/IS
+Capturing subpattern count = 1
+Partial matching not supported
+No options
+No first char
+No need char
+Starting byte set: C a b c d
+
+/a$/I
+Capturing subpattern count = 0
+No options
+First char = 'a'
+No need char
+ a
+ 0: a
+ a\n
+ 0: a
+ *** Failers
+No match
+ \Za
+No match
+ \Za\n
+No match
+
+/a$/Im
+Capturing subpattern count = 0
+Options: multiline
+First char = 'a'
+No need char
+ a
+ 0: a
+ a\n
+ 0: a
+ \Za\n
+ 0: a
+ *** Failers
+No match
+ \Za
+No match
+
+/\Aabc/Im
+Capturing subpattern count = 0
+Options: anchored multiline
+No first char
+No need char
+
+/^abc/Im
+Capturing subpattern count = 0
+Options: multiline
+First char at start or follows newline
+Need char = 'c'
+
+/^((a+)(?U)([ab]+)(?-U)([bc]+)(\w*))/I
+Capturing subpattern count = 5
+Partial matching not supported
+Options: anchored
+No first char
+No need char
+ aaaaabbbbbcccccdef
+ 0: aaaaabbbbbcccccdef
+ 1: aaaaabbbbbcccccdef
+ 2: aaaaa
+ 3: b
+ 4: bbbbccccc
+ 5: def
+
+/(?<=foo)[ab]/IS
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+Starting byte set: a b
+
+/(?<!foo)(alpha|omega)/IS
+Capturing subpattern count = 1
+No options
+No first char
+Need char = 'a'
+Starting byte set: a o
+
+/(?!alphabet)[ab]/IS
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+Starting byte set: a b
+
+/(?<=foo\n)^bar/Im
+Capturing subpattern count = 0
+Contains explicit CR or LF match
+Options: multiline
+No first char
+Need char = 'r'
+ foo\nbarbar
+ 0: bar
+ ***Failers
+No match
+ rhubarb
+No match
+ barbell
+No match
+ abc\nbarton
+No match
+
+/^(?<=foo\n)bar/Im
+Capturing subpattern count = 0
+Contains explicit CR or LF match
+Options: multiline
+First char at start or follows newline
+Need char = 'r'
+ foo\nbarbar
+ 0: bar
+ ***Failers
+No match
+ rhubarb
+No match
+ barbell
+No match
+ abc\nbarton
+No match
+
+/(?>^abc)/Im
+Capturing subpattern count = 0
+Options: multiline
+First char at start or follows newline
+Need char = 'c'
+ abc
+ 0: abc
+ def\nabc
+ 0: abc
+ *** Failers
+No match
+ defabc
+No match
+
+/(?<=ab(c+)d)ef/
+Failed: lookbehind assertion is not fixed length at offset 11
+
+/(?<=ab(?<=c+)d)ef/
+Failed: lookbehind assertion is not fixed length at offset 12
+
+/(?<=ab(c|de)f)g/
+Failed: lookbehind assertion is not fixed length at offset 13
+
+/The next three are in testinput2 because they have variable length branches/
+
+/(?<=bullock|donkey)-cart/I
+Capturing subpattern count = 0
+No options
+First char = '-'
+Need char = 't'
+ the bullock-cart
+ 0: -cart
+ a donkey-cart race
+ 0: -cart
+ *** Failers
+No match
+ cart
+No match
+ horse-and-cart
+No match
+
+/(?<=ab(?i)x|y|z)/I
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+
+/(?>.*)(?<=(abcd)|(xyz))/I
+Capturing subpattern count = 2
+Partial matching not supported
+No options
+First char at start or follows newline
+No need char
+ alphabetabcd
+ 0: alphabetabcd
+ 1: abcd
+ endingxyz
+ 0: endingxyz
+ 1: <unset>
+ 2: xyz
+
+/(?<=ab(?i)x(?-i)y|(?i)z|b)ZZ/I
+Capturing subpattern count = 0
+No options
+First char = 'Z'
+Need char = 'Z'
+ abxyZZ
+ 0: ZZ
+ abXyZZ
+ 0: ZZ
+ ZZZ
+ 0: ZZ
+ zZZ
+ 0: ZZ
+ bZZ
+ 0: ZZ
+ BZZ
+ 0: ZZ
+ *** Failers
+No match
+ ZZ
+No match
+ abXYZZ
+No match
+ zzz
+No match
+ bzz
+No match
+
+/(?<!(foo)a)bar/I
+Capturing subpattern count = 1
+No options
+First char = 'b'
+Need char = 'r'
+ bar
+ 0: bar
+ foobbar
+ 0: bar
+ *** Failers
+No match
+ fooabar
+No match
+
+/This one is here because Perl 5.005_02 doesn't fail it/I
+Capturing subpattern count = 0
+No options
+First char = 'T'
+Need char = 't'
+
+/^(a)?(?(1)a|b)+$/I
+Capturing subpattern count = 1
+Options: anchored
+No first char
+No need char
+ *** Failers
+No match
+ a
+No match
+
+/This one is here because I think Perl 5.005_02 gets the setting of $1 wrong/I
+Capturing subpattern count = 0
+No options
+First char = 'T'
+Need char = 'g'
+
+/^(a\1?){4}$/I
+Capturing subpattern count = 1
+Max back reference = 1
+Options: anchored
+No first char
+No need char
+ aaaaaa
+ 0: aaaaaa
+ 1: aa
+
+/These are syntax tests from Perl 5.005/I
+Capturing subpattern count = 0
+No options
+First char = 'T'
+Need char = '5'
+
+/a[b-a]/
+Failed: range out of order in character class at offset 4
+
+/a[]b/
+Failed: missing terminating ] for character class at offset 4
+
+/a[/
+Failed: missing terminating ] for character class at offset 2
+
+/*a/
+Failed: nothing to repeat at offset 0
+
+/(*)b/
+Failed: nothing to repeat at offset 1
+
+/abc)/
+Failed: unmatched parentheses at offset 3
+
+/(abc/
+Failed: missing ) at offset 4
+
+/a**/
+Failed: nothing to repeat at offset 2
+
+/)(/
+Failed: unmatched parentheses at offset 0
+
+/\1/
+Failed: reference to non-existent subpattern at offset 2
+
+/\2/
+Failed: reference to non-existent subpattern at offset 2
+
+/(a)|\2/
+Failed: reference to non-existent subpattern at offset 6
+
+/a[b-a]/Ii
+Failed: range out of order in character class at offset 4
+
+/a[]b/Ii
+Failed: missing terminating ] for character class at offset 4
+
+/a[/Ii
+Failed: missing terminating ] for character class at offset 2
+
+/*a/Ii
+Failed: nothing to repeat at offset 0
+
+/(*)b/Ii
+Failed: nothing to repeat at offset 1
+
+/abc)/Ii
+Failed: unmatched parentheses at offset 3
+
+/(abc/Ii
+Failed: missing ) at offset 4
+
+/a**/Ii
+Failed: nothing to repeat at offset 2
+
+/)(/Ii
+Failed: unmatched parentheses at offset 0
+
+/:(?:/
+Failed: missing ) at offset 4
+
+/(?<%)b/
+Failed: unrecognized character after (?< at offset 3
+
+/a(?{)b/
+Failed: unrecognized character after (? or (?- at offset 3
+
+/a(?{{})b/
+Failed: unrecognized character after (? or (?- at offset 3
+
+/a(?{}})b/
+Failed: unrecognized character after (? or (?- at offset 3
+
+/a(?{"{"})b/
+Failed: unrecognized character after (? or (?- at offset 3
+
+/a(?{"{"}})b/
+Failed: unrecognized character after (? or (?- at offset 3
+
+/(?(1?)a|b)/
+Failed: malformed number or name after (?( at offset 4
+
+/[a[:xyz:/
+Failed: missing terminating ] for character class at offset 8
+
+/(?<=x+)y/
+Failed: lookbehind assertion is not fixed length at offset 6
+
+/a{37,17}/
+Failed: numbers out of order in {} quantifier at offset 7
+
+/abc/\
+Failed: \ at end of pattern at offset 4
+
+/abc/\P
+Failed: POSIX code 9: bad escape sequence at offset 4
+
+/abc/\i
+Failed: \ at end of pattern at offset 4
+
+/(a)bc(d)/I
+Capturing subpattern count = 2
+No options
+First char = 'a'
+Need char = 'd'
+ abcd
+ 0: abcd
+ 1: a
+ 2: d
+ abcd\C2
+ 0: abcd
+ 1: a
+ 2: d
+ 2C d (1)
+ abcd\C5
+ 0: abcd
+ 1: a
+ 2: d
+copy substring 5 failed -7
+
+/(.{20})/I
+Capturing subpattern count = 1
+Partial matching not supported
+No options
+No first char
+No need char
+ abcdefghijklmnopqrstuvwxyz
+ 0: abcdefghijklmnopqrst
+ 1: abcdefghijklmnopqrst
+ abcdefghijklmnopqrstuvwxyz\C1
+ 0: abcdefghijklmnopqrst
+ 1: abcdefghijklmnopqrst
+ 1C abcdefghijklmnopqrst (20)
+ abcdefghijklmnopqrstuvwxyz\G1
+ 0: abcdefghijklmnopqrst
+ 1: abcdefghijklmnopqrst
+ 1G abcdefghijklmnopqrst (20)
+
+/(.{15})/I
+Capturing subpattern count = 1
+Partial matching not supported
+No options
+No first char
+No need char
+ abcdefghijklmnopqrstuvwxyz
+ 0: abcdefghijklmno
+ 1: abcdefghijklmno
+ abcdefghijklmnopqrstuvwxyz\C1\G1
+ 0: abcdefghijklmno
+ 1: abcdefghijklmno
+ 1C abcdefghijklmno (15)
+ 1G abcdefghijklmno (15)
+
+/(.{16})/I
+Capturing subpattern count = 1
+Partial matching not supported
+No options
+No first char
+No need char
+ abcdefghijklmnopqrstuvwxyz
+ 0: abcdefghijklmnop
+ 1: abcdefghijklmnop
+ abcdefghijklmnopqrstuvwxyz\C1\G1\L
+ 0: abcdefghijklmnop
+ 1: abcdefghijklmnop
+ 1C abcdefghijklmnop (16)
+ 1G abcdefghijklmnop (16)
+ 0L abcdefghijklmnop
+ 1L abcdefghijklmnop
+
+/^(a|(bc))de(f)/I
+Capturing subpattern count = 3
+Options: anchored
+No first char
+No need char
+ adef\G1\G2\G3\G4\L
+ 0: adef
+ 1: a
+ 2: <unset>
+ 3: f
+ 1G a (1)
+ 2G (0)
+ 3G f (1)
+get substring 4 failed -7
+ 0L adef
+ 1L a
+ 2L
+ 3L f
+ bcdef\G1\G2\G3\G4\L
+ 0: bcdef
+ 1: bc
+ 2: bc
+ 3: f
+ 1G bc (2)
+ 2G bc (2)
+ 3G f (1)
+get substring 4 failed -7
+ 0L bcdef
+ 1L bc
+ 2L bc
+ 3L f
+ adefghijk\C0
+ 0: adef
+ 1: a
+ 2: <unset>
+ 3: f
+ 0C adef (4)
+
+/^abc\00def/I
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+ abc\00def\L\C0
+ 0: abc\x00def
+ 0C abc (7)
+ 0L abc
+
+/word ((?:[a-zA-Z0-9]+ )((?:[a-zA-Z0-9]+ )((?:[a-zA-Z0-9]+ )((?:[a-zA-Z0-9]+
+)((?:[a-zA-Z0-9]+ )((?:[a-zA-Z0-9]+ )((?:[a-zA-Z0-9]+ )((?:[a-zA-Z0-9]+
+)?)?)?)?)?)?)?)?)?otherword/I
+Capturing subpattern count = 8
+Partial matching not supported
+Contains explicit CR or LF match
+No options
+First char = 'w'
+Need char = 'd'
+
+/.*X/IDZ
+------------------------------------------------------------------
+ Bra
+ Any*
+ X
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char at start or follows newline
+Need char = 'X'
+
+/.*X/IDZs
+------------------------------------------------------------------
+ Bra
+ Any*
+ X
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: anchored dotall
+No first char
+Need char = 'X'
+
+/(.*X|^B)/IDZ
+------------------------------------------------------------------
+ Bra
+ CBra 1
+ Any*
+ X
+ Alt
+ ^
+ B
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+Partial matching not supported
+No options
+First char at start or follows newline
+No need char
+
+/(.*X|^B)/IDZs
+------------------------------------------------------------------
+ Bra
+ CBra 1
+ Any*
+ X
+ Alt
+ ^
+ B
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+Partial matching not supported
+Options: anchored dotall
+No first char
+No need char
+
+/(?s)(.*X|^B)/IDZ
+------------------------------------------------------------------
+ Bra
+ CBra 1
+ Any*
+ X
+ Alt
+ ^
+ B
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+Partial matching not supported
+Options: anchored dotall
+No first char
+No need char
+
+/(?s:.*X|^B)/IDZ
+------------------------------------------------------------------
+ Bra
+ Bra
+ 04 Opt
+ Any*
+ X
+ Alt
+ 04 Opt
+ ^
+ B
+ Ket
+ 00 Opt
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char at start or follows newline
+No need char
+
+/\Biss\B/I+
+Capturing subpattern count = 0
+No options
+First char = 'i'
+Need char = 's'
+ Mississippi
+ 0: iss
+ 0+ issippi
+
+/\Biss\B/I+P
+ Mississippi
+ 0: iss
+ 0+ issippi
+
+/iss/IG+
+Capturing subpattern count = 0
+No options
+First char = 'i'
+Need char = 's'
+ Mississippi
+ 0: iss
+ 0+ issippi
+ 0: iss
+ 0+ ippi
+
+/\Biss\B/IG+
+Capturing subpattern count = 0
+No options
+First char = 'i'
+Need char = 's'
+ Mississippi
+ 0: iss
+ 0+ issippi
+
+/\Biss\B/Ig+
+Capturing subpattern count = 0
+No options
+First char = 'i'
+Need char = 's'
+ Mississippi
+ 0: iss
+ 0+ issippi
+ 0: iss
+ 0+ ippi
+ *** Failers
+No match
+ Mississippi\A
+No match
+
+/(?<=[Ms])iss/Ig+
+Capturing subpattern count = 0
+No options
+First char = 'i'
+Need char = 's'
+ Mississippi
+ 0: iss
+ 0+ issippi
+ 0: iss
+ 0+ ippi
+
+/(?<=[Ms])iss/IG+
+Capturing subpattern count = 0
+No options
+First char = 'i'
+Need char = 's'
+ Mississippi
+ 0: iss
+ 0+ issippi
+
+/^iss/Ig+
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+ ississippi
+ 0: iss
+ 0+ issippi
+
+/.*iss/Ig+
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char at start or follows newline
+Need char = 's'
+ abciss\nxyzisspqr
+ 0: abciss
+ 0+ \x0axyzisspqr
+ 0: xyziss
+ 0+ pqr
+
+/.i./I+g
+Capturing subpattern count = 0
+No options
+No first char
+Need char = 'i'
+ Mississippi
+ 0: Mis
+ 0+ sissippi
+ 0: sis
+ 0+ sippi
+ 0: sip
+ 0+ pi
+ Mississippi\A
+ 0: Mis
+ 0+ sissippi
+ 0: sis
+ 0+ sippi
+ 0: sip
+ 0+ pi
+ Missouri river
+ 0: Mis
+ 0+ souri river
+ 0: ri
+ 0+ river
+ 0: riv
+ 0+ er
+ Missouri river\A
+ 0: Mis
+ 0+ souri river
+
+/^.is/I+g
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+ Mississippi
+ 0: Mis
+ 0+ sissippi
+
+/^ab\n/Ig+
+Capturing subpattern count = 0
+Contains explicit CR or LF match
+Options: anchored
+No first char
+No need char
+ ab\nab\ncd
+ 0: ab\x0a
+ 0+ ab\x0acd
+
+/^ab\n/Img+
+Capturing subpattern count = 0
+Contains explicit CR or LF match
+Options: multiline
+First char at start or follows newline
+Need char = 10
+ ab\nab\ncd
+ 0: ab\x0a
+ 0+ ab\x0acd
+ 0: ab\x0a
+ 0+ cd
+
+/abc/I
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'c'
+
+/abc|bac/I
+Capturing subpattern count = 0
+No options
+No first char
+Need char = 'c'
+
+/(abc|bac)/I
+Capturing subpattern count = 1
+No options
+No first char
+Need char = 'c'
+
+/(abc|(c|dc))/I
+Capturing subpattern count = 2
+No options
+No first char
+Need char = 'c'
+
+/(abc|(d|de)c)/I
+Capturing subpattern count = 2
+No options
+No first char
+Need char = 'c'
+
+/a*/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+No first char
+No need char
+
+/a+/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = 'a'
+No need char
+
+/(baa|a+)/I
+Capturing subpattern count = 1
+Partial matching not supported
+No options
+No first char
+Need char = 'a'
+
+/a{0,3}/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+No first char
+No need char
+
+/baa{3,}/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = 'b'
+Need char = 'a'
+
+/"([^\\"]+|\\.)*"/I
+Capturing subpattern count = 1
+Partial matching not supported
+No options
+First char = '"'
+Need char = '"'
+
+/(abc|ab[cd])/I
+Capturing subpattern count = 1
+No options
+First char = 'a'
+No need char
+
+/(a|.)/I
+Capturing subpattern count = 1
+No options
+No first char
+No need char
+
+/a|ba|\w/I
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+
+/abc(?=pqr)/I
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'r'
+
+/...(?<=abc)/I
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+
+/abc(?!pqr)/I
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'c'
+
+/ab./I
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'b'
+
+/ab[xyz]/I
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'b'
+
+/abc*/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = 'a'
+Need char = 'b'
+
+/ab.c*/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = 'a'
+Need char = 'b'
+
+/a.c*/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = 'a'
+No need char
+
+/.c*/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+No first char
+No need char
+
+/ac*/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = 'a'
+No need char
+
+/(a.c*|b.c*)/I
+Capturing subpattern count = 1
+Partial matching not supported
+No options
+No first char
+No need char
+
+/a.c*|aba/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = 'a'
+No need char
+
+/.+a/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+No first char
+Need char = 'a'
+
+/(?=abcda)a.*/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = 'a'
+Need char = 'a'
+
+/(?=a)a.*/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = 'a'
+No need char
+
+/a(b)*/I
+Capturing subpattern count = 1
+No options
+First char = 'a'
+No need char
+
+/a\d*/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = 'a'
+No need char
+
+/ab\d*/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = 'a'
+Need char = 'b'
+
+/a(\d)*/I
+Capturing subpattern count = 1
+No options
+First char = 'a'
+No need char
+
+/abcde{0,0}/I
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'd'
+
+/ab\d+/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = 'a'
+Need char = 'b'
+
+/a(?(1)b)(.)/I
+Capturing subpattern count = 1
+No options
+First char = 'a'
+No need char
+
+/a(?(1)bag|big)(.)/I
+Capturing subpattern count = 1
+No options
+First char = 'a'
+Need char = 'g'
+
+/a(?(1)bag|big)*(.)/I
+Capturing subpattern count = 1
+No options
+First char = 'a'
+No need char
+
+/a(?(1)bag|big)+(.)/I
+Capturing subpattern count = 1
+No options
+First char = 'a'
+Need char = 'g'
+
+/a(?(1)b..|b..)(.)/I
+Capturing subpattern count = 1
+No options
+First char = 'a'
+Need char = 'b'
+
+/ab\d{0}e/I
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'e'
+
+/a?b?/I
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+ a
+ 0: a
+ b
+ 0: b
+ ab
+ 0: ab
+ \
+ 0:
+ *** Failers
+ 0:
+ \N
+No match
+
+/|-/I
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+ abcd
+ 0:
+ -abc
+ 0:
+ \Nab-c
+ 0: -
+ *** Failers
+ 0:
+ \Nabc
+No match
+
+/a*(b+)(z)(z)/IP
+ aaaabbbbzzzz
+ 0: aaaabbbbzz
+ 1: bbbb
+ 2: z
+ 3: z
+ aaaabbbbzzzz\O0
+ aaaabbbbzzzz\O1
+ 0: aaaabbbbzz
+ aaaabbbbzzzz\O2
+ 0: aaaabbbbzz
+ 1: bbbb
+ aaaabbbbzzzz\O3
+ 0: aaaabbbbzz
+ 1: bbbb
+ 2: z
+ aaaabbbbzzzz\O4
+ 0: aaaabbbbzz
+ 1: bbbb
+ 2: z
+ 3: z
+ aaaabbbbzzzz\O5
+ 0: aaaabbbbzz
+ 1: bbbb
+ 2: z
+ 3: z
+
+/^.?abcd/IS
+Capturing subpattern count = 0
+Options: anchored
+No first char
+Need char = 'd'
+Study returned NULL
+
+/\( # ( at start
+ (?: # Non-capturing bracket
+ (?>[^()]+) # Either a sequence of non-brackets (no backtracking)
+ | # Or
+ (?R) # Recurse - i.e. nested bracketed string
+ )* # Zero or more contents
+ \) # Closing )
+ /Ix
+Capturing subpattern count = 0
+Partial matching not supported
+Options: extended
+First char = '('
+Need char = ')'
+ (abcd)
+ 0: (abcd)
+ (abcd)xyz
+ 0: (abcd)
+ xyz(abcd)
+ 0: (abcd)
+ (ab(xy)cd)pqr
+ 0: (ab(xy)cd)
+ (ab(xycd)pqr
+ 0: (xycd)
+ () abc ()
+ 0: ()
+ 12(abcde(fsh)xyz(foo(bar))lmno)89
+ 0: (abcde(fsh)xyz(foo(bar))lmno)
+ *** Failers
+No match
+ abcd
+No match
+ abcd)
+No match
+ (abcd
+No match
+
+/\( ( (?>[^()]+) | (?R) )* \) /Ixg
+Capturing subpattern count = 1
+Partial matching not supported
+Options: extended
+First char = '('
+Need char = ')'
+ (ab(xy)cd)pqr
+ 0: (ab(xy)cd)
+ 1: cd
+ 1(abcd)(x(y)z)pqr
+ 0: (abcd)
+ 1: abcd
+ 0: (x(y)z)
+ 1: z
+
+/\( (?: (?>[^()]+) | (?R) ) \) /Ix
+Capturing subpattern count = 0
+Partial matching not supported
+Options: extended
+First char = '('
+Need char = ')'
+ (abcd)
+ 0: (abcd)
+ (ab(xy)cd)
+ 0: (xy)
+ (a(b(c)d)e)
+ 0: (c)
+ ((ab))
+ 0: ((ab))
+ *** Failers
+No match
+ ()
+No match
+
+/\( (?: (?>[^()]+) | (?R) )? \) /Ix
+Capturing subpattern count = 0
+Partial matching not supported
+Options: extended
+First char = '('
+Need char = ')'
+ ()
+ 0: ()
+ 12(abcde(fsh)xyz(foo(bar))lmno)89
+ 0: (fsh)
+
+/\( ( (?>[^()]+) | (?R) )* \) /Ix
+Capturing subpattern count = 1
+Partial matching not supported
+Options: extended
+First char = '('
+Need char = ')'
+ (ab(xy)cd)
+ 0: (ab(xy)cd)
+ 1: cd
+
+/\( ( ( (?>[^()]+) | (?R) )* ) \) /Ix
+Capturing subpattern count = 2
+Partial matching not supported
+Options: extended
+First char = '('
+Need char = ')'
+ (ab(xy)cd)
+ 0: (ab(xy)cd)
+ 1: ab(xy)cd
+ 2: cd
+
+/\( (123)? ( ( (?>[^()]+) | (?R) )* ) \) /Ix
+Capturing subpattern count = 3
+Partial matching not supported
+Options: extended
+First char = '('
+Need char = ')'
+ (ab(xy)cd)
+ 0: (ab(xy)cd)
+ 1: <unset>
+ 2: ab(xy)cd
+ 3: cd
+ (123ab(xy)cd)
+ 0: (123ab(xy)cd)
+ 1: 123
+ 2: ab(xy)cd
+ 3: cd
+
+/\( ( (123)? ( (?>[^()]+) | (?R) )* ) \) /Ix
+Capturing subpattern count = 3
+Partial matching not supported
+Options: extended
+First char = '('
+Need char = ')'
+ (ab(xy)cd)
+ 0: (ab(xy)cd)
+ 1: ab(xy)cd
+ 2: <unset>
+ 3: cd
+ (123ab(xy)cd)
+ 0: (123ab(xy)cd)
+ 1: 123ab(xy)cd
+ 2: 123
+ 3: cd
+
+/\( (((((((((( ( (?>[^()]+) | (?R) )* )))))))))) \) /Ix
+Capturing subpattern count = 11
+Partial matching not supported
+Options: extended
+First char = '('
+Need char = ')'
+ (ab(xy)cd)
+ 0: (ab(xy)cd)
+ 1: ab(xy)cd
+ 2: ab(xy)cd
+ 3: ab(xy)cd
+ 4: ab(xy)cd
+ 5: ab(xy)cd
+ 6: ab(xy)cd
+ 7: ab(xy)cd
+ 8: ab(xy)cd
+ 9: ab(xy)cd
+10: ab(xy)cd
+11: cd
+
+/\( ( ( (?>[^()<>]+) | ((?>[^()]+)) | (?R) )* ) \) /Ix
+Capturing subpattern count = 3
+Partial matching not supported
+Options: extended
+First char = '('
+Need char = ')'
+ (abcd(xyz<p>qrs)123)
+ 0: (abcd(xyz<p>qrs)123)
+ 1: abcd(xyz<p>qrs)123
+ 2: 123
+ 3: <unset>
+
+/\( ( ( (?>[^()]+) | ((?R)) )* ) \) /Ix
+Capturing subpattern count = 3
+Partial matching not supported
+Options: extended
+First char = '('
+Need char = ')'
+ (ab(cd)ef)
+ 0: (ab(cd)ef)
+ 1: ab(cd)ef
+ 2: ef
+ 3: (cd)
+ (ab(cd(ef)gh)ij)
+ 0: (ab(cd(ef)gh)ij)
+ 1: ab(cd(ef)gh)ij
+ 2: ij
+ 3: (cd(ef)gh)
+
+/^[[:alnum:]]/DZ
+------------------------------------------------------------------
+ Bra
+ ^
+ [0-9A-Za-z]
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/^[[:^alnum:]]/DZ
+------------------------------------------------------------------
+ Bra
+ ^
+ [\x00-/:-@[-`{-\xff] (neg)
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/^[[:alpha:]]/DZ
+------------------------------------------------------------------
+ Bra
+ ^
+ [A-Za-z]
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/^[[:^alpha:]]/DZ
+------------------------------------------------------------------
+ Bra
+ ^
+ [\x00-@[-`{-\xff] (neg)
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/[_[:alpha:]]/IS
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+Starting byte set: A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
+ _ a b c d e f g h i j k l m n o p q r s t u v w x y z
+
+/^[[:ascii:]]/DZ
+------------------------------------------------------------------
+ Bra
+ ^
+ [\x00-\x7f]
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/^[[:^ascii:]]/DZ
+------------------------------------------------------------------
+ Bra
+ ^
+ [\x80-\xff] (neg)
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/^[[:blank:]]/DZ
+------------------------------------------------------------------
+ Bra
+ ^
+ [\x09 ]
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/^[[:^blank:]]/DZ
+------------------------------------------------------------------
+ Bra
+ ^
+ [\x00-\x08\x0a-\x1f!-\xff] (neg)
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/[\n\x0b\x0c\x0d[:blank:]]/IS
+Capturing subpattern count = 0
+Contains explicit CR or LF match
+No options
+No first char
+No need char
+Starting byte set: \x09 \x0a \x0b \x0c \x0d \x20
+
+/^[[:cntrl:]]/DZ
+------------------------------------------------------------------
+ Bra
+ ^
+ [\x00-\x1f\x7f]
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/^[[:digit:]]/DZ
+------------------------------------------------------------------
+ Bra
+ ^
+ [0-9]
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/^[[:graph:]]/DZ
+------------------------------------------------------------------
+ Bra
+ ^
+ [!-~]
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/^[[:lower:]]/DZ
+------------------------------------------------------------------
+ Bra
+ ^
+ [a-z]
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/^[[:print:]]/DZ
+------------------------------------------------------------------
+ Bra
+ ^
+ [ -~]
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/^[[:punct:]]/DZ
+------------------------------------------------------------------
+ Bra
+ ^
+ [!-/:-@[-`{-~]
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/^[[:space:]]/DZ
+------------------------------------------------------------------
+ Bra
+ ^
+ [\x09-\x0d ]
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/^[[:upper:]]/DZ
+------------------------------------------------------------------
+ Bra
+ ^
+ [A-Z]
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/^[[:xdigit:]]/DZ
+------------------------------------------------------------------
+ Bra
+ ^
+ [0-9A-Fa-f]
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/^[[:word:]]/DZ
+------------------------------------------------------------------
+ Bra
+ ^
+ [0-9A-Z_a-z]
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/^[[:^cntrl:]]/DZ
+------------------------------------------------------------------
+ Bra
+ ^
+ [ -~\x80-\xff] (neg)
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/^[12[:^digit:]]/DZ
+------------------------------------------------------------------
+ Bra
+ ^
+ [\x00-/12:-\xff] (neg)
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/^[[:^blank:]]/DZ
+------------------------------------------------------------------
+ Bra
+ ^
+ [\x00-\x08\x0a-\x1f!-\xff] (neg)
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/[01[:alpha:]%]/DZ
+------------------------------------------------------------------
+ Bra
+ [%01A-Za-z]
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+
+/[[.ch.]]/I
+Failed: POSIX collating elements are not supported at offset 1
+
+/[[=ch=]]/I
+Failed: POSIX collating elements are not supported at offset 1
+
+/[[:rhubarb:]]/I
+Failed: unknown POSIX class name at offset 3
+
+/[[:upper:]]/Ii
+Capturing subpattern count = 0
+Options: caseless
+No first char
+No need char
+ A
+ 0: A
+ a
+ 0: a
+
+/[[:lower:]]/Ii
+Capturing subpattern count = 0
+Options: caseless
+No first char
+No need char
+ A
+ 0: A
+ a
+ 0: a
+
+/((?-i)[[:lower:]])[[:lower:]]/Ii
+Capturing subpattern count = 1
+Options: caseless
+No first char
+No need char
+ ab
+ 0: ab
+ 1: a
+ aB
+ 0: aB
+ 1: a
+ *** Failers
+ 0: ai
+ 1: a
+ Ab
+No match
+ AB
+No match
+
+/[\200-\110]/I
+Failed: range out of order in character class at offset 9
+
+/^(?(0)f|b)oo/I
+Failed: invalid condition (?(0) at offset 6
+
+/This one's here because of the large output vector needed/I
+Capturing subpattern count = 0
+No options
+First char = 'T'
+Need char = 'd'
+
+/(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\w+)\s+(\270)/I
+Capturing subpattern count = 271
+Max back reference = 270
+Partial matching not supported
+No options
+No first char
+No need char
+ \O900 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 ABC ABC
+ 0: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 ABC ABC
+ 1: 1
+ 2: 2
+ 3: 3
+ 4: 4
+ 5: 5
+ 6: 6
+ 7: 7
+ 8: 8
+ 9: 9
+10: 10
+11: 11
+12: 12
+13: 13
+14: 14
+15: 15
+16: 16
+17: 17
+18: 18
+19: 19
+20: 20
+21: 21
+22: 22
+23: 23
+24: 24
+25: 25
+26: 26
+27: 27
+28: 28
+29: 29
+30: 30
+31: 31
+32: 32
+33: 33
+34: 34
+35: 35
+36: 36
+37: 37
+38: 38
+39: 39
+40: 40
+41: 41
+42: 42
+43: 43
+44: 44
+45: 45
+46: 46
+47: 47
+48: 48
+49: 49
+50: 50
+51: 51
+52: 52
+53: 53
+54: 54
+55: 55
+56: 56
+57: 57
+58: 58
+59: 59
+60: 60
+61: 61
+62: 62
+63: 63
+64: 64
+65: 65
+66: 66
+67: 67
+68: 68
+69: 69
+70: 70
+71: 71
+72: 72
+73: 73
+74: 74
+75: 75
+76: 76
+77: 77
+78: 78
+79: 79
+80: 80
+81: 81
+82: 82
+83: 83
+84: 84
+85: 85
+86: 86
+87: 87
+88: 88
+89: 89
+90: 90
+91: 91
+92: 92
+93: 93
+94: 94
+95: 95
+96: 96
+97: 97
+98: 98
+99: 99
+100: 100
+101: 101
+102: 102
+103: 103
+104: 104
+105: 105
+106: 106
+107: 107
+108: 108
+109: 109
+110: 110
+111: 111
+112: 112
+113: 113
+114: 114
+115: 115
+116: 116
+117: 117
+118: 118
+119: 119
+120: 120
+121: 121
+122: 122
+123: 123
+124: 124
+125: 125
+126: 126
+127: 127
+128: 128
+129: 129
+130: 130
+131: 131
+132: 132
+133: 133
+134: 134
+135: 135
+136: 136
+137: 137
+138: 138
+139: 139
+140: 140
+141: 141
+142: 142
+143: 143
+144: 144
+145: 145
+146: 146
+147: 147
+148: 148
+149: 149
+150: 150
+151: 151
+152: 152
+153: 153
+154: 154
+155: 155
+156: 156
+157: 157
+158: 158
+159: 159
+160: 160
+161: 161
+162: 162
+163: 163
+164: 164
+165: 165
+166: 166
+167: 167
+168: 168
+169: 169
+170: 170
+171: 171
+172: 172
+173: 173
+174: 174
+175: 175
+176: 176
+177: 177
+178: 178
+179: 179
+180: 180
+181: 181
+182: 182
+183: 183
+184: 184
+185: 185
+186: 186
+187: 187
+188: 188
+189: 189
+190: 190
+191: 191
+192: 192
+193: 193
+194: 194
+195: 195
+196: 196
+197: 197
+198: 198
+199: 199
+200: 200
+201: 201
+202: 202
+203: 203
+204: 204
+205: 205
+206: 206
+207: 207
+208: 208
+209: 209
+210: 210
+211: 211
+212: 212
+213: 213
+214: 214
+215: 215
+216: 216
+217: 217
+218: 218
+219: 219
+220: 220
+221: 221
+222: 222
+223: 223
+224: 224
+225: 225
+226: 226
+227: 227
+228: 228
+229: 229
+230: 230
+231: 231
+232: 232
+233: 233
+234: 234
+235: 235
+236: 236
+237: 237
+238: 238
+239: 239
+240: 240
+241: 241
+242: 242
+243: 243
+244: 244
+245: 245
+246: 246
+247: 247
+248: 248
+249: 249
+250: 250
+251: 251
+252: 252
+253: 253
+254: 254
+255: 255
+256: 256
+257: 257
+258: 258
+259: 259
+260: 260
+261: 261
+262: 262
+263: 263
+264: 264
+265: 265
+266: 266
+267: 267
+268: 268
+269: 269
+270: ABC
+271: ABC
+
+/This one's here because Perl does this differently and PCRE can't at present/I
+Capturing subpattern count = 0
+No options
+First char = 'T'
+Need char = 't'
+
+/(main(O)?)+/I
+Capturing subpattern count = 2
+No options
+First char = 'm'
+Need char = 'n'
+ mainmain
+ 0: mainmain
+ 1: main
+ mainOmain
+ 0: mainOmain
+ 1: main
+ 2: O
+
+/These are all cases where Perl does it differently (nested captures)/I
+Capturing subpattern count = 1
+No options
+First char = 'T'
+Need char = 's'
+
+/^(a(b)?)+$/I
+Capturing subpattern count = 2
+Options: anchored
+No first char
+No need char
+ aba
+ 0: aba
+ 1: a
+ 2: b
+
+/^(aa(bb)?)+$/I
+Capturing subpattern count = 2
+Options: anchored
+No first char
+No need char
+ aabbaa
+ 0: aabbaa
+ 1: aa
+ 2: bb
+
+/^(aa|aa(bb))+$/I
+Capturing subpattern count = 2
+Options: anchored
+No first char
+No need char
+ aabbaa
+ 0: aabbaa
+ 1: aa
+ 2: bb
+
+/^(aa(bb)??)+$/I
+Capturing subpattern count = 2
+Options: anchored
+No first char
+No need char
+ aabbaa
+ 0: aabbaa
+ 1: aa
+ 2: bb
+
+/^(?:aa(bb)?)+$/I
+Capturing subpattern count = 1
+Options: anchored
+No first char
+No need char
+ aabbaa
+ 0: aabbaa
+ 1: bb
+
+/^(aa(b(b))?)+$/I
+Capturing subpattern count = 3
+Options: anchored
+No first char
+No need char
+ aabbaa
+ 0: aabbaa
+ 1: aa
+ 2: bb
+ 3: b
+
+/^(?:aa(b(b))?)+$/I
+Capturing subpattern count = 2
+Options: anchored
+No first char
+No need char
+ aabbaa
+ 0: aabbaa
+ 1: bb
+ 2: b
+
+/^(?:aa(b(?:b))?)+$/I
+Capturing subpattern count = 1
+Options: anchored
+No first char
+No need char
+ aabbaa
+ 0: aabbaa
+ 1: bb
+
+/^(?:aa(bb(?:b))?)+$/I
+Capturing subpattern count = 1
+Options: anchored
+No first char
+No need char
+ aabbbaa
+ 0: aabbbaa
+ 1: bbb
+
+/^(?:aa(b(?:bb))?)+$/I
+Capturing subpattern count = 1
+Options: anchored
+No first char
+No need char
+ aabbbaa
+ 0: aabbbaa
+ 1: bbb
+
+/^(?:aa(?:b(b))?)+$/I
+Capturing subpattern count = 1
+Options: anchored
+No first char
+No need char
+ aabbaa
+ 0: aabbaa
+ 1: b
+
+/^(?:aa(?:b(bb))?)+$/I
+Capturing subpattern count = 1
+Options: anchored
+No first char
+No need char
+ aabbbaa
+ 0: aabbbaa
+ 1: bb
+
+/^(aa(b(bb))?)+$/I
+Capturing subpattern count = 3
+Options: anchored
+No first char
+No need char
+ aabbbaa
+ 0: aabbbaa
+ 1: aa
+ 2: bbb
+ 3: bb
+
+/^(aa(bb(bb))?)+$/I
+Capturing subpattern count = 3
+Options: anchored
+No first char
+No need char
+ aabbbbaa
+ 0: aabbbbaa
+ 1: aa
+ 2: bbbb
+ 3: bb
+
+/--------------------------------------------------------------------/I
+Capturing subpattern count = 0
+No options
+First char = '-'
+Need char = '-'
+
+/#/IxDZ
+------------------------------------------------------------------
+ Bra
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: extended
+No first char
+No need char
+
+/a#/IxDZ
+------------------------------------------------------------------
+ Bra
+ a
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: extended
+First char = 'a'
+No need char
+
+/[\s]/DZ
+------------------------------------------------------------------
+ Bra
+ [\x09\x0a\x0c\x0d ]
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+
+/[\S]/DZ
+------------------------------------------------------------------
+ Bra
+ [\x00-\x08\x0b\x0e-\x1f!-\xff] (neg)
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+
+/a(?i)b/DZ
+------------------------------------------------------------------
+ Bra
+ a
+ 01 Opt
+ NC b
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'b' (caseless)
+ ab
+ 0: ab
+ aB
+ 0: aB
+ *** Failers
+No match
+ AB
+No match
+
+/(a(?i)b)/DZ
+------------------------------------------------------------------
+ Bra
+ CBra 1
+ a
+ 01 Opt
+ NC b
+ Ket
+ 00 Opt
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+No options
+First char = 'a'
+Need char = 'b' (caseless)
+ ab
+ 0: ab
+ 1: ab
+ aB
+ 0: aB
+ 1: aB
+ *** Failers
+No match
+ AB
+No match
+
+/ (?i)abc/IxDZ
+------------------------------------------------------------------
+ Bra
+ NC abc
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: caseless extended
+First char = 'a' (caseless)
+Need char = 'c' (caseless)
+
+/#this is a comment
+ (?i)abc/IxDZ
+------------------------------------------------------------------
+ Bra
+ NC abc
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: caseless extended
+First char = 'a' (caseless)
+Need char = 'c' (caseless)
+
+/123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890/DZ
+------------------------------------------------------------------
+ Bra
+ 123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+First char = '1'
+Need char = '0'
+
+/\Q123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890/DZ
+------------------------------------------------------------------
+ Bra
+ 123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+First char = '1'
+Need char = '0'
+
+/\Q\E/DZ
+------------------------------------------------------------------
+ Bra
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+ \
+ 0:
+
+/\Q\Ex/DZ
+------------------------------------------------------------------
+ Bra
+ x
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+First char = 'x'
+No need char
+
+/ \Q\E/DZ
+------------------------------------------------------------------
+ Bra
+
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+First char = ' '
+No need char
+
+/a\Q\E/DZ
+------------------------------------------------------------------
+ Bra
+ a
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+First char = 'a'
+No need char
+ abc
+ 0: a
+ bca
+ 0: a
+ bac
+ 0: a
+
+/a\Q\Eb/DZ
+------------------------------------------------------------------
+ Bra
+ ab
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'b'
+ abc
+ 0: ab
+
+/\Q\Eabc/DZ
+------------------------------------------------------------------
+ Bra
+ abc
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'c'
+
+/x*+\w/DZ
+------------------------------------------------------------------
+ Bra
+ x*+
+ \w
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+No first char
+No need char
+ *** Failers
+ 0: F
+ xxxxx
+No match
+
+/x?+/DZ
+------------------------------------------------------------------
+ Bra
+ x?+
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+
+/x++/DZ
+------------------------------------------------------------------
+ Bra
+ x++
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = 'x'
+No need char
+
+/x{1,3}+/DZ
+------------------------------------------------------------------
+ Bra
+ Once
+ x
+ x{0,2}
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = 'x'
+No need char
+
+/(x)*+/DZ
+------------------------------------------------------------------
+ Bra
+ Once
+ Brazero
+ CBra 1
+ x
+ KetRmax
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+No options
+No first char
+No need char
+
+/^(\w++|\s++)*$/I
+Capturing subpattern count = 1
+Partial matching not supported
+Options: anchored
+No first char
+No need char
+ now is the time for all good men to come to the aid of the party
+ 0: now is the time for all good men to come to the aid of the party
+ 1: party
+ *** Failers
+No match
+ this is not a line with only words and spaces!
+No match
+
+/(\d++)(\w)/I
+Capturing subpattern count = 2
+Partial matching not supported
+No options
+No first char
+No need char
+ 12345a
+ 0: 12345a
+ 1: 12345
+ 2: a
+ *** Failers
+No match
+ 12345+
+No match
+
+/a++b/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = 'a'
+Need char = 'b'
+ aaab
+ 0: aaab
+
+/(a++b)/I
+Capturing subpattern count = 1
+Partial matching not supported
+No options
+First char = 'a'
+Need char = 'b'
+ aaab
+ 0: aaab
+ 1: aaab
+
+/(a++)b/I
+Capturing subpattern count = 1
+Partial matching not supported
+No options
+First char = 'a'
+Need char = 'b'
+ aaab
+ 0: aaab
+ 1: aaa
+
+/([^()]++|\([^()]*\))+/I
+Capturing subpattern count = 1
+Partial matching not supported
+No options
+No first char
+No need char
+ ((abc(ade)ufh()()x
+ 0: abc(ade)ufh()()x
+ 1: x
+
+/\(([^()]++|\([^()]+\))+\)/I
+Capturing subpattern count = 1
+Partial matching not supported
+No options
+First char = '('
+Need char = ')'
+ (abc)
+ 0: (abc)
+ 1: abc
+ (abc(def)xyz)
+ 0: (abc(def)xyz)
+ 1: xyz
+ *** Failers
+No match
+ ((()aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+No match
+
+/(abc){1,3}+/DZ
+------------------------------------------------------------------
+ Bra
+ Once
+ CBra 1
+ abc
+ Ket
+ Brazero
+ Bra
+ CBra 1
+ abc
+ Ket
+ Brazero
+ CBra 1
+ abc
+ Ket
+ Ket
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+No options
+First char = 'a'
+Need char = 'c'
+
+/a+?+/I
+Failed: nothing to repeat at offset 3
+
+/a{2,3}?+b/I
+Failed: nothing to repeat at offset 7
+
+/(?U)a+?+/I
+Failed: nothing to repeat at offset 7
+
+/a{2,3}?+b/IU
+Failed: nothing to repeat at offset 7
+
+/x(?U)a++b/DZ
+------------------------------------------------------------------
+ Bra
+ x
+ a++
+ b
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = 'x'
+Need char = 'b'
+ xaaaab
+ 0: xaaaab
+
+/(?U)xa++b/DZ
+------------------------------------------------------------------
+ Bra
+ x
+ a++
+ b
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: ungreedy
+First char = 'x'
+Need char = 'b'
+ xaaaab
+ 0: xaaaab
+
+/^((a+)(?U)([ab]+)(?-U)([bc]+)(\w*))/DZ
+------------------------------------------------------------------
+ Bra
+ ^
+ CBra 1
+ CBra 2
+ a+
+ Ket
+ CBra 3
+ [ab]+?
+ Ket
+ CBra 4
+ [bc]+
+ Ket
+ CBra 5
+ \w*
+ Ket
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 5
+Partial matching not supported
+Options: anchored
+No first char
+No need char
+
+/^x(?U)a+b/DZ
+------------------------------------------------------------------
+ Bra
+ ^
+ x
+ a++
+ b
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: anchored
+No first char
+Need char = 'b'
+
+/^x(?U)(a+)b/DZ
+------------------------------------------------------------------
+ Bra
+ ^
+ x
+ CBra 1
+ a+?
+ Ket
+ b
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+Partial matching not supported
+Options: anchored
+No first char
+Need char = 'b'
+
+/[.x.]/I
+Failed: POSIX collating elements are not supported at offset 0
+
+/[=x=]/I
+Failed: POSIX collating elements are not supported at offset 0
+
+/[:x:]/I
+Failed: POSIX named classes are supported only within a class at offset 0
+
+/\l/I
+Failed: PCRE does not support \L, \l, \N, \U, or \u at offset 1
+
+/\L/I
+Failed: PCRE does not support \L, \l, \N, \U, or \u at offset 1
+
+/\N{name}/I
+Failed: PCRE does not support \L, \l, \N, \U, or \u at offset 1
+
+/\u/I
+Failed: PCRE does not support \L, \l, \N, \U, or \u at offset 1
+
+/\U/I
+Failed: PCRE does not support \L, \l, \N, \U, or \u at offset 1
+
+/[/I
+Failed: missing terminating ] for character class at offset 1
+
+/[a-/I
+Failed: missing terminating ] for character class at offset 3
+
+/[[:space:]/I
+Failed: missing terminating ] for character class at offset 10
+
+/[\s]/IDZ
+------------------------------------------------------------------
+ Bra
+ [\x09\x0a\x0c\x0d ]
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+
+/[[:space:]]/IDZ
+------------------------------------------------------------------
+ Bra
+ [\x09-\x0d ]
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+
+/[[:space:]abcde]/IDZ
+------------------------------------------------------------------
+ Bra
+ [\x09-\x0d a-e]
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+
+/< (?: (?(R) \d++ | [^<>]*+) | (?R)) * >/Ix
+Capturing subpattern count = 0
+Partial matching not supported
+Options: extended
+First char = '<'
+Need char = '>'
+ <>
+ 0: <>
+ <abcd>
+ 0: <abcd>
+ <abc <123> hij>
+ 0: <abc <123> hij>
+ <abc <def> hij>
+ 0: <def>
+ <abc<>def>
+ 0: <abc<>def>
+ <abc<>
+ 0: <>
+ *** Failers
+No match
+ <abc
+No match
+
+|8J\$WE\<\.rX\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\<EjmhUZ\?\.akp2dF\>qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b|IDZ
+------------------------------------------------------------------
+ Bra
+ 8J$WE<.rX+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDD<EjmhUZ?.akp2dF>qmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X
+ \b
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+First char = '8'
+Need char = 'X'
+
+|\$\<\.X\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\<EjmhUZ\?\.akp2dF\>qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b|IDZ
+------------------------------------------------------------------
+ Bra
+ $<.X+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW@QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDD<EjmhUZ?.akp2dF>qmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X
+ \b
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+First char = '$'
+Need char = 'X'
+
+/(.*)\d+\1/I
+Capturing subpattern count = 1
+Max back reference = 1
+Partial matching not supported
+No options
+No first char
+No need char
+
+/(.*)\d+/I
+Capturing subpattern count = 1
+Partial matching not supported
+No options
+First char at start or follows newline
+No need char
+
+/(.*)\d+\1/Is
+Capturing subpattern count = 1
+Max back reference = 1
+Partial matching not supported
+Options: dotall
+No first char
+No need char
+
+/(.*)\d+/Is
+Capturing subpattern count = 1
+Partial matching not supported
+Options: anchored dotall
+No first char
+No need char
+
+/(.*(xyz))\d+\2/I
+Capturing subpattern count = 2
+Max back reference = 2
+Partial matching not supported
+No options
+First char at start or follows newline
+Need char = 'z'
+
+/((.*))\d+\1/I
+Capturing subpattern count = 2
+Max back reference = 1
+Partial matching not supported
+No options
+No first char
+No need char
+ abc123bc
+ 0: bc123bc
+ 1: bc
+ 2: bc
+
+/a[b]/I
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'b'
+
+/(?=a).*/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = 'a'
+No need char
+
+/(?=abc).xyz/IiI
+Capturing subpattern count = 0
+Options: caseless
+First char = 'a' (caseless)
+Need char = 'z' (caseless)
+
+/(?=abc)(?i).xyz/I
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'z' (caseless)
+
+/(?=a)(?=b)/I
+Capturing subpattern count = 0
+No options
+First char = 'a'
+No need char
+
+/(?=.)a/I
+Capturing subpattern count = 0
+No options
+First char = 'a'
+No need char
+
+/((?=abcda)a)/I
+Capturing subpattern count = 1
+No options
+First char = 'a'
+Need char = 'a'
+
+/((?=abcda)ab)/I
+Capturing subpattern count = 1
+No options
+First char = 'a'
+Need char = 'b'
+
+/()a/I
+Capturing subpattern count = 1
+No options
+No first char
+Need char = 'a'
+
+/(?(1)ab|ac)(.)/I
+Capturing subpattern count = 1
+No options
+First char = 'a'
+No need char
+
+/(?(1)abz|acz)(.)/I
+Capturing subpattern count = 1
+No options
+First char = 'a'
+Need char = 'z'
+
+/(?(1)abz)(.)/I
+Capturing subpattern count = 1
+No options
+No first char
+No need char
+
+/(?(1)abz)(1)23/I
+Capturing subpattern count = 1
+No options
+No first char
+Need char = '3'
+
+/(a)+/I
+Capturing subpattern count = 1
+No options
+First char = 'a'
+No need char
+
+/(a){2,3}/I
+Capturing subpattern count = 1
+No options
+First char = 'a'
+Need char = 'a'
+
+/(a)*/I
+Capturing subpattern count = 1
+No options
+No first char
+No need char
+
+/[a]/I
+Capturing subpattern count = 0
+No options
+First char = 'a'
+No need char
+
+/[ab]/I
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+
+/[ab]/IS
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+Starting byte set: a b
+
+/[^a]/I
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+
+/\d456/I
+Capturing subpattern count = 0
+No options
+No first char
+Need char = '6'
+
+/\d456/IS
+Capturing subpattern count = 0
+No options
+No first char
+Need char = '6'
+Starting byte set: 0 1 2 3 4 5 6 7 8 9
+
+/a^b/I
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'b'
+
+/^a/Im
+Capturing subpattern count = 0
+Options: multiline
+First char at start or follows newline
+Need char = 'a'
+ abcde
+ 0: a
+ xy\nabc
+ 0: a
+ *** Failers
+No match
+ xyabc
+No match
+
+/c|abc/I
+Capturing subpattern count = 0
+No options
+No first char
+Need char = 'c'
+
+/(?i)[ab]/IS
+Capturing subpattern count = 0
+Options: caseless
+No first char
+No need char
+Starting byte set: A B a b
+
+/[ab](?i)cd/IS
+Capturing subpattern count = 0
+No options
+No first char
+Need char = 'd' (caseless)
+Starting byte set: a b
+
+/abc(?C)def/I
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'f'
+ abcdef
+--->abcdef
+ 0 ^ ^ d
+ 0: abcdef
+ 1234abcdef
+--->1234abcdef
+ 0 ^ ^ d
+ 0: abcdef
+ *** Failers
+No match
+ abcxyz
+No match
+ abcxyzf
+--->abcxyzf
+ 0 ^ ^ d
+No match
+
+/abc(?C)de(?C1)f/I
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'f'
+ 123abcdef
+--->123abcdef
+ 0 ^ ^ d
+ 1 ^ ^ f
+ 0: abcdef
+
+/(?C1)\dabc(?C2)def/I
+Capturing subpattern count = 0
+No options
+No first char
+Need char = 'f'
+ 1234abcdef
+--->1234abcdef
+ 1 ^ \d
+ 1 ^ \d
+ 1 ^ \d
+ 1 ^ \d
+ 2 ^ ^ d
+ 0: 4abcdef
+ *** Failers
+No match
+ abcdef
+--->abcdef
+ 1 ^ \d
+ 1 ^ \d
+ 1 ^ \d
+ 1 ^ \d
+ 1 ^ \d
+ 1 ^ \d
+No match
+
+/(?C255)ab/I
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'b'
+
+/(?C256)ab/I
+Failed: number after (?C is > 255 at offset 6
+
+/(?Cab)xx/I
+Failed: closing ) for (?C expected at offset 3
+
+/(?C12vr)x/I
+Failed: closing ) for (?C expected at offset 5
+
+/abc(?C)def/I
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'f'
+ *** Failers
+No match
+ \x83\x0\x61bcdef
+--->\x83\x00abcdef
+ 0 ^ ^ d
+ 0: abcdef
+
+/(abc)(?C)de(?C1)f/I
+Capturing subpattern count = 1
+No options
+First char = 'a'
+Need char = 'f'
+ 123abcdef
+--->123abcdef
+ 0 ^ ^ d
+ 1 ^ ^ f
+ 0: abcdef
+ 1: abc
+ 123abcdef\C+
+Callout 0: last capture = 1
+ 0: <unset>
+ 1: abc
+--->123abcdef
+ ^ ^ d
+Callout 1: last capture = 1
+ 0: <unset>
+ 1: abc
+--->123abcdef
+ ^ ^ f
+ 0: abcdef
+ 1: abc
+ 123abcdef\C-
+ 0: abcdef
+ 1: abc
+ *** Failers
+No match
+ 123abcdef\C!1
+--->123abcdef
+ 0 ^ ^ d
+ 1 ^ ^ f
+No match
+
+/(?C0)(abc(?C1))*/I
+Capturing subpattern count = 1
+No options
+No first char
+No need char
+ abcabcabc
+--->abcabcabc
+ 0 ^ (abc(?C1))*
+ 1 ^ ^ )
+ 1 ^ ^ )
+ 1 ^ ^ )
+ 0: abcabcabc
+ 1: abc
+ abcabc\C!1!3
+--->abcabc
+ 0 ^ (abc(?C1))*
+ 1 ^ ^ )
+ 1 ^ ^ )
+ 0: abcabc
+ 1: abc
+ *** Failers
+--->*** Failers
+ 0 ^ (abc(?C1))*
+ 0:
+ abcabcabc\C!1!3
+--->abcabcabc
+ 0 ^ (abc(?C1))*
+ 1 ^ ^ )
+ 1 ^ ^ )
+ 1 ^ ^ )
+ 0: abcabc
+ 1: abc
+
+/(\d{3}(?C))*/I
+Capturing subpattern count = 1
+Partial matching not supported
+No options
+No first char
+No need char
+ 123\C+
+Callout 0: last capture = -1
+ 0: <unset>
+--->123
+ ^ ^ )
+ 0: 123
+ 1: 123
+ 123456\C+
+Callout 0: last capture = -1
+ 0: <unset>
+--->123456
+ ^ ^ )
+Callout 0: last capture = 1
+ 0: <unset>
+ 1: 123
+--->123456
+ ^ ^ )
+ 0: 123456
+ 1: 456
+ 123456789\C+
+Callout 0: last capture = -1
+ 0: <unset>
+--->123456789
+ ^ ^ )
+Callout 0: last capture = 1
+ 0: <unset>
+ 1: 123
+--->123456789
+ ^ ^ )
+Callout 0: last capture = 1
+ 0: <unset>
+ 1: 456
+--->123456789
+ ^ ^ )
+ 0: 123456789
+ 1: 789
+
+/((xyz)(?C)p|(?C1)xyzabc)/I
+Capturing subpattern count = 2
+No options
+First char = 'x'
+No need char
+ xyzabc\C+
+Callout 0: last capture = 2
+ 0: <unset>
+ 1: <unset>
+ 2: xyz
+--->xyzabc
+ ^ ^ p
+Callout 1: last capture = -1
+ 0: <unset>
+--->xyzabc
+ ^ x
+ 0: xyzabc
+ 1: xyzabc
+
+/(X)((xyz)(?C)p|(?C1)xyzabc)/I
+Capturing subpattern count = 3
+No options
+First char = 'X'
+Need char = 'x'
+ Xxyzabc\C+
+Callout 0: last capture = 3
+ 0: <unset>
+ 1: X
+ 2: <unset>
+ 3: xyz
+--->Xxyzabc
+ ^ ^ p
+Callout 1: last capture = 1
+ 0: <unset>
+ 1: X
+--->Xxyzabc
+ ^^ x
+ 0: Xxyzabc
+ 1: X
+ 2: xyzabc
+
+/(?=(abc))(?C)abcdef/I
+Capturing subpattern count = 1
+No options
+First char = 'a'
+Need char = 'f'
+ abcdef\C+
+Callout 0: last capture = 1
+ 0: <unset>
+ 1: abc
+--->abcdef
+ ^ a
+ 0: abcdef
+ 1: abc
+
+/(?!(abc)(?C1)d)(?C2)abcxyz/I
+Capturing subpattern count = 1
+No options
+First char = 'a'
+Need char = 'z'
+ abcxyz\C+
+Callout 1: last capture = 1
+ 0: <unset>
+ 1: abc
+--->abcxyz
+ ^ ^ d
+Callout 2: last capture = -1
+ 0: <unset>
+--->abcxyz
+ ^ a
+ 0: abcxyz
+
+/(?<=(abc)(?C))xyz/I
+Capturing subpattern count = 1
+No options
+First char = 'x'
+Need char = 'z'
+ abcxyz\C+
+Callout 0: last capture = 1
+ 0: <unset>
+ 1: abc
+--->abcxyz
+ ^ )
+ 0: xyz
+ 1: abc
+
+/a(b+)(c*)(?C1)/I
+Capturing subpattern count = 2
+Partial matching not supported
+No options
+First char = 'a'
+Need char = 'b'
+ abbbbbccc\C*1
+--->abbbbbccc
+ 1 ^ ^
+Callout data = 1
+ 1 ^ ^
+Callout data = 1
+ 1 ^ ^
+Callout data = 1
+ 1 ^ ^
+Callout data = 1
+ 1 ^ ^
+Callout data = 1
+ 1 ^ ^
+Callout data = 1
+ 1 ^ ^
+Callout data = 1
+ 1 ^ ^
+Callout data = 1
+No match
+
+/a(b+?)(c*?)(?C1)/I
+Capturing subpattern count = 2
+Partial matching not supported
+No options
+First char = 'a'
+Need char = 'b'
+ abbbbbccc\C*1
+--->abbbbbccc
+ 1 ^ ^
+Callout data = 1
+ 1 ^ ^
+Callout data = 1
+ 1 ^ ^
+Callout data = 1
+ 1 ^ ^
+Callout data = 1
+ 1 ^ ^
+Callout data = 1
+ 1 ^ ^
+Callout data = 1
+ 1 ^ ^
+Callout data = 1
+ 1 ^ ^
+Callout data = 1
+No match
+
+/(?C)abc/I
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'c'
+
+/(?C)^abc/I
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/(?C)a|b/IS
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+Starting byte set: a b
+
+/(?R)/I
+Failed: recursive call could loop indefinitely at offset 3
+
+/(a|(?R))/I
+Failed: recursive call could loop indefinitely at offset 6
+
+/(ab|(bc|(de|(?R))))/I
+Failed: recursive call could loop indefinitely at offset 15
+
+/x(ab|(bc|(de|(?R))))/I
+Capturing subpattern count = 3
+No options
+First char = 'x'
+No need char
+ xab
+ 0: xab
+ 1: ab
+ xbc
+ 0: xbc
+ 1: bc
+ 2: bc
+ xde
+ 0: xde
+ 1: de
+ 2: de
+ 3: de
+ xxab
+ 0: xxab
+ 1: xab
+ 2: xab
+ 3: xab
+ xxxab
+ 0: xxxab
+ 1: xxab
+ 2: xxab
+ 3: xxab
+ *** Failers
+No match
+ xyab
+No match
+
+/(ab|(bc|(de|(?1))))/I
+Failed: recursive call could loop indefinitely at offset 15
+
+/x(ab|(bc|(de|(?1)x)x)x)/I
+Failed: recursive call could loop indefinitely at offset 16
+
+/^([^()]|\((?1)*\))*$/I
+Capturing subpattern count = 1
+Options: anchored
+No first char
+No need char
+ abc
+ 0: abc
+ 1: c
+ a(b)c
+ 0: a(b)c
+ 1: c
+ a(b(c))d
+ 0: a(b(c))d
+ 1: d
+ *** Failers)
+No match
+ a(b(c)d
+No match
+
+/^>abc>([^()]|\((?1)*\))*<xyz<$/I
+Capturing subpattern count = 1
+Options: anchored
+No first char
+Need char = '<'
+ >abc>123<xyz<
+ 0: >abc>123<xyz<
+ 1: 3
+ >abc>1(2)3<xyz<
+ 0: >abc>1(2)3<xyz<
+ 1: 3
+ >abc>(1(2)3)<xyz<
+ 0: >abc>(1(2)3)<xyz<
+ 1: (1(2)3)
+
+/(a(?1)b)/DZ
+------------------------------------------------------------------
+ Bra
+ CBra 1
+ a
+ Once
+ Recurse
+ Ket
+ b
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+No options
+First char = 'a'
+Need char = 'b'
+
+/(a(?1)+b)/DZ
+------------------------------------------------------------------
+ Bra
+ CBra 1
+ a
+ Once
+ Recurse
+ KetRmax
+ b
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+No options
+First char = 'a'
+Need char = 'b'
+
+/^\W*(?:((.)\W*(?1)\W*\2|)|((.)\W*(?3)\W*\4|\W*.\W*))\W*$/Ii
+Capturing subpattern count = 4
+Max back reference = 4
+Partial matching not supported
+Options: anchored caseless
+No first char
+No need char
+ 1221
+ 0: 1221
+ 1: 1221
+ 2: 1
+ Satan, oscillate my metallic sonatas!
+ 0: Satan, oscillate my metallic sonatas!
+ 1: <unset>
+ 2: <unset>
+ 3: Satan, oscillate my metallic sonatas
+ 4: S
+ A man, a plan, a canal: Panama!
+ 0: A man, a plan, a canal: Panama!
+ 1: <unset>
+ 2: <unset>
+ 3: A man, a plan, a canal: Panama
+ 4: A
+ Able was I ere I saw Elba.
+ 0: Able was I ere I saw Elba.
+ 1: <unset>
+ 2: <unset>
+ 3: Able was I ere I saw Elba
+ 4: A
+ *** Failers
+No match
+ The quick brown fox
+No match
+
+/^(\d+|\((?1)([+*-])(?1)\)|-(?1))$/I
+Capturing subpattern count = 2
+Partial matching not supported
+Options: anchored
+No first char
+No need char
+ 12
+ 0: 12
+ 1: 12
+ (((2+2)*-3)-7)
+ 0: (((2+2)*-3)-7)
+ 1: (((2+2)*-3)-7)
+ 2: -
+ -12
+ 0: -12
+ 1: -12
+ *** Failers
+No match
+ ((2+2)*-3)-7)
+No match
+
+/^(x(y|(?1){2})z)/I
+Capturing subpattern count = 2
+Options: anchored
+No first char
+No need char
+ xyz
+ 0: xyz
+ 1: xyz
+ 2: y
+ xxyzxyzz
+ 0: xxyzxyzz
+ 1: xxyzxyzz
+ 2: xyzxyz
+ *** Failers
+No match
+ xxyzz
+No match
+ xxyzxyzxyzz
+No match
+
+/((< (?: (?(R) \d++ | [^<>]*+) | (?2)) * >))/Ix
+Capturing subpattern count = 2
+Partial matching not supported
+Options: extended
+First char = '<'
+Need char = '>'
+ <>
+ 0: <>
+ 1: <>
+ 2: <>
+ <abcd>
+ 0: <abcd>
+ 1: <abcd>
+ 2: <abcd>
+ <abc <123> hij>
+ 0: <abc <123> hij>
+ 1: <abc <123> hij>
+ 2: <abc <123> hij>
+ <abc <def> hij>
+ 0: <def>
+ 1: <def>
+ 2: <def>
+ <abc<>def>
+ 0: <abc<>def>
+ 1: <abc<>def>
+ 2: <abc<>def>
+ <abc<>
+ 0: <>
+ 1: <>
+ 2: <>
+ *** Failers
+No match
+ <abc
+No match
+
+/(?1)/I
+Failed: reference to non-existent subpattern at offset 3
+
+/((?2)(abc)/I
+Failed: missing ) at offset 10
+
+/^(abc)def(?1)/I
+Capturing subpattern count = 1
+Options: anchored
+No first char
+No need char
+ abcdefabc
+ 0: abcdefabc
+ 1: abc
+
+/^(a|b|c)=(?1)+/I
+Capturing subpattern count = 1
+Options: anchored
+No first char
+No need char
+ a=a
+ 0: a=a
+ 1: a
+ a=b
+ 0: a=b
+ 1: a
+ a=bc
+ 0: a=bc
+ 1: a
+
+/^(a|b|c)=((?1))+/I
+Capturing subpattern count = 2
+Options: anchored
+No first char
+No need char
+ a=a
+ 0: a=a
+ 1: a
+ 2: a
+ a=b
+ 0: a=b
+ 1: a
+ 2: b
+ a=bc
+ 0: a=bc
+ 1: a
+ 2: c
+
+/a(?P<name1>b|c)d(?P<longername2>e)/DZ
+------------------------------------------------------------------
+ Bra
+ a
+ CBra 1
+ b
+ Alt
+ c
+ Ket
+ d
+ CBra 2
+ e
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 2
+Named capturing subpatterns:
+ longername2 2
+ name1 1
+No options
+First char = 'a'
+Need char = 'e'
+ abde
+ 0: abde
+ 1: b
+ 2: e
+ acde
+ 0: acde
+ 1: c
+ 2: e
+
+/(?:a(?P<c>c(?P<d>d)))(?P<a>a)/DZ
+------------------------------------------------------------------
+ Bra
+ Bra
+ a
+ CBra 1
+ c
+ CBra 2
+ d
+ Ket
+ Ket
+ Ket
+ CBra 3
+ a
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 3
+Named capturing subpatterns:
+ a 3
+ c 1
+ d 2
+No options
+First char = 'a'
+Need char = 'a'
+
+/(?P<a>a)...(?P=a)bbb(?P>a)d/DZ
+------------------------------------------------------------------
+ Bra
+ CBra 1
+ a
+ Ket
+ Any
+ Any
+ Any
+ \1
+ bbb
+ Once
+ Recurse
+ Ket
+ d
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+Max back reference = 1
+Named capturing subpatterns:
+ a 1
+No options
+First char = 'a'
+Need char = 'd'
+
+/^\W*(?:(?P<one>(?P<two>.)\W*(?P>one)\W*(?P=two)|)|(?P<three>(?P<four>.)\W*(?P>three)\W*(?P=four)|\W*.\W*))\W*$/Ii
+Capturing subpattern count = 4
+Max back reference = 4
+Named capturing subpatterns:
+ four 4
+ one 1
+ three 3
+ two 2
+Partial matching not supported
+Options: anchored caseless
+No first char
+No need char
+ 1221
+ 0: 1221
+ 1: 1221
+ 2: 1
+ Satan, oscillate my metallic sonatas!
+ 0: Satan, oscillate my metallic sonatas!
+ 1: <unset>
+ 2: <unset>
+ 3: Satan, oscillate my metallic sonatas
+ 4: S
+ A man, a plan, a canal: Panama!
+ 0: A man, a plan, a canal: Panama!
+ 1: <unset>
+ 2: <unset>
+ 3: A man, a plan, a canal: Panama
+ 4: A
+ Able was I ere I saw Elba.
+ 0: Able was I ere I saw Elba.
+ 1: <unset>
+ 2: <unset>
+ 3: Able was I ere I saw Elba
+ 4: A
+ *** Failers
+No match
+ The quick brown fox
+No match
+
+/((?(R)a|b))\1(?1)?/I
+Capturing subpattern count = 1
+Max back reference = 1
+No options
+No first char
+No need char
+ bb
+ 0: bb
+ 1: b
+ bbaa
+ 0: bba
+ 1: b
+
+/(.*)a/Is
+Capturing subpattern count = 1
+Partial matching not supported
+Options: anchored dotall
+No first char
+Need char = 'a'
+
+/(.*)a\1/Is
+Capturing subpattern count = 1
+Max back reference = 1
+Partial matching not supported
+Options: dotall
+No first char
+Need char = 'a'
+
+/(.*)a(b)\2/Is
+Capturing subpattern count = 2
+Max back reference = 2
+Partial matching not supported
+Options: anchored dotall
+No first char
+Need char = 'b'
+
+/((.*)a|(.*)b)z/Is
+Capturing subpattern count = 3
+Partial matching not supported
+Options: anchored dotall
+No first char
+Need char = 'z'
+
+/((.*)a|(.*)b)z\1/Is
+Capturing subpattern count = 3
+Max back reference = 1
+Partial matching not supported
+Options: dotall
+No first char
+Need char = 'z'
+
+/((.*)a|(.*)b)z\2/Is
+Capturing subpattern count = 3
+Max back reference = 2
+Partial matching not supported
+Options: dotall
+No first char
+Need char = 'z'
+
+/((.*)a|(.*)b)z\3/Is
+Capturing subpattern count = 3
+Max back reference = 3
+Partial matching not supported
+Options: dotall
+No first char
+Need char = 'z'
+
+/((.*)a|^(.*)b)z\3/Is
+Capturing subpattern count = 3
+Max back reference = 3
+Partial matching not supported
+Options: anchored dotall
+No first char
+Need char = 'z'
+
+/(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)a/Is
+Capturing subpattern count = 31
+Partial matching not supported
+Options: anchored dotall
+No first char
+No need char
+
+/(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)a\31/Is
+Capturing subpattern count = 31
+Max back reference = 31
+Partial matching not supported
+Options: dotall
+No first char
+No need char
+
+/(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)a\32/Is
+Capturing subpattern count = 32
+Max back reference = 32
+Partial matching not supported
+Options: dotall
+No first char
+No need char
+
+/(a)(bc)/INDZ
+------------------------------------------------------------------
+ Bra
+ Bra
+ a
+ Ket
+ Bra
+ bc
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: no_auto_capture
+First char = 'a'
+Need char = 'c'
+ abc
+ 0: abc
+
+/(?P<one>a)(bc)/INDZ
+------------------------------------------------------------------
+ Bra
+ CBra 1
+ a
+ Ket
+ Bra
+ bc
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+Named capturing subpatterns:
+ one 1
+Options: no_auto_capture
+First char = 'a'
+Need char = 'c'
+ abc
+ 0: abc
+ 1: a
+
+/(a)(?P<named>bc)/INDZ
+------------------------------------------------------------------
+ Bra
+ Bra
+ a
+ Ket
+ CBra 1
+ bc
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+Named capturing subpatterns:
+ named 1
+Options: no_auto_capture
+First char = 'a'
+Need char = 'c'
+
+/(a+)*zz/I
+Capturing subpattern count = 1
+Partial matching not supported
+No options
+No first char
+Need char = 'z'
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaazzbbbbbb\M
+Minimum match() limit = 8
+Minimum match() recursion limit = 6
+ 0: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaazz
+ 1: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ aaaaaaaaaaaaaz\M
+Minimum match() limit = 32768
+Minimum match() recursion limit = 42
+No match
+
+/(aaa(?C1)bbb|ab)/I
+Capturing subpattern count = 1
+No options
+First char = 'a'
+Need char = 'b'
+ aaabbb
+--->aaabbb
+ 1 ^ ^ b
+ 0: aaabbb
+ 1: aaabbb
+ aaabbb\C*0
+--->aaabbb
+ 1 ^ ^ b
+ 0: aaabbb
+ 1: aaabbb
+ aaabbb\C*1
+--->aaabbb
+ 1 ^ ^ b
+Callout data = 1
+ 0: ab
+ 1: ab
+ aaabbb\C*-1
+--->aaabbb
+ 1 ^ ^ b
+Callout data = -1
+No match
+
+/ab(?P<one>cd)ef(?P<two>gh)/I
+Capturing subpattern count = 2
+Named capturing subpatterns:
+ one 1
+ two 2
+No options
+First char = 'a'
+Need char = 'h'
+ abcdefgh
+ 0: abcdefgh
+ 1: cd
+ 2: gh
+ abcdefgh\C1\Gtwo
+ 0: abcdefgh
+ 1: cd
+ 2: gh
+ 1C cd (2)
+ G gh (2) two
+ abcdefgh\Cone\Ctwo
+ 0: abcdefgh
+ 1: cd
+ 2: gh
+ C cd (2) one
+ C gh (2) two
+ abcdefgh\Cthree
+no parentheses with name "three"
+ 0: abcdefgh
+ 1: cd
+ 2: gh
+copy substring three failed -7
+
+/(?P<Tes>)(?P<Test>)/DZ
+------------------------------------------------------------------
+ Bra
+ CBra 1
+ Ket
+ CBra 2
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 2
+Named capturing subpatterns:
+ Tes 1
+ Test 2
+No options
+No first char
+No need char
+
+/(?P<Test>)(?P<Tes>)/DZ
+------------------------------------------------------------------
+ Bra
+ CBra 1
+ Ket
+ CBra 2
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 2
+Named capturing subpatterns:
+ Tes 2
+ Test 1
+No options
+No first char
+No need char
+
+/(?P<Z>zz)(?P<A>aa)/I
+Capturing subpattern count = 2
+Named capturing subpatterns:
+ A 2
+ Z 1
+No options
+First char = 'z'
+Need char = 'a'
+ zzaa\CZ
+ 0: zzaa
+ 1: zz
+ 2: aa
+ C zz (2) Z
+ zzaa\CA
+ 0: zzaa
+ 1: zz
+ 2: aa
+ C aa (2) A
+
+/(?P<x>eks)(?P<x>eccs)/I
+Failed: two named subpatterns have the same name at offset 15
+
+/(?P<abc>abc(?P<def>def)(?P<abc>xyz))/I
+Failed: two named subpatterns have the same name at offset 30
+
+"\[((?P<elem>\d+)(,(?P>elem))*)\]"I
+Capturing subpattern count = 3
+Named capturing subpatterns:
+ elem 2
+Partial matching not supported
+No options
+First char = '['
+Need char = ']'
+ [10,20,30,5,5,4,4,2,43,23,4234]
+ 0: [10,20,30,5,5,4,4,2,43,23,4234]
+ 1: 10,20,30,5,5,4,4,2,43,23,4234
+ 2: 10
+ 3: ,4234
+ *** Failers
+No match
+ []
+No match
+
+"\[((?P<elem>\d+)(,(?P>elem))*)?\]"I
+Capturing subpattern count = 3
+Named capturing subpatterns:
+ elem 2
+Partial matching not supported
+No options
+First char = '['
+Need char = ']'
+ [10,20,30,5,5,4,4,2,43,23,4234]
+ 0: [10,20,30,5,5,4,4,2,43,23,4234]
+ 1: 10,20,30,5,5,4,4,2,43,23,4234
+ 2: 10
+ 3: ,4234
+ []
+ 0: []
+
+/(a(b(?2)c))?/DZ
+------------------------------------------------------------------
+ Bra
+ Brazero
+ CBra 1
+ a
+ CBra 2
+ b
+ Once
+ Recurse
+ Ket
+ c
+ Ket
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 2
+No options
+No first char
+No need char
+
+/(a(b(?2)c))*/DZ
+------------------------------------------------------------------
+ Bra
+ Brazero
+ CBra 1
+ a
+ CBra 2
+ b
+ Once
+ Recurse
+ Ket
+ c
+ Ket
+ KetRmax
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 2
+No options
+No first char
+No need char
+
+/(a(b(?2)c)){0,2}/DZ
+------------------------------------------------------------------
+ Bra
+ Brazero
+ Bra
+ CBra 1
+ a
+ CBra 2
+ b
+ Once
+ Recurse
+ Ket
+ c
+ Ket
+ Ket
+ Brazero
+ CBra 1
+ a
+ CBra 2
+ b
+ Once
+ Recurse
+ Ket
+ c
+ Ket
+ Ket
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 2
+No options
+No first char
+No need char
+
+/[ab]{1}+/DZ
+------------------------------------------------------------------
+ Bra
+ Once
+ [ab]{1,1}
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+
+/((w\/|-|with)*(free|immediate)*.*?shipping\s*[!.-]*)/Ii
+Capturing subpattern count = 3
+Partial matching not supported
+Options: caseless
+No first char
+Need char = 'g' (caseless)
+ Baby Bjorn Active Carrier - With free SHIPPING!!
+ 0: Baby Bjorn Active Carrier - With free SHIPPING!!
+ 1: Baby Bjorn Active Carrier - With free SHIPPING!!
+
+/((w\/|-|with)*(free|immediate)*.*?shipping\s*[!.-]*)/IiS
+Capturing subpattern count = 3
+Partial matching not supported
+Options: caseless
+No first char
+Need char = 'g' (caseless)
+Study returned NULL
+ Baby Bjorn Active Carrier - With free SHIPPING!!
+ 0: Baby Bjorn Active Carrier - With free SHIPPING!!
+ 1: Baby Bjorn Active Carrier - With free SHIPPING!!
+
+/a*.*b/ISDZ
+------------------------------------------------------------------
+ Bra
+ a*
+ Any*
+ b
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+No first char
+Need char = 'b'
+Study returned NULL
+
+/(a|b)*.?c/ISDZ
+------------------------------------------------------------------
+ Bra
+ Brazero
+ CBra 1
+ a
+ Alt
+ b
+ KetRmax
+ Any?
+ c
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+No options
+No first char
+Need char = 'c'
+Study returned NULL
+
+/abc(?C255)de(?C)f/DZ
+------------------------------------------------------------------
+ Bra
+ abc
+ Callout 255 10 1
+ de
+ Callout 0 16 1
+ f
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'f'
+
+/abcde/ICDZ
+------------------------------------------------------------------
+ Bra
+ Callout 255 0 1
+ a
+ Callout 255 1 1
+ b
+ Callout 255 2 1
+ c
+ Callout 255 3 1
+ d
+ Callout 255 4 1
+ e
+ Callout 255 5 0
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options:
+First char = 'a'
+Need char = 'e'
+ abcde
+--->abcde
+ +0 ^ a
+ +1 ^^ b
+ +2 ^ ^ c
+ +3 ^ ^ d
+ +4 ^ ^ e
+ +5 ^ ^
+ 0: abcde
+ abcdfe
+--->abcdfe
+ +0 ^ a
+ +1 ^^ b
+ +2 ^ ^ c
+ +3 ^ ^ d
+ +4 ^ ^ e
+No match
+
+/a*b/ICDZ
+------------------------------------------------------------------
+ Bra
+ Callout 255 0 2
+ a*+
+ Callout 255 2 1
+ b
+ Callout 255 3 0
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options:
+No first char
+Need char = 'b'
+ ab
+--->ab
+ +0 ^ a*
+ +2 ^^ b
+ +3 ^ ^
+ 0: ab
+ aaaab
+--->aaaab
+ +0 ^ a*
+ +2 ^ ^ b
+ +3 ^ ^
+ 0: aaaab
+ aaaacb
+--->aaaacb
+ +0 ^ a*
+ +2 ^ ^ b
+ +0 ^ a*
+ +2 ^ ^ b
+ +0 ^ a*
+ +2 ^ ^ b
+ +0 ^ a*
+ +2 ^^ b
+ +0 ^ a*
+ +2 ^ b
+ +0 ^ a*
+ +2 ^ b
+ +3 ^^
+ 0: b
+
+/a+b/ICDZ
+------------------------------------------------------------------
+ Bra
+ Callout 255 0 2
+ a++
+ Callout 255 2 1
+ b
+ Callout 255 3 0
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options:
+First char = 'a'
+Need char = 'b'
+ ab
+--->ab
+ +0 ^ a+
+ +2 ^^ b
+ +3 ^ ^
+ 0: ab
+ aaaab
+--->aaaab
+ +0 ^ a+
+ +2 ^ ^ b
+ +3 ^ ^
+ 0: aaaab
+ aaaacb
+--->aaaacb
+ +0 ^ a+
+ +2 ^ ^ b
+ +0 ^ a+
+ +2 ^ ^ b
+ +0 ^ a+
+ +2 ^ ^ b
+ +0 ^ a+
+ +2 ^^ b
+No match
+
+/(abc|def)x/ICDZ
+------------------------------------------------------------------
+ Bra
+ Callout 255 0 9
+ CBra 1
+ Callout 255 1 1
+ a
+ Callout 255 2 1
+ b
+ Callout 255 3 1
+ c
+ Callout 255 4 0
+ Alt
+ Callout 255 5 1
+ d
+ Callout 255 6 1
+ e
+ Callout 255 7 1
+ f
+ Callout 255 8 0
+ Ket
+ Callout 255 9 1
+ x
+ Callout 255 10 0
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+Options:
+No first char
+Need char = 'x'
+ abcx
+--->abcx
+ +0 ^ (abc|def)
+ +1 ^ a
+ +2 ^^ b
+ +3 ^ ^ c
+ +4 ^ ^ |
+ +9 ^ ^ x
++10 ^ ^
+ 0: abcx
+ 1: abc
+ defx
+--->defx
+ +0 ^ (abc|def)
+ +1 ^ a
+ +5 ^ d
+ +6 ^^ e
+ +7 ^ ^ f
+ +8 ^ ^ )
+ +9 ^ ^ x
++10 ^ ^
+ 0: defx
+ 1: def
+ abcdefzx
+--->abcdefzx
+ +0 ^ (abc|def)
+ +1 ^ a
+ +2 ^^ b
+ +3 ^ ^ c
+ +4 ^ ^ |
+ +9 ^ ^ x
+ +5 ^ d
+ +0 ^ (abc|def)
+ +1 ^ a
+ +5 ^ d
+ +0 ^ (abc|def)
+ +1 ^ a
+ +5 ^ d
+ +0 ^ (abc|def)
+ +1 ^ a
+ +5 ^ d
+ +6 ^^ e
+ +7 ^ ^ f
+ +8 ^ ^ )
+ +9 ^ ^ x
+ +0 ^ (abc|def)
+ +1 ^ a
+ +5 ^ d
+ +0 ^ (abc|def)
+ +1 ^ a
+ +5 ^ d
+ +0 ^ (abc|def)
+ +1 ^ a
+ +5 ^ d
+ +0 ^ (abc|def)
+ +1 ^ a
+ +5 ^ d
+No match
+
+/(ab|cd){3,4}/IC
+Capturing subpattern count = 1
+Options:
+No first char
+No need char
+ ababab
+--->ababab
+ +0 ^ (ab|cd){3,4}
+ +1 ^ a
+ +2 ^^ b
+ +3 ^ ^ |
+ +1 ^ ^ a
+ +2 ^ ^ b
+ +3 ^ ^ |
+ +1 ^ ^ a
+ +2 ^ ^ b
+ +3 ^ ^ |
+ +1 ^ ^ a
+ +4 ^ ^ c
++12 ^ ^
+ 0: ababab
+ 1: ab
+ abcdabcd
+--->abcdabcd
+ +0 ^ (ab|cd){3,4}
+ +1 ^ a
+ +2 ^^ b
+ +3 ^ ^ |
+ +1 ^ ^ a
+ +4 ^ ^ c
+ +5 ^ ^ d
+ +6 ^ ^ )
+ +1 ^ ^ a
+ +2 ^ ^ b
+ +3 ^ ^ |
+ +1 ^ ^ a
+ +4 ^ ^ c
+ +5 ^ ^ d
+ +6 ^ ^ )
++12 ^ ^
+ 0: abcdabcd
+ 1: cd
+ abcdcdcdcdcd
+--->abcdcdcdcdcd
+ +0 ^ (ab|cd){3,4}
+ +1 ^ a
+ +2 ^^ b
+ +3 ^ ^ |
+ +1 ^ ^ a
+ +4 ^ ^ c
+ +5 ^ ^ d
+ +6 ^ ^ )
+ +1 ^ ^ a
+ +4 ^ ^ c
+ +5 ^ ^ d
+ +6 ^ ^ )
+ +1 ^ ^ a
+ +4 ^ ^ c
+ +5 ^ ^ d
+ +6 ^ ^ )
++12 ^ ^
+ 0: abcdcdcd
+ 1: cd
+
+/([ab]{,4}c|xy)/ICDZ
+------------------------------------------------------------------
+ Bra
+ Callout 255 0 14
+ CBra 1
+ Callout 255 1 4
+ [ab]
+ Callout 255 5 1
+ {
+ Callout 255 6 1
+ ,
+ Callout 255 7 1
+ 4
+ Callout 255 8 1
+ }
+ Callout 255 9 1
+ c
+ Callout 255 10 0
+ Alt
+ Callout 255 11 1
+ x
+ Callout 255 12 1
+ y
+ Callout 255 13 0
+ Ket
+ Callout 255 14 0
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+Options:
+No first char
+No need char
+ Note: that { does NOT introduce a quantifier
+--->Note: that { does NOT introduce a quantifier
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
+ +5 ^^ {
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
+ +5 ^^ {
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
+ +5 ^^ {
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+ +0 ^ ([ab]{,4}c|xy)
+ +1 ^ [ab]
++11 ^ x
+No match
+
+/([ab]{1,4}c|xy){4,5}?123/ICDZ
+------------------------------------------------------------------
+ Bra
+ Callout 255 0 21
+ CBra 1
+ Callout 255 1 9
+ [ab]{1,4}
+ Callout 255 10 1
+ c
+ Callout 255 11 0
+ Alt
+ Callout 255 12 1
+ x
+ Callout 255 13 1
+ y
+ Callout 255 14 0
+ Ket
+ CBra 1
+ Callout 255 1 9
+ [ab]{1,4}
+ Callout 255 10 1
+ c
+ Callout 255 11 0
+ Alt
+ Callout 255 12 1
+ x
+ Callout 255 13 1
+ y
+ Callout 255 14 0
+ Ket
+ CBra 1
+ Callout 255 1 9
+ [ab]{1,4}
+ Callout 255 10 1
+ c
+ Callout 255 11 0
+ Alt
+ Callout 255 12 1
+ x
+ Callout 255 13 1
+ y
+ Callout 255 14 0
+ Ket
+ CBra 1
+ Callout 255 1 9
+ [ab]{1,4}
+ Callout 255 10 1
+ c
+ Callout 255 11 0
+ Alt
+ Callout 255 12 1
+ x
+ Callout 255 13 1
+ y
+ Callout 255 14 0
+ Ket
+ Braminzero
+ CBra 1
+ Callout 255 1 9
+ [ab]{1,4}
+ Callout 255 10 1
+ c
+ Callout 255 11 0
+ Alt
+ Callout 255 12 1
+ x
+ Callout 255 13 1
+ y
+ Callout 255 14 0
+ Ket
+ Callout 255 21 1
+ 1
+ Callout 255 22 1
+ 2
+ Callout 255 23 1
+ 3
+ Callout 255 24 0
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+Partial matching not supported
+Options:
+No first char
+Need char = '3'
+ aacaacaacaacaac123
+--->aacaacaacaacaac123
+ +0 ^ ([ab]{1,4}c|xy){4,5}?
+ +1 ^ [ab]{1,4}
++10 ^ ^ c
++11 ^ ^ |
+ +1 ^ ^ [ab]{1,4}
++10 ^ ^ c
++11 ^ ^ |
+ +1 ^ ^ [ab]{1,4}
++10 ^ ^ c
++11 ^ ^ |
+ +1 ^ ^ [ab]{1,4}
++10 ^ ^ c
++11 ^ ^ |
++21 ^ ^ 1
+ +1 ^ ^ [ab]{1,4}
++10 ^ ^ c
++11 ^ ^ |
++21 ^ ^ 1
++22 ^ ^ 2
++23 ^ ^ 3
++24 ^ ^
+ 0: aacaacaacaacaac123
+ 1: aac
+
+/\b.*/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+No first char
+No need char
+ ab cd\>1
+ 0: cd
+
+/\b.*/Is
+Capturing subpattern count = 0
+Partial matching not supported
+Options: dotall
+No first char
+No need char
+ ab cd\>1
+ 0: cd
+
+/(?!.bcd).*/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+No first char
+No need char
+ Xbcd12345
+ 0: bcd12345
+
+/abcde/I
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'e'
+ ab\P
+Partial match
+ abc\P
+Partial match
+ abcd\P
+Partial match
+ abcde\P
+ 0: abcde
+ the quick brown abc\P
+Partial match
+ ** Failers\P
+No match
+ the quick brown abxyz fox\P
+No match
+
+"^(0?[1-9]|[12][0-9]|3[01])/(0?[1-9]|1[012])/(20)?\d\d$"I
+Capturing subpattern count = 3
+Options: anchored
+No first char
+Need char = '/'
+ 13/05/04\P
+ 0: 13/05/04
+ 1: 13
+ 2: 05
+ 13/5/2004\P
+ 0: 13/5/2004
+ 1: 13
+ 2: 5
+ 3: 20
+ 02/05/09\P
+ 0: 02/05/09
+ 1: 02
+ 2: 05
+ 1\P
+Partial match
+ 1/2\P
+Partial match
+ 1/2/0\P
+Partial match
+ 1/2/04\P
+ 0: 1/2/04
+ 1: 1
+ 2: 2
+ 0\P
+Partial match
+ 02/\P
+Partial match
+ 02/0\P
+Partial match
+ 02/1\P
+Partial match
+ ** Failers\P
+No match
+ \P
+No match
+ 123\P
+No match
+ 33/4/04\P
+No match
+ 3/13/04\P
+No match
+ 0/1/2003\P
+No match
+ 0/\P
+No match
+ 02/0/\P
+No match
+ 02/13\P
+No match
+
+/0{0,2}ABC/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+No first char
+Need char = 'C'
+
+/\d{3,}ABC/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+No first char
+Need char = 'C'
+
+/\d*ABC/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+No first char
+Need char = 'C'
+
+/[abc]+DE/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+No first char
+Need char = 'E'
+
+/[abc]?123/I
+Capturing subpattern count = 0
+No options
+No first char
+Need char = '3'
+ 123\P
+ 0: 123
+ a\P
+Partial match
+ b\P
+Partial match
+ c\P
+Partial match
+ c12\P
+Partial match
+ c123\P
+ 0: c123
+
+/^(?:\d){3,5}X/I
+Capturing subpattern count = 0
+Options: anchored
+No first char
+Need char = 'X'
+ 1\P
+Partial match
+ 123\P
+Partial match
+ 123X
+ 0: 123X
+ 1234\P
+Partial match
+ 1234X
+ 0: 1234X
+ 12345\P
+Partial match
+ 12345X
+ 0: 12345X
+ *** Failers
+No match
+ 1X
+No match
+ 123456\P
+No match
+
+/abc/I>testsavedregex
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'c'
+Compiled regex written to testsavedregex
+<testsavedregex
+Compiled regex loaded from testsavedregex
+No study data
+ abc
+ 0: abc
+ ** Failers
+No match
+ bca
+No match
+
+/abc/IF>testsavedregex
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'c'
+Compiled regex written to testsavedregex
+<testsavedregex
+Compiled regex (byte-inverted) loaded from testsavedregex
+No study data
+ abc
+ 0: abc
+ ** Failers
+No match
+ bca
+No match
+
+/(a|b)/IS>testsavedregex
+Capturing subpattern count = 1
+No options
+No first char
+No need char
+Starting byte set: a b
+Compiled regex written to testsavedregex
+Study data written to testsavedregex
+<testsavedregex
+Compiled regex loaded from testsavedregex
+Study data loaded from testsavedregex
+ abc
+ 0: a
+ 1: a
+ ** Failers
+ 0: a
+ 1: a
+ def
+No match
+
+/(a|b)/ISF>testsavedregex
+Capturing subpattern count = 1
+No options
+No first char
+No need char
+Starting byte set: a b
+Compiled regex written to testsavedregex
+Study data written to testsavedregex
+<testsavedregex
+Compiled regex (byte-inverted) loaded from testsavedregex
+Study data loaded from testsavedregex
+ abc
+ 0: a
+ 1: a
+ ** Failers
+ 0: a
+ 1: a
+ def
+No match
+
+~<(\w+)/?>(.)*</(\1)>~smgI
+Capturing subpattern count = 3
+Max back reference = 1
+Partial matching not supported
+Options: multiline dotall
+First char = '<'
+Need char = '>'
+ <!DOCTYPE seite SYSTEM "http://www.lco.lineas.de/xmlCms.dtd">\n<seite>\n<dokumenteninformation>\n<seitentitel>Partner der LCO</seitentitel>\n<sprache>de</sprache>\n<seitenbeschreibung>Partner der LINEAS Consulting\nGmbH</seitenbeschreibung>\n<schluesselworte>LINEAS Consulting GmbH Hamburg\nPartnerfirmen</schluesselworte>\n<revisit>30 days</revisit>\n<robots>index,follow</robots>\n<menueinformation>\n<aktiv>ja</aktiv>\n<menueposition>3</menueposition>\n<menuetext>Partner</menuetext>\n</menueinformation>\n<lastedited>\n<autor>LCO</autor>\n<firma>LINEAS Consulting</firma>\n<datum>15.10.2003</datum>\n</lastedited>\n</dokumenteninformation>\n<inhalt>\n\n<absatzueberschrift>Die Partnerfirmen der LINEAS Consulting\nGmbH</absatzueberschrift>\n\n<absatz><link ziel="http://www.ca.com/" zielfenster="_blank">\n<bild name="logo_ca.gif" rahmen="no"/></link> <link\nziel="http://www.ey.com/" zielfenster="_blank"><bild\nname="logo_euy.gif" rahmen="no"/></link>\n</absatz>\n\n<absatz><link ziel="http://www.cisco.de/" zielfenster="_blank">\n<bild name="logo_cisco.gif" rahmen="ja"/></link></absatz>\n\n<absatz><link ziel="http://www.atelion.de/"\nzielfenster="_blank"><bild\nname="logo_atelion.gif" rahmen="no"/></link>\n</absatz>\n\n<absatz><link ziel="http://www.line-information.de/"\nzielfenster="_blank">\n<bild name="logo_line_information.gif" rahmen="no"/></link>\n</absatz>\n\n<absatz><bild name="logo_aw.gif" rahmen="no"/></absatz>\n\n<absatz><link ziel="http://www.incognis.de/"\nzielfenster="_blank"><bild\nname="logo_incognis.gif" rahmen="no"/></link></absatz>\n\n<absatz><link ziel="http://www.addcraft.com/"\nzielfenster="_blank"><bild\nname="logo_addcraft.gif" rahmen="no"/></link></absatz>\n\n<absatz><link ziel="http://www.comendo.com/"\nzielfenster="_blank"><bild\nname="logo_comendo.gif" rahmen="no"/></link></absatz>\n\n</inhalt>\n</seite>
+ 0: <seite>\x0a<dokumenteninformation>\x0a<seitentitel>Partner der LCO</seitentitel>\x0a<sprache>de</sprache>\x0a<seitenbeschreibung>Partner der LINEAS Consulting\x0aGmbH</seitenbeschreibung>\x0a<schluesselworte>LINEAS Consulting GmbH Hamburg\x0aPartnerfirmen</schluesselworte>\x0a<revisit>30 days</revisit>\x0a<robots>index,follow</robots>\x0a<menueinformation>\x0a<aktiv>ja</aktiv>\x0a<menueposition>3</menueposition>\x0a<menuetext>Partner</menuetext>\x0a</menueinformation>\x0a<lastedited>\x0a<autor>LCO</autor>\x0a<firma>LINEAS Consulting</firma>\x0a<datum>15.10.2003</datum>\x0a</lastedited>\x0a</dokumenteninformation>\x0a<inhalt>\x0a\x0a<absatzueberschrift>Die Partnerfirmen der LINEAS Consulting\x0aGmbH</absatzueberschrift>\x0a\x0a<absatz><link ziel="http://www.ca.com/" zielfenster="_blank">\x0a<bild name="logo_ca.gif" rahmen="no"/></link> <link\x0aziel="http://www.ey.com/" zielfenster="_blank"><bild\x0aname="logo_euy.gif" rahmen="no"/></link>\x0a</absatz>\x0a\x0a<absatz><link ziel="http://www.cisco.de/" zielfenster="_blank">\x0a<bild name="logo_cisco.gif" rahmen="ja"/></link></absatz>\x0a\x0a<absatz><link ziel="http://www.atelion.de/"\x0azielfenster="_blank"><bild\x0aname="logo_atelion.gif" rahmen="no"/></link>\x0a</absatz>\x0a\x0a<absatz><link ziel="http://www.line-information.de/"\x0azielfenster="_blank">\x0a<bild name="logo_line_information.gif" rahmen="no"/></link>\x0a</absatz>\x0a\x0a<absatz><bild name="logo_aw.gif" rahmen="no"/></absatz>\x0a\x0a<absatz><link ziel="http://www.incognis.de/"\x0azielfenster="_blank"><bild\x0aname="logo_incognis.gif" rahmen="no"/></link></absatz>\x0a\x0a<absatz><link ziel="http://www.addcraft.com/"\x0azielfenster="_blank"><bild\x0aname="logo_addcraft.gif" rahmen="no"/></link></absatz>\x0a\x0a<absatz><link ziel="http://www.comendo.com/"\x0azielfenster="_blank"><bild\x0aname="logo_comendo.gif" rahmen="no"/></link></absatz>\x0a\x0a</inhalt>\x0a</seite>
+ 1: seite
+ 2: \x0a
+ 3: seite
+
+/^a/IF
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/line\nbreak/I
+Capturing subpattern count = 0
+Contains explicit CR or LF match
+No options
+First char = 'l'
+Need char = 'k'
+ this is a line\nbreak
+ 0: line\x0abreak
+ line one\nthis is a line\nbreak in the second line
+ 0: line\x0abreak
+
+/line\nbreak/If
+Capturing subpattern count = 0
+Contains explicit CR or LF match
+Options: firstline
+First char = 'l'
+Need char = 'k'
+ this is a line\nbreak
+ 0: line\x0abreak
+ ** Failers
+No match
+ line one\nthis is a line\nbreak in the second line
+No match
+
+/line\nbreak/Imf
+Capturing subpattern count = 0
+Contains explicit CR or LF match
+Options: multiline firstline
+First char = 'l'
+Need char = 'k'
+ this is a line\nbreak
+ 0: line\x0abreak
+ ** Failers
+No match
+ line one\nthis is a line\nbreak in the second line
+No match
+
+/ab.cd/IP
+ ab-cd
+ 0: ab-cd
+ ab=cd
+ 0: ab=cd
+ ** Failers
+No match: POSIX code 17: match failed
+ ab\ncd
+No match: POSIX code 17: match failed
+
+/ab.cd/IPs
+ ab-cd
+ 0: ab-cd
+ ab=cd
+ 0: ab=cd
+ ab\ncd
+ 0: ab\x0acd
+
+/(?i)(?-i)AbCd/I
+Capturing subpattern count = 0
+No options
+First char = 'A'
+Need char = 'd'
+ AbCd
+ 0: AbCd
+ ** Failers
+No match
+ abcd
+No match
+
+/a{11111111111111111111}/I
+Failed: number too big in {} quantifier at offset 22
+
+/(){64294967295}/I
+Failed: number too big in {} quantifier at offset 14
+
+/(){2,4294967295}/I
+Failed: number too big in {} quantifier at offset 15
+
+"(?i:a)(?i:b)(?i:c)(?i:d)(?i:e)(?i:f)(?i:g)(?i:h)(?i:i)(?i:j)(k)(?i:l)A\1B"I
+Capturing subpattern count = 1
+Max back reference = 1
+No options
+First char = 'a' (caseless)
+Need char = 'B'
+ abcdefghijklAkB
+ 0: abcdefghijklAkB
+ 1: k
+
+"(?P<n0>a)(?P<n1>b)(?P<n2>c)(?P<n3>d)(?P<n4>e)(?P<n5>f)(?P<n6>g)(?P<n7>h)(?P<n8>i)(?P<n9>j)(?P<n10>k)(?P<n11>l)A\11B"I
+Capturing subpattern count = 12
+Max back reference = 11
+Named capturing subpatterns:
+ n0 1
+ n1 2
+ n10 11
+ n11 12
+ n2 3
+ n3 4
+ n4 5
+ n5 6
+ n6 7
+ n7 8
+ n8 9
+ n9 10
+No options
+First char = 'a'
+Need char = 'B'
+ abcdefghijklAkB
+ 0: abcdefghijklAkB
+ 1: a
+ 2: b
+ 3: c
+ 4: d
+ 5: e
+ 6: f
+ 7: g
+ 8: h
+ 9: i
+10: j
+11: k
+12: l
+
+"(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)A\11B"I
+Capturing subpattern count = 12
+Max back reference = 11
+No options
+First char = 'a'
+Need char = 'B'
+ abcdefghijklAkB
+ 0: abcdefghijklAkB
+ 1: a
+ 2: b
+ 3: c
+ 4: d
+ 5: e
+ 6: f
+ 7: g
+ 8: h
+ 9: i
+10: j
+11: k
+12: l
+
+"(?P<name0>a)(?P<name1>a)(?P<name2>a)(?P<name3>a)(?P<name4>a)(?P<name5>a)(?P<name6>a)(?P<name7>a)(?P<name8>a)(?P<name9>a)(?P<name10>a)(?P<name11>a)(?P<name12>a)(?P<name13>a)(?P<name14>a)(?P<name15>a)(?P<name16>a)(?P<name17>a)(?P<name18>a)(?P<name19>a)(?P<name20>a)(?P<name21>a)(?P<name22>a)(?P<name23>a)(?P<name24>a)(?P<name25>a)(?P<name26>a)(?P<name27>a)(?P<name28>a)(?P<name29>a)(?P<name30>a)(?P<name31>a)(?P<name32>a)(?P<name33>a)(?P<name34>a)(?P<name35>a)(?P<name36>a)(?P<name37>a)(?P<name38>a)(?P<name39>a)(?P<name40>a)(?P<name41>a)(?P<name42>a)(?P<name43>a)(?P<name44>a)(?P<name45>a)(?P<name46>a)(?P<name47>a)(?P<name48>a)(?P<name49>a)(?P<name50>a)(?P<name51>a)(?P<name52>a)(?P<name53>a)(?P<name54>a)(?P<name55>a)(?P<name56>a)(?P<name57>a)(?P<name58>a)(?P<name59>a)(?P<name60>a)(?P<name61>a)(?P<name62>a)(?P<name63>a)(?P<name64>a)(?P<name65>a)(?P<name66>a)(?P<name67>a)(?P<name68>a)(?P<name69>a)(?P<name70>a)(?P<name71>a)(?P<name72>a)(?P<name73>a)(?P<name74>a)(?P<name75>a)(?P<name76>a)(?P<name77>a)(?P<name78>a)(?P<name79>a)(?P<name80>a)(?P<name81>a)(?P<name82>a)(?P<name83>a)(?P<name84>a)(?P<name85>a)(?P<name86>a)(?P<name87>a)(?P<name88>a)(?P<name89>a)(?P<name90>a)(?P<name91>a)(?P<name92>a)(?P<name93>a)(?P<name94>a)(?P<name95>a)(?P<name96>a)(?P<name97>a)(?P<name98>a)(?P<name99>a)(?P<name100>a)"I
+Capturing subpattern count = 101
+Named capturing subpatterns:
+ name0 1
+ name1 2
+ name10 11
+ name100 101
+ name11 12
+ name12 13
+ name13 14
+ name14 15
+ name15 16
+ name16 17
+ name17 18
+ name18 19
+ name19 20
+ name2 3
+ name20 21
+ name21 22
+ name22 23
+ name23 24
+ name24 25
+ name25 26
+ name26 27
+ name27 28
+ name28 29
+ name29 30
+ name3 4
+ name30 31
+ name31 32
+ name32 33
+ name33 34
+ name34 35
+ name35 36
+ name36 37
+ name37 38
+ name38 39
+ name39 40
+ name4 5
+ name40 41
+ name41 42
+ name42 43
+ name43 44
+ name44 45
+ name45 46
+ name46 47
+ name47 48
+ name48 49
+ name49 50
+ name5 6
+ name50 51
+ name51 52
+ name52 53
+ name53 54
+ name54 55
+ name55 56
+ name56 57
+ name57 58
+ name58 59
+ name59 60
+ name6 7
+ name60 61
+ name61 62
+ name62 63
+ name63 64
+ name64 65
+ name65 66
+ name66 67
+ name67 68
+ name68 69
+ name69 70
+ name7 8
+ name70 71
+ name71 72
+ name72 73
+ name73 74
+ name74 75
+ name75 76
+ name76 77
+ name77 78
+ name78 79
+ name79 80
+ name8 9
+ name80 81
+ name81 82
+ name82 83
+ name83 84
+ name84 85
+ name85 86
+ name86 87
+ name87 88
+ name88 89
+ name89 90
+ name9 10
+ name90 91
+ name91 92
+ name92 93
+ name93 94
+ name94 95
+ name95 96
+ name96 97
+ name97 98
+ name98 99
+ name99 100
+No options
+First char = 'a'
+Need char = 'a'
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+Matched, but too many substrings
+ 0: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 1: a
+ 2: a
+ 3: a
+ 4: a
+ 5: a
+ 6: a
+ 7: a
+ 8: a
+ 9: a
+10: a
+11: a
+12: a
+13: a
+14: a
+
+"(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)(a)"I
+Capturing subpattern count = 101
+No options
+First char = 'a'
+Need char = 'a'
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+Matched, but too many substrings
+ 0: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 1: a
+ 2: a
+ 3: a
+ 4: a
+ 5: a
+ 6: a
+ 7: a
+ 8: a
+ 9: a
+10: a
+11: a
+12: a
+13: a
+14: a
+
+/[^()]*(?:\((?R)\)[^()]*)*/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+No first char
+No need char
+ (this(and)that
+ 0:
+ (this(and)that)
+ 0: (this(and)that)
+ (this(and)that)stuff
+ 0: (this(and)that)stuff
+
+/[^()]*(?:\((?>(?R))\)[^()]*)*/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+No first char
+No need char
+ (this(and)that
+ 0:
+ (this(and)that)
+ 0: (this(and)that)
+
+/[^()]*(?:\((?R)\))*[^()]*/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+No first char
+No need char
+ (this(and)that
+ 0:
+ (this(and)that)
+ 0: (this(and)that)
+
+/(?:\((?R)\))*[^()]*/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+No first char
+No need char
+ (this(and)that
+ 0:
+ (this(and)that)
+ 0:
+ ((this))
+ 0: ((this))
+
+/(?:\((?R)\))|[^()]*/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+No first char
+No need char
+ (this(and)that
+ 0:
+ (this(and)that)
+ 0:
+ (this)
+ 0: (this)
+ ((this))
+ 0: ((this))
+
+/a(b)c/IPN
+ abc
+Matched with REG_NOSUB
+
+/a(?P<name>b)c/IPN
+ abc
+Matched with REG_NOSUB
+
+/\x{100}/I
+Failed: character value in \x{...} sequence is too large at offset 6
+
+/\x{0000ff}/I
+Capturing subpattern count = 0
+No options
+First char = 255
+No need char
+
+/^((?P<A>a1)|(?P<A>a2)b)/I
+Failed: two named subpatterns have the same name at offset 17
+
+/^((?P<A>a1)|(?P<A>a2)b)/IJ
+Capturing subpattern count = 3
+Named capturing subpatterns:
+ A 2
+ A 3
+Options: anchored dupnames
+No first char
+No need char
+ a1b\CA
+ 0: a1
+ 1: a1
+ 2: a1
+ C a1 (2) A
+ a2b\CA
+ 0: a2b
+ 1: a2b
+ 2: <unset>
+ 3: a2
+ C a2 (2) A
+ ** Failers
+No match
+ a1b\CZ\CA
+no parentheses with name "Z"
+ 0: a1
+ 1: a1
+ 2: a1
+copy substring Z failed -7
+ C a1 (2) A
+
+/^(?P<A>a)(?P<A>b)/IJ
+Capturing subpattern count = 2
+Named capturing subpatterns:
+ A 1
+ A 2
+Options: anchored dupnames
+No first char
+No need char
+ ab\CA
+ 0: ab
+ 1: a
+ 2: b
+ C a (1) A
+
+/^(?P<A>a)(?P<A>b)|cd/IJ
+Capturing subpattern count = 2
+Named capturing subpatterns:
+ A 1
+ A 2
+Options: dupnames
+No first char
+No need char
+ ab\CA
+ 0: ab
+ 1: a
+ 2: b
+ C a (1) A
+ cd\CA
+ 0: cd
+copy substring A failed -7
+
+/^(?P<A>a)(?P<A>b)|cd(?P<A>ef)(?P<A>gh)/IJ
+Capturing subpattern count = 4
+Named capturing subpatterns:
+ A 1
+ A 2
+ A 3
+ A 4
+Options: dupnames
+No first char
+No need char
+ cdefgh\CA
+ 0: cdefgh
+ 1: <unset>
+ 2: <unset>
+ 3: ef
+ 4: gh
+ C ef (2) A
+
+/^((?P<A>a1)|(?P<A>a2)b)/IJ
+Capturing subpattern count = 3
+Named capturing subpatterns:
+ A 2
+ A 3
+Options: anchored dupnames
+No first char
+No need char
+ a1b\GA
+ 0: a1
+ 1: a1
+ 2: a1
+ G a1 (2) A
+ a2b\GA
+ 0: a2b
+ 1: a2b
+ 2: <unset>
+ 3: a2
+ G a2 (2) A
+ ** Failers
+No match
+ a1b\GZ\GA
+no parentheses with name "Z"
+ 0: a1
+ 1: a1
+ 2: a1
+copy substring Z failed -7
+ G a1 (2) A
+
+/^(?P<A>a)(?P<A>b)/IJ
+Capturing subpattern count = 2
+Named capturing subpatterns:
+ A 1
+ A 2
+Options: anchored dupnames
+No first char
+No need char
+ ab\GA
+ 0: ab
+ 1: a
+ 2: b
+ G a (1) A
+
+/^(?P<A>a)(?P<A>b)|cd/IJ
+Capturing subpattern count = 2
+Named capturing subpatterns:
+ A 1
+ A 2
+Options: dupnames
+No first char
+No need char
+ ab\GA
+ 0: ab
+ 1: a
+ 2: b
+ G a (1) A
+ cd\GA
+ 0: cd
+copy substring A failed -7
+
+/^(?P<A>a)(?P<A>b)|cd(?P<A>ef)(?P<A>gh)/IJ
+Capturing subpattern count = 4
+Named capturing subpatterns:
+ A 1
+ A 2
+ A 3
+ A 4
+Options: dupnames
+No first char
+No need char
+ cdefgh\GA
+ 0: cdefgh
+ 1: <unset>
+ 2: <unset>
+ 3: ef
+ 4: gh
+ G ef (2) A
+
+/(?J)^((?P<A>a1)|(?P<A>a2)b)/I
+Capturing subpattern count = 3
+Named capturing subpatterns:
+ A 2
+ A 3
+Options: anchored dupnames
+Duplicate name status changes
+No first char
+No need char
+ a1b\CA
+ 0: a1
+ 1: a1
+ 2: a1
+ C a1 (2) A
+ a2b\CA
+ 0: a2b
+ 1: a2b
+ 2: <unset>
+ 3: a2
+ C a2 (2) A
+
+/^(?P<A>a) (?J:(?P<B>b)(?P<B>c)) (?P<A>d)/I
+Failed: two named subpatterns have the same name at offset 37
+
+/ In this next test, J is not set at the outer level; consequently it isn't
+set in the pattern's options; consequently pcre_get_named_substring() produces
+a random value. /Ix
+Capturing subpattern count = 1
+Options: extended
+First char = 'I'
+Need char = 'e'
+
+/^(?P<A>a) (?J:(?P<B>b)(?P<B>c)) (?P<C>d)/I
+Capturing subpattern count = 4
+Named capturing subpatterns:
+ A 1
+ B 2
+ B 3
+ C 4
+Options: anchored
+Duplicate name status changes
+No first char
+No need char
+ a bc d\CA\CB\CC
+ 0: a bc d
+ 1: a
+ 2: b
+ 3: c
+ 4: d
+ C a (1) A
+ C b (1) B
+ C d (1) C
+
+/^(?P<A>a)?(?(A)a|b)/I
+Capturing subpattern count = 1
+Named capturing subpatterns:
+ A 1
+Options: anchored
+No first char
+No need char
+ aabc
+ 0: aa
+ 1: a
+ bc
+ 0: b
+ ** Failers
+No match
+ abc
+No match
+
+/(?:(?(ZZ)a|b)(?P<ZZ>X))+/I
+Capturing subpattern count = 1
+Named capturing subpatterns:
+ ZZ 1
+No options
+No first char
+Need char = 'X'
+ bXaX
+ 0: bXaX
+ 1: X
+
+/(?:(?(2y)a|b)(X))+/I
+Failed: reference to non-existent subpattern at offset 9
+
+/(?:(?(ZA)a|b)(?P<ZZ>X))+/I
+Failed: reference to non-existent subpattern at offset 9
+
+/(?:(?(ZZ)a|b)(?(ZZ)a|b)(?P<ZZ>X))+/I
+Capturing subpattern count = 1
+Named capturing subpatterns:
+ ZZ 1
+No options
+No first char
+Need char = 'X'
+ bbXaaX
+ 0: bbXaaX
+ 1: X
+
+/(?:(?(ZZ)a|\(b\))\\(?P<ZZ>X))+/I
+Capturing subpattern count = 1
+Named capturing subpatterns:
+ ZZ 1
+No options
+No first char
+Need char = 'X'
+ (b)\\Xa\\X
+ 0: (b)\Xa\X
+ 1: X
+
+/(?P<ABC/I
+Failed: syntax error in subpattern name (missing terminator) at offset 7
+
+/(?:(?(A)(?P=A)a|b)(?P<A>X|Y))+/I
+Capturing subpattern count = 1
+Max back reference = 1
+Named capturing subpatterns:
+ A 1
+No options
+No first char
+No need char
+ bXXaYYaY
+ 0: bXXaYYaY
+ 1: Y
+ bXYaXXaX
+ 0: bX
+ 1: X
+
+/()()()()()()()()()(?:(?(A)(?P=A)a|b)(?P<A>X|Y))+/I
+Capturing subpattern count = 10
+Max back reference = 10
+Named capturing subpatterns:
+ A 10
+No options
+No first char
+No need char
+ bXXaYYaY
+ 0: bXXaYYaY
+ 1:
+ 2:
+ 3:
+ 4:
+ 5:
+ 6:
+ 7:
+ 8:
+ 9:
+10: Y
+
+/\777/I
+Failed: octal value is greater than \377 (not in UTF-8 mode) at offset 3
+
+/\s*,\s*/IS
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+No first char
+Need char = ','
+Starting byte set: \x09 \x0a \x0c \x0d \x20 ,
+ \x0b,\x0b
+ 0: ,
+ \x0c,\x0d
+ 0: \x0c,\x0d
+
+/^abc/Im
+Capturing subpattern count = 0
+Options: multiline
+First char at start or follows newline
+Need char = 'c'
+ xyz\nabc
+ 0: abc
+ xyz\nabc\<lf>
+ 0: abc
+ xyz\r\nabc\<lf>
+ 0: abc
+ xyz\rabc\<cr>
+ 0: abc
+ xyz\r\nabc\<crlf>
+ 0: abc
+ ** Failers
+No match
+ xyz\nabc\<cr>
+No match
+ xyz\r\nabc\<cr>
+No match
+ xyz\nabc\<crlf>
+No match
+ xyz\rabc\<crlf>
+No match
+ xyz\rabc\<lf>
+No match
+
+/abc$/Im<lf>
+Capturing subpattern count = 0
+Options: multiline
+Forced newline sequence: LF
+First char = 'a'
+Need char = 'c'
+ xyzabc
+ 0: abc
+ xyzabc\n
+ 0: abc
+ xyzabc\npqr
+ 0: abc
+ xyzabc\r\<cr>
+ 0: abc
+ xyzabc\rpqr\<cr>
+ 0: abc
+ xyzabc\r\n\<crlf>
+ 0: abc
+ xyzabc\r\npqr\<crlf>
+ 0: abc
+ ** Failers
+No match
+ xyzabc\r
+No match
+ xyzabc\rpqr
+No match
+ xyzabc\r\n
+No match
+ xyzabc\r\npqr
+No match
+
+/^abc/Im<cr>
+Capturing subpattern count = 0
+Options: multiline
+Forced newline sequence: CR
+First char at start or follows newline
+Need char = 'c'
+ xyz\rabcdef
+ 0: abc
+ xyz\nabcdef\<lf>
+ 0: abc
+ ** Failers
+No match
+ xyz\nabcdef
+No match
+
+/^abc/Im<lf>
+Capturing subpattern count = 0
+Options: multiline
+Forced newline sequence: LF
+First char at start or follows newline
+Need char = 'c'
+ xyz\nabcdef
+ 0: abc
+ xyz\rabcdef\<cr>
+ 0: abc
+ ** Failers
+No match
+ xyz\rabcdef
+No match
+
+/^abc/Im<crlf>
+Capturing subpattern count = 0
+Options: multiline
+Forced newline sequence: CRLF
+First char at start or follows newline
+Need char = 'c'
+ xyz\r\nabcdef
+ 0: abc
+ xyz\rabcdef\<cr>
+ 0: abc
+ ** Failers
+No match
+ xyz\rabcdef
+No match
+
+/^abc/Im<bad>
+Unknown newline type at: <bad>
+
+
+/abc/I
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'c'
+ xyz\rabc\<bad>
+Unknown newline type at: <bad>
+ abc
+ 0: abc
+
+/.*/I<lf>
+Capturing subpattern count = 0
+Partial matching not supported
+Options:
+Forced newline sequence: LF
+First char at start or follows newline
+No need char
+ abc\ndef
+ 0: abc
+ abc\rdef
+ 0: abc\x0ddef
+ abc\r\ndef
+ 0: abc\x0d
+ \<cr>abc\ndef
+ 0: abc\x0adef
+ \<cr>abc\rdef
+ 0: abc
+ \<cr>abc\r\ndef
+ 0: abc
+ \<crlf>abc\ndef
+ 0: abc\x0adef
+ \<crlf>abc\rdef
+ 0: abc\x0ddef
+ \<crlf>abc\r\ndef
+ 0: abc
+
+/\w+(.)(.)?def/Is
+Capturing subpattern count = 2
+Partial matching not supported
+Options: dotall
+No first char
+Need char = 'f'
+ abc\ndef
+ 0: abc\x0adef
+ 1: \x0a
+ abc\rdef
+ 0: abc\x0ddef
+ 1: \x0d
+ abc\r\ndef
+ 0: abc\x0d\x0adef
+ 1: \x0d
+ 2: \x0a
+
++((?:\s|//.*\\n|/[*](?:\\n|.)*?[*]/)*)+I
+Capturing subpattern count = 1
+Partial matching not supported
+No options
+No first char
+No need char
+ /* this is a C style comment */\M
+Minimum match() limit = 120
+Minimum match() recursion limit = 6
+ 0: /* this is a C style comment */
+ 1: /* this is a C style comment */
+
+/(?P<B>25[0-5]|2[0-4]\d|[01]?\d?\d)(?:\.(?P>B)){3}/I
+Capturing subpattern count = 1
+Named capturing subpatterns:
+ B 1
+No options
+No first char
+Need char = '.'
+
+/()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()
+ ()()()()()()()()()()()()()()()()()()()()
+ (.(.))/Ix
+Capturing subpattern count = 102
+Options: extended
+No first char
+No need char
+ XY\O400
+ 0: XY
+ 1:
+ 2:
+ 3:
+ 4:
+ 5:
+ 6:
+ 7:
+ 8:
+ 9:
+10:
+11:
+12:
+13:
+14:
+15:
+16:
+17:
+18:
+19:
+20:
+21:
+22:
+23:
+24:
+25:
+26:
+27:
+28:
+29:
+30:
+31:
+32:
+33:
+34:
+35:
+36:
+37:
+38:
+39:
+40:
+41:
+42:
+43:
+44:
+45:
+46:
+47:
+48:
+49:
+50:
+51:
+52:
+53:
+54:
+55:
+56:
+57:
+58:
+59:
+60:
+61:
+62:
+63:
+64:
+65:
+66:
+67:
+68:
+69:
+70:
+71:
+72:
+73:
+74:
+75:
+76:
+77:
+78:
+79:
+80:
+81:
+82:
+83:
+84:
+85:
+86:
+87:
+88:
+89:
+90:
+91:
+92:
+93:
+94:
+95:
+96:
+97:
+98:
+99:
+100:
+101: XY
+102: Y
+
+/(a*b|(?i:c*(?-i)d))/IS
+Capturing subpattern count = 1
+Partial matching not supported
+No options
+No first char
+No need char
+Starting byte set: C a b c d
+
+/()[ab]xyz/IS
+Capturing subpattern count = 1
+No options
+No first char
+Need char = 'z'
+Starting byte set: a b
+
+/(|)[ab]xyz/IS
+Capturing subpattern count = 1
+No options
+No first char
+Need char = 'z'
+Starting byte set: a b
+
+/(|c)[ab]xyz/IS
+Capturing subpattern count = 1
+No options
+No first char
+Need char = 'z'
+Starting byte set: a b c
+
+/(|c?)[ab]xyz/IS
+Capturing subpattern count = 1
+No options
+No first char
+Need char = 'z'
+Starting byte set: a b c
+
+/(d?|c?)[ab]xyz/IS
+Capturing subpattern count = 1
+No options
+No first char
+Need char = 'z'
+Starting byte set: a b c d
+
+/(d?|c)[ab]xyz/IS
+Capturing subpattern count = 1
+No options
+No first char
+Need char = 'z'
+Starting byte set: a b c d
+
+/^a*b\d/DZ
+------------------------------------------------------------------
+ Bra
+ ^
+ a*+
+ b
+ \d
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: anchored
+No first char
+Need char = 'b'
+
+/^a*+b\d/DZ
+------------------------------------------------------------------
+ Bra
+ ^
+ a*+
+ b
+ \d
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: anchored
+No first char
+Need char = 'b'
+
+/^a*?b\d/DZ
+------------------------------------------------------------------
+ Bra
+ ^
+ a*+
+ b
+ \d
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: anchored
+No first char
+Need char = 'b'
+
+/^a+A\d/DZ
+------------------------------------------------------------------
+ Bra
+ ^
+ a++
+ A
+ \d
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: anchored
+No first char
+Need char = 'A'
+ aaaA5
+ 0: aaaA5
+ ** Failers
+No match
+ aaaa5
+No match
+
+/^a*A\d/IiDZ
+------------------------------------------------------------------
+ Bra
+ ^
+ a*
+ NC A
+ \d
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: anchored caseless
+No first char
+Need char = 'A' (caseless)
+ aaaA5
+ 0: aaaA5
+ aaaa5
+ 0: aaaa5
+
+/(a*|b*)[cd]/IS
+Capturing subpattern count = 1
+Partial matching not supported
+No options
+No first char
+No need char
+Starting byte set: a b c d
+
+/(a+|b*)[cd]/IS
+Capturing subpattern count = 1
+Partial matching not supported
+No options
+No first char
+No need char
+Starting byte set: a b c d
+
+/(a*|b+)[cd]/IS
+Capturing subpattern count = 1
+Partial matching not supported
+No options
+No first char
+No need char
+Starting byte set: a b c d
+
+/(a+|b+)[cd]/IS
+Capturing subpattern count = 1
+Partial matching not supported
+No options
+No first char
+No need char
+Starting byte set: a b
+
+/((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
+ ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
+ (((
+ a
+ ))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
+ ))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
+ )))
+/Ix
+Capturing subpattern count = 203
+Options: extended
+First char = 'a'
+No need char
+ large nest
+Matched, but too many substrings
+ 0: a
+ 1: a
+ 2: a
+ 3: a
+ 4: a
+ 5: a
+ 6: a
+ 7: a
+ 8: a
+ 9: a
+10: a
+11: a
+12: a
+13: a
+14: a
+
+/a*\d/BZ
+------------------------------------------------------------------
+ Bra
+ a*+
+ \d
+ Ket
+ End
+------------------------------------------------------------------
+
+/a*\D/BZ
+------------------------------------------------------------------
+ Bra
+ a*
+ \D
+ Ket
+ End
+------------------------------------------------------------------
+
+/0*\d/BZ
+------------------------------------------------------------------
+ Bra
+ 0*
+ \d
+ Ket
+ End
+------------------------------------------------------------------
+
+/0*\D/BZ
+------------------------------------------------------------------
+ Bra
+ 0*+
+ \D
+ Ket
+ End
+------------------------------------------------------------------
+
+/a*\s/BZ
+------------------------------------------------------------------
+ Bra
+ a*+
+ \s
+ Ket
+ End
+------------------------------------------------------------------
+
+/a*\S/BZ
+------------------------------------------------------------------
+ Bra
+ a*
+ \S
+ Ket
+ End
+------------------------------------------------------------------
+
+/ *\s/BZ
+------------------------------------------------------------------
+ Bra
+ *
+ \s
+ Ket
+ End
+------------------------------------------------------------------
+
+/ *\S/BZ
+------------------------------------------------------------------
+ Bra
+ *+
+ \S
+ Ket
+ End
+------------------------------------------------------------------
+
+/a*\w/BZ
+------------------------------------------------------------------
+ Bra
+ a*
+ \w
+ Ket
+ End
+------------------------------------------------------------------
+
+/a*\W/BZ
+------------------------------------------------------------------
+ Bra
+ a*+
+ \W
+ Ket
+ End
+------------------------------------------------------------------
+
+/=*\w/BZ
+------------------------------------------------------------------
+ Bra
+ =*+
+ \w
+ Ket
+ End
+------------------------------------------------------------------
+
+/=*\W/BZ
+------------------------------------------------------------------
+ Bra
+ =*
+ \W
+ Ket
+ End
+------------------------------------------------------------------
+
+/\d*a/BZ
+------------------------------------------------------------------
+ Bra
+ \d*+
+ a
+ Ket
+ End
+------------------------------------------------------------------
+
+/\d*2/BZ
+------------------------------------------------------------------
+ Bra
+ \d*
+ 2
+ Ket
+ End
+------------------------------------------------------------------
+
+/\d*\d/BZ
+------------------------------------------------------------------
+ Bra
+ \d*
+ \d
+ Ket
+ End
+------------------------------------------------------------------
+
+/\d*\D/BZ
+------------------------------------------------------------------
+ Bra
+ \d*+
+ \D
+ Ket
+ End
+------------------------------------------------------------------
+
+/\d*\s/BZ
+------------------------------------------------------------------
+ Bra
+ \d*+
+ \s
+ Ket
+ End
+------------------------------------------------------------------
+
+/\d*\S/BZ
+------------------------------------------------------------------
+ Bra
+ \d*
+ \S
+ Ket
+ End
+------------------------------------------------------------------
+
+/\d*\w/BZ
+------------------------------------------------------------------
+ Bra
+ \d*
+ \w
+ Ket
+ End
+------------------------------------------------------------------
+
+/\d*\W/BZ
+------------------------------------------------------------------
+ Bra
+ \d*+
+ \W
+ Ket
+ End
+------------------------------------------------------------------
+
+/\D*a/BZ
+------------------------------------------------------------------
+ Bra
+ \D*
+ a
+ Ket
+ End
+------------------------------------------------------------------
+
+/\D*2/BZ
+------------------------------------------------------------------
+ Bra
+ \D*+
+ 2
+ Ket
+ End
+------------------------------------------------------------------
+
+/\D*\d/BZ
+------------------------------------------------------------------
+ Bra
+ \D*+
+ \d
+ Ket
+ End
+------------------------------------------------------------------
+
+/\D*\D/BZ
+------------------------------------------------------------------
+ Bra
+ \D*
+ \D
+ Ket
+ End
+------------------------------------------------------------------
+
+/\D*\s/BZ
+------------------------------------------------------------------
+ Bra
+ \D*
+ \s
+ Ket
+ End
+------------------------------------------------------------------
+
+/\D*\S/BZ
+------------------------------------------------------------------
+ Bra
+ \D*
+ \S
+ Ket
+ End
+------------------------------------------------------------------
+
+/\D*\w/BZ
+------------------------------------------------------------------
+ Bra
+ \D*
+ \w
+ Ket
+ End
+------------------------------------------------------------------
+
+/\D*\W/BZ
+------------------------------------------------------------------
+ Bra
+ \D*
+ \W
+ Ket
+ End
+------------------------------------------------------------------
+
+/\s*a/BZ
+------------------------------------------------------------------
+ Bra
+ \s*+
+ a
+ Ket
+ End
+------------------------------------------------------------------
+
+/\s*2/BZ
+------------------------------------------------------------------
+ Bra
+ \s*+
+ 2
+ Ket
+ End
+------------------------------------------------------------------
+
+/\s*\d/BZ
+------------------------------------------------------------------
+ Bra
+ \s*+
+ \d
+ Ket
+ End
+------------------------------------------------------------------
+
+/\s*\D/BZ
+------------------------------------------------------------------
+ Bra
+ \s*
+ \D
+ Ket
+ End
+------------------------------------------------------------------
+
+/\s*\s/BZ
+------------------------------------------------------------------
+ Bra
+ \s*
+ \s
+ Ket
+ End
+------------------------------------------------------------------
+
+/\s*\S/BZ
+------------------------------------------------------------------
+ Bra
+ \s*+
+ \S
+ Ket
+ End
+------------------------------------------------------------------
+
+/\s*\w/BZ
+------------------------------------------------------------------
+ Bra
+ \s*+
+ \w
+ Ket
+ End
+------------------------------------------------------------------
+
+/\s*\W/BZ
+------------------------------------------------------------------
+ Bra
+ \s*
+ \W
+ Ket
+ End
+------------------------------------------------------------------
+
+/\S*a/BZ
+------------------------------------------------------------------
+ Bra
+ \S*
+ a
+ Ket
+ End
+------------------------------------------------------------------
+
+/\S*2/BZ
+------------------------------------------------------------------
+ Bra
+ \S*
+ 2
+ Ket
+ End
+------------------------------------------------------------------
+
+/\S*\d/BZ
+------------------------------------------------------------------
+ Bra
+ \S*
+ \d
+ Ket
+ End
+------------------------------------------------------------------
+
+/\S*\D/BZ
+------------------------------------------------------------------
+ Bra
+ \S*
+ \D
+ Ket
+ End
+------------------------------------------------------------------
+
+/\S*\s/BZ
+------------------------------------------------------------------
+ Bra
+ \S*+
+ \s
+ Ket
+ End
+------------------------------------------------------------------
+
+/\S*\S/BZ
+------------------------------------------------------------------
+ Bra
+ \S*
+ \S
+ Ket
+ End
+------------------------------------------------------------------
+
+/\S*\w/BZ
+------------------------------------------------------------------
+ Bra
+ \S*
+ \w
+ Ket
+ End
+------------------------------------------------------------------
+
+/\S*\W/BZ
+------------------------------------------------------------------
+ Bra
+ \S*
+ \W
+ Ket
+ End
+------------------------------------------------------------------
+
+/\w*a/BZ
+------------------------------------------------------------------
+ Bra
+ \w*
+ a
+ Ket
+ End
+------------------------------------------------------------------
+
+/\w*2/BZ
+------------------------------------------------------------------
+ Bra
+ \w*
+ 2
+ Ket
+ End
+------------------------------------------------------------------
+
+/\w*\d/BZ
+------------------------------------------------------------------
+ Bra
+ \w*
+ \d
+ Ket
+ End
+------------------------------------------------------------------
+
+/\w*\D/BZ
+------------------------------------------------------------------
+ Bra
+ \w*
+ \D
+ Ket
+ End
+------------------------------------------------------------------
+
+/\w*\s/BZ
+------------------------------------------------------------------
+ Bra
+ \w*+
+ \s
+ Ket
+ End
+------------------------------------------------------------------
+
+/\w*\S/BZ
+------------------------------------------------------------------
+ Bra
+ \w*
+ \S
+ Ket
+ End
+------------------------------------------------------------------
+
+/\w*\w/BZ
+------------------------------------------------------------------
+ Bra
+ \w*
+ \w
+ Ket
+ End
+------------------------------------------------------------------
+
+/\w*\W/BZ
+------------------------------------------------------------------
+ Bra
+ \w*+
+ \W
+ Ket
+ End
+------------------------------------------------------------------
+
+/\W*a/BZ
+------------------------------------------------------------------
+ Bra
+ \W*+
+ a
+ Ket
+ End
+------------------------------------------------------------------
+
+/\W*2/BZ
+------------------------------------------------------------------
+ Bra
+ \W*+
+ 2
+ Ket
+ End
+------------------------------------------------------------------
+
+/\W*\d/BZ
+------------------------------------------------------------------
+ Bra
+ \W*+
+ \d
+ Ket
+ End
+------------------------------------------------------------------
+
+/\W*\D/BZ
+------------------------------------------------------------------
+ Bra
+ \W*
+ \D
+ Ket
+ End
+------------------------------------------------------------------
+
+/\W*\s/BZ
+------------------------------------------------------------------
+ Bra
+ \W*
+ \s
+ Ket
+ End
+------------------------------------------------------------------
+
+/\W*\S/BZ
+------------------------------------------------------------------
+ Bra
+ \W*
+ \S
+ Ket
+ End
+------------------------------------------------------------------
+
+/\W*\w/BZ
+------------------------------------------------------------------
+ Bra
+ \W*+
+ \w
+ Ket
+ End
+------------------------------------------------------------------
+
+/\W*\W/BZ
+------------------------------------------------------------------
+ Bra
+ \W*
+ \W
+ Ket
+ End
+------------------------------------------------------------------
+
+/[^a]+a/BZ
+------------------------------------------------------------------
+ Bra
+ [^a]++
+ a
+ Ket
+ End
+------------------------------------------------------------------
+
+/[^a]+a/BZi
+------------------------------------------------------------------
+ Bra
+ [^A]++
+ NC a
+ Ket
+ End
+------------------------------------------------------------------
+
+/[^a]+A/BZi
+------------------------------------------------------------------
+ Bra
+ [^A]++
+ NC A
+ Ket
+ End
+------------------------------------------------------------------
+
+/[^a]+b/BZ
+------------------------------------------------------------------
+ Bra
+ [^a]+
+ b
+ Ket
+ End
+------------------------------------------------------------------
+
+/[^a]+\d/BZ
+------------------------------------------------------------------
+ Bra
+ [^a]+
+ \d
+ Ket
+ End
+------------------------------------------------------------------
+
+/a*[^a]/BZ
+------------------------------------------------------------------
+ Bra
+ a*
+ [^a]
+ Ket
+ End
+------------------------------------------------------------------
+
+/(?P<abc>x)(?P<xyz>y)/I
+Capturing subpattern count = 2
+Named capturing subpatterns:
+ abc 1
+ xyz 2
+No options
+First char = 'x'
+Need char = 'y'
+ xy\Cabc\Cxyz
+ 0: xy
+ 1: x
+ 2: y
+ C x (1) abc
+ C y (1) xyz
+
+/(?<abc>x)(?'xyz'y)/I
+Capturing subpattern count = 2
+Named capturing subpatterns:
+ abc 1
+ xyz 2
+No options
+First char = 'x'
+Need char = 'y'
+ xy\Cabc\Cxyz
+ 0: xy
+ 1: x
+ 2: y
+ C x (1) abc
+ C y (1) xyz
+
+/(?<abc'x)(?'xyz'y)/I
+Failed: syntax error in subpattern name (missing terminator) at offset 6
+
+/(?<abc>x)(?'xyz>y)/I
+Failed: syntax error in subpattern name (missing terminator) at offset 15
+
+/(?P'abc'x)(?P<xyz>y)/I
+Failed: unrecognized character after (?P at offset 3
+
+/^(?:(?(ZZ)a|b)(?<ZZ>X))+/
+ bXaX
+ 0: bXaX
+ 1: X
+ bXbX
+ 0: bX
+ 1: X
+ ** Failers
+No match
+ aXaX
+No match
+ aXbX
+No match
+
+/^(?P>abc)(?<abcd>xxx)/
+Failed: reference to non-existent subpattern at offset 8
+
+/^(?P>abc)(?<abc>x|y)/
+ xx
+ 0: xx
+ 1: x
+ xy
+ 0: xy
+ 1: y
+ yy
+ 0: yy
+ 1: y
+ yx
+ 0: yx
+ 1: x
+
+/^(?P>abc)(?P<abc>x|y)/
+ xx
+ 0: xx
+ 1: x
+ xy
+ 0: xy
+ 1: y
+ yy
+ 0: yy
+ 1: y
+ yx
+ 0: yx
+ 1: x
+
+/^((?(abc)a|b)(?<abc>x|y))+/
+ bxay
+ 0: bxay
+ 1: ay
+ 2: y
+ bxby
+ 0: bx
+ 1: bx
+ 2: x
+ ** Failers
+No match
+ axby
+No match
+
+/^(((?P=abc)|X)(?<abc>x|y))+/
+ XxXxxx
+ 0: XxXxxx
+ 1: xx
+ 2: x
+ 3: x
+ XxXyyx
+ 0: XxXyyx
+ 1: yx
+ 2: y
+ 3: x
+ XxXyxx
+ 0: XxXy
+ 1: Xy
+ 2: X
+ 3: y
+ ** Failers
+No match
+ x
+No match
+
+/^(?1)(abc)/
+ abcabc
+ 0: abcabc
+ 1: abc
+
+/^(?:(?:\1|X)(a|b))+/
+ Xaaa
+ 0: Xaaa
+ 1: a
+ Xaba
+ 0: Xa
+ 1: a
+
+/^[\E\Qa\E-\Qz\E]+/BZ
+------------------------------------------------------------------
+ Bra
+ ^
+ [a-z]+
+ Ket
+ End
+------------------------------------------------------------------
+
+/^[a\Q]bc\E]/BZ
+------------------------------------------------------------------
+ Bra
+ ^
+ [\]a-c]
+ Ket
+ End
+------------------------------------------------------------------
+
+/^[a-\Q\E]/BZ
+------------------------------------------------------------------
+ Bra
+ ^
+ [\-a]
+ Ket
+ End
+------------------------------------------------------------------
+
+/^(?P>abc)[()](?<abc>)/BZ
+------------------------------------------------------------------
+ Bra
+ ^
+ Once
+ Recurse
+ Ket
+ [()]
+ CBra 1
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+
+/^((?(abc)y)[()](?P<abc>x))+/BZ
+------------------------------------------------------------------
+ Bra
+ ^
+ CBra 1
+ Cond
+ 2 Cond ref
+ y
+ Ket
+ [()]
+ CBra 2
+ x
+ Ket
+ KetRmax
+ Ket
+ End
+------------------------------------------------------------------
+ (xy)x
+ 0: (xy)x
+ 1: y)x
+ 2: x
+
+/^(?P>abc)\Q()\E(?<abc>)/BZ
+------------------------------------------------------------------
+ Bra
+ ^
+ Once
+ Recurse
+ Ket
+ ()
+ CBra 1
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+
+/^(?P>abc)[a\Q(]\E(](?<abc>)/BZ
+------------------------------------------------------------------
+ Bra
+ ^
+ Once
+ Recurse
+ Ket
+ [(\]a]
+ CBra 1
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+
+/^(?P>abc) # this is (a comment)
+ (?<abc>)/BZx
+------------------------------------------------------------------
+ Bra
+ ^
+ Once
+ Recurse
+ Ket
+ CBra 1
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+
+/^\W*(?:(?<one>(?<two>.)\W*(?&one)\W*\k<two>|)|(?<three>(?<four>.)\W*(?&three)\W*\k'four'|\W*.\W*))\W*$/Ii
+Capturing subpattern count = 4
+Max back reference = 4
+Named capturing subpatterns:
+ four 4
+ one 1
+ three 3
+ two 2
+Partial matching not supported
+Options: anchored caseless
+No first char
+No need char
+ 1221
+ 0: 1221
+ 1: 1221
+ 2: 1
+ Satan, oscillate my metallic sonatas!
+ 0: Satan, oscillate my metallic sonatas!
+ 1: <unset>
+ 2: <unset>
+ 3: Satan, oscillate my metallic sonatas
+ 4: S
+ A man, a plan, a canal: Panama!
+ 0: A man, a plan, a canal: Panama!
+ 1: <unset>
+ 2: <unset>
+ 3: A man, a plan, a canal: Panama
+ 4: A
+ Able was I ere I saw Elba.
+ 0: Able was I ere I saw Elba.
+ 1: <unset>
+ 2: <unset>
+ 3: Able was I ere I saw Elba
+ 4: A
+ *** Failers
+No match
+ The quick brown fox
+No match
+
+/(?=(\w+))\1:/I
+Capturing subpattern count = 1
+Max back reference = 1
+Partial matching not supported
+No options
+No first char
+Need char = ':'
+ abcd:
+ 0: abcd:
+ 1: abcd
+
+/(?=(?'abc'\w+))\k<abc>:/I
+Capturing subpattern count = 1
+Max back reference = 1
+Named capturing subpatterns:
+ abc 1
+Partial matching not supported
+No options
+No first char
+Need char = ':'
+ abcd:
+ 0: abcd:
+ 1: abcd
+
+/(?'abc'\w+):\k<abc>{2}/
+ a:aaxyz
+ 0: a:aa
+ 1: a
+ ab:ababxyz
+ 0: ab:abab
+ 1: ab
+ ** Failers
+No match
+ a:axyz
+No match
+ ab:abxyz
+No match
+
+/(?'abc'a|b)(?<abc>d|e)\k<abc>{2}/J
+ adaa
+ 0: adaa
+ 1: a
+ 2: d
+ ** Failers
+No match
+ addd
+No match
+ adbb
+No match
+
+/(?'abc'a|b)(?<abc>d|e)(?&abc){2}/J
+ bdaa
+ 0: bdaa
+ 1: b
+ 2: d
+ bdab
+ 0: bdab
+ 1: b
+ 2: d
+ ** Failers
+No match
+ bddd
+No match
+
+/^(?<ab>a)? (?(<ab>)b|c) (?('ab')d|e)/x
+ abd
+ 0: abd
+ 1: a
+ ce
+ 0: ce
+
+/(?(<bc))/
+Failed: malformed number or name after (?( at offset 6
+
+/(?(''))/
+Failed: assertion expected after (?( at offset 4
+
+/(?('R')stuff)/
+Failed: reference to non-existent subpattern at offset 7
+
+/((abc (?(R) (?(R1)1) (?(R2)2) X | (?1) (?2) (?R) ))) /x
+ abcabc1Xabc2XabcXabcabc
+ 0: abcabc1Xabc2XabcX
+ 1: abcabc1Xabc2XabcX
+ 2: abcabc1Xabc2XabcX
+
+/(?<A> (?'B' abc (?(R) (?(R&A)1) (?(R&B)2) X | (?1) (?2) (?R) ))) /x
+ abcabc1Xabc2XabcXabcabc
+ 0: abcabc1Xabc2XabcX
+ 1: abcabc1Xabc2XabcX
+ 2: abcabc1Xabc2XabcX
+
+/(?<A> (?'B' abc (?(R) (?(R&1)1) (?(R&B)2) X | (?1) (?2) (?R) ))) /x
+Failed: reference to non-existent subpattern at offset 29
+
+/(?<1> (?'B' abc (?(R) (?(R&1)1) (?(R&B)2) X | (?1) (?2) (?R) ))) /x
+ abcabc1Xabc2XabcXabcabc
+ 0: abcabc1Xabc2XabcX
+ 1: abcabc1Xabc2XabcX
+ 2: abcabc1Xabc2XabcX
+
+/^(?(DEFINE) (?<A> a) (?<B> b) ) (?&A) (?&B) /x
+ abcd
+ 0: ab
+ 1: <unset>
+ 2: <unset>
+
+/(?<NAME>(?&NAME_PAT))\s+(?<ADDR>(?&ADDRESS_PAT))
+ (?(DEFINE)
+ (?<NAME_PAT>[a-z]+)
+ (?<ADDRESS_PAT>\d+)
+ )/x
+ metcalfe 33
+ 0: metcalfe 33
+ 1: metcalfe
+ 2: 33
+ 3: <unset>
+ 4: <unset>
+
+/^(?(DEFINE) abc | xyz ) /x
+Failed: DEFINE group contains more than one branch at offset 22
+
+/(?(DEFINE) abc) xyz/xI
+Capturing subpattern count = 0
+Options: extended
+First char = 'x'
+Need char = 'z'
+
+/(?(DEFINE) abc){3} xyz/x
+Failed: repeating a DEFINE group is not allowed at offset 17
+
+/(a|)*\d/
+ \O0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+No match
+ \O0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4
+Matched, but too many substrings
+
+/^a.b/<lf>
+ a\rb
+ 0: a\x0db
+ a\nb\<cr>
+ 0: a\x0ab
+ a\x85b\<anycrlf>
+ 0: a\x85b
+ ** Failers
+No match
+ a\nb
+No match
+ a\nb\<any>
+No match
+ a\rb\<cr>
+No match
+ a\rb\<any>
+No match
+ a\x85b\<any>
+No match
+ a\rb\<anycrlf>
+No match
+
+/^abc./mgx<any>
+ abc1 \x0aabc2 \x0babc3xx \x0cabc4 \x0dabc5xx \x0d\x0aabc6 \x85abc7 \x{2028}abc8 \x{2029}abc9 JUNK
+ 0: abc1
+ 0: abc2
+ 0: abc3
+ 0: abc4
+ 0: abc5
+ 0: abc6
+ 0: abc7
+
+/abc.$/mgx<any>
+ abc1\x0a abc2\x0b abc3\x0c abc4\x0d abc5\x0d\x0a abc6\x85 abc7\x{2028} abc8\x{2029} abc9
+ 0: abc1
+ 0: abc2
+ 0: abc3
+ 0: abc4
+ 0: abc5
+ 0: abc6
+ 0: abc9
+
+/a/<cr><any>
+
+/a/<any><crlf>
+Failed: inconsistent NEWLINE options at offset 0
+
+/^a\Rb/<bsr_unicode>
+ a\nb
+ 0: a\x0ab
+ a\rb
+ 0: a\x0db
+ a\r\nb
+ 0: a\x0d\x0ab
+ a\x0bb
+ 0: a\x0bb
+ a\x0cb
+ 0: a\x0cb
+ a\x85b
+ 0: a\x85b
+ ** Failers
+No match
+ a\n\rb
+No match
+
+/^a\R*b/<bsr_unicode>
+ ab
+ 0: ab
+ a\nb
+ 0: a\x0ab
+ a\rb
+ 0: a\x0db
+ a\r\nb
+ 0: a\x0d\x0ab
+ a\x0bb
+ 0: a\x0bb
+ a\x0cb
+ 0: a\x0cb
+ a\x85b
+ 0: a\x85b
+ a\n\rb
+ 0: a\x0a\x0db
+ a\n\r\x85\x0cb
+ 0: a\x0a\x0d\x85\x0cb
+
+/^a\R+b/<bsr_unicode>
+ a\nb
+ 0: a\x0ab
+ a\rb
+ 0: a\x0db
+ a\r\nb
+ 0: a\x0d\x0ab
+ a\x0bb
+ 0: a\x0bb
+ a\x0cb
+ 0: a\x0cb
+ a\x85b
+ 0: a\x85b
+ a\n\rb
+ 0: a\x0a\x0db
+ a\n\r\x85\x0cb
+ 0: a\x0a\x0d\x85\x0cb
+ ** Failers
+No match
+ ab
+No match
+
+/^a\R{1,3}b/<bsr_unicode>
+ a\nb
+ 0: a\x0ab
+ a\n\rb
+ 0: a\x0a\x0db
+ a\n\r\x85b
+ 0: a\x0a\x0d\x85b
+ a\r\n\r\nb
+ 0: a\x0d\x0a\x0d\x0ab
+ a\r\n\r\n\r\nb
+ 0: a\x0d\x0a\x0d\x0a\x0d\x0ab
+ a\n\r\n\rb
+ 0: a\x0a\x0d\x0a\x0db
+ a\n\n\r\nb
+ 0: a\x0a\x0a\x0d\x0ab
+ ** Failers
+No match
+ a\n\n\n\rb
+No match
+ a\r
+No match
+
+/^a[\R]b/<bsr_unicode>
+ aRb
+ 0: aRb
+ ** Failers
+No match
+ a\nb
+No match
+
+/(?&abc)X(?<abc>P)/I
+Capturing subpattern count = 1
+Named capturing subpatterns:
+ abc 1
+No options
+No first char
+Need char = 'P'
+ abcPXP123
+ 0: PXP
+ 1: P
+
+/(?1)X(?<abc>P)/I
+Capturing subpattern count = 1
+Named capturing subpatterns:
+ abc 1
+No options
+No first char
+Need char = 'P'
+ abcPXP123
+ 0: PXP
+ 1: P
+
+/(?(DEFINE)(?<byte>2[0-4]\d|25[0-5]|1\d\d|[1-9]?\d))\b(?&byte)(\.(?&byte)){3}/
+ 1.2.3.4
+ 0: 1.2.3.4
+ 1: <unset>
+ 2: .4
+ 131.111.10.206
+ 0: 131.111.10.206
+ 1: <unset>
+ 2: .206
+ 10.0.0.0
+ 0: 10.0.0.0
+ 1: <unset>
+ 2: .0
+ ** Failers
+No match
+ 10.6
+No match
+ 455.3.4.5
+No match
+
+/\b(?&byte)(\.(?&byte)){3}(?(DEFINE)(?<byte>2[0-4]\d|25[0-5]|1\d\d|[1-9]?\d))/
+ 1.2.3.4
+ 0: 1.2.3.4
+ 1: .4
+ 2: <unset>
+ 131.111.10.206
+ 0: 131.111.10.206
+ 1: .206
+ 2: <unset>
+ 10.0.0.0
+ 0: 10.0.0.0
+ 1: .0
+ 2: <unset>
+ ** Failers
+No match
+ 10.6
+No match
+ 455.3.4.5
+No match
+
+/(?:a(?&abc)b)*(?<abc>x)/
+ 123axbaxbaxbx456
+ 0: axbaxbaxbx
+ 1: x
+ 123axbaxbaxb456
+ 0: x
+ 1: x
+
+/(?:a(?&abc)b){1,5}(?<abc>x)/
+ 123axbaxbaxbx456
+ 0: axbaxbaxbx
+ 1: x
+
+/(?:a(?&abc)b){2,5}(?<abc>x)/
+ 123axbaxbaxbx456
+ 0: axbaxbaxbx
+ 1: x
+
+/(?:a(?&abc)b){2,}(?<abc>x)/
+ 123axbaxbaxbx456
+ 0: axbaxbaxbx
+ 1: x
+
+/(abc)(?i:(?1))/
+ defabcabcxyz
+ 0: abcabc
+ 1: abc
+ DEFabcABCXYZ
+No match
+
+/(abc)(?:(?i)(?1))/
+ defabcabcxyz
+ 0: abcabc
+ 1: abc
+ DEFabcABCXYZ
+No match
+
+/^(a(b))\1\g1\g{1}\g-1\g{-1}\g{-02}Z/
+ ababababbbabZXXXX
+ 0: ababababbbabZ
+ 1: ab
+ 2: b
+
+/^(a)\g-2/
+Failed: reference to non-existent subpattern at offset 7
+
+/^(a)\g/
+Failed: \g is not followed by a braced name or an optionally braced non-zero number at offset 5
+
+/^(a)\g{0}/
+Failed: \g is not followed by a braced name or an optionally braced non-zero number at offset 7
+
+/^(a)\g{3/
+Failed: \g is not followed by a braced name or an optionally braced non-zero number at offset 8
+
+/^(a)\g{4a}/
+Failed: reference to non-existent subpattern at offset 9
+
+/^a.b/<lf>
+ a\rb
+ 0: a\x0db
+ *** Failers
+No match
+ a\nb
+No match
+
+/.+foo/
+ afoo
+ 0: afoo
+ ** Failers
+No match
+ \r\nfoo
+No match
+ \nfoo
+No match
+
+/.+foo/<crlf>
+ afoo
+ 0: afoo
+ \nfoo
+ 0: \x0afoo
+ ** Failers
+No match
+ \r\nfoo
+No match
+
+/.+foo/<any>
+ afoo
+ 0: afoo
+ ** Failers
+No match
+ \nfoo
+No match
+ \r\nfoo
+No match
+
+/.+foo/s
+ afoo
+ 0: afoo
+ \r\nfoo
+ 0: \x0d\x0afoo
+ \nfoo
+ 0: \x0afoo
+
+/^$/mg<any>
+ abc\r\rxyz
+ 0:
+ abc\n\rxyz
+ 0:
+ ** Failers
+No match
+ abc\r\nxyz
+No match
+
+/(?m)^$/<any>g+
+ abc\r\n\r\n
+ 0:
+ 0+ \x0d\x0a
+
+/(?m)^$|^\r\n/<any>g+
+ abc\r\n\r\n
+ 0:
+ 0+ \x0d\x0a
+ 0: \x0d\x0a
+ 0+
+
+/(?m)$/<any>g+
+ abc\r\n\r\n
+ 0:
+ 0+ \x0d\x0a\x0d\x0a
+ 0:
+ 0+ \x0d\x0a
+ 0:
+ 0+
+
+/abc.$/mgx<anycrlf>
+ abc1\x0a abc2\x0b abc3\x0c abc4\x0d abc5\x0d\x0a abc6\x85 abc7\x{2028} abc8\x{2029} abc9
+ 0: abc1
+ 0: abc4
+ 0: abc5
+ 0: abc9
+
+/^X/m
+ XABC
+ 0: X
+ ** Failers
+No match
+ XABC\B
+No match
+
+/(ab|c)(?-1)/BZ
+------------------------------------------------------------------
+ Bra
+ CBra 1
+ ab
+ Alt
+ c
+ Ket
+ Once
+ Recurse
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+ abc
+ 0: abc
+ 1: ab
+
+/xy(?+1)(abc)/BZ
+------------------------------------------------------------------
+ Bra
+ xy
+ Once
+ Recurse
+ Ket
+ CBra 1
+ abc
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+ xyabcabc
+ 0: xyabcabc
+ 1: abc
+ ** Failers
+No match
+ xyabc
+No match
+
+/x(?-0)y/
+Failed: (?+ or (?- or (?(+ or (?(- must be followed by a non-zero number at offset 5
+
+/x(?-1)y/
+Failed: reference to non-existent subpattern at offset 5
+
+/x(?+0)y/
+Failed: (?+ or (?- or (?(+ or (?(- must be followed by a non-zero number at offset 5
+
+/x(?+1)y/
+Failed: reference to non-existent subpattern at offset 5
+
+/^(abc)?(?(-1)X|Y)/BZ
+------------------------------------------------------------------
+ Bra
+ ^
+ Brazero
+ CBra 1
+ abc
+ Ket
+ Cond
+ 1 Cond ref
+ X
+ Alt
+ Y
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+ abcX
+ 0: abcX
+ 1: abc
+ Y
+ 0: Y
+ ** Failers
+No match
+ abcY
+No match
+
+/^((?(+1)X|Y)(abc))+/BZ
+------------------------------------------------------------------
+ Bra
+ ^
+ CBra 1
+ Cond
+ 2 Cond ref
+ X
+ Alt
+ Y
+ Ket
+ CBra 2
+ abc
+ Ket
+ KetRmax
+ Ket
+ End
+------------------------------------------------------------------
+ YabcXabc
+ 0: YabcXabc
+ 1: Xabc
+ 2: abc
+ YabcXabcXabc
+ 0: YabcXabcXabc
+ 1: Xabc
+ 2: abc
+ ** Failers
+No match
+ XabcXabc
+No match
+
+/(?(-1)a)/BZ
+Failed: reference to non-existent subpattern at offset 6
+
+/((?(-1)a))/BZ
+------------------------------------------------------------------
+ Bra
+ CBra 1
+ Cond
+ 1 Cond ref
+ a
+ Ket
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+
+/((?(-2)a))/BZ
+Failed: reference to non-existent subpattern at offset 7
+
+/^(?(+1)X|Y)(.)/BZ
+------------------------------------------------------------------
+ Bra
+ ^
+ Cond
+ 1 Cond ref
+ X
+ Alt
+ Y
+ Ket
+ CBra 1
+ Any
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+ Y!
+ 0: Y!
+ 1: !
+
+/(foo)\Kbar/
+ foobar
+ 0: bar
+ 1: foo
+
+/(foo)(\Kbar|baz)/
+ foobar
+ 0: bar
+ 1: foo
+ 2: bar
+ foobaz
+ 0: foobaz
+ 1: foo
+ 2: baz
+
+/(foo\Kbar)baz/
+ foobarbaz
+ 0: barbaz
+ 1: foobar
+
+/(?<A>tom|bon)-\k{A}/
+ tom-tom
+ 0: tom-tom
+ 1: tom
+ bon-bon
+ 0: bon-bon
+ 1: bon
+ ** Failers
+No match
+ tom-bon
+No match
+
+/(?<A>tom|bon)-\g{A}/
+ tom-tom
+ 0: tom-tom
+ 1: tom
+ bon-bon
+ 0: bon-bon
+ 1: bon
+
+/\g{A/
+Failed: syntax error in subpattern name (missing terminator) at offset 4
+
+/(?|(abc)|(xyz))/BZ
+------------------------------------------------------------------
+ Bra
+ Bra
+ CBra 1
+ abc
+ Ket
+ Alt
+ CBra 1
+ xyz
+ Ket
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+ >abc<
+ 0: abc
+ 1: abc
+ >xyz<
+ 0: xyz
+ 1: xyz
+
+/(x)(?|(abc)|(xyz))(x)/BZ
+------------------------------------------------------------------
+ Bra
+ CBra 1
+ x
+ Ket
+ Bra
+ CBra 2
+ abc
+ Ket
+ Alt
+ CBra 2
+ xyz
+ Ket
+ Ket
+ CBra 3
+ x
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+ xabcx
+ 0: xabcx
+ 1: x
+ 2: abc
+ 3: x
+ xxyzx
+ 0: xxyzx
+ 1: x
+ 2: xyz
+ 3: x
+
+/(x)(?|(abc)(pqr)|(xyz))(x)/BZ
+------------------------------------------------------------------
+ Bra
+ CBra 1
+ x
+ Ket
+ Bra
+ CBra 2
+ abc
+ Ket
+ CBra 3
+ pqr
+ Ket
+ Alt
+ CBra 2
+ xyz
+ Ket
+ Ket
+ CBra 4
+ x
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+ xabcpqrx
+ 0: xabcpqrx
+ 1: x
+ 2: abc
+ 3: pqr
+ 4: x
+ xxyzx
+ 0: xxyzx
+ 1: x
+ 2: xyz
+ 3: <unset>
+ 4: x
+
+/(?|(abc)|(xyz))\1/
+ abcabc
+ 0: abcabc
+ 1: abc
+ xyzxyz
+ 0: xyzxyz
+ 1: xyz
+ ** Failers
+No match
+ abcxyz
+No match
+ xyzabc
+No match
+
+/(?|(abc)|(xyz))(?1)/
+ abcabc
+ 0: abcabc
+ 1: abc
+ xyzabc
+ 0: xyzabc
+ 1: xyz
+ ** Failers
+No match
+ xyzxyz
+No match
+
+/\H\h\V\v/
+ X X\x0a
+ 0: X X\x0a
+ X\x09X\x0b
+ 0: X\x09X\x0b
+ ** Failers
+No match
+ \xa0 X\x0a
+No match
+
+/\H*\h+\V?\v{3,4}/
+ \x09\x20\xa0X\x0a\x0b\x0c\x0d\x0a
+ 0: \x09 \xa0X\x0a\x0b\x0c\x0d
+ \x09\x20\xa0\x0a\x0b\x0c\x0d\x0a
+ 0: \x09 \xa0\x0a\x0b\x0c\x0d
+ \x09\x20\xa0\x0a\x0b\x0c
+ 0: \x09 \xa0\x0a\x0b\x0c
+ ** Failers
+No match
+ \x09\x20\xa0\x0a\x0b
+No match
+
+/\H{3,4}/
+ XY ABCDE
+ 0: ABCD
+ XY PQR ST
+ 0: PQR
+
+/.\h{3,4}./
+ XY AB PQRS
+ 0: B P
+
+/\h*X\h?\H+Y\H?Z/
+ >XNNNYZ
+ 0: XNNNYZ
+ > X NYQZ
+ 0: X NYQZ
+ ** Failers
+No match
+ >XYZ
+No match
+ > X NY Z
+No match
+
+/\v*X\v?Y\v+Z\V*\x0a\V+\x0b\V{2,3}\x0c/
+ >XY\x0aZ\x0aA\x0bNN\x0c
+ 0: XY\x0aZ\x0aA\x0bNN\x0c
+ >\x0a\x0dX\x0aY\x0a\x0bZZZ\x0aAAA\x0bNNN\x0c
+ 0: \x0a\x0dX\x0aY\x0a\x0bZZZ\x0aAAA\x0bNNN\x0c
+
+/[\h]/BZ
+------------------------------------------------------------------
+ Bra
+ [\x09 \xa0]
+ Ket
+ End
+------------------------------------------------------------------
+ >\x09<
+ 0: \x09
+
+/[\h]+/BZ
+------------------------------------------------------------------
+ Bra
+ [\x09 \xa0]+
+ Ket
+ End
+------------------------------------------------------------------
+ >\x09\x20\xa0<
+ 0: \x09 \xa0
+
+/[\v]/BZ
+------------------------------------------------------------------
+ Bra
+ [\x0a-\x0d\x85]
+ Ket
+ End
+------------------------------------------------------------------
+
+/[\H]/BZ
+------------------------------------------------------------------
+ Bra
+ [\x00-\x08\x0a-\x1f!-\x9f\xa1-\xff]
+ Ket
+ End
+------------------------------------------------------------------
+
+/[^\h]/BZ
+------------------------------------------------------------------
+ Bra
+ [\x00-\x08\x0a-\x1f!-\x9f\xa1-\xff] (neg)
+ Ket
+ End
+------------------------------------------------------------------
+
+/[\V]/BZ
+------------------------------------------------------------------
+ Bra
+ [\x00-\x09\x0e-\x84\x86-\xff]
+ Ket
+ End
+------------------------------------------------------------------
+
+/[\x0a\V]/BZ
+------------------------------------------------------------------
+ Bra
+ [\x00-\x0a\x0e-\x84\x86-\xff]
+ Ket
+ End
+------------------------------------------------------------------
+
+/\H++X/BZ
+------------------------------------------------------------------
+ Bra
+ \H++
+ X
+ Ket
+ End
+------------------------------------------------------------------
+ ** Failers
+No match
+ XXXX
+No match
+
+/\H+\hY/BZ
+------------------------------------------------------------------
+ Bra
+ \H++
+ \h
+ Y
+ Ket
+ End
+------------------------------------------------------------------
+ XXXX Y
+ 0: XXXX Y
+
+/\H+ Y/BZ
+------------------------------------------------------------------
+ Bra
+ \H++
+ Y
+ Ket
+ End
+------------------------------------------------------------------
+
+/\h+A/BZ
+------------------------------------------------------------------
+ Bra
+ \h++
+ A
+ Ket
+ End
+------------------------------------------------------------------
+
+/\v*B/BZ
+------------------------------------------------------------------
+ Bra
+ \v*+
+ B
+ Ket
+ End
+------------------------------------------------------------------
+
+/\V+\x0a/BZ
+------------------------------------------------------------------
+ Bra
+ \V++
+ \x0a
+ Ket
+ End
+------------------------------------------------------------------
+
+/A+\h/BZ
+------------------------------------------------------------------
+ Bra
+ A++
+ \h
+ Ket
+ End
+------------------------------------------------------------------
+
+/ *\H/BZ
+------------------------------------------------------------------
+ Bra
+ *+
+ \H
+ Ket
+ End
+------------------------------------------------------------------
+
+/A*\v/BZ
+------------------------------------------------------------------
+ Bra
+ A*+
+ \v
+ Ket
+ End
+------------------------------------------------------------------
+
+/\x0b*\V/BZ
+------------------------------------------------------------------
+ Bra
+ \x0b*+
+ \V
+ Ket
+ End
+------------------------------------------------------------------
+
+/\d+\h/BZ
+------------------------------------------------------------------
+ Bra
+ \d++
+ \h
+ Ket
+ End
+------------------------------------------------------------------
+
+/\d*\v/BZ
+------------------------------------------------------------------
+ Bra
+ \d*+
+ \v
+ Ket
+ End
+------------------------------------------------------------------
+
+/S+\h\S+\v/BZ
+------------------------------------------------------------------
+ Bra
+ S++
+ \h
+ \S++
+ \v
+ Ket
+ End
+------------------------------------------------------------------
+
+/\w{3,}\h\w+\v/BZ
+------------------------------------------------------------------
+ Bra
+ \w{3}
+ \w*+
+ \h
+ \w++
+ \v
+ Ket
+ End
+------------------------------------------------------------------
+
+/\h+\d\h+\w\h+\S\h+\H/BZ
+------------------------------------------------------------------
+ Bra
+ \h++
+ \d
+ \h++
+ \w
+ \h++
+ \S
+ \h++
+ \H
+ Ket
+ End
+------------------------------------------------------------------
+
+/\v+\d\v+\w\v+\S\v+\V/BZ
+------------------------------------------------------------------
+ Bra
+ \v++
+ \d
+ \v++
+ \w
+ \v+
+ \S
+ \v++
+ \V
+ Ket
+ End
+------------------------------------------------------------------
+
+/\H+\h\H+\d/BZ
+------------------------------------------------------------------
+ Bra
+ \H++
+ \h
+ \H+
+ \d
+ Ket
+ End
+------------------------------------------------------------------
+
+/\V+\v\V+\w/BZ
+------------------------------------------------------------------
+ Bra
+ \V++
+ \v
+ \V+
+ \w
+ Ket
+ End
+------------------------------------------------------------------
+
+/\( (?: [^()]* | (?R) )* \)/x
+(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(00)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)
+ 0: (0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(00)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)0)
+
+/[\E]AAA/
+Failed: missing terminating ] for character class at offset 7
+
+/[\Q\E]AAA/
+Failed: missing terminating ] for character class at offset 9
+
+/[^\E]AAA/
+Failed: missing terminating ] for character class at offset 8
+
+/[^\Q\E]AAA/
+Failed: missing terminating ] for character class at offset 10
+
+/[\E^]AAA/
+Failed: missing terminating ] for character class at offset 8
+
+/[\Q\E^]AAA/
+Failed: missing terminating ] for character class at offset 10
+
+/A(*PRUNE)B(*SKIP)C(*THEN)D(*COMMIT)E(*F)F(*FAIL)G(?!)H(*ACCEPT)I/BZ
+------------------------------------------------------------------
+ Bra
+ A
+ *PRUNE
+ B
+ *SKIP
+ C
+ *THEN
+ D
+ *COMMIT
+ E
+ *FAIL
+ F
+ *FAIL
+ G
+ *FAIL
+ H
+ *ACCEPT
+ I
+ Ket
+ End
+------------------------------------------------------------------
+
+/^a+(*FAIL)/
+ aaaaaa
+No match
+
+/a+b?c+(*FAIL)/
+ aaabccc
+No match
+
+/a+b?(*PRUNE)c+(*FAIL)/
+ aaabccc
+No match
+
+/a+b?(*COMMIT)c+(*FAIL)/
+ aaabccc
+No match
+
+/a+b?(*SKIP)c+(*FAIL)/
+ aaabcccaaabccc
+No match
+
+/^(?:aaa(*THEN)\w{6}|bbb(*THEN)\w{5}|ccc(*THEN)\w{4}|\w{3})/
+ aaaxxxxxx
+ 0: aaaxxxxxx
+ aaa++++++
+ 0: aaa
+ bbbxxxxx
+ 0: bbbxxxxx
+ bbb+++++
+ 0: bbb
+ cccxxxx
+ 0: cccxxxx
+ ccc++++
+ 0: ccc
+ dddddddd
+ 0: ddd
+
+/^(aaa(*THEN)\w{6}|bbb(*THEN)\w{5}|ccc(*THEN)\w{4}|\w{3})/
+ aaaxxxxxx
+ 0: aaaxxxxxx
+ 1: aaaxxxxxx
+ aaa++++++
+ 0: aaa
+ 1: aaa
+ bbbxxxxx
+ 0: bbbxxxxx
+ 1: bbbxxxxx
+ bbb+++++
+ 0: bbb
+ 1: bbb
+ cccxxxx
+ 0: cccxxxx
+ 1: cccxxxx
+ ccc++++
+ 0: ccc
+ 1: ccc
+ dddddddd
+ 0: ddd
+ 1: ddd
+
+/a+b?(*THEN)c+(*FAIL)/
+ aaabccc
+No match
+
+/(A (A|B(*ACCEPT)|C) D)(E)/x
+ ABX
+ 0: AB
+ AADE
+ 0: AADE
+ 1: AAD
+ 2: A
+ 3: E
+ ACDE
+ 0: ACDE
+ 1: ACD
+ 2: C
+ 3: E
+ ** Failers
+No match
+ AD
+No match
+
+/^a+(*FAIL)/C
+ aaaaaa
+--->aaaaaa
+ +0 ^ ^
+ +1 ^ a+
+ +3 ^ ^ (*FAIL)
+ +3 ^ ^ (*FAIL)
+ +3 ^ ^ (*FAIL)
+ +3 ^ ^ (*FAIL)
+ +3 ^ ^ (*FAIL)
+ +3 ^^ (*FAIL)
+No match
+
+/a+b?c+(*FAIL)/C
+ aaabccc
+--->aaabccc
+ +0 ^ a+
+ +2 ^ ^ b?
+ +4 ^ ^ c+
+ +6 ^ ^ (*FAIL)
+ +6 ^ ^ (*FAIL)
+ +6 ^ ^ (*FAIL)
+ +4 ^ ^ c+
+ +2 ^ ^ b?
+ +4 ^ ^ c+
+ +2 ^^ b?
+ +4 ^^ c+
+ +0 ^ a+
+ +2 ^ ^ b?
+ +4 ^ ^ c+
+ +6 ^ ^ (*FAIL)
+ +6 ^ ^ (*FAIL)
+ +6 ^ ^ (*FAIL)
+ +4 ^ ^ c+
+ +2 ^^ b?
+ +4 ^^ c+
+ +0 ^ a+
+ +2 ^^ b?
+ +4 ^ ^ c+
+ +6 ^ ^ (*FAIL)
+ +6 ^ ^ (*FAIL)
+ +6 ^ ^ (*FAIL)
+ +4 ^^ c+
+No match
+
+/a+b?(*PRUNE)c+(*FAIL)/C
+ aaabccc
+--->aaabccc
+ +0 ^ a+
+ +2 ^ ^ b?
+ +4 ^ ^ (*PRUNE)
++12 ^ ^ c+
++14 ^ ^ (*FAIL)
++14 ^ ^ (*FAIL)
++14 ^ ^ (*FAIL)
+ +0 ^ a+
+ +2 ^ ^ b?
+ +4 ^ ^ (*PRUNE)
++12 ^ ^ c+
++14 ^ ^ (*FAIL)
++14 ^ ^ (*FAIL)
++14 ^ ^ (*FAIL)
+ +0 ^ a+
+ +2 ^^ b?
+ +4 ^ ^ (*PRUNE)
++12 ^ ^ c+
++14 ^ ^ (*FAIL)
++14 ^ ^ (*FAIL)
++14 ^ ^ (*FAIL)
+No match
+
+/a+b?(*COMMIT)c+(*FAIL)/C
+ aaabccc
+--->aaabccc
+ +0 ^ a+
+ +2 ^ ^ b?
+ +4 ^ ^ (*COMMIT)
++13 ^ ^ c+
++15 ^ ^ (*FAIL)
++15 ^ ^ (*FAIL)
++15 ^ ^ (*FAIL)
+No match
+
+/a+b?(*SKIP)c+(*FAIL)/C
+ aaabcccaaabccc
+--->aaabcccaaabccc
+ +0 ^ a+
+ +2 ^ ^ b?
+ +4 ^ ^ (*SKIP)
++11 ^ ^ c+
++13 ^ ^ (*FAIL)
++13 ^ ^ (*FAIL)
++13 ^ ^ (*FAIL)
+ +0 ^ a+
+ +2 ^ ^ b?
+ +4 ^ ^ (*SKIP)
++11 ^ ^ c+
++13 ^ ^ (*FAIL)
++13 ^ ^ (*FAIL)
++13 ^ ^ (*FAIL)
+No match
+
+/a+b?(*THEN)c+(*FAIL)/C
+ aaabccc
+--->aaabccc
+ +0 ^ a+
+ +2 ^ ^ b?
+ +4 ^ ^ (*THEN)
++11 ^ ^ c+
++13 ^ ^ (*FAIL)
++13 ^ ^ (*FAIL)
++13 ^ ^ (*FAIL)
+ +0 ^ a+
+ +2 ^ ^ b?
+ +4 ^ ^ (*THEN)
++11 ^ ^ c+
++13 ^ ^ (*FAIL)
++13 ^ ^ (*FAIL)
++13 ^ ^ (*FAIL)
+ +0 ^ a+
+ +2 ^^ b?
+ +4 ^ ^ (*THEN)
++11 ^ ^ c+
++13 ^ ^ (*FAIL)
++13 ^ ^ (*FAIL)
++13 ^ ^ (*FAIL)
+No match
+
+/a(*PRUNE:XXX)b/
+Failed: (*VERB) with an argument is not supported at offset 8
+
+/a(*MARK)b/
+Failed: (*VERB) not recognized at offset 7
+
+/(?i:A{1,}\6666666666)/
+Failed: number is too big at offset 19
+
+/\g6666666666/
+Failed: number is too big at offset 11
+
+/[\g6666666666]/
+Failed: number is too big at offset 12
+
+/(?1)\c[/
+Failed: reference to non-existent subpattern at offset 3
+
+/.+A/<crlf>
+ \r\nA
+No match
+
+/\nA/<crlf>
+ \r\nA
+ 0: \x0aA
+
+/[\r\n]A/<crlf>
+ \r\nA
+ 0: \x0aA
+
+/(\r|\n)A/<crlf>
+ \r\nA
+ 0: \x0aA
+ 1: \x0a
+
+/a(*CR)b/
+Failed: (*VERB) not recognized at offset 5
+
+/(*CR)a.b/
+ a\nb
+ 0: a\x0ab
+ ** Failers
+No match
+ a\rb
+No match
+
+/(*CR)a.b/<lf>
+ a\nb
+ 0: a\x0ab
+ ** Failers
+No match
+ a\rb
+No match
+
+/(*LF)a.b/<CRLF>
+ a\rb
+ 0: a\x0db
+ ** Failers
+No match
+ a\nb
+No match
+
+/(*CRLF)a.b/
+ a\rb
+ 0: a\x0db
+ a\nb
+ 0: a\x0ab
+ ** Failers
+No match
+ a\r\nb
+No match
+
+/(*ANYCRLF)a.b/<CR>
+ ** Failers
+No match
+ a\rb
+No match
+ a\nb
+No match
+ a\r\nb
+No match
+
+/(*ANY)a.b/<cr>
+ ** Failers
+No match
+ a\rb
+No match
+ a\nb
+No match
+ a\r\nb
+No match
+ a\x85b
+No match
+
+/a\Rb/I<bsr_anycrlf>
+Capturing subpattern count = 0
+Options: bsr_anycrlf
+First char = 'a'
+Need char = 'b'
+ a\rb
+ 0: a\x0db
+ a\nb
+ 0: a\x0ab
+ a\r\nb
+ 0: a\x0d\x0ab
+ ** Failers
+No match
+ a\x85b
+No match
+ a\x0bb
+No match
+
+/a\Rb/I<bsr_unicode>
+Capturing subpattern count = 0
+Options: bsr_unicode
+First char = 'a'
+Need char = 'b'
+ a\rb
+ 0: a\x0db
+ a\nb
+ 0: a\x0ab
+ a\r\nb
+ 0: a\x0d\x0ab
+ a\x85b
+ 0: a\x85b
+ a\x0bb
+ 0: a\x0bb
+ ** Failers
+No match
+ a\x85b\<bsr_anycrlf>
+No match
+ a\x0bb\<bsr_anycrlf>
+No match
+
+/a\R?b/I<bsr_anycrlf>
+Capturing subpattern count = 0
+Options: bsr_anycrlf
+First char = 'a'
+Need char = 'b'
+ a\rb
+ 0: a\x0db
+ a\nb
+ 0: a\x0ab
+ a\r\nb
+ 0: a\x0d\x0ab
+ ** Failers
+No match
+ a\x85b
+No match
+ a\x0bb
+No match
+
+/a\R?b/I<bsr_unicode>
+Capturing subpattern count = 0
+Options: bsr_unicode
+First char = 'a'
+Need char = 'b'
+ a\rb
+ 0: a\x0db
+ a\nb
+ 0: a\x0ab
+ a\r\nb
+ 0: a\x0d\x0ab
+ a\x85b
+ 0: a\x85b
+ a\x0bb
+ 0: a\x0bb
+ ** Failers
+No match
+ a\x85b\<bsr_anycrlf>
+No match
+ a\x0bb\<bsr_anycrlf>
+No match
+
+/a\R{2,4}b/I<bsr_anycrlf>
+Capturing subpattern count = 0
+Partial matching not supported
+Options: bsr_anycrlf
+First char = 'a'
+Need char = 'b'
+ a\r\n\nb
+ 0: a\x0d\x0a\x0ab
+ a\n\r\rb
+ 0: a\x0a\x0d\x0db
+ a\r\n\r\n\r\n\r\nb
+ 0: a\x0d\x0a\x0d\x0a\x0d\x0a\x0d\x0ab
+ ** Failers
+No match
+ a\x85\85b
+No match
+ a\x0b\0bb
+No match
+
+/a\R{2,4}b/I<bsr_unicode>
+Capturing subpattern count = 0
+Partial matching not supported
+Options: bsr_unicode
+First char = 'a'
+Need char = 'b'
+ a\r\rb
+ 0: a\x0d\x0db
+ a\n\n\nb
+ 0: a\x0a\x0a\x0ab
+ a\r\n\n\r\rb
+ 0: a\x0d\x0a\x0a\x0d\x0db
+ a\x85\85b
+No match
+ a\x0b\0bb
+No match
+ ** Failers
+No match
+ a\r\r\r\r\rb
+No match
+ a\x85\85b\<bsr_anycrlf>
+No match
+ a\x0b\0bb\<bsr_anycrlf>
+No match
+
+/(*BSR_ANYCRLF)a\Rb/I
+Capturing subpattern count = 0
+Options: bsr_anycrlf
+First char = 'a'
+Need char = 'b'
+ a\nb
+ 0: a\x0ab
+ a\rb
+ 0: a\x0db
+
+/(*BSR_UNICODE)a\Rb/I
+Capturing subpattern count = 0
+Options: bsr_unicode
+First char = 'a'
+Need char = 'b'
+ a\x85b
+ 0: a\x85b
+
+/(*BSR_ANYCRLF)(*CRLF)a\Rb/I
+Capturing subpattern count = 0
+Options: bsr_anycrlf
+Forced newline sequence: CRLF
+First char = 'a'
+Need char = 'b'
+ a\nb
+ 0: a\x0ab
+ a\rb
+ 0: a\x0db
+
+/(*CRLF)(*BSR_UNICODE)a\Rb/I
+Capturing subpattern count = 0
+Options: bsr_unicode
+Forced newline sequence: CRLF
+First char = 'a'
+Need char = 'b'
+ a\x85b
+ 0: a\x85b
+
+/(*CRLF)(*BSR_ANYCRLF)(*CR)ab/I
+Capturing subpattern count = 0
+Options: bsr_anycrlf
+Forced newline sequence: CR
+First char = 'a'
+Need char = 'b'
+
+/(?<a>)(?&)/
+Failed: subpattern name expected at offset 9
+
+/(?<abc>)(?&a)/
+Failed: reference to non-existent subpattern at offset 12
+
+/(?<a>)(?&aaaaaaaaaaaaaaaaaaaaaaa)/
+Failed: reference to non-existent subpattern at offset 32
+
+/(?+-a)/
+Failed: digit expected after (?+ at offset 3
+
+/(?-+a)/
+Failed: unrecognized character after (? or (?- at offset 3
+
+/(?(-1))/
+Failed: reference to non-existent subpattern at offset 6
+
+/(?(+10))/
+Failed: reference to non-existent subpattern at offset 7
+
+/(?(10))/
+Failed: reference to non-existent subpattern at offset 6
+
+/(?(+2))()()/
+
+/(?(2))()()/
+
+/\k''/
+Failed: subpattern name expected at offset 3
+
+/\k<>/
+Failed: subpattern name expected at offset 3
+
+/\k{}/
+Failed: subpattern name expected at offset 3
+
+/(?P=)/
+Failed: subpattern name expected at offset 4
+
+/(?P>)/
+Failed: subpattern name expected at offset 4
+
+/(?!\w)(?R)/
+Failed: recursive call could loop indefinitely at offset 9
+
+/(?=\w)(?R)/
+Failed: recursive call could loop indefinitely at offset 9
+
+/(?<!\w)(?R)/
+Failed: recursive call could loop indefinitely at offset 10
+
+/(?<=\w)(?R)/
+Failed: recursive call could loop indefinitely at offset 10
+
+/[[:foo:]]/
+Failed: unknown POSIX class name at offset 3
+
+/[[:1234:]]/
+Failed: unknown POSIX class name at offset 3
+
+/[[:f\oo:]]/
+Failed: unknown POSIX class name at offset 3
+
+/[[: :]]/
+Failed: unknown POSIX class name at offset 3
+
+/[[:...:]]/
+Failed: unknown POSIX class name at offset 3
+
+/[[:l\ower:]]/
+Failed: unknown POSIX class name at offset 3
+
+/[[:abc\:]]/
+Failed: unknown POSIX class name at offset 3
+
+/[abc[:x\]pqr:]]/
+Failed: unknown POSIX class name at offset 6
+
+/[[:a\dz:]]/
+Failed: unknown POSIX class name at offset 3
+
+/ End of testinput2 /
diff --git a/lib/stdlib/test/re_SUITE_data/testoutput3 b/lib/stdlib/test/re_SUITE_data/testoutput3
new file mode 100644
index 0000000000..28b1c3aaaf
--- /dev/null
+++ b/lib/stdlib/test/re_SUITE_data/testoutput3
@@ -0,0 +1,163 @@
+/^[\w]+/
+ *** Failers
+No match
+ �cole
+No match
+
+/^[\w]+/Lfr_FR
+ �cole
+ 0: �cole
+
+/^[\w]+/
+ *** Failers
+No match
+ �cole
+No match
+
+/^[\W]+/
+ �cole
+ 0: \xc9
+
+/^[\W]+/Lfr_FR
+ *** Failers
+ 0: ***
+ �cole
+No match
+
+/[\b]/
+ \b
+ 0: \x08
+ *** Failers
+No match
+ a
+No match
+
+/[\b]/Lfr_FR
+ \b
+ 0: \x08
+ *** Failers
+No match
+ a
+No match
+
+/^\w+/
+ *** Failers
+No match
+ �cole
+No match
+
+/^\w+/Lfr_FR
+ �cole
+ 0: �cole
+
+/(.+)\b(.+)/
+ �cole
+ 0: \xc9cole
+ 1: \xc9
+ 2: cole
+
+/(.+)\b(.+)/Lfr_FR
+ *** Failers
+ 0: *** Failers
+ 1: ***
+ 2: Failers
+ �cole
+No match
+
+/�cole/i
+ �cole
+ 0: \xc9cole
+ *** Failers
+No match
+ �cole
+No match
+
+/�cole/iLfr_FR
+ �cole
+ 0: �cole
+ �cole
+ 0: �cole
+
+/\w/IS
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+Starting byte set: 0 1 2 3 4 5 6 7 8 9 A B C D E F G H I J K L M N O P
+ Q R S T U V W X Y Z _ a b c d e f g h i j k l m n o p q r s t u v w x y z
+
+/\w/ISLfr_FR
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+Starting byte set: 0 1 2 3 4 5 6 7 8 9 A B C D E F G H I J K L M N O P
+ Q R S T U V W X Y Z _ a b c d e f g h i j k l m n o p q r s t u v w x y z
+ � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � �
+ � � � � � � � � � � � � � � � � � � � � � � � � � � � �
+
+/^[\xc8-\xc9]/iLfr_FR
+ �cole
+ 0: �
+ �cole
+ 0: �
+
+/^[\xc8-\xc9]/Lfr_FR
+ �cole
+ 0: �
+ *** Failers
+No match
+ �cole
+No match
+
+/\W+/Lfr_FR
+ >>>\xaa<<<
+ 0: >>>
+ >>>\xba<<<
+ 0: >>>
+
+/[\W]+/Lfr_FR
+ >>>\xaa<<<
+ 0: >>>
+ >>>\xba<<<
+ 0: >>>
+
+/[^[:alpha:]]+/Lfr_FR
+ >>>\xaa<<<
+ 0: >>>
+ >>>\xba<<<
+ 0: >>>
+
+/\w+/Lfr_FR
+ >>>\xaa<<<
+ 0: �
+ >>>\xba<<<
+ 0: �
+
+/[\w]+/Lfr_FR
+ >>>\xaa<<<
+ 0: �
+ >>>\xba<<<
+ 0: �
+
+/[[:alpha:]]+/Lfr_FR
+ >>>\xaa<<<
+ 0: �
+ >>>\xba<<<
+ 0: �
+
+/[[:alpha:]][[:lower:]][[:upper:]]/DZLfr_FR
+------------------------------------------------------------------
+ Bra
+ [A-Za-z\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\xff]
+ [a-z\xb5\xdf-\xf6\xf8-\xff]
+ [A-Z\xc0-\xd6\xd8-\xde]
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+
+/ End of testinput3 /
diff --git a/lib/stdlib/test/re_SUITE_data/testoutput4 b/lib/stdlib/test/re_SUITE_data/testoutput4
new file mode 100644
index 0000000000..d87ea4bcc4
--- /dev/null
+++ b/lib/stdlib/test/re_SUITE_data/testoutput4
@@ -0,0 +1,1074 @@
+/-- Do not use the \x{} construct except with patterns that have the --/
+/-- /8 option set, because PCRE doesn't recognize them as UTF-8 unless --/
+No match
+/-- that option is set. However, the latest Perls recognize them always. --/
+No match
+
+/a.b/8
+ acb
+ 0: acb
+ a\x7fb
+ 0: a\x{7f}b
+ a\x{100}b
+ 0: a\x{100}b
+ *** Failers
+No match
+ a\nb
+No match
+
+/a(.{3})b/8
+ a\x{4000}xyb
+ 0: a\x{4000}xyb
+ 1: \x{4000}xy
+ a\x{4000}\x7fyb
+ 0: a\x{4000}\x{7f}yb
+ 1: \x{4000}\x{7f}y
+ a\x{4000}\x{100}yb
+ 0: a\x{4000}\x{100}yb
+ 1: \x{4000}\x{100}y
+ *** Failers
+No match
+ a\x{4000}b
+No match
+ ac\ncb
+No match
+
+/a(.*?)(.)/
+ a\xc0\x88b
+ 0: a\xc0
+ 1:
+ 2: \xc0
+
+/a(.*?)(.)/8
+ a\x{100}b
+ 0: a\x{100}
+ 1:
+ 2: \x{100}
+
+/a(.*)(.)/
+ a\xc0\x88b
+ 0: a\xc0\x88b
+ 1: \xc0\x88
+ 2: b
+
+/a(.*)(.)/8
+ a\x{100}b
+ 0: a\x{100}b
+ 1: \x{100}
+ 2: b
+
+/a(.)(.)/
+ a\xc0\x92bcd
+ 0: a\xc0\x92
+ 1: \xc0
+ 2: \x92
+
+/a(.)(.)/8
+ a\x{240}bcd
+ 0: a\x{240}b
+ 1: \x{240}
+ 2: b
+
+/a(.?)(.)/
+ a\xc0\x92bcd
+ 0: a\xc0\x92
+ 1: \xc0
+ 2: \x92
+
+/a(.?)(.)/8
+ a\x{240}bcd
+ 0: a\x{240}b
+ 1: \x{240}
+ 2: b
+
+/a(.??)(.)/
+ a\xc0\x92bcd
+ 0: a\xc0
+ 1:
+ 2: \xc0
+
+/a(.??)(.)/8
+ a\x{240}bcd
+ 0: a\x{240}
+ 1:
+ 2: \x{240}
+
+/a(.{3})b/8
+ a\x{1234}xyb
+ 0: a\x{1234}xyb
+ 1: \x{1234}xy
+ a\x{1234}\x{4321}yb
+ 0: a\x{1234}\x{4321}yb
+ 1: \x{1234}\x{4321}y
+ a\x{1234}\x{4321}\x{3412}b
+ 0: a\x{1234}\x{4321}\x{3412}b
+ 1: \x{1234}\x{4321}\x{3412}
+ *** Failers
+No match
+ a\x{1234}b
+No match
+ ac\ncb
+No match
+
+/a(.{3,})b/8
+ a\x{1234}xyb
+ 0: a\x{1234}xyb
+ 1: \x{1234}xy
+ a\x{1234}\x{4321}yb
+ 0: a\x{1234}\x{4321}yb
+ 1: \x{1234}\x{4321}y
+ a\x{1234}\x{4321}\x{3412}b
+ 0: a\x{1234}\x{4321}\x{3412}b
+ 1: \x{1234}\x{4321}\x{3412}
+ axxxxbcdefghijb
+ 0: axxxxbcdefghijb
+ 1: xxxxbcdefghij
+ a\x{1234}\x{4321}\x{3412}\x{3421}b
+ 0: a\x{1234}\x{4321}\x{3412}\x{3421}b
+ 1: \x{1234}\x{4321}\x{3412}\x{3421}
+ *** Failers
+No match
+ a\x{1234}b
+No match
+
+/a(.{3,}?)b/8
+ a\x{1234}xyb
+ 0: a\x{1234}xyb
+ 1: \x{1234}xy
+ a\x{1234}\x{4321}yb
+ 0: a\x{1234}\x{4321}yb
+ 1: \x{1234}\x{4321}y
+ a\x{1234}\x{4321}\x{3412}b
+ 0: a\x{1234}\x{4321}\x{3412}b
+ 1: \x{1234}\x{4321}\x{3412}
+ axxxxbcdefghijb
+ 0: axxxxb
+ 1: xxxx
+ a\x{1234}\x{4321}\x{3412}\x{3421}b
+ 0: a\x{1234}\x{4321}\x{3412}\x{3421}b
+ 1: \x{1234}\x{4321}\x{3412}\x{3421}
+ *** Failers
+No match
+ a\x{1234}b
+No match
+
+/a(.{3,5})b/8
+ a\x{1234}xyb
+ 0: a\x{1234}xyb
+ 1: \x{1234}xy
+ a\x{1234}\x{4321}yb
+ 0: a\x{1234}\x{4321}yb
+ 1: \x{1234}\x{4321}y
+ a\x{1234}\x{4321}\x{3412}b
+ 0: a\x{1234}\x{4321}\x{3412}b
+ 1: \x{1234}\x{4321}\x{3412}
+ axxxxbcdefghijb
+ 0: axxxxb
+ 1: xxxx
+ a\x{1234}\x{4321}\x{3412}\x{3421}b
+ 0: a\x{1234}\x{4321}\x{3412}\x{3421}b
+ 1: \x{1234}\x{4321}\x{3412}\x{3421}
+ axbxxbcdefghijb
+ 0: axbxxb
+ 1: xbxx
+ axxxxxbcdefghijb
+ 0: axxxxxb
+ 1: xxxxx
+ *** Failers
+No match
+ a\x{1234}b
+No match
+ axxxxxxbcdefghijb
+No match
+
+/a(.{3,5}?)b/8
+ a\x{1234}xyb
+ 0: a\x{1234}xyb
+ 1: \x{1234}xy
+ a\x{1234}\x{4321}yb
+ 0: a\x{1234}\x{4321}yb
+ 1: \x{1234}\x{4321}y
+ a\x{1234}\x{4321}\x{3412}b
+ 0: a\x{1234}\x{4321}\x{3412}b
+ 1: \x{1234}\x{4321}\x{3412}
+ axxxxbcdefghijb
+ 0: axxxxb
+ 1: xxxx
+ a\x{1234}\x{4321}\x{3412}\x{3421}b
+ 0: a\x{1234}\x{4321}\x{3412}\x{3421}b
+ 1: \x{1234}\x{4321}\x{3412}\x{3421}
+ axbxxbcdefghijb
+ 0: axbxxb
+ 1: xbxx
+ axxxxxbcdefghijb
+ 0: axxxxxb
+ 1: xxxxx
+ *** Failers
+No match
+ a\x{1234}b
+No match
+ axxxxxxbcdefghijb
+No match
+
+/^[a\x{c0}]/8
+ *** Failers
+No match
+ \x{100}
+No match
+
+/(?<=aXb)cd/8
+ aXbcd
+ 0: cd
+
+/(?<=a\x{100}b)cd/8
+ a\x{100}bcd
+ 0: cd
+
+/(?<=a\x{100000}b)cd/8
+ a\x{100000}bcd
+ 0: cd
+
+/(?:\x{100}){3}b/8
+ \x{100}\x{100}\x{100}b
+ 0: \x{100}\x{100}\x{100}b
+ *** Failers
+No match
+ \x{100}\x{100}b
+No match
+
+/\x{ab}/8
+ \x{ab}
+ 0: \x{ab}
+ \xc2\xab
+ 0: \x{ab}
+ *** Failers
+No match
+ \x00{ab}
+No match
+
+/(?<=(.))X/8
+ WXYZ
+ 0: X
+ 1: W
+ \x{256}XYZ
+ 0: X
+ 1: \x{256}
+ *** Failers
+No match
+ XYZ
+No match
+
+/X(\C{3})/8
+ X\x{1234}
+ 0: X\x{1234}
+ 1: \x{1234}
+
+/X(\C{4})/8
+ X\x{1234}YZ
+ 0: X\x{1234}Y
+ 1: \x{1234}Y
+
+/X\C*/8
+ XYZabcdce
+ 0: XYZabcdce
+
+/X\C*?/8
+ XYZabcde
+ 0: X
+
+/X\C{3,5}/8
+ Xabcdefg
+ 0: Xabcde
+ X\x{1234}
+ 0: X\x{1234}
+ X\x{1234}YZ
+ 0: X\x{1234}YZ
+ X\x{1234}\x{512}
+ 0: X\x{1234}\x{512}
+ X\x{1234}\x{512}YZ
+ 0: X\x{1234}\x{512}
+
+/X\C{3,5}?/8
+ Xabcdefg
+ 0: Xabc
+ X\x{1234}
+ 0: X\x{1234}
+ X\x{1234}YZ
+ 0: X\x{1234}
+ X\x{1234}\x{512}
+ 0: X\x{1234}
+
+/[^a]+/8g
+ bcd
+ 0: bcd
+ \x{100}aY\x{256}Z
+ 0: \x{100}
+ 0: Y\x{256}Z
+
+/^[^a]{2}/8
+ \x{100}bc
+ 0: \x{100}b
+
+/^[^a]{2,}/8
+ \x{100}bcAa
+ 0: \x{100}bcA
+
+/^[^a]{2,}?/8
+ \x{100}bca
+ 0: \x{100}b
+
+/[^a]+/8ig
+ bcd
+ 0: bcd
+ \x{100}aY\x{256}Z
+ 0: \x{100}
+ 0: Y\x{256}Z
+
+/^[^a]{2}/8i
+ \x{100}bc
+ 0: \x{100}b
+
+/^[^a]{2,}/8i
+ \x{100}bcAa
+ 0: \x{100}bc
+
+/^[^a]{2,}?/8i
+ \x{100}bca
+ 0: \x{100}b
+
+/\x{100}{0,0}/8
+ abcd
+ 0:
+
+/\x{100}?/8
+ abcd
+ 0:
+ \x{100}\x{100}
+ 0: \x{100}
+
+/\x{100}{0,3}/8
+ \x{100}\x{100}
+ 0: \x{100}\x{100}
+ \x{100}\x{100}\x{100}\x{100}
+ 0: \x{100}\x{100}\x{100}
+
+/\x{100}*/8
+ abce
+ 0:
+ \x{100}\x{100}\x{100}\x{100}
+ 0: \x{100}\x{100}\x{100}\x{100}
+
+/\x{100}{1,1}/8
+ abcd\x{100}\x{100}\x{100}\x{100}
+ 0: \x{100}
+
+/\x{100}{1,3}/8
+ abcd\x{100}\x{100}\x{100}\x{100}
+ 0: \x{100}\x{100}\x{100}
+
+/\x{100}+/8
+ abcd\x{100}\x{100}\x{100}\x{100}
+ 0: \x{100}\x{100}\x{100}\x{100}
+
+/\x{100}{3}/8
+ abcd\x{100}\x{100}\x{100}XX
+ 0: \x{100}\x{100}\x{100}
+
+/\x{100}{3,5}/8
+ abcd\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}XX
+ 0: \x{100}\x{100}\x{100}\x{100}\x{100}
+
+/\x{100}{3,}/8
+ abcd\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}XX
+ 0: \x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}
+
+/(?<=a\x{100}{2}b)X/8+
+ Xyyya\x{100}\x{100}bXzzz
+ 0: X
+ 0+ zzz
+
+/\D*/8
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 0: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+
+/\D*/8
+ \x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}
+ 0: \x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}
+
+/\D/8
+ 1X2
+ 0: X
+ 1\x{100}2
+ 0: \x{100}
+
+/>\S/8
+ > >X Y
+ 0: >X
+ > >\x{100} Y
+ 0: >\x{100}
+
+/\d/8
+ \x{100}3
+ 0: 3
+
+/\s/8
+ \x{100} X
+ 0:
+
+/\D+/8
+ 12abcd34
+ 0: abcd
+ *** Failers
+ 0: *** Failers
+ 1234
+No match
+
+/\D{2,3}/8
+ 12abcd34
+ 0: abc
+ 12ab34
+ 0: ab
+ *** Failers
+ 0: ***
+ 1234
+No match
+ 12a34
+No match
+
+/\D{2,3}?/8
+ 12abcd34
+ 0: ab
+ 12ab34
+ 0: ab
+ *** Failers
+ 0: **
+ 1234
+No match
+ 12a34
+No match
+
+/\d+/8
+ 12abcd34
+ 0: 12
+ *** Failers
+No match
+
+/\d{2,3}/8
+ 12abcd34
+ 0: 12
+ 1234abcd
+ 0: 123
+ *** Failers
+No match
+ 1.4
+No match
+
+/\d{2,3}?/8
+ 12abcd34
+ 0: 12
+ 1234abcd
+ 0: 12
+ *** Failers
+No match
+ 1.4
+No match
+
+/\S+/8
+ 12abcd34
+ 0: 12abcd34
+ *** Failers
+ 0: ***
+ \ \
+No match
+
+/\S{2,3}/8
+ 12abcd34
+ 0: 12a
+ 1234abcd
+ 0: 123
+ *** Failers
+ 0: ***
+ \ \
+No match
+
+/\S{2,3}?/8
+ 12abcd34
+ 0: 12
+ 1234abcd
+ 0: 12
+ *** Failers
+ 0: **
+ \ \
+No match
+
+/>\s+</8+
+ 12> <34
+ 0: > <
+ 0+ 34
+ *** Failers
+No match
+
+/>\s{2,3}</8+
+ ab> <cd
+ 0: > <
+ 0+ cd
+ ab> <ce
+ 0: > <
+ 0+ ce
+ *** Failers
+No match
+ ab> <cd
+No match
+
+/>\s{2,3}?</8+
+ ab> <cd
+ 0: > <
+ 0+ cd
+ ab> <ce
+ 0: > <
+ 0+ ce
+ *** Failers
+No match
+ ab> <cd
+No match
+
+/\w+/8
+ 12 34
+ 0: 12
+ *** Failers
+ 0: Failers
+ +++=*!
+No match
+
+/\w{2,3}/8
+ ab cd
+ 0: ab
+ abcd ce
+ 0: abc
+ *** Failers
+ 0: Fai
+ a.b.c
+No match
+
+/\w{2,3}?/8
+ ab cd
+ 0: ab
+ abcd ce
+ 0: ab
+ *** Failers
+ 0: Fa
+ a.b.c
+No match
+
+/\W+/8
+ 12====34
+ 0: ====
+ *** Failers
+ 0: ***
+ abcd
+No match
+
+/\W{2,3}/8
+ ab====cd
+ 0: ===
+ ab==cd
+ 0: ==
+ *** Failers
+ 0: ***
+ a.b.c
+No match
+
+/\W{2,3}?/8
+ ab====cd
+ 0: ==
+ ab==cd
+ 0: ==
+ *** Failers
+ 0: **
+ a.b.c
+No match
+
+/[\x{100}]/8
+ \x{100}
+ 0: \x{100}
+ Z\x{100}
+ 0: \x{100}
+ \x{100}Z
+ 0: \x{100}
+ *** Failers
+No match
+
+/[Z\x{100}]/8
+ Z\x{100}
+ 0: Z
+ \x{100}
+ 0: \x{100}
+ \x{100}Z
+ 0: \x{100}
+ *** Failers
+No match
+
+/[\x{100}\x{200}]/8
+ ab\x{100}cd
+ 0: \x{100}
+ ab\x{200}cd
+ 0: \x{200}
+ *** Failers
+No match
+
+/[\x{100}-\x{200}]/8
+ ab\x{100}cd
+ 0: \x{100}
+ ab\x{200}cd
+ 0: \x{200}
+ ab\x{111}cd
+ 0: \x{111}
+ *** Failers
+No match
+
+/[z-\x{200}]/8
+ ab\x{100}cd
+ 0: \x{100}
+ ab\x{200}cd
+ 0: \x{200}
+ ab\x{111}cd
+ 0: \x{111}
+ abzcd
+ 0: z
+ ab|cd
+ 0: |
+ *** Failers
+No match
+
+/[Q\x{100}\x{200}]/8
+ ab\x{100}cd
+ 0: \x{100}
+ ab\x{200}cd
+ 0: \x{200}
+ Q?
+ 0: Q
+ *** Failers
+No match
+
+/[Q\x{100}-\x{200}]/8
+ ab\x{100}cd
+ 0: \x{100}
+ ab\x{200}cd
+ 0: \x{200}
+ ab\x{111}cd
+ 0: \x{111}
+ Q?
+ 0: Q
+ *** Failers
+No match
+
+/[Qz-\x{200}]/8
+ ab\x{100}cd
+ 0: \x{100}
+ ab\x{200}cd
+ 0: \x{200}
+ ab\x{111}cd
+ 0: \x{111}
+ abzcd
+ 0: z
+ ab|cd
+ 0: |
+ Q?
+ 0: Q
+ *** Failers
+No match
+
+/[\x{100}\x{200}]{1,3}/8
+ ab\x{100}cd
+ 0: \x{100}
+ ab\x{200}cd
+ 0: \x{200}
+ ab\x{200}\x{100}\x{200}\x{100}cd
+ 0: \x{200}\x{100}\x{200}
+ *** Failers
+No match
+
+/[\x{100}\x{200}]{1,3}?/8
+ ab\x{100}cd
+ 0: \x{100}
+ ab\x{200}cd
+ 0: \x{200}
+ ab\x{200}\x{100}\x{200}\x{100}cd
+ 0: \x{200}
+ *** Failers
+No match
+
+/[Q\x{100}\x{200}]{1,3}/8
+ ab\x{100}cd
+ 0: \x{100}
+ ab\x{200}cd
+ 0: \x{200}
+ ab\x{200}\x{100}\x{200}\x{100}cd
+ 0: \x{200}\x{100}\x{200}
+ *** Failers
+No match
+
+/[Q\x{100}\x{200}]{1,3}?/8
+ ab\x{100}cd
+ 0: \x{100}
+ ab\x{200}cd
+ 0: \x{200}
+ ab\x{200}\x{100}\x{200}\x{100}cd
+ 0: \x{200}
+ *** Failers
+No match
+
+/(?<=[\x{100}\x{200}])X/8
+ abc\x{200}X
+ 0: X
+ abc\x{100}X
+ 0: X
+ *** Failers
+No match
+ X
+No match
+
+/(?<=[Q\x{100}\x{200}])X/8
+ abc\x{200}X
+ 0: X
+ abc\x{100}X
+ 0: X
+ abQX
+ 0: X
+ *** Failers
+No match
+ X
+No match
+
+/(?<=[\x{100}\x{200}]{3})X/8
+ abc\x{100}\x{200}\x{100}X
+ 0: X
+ *** Failers
+No match
+ abc\x{200}X
+No match
+ X
+No match
+
+/[^\x{100}\x{200}]X/8
+ AX
+ 0: AX
+ \x{150}X
+ 0: \x{150}X
+ \x{500}X
+ 0: \x{500}X
+ *** Failers
+No match
+ \x{100}X
+No match
+ \x{200}X
+No match
+
+/[^Q\x{100}\x{200}]X/8
+ AX
+ 0: AX
+ \x{150}X
+ 0: \x{150}X
+ \x{500}X
+ 0: \x{500}X
+ *** Failers
+No match
+ \x{100}X
+No match
+ \x{200}X
+No match
+ QX
+No match
+
+/[^\x{100}-\x{200}]X/8
+ AX
+ 0: AX
+ \x{500}X
+ 0: \x{500}X
+ *** Failers
+No match
+ \x{100}X
+No match
+ \x{150}X
+No match
+ \x{200}X
+No match
+
+/a\Cb/
+ aXb
+ 0: aXb
+ a\nb
+ 0: a\x0ab
+
+/a\Cb/8
+ aXb
+ 0: aXb
+ a\nb
+ 0: a\x{0a}b
+ *** Failers
+No match
+ a\x{100}b
+No match
+
+/[z-\x{100}]/8i
+ z
+ 0: z
+ Z
+ 0: Z
+ \x{100}
+ 0: \x{100}
+ *** Failers
+No match
+ \x{102}
+No match
+ y
+No match
+
+/[\xFF]/
+ >\xff<
+ 0: \xff
+
+/[\xff]/8
+ >\x{ff}<
+ 0: \x{ff}
+
+/[^\xFF]/
+ XYZ
+ 0: X
+
+/[^\xff]/8
+ XYZ
+ 0: X
+ \x{123}
+ 0: \x{123}
+
+/^[ac]*b/8
+ xb
+No match
+
+/^[ac\x{100}]*b/8
+ xb
+No match
+
+/^[^x]*b/8i
+ xb
+No match
+
+/^[^x]*b/8
+ xb
+No match
+
+/^\d*b/8
+ xb
+No match
+
+/(|a)/g8
+ catac
+ 0:
+ 1:
+ 0:
+ 1:
+ 0: a
+ 1: a
+ 0:
+ 1:
+ 0:
+ 1:
+ 0: a
+ 1: a
+ 0:
+ 1:
+ 0:
+ 1:
+ a\x{256}a
+ 0:
+ 1:
+ 0: a
+ 1: a
+ 0:
+ 1:
+ 0:
+ 1:
+ 0: a
+ 1: a
+ 0:
+ 1:
+
+/^\x{85}$/8i
+ \x{85}
+ 0: \x{85}
+
+/^ሴ/8
+ ሴ
+ 0: \x{1234}
+
+/^\ሴ/8
+ ሴ
+ 0: \x{1234}
+
+"(?s)(.{1,5})"8
+ abcdefg
+ 0: abcde
+ 1: abcde
+ ab
+ 0: ab
+ 1: ab
+
+/a*\x{100}*\w/8
+ a
+ 0: a
+
+/\S\S/8g
+ A\x{a3}BC
+ 0: A\x{a3}
+ 0: BC
+
+/\S{2}/8g
+ A\x{a3}BC
+ 0: A\x{a3}
+ 0: BC
+
+/\W\W/8g
+ +\x{a3}==
+ 0: +\x{a3}
+ 0: ==
+
+/\W{2}/8g
+ +\x{a3}==
+ 0: +\x{a3}
+ 0: ==
+
+/\S/8g
+ \x{442}\x{435}\x{441}\x{442}
+ 0: \x{442}
+ 0: \x{435}
+ 0: \x{441}
+ 0: \x{442}
+
+/[\S]/8g
+ \x{442}\x{435}\x{441}\x{442}
+ 0: \x{442}
+ 0: \x{435}
+ 0: \x{441}
+ 0: \x{442}
+
+/\D/8g
+ \x{442}\x{435}\x{441}\x{442}
+ 0: \x{442}
+ 0: \x{435}
+ 0: \x{441}
+ 0: \x{442}
+
+/[\D]/8g
+ \x{442}\x{435}\x{441}\x{442}
+ 0: \x{442}
+ 0: \x{435}
+ 0: \x{441}
+ 0: \x{442}
+
+/\W/8g
+ \x{2442}\x{2435}\x{2441}\x{2442}
+ 0: \x{2442}
+ 0: \x{2435}
+ 0: \x{2441}
+ 0: \x{2442}
+
+/[\W]/8g
+ \x{2442}\x{2435}\x{2441}\x{2442}
+ 0: \x{2442}
+ 0: \x{2435}
+ 0: \x{2441}
+ 0: \x{2442}
+
+/[\S\s]*/8
+ abc\n\r\x{442}\x{435}\x{441}\x{442}xyz
+ 0: abc\x{0a}\x{0d}\x{442}\x{435}\x{441}\x{442}xyz
+
+/[\x{41f}\S]/8g
+ \x{442}\x{435}\x{441}\x{442}
+ 0: \x{442}
+ 0: \x{435}
+ 0: \x{441}
+ 0: \x{442}
+
+/.[^\S]./8g
+ abc def\x{442}\x{443}xyz\npqr
+ 0: c d
+ 0: z\x{0a}p
+
+/.[^\S\n]./8g
+ abc def\x{442}\x{443}xyz\npqr
+ 0: c d
+
+/[[:^alnum:]]/8g
+ +\x{2442}
+ 0: +
+ 0: \x{2442}
+
+/[[:^alpha:]]/8g
+ +\x{2442}
+ 0: +
+ 0: \x{2442}
+
+/[[:^ascii:]]/8g
+ A\x{442}
+ 0: \x{442}
+
+/[[:^blank:]]/8g
+ A\x{442}
+ 0: A
+ 0: \x{442}
+
+/[[:^cntrl:]]/8g
+ A\x{442}
+ 0: A
+ 0: \x{442}
+
+/[[:^digit:]]/8g
+ A\x{442}
+ 0: A
+ 0: \x{442}
+
+/[[:^graph:]]/8g
+ \x19\x{e01ff}
+ 0: \x{19}
+ 0: \x{e01ff}
+
+/[[:^lower:]]/8g
+ A\x{422}
+ 0: A
+ 0: \x{422}
+
+/[[:^print:]]/8g
+ \x{19}\x{e01ff}
+ 0: \x{19}
+ 0: \x{e01ff}
+
+/[[:^punct:]]/8g
+ A\x{442}
+ 0: A
+ 0: \x{442}
+
+/[[:^space:]]/8g
+ A\x{442}
+ 0: A
+ 0: \x{442}
+
+/[[:^upper:]]/8g
+ a\x{442}
+ 0: a
+ 0: \x{442}
+
+/[[:^word:]]/8g
+ +\x{2442}
+ 0: +
+ 0: \x{2442}
+
+/[[:^xdigit:]]/8g
+ M\x{442}
+ 0: M
+ 0: \x{442}
+
+/[^ABCDEFGHIJKLMNOPQRSTUVWXYZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮİIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŸŹŻŽƁƂƄƆƇƉƊƋƎƏƐƑƓƔƖƗƘƜƝƟƠƢƤƦƧƩƬƮƯƱƲƳƵƷƸƼDŽLJNJǍǏǑǓǕǗǙǛǞǠǢǤǦǨǪǬǮDZǴǶǷǸǺǼǾȀȂȄȆȈȊȌȎȐȒȔȖȘȚȜȞȠȢȤȦȨȪȬȮȰȲȺȻȽȾɁΆΈΉΊΌΎΏΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩΪΫϒϓϔϘϚϜϞϠϢϤϦϨϪϬϮϴϷϹϺϽϾϿЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯѠѢѤѦѨѪѬѮѰѲѴѶѸѺѼѾҀҊҌҎҐҒҔҖҘҚҜҞҠҢҤҦҨҪҬҮҰҲҴҶҸҺҼҾӀӁӃӅӇӉӋӍӐӒӔӖӘӚӜӞӠӢӤӦӨӪӬӮӰӲӴӶӸԀԂԄԆԈԊԌԎԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉՊՋՌՍՎՏՐՑՒՓՔՕՖႠႡႢႣႤႥႦႧႨႩႪႫႬႭႮႯႰႱႲႳႴႵႶႷႸႹႺႻႼႽႾႿჀჁჂჃჄჅḀḂḄḆḈḊḌḎḐḒḔḖḘḚḜḞḠḢḤḦḨḪḬḮḰḲḴḶḸḺḼḾṀṂṄṆṈṊṌṎṐṒṔṖṘṚṜṞṠṢṤṦṨṪṬṮṰṲṴṶṸṺṼṾẀẂẄẆẈẊẌẎẐẒẔẠẢẤẦẨẪẬẮẰẲẴẶẸẺẼẾỀỂỄỆỈỊỌỎỐỒỔỖỘỚỜỞỠỢỤỦỨỪỬỮỰỲỴỶỸἈἉἊἋἌἍἎἏἘἙἚἛἜἝἨἩἪἫἬἭἮἯἸἹἺἻἼἽἾἿὈὉὊὋὌὍὙὛὝὟὨὩὪὫὬὭὮὯᾸᾹᾺΆῈΈῊΉῘῙῚΊῨῩῪΎῬῸΌῺΏabcdefghijklmnopqrstuvwxyzªµºßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿāăąćĉċčďđēĕėęěĝğġģĥħĩīĭįıijĵķĸĺļľŀłńņňʼnŋōŏőœŕŗřśŝşšţťŧũūŭůűųŵŷźżžſƀƃƅƈƌƍƒƕƙƚƛƞơƣƥƨƪƫƭưƴƶƹƺƽƾƿdžljnjǎǐǒǔǖǘǚǜǝǟǡǣǥǧǩǫǭǯǰdzǵǹǻǽǿȁȃȅȇȉȋȍȏȑȓȕȗșțȝȟȡȣȥȧȩȫȭȯȱȳȴȵȶȷȸȹȼȿɀɐɑɒɓɔɕɖɗɘəɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯΐάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύώϐϑϕϖϗϙϛϝϟϡϣϥϧϩϫϭϯϰϱϲϳϵϸϻϼабвгдежзийклмнопрстуфхцчшщъыьэюяѐёђѓєѕіїјљњћќѝўџѡѣѥѧѩѫѭѯѱѳѵѷѹѻѽѿҁҋҍҏґғҕҗҙқҝҟҡңҥҧҩҫҭүұҳҵҷҹһҽҿӂӄӆӈӊӌӎӑӓӕӗәӛӝӟӡӣӥӧөӫӭӯӱӳӵӷӹԁԃԅԇԉԋԍԏաբգդեզէըթժիլխծկհձղճմյնշոչպջռսվտրցւփքօֆևᴀᴁᴂᴃᴄᴅᴆᴇᴈᴉᴊᴋᴌᴍᴎᴏᴐᴑᴒᴓᴔᴕᴖᴗᴘᴙᴚᴛᴜᴝᴞᴟᴠᴡᴢᴣᴤᴥᴦᴧᴨᴩᴪᴫᵢᵣᵤᵥᵦᵧᵨᵩᵪᵫᵬᵭᵮᵯᵰᵱᵲᵳᵴᵵᵶᵷᵹᵺᵻᵼᵽᵾᵿᶀᶁᶂᶃᶄᶅᶆᶇᶈᶉᶊᶋᶌᶍᶎᶏᶐᶑᶒᶓᶔᶕᶖᶗᶘᶙᶚḁḃḅḇḉḋḍḏḑḓḕḗḙḛḝḟḡḣḥḧḩḫḭḯḱḳḵḷḹḻḽḿṁṃṅṇṉṋṍṏṑṓṕṗṙṛṝṟṡṣṥṧṩṫṭṯṱṳṵṷṹṻṽṿẁẃẅẇẉẋẍẏẑẓẕẖẗẘẙẚẛạảấầẩẫậắằẳẵặẹẻẽếềểễệỉịọỏốồổỗộớờởỡợụủứừửữựỳỵỷỹἀἁἂἃἄἅἆἇἐἑἒἓἔἕἠἡἢἣἤἥἦἧἰἱἲἳἴἵἶἷὀὁὂὃὄὅὐὑὒὓὔὕὖὗὠὡὢὣὤὥὦὧὰάὲέὴήὶίὸόὺύὼώᾀᾁᾂᾃᾄᾅᾆᾇᾐᾑᾒᾓᾔᾕᾖᾗᾠᾡᾢᾣᾤᾥᾦᾧᾰᾱᾲᾳᾴᾶᾷιῂῃῄῆῇῐῑῒΐῖῗῠῡῢΰῤῥῦῧῲῳῴῶῷⲁⲃⲅⲇⲉⲋⲍⲏⲑⲓⲕⲗⲙⲛⲝⲟⲡⲣⲥⲧⲩⲫⲭⲯⲱⲳⲵⲷⲹⲻⲽⲿⳁⳃⳅⳇⳉⳋⳍⳏⳑⳓⳕⳗⳙⳛⳝⳟⳡⳣⳤⴀⴁⴂⴃⴄⴅⴆⴇⴈⴉⴊⴋⴌⴍⴎⴏⴐⴑⴒⴓⴔⴕⴖⴗⴘⴙⴚⴛⴜⴝⴞⴟⴠⴡⴢⴣⴤⴥfffiflffifflſtstﬓﬔﬕﬖﬗ\d-_^]/8
+
+/ End of testinput4 /
diff --git a/lib/stdlib/test/re_SUITE_data/testoutput5 b/lib/stdlib/test/re_SUITE_data/testoutput5
new file mode 100644
index 0000000000..abbe1c87de
--- /dev/null
+++ b/lib/stdlib/test/re_SUITE_data/testoutput5
@@ -0,0 +1,1611 @@
+/\x{100}/8DZ
+------------------------------------------------------------------
+ Bra
+ \x{100}
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 196
+Need char = 128
+
+/\x{1000}/8DZ
+------------------------------------------------------------------
+ Bra
+ \x{1000}
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 225
+Need char = 128
+
+/\x{10000}/8DZ
+------------------------------------------------------------------
+ Bra
+ \x{10000}
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 240
+Need char = 128
+
+/\x{100000}/8DZ
+------------------------------------------------------------------
+ Bra
+ \x{100000}
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 244
+Need char = 128
+
+/\x{1000000}/8DZ
+------------------------------------------------------------------
+ Bra
+ \x{1000000}
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 249
+Need char = 128
+
+/\x{4000000}/8DZ
+------------------------------------------------------------------
+ Bra
+ \x{4000000}
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 252
+Need char = 128
+
+/\x{7fffFFFF}/8DZ
+------------------------------------------------------------------
+ Bra
+ \x{7fffffff}
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 253
+Need char = 191
+
+/[\x{ff}]/8DZ
+------------------------------------------------------------------
+ Bra
+ \x{ff}
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 195
+Need char = 191
+
+/[\x{100}]/8DZ
+------------------------------------------------------------------
+ Bra
+ [\x{100}]
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+No first char
+No need char
+
+/\x{ffffffff}/8
+Failed: character value in \x{...} sequence is too large at offset 11
+
+/\x{100000000}/8
+Failed: character value in \x{...} sequence is too large at offset 12
+
+/^\x{100}a\x{1234}/8
+ \x{100}a\x{1234}bcd
+ 0: \x{100}a\x{1234}
+
+/\x80/8DZ
+------------------------------------------------------------------
+ Bra
+ \x{80}
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 194
+Need char = 128
+
+/\xff/8DZ
+------------------------------------------------------------------
+ Bra
+ \x{ff}
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 195
+Need char = 191
+
+/\x{0041}\x{2262}\x{0391}\x{002e}/DZ8
+------------------------------------------------------------------
+ Bra
+ A\x{2262}\x{391}.
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 'A'
+Need char = '.'
+ \x{0041}\x{2262}\x{0391}\x{002e}
+ 0: A\x{2262}\x{391}.
+
+/\x{D55c}\x{ad6d}\x{C5B4}/DZ8
+------------------------------------------------------------------
+ Bra
+ \x{d55c}\x{ad6d}\x{c5b4}
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 237
+Need char = 180
+ \x{D55c}\x{ad6d}\x{C5B4}
+ 0: \x{d55c}\x{ad6d}\x{c5b4}
+
+/\x{65e5}\x{672c}\x{8a9e}/DZ8
+------------------------------------------------------------------
+ Bra
+ \x{65e5}\x{672c}\x{8a9e}
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 230
+Need char = 158
+ \x{65e5}\x{672c}\x{8a9e}
+ 0: \x{65e5}\x{672c}\x{8a9e}
+
+/\x{80}/DZ8
+------------------------------------------------------------------
+ Bra
+ \x{80}
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 194
+Need char = 128
+
+/\x{084}/DZ8
+------------------------------------------------------------------
+ Bra
+ \x{84}
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 194
+Need char = 132
+
+/\x{104}/DZ8
+------------------------------------------------------------------
+ Bra
+ \x{104}
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 196
+Need char = 132
+
+/\x{861}/DZ8
+------------------------------------------------------------------
+ Bra
+ \x{861}
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 224
+Need char = 161
+
+/\x{212ab}/DZ8
+------------------------------------------------------------------
+ Bra
+ \x{212ab}
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 240
+Need char = 171
+
+/.{3,5}X/DZ8
+------------------------------------------------------------------
+ Bra
+ Any{3}
+ Any{0,2}
+ X
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: utf8
+No first char
+Need char = 'X'
+ \x{212ab}\x{212ab}\x{212ab}\x{861}X
+ 0: \x{212ab}\x{212ab}\x{212ab}\x{861}X
+
+
+/.{3,5}?/DZ8
+------------------------------------------------------------------
+ Bra
+ Any{3}
+ Any{0,2}?
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: utf8
+No first char
+No need char
+ \x{212ab}\x{212ab}\x{212ab}\x{861}
+ 0: \x{212ab}\x{212ab}\x{212ab}
+
+/-- These tests are here rather than in testinput4 because Perl 5.6 has some
+problems with UTF-8 support, in the area of \x{..} where the value is < 255.
+It grumbles about invalid UTF-8 strings. --/
+
+/^[a\x{c0}]b/8
+ \x{c0}b
+ 0: \x{c0}b
+
+/^([a\x{c0}]*?)aa/8
+ a\x{c0}aaaa/
+ 0: a\x{c0}aa
+ 1: a\x{c0}
+
+/^([a\x{c0}]*?)aa/8
+ a\x{c0}aaaa/
+ 0: a\x{c0}aa
+ 1: a\x{c0}
+ a\x{c0}a\x{c0}aaa/
+ 0: a\x{c0}a\x{c0}aa
+ 1: a\x{c0}a\x{c0}
+
+/^([a\x{c0}]*)aa/8
+ a\x{c0}aaaa/
+ 0: a\x{c0}aaaa
+ 1: a\x{c0}aa
+ a\x{c0}a\x{c0}aaa/
+ 0: a\x{c0}a\x{c0}aaa
+ 1: a\x{c0}a\x{c0}a
+
+/^([a\x{c0}]*)a\x{c0}/8
+ a\x{c0}aaaa/
+ 0: a\x{c0}
+ 1:
+ a\x{c0}a\x{c0}aaa/
+ 0: a\x{c0}a\x{c0}
+ 1: a\x{c0}
+
+/-- --/
+
+/(?<=\C)X/8
+Failed: \C not allowed in lookbehind assertion at offset 6
+
+/-- This one is here not because it's different to Perl, but because the way
+the captured single-byte is displayed. (In Perl it becomes a character, and you
+can't tell the difference.) --/
+
+/X(\C)(.*)/8
+ X\x{1234}
+ 0: X\x{1234}
+ 1: \xe1
+ 2: \x88\xb4
+ X\nabc
+ 0: X\x{0a}abc
+ 1: \x{0a}
+ 2: abc
+
+/^[ab]/8DZ
+------------------------------------------------------------------
+ Bra
+ ^
+ [ab]
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored utf8
+No first char
+No need char
+ bar
+ 0: b
+ *** Failers
+No match
+ c
+No match
+ \x{ff}
+No match
+ \x{100}
+No match
+
+/^[^ab]/8DZ
+------------------------------------------------------------------
+ Bra
+ ^
+ [\x00-`c-\xff] (neg)
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored utf8
+No first char
+No need char
+ c
+ 0: c
+ \x{ff}
+ 0: \x{ff}
+ \x{100}
+ 0: \x{100}
+ *** Failers
+ 0: *
+ aaa
+No match
+
+/[^ab\xC0-\xF0]/8SDZ
+------------------------------------------------------------------
+ Bra
+ [\x00-`c-\xbf\xf1-\xff] (neg)
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+No first char
+No need char
+Starting byte set: \x00 \x01 \x02 \x03 \x04 \x05 \x06 \x07 \x08 \x09 \x0a
+ \x0b \x0c \x0d \x0e \x0f \x10 \x11 \x12 \x13 \x14 \x15 \x16 \x17 \x18 \x19
+ \x1a \x1b \x1c \x1d \x1e \x1f \x20 ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4
+ 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y
+ Z [ \ ] ^ _ ` c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ \x7f
+ \xc2 \xc3 \xc4 \xc5 \xc6 \xc7 \xc8 \xc9 \xca \xcb \xcc \xcd \xce \xcf \xd0
+ \xd1 \xd2 \xd3 \xd4 \xd5 \xd6 \xd7 \xd8 \xd9 \xda \xdb \xdc \xdd \xde \xdf
+ \xe0 \xe1 \xe2 \xe3 \xe4 \xe5 \xe6 \xe7 \xe8 \xe9 \xea \xeb \xec \xed \xee
+ \xef \xf0 \xf1 \xf2 \xf3 \xf4 \xf5 \xf6 \xf7 \xf8 \xf9 \xfa \xfb \xfc \xfd
+ \xfe \xff
+ \x{f1}
+ 0: \x{f1}
+ \x{bf}
+ 0: \x{bf}
+ \x{100}
+ 0: \x{100}
+ \x{1000}
+ 0: \x{1000}
+ *** Failers
+ 0: *
+ \x{c0}
+No match
+ \x{f0}
+No match
+
+/Ā{3,4}/8SDZ
+------------------------------------------------------------------
+ Bra
+ \x{100}{3}
+ \x{100}?
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: utf8
+First char = 196
+Need char = 128
+Study returned NULL
+ \x{100}\x{100}\x{100}\x{100\x{100}
+ 0: \x{100}\x{100}\x{100}
+
+/(\x{100}+|x)/8SDZ
+------------------------------------------------------------------
+ Bra
+ CBra 1
+ \x{100}+
+ Alt
+ x
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+Partial matching not supported
+Options: utf8
+No first char
+No need char
+Starting byte set: x \xc4
+
+/(\x{100}*a|x)/8SDZ
+------------------------------------------------------------------
+ Bra
+ CBra 1
+ \x{100}*+
+ a
+ Alt
+ x
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+Partial matching not supported
+Options: utf8
+No first char
+No need char
+Starting byte set: a x \xc4
+
+/(\x{100}{0,2}a|x)/8SDZ
+------------------------------------------------------------------
+ Bra
+ CBra 1
+ \x{100}{0,2}
+ a
+ Alt
+ x
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+Partial matching not supported
+Options: utf8
+No first char
+No need char
+Starting byte set: a x \xc4
+
+/(\x{100}{1,2}a|x)/8SDZ
+------------------------------------------------------------------
+ Bra
+ CBra 1
+ \x{100}
+ \x{100}{0,1}
+ a
+ Alt
+ x
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+Partial matching not supported
+Options: utf8
+No first char
+No need char
+Starting byte set: x \xc4
+
+/\x{100}*(\d+|"(?1)")/8
+ 1234
+ 0: 1234
+ 1: 1234
+ "1234"
+ 0: "1234"
+ 1: "1234"
+ \x{100}1234
+ 0: \x{100}1234
+ 1: 1234
+ "\x{100}1234"
+ 0: \x{100}1234
+ 1: 1234
+ \x{100}\x{100}12ab
+ 0: \x{100}\x{100}12
+ 1: 12
+ \x{100}\x{100}"12"
+ 0: \x{100}\x{100}"12"
+ 1: "12"
+ *** Failers
+No match
+ \x{100}\x{100}abcd
+No match
+
+/\x{100}/8DZ
+------------------------------------------------------------------
+ Bra
+ \x{100}
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 196
+Need char = 128
+
+/\x{100}*/8DZ
+------------------------------------------------------------------
+ Bra
+ \x{100}*
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: utf8
+No first char
+No need char
+
+/a\x{100}*/8DZ
+------------------------------------------------------------------
+ Bra
+ a
+ \x{100}*
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: utf8
+First char = 'a'
+No need char
+
+/ab\x{100}*/8DZ
+------------------------------------------------------------------
+ Bra
+ ab
+ \x{100}*
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: utf8
+First char = 'a'
+Need char = 'b'
+
+/a\x{100}\x{101}*/8DZ
+------------------------------------------------------------------
+ Bra
+ a\x{100}
+ \x{101}*
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: utf8
+First char = 'a'
+Need char = 128
+
+/a\x{100}\x{101}+/8DZ
+------------------------------------------------------------------
+ Bra
+ a\x{100}
+ \x{101}+
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: utf8
+First char = 'a'
+Need char = 129
+
+/\x{100}*A/8DZ
+------------------------------------------------------------------
+ Bra
+ \x{100}*+
+ A
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: utf8
+No first char
+Need char = 'A'
+ A
+ 0: A
+
+/\x{100}*\d(?R)/8DZ
+------------------------------------------------------------------
+ Bra
+ \x{100}*+
+ \d
+ Once
+ Recurse
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: utf8
+No first char
+No need char
+
+/[^\x{c4}]/DZ
+------------------------------------------------------------------
+ Bra
+ [^\xc4]
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+
+/[^\x{c4}]/8DZ
+------------------------------------------------------------------
+ Bra
+ [\x00-\xc3\xc5-\xff] (neg)
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+No first char
+No need char
+
+/[\x{100}]/8DZ
+------------------------------------------------------------------
+ Bra
+ [\x{100}]
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+No first char
+No need char
+ \x{100}
+ 0: \x{100}
+ Z\x{100}
+ 0: \x{100}
+ \x{100}Z
+ 0: \x{100}
+ *** Failers
+No match
+
+/[Z\x{100}]/8DZ
+------------------------------------------------------------------
+ Bra
+ [Z\x{100}]
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+No first char
+No need char
+ Z\x{100}
+ 0: Z
+ \x{100}
+ 0: \x{100}
+ \x{100}Z
+ 0: \x{100}
+ *** Failers
+No match
+
+/[\x{200}-\x{100}]/8
+Failed: range out of order in character class at offset 15
+
+/[Ā-Ą]/8
+ \x{100}
+ 0: \x{100}
+ \x{104}
+ 0: \x{104}
+ *** Failers
+No match
+ \x{105}
+No match
+ \x{ff}
+No match
+
+/[z-\x{100}]/8DZ
+------------------------------------------------------------------
+ Bra
+ [z-\x{100}]
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+No first char
+No need char
+
+/[z\Qa-d]Ā\E]/8DZ
+------------------------------------------------------------------
+ Bra
+ [\-\]adz\x{100}]
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+No first char
+No need char
+ \x{100}
+ 0: \x{100}
+ Ā
+ 0: \x{100}
+
+/[\xFF]/DZ
+------------------------------------------------------------------
+ Bra
+ \xff
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+First char = 255
+No need char
+ >\xff<
+ 0: \xff
+
+/[\xff]/DZ8
+------------------------------------------------------------------
+ Bra
+ \x{ff}
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 195
+Need char = 191
+ >\x{ff}<
+ 0: \x{ff}
+
+/[^\xFF]/DZ
+------------------------------------------------------------------
+ Bra
+ [^\xff]
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+
+/[^\xff]/8DZ
+------------------------------------------------------------------
+ Bra
+ [\x00-\xfe] (neg)
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+No first char
+No need char
+
+/[Ä-Ü]/8
+ Ö # Matches without Study
+ 0: \x{d6}
+ \x{d6}
+ 0: \x{d6}
+
+/[Ä-Ü]/8S
+ Ö <-- Same with Study
+ 0: \x{d6}
+ \x{d6}
+ 0: \x{d6}
+
+/[\x{c4}-\x{dc}]/8
+ Ö # Matches without Study
+ 0: \x{d6}
+ \x{d6}
+ 0: \x{d6}
+
+/[\x{c4}-\x{dc}]/8S
+ Ö <-- Same with Study
+ 0: \x{d6}
+ \x{d6}
+ 0: \x{d6}
+
+/[�]/8
+Failed: invalid UTF-8 string at offset 2
+
+/�/8
+Failed: invalid UTF-8 string at offset 0
+
+/���xxx/8
+Failed: invalid UTF-8 string at offset 1
+
+/���xxx/8?DZ
+------------------------------------------------------------------
+ Bra
+ \X{c0}\X{c0}\X{c0}xxx
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8 no_utf8_check
+First char = 195
+Need char = 'x'
+
+/abc/8
+ �]
+Error -10
+ �
+Error -10
+ ���
+Error -10
+ ���\?
+No match
+
+/anything/8
+ \xc0\x80
+Error -10
+ \xc1\x8f
+Error -10
+ \xe0\x9f\x80
+Error -10
+ \xf0\x8f\x80\x80
+Error -10
+ \xf8\x87\x80\x80\x80
+Error -10
+ \xfc\x83\x80\x80\x80\x80
+Error -10
+ \xfe\x80\x80\x80\x80\x80
+Error -10
+ \xff\x80\x80\x80\x80\x80
+Error -10
+ \xc3\x8f
+No match
+ \xe0\xaf\x80
+No match
+ \xe1\x80\x80
+No match
+ \xf0\x9f\x80\x80
+No match
+ \xf1\x8f\x80\x80
+No match
+ \xf8\x88\x80\x80\x80
+Error -10
+ \xf9\x87\x80\x80\x80
+Error -10
+ \xfc\x84\x80\x80\x80\x80
+Error -10
+ \xfd\x83\x80\x80\x80\x80
+Error -10
+ \?\xf8\x88\x80\x80\x80
+No match
+ \?\xf9\x87\x80\x80\x80
+No match
+ \?\xfc\x84\x80\x80\x80\x80
+No match
+ \?\xfd\x83\x80\x80\x80\x80
+No match
+
+/\x{100}abc(xyz(?1))/8DZ
+------------------------------------------------------------------
+ Bra
+ \x{100}abc
+ CBra 1
+ xyz
+ Once
+ Recurse
+ Ket
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+Options: utf8
+First char = 196
+Need char = 'z'
+
+/[^\x{100}]abc(xyz(?1))/8DZ
+------------------------------------------------------------------
+ Bra
+ [^\x{100}]
+ abc
+ CBra 1
+ xyz
+ Once
+ Recurse
+ Ket
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+Options: utf8
+No first char
+Need char = 'z'
+
+/[ab\x{100}]abc(xyz(?1))/8DZ
+------------------------------------------------------------------
+ Bra
+ [ab\x{100}]
+ abc
+ CBra 1
+ xyz
+ Once
+ Recurse
+ Ket
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+Options: utf8
+No first char
+Need char = 'z'
+
+/(\x{100}(b(?2)c))?/DZ8
+------------------------------------------------------------------
+ Bra
+ Brazero
+ CBra 1
+ \x{100}
+ CBra 2
+ b
+ Once
+ Recurse
+ Ket
+ c
+ Ket
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 2
+Options: utf8
+No first char
+No need char
+
+/(\x{100}(b(?2)c)){0,2}/DZ8
+------------------------------------------------------------------
+ Bra
+ Brazero
+ Bra
+ CBra 1
+ \x{100}
+ CBra 2
+ b
+ Once
+ Recurse
+ Ket
+ c
+ Ket
+ Ket
+ Brazero
+ CBra 1
+ \x{100}
+ CBra 2
+ b
+ Once
+ Recurse
+ Ket
+ c
+ Ket
+ Ket
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 2
+Options: utf8
+No first char
+No need char
+
+/(\x{100}(b(?1)c))?/DZ8
+------------------------------------------------------------------
+ Bra
+ Brazero
+ CBra 1
+ \x{100}
+ CBra 2
+ b
+ Once
+ Recurse
+ Ket
+ c
+ Ket
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 2
+Options: utf8
+No first char
+No need char
+
+/(\x{100}(b(?1)c)){0,2}/DZ8
+------------------------------------------------------------------
+ Bra
+ Brazero
+ Bra
+ CBra 1
+ \x{100}
+ CBra 2
+ b
+ Once
+ Recurse
+ Ket
+ c
+ Ket
+ Ket
+ Brazero
+ CBra 1
+ \x{100}
+ CBra 2
+ b
+ Once
+ Recurse
+ Ket
+ c
+ Ket
+ Ket
+ Ket
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 2
+Options: utf8
+No first char
+No need char
+
+/\W/8
+ A.B
+ 0: .
+ A\x{100}B
+ 0: \x{100}
+
+/\w/8
+ \x{100}X
+ 0: X
+
+/a\x{1234}b/P8
+ a\x{1234}b
+ 0: a\x{1234}b
+
+/^\ሴ/8DZ
+------------------------------------------------------------------
+ Bra
+ ^
+ \x{1234}
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored utf8
+No first char
+No need char
+
+/\777/I
+Failed: octal value is greater than \377 (not in UTF-8 mode) at offset 3
+
+/\777/8I
+Capturing subpattern count = 0
+Options: utf8
+First char = 199
+Need char = 191
+ \x{1ff}
+ 0: \x{1ff}
+ \777
+ 0: \x{1ff}
+
+/\x{100}*\d/8DZ
+------------------------------------------------------------------
+ Bra
+ \x{100}*+
+ \d
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: utf8
+No first char
+No need char
+
+/\x{100}*\s/8DZ
+------------------------------------------------------------------
+ Bra
+ \x{100}*+
+ \s
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: utf8
+No first char
+No need char
+
+/\x{100}*\w/8DZ
+------------------------------------------------------------------
+ Bra
+ \x{100}*+
+ \w
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: utf8
+No first char
+No need char
+
+/\x{100}*\D/8DZ
+------------------------------------------------------------------
+ Bra
+ \x{100}*
+ \D
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: utf8
+No first char
+No need char
+
+/\x{100}*\S/8DZ
+------------------------------------------------------------------
+ Bra
+ \x{100}*
+ \S
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: utf8
+No first char
+No need char
+
+/\x{100}*\W/8DZ
+------------------------------------------------------------------
+ Bra
+ \x{100}*
+ \W
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: utf8
+No first char
+No need char
+
+/\x{100}+\x{200}/8DZ
+------------------------------------------------------------------
+ Bra
+ \x{100}++
+ \x{200}
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: utf8
+First char = 196
+Need char = 128
+
+/\x{100}+X/8DZ
+------------------------------------------------------------------
+ Bra
+ \x{100}++
+ X
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: utf8
+First char = 196
+Need char = 'X'
+
+/X+\x{200}/8DZ
+------------------------------------------------------------------
+ Bra
+ X++
+ \x{200}
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: utf8
+First char = 'X'
+Need char = 128
+
+/()()()()()()()()()()
+ ()()()()()()()()()()
+ ()()()()()()()()()()
+ ()()()()()()()()()()
+ A (x) (?41) B/8x
+ AxxB
+Matched, but too many substrings
+ 0: AxxB
+ 1:
+ 2:
+ 3:
+ 4:
+ 5:
+ 6:
+ 7:
+ 8:
+ 9:
+10:
+11:
+12:
+13:
+14:
+
+/^[\x{100}\E-\Q\E\x{150}]/BZ8
+------------------------------------------------------------------
+ Bra
+ ^
+ [\x{100}-\x{150}]
+ Ket
+ End
+------------------------------------------------------------------
+
+/^[\QĀ\E-\QŐ\E]/BZ8
+------------------------------------------------------------------
+ Bra
+ ^
+ [\x{100}-\x{150}]
+ Ket
+ End
+------------------------------------------------------------------
+
+/^[\QĀ\E-\QŐ\E/BZ8
+Failed: missing terminating ] for character class at offset 15
+
+/^abc./mgx8<any>
+ abc1 \x0aabc2 \x0babc3xx \x0cabc4 \x0dabc5xx \x0d\x0aabc6 \x{0085}abc7 \x{2028}abc8 \x{2029}abc9 JUNK
+ 0: abc1
+ 0: abc2
+ 0: abc3
+ 0: abc4
+ 0: abc5
+ 0: abc6
+ 0: abc7
+ 0: abc8
+ 0: abc9
+
+/abc.$/mgx8<any>
+ abc1\x0a abc2\x0b abc3\x0c abc4\x0d abc5\x0d\x0a abc6\x{0085} abc7\x{2028} abc8\x{2029} abc9
+ 0: abc1
+ 0: abc2
+ 0: abc3
+ 0: abc4
+ 0: abc5
+ 0: abc6
+ 0: abc7
+ 0: abc8
+ 0: abc9
+
+/^a\Rb/8<bsr_unicode>
+ a\nb
+ 0: a\x{0a}b
+ a\rb
+ 0: a\x{0d}b
+ a\r\nb
+ 0: a\x{0d}\x{0a}b
+ a\x0bb
+ 0: a\x{0b}b
+ a\x0cb
+ 0: a\x{0c}b
+ a\x{85}b
+ 0: a\x{85}b
+ a\x{2028}b
+ 0: a\x{2028}b
+ a\x{2029}b
+ 0: a\x{2029}b
+ ** Failers
+No match
+ a\n\rb
+No match
+
+/^a\R*b/8<bsr_unicode>
+ ab
+ 0: ab
+ a\nb
+ 0: a\x{0a}b
+ a\rb
+ 0: a\x{0d}b
+ a\r\nb
+ 0: a\x{0d}\x{0a}b
+ a\x0bb
+ 0: a\x{0b}b
+ a\x0c\x{2028}\x{2029}b
+ 0: a\x{0c}\x{2028}\x{2029}b
+ a\x{85}b
+ 0: a\x{85}b
+ a\n\rb
+ 0: a\x{0a}\x{0d}b
+ a\n\r\x{85}\x0cb
+ 0: a\x{0a}\x{0d}\x{85}\x{0c}b
+
+/^a\R+b/8<bsr_unicode>
+ a\nb
+ 0: a\x{0a}b
+ a\rb
+ 0: a\x{0d}b
+ a\r\nb
+ 0: a\x{0d}\x{0a}b
+ a\x0bb
+ 0: a\x{0b}b
+ a\x0c\x{2028}\x{2029}b
+ 0: a\x{0c}\x{2028}\x{2029}b
+ a\x{85}b
+ 0: a\x{85}b
+ a\n\rb
+ 0: a\x{0a}\x{0d}b
+ a\n\r\x{85}\x0cb
+ 0: a\x{0a}\x{0d}\x{85}\x{0c}b
+ ** Failers
+No match
+ ab
+No match
+
+/^a\R{1,3}b/8<bsr_unicode>
+ a\nb
+ 0: a\x{0a}b
+ a\n\rb
+ 0: a\x{0a}\x{0d}b
+ a\n\r\x{85}b
+ 0: a\x{0a}\x{0d}\x{85}b
+ a\r\n\r\nb
+ 0: a\x{0d}\x{0a}\x{0d}\x{0a}b
+ a\r\n\r\n\r\nb
+ 0: a\x{0d}\x{0a}\x{0d}\x{0a}\x{0d}\x{0a}b
+ a\n\r\n\rb
+ 0: a\x{0a}\x{0d}\x{0a}\x{0d}b
+ a\n\n\r\nb
+ 0: a\x{0a}\x{0a}\x{0d}\x{0a}b
+ ** Failers
+No match
+ a\n\n\n\rb
+No match
+ a\r
+No match
+
+/\H\h\V\v/8
+ X X\x0a
+ 0: X X\x{0a}
+ X\x09X\x0b
+ 0: X\x{09}X\x{0b}
+ ** Failers
+No match
+ \x{a0} X\x0a
+No match
+
+/\H*\h+\V?\v{3,4}/8
+ \x09\x20\x{a0}X\x0a\x0b\x0c\x0d\x0a
+ 0: \x{09} \x{a0}X\x{0a}\x{0b}\x{0c}\x{0d}
+ \x09\x20\x{a0}\x0a\x0b\x0c\x0d\x0a
+ 0: \x{09} \x{a0}\x{0a}\x{0b}\x{0c}\x{0d}
+ \x09\x20\x{a0}\x0a\x0b\x0c
+ 0: \x{09} \x{a0}\x{0a}\x{0b}\x{0c}
+ ** Failers
+No match
+ \x09\x20\x{a0}\x0a\x0b
+No match
+
+/\H\h\V\v/8
+ \x{3001}\x{3000}\x{2030}\x{2028}
+ 0: \x{3001}\x{3000}\x{2030}\x{2028}
+ X\x{180e}X\x{85}
+ 0: X\x{180e}X\x{85}
+ ** Failers
+No match
+ \x{2009} X\x0a
+No match
+
+/\H*\h+\V?\v{3,4}/8
+ \x{1680}\x{180e}\x{2007}X\x{2028}\x{2029}\x0c\x0d\x0a
+ 0: \x{1680}\x{180e}\x{2007}X\x{2028}\x{2029}\x{0c}\x{0d}
+ \x09\x{205f}\x{a0}\x0a\x{2029}\x0c\x{2028}\x0a
+ 0: \x{09}\x{205f}\x{a0}\x{0a}\x{2029}\x{0c}\x{2028}
+ \x09\x20\x{202f}\x0a\x0b\x0c
+ 0: \x{09} \x{202f}\x{0a}\x{0b}\x{0c}
+ ** Failers
+No match
+ \x09\x{200a}\x{a0}\x{2028}\x0b
+No match
+
+/[\h]/8BZ
+------------------------------------------------------------------
+ Bra
+ [\x09 \xa0\x{1680}\x{180e}\x{2000}-\x{200a}\x{202f}\x{205f}\x{3000}]
+ Ket
+ End
+------------------------------------------------------------------
+ >\x{1680}
+ 0: \x{1680}
+
+/[\h]{3,}/8BZ
+------------------------------------------------------------------
+ Bra
+ [\x09 \xa0\x{1680}\x{180e}\x{2000}-\x{200a}\x{202f}\x{205f}\x{3000}]{3,}
+ Ket
+ End
+------------------------------------------------------------------
+ >\x{1680}\x{180e}\x{2000}\x{2003}\x{200a}\x{202f}\x{205f}\x{3000}<
+ 0: \x{1680}\x{180e}\x{2000}\x{2003}\x{200a}\x{202f}\x{205f}\x{3000}
+
+/[\v]/8BZ
+------------------------------------------------------------------
+ Bra
+ [\x0a-\x0d\x85\x{2028}-\x{2029}]
+ Ket
+ End
+------------------------------------------------------------------
+
+/[\H]/8BZ
+------------------------------------------------------------------
+ Bra
+ [\x00-\x08\x0a-\x1f!-\x9f\xa1-\xff\x{100}-\x{167f}\x{1681}-\x{180d}\x{180f}-\x{1fff}\x{200b}-\x{202e}\x{2030}-\x{205e}\x{2060}-\x{2fff}\x{3001}-\x{7fffffff}]
+ Ket
+ End
+------------------------------------------------------------------
+
+/[\V]/8BZ
+------------------------------------------------------------------
+ Bra
+ [\x00-\x09\x0e-\x84\x86-\xff\x{100}-\x{2027}\x{2029}-\x{7fffffff}]
+ Ket
+ End
+------------------------------------------------------------------
+
+/.*$/8<any>
+ \x{1ec5}
+ 0: \x{1ec5}
+
+/-- This tests the stricter UTF-8 check according to RFC 3629. --/
+
+/X/8
+ \x{0}\x{d7ff}\x{e000}\x{10ffff}
+No match
+ \x{d800}
+Error -10
+ \x{d800}\?
+No match
+ \x{da00}
+Error -10
+ \x{da00}\?
+No match
+ \x{dfff}
+Error -10
+ \x{dfff}\?
+No match
+ \x{110000}
+Error -10
+ \x{110000}\?
+No match
+ \x{2000000}
+Error -10
+ \x{2000000}\?
+No match
+ \x{7fffffff}
+Error -10
+ \x{7fffffff}\?
+No match
+
+/a\Rb/I8<bsr_anycrlf>
+Capturing subpattern count = 0
+Options: bsr_anycrlf utf8
+First char = 'a'
+Need char = 'b'
+ a\rb
+ 0: a\x{0d}b
+ a\nb
+ 0: a\x{0a}b
+ a\r\nb
+ 0: a\x{0d}\x{0a}b
+ ** Failers
+No match
+ a\x{85}b
+No match
+ a\x0bb
+No match
+
+/a\Rb/I8<bsr_unicode>
+Capturing subpattern count = 0
+Options: bsr_unicode utf8
+First char = 'a'
+Need char = 'b'
+ a\rb
+ 0: a\x{0d}b
+ a\nb
+ 0: a\x{0a}b
+ a\r\nb
+ 0: a\x{0d}\x{0a}b
+ a\x{85}b
+ 0: a\x{85}b
+ a\x0bb
+ 0: a\x{0b}b
+ ** Failers
+No match
+ a\x{85}b\<bsr_anycrlf>
+No match
+ a\x0bb\<bsr_anycrlf>
+No match
+
+/a\R?b/I8<bsr_anycrlf>
+Capturing subpattern count = 0
+Options: bsr_anycrlf utf8
+First char = 'a'
+Need char = 'b'
+ a\rb
+ 0: a\x{0d}b
+ a\nb
+ 0: a\x{0a}b
+ a\r\nb
+ 0: a\x{0d}\x{0a}b
+ ** Failers
+No match
+ a\x{85}b
+No match
+ a\x0bb
+No match
+
+/a\R?b/I8<bsr_unicode>
+Capturing subpattern count = 0
+Options: bsr_unicode utf8
+First char = 'a'
+Need char = 'b'
+ a\rb
+ 0: a\x{0d}b
+ a\nb
+ 0: a\x{0a}b
+ a\r\nb
+ 0: a\x{0d}\x{0a}b
+ a\x{85}b
+ 0: a\x{85}b
+ a\x0bb
+ 0: a\x{0b}b
+ ** Failers
+No match
+ a\x{85}b\<bsr_anycrlf>
+No match
+ a\x0bb\<bsr_anycrlf>
+No match
+
+/.*a.*=.b.*/8<ANY>
+ QQQ\x{2029}ABCaXYZ=!bPQR
+ 0: ABCaXYZ=!bPQR
+ ** Failers
+No match
+ a\x{2029}b
+No match
+ \x61\xe2\x80\xa9\x62
+No match
+
+/[[:a\x{100}b:]]/8
+Failed: unknown POSIX class name at offset 3
+
+/ End of testinput5 /
diff --git a/lib/stdlib/test/re_SUITE_data/testoutput6 b/lib/stdlib/test/re_SUITE_data/testoutput6
new file mode 100644
index 0000000000..db825b08c1
--- /dev/null
+++ b/lib/stdlib/test/re_SUITE_data/testoutput6
@@ -0,0 +1,1682 @@
+/^\pC\pL\pM\pN\pP\pS\pZ</8
+ \x7f\x{c0}\x{30f}\x{660}\x{66c}\x{f01}\x{1680}<
+ 0: \x{7f}\x{c0}\x{30f}\x{660}\x{66c}\x{f01}\x{1680}<
+ \np\x{300}9!\$ <
+ 0: \x{0a}p\x{300}9!$ <
+ ** Failers
+No match
+ ap\x{300}9!\$ <
+No match
+
+/^\PC/8
+ X
+ 0: X
+ ** Failers
+ 0: *
+ \x7f
+No match
+
+/^\PL/8
+ 9
+ 0: 9
+ ** Failers
+ 0: *
+ \x{c0}
+No match
+
+/^\PM/8
+ X
+ 0: X
+ ** Failers
+ 0: *
+ \x{30f}
+No match
+
+/^\PN/8
+ X
+ 0: X
+ ** Failers
+ 0: *
+ \x{660}
+No match
+
+/^\PP/8
+ X
+ 0: X
+ ** Failers
+No match
+ \x{66c}
+No match
+
+/^\PS/8
+ X
+ 0: X
+ ** Failers
+ 0: *
+ \x{f01}
+No match
+
+/^\PZ/8
+ X
+ 0: X
+ ** Failers
+ 0: *
+ \x{1680}
+No match
+
+/^\p{Cc}/8
+ \x{017}
+ 0: \x{17}
+ \x{09f}
+ 0: \x{9f}
+ ** Failers
+No match
+ \x{0600}
+No match
+
+/^\p{Cf}/8
+ \x{601}
+ 0: \x{601}
+ ** Failers
+No match
+ \x{09f}
+No match
+
+/^\p{Cn}/8
+ \x{e0000}
+ 0: \x{e0000}
+ ** Failers
+No match
+ \x{09f}
+No match
+
+/^\p{Co}/8
+ \x{f8ff}
+ 0: \x{f8ff}
+ ** Failers
+No match
+ \x{09f}
+No match
+
+/^\p{Cs}/8
+ \?\x{dfff}
+ 0: \x{dfff}
+ ** Failers
+No match
+ \x{09f}
+No match
+
+/^\p{Ll}/8
+ a
+ 0: a
+ ** Failers
+No match
+ Z
+No match
+ \x{e000}
+No match
+
+/^\p{Lm}/8
+ \x{2b0}
+ 0: \x{2b0}
+ ** Failers
+No match
+ a
+No match
+
+/^\p{Lo}/8
+ \x{1bb}
+ 0: \x{1bb}
+ \x{3400}
+ 0: \x{3400}
+ \x{3401}
+ 0: \x{3401}
+ \x{4d00}
+ 0: \x{4d00}
+ \x{4db4}
+ 0: \x{4db4}
+ \x{4db5}
+ 0: \x{4db5}
+ ** Failers
+No match
+ a
+No match
+ \x{2b0}
+No match
+ \x{4db6}
+No match
+
+/^\p{Lt}/8
+ \x{1c5}
+ 0: \x{1c5}
+ ** Failers
+No match
+ a
+No match
+ \x{2b0}
+No match
+
+/^\p{Lu}/8
+ A
+ 0: A
+ ** Failers
+No match
+ \x{2b0}
+No match
+
+/^\p{Mc}/8
+ \x{903}
+ 0: \x{903}
+ ** Failers
+No match
+ X
+No match
+ \x{300}
+No match
+
+/^\p{Me}/8
+ \x{488}
+ 0: \x{488}
+ ** Failers
+No match
+ X
+No match
+ \x{903}
+No match
+ \x{300}
+No match
+
+/^\p{Mn}/8
+ \x{300}
+ 0: \x{300}
+ ** Failers
+No match
+ X
+No match
+ \x{903}
+No match
+
+/^\p{Nd}+/8
+ 0123456789\x{660}\x{661}\x{662}\x{663}\x{664}\x{665}\x{666}\x{667}\x{668}\x{669}\x{66a}
+ 0: 0123456789\x{660}\x{661}\x{662}\x{663}\x{664}\x{665}\x{666}\x{667}\x{668}\x{669}
+ \x{6f0}\x{6f1}\x{6f2}\x{6f3}\x{6f4}\x{6f5}\x{6f6}\x{6f7}\x{6f8}\x{6f9}\x{6fa}
+ 0: \x{6f0}\x{6f1}\x{6f2}\x{6f3}\x{6f4}\x{6f5}\x{6f6}\x{6f7}\x{6f8}\x{6f9}
+ \x{966}\x{967}\x{968}\x{969}\x{96a}\x{96b}\x{96c}\x{96d}\x{96e}\x{96f}\x{970}
+ 0: \x{966}\x{967}\x{968}\x{969}\x{96a}\x{96b}\x{96c}\x{96d}\x{96e}\x{96f}
+ ** Failers
+No match
+ X
+No match
+
+/^\p{Nl}/8
+ \x{16ee}
+ 0: \x{16ee}
+ ** Failers
+No match
+ X
+No match
+ \x{966}
+No match
+
+/^\p{No}/8
+ \x{b2}
+ 0: \x{b2}
+ \x{b3}
+ 0: \x{b3}
+ ** Failers
+No match
+ X
+No match
+ \x{16ee}
+No match
+
+/^\p{Pc}/8
+ \x5f
+ 0: _
+ \x{203f}
+ 0: \x{203f}
+ ** Failers
+No match
+ X
+No match
+ -
+No match
+ \x{58a}
+No match
+
+/^\p{Pd}/8
+ -
+ 0: -
+ \x{58a}
+ 0: \x{58a}
+ ** Failers
+No match
+ X
+No match
+ \x{203f}
+No match
+
+/^\p{Pe}/8
+ )
+ 0: )
+ ]
+ 0: ]
+ }
+ 0: }
+ \x{f3b}
+ 0: \x{f3b}
+ ** Failers
+No match
+ X
+No match
+ \x{203f}
+No match
+ (
+No match
+ [
+No match
+ {
+No match
+ \x{f3c}
+No match
+
+/^\p{Pf}/8
+ \x{bb}
+ 0: \x{bb}
+ \x{2019}
+ 0: \x{2019}
+ ** Failers
+No match
+ X
+No match
+ \x{203f}
+No match
+
+/^\p{Pi}/8
+ \x{ab}
+ 0: \x{ab}
+ \x{2018}
+ 0: \x{2018}
+ ** Failers
+No match
+ X
+No match
+ \x{203f}
+No match
+
+/^\p{Po}/8
+ !
+ 0: !
+ \x{37e}
+ 0: \x{37e}
+ ** Failers
+ 0: *
+ X
+No match
+ \x{203f}
+No match
+
+/^\p{Ps}/8
+ (
+ 0: (
+ [
+ 0: [
+ {
+ 0: {
+ \x{f3c}
+ 0: \x{f3c}
+ ** Failers
+No match
+ X
+No match
+ )
+No match
+ ]
+No match
+ }
+No match
+ \x{f3b}
+No match
+
+/^\p{Sc}+/8
+ $\x{a2}\x{a3}\x{a4}\x{a5}\x{a6}
+ 0: $\x{a2}\x{a3}\x{a4}\x{a5}
+ \x{9f2}
+ 0: \x{9f2}
+ ** Failers
+No match
+ X
+No match
+ \x{2c2}
+No match
+
+/^\p{Sk}/8
+ \x{2c2}
+ 0: \x{2c2}
+ ** Failers
+No match
+ X
+No match
+ \x{9f2}
+No match
+
+/^\p{Sm}+/8
+ +<|~\x{ac}\x{2044}
+ 0: +<|~\x{ac}\x{2044}
+ ** Failers
+No match
+ X
+No match
+ \x{9f2}
+No match
+
+/^\p{So}/8
+ \x{a6}
+ 0: \x{a6}
+ \x{482}
+ 0: \x{482}
+ ** Failers
+No match
+ X
+No match
+ \x{9f2}
+No match
+
+/^\p{Zl}/8
+ \x{2028}
+ 0: \x{2028}
+ ** Failers
+No match
+ X
+No match
+ \x{2029}
+No match
+
+/^\p{Zp}/8
+ \x{2029}
+ 0: \x{2029}
+ ** Failers
+No match
+ X
+No match
+ \x{2028}
+No match
+
+/^\p{Zs}/8
+ \ \
+ 0:
+ \x{a0}
+ 0: \x{a0}
+ \x{1680}
+ 0: \x{1680}
+ \x{180e}
+ 0: \x{180e}
+ \x{2000}
+ 0: \x{2000}
+ \x{2001}
+ 0: \x{2001}
+ ** Failers
+No match
+ \x{2028}
+No match
+ \x{200d}
+No match
+
+/\p{Nd}+(..)/8
+ \x{660}\x{661}\x{662}ABC
+ 0: \x{660}\x{661}\x{662}AB
+ 1: AB
+
+/\p{Nd}+?(..)/8
+ \x{660}\x{661}\x{662}ABC
+ 0: \x{660}\x{661}\x{662}
+ 1: \x{661}\x{662}
+
+/\p{Nd}{2,}(..)/8
+ \x{660}\x{661}\x{662}ABC
+ 0: \x{660}\x{661}\x{662}AB
+ 1: AB
+
+/\p{Nd}{2,}?(..)/8
+ \x{660}\x{661}\x{662}ABC
+ 0: \x{660}\x{661}\x{662}A
+ 1: \x{662}A
+
+/\p{Nd}*(..)/8
+ \x{660}\x{661}\x{662}ABC
+ 0: \x{660}\x{661}\x{662}AB
+ 1: AB
+
+/\p{Nd}*?(..)/8
+ \x{660}\x{661}\x{662}ABC
+ 0: \x{660}\x{661}
+ 1: \x{660}\x{661}
+
+/\p{Nd}{2}(..)/8
+ \x{660}\x{661}\x{662}ABC
+ 0: \x{660}\x{661}\x{662}A
+ 1: \x{662}A
+
+/\p{Nd}{2,3}(..)/8
+ \x{660}\x{661}\x{662}ABC
+ 0: \x{660}\x{661}\x{662}AB
+ 1: AB
+
+/\p{Nd}{2,3}?(..)/8
+ \x{660}\x{661}\x{662}ABC
+ 0: \x{660}\x{661}\x{662}A
+ 1: \x{662}A
+
+/\p{Nd}?(..)/8
+ \x{660}\x{661}\x{662}ABC
+ 0: \x{660}\x{661}\x{662}
+ 1: \x{661}\x{662}
+
+/\p{Nd}??(..)/8
+ \x{660}\x{661}\x{662}ABC
+ 0: \x{660}\x{661}
+ 1: \x{660}\x{661}
+
+/\p{Nd}*+(..)/8
+ \x{660}\x{661}\x{662}ABC
+ 0: \x{660}\x{661}\x{662}AB
+ 1: AB
+
+/\p{Nd}*+(...)/8
+ \x{660}\x{661}\x{662}ABC
+ 0: \x{660}\x{661}\x{662}ABC
+ 1: ABC
+
+/\p{Nd}*+(....)/8
+ ** Failers
+ 0: ** F
+ 1: ** F
+ \x{660}\x{661}\x{662}ABC
+No match
+
+/\p{Lu}/8i
+ A
+ 0: A
+ a\x{10a0}B
+ 0: \x{10a0}
+ ** Failers
+ 0: F
+ a
+No match
+ \x{1d00}
+No match
+
+/\p{^Lu}/8i
+ 1234
+ 0: 1
+ ** Failers
+ 0: *
+ ABC
+No match
+
+/\P{Lu}/8i
+ 1234
+ 0: 1
+ ** Failers
+ 0: *
+ ABC
+No match
+
+/(?<=A\p{Nd})XYZ/8
+ A2XYZ
+ 0: XYZ
+ 123A5XYZPQR
+ 0: XYZ
+ ABA\x{660}XYZpqr
+ 0: XYZ
+ ** Failers
+No match
+ AXYZ
+No match
+ XYZ
+No match
+
+/(?<!\pL)XYZ/8
+ 1XYZ
+ 0: XYZ
+ AB=XYZ..
+ 0: XYZ
+ XYZ
+ 0: XYZ
+ ** Failers
+No match
+ WXYZ
+No match
+
+/[\p{L}]/DZ
+------------------------------------------------------------------
+ Bra
+ [\p{L}]
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+
+/[\p{^L}]/DZ
+------------------------------------------------------------------
+ Bra
+ [\P{L}]
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+
+/[\P{L}]/DZ
+------------------------------------------------------------------
+ Bra
+ [\P{L}]
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+
+/[\P{^L}]/DZ
+------------------------------------------------------------------
+ Bra
+ [\p{L}]
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+
+/[abc\p{L}\x{0660}]/8DZ
+------------------------------------------------------------------
+ Bra
+ [a-c\p{L}\x{660}]
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+No first char
+No need char
+
+/[\p{Nd}]/8DZ
+------------------------------------------------------------------
+ Bra
+ [\p{Nd}]
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+No first char
+No need char
+ 1234
+ 0: 1
+
+/[\p{Nd}+-]+/8DZ
+------------------------------------------------------------------
+ Bra
+ [+\-\p{Nd}]+
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: utf8
+No first char
+No need char
+ 1234
+ 0: 1234
+ 12-34
+ 0: 12-34
+ 12+\x{661}-34
+ 0: 12+\x{661}-34
+ ** Failers
+No match
+ abcd
+No match
+
+/[\P{Nd}]+/8
+ abcd
+ 0: abcd
+ ** Failers
+ 0: ** Failers
+ 1234
+No match
+
+/\D+/8
+ 11111111111111111111111111111111111111111111111111111111111111111111111
+No match
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 0: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+
+/\P{Nd}+/8
+ 11111111111111111111111111111111111111111111111111111111111111111111111
+No match
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 0: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+
+/[\D]+/8
+ 11111111111111111111111111111111111111111111111111111111111111111111111
+No match
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 0: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+
+/[\P{Nd}]+/8
+ 11111111111111111111111111111111111111111111111111111111111111111111111
+No match
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 0: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+
+/[\D\P{Nd}]+/8
+ 11111111111111111111111111111111111111111111111111111111111111111111111
+No match
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 0: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+
+/\pL/8
+ a
+ 0: a
+ A
+ 0: A
+
+/\pL/8i
+ a
+ 0: a
+ A
+ 0: A
+
+/\p{Lu}/8
+ A
+ 0: A
+ aZ
+ 0: Z
+ ** Failers
+ 0: F
+ abc
+No match
+
+/\p{Lu}/8i
+ A
+ 0: A
+ aZ
+ 0: Z
+ ** Failers
+ 0: F
+ abc
+No match
+
+/\p{Ll}/8
+ a
+ 0: a
+ Az
+ 0: z
+ ** Failers
+ 0: a
+ ABC
+No match
+
+/\p{Ll}/8i
+ a
+ 0: a
+ Az
+ 0: z
+ ** Failers
+ 0: a
+ ABC
+No match
+
+/^\x{c0}$/8i
+ \x{c0}
+ 0: \x{c0}
+ \x{e0}
+ 0: \x{e0}
+
+/^\x{e0}$/8i
+ \x{c0}
+ 0: \x{c0}
+ \x{e0}
+ 0: \x{e0}
+
+/A\x{391}\x{10427}\x{ff3a}\x{1fb0}/8
+ A\x{391}\x{10427}\x{ff3a}\x{1fb0}
+ 0: A\x{391}\x{10427}\x{ff3a}\x{1fb0}
+ ** Failers
+No match
+ a\x{391}\x{10427}\x{ff3a}\x{1fb0}
+No match
+ A\x{3b1}\x{10427}\x{ff3a}\x{1fb0}
+No match
+ A\x{391}\x{1044F}\x{ff3a}\x{1fb0}
+No match
+ A\x{391}\x{10427}\x{ff5a}\x{1fb0}
+No match
+ A\x{391}\x{10427}\x{ff3a}\x{1fb8}
+No match
+
+/A\x{391}\x{10427}\x{ff3a}\x{1fb0}/8i
+ A\x{391}\x{10427}\x{ff3a}\x{1fb0}
+ 0: A\x{391}\x{10427}\x{ff3a}\x{1fb0}
+ a\x{391}\x{10427}\x{ff3a}\x{1fb0}
+ 0: a\x{391}\x{10427}\x{ff3a}\x{1fb0}
+ A\x{3b1}\x{10427}\x{ff3a}\x{1fb0}
+ 0: A\x{3b1}\x{10427}\x{ff3a}\x{1fb0}
+ A\x{391}\x{1044F}\x{ff3a}\x{1fb0}
+ 0: A\x{391}\x{1044f}\x{ff3a}\x{1fb0}
+ A\x{391}\x{10427}\x{ff5a}\x{1fb0}
+ 0: A\x{391}\x{10427}\x{ff5a}\x{1fb0}
+ A\x{391}\x{10427}\x{ff3a}\x{1fb8}
+ 0: A\x{391}\x{10427}\x{ff3a}\x{1fb8}
+
+/A\x{391}\x{10427}\x{ff3a}\x{1fb0}/8iDZ
+------------------------------------------------------------------
+ Bra
+ NC A\x{391}\x{10427}\x{ff3a}\x{1fb0}
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: caseless utf8
+First char = 'A' (caseless)
+No need char
+
+/A\x{391}\x{10427}\x{ff3a}\x{1fb0}/8DZ
+------------------------------------------------------------------
+ Bra
+ A\x{391}\x{10427}\x{ff3a}\x{1fb0}
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 'A'
+Need char = 176
+
+/AB\x{1fb0}/8DZ
+------------------------------------------------------------------
+ Bra
+ AB\x{1fb0}
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 'A'
+Need char = 176
+
+/AB\x{1fb0}/8DZi
+------------------------------------------------------------------
+ Bra
+ NC AB\x{1fb0}
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: caseless utf8
+First char = 'A' (caseless)
+Need char = 'B' (caseless)
+
+/\x{391}+/8i
+ \x{391}\x{3b1}\x{3b1}\x{3b1}\x{391}
+ 0: \x{391}\x{3b1}\x{3b1}\x{3b1}\x{391}
+
+/\x{391}{3,5}(.)/8i
+ \x{391}\x{3b1}\x{3b1}\x{3b1}\x{391}X
+ 0: \x{391}\x{3b1}\x{3b1}\x{3b1}\x{391}X
+ 1: X
+
+/\x{391}{3,5}?(.)/8i
+ \x{391}\x{3b1}\x{3b1}\x{3b1}\x{391}X
+ 0: \x{391}\x{3b1}\x{3b1}\x{3b1}
+ 1: \x{3b1}
+
+/[\x{391}\x{ff3a}]/8i
+ \x{391}
+ 0: \x{391}
+ \x{ff3a}
+ 0: \x{ff3a}
+ \x{3b1}
+ 0: \x{3b1}
+ \x{ff5a}
+ 0: \x{ff5a}
+
+/[\x{c0}\x{391}]/8i
+ \x{c0}
+ 0: \x{c0}
+ \x{e0}
+ 0: \x{e0}
+
+/[\x{105}-\x{109}]/8iDZ
+------------------------------------------------------------------
+ Bra
+ [\x{104}-\x{109}]
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: caseless utf8
+No first char
+No need char
+ \x{104}
+ 0: \x{104}
+ \x{105}
+ 0: \x{105}
+ \x{109}
+ 0: \x{109}
+ ** Failers
+No match
+ \x{100}
+No match
+ \x{10a}
+No match
+
+/[z-\x{100}]/8iDZ
+------------------------------------------------------------------
+ Bra
+ [Z\x{39c}\x{178}z-\x{101}]
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: caseless utf8
+No first char
+No need char
+ Z
+ 0: Z
+ z
+ 0: z
+ \x{39c}
+ 0: \x{39c}
+ \x{178}
+ 0: \x{178}
+ |
+ 0: |
+ \x{80}
+ 0: \x{80}
+ \x{ff}
+ 0: \x{ff}
+ \x{100}
+ 0: \x{100}
+ \x{101}
+ 0: \x{101}
+ ** Failers
+No match
+ \x{102}
+No match
+ Y
+No match
+ y
+No match
+
+/[z-\x{100}]/8DZi
+------------------------------------------------------------------
+ Bra
+ [Z\x{39c}\x{178}z-\x{101}]
+ Ket
+ End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: caseless utf8
+No first char
+No need char
+
+/^\X/8
+ A
+ 0: A
+ A\x{300}BC
+ 0: A\x{300}
+ A\x{300}\x{301}\x{302}BC
+ 0: A\x{300}\x{301}\x{302}
+ *** Failers
+ 0: *
+ \x{300}
+No match
+
+/^[\X]/8
+ X123
+ 0: X
+ *** Failers
+No match
+ AXYZ
+No match
+
+/^(\X*)C/8
+ A\x{300}\x{301}\x{302}BCA\x{300}\x{301}
+ 0: A\x{300}\x{301}\x{302}BC
+ 1: A\x{300}\x{301}\x{302}B
+ A\x{300}\x{301}\x{302}BCA\x{300}\x{301}C
+ 0: A\x{300}\x{301}\x{302}BCA\x{300}\x{301}C
+ 1: A\x{300}\x{301}\x{302}BCA\x{300}\x{301}
+
+/^(\X*?)C/8
+ A\x{300}\x{301}\x{302}BCA\x{300}\x{301}
+ 0: A\x{300}\x{301}\x{302}BC
+ 1: A\x{300}\x{301}\x{302}B
+ A\x{300}\x{301}\x{302}BCA\x{300}\x{301}C
+ 0: A\x{300}\x{301}\x{302}BC
+ 1: A\x{300}\x{301}\x{302}B
+
+/^(\X*)(.)/8
+ A\x{300}\x{301}\x{302}BCA\x{300}\x{301}
+ 0: A\x{300}\x{301}\x{302}BCA
+ 1: A\x{300}\x{301}\x{302}BC
+ 2: A
+ A\x{300}\x{301}\x{302}BCA\x{300}\x{301}C
+ 0: A\x{300}\x{301}\x{302}BCA\x{300}\x{301}C
+ 1: A\x{300}\x{301}\x{302}BCA\x{300}\x{301}
+ 2: C
+
+/^(\X*?)(.)/8
+ A\x{300}\x{301}\x{302}BCA\x{300}\x{301}
+ 0: A
+ 1:
+ 2: A
+ A\x{300}\x{301}\x{302}BCA\x{300}\x{301}C
+ 0: A
+ 1:
+ 2: A
+
+/^\X(.)/8
+ *** Failers
+ 0: **
+ 1: *
+ A\x{300}\x{301}\x{302}
+No match
+
+/^\X{2,3}(.)/8
+ A\x{300}\x{301}B\x{300}X
+ 0: A\x{300}\x{301}B\x{300}X
+ 1: X
+ A\x{300}\x{301}B\x{300}C\x{300}\x{301}
+ 0: A\x{300}\x{301}B\x{300}C
+ 1: C
+ A\x{300}\x{301}B\x{300}C\x{300}\x{301}X
+ 0: A\x{300}\x{301}B\x{300}C\x{300}\x{301}X
+ 1: X
+ A\x{300}\x{301}B\x{300}C\x{300}\x{301}DA\x{300}X
+ 0: A\x{300}\x{301}B\x{300}C\x{300}\x{301}D
+ 1: D
+
+/^\X{2,3}?(.)/8
+ A\x{300}\x{301}B\x{300}X
+ 0: A\x{300}\x{301}B\x{300}X
+ 1: X
+ A\x{300}\x{301}B\x{300}C\x{300}\x{301}
+ 0: A\x{300}\x{301}B\x{300}C
+ 1: C
+ A\x{300}\x{301}B\x{300}C\x{300}\x{301}X
+ 0: A\x{300}\x{301}B\x{300}C
+ 1: C
+ A\x{300}\x{301}B\x{300}C\x{300}\x{301}DA\x{300}X
+ 0: A\x{300}\x{301}B\x{300}C
+ 1: C
+
+/^\p{Han}+/8
+ \x{2e81}\x{3007}\x{2f804}\x{31a0}
+ 0: \x{2e81}\x{3007}\x{2f804}
+ ** Failers
+No match
+ \x{2e7f}
+No match
+
+/^\P{Katakana}+/8
+ \x{3105}
+ 0: \x{3105}
+ ** Failers
+ 0: ** Failers
+ \x{30ff}
+No match
+
+/^[\p{Arabic}]/8
+ \x{06e9}
+ 0: \x{6e9}
+ \x{060b}
+ 0: \x{60b}
+ ** Failers
+No match
+ X\x{06e9}
+No match
+
+/^[\P{Yi}]/8
+ \x{2f800}
+ 0: \x{2f800}
+ ** Failers
+ 0: *
+ \x{a014}
+No match
+ \x{a4c6}
+No match
+
+/^\p{Any}X/8
+ AXYZ
+ 0: AX
+ \x{1234}XYZ
+ 0: \x{1234}X
+ ** Failers
+No match
+ X
+No match
+
+/^\P{Any}X/8
+ ** Failers
+No match
+ AX
+No match
+
+/^\p{Any}?X/8
+ XYZ
+ 0: X
+ AXYZ
+ 0: AX
+ \x{1234}XYZ
+ 0: \x{1234}X
+ ** Failers
+No match
+ ABXYZ
+No match
+
+/^\P{Any}?X/8
+ XYZ
+ 0: X
+ ** Failers
+No match
+ AXYZ
+No match
+ \x{1234}XYZ
+No match
+ ABXYZ
+No match
+
+/^\p{Any}+X/8
+ AXYZ
+ 0: AX
+ \x{1234}XYZ
+ 0: \x{1234}X
+ A\x{1234}XYZ
+ 0: A\x{1234}X
+ ** Failers
+No match
+ XYZ
+No match
+
+/^\P{Any}+X/8
+ ** Failers
+No match
+ AXYZ
+No match
+ \x{1234}XYZ
+No match
+ A\x{1234}XYZ
+No match
+ XYZ
+No match
+
+/^\p{Any}*X/8
+ XYZ
+ 0: X
+ AXYZ
+ 0: AX
+ \x{1234}XYZ
+ 0: \x{1234}X
+ A\x{1234}XYZ
+ 0: A\x{1234}X
+ ** Failers
+No match
+
+/^\P{Any}*X/8
+ XYZ
+ 0: X
+ ** Failers
+No match
+ AXYZ
+No match
+ \x{1234}XYZ
+No match
+ A\x{1234}XYZ
+No match
+
+/^[\p{Any}]X/8
+ AXYZ
+ 0: AX
+ \x{1234}XYZ
+ 0: \x{1234}X
+ ** Failers
+No match
+ X
+No match
+
+/^[\P{Any}]X/8
+ ** Failers
+No match
+ AX
+No match
+
+/^[\p{Any}]?X/8
+ XYZ
+ 0: X
+ AXYZ
+ 0: AX
+ \x{1234}XYZ
+ 0: \x{1234}X
+ ** Failers
+No match
+ ABXYZ
+No match
+
+/^[\P{Any}]?X/8
+ XYZ
+ 0: X
+ ** Failers
+No match
+ AXYZ
+No match
+ \x{1234}XYZ
+No match
+ ABXYZ
+No match
+
+/^[\p{Any}]+X/8
+ AXYZ
+ 0: AX
+ \x{1234}XYZ
+ 0: \x{1234}X
+ A\x{1234}XYZ
+ 0: A\x{1234}X
+ ** Failers
+No match
+ XYZ
+No match
+
+/^[\P{Any}]+X/8
+ ** Failers
+No match
+ AXYZ
+No match
+ \x{1234}XYZ
+No match
+ A\x{1234}XYZ
+No match
+ XYZ
+No match
+
+/^[\p{Any}]*X/8
+ XYZ
+ 0: X
+ AXYZ
+ 0: AX
+ \x{1234}XYZ
+ 0: \x{1234}X
+ A\x{1234}XYZ
+ 0: A\x{1234}X
+ ** Failers
+No match
+
+/^[\P{Any}]*X/8
+ XYZ
+ 0: X
+ ** Failers
+No match
+ AXYZ
+No match
+ \x{1234}XYZ
+No match
+ A\x{1234}XYZ
+No match
+
+/^\p{Any}{3,5}?/8
+ abcdefgh
+ 0: abc
+ \x{1234}\n\r\x{3456}xyz
+ 0: \x{1234}\x{0a}\x{0d}
+
+/^\p{Any}{3,5}/8
+ abcdefgh
+ 0: abcde
+ \x{1234}\n\r\x{3456}xyz
+ 0: \x{1234}\x{0a}\x{0d}\x{3456}x
+
+/^\P{Any}{3,5}?/8
+ ** Failers
+No match
+ abcdefgh
+No match
+ \x{1234}\n\r\x{3456}xyz
+No match
+
+/^\p{L&}X/8
+ AXY
+ 0: AX
+ aXY
+ 0: aX
+ \x{1c5}XY
+ 0: \x{1c5}X
+ ** Failers
+No match
+ \x{1bb}XY
+No match
+ \x{2b0}XY
+No match
+ !XY
+No match
+
+/^[\p{L&}]X/8
+ AXY
+ 0: AX
+ aXY
+ 0: aX
+ \x{1c5}XY
+ 0: \x{1c5}X
+ ** Failers
+No match
+ \x{1bb}XY
+No match
+ \x{2b0}XY
+No match
+ !XY
+No match
+
+/^\p{L&}+X/8
+ AXY
+ 0: AX
+ aXY
+ 0: aX
+ AbcdeXyz
+ 0: AbcdeX
+ \x{1c5}AbXY
+ 0: \x{1c5}AbX
+ abcDEXypqreXlmn
+ 0: abcDEXypqreX
+ ** Failers
+No match
+ \x{1bb}XY
+No match
+ \x{2b0}XY
+No match
+ !XY
+No match
+
+/^[\p{L&}]+X/8
+ AXY
+ 0: AX
+ aXY
+ 0: aX
+ AbcdeXyz
+ 0: AbcdeX
+ \x{1c5}AbXY
+ 0: \x{1c5}AbX
+ abcDEXypqreXlmn
+ 0: abcDEXypqreX
+ ** Failers
+No match
+ \x{1bb}XY
+No match
+ \x{2b0}XY
+No match
+ !XY
+No match
+
+/^\p{L&}+?X/8
+ AXY
+ 0: AX
+ aXY
+ 0: aX
+ AbcdeXyz
+ 0: AbcdeX
+ \x{1c5}AbXY
+ 0: \x{1c5}AbX
+ abcDEXypqreXlmn
+ 0: abcDEX
+ ** Failers
+No match
+ \x{1bb}XY
+No match
+ \x{2b0}XY
+No match
+ !XY
+No match
+
+/^[\p{L&}]+?X/8
+ AXY
+ 0: AX
+ aXY
+ 0: aX
+ AbcdeXyz
+ 0: AbcdeX
+ \x{1c5}AbXY
+ 0: \x{1c5}AbX
+ abcDEXypqreXlmn
+ 0: abcDEX
+ ** Failers
+No match
+ \x{1bb}XY
+No match
+ \x{2b0}XY
+No match
+ !XY
+No match
+
+/^\P{L&}X/8
+ !XY
+ 0: !X
+ \x{1bb}XY
+ 0: \x{1bb}X
+ \x{2b0}XY
+ 0: \x{2b0}X
+ ** Failers
+No match
+ \x{1c5}XY
+No match
+ AXY
+No match
+
+/^[\P{L&}]X/8
+ !XY
+ 0: !X
+ \x{1bb}XY
+ 0: \x{1bb}X
+ \x{2b0}XY
+ 0: \x{2b0}X
+ ** Failers
+No match
+ \x{1c5}XY
+No match
+ AXY
+No match
+
+/^(\p{Z}[^\p{C}\p{Z}]+)*$/
+ \xa0!
+ 0: \xa0!
+ 1: \xa0!
+
+/^[\pL](abc)(?1)/
+ AabcabcYZ
+ 0: Aabcabc
+ 1: abc
+
+/([\pL]=(abc))*X/
+ L=abcX
+ 0: L=abcX
+ 1: L=abc
+ 2: abc
+
+/The next two should be Perl-compatible, but it fails to match \x{e0}. PCRE
+will match it only with UCP support, because without that it has no notion
+of case for anything other than the ASCII letters. /
+
+/((?i)[\x{c0}])/8
+ \x{c0}
+ 0: \x{c0}
+ 1: \x{c0}
+ \x{e0}
+ 0: \x{e0}
+ 1: \x{e0}
+
+/(?i:[\x{c0}])/8
+ \x{c0}
+ 0: \x{c0}
+ \x{e0}
+ 0: \x{e0}
+
+/^\p{Balinese}\p{Cuneiform}\p{Nko}\p{Phags_Pa}\p{Phoenician}/8
+ \x{1b00}\x{12000}\x{7c0}\x{a840}\x{10900}
+ 0: \x{1b00}\x{12000}\x{7c0}\x{a840}\x{10900}
+
+/The next two are special cases where the lengths of the different cases of the
+same character differ. The first went wrong with heap fram storage; the 2nd
+was broken in all cases./
+
+/^\x{023a}+?(\x{0130}+)/8i
+ \x{023a}\x{2c65}\x{0130}
+ 0: \x{23a}\x{2c65}\x{130}
+ 1: \x{130}
+
+/^\x{023a}+([^X])/8i
+ \x{023a}\x{2c65}X
+ 0: \x{23a}\x{2c65}
+ 1: \x{2c65}
+
+/Check property support in non-UTF-8 mode/
+
+/\p{L}{4}/
+ 123abcdefg
+ 0: abcd
+ 123abc\xc4\xc5zz
+ 0: abc\xc4
+
+/\X{1,3}\d/
+ \x8aBCD
+No match
+
+/\X?\d/
+ \x8aBCD
+No match
+
+/\P{L}?\d/
+ \x8aBCD
+No match
+
+/[\PPP\x8a]{1,}\x80/
+ A\x80
+ 0: A\x80
+
+/(?:[\PPa*]*){8,}/
+
+/[\P{Any}]/BZ
+------------------------------------------------------------------
+ Bra
+ [\P{Any}]
+ Ket
+ End
+------------------------------------------------------------------
+
+/[\P{Any}\E]/BZ
+------------------------------------------------------------------
+ Bra
+ [\P{Any}]
+ Ket
+ End
+------------------------------------------------------------------
+
+/(\P{Yi}+\277)/
+
+/(\P{Yi}+\277)?/
+
+/(?<=\P{Yi}{3}A)X/
+
+/\p{Yi}+(\P{Yi}+)(?1)/
+
+/(\P{Yi}{2}\277)?/
+
+/[\P{Yi}A]/
+
+/[\P{Yi}\P{Yi}\P{Yi}A]/
+
+/[^\P{Yi}A]/
+
+/[^\P{Yi}\P{Yi}\P{Yi}A]/
+
+/(\P{Yi}*\277)*/
+
+/(\P{Yi}*?\277)*/
+
+/(\p{Yi}*+\277)*/
+
+/(\P{Yi}?\277)*/
+
+/(\P{Yi}??\277)*/
+
+/(\p{Yi}?+\277)*/
+
+/(\P{Yi}{0,3}\277)*/
+
+/(\P{Yi}{0,3}?\277)*/
+
+/(\p{Yi}{0,3}+\277)*/
+
+/^[\p{Arabic}]/8
+ \x{60e}
+ 0: \x{60e}
+ \x{656}
+ 0: \x{656}
+ \x{657}
+ 0: \x{657}
+ \x{658}
+ 0: \x{658}
+ \x{659}
+ 0: \x{659}
+ \x{65a}
+ 0: \x{65a}
+ \x{65b}
+ 0: \x{65b}
+ \x{65c}
+ 0: \x{65c}
+ \x{65d}
+ 0: \x{65d}
+ \x{65e}
+ 0: \x{65e}
+ \x{66a}
+ 0: \x{66a}
+ \x{6e9}
+ 0: \x{6e9}
+ \x{6ef}
+ 0: \x{6ef}
+ \x{6fa}
+ 0: \x{6fa}
+ ** Failers
+No match
+ \x{600}
+No match
+ \x{650}
+No match
+ \x{651}
+No match
+ \x{652}
+No match
+ \x{653}
+No match
+ \x{654}
+No match
+ \x{655}
+No match
+ \x{65f}
+No match
+
+/^\p{Cyrillic}/8
+ \x{1d2b}
+ 0: \x{1d2b}
+
+/^\p{Common}/8
+ \x{589}
+ 0: \x{589}
+ \x{60c}
+ 0: \x{60c}
+ \x{61f}
+ 0: \x{61f}
+ \x{964}
+ 0: \x{964}
+ \x{965}
+ 0: \x{965}
+ \x{970}
+ 0: \x{970}
+
+/^\p{Inherited}/8
+ \x{64b}
+ 0: \x{64b}
+ \x{654}
+ 0: \x{654}
+ \x{655}
+ 0: \x{655}
+ \x{200c}
+ 0: \x{200c}
+ ** Failers
+No match
+ \x{64a}
+No match
+ \x{656}
+No match
+
+/^\p{Shavian}/8
+ \x{10450}
+ 0: \x{10450}
+ \x{1047f}
+ 0: \x{1047f}
+
+/^\p{Deseret}/8
+ \x{10400}
+ 0: \x{10400}
+ \x{1044f}
+ 0: \x{1044f}
+
+/^\p{Osmanya}/8
+ \x{10480}
+ 0: \x{10480}
+ \x{1049d}
+ 0: \x{1049d}
+ \x{104a0}
+ 0: \x{104a0}
+ \x{104a9}
+ 0: \x{104a9}
+ ** Failers
+No match
+ \x{1049e}
+No match
+ \x{1049f}
+No match
+ \x{104aa}
+No match
+
+/\p{Zl}{2,3}+/8BZ
+------------------------------------------------------------------
+ Bra
+ prop Zl {2}
+ prop Zl ?+
+ Ket
+ End
+------------------------------------------------------------------
+ \xe2\x80\xa8\xe2\x80\xa8
+ 0: \x{2028}\x{2028}
+ \x{2028}\x{2028}\x{2028}
+ 0: \x{2028}\x{2028}\x{2028}
+
+/\p{Zl}/8BZ
+------------------------------------------------------------------
+ Bra
+ prop Zl
+ Ket
+ End
+------------------------------------------------------------------
+
+/\p{Lu}{3}+/8BZ
+------------------------------------------------------------------
+ Bra
+ prop Lu {3}
+ Ket
+ End
+------------------------------------------------------------------
+
+/\pL{2}+/8BZ
+------------------------------------------------------------------
+ Bra
+ prop L {2}
+ Ket
+ End
+------------------------------------------------------------------
+
+/\p{Cc}{2}+/8BZ
+------------------------------------------------------------------
+ Bra
+ prop Cc {2}
+ Ket
+ End
+------------------------------------------------------------------
+
+/ End of testinput6 /
diff --git a/lib/stdlib/test/re_SUITE_data/testoutput7 b/lib/stdlib/test/re_SUITE_data/testoutput7
new file mode 100644
index 0000000000..d8e3833f39
--- /dev/null
+++ b/lib/stdlib/test/re_SUITE_data/testoutput7
@@ -0,0 +1,7215 @@
+/abc/
+ abc
+ 0: abc
+
+/ab*c/
+ abc
+ 0: abc
+ abbbbc
+ 0: abbbbc
+ ac
+ 0: ac
+
+/ab+c/
+ abc
+ 0: abc
+ abbbbbbc
+ 0: abbbbbbc
+ *** Failers
+No match
+ ac
+No match
+ ab
+No match
+
+/a*/
+ a
+ 0: a
+ 1:
+ aaaaaaaaaaaaaaaaa
+ 0: aaaaaaaaaaaaaaaaa
+ 1: aaaaaaaaaaaaaaaa
+ 2: aaaaaaaaaaaaaaa
+ 3: aaaaaaaaaaaaaa
+ 4: aaaaaaaaaaaaa
+ 5: aaaaaaaaaaaa
+ 6: aaaaaaaaaaa
+ 7: aaaaaaaaaa
+ 8: aaaaaaaaa
+ 9: aaaaaaaa
+10: aaaaaaa
+11: aaaaaa
+12: aaaaa
+13: aaaa
+14: aaa
+15: aa
+16: a
+17:
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+Matched, but too many subsidiary matches
+ 0: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 1: aaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 2: aaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 3: aaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 4: aaaaaaaaaaaaaaaaaaaaaaaaaa
+ 5: aaaaaaaaaaaaaaaaaaaaaaaaa
+ 6: aaaaaaaaaaaaaaaaaaaaaaaa
+ 7: aaaaaaaaaaaaaaaaaaaaaaa
+ 8: aaaaaaaaaaaaaaaaaaaaaa
+ 9: aaaaaaaaaaaaaaaaaaaaa
+10: aaaaaaaaaaaaaaaaaaaa
+11: aaaaaaaaaaaaaaaaaaa
+12: aaaaaaaaaaaaaaaaaa
+13: aaaaaaaaaaaaaaaaa
+14: aaaaaaaaaaaaaaaa
+15: aaaaaaaaaaaaaaa
+16: aaaaaaaaaaaaaa
+17: aaaaaaaaaaaaa
+18: aaaaaaaaaaaa
+19: aaaaaaaaaaa
+20: aaaaaaaaaa
+21: aaaaaaaaa
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\F
+ 0:
+
+/(a|abcd|african)/
+ a
+ 0: a
+ abcd
+ 0: abcd
+ 1: a
+ african
+ 0: african
+ 1: a
+
+/^abc/
+ abcdef
+ 0: abc
+ *** Failers
+No match
+ xyzabc
+No match
+ xyz\nabc
+No match
+
+/^abc/m
+ abcdef
+ 0: abc
+ xyz\nabc
+ 0: abc
+ *** Failers
+No match
+ xyzabc
+No match
+
+/\Aabc/
+ abcdef
+ 0: abc
+ *** Failers
+No match
+ xyzabc
+No match
+ xyz\nabc
+No match
+
+/\Aabc/m
+ abcdef
+ 0: abc
+ *** Failers
+No match
+ xyzabc
+No match
+ xyz\nabc
+No match
+
+/\Gabc/
+ abcdef
+ 0: abc
+ xyzabc\>3
+ 0: abc
+ *** Failers
+No match
+ xyzabc
+No match
+ xyzabc\>2
+No match
+
+/x\dy\Dz/
+ x9yzz
+ 0: x9yzz
+ x0y+z
+ 0: x0y+z
+ *** Failers
+No match
+ xyz
+No match
+ xxy0z
+No match
+
+/x\sy\Sz/
+ x yzz
+ 0: x yzz
+ x y+z
+ 0: x y+z
+ *** Failers
+No match
+ xyz
+No match
+ xxyyz
+No match
+
+/x\wy\Wz/
+ xxy+z
+ 0: xxy+z
+ *** Failers
+No match
+ xxy0z
+No match
+ x+y+z
+No match
+
+/x.y/
+ x+y
+ 0: x+y
+ x-y
+ 0: x-y
+ *** Failers
+No match
+ x\ny
+No match
+
+/x.y/s
+ x+y
+ 0: x+y
+ x-y
+ 0: x-y
+ x\ny
+ 0: x\x0ay
+
+/(a.b(?s)c.d|x.y)p.q/
+ a+bc+dp+q
+ 0: a+bc+dp+q
+ a+bc\ndp+q
+ 0: a+bc\x0adp+q
+ x\nyp+q
+ 0: x\x0ayp+q
+ *** Failers
+No match
+ a\nbc\ndp+q
+No match
+ a+bc\ndp\nq
+No match
+ x\nyp\nq
+No match
+
+/a\d\z/
+ ba0
+ 0: a0
+ *** Failers
+No match
+ ba0\n
+No match
+ ba0\ncd
+No match
+
+/a\d\z/m
+ ba0
+ 0: a0
+ *** Failers
+No match
+ ba0\n
+No match
+ ba0\ncd
+No match
+
+/a\d\Z/
+ ba0
+ 0: a0
+ ba0\n
+ 0: a0
+ *** Failers
+No match
+ ba0\ncd
+No match
+
+/a\d\Z/m
+ ba0
+ 0: a0
+ ba0\n
+ 0: a0
+ *** Failers
+No match
+ ba0\ncd
+No match
+
+/a\d$/
+ ba0
+ 0: a0
+ ba0\n
+ 0: a0
+ *** Failers
+No match
+ ba0\ncd
+No match
+
+/a\d$/m
+ ba0
+ 0: a0
+ ba0\n
+ 0: a0
+ ba0\ncd
+ 0: a0
+ *** Failers
+No match
+
+/abc/i
+ abc
+ 0: abc
+ aBc
+ 0: aBc
+ ABC
+ 0: ABC
+
+/[^a]/
+ abcd
+ 0: b
+
+/ab?\w/
+ abz
+ 0: abz
+ 1: ab
+ abbz
+ 0: abb
+ 1: ab
+ azz
+ 0: az
+
+/x{0,3}yz/
+ ayzq
+ 0: yz
+ axyzq
+ 0: xyz
+ axxyz
+ 0: xxyz
+ axxxyzq
+ 0: xxxyz
+ axxxxyzq
+ 0: xxxyz
+ *** Failers
+No match
+ ax
+No match
+ axx
+No match
+
+/x{3}yz/
+ axxxyzq
+ 0: xxxyz
+ axxxxyzq
+ 0: xxxyz
+ *** Failers
+No match
+ ax
+No match
+ axx
+No match
+ ayzq
+No match
+ axyzq
+No match
+ axxyz
+No match
+
+/x{2,3}yz/
+ axxyz
+ 0: xxyz
+ axxxyzq
+ 0: xxxyz
+ axxxxyzq
+ 0: xxxyz
+ *** Failers
+No match
+ ax
+No match
+ axx
+No match
+ ayzq
+No match
+ axyzq
+No match
+
+/[^a]+/
+ bac
+ 0: b
+ bcdefax
+ 0: bcdef
+ 1: bcde
+ 2: bcd
+ 3: bc
+ 4: b
+ *** Failers
+ 0: *** F
+ 1: ***
+ 2: ***
+ 3: **
+ 4: *
+ aaaaa
+No match
+
+/[^a]*/
+ bac
+ 0: b
+ 1:
+ bcdefax
+ 0: bcdef
+ 1: bcde
+ 2: bcd
+ 3: bc
+ 4: b
+ 5:
+ *** Failers
+ 0: *** F
+ 1: ***
+ 2: ***
+ 3: **
+ 4: *
+ 5:
+ aaaaa
+ 0:
+
+/[^a]{3,5}/
+ xyz
+ 0: xyz
+ awxyza
+ 0: wxyz
+ 1: wxy
+ abcdefa
+ 0: bcdef
+ 1: bcde
+ 2: bcd
+ abcdefghijk
+ 0: bcdef
+ 1: bcde
+ 2: bcd
+ *** Failers
+ 0: *** F
+ 1: ***
+ 2: ***
+ axya
+No match
+ axa
+No match
+ aaaaa
+No match
+
+/\d*/
+ 1234b567
+ 0: 1234
+ 1: 123
+ 2: 12
+ 3: 1
+ 4:
+ xyz
+ 0:
+
+/\D*/
+ a1234b567
+ 0: a
+ 1:
+ xyz
+ 0: xyz
+ 1: xy
+ 2: x
+ 3:
+
+/\d+/
+ ab1234c56
+ 0: 1234
+ 1: 123
+ 2: 12
+ 3: 1
+ *** Failers
+No match
+ xyz
+No match
+
+/\D+/
+ ab123c56
+ 0: ab
+ 1: a
+ *** Failers
+ 0: *** Failers
+ 1: *** Failer
+ 2: *** Faile
+ 3: *** Fail
+ 4: *** Fai
+ 5: *** Fa
+ 6: *** F
+ 7: ***
+ 8: ***
+ 9: **
+10: *
+ 789
+No match
+
+/\d?A/
+ 045ABC
+ 0: 5A
+ ABC
+ 0: A
+ *** Failers
+No match
+ XYZ
+No match
+
+/\D?A/
+ ABC
+ 0: A
+ BAC
+ 0: BA
+ 9ABC
+ 0: A
+ *** Failers
+No match
+
+/a+/
+ aaaa
+ 0: aaaa
+ 1: aaa
+ 2: aa
+ 3: a
+
+/^.*xyz/
+ xyz
+ 0: xyz
+ ggggggggxyz
+ 0: ggggggggxyz
+
+/^.+xyz/
+ abcdxyz
+ 0: abcdxyz
+ axyz
+ 0: axyz
+ *** Failers
+No match
+ xyz
+No match
+
+/^.?xyz/
+ xyz
+ 0: xyz
+ cxyz
+ 0: cxyz
+
+/^\d{2,3}X/
+ 12X
+ 0: 12X
+ 123X
+ 0: 123X
+ *** Failers
+No match
+ X
+No match
+ 1X
+No match
+ 1234X
+No match
+
+/^[abcd]\d/
+ a45
+ 0: a4
+ b93
+ 0: b9
+ c99z
+ 0: c9
+ d04
+ 0: d0
+ *** Failers
+No match
+ e45
+No match
+ abcd
+No match
+ abcd1234
+No match
+ 1234
+No match
+
+/^[abcd]*\d/
+ a45
+ 0: a4
+ b93
+ 0: b9
+ c99z
+ 0: c9
+ d04
+ 0: d0
+ abcd1234
+ 0: abcd1
+ 1234
+ 0: 1
+ *** Failers
+No match
+ e45
+No match
+ abcd
+No match
+
+/^[abcd]+\d/
+ a45
+ 0: a4
+ b93
+ 0: b9
+ c99z
+ 0: c9
+ d04
+ 0: d0
+ abcd1234
+ 0: abcd1
+ *** Failers
+No match
+ 1234
+No match
+ e45
+No match
+ abcd
+No match
+
+/^a+X/
+ aX
+ 0: aX
+ aaX
+ 0: aaX
+
+/^[abcd]?\d/
+ a45
+ 0: a4
+ b93
+ 0: b9
+ c99z
+ 0: c9
+ d04
+ 0: d0
+ 1234
+ 0: 1
+ *** Failers
+No match
+ abcd1234
+No match
+ e45
+No match
+
+/^[abcd]{2,3}\d/
+ ab45
+ 0: ab4
+ bcd93
+ 0: bcd9
+ *** Failers
+No match
+ 1234
+No match
+ a36
+No match
+ abcd1234
+No match
+ ee45
+No match
+
+/^(abc)*\d/
+ abc45
+ 0: abc4
+ abcabcabc45
+ 0: abcabcabc4
+ 42xyz
+ 0: 4
+ *** Failers
+No match
+
+/^(abc)+\d/
+ abc45
+ 0: abc4
+ abcabcabc45
+ 0: abcabcabc4
+ *** Failers
+No match
+ 42xyz
+No match
+
+/^(abc)?\d/
+ abc45
+ 0: abc4
+ 42xyz
+ 0: 4
+ *** Failers
+No match
+ abcabcabc45
+No match
+
+/^(abc){2,3}\d/
+ abcabc45
+ 0: abcabc4
+ abcabcabc45
+ 0: abcabcabc4
+ *** Failers
+No match
+ abcabcabcabc45
+No match
+ abc45
+No match
+ 42xyz
+No match
+
+/1(abc|xyz)2(?1)3/
+ 1abc2abc3456
+ 0: 1abc2abc3
+ 1abc2xyz3456
+ 0: 1abc2xyz3
+
+/^(a*\w|ab)=(a*\w|ab)/
+ ab=ab
+ 0: ab=ab
+ 1: ab=a
+
+/^(a*\w|ab)=(?1)/
+ ab=ab
+ 0: ab=ab
+
+/^([^()]|\((?1)*\))*$/
+ abc
+ 0: abc
+ a(b)c
+ 0: a(b)c
+ a(b(c))d
+ 0: a(b(c))d
+ *** Failers)
+No match
+ a(b(c)d
+No match
+
+/^>abc>([^()]|\((?1)*\))*<xyz<$/
+ >abc>123<xyz<
+ 0: >abc>123<xyz<
+ >abc>1(2)3<xyz<
+ 0: >abc>1(2)3<xyz<
+ >abc>(1(2)3)<xyz<
+ 0: >abc>(1(2)3)<xyz<
+
+/^(?>a*)\d/
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa9876
+ 0: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa9
+ *** Failers
+No match
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+No match
+
+/< (?: (?(R) \d++ | [^<>]*+) | (?R)) * >/x
+ <>
+ 0: <>
+ <abcd>
+ 0: <abcd>
+ <abc <123> hij>
+ 0: <abc <123> hij>
+ <abc <def> hij>
+ 0: <def>
+ <abc<>def>
+ 0: <abc<>def>
+ <abc<>
+ 0: <>
+ *** Failers
+No match
+ <abc
+No match
+
+/^(?(?=abc)\w{3}:|\d\d)$/
+ abc:
+ 0: abc:
+ 12
+ 0: 12
+ *** Failers
+No match
+ 123
+No match
+ xyz
+No match
+
+/^(?(?!abc)\d\d|\w{3}:)$/
+ abc:
+ 0: abc:
+ 12
+ 0: 12
+ *** Failers
+No match
+ 123
+No match
+ xyz
+No match
+
+/^(?=abc)\w{5}:$/
+ abcde:
+ 0: abcde:
+ *** Failers
+No match
+ abc..
+No match
+ 123
+No match
+ vwxyz
+No match
+
+/^(?!abc)\d\d$/
+ 12
+ 0: 12
+ *** Failers
+No match
+ abcde:
+No match
+ abc..
+No match
+ 123
+No match
+ vwxyz
+No match
+
+/(?<=abc|xy)123/
+ abc12345
+ 0: 123
+ wxy123z
+ 0: 123
+ *** Failers
+No match
+ 123abc
+No match
+
+/(?<!abc|xy)123/
+ 123abc
+ 0: 123
+ mno123456
+ 0: 123
+ *** Failers
+No match
+ abc12345
+No match
+ wxy123z
+No match
+
+/abc(?C1)xyz/
+ abcxyz
+--->abcxyz
+ 1 ^ ^ x
+ 0: abcxyz
+ 123abcxyz999
+--->123abcxyz999
+ 1 ^ ^ x
+ 0: abcxyz
+
+/(ab|cd){3,4}/C
+ ababab
+--->ababab
+ +0 ^ (ab|cd){3,4}
+ +1 ^ a
+ +4 ^ c
+ +2 ^^ b
+ +3 ^ ^ |
+ +1 ^ ^ a
+ +4 ^ ^ c
+ +2 ^ ^ b
+ +3 ^ ^ |
+ +1 ^ ^ a
+ +4 ^ ^ c
+ +2 ^ ^ b
+ +3 ^ ^ |
++12 ^ ^
+ +1 ^ ^ a
+ +4 ^ ^ c
+ 0: ababab
+ abcdabcd
+--->abcdabcd
+ +0 ^ (ab|cd){3,4}
+ +1 ^ a
+ +4 ^ c
+ +2 ^^ b
+ +3 ^ ^ |
+ +1 ^ ^ a
+ +4 ^ ^ c
+ +5 ^ ^ d
+ +6 ^ ^ )
+ +1 ^ ^ a
+ +4 ^ ^ c
+ +2 ^ ^ b
+ +3 ^ ^ |
++12 ^ ^
+ +1 ^ ^ a
+ +4 ^ ^ c
+ +5 ^ ^ d
+ +6 ^ ^ )
++12 ^ ^
+ 0: abcdabcd
+ 1: abcdab
+ abcdcdcdcdcd
+--->abcdcdcdcdcd
+ +0 ^ (ab|cd){3,4}
+ +1 ^ a
+ +4 ^ c
+ +2 ^^ b
+ +3 ^ ^ |
+ +1 ^ ^ a
+ +4 ^ ^ c
+ +5 ^ ^ d
+ +6 ^ ^ )
+ +1 ^ ^ a
+ +4 ^ ^ c
+ +5 ^ ^ d
+ +6 ^ ^ )
++12 ^ ^
+ +1 ^ ^ a
+ +4 ^ ^ c
+ +5 ^ ^ d
+ +6 ^ ^ )
++12 ^ ^
+ 0: abcdcdcd
+ 1: abcdcd
+
+/^abc/
+ abcdef
+ 0: abc
+ *** Failers
+No match
+ abcdef\B
+No match
+
+/^(a*|xyz)/
+ bcd
+ 0:
+ aaabcd
+ 0: aaa
+ 1: aa
+ 2: a
+ 3:
+ xyz
+ 0: xyz
+ 1:
+ xyz\N
+ 0: xyz
+ *** Failers
+ 0:
+ bcd\N
+No match
+
+/xyz$/
+ xyz
+ 0: xyz
+ xyz\n
+ 0: xyz
+ *** Failers
+No match
+ xyz\Z
+No match
+ xyz\n\Z
+No match
+
+/xyz$/m
+ xyz
+ 0: xyz
+ xyz\n
+ 0: xyz
+ abcxyz\npqr
+ 0: xyz
+ abcxyz\npqr\Z
+ 0: xyz
+ xyz\n\Z
+ 0: xyz
+ *** Failers
+No match
+ xyz\Z
+No match
+
+/\Gabc/
+ abcdef
+ 0: abc
+ defabcxyz\>3
+ 0: abc
+ *** Failers
+No match
+ defabcxyz
+No match
+
+/^abcdef/
+ ab\P
+Partial match: ab
+ abcde\P
+Partial match: abcde
+ abcdef\P
+ 0: abcdef
+ *** Failers
+No match
+ abx\P
+No match
+
+/^a{2,4}\d+z/
+ a\P
+Partial match: a
+ aa\P
+Partial match: aa
+ aa2\P
+Partial match: aa2
+ aaa\P
+Partial match: aaa
+ aaa23\P
+Partial match: aaa23
+ aaaa12345\P
+Partial match: aaaa12345
+ aa0z\P
+ 0: aa0z
+ aaaa4444444444444z\P
+ 0: aaaa4444444444444z
+ *** Failers
+No match
+ az\P
+No match
+ aaaaa\P
+No match
+ a56\P
+No match
+
+/^abcdef/
+ abc\P
+Partial match: abc
+ def\R
+ 0: def
+
+/(?<=foo)bar/
+ xyzfo\P
+No match
+ foob\P\>2
+Partial match: b
+ foobar...\R\P\>4
+ 0: ar
+ xyzfo\P
+No match
+ foobar\>2
+ 0: bar
+ *** Failers
+No match
+ xyzfo\P
+No match
+ obar\R
+No match
+
+/(ab*(cd|ef))+X/
+ adfadadaklhlkalkajhlkjahdfasdfasdfladsfjkj\P\Z
+No match
+ lkjhlkjhlkjhlkjhabbbbbbcdaefabbbbbbbefa\P\B\Z
+Partial match: abbbbbbcdaefabbbbbbbefa
+ cdabbbbbbbb\P\R\B\Z
+Partial match: cdabbbbbbbb
+ efabbbbbbbbbbbbbbbb\P\R\B\Z
+Partial match: efabbbbbbbbbbbbbbbb
+ bbbbbbbbbbbbcdXyasdfadf\P\R\B\Z
+ 0: bbbbbbbbbbbbcdX
+
+/(a|b)/SF>testsavedregex
+Compiled regex written to testsavedregex
+Study data written to testsavedregex
+<testsavedregex
+Compiled regex (byte-inverted) loaded from testsavedregex
+Study data loaded from testsavedregex
+ abc
+ 0: a
+ ** Failers
+ 0: a
+ def
+No match
+
+/the quick brown fox/
+ the quick brown fox
+ 0: the quick brown fox
+ The quick brown FOX
+No match
+ What do you know about the quick brown fox?
+ 0: the quick brown fox
+ What do you know about THE QUICK BROWN FOX?
+No match
+
+/The quick brown fox/i
+ the quick brown fox
+ 0: the quick brown fox
+ The quick brown FOX
+ 0: The quick brown FOX
+ What do you know about the quick brown fox?
+ 0: the quick brown fox
+ What do you know about THE QUICK BROWN FOX?
+ 0: THE QUICK BROWN FOX
+
+/abcd\t\n\r\f\a\e\071\x3b\$\\\?caxyz/
+ abcd\t\n\r\f\a\e9;\$\\?caxyz
+ 0: abcd\x09\x0a\x0d\x0c\x07\x1b9;$\?caxyz
+
+/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/
+ abxyzpqrrrabbxyyyypqAzz
+ 0: abxyzpqrrrabbxyyyypqAzz
+ abxyzpqrrrabbxyyyypqAzz
+ 0: abxyzpqrrrabbxyyyypqAzz
+ aabxyzpqrrrabbxyyyypqAzz
+ 0: aabxyzpqrrrabbxyyyypqAzz
+ aaabxyzpqrrrabbxyyyypqAzz
+ 0: aaabxyzpqrrrabbxyyyypqAzz
+ aaaabxyzpqrrrabbxyyyypqAzz
+ 0: aaaabxyzpqrrrabbxyyyypqAzz
+ abcxyzpqrrrabbxyyyypqAzz
+ 0: abcxyzpqrrrabbxyyyypqAzz
+ aabcxyzpqrrrabbxyyyypqAzz
+ 0: aabcxyzpqrrrabbxyyyypqAzz
+ aaabcxyzpqrrrabbxyyyypAzz
+ 0: aaabcxyzpqrrrabbxyyyypAzz
+ aaabcxyzpqrrrabbxyyyypqAzz
+ 0: aaabcxyzpqrrrabbxyyyypqAzz
+ aaabcxyzpqrrrabbxyyyypqqAzz
+ 0: aaabcxyzpqrrrabbxyyyypqqAzz
+ aaabcxyzpqrrrabbxyyyypqqqAzz
+ 0: aaabcxyzpqrrrabbxyyyypqqqAzz
+ aaabcxyzpqrrrabbxyyyypqqqqAzz
+ 0: aaabcxyzpqrrrabbxyyyypqqqqAzz
+ aaabcxyzpqrrrabbxyyyypqqqqqAzz
+ 0: aaabcxyzpqrrrabbxyyyypqqqqqAzz
+ aaabcxyzpqrrrabbxyyyypqqqqqqAzz
+ 0: aaabcxyzpqrrrabbxyyyypqqqqqqAzz
+ aaaabcxyzpqrrrabbxyyyypqAzz
+ 0: aaaabcxyzpqrrrabbxyyyypqAzz
+ abxyzzpqrrrabbxyyyypqAzz
+ 0: abxyzzpqrrrabbxyyyypqAzz
+ aabxyzzzpqrrrabbxyyyypqAzz
+ 0: aabxyzzzpqrrrabbxyyyypqAzz
+ aaabxyzzzzpqrrrabbxyyyypqAzz
+ 0: aaabxyzzzzpqrrrabbxyyyypqAzz
+ aaaabxyzzzzpqrrrabbxyyyypqAzz
+ 0: aaaabxyzzzzpqrrrabbxyyyypqAzz
+ abcxyzzpqrrrabbxyyyypqAzz
+ 0: abcxyzzpqrrrabbxyyyypqAzz
+ aabcxyzzzpqrrrabbxyyyypqAzz
+ 0: aabcxyzzzpqrrrabbxyyyypqAzz
+ aaabcxyzzzzpqrrrabbxyyyypqAzz
+ 0: aaabcxyzzzzpqrrrabbxyyyypqAzz
+ aaaabcxyzzzzpqrrrabbxyyyypqAzz
+ 0: aaaabcxyzzzzpqrrrabbxyyyypqAzz
+ aaaabcxyzzzzpqrrrabbbxyyyypqAzz
+ 0: aaaabcxyzzzzpqrrrabbbxyyyypqAzz
+ aaaabcxyzzzzpqrrrabbbxyyyyypqAzz
+ 0: aaaabcxyzzzzpqrrrabbbxyyyyypqAzz
+ aaabcxyzpqrrrabbxyyyypABzz
+ 0: aaabcxyzpqrrrabbxyyyypABzz
+ aaabcxyzpqrrrabbxyyyypABBzz
+ 0: aaabcxyzpqrrrabbxyyyypABBzz
+ >>>aaabxyzpqrrrabbxyyyypqAzz
+ 0: aaabxyzpqrrrabbxyyyypqAzz
+ >aaaabxyzpqrrrabbxyyyypqAzz
+ 0: aaaabxyzpqrrrabbxyyyypqAzz
+ >>>>abcxyzpqrrrabbxyyyypqAzz
+ 0: abcxyzpqrrrabbxyyyypqAzz
+ *** Failers
+No match
+ abxyzpqrrabbxyyyypqAzz
+No match
+ abxyzpqrrrrabbxyyyypqAzz
+No match
+ abxyzpqrrrabxyyyypqAzz
+No match
+ aaaabcxyzzzzpqrrrabbbxyyyyyypqAzz
+No match
+ aaaabcxyzzzzpqrrrabbbxyyypqAzz
+No match
+ aaabcxyzpqrrrabbxyyyypqqqqqqqAzz
+No match
+
+/^(abc){1,2}zz/
+ abczz
+ 0: abczz
+ abcabczz
+ 0: abcabczz
+ *** Failers
+No match
+ zz
+No match
+ abcabcabczz
+No match
+ >>abczz
+No match
+
+/^(b+?|a){1,2}?c/
+ bc
+ 0: bc
+ bbc
+ 0: bbc
+ bbbc
+ 0: bbbc
+ bac
+ 0: bac
+ bbac
+ 0: bbac
+ aac
+ 0: aac
+ abbbbbbbbbbbc
+ 0: abbbbbbbbbbbc
+ bbbbbbbbbbbac
+ 0: bbbbbbbbbbbac
+ *** Failers
+No match
+ aaac
+No match
+ abbbbbbbbbbbac
+No match
+
+/^(b+|a){1,2}c/
+ bc
+ 0: bc
+ bbc
+ 0: bbc
+ bbbc
+ 0: bbbc
+ bac
+ 0: bac
+ bbac
+ 0: bbac
+ aac
+ 0: aac
+ abbbbbbbbbbbc
+ 0: abbbbbbbbbbbc
+ bbbbbbbbbbbac
+ 0: bbbbbbbbbbbac
+ *** Failers
+No match
+ aaac
+No match
+ abbbbbbbbbbbac
+No match
+
+/^(b+|a){1,2}?bc/
+ bbc
+ 0: bbc
+
+/^(b*|ba){1,2}?bc/
+ babc
+ 0: babc
+ bbabc
+ 0: bbabc
+ bababc
+ 0: bababc
+ *** Failers
+No match
+ bababbc
+No match
+ babababc
+No match
+
+/^(ba|b*){1,2}?bc/
+ babc
+ 0: babc
+ bbabc
+ 0: bbabc
+ bababc
+ 0: bababc
+ *** Failers
+No match
+ bababbc
+No match
+ babababc
+No match
+
+/^\ca\cA\c[\c{\c:/
+ \x01\x01\e;z
+ 0: \x01\x01\x1b;z
+
+/^[ab\]cde]/
+ athing
+ 0: a
+ bthing
+ 0: b
+ ]thing
+ 0: ]
+ cthing
+ 0: c
+ dthing
+ 0: d
+ ething
+ 0: e
+ *** Failers
+No match
+ fthing
+No match
+ [thing
+No match
+ \\thing
+No match
+
+/^[]cde]/
+ ]thing
+ 0: ]
+ cthing
+ 0: c
+ dthing
+ 0: d
+ ething
+ 0: e
+ *** Failers
+No match
+ athing
+No match
+ fthing
+No match
+
+/^[^ab\]cde]/
+ fthing
+ 0: f
+ [thing
+ 0: [
+ \\thing
+ 0: \
+ *** Failers
+ 0: *
+ athing
+No match
+ bthing
+No match
+ ]thing
+No match
+ cthing
+No match
+ dthing
+No match
+ ething
+No match
+
+/^[^]cde]/
+ athing
+ 0: a
+ fthing
+ 0: f
+ *** Failers
+ 0: *
+ ]thing
+No match
+ cthing
+No match
+ dthing
+No match
+ ething
+No match
+
+/^\�/
+ �
+ 0: \x81
+
+/^�/
+ �
+ 0: \xff
+
+/^[0-9]+$/
+ 0
+ 0: 0
+ 1
+ 0: 1
+ 2
+ 0: 2
+ 3
+ 0: 3
+ 4
+ 0: 4
+ 5
+ 0: 5
+ 6
+ 0: 6
+ 7
+ 0: 7
+ 8
+ 0: 8
+ 9
+ 0: 9
+ 10
+ 0: 10
+ 100
+ 0: 100
+ *** Failers
+No match
+ abc
+No match
+
+/^.*nter/
+ enter
+ 0: enter
+ inter
+ 0: inter
+ uponter
+ 0: uponter
+
+/^xxx[0-9]+$/
+ xxx0
+ 0: xxx0
+ xxx1234
+ 0: xxx1234
+ *** Failers
+No match
+ xxx
+No match
+
+/^.+[0-9][0-9][0-9]$/
+ x123
+ 0: x123
+ xx123
+ 0: xx123
+ 123456
+ 0: 123456
+ *** Failers
+No match
+ 123
+No match
+ x1234
+ 0: x1234
+
+/^.+?[0-9][0-9][0-9]$/
+ x123
+ 0: x123
+ xx123
+ 0: xx123
+ 123456
+ 0: 123456
+ *** Failers
+No match
+ 123
+No match
+ x1234
+ 0: x1234
+
+/^([^!]+)!(.+)=apquxz\.ixr\.zzz\.ac\.uk$/
+ abc!pqr=apquxz.ixr.zzz.ac.uk
+ 0: abc!pqr=apquxz.ixr.zzz.ac.uk
+ *** Failers
+No match
+ !pqr=apquxz.ixr.zzz.ac.uk
+No match
+ abc!=apquxz.ixr.zzz.ac.uk
+No match
+ abc!pqr=apquxz:ixr.zzz.ac.uk
+No match
+ abc!pqr=apquxz.ixr.zzz.ac.ukk
+No match
+
+/:/
+ Well, we need a colon: somewhere
+ 0: :
+ *** Fail if we don't
+No match
+
+/([\da-f:]+)$/i
+ 0abc
+ 0: 0abc
+ abc
+ 0: abc
+ fed
+ 0: fed
+ E
+ 0: E
+ ::
+ 0: ::
+ 5f03:12C0::932e
+ 0: 5f03:12C0::932e
+ fed def
+ 0: def
+ Any old stuff
+ 0: ff
+ *** Failers
+No match
+ 0zzz
+No match
+ gzzz
+No match
+ fed\x20
+No match
+ Any old rubbish
+No match
+
+/^.*\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/
+ .1.2.3
+ 0: .1.2.3
+ A.12.123.0
+ 0: A.12.123.0
+ *** Failers
+No match
+ .1.2.3333
+No match
+ 1.2.3
+No match
+ 1234.2.3
+No match
+
+/^(\d+)\s+IN\s+SOA\s+(\S+)\s+(\S+)\s*\(\s*$/
+ 1 IN SOA non-sp1 non-sp2(
+ 0: 1 IN SOA non-sp1 non-sp2(
+ 1 IN SOA non-sp1 non-sp2 (
+ 0: 1 IN SOA non-sp1 non-sp2 (
+ *** Failers
+No match
+ 1IN SOA non-sp1 non-sp2(
+No match
+
+/^[a-zA-Z\d][a-zA-Z\d\-]*(\.[a-zA-Z\d][a-zA-z\d\-]*)*\.$/
+ a.
+ 0: a.
+ Z.
+ 0: Z.
+ 2.
+ 0: 2.
+ ab-c.pq-r.
+ 0: ab-c.pq-r.
+ sxk.zzz.ac.uk.
+ 0: sxk.zzz.ac.uk.
+ x-.y-.
+ 0: x-.y-.
+ *** Failers
+No match
+ -abc.peq.
+No match
+
+/^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$/
+ *.a
+ 0: *.a
+ *.b0-a
+ 0: *.b0-a
+ *.c3-b.c
+ 0: *.c3-b.c
+ *.c-a.b-c
+ 0: *.c-a.b-c
+ *** Failers
+No match
+ *.0
+No match
+ *.a-
+No match
+ *.a-b.c-
+No match
+ *.c-a.0-c
+No match
+
+/^(?=ab(de))(abd)(e)/
+ abde
+ 0: abde
+
+/^(?!(ab)de|x)(abd)(f)/
+ abdf
+ 0: abdf
+
+/^(?=(ab(cd)))(ab)/
+ abcd
+ 0: ab
+
+/^[\da-f](\.[\da-f])*$/i
+ a.b.c.d
+ 0: a.b.c.d
+ A.B.C.D
+ 0: A.B.C.D
+ a.b.c.1.2.3.C
+ 0: a.b.c.1.2.3.C
+
+/^\".*\"\s*(;.*)?$/
+ \"1234\"
+ 0: "1234"
+ \"abcd\" ;
+ 0: "abcd" ;
+ \"\" ; rhubarb
+ 0: "" ; rhubarb
+ *** Failers
+No match
+ \"1234\" : things
+No match
+
+/^$/
+ \
+ 0:
+ *** Failers
+No match
+
+/ ^ a (?# begins with a) b\sc (?# then b c) $ (?# then end)/x
+ ab c
+ 0: ab c
+ *** Failers
+No match
+ abc
+No match
+ ab cde
+No match
+
+/(?x) ^ a (?# begins with a) b\sc (?# then b c) $ (?# then end)/
+ ab c
+ 0: ab c
+ *** Failers
+No match
+ abc
+No match
+ ab cde
+No match
+
+/^ a\ b[c ]d $/x
+ a bcd
+ 0: a bcd
+ a b d
+ 0: a b d
+ *** Failers
+No match
+ abcd
+No match
+ ab d
+No match
+
+/^(a(b(c)))(d(e(f)))(h(i(j)))(k(l(m)))$/
+ abcdefhijklm
+ 0: abcdefhijklm
+
+/^(?:a(b(c)))(?:d(e(f)))(?:h(i(j)))(?:k(l(m)))$/
+ abcdefhijklm
+ 0: abcdefhijklm
+
+/^[\w][\W][\s][\S][\d][\D][\b][\n][\c]][\022]/
+ a+ Z0+\x08\n\x1d\x12
+ 0: a+ Z0+\x08\x0a\x1d\x12
+
+/^[.^$|()*+?{,}]+/
+ .^\$(*+)|{?,?}
+ 0: .^$(*+)|{?,?}
+ 1: .^$(*+)|{?,?
+ 2: .^$(*+)|{?,
+ 3: .^$(*+)|{?
+ 4: .^$(*+)|{
+ 5: .^$(*+)|
+ 6: .^$(*+)
+ 7: .^$(*+
+ 8: .^$(*
+ 9: .^$(
+10: .^$
+11: .^
+12: .
+
+/^a*\w/
+ z
+ 0: z
+ az
+ 0: az
+ 1: a
+ aaaz
+ 0: aaaz
+ 1: aaa
+ 2: aa
+ 3: a
+ a
+ 0: a
+ aa
+ 0: aa
+ 1: a
+ aaaa
+ 0: aaaa
+ 1: aaa
+ 2: aa
+ 3: a
+ a+
+ 0: a
+ aa+
+ 0: aa
+ 1: a
+
+/^a*?\w/
+ z
+ 0: z
+ az
+ 0: az
+ 1: a
+ aaaz
+ 0: aaaz
+ 1: aaa
+ 2: aa
+ 3: a
+ a
+ 0: a
+ aa
+ 0: aa
+ 1: a
+ aaaa
+ 0: aaaa
+ 1: aaa
+ 2: aa
+ 3: a
+ a+
+ 0: a
+ aa+
+ 0: aa
+ 1: a
+
+/^a+\w/
+ az
+ 0: az
+ aaaz
+ 0: aaaz
+ 1: aaa
+ 2: aa
+ aa
+ 0: aa
+ aaaa
+ 0: aaaa
+ 1: aaa
+ 2: aa
+ aa+
+ 0: aa
+
+/^a+?\w/
+ az
+ 0: az
+ aaaz
+ 0: aaaz
+ 1: aaa
+ 2: aa
+ aa
+ 0: aa
+ aaaa
+ 0: aaaa
+ 1: aaa
+ 2: aa
+ aa+
+ 0: aa
+
+/^\d{8}\w{2,}/
+ 1234567890
+ 0: 1234567890
+ 12345678ab
+ 0: 12345678ab
+ 12345678__
+ 0: 12345678__
+ *** Failers
+No match
+ 1234567
+No match
+
+/^[aeiou\d]{4,5}$/
+ uoie
+ 0: uoie
+ 1234
+ 0: 1234
+ 12345
+ 0: 12345
+ aaaaa
+ 0: aaaaa
+ *** Failers
+No match
+ 123456
+No match
+
+/^[aeiou\d]{4,5}?/
+ uoie
+ 0: uoie
+ 1234
+ 0: 1234
+ 12345
+ 0: 12345
+ 1: 1234
+ aaaaa
+ 0: aaaaa
+ 1: aaaa
+ 123456
+ 0: 12345
+ 1: 1234
+
+/^From +([^ ]+) +[a-zA-Z][a-zA-Z][a-zA-Z] +[a-zA-Z][a-zA-Z][a-zA-Z] +[0-9]?[0-9] +[0-9][0-9]:[0-9][0-9]/
+ From abcd Mon Sep 01 12:33:02 1997
+ 0: From abcd Mon Sep 01 12:33
+
+/^From\s+\S+\s+([a-zA-Z]{3}\s+){2}\d{1,2}\s+\d\d:\d\d/
+ From abcd Mon Sep 01 12:33:02 1997
+ 0: From abcd Mon Sep 01 12:33
+ From abcd Mon Sep 1 12:33:02 1997
+ 0: From abcd Mon Sep 1 12:33
+ *** Failers
+No match
+ From abcd Sep 01 12:33:02 1997
+No match
+
+/^12.34/s
+ 12\n34
+ 0: 12\x0a34
+ 12\r34
+ 0: 12\x0d34
+
+/\w+(?=\t)/
+ the quick brown\t fox
+ 0: brown
+
+/foo(?!bar)(.*)/
+ foobar is foolish see?
+ 0: foolish see?
+ 1: foolish see
+ 2: foolish se
+ 3: foolish s
+ 4: foolish
+ 5: foolish
+ 6: foolis
+ 7: fooli
+ 8: fool
+ 9: foo
+
+/(?:(?!foo)...|^.{0,2})bar(.*)/
+ foobar crowbar etc
+ 0: rowbar etc
+ 1: rowbar et
+ 2: rowbar e
+ 3: rowbar
+ 4: rowbar
+ barrel
+ 0: barrel
+ 1: barre
+ 2: barr
+ 3: bar
+ 2barrel
+ 0: 2barrel
+ 1: 2barre
+ 2: 2barr
+ 3: 2bar
+ A barrel
+ 0: A barrel
+ 1: A barre
+ 2: A barr
+ 3: A bar
+
+/^(\D*)(?=\d)(?!123)/
+ abc456
+ 0: abc
+ *** Failers
+No match
+ abc123
+No match
+
+/^1234(?# test newlines
+ inside)/
+ 1234
+ 0: 1234
+
+/^1234 #comment in extended re
+ /x
+ 1234
+ 0: 1234
+
+/#rhubarb
+ abcd/x
+ abcd
+ 0: abcd
+
+/^abcd#rhubarb/x
+ abcd
+ 0: abcd
+
+/(?!^)abc/
+ the abc
+ 0: abc
+ *** Failers
+No match
+ abc
+No match
+
+/(?=^)abc/
+ abc
+ 0: abc
+ *** Failers
+No match
+ the abc
+No match
+
+/^[ab]{1,3}(ab*|b)/
+ aabbbbb
+ 0: aabbbbb
+ 1: aabbbb
+ 2: aabbb
+ 3: aabb
+ 4: aab
+ 5: aa
+
+/^[ab]{1,3}?(ab*|b)/
+ aabbbbb
+ 0: aabbbbb
+ 1: aabbbb
+ 2: aabbb
+ 3: aabb
+ 4: aab
+ 5: aa
+
+/^[ab]{1,3}?(ab*?|b)/
+ aabbbbb
+ 0: aabbbbb
+ 1: aabbbb
+ 2: aabbb
+ 3: aabb
+ 4: aab
+ 5: aa
+
+/^[ab]{1,3}(ab*?|b)/
+ aabbbbb
+ 0: aabbbbb
+ 1: aabbbb
+ 2: aabbb
+ 3: aabb
+ 4: aab
+ 5: aa
+
+/ (?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* # optional leading comment
+(?: (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+" (?: # opening quote...
+[^\\\x80-\xff\n\015"] # Anything except backslash and quote
+| # or
+\\ [^\x80-\xff] # Escaped something (something != CR)
+)* " # closing quote
+) # initial word
+(?: (?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* \. (?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+" (?: # opening quote...
+[^\\\x80-\xff\n\015"] # Anything except backslash and quote
+| # or
+\\ [^\x80-\xff] # Escaped something (something != CR)
+)* " # closing quote
+) )* # further okay, if led by a period
+(?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* @ (?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+| \[ # [
+(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff
+\] # ]
+) # initial subdomain
+(?: #
+(?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* \. # if led by a period...
+(?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+| \[ # [
+(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff
+\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+" (?: # opening quote...
+[^\\\x80-\xff\n\015"] # Anything except backslash and quote
+| # or
+\\ [^\x80-\xff] # Escaped something (something != CR)
+)* " # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] | # atom and space parts, or...
+\(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) | # comments, or...
+
+" (?: # opening quote...
+[^\\\x80-\xff\n\015"] # Anything except backslash and quote
+| # or
+\\ [^\x80-\xff] # Escaped something (something != CR)
+)* " # closing quote
+# quoted strings
+)*
+< (?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* # leading <
+(?: @ (?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+| \[ # [
+(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff
+\] # ]
+) # initial subdomain
+(?: #
+(?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* \. # if led by a period...
+(?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+| \[ # [
+(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff
+\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* , (?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* @ (?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+| \[ # [
+(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff
+\] # ]
+) # initial subdomain
+(?: #
+(?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* \. # if led by a period...
+(?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+| \[ # [
+(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff
+\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* )? # optional route
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+" (?: # opening quote...
+[^\\\x80-\xff\n\015"] # Anything except backslash and quote
+| # or
+\\ [^\x80-\xff] # Escaped something (something != CR)
+)* " # closing quote
+) # initial word
+(?: (?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* \. (?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+" (?: # opening quote...
+[^\\\x80-\xff\n\015"] # Anything except backslash and quote
+| # or
+\\ [^\x80-\xff] # Escaped something (something != CR)
+)* " # closing quote
+) )* # further okay, if led by a period
+(?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* @ (?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+| \[ # [
+(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff
+\] # ]
+) # initial subdomain
+(?: #
+(?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* \. # if led by a period...
+(?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+| \[ # [
+(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff
+\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* > # trailing >
+# name and address
+) (?: [\040\t] | \(
+(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )*
+\) )* # optional trailing comment
+/x
+ Alan Other <user\@dom.ain>
+ 0: Alan Other <[email protected]>
+ <user\@dom.ain>
+ 1: user@dom
+ user\@dom.ain
+ 1: user@dom
+ \"A. Other\" <user.1234\@dom.ain> (a comment)
+ 0: "A. Other" <[email protected]> (a comment)
+ 1: "A. Other" <[email protected]>
+ 2: "A. Other" <[email protected]>
+ A. Other <user.1234\@dom.ain> (a comment)
+ 0: Other <[email protected]> (a comment)
+ 1: Other <[email protected]>
+ 2: Other <[email protected]>
+ \"/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/\"\@x400-re.lay
+ 0: "/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/"@x400-re.lay
+ 1: "/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/"@x400-re
+ A missing angle <user\@some.where
+ 1: user@some
+ *** Failers
+No match
+ The quick brown fox
+No match
+
+/[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+" # "
+[^\\\x80-\xff\n\015"] * # normal
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )*
+" # "
+# Quoted string
+)
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+(?:
+\.
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+" # "
+[^\\\x80-\xff\n\015"] * # normal
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )*
+" # "
+# Quoted string
+)
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+\[ # [
+(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff
+\] # ]
+)
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\.
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+\[ # [
+(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff
+\] # ]
+)
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+" # "
+[^\\\x80-\xff\n\015"] * # normal
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )*
+" # "
+# Quoted string
+)
+# leading word
+[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # "normal" atoms and or spaces
+(?:
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+|
+" # "
+[^\\\x80-\xff\n\015"] * # normal
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )*
+" # "
+) # "special" comment or quoted string
+[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # more "normal"
+)*
+<
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+\[ # [
+(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff
+\] # ]
+)
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\.
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+\[ # [
+(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff
+\] # ]
+)
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+@
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+\[ # [
+(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff
+\] # ]
+)
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\.
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+\[ # [
+(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff
+\] # ]
+)
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+" # "
+[^\\\x80-\xff\n\015"] * # normal
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )*
+" # "
+# Quoted string
+)
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+(?:
+\.
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+" # "
+[^\\\x80-\xff\n\015"] * # normal
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )*
+" # "
+# Quoted string
+)
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+\[ # [
+(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff
+\] # ]
+)
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\.
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+\[ # [
+(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff
+\] # ]
+)
+[\040\t]* # Nab whitespace.
+(?:
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: # (
+(?: \\ [^\x80-\xff] |
+\( # (
+[^\\\x80-\xff\n\015()] * # normal*
+(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)*
+\) # )
+) # special
+[^\\\x80-\xff\n\015()] * # normal*
+)* # )*
+\) # )
+[\040\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)
+/x
+ Alan Other <user\@dom.ain>
+ 0: Alan Other <[email protected]>
+ <user\@dom.ain>
+ 1: user@dom
+ user\@dom.ain
+ 1: user@dom
+ \"A. Other\" <user.1234\@dom.ain> (a comment)
+ 0: "A. Other" <[email protected]>
+ A. Other <user.1234\@dom.ain> (a comment)
+ 0: Other <[email protected]>
+ \"/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/\"\@x400-re.lay
+ 0: "/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/"@x400-re.lay
+ 1: "/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/"@x400-re
+ A missing angle <user\@some.where
+ 1: user@some
+ *** Failers
+No match
+ The quick brown fox
+No match
+
+/abc\0def\00pqr\000xyz\0000AB/
+ abc\0def\00pqr\000xyz\0000AB
+ 0: abc\x00def\x00pqr\x00xyz\x000AB
+ abc456 abc\0def\00pqr\000xyz\0000ABCDE
+ 0: abc\x00def\x00pqr\x00xyz\x000AB
+
+/abc\x0def\x00pqr\x000xyz\x0000AB/
+ abc\x0def\x00pqr\x000xyz\x0000AB
+ 0: abc\x0def\x00pqr\x000xyz\x0000AB
+ abc456 abc\x0def\x00pqr\x000xyz\x0000ABCDE
+ 0: abc\x0def\x00pqr\x000xyz\x0000AB
+
+/^[\000-\037]/
+ \0A
+ 0: \x00
+ \01B
+ 0: \x01
+ \037C
+ 0: \x1f
+
+/\0*/
+ \0\0\0\0
+ 0: \x00\x00\x00\x00
+ 1: \x00\x00\x00
+ 2: \x00\x00
+ 3: \x00
+ 4:
+
+/A\x0{2,3}Z/
+ The A\x0\x0Z
+ 0: A\x00\x00Z
+ An A\0\x0\0Z
+ 0: A\x00\x00\x00Z
+ *** Failers
+No match
+ A\0Z
+No match
+ A\0\x0\0\x0Z
+No match
+
+/^\s/
+ \040abc
+ 0:
+ \x0cabc
+ 0: \x0c
+ \nabc
+ 0: \x0a
+ \rabc
+ 0: \x0d
+ \tabc
+ 0: \x09
+ *** Failers
+No match
+ abc
+No match
+
+/^a b
+ c/x
+ abc
+ 0: abc
+
+/ab{1,3}bc/
+ abbbbc
+ 0: abbbbc
+ abbbc
+ 0: abbbc
+ abbc
+ 0: abbc
+ *** Failers
+No match
+ abc
+No match
+ abbbbbc
+No match
+
+/([^.]*)\.([^:]*):[T ]+(.*)/
+ track1.title:TBlah blah blah
+ 0: track1.title:TBlah blah blah
+ 1: track1.title:TBlah blah bla
+ 2: track1.title:TBlah blah bl
+ 3: track1.title:TBlah blah b
+ 4: track1.title:TBlah blah
+ 5: track1.title:TBlah blah
+ 6: track1.title:TBlah bla
+ 7: track1.title:TBlah bl
+ 8: track1.title:TBlah b
+ 9: track1.title:TBlah
+10: track1.title:TBlah
+11: track1.title:TBla
+12: track1.title:TBl
+13: track1.title:TB
+14: track1.title:T
+
+/([^.]*)\.([^:]*):[T ]+(.*)/i
+ track1.title:TBlah blah blah
+ 0: track1.title:TBlah blah blah
+ 1: track1.title:TBlah blah bla
+ 2: track1.title:TBlah blah bl
+ 3: track1.title:TBlah blah b
+ 4: track1.title:TBlah blah
+ 5: track1.title:TBlah blah
+ 6: track1.title:TBlah bla
+ 7: track1.title:TBlah bl
+ 8: track1.title:TBlah b
+ 9: track1.title:TBlah
+10: track1.title:TBlah
+11: track1.title:TBla
+12: track1.title:TBl
+13: track1.title:TB
+14: track1.title:T
+
+/([^.]*)\.([^:]*):[t ]+(.*)/i
+ track1.title:TBlah blah blah
+ 0: track1.title:TBlah blah blah
+ 1: track1.title:TBlah blah bla
+ 2: track1.title:TBlah blah bl
+ 3: track1.title:TBlah blah b
+ 4: track1.title:TBlah blah
+ 5: track1.title:TBlah blah
+ 6: track1.title:TBlah bla
+ 7: track1.title:TBlah bl
+ 8: track1.title:TBlah b
+ 9: track1.title:TBlah
+10: track1.title:TBlah
+11: track1.title:TBla
+12: track1.title:TBl
+13: track1.title:TB
+14: track1.title:T
+
+/^[W-c]+$/
+ WXY_^abc
+ 0: WXY_^abc
+ *** Failers
+No match
+ wxy
+No match
+
+/^[W-c]+$/i
+ WXY_^abc
+ 0: WXY_^abc
+ wxy_^ABC
+ 0: wxy_^ABC
+
+/^[\x3f-\x5F]+$/i
+ WXY_^abc
+ 0: WXY_^abc
+ wxy_^ABC
+ 0: wxy_^ABC
+
+/^abc$/m
+ abc
+ 0: abc
+ qqq\nabc
+ 0: abc
+ abc\nzzz
+ 0: abc
+ qqq\nabc\nzzz
+ 0: abc
+
+/^abc$/
+ abc
+ 0: abc
+ *** Failers
+No match
+ qqq\nabc
+No match
+ abc\nzzz
+No match
+ qqq\nabc\nzzz
+No match
+
+/\Aabc\Z/m
+ abc
+ 0: abc
+ abc\n
+ 0: abc
+ *** Failers
+No match
+ qqq\nabc
+No match
+ abc\nzzz
+No match
+ qqq\nabc\nzzz
+No match
+
+/\A(.)*\Z/s
+ abc\ndef
+ 0: abc\x0adef
+
+/\A(.)*\Z/m
+ *** Failers
+ 0: *** Failers
+ abc\ndef
+No match
+
+/(?:b)|(?::+)/
+ b::c
+ 0: b
+ c::b
+ 0: ::
+ 1: :
+
+/[-az]+/
+ az-
+ 0: az-
+ 1: az
+ 2: a
+ *** Failers
+ 0: a
+ b
+No match
+
+/[az-]+/
+ za-
+ 0: za-
+ 1: za
+ 2: z
+ *** Failers
+ 0: a
+ b
+No match
+
+/[a\-z]+/
+ a-z
+ 0: a-z
+ 1: a-
+ 2: a
+ *** Failers
+ 0: a
+ b
+No match
+
+/[a-z]+/
+ abcdxyz
+ 0: abcdxyz
+ 1: abcdxy
+ 2: abcdx
+ 3: abcd
+ 4: abc
+ 5: ab
+ 6: a
+
+/[\d-]+/
+ 12-34
+ 0: 12-34
+ 1: 12-3
+ 2: 12-
+ 3: 12
+ 4: 1
+ *** Failers
+No match
+ aaa
+No match
+
+/[\d-z]+/
+ 12-34z
+ 0: 12-34z
+ 1: 12-34
+ 2: 12-3
+ 3: 12-
+ 4: 12
+ 5: 1
+ *** Failers
+No match
+ aaa
+No match
+
+/\x5c/
+ \\
+ 0: \
+
+/\x20Z/
+ the Zoo
+ 0: Z
+ *** Failers
+No match
+ Zulu
+No match
+
+/ab{3cd/
+ ab{3cd
+ 0: ab{3cd
+
+/ab{3,cd/
+ ab{3,cd
+ 0: ab{3,cd
+
+/ab{3,4a}cd/
+ ab{3,4a}cd
+ 0: ab{3,4a}cd
+
+/{4,5a}bc/
+ {4,5a}bc
+ 0: {4,5a}bc
+
+/^a.b/<lf>
+ a\rb
+ 0: a\x0db
+ *** Failers
+No match
+ a\nb
+No match
+
+/abc$/
+ abc
+ 0: abc
+ abc\n
+ 0: abc
+ *** Failers
+No match
+ abc\ndef
+No match
+
+/(abc)\123/
+ abc\x53
+ 0: abcS
+
+/(abc)\223/
+ abc\x93
+ 0: abc\x93
+
+/(abc)\323/
+ abc\xd3
+ 0: abc\xd3
+
+/(abc)\100/
+ abc\x40
+ 0: abc@
+ abc\100
+ 0: abc@
+
+/(abc)\1000/
+ abc\x400
+ 0: abc@0
+ abc\x40\x30
+ 0: abc@0
+ abc\1000
+ 0: abc@0
+ abc\100\x30
+ 0: abc@0
+ abc\100\060
+ 0: abc@0
+ abc\100\60
+ 0: abc@0
+
+/abc\81/
+ abc\081
+ 0: abc\x0081
+ abc\0\x38\x31
+ 0: abc\x0081
+
+/abc\91/
+ abc\091
+ 0: abc\x0091
+ abc\0\x39\x31
+ 0: abc\x0091
+
+/(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\12\123/
+ abcdefghijk\12S
+ 0: abcdefghijk\x0aS
+
+/ab\idef/
+ abidef
+ 0: abidef
+
+/a{0}bc/
+ bc
+ 0: bc
+
+/(a|(bc)){0,0}?xyz/
+ xyz
+ 0: xyz
+
+/abc[\10]de/
+ abc\010de
+ 0: abc\x08de
+
+/abc[\1]de/
+ abc\1de
+ 0: abc\x01de
+
+/(abc)[\1]de/
+ abc\1de
+ 0: abc\x01de
+
+/(?s)a.b/
+ a\nb
+ 0: a\x0ab
+
+/^([^a])([^\b])([^c]*)([^d]{3,4})/
+ baNOTccccd
+ 0: baNOTcccc
+ 1: baNOTccc
+ 2: baNOTcc
+ 3: baNOTc
+ 4: baNOT
+ baNOTcccd
+ 0: baNOTccc
+ 1: baNOTcc
+ 2: baNOTc
+ 3: baNOT
+ baNOTccd
+ 0: baNOTcc
+ 1: baNOTc
+ 2: baNOT
+ bacccd
+ 0: baccc
+ *** Failers
+ 0: *** Failers
+ 1: *** Failer
+ 2: *** Faile
+ 3: *** Fail
+ 4: *** Fai
+ 5: *** Fa
+ 6: *** F
+ anything
+No match
+ b\bc
+No match
+ baccd
+No match
+
+/[^a]/
+ Abc
+ 0: A
+
+/[^a]/i
+ Abc
+ 0: b
+
+/[^a]+/
+ AAAaAbc
+ 0: AAA
+ 1: AA
+ 2: A
+
+/[^a]+/i
+ AAAaAbc
+ 0: bc
+ 1: b
+
+/[^a]+/
+ bbb\nccc
+ 0: bbb\x0accc
+ 1: bbb\x0acc
+ 2: bbb\x0ac
+ 3: bbb\x0a
+ 4: bbb
+ 5: bb
+ 6: b
+
+/[^k]$/
+ abc
+ 0: c
+ *** Failers
+ 0: s
+ abk
+No match
+
+/[^k]{2,3}$/
+ abc
+ 0: abc
+ kbc
+ 0: bc
+ kabc
+ 0: abc
+ *** Failers
+ 0: ers
+ abk
+No match
+ akb
+No match
+ akk
+No match
+
+/^\d{8,}\@.+[^k]$/
+ 12345678\@a.b.c.d
+ 123456789\@x.y.z
+ *** Failers
+No match
+ 12345678\@x.y.uk
+No match
+ 1234567\@a.b.c.d
+No match
+
+/[^a]/
+ aaaabcd
+ 0: b
+ aaAabcd
+ 0: A
+
+/[^a]/i
+ aaaabcd
+ 0: b
+ aaAabcd
+ 0: b
+
+/[^az]/
+ aaaabcd
+ 0: b
+ aaAabcd
+ 0: A
+
+/[^az]/i
+ aaaabcd
+ 0: b
+ aaAabcd
+ 0: b
+
+/\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377/
+ \000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377
+ 0: \x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff
+
+/P[^*]TAIRE[^*]{1,6}?LL/
+ xxxxxxxxxxxPSTAIREISLLxxxxxxxxx
+ 0: PSTAIREISLL
+
+/P[^*]TAIRE[^*]{1,}?LL/
+ xxxxxxxxxxxPSTAIREISLLxxxxxxxxx
+ 0: PSTAIREISLL
+
+/(\.\d\d[1-9]?)\d+/
+ 1.230003938
+ 0: .230003938
+ 1: .23000393
+ 2: .2300039
+ 3: .230003
+ 4: .23000
+ 5: .2300
+ 6: .230
+ 1.875000282
+ 0: .875000282
+ 1: .87500028
+ 2: .8750002
+ 3: .875000
+ 4: .87500
+ 5: .8750
+ 6: .875
+ 1.235
+ 0: .235
+
+/(\.\d\d((?=0)|\d(?=\d)))/
+ 1.230003938
+ 0: .230
+ 1: .23
+ 1.875000282
+ 0: .875
+ *** Failers
+No match
+ 1.235
+No match
+
+/a(?)b/
+ ab
+ 0: ab
+
+/\b(foo)\s+(\w+)/i
+ Food is on the foo table
+ 0: foo table
+ 1: foo tabl
+ 2: foo tab
+ 3: foo ta
+ 4: foo t
+
+/foo(.*)bar/
+ The food is under the bar in the barn.
+ 0: food is under the bar in the bar
+ 1: food is under the bar
+
+/foo(.*?)bar/
+ The food is under the bar in the barn.
+ 0: food is under the bar in the bar
+ 1: food is under the bar
+
+/(.*)(\d*)/
+ I have 2 numbers: 53147
+Matched, but too many subsidiary matches
+ 0: I have 2 numbers: 53147
+ 1: I have 2 numbers: 5314
+ 2: I have 2 numbers: 531
+ 3: I have 2 numbers: 53
+ 4: I have 2 numbers: 5
+ 5: I have 2 numbers:
+ 6: I have 2 numbers:
+ 7: I have 2 numbers
+ 8: I have 2 number
+ 9: I have 2 numbe
+10: I have 2 numb
+11: I have 2 num
+12: I have 2 nu
+13: I have 2 n
+14: I have 2
+15: I have 2
+16: I have
+17: I have
+18: I hav
+19: I ha
+20: I h
+21: I
+
+/(.*)(\d+)/
+ I have 2 numbers: 53147
+ 0: I have 2 numbers: 53147
+ 1: I have 2 numbers: 5314
+ 2: I have 2 numbers: 531
+ 3: I have 2 numbers: 53
+ 4: I have 2 numbers: 5
+ 5: I have 2
+
+/(.*?)(\d*)/
+ I have 2 numbers: 53147
+Matched, but too many subsidiary matches
+ 0: I have 2 numbers: 53147
+ 1: I have 2 numbers: 5314
+ 2: I have 2 numbers: 531
+ 3: I have 2 numbers: 53
+ 4: I have 2 numbers: 5
+ 5: I have 2 numbers:
+ 6: I have 2 numbers:
+ 7: I have 2 numbers
+ 8: I have 2 number
+ 9: I have 2 numbe
+10: I have 2 numb
+11: I have 2 num
+12: I have 2 nu
+13: I have 2 n
+14: I have 2
+15: I have 2
+16: I have
+17: I have
+18: I hav
+19: I ha
+20: I h
+21: I
+
+/(.*?)(\d+)/
+ I have 2 numbers: 53147
+ 0: I have 2 numbers: 53147
+ 1: I have 2 numbers: 5314
+ 2: I have 2 numbers: 531
+ 3: I have 2 numbers: 53
+ 4: I have 2 numbers: 5
+ 5: I have 2
+
+/(.*)(\d+)$/
+ I have 2 numbers: 53147
+ 0: I have 2 numbers: 53147
+
+/(.*?)(\d+)$/
+ I have 2 numbers: 53147
+ 0: I have 2 numbers: 53147
+
+/(.*)\b(\d+)$/
+ I have 2 numbers: 53147
+ 0: I have 2 numbers: 53147
+
+/(.*\D)(\d+)$/
+ I have 2 numbers: 53147
+ 0: I have 2 numbers: 53147
+
+/^\D*(?!123)/
+ ABC123
+ 0: AB
+ 1: A
+ 2:
+
+/^(\D*)(?=\d)(?!123)/
+ ABC445
+ 0: ABC
+ *** Failers
+No match
+ ABC123
+No match
+
+/^[W-]46]/
+ W46]789
+ 0: W46]
+ -46]789
+ 0: -46]
+ *** Failers
+No match
+ Wall
+No match
+ Zebra
+No match
+ 42
+No match
+ [abcd]
+No match
+ ]abcd[
+No match
+
+/^[W-\]46]/
+ W46]789
+ 0: W
+ Wall
+ 0: W
+ Zebra
+ 0: Z
+ Xylophone
+ 0: X
+ 42
+ 0: 4
+ [abcd]
+ 0: [
+ ]abcd[
+ 0: ]
+ \\backslash
+ 0: \
+ *** Failers
+No match
+ -46]789
+No match
+ well
+No match
+
+/\d\d\/\d\d\/\d\d\d\d/
+ 01/01/2000
+ 0: 01/01/2000
+
+/word (?:[a-zA-Z0-9]+ ){0,10}otherword/
+ word cat dog elephant mussel cow horse canary baboon snake shark otherword
+ 0: word cat dog elephant mussel cow horse canary baboon snake shark otherword
+ word cat dog elephant mussel cow horse canary baboon snake shark
+No match
+
+/word (?:[a-zA-Z0-9]+ ){0,300}otherword/
+ word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope
+No match
+
+/^(a){0,0}/
+ bcd
+ 0:
+ abc
+ 0:
+ aab
+ 0:
+
+/^(a){0,1}/
+ bcd
+ 0:
+ abc
+ 0: a
+ 1:
+ aab
+ 0: a
+ 1:
+
+/^(a){0,2}/
+ bcd
+ 0:
+ abc
+ 0: a
+ 1:
+ aab
+ 0: aa
+ 1: a
+ 2:
+
+/^(a){0,3}/
+ bcd
+ 0:
+ abc
+ 0: a
+ 1:
+ aab
+ 0: aa
+ 1: a
+ 2:
+ aaa
+ 0: aaa
+ 1: aa
+ 2: a
+ 3:
+
+/^(a){0,}/
+ bcd
+ 0:
+ abc
+ 0: a
+ 1:
+ aab
+ 0: aa
+ 1: a
+ 2:
+ aaa
+ 0: aaa
+ 1: aa
+ 2: a
+ 3:
+ aaaaaaaa
+ 0: aaaaaaaa
+ 1: aaaaaaa
+ 2: aaaaaa
+ 3: aaaaa
+ 4: aaaa
+ 5: aaa
+ 6: aa
+ 7: a
+ 8:
+
+/^(a){1,1}/
+ bcd
+No match
+ abc
+ 0: a
+ aab
+ 0: a
+
+/^(a){1,2}/
+ bcd
+No match
+ abc
+ 0: a
+ aab
+ 0: aa
+ 1: a
+
+/^(a){1,3}/
+ bcd
+No match
+ abc
+ 0: a
+ aab
+ 0: aa
+ 1: a
+ aaa
+ 0: aaa
+ 1: aa
+ 2: a
+
+/^(a){1,}/
+ bcd
+No match
+ abc
+ 0: a
+ aab
+ 0: aa
+ 1: a
+ aaa
+ 0: aaa
+ 1: aa
+ 2: a
+ aaaaaaaa
+ 0: aaaaaaaa
+ 1: aaaaaaa
+ 2: aaaaaa
+ 3: aaaaa
+ 4: aaaa
+ 5: aaa
+ 6: aa
+ 7: a
+
+/.*\.gif/
+ borfle\nbib.gif\nno
+ 0: bib.gif
+
+/.{0,}\.gif/
+ borfle\nbib.gif\nno
+ 0: bib.gif
+
+/.*\.gif/m
+ borfle\nbib.gif\nno
+ 0: bib.gif
+
+/.*\.gif/s
+ borfle\nbib.gif\nno
+ 0: borfle\x0abib.gif
+
+/.*\.gif/ms
+ borfle\nbib.gif\nno
+ 0: borfle\x0abib.gif
+
+/.*$/
+ borfle\nbib.gif\nno
+ 0: no
+
+/.*$/m
+ borfle\nbib.gif\nno
+ 0: borfle
+
+/.*$/s
+ borfle\nbib.gif\nno
+ 0: borfle\x0abib.gif\x0ano
+
+/.*$/ms
+ borfle\nbib.gif\nno
+ 0: borfle\x0abib.gif\x0ano
+ 1: borfle\x0abib.gif
+ 2: borfle
+
+/.*$/
+ borfle\nbib.gif\nno\n
+ 0: no
+
+/.*$/m
+ borfle\nbib.gif\nno\n
+ 0: borfle
+
+/.*$/s
+ borfle\nbib.gif\nno\n
+ 0: borfle\x0abib.gif\x0ano\x0a
+ 1: borfle\x0abib.gif\x0ano
+
+/.*$/ms
+ borfle\nbib.gif\nno\n
+ 0: borfle\x0abib.gif\x0ano\x0a
+ 1: borfle\x0abib.gif\x0ano
+ 2: borfle\x0abib.gif
+ 3: borfle
+
+/(.*X|^B)/
+ abcde\n1234Xyz
+ 0: 1234X
+ BarFoo
+ 0: B
+ *** Failers
+No match
+ abcde\nBar
+No match
+
+/(.*X|^B)/m
+ abcde\n1234Xyz
+ 0: 1234X
+ BarFoo
+ 0: B
+ abcde\nBar
+ 0: B
+
+/(.*X|^B)/s
+ abcde\n1234Xyz
+ 0: abcde\x0a1234X
+ BarFoo
+ 0: B
+ *** Failers
+No match
+ abcde\nBar
+No match
+
+/(.*X|^B)/ms
+ abcde\n1234Xyz
+ 0: abcde\x0a1234X
+ BarFoo
+ 0: B
+ abcde\nBar
+ 0: B
+
+/(?s)(.*X|^B)/
+ abcde\n1234Xyz
+ 0: abcde\x0a1234X
+ BarFoo
+ 0: B
+ *** Failers
+No match
+ abcde\nBar
+No match
+
+/(?s:.*X|^B)/
+ abcde\n1234Xyz
+ 0: abcde\x0a1234X
+ BarFoo
+ 0: B
+ *** Failers
+No match
+ abcde\nBar
+No match
+
+/^.*B/
+ **** Failers
+No match
+ abc\nB
+No match
+
+/(?s)^.*B/
+ abc\nB
+ 0: abc\x0aB
+
+/(?m)^.*B/
+ abc\nB
+ 0: B
+
+/(?ms)^.*B/
+ abc\nB
+ 0: abc\x0aB
+
+/(?ms)^B/
+ abc\nB
+ 0: B
+
+/(?s)B$/
+ B\n
+ 0: B
+
+/^[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]/
+ 123456654321
+ 0: 123456654321
+
+/^\d\d\d\d\d\d\d\d\d\d\d\d/
+ 123456654321
+ 0: 123456654321
+
+/^[\d][\d][\d][\d][\d][\d][\d][\d][\d][\d][\d][\d]/
+ 123456654321
+ 0: 123456654321
+
+/^[abc]{12}/
+ abcabcabcabc
+ 0: abcabcabcabc
+
+/^[a-c]{12}/
+ abcabcabcabc
+ 0: abcabcabcabc
+
+/^(a|b|c){12}/
+ abcabcabcabc
+ 0: abcabcabcabc
+
+/^[abcdefghijklmnopqrstuvwxy0123456789]/
+ n
+ 0: n
+ *** Failers
+No match
+ z
+No match
+
+/abcde{0,0}/
+ abcd
+ 0: abcd
+ *** Failers
+No match
+ abce
+No match
+
+/ab[cd]{0,0}e/
+ abe
+ 0: abe
+ *** Failers
+No match
+ abcde
+No match
+
+/ab(c){0,0}d/
+ abd
+ 0: abd
+ *** Failers
+No match
+ abcd
+No match
+
+/a(b*)/
+ a
+ 0: a
+ ab
+ 0: ab
+ 1: a
+ abbbb
+ 0: abbbb
+ 1: abbb
+ 2: abb
+ 3: ab
+ 4: a
+ *** Failers
+ 0: a
+ bbbbb
+No match
+
+/ab\d{0}e/
+ abe
+ 0: abe
+ *** Failers
+No match
+ ab1e
+No match
+
+/"([^\\"]+|\\.)*"/
+ the \"quick\" brown fox
+ 0: "quick"
+ \"the \\\"quick\\\" brown fox\"
+ 0: "the \"quick\" brown fox"
+
+/.*?/g+
+ abc
+ 0: abc
+ 0+
+ 1: ab
+ 2: a
+ 3:
+ 0:
+ 0+
+
+/\b/g+
+ abc
+ 0:
+ 0+ abc
+ 0:
+ 0+
+
+/\b/+g
+ abc
+ 0:
+ 0+ abc
+ 0:
+ 0+
+
+//g
+ abc
+ 0:
+ 0:
+ 0:
+ 0:
+
+/<tr([\w\W\s\d][^<>]{0,})><TD([\w\W\s\d][^<>]{0,})>([\d]{0,}\.)(.*)((<BR>([\w\W\s\d][^<>]{0,})|[\s]{0,}))<\/a><\/TD><TD([\w\W\s\d][^<>]{0,})>([\w\W\s\d][^<>]{0,})<\/TD><TD([\w\W\s\d][^<>]{0,})>([\w\W\s\d][^<>]{0,})<\/TD><\/TR>/is
+ <TR BGCOLOR='#DBE9E9'><TD align=left valign=top>43.<a href='joblist.cfm?JobID=94 6735&Keyword='>Word Processor<BR>(N-1286)</a></TD><TD align=left valign=top>Lega lstaff.com</TD><TD align=left valign=top>CA - Statewide</TD></TR>
+ 0: <TR BGCOLOR='#DBE9E9'><TD align=left valign=top>43.<a href='joblist.cfm?JobID=94 6735&Keyword='>Word Processor<BR>(N-1286)</a></TD><TD align=left valign=top>Lega lstaff.com</TD><TD align=left valign=top>CA - Statewide</TD></TR>
+
+/a[^a]b/
+ acb
+ 0: acb
+ a\nb
+ 0: a\x0ab
+
+/a.b/
+ acb
+ 0: acb
+ *** Failers
+No match
+ a\nb
+No match
+
+/a[^a]b/s
+ acb
+ 0: acb
+ a\nb
+ 0: a\x0ab
+
+/a.b/s
+ acb
+ 0: acb
+ a\nb
+ 0: a\x0ab
+
+/^(b+?|a){1,2}?c/
+ bac
+ 0: bac
+ bbac
+ 0: bbac
+ bbbac
+ 0: bbbac
+ bbbbac
+ 0: bbbbac
+ bbbbbac
+ 0: bbbbbac
+
+/^(b+|a){1,2}?c/
+ bac
+ 0: bac
+ bbac
+ 0: bbac
+ bbbac
+ 0: bbbac
+ bbbbac
+ 0: bbbbac
+ bbbbbac
+ 0: bbbbbac
+
+/(?!\A)x/m
+ x\nb\n
+No match
+ a\bx\n
+ 0: x
+
+/\x0{ab}/
+ \0{ab}
+ 0: \x00{ab}
+
+/(A|B)*?CD/
+ CD
+ 0: CD
+
+/(A|B)*CD/
+ CD
+ 0: CD
+
+/(?<!bar)foo/
+ foo
+ 0: foo
+ catfood
+ 0: foo
+ arfootle
+ 0: foo
+ rfoosh
+ 0: foo
+ *** Failers
+No match
+ barfoo
+No match
+ towbarfoo
+No match
+
+/\w{3}(?<!bar)foo/
+ catfood
+ 0: catfoo
+ *** Failers
+No match
+ foo
+No match
+ barfoo
+No match
+ towbarfoo
+No match
+
+/(?<=(foo)a)bar/
+ fooabar
+ 0: bar
+ *** Failers
+No match
+ bar
+No match
+ foobbar
+No match
+
+/\Aabc\z/m
+ abc
+ 0: abc
+ *** Failers
+No match
+ abc\n
+No match
+ qqq\nabc
+No match
+ abc\nzzz
+No match
+ qqq\nabc\nzzz
+No match
+
+"(?>.*/)foo"
+ /this/is/a/very/long/line/in/deed/with/very/many/slashes/in/it/you/see/
+No match
+
+"(?>.*/)foo"
+ /this/is/a/very/long/line/in/deed/with/very/many/slashes/in/and/foo
+ 0: /this/is/a/very/long/line/in/deed/with/very/many/slashes/in/and/foo
+
+/(?>(\.\d\d[1-9]?))\d+/
+ 1.230003938
+ 0: .230003938
+ 1: .23000393
+ 2: .2300039
+ 3: .230003
+ 4: .23000
+ 5: .2300
+ 6: .230
+ 1.875000282
+ 0: .875000282
+ 1: .87500028
+ 2: .8750002
+ 3: .875000
+ 4: .87500
+ 5: .8750
+ *** Failers
+No match
+ 1.235
+No match
+
+/^((?>\w+)|(?>\s+))*$/
+ now is the time for all good men to come to the aid of the party
+ 0: now is the time for all good men to come to the aid of the party
+ *** Failers
+No match
+ this is not a line with only words and spaces!
+No match
+
+/(\d+)(\w)/
+ 12345a
+ 0: 12345a
+ 1: 12345
+ 2: 1234
+ 3: 123
+ 4: 12
+ 12345+
+ 0: 12345
+ 1: 1234
+ 2: 123
+ 3: 12
+
+/((?>\d+))(\w)/
+ 12345a
+ 0: 12345a
+ *** Failers
+No match
+ 12345+
+No match
+
+/(?>a+)b/
+ aaab
+ 0: aaab
+
+/((?>a+)b)/
+ aaab
+ 0: aaab
+
+/(?>(a+))b/
+ aaab
+ 0: aaab
+
+/(?>b)+/
+ aaabbbccc
+ 0: bbb
+ 1: bb
+ 2: b
+
+/(?>a+|b+|c+)*c/
+ aaabbbbccccd
+ 0: aaabbbbcccc
+ 1: aaabbbbc
+
+/(a+|b+|c+)*c/
+ aaabbbbccccd
+ 0: aaabbbbcccc
+ 1: aaabbbbccc
+ 2: aaabbbbcc
+ 3: aaabbbbc
+
+/((?>[^()]+)|\([^()]*\))+/
+ ((abc(ade)ufh()()x
+ 0: abc(ade)ufh()()x
+ 1: abc(ade)ufh()()
+ 2: abc(ade)ufh()
+ 3: abc(ade)ufh
+ 4: abc(ade)
+ 5: abc
+
+/\(((?>[^()]+)|\([^()]+\))+\)/
+ (abc)
+ 0: (abc)
+ (abc(def)xyz)
+ 0: (abc(def)xyz)
+ *** Failers
+No match
+ ((()aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+No match
+
+/a(?-i)b/i
+ ab
+ 0: ab
+ Ab
+ 0: Ab
+ *** Failers
+No match
+ aB
+No match
+ AB
+No match
+
+/(a (?x)b c)d e/
+ a bcd e
+ 0: a bcd e
+ *** Failers
+No match
+ a b cd e
+No match
+ abcd e
+No match
+ a bcde
+No match
+
+/(a b(?x)c d (?-x)e f)/
+ a bcde f
+ 0: a bcde f
+ *** Failers
+No match
+ abcdef
+No match
+
+/(a(?i)b)c/
+ abc
+ 0: abc
+ aBc
+ 0: aBc
+ *** Failers
+No match
+ abC
+No match
+ aBC
+No match
+ Abc
+No match
+ ABc
+No match
+ ABC
+No match
+ AbC
+No match
+
+/a(?i:b)c/
+ abc
+ 0: abc
+ aBc
+ 0: aBc
+ *** Failers
+No match
+ ABC
+No match
+ abC
+No match
+ aBC
+No match
+
+/a(?i:b)*c/
+ aBc
+ 0: aBc
+ aBBc
+ 0: aBBc
+ *** Failers
+No match
+ aBC
+No match
+ aBBC
+No match
+
+/a(?=b(?i)c)\w\wd/
+ abcd
+ 0: abcd
+ abCd
+ 0: abCd
+ *** Failers
+No match
+ aBCd
+No match
+ abcD
+No match
+
+/(?s-i:more.*than).*million/i
+ more than million
+ 0: more than million
+ more than MILLION
+ 0: more than MILLION
+ more \n than Million
+ 0: more \x0a than Million
+ *** Failers
+No match
+ MORE THAN MILLION
+No match
+ more \n than \n million
+No match
+
+/(?:(?s-i)more.*than).*million/i
+ more than million
+ 0: more than million
+ more than MILLION
+ 0: more than MILLION
+ more \n than Million
+ 0: more \x0a than Million
+ *** Failers
+No match
+ MORE THAN MILLION
+No match
+ more \n than \n million
+No match
+
+/(?>a(?i)b+)+c/
+ abc
+ 0: abc
+ aBbc
+ 0: aBbc
+ aBBc
+ 0: aBBc
+ *** Failers
+No match
+ Abc
+No match
+ abAb
+No match
+ abbC
+No match
+
+/(?=a(?i)b)\w\wc/
+ abc
+ 0: abc
+ aBc
+ 0: aBc
+ *** Failers
+No match
+ Ab
+No match
+ abC
+No match
+ aBC
+No match
+
+/(?<=a(?i)b)(\w\w)c/
+ abxxc
+ 0: xxc
+ aBxxc
+ 0: xxc
+ *** Failers
+No match
+ Abxxc
+No match
+ ABxxc
+No match
+ abxxC
+No match
+
+/^(?(?=abc)\w{3}:|\d\d)$/
+ abc:
+ 0: abc:
+ 12
+ 0: 12
+ *** Failers
+No match
+ 123
+No match
+ xyz
+No match
+
+/^(?(?!abc)\d\d|\w{3}:)$/
+ abc:
+ 0: abc:
+ 12
+ 0: 12
+ *** Failers
+No match
+ 123
+No match
+ xyz
+No match
+
+/(?(?<=foo)bar|cat)/
+ foobar
+ 0: bar
+ cat
+ 0: cat
+ fcat
+ 0: cat
+ focat
+ 0: cat
+ *** Failers
+No match
+ foocat
+No match
+
+/(?(?<!foo)cat|bar)/
+ foobar
+ 0: bar
+ cat
+ 0: cat
+ fcat
+ 0: cat
+ focat
+ 0: cat
+ *** Failers
+No match
+ foocat
+No match
+
+/(?>a*)*/
+ a
+ 0: a
+ 1:
+ aa
+ 0: aa
+ 1:
+ aaaa
+ 0: aaaa
+ 1:
+
+/(abc|)+/
+ abc
+ 0: abc
+ 1:
+ abcabc
+ 0: abcabc
+ 1: abc
+ 2:
+ abcabcabc
+ 0: abcabcabc
+ 1: abcabc
+ 2: abc
+ 3:
+ xyz
+ 0:
+
+/([a]*)*/
+ a
+ 0: a
+ 1:
+ aaaaa
+ 0: aaaaa
+ 1: aaaa
+ 2: aaa
+ 3: aa
+ 4: a
+ 5:
+
+/([ab]*)*/
+ a
+ 0: a
+ 1:
+ b
+ 0: b
+ 1:
+ ababab
+ 0: ababab
+ 1: ababa
+ 2: abab
+ 3: aba
+ 4: ab
+ 5: a
+ 6:
+ aaaabcde
+ 0: aaaab
+ 1: aaaa
+ 2: aaa
+ 3: aa
+ 4: a
+ 5:
+ bbbb
+ 0: bbbb
+ 1: bbb
+ 2: bb
+ 3: b
+ 4:
+
+/([^a]*)*/
+ b
+ 0: b
+ 1:
+ bbbb
+ 0: bbbb
+ 1: bbb
+ 2: bb
+ 3: b
+ 4:
+ aaa
+ 0:
+
+/([^ab]*)*/
+ cccc
+ 0: cccc
+ 1: ccc
+ 2: cc
+ 3: c
+ 4:
+ abab
+ 0:
+
+/([a]*?)*/
+ a
+ 0: a
+ 1:
+ aaaa
+ 0: aaaa
+ 1: aaa
+ 2: aa
+ 3: a
+ 4:
+
+/([ab]*?)*/
+ a
+ 0: a
+ 1:
+ b
+ 0: b
+ 1:
+ abab
+ 0: abab
+ 1: aba
+ 2: ab
+ 3: a
+ 4:
+ baba
+ 0: baba
+ 1: bab
+ 2: ba
+ 3: b
+ 4:
+
+/([^a]*?)*/
+ b
+ 0: b
+ 1:
+ bbbb
+ 0: bbbb
+ 1: bbb
+ 2: bb
+ 3: b
+ 4:
+ aaa
+ 0:
+
+/([^ab]*?)*/
+ c
+ 0: c
+ 1:
+ cccc
+ 0: cccc
+ 1: ccc
+ 2: cc
+ 3: c
+ 4:
+ baba
+ 0:
+
+/(?>a*)*/
+ a
+ 0: a
+ 1:
+ aaabcde
+ 0: aaa
+ 1:
+
+/((?>a*))*/
+ aaaaa
+ 0: aaaaa
+ 1:
+ aabbaa
+ 0: aa
+ 1:
+
+/((?>a*?))*/
+ aaaaa
+ 0: aaaaa
+ 1:
+ aabbaa
+ 0: aa
+ 1:
+
+/(?(?=[^a-z]+[a-z]) \d{2}-[a-z]{3}-\d{2} | \d{2}-\d{2}-\d{2} ) /x
+ 12-sep-98
+ 0: 12-sep-98
+ 12-09-98
+ 0: 12-09-98
+ *** Failers
+No match
+ sep-12-98
+No match
+
+/(?i:saturday|sunday)/
+ saturday
+ 0: saturday
+ sunday
+ 0: sunday
+ Saturday
+ 0: Saturday
+ Sunday
+ 0: Sunday
+ SATURDAY
+ 0: SATURDAY
+ SUNDAY
+ 0: SUNDAY
+ SunDay
+ 0: SunDay
+
+/(a(?i)bc|BB)x/
+ abcx
+ 0: abcx
+ aBCx
+ 0: aBCx
+ bbx
+ 0: bbx
+ BBx
+ 0: BBx
+ *** Failers
+No match
+ abcX
+No match
+ aBCX
+No match
+ bbX
+No match
+ BBX
+No match
+
+/^([ab](?i)[cd]|[ef])/
+ ac
+ 0: ac
+ aC
+ 0: aC
+ bD
+ 0: bD
+ elephant
+ 0: e
+ Europe
+ 0: E
+ frog
+ 0: f
+ France
+ 0: F
+ *** Failers
+No match
+ Africa
+No match
+
+/^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)/
+ ab
+ 0: ab
+ aBd
+ 0: aBd
+ xy
+ 0: xy
+ xY
+ 0: xY
+ zebra
+ 0: z
+ Zambesi
+ 0: Z
+ *** Failers
+No match
+ aCD
+No match
+ XY
+No match
+
+/(?<=foo\n)^bar/m
+ foo\nbar
+ 0: bar
+ *** Failers
+No match
+ bar
+No match
+ baz\nbar
+No match
+
+/(?<=(?<!foo)bar)baz/
+ barbaz
+ 0: baz
+ barbarbaz
+ 0: baz
+ koobarbaz
+ 0: baz
+ *** Failers
+No match
+ baz
+No match
+ foobarbaz
+No match
+
+/The following tests are taken from the Perl 5.005 test suite; some of them/
+/are compatible with 5.004, but I'd rather not have to sort them out./
+No match
+
+/abc/
+ abc
+ 0: abc
+ xabcy
+ 0: abc
+ ababc
+ 0: abc
+ *** Failers
+No match
+ xbc
+No match
+ axc
+No match
+ abx
+No match
+
+/ab*c/
+ abc
+ 0: abc
+
+/ab*bc/
+ abc
+ 0: abc
+ abbc
+ 0: abbc
+ abbbbc
+ 0: abbbbc
+
+/.{1}/
+ abbbbc
+ 0: a
+
+/.{3,4}/
+ abbbbc
+ 0: abbb
+ 1: abb
+
+/ab{0,}bc/
+ abbbbc
+ 0: abbbbc
+
+/ab+bc/
+ abbc
+ 0: abbc
+ *** Failers
+No match
+ abc
+No match
+ abq
+No match
+
+/ab{1,}bc/
+
+/ab+bc/
+ abbbbc
+ 0: abbbbc
+
+/ab{1,}bc/
+ abbbbc
+ 0: abbbbc
+
+/ab{1,3}bc/
+ abbbbc
+ 0: abbbbc
+
+/ab{3,4}bc/
+ abbbbc
+ 0: abbbbc
+
+/ab{4,5}bc/
+ *** Failers
+No match
+ abq
+No match
+ abbbbc
+No match
+
+/ab?bc/
+ abbc
+ 0: abbc
+ abc
+ 0: abc
+
+/ab{0,1}bc/
+ abc
+ 0: abc
+
+/ab?bc/
+
+/ab?c/
+ abc
+ 0: abc
+
+/ab{0,1}c/
+ abc
+ 0: abc
+
+/^abc$/
+ abc
+ 0: abc
+ *** Failers
+No match
+ abbbbc
+No match
+ abcc
+No match
+
+/^abc/
+ abcc
+ 0: abc
+
+/^abc$/
+
+/abc$/
+ aabc
+ 0: abc
+ *** Failers
+No match
+ aabc
+ 0: abc
+ aabcd
+No match
+
+/^/
+ abc
+ 0:
+
+/$/
+ abc
+ 0:
+
+/a.c/
+ abc
+ 0: abc
+ axc
+ 0: axc
+
+/a.*c/
+ axyzc
+ 0: axyzc
+
+/a[bc]d/
+ abd
+ 0: abd
+ *** Failers
+No match
+ axyzd
+No match
+ abc
+No match
+
+/a[b-d]e/
+ ace
+ 0: ace
+
+/a[b-d]/
+ aac
+ 0: ac
+
+/a[-b]/
+ a-
+ 0: a-
+
+/a[b-]/
+ a-
+ 0: a-
+
+/a]/
+ a]
+ 0: a]
+
+/a[]]b/
+ a]b
+ 0: a]b
+
+/a[^bc]d/
+ aed
+ 0: aed
+ *** Failers
+No match
+ abd
+No match
+ abd
+No match
+
+/a[^-b]c/
+ adc
+ 0: adc
+
+/a[^]b]c/
+ adc
+ 0: adc
+ *** Failers
+No match
+ a-c
+ 0: a-c
+ a]c
+No match
+
+/\ba\b/
+ a-
+ 0: a
+ -a
+ 0: a
+ -a-
+ 0: a
+
+/\by\b/
+ *** Failers
+No match
+ xy
+No match
+ yz
+No match
+ xyz
+No match
+
+/\Ba\B/
+ *** Failers
+ 0: a
+ a-
+No match
+ -a
+No match
+ -a-
+No match
+
+/\By\b/
+ xy
+ 0: y
+
+/\by\B/
+ yz
+ 0: y
+
+/\By\B/
+ xyz
+ 0: y
+
+/\w/
+ a
+ 0: a
+
+/\W/
+ -
+ 0: -
+ *** Failers
+ 0: *
+ -
+ 0: -
+ a
+No match
+
+/a\sb/
+ a b
+ 0: a b
+
+/a\Sb/
+ a-b
+ 0: a-b
+ *** Failers
+No match
+ a-b
+ 0: a-b
+ a b
+No match
+
+/\d/
+ 1
+ 0: 1
+
+/\D/
+ -
+ 0: -
+ *** Failers
+ 0: *
+ -
+ 0: -
+ 1
+No match
+
+/[\w]/
+ a
+ 0: a
+
+/[\W]/
+ -
+ 0: -
+ *** Failers
+ 0: *
+ -
+ 0: -
+ a
+No match
+
+/a[\s]b/
+ a b
+ 0: a b
+
+/a[\S]b/
+ a-b
+ 0: a-b
+ *** Failers
+No match
+ a-b
+ 0: a-b
+ a b
+No match
+
+/[\d]/
+ 1
+ 0: 1
+
+/[\D]/
+ -
+ 0: -
+ *** Failers
+ 0: *
+ -
+ 0: -
+ 1
+No match
+
+/ab|cd/
+ abc
+ 0: ab
+ abcd
+ 0: ab
+
+/()ef/
+ def
+ 0: ef
+
+/$b/
+
+/a\(b/
+ a(b
+ 0: a(b
+
+/a\(*b/
+ ab
+ 0: ab
+ a((b
+ 0: a((b
+
+/a\\b/
+ a\b
+No match
+
+/((a))/
+ abc
+ 0: a
+
+/(a)b(c)/
+ abc
+ 0: abc
+
+/a+b+c/
+ aabbabc
+ 0: abc
+
+/a{1,}b{1,}c/
+ aabbabc
+ 0: abc
+
+/a.+?c/
+ abcabc
+ 0: abcabc
+ 1: abc
+
+/(a+|b)*/
+ ab
+ 0: ab
+ 1: a
+ 2:
+
+/(a+|b){0,}/
+ ab
+ 0: ab
+ 1: a
+ 2:
+
+/(a+|b)+/
+ ab
+ 0: ab
+ 1: a
+
+/(a+|b){1,}/
+ ab
+ 0: ab
+ 1: a
+
+/(a+|b)?/
+ ab
+ 0: a
+ 1:
+
+/(a+|b){0,1}/
+ ab
+ 0: a
+ 1:
+
+/[^ab]*/
+ cde
+ 0: cde
+ 1: cd
+ 2: c
+ 3:
+
+/abc/
+ *** Failers
+No match
+ b
+No match
+
+
+/a*/
+
+
+/([abc])*d/
+ abbbcd
+ 0: abbbcd
+
+/([abc])*bcd/
+ abcd
+ 0: abcd
+
+/a|b|c|d|e/
+ e
+ 0: e
+
+/(a|b|c|d|e)f/
+ ef
+ 0: ef
+
+/abcd*efg/
+ abcdefg
+ 0: abcdefg
+
+/ab*/
+ xabyabbbz
+ 0: ab
+ 1: a
+ xayabbbz
+ 0: a
+
+/(ab|cd)e/
+ abcde
+ 0: cde
+
+/[abhgefdc]ij/
+ hij
+ 0: hij
+
+/^(ab|cd)e/
+
+/(abc|)ef/
+ abcdef
+ 0: ef
+
+/(a|b)c*d/
+ abcd
+ 0: bcd
+
+/(ab|ab*)bc/
+ abc
+ 0: abc
+
+/a([bc]*)c*/
+ abc
+ 0: abc
+ 1: ab
+ 2: a
+
+/a([bc]*)(c*d)/
+ abcd
+ 0: abcd
+
+/a([bc]+)(c*d)/
+ abcd
+ 0: abcd
+
+/a([bc]*)(c+d)/
+ abcd
+ 0: abcd
+
+/a[bcd]*dcdcde/
+ adcdcde
+ 0: adcdcde
+
+/a[bcd]+dcdcde/
+ *** Failers
+No match
+ abcde
+No match
+ adcdcde
+No match
+
+/(ab|a)b*c/
+ abc
+ 0: abc
+
+/((a)(b)c)(d)/
+ abcd
+ 0: abcd
+
+/[a-zA-Z_][a-zA-Z0-9_]*/
+ alpha
+ 0: alpha
+ 1: alph
+ 2: alp
+ 3: al
+ 4: a
+
+/^a(bc+|b[eh])g|.h$/
+ abh
+ 0: bh
+
+/(bc+d$|ef*g.|h?i(j|k))/
+ effgz
+ 0: effgz
+ ij
+ 0: ij
+ reffgz
+ 0: effgz
+ *** Failers
+No match
+ effg
+No match
+ bcdd
+No match
+
+/((((((((((a))))))))))/
+ a
+ 0: a
+
+/(((((((((a)))))))))/
+ a
+ 0: a
+
+/multiple words of text/
+ *** Failers
+No match
+ aa
+No match
+ uh-uh
+No match
+
+/multiple words/
+ multiple words, yeah
+ 0: multiple words
+
+/(.*)c(.*)/
+ abcde
+ 0: abcde
+ 1: abcd
+ 2: abc
+
+/\((.*), (.*)\)/
+ (a, b)
+ 0: (a, b)
+
+/[k]/
+
+/abcd/
+ abcd
+ 0: abcd
+
+/a(bc)d/
+ abcd
+ 0: abcd
+
+/a[-]?c/
+ ac
+ 0: ac
+
+/abc/i
+ ABC
+ 0: ABC
+ XABCY
+ 0: ABC
+ ABABC
+ 0: ABC
+ *** Failers
+No match
+ aaxabxbaxbbx
+No match
+ XBC
+No match
+ AXC
+No match
+ ABX
+No match
+
+/ab*c/i
+ ABC
+ 0: ABC
+
+/ab*bc/i
+ ABC
+ 0: ABC
+ ABBC
+ 0: ABBC
+
+/ab*?bc/i
+ ABBBBC
+ 0: ABBBBC
+
+/ab{0,}?bc/i
+ ABBBBC
+ 0: ABBBBC
+
+/ab+?bc/i
+ ABBC
+ 0: ABBC
+
+/ab+bc/i
+ *** Failers
+No match
+ ABC
+No match
+ ABQ
+No match
+
+/ab{1,}bc/i
+
+/ab+bc/i
+ ABBBBC
+ 0: ABBBBC
+
+/ab{1,}?bc/i
+ ABBBBC
+ 0: ABBBBC
+
+/ab{1,3}?bc/i
+ ABBBBC
+ 0: ABBBBC
+
+/ab{3,4}?bc/i
+ ABBBBC
+ 0: ABBBBC
+
+/ab{4,5}?bc/i
+ *** Failers
+No match
+ ABQ
+No match
+ ABBBBC
+No match
+
+/ab??bc/i
+ ABBC
+ 0: ABBC
+ ABC
+ 0: ABC
+
+/ab{0,1}?bc/i
+ ABC
+ 0: ABC
+
+/ab??bc/i
+
+/ab??c/i
+ ABC
+ 0: ABC
+
+/ab{0,1}?c/i
+ ABC
+ 0: ABC
+
+/^abc$/i
+ ABC
+ 0: ABC
+ *** Failers
+No match
+ ABBBBC
+No match
+ ABCC
+No match
+
+/^abc/i
+ ABCC
+ 0: ABC
+
+/^abc$/i
+
+/abc$/i
+ AABC
+ 0: ABC
+
+/^/i
+ ABC
+ 0:
+
+/$/i
+ ABC
+ 0:
+
+/a.c/i
+ ABC
+ 0: ABC
+ AXC
+ 0: AXC
+
+/a.*?c/i
+ AXYZC
+ 0: AXYZC
+
+/a.*c/i
+ *** Failers
+No match
+ AABC
+ 0: AABC
+ AXYZD
+No match
+
+/a[bc]d/i
+ ABD
+ 0: ABD
+
+/a[b-d]e/i
+ ACE
+ 0: ACE
+ *** Failers
+No match
+ ABC
+No match
+ ABD
+No match
+
+/a[b-d]/i
+ AAC
+ 0: AC
+
+/a[-b]/i
+ A-
+ 0: A-
+
+/a[b-]/i
+ A-
+ 0: A-
+
+/a]/i
+ A]
+ 0: A]
+
+/a[]]b/i
+ A]B
+ 0: A]B
+
+/a[^bc]d/i
+ AED
+ 0: AED
+
+/a[^-b]c/i
+ ADC
+ 0: ADC
+ *** Failers
+No match
+ ABD
+No match
+ A-C
+No match
+
+/a[^]b]c/i
+ ADC
+ 0: ADC
+
+/ab|cd/i
+ ABC
+ 0: AB
+ ABCD
+ 0: AB
+
+/()ef/i
+ DEF
+ 0: EF
+
+/$b/i
+ *** Failers
+No match
+ A]C
+No match
+ B
+No match
+
+/a\(b/i
+ A(B
+ 0: A(B
+
+/a\(*b/i
+ AB
+ 0: AB
+ A((B
+ 0: A((B
+
+/a\\b/i
+ A\B
+No match
+
+/((a))/i
+ ABC
+ 0: A
+
+/(a)b(c)/i
+ ABC
+ 0: ABC
+
+/a+b+c/i
+ AABBABC
+ 0: ABC
+
+/a{1,}b{1,}c/i
+ AABBABC
+ 0: ABC
+
+/a.+?c/i
+ ABCABC
+ 0: ABCABC
+ 1: ABC
+
+/a.*?c/i
+ ABCABC
+ 0: ABCABC
+ 1: ABC
+
+/a.{0,5}?c/i
+ ABCABC
+ 0: ABCABC
+ 1: ABC
+
+/(a+|b)*/i
+ AB
+ 0: AB
+ 1: A
+ 2:
+
+/(a+|b){0,}/i
+ AB
+ 0: AB
+ 1: A
+ 2:
+
+/(a+|b)+/i
+ AB
+ 0: AB
+ 1: A
+
+/(a+|b){1,}/i
+ AB
+ 0: AB
+ 1: A
+
+/(a+|b)?/i
+ AB
+ 0: A
+ 1:
+
+/(a+|b){0,1}/i
+ AB
+ 0: A
+ 1:
+
+/(a+|b){0,1}?/i
+ AB
+ 0: A
+ 1:
+
+/[^ab]*/i
+ CDE
+ 0: CDE
+ 1: CD
+ 2: C
+ 3:
+
+/abc/i
+
+/a*/i
+
+
+/([abc])*d/i
+ ABBBCD
+ 0: ABBBCD
+
+/([abc])*bcd/i
+ ABCD
+ 0: ABCD
+
+/a|b|c|d|e/i
+ E
+ 0: E
+
+/(a|b|c|d|e)f/i
+ EF
+ 0: EF
+
+/abcd*efg/i
+ ABCDEFG
+ 0: ABCDEFG
+
+/ab*/i
+ XABYABBBZ
+ 0: AB
+ 1: A
+ XAYABBBZ
+ 0: A
+
+/(ab|cd)e/i
+ ABCDE
+ 0: CDE
+
+/[abhgefdc]ij/i
+ HIJ
+ 0: HIJ
+
+/^(ab|cd)e/i
+ ABCDE
+No match
+
+/(abc|)ef/i
+ ABCDEF
+ 0: EF
+
+/(a|b)c*d/i
+ ABCD
+ 0: BCD
+
+/(ab|ab*)bc/i
+ ABC
+ 0: ABC
+
+/a([bc]*)c*/i
+ ABC
+ 0: ABC
+ 1: AB
+ 2: A
+
+/a([bc]*)(c*d)/i
+ ABCD
+ 0: ABCD
+
+/a([bc]+)(c*d)/i
+ ABCD
+ 0: ABCD
+
+/a([bc]*)(c+d)/i
+ ABCD
+ 0: ABCD
+
+/a[bcd]*dcdcde/i
+ ADCDCDE
+ 0: ADCDCDE
+
+/a[bcd]+dcdcde/i
+
+/(ab|a)b*c/i
+ ABC
+ 0: ABC
+
+/((a)(b)c)(d)/i
+ ABCD
+ 0: ABCD
+
+/[a-zA-Z_][a-zA-Z0-9_]*/i
+ ALPHA
+ 0: ALPHA
+ 1: ALPH
+ 2: ALP
+ 3: AL
+ 4: A
+
+/^a(bc+|b[eh])g|.h$/i
+ ABH
+ 0: BH
+
+/(bc+d$|ef*g.|h?i(j|k))/i
+ EFFGZ
+ 0: EFFGZ
+ IJ
+ 0: IJ
+ REFFGZ
+ 0: EFFGZ
+ *** Failers
+No match
+ ADCDCDE
+No match
+ EFFG
+No match
+ BCDD
+No match
+
+/((((((((((a))))))))))/i
+ A
+ 0: A
+
+/(((((((((a)))))))))/i
+ A
+ 0: A
+
+/(?:(?:(?:(?:(?:(?:(?:(?:(?:(a))))))))))/i
+ A
+ 0: A
+
+/(?:(?:(?:(?:(?:(?:(?:(?:(?:(a|b|c))))))))))/i
+ C
+ 0: C
+
+/multiple words of text/i
+ *** Failers
+No match
+ AA
+No match
+ UH-UH
+No match
+
+/multiple words/i
+ MULTIPLE WORDS, YEAH
+ 0: MULTIPLE WORDS
+
+/(.*)c(.*)/i
+ ABCDE
+ 0: ABCDE
+ 1: ABCD
+ 2: ABC
+
+/\((.*), (.*)\)/i
+ (A, B)
+ 0: (A, B)
+
+/[k]/i
+
+/abcd/i
+ ABCD
+ 0: ABCD
+
+/a(bc)d/i
+ ABCD
+ 0: ABCD
+
+/a[-]?c/i
+ AC
+ 0: AC
+
+/a(?!b)./
+ abad
+ 0: ad
+
+/a(?=d)./
+ abad
+ 0: ad
+
+/a(?=c|d)./
+ abad
+ 0: ad
+
+/a(?:b|c|d)(.)/
+ ace
+ 0: ace
+
+/a(?:b|c|d)*(.)/
+ ace
+ 0: ace
+ 1: ac
+
+/a(?:b|c|d)+?(.)/
+ ace
+ 0: ace
+ acdbcdbe
+ 0: acdbcdbe
+ 1: acdbcdb
+ 2: acdbcd
+ 3: acdbc
+ 4: acdb
+ 5: acd
+
+/a(?:b|c|d)+(.)/
+ acdbcdbe
+ 0: acdbcdbe
+ 1: acdbcdb
+ 2: acdbcd
+ 3: acdbc
+ 4: acdb
+ 5: acd
+
+/a(?:b|c|d){2}(.)/
+ acdbcdbe
+ 0: acdb
+
+/a(?:b|c|d){4,5}(.)/
+ acdbcdbe
+ 0: acdbcdb
+ 1: acdbcd
+
+/a(?:b|c|d){4,5}?(.)/
+ acdbcdbe
+ 0: acdbcdb
+ 1: acdbcd
+
+/((foo)|(bar))*/
+ foobar
+ 0: foobar
+ 1: foo
+ 2:
+
+/a(?:b|c|d){6,7}(.)/
+ acdbcdbe
+ 0: acdbcdbe
+
+/a(?:b|c|d){6,7}?(.)/
+ acdbcdbe
+ 0: acdbcdbe
+
+/a(?:b|c|d){5,6}(.)/
+ acdbcdbe
+ 0: acdbcdbe
+ 1: acdbcdb
+
+/a(?:b|c|d){5,6}?(.)/
+ acdbcdbe
+ 0: acdbcdbe
+ 1: acdbcdb
+
+/a(?:b|c|d){5,7}(.)/
+ acdbcdbe
+ 0: acdbcdbe
+ 1: acdbcdb
+
+/a(?:b|c|d){5,7}?(.)/
+ acdbcdbe
+ 0: acdbcdbe
+ 1: acdbcdb
+
+/a(?:b|(c|e){1,2}?|d)+?(.)/
+ ace
+ 0: ace
+
+/^(.+)?B/
+ AB
+ 0: AB
+
+/^([^a-z])|(\^)$/
+ .
+ 0: .
+
+/^[<>]&/
+ <&OUT
+ 0: <&
+
+/(?:(f)(o)(o)|(b)(a)(r))*/
+ foobar
+ 0: foobar
+ 1: foo
+ 2:
+
+/(?<=a)b/
+ ab
+ 0: b
+ *** Failers
+No match
+ cb
+No match
+ b
+No match
+
+/(?<!c)b/
+ ab
+ 0: b
+ b
+ 0: b
+ b
+ 0: b
+
+/(?:..)*a/
+ aba
+ 0: aba
+ 1: a
+
+/(?:..)*?a/
+ aba
+ 0: aba
+ 1: a
+
+/^(){3,5}/
+ abc
+ 0:
+
+/^(a+)*ax/
+ aax
+ 0: aax
+
+/^((a|b)+)*ax/
+ aax
+ 0: aax
+
+/^((a|bc)+)*ax/
+ aax
+ 0: aax
+
+/(a|x)*ab/
+ cab
+ 0: ab
+
+/(a)*ab/
+ cab
+ 0: ab
+
+/(?:(?i)a)b/
+ ab
+ 0: ab
+
+/((?i)a)b/
+ ab
+ 0: ab
+
+/(?:(?i)a)b/
+ Ab
+ 0: Ab
+
+/((?i)a)b/
+ Ab
+ 0: Ab
+
+/(?:(?i)a)b/
+ *** Failers
+No match
+ cb
+No match
+ aB
+No match
+
+/((?i)a)b/
+
+/(?i:a)b/
+ ab
+ 0: ab
+
+/((?i:a))b/
+ ab
+ 0: ab
+
+/(?i:a)b/
+ Ab
+ 0: Ab
+
+/((?i:a))b/
+ Ab
+ 0: Ab
+
+/(?i:a)b/
+ *** Failers
+No match
+ aB
+No match
+ aB
+No match
+
+/((?i:a))b/
+
+/(?:(?-i)a)b/i
+ ab
+ 0: ab
+
+/((?-i)a)b/i
+ ab
+ 0: ab
+
+/(?:(?-i)a)b/i
+ aB
+ 0: aB
+
+/((?-i)a)b/i
+ aB
+ 0: aB
+
+/(?:(?-i)a)b/i
+ *** Failers
+No match
+ aB
+ 0: aB
+ Ab
+No match
+
+/((?-i)a)b/i
+
+/(?:(?-i)a)b/i
+ aB
+ 0: aB
+
+/((?-i)a)b/i
+ aB
+ 0: aB
+
+/(?:(?-i)a)b/i
+ *** Failers
+No match
+ Ab
+No match
+ AB
+No match
+
+/((?-i)a)b/i
+
+/(?-i:a)b/i
+ ab
+ 0: ab
+
+/((?-i:a))b/i
+ ab
+ 0: ab
+
+/(?-i:a)b/i
+ aB
+ 0: aB
+
+/((?-i:a))b/i
+ aB
+ 0: aB
+
+/(?-i:a)b/i
+ *** Failers
+No match
+ AB
+No match
+ Ab
+No match
+
+/((?-i:a))b/i
+
+/(?-i:a)b/i
+ aB
+ 0: aB
+
+/((?-i:a))b/i
+ aB
+ 0: aB
+
+/(?-i:a)b/i
+ *** Failers
+No match
+ Ab
+No match
+ AB
+No match
+
+/((?-i:a))b/i
+
+/((?-i:a.))b/i
+ *** Failers
+No match
+ AB
+No match
+ a\nB
+No match
+
+/((?s-i:a.))b/i
+ a\nB
+ 0: a\x0aB
+
+/(?:c|d)(?:)(?:a(?:)(?:b)(?:b(?:))(?:b(?:)(?:b)))/
+ cabbbb
+ 0: cabbbb
+
+/(?:c|d)(?:)(?:aaaaaaaa(?:)(?:bbbbbbbb)(?:bbbbbbbb(?:))(?:bbbbbbbb(?:)(?:bbbbbbbb)))/
+ caaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+ 0: caaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+
+/foo\w*\d{4}baz/
+ foobar1234baz
+ 0: foobar1234baz
+
+/x(~~)*(?:(?:F)?)?/
+ x~~
+ 0: x~~
+ 1: x
+
+/^a(?#xxx){3}c/
+ aaac
+ 0: aaac
+
+/^a (?#xxx) (?#yyy) {3}c/x
+ aaac
+ 0: aaac
+
+/(?<![cd])b/
+ *** Failers
+No match
+ B\nB
+No match
+ dbcb
+No match
+
+/(?<![cd])[ab]/
+ dbaacb
+ 0: a
+
+/(?<!(c|d))b/
+
+/(?<!(c|d))[ab]/
+ dbaacb
+ 0: a
+
+/(?<!cd)[ab]/
+ cdaccb
+ 0: b
+
+/^(?:a?b?)*$/
+ *** Failers
+No match
+ dbcb
+No match
+ a--
+No match
+
+/((?s)^a(.))((?m)^b$)/
+ a\nb\nc\n
+ 0: a\x0ab
+
+/((?m)^b$)/
+ a\nb\nc\n
+ 0: b
+
+/(?m)^b/
+ a\nb\n
+ 0: b
+
+/(?m)^(b)/
+ a\nb\n
+ 0: b
+
+/((?m)^b)/
+ a\nb\n
+ 0: b
+
+/\n((?m)^b)/
+ a\nb\n
+ 0: \x0ab
+
+/((?s).)c(?!.)/
+ a\nb\nc\n
+ 0: \x0ac
+ a\nb\nc\n
+ 0: \x0ac
+
+/((?s)b.)c(?!.)/
+ a\nb\nc\n
+ 0: b\x0ac
+ a\nb\nc\n
+ 0: b\x0ac
+
+/^b/
+
+/()^b/
+ *** Failers
+No match
+ a\nb\nc\n
+No match
+ a\nb\nc\n
+No match
+
+/((?m)^b)/
+ a\nb\nc\n
+ 0: b
+
+/(?(?!a)a|b)/
+
+/(?(?!a)b|a)/
+ a
+ 0: a
+
+/(?(?=a)b|a)/
+ *** Failers
+No match
+ a
+No match
+ a
+No match
+
+/(?(?=a)a|b)/
+ a
+ 0: a
+
+/(\w+:)+/
+ one:
+ 0: one:
+
+/$(?<=^(a))/
+ a
+ 0:
+
+/([\w:]+::)?(\w+)$/
+ abcd
+ 0: abcd
+ xy:z:::abcd
+ 0: xy:z:::abcd
+
+/^[^bcd]*(c+)/
+ aexycd
+ 0: aexyc
+
+/(a*)b+/
+ caab
+ 0: aab
+
+/([\w:]+::)?(\w+)$/
+ abcd
+ 0: abcd
+ xy:z:::abcd
+ 0: xy:z:::abcd
+ *** Failers
+ 0: Failers
+ abcd:
+No match
+ abcd:
+No match
+
+/^[^bcd]*(c+)/
+ aexycd
+ 0: aexyc
+
+/(>a+)ab/
+
+/(?>a+)b/
+ aaab
+ 0: aaab
+
+/([[:]+)/
+ a:[b]:
+ 0: :[
+ 1: :
+
+/([[=]+)/
+ a=[b]=
+ 0: =[
+ 1: =
+
+/([[.]+)/
+ a.[b].
+ 0: .[
+ 1: .
+
+/((?>a+)b)/
+ aaab
+ 0: aaab
+
+/(?>(a+))b/
+ aaab
+ 0: aaab
+
+/((?>[^()]+)|\([^()]*\))+/
+ ((abc(ade)ufh()()x
+ 0: abc(ade)ufh()()x
+ 1: abc(ade)ufh()()
+ 2: abc(ade)ufh()
+ 3: abc(ade)ufh
+ 4: abc(ade)
+ 5: abc
+
+/a\Z/
+ *** Failers
+No match
+ aaab
+No match
+ a\nb\n
+No match
+
+/b\Z/
+ a\nb\n
+ 0: b
+
+/b\z/
+
+/b\Z/
+ a\nb
+ 0: b
+
+/b\z/
+ a\nb
+ 0: b
+ *** Failers
+No match
+
+/(?>.*)(?<=(abcd|wxyz))/
+ alphabetabcd
+ 0: alphabetabcd
+ endingwxyz
+ 0: endingwxyz
+ *** Failers
+No match
+ a rather long string that doesn't end with one of them
+No match
+
+/word (?>(?:(?!otherword)[a-zA-Z0-9]+ ){0,30})otherword/
+ word cat dog elephant mussel cow horse canary baboon snake shark otherword
+ 0: word cat dog elephant mussel cow horse canary baboon snake shark otherword
+ word cat dog elephant mussel cow horse canary baboon snake shark
+No match
+
+/word (?>[a-zA-Z0-9]+ ){0,30}otherword/
+ word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope
+No match
+
+/(?<=\d{3}(?!999))foo/
+ 999foo
+ 0: foo
+ 123999foo
+ 0: foo
+ *** Failers
+No match
+ 123abcfoo
+No match
+
+/(?<=(?!...999)\d{3})foo/
+ 999foo
+ 0: foo
+ 123999foo
+ 0: foo
+ *** Failers
+No match
+ 123abcfoo
+No match
+
+/(?<=\d{3}(?!999)...)foo/
+ 123abcfoo
+ 0: foo
+ 123456foo
+ 0: foo
+ *** Failers
+No match
+ 123999foo
+No match
+
+/(?<=\d{3}...)(?<!999)foo/
+ 123abcfoo
+ 0: foo
+ 123456foo
+ 0: foo
+ *** Failers
+No match
+ 123999foo
+No match
+
+/((Z)+|A)*/
+ ZABCDEFG
+ 0: ZA
+ 1: Z
+ 2:
+
+/(Z()|A)*/
+ ZABCDEFG
+ 0: ZA
+ 1: Z
+ 2:
+
+/(Z(())|A)*/
+ ZABCDEFG
+ 0: ZA
+ 1: Z
+ 2:
+
+/((?>Z)+|A)*/
+ ZABCDEFG
+ 0: ZA
+ 1: Z
+ 2:
+
+/((?>)+|A)*/
+ ZABCDEFG
+ 0:
+
+/a*/g
+ abbab
+ 0: a
+ 1:
+ 0:
+ 0:
+ 0: a
+ 1:
+ 0:
+ 0:
+
+/^[a-\d]/
+ abcde
+ 0: a
+ -things
+ 0: -
+ 0digit
+ 0: 0
+ *** Failers
+No match
+ bcdef
+No match
+
+/^[\d-a]/
+ abcde
+ 0: a
+ -things
+ 0: -
+ 0digit
+ 0: 0
+ *** Failers
+No match
+ bcdef
+No match
+
+/[[:space:]]+/
+ > \x09\x0a\x0c\x0d\x0b<
+ 0: \x09\x0a\x0c\x0d\x0b
+ 1: \x09\x0a\x0c\x0d
+ 2: \x09\x0a\x0c
+ 3: \x09\x0a
+ 4: \x09
+ 5:
+
+/[[:blank:]]+/
+ > \x09\x0a\x0c\x0d\x0b<
+ 0: \x09
+ 1:
+
+/[\s]+/
+ > \x09\x0a\x0c\x0d\x0b<
+ 0: \x09\x0a\x0c\x0d
+ 1: \x09\x0a\x0c
+ 2: \x09\x0a
+ 3: \x09
+ 4:
+
+/\s+/
+ > \x09\x0a\x0c\x0d\x0b<
+ 0: \x09\x0a\x0c\x0d
+ 1: \x09\x0a\x0c
+ 2: \x09\x0a
+ 3: \x09
+ 4:
+
+/a b/x
+ ab
+No match
+
+/(?!\A)x/m
+ a\nxb\n
+ 0: x
+
+/(?!^)x/m
+ a\nxb\n
+No match
+
+/abc\Qabc\Eabc/
+ abcabcabc
+ 0: abcabcabc
+
+/abc\Q(*+|\Eabc/
+ abc(*+|abc
+ 0: abc(*+|abc
+
+/ abc\Q abc\Eabc/x
+ abc abcabc
+ 0: abc abcabc
+ *** Failers
+No match
+ abcabcabc
+No match
+
+/abc#comment
+ \Q#not comment
+ literal\E/x
+ abc#not comment\n literal
+ 0: abc#not comment\x0a literal
+
+/abc#comment
+ \Q#not comment
+ literal/x
+ abc#not comment\n literal
+ 0: abc#not comment\x0a literal
+
+/abc#comment
+ \Q#not comment
+ literal\E #more comment
+ /x
+ abc#not comment\n literal
+ 0: abc#not comment\x0a literal
+
+/abc#comment
+ \Q#not comment
+ literal\E #more comment/x
+ abc#not comment\n literal
+ 0: abc#not comment\x0a literal
+
+/\Qabc\$xyz\E/
+ abc\\\$xyz
+ 0: abc\$xyz
+
+/\Qabc\E\$\Qxyz\E/
+ abc\$xyz
+ 0: abc$xyz
+
+/\Gabc/
+ abc
+ 0: abc
+ *** Failers
+No match
+ xyzabc
+No match
+
+/\Gabc./g
+ abc1abc2xyzabc3
+ 0: abc1
+ 0: abc2
+
+/abc./g
+ abc1abc2xyzabc3
+ 0: abc1
+ 0: abc2
+ 0: abc3
+
+/a(?x: b c )d/
+ XabcdY
+ 0: abcd
+ *** Failers
+No match
+ Xa b c d Y
+No match
+
+/((?x)x y z | a b c)/
+ XabcY
+ 0: abc
+ AxyzB
+ 0: xyz
+
+/(?i)AB(?-i)C/
+ XabCY
+ 0: abC
+ *** Failers
+No match
+ XabcY
+No match
+
+/((?i)AB(?-i)C|D)E/
+ abCE
+ 0: abCE
+ DE
+ 0: DE
+ *** Failers
+No match
+ abcE
+No match
+ abCe
+No match
+ dE
+No match
+ De
+No match
+
+/[z\Qa-d]\E]/
+ z
+ 0: z
+ a
+ 0: a
+ -
+ 0: -
+ d
+ 0: d
+ ]
+ 0: ]
+ *** Failers
+ 0: a
+ b
+No match
+
+/[\z\C]/
+ z
+ 0: z
+ C
+ 0: C
+
+/\M/
+ M
+ 0: M
+
+/(a+)*b/
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+No match
+
+/(?i)reg(?:ul(?:[a�]|ae)r|ex)/
+ REGular
+ 0: REGular
+ regulaer
+ 0: regulaer
+ Regex
+ 0: Regex
+ regul�r
+ 0: regul\xe4r
+
+/����[�-��-�]+/
+ �����
+ 0: \xc5\xe6\xe5\xe4\xe0
+ �����
+ 0: \xc5\xe6\xe5\xe4\xff
+ �����
+ 0: \xc5\xe6\xe5\xe4\xc0
+ �����
+ 0: \xc5\xe6\xe5\xe4\xdf
+
+/(?<=Z)X./
+ \x84XAZXB
+ 0: XB
+
+/^(?(2)a|(1)(2))+$/
+ 123a
+Error -17
+
+/(?<=a|bbbb)c/
+ ac
+ 0: c
+ bbbbc
+ 0: c
+
+/abc/>testsavedregex
+Compiled regex written to testsavedregex
+<testsavedregex
+Compiled regex loaded from testsavedregex
+No study data
+ abc
+ 0: abc
+ *** Failers
+No match
+ bca
+No match
+
+/abc/F>testsavedregex
+Compiled regex written to testsavedregex
+<testsavedregex
+Compiled regex (byte-inverted) loaded from testsavedregex
+No study data
+ abc
+ 0: abc
+ *** Failers
+No match
+ bca
+No match
+
+/(a|b)/S>testsavedregex
+Compiled regex written to testsavedregex
+Study data written to testsavedregex
+<testsavedregex
+Compiled regex loaded from testsavedregex
+Study data loaded from testsavedregex
+ abc
+ 0: a
+ *** Failers
+ 0: a
+ def
+No match
+
+/(a|b)/SF>testsavedregex
+Compiled regex written to testsavedregex
+Study data written to testsavedregex
+<testsavedregex
+Compiled regex (byte-inverted) loaded from testsavedregex
+Study data loaded from testsavedregex
+ abc
+ 0: a
+ *** Failers
+ 0: a
+ def
+No match
+
+/line\nbreak/
+ this is a line\nbreak
+ 0: line\x0abreak
+ line one\nthis is a line\nbreak in the second line
+ 0: line\x0abreak
+
+/line\nbreak/f
+ this is a line\nbreak
+ 0: line\x0abreak
+ ** Failers
+No match
+ line one\nthis is a line\nbreak in the second line
+No match
+
+/line\nbreak/mf
+ this is a line\nbreak
+ 0: line\x0abreak
+ ** Failers
+No match
+ line one\nthis is a line\nbreak in the second line
+No match
+
+/1234/
+ 123\P
+Partial match: 123
+ a4\P\R
+No match
+
+/1234/
+ 123\P
+Partial match: 123
+ 4\P\R
+ 0: 4
+
+/^/mg
+ a\nb\nc\n
+ 0:
+ 0:
+ 0:
+ \
+ 0:
+
+/(?<=C\n)^/mg
+ A\nC\nC\n
+ 0:
+
+/(?s)A?B/
+ AB
+ 0: AB
+ aB
+ 0: B
+
+/(?s)A*B/
+ AB
+ 0: AB
+ aB
+ 0: B
+
+/(?m)A?B/
+ AB
+ 0: AB
+ aB
+ 0: B
+
+/(?m)A*B/
+ AB
+ 0: AB
+ aB
+ 0: B
+
+/Content-Type\x3A[^\r\n]{6,}/
+ Content-Type:xxxxxyyy
+ 0: Content-Type:xxxxxyyy
+ 1: Content-Type:xxxxxyy
+ 2: Content-Type:xxxxxy
+
+/Content-Type\x3A[^\r\n]{6,}z/
+ Content-Type:xxxxxyyyz
+ 0: Content-Type:xxxxxyyyz
+
+/Content-Type\x3A[^a]{6,}/
+ Content-Type:xxxyyy
+ 0: Content-Type:xxxyyy
+
+/Content-Type\x3A[^a]{6,}z/
+ Content-Type:xxxyyyz
+ 0: Content-Type:xxxyyyz
+
+/^abc/m
+ xyz\nabc
+ 0: abc
+ xyz\nabc\<lf>
+ 0: abc
+ xyz\r\nabc\<lf>
+ 0: abc
+ xyz\rabc\<cr>
+ 0: abc
+ xyz\r\nabc\<crlf>
+ 0: abc
+ ** Failers
+No match
+ xyz\nabc\<cr>
+No match
+ xyz\r\nabc\<cr>
+No match
+ xyz\nabc\<crlf>
+No match
+ xyz\rabc\<crlf>
+No match
+ xyz\rabc\<lf>
+No match
+
+/abc$/m<lf>
+ xyzabc
+ 0: abc
+ xyzabc\n
+ 0: abc
+ xyzabc\npqr
+ 0: abc
+ xyzabc\r\<cr>
+ 0: abc
+ xyzabc\rpqr\<cr>
+ 0: abc
+ xyzabc\r\n\<crlf>
+ 0: abc
+ xyzabc\r\npqr\<crlf>
+ 0: abc
+ ** Failers
+No match
+ xyzabc\r
+No match
+ xyzabc\rpqr
+No match
+ xyzabc\r\n
+No match
+ xyzabc\r\npqr
+No match
+
+/^abc/m<cr>
+ xyz\rabcdef
+ 0: abc
+ xyz\nabcdef\<lf>
+ 0: abc
+ ** Failers
+No match
+ xyz\nabcdef
+No match
+
+/^abc/m<lf>
+ xyz\nabcdef
+ 0: abc
+ xyz\rabcdef\<cr>
+ 0: abc
+ ** Failers
+No match
+ xyz\rabcdef
+No match
+
+/^abc/m<crlf>
+ xyz\r\nabcdef
+ 0: abc
+ xyz\rabcdef\<cr>
+ 0: abc
+ ** Failers
+No match
+ xyz\rabcdef
+No match
+
+/.*/<lf>
+ abc\ndef
+ 0: abc
+ 1: ab
+ 2: a
+ 3:
+ abc\rdef
+ 0: abc\x0ddef
+ 1: abc\x0dde
+ 2: abc\x0dd
+ 3: abc\x0d
+ 4: abc
+ 5: ab
+ 6: a
+ 7:
+ abc\r\ndef
+ 0: abc\x0d
+ 1: abc
+ 2: ab
+ 3: a
+ 4:
+ \<cr>abc\ndef
+ 0: abc\x0adef
+ 1: abc\x0ade
+ 2: abc\x0ad
+ 3: abc\x0a
+ 4: abc
+ 5: ab
+ 6: a
+ 7:
+ \<cr>abc\rdef
+ 0: abc
+ 1: ab
+ 2: a
+ 3:
+ \<cr>abc\r\ndef
+ 0: abc
+ 1: ab
+ 2: a
+ 3:
+ \<crlf>abc\ndef
+ 0: abc\x0adef
+ 1: abc\x0ade
+ 2: abc\x0ad
+ 3: abc\x0a
+ 4: abc
+ 5: ab
+ 6: a
+ 7:
+ \<crlf>abc\rdef
+ 0: abc\x0ddef
+ 1: abc\x0dde
+ 2: abc\x0dd
+ 3: abc\x0d
+ 4: abc
+ 5: ab
+ 6: a
+ 7:
+ \<crlf>abc\r\ndef
+ 0: abc
+ 1: ab
+ 2: a
+ 3:
+
+/\w+(.)(.)?def/s
+ abc\ndef
+ 0: abc\x0adef
+ abc\rdef
+ 0: abc\x0ddef
+ abc\r\ndef
+ 0: abc\x0d\x0adef
+
+/^\w+=.*(\\\n.*)*/
+ abc=xyz\\\npqr
+ 0: abc=xyz\\x0apqr
+ 1: abc=xyz\\x0apq
+ 2: abc=xyz\\x0ap
+ 3: abc=xyz\\x0a
+ 4: abc=xyz\
+ 5: abc=xyz
+ 6: abc=xy
+ 7: abc=x
+ 8: abc=
+
+/^(a()*)*/
+ aaaa
+ 0: aaaa
+ 1: aaa
+ 2: aa
+ 3: a
+ 4:
+
+/^(?:a(?:(?:))*)*/
+ aaaa
+ 0: aaaa
+ 1: aaa
+ 2: aa
+ 3: a
+ 4:
+
+/^(a()+)+/
+ aaaa
+ 0: aaaa
+ 1: aaa
+ 2: aa
+ 3: a
+
+/^(?:a(?:(?:))+)+/
+ aaaa
+ 0: aaaa
+ 1: aaa
+ 2: aa
+ 3: a
+
+/(a|)*\d/
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+No match
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4
+ 0: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4
+
+/(?>a|)*\d/
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+No match
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4
+ 0: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4
+
+/(?:a|)*\d/
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+No match
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4
+ 0: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4
+
+/^a.b/<lf>
+ a\rb
+ 0: a\x0db
+ a\nb\<cr>
+ 0: a\x0ab
+ ** Failers
+No match
+ a\nb
+No match
+ a\nb\<any>
+No match
+ a\rb\<cr>
+No match
+ a\rb\<any>
+No match
+
+/^abc./mgx<any>
+ abc1 \x0aabc2 \x0babc3xx \x0cabc4 \x0dabc5xx \x0d\x0aabc6 \x85abc7 \x{2028}abc8 \x{2029}abc9 JUNK
+ 0: abc1
+ 0: abc2
+ 0: abc3
+ 0: abc4
+ 0: abc5
+ 0: abc6
+ 0: abc7
+
+/abc.$/mgx<any>
+ abc1\x0a abc2\x0b abc3\x0c abc4\x0d abc5\x0d\x0a abc6\x85 abc7\x{2028} abc8\x{2029} abc9
+ 0: abc1
+ 0: abc2
+ 0: abc3
+ 0: abc4
+ 0: abc5
+ 0: abc6
+ 0: abc9
+
+/^a\Rb/<bsr_unicode>
+ a\nb
+ 0: a\x0ab
+ a\rb
+ 0: a\x0db
+ a\r\nb
+ 0: a\x0d\x0ab
+ a\x0bb
+ 0: a\x0bb
+ a\x0cb
+ 0: a\x0cb
+ a\x85b
+ 0: a\x85b
+ ** Failers
+No match
+ a\n\rb
+No match
+
+/^a\R*b/<bsr_unicode>
+ ab
+ 0: ab
+ a\nb
+ 0: a\x0ab
+ a\rb
+ 0: a\x0db
+ a\r\nb
+ 0: a\x0d\x0ab
+ a\x0bb
+ 0: a\x0bb
+ a\x0cb
+ 0: a\x0cb
+ a\x85b
+ 0: a\x85b
+ a\n\rb
+ 0: a\x0a\x0db
+ a\n\r\x85\x0cb
+ 0: a\x0a\x0d\x85\x0cb
+
+/^a\R+b/<bsr_unicode>
+ a\nb
+ 0: a\x0ab
+ a\rb
+ 0: a\x0db
+ a\r\nb
+ 0: a\x0d\x0ab
+ a\x0bb
+ 0: a\x0bb
+ a\x0cb
+ 0: a\x0cb
+ a\x85b
+ 0: a\x85b
+ a\n\rb
+ 0: a\x0a\x0db
+ a\n\r\x85\x0cb
+ 0: a\x0a\x0d\x85\x0cb
+ ** Failers
+No match
+ ab
+No match
+
+/^a\R{1,3}b/<bsr_unicode>
+ a\nb
+ 0: a\x0ab
+ a\n\rb
+ 0: a\x0a\x0db
+ a\n\r\x85b
+ 0: a\x0a\x0d\x85b
+ a\r\n\r\nb
+ 0: a\x0d\x0a\x0d\x0ab
+ a\r\n\r\n\r\nb
+ 0: a\x0d\x0a\x0d\x0a\x0d\x0ab
+ a\n\r\n\rb
+ 0: a\x0a\x0d\x0a\x0db
+ a\n\n\r\nb
+ 0: a\x0a\x0a\x0d\x0ab
+ ** Failers
+No match
+ a\n\n\n\rb
+No match
+ a\r
+No match
+
+/^a[\R]b/<bsr_unicode>
+ aRb
+ 0: aRb
+ ** Failers
+No match
+ a\nb
+No match
+
+/.+foo/
+ afoo
+ 0: afoo
+ ** Failers
+No match
+ \r\nfoo
+No match
+ \nfoo
+No match
+
+/.+foo/<crlf>
+ afoo
+ 0: afoo
+ \nfoo
+ 0: \x0afoo
+ ** Failers
+No match
+ \r\nfoo
+No match
+
+/.+foo/<any>
+ afoo
+ 0: afoo
+ ** Failers
+No match
+ \nfoo
+No match
+ \r\nfoo
+No match
+
+/.+foo/s
+ afoo
+ 0: afoo
+ \r\nfoo
+ 0: \x0d\x0afoo
+ \nfoo
+ 0: \x0afoo
+
+/^$/mg<any>
+ abc\r\rxyz
+ 0:
+ abc\n\rxyz
+ 0:
+ ** Failers
+No match
+ abc\r\nxyz
+No match
+
+/^X/m
+ XABC
+ 0: X
+ ** Failers
+No match
+ XABC\B
+No match
+
+/(?m)^$/<any>g+
+ abc\r\n\r\n
+ 0:
+ 0+ \x0d\x0a
+
+/(?m)^$|^\r\n/<any>g+
+ abc\r\n\r\n
+ 0: \x0d\x0a
+ 0+
+ 1:
+
+/(?m)$/<any>g+
+ abc\r\n\r\n
+ 0:
+ 0+ \x0d\x0a\x0d\x0a
+ 0:
+ 0+ \x0d\x0a
+ 0:
+ 0+
+
+/(?|(abc)|(xyz))/
+ >abc<
+ 0: abc
+ >xyz<
+ 0: xyz
+
+/(x)(?|(abc)|(xyz))(x)/
+ xabcx
+ 0: xabcx
+ xxyzx
+ 0: xxyzx
+
+/(x)(?|(abc)(pqr)|(xyz))(x)/
+ xabcpqrx
+ 0: xabcpqrx
+ xxyzx
+ 0: xxyzx
+
+/(?|(abc)|(xyz))(?1)/
+ abcabc
+ 0: abcabc
+ xyzabc
+ 0: xyzabc
+ ** Failers
+No match
+ xyzxyz
+No match
+
+/\H\h\V\v/
+ X X\x0a
+ 0: X X\x0a
+ X\x09X\x0b
+ 0: X\x09X\x0b
+ ** Failers
+No match
+ \xa0 X\x0a
+No match
+
+/\H*\h+\V?\v{3,4}/
+ \x09\x20\xa0X\x0a\x0b\x0c\x0d\x0a
+ 0: \x09 \xa0X\x0a\x0b\x0c\x0d
+ 1: \x09 \xa0X\x0a\x0b\x0c
+ \x09\x20\xa0\x0a\x0b\x0c\x0d\x0a
+ 0: \x09 \xa0\x0a\x0b\x0c\x0d
+ 1: \x09 \xa0\x0a\x0b\x0c
+ \x09\x20\xa0\x0a\x0b\x0c
+ 0: \x09 \xa0\x0a\x0b\x0c
+ ** Failers
+No match
+ \x09\x20\xa0\x0a\x0b
+No match
+
+/\H{3,4}/
+ XY ABCDE
+ 0: ABCD
+ 1: ABC
+ XY PQR ST
+ 0: PQR
+
+/.\h{3,4}./
+ XY AB PQRS
+ 0: B P
+ 1: B
+
+/\h*X\h?\H+Y\H?Z/
+ >XNNNYZ
+ 0: XNNNYZ
+ > X NYQZ
+ 0: X NYQZ
+ ** Failers
+No match
+ >XYZ
+No match
+ > X NY Z
+No match
+
+/\v*X\v?Y\v+Z\V*\x0a\V+\x0b\V{2,3}\x0c/
+ >XY\x0aZ\x0aA\x0bNN\x0c
+ 0: XY\x0aZ\x0aA\x0bNN\x0c
+ >\x0a\x0dX\x0aY\x0a\x0bZZZ\x0aAAA\x0bNNN\x0c
+ 0: \x0a\x0dX\x0aY\x0a\x0bZZZ\x0aAAA\x0bNNN\x0c
+
+/.+A/<crlf>
+ \r\nA
+No match
+
+/\nA/<crlf>
+ \r\nA
+ 0: \x0aA
+
+/[\r\n]A/<crlf>
+ \r\nA
+ 0: \x0aA
+
+/(\r|\n)A/<crlf>
+ \r\nA
+ 0: \x0aA
+
+/a\Rb/I<bsr_anycrlf>
+Capturing subpattern count = 0
+Options: bsr_anycrlf
+First char = 'a'
+Need char = 'b'
+ a\rb
+ 0: a\x0db
+ a\nb
+ 0: a\x0ab
+ a\r\nb
+ 0: a\x0d\x0ab
+ ** Failers
+No match
+ a\x85b
+No match
+ a\x0bb
+No match
+
+/a\Rb/I<bsr_unicode>
+Capturing subpattern count = 0
+Options: bsr_unicode
+First char = 'a'
+Need char = 'b'
+ a\rb
+ 0: a\x0db
+ a\nb
+ 0: a\x0ab
+ a\r\nb
+ 0: a\x0d\x0ab
+ a\x85b
+ 0: a\x85b
+ a\x0bb
+ 0: a\x0bb
+ ** Failers
+No match
+ a\x85b\<bsr_anycrlf>
+No match
+ a\x0bb\<bsr_anycrlf>
+No match
+
+/a\R?b/I<bsr_anycrlf>
+Capturing subpattern count = 0
+Options: bsr_anycrlf
+First char = 'a'
+Need char = 'b'
+ a\rb
+ 0: a\x0db
+ a\nb
+ 0: a\x0ab
+ a\r\nb
+ 0: a\x0d\x0ab
+ ** Failers
+No match
+ a\x85b
+No match
+ a\x0bb
+No match
+
+/a\R?b/I<bsr_unicode>
+Capturing subpattern count = 0
+Options: bsr_unicode
+First char = 'a'
+Need char = 'b'
+ a\rb
+ 0: a\x0db
+ a\nb
+ 0: a\x0ab
+ a\r\nb
+ 0: a\x0d\x0ab
+ a\x85b
+ 0: a\x85b
+ a\x0bb
+ 0: a\x0bb
+ ** Failers
+No match
+ a\x85b\<bsr_anycrlf>
+No match
+ a\x0bb\<bsr_anycrlf>
+No match
+
+/a\R{2,4}b/I<bsr_anycrlf>
+Capturing subpattern count = 0
+Partial matching not supported
+Options: bsr_anycrlf
+First char = 'a'
+Need char = 'b'
+ a\r\n\nb
+ 0: a\x0d\x0a\x0ab
+ a\n\r\rb
+ 0: a\x0a\x0d\x0db
+ a\r\n\r\n\r\n\r\nb
+ 0: a\x0d\x0a\x0d\x0a\x0d\x0a\x0d\x0ab
+ ** Failers
+No match
+ a\x85\85b
+No match
+ a\x0b\0bb
+No match
+
+/a\R{2,4}b/I<bsr_unicode>
+Capturing subpattern count = 0
+Partial matching not supported
+Options: bsr_unicode
+First char = 'a'
+Need char = 'b'
+ a\r\rb
+ 0: a\x0d\x0db
+ a\n\n\nb
+ 0: a\x0a\x0a\x0ab
+ a\r\n\n\r\rb
+ 0: a\x0d\x0a\x0a\x0d\x0db
+ a\x85\85b
+No match
+ a\x0b\0bb
+No match
+ ** Failers
+No match
+ a\r\r\r\r\rb
+No match
+ a\x85\85b\<bsr_anycrlf>
+No match
+ a\x0b\0bb\<bsr_anycrlf>
+No match
+
+/ End of testinput7 /
diff --git a/lib/stdlib/test/re_SUITE_data/testoutput8 b/lib/stdlib/test/re_SUITE_data/testoutput8
new file mode 100644
index 0000000000..631e5b82f9
--- /dev/null
+++ b/lib/stdlib/test/re_SUITE_data/testoutput8
@@ -0,0 +1,1287 @@
+/-- Do not use the \x{} construct except with patterns that have the --/
+/-- /8 option set, because PCRE doesn't recognize them as UTF-8 unless --/
+No match
+/-- that option is set. However, the latest Perls recognize them always. --/
+No match
+
+/\x{100}ab/8
+ \x{100}ab
+ 0: \x{100}ab
+
+/a\x{100}*b/8
+ ab
+ 0: ab
+ a\x{100}b
+ 0: a\x{100}b
+ a\x{100}\x{100}b
+ 0: a\x{100}\x{100}b
+
+/a\x{100}+b/8
+ a\x{100}b
+ 0: a\x{100}b
+ a\x{100}\x{100}b
+ 0: a\x{100}\x{100}b
+ *** Failers
+No match
+ ab
+No match
+
+/\bX/8
+ Xoanon
+ 0: X
+ +Xoanon
+ 0: X
+ \x{300}Xoanon
+ 0: X
+ *** Failers
+No match
+ YXoanon
+No match
+
+/\BX/8
+ YXoanon
+ 0: X
+ *** Failers
+No match
+ Xoanon
+No match
+ +Xoanon
+No match
+ \x{300}Xoanon
+No match
+
+/X\b/8
+ X+oanon
+ 0: X
+ ZX\x{300}oanon
+ 0: X
+ FAX
+ 0: X
+ *** Failers
+No match
+ Xoanon
+No match
+
+/X\B/8
+ Xoanon
+ 0: X
+ *** Failers
+No match
+ X+oanon
+No match
+ ZX\x{300}oanon
+No match
+ FAX
+No match
+
+/[^a]/8
+ abcd
+ 0: b
+ a\x{100}
+ 0: \x{100}
+
+/^[abc\x{123}\x{400}-\x{402}]{2,3}\d/8
+ ab99
+ 0: ab9
+ \x{123}\x{123}45
+ 0: \x{123}\x{123}4
+ \x{400}\x{401}\x{402}6
+ 0: \x{400}\x{401}\x{402}6
+ *** Failers
+No match
+ d99
+No match
+ \x{123}\x{122}4
+No match
+ \x{400}\x{403}6
+No match
+ \x{400}\x{401}\x{402}\x{402}6
+No match
+
+/abc/8
+ �]
+Error -10
+ �
+Error -10
+ ���
+Error -10
+ ���\?
+No match
+
+/a.b/8
+ acb
+ 0: acb
+ a\x7fb
+ 0: a\x{7f}b
+ a\x{100}b
+ 0: a\x{100}b
+ *** Failers
+No match
+ a\nb
+No match
+
+/a(.{3})b/8
+ a\x{4000}xyb
+ 0: a\x{4000}xyb
+ a\x{4000}\x7fyb
+ 0: a\x{4000}\x{7f}yb
+ a\x{4000}\x{100}yb
+ 0: a\x{4000}\x{100}yb
+ *** Failers
+No match
+ a\x{4000}b
+No match
+ ac\ncb
+No match
+
+/a(.*?)(.)/
+ a\xc0\x88b
+ 0: a\xc0\x88b
+ 1: a\xc0\x88
+ 2: a\xc0
+
+/a(.*?)(.)/8
+ a\x{100}b
+ 0: a\x{100}b
+ 1: a\x{100}
+
+/a(.*)(.)/
+ a\xc0\x88b
+ 0: a\xc0\x88b
+ 1: a\xc0\x88
+ 2: a\xc0
+
+/a(.*)(.)/8
+ a\x{100}b
+ 0: a\x{100}b
+ 1: a\x{100}
+
+/a(.)(.)/
+ a\xc0\x92bcd
+ 0: a\xc0\x92
+
+/a(.)(.)/8
+ a\x{240}bcd
+ 0: a\x{240}b
+
+/a(.?)(.)/
+ a\xc0\x92bcd
+ 0: a\xc0\x92
+ 1: a\xc0
+
+/a(.?)(.)/8
+ a\x{240}bcd
+ 0: a\x{240}b
+ 1: a\x{240}
+
+/a(.??)(.)/
+ a\xc0\x92bcd
+ 0: a\xc0\x92
+ 1: a\xc0
+
+/a(.??)(.)/8
+ a\x{240}bcd
+ 0: a\x{240}b
+ 1: a\x{240}
+
+/a(.{3})b/8
+ a\x{1234}xyb
+ 0: a\x{1234}xyb
+ a\x{1234}\x{4321}yb
+ 0: a\x{1234}\x{4321}yb
+ a\x{1234}\x{4321}\x{3412}b
+ 0: a\x{1234}\x{4321}\x{3412}b
+ *** Failers
+No match
+ a\x{1234}b
+No match
+ ac\ncb
+No match
+
+/a(.{3,})b/8
+ a\x{1234}xyb
+ 0: a\x{1234}xyb
+ a\x{1234}\x{4321}yb
+ 0: a\x{1234}\x{4321}yb
+ a\x{1234}\x{4321}\x{3412}b
+ 0: a\x{1234}\x{4321}\x{3412}b
+ axxxxbcdefghijb
+ 0: axxxxbcdefghijb
+ 1: axxxxb
+ a\x{1234}\x{4321}\x{3412}\x{3421}b
+ 0: a\x{1234}\x{4321}\x{3412}\x{3421}b
+ *** Failers
+No match
+ a\x{1234}b
+No match
+
+/a(.{3,}?)b/8
+ a\x{1234}xyb
+ 0: a\x{1234}xyb
+ a\x{1234}\x{4321}yb
+ 0: a\x{1234}\x{4321}yb
+ a\x{1234}\x{4321}\x{3412}b
+ 0: a\x{1234}\x{4321}\x{3412}b
+ axxxxbcdefghijb
+ 0: axxxxbcdefghijb
+ 1: axxxxb
+ a\x{1234}\x{4321}\x{3412}\x{3421}b
+ 0: a\x{1234}\x{4321}\x{3412}\x{3421}b
+ *** Failers
+No match
+ a\x{1234}b
+No match
+
+/a(.{3,5})b/8
+ a\x{1234}xyb
+ 0: a\x{1234}xyb
+ a\x{1234}\x{4321}yb
+ 0: a\x{1234}\x{4321}yb
+ a\x{1234}\x{4321}\x{3412}b
+ 0: a\x{1234}\x{4321}\x{3412}b
+ axxxxbcdefghijb
+ 0: axxxxb
+ a\x{1234}\x{4321}\x{3412}\x{3421}b
+ 0: a\x{1234}\x{4321}\x{3412}\x{3421}b
+ axbxxbcdefghijb
+ 0: axbxxb
+ axxxxxbcdefghijb
+ 0: axxxxxb
+ *** Failers
+No match
+ a\x{1234}b
+No match
+ axxxxxxbcdefghijb
+No match
+
+/a(.{3,5}?)b/8
+ a\x{1234}xyb
+ 0: a\x{1234}xyb
+ a\x{1234}\x{4321}yb
+ 0: a\x{1234}\x{4321}yb
+ a\x{1234}\x{4321}\x{3412}b
+ 0: a\x{1234}\x{4321}\x{3412}b
+ axxxxbcdefghijb
+ 0: axxxxb
+ a\x{1234}\x{4321}\x{3412}\x{3421}b
+ 0: a\x{1234}\x{4321}\x{3412}\x{3421}b
+ axbxxbcdefghijb
+ 0: axbxxb
+ axxxxxbcdefghijb
+ 0: axxxxxb
+ *** Failers
+No match
+ a\x{1234}b
+No match
+ axxxxxxbcdefghijb
+No match
+
+/^[a\x{c0}]/8
+ *** Failers
+No match
+ \x{100}
+No match
+
+/(?<=aXb)cd/8
+ aXbcd
+ 0: cd
+
+/(?<=a\x{100}b)cd/8
+ a\x{100}bcd
+ 0: cd
+
+/(?<=a\x{100000}b)cd/8
+ a\x{100000}bcd
+ 0: cd
+
+/(?:\x{100}){3}b/8
+ \x{100}\x{100}\x{100}b
+ 0: \x{100}\x{100}\x{100}b
+ *** Failers
+No match
+ \x{100}\x{100}b
+No match
+
+/\x{ab}/8
+ \x{ab}
+ 0: \x{ab}
+ \xc2\xab
+ 0: \x{ab}
+ *** Failers
+No match
+ \x00{ab}
+No match
+
+/(?<=(.))X/8
+ WXYZ
+ 0: X
+ \x{256}XYZ
+ 0: X
+ *** Failers
+No match
+ XYZ
+No match
+
+/[^a]+/8g
+ bcd
+ 0: bcd
+ 1: bc
+ 2: b
+ \x{100}aY\x{256}Z
+ 0: \x{100}
+ 0: Y\x{256}Z
+ 1: Y\x{256}
+ 2: Y
+
+/^[^a]{2}/8
+ \x{100}bc
+ 0: \x{100}b
+
+/^[^a]{2,}/8
+ \x{100}bcAa
+ 0: \x{100}bcA
+ 1: \x{100}bc
+ 2: \x{100}b
+
+/^[^a]{2,}?/8
+ \x{100}bca
+ 0: \x{100}bc
+ 1: \x{100}b
+
+/[^a]+/8ig
+ bcd
+ 0: bcd
+ 1: bc
+ 2: b
+ \x{100}aY\x{256}Z
+ 0: \x{100}
+ 0: Y\x{256}Z
+ 1: Y\x{256}
+ 2: Y
+
+/^[^a]{2}/8i
+ \x{100}bc
+ 0: \x{100}b
+
+/^[^a]{2,}/8i
+ \x{100}bcAa
+ 0: \x{100}bc
+ 1: \x{100}b
+
+/^[^a]{2,}?/8i
+ \x{100}bca
+ 0: \x{100}bc
+ 1: \x{100}b
+
+/\x{100}{0,0}/8
+ abcd
+ 0:
+
+/\x{100}?/8
+ abcd
+ 0:
+ \x{100}\x{100}
+ 0: \x{100}
+ 1:
+
+/\x{100}{0,3}/8
+ \x{100}\x{100}
+ 0: \x{100}\x{100}
+ 1: \x{100}
+ 2:
+ \x{100}\x{100}\x{100}\x{100}
+ 0: \x{100}\x{100}\x{100}
+ 1: \x{100}\x{100}
+ 2: \x{100}
+ 3:
+
+/\x{100}*/8
+ abce
+ 0:
+ \x{100}\x{100}\x{100}\x{100}
+ 0: \x{100}\x{100}\x{100}\x{100}
+ 1: \x{100}\x{100}\x{100}
+ 2: \x{100}\x{100}
+ 3: \x{100}
+ 4:
+
+/\x{100}{1,1}/8
+ abcd\x{100}\x{100}\x{100}\x{100}
+ 0: \x{100}
+
+/\x{100}{1,3}/8
+ abcd\x{100}\x{100}\x{100}\x{100}
+ 0: \x{100}\x{100}\x{100}
+ 1: \x{100}\x{100}
+ 2: \x{100}
+
+/\x{100}+/8
+ abcd\x{100}\x{100}\x{100}\x{100}
+ 0: \x{100}\x{100}\x{100}\x{100}
+ 1: \x{100}\x{100}\x{100}
+ 2: \x{100}\x{100}
+ 3: \x{100}
+
+/\x{100}{3}/8
+ abcd\x{100}\x{100}\x{100}XX
+ 0: \x{100}\x{100}\x{100}
+
+/\x{100}{3,5}/8
+ abcd\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}XX
+ 0: \x{100}\x{100}\x{100}\x{100}\x{100}
+ 1: \x{100}\x{100}\x{100}\x{100}
+ 2: \x{100}\x{100}\x{100}
+
+/\x{100}{3,}/8
+ abcd\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}XX
+ 0: \x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}
+ 1: \x{100}\x{100}\x{100}\x{100}\x{100}\x{100}
+ 2: \x{100}\x{100}\x{100}\x{100}\x{100}
+ 3: \x{100}\x{100}\x{100}\x{100}
+ 4: \x{100}\x{100}\x{100}
+
+/(?<=a\x{100}{2}b)X/8
+ Xyyya\x{100}\x{100}bXzzz
+ 0: X
+
+/\D*/8
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+Matched, but too many subsidiary matches
+ 0: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 1: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 2: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 3: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 4: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 5: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 6: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 7: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 8: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 9: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+10: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+11: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+12: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+13: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+14: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+15: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+16: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+17: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+18: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+19: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+20: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+21: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+
+/\D*/8
+ \x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}
+Matched, but too many subsidiary matches
+ 0: \x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}
+ 1: \x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}
+ 2: \x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}
+ 3: \x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}
+ 4: \x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}
+ 5: \x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}
+ 6: \x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}
+ 7: \x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}
+ 8: \x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}
+ 9: \x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}
+10: \x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}
+11: \x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}
+12: \x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}
+13: \x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}
+14: \x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}
+15: \x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}
+16: \x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}
+17: \x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}
+18: \x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}
+19: \x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}
+20: \x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}
+21: \x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}
+
+/\D/8
+ 1X2
+ 0: X
+ 1\x{100}2
+ 0: \x{100}
+
+/>\S/8
+ > >X Y
+ 0: >X
+ > >\x{100} Y
+ 0: >\x{100}
+
+/\d/8
+ \x{100}3
+ 0: 3
+
+/\s/8
+ \x{100} X
+ 0:
+
+/\D+/8
+ 12abcd34
+ 0: abcd
+ 1: abc
+ 2: ab
+ 3: a
+ *** Failers
+ 0: *** Failers
+ 1: *** Failer
+ 2: *** Faile
+ 3: *** Fail
+ 4: *** Fai
+ 5: *** Fa
+ 6: *** F
+ 7: ***
+ 8: ***
+ 9: **
+10: *
+ 1234
+No match
+
+/\D{2,3}/8
+ 12abcd34
+ 0: abc
+ 1: ab
+ 12ab34
+ 0: ab
+ *** Failers
+ 0: ***
+ 1: **
+ 1234
+No match
+ 12a34
+No match
+
+/\D{2,3}?/8
+ 12abcd34
+ 0: abc
+ 1: ab
+ 12ab34
+ 0: ab
+ *** Failers
+ 0: ***
+ 1: **
+ 1234
+No match
+ 12a34
+No match
+
+/\d+/8
+ 12abcd34
+ 0: 12
+ 1: 1
+ *** Failers
+No match
+
+/\d{2,3}/8
+ 12abcd34
+ 0: 12
+ 1234abcd
+ 0: 123
+ 1: 12
+ *** Failers
+No match
+ 1.4
+No match
+
+/\d{2,3}?/8
+ 12abcd34
+ 0: 12
+ 1234abcd
+ 0: 123
+ 1: 12
+ *** Failers
+No match
+ 1.4
+No match
+
+/\S+/8
+ 12abcd34
+ 0: 12abcd34
+ 1: 12abcd3
+ 2: 12abcd
+ 3: 12abc
+ 4: 12ab
+ 5: 12a
+ 6: 12
+ 7: 1
+ *** Failers
+ 0: ***
+ 1: **
+ 2: *
+ \ \
+No match
+
+/\S{2,3}/8
+ 12abcd34
+ 0: 12a
+ 1: 12
+ 1234abcd
+ 0: 123
+ 1: 12
+ *** Failers
+ 0: ***
+ 1: **
+ \ \
+No match
+
+/\S{2,3}?/8
+ 12abcd34
+ 0: 12a
+ 1: 12
+ 1234abcd
+ 0: 123
+ 1: 12
+ *** Failers
+ 0: ***
+ 1: **
+ \ \
+No match
+
+/>\s+</8
+ 12> <34
+ 0: > <
+ *** Failers
+No match
+
+/>\s{2,3}</8
+ ab> <cd
+ 0: > <
+ ab> <ce
+ 0: > <
+ *** Failers
+No match
+ ab> <cd
+No match
+
+/>\s{2,3}?</8
+ ab> <cd
+ 0: > <
+ ab> <ce
+ 0: > <
+ *** Failers
+No match
+ ab> <cd
+No match
+
+/\w+/8
+ 12 34
+ 0: 12
+ 1: 1
+ *** Failers
+ 0: Failers
+ 1: Failer
+ 2: Faile
+ 3: Fail
+ 4: Fai
+ 5: Fa
+ 6: F
+ +++=*!
+No match
+
+/\w{2,3}/8
+ ab cd
+ 0: ab
+ abcd ce
+ 0: abc
+ 1: ab
+ *** Failers
+ 0: Fai
+ 1: Fa
+ a.b.c
+No match
+
+/\w{2,3}?/8
+ ab cd
+ 0: ab
+ abcd ce
+ 0: abc
+ 1: ab
+ *** Failers
+ 0: Fai
+ 1: Fa
+ a.b.c
+No match
+
+/\W+/8
+ 12====34
+ 0: ====
+ 1: ===
+ 2: ==
+ 3: =
+ *** Failers
+ 0: ***
+ 1: ***
+ 2: **
+ 3: *
+ abcd
+No match
+
+/\W{2,3}/8
+ ab====cd
+ 0: ===
+ 1: ==
+ ab==cd
+ 0: ==
+ *** Failers
+ 0: ***
+ 1: **
+ a.b.c
+No match
+
+/\W{2,3}?/8
+ ab====cd
+ 0: ===
+ 1: ==
+ ab==cd
+ 0: ==
+ *** Failers
+ 0: ***
+ 1: **
+ a.b.c
+No match
+
+/[\x{100}]/8
+ \x{100}
+ 0: \x{100}
+ Z\x{100}
+ 0: \x{100}
+ \x{100}Z
+ 0: \x{100}
+ *** Failers
+No match
+
+/[Z\x{100}]/8
+ Z\x{100}
+ 0: Z
+ \x{100}
+ 0: \x{100}
+ \x{100}Z
+ 0: \x{100}
+ *** Failers
+No match
+
+/[\x{100}\x{200}]/8
+ ab\x{100}cd
+ 0: \x{100}
+ ab\x{200}cd
+ 0: \x{200}
+ *** Failers
+No match
+
+/[\x{100}-\x{200}]/8
+ ab\x{100}cd
+ 0: \x{100}
+ ab\x{200}cd
+ 0: \x{200}
+ ab\x{111}cd
+ 0: \x{111}
+ *** Failers
+No match
+
+/[z-\x{200}]/8
+ ab\x{100}cd
+ 0: \x{100}
+ ab\x{200}cd
+ 0: \x{200}
+ ab\x{111}cd
+ 0: \x{111}
+ abzcd
+ 0: z
+ ab|cd
+ 0: |
+ *** Failers
+No match
+
+/[Q\x{100}\x{200}]/8
+ ab\x{100}cd
+ 0: \x{100}
+ ab\x{200}cd
+ 0: \x{200}
+ Q?
+ 0: Q
+ *** Failers
+No match
+
+/[Q\x{100}-\x{200}]/8
+ ab\x{100}cd
+ 0: \x{100}
+ ab\x{200}cd
+ 0: \x{200}
+ ab\x{111}cd
+ 0: \x{111}
+ Q?
+ 0: Q
+ *** Failers
+No match
+
+/[Qz-\x{200}]/8
+ ab\x{100}cd
+ 0: \x{100}
+ ab\x{200}cd
+ 0: \x{200}
+ ab\x{111}cd
+ 0: \x{111}
+ abzcd
+ 0: z
+ ab|cd
+ 0: |
+ Q?
+ 0: Q
+ *** Failers
+No match
+
+/[\x{100}\x{200}]{1,3}/8
+ ab\x{100}cd
+ 0: \x{100}
+ ab\x{200}cd
+ 0: \x{200}
+ ab\x{200}\x{100}\x{200}\x{100}cd
+ 0: \x{200}\x{100}\x{200}
+ 1: \x{200}\x{100}
+ 2: \x{200}
+ *** Failers
+No match
+
+/[\x{100}\x{200}]{1,3}?/8
+ ab\x{100}cd
+ 0: \x{100}
+ ab\x{200}cd
+ 0: \x{200}
+ ab\x{200}\x{100}\x{200}\x{100}cd
+ 0: \x{200}\x{100}\x{200}
+ 1: \x{200}\x{100}
+ 2: \x{200}
+ *** Failers
+No match
+
+/[Q\x{100}\x{200}]{1,3}/8
+ ab\x{100}cd
+ 0: \x{100}
+ ab\x{200}cd
+ 0: \x{200}
+ ab\x{200}\x{100}\x{200}\x{100}cd
+ 0: \x{200}\x{100}\x{200}
+ 1: \x{200}\x{100}
+ 2: \x{200}
+ *** Failers
+No match
+
+/[Q\x{100}\x{200}]{1,3}?/8
+ ab\x{100}cd
+ 0: \x{100}
+ ab\x{200}cd
+ 0: \x{200}
+ ab\x{200}\x{100}\x{200}\x{100}cd
+ 0: \x{200}\x{100}\x{200}
+ 1: \x{200}\x{100}
+ 2: \x{200}
+ *** Failers
+No match
+
+/(?<=[\x{100}\x{200}])X/8
+ abc\x{200}X
+ 0: X
+ abc\x{100}X
+ 0: X
+ *** Failers
+No match
+ X
+No match
+
+/(?<=[Q\x{100}\x{200}])X/8
+ abc\x{200}X
+ 0: X
+ abc\x{100}X
+ 0: X
+ abQX
+ 0: X
+ *** Failers
+No match
+ X
+No match
+
+/(?<=[\x{100}\x{200}]{3})X/8
+ abc\x{100}\x{200}\x{100}X
+ 0: X
+ *** Failers
+No match
+ abc\x{200}X
+No match
+ X
+No match
+
+/[^\x{100}\x{200}]X/8
+ AX
+ 0: AX
+ \x{150}X
+ 0: \x{150}X
+ \x{500}X
+ 0: \x{500}X
+ *** Failers
+No match
+ \x{100}X
+No match
+ \x{200}X
+No match
+
+/[^Q\x{100}\x{200}]X/8
+ AX
+ 0: AX
+ \x{150}X
+ 0: \x{150}X
+ \x{500}X
+ 0: \x{500}X
+ *** Failers
+No match
+ \x{100}X
+No match
+ \x{200}X
+No match
+ QX
+No match
+
+/[^\x{100}-\x{200}]X/8
+ AX
+ 0: AX
+ \x{500}X
+ 0: \x{500}X
+ *** Failers
+No match
+ \x{100}X
+No match
+ \x{150}X
+No match
+ \x{200}X
+No match
+
+/[z-\x{100}]/8i
+ z
+ 0: z
+ Z
+ 0: Z
+ \x{100}
+ 0: \x{100}
+ *** Failers
+No match
+ \x{102}
+No match
+ y
+No match
+
+/[\xFF]/
+ >\xff<
+ 0: \xff
+
+/[\xff]/8
+ >\x{ff}<
+ 0: \x{ff}
+
+/[^\xFF]/
+ XYZ
+ 0: X
+
+/[^\xff]/8
+ XYZ
+ 0: X
+ \x{123}
+ 0: \x{123}
+
+/^[ac]*b/8
+ xb
+No match
+
+/^[ac\x{100}]*b/8
+ xb
+No match
+
+/^[^x]*b/8i
+ xb
+No match
+
+/^[^x]*b/8
+ xb
+No match
+
+/^\d*b/8
+ xb
+No match
+
+/(|a)/g8
+ catac
+ 0:
+ 0: a
+ 1:
+ 0:
+ 0: a
+ 1:
+ 0:
+ 0:
+ a\x{256}a
+ 0: a
+ 1:
+ 0:
+ 0: a
+ 1:
+ 0:
+
+/^\x{85}$/8i
+ \x{85}
+ 0: \x{85}
+
+/^abc./mgx8<any>
+ abc1 \x0aabc2 \x0babc3xx \x0cabc4 \x0dabc5xx \x0d\x0aabc6 \x{0085}abc7 \x{2028}abc8 \x{2029}abc9 JUNK
+ 0: abc1
+ 0: abc2
+ 0: abc3
+ 0: abc4
+ 0: abc5
+ 0: abc6
+ 0: abc7
+ 0: abc8
+ 0: abc9
+
+/abc.$/mgx8<any>
+ abc1\x0a abc2\x0b abc3\x0c abc4\x0d abc5\x0d\x0a abc6\x{0085} abc7\x{2028} abc8\x{2029} abc9
+ 0: abc1
+ 0: abc2
+ 0: abc3
+ 0: abc4
+ 0: abc5
+ 0: abc6
+ 0: abc7
+ 0: abc8
+ 0: abc9
+
+/^a\Rb/8<bsr_unicode>
+ a\nb
+ 0: a\x{0a}b
+ a\rb
+ 0: a\x{0d}b
+ a\r\nb
+ 0: a\x{0d}\x{0a}b
+ a\x0bb
+ 0: a\x{0b}b
+ a\x0cb
+ 0: a\x{0c}b
+ a\x{85}b
+ 0: a\x{85}b
+ a\x{2028}b
+ 0: a\x{2028}b
+ a\x{2029}b
+ 0: a\x{2029}b
+ ** Failers
+No match
+ a\n\rb
+No match
+
+/^a\R*b/8<bsr_unicode>
+ ab
+ 0: ab
+ a\nb
+ 0: a\x{0a}b
+ a\rb
+ 0: a\x{0d}b
+ a\r\nb
+ 0: a\x{0d}\x{0a}b
+ a\x0bb
+ 0: a\x{0b}b
+ a\x0c\x{2028}\x{2029}b
+ 0: a\x{0c}\x{2028}\x{2029}b
+ a\x{85}b
+ 0: a\x{85}b
+ a\n\rb
+ 0: a\x{0a}\x{0d}b
+ a\n\r\x{85}\x0cb
+ 0: a\x{0a}\x{0d}\x{85}\x{0c}b
+
+/^a\R+b/8<bsr_unicode>
+ a\nb
+ 0: a\x{0a}b
+ a\rb
+ 0: a\x{0d}b
+ a\r\nb
+ 0: a\x{0d}\x{0a}b
+ a\x0bb
+ 0: a\x{0b}b
+ a\x0c\x{2028}\x{2029}b
+ 0: a\x{0c}\x{2028}\x{2029}b
+ a\x{85}b
+ 0: a\x{85}b
+ a\n\rb
+ 0: a\x{0a}\x{0d}b
+ a\n\r\x{85}\x0cb
+ 0: a\x{0a}\x{0d}\x{85}\x{0c}b
+ ** Failers
+No match
+ ab
+No match
+
+/^a\R{1,3}b/8<bsr_unicode>
+ a\nb
+ 0: a\x{0a}b
+ a\n\rb
+ 0: a\x{0a}\x{0d}b
+ a\n\r\x{85}b
+ 0: a\x{0a}\x{0d}\x{85}b
+ a\r\n\r\nb
+ 0: a\x{0d}\x{0a}\x{0d}\x{0a}b
+ a\r\n\r\n\r\nb
+ 0: a\x{0d}\x{0a}\x{0d}\x{0a}\x{0d}\x{0a}b
+ a\n\r\n\rb
+ 0: a\x{0a}\x{0d}\x{0a}\x{0d}b
+ a\n\n\r\nb
+ 0: a\x{0a}\x{0a}\x{0d}\x{0a}b
+ ** Failers
+No match
+ a\n\n\n\rb
+No match
+ a\r
+No match
+
+/\h+\V?\v{3,4}/8
+ \x09\x20\x{a0}X\x0a\x0b\x0c\x0d\x0a
+ 0: \x{09} \x{a0}X\x{0a}\x{0b}\x{0c}\x{0d}
+ 1: \x{09} \x{a0}X\x{0a}\x{0b}\x{0c}
+
+/\V?\v{3,4}/8
+ \x20\x{a0}X\x0a\x0b\x0c\x0d\x0a
+ 0: X\x{0a}\x{0b}\x{0c}\x{0d}
+ 1: X\x{0a}\x{0b}\x{0c}
+
+/\h+\V?\v{3,4}/8
+ >\x09\x20\x{a0}X\x0a\x0a\x0a<
+ 0: \x{09} \x{a0}X\x{0a}\x{0a}\x{0a}
+
+/\V?\v{3,4}/8
+ >\x09\x20\x{a0}X\x0a\x0a\x0a<
+ 0: X\x{0a}\x{0a}\x{0a}
+
+/\H\h\V\v/8
+ X X\x0a
+ 0: X X\x{0a}
+ X\x09X\x0b
+ 0: X\x{09}X\x{0b}
+ ** Failers
+No match
+ \x{a0} X\x0a
+No match
+
+/\H*\h+\V?\v{3,4}/8
+ \x09\x20\x{a0}X\x0a\x0b\x0c\x0d\x0a
+ 0: \x{09} \x{a0}X\x{0a}\x{0b}\x{0c}\x{0d}
+ 1: \x{09} \x{a0}X\x{0a}\x{0b}\x{0c}
+ \x09\x20\x{a0}\x0a\x0b\x0c\x0d\x0a
+ 0: \x{09} \x{a0}\x{0a}\x{0b}\x{0c}\x{0d}
+ 1: \x{09} \x{a0}\x{0a}\x{0b}\x{0c}
+ \x09\x20\x{a0}\x0a\x0b\x0c
+ 0: \x{09} \x{a0}\x{0a}\x{0b}\x{0c}
+ ** Failers
+No match
+ \x09\x20\x{a0}\x0a\x0b
+No match
+
+/\H\h\V\v/8
+ \x{3001}\x{3000}\x{2030}\x{2028}
+ 0: \x{3001}\x{3000}\x{2030}\x{2028}
+ X\x{180e}X\x{85}
+ 0: X\x{180e}X\x{85}
+ ** Failers
+No match
+ \x{2009} X\x0a
+No match
+
+/\H*\h+\V?\v{3,4}/8
+ \x{1680}\x{180e}\x{2007}X\x{2028}\x{2029}\x0c\x0d\x0a
+ 0: \x{1680}\x{180e}\x{2007}X\x{2028}\x{2029}\x{0c}\x{0d}
+ 1: \x{1680}\x{180e}\x{2007}X\x{2028}\x{2029}\x{0c}
+ \x09\x{205f}\x{a0}\x0a\x{2029}\x0c\x{2028}\x0a
+ 0: \x{09}\x{205f}\x{a0}\x{0a}\x{2029}\x{0c}\x{2028}
+ 1: \x{09}\x{205f}\x{a0}\x{0a}\x{2029}\x{0c}
+ \x09\x20\x{202f}\x0a\x0b\x0c
+ 0: \x{09} \x{202f}\x{0a}\x{0b}\x{0c}
+ ** Failers
+No match
+ \x09\x{200a}\x{a0}\x{2028}\x0b
+No match
+
+/a\Rb/I8<bsr_anycrlf>
+Capturing subpattern count = 0
+Options: bsr_anycrlf utf8
+First char = 'a'
+Need char = 'b'
+ a\rb
+ 0: a\x{0d}b
+ a\nb
+ 0: a\x{0a}b
+ a\r\nb
+ 0: a\x{0d}\x{0a}b
+ ** Failers
+No match
+ a\x{85}b
+No match
+ a\x0bb
+No match
+
+/a\Rb/I8<bsr_unicode>
+Capturing subpattern count = 0
+Options: bsr_unicode utf8
+First char = 'a'
+Need char = 'b'
+ a\rb
+ 0: a\x{0d}b
+ a\nb
+ 0: a\x{0a}b
+ a\r\nb
+ 0: a\x{0d}\x{0a}b
+ a\x{85}b
+ 0: a\x{85}b
+ a\x0bb
+ 0: a\x{0b}b
+ ** Failers
+No match
+ a\x{85}b\<bsr_anycrlf>
+No match
+ a\x0bb\<bsr_anycrlf>
+No match
+
+/a\R?b/I8<bsr_anycrlf>
+Capturing subpattern count = 0
+Options: bsr_anycrlf utf8
+First char = 'a'
+Need char = 'b'
+ a\rb
+ 0: a\x{0d}b
+ a\nb
+ 0: a\x{0a}b
+ a\r\nb
+ 0: a\x{0d}\x{0a}b
+ ** Failers
+No match
+ a\x{85}b
+No match
+ a\x0bb
+No match
+
+/a\R?b/I8<bsr_unicode>
+Capturing subpattern count = 0
+Options: bsr_unicode utf8
+First char = 'a'
+Need char = 'b'
+ a\rb
+ 0: a\x{0d}b
+ a\nb
+ 0: a\x{0a}b
+ a\r\nb
+ 0: a\x{0d}\x{0a}b
+ a\x{85}b
+ 0: a\x{85}b
+ a\x0bb
+ 0: a\x{0b}b
+ ** Failers
+No match
+ a\x{85}b\<bsr_anycrlf>
+No match
+ a\x0bb\<bsr_anycrlf>
+No match
+
+/ End of testinput 8 /
diff --git a/lib/stdlib/test/re_SUITE_data/testoutput9 b/lib/stdlib/test/re_SUITE_data/testoutput9
new file mode 100644
index 0000000000..acaeb398dd
--- /dev/null
+++ b/lib/stdlib/test/re_SUITE_data/testoutput9
@@ -0,0 +1,1643 @@
+/\pL\P{Nd}/8
+ AB
+ 0: AB
+ *** Failers
+ 0: Fa
+ A0
+No match
+ 00
+No match
+
+/\X./8
+ AB
+ 0: AB
+ A\x{300}BC
+ 0: A\x{300}B
+ A\x{300}\x{301}\x{302}BC
+ 0: A\x{300}\x{301}\x{302}B
+ *** Failers
+ 0: **
+ \x{300}
+No match
+
+/\X\X/8
+ ABC
+ 0: AB
+ A\x{300}B\x{300}\x{301}C
+ 0: A\x{300}B\x{300}\x{301}
+ A\x{300}\x{301}\x{302}BC
+ 0: A\x{300}\x{301}\x{302}B
+ *** Failers
+ 0: **
+ \x{300}
+No match
+
+/^\pL+/8
+ abcd
+ 0: abcd
+ 1: abc
+ 2: ab
+ 3: a
+ a
+ 0: a
+ *** Failers
+No match
+
+/^\PL+/8
+ 1234
+ 0: 1234
+ 1: 123
+ 2: 12
+ 3: 1
+ =
+ 0: =
+ *** Failers
+ 0: ***
+ 1: ***
+ 2: **
+ 3: *
+ abcd
+No match
+
+/^\X+/8
+ abcdA\x{300}\x{301}\x{302}
+ 0: abcdA\x{300}\x{301}\x{302}
+ 1: abcd
+ 2: abc
+ 3: ab
+ 4: a
+ A\x{300}\x{301}\x{302}
+ 0: A\x{300}\x{301}\x{302}
+ A\x{300}\x{301}\x{302}A\x{300}\x{301}\x{302}
+ 0: A\x{300}\x{301}\x{302}A\x{300}\x{301}\x{302}
+ 1: A\x{300}\x{301}\x{302}
+ a
+ 0: a
+ *** Failers
+ 0: *** Failers
+ 1: *** Failer
+ 2: *** Faile
+ 3: *** Fail
+ 4: *** Fai
+ 5: *** Fa
+ 6: *** F
+ 7: ***
+ 8: ***
+ 9: **
+10: *
+ \x{300}\x{301}\x{302}
+No match
+
+/\X?abc/8
+ abc
+ 0: abc
+ A\x{300}abc
+ 0: A\x{300}abc
+ A\x{300}\x{301}\x{302}A\x{300}A\x{300}A\x{300}abcxyz
+ 0: A\x{300}abc
+ \x{300}abc
+ 0: abc
+ *** Failers
+No match
+
+/^\X?abc/8
+ abc
+ 0: abc
+ A\x{300}abc
+ 0: A\x{300}abc
+ *** Failers
+No match
+ A\x{300}\x{301}\x{302}A\x{300}A\x{300}A\x{300}abcxyz
+No match
+ \x{300}abc
+No match
+
+/\X*abc/8
+ abc
+ 0: abc
+ A\x{300}abc
+ 0: A\x{300}abc
+ A\x{300}\x{301}\x{302}A\x{300}A\x{300}A\x{300}abcxyz
+ 0: A\x{300}\x{301}\x{302}A\x{300}A\x{300}A\x{300}abc
+ \x{300}abc
+ 0: abc
+ *** Failers
+No match
+
+/^\X*abc/8
+ abc
+ 0: abc
+ A\x{300}abc
+ 0: A\x{300}abc
+ A\x{300}\x{301}\x{302}A\x{300}A\x{300}A\x{300}abcxyz
+ 0: A\x{300}\x{301}\x{302}A\x{300}A\x{300}A\x{300}abc
+ *** Failers
+No match
+ \x{300}abc
+No match
+
+/^\pL?=./8
+ A=b
+ 0: A=b
+ =c
+ 0: =c
+ *** Failers
+No match
+ 1=2
+No match
+ AAAA=b
+No match
+
+/^\pL*=./8
+ AAAA=b
+ 0: AAAA=b
+ =c
+ 0: =c
+ *** Failers
+No match
+ 1=2
+No match
+
+/^\X{2,3}X/8
+ A\x{300}\x{301}\x{302}A\x{300}\x{301}\x{302}X
+ 0: A\x{300}\x{301}\x{302}A\x{300}\x{301}\x{302}X
+ A\x{300}\x{301}\x{302}A\x{300}\x{301}\x{302}A\x{300}\x{301}\x{302}X
+ 0: A\x{300}\x{301}\x{302}A\x{300}\x{301}\x{302}A\x{300}\x{301}\x{302}X
+ *** Failers
+No match
+ X
+No match
+ A\x{300}\x{301}\x{302}X
+No match
+ A\x{300}\x{301}\x{302}A\x{300}\x{301}\x{302}A\x{300}\x{301}\x{302}A\x{300}\x{301}\x{302}X
+No match
+
+/^\pC\pL\pM\pN\pP\pS\pZ</8
+ \x7f\x{c0}\x{30f}\x{660}\x{66c}\x{f01}\x{1680}<
+ 0: \x{7f}\x{c0}\x{30f}\x{660}\x{66c}\x{f01}\x{1680}<
+ \np\x{300}9!\$ <
+ 0: \x{0a}p\x{300}9!$ <
+ ** Failers
+No match
+ ap\x{300}9!\$ <
+No match
+
+/^\PC/8
+ X
+ 0: X
+ ** Failers
+ 0: *
+ \x7f
+No match
+
+/^\PL/8
+ 9
+ 0: 9
+ ** Failers
+ 0: *
+ \x{c0}
+No match
+
+/^\PM/8
+ X
+ 0: X
+ ** Failers
+ 0: *
+ \x{30f}
+No match
+
+/^\PN/8
+ X
+ 0: X
+ ** Failers
+ 0: *
+ \x{660}
+No match
+
+/^\PP/8
+ X
+ 0: X
+ ** Failers
+No match
+ \x{66c}
+No match
+
+/^\PS/8
+ X
+ 0: X
+ ** Failers
+ 0: *
+ \x{f01}
+No match
+
+/^\PZ/8
+ X
+ 0: X
+ ** Failers
+ 0: *
+ \x{1680}
+No match
+
+/^\p{Cc}/8
+ \x{017}
+ 0: \x{17}
+ \x{09f}
+ 0: \x{9f}
+ ** Failers
+No match
+ \x{0600}
+No match
+
+/^\p{Cf}/8
+ \x{601}
+ 0: \x{601}
+ ** Failers
+No match
+ \x{09f}
+No match
+
+/^\p{Cn}/8
+ ** Failers
+No match
+ \x{09f}
+No match
+
+/^\p{Co}/8
+ \x{f8ff}
+ 0: \x{f8ff}
+ ** Failers
+No match
+ \x{09f}
+No match
+
+/^\p{Cs}/8
+ \?\x{dfff}
+ 0: \x{dfff}
+ ** Failers
+No match
+ \x{09f}
+No match
+
+/^\p{Ll}/8
+ a
+ 0: a
+ ** Failers
+No match
+ Z
+No match
+ \x{e000}
+No match
+
+/^\p{Lm}/8
+ \x{2b0}
+ 0: \x{2b0}
+ ** Failers
+No match
+ a
+No match
+
+/^\p{Lo}/8
+ \x{1bb}
+ 0: \x{1bb}
+ ** Failers
+No match
+ a
+No match
+ \x{2b0}
+No match
+
+/^\p{Lt}/8
+ \x{1c5}
+ 0: \x{1c5}
+ ** Failers
+No match
+ a
+No match
+ \x{2b0}
+No match
+
+/^\p{Lu}/8
+ A
+ 0: A
+ ** Failers
+No match
+ \x{2b0}
+No match
+
+/^\p{Mc}/8
+ \x{903}
+ 0: \x{903}
+ ** Failers
+No match
+ X
+No match
+ \x{300}
+No match
+
+/^\p{Me}/8
+ \x{488}
+ 0: \x{488}
+ ** Failers
+No match
+ X
+No match
+ \x{903}
+No match
+ \x{300}
+No match
+
+/^\p{Mn}/8
+ \x{300}
+ 0: \x{300}
+ ** Failers
+No match
+ X
+No match
+ \x{903}
+No match
+
+/^\p{Nd}+/8
+ 0123456789\x{660}\x{661}\x{662}\x{663}\x{664}\x{665}\x{666}\x{667}\x{668}\x{669}\x{66a}
+ 0: 0123456789\x{660}\x{661}\x{662}\x{663}\x{664}\x{665}\x{666}\x{667}\x{668}\x{669}
+ 1: 0123456789\x{660}\x{661}\x{662}\x{663}\x{664}\x{665}\x{666}\x{667}\x{668}
+ 2: 0123456789\x{660}\x{661}\x{662}\x{663}\x{664}\x{665}\x{666}\x{667}
+ 3: 0123456789\x{660}\x{661}\x{662}\x{663}\x{664}\x{665}\x{666}
+ 4: 0123456789\x{660}\x{661}\x{662}\x{663}\x{664}\x{665}
+ 5: 0123456789\x{660}\x{661}\x{662}\x{663}\x{664}
+ 6: 0123456789\x{660}\x{661}\x{662}\x{663}
+ 7: 0123456789\x{660}\x{661}\x{662}
+ 8: 0123456789\x{660}\x{661}
+ 9: 0123456789\x{660}
+10: 0123456789
+11: 012345678
+12: 01234567
+13: 0123456
+14: 012345
+15: 01234
+16: 0123
+17: 012
+18: 01
+19: 0
+ \x{6f0}\x{6f1}\x{6f2}\x{6f3}\x{6f4}\x{6f5}\x{6f6}\x{6f7}\x{6f8}\x{6f9}\x{6fa}
+ 0: \x{6f0}\x{6f1}\x{6f2}\x{6f3}\x{6f4}\x{6f5}\x{6f6}\x{6f7}\x{6f8}\x{6f9}
+ 1: \x{6f0}\x{6f1}\x{6f2}\x{6f3}\x{6f4}\x{6f5}\x{6f6}\x{6f7}\x{6f8}
+ 2: \x{6f0}\x{6f1}\x{6f2}\x{6f3}\x{6f4}\x{6f5}\x{6f6}\x{6f7}
+ 3: \x{6f0}\x{6f1}\x{6f2}\x{6f3}\x{6f4}\x{6f5}\x{6f6}
+ 4: \x{6f0}\x{6f1}\x{6f2}\x{6f3}\x{6f4}\x{6f5}
+ 5: \x{6f0}\x{6f1}\x{6f2}\x{6f3}\x{6f4}
+ 6: \x{6f0}\x{6f1}\x{6f2}\x{6f3}
+ 7: \x{6f0}\x{6f1}\x{6f2}
+ 8: \x{6f0}\x{6f1}
+ 9: \x{6f0}
+ \x{966}\x{967}\x{968}\x{969}\x{96a}\x{96b}\x{96c}\x{96d}\x{96e}\x{96f}\x{970}
+ 0: \x{966}\x{967}\x{968}\x{969}\x{96a}\x{96b}\x{96c}\x{96d}\x{96e}\x{96f}
+ 1: \x{966}\x{967}\x{968}\x{969}\x{96a}\x{96b}\x{96c}\x{96d}\x{96e}
+ 2: \x{966}\x{967}\x{968}\x{969}\x{96a}\x{96b}\x{96c}\x{96d}
+ 3: \x{966}\x{967}\x{968}\x{969}\x{96a}\x{96b}\x{96c}
+ 4: \x{966}\x{967}\x{968}\x{969}\x{96a}\x{96b}
+ 5: \x{966}\x{967}\x{968}\x{969}\x{96a}
+ 6: \x{966}\x{967}\x{968}\x{969}
+ 7: \x{966}\x{967}\x{968}
+ 8: \x{966}\x{967}
+ 9: \x{966}
+ ** Failers
+No match
+ X
+No match
+
+/^\p{Nl}/8
+ \x{16ee}
+ 0: \x{16ee}
+ ** Failers
+No match
+ X
+No match
+ \x{966}
+No match
+
+/^\p{No}/8
+ \x{b2}
+ 0: \x{b2}
+ \x{b3}
+ 0: \x{b3}
+ ** Failers
+No match
+ X
+No match
+ \x{16ee}
+No match
+
+/^\p{Pc}/8
+ \x5f
+ 0: _
+ \x{203f}
+ 0: \x{203f}
+ ** Failers
+No match
+ X
+No match
+ -
+No match
+ \x{58a}
+No match
+
+/^\p{Pd}/8
+ -
+ 0: -
+ \x{58a}
+ 0: \x{58a}
+ ** Failers
+No match
+ X
+No match
+ \x{203f}
+No match
+
+/^\p{Pe}/8
+ )
+ 0: )
+ ]
+ 0: ]
+ }
+ 0: }
+ \x{f3b}
+ 0: \x{f3b}
+ ** Failers
+No match
+ X
+No match
+ \x{203f}
+No match
+ (
+No match
+ [
+No match
+ {
+No match
+ \x{f3c}
+No match
+
+/^\p{Pf}/8
+ \x{bb}
+ 0: \x{bb}
+ \x{2019}
+ 0: \x{2019}
+ ** Failers
+No match
+ X
+No match
+ \x{203f}
+No match
+
+/^\p{Pi}/8
+ \x{ab}
+ 0: \x{ab}
+ \x{2018}
+ 0: \x{2018}
+ ** Failers
+No match
+ X
+No match
+ \x{203f}
+No match
+
+/^\p{Po}/8
+ !
+ 0: !
+ \x{37e}
+ 0: \x{37e}
+ ** Failers
+ 0: *
+ X
+No match
+ \x{203f}
+No match
+
+/^\p{Ps}/8
+ (
+ 0: (
+ [
+ 0: [
+ {
+ 0: {
+ \x{f3c}
+ 0: \x{f3c}
+ ** Failers
+No match
+ X
+No match
+ )
+No match
+ ]
+No match
+ }
+No match
+ \x{f3b}
+No match
+
+/^\p{Sc}+/8
+ $\x{a2}\x{a3}\x{a4}\x{a5}\x{a6}
+ 0: $\x{a2}\x{a3}\x{a4}\x{a5}
+ 1: $\x{a2}\x{a3}\x{a4}
+ 2: $\x{a2}\x{a3}
+ 3: $\x{a2}
+ 4: $
+ \x{9f2}
+ 0: \x{9f2}
+ ** Failers
+No match
+ X
+No match
+ \x{2c2}
+No match
+
+/^\p{Sk}/8
+ \x{2c2}
+ 0: \x{2c2}
+ ** Failers
+No match
+ X
+No match
+ \x{9f2}
+No match
+
+/^\p{Sm}+/8
+ +<|~\x{ac}\x{2044}
+ 0: +<|~\x{ac}\x{2044}
+ 1: +<|~\x{ac}
+ 2: +<|~
+ 3: +<|
+ 4: +<
+ 5: +
+ ** Failers
+No match
+ X
+No match
+ \x{9f2}
+No match
+
+/^\p{So}/8
+ \x{a6}
+ 0: \x{a6}
+ \x{482}
+ 0: \x{482}
+ ** Failers
+No match
+ X
+No match
+ \x{9f2}
+No match
+
+/^\p{Zl}/8
+ \x{2028}
+ 0: \x{2028}
+ ** Failers
+No match
+ X
+No match
+ \x{2029}
+No match
+
+/^\p{Zp}/8
+ \x{2029}
+ 0: \x{2029}
+ ** Failers
+No match
+ X
+No match
+ \x{2028}
+No match
+
+/^\p{Zs}/8
+ \ \
+ 0:
+ \x{a0}
+ 0: \x{a0}
+ \x{1680}
+ 0: \x{1680}
+ \x{180e}
+ 0: \x{180e}
+ \x{2000}
+ 0: \x{2000}
+ \x{2001}
+ 0: \x{2001}
+ ** Failers
+No match
+ \x{2028}
+No match
+ \x{200d}
+No match
+
+/\p{Nd}+(..)/8
+ \x{660}\x{661}\x{662}ABC
+ 0: \x{660}\x{661}\x{662}AB
+ 1: \x{660}\x{661}\x{662}A
+ 2: \x{660}\x{661}\x{662}
+
+/\p{Nd}+?(..)/8
+ \x{660}\x{661}\x{662}ABC
+ 0: \x{660}\x{661}\x{662}AB
+ 1: \x{660}\x{661}\x{662}A
+ 2: \x{660}\x{661}\x{662}
+
+/\p{Nd}{2,}(..)/8
+ \x{660}\x{661}\x{662}ABC
+ 0: \x{660}\x{661}\x{662}AB
+ 1: \x{660}\x{661}\x{662}A
+
+/\p{Nd}{2,}?(..)/8
+ \x{660}\x{661}\x{662}ABC
+ 0: \x{660}\x{661}\x{662}AB
+ 1: \x{660}\x{661}\x{662}A
+
+/\p{Nd}*(..)/8
+ \x{660}\x{661}\x{662}ABC
+ 0: \x{660}\x{661}\x{662}AB
+ 1: \x{660}\x{661}\x{662}A
+ 2: \x{660}\x{661}\x{662}
+ 3: \x{660}\x{661}
+
+/\p{Nd}*?(..)/8
+ \x{660}\x{661}\x{662}ABC
+ 0: \x{660}\x{661}\x{662}AB
+ 1: \x{660}\x{661}\x{662}A
+ 2: \x{660}\x{661}\x{662}
+ 3: \x{660}\x{661}
+
+/\p{Nd}{2}(..)/8
+ \x{660}\x{661}\x{662}ABC
+ 0: \x{660}\x{661}\x{662}A
+
+/\p{Nd}{2,3}(..)/8
+ \x{660}\x{661}\x{662}ABC
+ 0: \x{660}\x{661}\x{662}AB
+ 1: \x{660}\x{661}\x{662}A
+
+/\p{Nd}{2,3}?(..)/8
+ \x{660}\x{661}\x{662}ABC
+ 0: \x{660}\x{661}\x{662}AB
+ 1: \x{660}\x{661}\x{662}A
+
+/\p{Nd}?(..)/8
+ \x{660}\x{661}\x{662}ABC
+ 0: \x{660}\x{661}\x{662}
+ 1: \x{660}\x{661}
+
+/\p{Nd}??(..)/8
+ \x{660}\x{661}\x{662}ABC
+ 0: \x{660}\x{661}\x{662}
+ 1: \x{660}\x{661}
+
+/\p{Nd}*+(..)/8
+ \x{660}\x{661}\x{662}ABC
+ 0: \x{660}\x{661}\x{662}AB
+
+/\p{Nd}*+(...)/8
+ \x{660}\x{661}\x{662}ABC
+ 0: \x{660}\x{661}\x{662}ABC
+
+/\p{Nd}*+(....)/8
+ ** Failers
+ 0: ** F
+ \x{660}\x{661}\x{662}ABC
+No match
+
+/\p{Lu}/8i
+ A
+ 0: A
+ a\x{10a0}B
+ 0: \x{10a0}
+ ** Failers
+ 0: F
+ a
+No match
+ \x{1d00}
+No match
+
+/\p{^Lu}/8i
+ 1234
+ 0: 1
+ ** Failers
+ 0: *
+ ABC
+No match
+
+/\P{Lu}/8i
+ 1234
+ 0: 1
+ ** Failers
+ 0: *
+ ABC
+No match
+
+/(?<=A\p{Nd})XYZ/8
+ A2XYZ
+ 0: XYZ
+ 123A5XYZPQR
+ 0: XYZ
+ ABA\x{660}XYZpqr
+ 0: XYZ
+ ** Failers
+No match
+ AXYZ
+No match
+ XYZ
+No match
+
+/(?<!\pL)XYZ/8
+ 1XYZ
+ 0: XYZ
+ AB=XYZ..
+ 0: XYZ
+ XYZ
+ 0: XYZ
+ ** Failers
+No match
+ WXYZ
+No match
+
+/[\p{Nd}]/8
+ 1234
+ 0: 1
+
+/[\p{Nd}+-]+/8
+ 1234
+ 0: 1234
+ 1: 123
+ 2: 12
+ 3: 1
+ 12-34
+ 0: 12-34
+ 1: 12-3
+ 2: 12-
+ 3: 12
+ 4: 1
+ 12+\x{661}-34
+ 0: 12+\x{661}-34
+ 1: 12+\x{661}-3
+ 2: 12+\x{661}-
+ 3: 12+\x{661}
+ 4: 12+
+ 5: 12
+ 6: 1
+ ** Failers
+No match
+ abcd
+No match
+
+/[\P{Nd}]+/8
+ abcd
+ 0: abcd
+ 1: abc
+ 2: ab
+ 3: a
+ ** Failers
+ 0: ** Failers
+ 1: ** Failer
+ 2: ** Faile
+ 3: ** Fail
+ 4: ** Fai
+ 5: ** Fa
+ 6: ** F
+ 7: **
+ 8: **
+ 9: *
+ 1234
+No match
+
+/\D+/8
+ 11111111111111111111111111111111111111111111111111111111111111111111111
+No match
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+Matched, but too many subsidiary matches
+ 0: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 1: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 2: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 3: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 4: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 5: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 6: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 7: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 8: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 9: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+10: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+11: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+12: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+13: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+14: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+15: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+16: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+17: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+18: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+19: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+20: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+21: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+
+/\P{Nd}+/8
+ 11111111111111111111111111111111111111111111111111111111111111111111111
+No match
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+Matched, but too many subsidiary matches
+ 0: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 1: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 2: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 3: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 4: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 5: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 6: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 7: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 8: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 9: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+10: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+11: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+12: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+13: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+14: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+15: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+16: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+17: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+18: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+19: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+20: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+21: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+
+/[\D]+/8
+ 11111111111111111111111111111111111111111111111111111111111111111111111
+No match
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+Matched, but too many subsidiary matches
+ 0: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 1: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 2: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 3: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 4: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 5: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 6: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 7: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 8: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 9: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+10: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+11: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+12: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+13: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+14: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+15: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+16: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+17: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+18: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+19: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+20: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+21: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+
+/[\P{Nd}]+/8
+ 11111111111111111111111111111111111111111111111111111111111111111111111
+No match
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+Matched, but too many subsidiary matches
+ 0: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 1: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 2: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 3: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 4: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 5: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 6: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 7: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 8: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 9: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+10: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+11: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+12: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+13: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+14: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+15: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+16: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+17: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+18: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+19: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+20: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+21: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+
+/[\D\P{Nd}]+/8
+ 11111111111111111111111111111111111111111111111111111111111111111111111
+No match
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+Matched, but too many subsidiary matches
+ 0: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 1: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 2: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 3: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 4: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 5: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 6: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 7: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 8: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 9: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+10: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+11: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+12: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+13: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+14: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+15: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+16: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+17: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+18: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+19: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+20: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+21: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+
+/\pL/8
+ a
+ 0: a
+ A
+ 0: A
+
+/\pL/8i
+ a
+ 0: a
+ A
+ 0: A
+
+/\p{Lu}/8
+ A
+ 0: A
+ aZ
+ 0: Z
+ ** Failers
+ 0: F
+ abc
+No match
+
+/\p{Lu}/8i
+ A
+ 0: A
+ aZ
+ 0: Z
+ ** Failers
+ 0: F
+ abc
+No match
+
+/\p{Ll}/8
+ a
+ 0: a
+ Az
+ 0: z
+ ** Failers
+ 0: a
+ ABC
+No match
+
+/\p{Ll}/8i
+ a
+ 0: a
+ Az
+ 0: z
+ ** Failers
+ 0: a
+ ABC
+No match
+
+/^\x{c0}$/8i
+ \x{c0}
+ 0: \x{c0}
+ \x{e0}
+ 0: \x{e0}
+
+/^\x{e0}$/8i
+ \x{c0}
+ 0: \x{c0}
+ \x{e0}
+ 0: \x{e0}
+
+/A\x{391}\x{10427}\x{ff3a}\x{1fb0}/8
+ A\x{391}\x{10427}\x{ff3a}\x{1fb0}
+ 0: A\x{391}\x{10427}\x{ff3a}\x{1fb0}
+ ** Failers
+No match
+ a\x{391}\x{10427}\x{ff3a}\x{1fb0}
+No match
+ A\x{3b1}\x{10427}\x{ff3a}\x{1fb0}
+No match
+ A\x{391}\x{1044F}\x{ff3a}\x{1fb0}
+No match
+ A\x{391}\x{10427}\x{ff5a}\x{1fb0}
+No match
+ A\x{391}\x{10427}\x{ff3a}\x{1fb8}
+No match
+
+/A\x{391}\x{10427}\x{ff3a}\x{1fb0}/8i
+ A\x{391}\x{10427}\x{ff3a}\x{1fb0}
+ 0: A\x{391}\x{10427}\x{ff3a}\x{1fb0}
+ a\x{391}\x{10427}\x{ff3a}\x{1fb0}
+ 0: a\x{391}\x{10427}\x{ff3a}\x{1fb0}
+ A\x{3b1}\x{10427}\x{ff3a}\x{1fb0}
+ 0: A\x{3b1}\x{10427}\x{ff3a}\x{1fb0}
+ A\x{391}\x{1044F}\x{ff3a}\x{1fb0}
+ 0: A\x{391}\x{1044f}\x{ff3a}\x{1fb0}
+ A\x{391}\x{10427}\x{ff5a}\x{1fb0}
+ 0: A\x{391}\x{10427}\x{ff5a}\x{1fb0}
+ A\x{391}\x{10427}\x{ff3a}\x{1fb8}
+ 0: A\x{391}\x{10427}\x{ff3a}\x{1fb8}
+
+/\x{391}+/8i
+ \x{391}\x{3b1}\x{3b1}\x{3b1}\x{391}
+ 0: \x{391}\x{3b1}\x{3b1}\x{3b1}\x{391}
+ 1: \x{391}\x{3b1}\x{3b1}\x{3b1}
+ 2: \x{391}\x{3b1}\x{3b1}
+ 3: \x{391}\x{3b1}
+ 4: \x{391}
+
+/\x{391}{3,5}(.)/8i
+ \x{391}\x{3b1}\x{3b1}\x{3b1}\x{391}X
+ 0: \x{391}\x{3b1}\x{3b1}\x{3b1}\x{391}X
+ 1: \x{391}\x{3b1}\x{3b1}\x{3b1}\x{391}
+ 2: \x{391}\x{3b1}\x{3b1}\x{3b1}
+
+/\x{391}{3,5}?(.)/8i
+ \x{391}\x{3b1}\x{3b1}\x{3b1}\x{391}X
+ 0: \x{391}\x{3b1}\x{3b1}\x{3b1}\x{391}X
+ 1: \x{391}\x{3b1}\x{3b1}\x{3b1}\x{391}
+ 2: \x{391}\x{3b1}\x{3b1}\x{3b1}
+
+/[\x{391}\x{ff3a}]/8i
+ \x{391}
+ 0: \x{391}
+ \x{ff3a}
+ 0: \x{ff3a}
+ \x{3b1}
+ 0: \x{3b1}
+ \x{ff5a}
+ 0: \x{ff5a}
+
+/[\x{c0}\x{391}]/8i
+ \x{c0}
+ 0: \x{c0}
+ \x{e0}
+ 0: \x{e0}
+
+/[\x{105}-\x{109}]/8i
+ \x{104}
+ 0: \x{104}
+ \x{105}
+ 0: \x{105}
+ \x{109}
+ 0: \x{109}
+ ** Failers
+No match
+ \x{100}
+No match
+ \x{10a}
+No match
+
+/[z-\x{100}]/8i
+ Z
+ 0: Z
+ z
+ 0: z
+ \x{39c}
+ 0: \x{39c}
+ \x{178}
+ 0: \x{178}
+ |
+ 0: |
+ \x{80}
+ 0: \x{80}
+ \x{ff}
+ 0: \x{ff}
+ \x{100}
+ 0: \x{100}
+ \x{101}
+ 0: \x{101}
+ ** Failers
+No match
+ \x{102}
+No match
+ Y
+No match
+ y
+No match
+
+/[z-\x{100}]/8i
+
+/^\X/8
+ A
+ 0: A
+ A\x{300}BC
+ 0: A\x{300}
+ A\x{300}\x{301}\x{302}BC
+ 0: A\x{300}\x{301}\x{302}
+ *** Failers
+ 0: *
+ \x{300}
+No match
+
+/^[\X]/8
+ X123
+ 0: X
+ *** Failers
+No match
+ AXYZ
+No match
+
+/^(\X*)C/8
+ A\x{300}\x{301}\x{302}BCA\x{300}\x{301}
+ 0: A\x{300}\x{301}\x{302}BC
+ A\x{300}\x{301}\x{302}BCA\x{300}\x{301}C
+ 0: A\x{300}\x{301}\x{302}BCA\x{300}\x{301}C
+ 1: A\x{300}\x{301}\x{302}BC
+
+/^(\X*?)C/8
+ A\x{300}\x{301}\x{302}BCA\x{300}\x{301}
+ 0: A\x{300}\x{301}\x{302}BC
+ A\x{300}\x{301}\x{302}BCA\x{300}\x{301}C
+ 0: A\x{300}\x{301}\x{302}BCA\x{300}\x{301}C
+ 1: A\x{300}\x{301}\x{302}BC
+
+/^(\X*)(.)/8
+ A\x{300}\x{301}\x{302}BCA\x{300}\x{301}
+ 0: A\x{300}\x{301}\x{302}BCA
+ 1: A\x{300}\x{301}\x{302}BC
+ 2: A\x{300}\x{301}\x{302}B
+ 3: A
+ A\x{300}\x{301}\x{302}BCA\x{300}\x{301}C
+ 0: A\x{300}\x{301}\x{302}BCA\x{300}\x{301}C
+ 1: A\x{300}\x{301}\x{302}BCA
+ 2: A\x{300}\x{301}\x{302}BC
+ 3: A\x{300}\x{301}\x{302}B
+ 4: A
+
+/^(\X*?)(.)/8
+ A\x{300}\x{301}\x{302}BCA\x{300}\x{301}
+ 0: A\x{300}\x{301}\x{302}BCA
+ 1: A\x{300}\x{301}\x{302}BC
+ 2: A\x{300}\x{301}\x{302}B
+ 3: A
+ A\x{300}\x{301}\x{302}BCA\x{300}\x{301}C
+ 0: A\x{300}\x{301}\x{302}BCA\x{300}\x{301}C
+ 1: A\x{300}\x{301}\x{302}BCA
+ 2: A\x{300}\x{301}\x{302}BC
+ 3: A\x{300}\x{301}\x{302}B
+ 4: A
+
+/^\X(.)/8
+ *** Failers
+ 0: **
+ A\x{300}\x{301}\x{302}
+No match
+
+/^\X{2,3}(.)/8
+ A\x{300}\x{301}B\x{300}X
+ 0: A\x{300}\x{301}B\x{300}X
+ A\x{300}\x{301}B\x{300}C\x{300}\x{301}
+ 0: A\x{300}\x{301}B\x{300}C
+ A\x{300}\x{301}B\x{300}C\x{300}\x{301}X
+ 0: A\x{300}\x{301}B\x{300}C\x{300}\x{301}X
+ 1: A\x{300}\x{301}B\x{300}C
+ A\x{300}\x{301}B\x{300}C\x{300}\x{301}DA\x{300}X
+ 0: A\x{300}\x{301}B\x{300}C\x{300}\x{301}D
+ 1: A\x{300}\x{301}B\x{300}C
+
+/^\X{2,3}?(.)/8
+ A\x{300}\x{301}B\x{300}X
+ 0: A\x{300}\x{301}B\x{300}X
+ A\x{300}\x{301}B\x{300}C\x{300}\x{301}
+ 0: A\x{300}\x{301}B\x{300}C
+ A\x{300}\x{301}B\x{300}C\x{300}\x{301}X
+ 0: A\x{300}\x{301}B\x{300}C\x{300}\x{301}X
+ 1: A\x{300}\x{301}B\x{300}C
+ A\x{300}\x{301}B\x{300}C\x{300}\x{301}DA\x{300}X
+ 0: A\x{300}\x{301}B\x{300}C\x{300}\x{301}D
+ 1: A\x{300}\x{301}B\x{300}C
+
+/^\pN{2,3}X/
+ 12X
+ 0: 12X
+ 123X
+ 0: 123X
+ *** Failers
+No match
+ X
+No match
+ 1X
+No match
+ 1234X
+No match
+
+/\x{100}/i8
+ \x{100}
+ 0: \x{100}
+ \x{101}
+ 0: \x{101}
+
+/^\p{Han}+/8
+ \x{2e81}\x{3007}\x{2f804}\x{31a0}
+ 0: \x{2e81}\x{3007}\x{2f804}
+ 1: \x{2e81}\x{3007}
+ 2: \x{2e81}
+ ** Failers
+No match
+ \x{2e7f}
+No match
+
+/^\P{Katakana}+/8
+ \x{3105}
+ 0: \x{3105}
+ ** Failers
+ 0: ** Failers
+ 1: ** Failer
+ 2: ** Faile
+ 3: ** Fail
+ 4: ** Fai
+ 5: ** Fa
+ 6: ** F
+ 7: **
+ 8: **
+ 9: *
+ \x{30ff}
+No match
+
+/^[\p{Arabic}]/8
+ \x{06e9}
+ 0: \x{6e9}
+ \x{060b}
+ 0: \x{60b}
+ ** Failers
+No match
+ X\x{06e9}
+No match
+
+/^[\P{Yi}]/8
+ \x{2f800}
+ 0: \x{2f800}
+ ** Failers
+ 0: *
+ \x{a014}
+No match
+ \x{a4c6}
+No match
+
+/^\p{Any}X/8
+ AXYZ
+ 0: AX
+ \x{1234}XYZ
+ 0: \x{1234}X
+ ** Failers
+No match
+ X
+No match
+
+/^\P{Any}X/8
+ ** Failers
+No match
+ AX
+No match
+
+/^\p{Any}?X/8
+ XYZ
+ 0: X
+ AXYZ
+ 0: AX
+ \x{1234}XYZ
+ 0: \x{1234}X
+ ** Failers
+No match
+ ABXYZ
+No match
+
+/^\P{Any}?X/8
+ XYZ
+ 0: X
+ ** Failers
+No match
+ AXYZ
+No match
+ \x{1234}XYZ
+No match
+ ABXYZ
+No match
+
+/^\p{Any}+X/8
+ AXYZ
+ 0: AX
+ \x{1234}XYZ
+ 0: \x{1234}X
+ A\x{1234}XYZ
+ 0: A\x{1234}X
+ ** Failers
+No match
+ XYZ
+No match
+
+/^\P{Any}+X/8
+ ** Failers
+No match
+ AXYZ
+No match
+ \x{1234}XYZ
+No match
+ A\x{1234}XYZ
+No match
+ XYZ
+No match
+
+/^\p{Any}*X/8
+ XYZ
+ 0: X
+ AXYZ
+ 0: AX
+ \x{1234}XYZ
+ 0: \x{1234}X
+ A\x{1234}XYZ
+ 0: A\x{1234}X
+ ** Failers
+No match
+
+/^\P{Any}*X/8
+ XYZ
+ 0: X
+ ** Failers
+No match
+ AXYZ
+No match
+ \x{1234}XYZ
+No match
+ A\x{1234}XYZ
+No match
+
+/^[\p{Any}]X/8
+ AXYZ
+ 0: AX
+ \x{1234}XYZ
+ 0: \x{1234}X
+ ** Failers
+No match
+ X
+No match
+
+/^[\P{Any}]X/8
+ ** Failers
+No match
+ AX
+No match
+
+/^[\p{Any}]?X/8
+ XYZ
+ 0: X
+ AXYZ
+ 0: AX
+ \x{1234}XYZ
+ 0: \x{1234}X
+ ** Failers
+No match
+ ABXYZ
+No match
+
+/^[\P{Any}]?X/8
+ XYZ
+ 0: X
+ ** Failers
+No match
+ AXYZ
+No match
+ \x{1234}XYZ
+No match
+ ABXYZ
+No match
+
+/^[\p{Any}]+X/8
+ AXYZ
+ 0: AX
+ \x{1234}XYZ
+ 0: \x{1234}X
+ A\x{1234}XYZ
+ 0: A\x{1234}X
+ ** Failers
+No match
+ XYZ
+No match
+
+/^[\P{Any}]+X/8
+ ** Failers
+No match
+ AXYZ
+No match
+ \x{1234}XYZ
+No match
+ A\x{1234}XYZ
+No match
+ XYZ
+No match
+
+/^[\p{Any}]*X/8
+ XYZ
+ 0: X
+ AXYZ
+ 0: AX
+ \x{1234}XYZ
+ 0: \x{1234}X
+ A\x{1234}XYZ
+ 0: A\x{1234}X
+ ** Failers
+No match
+
+/^[\P{Any}]*X/8
+ XYZ
+ 0: X
+ ** Failers
+No match
+ AXYZ
+No match
+ \x{1234}XYZ
+No match
+ A\x{1234}XYZ
+No match
+
+/^\p{Any}{3,5}?/8
+ abcdefgh
+ 0: abcde
+ 1: abcd
+ 2: abc
+ \x{1234}\n\r\x{3456}xyz
+ 0: \x{1234}\x{0a}\x{0d}\x{3456}x
+ 1: \x{1234}\x{0a}\x{0d}\x{3456}
+ 2: \x{1234}\x{0a}\x{0d}
+
+/^\p{Any}{3,5}/8
+ abcdefgh
+ 0: abcde
+ 1: abcd
+ 2: abc
+ \x{1234}\n\r\x{3456}xyz
+ 0: \x{1234}\x{0a}\x{0d}\x{3456}x
+ 1: \x{1234}\x{0a}\x{0d}\x{3456}
+ 2: \x{1234}\x{0a}\x{0d}
+
+/^\P{Any}{3,5}?/8
+ ** Failers
+No match
+ abcdefgh
+No match
+ \x{1234}\n\r\x{3456}xyz
+No match
+
+/^\p{L&}X/8
+ AXY
+ 0: AX
+ aXY
+ 0: aX
+ \x{1c5}XY
+ 0: \x{1c5}X
+ ** Failers
+No match
+ \x{1bb}XY
+No match
+ \x{2b0}XY
+No match
+ !XY
+No match
+
+/^[\p{L&}]X/8
+ AXY
+ 0: AX
+ aXY
+ 0: aX
+ \x{1c5}XY
+ 0: \x{1c5}X
+ ** Failers
+No match
+ \x{1bb}XY
+No match
+ \x{2b0}XY
+No match
+ !XY
+No match
+
+/^\p{L&}+X/8
+ AXY
+ 0: AX
+ aXY
+ 0: aX
+ AbcdeXyz
+ 0: AbcdeX
+ \x{1c5}AbXY
+ 0: \x{1c5}AbX
+ abcDEXypqreXlmn
+ 0: abcDEXypqreX
+ 1: abcDEX
+ ** Failers
+No match
+ \x{1bb}XY
+No match
+ \x{2b0}XY
+No match
+ !XY
+No match
+
+/^[\p{L&}]+X/8
+ AXY
+ 0: AX
+ aXY
+ 0: aX
+ AbcdeXyz
+ 0: AbcdeX
+ \x{1c5}AbXY
+ 0: \x{1c5}AbX
+ abcDEXypqreXlmn
+ 0: abcDEXypqreX
+ 1: abcDEX
+ ** Failers
+No match
+ \x{1bb}XY
+No match
+ \x{2b0}XY
+No match
+ !XY
+No match
+
+/^\p{L&}+?X/8
+ AXY
+ 0: AX
+ aXY
+ 0: aX
+ AbcdeXyz
+ 0: AbcdeX
+ \x{1c5}AbXY
+ 0: \x{1c5}AbX
+ abcDEXypqreXlmn
+ 0: abcDEXypqreX
+ 1: abcDEX
+ ** Failers
+No match
+ \x{1bb}XY
+No match
+ \x{2b0}XY
+No match
+ !XY
+No match
+
+/^[\p{L&}]+?X/8
+ AXY
+ 0: AX
+ aXY
+ 0: aX
+ AbcdeXyz
+ 0: AbcdeX
+ \x{1c5}AbXY
+ 0: \x{1c5}AbX
+ abcDEXypqreXlmn
+ 0: abcDEXypqreX
+ 1: abcDEX
+ ** Failers
+No match
+ \x{1bb}XY
+No match
+ \x{2b0}XY
+No match
+ !XY
+No match
+
+/^\P{L&}X/8
+ !XY
+ 0: !X
+ \x{1bb}XY
+ 0: \x{1bb}X
+ \x{2b0}XY
+ 0: \x{2b0}X
+ ** Failers
+No match
+ \x{1c5}XY
+No match
+ AXY
+No match
+
+/^[\P{L&}]X/8
+ !XY
+ 0: !X
+ \x{1bb}XY
+ 0: \x{1bb}X
+ \x{2b0}XY
+ 0: \x{2b0}X
+ ** Failers
+No match
+ \x{1c5}XY
+No match
+ AXY
+No match
+
+/^\x{023a}+?(\x{0130}+)/8i
+ \x{023a}\x{2c65}\x{0130}
+ 0: \x{23a}\x{2c65}\x{130}
+
+/^\x{023a}+([^X])/8i
+ \x{023a}\x{2c65}X
+ 0: \x{23a}\x{2c65}
+
+/Check property support in non-UTF-8 mode/
+
+/\p{L}{4}/
+ 123abcdefg
+ 0: abcd
+ 123abc\xc4\xc5zz
+ 0: abc\xc4
+
+/ End /
diff --git a/lib/stdlib/test/re_testoutput1_replacement_test.erl b/lib/stdlib/test/re_testoutput1_replacement_test.erl
new file mode 100644
index 0000000000..b20db3f9c3
--- /dev/null
+++ b/lib/stdlib/test/re_testoutput1_replacement_test.erl
@@ -0,0 +1,18596 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(re_testoutput1_replacement_test).
+-compile(export_all).
+-include("test_server.hrl").
+%% This file is generated by running run_pcre_tests:gen_repl_test("re_SUITE_data/testoutput1")
+run() ->
+?line <<"WkCthe quick brown foxtthe quick brown foxjthe quick brown foxPpfmthe quick brown foxthe quick brown foxy">> = iolist_to_binary(re:replace("the quick brown fox","the quick brown fox","WkC&t\\1\\1&j&Ppfm&&y",[])),
+?line <<"WkCthe quick brown foxtthe quick brown foxjthe quick brown foxPpfmthe quick brown foxthe quick brown foxy">> = iolist_to_binary(re:replace("the quick brown fox","the quick brown fox","WkC&t\\1\\1&j&Ppfm&&y",[global])),
+?line <<"The quick brown FOX">> = iolist_to_binary(re:replace("The quick brown FOX","the quick brown fox","in&&CSwx",[])),
+?line <<"The quick brown FOX">> = iolist_to_binary(re:replace("The quick brown FOX","the quick brown fox","in&&CSwx",[global])),
+?line <<"What do you know about ORtMvuTRHtLthe quick brown foxiYthe quick brown foxGi?">> = iolist_to_binary(re:replace("What do you know about the quick brown fox?","the quick brown fox","ORtMvuTRHtL&iY&Gi",[])),
+?line <<"What do you know about ORtMvuTRHtLthe quick brown foxiYthe quick brown foxGi?">> = iolist_to_binary(re:replace("What do you know about the quick brown fox?","the quick brown fox","ORtMvuTRHtL&iY&Gi",[global])),
+?line <<"What do you know about THE QUICK BROWN FOX?">> = iolist_to_binary(re:replace("What do you know about THE QUICK BROWN FOX?","the quick brown fox","\\1nfTnvooMaxHdXgGO",[])),
+?line <<"What do you know about THE QUICK BROWN FOX?">> = iolist_to_binary(re:replace("What do you know about THE QUICK BROWN FOX?","the quick brown fox","\\1nfTnvooMaxHdXgGO",[global])),
+?line <<"hSniFQTqBU">> = iolist_to_binary(re:replace("the quick brown fox","The quick brown fox","hSniFQTqBU",[caseless])),
+?line <<"hSniFQTqBU">> = iolist_to_binary(re:replace("the quick brown fox","The quick brown fox","hSniFQTqBU",[caseless,
+ global])),
+?line <<"q">> = iolist_to_binary(re:replace("The quick brown FOX","The quick brown fox","q",[caseless])),
+?line <<"q">> = iolist_to_binary(re:replace("The quick brown FOX","The quick brown fox","q",[caseless,
+ global])),
+?line <<"What do you know about uJnke?">> = iolist_to_binary(re:replace("What do you know about the quick brown fox?","The quick brown fox","uJ\\1nke",[caseless])),
+?line <<"What do you know about uJnke?">> = iolist_to_binary(re:replace("What do you know about the quick brown fox?","The quick brown fox","uJ\\1nke",[caseless,
+ global])),
+?line <<"What do you know about VRUTHE QUICK BROWN FOXYgJqUVfiTHE QUICK BROWN FOXqb?">> = iolist_to_binary(re:replace("What do you know about THE QUICK BROWN FOX?","The quick brown fox","VRU&YgJqUVfi&\\1qb",[caseless])),
+?line <<"What do you know about VRUTHE QUICK BROWN FOXYgJqUVfiTHE QUICK BROWN FOXqb?">> = iolist_to_binary(re:replace("What do you know about THE QUICK BROWN FOX?","The quick brown fox","VRU&YgJqUVfi&\\1qb",[caseless,
+ global])),
+?line <<"jeUmEaUYOfHpPURCabcd
+ 9;$\\?caxyz">> = iolist_to_binary(re:replace("abcd
+ 9;$\\?caxyz","abcd\\t\\n\\r\\f\\a\\e\\071\\x3b\\$\\\\\\?caxyz","jeUmEaUYOfHpPURC&",[])),
+?line <<"jeUmEaUYOfHpPURCabcd
+ 9;$\\?caxyz">> = iolist_to_binary(re:replace("abcd
+ 9;$\\?caxyz","abcd\\t\\n\\r\\f\\a\\e\\071\\x3b\\$\\\\\\?caxyz","jeUmEaUYOfHpPURC&",[global])),
+?line <<"YVh">> = iolist_to_binary(re:replace("abxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","YVh",[])),
+?line <<"YVh">> = iolist_to_binary(re:replace("abxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","YVh",[global])),
+?line <<"wDCxbqXSqpabxyzpqrrrabbxyyyypqAzzX">> = iolist_to_binary(re:replace("abxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","wDCxbqXSqp&X",[])),
+?line <<"wDCxbqXSqpabxyzpqrrrabbxyyyypqAzzX">> = iolist_to_binary(re:replace("abxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","wDCxbqXSqp&X",[global])),
+?line <<"XOnDbhuPYPfGm">> = iolist_to_binary(re:replace("aabxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","\\1XOnDbhuP\\1Y\\1PfGm",[])),
+?line <<"XOnDbhuPYPfGm">> = iolist_to_binary(re:replace("aabxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","\\1XOnDbhuP\\1Y\\1PfGm",[global])),
+?line <<"vgswmIcA">> = iolist_to_binary(re:replace("aaabxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","vgswmI\\1cA",[])),
+?line <<"vgswmIcA">> = iolist_to_binary(re:replace("aaabxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","vgswmI\\1cA",[global])),
+?line <<"YaaaabxyzpqrrrabbxyyyypqAzzOXXRaa">> = iolist_to_binary(re:replace("aaaabxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","Y&OXXRaa",[])),
+?line <<"YaaaabxyzpqrrrabbxyyyypqAzzOXXRaa">> = iolist_to_binary(re:replace("aaaabxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","Y&OXXRaa",[global])),
+?line <<"CAeqsXe">> = iolist_to_binary(re:replace("abcxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","\\1CAeq\\1s\\1Xe",[])),
+?line <<"CAeqsXe">> = iolist_to_binary(re:replace("abcxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","\\1CAeq\\1s\\1Xe",[global])),
+?line <<"cDLaApdgW">> = iolist_to_binary(re:replace("aabcxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","cDLaApdgW",[])),
+?line <<"cDLaApdgW">> = iolist_to_binary(re:replace("aabcxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","cDLaApdgW",[global])),
+?line <<"aLfXiUYS">> = iolist_to_binary(re:replace("aaabcxyzpqrrrabbxyyyypAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","aLf\\1XiUYS",[])),
+?line <<"aLfXiUYS">> = iolist_to_binary(re:replace("aaabcxyzpqrrrabbxyyyypAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","aLf\\1XiUYS",[global])),
+?line <<"aaabcxyzpqrrrabbxyyyypqAzzBcaaabcxyzpqrrrabbxyyyypqAzzDAyoYqGn">> = iolist_to_binary(re:replace("aaabcxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","\\1&Bc&DAyoYqGn",[])),
+?line <<"aaabcxyzpqrrrabbxyyyypqAzzBcaaabcxyzpqrrrabbxyyyypqAzzDAyoYqGn">> = iolist_to_binary(re:replace("aaabcxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","\\1&Bc&DAyoYqGn",[global])),
+?line <<"aaabcxyzpqrrrabbxyyyypqqAzzijaaabcxyzpqrrrabbxyyyypqqAzzdIBcB">> = iolist_to_binary(re:replace("aaabcxyzpqrrrabbxyyyypqqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","&ij&dI\\1BcB",[])),
+?line <<"aaabcxyzpqrrrabbxyyyypqqAzzijaaabcxyzpqrrrabbxyyyypqqAzzdIBcB">> = iolist_to_binary(re:replace("aaabcxyzpqrrrabbxyyyypqqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","&ij&dI\\1BcB",[global])),
+?line <<"qrxTuPSgEjNvkaaabcxyzpqrrrabbxyyyypqqqAzz">> = iolist_to_binary(re:replace("aaabcxyzpqrrrabbxyyyypqqqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","\\1qrx\\1\\1TuPSgEjNvk&",[])),
+?line <<"qrxTuPSgEjNvkaaabcxyzpqrrrabbxyyyypqqqAzz">> = iolist_to_binary(re:replace("aaabcxyzpqrrrabbxyyyypqqqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","\\1qrx\\1\\1TuPSgEjNvk&",[global])),
+?line <<"oWxyrN">> = iolist_to_binary(re:replace("aaabcxyzpqrrrabbxyyyypqqqqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","\\1oWx\\1y\\1rN",[])),
+?line <<"oWxyrN">> = iolist_to_binary(re:replace("aaabcxyzpqrrrabbxyyyypqqqqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","\\1oWx\\1y\\1rN",[global])),
+?line <<"TPbeAcarX">> = iolist_to_binary(re:replace("aaabcxyzpqrrrabbxyyyypqqqqqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","\\1T\\1PbeAcarX",[])),
+?line <<"TPbeAcarX">> = iolist_to_binary(re:replace("aaabcxyzpqrrrabbxyyyypqqqqqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","\\1T\\1PbeAcarX",[global])),
+?line <<"xWhhgaaabcxyzpqrrrabbxyyyypqqqqqqAzzsHcQaaabcxyzpqrrrabbxyyyypqqqqqqAzzAeU">> = iolist_to_binary(re:replace("aaabcxyzpqrrrabbxyyyypqqqqqqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","xWh\\1hg&sHcQ&AeU",[])),
+?line <<"xWhhgaaabcxyzpqrrrabbxyyyypqqqqqqAzzsHcQaaabcxyzpqrrrabbxyyyypqqqqqqAzzAeU">> = iolist_to_binary(re:replace("aaabcxyzpqrrrabbxyyyypqqqqqqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","xWh\\1hg&sHcQ&AeU",[global])),
+?line <<"HasuDgVdEpaaaabcxyzpqrrrabbxyyyypqAzz">> = iolist_to_binary(re:replace("aaaabcxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","Hasu\\1\\1DgV\\1dEp&",[])),
+?line <<"HasuDgVdEpaaaabcxyzpqrrrabbxyyyypqAzz">> = iolist_to_binary(re:replace("aaaabcxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","Hasu\\1\\1DgV\\1dEp&",[global])),
+?line <<"XWMcabxyzzpqrrrabbxyyyypqAzzIUK">> = iolist_to_binary(re:replace("abxyzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","XWMc&\\1IUK",[])),
+?line <<"XWMcabxyzzpqrrrabbxyyyypqAzzIUK">> = iolist_to_binary(re:replace("abxyzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","XWMc&\\1IUK",[global])),
+?line <<"UBljDAPnposGdT">> = iolist_to_binary(re:replace("aabxyzzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","UBljDAPnposGdT",[])),
+?line <<"UBljDAPnposGdT">> = iolist_to_binary(re:replace("aabxyzzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","UBljDAPnposGdT",[global])),
+?line <<"boTxGt">> = iolist_to_binary(re:replace("aaabxyzzzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","boTxGt",[])),
+?line <<"boTxGt">> = iolist_to_binary(re:replace("aaabxyzzzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","boTxGt",[global])),
+?line <<"mnBWBx">> = iolist_to_binary(re:replace("aaaabxyzzzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","mnB\\1\\1WBx",[])),
+?line <<"mnBWBx">> = iolist_to_binary(re:replace("aaaabxyzzzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","mnB\\1\\1WBx",[global])),
+?line <<"lcgIVpnY">> = iolist_to_binary(re:replace("abcxyzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","lcgIVpnY\\1",[])),
+?line <<"lcgIVpnY">> = iolist_to_binary(re:replace("abcxyzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","lcgIVpnY\\1",[global])),
+?line <<"aabcxyzzzpqrrrabbxyyyypqAzznutiQsQaabcxyzzzpqrrrabbxyyyypqAzzokm">> = iolist_to_binary(re:replace("aabcxyzzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","&n\\1\\1utiQsQ&o\\1km",[])),
+?line <<"aabcxyzzzpqrrrabbxyyyypqAzznutiQsQaabcxyzzzpqrrrabbxyyyypqAzzokm">> = iolist_to_binary(re:replace("aabcxyzzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","&n\\1\\1utiQsQ&o\\1km",[global])),
+?line <<"rshbaaabcxyzzzzpqrrrabbxyyyypqAzzyCaaabcxyzzzzpqrrrabbxyyyypqAzzFuphTaaabcxyzzzzpqrrrabbxyyyypqAzzb">> = iolist_to_binary(re:replace("aaabcxyzzzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","rshb&yC&FuphT&b",[])),
+?line <<"rshbaaabcxyzzzzpqrrrabbxyyyypqAzzyCaaabcxyzzzzpqrrrabbxyyyypqAzzFuphTaaabcxyzzzzpqrrrabbxyyyypqAzzb">> = iolist_to_binary(re:replace("aaabcxyzzzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","rshb&yC&FuphT&b",[global])),
+?line <<"aaaabcxyzzzzpqrrrabbxyyyypqAzzDpUaaaabcxyzzzzpqrrrabbxyyyypqAzzWxWLwIQUnS">> = iolist_to_binary(re:replace("aaaabcxyzzzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","&DpU&WxW\\1LwIQUnS",[])),
+?line <<"aaaabcxyzzzzpqrrrabbxyyyypqAzzDpUaaaabcxyzzzzpqrrrabbxyyyypqAzzWxWLwIQUnS">> = iolist_to_binary(re:replace("aaaabcxyzzzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","&DpU&WxW\\1LwIQUnS",[global])),
+?line <<"maaaabcxyzzzzpqrrrabbbxyyyypqAzzaaaabcxyzzzzpqrrrabbbxyyyypqAzzdV">> = iolist_to_binary(re:replace("aaaabcxyzzzzpqrrrabbbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","m\\1&&dV",[])),
+?line <<"maaaabcxyzzzzpqrrrabbbxyyyypqAzzaaaabcxyzzzzpqrrrabbbxyyyypqAzzdV">> = iolist_to_binary(re:replace("aaaabcxyzzzzpqrrrabbbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","m\\1&&dV",[global])),
+?line <<"qABAquMpjbGrEQl">> = iolist_to_binary(re:replace("aaaabcxyzzzzpqrrrabbbxyyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","qAB\\1A\\1quMpjbGrEQl",[])),
+?line <<"qABAquMpjbGrEQl">> = iolist_to_binary(re:replace("aaaabcxyzzzzpqrrrabbbxyyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","qAB\\1A\\1quMpjbGrEQl",[global])),
+?line <<"XEmwtsQHVhnjgxANa">> = iolist_to_binary(re:replace("aaabcxyzpqrrrabbxyyyypABzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","XEmw\\1tsQHVhn\\1jgx\\1ANa",[])),
+?line <<"XEmwtsQHVhnjgxANa">> = iolist_to_binary(re:replace("aaabcxyzpqrrrabbxyyyypABzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","XEmw\\1tsQHVhn\\1jgx\\1ANa",[global])),
+?line <<"agMMGdMqblL">> = iolist_to_binary(re:replace("aaabcxyzpqrrrabbxyyyypABBzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","agMMGdMq\\1blL\\1",[])),
+?line <<"agMMGdMqblL">> = iolist_to_binary(re:replace("aaabcxyzpqrrrabbxyyyypABBzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","agMMGdMq\\1blL\\1",[global])),
+?line <<">>>EFCLJKUGJXH">> = iolist_to_binary(re:replace(">>>aaabxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","EFCLJKUGJXH",[])),
+?line <<">>>EFCLJKUGJXH">> = iolist_to_binary(re:replace(">>>aaabxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","EFCLJKUGJXH",[global])),
+?line <<">IW">> = iolist_to_binary(re:replace(">aaaabxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","\\1IW",[])),
+?line <<">IW">> = iolist_to_binary(re:replace(">aaaabxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","\\1IW",[global])),
+?line <<">>>>uiixDteuEA">> = iolist_to_binary(re:replace(">>>>abcxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","\\1uiixD\\1teuEA",[])),
+?line <<">>>>uiixDteuEA">> = iolist_to_binary(re:replace(">>>>abcxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","\\1uiixD\\1teuEA",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","vayXo\\1eo\\1H",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","vayXo\\1eo\\1H",[global])),
+?line <<"abxyzpqrrabbxyyyypqAzz">> = iolist_to_binary(re:replace("abxyzpqrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","nJK",[])),
+?line <<"abxyzpqrrabbxyyyypqAzz">> = iolist_to_binary(re:replace("abxyzpqrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","nJK",[global])),
+?line <<"abxyzpqrrrrabbxyyyypqAzz">> = iolist_to_binary(re:replace("abxyzpqrrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","msrV\\1",[])),
+?line <<"abxyzpqrrrrabbxyyyypqAzz">> = iolist_to_binary(re:replace("abxyzpqrrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","msrV\\1",[global])),
+?line <<"abxyzpqrrrabxyyyypqAzz">> = iolist_to_binary(re:replace("abxyzpqrrrabxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","nVAVmEdY&rfTu",[])),
+?line <<"abxyzpqrrrabxyyyypqAzz">> = iolist_to_binary(re:replace("abxyzpqrrrabxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","nVAVmEdY&rfTu",[global])),
+?line <<"aaaabcxyzzzzpqrrrabbbxyyyyyypqAzz">> = iolist_to_binary(re:replace("aaaabcxyzzzzpqrrrabbbxyyyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","&G&\\1eyiM",[])),
+?line <<"aaaabcxyzzzzpqrrrabbbxyyyyyypqAzz">> = iolist_to_binary(re:replace("aaaabcxyzzzzpqrrrabbbxyyyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","&G&\\1eyiM",[global])),
+?line <<"aaaabcxyzzzzpqrrrabbbxyyypqAzz">> = iolist_to_binary(re:replace("aaaabcxyzzzzpqrrrabbbxyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","AIYq\\1nFUePr&s\\1s",[])),
+?line <<"aaaabcxyzzzzpqrrrabbbxyyypqAzz">> = iolist_to_binary(re:replace("aaaabcxyzzzzpqrrrabbbxyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","AIYq\\1nFUePr&s\\1s",[global])),
+?line <<"aaabcxyzpqrrrabbxyyyypqqqqqqqAzz">> = iolist_to_binary(re:replace("aaabcxyzpqrrrabbxyyyypqqqqqqqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","G\\1\\1XF\\1XcTk&D&Vd",[])),
+?line <<"aaabcxyzpqrrrabbxyyyypqqqqqqqAzz">> = iolist_to_binary(re:replace("aaabcxyzpqrrrabbxyyyypqqqqqqqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz","G\\1\\1XF\\1XcTk&D&Vd",[global])),
+?line <<"NMabcYpabcatqabczzabczzReBo">> = iolist_to_binary(re:replace("abczz","^(abc){1,2}zz","NM\\1Yp\\1atq&&ReBo",[])),
+?line <<"NMabcYpabcatqabczzabczzReBo">> = iolist_to_binary(re:replace("abczz","^(abc){1,2}zz","NM\\1Yp\\1atq&&ReBo",[global])),
+?line <<"PabcabczzabcsubxWpWrabcCabcabczzBDsb">> = iolist_to_binary(re:replace("abcabczz","^(abc){1,2}zz","P&\\1subxWpWr\\1C&BDsb",[])),
+?line <<"PabcabczzabcsubxWpWrabcCabcabczzBDsb">> = iolist_to_binary(re:replace("abcabczz","^(abc){1,2}zz","P&\\1subxWpWr\\1C&BDsb",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(abc){1,2}zz","u&MSQ\\1MwaXNEFxKb\\1v\\1r",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(abc){1,2}zz","u&MSQ\\1MwaXNEFxKb\\1v\\1r",[global])),
+?line <<"zz">> = iolist_to_binary(re:replace("zz","^(abc){1,2}zz","&XIfLMiKJsG&X",[])),
+?line <<"zz">> = iolist_to_binary(re:replace("zz","^(abc){1,2}zz","&XIfLMiKJsG&X",[global])),
+?line <<"abcabcabczz">> = iolist_to_binary(re:replace("abcabcabczz","^(abc){1,2}zz","k\\1S&UT&HR\\1\\1MHKIh&mv",[])),
+?line <<"abcabcabczz">> = iolist_to_binary(re:replace("abcabcabczz","^(abc){1,2}zz","k\\1S&UT&HR\\1\\1MHKIh&mv",[global])),
+?line <<">>abczz">> = iolist_to_binary(re:replace(">>abczz","^(abc){1,2}zz","R\\1GKCdWtC&\\1ULoV",[])),
+?line <<">>abczz">> = iolist_to_binary(re:replace(">>abczz","^(abc){1,2}zz","R\\1GKCdWtC&\\1ULoV",[global])),
+?line <<"bcbcvRuVbMbcbcOSuQfOJbc">> = iolist_to_binary(re:replace("bc","^(b+?|a){1,2}?c","&bcvRuV\\1M&&OSuQfOJ\\1c",[])),
+?line <<"bcbcvRuVbMbcbcOSuQfOJbc">> = iolist_to_binary(re:replace("bc","^(b+?|a){1,2}?c","&bcvRuV\\1M&&OSuQfOJ\\1c",[global])),
+?line <<"L">> = iolist_to_binary(re:replace("bbc","^(b+?|a){1,2}?c","L",[])),
+?line <<"L">> = iolist_to_binary(re:replace("bbc","^(b+?|a){1,2}?c","L",[global])),
+?line <<"pFFAeA">> = iolist_to_binary(re:replace("bbbc","^(b+?|a){1,2}?c","pFFAeA",[])),
+?line <<"pFFAeA">> = iolist_to_binary(re:replace("bbbc","^(b+?|a){1,2}?c","pFFAeA",[global])),
+?line <<"OpEK">> = iolist_to_binary(re:replace("bac","^(b+?|a){1,2}?c","OpEK",[])),
+?line <<"OpEK">> = iolist_to_binary(re:replace("bac","^(b+?|a){1,2}?c","OpEK",[global])),
+?line <<"bbacQeabbactAVaalybbacdBwbbac">> = iolist_to_binary(re:replace("bbac","^(b+?|a){1,2}?c","&Qe\\1&tAV\\1\\1ly&dBw&",[])),
+?line <<"bbacQeabbactAVaalybbacdBwbbac">> = iolist_to_binary(re:replace("bbac","^(b+?|a){1,2}?c","&Qe\\1&tAV\\1\\1ly&dBw&",[global])),
+?line <<"atVuxqLMNgBtlattKaT">> = iolist_to_binary(re:replace("aac","^(b+?|a){1,2}?c","\\1tVuxqLMNgBtl\\1ttKaT",[])),
+?line <<"atVuxqLMNgBtlattKaT">> = iolist_to_binary(re:replace("aac","^(b+?|a){1,2}?c","\\1tVuxqLMNgBtl\\1ttKaT",[global])),
+?line <<"Y">> = iolist_to_binary(re:replace("abbbbbbbbbbbc","^(b+?|a){1,2}?c","Y",[])),
+?line <<"Y">> = iolist_to_binary(re:replace("abbbbbbbbbbbc","^(b+?|a){1,2}?c","Y",[global])),
+?line <<"bbbbbbbbbbbactDhmKI">> = iolist_to_binary(re:replace("bbbbbbbbbbbac","^(b+?|a){1,2}?c","&tDhmKI",[])),
+?line <<"bbbbbbbbbbbactDhmKI">> = iolist_to_binary(re:replace("bbbbbbbbbbbac","^(b+?|a){1,2}?c","&tDhmKI",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(b+?|a){1,2}?c","qVVVR&C\\1&etAsmWh",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(b+?|a){1,2}?c","qVVVR&C\\1&etAsmWh",[global])),
+?line <<"aaac">> = iolist_to_binary(re:replace("aaac","^(b+?|a){1,2}?c","jD\\1&q&KCdV&RhT",[])),
+?line <<"aaac">> = iolist_to_binary(re:replace("aaac","^(b+?|a){1,2}?c","jD\\1&q&KCdV&RhT",[global])),
+?line <<"abbbbbbbbbbbac">> = iolist_to_binary(re:replace("abbbbbbbbbbbac","^(b+?|a){1,2}?c","\\1jT&nRG",[])),
+?line <<"abbbbbbbbbbbac">> = iolist_to_binary(re:replace("abbbbbbbbbbbac","^(b+?|a){1,2}?c","\\1jT&nRG",[global])),
+?line <<"bcXfvbIubUfhmIRev">> = iolist_to_binary(re:replace("bc","^(b+|a){1,2}c","&Xfv\\1IubUfhmIRev",[])),
+?line <<"bcXfvbIubUfhmIRev">> = iolist_to_binary(re:replace("bc","^(b+|a){1,2}c","&Xfv\\1IubUfhmIRev",[global])),
+?line <<"EbbbbcwbbWbbcVuAOqROLkbbcwbbc">> = iolist_to_binary(re:replace("bbc","^(b+|a){1,2}c","E\\1&w\\1W&VuAOqROLk&w&",[])),
+?line <<"EbbbbcwbbWbbcVuAOqROLkbbcwbbc">> = iolist_to_binary(re:replace("bbc","^(b+|a){1,2}c","E\\1&w\\1W&VuAOqROLk&w&",[global])),
+?line <<"I">> = iolist_to_binary(re:replace("bbbc","^(b+|a){1,2}c","I",[])),
+?line <<"I">> = iolist_to_binary(re:replace("bbbc","^(b+|a){1,2}c","I",[global])),
+?line <<"dctSELQIPb">> = iolist_to_binary(re:replace("bac","^(b+|a){1,2}c","dctSELQIPb",[])),
+?line <<"dctSELQIPb">> = iolist_to_binary(re:replace("bac","^(b+|a){1,2}c","dctSELQIPb",[global])),
+?line <<"kbdarKarpbbacbbacbDO">> = iolist_to_binary(re:replace("bbac","^(b+|a){1,2}c","kbd\\1rK\\1rp&&bDO",[])),
+?line <<"kbdarKarpbbacbbacbDO">> = iolist_to_binary(re:replace("bbac","^(b+|a){1,2}c","kbd\\1rK\\1rp&&bDO",[global])),
+?line <<"aFIlpaasKQWsFRadP">> = iolist_to_binary(re:replace("aac","^(b+|a){1,2}c","\\1FIlp\\1\\1sKQWsFR\\1dP",[])),
+?line <<"aFIlpaasKQWsFRadP">> = iolist_to_binary(re:replace("aac","^(b+|a){1,2}c","\\1FIlp\\1\\1sKQWsFR\\1dP",[global])),
+?line <<"bbbbbbbbbbbfbbbbbbbbbbbHo">> = iolist_to_binary(re:replace("abbbbbbbbbbbc","^(b+|a){1,2}c","\\1f\\1Ho",[])),
+?line <<"bbbbbbbbbbbfbbbbbbbbbbbHo">> = iolist_to_binary(re:replace("abbbbbbbbbbbc","^(b+|a){1,2}c","\\1f\\1Ho",[global])),
+?line <<"bbbbbbbbbbbacOuqvbbbbbbbbbbbaclVwIa">> = iolist_to_binary(re:replace("bbbbbbbbbbbac","^(b+|a){1,2}c","&Ouqv&lVwI\\1",[])),
+?line <<"bbbbbbbbbbbacOuqvbbbbbbbbbbbaclVwIa">> = iolist_to_binary(re:replace("bbbbbbbbbbbac","^(b+|a){1,2}c","&Ouqv&lVwI\\1",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(b+|a){1,2}c","\\1sSSP\\1Tw&R&byI\\1TN",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(b+|a){1,2}c","\\1sSSP\\1Tw&R&byI\\1TN",[global])),
+?line <<"aaac">> = iolist_to_binary(re:replace("aaac","^(b+|a){1,2}c","lBeqV\\1ygD\\1oXXqs",[])),
+?line <<"aaac">> = iolist_to_binary(re:replace("aaac","^(b+|a){1,2}c","lBeqV\\1ygD\\1oXXqs",[global])),
+?line <<"abbbbbbbbbbbac">> = iolist_to_binary(re:replace("abbbbbbbbbbbac","^(b+|a){1,2}c","HVL\\1kIEVrx\\1hyh\\1&eY\\1R",[])),
+?line <<"abbbbbbbbbbbac">> = iolist_to_binary(re:replace("abbbbbbbbbbbac","^(b+|a){1,2}c","HVL\\1kIEVrx\\1hyh\\1&eY\\1R",[global])),
+?line <<"ScHjJbbcrs">> = iolist_to_binary(re:replace("bbc","^(b+|a){1,2}?bc","ScHjJ&rs",[])),
+?line <<"ScHjJbbcrs">> = iolist_to_binary(re:replace("bbc","^(b+|a){1,2}?bc","ScHjJ&rs",[global])),
+?line <<"xbabcCeyVbabcbaXLUCoov">> = iolist_to_binary(re:replace("babc","^(b*|ba){1,2}?bc","x&CeyV&\\1XLUCoov",[])),
+?line <<"xbabcCeyVbabcbaXLUCoov">> = iolist_to_binary(re:replace("babc","^(b*|ba){1,2}?bc","x&CeyV&\\1XLUCoov",[global])),
+?line <<"HbPsbrWbbabcba">> = iolist_to_binary(re:replace("bbabc","^(b*|ba){1,2}?bc","HbPsbrW&\\1",[])),
+?line <<"HbPsbrWbbabcba">> = iolist_to_binary(re:replace("bbabc","^(b*|ba){1,2}?bc","HbPsbrW&\\1",[global])),
+?line <<"IpbababcRBSkmAw">> = iolist_to_binary(re:replace("bababc","^(b*|ba){1,2}?bc","Ip&RBSkmAw",[])),
+?line <<"IpbababcRBSkmAw">> = iolist_to_binary(re:replace("bababc","^(b*|ba){1,2}?bc","Ip&RBSkmAw",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(b*|ba){1,2}?bc","e\\1\\1Tx",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(b*|ba){1,2}?bc","e\\1\\1Tx",[global])),
+?line <<"bababbc">> = iolist_to_binary(re:replace("bababbc","^(b*|ba){1,2}?bc","llyNxYhfjNKiNYM\\1&Ko",[])),
+?line <<"bababbc">> = iolist_to_binary(re:replace("bababbc","^(b*|ba){1,2}?bc","llyNxYhfjNKiNYM\\1&Ko",[global])),
+?line <<"babababc">> = iolist_to_binary(re:replace("babababc","^(b*|ba){1,2}?bc","R&TKD\\1JpYJGqtjf",[])),
+?line <<"babababc">> = iolist_to_binary(re:replace("babababc","^(b*|ba){1,2}?bc","R&TKD\\1JpYJGqtjf",[global])),
+?line <<"babcfHFubaafbYLoJba">> = iolist_to_binary(re:replace("babc","^(ba|b*){1,2}?bc","&fHFu\\1afbYLoJ\\1",[])),
+?line <<"babcfHFubaafbYLoJba">> = iolist_to_binary(re:replace("babc","^(ba|b*){1,2}?bc","&fHFu\\1afbYLoJ\\1",[global])),
+?line <<"ewhbbabc">> = iolist_to_binary(re:replace("bbabc","^(ba|b*){1,2}?bc","ewh&",[])),
+?line <<"ewhbbabc">> = iolist_to_binary(re:replace("bbabc","^(ba|b*){1,2}?bc","ewh&",[global])),
+?line <<"L">> = iolist_to_binary(re:replace("bababc","^(ba|b*){1,2}?bc","L",[])),
+?line <<"L">> = iolist_to_binary(re:replace("bababc","^(ba|b*){1,2}?bc","L",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(ba|b*){1,2}?bc","\\1wv",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(ba|b*){1,2}?bc","\\1wv",[global])),
+?line <<"bababbc">> = iolist_to_binary(re:replace("bababbc","^(ba|b*){1,2}?bc","&F",[])),
+?line <<"bababbc">> = iolist_to_binary(re:replace("bababbc","^(ba|b*){1,2}?bc","&F",[global])),
+?line <<"babababc">> = iolist_to_binary(re:replace("babababc","^(ba|b*){1,2}?bc","Yk",[])),
+?line <<"babababc">> = iolist_to_binary(re:replace("babababc","^(ba|b*){1,2}?bc","Yk",[global])),
+?line <<"rdI;zTYuI;zcdx">> = iolist_to_binary(re:replace(";z","^\\ca\\cA\\c[\\c{\\c:","rdI&TYuI&cdx\\1",[])),
+?line <<"rdI;zTYuI;zcdx">> = iolist_to_binary(re:replace(";z","^\\ca\\cA\\c[\\c{\\c:","rdI&TYuI&cdx\\1",[global])),
+?line <<"XgOhHATXLthing">> = iolist_to_binary(re:replace("athing","^[ab\\]cde]","XgO\\1hHATXL",[])),
+?line <<"XgOhHATXLthing">> = iolist_to_binary(re:replace("athing","^[ab\\]cde]","XgO\\1hHATXL",[global])),
+?line <<"xIBYFthing">> = iolist_to_binary(re:replace("bthing","^[ab\\]cde]","xIBYF",[])),
+?line <<"xIBYFthing">> = iolist_to_binary(re:replace("bthing","^[ab\\]cde]","xIBYF",[global])),
+?line <<"]lthing">> = iolist_to_binary(re:replace("]thing","^[ab\\]cde]","&l",[])),
+?line <<"]lthing">> = iolist_to_binary(re:replace("]thing","^[ab\\]cde]","&l",[global])),
+?line <<"qbsthing">> = iolist_to_binary(re:replace("cthing","^[ab\\]cde]","\\1qbs",[])),
+?line <<"qbsthing">> = iolist_to_binary(re:replace("cthing","^[ab\\]cde]","\\1qbs",[global])),
+?line <<"gyOCYsthing">> = iolist_to_binary(re:replace("dthing","^[ab\\]cde]","gyOCYs",[])),
+?line <<"gyOCYsthing">> = iolist_to_binary(re:replace("dthing","^[ab\\]cde]","gyOCYs",[global])),
+?line <<"DrUmPIeSUthing">> = iolist_to_binary(re:replace("ething","^[ab\\]cde]","DrUmP\\1IeSU",[])),
+?line <<"DrUmPIeSUthing">> = iolist_to_binary(re:replace("ething","^[ab\\]cde]","DrUmP\\1IeSU",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^[ab\\]cde]","Xi\\1luACtdK",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^[ab\\]cde]","Xi\\1luACtdK",[global])),
+?line <<"fthing">> = iolist_to_binary(re:replace("fthing","^[ab\\]cde]","&u&Y\\1obNLU\\1tyonhH",[])),
+?line <<"fthing">> = iolist_to_binary(re:replace("fthing","^[ab\\]cde]","&u&Y\\1obNLU\\1tyonhH",[global])),
+?line <<"[thing">> = iolist_to_binary(re:replace("[thing","^[ab\\]cde]","TVEAE&ooeuGQJgKnrqW",[])),
+?line <<"[thing">> = iolist_to_binary(re:replace("[thing","^[ab\\]cde]","TVEAE&ooeuGQJgKnrqW",[global])),
+?line <<"\\thing">> = iolist_to_binary(re:replace("\\thing","^[ab\\]cde]","vRby\\1&",[])),
+?line <<"\\thing">> = iolist_to_binary(re:replace("\\thing","^[ab\\]cde]","vRby\\1&",[global])),
+?line <<"]n]ExaxasbKqYi]CHthing">> = iolist_to_binary(re:replace("]thing","^[]cde]","&n&Ex\\1axa\\1sbKqYi&CH",[])),
+?line <<"]n]ExaxasbKqYi]CHthing">> = iolist_to_binary(re:replace("]thing","^[]cde]","&n&Ex\\1axa\\1sbKqYi&CH",[global])),
+?line <<"nLnsthing">> = iolist_to_binary(re:replace("cthing","^[]cde]","nLns",[])),
+?line <<"nLnsthing">> = iolist_to_binary(re:replace("cthing","^[]cde]","nLns",[global])),
+?line <<"dOETLdnanQKLkkVthing">> = iolist_to_binary(re:replace("dthing","^[]cde]","\\1&OET\\1L&nanQKLkkV",[])),
+?line <<"dOETLdnanQKLkkVthing">> = iolist_to_binary(re:replace("dthing","^[]cde]","\\1&OET\\1L&nanQKLkkV",[global])),
+?line <<"UKthing">> = iolist_to_binary(re:replace("ething","^[]cde]","UK",[])),
+?line <<"UKthing">> = iolist_to_binary(re:replace("ething","^[]cde]","UK",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^[]cde]","OEN&h&RDky",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^[]cde]","OEN&h&RDky",[global])),
+?line <<"athing">> = iolist_to_binary(re:replace("athing","^[]cde]","ADIYuoD\\1PwBWBN",[])),
+?line <<"athing">> = iolist_to_binary(re:replace("athing","^[]cde]","ADIYuoD\\1PwBWBN",[global])),
+?line <<"fthing">> = iolist_to_binary(re:replace("fthing","^[]cde]","H&UGGJFd\\1Ys\\1xgEg",[])),
+?line <<"fthing">> = iolist_to_binary(re:replace("fthing","^[]cde]","H&UGGJFd\\1Ys\\1xgEg",[global])),
+?line <<"yipHChvHfthing">> = iolist_to_binary(re:replace("fthing","^[^ab\\]cde]","yi\\1pHC\\1hvH&",[])),
+?line <<"yipHChvHfthing">> = iolist_to_binary(re:replace("fthing","^[^ab\\]cde]","yi\\1pHC\\1hvH&",[global])),
+?line <<"pthing">> = iolist_to_binary(re:replace("[thing","^[^ab\\]cde]","p",[])),
+?line <<"pthing">> = iolist_to_binary(re:replace("[thing","^[^ab\\]cde]","p",[global])),
+?line <<"nvbthing">> = iolist_to_binary(re:replace("\\thing","^[^ab\\]cde]","n\\1v\\1b",[])),
+?line <<"nvbthing">> = iolist_to_binary(re:replace("\\thing","^[^ab\\]cde]","n\\1v\\1b",[global])),
+?line <<"o*r*CQayoALTVo** Failers">> = iolist_to_binary(re:replace("*** Failers","^[^ab\\]cde]","o&r&CQa\\1yoALTVo\\1",[])),
+?line <<"o*r*CQayoALTVo** Failers">> = iolist_to_binary(re:replace("*** Failers","^[^ab\\]cde]","o&r&CQa\\1yoALTVo\\1",[global])),
+?line <<"athing">> = iolist_to_binary(re:replace("athing","^[^ab\\]cde]","k\\1&MCQ",[])),
+?line <<"athing">> = iolist_to_binary(re:replace("athing","^[^ab\\]cde]","k\\1&MCQ",[global])),
+?line <<"bthing">> = iolist_to_binary(re:replace("bthing","^[^ab\\]cde]","XKeFQEPnv",[])),
+?line <<"bthing">> = iolist_to_binary(re:replace("bthing","^[^ab\\]cde]","XKeFQEPnv",[global])),
+?line <<"]thing">> = iolist_to_binary(re:replace("]thing","^[^ab\\]cde]","\\1",[])),
+?line <<"]thing">> = iolist_to_binary(re:replace("]thing","^[^ab\\]cde]","\\1",[global])),
+?line <<"cthing">> = iolist_to_binary(re:replace("cthing","^[^ab\\]cde]","NU",[])),
+?line <<"cthing">> = iolist_to_binary(re:replace("cthing","^[^ab\\]cde]","NU",[global])),
+?line <<"dthing">> = iolist_to_binary(re:replace("dthing","^[^ab\\]cde]","GVUo\\1m&I",[])),
+?line <<"dthing">> = iolist_to_binary(re:replace("dthing","^[^ab\\]cde]","GVUo\\1m&I",[global])),
+?line <<"ething">> = iolist_to_binary(re:replace("ething","^[^ab\\]cde]","Ms\\1&GwiawlCHng&EEX",[])),
+?line <<"ething">> = iolist_to_binary(re:replace("ething","^[^ab\\]cde]","Ms\\1&GwiawlCHng&EEX",[global])),
+?line <<"lqtFwcAYthing">> = iolist_to_binary(re:replace("athing","^[^]cde]","lqtFwcAY",[])),
+?line <<"lqtFwcAYthing">> = iolist_to_binary(re:replace("athing","^[^]cde]","lqtFwcAY",[global])),
+?line <<"Fxtpjthing">> = iolist_to_binary(re:replace("fthing","^[^]cde]","Fxt\\1pj",[])),
+?line <<"Fxtpjthing">> = iolist_to_binary(re:replace("fthing","^[^]cde]","Fxt\\1pj",[global])),
+?line <<"xT*oD*U** Failers">> = iolist_to_binary(re:replace("*** Failers","^[^]cde]","xT&oD\\1&U",[])),
+?line <<"xT*oD*U** Failers">> = iolist_to_binary(re:replace("*** Failers","^[^]cde]","xT&oD\\1&U",[global])),
+?line <<"]thing">> = iolist_to_binary(re:replace("]thing","^[^]cde]","R\\1M&\\1m",[])),
+?line <<"]thing">> = iolist_to_binary(re:replace("]thing","^[^]cde]","R\\1M&\\1m",[global])),
+?line <<"cthing">> = iolist_to_binary(re:replace("cthing","^[^]cde]","\\1tF\\1WOFN&fB",[])),
+?line <<"cthing">> = iolist_to_binary(re:replace("cthing","^[^]cde]","\\1tF\\1WOFN&fB",[global])),
+?line <<"dthing">> = iolist_to_binary(re:replace("dthing","^[^]cde]","y\\1I&MoqRPG&GQa\\1l",[])),
+?line <<"dthing">> = iolist_to_binary(re:replace("dthing","^[^]cde]","y\\1I&MoqRPG&GQa\\1l",[global])),
+?line <<"ething">> = iolist_to_binary(re:replace("ething","^[^]cde]","AsxwUn\\1GqkWNdgRJk",[])),
+?line <<"ething">> = iolist_to_binary(re:replace("ething","^[^]cde]","AsxwUn\\1GqkWNdgRJk",[global])),
+?line <<"RornKmOnaFr�tWgtW">> = iolist_to_binary(re:replace("�","^\\�","R\\1o\\1r\\1nKmOnaFr&tWgtW",[])),
+?line <<"RornKmOnaFr�tWgtW">> = iolist_to_binary(re:replace("�","^\\�","R\\1o\\1r\\1nKmOnaFr&tWgtW",[global])),
+?line <<"ufbmbfOYuK�wf�E�dx">> = iolist_to_binary(re:replace("�","^�","ufbmbfOYuK&wf&E&\\1dx",[])),
+?line <<"ufbmbfOYuK�wf�E�dx">> = iolist_to_binary(re:replace("�","^�","ufbmbfOYuK&wf&E&\\1dx",[global])),
+?line <<"oAdJme0jw">> = iolist_to_binary(re:replace("0","^[0-9]+$","oAdJme\\1&jw",[])),
+?line <<"oAdJme0jw">> = iolist_to_binary(re:replace("0","^[0-9]+$","oAdJme\\1&jw",[global])),
+?line <<"1aoKN">> = iolist_to_binary(re:replace("1","^[0-9]+$","&aoKN",[])),
+?line <<"1aoKN">> = iolist_to_binary(re:replace("1","^[0-9]+$","&aoKN",[global])),
+?line <<"tIHn">> = iolist_to_binary(re:replace("2","^[0-9]+$","tIHn\\1",[])),
+?line <<"tIHn">> = iolist_to_binary(re:replace("2","^[0-9]+$","tIHn\\1",[global])),
+?line <<"wgA3cJbrrCyMvMXM3">> = iolist_to_binary(re:replace("3","^[0-9]+$","wgA&cJbrrCyMv\\1M\\1XM&",[])),
+?line <<"wgA3cJbrrCyMvMXM3">> = iolist_to_binary(re:replace("3","^[0-9]+$","wgA&cJbrrCyMv\\1M\\1XM&",[global])),
+?line <<"huUpJ">> = iolist_to_binary(re:replace("4","^[0-9]+$","huUpJ",[])),
+?line <<"huUpJ">> = iolist_to_binary(re:replace("4","^[0-9]+$","huUpJ",[global])),
+?line <<"Fe5F5">> = iolist_to_binary(re:replace("5","^[0-9]+$","F\\1e&F&",[])),
+?line <<"Fe5F5">> = iolist_to_binary(re:replace("5","^[0-9]+$","F\\1e&F&",[global])),
+?line <<"HJ">> = iolist_to_binary(re:replace("6","^[0-9]+$","HJ",[])),
+?line <<"HJ">> = iolist_to_binary(re:replace("6","^[0-9]+$","HJ",[global])),
+?line <<"e">> = iolist_to_binary(re:replace("7","^[0-9]+$","e",[])),
+?line <<"e">> = iolist_to_binary(re:replace("7","^[0-9]+$","e",[global])),
+?line <<"Fmds88NtMX">> = iolist_to_binary(re:replace("8","^[0-9]+$","F\\1mds&&Nt\\1MX",[])),
+?line <<"Fmds88NtMX">> = iolist_to_binary(re:replace("8","^[0-9]+$","F\\1mds&&Nt\\1MX",[global])),
+?line <<"99cE9SqMch">> = iolist_to_binary(re:replace("9","^[0-9]+$","&&cE&\\1SqMch",[])),
+?line <<"99cE9SqMch">> = iolist_to_binary(re:replace("9","^[0-9]+$","&&cE&\\1SqMch",[global])),
+?line <<"xhR">> = iolist_to_binary(re:replace("10","^[0-9]+$","xhR",[])),
+?line <<"xhR">> = iolist_to_binary(re:replace("10","^[0-9]+$","xhR",[global])),
+?line <<"j100">> = iolist_to_binary(re:replace("100","^[0-9]+$","j&",[])),
+?line <<"j100">> = iolist_to_binary(re:replace("100","^[0-9]+$","j&",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^[0-9]+$","SR&tOYsEgJid&hfCF",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^[0-9]+$","SR&tOYsEgJid&hfCF",[global])),
+?line <<"abc">> = iolist_to_binary(re:replace("abc","^[0-9]+$","JK&",[])),
+?line <<"abc">> = iolist_to_binary(re:replace("abc","^[0-9]+$","JK&",[global])),
+?line <<"rXjkB">> = iolist_to_binary(re:replace("enter","^.*nter","rXjkB",[])),
+?line <<"rXjkB">> = iolist_to_binary(re:replace("enter","^.*nter","rXjkB",[global])),
+?line <<"oOEtqV">> = iolist_to_binary(re:replace("inter","^.*nter","oO\\1EtqV",[])),
+?line <<"oOEtqV">> = iolist_to_binary(re:replace("inter","^.*nter","oO\\1EtqV",[global])),
+?line <<"">> = iolist_to_binary(re:replace("uponter","^.*nter","\\1",[])),
+?line <<"">> = iolist_to_binary(re:replace("uponter","^.*nter","\\1",[global])),
+?line <<"SODUcOgFnbuQEN">> = iolist_to_binary(re:replace("xxx0","^xxx[0-9]+$","\\1\\1SODU\\1\\1cOgFnbuQEN",[])),
+?line <<"SODUcOgFnbuQEN">> = iolist_to_binary(re:replace("xxx0","^xxx[0-9]+$","\\1\\1SODU\\1\\1cOgFnbuQEN",[global])),
+?line <<"hsacOxxx1234kudxxx1234sEIrIdI">> = iolist_to_binary(re:replace("xxx1234","^xxx[0-9]+$","hsacO\\1&kud&s\\1EIrIdI\\1",[])),
+?line <<"hsacOxxx1234kudxxx1234sEIrIdI">> = iolist_to_binary(re:replace("xxx1234","^xxx[0-9]+$","hsacO\\1&kud&s\\1EIrIdI\\1",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^xxx[0-9]+$","e",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^xxx[0-9]+$","e",[global])),
+?line <<"xxx">> = iolist_to_binary(re:replace("xxx","^xxx[0-9]+$","oSBYD&M",[])),
+?line <<"xxx">> = iolist_to_binary(re:replace("xxx","^xxx[0-9]+$","oSBYD&M",[global])),
+?line <<"x123HgGUYCx123PowSBtYb">> = iolist_to_binary(re:replace("x123","^.+[0-9][0-9][0-9]$","&HgGUYC&PowSBtY\\1b",[])),
+?line <<"x123HgGUYCx123PowSBtYb">> = iolist_to_binary(re:replace("x123","^.+[0-9][0-9][0-9]$","&HgGUYC&PowSBtY\\1b",[global])),
+?line <<"mEVxx123SNuYPQIaJ">> = iolist_to_binary(re:replace("xx123","^.+[0-9][0-9][0-9]$","mE\\1V\\1&SNuYPQIa\\1J",[])),
+?line <<"mEVxx123SNuYPQIaJ">> = iolist_to_binary(re:replace("xx123","^.+[0-9][0-9][0-9]$","mE\\1V\\1&SNuYPQIa\\1J",[global])),
+?line <<"l123456O123456">> = iolist_to_binary(re:replace("123456","^.+[0-9][0-9][0-9]$","l&O&",[])),
+?line <<"l123456O123456">> = iolist_to_binary(re:replace("123456","^.+[0-9][0-9][0-9]$","l&O&",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^.+[0-9][0-9][0-9]$","MX&hxvs",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^.+[0-9][0-9][0-9]$","MX&hxvs",[global])),
+?line <<"123">> = iolist_to_binary(re:replace("123","^.+[0-9][0-9][0-9]$","RBYgTXkgO&TLdWqjEUps",[])),
+?line <<"123">> = iolist_to_binary(re:replace("123","^.+[0-9][0-9][0-9]$","RBYgTXkgO&TLdWqjEUps",[global])),
+?line <<"fgx1234">> = iolist_to_binary(re:replace("x1234","^.+[0-9][0-9][0-9]$","fg&",[])),
+?line <<"fgx1234">> = iolist_to_binary(re:replace("x1234","^.+[0-9][0-9][0-9]$","fg&",[global])),
+?line <<"FLbkgx123RdPrD">> = iolist_to_binary(re:replace("x123","^.+?[0-9][0-9][0-9]$","FLbkg&R\\1dPrD",[])),
+?line <<"FLbkgx123RdPrD">> = iolist_to_binary(re:replace("x123","^.+?[0-9][0-9][0-9]$","FLbkg&R\\1dPrD",[global])),
+?line <<"C">> = iolist_to_binary(re:replace("xx123","^.+?[0-9][0-9][0-9]$","C",[])),
+?line <<"C">> = iolist_to_binary(re:replace("xx123","^.+?[0-9][0-9][0-9]$","C",[global])),
+?line <<"oWjVDKTAoaLU">> = iolist_to_binary(re:replace("123456","^.+?[0-9][0-9][0-9]$","oW\\1jVDK\\1TAoaLU",[])),
+?line <<"oWjVDKTAoaLU">> = iolist_to_binary(re:replace("123456","^.+?[0-9][0-9][0-9]$","oW\\1jVDK\\1TAoaLU",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^.+?[0-9][0-9][0-9]$","xA&\\1sIV",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^.+?[0-9][0-9][0-9]$","xA&\\1sIV",[global])),
+?line <<"123">> = iolist_to_binary(re:replace("123","^.+?[0-9][0-9][0-9]$","ONX&",[])),
+?line <<"123">> = iolist_to_binary(re:replace("123","^.+?[0-9][0-9][0-9]$","ONX&",[global])),
+?line <<"oLgQtiSmGx1234wqbuoRB">> = iolist_to_binary(re:replace("x1234","^.+?[0-9][0-9][0-9]$","\\1oLgQtiSm\\1\\1G&wqbuoRB",[])),
+?line <<"oLgQtiSmGx1234wqbuoRB">> = iolist_to_binary(re:replace("x1234","^.+?[0-9][0-9][0-9]$","\\1oLgQtiSm\\1\\1G&wqbuoRB",[global])),
+?line <<"mcpuCvaabc!pqr=apquxz.ixr.zzz.ac.ukgabc!pqr=apquxz.ixr.zzz.ac.uk">> = iolist_to_binary(re:replace("abc!pqr=apquxz.ixr.zzz.ac.uk","^([^!]+)!(.+)=apquxz\\.ixr\\.zzz\\.ac\\.uk$","mcpuCva&g&",[])),
+?line <<"mcpuCvaabc!pqr=apquxz.ixr.zzz.ac.ukgabc!pqr=apquxz.ixr.zzz.ac.uk">> = iolist_to_binary(re:replace("abc!pqr=apquxz.ixr.zzz.ac.uk","^([^!]+)!(.+)=apquxz\\.ixr\\.zzz\\.ac\\.uk$","mcpuCva&g&",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^([^!]+)!(.+)=apquxz\\.ixr\\.zzz\\.ac\\.uk$","J&a\\1HaapJjylMMyeA\\1e",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^([^!]+)!(.+)=apquxz\\.ixr\\.zzz\\.ac\\.uk$","J&a\\1HaapJjylMMyeA\\1e",[global])),
+?line <<"!pqr=apquxz.ixr.zzz.ac.uk">> = iolist_to_binary(re:replace("!pqr=apquxz.ixr.zzz.ac.uk","^([^!]+)!(.+)=apquxz\\.ixr\\.zzz\\.ac\\.uk$","FOOFh&nQLU\\1c",[])),
+?line <<"!pqr=apquxz.ixr.zzz.ac.uk">> = iolist_to_binary(re:replace("!pqr=apquxz.ixr.zzz.ac.uk","^([^!]+)!(.+)=apquxz\\.ixr\\.zzz\\.ac\\.uk$","FOOFh&nQLU\\1c",[global])),
+?line <<"abc!=apquxz.ixr.zzz.ac.uk">> = iolist_to_binary(re:replace("abc!=apquxz.ixr.zzz.ac.uk","^([^!]+)!(.+)=apquxz\\.ixr\\.zzz\\.ac\\.uk$","H\\1G",[])),
+?line <<"abc!=apquxz.ixr.zzz.ac.uk">> = iolist_to_binary(re:replace("abc!=apquxz.ixr.zzz.ac.uk","^([^!]+)!(.+)=apquxz\\.ixr\\.zzz\\.ac\\.uk$","H\\1G",[global])),
+?line <<"abc!pqr=apquxz:ixr.zzz.ac.uk">> = iolist_to_binary(re:replace("abc!pqr=apquxz:ixr.zzz.ac.uk","^([^!]+)!(.+)=apquxz\\.ixr\\.zzz\\.ac\\.uk$","&tBS&",[])),
+?line <<"abc!pqr=apquxz:ixr.zzz.ac.uk">> = iolist_to_binary(re:replace("abc!pqr=apquxz:ixr.zzz.ac.uk","^([^!]+)!(.+)=apquxz\\.ixr\\.zzz\\.ac\\.uk$","&tBS&",[global])),
+?line <<"abc!pqr=apquxz.ixr.zzz.ac.ukk">> = iolist_to_binary(re:replace("abc!pqr=apquxz.ixr.zzz.ac.ukk","^([^!]+)!(.+)=apquxz\\.ixr\\.zzz\\.ac\\.uk$","Gd&\\1CN\\1",[])),
+?line <<"abc!pqr=apquxz.ixr.zzz.ac.ukk">> = iolist_to_binary(re:replace("abc!pqr=apquxz.ixr.zzz.ac.ukk","^([^!]+)!(.+)=apquxz\\.ixr\\.zzz\\.ac\\.uk$","Gd&\\1CN\\1",[global])),
+?line <<"Well, we need a colonGTdcJbUips: somewhere">> = iolist_to_binary(re:replace("Well, we need a colon: somewhere",":","GTdc\\1J\\1bUips\\1&",[])),
+?line <<"Well, we need a colonGTdcJbUips: somewhere">> = iolist_to_binary(re:replace("Well, we need a colon: somewhere",":","GTdc\\1J\\1bUips\\1&",[global])),
+?line <<"*** Fail if we don't">> = iolist_to_binary(re:replace("*** Fail if we don't",":","d",[])),
+?line <<"*** Fail if we don't">> = iolist_to_binary(re:replace("*** Fail if we don't",":","d",[global])),
+?line <<"0abcDqVs0abc0abcptNR">> = iolist_to_binary(re:replace("0abc","([\\da-f:]+)$","\\1DqVs\\1\\1ptNR",[caseless])),
+?line <<"0abcDqVs0abc0abcptNR">> = iolist_to_binary(re:replace("0abc","([\\da-f:]+)$","\\1DqVs\\1\\1ptNR",[caseless,
+ global])),
+?line <<"abctJK">> = iolist_to_binary(re:replace("abc","([\\da-f:]+)$","&tJK",[caseless])),
+?line <<"abctJK">> = iolist_to_binary(re:replace("abc","([\\da-f:]+)$","&tJK",[caseless,
+ global])),
+?line <<"quighClnfedRB">> = iolist_to_binary(re:replace("fed","([\\da-f:]+)$","quighCln\\1RB",[caseless])),
+?line <<"quighClnfedRB">> = iolist_to_binary(re:replace("fed","([\\da-f:]+)$","quighCln\\1RB",[caseless,
+ global])),
+?line <<"ENd">> = iolist_to_binary(re:replace("E","([\\da-f:]+)$","\\1Nd",[caseless])),
+?line <<"ENd">> = iolist_to_binary(re:replace("E","([\\da-f:]+)$","\\1Nd",[caseless,
+ global])),
+?line <<"o::U::lkIj::XoRWPah::s">> = iolist_to_binary(re:replace("::","([\\da-f:]+)$","o&U&lkIj\\1XoRWPah&s",[caseless])),
+?line <<"o::U::lkIj::XoRWPah::s">> = iolist_to_binary(re:replace("::","([\\da-f:]+)$","o&U&lkIj\\1XoRWPah&s",[caseless,
+ global])),
+?line <<"ab5f03:12C0::932eONbt5f03:12C0::932ehnfLI5f03:12C0::932esqYx5f03:12C0::932e">> = iolist_to_binary(re:replace("5f03:12C0::932e","([\\da-f:]+)$","ab&ONbt\\1hnfLI\\1sqYx&",[caseless])),
+?line <<"ab5f03:12C0::932eONbt5f03:12C0::932ehnfLI5f03:12C0::932esqYx5f03:12C0::932e">> = iolist_to_binary(re:replace("5f03:12C0::932e","([\\da-f:]+)$","ab&ONbt\\1hnfLI\\1sqYx&",[caseless,
+ global])),
+?line <<"fed OAMdefijvdef">> = iolist_to_binary(re:replace("fed def","([\\da-f:]+)$","OAM\\1ijv&",[caseless])),
+?line <<"fed OAMdefijvdef">> = iolist_to_binary(re:replace("fed def","([\\da-f:]+)$","OAM\\1ijv&",[caseless,
+ global])),
+?line <<"Any old stuSVffaffeYffCjDlYffhWTMo">> = iolist_to_binary(re:replace("Any old stuff","([\\da-f:]+)$","SV&a\\1eY&CjDlY&hWTMo",[caseless])),
+?line <<"Any old stuSVffaffeYffCjDlYffhWTMo">> = iolist_to_binary(re:replace("Any old stuff","([\\da-f:]+)$","SV&a\\1eY&CjDlY&hWTMo",[caseless,
+ global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","([\\da-f:]+)$","j&R\\1oXiR",[caseless])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","([\\da-f:]+)$","j&R\\1oXiR",[caseless,
+ global])),
+?line <<"0zzz">> = iolist_to_binary(re:replace("0zzz","([\\da-f:]+)$","&HUuWH\\1&VEg",[caseless])),
+?line <<"0zzz">> = iolist_to_binary(re:replace("0zzz","([\\da-f:]+)$","&HUuWH\\1&VEg",[caseless,
+ global])),
+?line <<"gzzz">> = iolist_to_binary(re:replace("gzzz","([\\da-f:]+)$","l&n&p&DKUsLBFC",[caseless])),
+?line <<"gzzz">> = iolist_to_binary(re:replace("gzzz","([\\da-f:]+)$","l&n&p&DKUsLBFC",[caseless,
+ global])),
+?line <<"fed ">> = iolist_to_binary(re:replace("fed ","([\\da-f:]+)$","KuLffd&Y",[caseless])),
+?line <<"fed ">> = iolist_to_binary(re:replace("fed ","([\\da-f:]+)$","KuLffd&Y",[caseless,
+ global])),
+?line <<"Any old rubbish">> = iolist_to_binary(re:replace("Any old rubbish","([\\da-f:]+)$","Mid\\1",[caseless])),
+?line <<"Any old rubbish">> = iolist_to_binary(re:replace("Any old rubbish","([\\da-f:]+)$","Mid\\1",[caseless,
+ global])),
+?line <<"g.1.2.3WLxQ1s">> = iolist_to_binary(re:replace(".1.2.3","^.*\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$","g&WLxQ\\1s",[])),
+?line <<"g.1.2.3WLxQ1s">> = iolist_to_binary(re:replace(".1.2.3","^.*\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$","g&WLxQ\\1s",[global])),
+?line <<"12Oy">> = iolist_to_binary(re:replace("A.12.123.0","^.*\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$","\\1Oy",[])),
+?line <<"12Oy">> = iolist_to_binary(re:replace("A.12.123.0","^.*\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$","\\1Oy",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^.*\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$","eX\\1nRbXcnyEu",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^.*\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$","eX\\1nRbXcnyEu",[global])),
+?line <<".1.2.3333">> = iolist_to_binary(re:replace(".1.2.3333","^.*\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$","&iIBylLhNq",[])),
+?line <<".1.2.3333">> = iolist_to_binary(re:replace(".1.2.3333","^.*\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$","&iIBylLhNq",[global])),
+?line <<"1.2.3">> = iolist_to_binary(re:replace("1.2.3","^.*\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$","\\1G&pFELr\\1\\1&\\1HPX",[])),
+?line <<"1.2.3">> = iolist_to_binary(re:replace("1.2.3","^.*\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$","\\1G&pFELr\\1\\1&\\1HPX",[global])),
+?line <<"1234.2.3">> = iolist_to_binary(re:replace("1234.2.3","^.*\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$","&qtoJnh\\1h",[])),
+?line <<"1234.2.3">> = iolist_to_binary(re:replace("1234.2.3","^.*\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$","&qtoJnh\\1h",[global])),
+?line <<"eaSBc111LbN">> = iolist_to_binary(re:replace("1 IN SOA non-sp1 non-sp2(","^(\\d+)\\s+IN\\s+SOA\\s+(\\S+)\\s+(\\S+)\\s*\\(\\s*$","eaSBc\\1\\1\\1LbN",[])),
+?line <<"eaSBc111LbN">> = iolist_to_binary(re:replace("1 IN SOA non-sp1 non-sp2(","^(\\d+)\\s+IN\\s+SOA\\s+(\\S+)\\s+(\\S+)\\s*\\(\\s*$","eaSBc\\1\\1\\1LbN",[global])),
+?line <<"1 IN SOA non-sp1 non-sp2 (yranl1 IN SOA non-sp1 non-sp2 (kU">> = iolist_to_binary(re:replace("1 IN SOA non-sp1 non-sp2 (","^(\\d+)\\s+IN\\s+SOA\\s+(\\S+)\\s+(\\S+)\\s*\\(\\s*$","&yranl&kU",[])),
+?line <<"1 IN SOA non-sp1 non-sp2 (yranl1 IN SOA non-sp1 non-sp2 (kU">> = iolist_to_binary(re:replace("1 IN SOA non-sp1 non-sp2 (","^(\\d+)\\s+IN\\s+SOA\\s+(\\S+)\\s+(\\S+)\\s*\\(\\s*$","&yranl&kU",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(\\d+)\\s+IN\\s+SOA\\s+(\\S+)\\s+(\\S+)\\s*\\(\\s*$","W",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(\\d+)\\s+IN\\s+SOA\\s+(\\S+)\\s+(\\S+)\\s*\\(\\s*$","W",[global])),
+?line <<"1IN SOA non-sp1 non-sp2(">> = iolist_to_binary(re:replace("1IN SOA non-sp1 non-sp2(","^(\\d+)\\s+IN\\s+SOA\\s+(\\S+)\\s+(\\S+)\\s*\\(\\s*$","UyNVyrR",[])),
+?line <<"1IN SOA non-sp1 non-sp2(">> = iolist_to_binary(re:replace("1IN SOA non-sp1 non-sp2(","^(\\d+)\\s+IN\\s+SOA\\s+(\\S+)\\s+(\\S+)\\s*\\(\\s*$","UyNVyrR",[global])),
+?line <<"pbeGIhIlhvhv">> = iolist_to_binary(re:replace("a.","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$","pbeGIhIl\\1hvhv",[])),
+?line <<"pbeGIhIlhvhv">> = iolist_to_binary(re:replace("a.","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$","pbeGIhIl\\1hvhv",[global])),
+?line <<"gFDyTxSYOppWiRv">> = iolist_to_binary(re:replace("Z.","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$","gFDyTxSYOppWiR\\1v",[])),
+?line <<"gFDyTxSYOppWiRv">> = iolist_to_binary(re:replace("Z.","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$","gFDyTxSYOppWiR\\1v",[global])),
+?line <<"HSc2.vOMD">> = iolist_to_binary(re:replace("2.","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$","HSc&\\1vO\\1MD\\1",[])),
+?line <<"HSc2.vOMD">> = iolist_to_binary(re:replace("2.","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$","HSc&\\1vO\\1MD\\1",[global])),
+?line <<".pq-rd.pq-rG.pq-rUab-c.pq-r.HCGaTI">> = iolist_to_binary(re:replace("ab-c.pq-r.","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$","\\1d\\1G\\1U&HCGaTI",[])),
+?line <<".pq-rd.pq-rG.pq-rUab-c.pq-r.HCGaTI">> = iolist_to_binary(re:replace("ab-c.pq-r.","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$","\\1d\\1G\\1U&HCGaTI",[global])),
+?line <<"RwF">> = iolist_to_binary(re:replace("sxk.zzz.ac.uk.","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$","RwF",[])),
+?line <<"RwF">> = iolist_to_binary(re:replace("sxk.zzz.ac.uk.","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$","RwF",[global])),
+?line <<"oAJdUx-.y-.GMx-.y-.iBCRNx-.y-.wBW">> = iolist_to_binary(re:replace("x-.y-.","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$","oAJdU&GM&iBCRN&wBW",[])),
+?line <<"oAJdUx-.y-.GMx-.y-.iBCRNx-.y-.wBW">> = iolist_to_binary(re:replace("x-.y-.","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$","oAJdU&GM&iBCRN&wBW",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$","wwA&\\1snkRSCcfnG&S",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$","wwA&\\1snkRSCcfnG&S",[global])),
+?line <<"-abc.peq.">> = iolist_to_binary(re:replace("-abc.peq.","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$","YaFu&cvVYqVy",[])),
+?line <<"-abc.peq.">> = iolist_to_binary(re:replace("-abc.peq.","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$","YaFu&cvVYqVy",[global])),
+?line <<"*.aXojEWCW">> = iolist_to_binary(re:replace("*.a","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$","&\\1XojEWCW",[])),
+?line <<"*.aXojEWCW">> = iolist_to_binary(re:replace("*.a","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$","&\\1XojEWCW",[global])),
+?line <<"djXR0-a0-aFXv*.b0-awEtv">> = iolist_to_binary(re:replace("*.b0-a","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$","djXR\\1\\1FXv&wEtv",[])),
+?line <<"djXR0-a0-aFXv*.b0-awEtv">> = iolist_to_binary(re:replace("*.b0-a","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$","djXR\\1\\1FXv&wEtv",[global])),
+?line <<"*.c3-b.cregb">> = iolist_to_binary(re:replace("*.c3-b.c","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$","&regb",[])),
+?line <<"*.c3-b.cregb">> = iolist_to_binary(re:replace("*.c3-b.c","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$","&regb",[global])),
+?line <<"Vlm">> = iolist_to_binary(re:replace("*.c-a.b-c","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$","Vlm",[])),
+?line <<"Vlm">> = iolist_to_binary(re:replace("*.c-a.b-c","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$","Vlm",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$","Vxm\\1SKnM",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$","Vxm\\1SKnM",[global])),
+?line <<"*.0">> = iolist_to_binary(re:replace("*.0","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$","n\\1",[])),
+?line <<"*.0">> = iolist_to_binary(re:replace("*.0","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$","n\\1",[global])),
+?line <<"*.a-">> = iolist_to_binary(re:replace("*.a-","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$","SbmRQSxio",[])),
+?line <<"*.a-">> = iolist_to_binary(re:replace("*.a-","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$","SbmRQSxio",[global])),
+?line <<"*.a-b.c-">> = iolist_to_binary(re:replace("*.a-b.c-","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$","xINKaLRww\\1&\\1",[])),
+?line <<"*.a-b.c-">> = iolist_to_binary(re:replace("*.a-b.c-","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$","xINKaLRww\\1&\\1",[global])),
+?line <<"*.c-a.0-c">> = iolist_to_binary(re:replace("*.c-a.0-c","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$","akuY\\1pMWNGWjJ\\1oFTV\\1t",[])),
+?line <<"*.c-a.0-c">> = iolist_to_binary(re:replace("*.c-a.0-c","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$","akuY\\1pMWNGWjJ\\1oFTV\\1t",[global])),
+?line <<"Dy">> = iolist_to_binary(re:replace("abde","^(?=ab(de))(abd)(e)","Dy",[])),
+?line <<"Dy">> = iolist_to_binary(re:replace("abde","^(?=ab(de))(abd)(e)","Dy",[global])),
+?line <<"Sf">> = iolist_to_binary(re:replace("abdf","^(?!(ab)de|x)(abd)(f)","Sf",[])),
+?line <<"Sf">> = iolist_to_binary(re:replace("abdf","^(?!(ab)de|x)(abd)(f)","Sf",[global])),
+?line <<"IabcdJcd">> = iolist_to_binary(re:replace("abcd","^(?=(ab(cd)))(ab)","I\\1J",[])),
+?line <<"IabcdJcd">> = iolist_to_binary(re:replace("abcd","^(?=(ab(cd)))(ab)","I\\1J",[global])),
+?line <<"rvnE.d">> = iolist_to_binary(re:replace("a.b.c.d","^[\\da-f](\\.[\\da-f])*$","rvnE\\1",[caseless])),
+?line <<"rvnE.d">> = iolist_to_binary(re:replace("a.b.c.d","^[\\da-f](\\.[\\da-f])*$","rvnE\\1",[caseless,
+ global])),
+?line <<"niA.B.C.DL.DCGxjcuA.B.C.DhA.B.C.DT.DA.B.C.D.DM">> = iolist_to_binary(re:replace("A.B.C.D","^[\\da-f](\\.[\\da-f])*$","ni&L\\1CGxjcu&h&T\\1&\\1M",[caseless])),
+?line <<"niA.B.C.DL.DCGxjcuA.B.C.DhA.B.C.DT.DA.B.C.D.DM">> = iolist_to_binary(re:replace("A.B.C.D","^[\\da-f](\\.[\\da-f])*$","ni&L\\1CGxjcu&h&T\\1&\\1M",[caseless,
+ global])),
+?line <<"wARa.b.c.1.2.3.Ca.b.c.1.2.3.C.CpUAa.b.c.1.2.3.Cg">> = iolist_to_binary(re:replace("a.b.c.1.2.3.C","^[\\da-f](\\.[\\da-f])*$","wAR&&\\1pUA&g",[caseless])),
+?line <<"wARa.b.c.1.2.3.Ca.b.c.1.2.3.C.CpUAa.b.c.1.2.3.Cg">> = iolist_to_binary(re:replace("a.b.c.1.2.3.C","^[\\da-f](\\.[\\da-f])*$","wAR&&\\1pUA&g",[caseless,
+ global])),
+?line <<"a">> = iolist_to_binary(re:replace("\"1234\"","^\\\".*\\\"\\s*(;.*)?$","\\1a",[])),
+?line <<"a">> = iolist_to_binary(re:replace("\"1234\"","^\\\".*\\\"\\s*(;.*)?$","\\1a",[global])),
+?line <<"CIv">> = iolist_to_binary(re:replace("\"abcd\" ;","^\\\".*\\\"\\s*(;.*)?$","CIv",[])),
+?line <<"CIv">> = iolist_to_binary(re:replace("\"abcd\" ;","^\\\".*\\\"\\s*(;.*)?$","CIv",[global])),
+?line <<"; rhubarbK">> = iolist_to_binary(re:replace("\"\" ; rhubarb","^\\\".*\\\"\\s*(;.*)?$","\\1K",[])),
+?line <<"; rhubarbK">> = iolist_to_binary(re:replace("\"\" ; rhubarb","^\\\".*\\\"\\s*(;.*)?$","\\1K",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^\\\".*\\\"\\s*(;.*)?$","aWrdsUS\\1QSjQ&dFoGfF",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^\\\".*\\\"\\s*(;.*)?$","aWrdsUS\\1QSjQ&dFoGfF",[global])),
+?line <<"\"1234\" : things">> = iolist_to_binary(re:replace("\"1234\" : things","^\\\".*\\\"\\s*(;.*)?$","khMGlmiUM&d\\1\\1GGb",[])),
+?line <<"\"1234\" : things">> = iolist_to_binary(re:replace("\"1234\" : things","^\\\".*\\\"\\s*(;.*)?$","khMGlmiUM&d\\1\\1GGb",[global])),
+?line <<"ddsaVnvP">> = iolist_to_binary(re:replace("","^$","ddsaVnvP",[])),
+?line <<"ddsaVnvP">> = iolist_to_binary(re:replace("","^$","ddsaVnvP",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^$","d\\1yl\\1chv&DYUrRBp",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^$","d\\1yl\\1chv&DYUrRBp",[global])),
+?line <<"ubIEeu">> = iolist_to_binary(re:replace("ab c"," ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)","ubIEeu",[extended])),
+?line <<"ubIEeu">> = iolist_to_binary(re:replace("ab c"," ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)","ubIEeu",[extended,
+ global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers"," ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)","hTyFd&e\\1&PttRSXjwggW",[extended])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers"," ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)","hTyFd&e\\1&PttRSXjwggW",[extended,
+ global])),
+?line <<"abc">> = iolist_to_binary(re:replace("abc"," ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)","RUKr",[extended])),
+?line <<"abc">> = iolist_to_binary(re:replace("abc"," ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)","RUKr",[extended,
+ global])),
+?line <<"ab cde">> = iolist_to_binary(re:replace("ab cde"," ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)","&wELTyPo&oJqp&vLg\\1T",[extended])),
+?line <<"ab cde">> = iolist_to_binary(re:replace("ab cde"," ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)","&wELTyPo&oJqp&vLg\\1T",[extended,
+ global])),
+?line <<"NNDSkqab cNfQkVqmWj">> = iolist_to_binary(re:replace("ab c","(?x) ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)","NN\\1DSk\\1q&NfQkVqmWj",[])),
+?line <<"NNDSkqab cNfQkVqmWj">> = iolist_to_binary(re:replace("ab c","(?x) ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)","NN\\1DSk\\1q&NfQkVqmWj",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?x) ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)","vkwk\\1js\\1pepFK\\1\\1Wa&g",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?x) ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)","vkwk\\1js\\1pepFK\\1\\1Wa&g",[global])),
+?line <<"abc">> = iolist_to_binary(re:replace("abc","(?x) ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)","\\1&fYSPEB",[])),
+?line <<"abc">> = iolist_to_binary(re:replace("abc","(?x) ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)","\\1&fYSPEB",[global])),
+?line <<"ab cde">> = iolist_to_binary(re:replace("ab cde","(?x) ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)","\\1D\\1\\1\\1by&lUP\\1jTlVc",[])),
+?line <<"ab cde">> = iolist_to_binary(re:replace("ab cde","(?x) ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)","\\1D\\1\\1\\1by&lUP\\1jTlVc",[global])),
+?line <<"Pca bcdDXLbDTDa bcdja bcdTa bcdX">> = iolist_to_binary(re:replace("a bcd","^ a\\ b[c ]d $","Pc&DXLbDTD&j&T&X\\1",[extended])),
+?line <<"Pca bcdDXLbDTDa bcdja bcdTa bcdX">> = iolist_to_binary(re:replace("a bcd","^ a\\ b[c ]d $","Pc&DXLbDTD&j&T&X\\1",[extended,
+ global])),
+?line <<"cbruWa b dWvF">> = iolist_to_binary(re:replace("a b d","^ a\\ b[c ]d $","cbruW&WvF\\1",[extended])),
+?line <<"cbruWa b dWvF">> = iolist_to_binary(re:replace("a b d","^ a\\ b[c ]d $","cbruW&WvF\\1",[extended,
+ global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^ a\\ b[c ]d $","xLsLvmNGGbWjEqU\\1q",[extended])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^ a\\ b[c ]d $","xLsLvmNGGbWjEqU\\1q",[extended,
+ global])),
+?line <<"abcd">> = iolist_to_binary(re:replace("abcd","^ a\\ b[c ]d $","QvID",[extended])),
+?line <<"abcd">> = iolist_to_binary(re:replace("abcd","^ a\\ b[c ]d $","QvID",[extended,
+ global])),
+?line <<"ab d">> = iolist_to_binary(re:replace("ab d","^ a\\ b[c ]d $","CEUu&Jt",[extended])),
+?line <<"ab d">> = iolist_to_binary(re:replace("ab d","^ a\\ b[c ]d $","CEUu&Jt",[extended,
+ global])),
+?line <<"ohu">> = iolist_to_binary(re:replace("abcdefhijklm","^(a(b(c)))(d(e(f)))(h(i(j)))(k(l(m)))$","ohu",[])),
+?line <<"ohu">> = iolist_to_binary(re:replace("abcdefhijklm","^(a(b(c)))(d(e(f)))(h(i(j)))(k(l(m)))$","ohu",[global])),
+?line <<"rbcmNabcdefhijklmabcdefhijklmNGkLNbcabcdefhijklmxnbclO">> = iolist_to_binary(re:replace("abcdefhijklm","^(?:a(b(c)))(?:d(e(f)))(?:h(i(j)))(?:k(l(m)))$","r\\1mN&&NGkLN\\1&xn\\1lO",[])),
+?line <<"rbcmNabcdefhijklmabcdefhijklmNGkLNbcabcdefhijklmxnbclO">> = iolist_to_binary(re:replace("abcdefhijklm","^(?:a(b(c)))(?:d(e(f)))(?:h(i(j)))(?:k(l(m)))$","r\\1mN&&NGkLN\\1&xn\\1lO",[global])),
+?line <<"I">> = iolist_to_binary(re:replace("a+ Z0+
+","^[\\w][\\W][\\s][\\S][\\d][\\D][\\b][\\n][\\c]][\\022]","I",[])),
+?line <<"I">> = iolist_to_binary(re:replace("a+ Z0+
+","^[\\w][\\W][\\s][\\S][\\d][\\D][\\b][\\n][\\c]][\\022]","I",[global])),
+?line <<"ANdwkyHnc">> = iolist_to_binary(re:replace(".^$(*+)|{?,?}","^[.^$|()*+?{,}]+","ANdwkyHnc",[])),
+?line <<"ANdwkyHnc">> = iolist_to_binary(re:replace(".^$(*+)|{?,?}","^[.^$|()*+?{,}]+","ANdwkyHnc",[global])),
+?line <<"Dx">> = iolist_to_binary(re:replace("z","^a*\\w","Dx",[])),
+?line <<"Dx">> = iolist_to_binary(re:replace("z","^a*\\w","Dx",[global])),
+?line <<"OpVTjQkTaz">> = iolist_to_binary(re:replace("az","^a*\\w","OpVTjQkT&",[])),
+?line <<"OpVTjQkTaz">> = iolist_to_binary(re:replace("az","^a*\\w","OpVTjQkT&",[global])),
+?line <<"LexbuooAmFDifW">> = iolist_to_binary(re:replace("aaaz","^a*\\w","LexbuooAm\\1FDifW",[])),
+?line <<"LexbuooAmFDifW">> = iolist_to_binary(re:replace("aaaz","^a*\\w","LexbuooAm\\1FDifW",[global])),
+?line <<"arpLCDAadYpPkb">> = iolist_to_binary(re:replace("a","^a*\\w","arpLCDAadYpPk\\1b",[])),
+?line <<"arpLCDAadYpPkb">> = iolist_to_binary(re:replace("a","^a*\\w","arpLCDAadYpPk\\1b",[global])),
+?line <<"CyElaaTHfV">> = iolist_to_binary(re:replace("aa","^a*\\w","CyEl&T\\1HfV",[])),
+?line <<"CyElaaTHfV">> = iolist_to_binary(re:replace("aa","^a*\\w","CyEl&T\\1HfV",[global])),
+?line <<"v">> = iolist_to_binary(re:replace("aaaa","^a*\\w","v\\1\\1",[])),
+?line <<"v">> = iolist_to_binary(re:replace("aaaa","^a*\\w","v\\1\\1",[global])),
+?line <<"COSWtMTXCLic+">> = iolist_to_binary(re:replace("a+","^a*\\w","COSWtMTXCLic",[])),
+?line <<"COSWtMTXCLic+">> = iolist_to_binary(re:replace("a+","^a*\\w","COSWtMTXCLic",[global])),
+?line <<"kaaDuaauKGaaIaaFUK+">> = iolist_to_binary(re:replace("aa+","^a*\\w","k&Du&uKG\\1&I&FU\\1\\1K\\1",[])),
+?line <<"kaaDuaauKGaaIaaFUK+">> = iolist_to_binary(re:replace("aa+","^a*\\w","k&Du&uKG\\1&I&FU\\1\\1K\\1",[global])),
+?line <<"Pttz">> = iolist_to_binary(re:replace("z","^a*?\\w","Ptt&",[])),
+?line <<"Pttz">> = iolist_to_binary(re:replace("z","^a*?\\w","Ptt&",[global])),
+?line <<"QEHxyFSkkaz">> = iolist_to_binary(re:replace("az","^a*?\\w","QEHxyFSkk&",[])),
+?line <<"QEHxyFSkkaz">> = iolist_to_binary(re:replace("az","^a*?\\w","QEHxyFSkk&",[global])),
+?line <<"atHEjpaKrKaaz">> = iolist_to_binary(re:replace("aaaz","^a*?\\w","&tHE\\1jp&KrK",[])),
+?line <<"atHEjpaKrKaaz">> = iolist_to_binary(re:replace("aaaz","^a*?\\w","&tHE\\1jp&KrK",[global])),
+?line <<"YaSeqaaeBiLO">> = iolist_to_binary(re:replace("a","^a*?\\w","Y&Seq\\1&&eBiLO",[])),
+?line <<"YaSeqaaeBiLO">> = iolist_to_binary(re:replace("a","^a*?\\w","Y&Seq\\1&&eBiLO",[global])),
+?line <<"UlaGeGnImSoQaHibARka">> = iolist_to_binary(re:replace("aa","^a*?\\w","Ul&GeGnImSoQ&HibARk",[])),
+?line <<"UlaGeGnImSoQaHibARka">> = iolist_to_binary(re:replace("aa","^a*?\\w","Ul&GeGnImSoQ&HibARk",[global])),
+?line <<"upDbxncvqbwvaaa">> = iolist_to_binary(re:replace("aaaa","^a*?\\w","upDbxncvqb\\1wv",[])),
+?line <<"upDbxncvqbwvaaa">> = iolist_to_binary(re:replace("aaaa","^a*?\\w","upDbxncvqb\\1wv",[global])),
+?line <<"MalqdUPrj+">> = iolist_to_binary(re:replace("a+","^a*?\\w","M&\\1lqdUPr\\1j\\1\\1",[])),
+?line <<"MalqdUPrj+">> = iolist_to_binary(re:replace("a+","^a*?\\w","M&\\1lqdUPr\\1j\\1\\1",[global])),
+?line <<"JTa+">> = iolist_to_binary(re:replace("aa+","^a*?\\w","JT",[])),
+?line <<"JTa+">> = iolist_to_binary(re:replace("aa+","^a*?\\w","JT",[global])),
+?line <<"nnvJUazdlV">> = iolist_to_binary(re:replace("az","^a+\\w","\\1nnvJU&dlV",[])),
+?line <<"nnvJUazdlV">> = iolist_to_binary(re:replace("az","^a+\\w","\\1nnvJU&dlV",[global])),
+?line <<"aaaz">> = iolist_to_binary(re:replace("aaaz","^a+\\w","\\1&",[])),
+?line <<"aaaz">> = iolist_to_binary(re:replace("aaaz","^a+\\w","\\1&",[global])),
+?line <<"daaRBaauOlL">> = iolist_to_binary(re:replace("aa","^a+\\w","d&RB&uO\\1lL",[])),
+?line <<"daaRBaauOlL">> = iolist_to_binary(re:replace("aa","^a+\\w","d&RB&uO\\1lL",[global])),
+?line <<"uaaaajkPXJqfBddNNYaaaa">> = iolist_to_binary(re:replace("aaaa","^a+\\w","u&jkPXJqfBddNNY&",[])),
+?line <<"uaaaajkPXJqfBddNNYaaaa">> = iolist_to_binary(re:replace("aaaa","^a+\\w","u&jkPXJqfBddNNY&",[global])),
+?line <<"YAJlePYgQb+">> = iolist_to_binary(re:replace("aa+","^a+\\w","YAJlePYgQb",[])),
+?line <<"YAJlePYgQb+">> = iolist_to_binary(re:replace("aa+","^a+\\w","YAJlePYgQb",[global])),
+?line <<"MXsW">> = iolist_to_binary(re:replace("az","^a+?\\w","MXsW",[])),
+?line <<"MXsW">> = iolist_to_binary(re:replace("az","^a+?\\w","MXsW",[global])),
+?line <<"GaaMGsaaPiMScaz">> = iolist_to_binary(re:replace("aaaz","^a+?\\w","G&MGs&P\\1i\\1MSc",[])),
+?line <<"GaaMGsaaPiMScaz">> = iolist_to_binary(re:replace("aaaz","^a+?\\w","G&MGs&P\\1i\\1MSc",[global])),
+?line <<"aaYUHgT">> = iolist_to_binary(re:replace("aa","^a+?\\w","&YUHgT",[])),
+?line <<"aaYUHgT">> = iolist_to_binary(re:replace("aa","^a+?\\w","&YUHgT",[global])),
+?line <<"ePknVhaa">> = iolist_to_binary(re:replace("aaaa","^a+?\\w","ePknVh\\1",[])),
+?line <<"ePknVhaa">> = iolist_to_binary(re:replace("aaaa","^a+?\\w","ePknVh\\1",[global])),
+?line <<"+">> = iolist_to_binary(re:replace("aa+","^a+?\\w","\\1",[])),
+?line <<"+">> = iolist_to_binary(re:replace("aa+","^a+?\\w","\\1",[global])),
+?line <<"AFRGuhtn1234567890rEtjU">> = iolist_to_binary(re:replace("1234567890","^\\d{8}\\w{2,}","\\1AFRGuhtn&rEtjU",[])),
+?line <<"AFRGuhtn1234567890rEtjU">> = iolist_to_binary(re:replace("1234567890","^\\d{8}\\w{2,}","\\1AFRGuhtn&rEtjU",[global])),
+?line <<"nNSL12345678abRY">> = iolist_to_binary(re:replace("12345678ab","^\\d{8}\\w{2,}","nNSL&RY",[])),
+?line <<"nNSL12345678abRY">> = iolist_to_binary(re:replace("12345678ab","^\\d{8}\\w{2,}","nNSL&RY",[global])),
+?line <<"12345678__JUDy">> = iolist_to_binary(re:replace("12345678__","^\\d{8}\\w{2,}","&JUDy",[])),
+?line <<"12345678__JUDy">> = iolist_to_binary(re:replace("12345678__","^\\d{8}\\w{2,}","&JUDy",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^\\d{8}\\w{2,}","&OcK\\1P&XNvgrP",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^\\d{8}\\w{2,}","&OcK\\1P&XNvgrP",[global])),
+?line <<"1234567">> = iolist_to_binary(re:replace("1234567","^\\d{8}\\w{2,}","&Mo",[])),
+?line <<"1234567">> = iolist_to_binary(re:replace("1234567","^\\d{8}\\w{2,}","&Mo",[global])),
+?line <<"O">> = iolist_to_binary(re:replace("uoie","^[aeiou\\d]{4,5}$","O",[])),
+?line <<"O">> = iolist_to_binary(re:replace("uoie","^[aeiou\\d]{4,5}$","O",[global])),
+?line <<"1234b1234n">> = iolist_to_binary(re:replace("1234","^[aeiou\\d]{4,5}$","&b&n",[])),
+?line <<"1234b1234n">> = iolist_to_binary(re:replace("1234","^[aeiou\\d]{4,5}$","&b&n",[global])),
+?line <<"YBp12345Ul">> = iolist_to_binary(re:replace("12345","^[aeiou\\d]{4,5}$","YBp&Ul",[])),
+?line <<"YBp12345Ul">> = iolist_to_binary(re:replace("12345","^[aeiou\\d]{4,5}$","YBp&Ul",[global])),
+?line <<"SVHQqBtcrMAtQxy">> = iolist_to_binary(re:replace("aaaaa","^[aeiou\\d]{4,5}$","SVHQqBtcrMAtQxy\\1",[])),
+?line <<"SVHQqBtcrMAtQxy">> = iolist_to_binary(re:replace("aaaaa","^[aeiou\\d]{4,5}$","SVHQqBtcrMAtQxy\\1",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^[aeiou\\d]{4,5}$","ne",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^[aeiou\\d]{4,5}$","ne",[global])),
+?line <<"123456">> = iolist_to_binary(re:replace("123456","^[aeiou\\d]{4,5}$","QA&F\\1LJ",[])),
+?line <<"123456">> = iolist_to_binary(re:replace("123456","^[aeiou\\d]{4,5}$","QA&F\\1LJ",[global])),
+?line <<"gKGpFvTeUK">> = iolist_to_binary(re:replace("uoie","^[aeiou\\d]{4,5}?","gKGpFvTeUK",[])),
+?line <<"gKGpFvTeUK">> = iolist_to_binary(re:replace("uoie","^[aeiou\\d]{4,5}?","gKGpFvTeUK",[global])),
+?line <<"LCEqvLxHGWXWrexD">> = iolist_to_binary(re:replace("1234","^[aeiou\\d]{4,5}?","LCE\\1qvL\\1xHGWXWrexD",[])),
+?line <<"LCEqvLxHGWXWrexD">> = iolist_to_binary(re:replace("1234","^[aeiou\\d]{4,5}?","LCE\\1qvL\\1xHGWXWrexD",[global])),
+?line <<"QWV1234vhndnkkT1234l5">> = iolist_to_binary(re:replace("12345","^[aeiou\\d]{4,5}?","\\1QWV&\\1vhndnkk\\1T&l",[])),
+?line <<"QWV1234vhndnkkT1234l5">> = iolist_to_binary(re:replace("12345","^[aeiou\\d]{4,5}?","\\1QWV&\\1vhndnkk\\1T&l",[global])),
+?line <<"aaaaIaaaayaaaaEoAPYra">> = iolist_to_binary(re:replace("aaaaa","^[aeiou\\d]{4,5}?","&I&y&E\\1oAPYr",[])),
+?line <<"aaaaIaaaayaaaaEoAPYra">> = iolist_to_binary(re:replace("aaaaa","^[aeiou\\d]{4,5}?","&I&y&E\\1oAPYr",[global])),
+?line <<"xKUWgRs56">> = iolist_to_binary(re:replace("123456","^[aeiou\\d]{4,5}?","xKUWgRs",[])),
+?line <<"xKUWgRs56">> = iolist_to_binary(re:replace("123456","^[aeiou\\d]{4,5}?","xKUWgRs",[global])),
+?line <<"JlUywcabcvRabcPFPabcYSXE">> = iolist_to_binary(re:replace("abc=abcabc","\\A(abc|def)=(\\1){2,3}\\Z","JlUywc\\1vR\\1PFP\\1YSXE",[])),
+?line <<"JlUywcabcvRabcPFPabcYSXE">> = iolist_to_binary(re:replace("abc=abcabc","\\A(abc|def)=(\\1){2,3}\\Z","JlUywc\\1vR\\1PFP\\1YSXE",[global])),
+?line <<"def=defdefdefbucdef=defdefdef">> = iolist_to_binary(re:replace("def=defdefdef","\\A(abc|def)=(\\1){2,3}\\Z","&buc&",[])),
+?line <<"def=defdefdefbucdef=defdefdef">> = iolist_to_binary(re:replace("def=defdefdef","\\A(abc|def)=(\\1){2,3}\\Z","&buc&",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","\\A(abc|def)=(\\1){2,3}\\Z","AYuyHUCDlwjQc\\1OS",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","\\A(abc|def)=(\\1){2,3}\\Z","AYuyHUCDlwjQc\\1OS",[global])),
+?line <<"abc=defdef">> = iolist_to_binary(re:replace("abc=defdef","\\A(abc|def)=(\\1){2,3}\\Z","PM&h\\1\\1xD\\1&",[])),
+?line <<"abc=defdef">> = iolist_to_binary(re:replace("abc=defdef","\\A(abc|def)=(\\1){2,3}\\Z","PM&h\\1\\1xD\\1&",[global])),
+?line <<"UFhaagoHObvFc">> = iolist_to_binary(re:replace("abcdefghijkcda2","^(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\\11*(\\3\\4)\\1(?#)2$","UFh\\1\\1goHObvFc",[])),
+?line <<"UFhaagoHObvFc">> = iolist_to_binary(re:replace("abcdefghijkcda2","^(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\\11*(\\3\\4)\\1(?#)2$","UFh\\1\\1goHObvFc",[global])),
+?line <<"aabcdefghijkkkkcda2abcdefghijkkkkcda2abcdefghijkkkkcda2vuYabcdefghijkkkkcda2xdabcdefghijkkkkcda2njaJQEF">> = iolist_to_binary(re:replace("abcdefghijkkkkcda2","^(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\\11*(\\3\\4)\\1(?#)2$","\\1&&&vuY&xd&nj\\1JQEF",[])),
+?line <<"aabcdefghijkkkkcda2abcdefghijkkkkcda2abcdefghijkkkkcda2vuYabcdefghijkkkkcda2xdabcdefghijkkkkcda2njaJQEF">> = iolist_to_binary(re:replace("abcdefghijkkkkcda2","^(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\\11*(\\3\\4)\\1(?#)2$","\\1&&&vuY&xd&nj\\1JQEF",[global])),
+?line <<"mcataractcataract cataract23YTkMcataract cataract23">> = iolist_to_binary(re:replace("cataract cataract23","(cat(a(ract|tonic)|erpillar)) \\1()2(3)","m\\1&YTkM&",[])),
+?line <<"mcataractcataract cataract23YTkMcataract cataract23">> = iolist_to_binary(re:replace("cataract cataract23","(cat(a(ract|tonic)|erpillar)) \\1()2(3)","m\\1&YTkM&",[global])),
+?line <<"OXcatatonicoHKaXHQpryKFyhVcatatonic">> = iolist_to_binary(re:replace("catatonic catatonic23","(cat(a(ract|tonic)|erpillar)) \\1()2(3)","OX\\1oHKaXHQpryKFyhV\\1",[])),
+?line <<"OXcatatonicoHKaXHQpryKFyhVcatatonic">> = iolist_to_binary(re:replace("catatonic catatonic23","(cat(a(ract|tonic)|erpillar)) \\1()2(3)","OX\\1oHKaXHQpryKFyhV\\1",[global])),
+?line <<"caterpillarcaterpillar caterpillar23foVlhvplLSebcaterpillar">> = iolist_to_binary(re:replace("caterpillar caterpillar23","(cat(a(ract|tonic)|erpillar)) \\1()2(3)","\\1&foVlhvplLSeb\\1",[])),
+?line <<"caterpillarcaterpillar caterpillar23foVlhvplLSebcaterpillar">> = iolist_to_binary(re:replace("caterpillar caterpillar23","(cat(a(ract|tonic)|erpillar)) \\1()2(3)","\\1&foVlhvplLSeb\\1",[global])),
+?line <<"From abcd Mon Sep 01 12:33TNVlANgYabcdabcdFrom abcd Mon Sep 01 12:33aIFrom abcd Mon Sep 01 12:33TqsabcdQ:02 1997">> = iolist_to_binary(re:replace("From abcd Mon Sep 01 12:33:02 1997","^From +([^ ]+) +[a-zA-Z][a-zA-Z][a-zA-Z] +[a-zA-Z][a-zA-Z][a-zA-Z] +[0-9]?[0-9] +[0-9][0-9]:[0-9][0-9]","&TNVlANgY\\1\\1&aI&Tqs\\1Q",[])),
+?line <<"From abcd Mon Sep 01 12:33TNVlANgYabcdabcdFrom abcd Mon Sep 01 12:33aIFrom abcd Mon Sep 01 12:33TqsabcdQ:02 1997">> = iolist_to_binary(re:replace("From abcd Mon Sep 01 12:33:02 1997","^From +([^ ]+) +[a-zA-Z][a-zA-Z][a-zA-Z] +[a-zA-Z][a-zA-Z][a-zA-Z] +[0-9]?[0-9] +[0-9][0-9]:[0-9][0-9]","&TNVlANgY\\1\\1&aI&Tqs\\1Q",[global])),
+?line <<"isKrFrom abcd Mon Sep 01 12:33:02 1997">> = iolist_to_binary(re:replace("From abcd Mon Sep 01 12:33:02 1997","^From\\s+\\S+\\s+([a-zA-Z]{3}\\s+){2}\\d{1,2}\\s+\\d\\d:\\d\\d","isKr&",[])),
+?line <<"isKrFrom abcd Mon Sep 01 12:33:02 1997">> = iolist_to_binary(re:replace("From abcd Mon Sep 01 12:33:02 1997","^From\\s+\\S+\\s+([a-zA-Z]{3}\\s+){2}\\d{1,2}\\s+\\d\\d:\\d\\d","isKr&",[global])),
+?line <<"lNtEJS:02 1997">> = iolist_to_binary(re:replace("From abcd Mon Sep 1 12:33:02 1997","^From\\s+\\S+\\s+([a-zA-Z]{3}\\s+){2}\\d{1,2}\\s+\\d\\d:\\d\\d","lNtEJS",[])),
+?line <<"lNtEJS:02 1997">> = iolist_to_binary(re:replace("From abcd Mon Sep 1 12:33:02 1997","^From\\s+\\S+\\s+([a-zA-Z]{3}\\s+){2}\\d{1,2}\\s+\\d\\d:\\d\\d","lNtEJS",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^From\\s+\\S+\\s+([a-zA-Z]{3}\\s+){2}\\d{1,2}\\s+\\d\\d:\\d\\d","aR\\1i&Fxe",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^From\\s+\\S+\\s+([a-zA-Z]{3}\\s+){2}\\d{1,2}\\s+\\d\\d:\\d\\d","aR\\1i&Fxe",[global])),
+?line <<"From abcd Sep 01 12:33:02 1997">> = iolist_to_binary(re:replace("From abcd Sep 01 12:33:02 1997","^From\\s+\\S+\\s+([a-zA-Z]{3}\\s+){2}\\d{1,2}\\s+\\d\\d:\\d\\d","\\1NsrJ&\\1&PtWlXT",[])),
+?line <<"From abcd Sep 01 12:33:02 1997">> = iolist_to_binary(re:replace("From abcd Sep 01 12:33:02 1997","^From\\s+\\S+\\s+([a-zA-Z]{3}\\s+){2}\\d{1,2}\\s+\\d\\d:\\d\\d","\\1NsrJ&\\1&PtWlXT",[global])),
+?line <<"nGixKixjMO12
+34BhoReSp">> = iolist_to_binary(re:replace("12
+34","^12.34","nGixKixjMO&BhoReSp",[dotall])),
+?line <<"nGixKixjMO12
+34BhoReSp">> = iolist_to_binary(re:replace("12
+34","^12.34","nGixKixjMO&BhoReSp",[dotall,global])),
+?line <<"12 34OBfpF12 3412 34fh">> = iolist_to_binary(re:replace("12 34","^12.34","&OBfpF&&fh",[dotall])),
+?line <<"12 34OBfpF12 3412 34fh">> = iolist_to_binary(re:replace("12 34","^12.34","&OBfpF&&fh",[dotall,
+ global])),
+?line <<"the quick brownhubrownbrownubrownQ fox">> = iolist_to_binary(re:replace("the quick brown fox","\\w+(?=\\t)","&hu&&u&Q",[])),
+?line <<"the quick brownhubrownbrownubrownQ fox">> = iolist_to_binary(re:replace("the quick brown fox","\\w+(?=\\t)","&hu&&u&Q",[global])),
+?line <<"foobar is uqH">> = iolist_to_binary(re:replace("foobar is foolish see?","foo(?!bar)(.*)","uqH",[])),
+?line <<"foobar is uqH">> = iolist_to_binary(re:replace("foobar is foolish see?","foo(?!bar)(.*)","uqH",[global])),
+?line <<"foobar cn">> = iolist_to_binary(re:replace("foobar crowbar etc","(?:(?!foo)...|^.{0,2})bar(.*)","n",[])),
+?line <<"foobar cn">> = iolist_to_binary(re:replace("foobar crowbar etc","(?:(?!foo)...|^.{0,2})bar(.*)","n",[global])),
+?line <<"CpDjibh">> = iolist_to_binary(re:replace("barrel","(?:(?!foo)...|^.{0,2})bar(.*)","CpDjibh",[])),
+?line <<"CpDjibh">> = iolist_to_binary(re:replace("barrel","(?:(?!foo)...|^.{0,2})bar(.*)","CpDjibh",[global])),
+?line <<"wlcfLrelprelgrelD">> = iolist_to_binary(re:replace("2barrel","(?:(?!foo)...|^.{0,2})bar(.*)","wlcfL\\1p\\1g\\1D",[])),
+?line <<"wlcfLrelprelgrelD">> = iolist_to_binary(re:replace("2barrel","(?:(?!foo)...|^.{0,2})bar(.*)","wlcfL\\1p\\1g\\1D",[global])),
+?line <<"wbDA barrelYA barrelcQA barrelplrelA barrelXPrel">> = iolist_to_binary(re:replace("A barrel","(?:(?!foo)...|^.{0,2})bar(.*)","wbD&Y&cQ&pl\\1&XP\\1",[])),
+?line <<"wbDA barrelYA barrelcQA barrelplrelA barrelXPrel">> = iolist_to_binary(re:replace("A barrel","(?:(?!foo)...|^.{0,2})bar(.*)","wbD&Y&cQ&pl\\1&XP\\1",[global])),
+?line <<"PJMqUabctmoSPC456">> = iolist_to_binary(re:replace("abc456","^(\\D*)(?=\\d)(?!123)","PJMqU\\1tmoSPC",[])),
+?line <<"PJMqUabctmoSPC456">> = iolist_to_binary(re:replace("abc456","^(\\D*)(?=\\d)(?!123)","PJMqU\\1tmoSPC",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(\\D*)(?=\\d)(?!123)","k\\1&lgXOi",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(\\D*)(?=\\d)(?!123)","k\\1&lgXOi",[global])),
+?line <<"abc123">> = iolist_to_binary(re:replace("abc123","^(\\D*)(?=\\d)(?!123)","UgE&XTVNX&ygyaQdYO&",[])),
+?line <<"abc123">> = iolist_to_binary(re:replace("abc123","^(\\D*)(?=\\d)(?!123)","UgE&XTVNX&ygyaQdYO&",[global])),
+?line <<"CByu1234Oj12341234">> = iolist_to_binary(re:replace("1234","^1234(?# test newlines
+ inside)","CByu&Oj&&",[])),
+?line <<"CByu1234Oj12341234">> = iolist_to_binary(re:replace("1234","^1234(?# test newlines
+ inside)","CByu&Oj&&",[global])),
+?line <<"AVF1234DSEvHi">> = iolist_to_binary(re:replace("1234","^1234 #comment in extended re
+ ","AVF&DSEvHi",[extended])),
+?line <<"AVF1234DSEvHi">> = iolist_to_binary(re:replace("1234","^1234 #comment in extended re
+ ","AVF&DSEvHi",[extended,global])),
+?line <<"wiUNsYJdROkkkabcdSabcdjvS">> = iolist_to_binary(re:replace("abcd","#rhubarb
+ abcd","wiUNsYJdROkkk&S&jvS",[extended])),
+?line <<"wiUNsYJdROkkkabcdSabcdjvS">> = iolist_to_binary(re:replace("abcd","#rhubarb
+ abcd","wiUNsYJdROkkk&S&jvS",[extended,global])),
+?line <<"wxabcdyOpSDe">> = iolist_to_binary(re:replace("abcd","^abcd#rhubarb","wx&yOpSDe",[extended])),
+?line <<"wxabcdyOpSDe">> = iolist_to_binary(re:replace("abcd","^abcd#rhubarb","wx&yOpSDe",[extended,
+ global])),
+?line <<"aqfaaaab">> = iolist_to_binary(re:replace("aaab","^(a)\\1{2,3}(.)","\\1qf\\1&",[])),
+?line <<"aqfaaaab">> = iolist_to_binary(re:replace("aaab","^(a)\\1{2,3}(.)","\\1qf\\1&",[global])),
+?line <<"aLGaaaabhavaLLxaIaaaabJaaaabidaaaab">> = iolist_to_binary(re:replace("aaaab","^(a)\\1{2,3}(.)","\\1LG&h\\1v\\1LLx\\1I&J&id&",[])),
+?line <<"aLGaaaabhavaLLxaIaaaabJaaaabidaaaab">> = iolist_to_binary(re:replace("aaaab","^(a)\\1{2,3}(.)","\\1LG&h\\1v\\1LLx\\1I&J&id&",[global])),
+?line <<"aaaaaEaaaaagaawPOaNaaaaab">> = iolist_to_binary(re:replace("aaaaab","^(a)\\1{2,3}(.)","&E&g\\1\\1wPO\\1N&",[])),
+?line <<"aaaaaEaaaaagaawPOaNaaaaab">> = iolist_to_binary(re:replace("aaaaab","^(a)\\1{2,3}(.)","&E&g\\1\\1wPO\\1N&",[global])),
+?line <<"QwegtaHxecVVVaaaaaab">> = iolist_to_binary(re:replace("aaaaaab","^(a)\\1{2,3}(.)","QwegtaHxecVVV&",[])),
+?line <<"QwegtaHxecVVVaaaaaab">> = iolist_to_binary(re:replace("aaaaaab","^(a)\\1{2,3}(.)","QwegtaHxecVVV&",[global])),
+?line <<"the EcabcmU">> = iolist_to_binary(re:replace("the abc","(?!^)abc","Ec&mU",[])),
+?line <<"the EcabcmU">> = iolist_to_binary(re:replace("the abc","(?!^)abc","Ec&mU",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?!^)abc","NA",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?!^)abc","NA",[global])),
+?line <<"abc">> = iolist_to_binary(re:replace("abc","(?!^)abc","yjhaoMMFW\\1",[])),
+?line <<"abc">> = iolist_to_binary(re:replace("abc","(?!^)abc","yjhaoMMFW\\1",[global])),
+?line <<"PKCfTNYlWMooD">> = iolist_to_binary(re:replace("abc","(?=^)abc","\\1PK\\1CfTNYlWMooD",[])),
+?line <<"PKCfTNYlWMooD">> = iolist_to_binary(re:replace("abc","(?=^)abc","\\1PK\\1CfTNYlWMooD",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?=^)abc","fR\\1ltffBHNVYixMX",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?=^)abc","fR\\1ltffBHNVYixMX",[global])),
+?line <<"the abc">> = iolist_to_binary(re:replace("the abc","(?=^)abc","L\\1JJFtgfU&l",[])),
+?line <<"the abc">> = iolist_to_binary(re:replace("the abc","(?=^)abc","L\\1JJFtgfU&l",[global])),
+?line <<"aabbvbOdaabbyVtUjIbqObbbb">> = iolist_to_binary(re:replace("aabbbbb","^[ab]{1,3}(ab*|b)","&v\\1Od&yVtUjI\\1qO\\1",[])),
+?line <<"aabbvbOdaabbyVtUjIbqObbbb">> = iolist_to_binary(re:replace("aabbbbb","^[ab]{1,3}(ab*|b)","&v\\1Od&yVtUjI\\1qO\\1",[global])),
+?line <<"PLPJVxaabbbbbYrEOEywwHFp">> = iolist_to_binary(re:replace("aabbbbb","^[ab]{1,3}?(ab*|b)","PLPJVxa\\1YrEOEywwHFp",[])),
+?line <<"PLPJVxaabbbbbYrEOEywwHFp">> = iolist_to_binary(re:replace("aabbbbb","^[ab]{1,3}?(ab*|b)","PLPJVxa\\1YrEOEywwHFp",[global])),
+?line <<"VmghaaMBBitDaaaRnWKaaaAbbbbb">> = iolist_to_binary(re:replace("aabbbbb","^[ab]{1,3}?(ab*?|b)","Vmgh&MBBitD&\\1RnWK&\\1A",[])),
+?line <<"VmghaaMBBitDaaaRnWKaaaAbbbbb">> = iolist_to_binary(re:replace("aabbbbb","^[ab]{1,3}?(ab*?|b)","Vmgh&MBBitD&\\1RnWK&\\1A",[global])),
+?line <<"baabblNbbLhaabbtbbb">> = iolist_to_binary(re:replace("aabbbbb","^[ab]{1,3}(ab*?|b)","\\1&lNb\\1Lh&t",[])),
+?line <<"baabblNbbLhaabbtbbb">> = iolist_to_binary(re:replace("aabbbbb","^[ab]{1,3}(ab*?|b)","\\1&lNb\\1Lh&t",[global])),
+?line <<"Alan Other <user.ain>">> = iolist_to_binary(re:replace("Alan Other <user.ain>"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment","Ag",[extended])),
+?line <<"Alan Other <user.ain>">> = iolist_to_binary(re:replace("Alan Other <user.ain>"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment","Ag",[extended,
+ global])),
+?line <<"<user.ain>">> = iolist_to_binary(re:replace("<user.ain>"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment","OcN\\1",[extended])),
+?line <<"<user.ain>">> = iolist_to_binary(re:replace("<user.ain>"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment","OcN\\1",[extended,
+ global])),
+?line <<"user.ain">> = iolist_to_binary(re:replace("user.ain"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment","P\\1\\1",[extended])),
+?line <<"user.ain">> = iolist_to_binary(re:replace("user.ain"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment","P\\1\\1",[extended,
+ global])),
+?line <<"\"A. Other\" <user.1234.ain> (a comment)">> = iolist_to_binary(re:replace("\"A. Other\" <user.1234.ain> (a comment)"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment","tFTD&XMAPNeq",[extended])),
+?line <<"\"A. Other\" <user.1234.ain> (a comment)">> = iolist_to_binary(re:replace("\"A. Other\" <user.1234.ain> (a comment)"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment","tFTD&XMAPNeq",[extended,
+ global])),
+?line <<"A. Other <user.1234.ain> (a comment)">> = iolist_to_binary(re:replace("A. Other <user.1234.ain> (a comment)"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment","c\\1&C&YTXnfnhWs\\1g",[extended])),
+?line <<"A. Other <user.1234.ain> (a comment)">> = iolist_to_binary(re:replace("A. Other <user.1234.ain> (a comment)"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment","c\\1&C&YTXnfnhWs\\1g",[extended,
+ global])),
+?line <<"\"/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/\"-re.lay">> = iolist_to_binary(re:replace("\"/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/\"-re.lay"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment","\\1R&P&\\1aCnlgH",[extended])),
+?line <<"\"/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/\"-re.lay">> = iolist_to_binary(re:replace("\"/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/\"-re.lay"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment","\\1R&P&\\1aCnlgH",[extended,
+ global])),
+?line <<"A missing angle <user.where">> = iolist_to_binary(re:replace("A missing angle <user.where"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment","p\\1u\\1REy&",[extended])),
+?line <<"A missing angle <user.where">> = iolist_to_binary(re:replace("A missing angle <user.where"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment","p\\1u\\1REy&",[extended,
+ global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment","qytCjuWj\\1fpNNv\\1&ya",[extended])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment","qytCjuWj\\1fpNNv\\1&ya",[extended,
+ global])),
+?line <<"The quick brown fox">> = iolist_to_binary(re:replace("The quick brown fox"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment","L",[extended])),
+?line <<"The quick brown fox">> = iolist_to_binary(re:replace("The quick brown fox"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment","L",[extended,
+ global])),
+?line <<"Alan Other <user.ain>">> = iolist_to_binary(re:replace("Alan Other <user.ain>","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)","\\1",[extended])),
+?line <<"Alan Other <user.ain>">> = iolist_to_binary(re:replace("Alan Other <user.ain>","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)","\\1",[extended,global])),
+?line <<"<user.ain>">> = iolist_to_binary(re:replace("<user.ain>","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)","On",[extended])),
+?line <<"<user.ain>">> = iolist_to_binary(re:replace("<user.ain>","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)","On",[extended,global])),
+?line <<"user.ain">> = iolist_to_binary(re:replace("user.ain","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)","OLL\\1TqepmsD\\1V\\1\\1h\\1DsD",[extended])),
+?line <<"user.ain">> = iolist_to_binary(re:replace("user.ain","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)","OLL\\1TqepmsD\\1V\\1\\1h\\1DsD",[extended,global])),
+?line <<"\"A. Other\" <user.1234.ain> (a comment)">> = iolist_to_binary(re:replace("\"A. Other\" <user.1234.ain> (a comment)","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)","SHuKuC\\1Td",[extended])),
+?line <<"\"A. Other\" <user.1234.ain> (a comment)">> = iolist_to_binary(re:replace("\"A. Other\" <user.1234.ain> (a comment)","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)","SHuKuC\\1Td",[extended,global])),
+?line <<"A. Other <user.1234.ain> (a comment)">> = iolist_to_binary(re:replace("A. Other <user.1234.ain> (a comment)","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)","D&t&LSQGMfQpSXj",[extended])),
+?line <<"A. Other <user.1234.ain> (a comment)">> = iolist_to_binary(re:replace("A. Other <user.1234.ain> (a comment)","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)","D&t&LSQGMfQpSXj",[extended,global])),
+?line <<"\"/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/\"-re.lay">> = iolist_to_binary(re:replace("\"/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/\"-re.lay","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)","qDSGw",[extended])),
+?line <<"\"/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/\"-re.lay">> = iolist_to_binary(re:replace("\"/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/\"-re.lay","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)","qDSGw",[extended,global])),
+?line <<"A missing angle <user.where">> = iolist_to_binary(re:replace("A missing angle <user.where","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)","SOYovQniOUVJIil\\1",[extended])),
+?line <<"A missing angle <user.where">> = iolist_to_binary(re:replace("A missing angle <user.where","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)","SOYovQniOUVJIil\\1",[extended,global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)","D\\1",[extended])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)","D\\1",[extended,global])),
+?line <<"The quick brown fox">> = iolist_to_binary(re:replace("The quick brown fox","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)","X&ayUGYrNMDenjwrkvT",[extended])),
+?line <<"The quick brown fox">> = iolist_to_binary(re:replace("The quick brown fox","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)","X&ayUGYrNMDenjwrkvT",[extended,global])),
+?line <<"abcdefpqrxyz0AB">> = iolist_to_binary(re:replace("abcdefpqrxyz0AB","abc\\0def\\00pqr\\000xyz\\0000AB","bYVVTfV",[])),
+?line <<"abcdefpqrxyz0AB">> = iolist_to_binary(re:replace("abcdefpqrxyz0AB","abc\\0def\\00pqr\\000xyz\\0000AB","bYVVTfV",[global])),
+?line <<"abc456 abcdefpqrxyz0ABCDE">> = iolist_to_binary(re:replace("abc456 abcdefpqrxyz0ABCDE","abc\\0def\\00pqr\\000xyz\\0000AB","ALc",[])),
+?line <<"abc456 abcdefpqrxyz0ABCDE">> = iolist_to_binary(re:replace("abc456 abcdefpqrxyz0ABCDE","abc\\0def\\00pqr\\000xyz\\0000AB","ALc",[global])),
+?line <<"abc efpqr0xyz00AB">> = iolist_to_binary(re:replace("abc efpqr0xyz00AB","abc\\x0def\\x00pqr\\x000xyz\\x0000AB","FJjJa&MUN",[])),
+?line <<"abc efpqr0xyz00AB">> = iolist_to_binary(re:replace("abc efpqr0xyz00AB","abc\\x0def\\x00pqr\\x000xyz\\x0000AB","FJjJa&MUN",[global])),
+?line <<"abc456 abc efpqr0xyz00ABCDE">> = iolist_to_binary(re:replace("abc456 abc efpqr0xyz00ABCDE","abc\\x0def\\x00pqr\\x000xyz\\x0000AB","IsJK",[])),
+?line <<"abc456 abc efpqr0xyz00ABCDE">> = iolist_to_binary(re:replace("abc456 abc efpqr0xyz00ABCDE","abc\\x0def\\x00pqr\\x000xyz\\x0000AB","IsJK",[global])),
+?line <<"A">> = iolist_to_binary(re:replace("A","^[\\000-\\037]","&&&l&oFiYRb&dwnRVIB",[])),
+?line <<"A">> = iolist_to_binary(re:replace("A","^[\\000-\\037]","&&&l&oFiYRb&dwnRVIB",[global])),
+?line <<"pJINBIVHkbsQpNB">> = iolist_to_binary(re:replace("B","^[\\000-\\037]","p\\1JINBIVHkbs&QpN",[])),
+?line <<"pJINBIVHkbsQpNB">> = iolist_to_binary(re:replace("B","^[\\000-\\037]","p\\1JINBIVHkbs&QpN",[global])),
+?line <<"qnaxlKtxgBKMC">> = iolist_to_binary(re:replace("C","^[\\000-\\037]","qnax&lKtxgB&KM",[])),
+?line <<"qnaxlKtxgBKMC">> = iolist_to_binary(re:replace("C","^[\\000-\\037]","qnax&lKtxgB&KM",[global])),
+?line <<"WuuRxIy">> = iolist_to_binary(re:replace("","\\0*","Wu&uRxIy",[])),
+?line <<"WuuRxIy">> = iolist_to_binary(re:replace("","\\0*","Wu&uRxIy",[global])),
+?line <<"The AZ">> = iolist_to_binary(re:replace("The AZ","A\\x0{2,3}Z","ggJSniphIbt",[])),
+?line <<"The AZ">> = iolist_to_binary(re:replace("The AZ","A\\x0{2,3}Z","ggJSniphIbt",[global])),
+?line <<"An AZ">> = iolist_to_binary(re:replace("An AZ","A\\x0{2,3}Z","s&\\1Bwkjj",[])),
+?line <<"An AZ">> = iolist_to_binary(re:replace("An AZ","A\\x0{2,3}Z","s&\\1Bwkjj",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","A\\x0{2,3}Z","\\1eJyYpl",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","A\\x0{2,3}Z","\\1eJyYpl",[global])),
+?line <<"AZ">> = iolist_to_binary(re:replace("AZ","A\\x0{2,3}Z","aK\\1qVDC\\1uB",[])),
+?line <<"AZ">> = iolist_to_binary(re:replace("AZ","A\\x0{2,3}Z","aK\\1qVDC\\1uB",[global])),
+?line <<"AZ">> = iolist_to_binary(re:replace("AZ","A\\x0{2,3}Z","DMN&CNdjTe",[])),
+?line <<"AZ">> = iolist_to_binary(re:replace("AZ","A\\x0{2,3}Z","DMN&CNdjTe",[global])),
+?line <<"cowcowbelldrlcowNSbcowcowbelladivdcowcowbell">> = iolist_to_binary(re:replace("cowcowbell","^(cow|)\\1(bell)","&drl\\1NSb&adivd&",[])),
+?line <<"cowcowbelldrlcowNSbcowcowbelladivdcowcowbell">> = iolist_to_binary(re:replace("cowcowbell","^(cow|)\\1(bell)","&drl\\1NSb&adivd&",[global])),
+?line <<"UUUBpbellPtC">> = iolist_to_binary(re:replace("bell","^(cow|)\\1(bell)","UUUBp&P\\1tC",[])),
+?line <<"UUUBpbellPtC">> = iolist_to_binary(re:replace("bell","^(cow|)\\1(bell)","UUUBp&P\\1tC",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(cow|)\\1(bell)","\\1\\1L\\1foe&LDaKY",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(cow|)\\1(bell)","\\1\\1L\\1foe&LDaKY",[global])),
+?line <<"cowbell">> = iolist_to_binary(re:replace("cowbell","^(cow|)\\1(bell)","&pE",[])),
+?line <<"cowbell">> = iolist_to_binary(re:replace("cowbell","^(cow|)\\1(bell)","&pE",[global])),
+?line <<"KEPMMarMefAQoabc">> = iolist_to_binary(re:replace(" abc","^\\s","KEP\\1MMa\\1rMefAQ\\1\\1\\1o",[])),
+?line <<"KEPMMarMefAQoabc">> = iolist_to_binary(re:replace(" abc","^\\s","KEP\\1MMa\\1rMefAQ\\1\\1\\1o",[global])),
+?line <<"mdPwbKbGabc">> = iolist_to_binary(re:replace(" abc","^\\s","mdPwbKbG",[])),
+?line <<"mdPwbKbGabc">> = iolist_to_binary(re:replace(" abc","^\\s","mdPwbKbG",[global])),
+?line <<"Ed
+FNgfabc">> = iolist_to_binary(re:replace("
+abc","^\\s","Ed&FNgf",[])),
+?line <<"Ed
+FNgfabc">> = iolist_to_binary(re:replace("
+abc","^\\s","Ed&FNgf",[global])),
+?line <<"iYCabc">> = iolist_to_binary(re:replace(" abc","^\\s","iYC",[])),
+?line <<"iYCabc">> = iolist_to_binary(re:replace(" abc","^\\s","iYC",[global])),
+?line <<"Y KyKjBtWUscEoeabc">> = iolist_to_binary(re:replace(" abc","^\\s","Y\\1&\\1KyKjBtWUscEoe",[])),
+?line <<"Y KyKjBtWUscEoeabc">> = iolist_to_binary(re:replace(" abc","^\\s","Y\\1&\\1KyKjBtWUscEoe",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^\\s","fMXHNBeT",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^\\s","fMXHNBeT",[global])),
+?line <<"abc">> = iolist_to_binary(re:replace("abc","^\\s","GF\\1s&cS\\1yGC",[])),
+?line <<"abc">> = iolist_to_binary(re:replace("abc","^\\s","GF\\1s&cS\\1yGC",[global])),
+?line <<"Ur">> = iolist_to_binary(re:replace("abc","^a b
+ c","Ur",[extended])),
+?line <<"Ur">> = iolist_to_binary(re:replace("abc","^a b
+ c","Ur",[extended,global])),
+?line <<"UQqfOFVevBwaga">> = iolist_to_binary(re:replace("ab","^(a|)\\1*b","UQqfOFVevBwag\\1",[])),
+?line <<"UQqfOFVevBwaga">> = iolist_to_binary(re:replace("ab","^(a|)\\1*b","UQqfOFVevBwag\\1",[global])),
+?line <<"cAc">> = iolist_to_binary(re:replace("aaaab","^(a|)\\1*b","cAc",[])),
+?line <<"cAc">> = iolist_to_binary(re:replace("aaaab","^(a|)\\1*b","cAc",[global])),
+?line <<"QGbTLPFbbYYwpIhdW">> = iolist_to_binary(re:replace("b","^(a|)\\1*b","QG&TLPF&&YYwp\\1Ih\\1dW",[])),
+?line <<"QGbTLPFbbYYwpIhdW">> = iolist_to_binary(re:replace("b","^(a|)\\1*b","QG&TLPF&&YYwp\\1Ih\\1dW",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(a|)\\1*b","wY",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(a|)\\1*b","wY",[global])),
+?line <<"acb">> = iolist_to_binary(re:replace("acb","^(a|)\\1*b","IpD\\1tRUS",[])),
+?line <<"acb">> = iolist_to_binary(re:replace("acb","^(a|)\\1*b","IpD\\1tRUS",[global])),
+?line <<"PMaabaRKsKVgnxCiJtgp">> = iolist_to_binary(re:replace("aab","^(a|)\\1+b","PM&\\1RKsKVgnxCiJtgp",[])),
+?line <<"PMaabaRKsKVgnxCiJtgp">> = iolist_to_binary(re:replace("aab","^(a|)\\1+b","PM&\\1RKsKVgnxCiJtgp",[global])),
+?line <<"quaJPXxLfMHlVxH">> = iolist_to_binary(re:replace("aaaab","^(a|)\\1+b","qu\\1JPXxLfMHlVxH",[])),
+?line <<"quaJPXxLfMHlVxH">> = iolist_to_binary(re:replace("aaaab","^(a|)\\1+b","qu\\1JPXxLfMHlVxH",[global])),
+?line <<"b">> = iolist_to_binary(re:replace("b","^(a|)\\1+b","&",[])),
+?line <<"b">> = iolist_to_binary(re:replace("b","^(a|)\\1+b","&",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(a|)\\1+b","ywXwC",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(a|)\\1+b","ywXwC",[global])),
+?line <<"ab">> = iolist_to_binary(re:replace("ab","^(a|)\\1+b","hwwbvhOrVEaVOsD\\1",[])),
+?line <<"ab">> = iolist_to_binary(re:replace("ab","^(a|)\\1+b","hwwbvhOrVEaVOsD\\1",[global])),
+?line <<"tNvaWAg">> = iolist_to_binary(re:replace("ab","^(a|)\\1?b","tNv\\1WAg",[])),
+?line <<"tNvaWAg">> = iolist_to_binary(re:replace("ab","^(a|)\\1?b","tNv\\1WAg",[global])),
+?line <<"K">> = iolist_to_binary(re:replace("aab","^(a|)\\1?b","K",[])),
+?line <<"K">> = iolist_to_binary(re:replace("aab","^(a|)\\1?b","K",[global])),
+?line <<"bRibsTbLcleUeb">> = iolist_to_binary(re:replace("b","^(a|)\\1?b","&Ri\\1&sT&L\\1cl\\1e\\1Ue&",[])),
+?line <<"bRibsTbLcleUeb">> = iolist_to_binary(re:replace("b","^(a|)\\1?b","&Ri\\1&sT&L\\1cl\\1e\\1Ue&",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(a|)\\1?b","&CGRslcRfjatPWbOMT",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(a|)\\1?b","&CGRslcRfjatPWbOMT",[global])),
+?line <<"acb">> = iolist_to_binary(re:replace("acb","^(a|)\\1?b","&k\\1aoVMtug&hJsI",[])),
+?line <<"acb">> = iolist_to_binary(re:replace("acb","^(a|)\\1?b","&k\\1aoVMtug&hJsI",[global])),
+?line <<"gaaabFGtJRckPahi">> = iolist_to_binary(re:replace("aaab","^(a|)\\1{2}b","g&FGtJRckP\\1hi",[])),
+?line <<"gaaabFGtJRckPahi">> = iolist_to_binary(re:replace("aaab","^(a|)\\1{2}b","g&FGtJRckP\\1hi",[global])),
+?line <<"bINnRM">> = iolist_to_binary(re:replace("b","^(a|)\\1{2}b","bINnR\\1M",[])),
+?line <<"bINnRM">> = iolist_to_binary(re:replace("b","^(a|)\\1{2}b","bINnR\\1M",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(a|)\\1{2}b","cm",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(a|)\\1{2}b","cm",[global])),
+?line <<"ab">> = iolist_to_binary(re:replace("ab","^(a|)\\1{2}b","yT\\1\\1NlFQVleuHkXnE\\1",[])),
+?line <<"ab">> = iolist_to_binary(re:replace("ab","^(a|)\\1{2}b","yT\\1\\1NlFQVleuHkXnE\\1",[global])),
+?line <<"aab">> = iolist_to_binary(re:replace("aab","^(a|)\\1{2}b","PwBRhyP\\1txXQhbjE\\1a",[])),
+?line <<"aab">> = iolist_to_binary(re:replace("aab","^(a|)\\1{2}b","PwBRhyP\\1txXQhbjE\\1a",[global])),
+?line <<"aaaab">> = iolist_to_binary(re:replace("aaaab","^(a|)\\1{2}b","cxo",[])),
+?line <<"aaaab">> = iolist_to_binary(re:replace("aaaab","^(a|)\\1{2}b","cxo",[global])),
+?line <<"aaabXaaabMaaabdHhnqsiti">> = iolist_to_binary(re:replace("aaab","^(a|)\\1{2,3}b","&X&M&dHhnqsiti",[])),
+?line <<"aaabXaaabMaaabdHhnqsiti">> = iolist_to_binary(re:replace("aaab","^(a|)\\1{2,3}b","&X&M&dHhnqsiti",[global])),
+?line <<"QaaaablaaaabNnVdaaaabpaQEaaaaab">> = iolist_to_binary(re:replace("aaaab","^(a|)\\1{2,3}b","Q&l&NnVd&p\\1QE\\1&",[])),
+?line <<"QaaaablaaaabNnVdaaaabpaQEaaaaab">> = iolist_to_binary(re:replace("aaaab","^(a|)\\1{2,3}b","Q&l&NnVd&p\\1QE\\1&",[global])),
+?line <<"bCw">> = iolist_to_binary(re:replace("b","^(a|)\\1{2,3}b","&Cw",[])),
+?line <<"bCw">> = iolist_to_binary(re:replace("b","^(a|)\\1{2,3}b","&Cw",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(a|)\\1{2,3}b","\\1&puY",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(a|)\\1{2,3}b","\\1&puY",[global])),
+?line <<"ab">> = iolist_to_binary(re:replace("ab","^(a|)\\1{2,3}b","pbextvQnRWgXs",[])),
+?line <<"ab">> = iolist_to_binary(re:replace("ab","^(a|)\\1{2,3}b","pbextvQnRWgXs",[global])),
+?line <<"aab">> = iolist_to_binary(re:replace("aab","^(a|)\\1{2,3}b","fHRaaYYIr\\1l\\1",[])),
+?line <<"aab">> = iolist_to_binary(re:replace("aab","^(a|)\\1{2,3}b","fHRaaYYIr\\1l\\1",[global])),
+?line <<"aaaaab">> = iolist_to_binary(re:replace("aaaaab","^(a|)\\1{2,3}b","nXt&Aw\\1XCfLg\\1GGPmN",[])),
+?line <<"aaaaab">> = iolist_to_binary(re:replace("aaaaab","^(a|)\\1{2,3}b","nXt&Aw\\1XCfLg\\1GGPmN",[global])),
+?line <<"eRwvgLU">> = iolist_to_binary(re:replace("abbbbc","ab{1,3}bc","eRwvgLU",[])),
+?line <<"eRwvgLU">> = iolist_to_binary(re:replace("abbbbc","ab{1,3}bc","eRwvgLU",[global])),
+?line <<"mDnlkabbbcfTJ">> = iolist_to_binary(re:replace("abbbc","ab{1,3}bc","m\\1Dnl\\1k&fTJ",[])),
+?line <<"mDnlkabbbcfTJ">> = iolist_to_binary(re:replace("abbbc","ab{1,3}bc","m\\1Dnl\\1k&fTJ",[global])),
+?line <<"QabbcqIjjWabbchabbcBrTp">> = iolist_to_binary(re:replace("abbc","ab{1,3}bc","Q&qIjjW&h\\1&BrTp",[])),
+?line <<"QabbcqIjjWabbchabbcBrTp">> = iolist_to_binary(re:replace("abbc","ab{1,3}bc","Q&qIjjW&h\\1&BrTp",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","ab{1,3}bc","\\1Wj&Y&ML\\1RBiGiweww",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","ab{1,3}bc","\\1Wj&Y&ML\\1RBiGiweww",[global])),
+?line <<"abc">> = iolist_to_binary(re:replace("abc","ab{1,3}bc","HmlRU&NUwwokL",[])),
+?line <<"abc">> = iolist_to_binary(re:replace("abc","ab{1,3}bc","HmlRU&NUwwokL",[global])),
+?line <<"abbbbbc">> = iolist_to_binary(re:replace("abbbbbc","ab{1,3}bc","FUyCCDShGVXhEHX\\1V\\1bK",[])),
+?line <<"abbbbbc">> = iolist_to_binary(re:replace("abbbbbc","ab{1,3}bc","FUyCCDShGVXhEHX\\1V\\1bK",[global])),
+?line <<"track1astrack1track1tIDhtrack1.title:TBlah blah blahiA">> = iolist_to_binary(re:replace("track1.title:TBlah blah blah","([^.]*)\\.([^:]*):[T ]+(.*)","\\1as\\1\\1tIDh&iA",[])),
+?line <<"track1astrack1track1tIDhtrack1.title:TBlah blah blahiA">> = iolist_to_binary(re:replace("track1.title:TBlah blah blah","([^.]*)\\.([^:]*):[T ]+(.*)","\\1as\\1\\1tIDh&iA",[global])),
+?line <<"wUVSR">> = iolist_to_binary(re:replace("track1.title:TBlah blah blah","([^.]*)\\.([^:]*):[T ]+(.*)","wUVSR",[caseless])),
+?line <<"wUVSR">> = iolist_to_binary(re:replace("track1.title:TBlah blah blah","([^.]*)\\.([^:]*):[T ]+(.*)","wUVSR",[caseless,
+ global])),
+?line <<"htrack1TCNtrack1.title:TBlah blah blahpLtrack1.title:TBlah blah blahtrack1.title:TBlah blah blahFnNtrack1jOBdd">> = iolist_to_binary(re:replace("track1.title:TBlah blah blah","([^.]*)\\.([^:]*):[t ]+(.*)","h\\1TCN&pL&&FnN\\1jOBdd",[caseless])),
+?line <<"htrack1TCNtrack1.title:TBlah blah blahpLtrack1.title:TBlah blah blahtrack1.title:TBlah blah blahFnNtrack1jOBdd">> = iolist_to_binary(re:replace("track1.title:TBlah blah blah","([^.]*)\\.([^:]*):[t ]+(.*)","h\\1TCN&pL&&FnN\\1jOBdd",[caseless,
+ global])),
+?line <<"OKnYPU">> = iolist_to_binary(re:replace("WXY_^abc","^[W-c]+$","OKnYPU",[])),
+?line <<"OKnYPU">> = iolist_to_binary(re:replace("WXY_^abc","^[W-c]+$","OKnYPU",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^[W-c]+$","\\1GX\\1YVV&\\1WF",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^[W-c]+$","\\1GX\\1YVV&\\1WF",[global])),
+?line <<"wxy">> = iolist_to_binary(re:replace("wxy","^[W-c]+$","Uax\\1F",[])),
+?line <<"wxy">> = iolist_to_binary(re:replace("wxy","^[W-c]+$","Uax\\1F",[global])),
+?line <<"WXY_^abcARKQ">> = iolist_to_binary(re:replace("WXY_^abc","^[W-c]+$","&ARK\\1Q",[caseless])),
+?line <<"WXY_^abcARKQ">> = iolist_to_binary(re:replace("WXY_^abc","^[W-c]+$","&ARK\\1Q",[caseless,
+ global])),
+?line <<"fIwxy_^ABCwxy_^ABCGwxy_^ABCwAHLMA">> = iolist_to_binary(re:replace("wxy_^ABC","^[W-c]+$","fI&&G&w\\1AHL\\1MA",[caseless])),
+?line <<"fIwxy_^ABCwxy_^ABCGwxy_^ABCwAHLMA">> = iolist_to_binary(re:replace("wxy_^ABC","^[W-c]+$","fI&&G&w\\1AHL\\1MA",[caseless,
+ global])),
+?line <<"WXY_^abcrgsgXuYrmtfAuS">> = iolist_to_binary(re:replace("WXY_^abc","^[\\x3f-\\x5F]+$","&rgsgXuYrmtfAuS",[caseless])),
+?line <<"WXY_^abcrgsgXuYrmtfAuS">> = iolist_to_binary(re:replace("WXY_^abc","^[\\x3f-\\x5F]+$","&rgsgXuYrmtfAuS",[caseless,
+ global])),
+?line <<"FmwJKwxy_^ABCyluQcjQVnwQ">> = iolist_to_binary(re:replace("wxy_^ABC","^[\\x3f-\\x5F]+$","FmwJK&yluQcjQVnwQ",[caseless])),
+?line <<"FmwJKwxy_^ABCyluQcjQVnwQ">> = iolist_to_binary(re:replace("wxy_^ABC","^[\\x3f-\\x5F]+$","FmwJK&yluQcjQVnwQ",[caseless,
+ global])),
+?line <<"abcabcMObxlD">> = iolist_to_binary(re:replace("abc","^abc$","&\\1&MObxlD",[multiline])),
+?line <<"abcabcMObxlD">> = iolist_to_binary(re:replace("abc","^abc$","&\\1&MObxlD",[multiline,
+ global])),
+?line <<"qqq
+wgabc">> = iolist_to_binary(re:replace("qqq
+abc","^abc$","wg&",[multiline])),
+?line <<"qqq
+wgabc">> = iolist_to_binary(re:replace("qqq
+abc","^abc$","wg&",[multiline,global])),
+?line <<"abcwXeRgabcKmklKpYiE
+zzz">> = iolist_to_binary(re:replace("abc
+zzz","^abc$","&wXe\\1Rg&K\\1mklKpYiE",[multiline])),
+?line <<"abcwXeRgabcKmklKpYiE
+zzz">> = iolist_to_binary(re:replace("abc
+zzz","^abc$","&wXe\\1Rg&K\\1mklKpYiE",[multiline,global])),
+?line <<"qqq
+CabcCKxlJamS
+zzz">> = iolist_to_binary(re:replace("qqq
+abc
+zzz","^abc$","C&CKxlJam\\1S",[multiline])),
+?line <<"qqq
+CabcCKxlJamS
+zzz">> = iolist_to_binary(re:replace("qqq
+abc
+zzz","^abc$","C&CKxlJam\\1S",[multiline,global])),
+?line <<"MLKPlabcY">> = iolist_to_binary(re:replace("abc","^abc$","MLKPl&\\1Y",[])),
+?line <<"MLKPlabcY">> = iolist_to_binary(re:replace("abc","^abc$","MLKPl&\\1Y",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^abc$","\\1uRnMNc&\\1",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^abc$","\\1uRnMNc&\\1",[global])),
+?line <<"qqq
+abc">> = iolist_to_binary(re:replace("qqq
+abc","^abc$","b\\1",[])),
+?line <<"qqq
+abc">> = iolist_to_binary(re:replace("qqq
+abc","^abc$","b\\1",[global])),
+?line <<"abc
+zzz">> = iolist_to_binary(re:replace("abc
+zzz","^abc$","RAJ\\1a&Mvoue\\1d",[])),
+?line <<"abc
+zzz">> = iolist_to_binary(re:replace("abc
+zzz","^abc$","RAJ\\1a&Mvoue\\1d",[global])),
+?line <<"qqq
+abc
+zzz">> = iolist_to_binary(re:replace("qqq
+abc
+zzz","^abc$","\\1NghvSn\\1GSQvu&&grYN",[])),
+?line <<"qqq
+abc
+zzz">> = iolist_to_binary(re:replace("qqq
+abc
+zzz","^abc$","\\1NghvSn\\1GSQvu&&grYN",[global])),
+?line <<"abc">> = iolist_to_binary(re:replace("abc","\\Aabc\\Z","&",[multiline])),
+?line <<"abc">> = iolist_to_binary(re:replace("abc","\\Aabc\\Z","&",[multiline,
+ global])),
+?line <<"XQevmabcHXD">> = iolist_to_binary(re:replace("abc","\\Aabc\\Z","XQevm&HXD",[multiline])),
+?line <<"XQevmabcHXD">> = iolist_to_binary(re:replace("abc","\\Aabc\\Z","XQevm&HXD",[multiline,
+ global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","\\Aabc\\Z","plNA&&\\1Myw&e",[multiline])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","\\Aabc\\Z","plNA&&\\1Myw&e",[multiline,
+ global])),
+?line <<"qqq
+abc">> = iolist_to_binary(re:replace("qqq
+abc","\\Aabc\\Z","tActj",[multiline])),
+?line <<"qqq
+abc">> = iolist_to_binary(re:replace("qqq
+abc","\\Aabc\\Z","tActj",[multiline,global])),
+?line <<"abc
+zzz">> = iolist_to_binary(re:replace("abc
+zzz","\\Aabc\\Z","&PAnUmSADdk",[multiline])),
+?line <<"abc
+zzz">> = iolist_to_binary(re:replace("abc
+zzz","\\Aabc\\Z","&PAnUmSADdk",[multiline,global])),
+?line <<"qqq
+abc
+zzz">> = iolist_to_binary(re:replace("qqq
+abc
+zzz","\\Aabc\\Z","O&&GYJA",[multiline])),
+?line <<"qqq
+abc
+zzz">> = iolist_to_binary(re:replace("qqq
+abc
+zzz","\\Aabc\\Z","O&&GYJA",[multiline,global])),
+?line <<"ejfGpamjOGidXfWabc
+defiXJg">> = iolist_to_binary(re:replace("abc
+def","\\A(.)*\\Z","ej\\1GpamjOGidX\\1W&iXJg",[dotall])),
+?line <<"ejfGpamjOGidXfWabc
+defiXJg">> = iolist_to_binary(re:replace("abc
+def","\\A(.)*\\Z","ej\\1GpamjOGidX\\1W&iXJg",[dotall,global])),
+?line <<"UTI*** FailersagVgtIFYe*** Failerss*** Failers">> = iolist_to_binary(re:replace("*** Failers","\\A(.)*\\Z","UTI&agVgtIFYe&\\1&",[multiline])),
+?line <<"UTI*** FailersagVgtIFYe*** Failerss*** Failers">> = iolist_to_binary(re:replace("*** Failers","\\A(.)*\\Z","UTI&agVgtIFYe&\\1&",[multiline,
+ global])),
+?line <<"abc
+def">> = iolist_to_binary(re:replace("abc
+def","\\A(.)*\\Z","&PHW&rh&xcxs\\1Cy&Chhd",[multiline])),
+?line <<"abc
+def">> = iolist_to_binary(re:replace("abc
+def","\\A(.)*\\Z","&PHW&rh&xcxs\\1Cy&Chhd",[multiline,global])),
+?line <<"cjOwaTTW::c">> = iolist_to_binary(re:replace("b::c","(?:b)|(?::+)","cjOwaTTW",[])),
+?line <<"cjOwaTTWcjOwaTTWc">> = iolist_to_binary(re:replace("b::c","(?:b)|(?::+)","cjOwaTTW",[global])),
+?line <<"c::ReJbWufqTUdDqlXQb">> = iolist_to_binary(re:replace("c::b","(?:b)|(?::+)","\\1&ReJbWufqTUdDqlXQ",[])),
+?line <<"c::ReJbWufqTUdDqlXQbReJbWufqTUdDqlXQ">> = iolist_to_binary(re:replace("c::b","(?:b)|(?::+)","\\1&ReJbWufqTUdDqlXQ",[global])),
+?line <<"az-uaz-obYOlaz-DVbrqaz-y">> = iolist_to_binary(re:replace("az-","[-az]+","&u&obYOl&DVbrq&y",[])),
+?line <<"az-uaz-obYOlaz-DVbrqaz-y">> = iolist_to_binary(re:replace("az-","[-az]+","&u&obYOl&DVbrq&y",[global])),
+?line <<"*** FAlNlPvDnUXilers">> = iolist_to_binary(re:replace("*** Failers","[-az]+","AlNlPvDn\\1UX",[])),
+?line <<"*** FAlNlPvDnUXilers">> = iolist_to_binary(re:replace("*** Failers","[-az]+","AlNlPvDn\\1UX",[global])),
+?line <<"b">> = iolist_to_binary(re:replace("b","[-az]+","&xa\\1Q\\1BSaQG",[])),
+?line <<"b">> = iolist_to_binary(re:replace("b","[-az]+","&xa\\1Q\\1BSaQG",[global])),
+?line <<"rJXv">> = iolist_to_binary(re:replace("za-","[az-]+","\\1rJXv",[])),
+?line <<"rJXv">> = iolist_to_binary(re:replace("za-","[az-]+","\\1rJXv",[global])),
+?line <<"*** FIQWDsCilers">> = iolist_to_binary(re:replace("*** Failers","[az-]+","IQWD\\1\\1sC",[])),
+?line <<"*** FIQWDsCilers">> = iolist_to_binary(re:replace("*** Failers","[az-]+","IQWD\\1\\1sC",[global])),
+?line <<"b">> = iolist_to_binary(re:replace("b","[az-]+","G\\1TcEO\\1EAeKKLc&eOBg",[])),
+?line <<"b">> = iolist_to_binary(re:replace("b","[az-]+","G\\1TcEO\\1EAeKKLc&eOBg",[global])),
+?line <<"DsdWoREvsWCDpa-z">> = iolist_to_binary(re:replace("a-z","[a\\-z]+","Dsd\\1WoREvsWCD\\1p&",[])),
+?line <<"DsdWoREvsWCDpa-z">> = iolist_to_binary(re:replace("a-z","[a\\-z]+","Dsd\\1WoREvsWCD\\1p&",[global])),
+?line <<"*** FaUqEUvbeKTpilers">> = iolist_to_binary(re:replace("*** Failers","[a\\-z]+","&U\\1qEUvbeKTp",[])),
+?line <<"*** FaUqEUvbeKTpilers">> = iolist_to_binary(re:replace("*** Failers","[a\\-z]+","&U\\1qEUvbeKTp",[global])),
+?line <<"b">> = iolist_to_binary(re:replace("b","[a\\-z]+","IdIH&",[])),
+?line <<"b">> = iolist_to_binary(re:replace("b","[a\\-z]+","IdIH&",[global])),
+?line <<"CHIiEabcdxyzAXhIPVabcdxyz">> = iolist_to_binary(re:replace("abcdxyz","[a-z]+","CHIiE&AXhIPV&",[])),
+?line <<"CHIiEabcdxyzAXhIPVabcdxyz">> = iolist_to_binary(re:replace("abcdxyz","[a-z]+","CHIiE&AXhIPV&",[global])),
+?line <<"Tk12-34ptREc12-34dF">> = iolist_to_binary(re:replace("12-34","[\\d-]+","Tk&ptREc&dF\\1",[])),
+?line <<"Tk12-34ptREc12-34dF">> = iolist_to_binary(re:replace("12-34","[\\d-]+","Tk&ptREc&dF\\1",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","[\\d-]+","PO\\1\\1HuRnqA\\1miVVsKv",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","[\\d-]+","PO\\1\\1HuRnqA\\1miVVsKv",[global])),
+?line <<"aaa">> = iolist_to_binary(re:replace("aaa","[\\d-]+","QMUbdeC\\1fKgUg",[])),
+?line <<"aaa">> = iolist_to_binary(re:replace("aaa","[\\d-]+","QMUbdeC\\1fKgUg",[global])),
+?line <<"YypJ">> = iolist_to_binary(re:replace("12-34z","[\\d-z]+","YypJ",[])),
+?line <<"YypJ">> = iolist_to_binary(re:replace("12-34z","[\\d-z]+","YypJ",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","[\\d-z]+","d&ErDHl\\1&GDjyQy",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","[\\d-z]+","d&ErDHl\\1&GDjyQy",[global])),
+?line <<"aaa">> = iolist_to_binary(re:replace("aaa","[\\d-z]+","EVkS",[])),
+?line <<"aaa">> = iolist_to_binary(re:replace("aaa","[\\d-z]+","EVkS",[global])),
+?line <<"cHd\\ltkGr\\BqrhP ">> = iolist_to_binary(re:replace("\\ ","\\x5c","cHd&ltkGr&Bqr\\1hP",[])),
+?line <<"cHd\\ltkGr\\BqrhP ">> = iolist_to_binary(re:replace("\\ ","\\x5c","cHd&ltkGr&Bqr\\1hP",[global])),
+?line <<"the Z Z ZciyfJLvoo">> = iolist_to_binary(re:replace("the Zoo","\\x20Z","&&&ciyf\\1JLv",[])),
+?line <<"the Z Z ZciyfJLvoo">> = iolist_to_binary(re:replace("the Zoo","\\x20Z","&&&ciyf\\1JLv",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","\\x20Z","ry\\1S\\1&\\1\\1MkYc",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","\\x20Z","ry\\1S\\1&\\1\\1MkYc",[global])),
+?line <<"Zulu">> = iolist_to_binary(re:replace("Zulu","\\x20Z","b\\1Wc&RB\\1&&pO&Dd\\1&A",[])),
+?line <<"Zulu">> = iolist_to_binary(re:replace("Zulu","\\x20Z","b\\1Wc&RB\\1&&pO&Dd\\1&A",[global])),
+?line <<"aabcabcUxryabcAPabcabcDGgL">> = iolist_to_binary(re:replace("abcabc","(abc)\\1","a&Uxry\\1AP&DGgL",[caseless])),
+?line <<"aabcabcUxryabcAPabcabcDGgL">> = iolist_to_binary(re:replace("abcabc","(abc)\\1","a&Uxry\\1AP&DGgL",[caseless,
+ global])),
+?line <<"oStOWABCvVHVfFqojojfABC">> = iolist_to_binary(re:replace("ABCabc","(abc)\\1","oStOW\\1vVHVfFqojojf\\1",[caseless])),
+?line <<"oStOWABCvVHVfFqojojfABC">> = iolist_to_binary(re:replace("ABCabc","(abc)\\1","oStOW\\1vVHVfFqojojf\\1",[caseless,
+ global])),
+?line <<"GabcABCrGLdSabcABCWnHabcabcABCP">> = iolist_to_binary(re:replace("abcABC","(abc)\\1","G&rGLdS&WnH\\1&P",[caseless])),
+?line <<"GabcABCrGLdSabcABCWnHabcabcABCP">> = iolist_to_binary(re:replace("abcABC","(abc)\\1","G&rGLdS&WnH\\1&P",[caseless,
+ global])),
+?line <<"KVwWyab{3cdEWMab{3cdPr">> = iolist_to_binary(re:replace("ab{3cd","ab{3cd","KVwWy&\\1EWM&Pr",[])),
+?line <<"KVwWyab{3cdEWMab{3cdPr">> = iolist_to_binary(re:replace("ab{3cd","ab{3cd","KVwWy&\\1EWM&Pr",[global])),
+?line <<"KuJab{3,cd">> = iolist_to_binary(re:replace("ab{3,cd","ab{3,cd","KuJ&",[])),
+?line <<"KuJab{3,cd">> = iolist_to_binary(re:replace("ab{3,cd","ab{3,cd","KuJ&",[global])),
+?line <<"squJfab{3,4a}cd">> = iolist_to_binary(re:replace("ab{3,4a}cd","ab{3,4a}cd","squ\\1Jf&",[])),
+?line <<"squJfab{3,4a}cd">> = iolist_to_binary(re:replace("ab{3,4a}cd","ab{3,4a}cd","squ\\1Jf&",[global])),
+?line <<"{4,5a}bc{4,5a}bcH">> = iolist_to_binary(re:replace("{4,5a}bc","{4,5a}bc","&&H",[])),
+?line <<"{4,5a}bc{4,5a}bcH">> = iolist_to_binary(re:replace("{4,5a}bc","{4,5a}bc","&&H",[global])),
+?line <<"nb">> = iolist_to_binary(re:replace("abc","abc$","nb",[])),
+?line <<"nb">> = iolist_to_binary(re:replace("abc","abc$","nb",[global])),
+?line <<"aabcTslrEK">> = iolist_to_binary(re:replace("abc","abc$","a&TslrEK",[])),
+?line <<"aabcTslrEK">> = iolist_to_binary(re:replace("abc","abc$","a&TslrEK",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","abc$","rVkXRL&nq&w\\1NDuHM\\1dj",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","abc$","rVkXRL&nq&w\\1NDuHM\\1dj",[global])),
+?line <<"abc
+def">> = iolist_to_binary(re:replace("abc
+def","abc$","M",[])),
+?line <<"abc
+def">> = iolist_to_binary(re:replace("abc
+def","abc$","M",[global])),
+?line <<"abcWCabcSYXGPjRugTabcVGabcSX">> = iolist_to_binary(re:replace("abcS","(abc)\\123","\\1WC&YXGPjRugT\\1VG&X",[])),
+?line <<"abcWCabcSYXGPjRugTabcVGabcSX">> = iolist_to_binary(re:replace("abcS","(abc)\\123","\\1WC&YXGPjRugT\\1VG&X",[global])),
+?line <<"fabc�Uabc�UmiqabceCsabcabc�">> = iolist_to_binary(re:replace("abc�","(abc)\\223","f&U&Umiq\\1eCs\\1&",[])),
+?line <<"fabc�Uabc�UmiqabceCsabcabc�">> = iolist_to_binary(re:replace("abc�","(abc)\\223","f&U&Umiq\\1eCs\\1&",[global])),
+?line <<"JRFabcxnbabc�Vkabc�fWigQMuaY">> = iolist_to_binary(re:replace("abc�","(abc)\\323","JRF\\1xnb&Vk&fWigQMuaY",[])),
+?line <<"JRFabcxnbabc�Vkabc�fWigQMuaY">> = iolist_to_binary(re:replace("abc�","(abc)\\323","JRF\\1xnb&Vk&fWigQMuaY",[global])),
+?line <<"vgabc@QQ">> = iolist_to_binary(re:replace("abc@","(abc)\\100","vg&QQ",[])),
+?line <<"vgabc@QQ">> = iolist_to_binary(re:replace("abc@","(abc)\\100","vg&QQ",[global])),
+?line <<"abc@OkvNytabc@abcabc@a">> = iolist_to_binary(re:replace("abc@","(abc)\\100","&OkvNyt&\\1&a",[])),
+?line <<"abc@OkvNytabc@abcabc@a">> = iolist_to_binary(re:replace("abc@","(abc)\\100","&OkvNyt&\\1&a",[global])),
+?line <<"abc">> = iolist_to_binary(re:replace("abc","(abc)\\1000","P&kRot\\1ILA",[])),
+?line <<"abc">> = iolist_to_binary(re:replace("abc","(abc)\\1000","P&kRot\\1ILA",[global])),
+?line <<"abc">> = iolist_to_binary(re:replace("abc","(abc)\\1000","iULjBTiVDW&K\\1p&bj",[])),
+?line <<"abc">> = iolist_to_binary(re:replace("abc","(abc)\\1000","iULjBTiVDW&K\\1p&bj",[global])),
+?line <<"abc">> = iolist_to_binary(re:replace("abc","(abc)\\1000","cplYw\\1iuv\\1Okstb\\1p",[])),
+?line <<"abc">> = iolist_to_binary(re:replace("abc","(abc)\\1000","cplYw\\1iuv\\1Okstb\\1p",[global])),
+?line <<"abc">> = iolist_to_binary(re:replace("abc","(abc)\\1000","LDaRV&lAu\\1i",[])),
+?line <<"abc">> = iolist_to_binary(re:replace("abc","(abc)\\1000","LDaRV&lAu\\1i",[global])),
+?line <<"abc">> = iolist_to_binary(re:replace("abc","(abc)\\1000","K\\1",[])),
+?line <<"abc">> = iolist_to_binary(re:replace("abc","(abc)\\1000","K\\1",[global])),
+?line <<"abc">> = iolist_to_binary(re:replace("abc","(abc)\\1000","cXHTTaJLMXvR&\\1",[])),
+?line <<"abc">> = iolist_to_binary(re:replace("abc","(abc)\\1000","cXHTTaJLMXvR&\\1",[global])),
+?line <<"abc81">> = iolist_to_binary(re:replace("abc81","abc\\81","\\1kB&oGS\\1\\1lPn",[])),
+?line <<"abc81">> = iolist_to_binary(re:replace("abc81","abc\\81","\\1kB&oGS\\1\\1lPn",[global])),
+?line <<"abc81">> = iolist_to_binary(re:replace("abc81","abc\\81","\\1",[])),
+?line <<"abc81">> = iolist_to_binary(re:replace("abc81","abc\\81","\\1",[global])),
+?line <<"abc91">> = iolist_to_binary(re:replace("abc91","abc\\91","\\1GKLIQYEGVpGIxagx&&",[])),
+?line <<"abc91">> = iolist_to_binary(re:replace("abc91","abc\\91","\\1GKLIQYEGVpGIxagx&&",[global])),
+?line <<"abc91">> = iolist_to_binary(re:replace("abc91","abc\\91","og&&Tlj&jCLkmrllagN",[])),
+?line <<"abc91">> = iolist_to_binary(re:replace("abc91","abc\\91","og&&Tlj&jCLkmrllagN",[global])),
+?line <<"xMFEgabcdefghijkllSDGabcdefghijkllSN">> = iolist_to_binary(re:replace("abcdefghijkllS","(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)\\12\\123","xMFEg&DG&N",[])),
+?line <<"xMFEgabcdefghijkllSDGabcdefghijkllSN">> = iolist_to_binary(re:replace("abcdefghijkllS","(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)\\12\\123","xMFEg&DG&N",[global])),
+?line <<"WyroFQabcdefghijk
+SNfabcdefghijk
+SahyoPabcdefghijk
+Sqfbs">> = iolist_to_binary(re:replace("abcdefghijk
+S","(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\\12\\123","WyroFQ&Nf&ahyoP&qfbs",[])),
+?line <<"WyroFQabcdefghijk
+SNfabcdefghijk
+SahyoPabcdefghijk
+Sqfbs">> = iolist_to_binary(re:replace("abcdefghijk
+S","(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\\12\\123","WyroFQ&Nf&ahyoP&qfbs",[global])),
+?line <<"fCnqsFE">> = iolist_to_binary(re:replace("abidef","ab\\idef","fCnqs\\1FE",[])),
+?line <<"fCnqsFE">> = iolist_to_binary(re:replace("abidef","ab\\idef","fCnqs\\1FE",[global])),
+?line <<"QFATItqr">> = iolist_to_binary(re:replace("bc","a{0}bc","Q\\1FAT\\1Itqr",[])),
+?line <<"QFATItqr">> = iolist_to_binary(re:replace("bc","a{0}bc","Q\\1FAT\\1Itqr",[global])),
+?line <<"DnNn">> = iolist_to_binary(re:replace("xyz","(a|(bc)){0,0}?xyz","DnNn",[])),
+?line <<"DnNn">> = iolist_to_binary(re:replace("xyz","(a|(bc)){0,0}?xyz","DnNn",[global])),
+?line <<"GlvWIgK">> = iolist_to_binary(re:replace("abcde","abc[\\10]de","GlvW\\1\\1IgK",[])),
+?line <<"GlvWIgK">> = iolist_to_binary(re:replace("abcde","abc[\\10]de","GlvW\\1\\1IgK",[global])),
+?line <<"KDyabcdeXgxxbvI">> = iolist_to_binary(re:replace("abcde","abc[\\1]de","KDy&XgxxbvI",[])),
+?line <<"KDyabcdeXgxxbvI">> = iolist_to_binary(re:replace("abcde","abc[\\1]de","KDy&XgxxbvI",[global])),
+?line <<"abcSYuXabcUabckewfJS">> = iolist_to_binary(re:replace("abcde","(abc)[\\1]de","\\1SYuX\\1U\\1kewfJS",[])),
+?line <<"abcSYuXabcUabckewfJS">> = iolist_to_binary(re:replace("abcde","(abc)[\\1]de","\\1SYuX\\1U\\1kewfJS",[global])),
+?line <<"a
+b">> = iolist_to_binary(re:replace("a
+b","(?s)a.b","&",[])),
+?line <<"a
+b">> = iolist_to_binary(re:replace("a
+b","(?s)a.b","&",[global])),
+?line <<"sILYgbGPUbaNOTcccceynxed">> = iolist_to_binary(re:replace("baNOTccccd","^([^a])([^\\b])([^c]*)([^d]{3,4})","sILYg\\1GPU&eynxe",[])),
+?line <<"sILYgbGPUbaNOTcccceynxed">> = iolist_to_binary(re:replace("baNOTccccd","^([^a])([^\\b])([^c]*)([^d]{3,4})","sILYg\\1GPU&eynxe",[global])),
+?line <<"bURwd">> = iolist_to_binary(re:replace("baNOTcccd","^([^a])([^\\b])([^c]*)([^d]{3,4})","\\1URw",[])),
+?line <<"bURwd">> = iolist_to_binary(re:replace("baNOTcccd","^([^a])([^\\b])([^c]*)([^d]{3,4})","\\1URw",[global])),
+?line <<"rRcqtdVUmd">> = iolist_to_binary(re:replace("baNOTccd","^([^a])([^\\b])([^c]*)([^d]{3,4})","rRcqtdVUm",[])),
+?line <<"rRcqtdVUmd">> = iolist_to_binary(re:replace("baNOTccd","^([^a])([^\\b])([^c]*)([^d]{3,4})","rRcqtdVUm",[global])),
+?line <<"lYsStJbdoraarRd">> = iolist_to_binary(re:replace("bacccd","^([^a])([^\\b])([^c]*)([^d]{3,4})","lYsStJ\\1doraarR",[])),
+?line <<"lYsStJbdoraarRd">> = iolist_to_binary(re:replace("bacccd","^([^a])([^\\b])([^c]*)([^d]{3,4})","lYsStJ\\1doraarR",[global])),
+?line <<"*** Failersyu**c*** Failers*KH">> = iolist_to_binary(re:replace("*** Failers","^([^a])([^\\b])([^c]*)([^d]{3,4})","&yu\\1\\1c&\\1KH",[])),
+?line <<"*** Failersyu**c*** Failers*KH">> = iolist_to_binary(re:replace("*** Failers","^([^a])([^\\b])([^c]*)([^d]{3,4})","&yu\\1\\1c&\\1KH",[global])),
+?line <<"anything">> = iolist_to_binary(re:replace("anything","^([^a])([^\\b])([^c]*)([^d]{3,4})","&xLcPYkjD\\1YuJHCYWAIc",[])),
+?line <<"anything">> = iolist_to_binary(re:replace("anything","^([^a])([^\\b])([^c]*)([^d]{3,4})","&xLcPYkjD\\1YuJHCYWAIc",[global])),
+?line <<"bc">> = iolist_to_binary(re:replace("bc","^([^a])([^\\b])([^c]*)([^d]{3,4})","l\\1RIA&evjlHaNPGsYSx",[])),
+?line <<"bc">> = iolist_to_binary(re:replace("bc","^([^a])([^\\b])([^c]*)([^d]{3,4})","l\\1RIA&evjlHaNPGsYSx",[global])),
+?line <<"baccd">> = iolist_to_binary(re:replace("baccd","^([^a])([^\\b])([^c]*)([^d]{3,4})","SfTsSTMDCrU",[])),
+?line <<"baccd">> = iolist_to_binary(re:replace("baccd","^([^a])([^\\b])([^c]*)([^d]{3,4})","SfTsSTMDCrU",[global])),
+?line <<"KqAssSsdXronRAsbc">> = iolist_to_binary(re:replace("Abc","[^a]","Kq&s\\1sSsdXronR&s\\1",[])),
+?line <<"KqAssSsdXronRAsKqbssSsdXronRbsKqcssSsdXronRcs">> = iolist_to_binary(re:replace("Abc","[^a]","Kq&s\\1sSsdXronR&s\\1",[global])),
+?line <<"AXxbehbnMtJMOjc">> = iolist_to_binary(re:replace("Abc","[^a]","Xx&eh&nMtJMOj",[caseless])),
+?line <<"AXxbehbnMtJMOjXxcehcnMtJMOj">> = iolist_to_binary(re:replace("Abc","[^a]","Xx&eh&nMtJMOj",[caseless,
+ global])),
+?line <<"owGHnKmdtjnrJgSkEfaAbc">> = iolist_to_binary(re:replace("AAAaAbc","[^a]+","owGHnKmdtjnrJgSkEf",[])),
+?line <<"owGHnKmdtjnrJgSkEfaowGHnKmdtjnrJgSkEf">> = iolist_to_binary(re:replace("AAAaAbc","[^a]+","owGHnKmdtjnrJgSkEf",[global])),
+?line <<"AAAaAkm">> = iolist_to_binary(re:replace("AAAaAbc","[^a]+","\\1km",[caseless])),
+?line <<"AAAaAkm">> = iolist_to_binary(re:replace("AAAaAbc","[^a]+","\\1km",[caseless,
+ global])),
+?line <<"iBIdW">> = iolist_to_binary(re:replace("bbb
+ccc","[^a]+","iB\\1I\\1d\\1\\1W",[])),
+?line <<"iBIdW">> = iolist_to_binary(re:replace("bbb
+ccc","[^a]+","iB\\1I\\1d\\1\\1W",[global])),
+?line <<"abDIvvGgnrbcKkaSCbuiv">> = iolist_to_binary(re:replace("abc","[^k]$","DIvvGgnrb&KkaSCbuiv\\1",[])),
+?line <<"abDIvvGgnrbcKkaSCbuiv">> = iolist_to_binary(re:replace("abc","[^k]$","DIvvGgnrb&KkaSCbuiv\\1",[global])),
+?line <<"*** FailerbswvPHxEss">> = iolist_to_binary(re:replace("*** Failers","[^k]$","b&wvPH\\1xE&&",[])),
+?line <<"*** FailerbswvPHxEss">> = iolist_to_binary(re:replace("*** Failers","[^k]$","b&wvPH\\1xE&&",[global])),
+?line <<"abk">> = iolist_to_binary(re:replace("abk","[^k]$","nWvCPNUa\\1iDnbay",[])),
+?line <<"abk">> = iolist_to_binary(re:replace("abk","[^k]$","nWvCPNUa\\1iDnbay",[global])),
+?line <<"HWSo">> = iolist_to_binary(re:replace("abc","[^k]{2,3}$","HWSo\\1",[])),
+?line <<"HWSo">> = iolist_to_binary(re:replace("abc","[^k]{2,3}$","HWSo\\1",[global])),
+?line <<"kNKYkjbsvgnUOybcsuN">> = iolist_to_binary(re:replace("kbc","[^k]{2,3}$","NKYkjbsvgn\\1UO\\1y&suN",[])),
+?line <<"kNKYkjbsvgnUOybcsuN">> = iolist_to_binary(re:replace("kbc","[^k]{2,3}$","NKYkjbsvgn\\1UO\\1y&suN",[global])),
+?line <<"kDhBIRhnabc">> = iolist_to_binary(re:replace("kabc","[^k]{2,3}$","DhBIRhn&",[])),
+?line <<"kDhBIRhnabc">> = iolist_to_binary(re:replace("kabc","[^k]{2,3}$","DhBIRhn&",[global])),
+?line <<"*** FailQmVy">> = iolist_to_binary(re:replace("*** Failers","[^k]{2,3}$","QmVy",[])),
+?line <<"*** FailQmVy">> = iolist_to_binary(re:replace("*** Failers","[^k]{2,3}$","QmVy",[global])),
+?line <<"abk">> = iolist_to_binary(re:replace("abk","[^k]{2,3}$","L&e",[])),
+?line <<"abk">> = iolist_to_binary(re:replace("abk","[^k]{2,3}$","L&e",[global])),
+?line <<"akb">> = iolist_to_binary(re:replace("akb","[^k]{2,3}$","\\1aD\\1u&",[])),
+?line <<"akb">> = iolist_to_binary(re:replace("akb","[^k]{2,3}$","\\1aD\\1u&",[global])),
+?line <<"akk">> = iolist_to_binary(re:replace("akk","[^k]{2,3}$","lPwfbQvWcRAypQ&",[])),
+?line <<"akk">> = iolist_to_binary(re:replace("akk","[^k]{2,3}$","lPwfbQvWcRAypQ&",[global])),
+?line <<"12345678.b.c.d">> = iolist_to_binary(re:replace("12345678.b.c.d","^\\d{8,}\\@.+[^k]$","VKe&\\1iCfITU\\1&nqEh",[])),
+?line <<"12345678.b.c.d">> = iolist_to_binary(re:replace("12345678.b.c.d","^\\d{8,}\\@.+[^k]$","VKe&\\1iCfITU\\1&nqEh",[global])),
+?line <<"123456789.y.z">> = iolist_to_binary(re:replace("123456789.y.z","^\\d{8,}\\@.+[^k]$","aW\\1Jg&g",[])),
+?line <<"123456789.y.z">> = iolist_to_binary(re:replace("123456789.y.z","^\\d{8,}\\@.+[^k]$","aW\\1Jg&g",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^\\d{8,}\\@.+[^k]$","lHO",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^\\d{8,}\\@.+[^k]$","lHO",[global])),
+?line <<"12345678.y.uk">> = iolist_to_binary(re:replace("12345678.y.uk","^\\d{8,}\\@.+[^k]$","uVLRBqgT\\1c&\\1",[])),
+?line <<"12345678.y.uk">> = iolist_to_binary(re:replace("12345678.y.uk","^\\d{8,}\\@.+[^k]$","uVLRBqgT\\1c&\\1",[global])),
+?line <<"1234567.b.c.d">> = iolist_to_binary(re:replace("1234567.b.c.d","^\\d{8,}\\@.+[^k]$","VRE&uJDdtsECL",[])),
+?line <<"1234567.b.c.d">> = iolist_to_binary(re:replace("1234567.b.c.d","^\\d{8,}\\@.+[^k]$","VRE&uJDdtsECL",[global])),
+?line <<"XJnEEHYdC">> = iolist_to_binary(re:replace("aaaaaaaaa","(a)\\1{8,}","XJnEEHYdC",[])),
+?line <<"XJnEEHYdC">> = iolist_to_binary(re:replace("aaaaaaaaa","(a)\\1{8,}","XJnEEHYdC",[global])),
+?line <<"eviBaaaaaaaaaaaKMfaysHkyJyKi">> = iolist_to_binary(re:replace("aaaaaaaaaa","(a)\\1{8,}","eviB\\1&KMfaysHkyJyKi",[])),
+?line <<"eviBaaaaaaaaaaaKMfaysHkyJyKi">> = iolist_to_binary(re:replace("aaaaaaaaaa","(a)\\1{8,}","eviB\\1&KMfaysHkyJyKi",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(a)\\1{8,}","DjllScfItkb&J&&Nv\\1\\1C",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(a)\\1{8,}","DjllScfItkb&J&&Nv\\1\\1C",[global])),
+?line <<"aaaaaaa">> = iolist_to_binary(re:replace("aaaaaaa","(a)\\1{8,}","W&Bp\\1Bem",[])),
+?line <<"aaaaaaa">> = iolist_to_binary(re:replace("aaaaaaa","(a)\\1{8,}","W&Bp\\1Bem",[global])),
+?line <<"aaaaIEWbcd">> = iolist_to_binary(re:replace("aaaabcd","[^a]","IEW\\1&",[])),
+?line <<"aaaaIEWbIEWcIEWd">> = iolist_to_binary(re:replace("aaaabcd","[^a]","IEW\\1&",[global])),
+?line <<"aarhjHFaNDBbwVabcd">> = iolist_to_binary(re:replace("aaAabcd","[^a]","r\\1hjHFaNDBbwV",[])),
+?line <<"aarhjHFaNDBbwVarhjHFaNDBbwVrhjHFaNDBbwVrhjHFaNDBbwV">> = iolist_to_binary(re:replace("aaAabcd","[^a]","r\\1hjHFaNDBbwV",[global])),
+?line <<"aaaaUVFcd">> = iolist_to_binary(re:replace("aaaabcd","[^a]","U\\1V\\1F",[caseless])),
+?line <<"aaaaUVFUVFUVF">> = iolist_to_binary(re:replace("aaaabcd","[^a]","U\\1V\\1F",[caseless,
+ global])),
+?line <<"aaAacbLmqbDepcd">> = iolist_to_binary(re:replace("aaAabcd","[^a]","c&Lmq&De\\1p",[caseless])),
+?line <<"aaAacbLmqbDepccLmqcDepcdLmqdDep">> = iolist_to_binary(re:replace("aaAabcd","[^a]","c&Lmq&De\\1p",[caseless,
+ global])),
+?line <<"aaaaFtrLcd">> = iolist_to_binary(re:replace("aaaabcd","[^az]","Ftr\\1L",[])),
+?line <<"aaaaFtrLFtrLFtrL">> = iolist_to_binary(re:replace("aaaabcd","[^az]","Ftr\\1L",[global])),
+?line <<"aaxQoACFyabcd">> = iolist_to_binary(re:replace("aaAabcd","[^az]","xQo&C\\1Fy",[])),
+?line <<"aaxQoACFyaxQobCFyxQocCFyxQodCFy">> = iolist_to_binary(re:replace("aaAabcd","[^az]","xQo&C\\1Fy",[global])),
+?line <<"aaaawiJAqfcd">> = iolist_to_binary(re:replace("aaaabcd","[^az]","wiJ\\1Aq\\1f",[caseless])),
+?line <<"aaaawiJAqfwiJAqfwiJAqf">> = iolist_to_binary(re:replace("aaaabcd","[^az]","wiJ\\1Aq\\1f",[caseless,
+ global])),
+?line <<"aaAabheGsmSFcd">> = iolist_to_binary(re:replace("aaAabcd","[^az]","bheGsmSF",[caseless])),
+?line <<"aaAabheGsmSFbheGsmSFbheGsmSF">> = iolist_to_binary(re:replace("aaAabcd","[^az]","bheGsmSF",[caseless,
+ global])),
+?line <<"xxxxxxxxxxxINrCehGlgxfQWogKhXjxxxxxxxxx">> = iolist_to_binary(re:replace("xxxxxxxxxxxPSTAIREISLLxxxxxxxxx","P[^*]TAIRE[^*]{1,6}?LL","INrCe\\1hGlgxfQWogKhXj",[])),
+?line <<"xxxxxxxxxxxINrCehGlgxfQWogKhXjxxxxxxxxx">> = iolist_to_binary(re:replace("xxxxxxxxxxxPSTAIREISLLxxxxxxxxx","P[^*]TAIRE[^*]{1,6}?LL","INrCe\\1hGlgxfQWogKhXj",[global])),
+?line <<"xxxxxxxxxxxSxxxxxxxxx">> = iolist_to_binary(re:replace("xxxxxxxxxxxPSTAIREISLLxxxxxxxxx","P[^*]TAIRE[^*]{1,}?LL","S",[])),
+?line <<"xxxxxxxxxxxSxxxxxxxxx">> = iolist_to_binary(re:replace("xxxxxxxxxxxPSTAIREISLLxxxxxxxxx","P[^*]TAIRE[^*]{1,}?LL","S",[global])),
+?line <<"1yO.230003938DJNUSE">> = iolist_to_binary(re:replace("1.230003938","(\\.\\d\\d[1-9]?)\\d+","yO&DJNUSE",[])),
+?line <<"1yO.230003938DJNUSE">> = iolist_to_binary(re:replace("1.230003938","(\\.\\d\\d[1-9]?)\\d+","yO&DJNUSE",[global])),
+?line <<"1J.875RCmc.875000282SWmWrLgf">> = iolist_to_binary(re:replace("1.875000282","(\\.\\d\\d[1-9]?)\\d+","J\\1RCmc&SWmWrLgf",[])),
+?line <<"1J.875RCmc.875000282SWmWrLgf">> = iolist_to_binary(re:replace("1.875000282","(\\.\\d\\d[1-9]?)\\d+","J\\1RCmc&SWmWrLgf",[global])),
+?line <<"1QhH.23A.235j">> = iolist_to_binary(re:replace("1.235","(\\.\\d\\d[1-9]?)\\d+","QhH\\1A&j",[])),
+?line <<"1QhH.23A.235j">> = iolist_to_binary(re:replace("1.235","(\\.\\d\\d[1-9]?)\\d+","QhH\\1A&j",[global])),
+?line <<"1ASoXGLgq.23gkJkohg.23pCC0003938">> = iolist_to_binary(re:replace("1.230003938","(\\.\\d\\d((?=0)|\\d(?=\\d)))","ASoXGLgq\\1gkJkohg\\1pCC",[])),
+?line <<"1ASoXGLgq.23gkJkohg.23pCC0003938">> = iolist_to_binary(re:replace("1.230003938","(\\.\\d\\d((?=0)|\\d(?=\\d)))","ASoXGLgq\\1gkJkohg\\1pCC",[global])),
+?line <<"1rmMcAlqV000282">> = iolist_to_binary(re:replace("1.875000282","(\\.\\d\\d((?=0)|\\d(?=\\d)))","rmMcAlqV",[])),
+?line <<"1rmMcAlqV000282">> = iolist_to_binary(re:replace("1.875000282","(\\.\\d\\d((?=0)|\\d(?=\\d)))","rmMcAlqV",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(\\.\\d\\d((?=0)|\\d(?=\\d)))","wpfYj&AA",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(\\.\\d\\d((?=0)|\\d(?=\\d)))","wpfYj&AA",[global])),
+?line <<"1.235">> = iolist_to_binary(re:replace("1.235","(\\.\\d\\d((?=0)|\\d(?=\\d)))","Kq&VgFL",[])),
+?line <<"1.235">> = iolist_to_binary(re:replace("1.235","(\\.\\d\\d((?=0)|\\d(?=\\d)))","Kq&VgFL",[global])),
+?line <<"JabwbScGoababcabE">> = iolist_to_binary(re:replace("ab","a(?)b","J&wbSc\\1Go&\\1\\1&c&E",[])),
+?line <<"JabwbScGoababcabE">> = iolist_to_binary(re:replace("ab","a(?)b","J&wbSc\\1Go&\\1\\1&c&E",[global])),
+?line <<"Food is on the Qfoo tableygvPjujxbaDigfoo tablegCefoo table">> = iolist_to_binary(re:replace("Food is on the foo table","\\b(foo)\\s+(\\w+)","Q&ygvPjujxbaDig&gCe&",[caseless])),
+?line <<"Food is on the Qfoo tableygvPjujxbaDigfoo tablegCefoo table">> = iolist_to_binary(re:replace("Food is on the foo table","\\b(foo)\\s+(\\w+)","Q&ygvPjujxbaDig&gCe&",[caseless,
+ global])),
+?line <<"The pBETCXLfood is under the bar in the barWwWn.">> = iolist_to_binary(re:replace("The food is under the bar in the barn.","foo(.*)bar","pBETCXL&WwW",[])),
+?line <<"The pBETCXLfood is under the bar in the barWwWn.">> = iolist_to_binary(re:replace("The food is under the bar in the barn.","foo(.*)bar","pBETCXL&WwW",[global])),
+?line <<"The nfood is under the barnSrtWBfood is under the barXapfood is under the barr in the barn.">> = iolist_to_binary(re:replace("The food is under the bar in the barn.","foo(.*?)bar","n&nSrtWB&Xap&r",[])),
+?line <<"The nfood is under the barnSrtWBfood is under the barXapfood is under the barr in the barn.">> = iolist_to_binary(re:replace("The food is under the bar in the barn.","foo(.*?)bar","n&nSrtWB&Xap&r",[global])),
+?line <<"GI have 2 numbers: 53147mNBu">> = iolist_to_binary(re:replace("I have 2 numbers: 53147","(.*)(\\d*)","G&mNBu",[])),
+?line <<"GI have 2 numbers: 53147mNBuGmNBu">> = iolist_to_binary(re:replace("I have 2 numbers: 53147","(.*)(\\d*)","G&mNBu",[global])),
+?line <<"SI have 2 numbers: 53147">> = iolist_to_binary(re:replace("I have 2 numbers: 53147","(.*)(\\d+)","S&",[])),
+?line <<"SI have 2 numbers: 53147">> = iolist_to_binary(re:replace("I have 2 numbers: 53147","(.*)(\\d+)","S&",[global])),
+?line <<"bGeEvMOYIVDQHJHuI have 2 numbers: 53147">> = iolist_to_binary(re:replace("I have 2 numbers: 53147","(.*?)(\\d*)","bGeEvMO\\1YIVDQ&HJHu",[])),
+?line <<"bGeEvMOYIVDQHJHubGeEvMOIYIVDQIHJHubGeEvMOYIVDQHJHubGeEvMO YIVDQ HJHubGeEvMOYIVDQHJHubGeEvMOhYIVDQhHJHubGeEvMOYIVDQHJHubGeEvMOaYIVDQaHJHubGeEvMOYIVDQHJHubGeEvMOvYIVDQvHJHubGeEvMOYIVDQHJHubGeEvMOeYIVDQeHJHubGeEvMOYIVDQHJHubGeEvMO YIVDQ 2HJHubGeEvMOYIVDQHJHubGeEvMO YIVDQ HJHubGeEvMOYIVDQHJHubGeEvMOnYIVDQnHJHubGeEvMOYIVDQHJHubGeEvMOuYIVDQuHJHubGeEvMOYIVDQHJHubGeEvMOmYIVDQmHJHubGeEvMOYIVDQHJHubGeEvMObYIVDQbHJHubGeEvMOYIVDQHJHubGeEvMOeYIVDQeHJHubGeEvMOYIVDQHJHubGeEvMOrYIVDQrHJHubGeEvMOYIVDQHJHubGeEvMOsYIVDQsHJHubGeEvMOYIVDQHJHubGeEvMO:YIVDQ:HJHubGeEvMOYIVDQHJHubGeEvMO YIVDQ 53147HJHubGeEvMOYIVDQHJHu">> = iolist_to_binary(re:replace("I have 2 numbers: 53147","(.*?)(\\d*)","bGeEvMO\\1YIVDQ&HJHu",[global])),
+?line <<"I have tsI have cgpNHsI have I have U numbers: 53147">> = iolist_to_binary(re:replace("I have 2 numbers: 53147","(.*?)(\\d+)","\\1ts\\1cgpNHs\\1\\1U",[])),
+?line <<"I have tsI have cgpNHsI have I have U numbers: ts numbers: cgpNHs numbers: numbers: U">> = iolist_to_binary(re:replace("I have 2 numbers: 53147","(.*?)(\\d+)","\\1ts\\1cgpNHs\\1\\1U",[global])),
+?line <<"mwinCVPlFdkqGucU">> = iolist_to_binary(re:replace("I have 2 numbers: 53147","(.*)(\\d+)$","mwinCVPlFdkqGucU",[])),
+?line <<"mwinCVPlFdkqGucU">> = iolist_to_binary(re:replace("I have 2 numbers: 53147","(.*)(\\d+)$","mwinCVPlFdkqGucU",[global])),
+?line <<"I have 2 numbers: 53147I have 2 numbers: 53147I have 2 numbers: 53147pEI have 2 numbers: 53147o">> = iolist_to_binary(re:replace("I have 2 numbers: 53147","(.*?)(\\d+)$","&&&pE&o",[])),
+?line <<"I have 2 numbers: 53147I have 2 numbers: 53147I have 2 numbers: 53147pEI have 2 numbers: 53147o">> = iolist_to_binary(re:replace("I have 2 numbers: 53147","(.*?)(\\d+)$","&&&pE&o",[global])),
+?line <<"ym">> = iolist_to_binary(re:replace("I have 2 numbers: 53147","(.*)\\b(\\d+)$","ym",[])),
+?line <<"ym">> = iolist_to_binary(re:replace("I have 2 numbers: 53147","(.*)\\b(\\d+)$","ym",[global])),
+?line <<"FI have 2 numbers: 53147QSb">> = iolist_to_binary(re:replace("I have 2 numbers: 53147","(.*\\D)(\\d+)$","F&QSb",[])),
+?line <<"FI have 2 numbers: 53147QSb">> = iolist_to_binary(re:replace("I have 2 numbers: 53147","(.*\\D)(\\d+)$","F&QSb",[global])),
+?line <<"ABDGFHjyNAtuJTC123">> = iolist_to_binary(re:replace("ABC123","^\\D*(?!123)","&DGFHjyNAtu\\1JT",[])),
+?line <<"ABDGFHjyNAtuJTC123">> = iolist_to_binary(re:replace("ABC123","^\\D*(?!123)","&DGFHjyNAtu\\1JT",[global])),
+?line <<"ABCUxCRnmWFAQVrawlJ445">> = iolist_to_binary(re:replace("ABC445","^(\\D*)(?=\\d)(?!123)","\\1UxCRnmWFAQVrawlJ",[])),
+?line <<"ABCUxCRnmWFAQVrawlJ445">> = iolist_to_binary(re:replace("ABC445","^(\\D*)(?=\\d)(?!123)","\\1UxCRnmWFAQVrawlJ",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(\\D*)(?=\\d)(?!123)","X\\1uOv\\1PUbsw&IOcqB",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(\\D*)(?=\\d)(?!123)","X\\1uOv\\1PUbsw&IOcqB",[global])),
+?line <<"ABC123">> = iolist_to_binary(re:replace("ABC123","^(\\D*)(?=\\d)(?!123)","&efpcH\\1vtp",[])),
+?line <<"ABC123">> = iolist_to_binary(re:replace("ABC123","^(\\D*)(?=\\d)(?!123)","&efpcH\\1vtp",[global])),
+?line <<"X789">> = iolist_to_binary(re:replace("W46]789","^[W-]46]","X",[])),
+?line <<"X789">> = iolist_to_binary(re:replace("W46]789","^[W-]46]","X",[global])),
+?line <<"-46]GqowvnKBMivOCTQ789">> = iolist_to_binary(re:replace("-46]789","^[W-]46]","&GqowvnKBMiv\\1\\1OCTQ",[])),
+?line <<"-46]GqowvnKBMivOCTQ789">> = iolist_to_binary(re:replace("-46]789","^[W-]46]","&GqowvnKBMiv\\1\\1OCTQ",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^[W-]46]","VkkVbQHsQJe\\1Oqgp",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^[W-]46]","VkkVbQHsQJe\\1Oqgp",[global])),
+?line <<"Wall">> = iolist_to_binary(re:replace("Wall","^[W-]46]","A\\1",[])),
+?line <<"Wall">> = iolist_to_binary(re:replace("Wall","^[W-]46]","A\\1",[global])),
+?line <<"Zebra">> = iolist_to_binary(re:replace("Zebra","^[W-]46]","D\\1Gh&rRMY",[])),
+?line <<"Zebra">> = iolist_to_binary(re:replace("Zebra","^[W-]46]","D\\1Gh&rRMY",[global])),
+?line <<"42">> = iolist_to_binary(re:replace("42","^[W-]46]","&NkVKe",[])),
+?line <<"42">> = iolist_to_binary(re:replace("42","^[W-]46]","&NkVKe",[global])),
+?line <<"[abcd]">> = iolist_to_binary(re:replace("[abcd]","^[W-]46]","UhUNReBRM\\1AIyjJpNT",[])),
+?line <<"[abcd]">> = iolist_to_binary(re:replace("[abcd]","^[W-]46]","UhUNReBRM\\1AIyjJpNT",[global])),
+?line <<"]abcd[">> = iolist_to_binary(re:replace("]abcd[","^[W-]46]","&GSivk\\1PUgboDgD\\1Q&\\1",[])),
+?line <<"]abcd[">> = iolist_to_binary(re:replace("]abcd[","^[W-]46]","&GSivk\\1PUgboDgD\\1Q&\\1",[global])),
+?line <<"CiPKWjJuYp46]789">> = iolist_to_binary(re:replace("W46]789","^[W-\\]46]","CiPK&jJuYp",[])),
+?line <<"CiPKWjJuYp46]789">> = iolist_to_binary(re:replace("W46]789","^[W-\\]46]","CiPK&jJuYp",[global])),
+?line <<"WWGQUxNBall">> = iolist_to_binary(re:replace("Wall","^[W-\\]46]","&&G\\1QUxN\\1\\1B",[])),
+?line <<"WWGQUxNBall">> = iolist_to_binary(re:replace("Wall","^[W-\\]46]","&&G\\1QUxN\\1\\1B",[global])),
+?line <<"BBmKOIEOebra">> = iolist_to_binary(re:replace("Zebra","^[W-\\]46]","BBmKOI\\1E\\1O",[])),
+?line <<"BBmKOIEOebra">> = iolist_to_binary(re:replace("Zebra","^[W-\\]46]","BBmKOI\\1E\\1O",[global])),
+?line <<"fsXBGOoQmDJroEwPIXEylophone">> = iolist_to_binary(re:replace("Xylophone","^[W-\\]46]","f\\1s&BGOoQmDJroEwPI&E",[])),
+?line <<"fsXBGOoQmDJroEwPIXEylophone">> = iolist_to_binary(re:replace("Xylophone","^[W-\\]46]","f\\1s&BGOoQmDJroEwPI&E",[global])),
+?line <<"rtkSPUv4c2">> = iolist_to_binary(re:replace("42","^[W-\\]46]","rtkSPUv&c",[])),
+?line <<"rtkSPUv4c2">> = iolist_to_binary(re:replace("42","^[W-\\]46]","rtkSPUv&c",[global])),
+?line <<"AqCR[dTqabcd]">> = iolist_to_binary(re:replace("[abcd]","^[W-\\]46]","AqCR\\1&dTq",[])),
+?line <<"AqCR[dTqabcd]">> = iolist_to_binary(re:replace("[abcd]","^[W-\\]46]","AqCR\\1&dTq",[global])),
+?line <<"XG]JRsPEtL]eoabcd[">> = iolist_to_binary(re:replace("]abcd[","^[W-\\]46]","XG&JRsPEtL&e\\1o",[])),
+?line <<"XG]JRsPEtL]eoabcd[">> = iolist_to_binary(re:replace("]abcd[","^[W-\\]46]","XG&JRsPEtL&e\\1o",[global])),
+?line <<"YrokgJhnnbackslash">> = iolist_to_binary(re:replace("\\backslash","^[W-\\]46]","YrokgJhnn\\1",[])),
+?line <<"YrokgJhnnbackslash">> = iolist_to_binary(re:replace("\\backslash","^[W-\\]46]","YrokgJhnn\\1",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^[W-\\]46]","\\1l",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^[W-\\]46]","\\1l",[global])),
+?line <<"-46]789">> = iolist_to_binary(re:replace("-46]789","^[W-\\]46]","lUctT",[])),
+?line <<"-46]789">> = iolist_to_binary(re:replace("-46]789","^[W-\\]46]","lUctT",[global])),
+?line <<"well">> = iolist_to_binary(re:replace("well","^[W-\\]46]","xELX&QH\\1AsnFr&SH",[])),
+?line <<"well">> = iolist_to_binary(re:replace("well","^[W-\\]46]","xELX&QH\\1AsnFr&SH",[global])),
+?line <<"vword cat dog elephant mussel cow horse canary baboon snake shark otherwordword cat dog elephant mussel cow horse canary baboon snake shark otherwordKteyKVE">> = iolist_to_binary(re:replace("word cat dog elephant mussel cow horse canary baboon snake shark otherword","word (?:[a-zA-Z0-9]+ ){0,10}otherword","v&&KteyKVE\\1",[])),
+?line <<"vword cat dog elephant mussel cow horse canary baboon snake shark otherwordword cat dog elephant mussel cow horse canary baboon snake shark otherwordKteyKVE">> = iolist_to_binary(re:replace("word cat dog elephant mussel cow horse canary baboon snake shark otherword","word (?:[a-zA-Z0-9]+ ){0,10}otherword","v&&KteyKVE\\1",[global])),
+?line <<"word cat dog elephant mussel cow horse canary baboon snake shark">> = iolist_to_binary(re:replace("word cat dog elephant mussel cow horse canary baboon snake shark","word (?:[a-zA-Z0-9]+ ){0,10}otherword","wUEYJgw",[])),
+?line <<"word cat dog elephant mussel cow horse canary baboon snake shark">> = iolist_to_binary(re:replace("word cat dog elephant mussel cow horse canary baboon snake shark","word (?:[a-zA-Z0-9]+ ){0,10}otherword","wUEYJgw",[global])),
+?line <<"word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope">> = iolist_to_binary(re:replace("word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope","word (?:[a-zA-Z0-9]+ ){0,300}otherword","ABdTK\\1Y\\1",[])),
+?line <<"word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope">> = iolist_to_binary(re:replace("word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope","word (?:[a-zA-Z0-9]+ ){0,300}otherword","ABdTK\\1Y\\1",[global])),
+?line <<"CahYoKbcd">> = iolist_to_binary(re:replace("bcd","^(a){0,0}","\\1CahYoK",[])),
+?line <<"CahYoKbcd">> = iolist_to_binary(re:replace("bcd","^(a){0,0}","\\1CahYoK",[global])),
+?line <<"QcFabc">> = iolist_to_binary(re:replace("abc","^(a){0,0}","&QcF",[])),
+?line <<"QcFabc">> = iolist_to_binary(re:replace("abc","^(a){0,0}","&QcF",[global])),
+?line <<"BvdvcHaab">> = iolist_to_binary(re:replace("aab","^(a){0,0}","BvdvcH",[])),
+?line <<"BvdvcHaab">> = iolist_to_binary(re:replace("aab","^(a){0,0}","BvdvcH",[global])),
+?line <<"mtLIyIhdbcd">> = iolist_to_binary(re:replace("bcd","^(a){0,1}","mtL\\1IyIhd",[])),
+?line <<"mtLIyIhdbcd">> = iolist_to_binary(re:replace("bcd","^(a){0,1}","mtL\\1IyIhd",[global])),
+?line <<"oaDoeSPhHaNhncDqkiabc">> = iolist_to_binary(re:replace("abc","^(a){0,1}","o\\1DoeSPhH&NhncDqki\\1",[])),
+?line <<"oaDoeSPhHaNhncDqkiabc">> = iolist_to_binary(re:replace("abc","^(a){0,1}","o\\1DoeSPhH&NhncDqki\\1",[global])),
+?line <<"ahaXsxVhaFHSKPhapJQab">> = iolist_to_binary(re:replace("aab","^(a){0,1}","\\1h\\1XsxVh\\1FHSKPhapJQ",[])),
+?line <<"ahaXsxVhaFHSKPhapJQab">> = iolist_to_binary(re:replace("aab","^(a){0,1}","\\1h\\1XsxVh\\1FHSKPhapJQ",[global])),
+?line <<"iMdtvIhKruTIdObcd">> = iolist_to_binary(re:replace("bcd","^(a){0,2}","iMd\\1\\1\\1tvIhK&r\\1uTIdO",[])),
+?line <<"iMdtvIhKruTIdObcd">> = iolist_to_binary(re:replace("bcd","^(a){0,2}","iMd\\1\\1\\1tvIhK&r\\1uTIdO",[global])),
+?line <<"WYRQMjbc">> = iolist_to_binary(re:replace("abc","^(a){0,2}","WYRQMj",[])),
+?line <<"WYRQMjbc">> = iolist_to_binary(re:replace("abc","^(a){0,2}","WYRQMj",[global])),
+?line <<"XaKbiaaaEub">> = iolist_to_binary(re:replace("aab","^(a){0,2}","XaKbi\\1&Eu",[])),
+?line <<"XaKbiaaaEub">> = iolist_to_binary(re:replace("aab","^(a){0,2}","XaKbi\\1&Eu",[global])),
+?line <<"cFVbcd">> = iolist_to_binary(re:replace("bcd","^(a){0,3}","&c&&FV&",[])),
+?line <<"cFVbcd">> = iolist_to_binary(re:replace("bcd","^(a){0,3}","&c&&FV&",[global])),
+?line <<"gEwbc">> = iolist_to_binary(re:replace("abc","^(a){0,3}","gEw",[])),
+?line <<"gEwbc">> = iolist_to_binary(re:replace("abc","^(a){0,3}","gEw",[global])),
+?line <<"aaSuagMaaaaIaaKb">> = iolist_to_binary(re:replace("aab","^(a){0,3}","&Su\\1gM&&I&K",[])),
+?line <<"aaSuagMaaaaIaaKb">> = iolist_to_binary(re:replace("aab","^(a){0,3}","&Su\\1gM&&I&K",[global])),
+?line <<"GaaahIAJLaMaaaaaSBlaaaTU">> = iolist_to_binary(re:replace("aaa","^(a){0,3}","G&hIAJL\\1M\\1&aSBl&TU",[])),
+?line <<"GaaahIAJLaMaaaaaSBlaaaTU">> = iolist_to_binary(re:replace("aaa","^(a){0,3}","G&hIAJL\\1M\\1&aSBl&TU",[global])),
+?line <<"gcHyvqMebtbcd">> = iolist_to_binary(re:replace("bcd","^(a){0,}","g&cHyvqMebt",[])),
+?line <<"gcHyvqMebtbcd">> = iolist_to_binary(re:replace("bcd","^(a){0,}","g&cHyvqMebt",[global])),
+?line <<"atJaOxHRjOnDbc">> = iolist_to_binary(re:replace("abc","^(a){0,}","\\1tJaOxHRjOnD",[])),
+?line <<"atJaOxHRjOnDbc">> = iolist_to_binary(re:replace("abc","^(a){0,}","\\1tJaOxHRjOnD",[global])),
+?line <<"RlAewSMFrb">> = iolist_to_binary(re:replace("aab","^(a){0,}","RlAewSMFr",[])),
+?line <<"RlAewSMFrb">> = iolist_to_binary(re:replace("aab","^(a){0,}","RlAewSMFr",[global])),
+?line <<"FaaaBoIPaaaLaaaYfapavgA">> = iolist_to_binary(re:replace("aaa","^(a){0,}","F&BoIP&L&Yf\\1p\\1vgA",[])),
+?line <<"FaaaBoIPaaaLaaaYfapavgA">> = iolist_to_binary(re:replace("aaa","^(a){0,}","F&BoIP&L&Yf\\1p\\1vgA",[global])),
+?line <<"baaaaaaaacUvaaaaaaaaCgeDoaRaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaa","^(a){0,}","b&cUv&CgeDo\\1R&",[])),
+?line <<"baaaaaaaacUvaaaaaaaaCgeDoaRaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaa","^(a){0,}","b&cUv&CgeDo\\1R&",[global])),
+?line <<"bcd">> = iolist_to_binary(re:replace("bcd","^(a){1,1}","F&vqwCbrndilc&Wb\\1LRH",[])),
+?line <<"bcd">> = iolist_to_binary(re:replace("bcd","^(a){1,1}","F&vqwCbrndilc&Wb\\1LRH",[global])),
+?line <<"BaaYanfjPxbaabc">> = iolist_to_binary(re:replace("abc","^(a){1,1}","B\\1\\1Y\\1nfjPxb\\1&",[])),
+?line <<"BaaYanfjPxbaabc">> = iolist_to_binary(re:replace("abc","^(a){1,1}","B\\1\\1Y\\1nfjPxb\\1&",[global])),
+?line <<"Pab">> = iolist_to_binary(re:replace("aab","^(a){1,1}","P",[])),
+?line <<"Pab">> = iolist_to_binary(re:replace("aab","^(a){1,1}","P",[global])),
+?line <<"bcd">> = iolist_to_binary(re:replace("bcd","^(a){1,2}","eK\\1B&ypECvCJqtlr&",[])),
+?line <<"bcd">> = iolist_to_binary(re:replace("bcd","^(a){1,2}","eK\\1B&ypECvCJqtlr&",[global])),
+?line <<"QYbc">> = iolist_to_binary(re:replace("abc","^(a){1,2}","QY",[])),
+?line <<"QYbc">> = iolist_to_binary(re:replace("abc","^(a){1,2}","QY",[global])),
+?line <<"MbnVXaaaXhaab">> = iolist_to_binary(re:replace("aab","^(a){1,2}","MbnVX&\\1Xh&",[])),
+?line <<"MbnVXaaaXhaab">> = iolist_to_binary(re:replace("aab","^(a){1,2}","MbnVX&\\1Xh&",[global])),
+?line <<"bcd">> = iolist_to_binary(re:replace("bcd","^(a){1,3}","UKOH",[])),
+?line <<"bcd">> = iolist_to_binary(re:replace("bcd","^(a){1,3}","UKOH",[global])),
+?line <<"TJxKYHFmaaadWlbc">> = iolist_to_binary(re:replace("abc","^(a){1,3}","TJxKYHFm&&\\1dWl",[])),
+?line <<"TJxKYHFmaaadWlbc">> = iolist_to_binary(re:replace("abc","^(a){1,3}","TJxKYHFm&&\\1dWl",[global])),
+?line <<"ub">> = iolist_to_binary(re:replace("aab","^(a){1,3}","u",[])),
+?line <<"ub">> = iolist_to_binary(re:replace("aab","^(a){1,3}","u",[global])),
+?line <<"FOX">> = iolist_to_binary(re:replace("aaa","^(a){1,3}","FOX",[])),
+?line <<"FOX">> = iolist_to_binary(re:replace("aaa","^(a){1,3}","FOX",[global])),
+?line <<"bcd">> = iolist_to_binary(re:replace("bcd","^(a){1,}","W\\1Urn\\1O",[])),
+?line <<"bcd">> = iolist_to_binary(re:replace("bcd","^(a){1,}","W\\1Urn\\1O",[global])),
+?line <<"awalKDgaLeMbc">> = iolist_to_binary(re:replace("abc","^(a){1,}","\\1w\\1lKDg&LeM",[])),
+?line <<"awalKDgaLeMbc">> = iolist_to_binary(re:replace("abc","^(a){1,}","\\1w\\1lKDg&LeM",[global])),
+?line <<"qHVYNjismoeaasSpb">> = iolist_to_binary(re:replace("aab","^(a){1,}","qHVYNjismoe&sSp",[])),
+?line <<"qHVYNjismoeaasSpb">> = iolist_to_binary(re:replace("aab","^(a){1,}","qHVYNjismoe&sSp",[global])),
+?line <<"laa">> = iolist_to_binary(re:replace("aaa","^(a){1,}","la\\1",[])),
+?line <<"laa">> = iolist_to_binary(re:replace("aaa","^(a){1,}","la\\1",[global])),
+?line <<"UJqaaaaaaaarcaaaaaaaaQHavwaGaaaaaaaaoX">> = iolist_to_binary(re:replace("aaaaaaaa","^(a){1,}","UJq&rc&QH\\1vw\\1G&oX",[])),
+?line <<"UJqaaaaaaaarcaaaaaaaaQHavwaGaaaaaaaaoX">> = iolist_to_binary(re:replace("aaaaaaaa","^(a){1,}","UJq&rc&QH\\1vw\\1G&oX",[global])),
+?line <<"borfle
+bib.gifs
+no">> = iolist_to_binary(re:replace("borfle
+bib.gif
+no",".*\\.gif","&s",[])),
+?line <<"borfle
+bib.gifs
+no">> = iolist_to_binary(re:replace("borfle
+bib.gif
+no",".*\\.gif","&s",[global])),
+?line <<"borfle
+BD
+no">> = iolist_to_binary(re:replace("borfle
+bib.gif
+no",".{0,}\\.gif","BD",[])),
+?line <<"borfle
+BD
+no">> = iolist_to_binary(re:replace("borfle
+bib.gif
+no",".{0,}\\.gif","BD",[global])),
+?line <<"borfle
+vDNsbib.gif
+no">> = iolist_to_binary(re:replace("borfle
+bib.gif
+no",".*\\.gif","vDNs&",[multiline])),
+?line <<"borfle
+vDNsbib.gif
+no">> = iolist_to_binary(re:replace("borfle
+bib.gif
+no",".*\\.gif","vDNs&",[multiline,global])),
+?line <<"dPgeQVbGVD
+no">> = iolist_to_binary(re:replace("borfle
+bib.gif
+no",".*\\.gif","dPge\\1QVbGVD",[dotall])),
+?line <<"dPgeQVbGVD
+no">> = iolist_to_binary(re:replace("borfle
+bib.gif
+no",".*\\.gif","dPge\\1QVbGVD",[dotall,global])),
+?line <<"SGyevborfle
+bib.gifCborfle
+bib.gifWUWborfle
+bib.gifHd
+no">> = iolist_to_binary(re:replace("borfle
+bib.gif
+no",".*\\.gif","SGyev&C\\1&\\1\\1WUW&Hd\\1",[multiline,dotall])),
+?line <<"SGyevborfle
+bib.gifCborfle
+bib.gifWUWborfle
+bib.gifHd
+no">> = iolist_to_binary(re:replace("borfle
+bib.gif
+no",".*\\.gif","SGyev&C\\1&\\1\\1WUW&Hd\\1",[multiline,dotall,
+ global])),
+?line <<"borfle
+bib.gif
+BKNYIMcbaV">> = iolist_to_binary(re:replace("borfle
+bib.gif
+no",".*$","BKNYIMcbaV",[])),
+?line <<"borfle
+bib.gif
+BKNYIMcbaVBKNYIMcbaV">> = iolist_to_binary(re:replace("borfle
+bib.gif
+no",".*$","BKNYIMcbaV",[global])),
+?line <<"borflevLMilNh
+bib.gif
+no">> = iolist_to_binary(re:replace("borfle
+bib.gif
+no",".*$","&vLM\\1ilNh\\1",[multiline])),
+?line <<"borflevLMilNhvLMilNh
+bib.gifvLMilNhvLMilNh
+novLMilNhvLMilNh">> = iolist_to_binary(re:replace("borfle
+bib.gif
+no",".*$","&vLM\\1ilNh\\1",[multiline,global])),
+?line <<"borfle
+bib.gif
+noMtTxgborfle
+bib.gif
+noXborfle
+bib.gif
+noqKCRborfle
+bib.gif
+noRFb">> = iolist_to_binary(re:replace("borfle
+bib.gif
+no",".*$","&MtTxg&X&qKCR&RFb",[dotall])),
+?line <<"borfle
+bib.gif
+noMtTxgborfle
+bib.gif
+noXborfle
+bib.gif
+noqKCRborfle
+bib.gif
+noRFbMtTxgXqKCRRFb">> = iolist_to_binary(re:replace("borfle
+bib.gif
+no",".*$","&MtTxg&X&qKCR&RFb",[dotall,global])),
+?line <<"rb">> = iolist_to_binary(re:replace("borfle
+bib.gif
+no",".*$","rb",[multiline,dotall])),
+?line <<"rbrb">> = iolist_to_binary(re:replace("borfle
+bib.gif
+no",".*$","rb",[multiline,dotall,global])),
+?line <<"borfle
+bib.gif
+dTAVnoxiWSnoiuGHA">> = iolist_to_binary(re:replace("borfle
+bib.gif
+no",".*$","dTAV&xiWS&iuGH\\1A\\1",[])),
+?line <<"borfle
+bib.gif
+dTAVnoxiWSnoiuGHAdTAVxiWSiuGHA">> = iolist_to_binary(re:replace("borfle
+bib.gif
+no",".*$","dTAV&xiWS&iuGH\\1A\\1",[global])),
+?line <<"bcnFLv
+bib.gif
+no">> = iolist_to_binary(re:replace("borfle
+bib.gif
+no",".*$","bc\\1nFLv",[multiline])),
+?line <<"bcnFLvbcnFLv
+bcnFLvbcnFLv
+bcnFLvbcnFLv">> = iolist_to_binary(re:replace("borfle
+bib.gif
+no",".*$","bc\\1nFLv",[multiline,global])),
+?line <<"LIQosdWborfle
+bib.gif
+nogcg">> = iolist_to_binary(re:replace("borfle
+bib.gif
+no",".*$","L\\1IQosd\\1W&gcg",[dotall])),
+?line <<"LIQosdWborfle
+bib.gif
+nogcgLIQosdWgcg">> = iolist_to_binary(re:replace("borfle
+bib.gif
+no",".*$","L\\1IQosd\\1W&gcg",[dotall,global])),
+?line <<"EcPBKTVborfle
+bib.gif
+noPrborfle
+bib.gif
+noXxQSc">> = iolist_to_binary(re:replace("borfle
+bib.gif
+no",".*$","EcPBKTV&Pr&XxQSc",[multiline,dotall])),
+?line <<"EcPBKTVborfle
+bib.gif
+noPrborfle
+bib.gif
+noXxQScEcPBKTVPrXxQSc">> = iolist_to_binary(re:replace("borfle
+bib.gif
+no",".*$","EcPBKTV&Pr&XxQSc",[multiline,dotall,global])),
+?line <<"abcde
+uhjjD1234XGTHcATIgH1234X1234XfbByz">> = iolist_to_binary(re:replace("abcde
+1234Xyz","(.*X|^B)","uhjjD&GTHcATIgH\\1\\1fbB",[])),
+?line <<"abcde
+uhjjD1234XGTHcATIgH1234X1234XfbByz">> = iolist_to_binary(re:replace("abcde
+1234Xyz","(.*X|^B)","uhjjD&GTHcATIgH\\1\\1fbB",[global])),
+?line <<"dbqarFoo">> = iolist_to_binary(re:replace("BarFoo","(.*X|^B)","dbq",[])),
+?line <<"dbqarFoo">> = iolist_to_binary(re:replace("BarFoo","(.*X|^B)","dbq",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(.*X|^B)","tdwOa\\1DQul",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(.*X|^B)","tdwOa\\1DQul",[global])),
+?line <<"abcde
+Bar">> = iolist_to_binary(re:replace("abcde
+Bar","(.*X|^B)","j\\1&fFKu\\1tLJjDOmjkU",[])),
+?line <<"abcde
+Bar">> = iolist_to_binary(re:replace("abcde
+Bar","(.*X|^B)","j\\1&fFKu\\1tLJjDOmjkU",[global])),
+?line <<"abcde
+cKv1234XFUwb1234XTPoWrycn1234XO1234Xyz">> = iolist_to_binary(re:replace("abcde
+1234Xyz","(.*X|^B)","cKv&FUwb&TPoWrycn&O&",[multiline])),
+?line <<"abcde
+cKv1234XFUwb1234XTPoWrycn1234XO1234Xyz">> = iolist_to_binary(re:replace("abcde
+1234Xyz","(.*X|^B)","cKv&FUwb&TPoWrycn&O&",[multiline,global])),
+?line <<"FBHWgBBNiGBkIarFoo">> = iolist_to_binary(re:replace("BarFoo","(.*X|^B)","F&HWgB\\1NiG\\1kI",[multiline])),
+?line <<"FBHWgBBNiGBkIarFoo">> = iolist_to_binary(re:replace("BarFoo","(.*X|^B)","F&HWgB\\1NiG\\1kI",[multiline,
+ global])),
+?line <<"abcde
+oArar">> = iolist_to_binary(re:replace("abcde
+Bar","(.*X|^B)","oAr",[multiline])),
+?line <<"abcde
+oArar">> = iolist_to_binary(re:replace("abcde
+Bar","(.*X|^B)","oAr",[multiline,global])),
+?line <<"abcde
+1234XpqJuWOcKJabcde
+1234XyXyvjQwPyz">> = iolist_to_binary(re:replace("abcde
+1234Xyz","(.*X|^B)","\\1pqJuWOcKJ&yXyvjQwP",[dotall])),
+?line <<"abcde
+1234XpqJuWOcKJabcde
+1234XyXyvjQwPyz">> = iolist_to_binary(re:replace("abcde
+1234Xyz","(.*X|^B)","\\1pqJuWOcKJ&yXyvjQwP",[dotall,global])),
+?line <<"BHBBBLbBBgBBoarFoo">> = iolist_to_binary(re:replace("BarFoo","(.*X|^B)","BH\\1&&Lb&&g\\1&o",[dotall])),
+?line <<"BHBBBLbBBgBBoarFoo">> = iolist_to_binary(re:replace("BarFoo","(.*X|^B)","BH\\1&&Lb&&g\\1&o",[dotall,
+ global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(.*X|^B)","&LH",[dotall])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(.*X|^B)","&LH",[dotall,
+ global])),
+?line <<"abcde
+Bar">> = iolist_to_binary(re:replace("abcde
+Bar","(.*X|^B)","HvNOg&qrhICiO",[dotall])),
+?line <<"abcde
+Bar">> = iolist_to_binary(re:replace("abcde
+Bar","(.*X|^B)","HvNOg&qrhICiO",[dotall,global])),
+?line <<"eabcde
+1234Xabcde
+1234XIRtabcde
+1234Xabcde
+1234XCMGsyz">> = iolist_to_binary(re:replace("abcde
+1234Xyz","(.*X|^B)","e\\1&IRt\\1\\1CMGs",[multiline,dotall])),
+?line <<"eabcde
+1234Xabcde
+1234XIRtabcde
+1234Xabcde
+1234XCMGsyz">> = iolist_to_binary(re:replace("abcde
+1234Xyz","(.*X|^B)","e\\1&IRt\\1\\1CMGs",[multiline,dotall,global])),
+?line <<"MBMpwYiMLarFoo">> = iolist_to_binary(re:replace("BarFoo","(.*X|^B)","M\\1MpwYiML",[multiline,
+ dotall])),
+?line <<"MBMpwYiMLarFoo">> = iolist_to_binary(re:replace("BarFoo","(.*X|^B)","M\\1MpwYiML",[multiline,
+ dotall,
+ global])),
+?line <<"abcde
+SOfar">> = iolist_to_binary(re:replace("abcde
+Bar","(.*X|^B)","SOf",[multiline,dotall])),
+?line <<"abcde
+SOfar">> = iolist_to_binary(re:replace("abcde
+Bar","(.*X|^B)","SOf",[multiline,dotall,global])),
+?line <<"Xabcde
+1234XIabcde
+1234XJyz">> = iolist_to_binary(re:replace("abcde
+1234Xyz","(?s)(.*X|^B)","X\\1I\\1J",[])),
+?line <<"Xabcde
+1234XIabcde
+1234XJyz">> = iolist_to_binary(re:replace("abcde
+1234Xyz","(?s)(.*X|^B)","X\\1I\\1J",[global])),
+?line <<"ckBBgDwBNcECcmswBGrarFoo">> = iolist_to_binary(re:replace("BarFoo","(?s)(.*X|^B)","ck\\1&gDw\\1NcECcmsw\\1Gr",[])),
+?line <<"ckBBgDwBNcECcmswBGrarFoo">> = iolist_to_binary(re:replace("BarFoo","(?s)(.*X|^B)","ck\\1&gDw\\1NcECcmsw\\1Gr",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?s)(.*X|^B)","dC\\1SBGDJPgKye\\1iTO",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?s)(.*X|^B)","dC\\1SBGDJPgKye\\1iTO",[global])),
+?line <<"abcde
+Bar">> = iolist_to_binary(re:replace("abcde
+Bar","(?s)(.*X|^B)","hL&HrGi&",[])),
+?line <<"abcde
+Bar">> = iolist_to_binary(re:replace("abcde
+Bar","(?s)(.*X|^B)","hL&HrGi&",[global])),
+?line <<"abcde
+1234Xabcde
+1234XBpOYYilckyz">> = iolist_to_binary(re:replace("abcde
+1234Xyz","(?s:.*X|^B)","&&\\1BpOYYilck",[])),
+?line <<"abcde
+1234Xabcde
+1234XBpOYYilckyz">> = iolist_to_binary(re:replace("abcde
+1234Xyz","(?s:.*X|^B)","&&\\1BpOYYilck",[global])),
+?line <<"ThDpSQKkSSwHarFoo">> = iolist_to_binary(re:replace("BarFoo","(?s:.*X|^B)","ThDpSQ\\1KkSSwH",[])),
+?line <<"ThDpSQKkSSwHarFoo">> = iolist_to_binary(re:replace("BarFoo","(?s:.*X|^B)","ThDpSQ\\1KkSSwH",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?s:.*X|^B)","H&KaW\\1iKok\\1x&gEh&",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?s:.*X|^B)","H&KaW\\1iKok\\1x&gEh&",[global])),
+?line <<"abcde
+Bar">> = iolist_to_binary(re:replace("abcde
+Bar","(?s:.*X|^B)","DFJoEUQUCdLTM\\1ETp",[])),
+?line <<"abcde
+Bar">> = iolist_to_binary(re:replace("abcde
+Bar","(?s:.*X|^B)","DFJoEUQUCdLTM\\1ETp",[global])),
+?line <<"**** Failers">> = iolist_to_binary(re:replace("**** Failers","^.*B","N&QUc\\1IX&",[])),
+?line <<"**** Failers">> = iolist_to_binary(re:replace("**** Failers","^.*B","N&QUc\\1IX&",[global])),
+?line <<"abc
+B">> = iolist_to_binary(re:replace("abc
+B","^.*B","XtHO\\1dFCGIat\\1\\1A\\1yj\\1",[])),
+?line <<"abc
+B">> = iolist_to_binary(re:replace("abc
+B","^.*B","XtHO\\1dFCGIat\\1\\1A\\1yj\\1",[global])),
+?line <<"yKkFabc
+B">> = iolist_to_binary(re:replace("abc
+B","(?s)^.*B","yKkF&",[])),
+?line <<"yKkFabc
+B">> = iolist_to_binary(re:replace("abc
+B","(?s)^.*B","yKkF&",[global])),
+?line <<"abc
+AQ">> = iolist_to_binary(re:replace("abc
+B","(?m)^.*B","AQ",[])),
+?line <<"abc
+AQ">> = iolist_to_binary(re:replace("abc
+B","(?m)^.*B","AQ",[global])),
+?line <<"abc
+BDabc
+BNabc
+BxoUHHabc
+Bo">> = iolist_to_binary(re:replace("abc
+B","(?ms)^.*B","\\1&D&N&xoUHH&o",[])),
+?line <<"abc
+BDabc
+BNabc
+BxoUHHabc
+Bo">> = iolist_to_binary(re:replace("abc
+B","(?ms)^.*B","\\1&D&N&xoUHH&o",[global])),
+?line <<"abc
+GHgiVrjlVxqskBLR">> = iolist_to_binary(re:replace("abc
+B","(?ms)^B","GHgiVrj\\1lVxqsk&LR",[])),
+?line <<"abc
+GHgiVrjlVxqskBLR">> = iolist_to_binary(re:replace("abc
+B","(?ms)^B","GHgiVrj\\1lVxqsk&LR",[global])),
+?line <<"RBtqaBce">> = iolist_to_binary(re:replace("B","(?s)B$","R&tqaBce",[])),
+?line <<"RBtqaBce">> = iolist_to_binary(re:replace("B","(?s)B$","R&tqaBce",[global])),
+?line <<"kG">> = iolist_to_binary(re:replace("123456654321","^[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]","kG",[])),
+?line <<"kG">> = iolist_to_binary(re:replace("123456654321","^[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]","kG",[global])),
+?line <<"Tx">> = iolist_to_binary(re:replace("123456654321","^\\d\\d\\d\\d\\d\\d\\d\\d\\d\\d\\d\\d","Tx",[])),
+?line <<"Tx">> = iolist_to_binary(re:replace("123456654321","^\\d\\d\\d\\d\\d\\d\\d\\d\\d\\d\\d\\d","Tx",[global])),
+?line <<"xB">> = iolist_to_binary(re:replace("123456654321","^[\\d][\\d][\\d][\\d][\\d][\\d][\\d][\\d][\\d][\\d][\\d][\\d]","xB",[])),
+?line <<"xB">> = iolist_to_binary(re:replace("123456654321","^[\\d][\\d][\\d][\\d][\\d][\\d][\\d][\\d][\\d][\\d][\\d][\\d]","xB",[global])),
+?line <<"OpPIBabcabcabcabcDcxDvlIdSoa">> = iolist_to_binary(re:replace("abcabcabcabc","^[abc]{12}","OpPIB&DcxDvlIdSoa",[])),
+?line <<"OpPIBabcabcabcabcDcxDvlIdSoa">> = iolist_to_binary(re:replace("abcabcabcabc","^[abc]{12}","OpPIB&DcxDvlIdSoa",[global])),
+?line <<"LGEMfnjAabcabcabcabcuAotOabcabcabcabcs">> = iolist_to_binary(re:replace("abcabcabcabc","^[a-c]{12}","LGEMfnj\\1A&uAotO&s",[])),
+?line <<"LGEMfnjAabcabcabcabcuAotOabcabcabcabcs">> = iolist_to_binary(re:replace("abcabcabcabc","^[a-c]{12}","LGEMfnj\\1A&uAotO&s",[global])),
+?line <<"PNcwcmOyx">> = iolist_to_binary(re:replace("abcabcabcabc","^(a|b|c){12}","PN\\1w\\1mOyx",[])),
+?line <<"PNcwcmOyx">> = iolist_to_binary(re:replace("abcabcabcabc","^(a|b|c){12}","PN\\1w\\1mOyx",[global])),
+?line <<"hVfRbFrAh">> = iolist_to_binary(re:replace("n","^[abcdefghijklmnopqrstuvwxy0123456789]","hVfRbFrAh",[])),
+?line <<"hVfRbFrAh">> = iolist_to_binary(re:replace("n","^[abcdefghijklmnopqrstuvwxy0123456789]","hVfRbFrAh",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^[abcdefghijklmnopqrstuvwxy0123456789]","R\\1gE\\1TmOo&B&\\1EaaIWLL",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^[abcdefghijklmnopqrstuvwxy0123456789]","R\\1gE\\1TmOo&B&\\1EaaIWLL",[global])),
+?line <<"z">> = iolist_to_binary(re:replace("z","^[abcdefghijklmnopqrstuvwxy0123456789]","dPAGng",[])),
+?line <<"z">> = iolist_to_binary(re:replace("z","^[abcdefghijklmnopqrstuvwxy0123456789]","dPAGng",[global])),
+?line <<"GalPHuLJkabcdJ">> = iolist_to_binary(re:replace("abcd","abcde{0,0}","Gal\\1PHu\\1LJk&J",[])),
+?line <<"GalPHuLJkabcdJ">> = iolist_to_binary(re:replace("abcd","abcde{0,0}","Gal\\1PHu\\1LJk&J",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","abcde{0,0}","nRSqklns\\1RNQ",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","abcde{0,0}","nRSqklns\\1RNQ",[global])),
+?line <<"abce">> = iolist_to_binary(re:replace("abce","abcde{0,0}","aYgl\\1WJ",[])),
+?line <<"abce">> = iolist_to_binary(re:replace("abce","abcde{0,0}","aYgl\\1WJ",[global])),
+?line <<"JSDhTpxGUy">> = iolist_to_binary(re:replace("abe","ab[cd]{0,0}e","J\\1SDhT\\1pxGUy",[])),
+?line <<"JSDhTpxGUy">> = iolist_to_binary(re:replace("abe","ab[cd]{0,0}e","J\\1SDhT\\1pxGUy",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","ab[cd]{0,0}e","K\\1VVqQdlOY\\1IFC",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","ab[cd]{0,0}e","K\\1VVqQdlOY\\1IFC",[global])),
+?line <<"abcde">> = iolist_to_binary(re:replace("abcde","ab[cd]{0,0}e","CBmXc&",[])),
+?line <<"abcde">> = iolist_to_binary(re:replace("abcde","ab[cd]{0,0}e","CBmXc&",[global])),
+?line <<"YKTMKcsKabd">> = iolist_to_binary(re:replace("abd","ab(c){0,0}d","YKT\\1MKcsK&",[])),
+?line <<"YKTMKcsKabd">> = iolist_to_binary(re:replace("abd","ab(c){0,0}d","YKT\\1MKcsK&",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","ab(c){0,0}d","&j&dtuA\\1A&vS",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","ab(c){0,0}d","&j&dtuA\\1A&vS",[global])),
+?line <<"abcd">> = iolist_to_binary(re:replace("abcd","ab(c){0,0}d","&ceeJC\\1HRtWmI",[])),
+?line <<"abcd">> = iolist_to_binary(re:replace("abcd","ab(c){0,0}d","&ceeJC\\1HRtWmI",[global])),
+?line <<"k">> = iolist_to_binary(re:replace("a","a(b*)","\\1k",[])),
+?line <<"k">> = iolist_to_binary(re:replace("a","a(b*)","\\1k",[global])),
+?line <<"abnwnAb">> = iolist_to_binary(re:replace("ab","a(b*)","&nwnA\\1",[])),
+?line <<"abnwnAb">> = iolist_to_binary(re:replace("ab","a(b*)","&nwnA\\1",[global])),
+?line <<"nLIbbbbd">> = iolist_to_binary(re:replace("abbbb","a(b*)","nLI\\1d",[])),
+?line <<"nLIbbbbd">> = iolist_to_binary(re:replace("abbbb","a(b*)","nLI\\1d",[global])),
+?line <<"*** FMxgxBanxQaNgAilers">> = iolist_to_binary(re:replace("*** Failers","a(b*)","Mxgx\\1\\1B&nxQ&NgA",[])),
+?line <<"*** FMxgxBanxQaNgAilers">> = iolist_to_binary(re:replace("*** Failers","a(b*)","Mxgx\\1\\1B&nxQ&NgA",[global])),
+?line <<"bbbbb">> = iolist_to_binary(re:replace("bbbbb","a(b*)","Yho\\1QKp",[])),
+?line <<"bbbbb">> = iolist_to_binary(re:replace("bbbbb","a(b*)","Yho\\1QKp",[global])),
+?line <<"c">> = iolist_to_binary(re:replace("abe","ab\\d{0}e","c",[])),
+?line <<"c">> = iolist_to_binary(re:replace("abe","ab\\d{0}e","c",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","ab\\d{0}e","e\\1Nu\\1BSg\\1Rxb",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","ab\\d{0}e","e\\1Nu\\1BSg\\1Rxb",[global])),
+?line <<"ab1e">> = iolist_to_binary(re:replace("ab1e","ab\\d{0}e","C\\1xDlVAxYcYUK\\1fMs",[])),
+?line <<"ab1e">> = iolist_to_binary(re:replace("ab1e","ab\\d{0}e","C\\1xDlVAxYcYUK\\1fMs",[global])),
+?line <<"the MipoEquickBcm brown fox">> = iolist_to_binary(re:replace("the \"quick\" brown fox","\"([^\\\\\"]+|\\\\.)*\"","MipoE\\1Bcm",[])),
+?line <<"the MipoEquickBcm brown fox">> = iolist_to_binary(re:replace("the \"quick\" brown fox","\"([^\\\\\"]+|\\\\.)*\"","MipoE\\1Bcm",[global])),
+?line <<"\"the \\\"quick\\\" brown fox\"\"the \\\"quick\\\" brown fox\"K brown fox\"the \\\"quick\\\" brown fox\"twdFEi\"the \\\"quick\\\" brown fox\"Tf">> = iolist_to_binary(re:replace("\"the \\\"quick\\\" brown fox\"","\"([^\\\\\"]+|\\\\.)*\"","&&K\\1&twdFEi&Tf",[])),
+?line <<"\"the \\\"quick\\\" brown fox\"\"the \\\"quick\\\" brown fox\"K brown fox\"the \\\"quick\\\" brown fox\"twdFEi\"the \\\"quick\\\" brown fox\"Tf">> = iolist_to_binary(re:replace("\"the \\\"quick\\\" brown fox\"","\"([^\\\\\"]+|\\\\.)*\"","&&K\\1&twdFEi&Tf",[global])),
+?line <<"uOiYpObvYvnabc">> = iolist_to_binary(re:replace("abc","","uOiYp&\\1Obv&Yvn",[])),
+?line <<"uOiYpObvYvnauOiYpObvYvnbuOiYpObvYvncuOiYpObvYvn">> = iolist_to_binary(re:replace("abc","","uOiYp&\\1Obv&Yvn",[global])),
+?line <<"cacbJUVL">> = iolist_to_binary(re:replace("acb","a[^a]b","c&JUVL",[])),
+?line <<"cacbJUVL">> = iolist_to_binary(re:replace("acb","a[^a]b","c&JUVL",[global])),
+?line <<"a
+bnnciOUFa
+bttqb">> = iolist_to_binary(re:replace("a
+b","a[^a]b","&nnciOUF&ttq\\1b",[])),
+?line <<"a
+bnnciOUFa
+bttqb">> = iolist_to_binary(re:replace("a
+b","a[^a]b","&nnciOUF&ttq\\1b",[global])),
+?line <<"acbrJrBLmacbnacb">> = iolist_to_binary(re:replace("acb","a.b","&rJrBLm&n&",[])),
+?line <<"acbrJrBLmacbnacb">> = iolist_to_binary(re:replace("acb","a.b","&rJrBLm&n&",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","a.b","lUyaU",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","a.b","lUyaU",[global])),
+?line <<"a
+b">> = iolist_to_binary(re:replace("a
+b","a.b","&etys",[])),
+?line <<"a
+b">> = iolist_to_binary(re:replace("a
+b","a.b","&etys",[global])),
+?line <<"BRCBYDDacbacbacbLfVw">> = iolist_to_binary(re:replace("acb","a[^a]b","BRCBY\\1D\\1D&&\\1&LfVw",[dotall])),
+?line <<"BRCBYDDacbacbacbLfVw">> = iolist_to_binary(re:replace("acb","a[^a]b","BRCBY\\1D\\1D&&\\1&LfVw",[dotall,
+ global])),
+?line <<"a
+bQkfhPqa
+bka
+byK">> = iolist_to_binary(re:replace("a
+b","a[^a]b","&Qk\\1fhPq&k&yK",[dotall])),
+?line <<"a
+bQkfhPqa
+bka
+byK">> = iolist_to_binary(re:replace("a
+b","a[^a]b","&Qk\\1fhPq&k&yK",[dotall,global])),
+?line <<"nKFpFMMacbmxur">> = iolist_to_binary(re:replace("acb","a.b","\\1nKF\\1\\1pF\\1MM\\1&mxur",[dotall])),
+?line <<"nKFpFMMacbmxur">> = iolist_to_binary(re:replace("acb","a.b","\\1nKF\\1\\1pF\\1MM\\1&mxur",[dotall,
+ global])),
+?line <<"RESrDVpIxqsoAT">> = iolist_to_binary(re:replace("a
+b","a.b","\\1RES\\1rDVpIxqso\\1AT",[dotall])),
+?line <<"RESrDVpIxqsoAT">> = iolist_to_binary(re:replace("a
+b","a.b","\\1RES\\1rDVpIxqso\\1AT",[dotall,global])),
+?line <<"aNchRRBHywejNvbacE">> = iolist_to_binary(re:replace("bac","^(b+?|a){1,2}?c","\\1NchRRBHywejNv&E",[])),
+?line <<"aNchRRBHywejNvbacE">> = iolist_to_binary(re:replace("bac","^(b+?|a){1,2}?c","\\1NchRRBHywejNv&E",[global])),
+?line <<"tOamCbbacgsmxbbac">> = iolist_to_binary(re:replace("bbac","^(b+?|a){1,2}?c","tO\\1mC&gsmx&",[])),
+?line <<"tOamCbbacgsmxbbac">> = iolist_to_binary(re:replace("bbac","^(b+?|a){1,2}?c","tO\\1mC&gsmx&",[global])),
+?line <<"xHTFdauecabbbacGpaol">> = iolist_to_binary(re:replace("bbbac","^(b+?|a){1,2}?c","xHTFd\\1uec\\1&Gp\\1ol",[])),
+?line <<"xHTFdauecabbbacGpaol">> = iolist_to_binary(re:replace("bbbac","^(b+?|a){1,2}?c","xHTFd\\1uec\\1&Gp\\1ol",[global])),
+?line <<"baapjPEIagYbbbbacvbbbbacUPkPJ">> = iolist_to_binary(re:replace("bbbbac","^(b+?|a){1,2}?c","b\\1\\1pjPEI\\1gY&v&UPkPJ",[])),
+?line <<"baapjPEIagYbbbbacvbbbbacUPkPJ">> = iolist_to_binary(re:replace("bbbbac","^(b+?|a){1,2}?c","b\\1\\1pjPEI\\1gY&v&UPkPJ",[global])),
+?line <<"atqCLSTaKnviKn">> = iolist_to_binary(re:replace("bbbbbac","^(b+?|a){1,2}?c","\\1tqCLST\\1KnviKn",[])),
+?line <<"atqCLSTaKnviKn">> = iolist_to_binary(re:replace("bbbbbac","^(b+?|a){1,2}?c","\\1tqCLST\\1KnviKn",[global])),
+?line <<"x">> = iolist_to_binary(re:replace("bac","^(b+|a){1,2}?c","x",[])),
+?line <<"x">> = iolist_to_binary(re:replace("bac","^(b+|a){1,2}?c","x",[global])),
+?line <<"ysaxGbbachYTP">> = iolist_to_binary(re:replace("bbac","^(b+|a){1,2}?c","ysaxG&hYTP",[])),
+?line <<"ysaxGbbachYTP">> = iolist_to_binary(re:replace("bbac","^(b+|a){1,2}?c","ysaxG&hYTP",[global])),
+?line <<"IxpOsaoUxbbbacCEcBow">> = iolist_to_binary(re:replace("bbbac","^(b+|a){1,2}?c","IxpOs\\1oUx&CEcBow",[])),
+?line <<"IxpOsaoUxbbbacCEcBow">> = iolist_to_binary(re:replace("bbbac","^(b+|a){1,2}?c","IxpOs\\1oUx&CEcBow",[global])),
+?line <<"bbbbacDeITf">> = iolist_to_binary(re:replace("bbbbac","^(b+|a){1,2}?c","&DeITf",[])),
+?line <<"bbbbacDeITf">> = iolist_to_binary(re:replace("bbbbac","^(b+|a){1,2}?c","&DeITf",[global])),
+?line <<"XlWabAqKnj">> = iolist_to_binary(re:replace("bbbbbac","^(b+|a){1,2}?c","XlW\\1bAqKnj",[])),
+?line <<"XlWabAqKnj">> = iolist_to_binary(re:replace("bbbbbac","^(b+|a){1,2}?c","XlW\\1bAqKnj",[global])),
+?line <<"x
+b">> = iolist_to_binary(re:replace("x
+b","(?!\\A)x","DxdEs\\1&\\1LKts&",[multiline])),
+?line <<"x
+b">> = iolist_to_binary(re:replace("x
+b","(?!\\A)x","DxdEs\\1&\\1LKts&",[multiline,global])),
+?line <<"aAx">> = iolist_to_binary(re:replace("ax","(?!\\A)x","Ax",[multiline])),
+?line <<"aAx">> = iolist_to_binary(re:replace("ax","(?!\\A)x","Ax",[multiline,
+ global])),
+?line <<"{ab}">> = iolist_to_binary(re:replace("{ab}","\\x0{ab}","aOVgpiCu\\1P\\1xjYe\\1",[])),
+?line <<"{ab}">> = iolist_to_binary(re:replace("{ab}","\\x0{ab}","aOVgpiCu\\1P\\1xjYe\\1",[global])),
+?line <<"PilCDnyDeI">> = iolist_to_binary(re:replace("CD","(A|B)*?CD","Pil&\\1nyDeI",[])),
+?line <<"PilCDnyDeI">> = iolist_to_binary(re:replace("CD","(A|B)*?CD","Pil&\\1nyDeI",[global])),
+?line <<"WrpDiffmnCDPINGCDSe">> = iolist_to_binary(re:replace("CD","(A|B)*CD","WrpDiffmn&PING&Se",[])),
+?line <<"WrpDiffmnCDPINGCDSe">> = iolist_to_binary(re:replace("CD","(A|B)*CD","WrpDiffmn&PING&Se",[global])),
+?line <<"mIeAB">> = iolist_to_binary(re:replace("ABABAB","(AB)*?\\1","mIe",[])),
+?line <<"mIeAB">> = iolist_to_binary(re:replace("ABABAB","(AB)*?\\1","mIe",[global])),
+?line <<"JThaowd">> = iolist_to_binary(re:replace("ABABAB","(AB)*\\1","JThaowd",[])),
+?line <<"JThaowd">> = iolist_to_binary(re:replace("ABABAB","(AB)*\\1","JThaowd",[global])),
+?line <<"mxivbdfooiW">> = iolist_to_binary(re:replace("foo","(?<!bar)foo","m\\1xi\\1\\1vbd&iW",[])),
+?line <<"mxivbdfooiW">> = iolist_to_binary(re:replace("foo","(?<!bar)foo","m\\1xi\\1\\1vbd&iW",[global])),
+?line <<"cathTPTYtGud">> = iolist_to_binary(re:replace("catfood","(?<!bar)foo","hTPTYtGu",[])),
+?line <<"cathTPTYtGud">> = iolist_to_binary(re:replace("catfood","(?<!bar)foo","hTPTYtGu",[global])),
+?line <<"arTMXuVvEElifooRfooXqctle">> = iolist_to_binary(re:replace("arfootle","(?<!bar)foo","TMXu\\1VvEEli&R&Xqc",[])),
+?line <<"arTMXuVvEElifooRfooXqctle">> = iolist_to_binary(re:replace("arfootle","(?<!bar)foo","TMXu\\1VvEEli&R&Xqc",[global])),
+?line <<"rCCfnfoopTfbpOVUOFBsh">> = iolist_to_binary(re:replace("rfoosh","(?<!bar)foo","CCfn&pT\\1fbpOVUOFB",[])),
+?line <<"rCCfnfoopTfbpOVUOFBsh">> = iolist_to_binary(re:replace("rfoosh","(?<!bar)foo","CCfn&pT\\1fbpOVUOFB",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?<!bar)foo","bxdEUE&SEpWXK&",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?<!bar)foo","bxdEUE&SEpWXK&",[global])),
+?line <<"barfoo">> = iolist_to_binary(re:replace("barfoo","(?<!bar)foo","ghAth&\\1XCvK&&",[])),
+?line <<"barfoo">> = iolist_to_binary(re:replace("barfoo","(?<!bar)foo","ghAth&\\1XCvK&&",[global])),
+?line <<"towbarfoo">> = iolist_to_binary(re:replace("towbarfoo","(?<!bar)foo","soY&O&QNmTi\\1xspnti&T",[])),
+?line <<"towbarfoo">> = iolist_to_binary(re:replace("towbarfoo","(?<!bar)foo","soY&O&QNmTi\\1xspnti&T",[global])),
+?line <<"JBHNVNd">> = iolist_to_binary(re:replace("catfood","\\w{3}(?<!bar)foo","J\\1BHN\\1VN\\1",[])),
+?line <<"JBHNVNd">> = iolist_to_binary(re:replace("catfood","\\w{3}(?<!bar)foo","J\\1BHN\\1VN\\1",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","\\w{3}(?<!bar)foo","&ucJ",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","\\w{3}(?<!bar)foo","&ucJ",[global])),
+?line <<"foo">> = iolist_to_binary(re:replace("foo","\\w{3}(?<!bar)foo","uasVxSucjJKX",[])),
+?line <<"foo">> = iolist_to_binary(re:replace("foo","\\w{3}(?<!bar)foo","uasVxSucjJKX",[global])),
+?line <<"barfoo">> = iolist_to_binary(re:replace("barfoo","\\w{3}(?<!bar)foo","u&&Su\\1&YWVvwAftwcE&",[])),
+?line <<"barfoo">> = iolist_to_binary(re:replace("barfoo","\\w{3}(?<!bar)foo","u&&Su\\1&YWVvwAftwcE&",[global])),
+?line <<"towbarfoo">> = iolist_to_binary(re:replace("towbarfoo","\\w{3}(?<!bar)foo","IH",[])),
+?line <<"towbarfoo">> = iolist_to_binary(re:replace("towbarfoo","\\w{3}(?<!bar)foo","IH",[global])),
+?line <<"fooabarSWfoobar">> = iolist_to_binary(re:replace("fooabar","(?<=(foo)a)bar","&SW\\1&",[])),
+?line <<"fooabarSWfoobar">> = iolist_to_binary(re:replace("fooabar","(?<=(foo)a)bar","&SW\\1&",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?<=(foo)a)bar","&ShYlKf",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?<=(foo)a)bar","&ShYlKf",[global])),
+?line <<"bar">> = iolist_to_binary(re:replace("bar","(?<=(foo)a)bar","Usk\\1PJ&",[])),
+?line <<"bar">> = iolist_to_binary(re:replace("bar","(?<=(foo)a)bar","Usk\\1PJ&",[global])),
+?line <<"foobbar">> = iolist_to_binary(re:replace("foobbar","(?<=(foo)a)bar","\\1pXSA",[])),
+?line <<"foobbar">> = iolist_to_binary(re:replace("foobbar","(?<=(foo)a)bar","\\1pXSA",[global])),
+?line <<"gWabcqJMuvLrGqnPLJK">> = iolist_to_binary(re:replace("abc","\\Aabc\\z","gW&qJ\\1MuvLrGqnPLJK",[multiline])),
+?line <<"gWabcqJMuvLrGqnPLJK">> = iolist_to_binary(re:replace("abc","\\Aabc\\z","gW&qJ\\1MuvLrGqnPLJK",[multiline,
+ global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","\\Aabc\\z","tcIt&YpWtGEy\\1p",[multiline])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","\\Aabc\\z","tcIt&YpWtGEy\\1p",[multiline,
+ global])),
+?line <<"abcM">> = iolist_to_binary(re:replace("abc","\\Aabc\\z","&M",[multiline])),
+?line <<"abcM">> = iolist_to_binary(re:replace("abc","\\Aabc\\z","&M",[multiline,
+ global])),
+?line <<"qqq
+abc">> = iolist_to_binary(re:replace("qqq
+abc","\\Aabc\\z","B\\1B\\1fqK\\1nocSHwGCCiM",[multiline])),
+?line <<"qqq
+abc">> = iolist_to_binary(re:replace("qqq
+abc","\\Aabc\\z","B\\1B\\1fqK\\1nocSHwGCCiM",[multiline,global])),
+?line <<"abc
+zzz">> = iolist_to_binary(re:replace("abc
+zzz","\\Aabc\\z","P",[multiline])),
+?line <<"abc
+zzz">> = iolist_to_binary(re:replace("abc
+zzz","\\Aabc\\z","P",[multiline,global])),
+?line <<"qqq
+abc
+zzz">> = iolist_to_binary(re:replace("qqq
+abc
+zzz","\\Aabc\\z","\\1adD\\1",[multiline])),
+?line <<"qqq
+abc
+zzz">> = iolist_to_binary(re:replace("qqq
+abc
+zzz","\\Aabc\\z","\\1adD\\1",[multiline,global])),
+?line <<"1U">> = iolist_to_binary(re:replace("1.230003938","(?>(\\.\\d\\d[1-9]?))\\d+","U",[])),
+?line <<"1U">> = iolist_to_binary(re:replace("1.230003938","(?>(\\.\\d\\d[1-9]?))\\d+","U",[global])),
+?line <<"1bJ.875fwFYOodDWXyr.875tm.875000282.875000282">> = iolist_to_binary(re:replace("1.875000282","(?>(\\.\\d\\d[1-9]?))\\d+","bJ\\1fwFYOodDWXyr\\1tm&&",[])),
+?line <<"1bJ.875fwFYOodDWXyr.875tm.875000282.875000282">> = iolist_to_binary(re:replace("1.875000282","(?>(\\.\\d\\d[1-9]?))\\d+","bJ\\1fwFYOodDWXyr\\1tm&&",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?>(\\.\\d\\d[1-9]?))\\d+","e\\1JPFf&",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?>(\\.\\d\\d[1-9]?))\\d+","e\\1JPFf&",[global])),
+?line <<"1.235">> = iolist_to_binary(re:replace("1.235","(?>(\\.\\d\\d[1-9]?))\\d+","yOPhp&Vy&fKXLBmiJx\\1a",[])),
+?line <<"1.235">> = iolist_to_binary(re:replace("1.235","(?>(\\.\\d\\d[1-9]?))\\d+","yOPhp&Vy&fKXLBmiJx\\1a",[global])),
+?line <<"partynow is the time for all good men to come to the aid of the partycnow is the time for all good men to come to the aid of the partynow is the time for all good men to come to the aid of the partypartyyecj">> = iolist_to_binary(re:replace("now is the time for all good men to come to the aid of the party","^((?>\\w+)|(?>\\s+))*$","\\1&c&&\\1yecj",[])),
+?line <<"partynow is the time for all good men to come to the aid of the partycnow is the time for all good men to come to the aid of the partynow is the time for all good men to come to the aid of the partypartyyecj">> = iolist_to_binary(re:replace("now is the time for all good men to come to the aid of the party","^((?>\\w+)|(?>\\s+))*$","\\1&c&&\\1yecj",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^((?>\\w+)|(?>\\s+))*$","\\1u",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^((?>\\w+)|(?>\\s+))*$","\\1u",[global])),
+?line <<"this is not a line with only words and spaces!">> = iolist_to_binary(re:replace("this is not a line with only words and spaces!","^((?>\\w+)|(?>\\s+))*$","gH&CX\\1&vnufnGXYAun",[])),
+?line <<"this is not a line with only words and spaces!">> = iolist_to_binary(re:replace("this is not a line with only words and spaces!","^((?>\\w+)|(?>\\s+))*$","gH&CX\\1&vnufnGXYAun",[global])),
+?line <<"K1234512345aH12345a">> = iolist_to_binary(re:replace("12345a","(\\d+)(\\w)","K\\1&H&",[])),
+?line <<"K1234512345aH12345a">> = iolist_to_binary(re:replace("12345a","(\\d+)(\\w)","K\\1&H&",[global])),
+?line <<"IdNK+">> = iolist_to_binary(re:replace("12345+","(\\d+)(\\w)","IdNK",[])),
+?line <<"IdNK+">> = iolist_to_binary(re:replace("12345+","(\\d+)(\\w)","IdNK",[global])),
+?line <<"jvjjhmthsl">> = iolist_to_binary(re:replace("12345a","((?>\\d+))(\\w)","jvjjhmthsl",[])),
+?line <<"jvjjhmthsl">> = iolist_to_binary(re:replace("12345a","((?>\\d+))(\\w)","jvjjhmthsl",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","((?>\\d+))(\\w)","eK&NTn&\\1T",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","((?>\\d+))(\\w)","eK&NTn&\\1T",[global])),
+?line <<"12345+">> = iolist_to_binary(re:replace("12345+","((?>\\d+))(\\w)","&&TXSquRgMqkDs&K&",[])),
+?line <<"12345+">> = iolist_to_binary(re:replace("12345+","((?>\\d+))(\\w)","&&TXSquRgMqkDs&K&",[global])),
+?line <<"NeYcvQCaaabtbOkx">> = iolist_to_binary(re:replace("aaab","(?>a+)b","NeYcvQC&tbOkx\\1",[])),
+?line <<"NeYcvQCaaabtbOkx">> = iolist_to_binary(re:replace("aaab","(?>a+)b","NeYcvQC&tbOkx\\1",[global])),
+?line <<"aaabbaaabFOSaaabKKtRUNaaabLDTCH">> = iolist_to_binary(re:replace("aaab","((?>a+)b)","&b&FOS&KKtRUN\\1LDTCH",[])),
+?line <<"aaabbaaabFOSaaabKKtRUNaaabLDTCH">> = iolist_to_binary(re:replace("aaab","((?>a+)b)","&b&FOS&KKtRUN\\1LDTCH",[global])),
+?line <<"xaaabaaabaaaiaaabCaGaaaaaabaaaaaaaaabaaabaaaF">> = iolist_to_binary(re:replace("aaab","(?>(a+))b","x\\1b&\\1i&CaG\\1&\\1\\1&&\\1F",[])),
+?line <<"xaaabaaabaaaiaaabCaGaaaaaabaaaaaaaaabaaabaaaF">> = iolist_to_binary(re:replace("aaab","(?>(a+))b","x\\1b&\\1i&CaG\\1&\\1\\1&&\\1F",[global])),
+?line <<"aaaLDSAYvgtbbbotccc">> = iolist_to_binary(re:replace("aaabbbccc","(?>b)+","LDSAYvgt&ot",[])),
+?line <<"aaaLDSAYvgtbbbotccc">> = iolist_to_binary(re:replace("aaabbbccc","(?>b)+","LDSAYvgt&ot",[global])),
+?line <<"ABQFhQjYaaabbbbcAcccd">> = iolist_to_binary(re:replace("aaabbbbccccd","(?>a+|b+|c+)*c","ABQ\\1Fh\\1QjY&A",[])),
+?line <<"ABQFhQjYaaabbbbcAABQFhQjYcAABQFhQjYcAABQFhQjYcAd">> = iolist_to_binary(re:replace("aaabbbbccccd","(?>a+|b+|c+)*c","ABQ\\1Fh\\1QjY&A",[global])),
+?line <<"((xiabc(ade)ufh()()xpJf">> = iolist_to_binary(re:replace("((abc(ade)ufh()()x","((?>[^()]+)|\\([^()]*\\))+","\\1i&pJf",[])),
+?line <<"((xiabc(ade)ufh()()xpJf">> = iolist_to_binary(re:replace("((abc(ade)ufh()()x","((?>[^()]+)|\\([^()]*\\))+","\\1i&pJf",[global])),
+?line <<"NBF">> = iolist_to_binary(re:replace("(abc)","\\(((?>[^()]+)|\\([^()]+\\))+\\)","NBF",[])),
+?line <<"NBF">> = iolist_to_binary(re:replace("(abc)","\\(((?>[^()]+)|\\([^()]+\\))+\\)","NBF",[global])),
+?line <<"(abc(def)xyz)AFLTv">> = iolist_to_binary(re:replace("(abc(def)xyz)","\\(((?>[^()]+)|\\([^()]+\\))+\\)","&AFLTv",[])),
+?line <<"(abc(def)xyz)AFLTv">> = iolist_to_binary(re:replace("(abc(def)xyz)","\\(((?>[^()]+)|\\([^()]+\\))+\\)","&AFLTv",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","\\(((?>[^()]+)|\\([^()]+\\))+\\)","P\\1OC",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","\\(((?>[^()]+)|\\([^()]+\\))+\\)","P\\1OC",[global])),
+?line <<"((()aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa">> = iolist_to_binary(re:replace("((()aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","\\(((?>[^()]+)|\\([^()]+\\))+\\)","u\\1\\1H\\1TOt\\1fVI&X",[])),
+?line <<"((()aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa">> = iolist_to_binary(re:replace("((()aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","\\(((?>[^()]+)|\\([^()]+\\))+\\)","u\\1\\1H\\1TOt\\1fVI&X",[global])),
+?line <<"E">> = iolist_to_binary(re:replace("ab","a(?-i)b","E",[caseless])),
+?line <<"E">> = iolist_to_binary(re:replace("ab","a(?-i)b","E",[caseless,
+ global])),
+?line <<"hAboOovpk">> = iolist_to_binary(re:replace("Ab","a(?-i)b","h&oOovpk",[caseless])),
+?line <<"hAboOovpk">> = iolist_to_binary(re:replace("Ab","a(?-i)b","h&oOovpk",[caseless,
+ global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","a(?-i)b","liOu",[caseless])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","a(?-i)b","liOu",[caseless,
+ global])),
+?line <<"aB">> = iolist_to_binary(re:replace("aB","a(?-i)b","P",[caseless])),
+?line <<"aB">> = iolist_to_binary(re:replace("aB","a(?-i)b","P",[caseless,
+ global])),
+?line <<"AB">> = iolist_to_binary(re:replace("AB","a(?-i)b","GdSF&e&",[caseless])),
+?line <<"AB">> = iolist_to_binary(re:replace("AB","a(?-i)b","GdSF&e&",[caseless,
+ global])),
+?line <<"a bcd eSPWrUhOwa">> = iolist_to_binary(re:replace("a bcd e","(a (?x)b c)d e","&SPWrUhOwa",[])),
+?line <<"a bcd eSPWrUhOwa">> = iolist_to_binary(re:replace("a bcd e","(a (?x)b c)d e","&SPWrUhOwa",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(a (?x)b c)d e","IgDGvOUoEIi",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(a (?x)b c)d e","IgDGvOUoEIi",[global])),
+?line <<"a b cd e">> = iolist_to_binary(re:replace("a b cd e","(a (?x)b c)d e","C\\1Lora&uj\\1nePq",[])),
+?line <<"a b cd e">> = iolist_to_binary(re:replace("a b cd e","(a (?x)b c)d e","C\\1Lora&uj\\1nePq",[global])),
+?line <<"abcd e">> = iolist_to_binary(re:replace("abcd e","(a (?x)b c)d e","M",[])),
+?line <<"abcd e">> = iolist_to_binary(re:replace("abcd e","(a (?x)b c)d e","M",[global])),
+?line <<"a bcde">> = iolist_to_binary(re:replace("a bcde","(a (?x)b c)d e","mNwUc&",[])),
+?line <<"a bcde">> = iolist_to_binary(re:replace("a bcde","(a (?x)b c)d e","mNwUc&",[global])),
+?line <<"a bcde fTra bcde fnDatbuPn">> = iolist_to_binary(re:replace("a bcde f","(a b(?x)c d (?-x)e f)","&Tr\\1nDatbuPn",[])),
+?line <<"a bcde fTra bcde fnDatbuPn">> = iolist_to_binary(re:replace("a bcde f","(a b(?x)c d (?-x)e f)","&Tr\\1nDatbuPn",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(a b(?x)c d (?-x)e f)","\\1AXE&qrGnJBeg",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(a b(?x)c d (?-x)e f)","\\1AXE&qrGnJBeg",[global])),
+?line <<"abcdef">> = iolist_to_binary(re:replace("abcdef","(a b(?x)c d (?-x)e f)","YXaHuSXEMrxHLIUXuNu\\1",[])),
+?line <<"abcdef">> = iolist_to_binary(re:replace("abcdef","(a b(?x)c d (?-x)e f)","YXaHuSXEMrxHLIUXuNu\\1",[global])),
+?line <<"AmT">> = iolist_to_binary(re:replace("abc","(a(?i)b)c","AmT",[])),
+?line <<"AmT">> = iolist_to_binary(re:replace("abc","(a(?i)b)c","AmT",[global])),
+?line <<"CYjrwVi">> = iolist_to_binary(re:replace("aBc","(a(?i)b)c","CYjrwVi",[])),
+?line <<"CYjrwVi">> = iolist_to_binary(re:replace("aBc","(a(?i)b)c","CYjrwVi",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(a(?i)b)c","STYFgfjhE&dcc",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(a(?i)b)c","STYFgfjhE&dcc",[global])),
+?line <<"abC">> = iolist_to_binary(re:replace("abC","(a(?i)b)c","BAcmfc\\1fAfr&o",[])),
+?line <<"abC">> = iolist_to_binary(re:replace("abC","(a(?i)b)c","BAcmfc\\1fAfr&o",[global])),
+?line <<"aBC">> = iolist_to_binary(re:replace("aBC","(a(?i)b)c","NGkAgBCJxbCgR",[])),
+?line <<"aBC">> = iolist_to_binary(re:replace("aBC","(a(?i)b)c","NGkAgBCJxbCgR",[global])),
+?line <<"Abc">> = iolist_to_binary(re:replace("Abc","(a(?i)b)c","aS&kKYGwkOB&YhadhLX",[])),
+?line <<"Abc">> = iolist_to_binary(re:replace("Abc","(a(?i)b)c","aS&kKYGwkOB&YhadhLX",[global])),
+?line <<"ABc">> = iolist_to_binary(re:replace("ABc","(a(?i)b)c","hP\\1RiAIeDp",[])),
+?line <<"ABc">> = iolist_to_binary(re:replace("ABc","(a(?i)b)c","hP\\1RiAIeDp",[global])),
+?line <<"ABC">> = iolist_to_binary(re:replace("ABC","(a(?i)b)c","Jj&j\\1&I&\\1&CR\\1qDG",[])),
+?line <<"ABC">> = iolist_to_binary(re:replace("ABC","(a(?i)b)c","Jj&j\\1&I&\\1&CR\\1qDG",[global])),
+?line <<"AbC">> = iolist_to_binary(re:replace("AbC","(a(?i)b)c","\\1h\\1XCNuqcxa",[])),
+?line <<"AbC">> = iolist_to_binary(re:replace("AbC","(a(?i)b)c","\\1h\\1XCNuqcxa",[global])),
+?line <<"hsDxrqJjHQabc">> = iolist_to_binary(re:replace("abc","a(?i:b)c","hsDxrqJjHQ&",[])),
+?line <<"hsDxrqJjHQabc">> = iolist_to_binary(re:replace("abc","a(?i:b)c","hsDxrqJjHQ&",[global])),
+?line <<"QltXULOSWaBcFaBcS">> = iolist_to_binary(re:replace("aBc","a(?i:b)c","Qlt\\1XU\\1L\\1OSW&F&S",[])),
+?line <<"QltXULOSWaBcFaBcS">> = iolist_to_binary(re:replace("aBc","a(?i:b)c","Qlt\\1XU\\1L\\1OSW&F&S",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","a(?i:b)c","owyoniUsut",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","a(?i:b)c","owyoniUsut",[global])),
+?line <<"ABC">> = iolist_to_binary(re:replace("ABC","a(?i:b)c","unB&TlphDWAD",[])),
+?line <<"ABC">> = iolist_to_binary(re:replace("ABC","a(?i:b)c","unB&TlphDWAD",[global])),
+?line <<"abC">> = iolist_to_binary(re:replace("abC","a(?i:b)c","\\1XaX&kAbe&\\1V",[])),
+?line <<"abC">> = iolist_to_binary(re:replace("abC","a(?i:b)c","\\1XaX&kAbe&\\1V",[global])),
+?line <<"aBC">> = iolist_to_binary(re:replace("aBC","a(?i:b)c","IY\\1aQ&tM\\1",[])),
+?line <<"aBC">> = iolist_to_binary(re:replace("aBC","a(?i:b)c","IY\\1aQ&tM\\1",[global])),
+?line <<"aBcOHQouBOaBc">> = iolist_to_binary(re:replace("aBc","a(?i:b)*c","&O\\1HQo\\1uBO&",[])),
+?line <<"aBcOHQouBOaBc">> = iolist_to_binary(re:replace("aBc","a(?i:b)*c","&O\\1HQo\\1uBO&",[global])),
+?line <<"lvjhpFaBBceaBBciWQNaBBcr">> = iolist_to_binary(re:replace("aBBc","a(?i:b)*c","lvjhpF&e&i\\1WQN\\1&r",[])),
+?line <<"lvjhpFaBBceaBBciWQNaBBcr">> = iolist_to_binary(re:replace("aBBc","a(?i:b)*c","lvjhpF&e&i\\1WQN\\1&r",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","a(?i:b)*c","\\1",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","a(?i:b)*c","\\1",[global])),
+?line <<"aBC">> = iolist_to_binary(re:replace("aBC","a(?i:b)*c","OaR&&ytX",[])),
+?line <<"aBC">> = iolist_to_binary(re:replace("aBC","a(?i:b)*c","OaR&&ytX",[global])),
+?line <<"aBBC">> = iolist_to_binary(re:replace("aBBC","a(?i:b)*c","Su",[])),
+?line <<"aBBC">> = iolist_to_binary(re:replace("aBBC","a(?i:b)*c","Su",[global])),
+?line <<"abcdabcdalFfabcdsPxC">> = iolist_to_binary(re:replace("abcd","a(?=b(?i)c)\\w\\wd","&&alFf&sPxC",[])),
+?line <<"abcdabcdalFfabcdsPxC">> = iolist_to_binary(re:replace("abcd","a(?=b(?i)c)\\w\\wd","&&alFf&sPxC",[global])),
+?line <<"hNuQEFvcSEabCdQTlwEabCd">> = iolist_to_binary(re:replace("abCd","a(?=b(?i)c)\\w\\wd","hNuQEFvcSE\\1&QTlwE&",[])),
+?line <<"hNuQEFvcSEabCdQTlwEabCd">> = iolist_to_binary(re:replace("abCd","a(?=b(?i)c)\\w\\wd","hNuQEFvcSE\\1&QTlwE&",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","a(?=b(?i)c)\\w\\wd","YLT",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","a(?=b(?i)c)\\w\\wd","YLT",[global])),
+?line <<"aBCd">> = iolist_to_binary(re:replace("aBCd","a(?=b(?i)c)\\w\\wd","u",[])),
+?line <<"aBCd">> = iolist_to_binary(re:replace("aBCd","a(?=b(?i)c)\\w\\wd","u",[global])),
+?line <<"abcD">> = iolist_to_binary(re:replace("abcD","a(?=b(?i)c)\\w\\wd","PIaL\\1rCHujWQjtBluw",[])),
+?line <<"abcD">> = iolist_to_binary(re:replace("abcD","a(?=b(?i)c)\\w\\wd","PIaL\\1rCHujWQjtBluw",[global])),
+?line <<"JklClgvcUHdcbpmore than million">> = iolist_to_binary(re:replace("more than million","(?s-i:more.*than).*million","JklCl\\1gvc\\1UHdcbp&",[caseless])),
+?line <<"JklClgvcUHdcbpmore than million">> = iolist_to_binary(re:replace("more than million","(?s-i:more.*than).*million","JklCl\\1gvc\\1UHdcbp&",[caseless,
+ global])),
+?line <<"RaiCEcYVVcTj">> = iolist_to_binary(re:replace("more than MILLION","(?s-i:more.*than).*million","R\\1\\1\\1aiCEcYVVcTj",[caseless])),
+?line <<"RaiCEcYVVcTj">> = iolist_to_binary(re:replace("more than MILLION","(?s-i:more.*than).*million","R\\1\\1\\1aiCEcYVVcTj",[caseless,
+ global])),
+?line <<"AGtSe">> = iolist_to_binary(re:replace("more
+ than Million","(?s-i:more.*than).*million","AGtSe",[caseless])),
+?line <<"AGtSe">> = iolist_to_binary(re:replace("more
+ than Million","(?s-i:more.*than).*million","AGtSe",[caseless,global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?s-i:more.*than).*million","vIAbYe&Vw\\1&VD",[caseless])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?s-i:more.*than).*million","vIAbYe&Vw\\1&VD",[caseless,
+ global])),
+?line <<"MORE THAN MILLION">> = iolist_to_binary(re:replace("MORE THAN MILLION","(?s-i:more.*than).*million","LhBYPjwD\\1kJ\\1",[caseless])),
+?line <<"MORE THAN MILLION">> = iolist_to_binary(re:replace("MORE THAN MILLION","(?s-i:more.*than).*million","LhBYPjwD\\1kJ\\1",[caseless,
+ global])),
+?line <<"more
+ than
+ million">> = iolist_to_binary(re:replace("more
+ than
+ million","(?s-i:more.*than).*million","SSp\\1ttOwEGO&H",[caseless])),
+?line <<"more
+ than
+ million">> = iolist_to_binary(re:replace("more
+ than
+ million","(?s-i:more.*than).*million","SSp\\1ttOwEGO&H",[caseless,
+ global])),
+?line <<"dmore than millionhFexWTaTmclBHK">> = iolist_to_binary(re:replace("more than million","(?:(?s-i)more.*than).*million","d&hFexWTaT\\1\\1mc\\1\\1lBHK",[caseless])),
+?line <<"dmore than millionhFexWTaTmclBHK">> = iolist_to_binary(re:replace("more than million","(?:(?s-i)more.*than).*million","d&hFexWTaT\\1\\1mc\\1\\1lBHK",[caseless,
+ global])),
+?line <<"wcVAikDmore than MILLIONFsmore than MILLIONIceKiuDm">> = iolist_to_binary(re:replace("more than MILLION","(?:(?s-i)more.*than).*million","wcVAikD&Fs&Ice\\1KiuDm",[caseless])),
+?line <<"wcVAikDmore than MILLIONFsmore than MILLIONIceKiuDm">> = iolist_to_binary(re:replace("more than MILLION","(?:(?s-i)more.*than).*million","wcVAikD&Fs&Ice\\1KiuDm",[caseless,
+ global])),
+?line <<"BMxnsX">> = iolist_to_binary(re:replace("more
+ than Million","(?:(?s-i)more.*than).*million","BMx\\1nsX",[caseless])),
+?line <<"BMxnsX">> = iolist_to_binary(re:replace("more
+ than Million","(?:(?s-i)more.*than).*million","BMx\\1nsX",[caseless,
+ global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?:(?s-i)more.*than).*million","e\\1KeC\\1LrMA",[caseless])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?:(?s-i)more.*than).*million","e\\1KeC\\1LrMA",[caseless,
+ global])),
+?line <<"MORE THAN MILLION">> = iolist_to_binary(re:replace("MORE THAN MILLION","(?:(?s-i)more.*than).*million","Oo&U&\\1O\\1royLyh\\1Uj\\1&e",[caseless])),
+?line <<"MORE THAN MILLION">> = iolist_to_binary(re:replace("MORE THAN MILLION","(?:(?s-i)more.*than).*million","Oo&U&\\1O\\1royLyh\\1Uj\\1&e",[caseless,
+ global])),
+?line <<"more
+ than
+ million">> = iolist_to_binary(re:replace("more
+ than
+ million","(?:(?s-i)more.*than).*million","rsd\\1UhwpU\\1&S",[caseless])),
+?line <<"more
+ than
+ million">> = iolist_to_binary(re:replace("more
+ than
+ million","(?:(?s-i)more.*than).*million","rsd\\1UhwpU\\1&S",[caseless,
+ global])),
+?line <<"rTdtycUabcoabcVaVEt">> = iolist_to_binary(re:replace("abc","(?>a(?i)b+)+c","r\\1\\1T\\1dtycU&o&V\\1aV\\1Et",[])),
+?line <<"rTdtycUabcoabcVaVEt">> = iolist_to_binary(re:replace("abc","(?>a(?i)b+)+c","r\\1\\1T\\1dtycU&o&V\\1aV\\1Et",[global])),
+?line <<"geFTAcqhWJc">> = iolist_to_binary(re:replace("aBbc","(?>a(?i)b+)+c","geFTAc\\1qhWJ\\1c",[])),
+?line <<"geFTAcqhWJc">> = iolist_to_binary(re:replace("aBbc","(?>a(?i)b+)+c","geFTAc\\1qhWJ\\1c",[global])),
+?line <<"lHStMaBBcnaBBcjCaBBcgdfm">> = iolist_to_binary(re:replace("aBBc","(?>a(?i)b+)+c","lHStM&n&jC&g\\1df\\1m",[])),
+?line <<"lHStMaBBcnaBBcjCaBBcgdfm">> = iolist_to_binary(re:replace("aBBc","(?>a(?i)b+)+c","lHStM&n&jC&g\\1df\\1m",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?>a(?i)b+)+c","U\\1pOiN&FCXl",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?>a(?i)b+)+c","U\\1pOiN&FCXl",[global])),
+?line <<"Abc">> = iolist_to_binary(re:replace("Abc","(?>a(?i)b+)+c","h",[])),
+?line <<"Abc">> = iolist_to_binary(re:replace("Abc","(?>a(?i)b+)+c","h",[global])),
+?line <<"abAb">> = iolist_to_binary(re:replace("abAb","(?>a(?i)b+)+c","f\\1\\1DwX\\1Y&y\\1dgv&A\\1",[])),
+?line <<"abAb">> = iolist_to_binary(re:replace("abAb","(?>a(?i)b+)+c","f\\1\\1DwX\\1Y&y\\1dgv&A\\1",[global])),
+?line <<"abbC">> = iolist_to_binary(re:replace("abbC","(?>a(?i)b+)+c","&\\1Gd&r\\1shP",[])),
+?line <<"abbC">> = iolist_to_binary(re:replace("abbC","(?>a(?i)b+)+c","&\\1Gd&r\\1shP",[global])),
+?line <<"VIaLabcabcCabcyvwsI">> = iolist_to_binary(re:replace("abc","(?=a(?i)b)\\w\\wc","VIaL&&C&yvwsI",[])),
+?line <<"VIaLabcabcCabcyvwsI">> = iolist_to_binary(re:replace("abc","(?=a(?i)b)\\w\\wc","VIaL&&C&yvwsI",[global])),
+?line <<"gaBcaBc">> = iolist_to_binary(re:replace("aBc","(?=a(?i)b)\\w\\wc","g&&",[])),
+?line <<"gaBcaBc">> = iolist_to_binary(re:replace("aBc","(?=a(?i)b)\\w\\wc","g&&",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?=a(?i)b)\\w\\wc","RMcFr&",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?=a(?i)b)\\w\\wc","RMcFr&",[global])),
+?line <<"Ab">> = iolist_to_binary(re:replace("Ab","(?=a(?i)b)\\w\\wc","y\\1&kD&os\\1E",[])),
+?line <<"Ab">> = iolist_to_binary(re:replace("Ab","(?=a(?i)b)\\w\\wc","y\\1&kD&os\\1E",[global])),
+?line <<"abC">> = iolist_to_binary(re:replace("abC","(?=a(?i)b)\\w\\wc","ms\\1m",[])),
+?line <<"abC">> = iolist_to_binary(re:replace("abC","(?=a(?i)b)\\w\\wc","ms\\1m",[global])),
+?line <<"aBC">> = iolist_to_binary(re:replace("aBC","(?=a(?i)b)\\w\\wc","lD&&vcs",[])),
+?line <<"aBC">> = iolist_to_binary(re:replace("aBC","(?=a(?i)b)\\w\\wc","lD&&vcs",[global])),
+?line <<"abxqXfVViuPuvfMxxcvcj">> = iolist_to_binary(re:replace("abxxc","(?<=a(?i)b)(\\w\\w)c","xqXfVViuPuvfM&vcj",[])),
+?line <<"abxqXfVViuPuvfMxxcvcj">> = iolist_to_binary(re:replace("abxxc","(?<=a(?i)b)(\\w\\w)c","xqXfVViuPuvfM&vcj",[global])),
+?line <<"aBXoxxcXtiuxxXqWYfixxKxxcxxUs">> = iolist_to_binary(re:replace("aBxxc","(?<=a(?i)b)(\\w\\w)c","Xo&Xtiu\\1XqWYfi\\1K&\\1Us",[])),
+?line <<"aBXoxxcXtiuxxXqWYfixxKxxcxxUs">> = iolist_to_binary(re:replace("aBxxc","(?<=a(?i)b)(\\w\\w)c","Xo&Xtiu\\1XqWYfi\\1K&\\1Us",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?<=a(?i)b)(\\w\\w)c","cGWOK&O&A\\1Xq&&aF\\1G",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?<=a(?i)b)(\\w\\w)c","cGWOK&O&A\\1Xq&&aF\\1G",[global])),
+?line <<"Abxxc">> = iolist_to_binary(re:replace("Abxxc","(?<=a(?i)b)(\\w\\w)c","uosfXS&Drr&Nsg",[])),
+?line <<"Abxxc">> = iolist_to_binary(re:replace("Abxxc","(?<=a(?i)b)(\\w\\w)c","uosfXS&Drr&Nsg",[global])),
+?line <<"ABxxc">> = iolist_to_binary(re:replace("ABxxc","(?<=a(?i)b)(\\w\\w)c","mKjv&im",[])),
+?line <<"ABxxc">> = iolist_to_binary(re:replace("ABxxc","(?<=a(?i)b)(\\w\\w)c","mKjv&im",[global])),
+?line <<"abxxC">> = iolist_to_binary(re:replace("abxxC","(?<=a(?i)b)(\\w\\w)c","ferUg\\1J\\1T\\1kWcDAY\\1jM",[])),
+?line <<"abxxC">> = iolist_to_binary(re:replace("abxxC","(?<=a(?i)b)(\\w\\w)c","ferUg\\1J\\1T\\1kWcDAY\\1jM",[global])),
+?line <<"a">> = iolist_to_binary(re:replace("aA","(?:(a)|b)(?(1)A|B)","\\1",[])),
+?line <<"a">> = iolist_to_binary(re:replace("aA","(?:(a)|b)(?(1)A|B)","\\1",[global])),
+?line <<"YdvbBbBsFnnbBKbB">> = iolist_to_binary(re:replace("bB","(?:(a)|b)(?(1)A|B)","Y\\1\\1dv&&\\1sFnn&K&",[])),
+?line <<"YdvbBbBsFnnbBKbB">> = iolist_to_binary(re:replace("bB","(?:(a)|b)(?(1)A|B)","Y\\1\\1dv&&\\1sFnn&K&",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?:(a)|b)(?(1)A|B)","\\1\\1",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?:(a)|b)(?(1)A|B)","\\1\\1",[global])),
+?line <<"aB">> = iolist_to_binary(re:replace("aB","(?:(a)|b)(?(1)A|B)","\\1To",[])),
+?line <<"aB">> = iolist_to_binary(re:replace("aB","(?:(a)|b)(?(1)A|B)","\\1To",[global])),
+?line <<"bA">> = iolist_to_binary(re:replace("bA","(?:(a)|b)(?(1)A|B)","K\\1UMD",[])),
+?line <<"bA">> = iolist_to_binary(re:replace("bA","(?:(a)|b)(?(1)A|B)","K\\1UMD",[global])),
+?line <<"mLbykSwT">> = iolist_to_binary(re:replace("aa","^(a)?(?(1)a|b)+$","mLbykSwT",[])),
+?line <<"mLbykSwT">> = iolist_to_binary(re:replace("aa","^(a)?(?(1)a|b)+$","mLbykSwT",[global])),
+?line <<"br">> = iolist_to_binary(re:replace("b","^(a)?(?(1)a|b)+$","&r",[])),
+?line <<"br">> = iolist_to_binary(re:replace("b","^(a)?(?(1)a|b)+$","&r",[global])),
+?line <<"yaAboE">> = iolist_to_binary(re:replace("bb","^(a)?(?(1)a|b)+$","yaAb\\1o\\1E",[])),
+?line <<"yaAboE">> = iolist_to_binary(re:replace("bb","^(a)?(?(1)a|b)+$","yaAb\\1o\\1E",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(a)?(?(1)a|b)+$","QkLpQarHEu\\1Fi",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(a)?(?(1)a|b)+$","QkLpQarHEu\\1Fi",[global])),
+?line <<"ab">> = iolist_to_binary(re:replace("ab","^(a)?(?(1)a|b)+$","U",[])),
+?line <<"ab">> = iolist_to_binary(re:replace("ab","^(a)?(?(1)a|b)+$","U",[global])),
+?line <<"MoTyD">> = iolist_to_binary(re:replace("abc:","^(?(?=abc)\\w{3}:|\\d\\d)$","M\\1oTyD",[])),
+?line <<"MoTyD">> = iolist_to_binary(re:replace("abc:","^(?(?=abc)\\w{3}:|\\d\\d)$","M\\1oTyD",[global])),
+?line <<"kawc12B">> = iolist_to_binary(re:replace("12","^(?(?=abc)\\w{3}:|\\d\\d)$","k\\1awc&B\\1",[])),
+?line <<"kawc12B">> = iolist_to_binary(re:replace("12","^(?(?=abc)\\w{3}:|\\d\\d)$","k\\1awc&B\\1",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(?(?=abc)\\w{3}:|\\d\\d)$","TAqA",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(?(?=abc)\\w{3}:|\\d\\d)$","TAqA",[global])),
+?line <<"123">> = iolist_to_binary(re:replace("123","^(?(?=abc)\\w{3}:|\\d\\d)$","WlKxg",[])),
+?line <<"123">> = iolist_to_binary(re:replace("123","^(?(?=abc)\\w{3}:|\\d\\d)$","WlKxg",[global])),
+?line <<"xyz">> = iolist_to_binary(re:replace("xyz","^(?(?=abc)\\w{3}:|\\d\\d)$","O",[])),
+?line <<"xyz">> = iolist_to_binary(re:replace("xyz","^(?(?=abc)\\w{3}:|\\d\\d)$","O",[global])),
+?line <<"kNqQd">> = iolist_to_binary(re:replace("abc:","^(?(?!abc)\\d\\d|\\w{3}:)$","kNq\\1Q\\1d",[])),
+?line <<"kNqQd">> = iolist_to_binary(re:replace("abc:","^(?(?!abc)\\d\\d|\\w{3}:)$","kNq\\1Q\\1d",[global])),
+?line <<"Cr">> = iolist_to_binary(re:replace("12","^(?(?!abc)\\d\\d|\\w{3}:)$","\\1C\\1r",[])),
+?line <<"Cr">> = iolist_to_binary(re:replace("12","^(?(?!abc)\\d\\d|\\w{3}:)$","\\1C\\1r",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(?(?!abc)\\d\\d|\\w{3}:)$","&\\1\\1RHBBR",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(?(?!abc)\\d\\d|\\w{3}:)$","&\\1\\1RHBBR",[global])),
+?line <<"123">> = iolist_to_binary(re:replace("123","^(?(?!abc)\\d\\d|\\w{3}:)$","P",[])),
+?line <<"123">> = iolist_to_binary(re:replace("123","^(?(?!abc)\\d\\d|\\w{3}:)$","P",[global])),
+?line <<"xyz">> = iolist_to_binary(re:replace("xyz","^(?(?!abc)\\d\\d|\\w{3}:)$","&awfl",[])),
+?line <<"xyz">> = iolist_to_binary(re:replace("xyz","^(?(?!abc)\\d\\d|\\w{3}:)$","&awfl",[global])),
+?line <<"fooHSXSjJapIqY">> = iolist_to_binary(re:replace("foobar","(?(?<=foo)bar|cat)","HSXSjJ\\1apIqY",[])),
+?line <<"fooHSXSjJapIqY">> = iolist_to_binary(re:replace("foobar","(?(?<=foo)bar|cat)","HSXSjJ\\1apIqY",[global])),
+?line <<"IouuQfOcatNN">> = iolist_to_binary(re:replace("cat","(?(?<=foo)bar|cat)","Iouu\\1QfO&NN\\1",[])),
+?line <<"IouuQfOcatNN">> = iolist_to_binary(re:replace("cat","(?(?<=foo)bar|cat)","Iouu\\1QfO&NN\\1",[global])),
+?line <<"fcatxAWTu">> = iolist_to_binary(re:replace("fcat","(?(?<=foo)bar|cat)","&\\1xAWTu",[])),
+?line <<"fcatxAWTu">> = iolist_to_binary(re:replace("fcat","(?(?<=foo)bar|cat)","&\\1xAWTu",[global])),
+?line <<"fodYcNREMccatAcatyvscatidk">> = iolist_to_binary(re:replace("focat","(?(?<=foo)bar|cat)","dYc\\1N\\1REMc&A&yvs&idk",[])),
+?line <<"fodYcNREMccatAcatyvscatidk">> = iolist_to_binary(re:replace("focat","(?(?<=foo)bar|cat)","dYc\\1N\\1REMc&A&yvs&idk",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?(?<=foo)bar|cat)","FmDOEt&",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?(?<=foo)bar|cat)","FmDOEt&",[global])),
+?line <<"foocat">> = iolist_to_binary(re:replace("foocat","(?(?<=foo)bar|cat)","Jj&OFdGEDut\\1HjNDH",[])),
+?line <<"foocat">> = iolist_to_binary(re:replace("foocat","(?(?<=foo)bar|cat)","Jj&OFdGEDut\\1HjNDH",[global])),
+?line <<"fooEGbarEwDYbarCNxYJbarbD">> = iolist_to_binary(re:replace("foobar","(?(?<!foo)cat|bar)","EG&Ew\\1DY&CN\\1xYJ&bD",[])),
+?line <<"fooEGbarEwDYbarCNxYJbarbD">> = iolist_to_binary(re:replace("foobar","(?(?<!foo)cat|bar)","EG&Ew\\1DY&CN\\1xYJ&bD",[global])),
+?line <<"jHKKpLcatBtkhMt">> = iolist_to_binary(re:replace("cat","(?(?<!foo)cat|bar)","jHKKpL&BtkhMt",[])),
+?line <<"jHKKpLcatBtkhMt">> = iolist_to_binary(re:replace("cat","(?(?<!foo)cat|bar)","jHKKpL&BtkhMt",[global])),
+?line <<"fiJOnynFk">> = iolist_to_binary(re:replace("fcat","(?(?<!foo)cat|bar)","iJ\\1O\\1ny\\1nFk",[])),
+?line <<"fiJOnynFk">> = iolist_to_binary(re:replace("fcat","(?(?<!foo)cat|bar)","iJ\\1O\\1ny\\1nFk",[global])),
+?line <<"foWCSvhChIBqicatcatLjMieK">> = iolist_to_binary(re:replace("focat","(?(?<!foo)cat|bar)","WCSvh\\1ChIBqi&&LjMieK",[])),
+?line <<"foWCSvhChIBqicatcatLjMieK">> = iolist_to_binary(re:replace("focat","(?(?<!foo)cat|bar)","WCSvh\\1ChIBqi&&LjMieK",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?(?<!foo)cat|bar)","v&yn",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?(?<!foo)cat|bar)","v&yn",[global])),
+?line <<"foocat">> = iolist_to_binary(re:replace("foocat","(?(?<!foo)cat|bar)","\\1&\\1\\1&dvNYDwrfFA\\1&d",[])),
+?line <<"foocat">> = iolist_to_binary(re:replace("foocat","(?(?<!foo)cat|bar)","\\1&\\1\\1&dvNYDwrfFA\\1&d",[global])),
+?line <<"TQKeRLoqn">> = iolist_to_binary(re:replace("abcd","( \\( )? [^()]+ (?(1) \\) |) ","T\\1\\1QK\\1e\\1RLoqn",[extended])),
+?line <<"TQKeRLoqn">> = iolist_to_binary(re:replace("abcd","( \\( )? [^()]+ (?(1) \\) |) ","T\\1\\1QK\\1e\\1RLoqn",[extended,
+ global])),
+?line <<"Qd(ovEgf(pkOYCuPDq(R">> = iolist_to_binary(re:replace("(abcd)","( \\( )? [^()]+ (?(1) \\) |) ","Qd\\1ovEgf\\1pkOYCuPDq\\1R",[extended])),
+?line <<"Qd(ovEgf(pkOYCuPDq(R">> = iolist_to_binary(re:replace("(abcd)","( \\( )? [^()]+ (?(1) \\) |) ","Qd\\1ovEgf\\1pkOYCuPDq\\1R",[extended,
+ global])),
+?line <<"Dmthe quick QWSbgBeLthe quick E(abcd) fox">> = iolist_to_binary(re:replace("the quick (abcd) fox","( \\( )? [^()]+ (?(1) \\) |) ","Dm\\1&QWSbgBeL&E",[extended])),
+?line <<"Dmthe quick QWSbgBeLthe quick EDm((abcd)QWSbgBeL(abcd)EDm foxQWSbgBeL foxE">> = iolist_to_binary(re:replace("the quick (abcd) fox","( \\( )? [^()]+ (?(1) \\) |) ","Dm\\1&QWSbgBeL&E",[extended,
+ global])),
+?line <<"(Ld">> = iolist_to_binary(re:replace("(abcd","( \\( )? [^()]+ (?(1) \\) |) ","Ld",[extended])),
+?line <<"(Ld">> = iolist_to_binary(re:replace("(abcd","( \\( )? [^()]+ (?(1) \\) |) ","Ld",[extended,
+ global])),
+?line <<"abcdiCLfuabcdkd">> = iolist_to_binary(re:replace("abcd","( \\( )? [^()]+ (?(1) \\) ) ","&iCLfu&kd",[extended])),
+?line <<"abcdiCLfuabcdkd">> = iolist_to_binary(re:replace("abcd","( \\( )? [^()]+ (?(1) \\) ) ","&iCLfu&kd",[extended,
+ global])),
+?line <<"uXgnII((abcd)SMj">> = iolist_to_binary(re:replace("(abcd)","( \\( )? [^()]+ (?(1) \\) ) ","uXgnII\\1&SMj",[extended])),
+?line <<"uXgnII((abcd)SMj">> = iolist_to_binary(re:replace("(abcd)","( \\( )? [^()]+ (?(1) \\) ) ","uXgnII\\1&SMj",[extended,
+ global])),
+?line <<"the quick the quick the quick xjaBhsFamkEL(abcd) fox">> = iolist_to_binary(re:replace("the quick (abcd) fox","( \\( )? [^()]+ (?(1) \\) ) ","&&&xjaBhsFa\\1mkEL\\1",[extended])),
+?line <<"the quick the quick the quick xjaBhsFamkEL(abcd)(abcd)(abcd)xjaBhsFa(mkEL( fox fox foxxjaBhsFamkEL">> = iolist_to_binary(re:replace("the quick (abcd) fox","( \\( )? [^()]+ (?(1) \\) ) ","&&&xjaBhsFa\\1mkEL\\1",[extended,
+ global])),
+?line <<"(KuH">> = iolist_to_binary(re:replace("(abcd","( \\( )? [^()]+ (?(1) \\) ) ","K\\1uH",[extended])),
+?line <<"(KuH">> = iolist_to_binary(re:replace("(abcd","( \\( )? [^()]+ (?(1) \\) ) ","K\\1uH",[extended,
+ global])),
+?line <<"IMNCUvkRpMGDtA">> = iolist_to_binary(re:replace("12","^(?(2)a|(1)(2))+$","IMNCUvkRpMGDtA",[])),
+?line <<"IMNCUvkRpMGDtA">> = iolist_to_binary(re:replace("12","^(?(2)a|(1)(2))+$","IMNCUvkRpMGDtA",[global])),
+?line <<"YQQcCpqUaDwGin12a1he">> = iolist_to_binary(re:replace("12a","^(?(2)a|(1)(2))+$","YQQcCpqUaDwGin&\\1he",[])),
+?line <<"YQQcCpqUaDwGin12a1he">> = iolist_to_binary(re:replace("12a","^(?(2)a|(1)(2))+$","YQQcCpqUaDwGin&\\1he",[global])),
+?line <<"LiJWEQyka">> = iolist_to_binary(re:replace("12aa","^(?(2)a|(1)(2))+$","LiJWEQyka",[])),
+?line <<"LiJWEQyka">> = iolist_to_binary(re:replace("12aa","^(?(2)a|(1)(2))+$","LiJWEQyka",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(?(2)a|(1)(2))+$","jNpGudmNvPautj\\1\\1rc",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(?(2)a|(1)(2))+$","jNpGudmNvPautj\\1\\1rc",[global])),
+?line <<"1234">> = iolist_to_binary(re:replace("1234","^(?(2)a|(1)(2))+$","TKb&DSqQCtNBSjto\\1",[])),
+?line <<"1234">> = iolist_to_binary(re:replace("1234","^(?(2)a|(1)(2))+$","TKb&DSqQCtNBSjto\\1",[global])),
+?line <<"OKbblah blahmEblah blahcAEblah">> = iolist_to_binary(re:replace("blah blah","((?i)blah)\\s+\\1","OKb&mE&cAE\\1",[])),
+?line <<"OKbblah blahmEblah blahcAEblah">> = iolist_to_binary(re:replace("blah blah","((?i)blah)\\s+\\1","OKb&mE&cAE\\1",[global])),
+?line <<"sHRABLAH BLAHDBLAH BLAHofBLAHMonBF">> = iolist_to_binary(re:replace("BLAH BLAH","((?i)blah)\\s+\\1","sHRA&D&of\\1MonBF",[])),
+?line <<"sHRABLAH BLAHDBLAH BLAHofBLAHMonBF">> = iolist_to_binary(re:replace("BLAH BLAH","((?i)blah)\\s+\\1","sHRA&D&of\\1MonBF",[global])),
+?line <<"rBlah BlahowtRMgXJKNBlah Blah">> = iolist_to_binary(re:replace("Blah Blah","((?i)blah)\\s+\\1","r&owtRMgXJKN&",[])),
+?line <<"rBlah BlahowtRMgXJKNBlah Blah">> = iolist_to_binary(re:replace("Blah Blah","((?i)blah)\\s+\\1","r&owtRMgXJKN&",[global])),
+?line <<"JblaHeNvblaHaSeblaHblaH blaHg">> = iolist_to_binary(re:replace("blaH blaH","((?i)blah)\\s+\\1","J\\1eNv\\1aSe\\1&g",[])),
+?line <<"JblaHeNvblaHaSeblaHblaH blaHg">> = iolist_to_binary(re:replace("blaH blaH","((?i)blah)\\s+\\1","J\\1eNv\\1aSe\\1&g",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","((?i)blah)\\s+\\1","\\1LVUknDVfgj\\1ij\\1eDhAE",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","((?i)blah)\\s+\\1","\\1LVUknDVfgj\\1ij\\1eDhAE",[global])),
+?line <<"blah BLAH">> = iolist_to_binary(re:replace("blah BLAH","((?i)blah)\\s+\\1","auAYHQ\\1S&PKut",[])),
+?line <<"blah BLAH">> = iolist_to_binary(re:replace("blah BLAH","((?i)blah)\\s+\\1","auAYHQ\\1S&PKut",[global])),
+?line <<"Blah blah">> = iolist_to_binary(re:replace("Blah blah","((?i)blah)\\s+\\1","\\1&N\\1tNui&w&CgfgFCbPk",[])),
+?line <<"Blah blah">> = iolist_to_binary(re:replace("Blah blah","((?i)blah)\\s+\\1","\\1&N\\1tNui&w&CgfgFCbPk",[global])),
+?line <<"blaH blah">> = iolist_to_binary(re:replace("blaH blah","((?i)blah)\\s+\\1","rLouaVXAOeWe",[])),
+?line <<"blaH blah">> = iolist_to_binary(re:replace("blaH blah","((?i)blah)\\s+\\1","rLouaVXAOeWe",[global])),
+?line <<"CXblahSqUjfblah blahblah blahblah">> = iolist_to_binary(re:replace("blah blah","((?i)blah)\\s+(?i:\\1)","CX\\1SqUjf&&\\1",[])),
+?line <<"CXblahSqUjfblah blahblah blahblah">> = iolist_to_binary(re:replace("blah blah","((?i)blah)\\s+(?i:\\1)","CX\\1SqUjf&&\\1",[global])),
+?line <<"XBLAHTkBLAHXUjMhbiRBLAH BLAHgXxxti">> = iolist_to_binary(re:replace("BLAH BLAH","((?i)blah)\\s+(?i:\\1)","X\\1Tk\\1XUjMhbiR&gXxxti",[])),
+?line <<"XBLAHTkBLAHXUjMhbiRBLAH BLAHgXxxti">> = iolist_to_binary(re:replace("BLAH BLAH","((?i)blah)\\s+(?i:\\1)","X\\1Tk\\1XUjMhbiR&gXxxti",[global])),
+?line <<"SBlahlpSqiBlah BlahLvYBlahJBlahxSbx">> = iolist_to_binary(re:replace("Blah Blah","((?i)blah)\\s+(?i:\\1)","S\\1lpSqi&LvY\\1J\\1xSbx",[])),
+?line <<"SBlahlpSqiBlah BlahLvYBlahJBlahxSbx">> = iolist_to_binary(re:replace("Blah Blah","((?i)blah)\\s+(?i:\\1)","S\\1lpSqi&LvY\\1J\\1xSbx",[global])),
+?line <<"oIFblaHCV">> = iolist_to_binary(re:replace("blaH blaH","((?i)blah)\\s+(?i:\\1)","oIF\\1CV",[])),
+?line <<"oIFblaHCV">> = iolist_to_binary(re:replace("blaH blaH","((?i)blah)\\s+(?i:\\1)","oIF\\1CV",[global])),
+?line <<"blahblah BLAHnOGRLblahgvVwkgjq">> = iolist_to_binary(re:replace("blah BLAH","((?i)blah)\\s+(?i:\\1)","\\1&nOGRL\\1gvVwkgjq",[])),
+?line <<"blahblah BLAHnOGRLblahgvVwkgjq">> = iolist_to_binary(re:replace("blah BLAH","((?i)blah)\\s+(?i:\\1)","\\1&nOGRL\\1gvVwkgjq",[global])),
+?line <<"PrLBlahTtgBlah blahpNNDBlah blahBlah blahBlah blah">> = iolist_to_binary(re:replace("Blah blah","((?i)blah)\\s+(?i:\\1)","PrL\\1Ttg&pNND&&&",[])),
+?line <<"PrLBlahTtgBlah blahpNNDBlah blahBlah blahBlah blah">> = iolist_to_binary(re:replace("Blah blah","((?i)blah)\\s+(?i:\\1)","PrL\\1Ttg&pNND&&&",[global])),
+?line <<"blaH blahGnDblaHFhNOIOmBhblaH blahfblaH blahKt">> = iolist_to_binary(re:replace("blaH blah","((?i)blah)\\s+(?i:\\1)","&GnD\\1FhNOIOmBh&f&Kt",[])),
+?line <<"blaH blahGnDblaHFhNOIOmBhblaH blahfblaH blahKt">> = iolist_to_binary(re:replace("blaH blah","((?i)blah)\\s+(?i:\\1)","&GnD\\1FhNOIOmBh&f&Kt",[global])),
+?line <<"aW">> = iolist_to_binary(re:replace("a","(?>a*)*","&W",[])),
+?line <<"aWW">> = iolist_to_binary(re:replace("a","(?>a*)*","&W",[global])),
+?line <<"Seaa">> = iolist_to_binary(re:replace("aa","(?>a*)*","Se&",[])),
+?line <<"SeaaSe">> = iolist_to_binary(re:replace("aa","(?>a*)*","Se&",[global])),
+?line <<"itILgCmaaaaioxBkDkO">> = iolist_to_binary(re:replace("aaaa","(?>a*)*","itIL\\1gCm&ioxBkDkO",[])),
+?line <<"itILgCmaaaaioxBkDkOitILgCmioxBkDkO">> = iolist_to_binary(re:replace("aaaa","(?>a*)*","itIL\\1gCm&ioxBkDkO",[global])),
+?line <<"aqm">> = iolist_to_binary(re:replace("abc","(abc|)+","\\1aqm",[])),
+?line <<"aqmaqm">> = iolist_to_binary(re:replace("abc","(abc|)+","\\1aqm",[global])),
+?line <<"tSWTMOLPTnvvJTwabcabcJwE">> = iolist_to_binary(re:replace("abcabc","(abc|)+","tSWTMOLPTnvvJTw\\1&JwE",[])),
+?line <<"tSWTMOLPTnvvJTwabcabcJwEtSWTMOLPTnvvJTwJwE">> = iolist_to_binary(re:replace("abcabc","(abc|)+","tSWTMOLPTnvvJTw\\1&JwE",[global])),
+?line <<"eMhIJbMyp">> = iolist_to_binary(re:replace("abcabcabc","(abc|)+","\\1eMh\\1\\1IJb\\1Myp",[])),
+?line <<"eMhIJbMypeMhIJbMyp">> = iolist_to_binary(re:replace("abcabcabc","(abc|)+","\\1eMh\\1\\1IJb\\1Myp",[global])),
+?line <<"dBxyz">> = iolist_to_binary(re:replace("xyz","(abc|)+","dB",[])),
+?line <<"dBxdBydBzdB">> = iolist_to_binary(re:replace("xyz","(abc|)+","dB",[global])),
+?line <<"wCrHnihkSygW">> = iolist_to_binary(re:replace("a","([a]*)*","wCrHnihkSygW",[])),
+?line <<"wCrHnihkSygWwCrHnihkSygW">> = iolist_to_binary(re:replace("a","([a]*)*","wCrHnihkSygW",[global])),
+?line <<"GjjjYNVefTgBaaaaafMw">> = iolist_to_binary(re:replace("aaaaa","([a]*)*","\\1Gjj\\1jYNVefTgB&fMw",[])),
+?line <<"GjjjYNVefTgBaaaaafMwGjjjYNVefTgBfMw">> = iolist_to_binary(re:replace("aaaaa","([a]*)*","\\1Gjj\\1jYNVefTgB&fMw",[global])),
+?line <<"pXFqCJUNaNU">> = iolist_to_binary(re:replace("a","([ab]*)*","pXFqCJUN&NU",[])),
+?line <<"pXFqCJUNaNUpXFqCJUNNU">> = iolist_to_binary(re:replace("a","([ab]*)*","pXFqCJUN&NU",[global])),
+?line <<"qbGbaTAUHHibHnl">> = iolist_to_binary(re:replace("b","([ab]*)*","q&\\1GbaTAUHHi&Hn\\1l",[])),
+?line <<"qbGbaTAUHHibHnlqGbaTAUHHiHnl">> = iolist_to_binary(re:replace("b","([ab]*)*","q&\\1GbaTAUHHi&Hn\\1l",[global])),
+?line <<"l">> = iolist_to_binary(re:replace("ababab","([ab]*)*","\\1l",[])),
+?line <<"ll">> = iolist_to_binary(re:replace("ababab","([ab]*)*","\\1l",[global])),
+?line <<"scde">> = iolist_to_binary(re:replace("aaaabcde","([ab]*)*","s\\1\\1",[])),
+?line <<"sscsdses">> = iolist_to_binary(re:replace("aaaabcde","([ab]*)*","s\\1\\1",[global])),
+?line <<"cLbwWRDkdHt">> = iolist_to_binary(re:replace("bbbb","([ab]*)*","cL\\1bwWRDkdHt",[])),
+?line <<"cLbwWRDkdHtcLbwWRDkdHt">> = iolist_to_binary(re:replace("bbbb","([ab]*)*","cL\\1bwWRDkdHt",[global])),
+?line <<"nmytevammko">> = iolist_to_binary(re:replace("b","([^a]*)*","nmytevammk\\1o",[])),
+?line <<"nmytevammkonmytevammko">> = iolist_to_binary(re:replace("b","([^a]*)*","nmytevammk\\1o",[global])),
+?line <<"bbbbqIbAMyI">> = iolist_to_binary(re:replace("bbbb","([^a]*)*","&qIbAMyI",[])),
+?line <<"bbbbqIbAMyIqIbAMyI">> = iolist_to_binary(re:replace("bbbb","([^a]*)*","&qIbAMyI",[global])),
+?line <<"ItRSFsauaaa">> = iolist_to_binary(re:replace("aaa","([^a]*)*","ItRS\\1Fs&a&&u",[])),
+?line <<"ItRSFsauaItRSFsauaItRSFsauaItRSFsau">> = iolist_to_binary(re:replace("aaa","([^a]*)*","ItRS\\1Fs&a&&u",[global])),
+?line <<"PKlYUFjsxy">> = iolist_to_binary(re:replace("cccc","([^ab]*)*","PKlYUFjsxy",[])),
+?line <<"PKlYUFjsxyPKlYUFjsxy">> = iolist_to_binary(re:replace("cccc","([^ab]*)*","PKlYUFjsxy",[global])),
+?line <<"eBumQabab">> = iolist_to_binary(re:replace("abab","([^ab]*)*","e\\1BumQ",[])),
+?line <<"eBumQaeBumQbeBumQaeBumQbeBumQ">> = iolist_to_binary(re:replace("abab","([^ab]*)*","e\\1BumQ",[global])),
+?line <<"VsNPa">> = iolist_to_binary(re:replace("a","([a]*?)*","&Vs\\1N&P",[])),
+?line <<"VsNPaVsNaPVsNP">> = iolist_to_binary(re:replace("a","([a]*?)*","&Vs\\1N&P",[global])),
+?line <<"oJTmjRIMESSEdaaaa">> = iolist_to_binary(re:replace("aaaa","([a]*?)*","o&JT\\1\\1\\1&m&jR&IMESSEd",[])),
+?line <<"oJTmjRIMESSEdoaJTamajRaIMESSEdoJTmjRIMESSEdoaJTamajRaIMESSEdoJTmjRIMESSEdoaJTamajRaIMESSEdoJTmjRIMESSEdoaJTamajRaIMESSEdoJTmjRIMESSEd">> = iolist_to_binary(re:replace("aaaa","([a]*?)*","o&JT\\1\\1\\1&m&jR&IMESSEd",[global])),
+?line <<"uSOa">> = iolist_to_binary(re:replace("a","([ab]*?)*","&\\1&u&SO",[])),
+?line <<"uSOaauaSOuSO">> = iolist_to_binary(re:replace("a","([ab]*?)*","&\\1&u&SO",[global])),
+?line <<"BfDNwUAfjUb">> = iolist_to_binary(re:replace("b","([ab]*?)*","B&fDNwU\\1Af&j\\1U\\1",[])),
+?line <<"BfDNwUAfjUBbfDNwUAfbjUBfDNwUAfjU">> = iolist_to_binary(re:replace("b","([ab]*?)*","B&fDNwU\\1Af&j\\1U\\1",[global])),
+?line <<"kTOkbSeRnabab">> = iolist_to_binary(re:replace("abab","([ab]*?)*","k&TOkb\\1\\1S&eR&n&",[])),
+?line <<"kTOkbSeRnkaTOkbSaeRanakTOkbSeRnkbTOkbSbeRbnbkTOkbSeRnkaTOkbSaeRanakTOkbSeRnkbTOkbSbeRbnbkTOkbSeRn">> = iolist_to_binary(re:replace("abab","([ab]*?)*","k&TOkb\\1\\1S&eR&n&",[global])),
+?line <<"Sbaba">> = iolist_to_binary(re:replace("baba","([ab]*?)*","S",[])),
+?line <<"SSSSSSSSS">> = iolist_to_binary(re:replace("baba","([ab]*?)*","S",[global])),
+?line <<"Aotb">> = iolist_to_binary(re:replace("b","([^a]*?)*","A\\1ot",[])),
+?line <<"AotAotAot">> = iolist_to_binary(re:replace("b","([^a]*?)*","A\\1ot",[global])),
+?line <<"CbPnbbbb">> = iolist_to_binary(re:replace("bbbb","([^a]*?)*","CbPn&&",[])),
+?line <<"CbPnCbPnbbCbPnCbPnbbCbPnCbPnbbCbPnCbPnbbCbPn">> = iolist_to_binary(re:replace("bbbb","([^a]*?)*","CbPn&&",[global])),
+?line <<"DUteaaa">> = iolist_to_binary(re:replace("aaa","([^a]*?)*","D\\1\\1Ute",[])),
+?line <<"DUteaDUteaDUteaDUte">> = iolist_to_binary(re:replace("aaa","([^a]*?)*","D\\1\\1Ute",[global])),
+?line <<"ATgsBhAkPic">> = iolist_to_binary(re:replace("c","([^ab]*?)*","ATg\\1sB\\1hAkP&i",[])),
+?line <<"ATgsBhAkPiATgsBhAkPciATgsBhAkPi">> = iolist_to_binary(re:replace("c","([^ab]*?)*","ATg\\1sB\\1hAkP&i",[global])),
+?line <<"lwFoWkRIxUcccc">> = iolist_to_binary(re:replace("cccc","([^ab]*?)*","l&wFoWk\\1RIxU",[])),
+?line <<"lwFoWkRIxUlcwFoWkRIxUlwFoWkRIxUlcwFoWkRIxUlwFoWkRIxUlcwFoWkRIxUlwFoWkRIxUlcwFoWkRIxUlwFoWkRIxU">> = iolist_to_binary(re:replace("cccc","([^ab]*?)*","l&wFoWk\\1RIxU",[global])),
+?line <<"QXSXCbaba">> = iolist_to_binary(re:replace("baba","([^ab]*?)*","&QXSXC",[])),
+?line <<"QXSXCbQXSXCaQXSXCbQXSXCaQXSXC">> = iolist_to_binary(re:replace("baba","([^ab]*?)*","&QXSXC",[global])),
+?line <<"epgEBpyDja">> = iolist_to_binary(re:replace("a","(?>a*)*","e\\1\\1pgEB\\1\\1pyD\\1j&",[])),
+?line <<"epgEBpyDjaepgEBpyDj">> = iolist_to_binary(re:replace("a","(?>a*)*","e\\1\\1pgEB\\1\\1pyD\\1j&",[global])),
+?line <<"SekThCelBbcde">> = iolist_to_binary(re:replace("aaabcde","(?>a*)*","SekT\\1hC\\1\\1elB",[])),
+?line <<"SekThCelBSekThCelBbSekThCelBcSekThCelBdSekThCelBeSekThCelB">> = iolist_to_binary(re:replace("aaabcde","(?>a*)*","SekT\\1hC\\1\\1elB",[global])),
+?line <<"goPCaaaaawO">> = iolist_to_binary(re:replace("aaaaa","((?>a*))*","go\\1PC\\1&\\1wO",[])),
+?line <<"goPCaaaaawOgoPCwO">> = iolist_to_binary(re:replace("aaaaa","((?>a*))*","go\\1PC\\1&\\1wO",[global])),
+?line <<"SCaadJliaaKfxRbbbaa">> = iolist_to_binary(re:replace("aabbaa","((?>a*))*","\\1S\\1C&\\1dJ\\1\\1li&KfxR\\1b",[])),
+?line <<"SCaadJliaaKfxRbSCdJliKfxRbbSCdJliKfxRbbSCaadJliaaKfxRbSCdJliKfxRb">> = iolist_to_binary(re:replace("aabbaa","((?>a*))*","\\1S\\1C&\\1dJ\\1\\1li&KfxR\\1b",[global])),
+?line <<"ssMfBjQEIebjdsmPRaaaaa">> = iolist_to_binary(re:replace("aaaaa","((?>a*?))*","s&s&MfBjQEIebjdsmPR",[])),
+?line <<"ssMfBjQEIebjdsmPRassMfBjQEIebjdsmPRassMfBjQEIebjdsmPRassMfBjQEIebjdsmPRassMfBjQEIebjdsmPRassMfBjQEIebjdsmPR">> = iolist_to_binary(re:replace("aaaaa","((?>a*?))*","s&s&MfBjQEIebjdsmPR",[global])),
+?line <<"VQJGaabbaa">> = iolist_to_binary(re:replace("aabbaa","((?>a*?))*","VQ\\1&J\\1G",[])),
+?line <<"VQJGaVQJGaVQJGbVQJGbVQJGaVQJGaVQJG">> = iolist_to_binary(re:replace("aabbaa","((?>a*?))*","VQ\\1&J\\1G",[global])),
+?line <<"t">> = iolist_to_binary(re:replace("12-sep-98","(?(?=[^a-z]+[a-z]) \\d{2}-[a-z]{3}-\\d{2} | \\d{2}-\\d{2}-\\d{2} ) ","t",[extended])),
+?line <<"t">> = iolist_to_binary(re:replace("12-sep-98","(?(?=[^a-z]+[a-z]) \\d{2}-[a-z]{3}-\\d{2} | \\d{2}-\\d{2}-\\d{2} ) ","t",[extended,
+ global])),
+?line <<"EIgEQmDKuIoMFts">> = iolist_to_binary(re:replace("12-09-98","(?(?=[^a-z]+[a-z]) \\d{2}-[a-z]{3}-\\d{2} | \\d{2}-\\d{2}-\\d{2} ) ","EIgEQmDKuIoMFts",[extended])),
+?line <<"EIgEQmDKuIoMFts">> = iolist_to_binary(re:replace("12-09-98","(?(?=[^a-z]+[a-z]) \\d{2}-[a-z]{3}-\\d{2} | \\d{2}-\\d{2}-\\d{2} ) ","EIgEQmDKuIoMFts",[extended,
+ global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?(?=[^a-z]+[a-z]) \\d{2}-[a-z]{3}-\\d{2} | \\d{2}-\\d{2}-\\d{2} ) ","M\\1K\\1N",[extended])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?(?=[^a-z]+[a-z]) \\d{2}-[a-z]{3}-\\d{2} | \\d{2}-\\d{2}-\\d{2} ) ","M\\1K\\1N",[extended,
+ global])),
+?line <<"sep-12-98">> = iolist_to_binary(re:replace("sep-12-98","(?(?=[^a-z]+[a-z]) \\d{2}-[a-z]{3}-\\d{2} | \\d{2}-\\d{2}-\\d{2} ) ","Xby\\1g&vVVPgw\\1",[extended])),
+?line <<"sep-12-98">> = iolist_to_binary(re:replace("sep-12-98","(?(?=[^a-z]+[a-z]) \\d{2}-[a-z]{3}-\\d{2} | \\d{2}-\\d{2}-\\d{2} ) ","Xby\\1g&vVVPgw\\1",[extended,
+ global])),
+?line <<"foonfoobJpbIfooAbKhpTIXfoofooEN">> = iolist_to_binary(re:replace("foobarfoo","(?<=(foo))bar\\1","n\\1bJpbI\\1AbKhpTIX\\1\\1EN",[])),
+?line <<"foonfoobJpbIfooAbKhpTIXfoofooEN">> = iolist_to_binary(re:replace("foobarfoo","(?<=(foo))bar\\1","n\\1bJpbI\\1AbKhpTIX\\1\\1EN",[global])),
+?line <<"foobarfoofooUWdHfoofoocfifXWQdmKgtling">> = iolist_to_binary(re:replace("foobarfootling","(?<=(foo))bar\\1","&\\1UWdH\\1\\1cfifXWQdmKg",[])),
+?line <<"foobarfoofooUWdHfoofoocfifXWQdmKgtling">> = iolist_to_binary(re:replace("foobarfootling","(?<=(foo))bar\\1","&\\1UWdH\\1\\1cfifXWQdmKg",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?<=(foo))bar\\1","\\1A\\1Do\\1roQX",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?<=(foo))bar\\1","\\1A\\1Do\\1roQX",[global])),
+?line <<"foobar">> = iolist_to_binary(re:replace("foobar","(?<=(foo))bar\\1","WqywQ",[])),
+?line <<"foobar">> = iolist_to_binary(re:replace("foobar","(?<=(foo))bar\\1","WqywQ",[global])),
+?line <<"barfoo">> = iolist_to_binary(re:replace("barfoo","(?<=(foo))bar\\1","g&dx",[])),
+?line <<"barfoo">> = iolist_to_binary(re:replace("barfoo","(?<=(foo))bar\\1","g&dx",[global])),
+?line <<"EqLnXCi">> = iolist_to_binary(re:replace("saturday","(?i:saturday|sunday)","EqLnX\\1Ci\\1",[])),
+?line <<"EqLnXCi">> = iolist_to_binary(re:replace("saturday","(?i:saturday|sunday)","EqLnX\\1Ci\\1",[global])),
+?line <<"rXiCVoMssundayWVsundayg">> = iolist_to_binary(re:replace("sunday","(?i:saturday|sunday)","rXiCVoMs&WV&\\1g",[])),
+?line <<"rXiCVoMssundayWVsundayg">> = iolist_to_binary(re:replace("sunday","(?i:saturday|sunday)","rXiCVoMs&WV&\\1g",[global])),
+?line <<"DCML">> = iolist_to_binary(re:replace("Saturday","(?i:saturday|sunday)","D\\1CML",[])),
+?line <<"DCML">> = iolist_to_binary(re:replace("Saturday","(?i:saturday|sunday)","D\\1CML",[global])),
+?line <<"caYSundaylQsqBJmDFf">> = iolist_to_binary(re:replace("Sunday","(?i:saturday|sunday)","caY&l\\1Q\\1\\1sq\\1BJmD\\1Ff",[])),
+?line <<"caYSundaylQsqBJmDFf">> = iolist_to_binary(re:replace("Sunday","(?i:saturday|sunday)","caY&l\\1Q\\1\\1sq\\1BJmD\\1Ff",[global])),
+?line <<"LSATURDAYSATURDAYb">> = iolist_to_binary(re:replace("SATURDAY","(?i:saturday|sunday)","L&&b",[])),
+?line <<"LSATURDAYSATURDAYb">> = iolist_to_binary(re:replace("SATURDAY","(?i:saturday|sunday)","L&&b",[global])),
+?line <<"J">> = iolist_to_binary(re:replace("SUNDAY","(?i:saturday|sunday)","J",[])),
+?line <<"J">> = iolist_to_binary(re:replace("SUNDAY","(?i:saturday|sunday)","J",[global])),
+?line <<"cCHUgeqmaSunDaySunDayQSunDayHUJ">> = iolist_to_binary(re:replace("SunDay","(?i:saturday|sunday)","c\\1CHUgeqma&&Q&HUJ",[])),
+?line <<"cCHUgeqmaSunDaySunDayQSunDayHUJ">> = iolist_to_binary(re:replace("SunDay","(?i:saturday|sunday)","c\\1CHUgeqma&&Q&HUJ",[global])),
+?line <<"abcEbXpYQWabcxNabcxabcxVrPLd">> = iolist_to_binary(re:replace("abcx","(a(?i)bc|BB)x","\\1EbXpYQW&N&&VrPLd",[])),
+?line <<"abcEbXpYQWabcxNabcxabcxVrPLd">> = iolist_to_binary(re:replace("abcx","(a(?i)bc|BB)x","\\1EbXpYQW&N&&VrPLd",[global])),
+?line <<"jBMIviaBCvaBCxTRLe">> = iolist_to_binary(re:replace("aBCx","(a(?i)bc|BB)x","jBMIvi\\1v&TRLe",[])),
+?line <<"jBMIviaBCvaBCxTRLe">> = iolist_to_binary(re:replace("aBCx","(a(?i)bc|BB)x","jBMIvi\\1v&TRLe",[global])),
+?line <<"wDnyUbbxDgOUSgpsDtqV">> = iolist_to_binary(re:replace("bbx","(a(?i)bc|BB)x","wDnyU&DgOUSgpsDtqV",[])),
+?line <<"wDnyUbbxDgOUSgpsDtqV">> = iolist_to_binary(re:replace("bbx","(a(?i)bc|BB)x","wDnyU&DgOUSgpsDtqV",[global])),
+?line <<"Vx">> = iolist_to_binary(re:replace("BBx","(a(?i)bc|BB)x","Vx",[])),
+?line <<"Vx">> = iolist_to_binary(re:replace("BBx","(a(?i)bc|BB)x","Vx",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(a(?i)bc|BB)x","vuaWcgIs\\1SRUcqMEb",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(a(?i)bc|BB)x","vuaWcgIs\\1SRUcqMEb",[global])),
+?line <<"abcX">> = iolist_to_binary(re:replace("abcX","(a(?i)bc|BB)x","V\\1",[])),
+?line <<"abcX">> = iolist_to_binary(re:replace("abcX","(a(?i)bc|BB)x","V\\1",[global])),
+?line <<"aBCX">> = iolist_to_binary(re:replace("aBCX","(a(?i)bc|BB)x","kcaH&mISces&gy\\1Mv",[])),
+?line <<"aBCX">> = iolist_to_binary(re:replace("aBCX","(a(?i)bc|BB)x","kcaH&mISces&gy\\1Mv",[global])),
+?line <<"bbX">> = iolist_to_binary(re:replace("bbX","(a(?i)bc|BB)x","hfQHW",[])),
+?line <<"bbX">> = iolist_to_binary(re:replace("bbX","(a(?i)bc|BB)x","hfQHW",[global])),
+?line <<"BBX">> = iolist_to_binary(re:replace("BBX","(a(?i)bc|BB)x","QWSdgANNG&a&hUuhv&T",[])),
+?line <<"BBX">> = iolist_to_binary(re:replace("BBX","(a(?i)bc|BB)x","QWSdgANNG&a&hUuhv&T",[global])),
+?line <<"tEacrW">> = iolist_to_binary(re:replace("ac","^([ab](?i)[cd]|[ef])","tE\\1rW",[])),
+?line <<"tEacrW">> = iolist_to_binary(re:replace("ac","^([ab](?i)[cd]|[ef])","tE\\1rW",[global])),
+?line <<"jjqwaCaCyaCpaCPWnSv">> = iolist_to_binary(re:replace("aC","^([ab](?i)[cd]|[ef])","jjqw\\1\\1y\\1p&PWnSv",[])),
+?line <<"jjqwaCaCyaCpaCPWnSv">> = iolist_to_binary(re:replace("aC","^([ab](?i)[cd]|[ef])","jjqw\\1\\1y\\1p&PWnSv",[global])),
+?line <<"pbDoK">> = iolist_to_binary(re:replace("bD","^([ab](?i)[cd]|[ef])","p&oK",[])),
+?line <<"pbDoK">> = iolist_to_binary(re:replace("bD","^([ab](?i)[cd]|[ef])","p&oK",[global])),
+?line <<"hOUSaMTfcPejGlephant">> = iolist_to_binary(re:replace("elephant","^([ab](?i)[cd]|[ef])","hOUSaMTfcP&jG",[])),
+?line <<"hOUSaMTfcPejGlephant">> = iolist_to_binary(re:replace("elephant","^([ab](?i)[cd]|[ef])","hOUSaMTfcP&jG",[global])),
+?line <<"EOnTdEESsrQXxRPurope">> = iolist_to_binary(re:replace("Europe","^([ab](?i)[cd]|[ef])","\\1OnTd&&SsrQXxRP",[])),
+?line <<"EOnTdEESsrQXxRPurope">> = iolist_to_binary(re:replace("Europe","^([ab](?i)[cd]|[ef])","\\1OnTd&&SsrQXxRP",[global])),
+?line <<"fhfBHfIDHldAwNfEfqrog">> = iolist_to_binary(re:replace("frog","^([ab](?i)[cd]|[ef])","\\1h&BH\\1IDHldAwN&E\\1q",[])),
+?line <<"fhfBHfIDHldAwNfEfqrog">> = iolist_to_binary(re:replace("frog","^([ab](?i)[cd]|[ef])","\\1h&BH\\1IDHldAwN&E\\1q",[global])),
+?line <<"FFFxSuhnFwrance">> = iolist_to_binary(re:replace("France","^([ab](?i)[cd]|[ef])","\\1&FxSuhn&w",[])),
+?line <<"FFFxSuhnFwrance">> = iolist_to_binary(re:replace("France","^([ab](?i)[cd]|[ef])","\\1&FxSuhn&w",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^([ab](?i)[cd]|[ef])","&ff\\1J\\1I",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^([ab](?i)[cd]|[ef])","&ff\\1J\\1I",[global])),
+?line <<"Africa">> = iolist_to_binary(re:replace("Africa","^([ab](?i)[cd]|[ef])","nEbgaPXOn\\1",[])),
+?line <<"Africa">> = iolist_to_binary(re:replace("Africa","^([ab](?i)[cd]|[ef])","nEbgaPXOn\\1",[global])),
+?line <<"abcabDXAiaSg">> = iolist_to_binary(re:replace("ab","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)","&c&DXAiaSg",[])),
+?line <<"abcabDXAiaSg">> = iolist_to_binary(re:replace("ab","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)","&c&DXAiaSg",[global])),
+?line <<"aBdqaBdmLoaaBdEb">> = iolist_to_binary(re:replace("aBd","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)","&q&mLoa&Eb",[])),
+?line <<"aBdqaBdmLoaaBdEb">> = iolist_to_binary(re:replace("aBd","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)","&q&mLoa&Eb",[global])),
+?line <<"xxyvFo">> = iolist_to_binary(re:replace("xy","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)","x&vFo",[])),
+?line <<"xxyvFo">> = iolist_to_binary(re:replace("xy","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)","x&vFo",[global])),
+?line <<"eWy">> = iolist_to_binary(re:replace("xY","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)","eWy",[])),
+?line <<"eWy">> = iolist_to_binary(re:replace("xY","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)","eWy",[global])),
+?line <<"bzVONndeqzaVKebra">> = iolist_to_binary(re:replace("zebra","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)","b&VONndeq\\1aVK",[])),
+?line <<"bzVONndeqzaVKebra">> = iolist_to_binary(re:replace("zebra","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)","b&VONndeq\\1aVK",[global])),
+?line <<"ZNZZjZVZJeZnZZCXZambesi">> = iolist_to_binary(re:replace("Zambesi","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)","&N&&j&V&Je\\1n&\\1CX&",[])),
+?line <<"ZNZZjZVZJeZnZZCXZambesi">> = iolist_to_binary(re:replace("Zambesi","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)","&N&&j&V&Je\\1n&\\1CX&",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)","vJ\\1\\1",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)","vJ\\1\\1",[global])),
+?line <<"aCD">> = iolist_to_binary(re:replace("aCD","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)","\\1FKPhO&",[])),
+?line <<"aCD">> = iolist_to_binary(re:replace("aCD","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)","\\1FKPhO&",[global])),
+?line <<"XY">> = iolist_to_binary(re:replace("XY","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)","SEE",[])),
+?line <<"XY">> = iolist_to_binary(re:replace("XY","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)","SEE",[global])),
+?line <<"foo
+rwHxBqDqeLQ">> = iolist_to_binary(re:replace("foo
+bar","(?<=foo\\n)^bar","rwHxBqDq\\1eLQ",[multiline])),
+?line <<"foo
+rwHxBqDqeLQ">> = iolist_to_binary(re:replace("foo
+bar","(?<=foo\\n)^bar","rwHxBqDq\\1eLQ",[multiline,global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?<=foo\\n)^bar","\\1P&&W&\\1oN",[multiline])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?<=foo\\n)^bar","\\1P&&W&\\1oN",[multiline,
+ global])),
+?line <<"bar">> = iolist_to_binary(re:replace("bar","(?<=foo\\n)^bar","rk\\1SSPj&JPOE",[multiline])),
+?line <<"bar">> = iolist_to_binary(re:replace("bar","(?<=foo\\n)^bar","rk\\1SSPj&JPOE",[multiline,
+ global])),
+?line <<"baz
+bar">> = iolist_to_binary(re:replace("baz
+bar","(?<=foo\\n)^bar","&JIhqO&Da",[multiline])),
+?line <<"baz
+bar">> = iolist_to_binary(re:replace("baz
+bar","(?<=foo\\n)^bar","&JIhqO&Da",[multiline,global])),
+?line <<"baruQUCmWhYKFBWj">> = iolist_to_binary(re:replace("barbaz","(?<=(?<!foo)bar)baz","uQUCmWhYKF\\1BWj\\1",[])),
+?line <<"baruQUCmWhYKFBWj">> = iolist_to_binary(re:replace("barbaz","(?<=(?<!foo)bar)baz","uQUCmWhYKF\\1BWj\\1",[global])),
+?line <<"barbarTNMlbazRYUbazYJyQER">> = iolist_to_binary(re:replace("barbarbaz","(?<=(?<!foo)bar)baz","TNMl\\1&RYU&YJyQER",[])),
+?line <<"barbarTNMlbazRYUbazYJyQER">> = iolist_to_binary(re:replace("barbarbaz","(?<=(?<!foo)bar)baz","TNMl\\1&RYU&YJyQER",[global])),
+?line <<"koobarxhTvv">> = iolist_to_binary(re:replace("koobarbaz","(?<=(?<!foo)bar)baz","xhTvv\\1",[])),
+?line <<"koobarxhTvv">> = iolist_to_binary(re:replace("koobarbaz","(?<=(?<!foo)bar)baz","xhTvv\\1",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?<=(?<!foo)bar)baz","uHmyIQ&yV&hQ&Di&\\1",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?<=(?<!foo)bar)baz","uHmyIQ&yV&hQ&Di&\\1",[global])),
+?line <<"baz">> = iolist_to_binary(re:replace("baz","(?<=(?<!foo)bar)baz","B",[])),
+?line <<"baz">> = iolist_to_binary(re:replace("baz","(?<=(?<!foo)bar)baz","B",[global])),
+?line <<"foobarbaz">> = iolist_to_binary(re:replace("foobarbaz","(?<=(?<!foo)bar)baz","BuNXYgf",[])),
+?line <<"foobarbaz">> = iolist_to_binary(re:replace("foobarbaz","(?<=(?<!foo)bar)baz","BuNXYgf",[global])),
+?line <<"a">> = iolist_to_binary(re:replace("a","^(a\\1?){4}$","N\\1&Psi",[])),
+?line <<"a">> = iolist_to_binary(re:replace("a","^(a\\1?){4}$","N\\1&Psi",[global])),
+?line <<"aa">> = iolist_to_binary(re:replace("aa","^(a\\1?){4}$","&",[])),
+?line <<"aa">> = iolist_to_binary(re:replace("aa","^(a\\1?){4}$","&",[global])),
+?line <<"aaa">> = iolist_to_binary(re:replace("aaa","^(a\\1?){4}$","\\1OPhpdjl&J&F&j",[])),
+?line <<"aaa">> = iolist_to_binary(re:replace("aaa","^(a\\1?){4}$","\\1OPhpdjl&J&F&j",[global])),
+?line <<"oEaaPaaaaFyHMpKbNxCqlyG">> = iolist_to_binary(re:replace("aaaa","^(a\\1?){4}$","oE\\1\\1P&FyHMpKbNxCqlyG",[])),
+?line <<"oEaaPaaaaFyHMpKbNxCqlyG">> = iolist_to_binary(re:replace("aaaa","^(a\\1?){4}$","oE\\1\\1P&FyHMpKbNxCqlyG",[global])),
+?line <<"aaaaaawR">> = iolist_to_binary(re:replace("aaaaa","^(a\\1?){4}$","\\1&wR",[])),
+?line <<"aaaaaawR">> = iolist_to_binary(re:replace("aaaaa","^(a\\1?){4}$","\\1&wR",[global])),
+?line <<"SaWUrMlNUaaaaaaaaaaaaaan">> = iolist_to_binary(re:replace("aaaaaaa","^(a\\1?){4}$","S\\1WUrMlNU&&n",[])),
+?line <<"SaWUrMlNUaaaaaaaaaaaaaan">> = iolist_to_binary(re:replace("aaaaaaa","^(a\\1?){4}$","S\\1WUrMlNU&&n",[global])),
+?line <<"aaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaa","^(a\\1?){4}$","Vk&&RgxI\\1\\1pJ&&",[])),
+?line <<"aaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaa","^(a\\1?){4}$","Vk&&RgxI\\1\\1pJ&&",[global])),
+?line <<"aaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaa","^(a\\1?){4}$","x",[])),
+?line <<"aaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaa","^(a\\1?){4}$","x",[global])),
+?line <<"FEkJCFraaaaaaaaaaaaaaaaaaaaMlwosy">> = iolist_to_binary(re:replace("aaaaaaaaaa","^(a\\1?){4}$","FEkJCFr&&Mlwosy",[])),
+?line <<"FEkJCFraaaaaaaaaaaaaaaaaaaaMlwosy">> = iolist_to_binary(re:replace("aaaaaaaaaa","^(a\\1?){4}$","FEkJCFr&&Mlwosy",[global])),
+?line <<"aaaaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaaaa","^(a\\1?){4}$","&IO",[])),
+?line <<"aaaaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaaaa","^(a\\1?){4}$","&IO",[global])),
+?line <<"aaaaaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaaaaa","^(a\\1?){4}$","lKw",[])),
+?line <<"aaaaaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaaaaa","^(a\\1?){4}$","lKw",[global])),
+?line <<"aaaaaaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaaaaaa","^(a\\1?){4}$","nN&bSVJh\\1J\\1d&Ko",[])),
+?line <<"aaaaaaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaaaaaa","^(a\\1?){4}$","nN&bSVJh\\1J\\1d&Ko",[global])),
+?line <<"aaaaaaaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaaaaaaa","^(a\\1?){4}$","Fut\\1X\\1",[])),
+?line <<"aaaaaaaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaaaaaaa","^(a\\1?){4}$","Fut\\1X\\1",[global])),
+?line <<"aaaaaaaaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaaaaaaaa","^(a\\1?){4}$","v",[])),
+?line <<"aaaaaaaaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaaaaaaaa","^(a\\1?){4}$","v",[global])),
+?line <<"aaaaaaaaaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaaaaaaaaa","^(a\\1?){4}$","b",[])),
+?line <<"aaaaaaaaaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaaaaaaaaa","^(a\\1?){4}$","b",[global])),
+?line <<"a">> = iolist_to_binary(re:replace("a","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$","VC",[])),
+?line <<"a">> = iolist_to_binary(re:replace("a","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$","VC",[global])),
+?line <<"aa">> = iolist_to_binary(re:replace("aa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$","&&mKsMkXfPP",[])),
+?line <<"aa">> = iolist_to_binary(re:replace("aa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$","&&mKsMkXfPP",[global])),
+?line <<"aaa">> = iolist_to_binary(re:replace("aaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$","c\\1HhkFrF&vy&\\1bmNHPw",[])),
+?line <<"aaa">> = iolist_to_binary(re:replace("aaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$","c\\1HhkFrF&vy&\\1bmNHPw",[global])),
+?line <<"SnJcTQRFQiat">> = iolist_to_binary(re:replace("aaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$","SnJcTQRFQi\\1t",[])),
+?line <<"SnJcTQRFQiat">> = iolist_to_binary(re:replace("aaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$","SnJcTQRFQi\\1t",[global])),
+?line <<"MaaaaakiYfFeaaaaaetD">> = iolist_to_binary(re:replace("aaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$","M&kiYfFe&etD",[])),
+?line <<"MaaaaakiYfFeaaaaaetD">> = iolist_to_binary(re:replace("aaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$","M&kiYfFe&etD",[global])),
+?line <<"WDaaaaaasEn">> = iolist_to_binary(re:replace("aaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$","WD&sEn",[])),
+?line <<"WDaaaaaasEn">> = iolist_to_binary(re:replace("aaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$","WD&sEn",[global])),
+?line <<"sauvrqyMaaaaaaaEvrD">> = iolist_to_binary(re:replace("aaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$","s\\1uvrqyM&EvrD",[])),
+?line <<"sauvrqyMaaaaaaaEvrD">> = iolist_to_binary(re:replace("aaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$","s\\1uvrqyM&EvrD",[global])),
+?line <<"aaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$","WyhxEMLFTAGuL&Hymc",[])),
+?line <<"aaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$","WyhxEMLFTAGuL&Hymc",[global])),
+?line <<"aaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$","\\1WXGI&T&rPigX\\1IAQu",[])),
+?line <<"aaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$","\\1WXGI&T&rPigX\\1IAQu",[global])),
+?line <<"HaaaaaaaaaajHUn">> = iolist_to_binary(re:replace("aaaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$","H&jHUn",[])),
+?line <<"HaaaaaaaaaajHUn">> = iolist_to_binary(re:replace("aaaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$","H&jHUn",[global])),
+?line <<"aaaaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$","e",[])),
+?line <<"aaaaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$","e",[global])),
+?line <<"aaaaaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$","dSM\\1GGkyX&xNUIVG&",[])),
+?line <<"aaaaaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$","dSM\\1GGkyX&xNUIVG&",[global])),
+?line <<"aaaaaaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$","p\\1T",[])),
+?line <<"aaaaaaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$","p\\1T",[global])),
+?line <<"aaaaaaaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$","wOWcxD\\1e&",[])),
+?line <<"aaaaaaaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$","wOWcxD\\1e&",[global])),
+?line <<"aaaaaaaaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$","C&CWw&kAen&",[])),
+?line <<"aaaaaaaaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$","C&CWw&kAen&",[global])),
+?line <<"aaaaaaaaaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$","rkiiFEQ&WDahG&lSqR",[])),
+?line <<"aaaaaaaaaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$","rkiiFEQ&WDahG&lSqR",[global])),
+?line <<"babcoabcabcESPlWKsDDog">> = iolist_to_binary(re:replace("abc","abc","b&o&&\\1ES\\1\\1PlWKsD\\1Dog",[])),
+?line <<"babcoabcabcESPlWKsDDog">> = iolist_to_binary(re:replace("abc","abc","b&o&&\\1ES\\1\\1PlWKsD\\1Dog",[global])),
+?line <<"xFfvcJy">> = iolist_to_binary(re:replace("xabcy","abc","FfvcJ",[])),
+?line <<"xFfvcJy">> = iolist_to_binary(re:replace("xabcy","abc","FfvcJ",[global])),
+?line <<"abaGvHrWEIIXoI">> = iolist_to_binary(re:replace("ababc","abc","a\\1\\1G\\1v\\1HrWEIIXoI\\1",[])),
+?line <<"abaGvHrWEIIXoI">> = iolist_to_binary(re:replace("ababc","abc","a\\1\\1G\\1v\\1HrWEIIXoI\\1",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","abc","DOtxCgk&UIBKmk\\1",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","abc","DOtxCgk&UIBKmk\\1",[global])),
+?line <<"xbc">> = iolist_to_binary(re:replace("xbc","abc","qmfvVTE\\1aHl\\1BT&U",[])),
+?line <<"xbc">> = iolist_to_binary(re:replace("xbc","abc","qmfvVTE\\1aHl\\1BT&U",[global])),
+?line <<"axc">> = iolist_to_binary(re:replace("axc","abc","uN&yFKoX\\1pBswe\\1HLf",[])),
+?line <<"axc">> = iolist_to_binary(re:replace("axc","abc","uN&yFKoX\\1pBswe\\1HLf",[global])),
+?line <<"abx">> = iolist_to_binary(re:replace("abx","abc","&v\\1\\1QwMhqY",[])),
+?line <<"abx">> = iolist_to_binary(re:replace("abx","abc","&v\\1\\1QwMhqY",[global])),
+?line <<"FIOGpcHeabcNHJ">> = iolist_to_binary(re:replace("abc","ab*c","FIOGpcHe&NHJ",[])),
+?line <<"FIOGpcHeabcNHJ">> = iolist_to_binary(re:replace("abc","ab*c","FIOGpcHe&NHJ",[global])),
+?line <<"abcbnCUabcnxKKHabcXVaO">> = iolist_to_binary(re:replace("abc","ab*bc","&bnCU&n\\1xKKH&\\1XVaO",[])),
+?line <<"abcbnCUabcnxKKHabcXVaO">> = iolist_to_binary(re:replace("abc","ab*bc","&bnCU&n\\1xKKH&\\1XVaO",[global])),
+?line <<"bFtejUbnDA">> = iolist_to_binary(re:replace("abbc","ab*bc","bFtejUbn\\1DA",[])),
+?line <<"bFtejUbnDA">> = iolist_to_binary(re:replace("abbc","ab*bc","bFtejUbn\\1DA",[global])),
+?line <<"W">> = iolist_to_binary(re:replace("abbbbc","ab*bc","W",[])),
+?line <<"W">> = iolist_to_binary(re:replace("abbbbc","ab*bc","W",[global])),
+?line <<"BlaEararHKSGaabbbbc">> = iolist_to_binary(re:replace("abbbbc",".{1}","Bl&E&r&r\\1HKSG&&\\1",[])),
+?line <<"BlaEararHKSGaaBlbEbrbrHKSGbbBlbEbrbrHKSGbbBlbEbrbrHKSGbbBlbEbrbrHKSGbbBlcEcrcrHKSGcc">> = iolist_to_binary(re:replace("abbbbc",".{1}","Bl&E&r&r\\1HKSG&&\\1",[global])),
+?line <<"pabbbcRXxcEabbbIabbbXTbc">> = iolist_to_binary(re:replace("abbbbc",".{3,4}","p&cRXxcE&I&XT",[])),
+?line <<"pabbbcRXxcEabbbIabbbXTbc">> = iolist_to_binary(re:replace("abbbbc",".{3,4}","p&cRXxcE&I&XT",[global])),
+?line <<"HkIFCqCBaabbbbcyHm">> = iolist_to_binary(re:replace("abbbbc","ab{0,}bc","Hk\\1IFCq\\1CBa&yHm",[])),
+?line <<"HkIFCqCBaabbbbcyHm">> = iolist_to_binary(re:replace("abbbbc","ab{0,}bc","Hk\\1IFCq\\1CBa&yHm",[global])),
+?line <<"HBKHabbcHxdabbciuxleGabbc">> = iolist_to_binary(re:replace("abbc","ab+bc","HBKH&\\1Hx\\1d&iuxleG&",[])),
+?line <<"HBKHabbcHxdabbciuxleGabbc">> = iolist_to_binary(re:replace("abbc","ab+bc","HBKH&\\1Hx\\1d&iuxleG&",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","ab+bc","&Pm&sRjS",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","ab+bc","&Pm&sRjS",[global])),
+?line <<"abc">> = iolist_to_binary(re:replace("abc","ab+bc","IiWLkYFrIIhMk\\1D\\1vagP",[])),
+?line <<"abc">> = iolist_to_binary(re:replace("abc","ab+bc","IiWLkYFrIIhMk\\1D\\1vagP",[global])),
+?line <<"abq">> = iolist_to_binary(re:replace("abq","ab+bc","&\\1\\1UiX\\1&MgPB",[])),
+?line <<"abq">> = iolist_to_binary(re:replace("abq","ab+bc","&\\1\\1UiX\\1&MgPB",[global])),
+?line <<"WLvlqVMuiA">> = iolist_to_binary(re:replace("abbbbc","ab+bc","WLvlqVMuiA",[])),
+?line <<"WLvlqVMuiA">> = iolist_to_binary(re:replace("abbbbc","ab+bc","WLvlqVMuiA",[global])),
+?line <<"qQ">> = iolist_to_binary(re:replace("abbbbc","ab{1,}bc","qQ",[])),
+?line <<"qQ">> = iolist_to_binary(re:replace("abbbbc","ab{1,}bc","qQ",[global])),
+?line <<"ALwvHVhFGH">> = iolist_to_binary(re:replace("abbbbc","ab{1,3}bc","A\\1LwvHVhFGH",[])),
+?line <<"ALwvHVhFGH">> = iolist_to_binary(re:replace("abbbbc","ab{1,3}bc","A\\1LwvHVhFGH",[global])),
+?line <<"ORLsuabbbbc">> = iolist_to_binary(re:replace("abbbbc","ab{3,4}bc","ORL\\1su&",[])),
+?line <<"ORLsuabbbbc">> = iolist_to_binary(re:replace("abbbbc","ab{3,4}bc","ORL\\1su&",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","ab{4,5}bc","APwPKjxS\\1Di&\\1",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","ab{4,5}bc","APwPKjxS\\1Di&\\1",[global])),
+?line <<"abq">> = iolist_to_binary(re:replace("abq","ab{4,5}bc","FVk",[])),
+?line <<"abq">> = iolist_to_binary(re:replace("abq","ab{4,5}bc","FVk",[global])),
+?line <<"abbbbc">> = iolist_to_binary(re:replace("abbbbc","ab{4,5}bc","PO&t",[])),
+?line <<"abbbbc">> = iolist_to_binary(re:replace("abbbbc","ab{4,5}bc","PO&t",[global])),
+?line <<"EHtIXyQbabbclaCBg">> = iolist_to_binary(re:replace("abbc","ab?bc","EHtIXyQb&laCBg",[])),
+?line <<"EHtIXyQbabbclaCBg">> = iolist_to_binary(re:replace("abbc","ab?bc","EHtIXyQb&laCBg",[global])),
+?line <<"SVx">> = iolist_to_binary(re:replace("abc","ab?bc","SVx",[])),
+?line <<"SVx">> = iolist_to_binary(re:replace("abc","ab?bc","SVx",[global])),
+?line <<"KJabcWtBNRX">> = iolist_to_binary(re:replace("abc","ab{0,1}bc","KJ&WtBNRX",[])),
+?line <<"KJabcWtBNRX">> = iolist_to_binary(re:replace("abc","ab{0,1}bc","KJ&WtBNRX",[global])),
+?line <<"oabcQlOwmmeXxTySSV">> = iolist_to_binary(re:replace("abc","ab?c","o&Q\\1lOwmmeXx\\1TySSV",[])),
+?line <<"oabcQlOwmmeXxTySSV">> = iolist_to_binary(re:replace("abc","ab?c","o&Q\\1lOwmmeXx\\1TySSV",[global])),
+?line <<"abcQpPYPtQcFabcCDEcWOl">> = iolist_to_binary(re:replace("abc","ab{0,1}c","&QpPY\\1PtQcF&CDEcWOl",[])),
+?line <<"abcQpPYPtQcFabcCDEcWOl">> = iolist_to_binary(re:replace("abc","ab{0,1}c","&QpPY\\1PtQcF&CDEcWOl",[global])),
+?line <<"YbB">> = iolist_to_binary(re:replace("abc","^abc$","YbB",[])),
+?line <<"YbB">> = iolist_to_binary(re:replace("abc","^abc$","YbB",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^abc$","r&t\\1OLYfC",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^abc$","r&t\\1OLYfC",[global])),
+?line <<"abbbbc">> = iolist_to_binary(re:replace("abbbbc","^abc$","P&QwAxc\\1vYfQF",[])),
+?line <<"abbbbc">> = iolist_to_binary(re:replace("abbbbc","^abc$","P&QwAxc\\1vYfQF",[global])),
+?line <<"abcc">> = iolist_to_binary(re:replace("abcc","^abc$","d\\1j&LhAN\\1JvojhyCmSwU",[])),
+?line <<"abcc">> = iolist_to_binary(re:replace("abcc","^abc$","d\\1j&LhAN\\1JvojhyCmSwU",[global])),
+?line <<"yabcxAc">> = iolist_to_binary(re:replace("abcc","^abc","y\\1&xA",[])),
+?line <<"yabcxAc">> = iolist_to_binary(re:replace("abcc","^abc","y\\1&xA",[global])),
+?line <<"awrOx">> = iolist_to_binary(re:replace("aabc","abc$","wrOx",[])),
+?line <<"awrOx">> = iolist_to_binary(re:replace("aabc","abc$","wrOx",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","abc$","XLe",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","abc$","XLe",[global])),
+?line <<"aRthCinfyGSJTg">> = iolist_to_binary(re:replace("aabc","abc$","\\1RthCi\\1nfyGSJTg",[])),
+?line <<"aRthCinfyGSJTg">> = iolist_to_binary(re:replace("aabc","abc$","\\1RthCi\\1nfyGSJTg",[global])),
+?line <<"aabcd">> = iolist_to_binary(re:replace("aabcd","abc$","UT&CPLaUA\\1nluQPA",[])),
+?line <<"aabcd">> = iolist_to_binary(re:replace("aabcd","abc$","UT&CPLaUA\\1nluQPA",[global])),
+?line <<"hYaxcodDoHwNTLtDQoabc">> = iolist_to_binary(re:replace("abc","^","hYaxc&o&dDoHwNTLtDQo",[])),
+?line <<"hYaxcodDoHwNTLtDQoabc">> = iolist_to_binary(re:replace("abc","^","hYaxc&o&dDoHwNTLtDQo",[global])),
+?line <<"abcepxRqYNdJMdQeRKr">> = iolist_to_binary(re:replace("abc","$","epxRqYNdJ&MdQeR&Kr",[])),
+?line <<"abcepxRqYNdJMdQeRKr">> = iolist_to_binary(re:replace("abc","$","epxRqYNdJ&MdQeR&Kr",[global])),
+?line <<"vnabcXvSRrFjWv">> = iolist_to_binary(re:replace("abc","a.c","\\1vn&X\\1vSRrFj\\1Wv",[])),
+?line <<"vnabcXvSRrFjWv">> = iolist_to_binary(re:replace("abc","a.c","\\1vn&X\\1vSRrFj\\1Wv",[global])),
+?line <<"YSYAvHCLl">> = iolist_to_binary(re:replace("axc","a.c","Y\\1\\1SYAvHCLl",[])),
+?line <<"YSYAvHCLl">> = iolist_to_binary(re:replace("axc","a.c","Y\\1\\1SYAvHCLl",[global])),
+?line <<"oTi">> = iolist_to_binary(re:replace("axyzc","a.*c","oTi",[])),
+?line <<"oTi">> = iolist_to_binary(re:replace("axyzc","a.*c","oTi",[global])),
+?line <<"abdd">> = iolist_to_binary(re:replace("abd","a[bc]d","&d",[])),
+?line <<"abdd">> = iolist_to_binary(re:replace("abd","a[bc]d","&d",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","a[bc]d","m",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","a[bc]d","m",[global])),
+?line <<"axyzd">> = iolist_to_binary(re:replace("axyzd","a[bc]d","xw\\1kClblo&A&pX",[])),
+?line <<"axyzd">> = iolist_to_binary(re:replace("axyzd","a[bc]d","xw\\1kClblo&A&pX",[global])),
+?line <<"abc">> = iolist_to_binary(re:replace("abc","a[bc]d","DXVJBfd&&nWiQKDXx&p",[])),
+?line <<"abc">> = iolist_to_binary(re:replace("abc","a[bc]d","DXVJBfd&&nWiQKDXx&p",[global])),
+?line <<"qgcyq">> = iolist_to_binary(re:replace("ace","a[b-d]e","qgcyq\\1",[])),
+?line <<"qgcyq">> = iolist_to_binary(re:replace("ace","a[b-d]e","qgcyq\\1",[global])),
+?line <<"aSo">> = iolist_to_binary(re:replace("aac","a[b-d]","S\\1o",[])),
+?line <<"aSo">> = iolist_to_binary(re:replace("aac","a[b-d]","S\\1o",[global])),
+?line <<"FalJiLh">> = iolist_to_binary(re:replace("a-","a[-b]","FalJ\\1iL\\1h",[])),
+?line <<"FalJiLh">> = iolist_to_binary(re:replace("a-","a[-b]","FalJ\\1iL\\1h",[global])),
+?line <<"aea-">> = iolist_to_binary(re:replace("a-","a[b-]","ae&",[])),
+?line <<"aea-">> = iolist_to_binary(re:replace("a-","a[b-]","ae&",[global])),
+?line <<"Uxci">> = iolist_to_binary(re:replace("a]","a]","Uxci",[])),
+?line <<"Uxci">> = iolist_to_binary(re:replace("a]","a]","Uxci",[global])),
+?line <<"fuDs">> = iolist_to_binary(re:replace("a]b","a[]]b","fu\\1Ds",[])),
+?line <<"fuDs">> = iolist_to_binary(re:replace("a]b","a[]]b","fu\\1Ds",[global])),
+?line <<"S">> = iolist_to_binary(re:replace("aed","a[^bc]d","\\1S",[])),
+?line <<"S">> = iolist_to_binary(re:replace("aed","a[^bc]d","\\1S",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","a[^bc]d","q\\1c",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","a[^bc]d","q\\1c",[global])),
+?line <<"abd">> = iolist_to_binary(re:replace("abd","a[^bc]d","CwigRG\\1",[])),
+?line <<"abd">> = iolist_to_binary(re:replace("abd","a[^bc]d","CwigRG\\1",[global])),
+?line <<"abd">> = iolist_to_binary(re:replace("abd","a[^bc]d","G&sOiYoXxtvjC\\1C",[])),
+?line <<"abd">> = iolist_to_binary(re:replace("abd","a[^bc]d","G&sOiYoXxtvjC\\1C",[global])),
+?line <<"WjwradcGadcGdiadcJadcadc">> = iolist_to_binary(re:replace("adc","a[^-b]c","Wjwr&G&Gdi&J&&",[])),
+?line <<"WjwradcGadcGdiadcJadcadc">> = iolist_to_binary(re:replace("adc","a[^-b]c","Wjwr&G&Gdi&J&&",[global])),
+?line <<"sXuNQuSoADXQHaadcc">> = iolist_to_binary(re:replace("adc","a[^]b]c","sXuNQuS\\1oAD\\1XQH\\1a&c",[])),
+?line <<"sXuNQuSoADXQHaadcc">> = iolist_to_binary(re:replace("adc","a[^]b]c","sXuNQuS\\1oAD\\1XQH\\1a&c",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","a[^]b]c","\\1WTVFfqlY\\1I",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","a[^]b]c","\\1WTVFfqlY\\1I",[global])),
+?line <<"a-c">> = iolist_to_binary(re:replace("a-c","a[^]b]c","&",[])),
+?line <<"a-c">> = iolist_to_binary(re:replace("a-c","a[^]b]c","&",[global])),
+?line <<"a]c">> = iolist_to_binary(re:replace("a]c","a[^]b]c","U\\1ASb",[])),
+?line <<"a]c">> = iolist_to_binary(re:replace("a]c","a[^]b]c","U\\1ASb",[global])),
+?line <<"FhmTxP-">> = iolist_to_binary(re:replace("a-","\\ba\\b","FhmTxP",[])),
+?line <<"FhmTxP-">> = iolist_to_binary(re:replace("a-","\\ba\\b","FhmTxP",[global])),
+?line <<"-sIgAwOVeaIs">> = iolist_to_binary(re:replace("-a","\\ba\\b","sIgAwOVe&Is",[])),
+?line <<"-sIgAwOVeaIs">> = iolist_to_binary(re:replace("-a","\\ba\\b","sIgAwOVe&Is",[global])),
+?line <<"-K-">> = iolist_to_binary(re:replace("-a-","\\ba\\b","K",[])),
+?line <<"-K-">> = iolist_to_binary(re:replace("-a-","\\ba\\b","K",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","\\by\\b","NFs\\1N&no&v&LBhrfD",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","\\by\\b","NFs\\1N&no&v&LBhrfD",[global])),
+?line <<"xy">> = iolist_to_binary(re:replace("xy","\\by\\b","\\1&WFL&q",[])),
+?line <<"xy">> = iolist_to_binary(re:replace("xy","\\by\\b","\\1&WFL&q",[global])),
+?line <<"yz">> = iolist_to_binary(re:replace("yz","\\by\\b","pjeKdgSu&&",[])),
+?line <<"yz">> = iolist_to_binary(re:replace("yz","\\by\\b","pjeKdgSu&&",[global])),
+?line <<"xyz">> = iolist_to_binary(re:replace("xyz","\\by\\b","hyG",[])),
+?line <<"xyz">> = iolist_to_binary(re:replace("xyz","\\by\\b","hyG",[global])),
+?line <<"*** FCasopdebailers">> = iolist_to_binary(re:replace("*** Failers","\\Ba\\B","C\\1&sopdeb&",[])),
+?line <<"*** FCasopdebailers">> = iolist_to_binary(re:replace("*** Failers","\\Ba\\B","C\\1&sopdeb&",[global])),
+?line <<"a-">> = iolist_to_binary(re:replace("a-","\\Ba\\B","mnLWav",[])),
+?line <<"a-">> = iolist_to_binary(re:replace("a-","\\Ba\\B","mnLWav",[global])),
+?line <<"-a">> = iolist_to_binary(re:replace("-a","\\Ba\\B","X&NpSD\\1If",[])),
+?line <<"-a">> = iolist_to_binary(re:replace("-a","\\Ba\\B","X&NpSD\\1If",[global])),
+?line <<"-a-">> = iolist_to_binary(re:replace("-a-","\\Ba\\B","loFA&cpicKF&FLSfj&",[])),
+?line <<"-a-">> = iolist_to_binary(re:replace("-a-","\\Ba\\B","loFA&cpicKF&FLSfj&",[global])),
+?line <<"xyTAT">> = iolist_to_binary(re:replace("xy","\\By\\b","&TAT",[])),
+?line <<"xyTAT">> = iolist_to_binary(re:replace("xy","\\By\\b","&TAT",[global])),
+?line <<"fxz">> = iolist_to_binary(re:replace("yz","\\by\\B","fx\\1\\1",[])),
+?line <<"fxz">> = iolist_to_binary(re:replace("yz","\\by\\B","fx\\1\\1",[global])),
+?line <<"xKryOdAEz">> = iolist_to_binary(re:replace("xyz","\\By\\B","Kr&OdAE",[])),
+?line <<"xKryOdAEz">> = iolist_to_binary(re:replace("xyz","\\By\\B","Kr&OdAE",[global])),
+?line <<"IRVtaAqLDh">> = iolist_to_binary(re:replace("a","\\w","IRVt&AqLDh\\1",[])),
+?line <<"IRVtaAqLDh">> = iolist_to_binary(re:replace("a","\\w","IRVt&AqLDh\\1",[global])),
+?line <<"EckncnNqwHO">> = iolist_to_binary(re:replace("-","\\W","EckncnNq\\1wHO\\1",[])),
+?line <<"EckncnNqwHO">> = iolist_to_binary(re:replace("-","\\W","EckncnNq\\1wHO\\1",[global])),
+?line <<"Yf*VvjLGbD*h** Failers">> = iolist_to_binary(re:replace("*** Failers","\\W","Yf&VvjLGbD&h",[])),
+?line <<"Yf*VvjLGbD*hYf*VvjLGbD*hYf*VvjLGbD*hYf VvjLGbD hFailers">> = iolist_to_binary(re:replace("*** Failers","\\W","Yf&VvjLGbD&h",[global])),
+?line <<"GBjpbjk">> = iolist_to_binary(re:replace("-","\\W","GBjpbjk",[])),
+?line <<"GBjpbjk">> = iolist_to_binary(re:replace("-","\\W","GBjpbjk",[global])),
+?line <<"a">> = iolist_to_binary(re:replace("a","\\W","j",[])),
+?line <<"a">> = iolist_to_binary(re:replace("a","\\W","j",[global])),
+?line <<"VAiCYGiBXpa bumnbi">> = iolist_to_binary(re:replace("a b","a\\sb","VAiCYGiBX\\1p&umn\\1bi",[])),
+?line <<"VAiCYGiBXpa bumnbi">> = iolist_to_binary(re:replace("a b","a\\sb","VAiCYGiBX\\1p&umn\\1bi",[global])),
+?line <<"Etv">> = iolist_to_binary(re:replace("a-b","a\\Sb","Etv",[])),
+?line <<"Etv">> = iolist_to_binary(re:replace("a-b","a\\Sb","Etv",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","a\\Sb","EbhHjGSDvEtLT\\1cSURa",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","a\\Sb","EbhHjGSDvEtLT\\1cSURa",[global])),
+?line <<"uD">> = iolist_to_binary(re:replace("a-b","a\\Sb","uD",[])),
+?line <<"uD">> = iolist_to_binary(re:replace("a-b","a\\Sb","uD",[global])),
+?line <<"a b">> = iolist_to_binary(re:replace("a b","a\\Sb","fQm&D&nJmqrWl",[])),
+?line <<"a b">> = iolist_to_binary(re:replace("a b","a\\Sb","fQm&D&nJmqrWl",[global])),
+?line <<"jti">> = iolist_to_binary(re:replace("1","\\d","jti",[])),
+?line <<"jti">> = iolist_to_binary(re:replace("1","\\d","jti",[global])),
+?line <<"-m">> = iolist_to_binary(re:replace("-","\\D","&m",[])),
+?line <<"-m">> = iolist_to_binary(re:replace("-","\\D","&m",[global])),
+?line <<"Tw** Failers">> = iolist_to_binary(re:replace("*** Failers","\\D","\\1Tw",[])),
+?line <<"TwTwTwTwTwTwTwTwTwTwTw">> = iolist_to_binary(re:replace("*** Failers","\\D","\\1Tw",[global])),
+?line <<"T">> = iolist_to_binary(re:replace("-","\\D","T",[])),
+?line <<"T">> = iolist_to_binary(re:replace("-","\\D","T",[global])),
+?line <<"1">> = iolist_to_binary(re:replace("1","\\D","QkyGdjVcibs",[])),
+?line <<"1">> = iolist_to_binary(re:replace("1","\\D","QkyGdjVcibs",[global])),
+?line <<"Vsg">> = iolist_to_binary(re:replace("a","[\\w]","Vsg",[])),
+?line <<"Vsg">> = iolist_to_binary(re:replace("a","[\\w]","Vsg",[global])),
+?line <<"AeUjdVITmvExYR">> = iolist_to_binary(re:replace("-","[\\W]","AeU\\1jdVITmvExYR\\1",[])),
+?line <<"AeUjdVITmvExYR">> = iolist_to_binary(re:replace("-","[\\W]","AeU\\1jdVITmvExYR\\1",[global])),
+?line <<"WhGTRj*eDnCm** Failers">> = iolist_to_binary(re:replace("*** Failers","[\\W]","WhGTRj&eDnCm",[])),
+?line <<"WhGTRj*eDnCmWhGTRj*eDnCmWhGTRj*eDnCmWhGTRj eDnCmFailers">> = iolist_to_binary(re:replace("*** Failers","[\\W]","WhGTRj&eDnCm",[global])),
+?line <<"c-aqg-Be">> = iolist_to_binary(re:replace("-","[\\W]","c&aqg&Be",[])),
+?line <<"c-aqg-Be">> = iolist_to_binary(re:replace("-","[\\W]","c&aqg&Be",[global])),
+?line <<"a">> = iolist_to_binary(re:replace("a","[\\W]","lS",[])),
+?line <<"a">> = iolist_to_binary(re:replace("a","[\\W]","lS",[global])),
+?line <<"aTa bLH">> = iolist_to_binary(re:replace("a b","a[\\s]b","aT&LH\\1",[])),
+?line <<"aTa bLH">> = iolist_to_binary(re:replace("a b","a[\\s]b","aT&LH\\1",[global])),
+?line <<"a">> = iolist_to_binary(re:replace("a-b","a[\\S]b","a",[])),
+?line <<"a">> = iolist_to_binary(re:replace("a-b","a[\\S]b","a",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","a[\\S]b","b\\1E&yC\\1kT&CwD",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","a[\\S]b","b\\1E&yC\\1kT&CwD",[global])),
+?line <<"a-bfLEHcwVqa-bwEar">> = iolist_to_binary(re:replace("a-b","a[\\S]b","&fLE\\1\\1Hcw\\1V\\1q&wEar",[])),
+?line <<"a-bfLEHcwVqa-bwEar">> = iolist_to_binary(re:replace("a-b","a[\\S]b","&fLE\\1\\1Hcw\\1V\\1q&wEar",[global])),
+?line <<"a b">> = iolist_to_binary(re:replace("a b","a[\\S]b","E\\1NcSC&l",[])),
+?line <<"a b">> = iolist_to_binary(re:replace("a b","a[\\S]b","E\\1NcSC&l",[global])),
+?line <<"U1LgIwNodaqkLmOQ">> = iolist_to_binary(re:replace("1","[\\d]","U\\1&LgIwNo\\1daqkL\\1mOQ",[])),
+?line <<"U1LgIwNodaqkLmOQ">> = iolist_to_binary(re:replace("1","[\\d]","U\\1&LgIwNo\\1daqkL\\1mOQ",[global])),
+?line <<"XTGOaAL-XOENvmW">> = iolist_to_binary(re:replace("-","[\\D]","XTGOa\\1AL&XOE\\1NvmW",[])),
+?line <<"XTGOaAL-XOENvmW">> = iolist_to_binary(re:replace("-","[\\D]","XTGOa\\1AL&XOE\\1NvmW",[global])),
+?line <<"*rIhW*QnqjR*** Failers">> = iolist_to_binary(re:replace("*** Failers","[\\D]","&\\1r\\1I\\1h\\1W&Q\\1n\\1qjR&",[])),
+?line <<"*rIhW*QnqjR**rIhW*QnqjR**rIhW*QnqjR* rIhW QnqjR FrIhWFQnqjRFarIhWaQnqjRairIhWiQnqjRilrIhWlQnqjRlerIhWeQnqjRerrIhWrQnqjRrsrIhWsQnqjRs">> = iolist_to_binary(re:replace("*** Failers","[\\D]","&\\1r\\1I\\1h\\1W&Q\\1n\\1qjR&",[global])),
+?line <<"TEOmg-mrq">> = iolist_to_binary(re:replace("-","[\\D]","TE\\1Omg&\\1mrq",[])),
+?line <<"TEOmg-mrq">> = iolist_to_binary(re:replace("-","[\\D]","TE\\1Omg&\\1mrq",[global])),
+?line <<"1">> = iolist_to_binary(re:replace("1","[\\D]","YI\\1o&\\1IwvchJgD&&",[])),
+?line <<"1">> = iolist_to_binary(re:replace("1","[\\D]","YI\\1o&\\1IwvchJgD&&",[global])),
+?line <<"DKXoAolSGIabc">> = iolist_to_binary(re:replace("abc","ab|cd","DKXoAolSGI&",[])),
+?line <<"DKXoAolSGIabc">> = iolist_to_binary(re:replace("abc","ab|cd","DKXoAolSGI&",[global])),
+?line <<"tFHUIrVcd">> = iolist_to_binary(re:replace("abcd","ab|cd","tFHUIrV\\1",[])),
+?line <<"tFHUIrVtFHUIrV">> = iolist_to_binary(re:replace("abcd","ab|cd","tFHUIrV\\1",[global])),
+?line <<"doeAAefCeUJ">> = iolist_to_binary(re:replace("def","()ef","oeAA&CeUJ",[])),
+?line <<"doeAAefCeUJ">> = iolist_to_binary(re:replace("def","()ef","oeAA&CeUJ",[global])),
+?line <<"B">> = iolist_to_binary(re:replace("a(b","a\\(b","B",[])),
+?line <<"B">> = iolist_to_binary(re:replace("a(b","a\\(b","B",[global])),
+?line <<"sFcBhj">> = iolist_to_binary(re:replace("ab","a\\(*b","sFcBhj",[])),
+?line <<"sFcBhj">> = iolist_to_binary(re:replace("ab","a\\(*b","sFcBhj",[global])),
+?line <<"iTla((bUcHSjwja((ba((b">> = iolist_to_binary(re:replace("a((b","a\\(*b","iTl&UcHSjwj\\1&&",[])),
+?line <<"iTla((bUcHSjwja((ba((b">> = iolist_to_binary(re:replace("a((b","a\\(*b","iTl&UcHSjwj\\1&&",[global])),
+?line <<"a">> = iolist_to_binary(re:replace("a","a\\\\b","AkoMVU&",[])),
+?line <<"a">> = iolist_to_binary(re:replace("a","a\\\\b","AkoMVU&",[global])),
+?line <<"Gbc">> = iolist_to_binary(re:replace("abc","((a))","G",[])),
+?line <<"Gbc">> = iolist_to_binary(re:replace("abc","((a))","G",[global])),
+?line <<"aaabcTualQ">> = iolist_to_binary(re:replace("abc","(a)b(c)","\\1\\1&Tu\\1lQ",[])),
+?line <<"aaabcTualQ">> = iolist_to_binary(re:replace("abc","(a)b(c)","\\1\\1&Tu\\1lQ",[global])),
+?line <<"aabbCivt">> = iolist_to_binary(re:replace("aabbabc","a+b+c","\\1Civt",[])),
+?line <<"aabbCivt">> = iolist_to_binary(re:replace("aabbabc","a+b+c","\\1Civt",[global])),
+?line <<"aabbT">> = iolist_to_binary(re:replace("aabbabc","a{1,}b{1,}c","T",[])),
+?line <<"aabbT">> = iolist_to_binary(re:replace("aabbabc","a{1,}b{1,}c","T",[global])),
+?line <<"VxJHThVabcketabcebWabc">> = iolist_to_binary(re:replace("abcabc","a.+?c","VxJHThV&ket&ebW",[])),
+?line <<"VxJHThVabcketabcebWVxJHThVabcketabcebW">> = iolist_to_binary(re:replace("abcabc","a.+?c","VxJHThV&ket&ebW",[global])),
+?line <<"LXfabNabCqMabHb">> = iolist_to_binary(re:replace("ab","(a+|b)*","LXf&N&CqM&H\\1",[])),
+?line <<"LXfabNabCqMabHbLXfNCqMH">> = iolist_to_binary(re:replace("ab","(a+|b)*","LXf&N&CqM&H\\1",[global])),
+?line <<"NNopapyUJpabVxnQ">> = iolist_to_binary(re:replace("ab","(a+|b){0,}","NNopapyUJpa\\1VxnQ",[])),
+?line <<"NNopapyUJpabVxnQNNopapyUJpaVxnQ">> = iolist_to_binary(re:replace("ab","(a+|b){0,}","NNopapyUJpa\\1VxnQ",[global])),
+?line <<"cejhccpabbAd">> = iolist_to_binary(re:replace("ab","(a+|b)+","cejhccp&\\1Ad",[])),
+?line <<"cejhccpabbAd">> = iolist_to_binary(re:replace("ab","(a+|b)+","cejhccp&\\1Ad",[global])),
+?line <<"uMqbbBaYPvPbkabNdlb">> = iolist_to_binary(re:replace("ab","(a+|b){1,}","uMqb\\1BaYPvP\\1k&Ndl\\1",[])),
+?line <<"uMqbbBaYPvPbkabNdlb">> = iolist_to_binary(re:replace("ab","(a+|b){1,}","uMqb\\1BaYPvP\\1k&Ndl\\1",[global])),
+?line <<"cyKMb">> = iolist_to_binary(re:replace("ab","(a+|b)?","cyKM",[])),
+?line <<"cyKMcyKMcyKM">> = iolist_to_binary(re:replace("ab","(a+|b)?","cyKM",[global])),
+?line <<"uaaPjgxb">> = iolist_to_binary(re:replace("ab","(a+|b){0,1}","u\\1\\1Pjgx",[])),
+?line <<"uaaPjgxubbPjgxuPjgx">> = iolist_to_binary(re:replace("ab","(a+|b){0,1}","u\\1\\1Pjgx",[global])),
+?line <<"JsG">> = iolist_to_binary(re:replace("cde","[^ab]*","\\1J\\1sG",[])),
+?line <<"JsGJsG">> = iolist_to_binary(re:replace("cde","[^ab]*","\\1J\\1sG",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","abc","NyHCvfJjxj\\1SrM&BdF",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","abc","NyHCvfJjxj\\1SrM&BdF",[global])),
+?line <<"b">> = iolist_to_binary(re:replace("b","abc","T&\\1Jd\\1tQxU\\1&\\1\\1bp",[])),
+?line <<"b">> = iolist_to_binary(re:replace("b","abc","T&\\1Jd\\1tQxU\\1&\\1\\1bp",[global])),
+?line <<"AHcabbbcdabbbcdabbbcdSCcNR">> = iolist_to_binary(re:replace("abbbcd","([abc])*d","AH\\1&&&SC\\1NR",[])),
+?line <<"AHcabbbcdabbbcdabbbcdSCcNR">> = iolist_to_binary(re:replace("abbbcd","([abc])*d","AH\\1&&&SC\\1NR",[global])),
+?line <<"jDJabcdqabcdgNaaNoyaGm">> = iolist_to_binary(re:replace("abcd","([abc])*bcd","jDJ&q&gN\\1\\1Noy\\1Gm",[])),
+?line <<"jDJabcdqabcdgNaaNoyaGm">> = iolist_to_binary(re:replace("abcd","([abc])*bcd","jDJ&q&gN\\1\\1Noy\\1Gm",[global])),
+?line <<"IHdxtFuTeF">> = iolist_to_binary(re:replace("e","a|b|c|d|e","IHdxtFuT&F",[])),
+?line <<"IHdxtFuTeF">> = iolist_to_binary(re:replace("e","a|b|c|d|e","IHdxtFuT&F",[global])),
+?line <<"RjceNtss">> = iolist_to_binary(re:replace("ef","(a|b|c|d|e)f","Rjc\\1Ntss",[])),
+?line <<"RjceNtss">> = iolist_to_binary(re:replace("ef","(a|b|c|d|e)f","Rjc\\1Ntss",[global])),
+?line <<"nViLDabcdefg">> = iolist_to_binary(re:replace("abcdefg","abcd*efg","nViL\\1D&\\1",[])),
+?line <<"nViLDabcdefg">> = iolist_to_binary(re:replace("abcdefg","abcd*efg","nViL\\1D&\\1",[global])),
+?line <<"xoJUabyHFyabbbz">> = iolist_to_binary(re:replace("xabyabbbz","ab*","oJ\\1U&yHF",[])),
+?line <<"xoJUabyHFyoJUabbbyHFz">> = iolist_to_binary(re:replace("xabyabbbz","ab*","oJ\\1U&yHF",[global])),
+?line <<"xbaEdBayabbbz">> = iolist_to_binary(re:replace("xayabbbz","ab*","b&EdBa",[])),
+?line <<"xbaEdBaybabbbEdBaz">> = iolist_to_binary(re:replace("xayabbbz","ab*","b&EdBa",[global])),
+?line <<"abHqcde">> = iolist_to_binary(re:replace("abcde","(ab|cd)e","Hq&",[])),
+?line <<"abHqcde">> = iolist_to_binary(re:replace("abcde","(ab|cd)e","Hq&",[global])),
+?line <<"lrrKIUARhij">> = iolist_to_binary(re:replace("hij","[abhgefdc]ij","l\\1\\1r\\1rKIUAR&",[])),
+?line <<"lrrKIUARhij">> = iolist_to_binary(re:replace("hij","[abhgefdc]ij","l\\1\\1r\\1rKIUAR&",[global])),
+?line <<"abcdWfgkefnnefNPAQ">> = iolist_to_binary(re:replace("abcdef","(abc|)ef","\\1Wfgk&nn&\\1NPAQ\\1",[])),
+?line <<"abcdWfgkefnnefNPAQ">> = iolist_to_binary(re:replace("abcdef","(abc|)ef","\\1Wfgk&nn&\\1NPAQ\\1",[global])),
+?line <<"aUbGqmbcdWXLMCpYbbcd">> = iolist_to_binary(re:replace("abcd","(a|b)c*d","U\\1Gqm&WXLMCpY\\1&",[])),
+?line <<"aUbGqmbcdWXLMCpYbbcd">> = iolist_to_binary(re:replace("abcd","(a|b)c*d","U\\1Gqm&WXLMCpY\\1&",[global])),
+?line <<"vYALaabcfgsaUfyDabcjOtcQ">> = iolist_to_binary(re:replace("abc","(ab|ab*)bc","vYAL\\1&fgs\\1UfyD&jOtcQ",[])),
+?line <<"vYALaabcfgsaUfyDabcjOtcQ">> = iolist_to_binary(re:replace("abc","(ab|ab*)bc","vYAL\\1&fgs\\1UfyD&jOtcQ",[global])),
+?line <<"uyabcabcp">> = iolist_to_binary(re:replace("abc","a([bc]*)c*","uy&&p",[])),
+?line <<"uyabcabcp">> = iolist_to_binary(re:replace("abc","a([bc]*)c*","uy&&p",[global])),
+?line <<"iAyJUbcM">> = iolist_to_binary(re:replace("abcd","a([bc]*)(c*d)","iAyJU\\1M",[])),
+?line <<"iAyJUbcM">> = iolist_to_binary(re:replace("abcd","a([bc]*)(c*d)","iAyJU\\1M",[global])),
+?line <<"abcdabcdabcd">> = iolist_to_binary(re:replace("abcd","a([bc]+)(c*d)","&&&",[])),
+?line <<"abcdabcdabcd">> = iolist_to_binary(re:replace("abcd","a([bc]+)(c*d)","&&&",[global])),
+?line <<"UgwJmKabcddNBBm">> = iolist_to_binary(re:replace("abcd","a([bc]*)(c+d)","UgwJmK&dNBBm",[])),
+?line <<"UgwJmKabcddNBBm">> = iolist_to_binary(re:replace("abcd","a([bc]*)(c+d)","UgwJmK&dNBBm",[global])),
+?line <<"glXDRFe">> = iolist_to_binary(re:replace("adcdcde","a[bcd]*dcdcde","glXDRFe\\1",[])),
+?line <<"glXDRFe">> = iolist_to_binary(re:replace("adcdcde","a[bcd]*dcdcde","glXDRFe\\1",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","a[bcd]+dcdcde","&\\1Tw",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","a[bcd]+dcdcde","&\\1Tw",[global])),
+?line <<"abcde">> = iolist_to_binary(re:replace("abcde","a[bcd]+dcdcde","OaFcNB\\1AbGk\\1RcX&\\1hU",[])),
+?line <<"abcde">> = iolist_to_binary(re:replace("abcde","a[bcd]+dcdcde","OaFcNB\\1AbGk\\1RcX&\\1hU",[global])),
+?line <<"adcdcde">> = iolist_to_binary(re:replace("adcdcde","a[bcd]+dcdcde","LRCnDGeISr",[])),
+?line <<"adcdcde">> = iolist_to_binary(re:replace("adcdcde","a[bcd]+dcdcde","LRCnDGeISr",[global])),
+?line <<"ab">> = iolist_to_binary(re:replace("abc","(ab|a)b*c","\\1",[])),
+?line <<"ab">> = iolist_to_binary(re:replace("abc","(ab|a)b*c","\\1",[global])),
+?line <<"abcdYujfprabcdqmHBi">> = iolist_to_binary(re:replace("abcd","((a)(b)c)(d)","&Yujfpr&qmHBi",[])),
+?line <<"abcdYujfprabcdqmHBi">> = iolist_to_binary(re:replace("abcd","((a)(b)c)(d)","&Yujfpr&qmHBi",[global])),
+?line <<"HSalphaw">> = iolist_to_binary(re:replace("alpha","[a-zA-Z_][a-zA-Z0-9_]*","HS&w",[])),
+?line <<"HSalphaw">> = iolist_to_binary(re:replace("alpha","[a-zA-Z_][a-zA-Z0-9_]*","HS&w",[global])),
+?line <<"amKrkJTTmWxwbhbhVXebhD">> = iolist_to_binary(re:replace("abh","^a(bc+|b[eh])g|.h$","mKrkJTT\\1mWxw&&VXe&D",[])),
+?line <<"amKrkJTTmWxwbhbhVXebhD">> = iolist_to_binary(re:replace("abh","^a(bc+|b[eh])g|.h$","mKrkJTT\\1mWxw&&VXe&D",[global])),
+?line <<"gkglaeffgzeffgzwvwD">> = iolist_to_binary(re:replace("effgz","(bc+d$|ef*g.|h?i(j|k))","gkgla\\1&wvwD",[])),
+?line <<"gkglaeffgzeffgzwvwD">> = iolist_to_binary(re:replace("effgz","(bc+d$|ef*g.|h?i(j|k))","gkgla\\1&wvwD",[global])),
+?line <<"ivMGijUoGoijri">> = iolist_to_binary(re:replace("ij","(bc+d$|ef*g.|h?i(j|k))","ivMG\\1UoGo\\1ri",[])),
+?line <<"ivMGijUoGoijri">> = iolist_to_binary(re:replace("ij","(bc+d$|ef*g.|h?i(j|k))","ivMG\\1UoGo\\1ri",[global])),
+?line <<"reffgzWeffgzJeffgzeffgzFUK">> = iolist_to_binary(re:replace("reffgz","(bc+d$|ef*g.|h?i(j|k))","&W\\1J\\1&FUK",[])),
+?line <<"reffgzWeffgzJeffgzeffgzFUK">> = iolist_to_binary(re:replace("reffgz","(bc+d$|ef*g.|h?i(j|k))","&W\\1J\\1&FUK",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(bc+d$|ef*g.|h?i(j|k))","qoREgh&sKvuYfqcVSQ",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(bc+d$|ef*g.|h?i(j|k))","qoREgh&sKvuYfqcVSQ",[global])),
+?line <<"effg">> = iolist_to_binary(re:replace("effg","(bc+d$|ef*g.|h?i(j|k))","OSMK&kVLNnI",[])),
+?line <<"effg">> = iolist_to_binary(re:replace("effg","(bc+d$|ef*g.|h?i(j|k))","OSMK&kVLNnI",[global])),
+?line <<"bcdd">> = iolist_to_binary(re:replace("bcdd","(bc+d$|ef*g.|h?i(j|k))","l\\1SFH&\\1WG\\1N&\\1WpNv",[])),
+?line <<"bcdd">> = iolist_to_binary(re:replace("bcdd","(bc+d$|ef*g.|h?i(j|k))","l\\1SFH&\\1WG\\1N&\\1WpNv",[global])),
+?line <<"uCcLk">> = iolist_to_binary(re:replace("a","((((((((((a))))))))))","uCcLk",[])),
+?line <<"uCcLk">> = iolist_to_binary(re:replace("a","((((((((((a))))))))))","uCcLk",[global])),
+?line <<"VCUvbvxORiulavLRaFa">> = iolist_to_binary(re:replace("aa","((((((((((a))))))))))\\10","VCUvbvxORiul\\1vLR\\1F\\1",[])),
+?line <<"VCUvbvxORiulavLRaFa">> = iolist_to_binary(re:replace("aa","((((((((((a))))))))))\\10","VCUvbvxORiul\\1vLR\\1F\\1",[global])),
+?line <<"vFhEaarfaQfeLfaFGiV">> = iolist_to_binary(re:replace("a","(((((((((a)))))))))","vFhE\\1&rf&QfeLf\\1FGiV",[])),
+?line <<"vFhEaarfaQfeLfaFGiV">> = iolist_to_binary(re:replace("a","(((((((((a)))))))))","vFhE\\1&rf&QfeLf\\1FGiV",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","multiple words of text","jlWax\\1&H",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","multiple words of text","jlWax\\1&H",[global])),
+?line <<"aa">> = iolist_to_binary(re:replace("aa","multiple words of text","hsUw",[])),
+?line <<"aa">> = iolist_to_binary(re:replace("aa","multiple words of text","hsUw",[global])),
+?line <<"uh-uh">> = iolist_to_binary(re:replace("uh-uh","multiple words of text","ASEw\\1gOsB",[])),
+?line <<"uh-uh">> = iolist_to_binary(re:replace("uh-uh","multiple words of text","ASEw\\1gOsB",[global])),
+?line <<"dmultiple wordsxkMtmultiple words, yeah">> = iolist_to_binary(re:replace("multiple words, yeah","multiple words","d&x\\1\\1kMt&",[])),
+?line <<"dmultiple wordsxkMtmultiple words, yeah">> = iolist_to_binary(re:replace("multiple words, yeah","multiple words","d&x\\1\\1kMt&",[global])),
+?line <<"ykkVabcdefmldQabUjIJjw">> = iolist_to_binary(re:replace("abcde","(.*)c(.*)","ykkV&fmldQ\\1UjIJjw",[])),
+?line <<"ykkVabcdefmldQabUjIJjw">> = iolist_to_binary(re:replace("abcde","(.*)c(.*)","ykkV&fmldQ\\1UjIJjw",[global])),
+?line <<"efWBSCaa(a, b)Q">> = iolist_to_binary(re:replace("(a, b)","\\((.*), (.*)\\)","efWBSC\\1\\1&Q",[])),
+?line <<"efWBSCaa(a, b)Q">> = iolist_to_binary(re:replace("(a, b)","\\((.*), (.*)\\)","efWBSC\\1\\1&Q",[global])),
+?line <<"abcdBdXhwHpBabcdPC">> = iolist_to_binary(re:replace("abcd","abcd","&Bd\\1XhwHp\\1B&PC",[])),
+?line <<"abcdBdXhwHpBabcdPC">> = iolist_to_binary(re:replace("abcd","abcd","&Bd\\1XhwHp\\1B&PC",[global])),
+?line <<"SbsAruCoIPbckBgbcSyqva">> = iolist_to_binary(re:replace("abcd","a(bc)d","SbsAruCoIP\\1kBg\\1Syqva",[])),
+?line <<"SbsAruCoIPbckBgbcSyqva">> = iolist_to_binary(re:replace("abcd","a(bc)d","SbsAruCoIP\\1kBg\\1Syqva",[global])),
+?line <<"XiUVfmkDnpfY">> = iolist_to_binary(re:replace("ac","a[-]?c","XiUVfmkDnpfY",[])),
+?line <<"XiUVfmkDnpfY">> = iolist_to_binary(re:replace("ac","a[-]?c","XiUVfmkDnpfY",[global])),
+?line <<"GYmabcndabcabcabcabcCjabcabcabcabctjmn">> = iolist_to_binary(re:replace("abcabc","(abc)\\1","GYm\\1nd&&Cj&\\1\\1tjmn",[])),
+?line <<"GYmabcndabcabcabcabcCjabcabcabcabctjmn">> = iolist_to_binary(re:replace("abcabc","(abc)\\1","GYm\\1nd&&Cj&\\1\\1tjmn",[global])),
+?line <<"AabcFabcabcOw">> = iolist_to_binary(re:replace("abcabc","([a-c]*)\\1","A\\1F&Ow",[])),
+?line <<"AabcFabcabcOwAFOw">> = iolist_to_binary(re:replace("abcabc","([a-c]*)\\1","A\\1F&Ow",[global])),
+?line <<"savneuiFiA">> = iolist_to_binary(re:replace("a","(a)|\\1","s&vneuiFiA",[])),
+?line <<"savneuiFiA">> = iolist_to_binary(re:replace("a","(a)|\\1","s&vneuiFiA",[global])),
+?line <<"*** FatXvbwaxGeTrgahaailers">> = iolist_to_binary(re:replace("*** Failers","(a)|\\1","\\1tXvbw&xGeTrg\\1h&\\1",[])),
+?line <<"*** FatXvbwaxGeTrgahaailers">> = iolist_to_binary(re:replace("*** Failers","(a)|\\1","\\1tXvbw&xGeTrg\\1h&\\1",[global])),
+?line <<"ShaaIOaiKrRarjaTFxavb">> = iolist_to_binary(re:replace("ab","(a)|\\1","Sh\\1\\1IO&iKrR\\1rj\\1TFx&v",[])),
+?line <<"ShaaIOaiKrRarjaTFxavb">> = iolist_to_binary(re:replace("ab","(a)|\\1","Sh\\1\\1IO&iKrR\\1rj\\1TFx&v",[global])),
+?line <<"x">> = iolist_to_binary(re:replace("x","(a)|\\1","wG&OmupsBaCA&ULU&br",[])),
+?line <<"x">> = iolist_to_binary(re:replace("x","(a)|\\1","wG&OmupsBaCA&ULU&br",[global])),
+?line <<"ababbsaHOnababbDlUpRwMMqlababbCbbbcbc">> = iolist_to_binary(re:replace("ababbbcbc","(([a-c])b*?\\2)*","&saHOn&DlUpRwMMql&C\\1",[])),
+?line <<"ababbsaHOnababbDlUpRwMMqlababbCbbsaHOnDlUpRwMMqlCbcbcsaHOncbcDlUpRwMMqlcbcCcbcsaHOnDlUpRwMMqlC">> = iolist_to_binary(re:replace("ababbbcbc","(([a-c])b*?\\2)*","&saHOn&DlUpRwMMql&C\\1",[global])),
+?line <<"YdAFYmyyababbbcbcHpJCababbbcbcQa">> = iolist_to_binary(re:replace("ababbbcbc","(([a-c])b*?\\2){3}","YdAFYmyy&HpJC&Qa",[])),
+?line <<"YdAFYmyyababbbcbcHpJCababbbcbcQa">> = iolist_to_binary(re:replace("ababbbcbc","(([a-c])b*?\\2){3}","YdAFYmyy&HpJC&Qa",[global])),
+?line <<"aaaxabaxbaaxabbax">> = iolist_to_binary(re:replace("aaaxabaxbaaxbbax","((\\3|b)\\2(a)x)+","a\\1",[])),
+?line <<"aaaxabaxbaaxabbax">> = iolist_to_binary(re:replace("aaaxabaxbaaxbbax","((\\3|b)\\2(a)x)+","a\\1",[global])),
+?line <<"bbaababbabaaaaaoh">> = iolist_to_binary(re:replace("bbaababbabaaaaabbaaaabba","((\\3|b)\\2(a)){2,}","oh",[])),
+?line <<"bbaababbabaaaaaoh">> = iolist_to_binary(re:replace("bbaababbabaaaaabbaaaabba","((\\3|b)\\2(a)){2,}","oh",[global])),
+?line <<"fABCaeUgIABCDABCNFvst">> = iolist_to_binary(re:replace("ABC","abc","f&aeUgI&D&\\1NFvst",[caseless])),
+?line <<"fABCaeUgIABCDABCNFvst">> = iolist_to_binary(re:replace("ABC","abc","f&aeUgI&D&\\1NFvst",[caseless,
+ global])),
+?line <<"XgOY">> = iolist_to_binary(re:replace("XABCY","abc","gO",[caseless])),
+?line <<"XgOY">> = iolist_to_binary(re:replace("XABCY","abc","gO",[caseless,
+ global])),
+?line <<"ABnpaQvR">> = iolist_to_binary(re:replace("ABABC","abc","npaQvR",[caseless])),
+?line <<"ABnpaQvR">> = iolist_to_binary(re:replace("ABABC","abc","npaQvR",[caseless,
+ global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","abc","E&beuUX&&",[caseless])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","abc","E&beuUX&&",[caseless,
+ global])),
+?line <<"aaxabxbaxbbx">> = iolist_to_binary(re:replace("aaxabxbaxbbx","abc","\\1hAU\\1hg&Pk",[caseless])),
+?line <<"aaxabxbaxbbx">> = iolist_to_binary(re:replace("aaxabxbaxbbx","abc","\\1hAU\\1hg&Pk",[caseless,
+ global])),
+?line <<"XBC">> = iolist_to_binary(re:replace("XBC","abc","yqsG",[caseless])),
+?line <<"XBC">> = iolist_to_binary(re:replace("XBC","abc","yqsG",[caseless,
+ global])),
+?line <<"AXC">> = iolist_to_binary(re:replace("AXC","abc","\\1bi&Ff\\1kGVy&V",[caseless])),
+?line <<"AXC">> = iolist_to_binary(re:replace("AXC","abc","\\1bi&Ff\\1kGVy&V",[caseless,
+ global])),
+?line <<"ABX">> = iolist_to_binary(re:replace("ABX","abc","x&m\\1jtf&ptFxBd",[caseless])),
+?line <<"ABX">> = iolist_to_binary(re:replace("ABX","abc","x&m\\1jtf&ptFxBd",[caseless,
+ global])),
+?line <<"VOTkukABC">> = iolist_to_binary(re:replace("ABC","ab*c","V\\1OTkuk&\\1",[caseless])),
+?line <<"VOTkukABC">> = iolist_to_binary(re:replace("ABC","ab*c","V\\1OTkuk&\\1",[caseless,
+ global])),
+?line <<"gkYiABCuYNOFDNc">> = iolist_to_binary(re:replace("ABC","ab*bc","g\\1kYi&uYNOFDNc",[caseless])),
+?line <<"gkYiABCuYNOFDNc">> = iolist_to_binary(re:replace("ABC","ab*bc","g\\1kYi&uYNOFDNc",[caseless,
+ global])),
+?line <<"GHfaNWh">> = iolist_to_binary(re:replace("ABBC","ab*bc","G\\1HfaNWh",[caseless])),
+?line <<"GHfaNWh">> = iolist_to_binary(re:replace("ABBC","ab*bc","G\\1HfaNWh",[caseless,
+ global])),
+?line <<"IJJBqWcABBBBCmU">> = iolist_to_binary(re:replace("ABBBBC","ab*?bc","I\\1JJB\\1\\1qWc&mU",[caseless])),
+?line <<"IJJBqWcABBBBCmU">> = iolist_to_binary(re:replace("ABBBBC","ab*?bc","I\\1JJB\\1\\1qWc&mU",[caseless,
+ global])),
+?line <<"YOCTcABBBBCABBBBCbVDCpABBBBChP">> = iolist_to_binary(re:replace("ABBBBC","ab{0,}?bc","YOCTc&&bVDCp&hP",[caseless])),
+?line <<"YOCTcABBBBCABBBBCbVDCpABBBBChP">> = iolist_to_binary(re:replace("ABBBBC","ab{0,}?bc","YOCTc&&bVDCp&hP",[caseless,
+ global])),
+?line <<"j">> = iolist_to_binary(re:replace("ABBC","ab+?bc","j",[caseless])),
+?line <<"j">> = iolist_to_binary(re:replace("ABBC","ab+?bc","j",[caseless,
+ global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","ab+bc","vLfo&Q\\1&uXHE",[caseless])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","ab+bc","vLfo&Q\\1&uXHE",[caseless,
+ global])),
+?line <<"ABC">> = iolist_to_binary(re:replace("ABC","ab+bc","hPVKmARvLrX&l",[caseless])),
+?line <<"ABC">> = iolist_to_binary(re:replace("ABC","ab+bc","hPVKmARvLrX&l",[caseless,
+ global])),
+?line <<"ABQ">> = iolist_to_binary(re:replace("ABQ","ab+bc","&\\1OP&EAg",[caseless])),
+?line <<"ABQ">> = iolist_to_binary(re:replace("ABQ","ab+bc","&\\1OP&EAg",[caseless,
+ global])),
+?line <<"PElq">> = iolist_to_binary(re:replace("ABBBBC","ab+bc","PElq",[caseless])),
+?line <<"PElq">> = iolist_to_binary(re:replace("ABBBBC","ab+bc","PElq",[caseless,
+ global])),
+?line <<"aqDjyRpvS">> = iolist_to_binary(re:replace("ABBBBC","ab{1,}?bc","\\1a\\1\\1q\\1DjyRpvS\\1",[caseless])),
+?line <<"aqDjyRpvS">> = iolist_to_binary(re:replace("ABBBBC","ab{1,}?bc","\\1a\\1\\1q\\1DjyRpvS\\1",[caseless,
+ global])),
+?line <<"aTWqxABBBBCInABBBBCpRFpO">> = iolist_to_binary(re:replace("ABBBBC","ab{1,3}?bc","aTW\\1qx&In&\\1pRFpO",[caseless])),
+?line <<"aTWqxABBBBCInABBBBCpRFpO">> = iolist_to_binary(re:replace("ABBBBC","ab{1,3}?bc","aTW\\1qx&In&\\1pRFpO",[caseless,
+ global])),
+?line <<"ABBBBCTlrABBBBCJOlJvqwgABBBBCh">> = iolist_to_binary(re:replace("ABBBBC","ab{3,4}?bc","&T\\1lr&JOl\\1Jvqwg&h",[caseless])),
+?line <<"ABBBBCTlrABBBBCJOlJvqwgABBBBCh">> = iolist_to_binary(re:replace("ABBBBC","ab{3,4}?bc","&T\\1lr&JOl\\1Jvqwg&h",[caseless,
+ global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","ab{4,5}?bc","QBVMd\\1eBP&j\\1Y\\1\\1",[caseless])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","ab{4,5}?bc","QBVMd\\1eBP&j\\1Y\\1\\1",[caseless,
+ global])),
+?line <<"ABQ">> = iolist_to_binary(re:replace("ABQ","ab{4,5}?bc","pvlNJ\\1o\\1yAcNJhSec\\1",[caseless])),
+?line <<"ABQ">> = iolist_to_binary(re:replace("ABQ","ab{4,5}?bc","pvlNJ\\1o\\1yAcNJhSec\\1",[caseless,
+ global])),
+?line <<"ABBBBC">> = iolist_to_binary(re:replace("ABBBBC","ab{4,5}?bc","dGdgiMqW\\1X",[caseless])),
+?line <<"ABBBBC">> = iolist_to_binary(re:replace("ABBBBC","ab{4,5}?bc","dGdgiMqW\\1X",[caseless,
+ global])),
+?line <<"eqlxxIffIhfLhL">> = iolist_to_binary(re:replace("ABBC","ab??bc","eqlxxIffIhfLhL",[caseless])),
+?line <<"eqlxxIffIhfLhL">> = iolist_to_binary(re:replace("ABBC","ab??bc","eqlxxIffIhfLhL",[caseless,
+ global])),
+?line <<"bQqNAjyKOqhMXyoABC">> = iolist_to_binary(re:replace("ABC","ab??bc","b\\1QqNAjyKOqhMXyo&",[caseless])),
+?line <<"bQqNAjyKOqhMXyoABC">> = iolist_to_binary(re:replace("ABC","ab??bc","b\\1QqNAjyKOqhMXyo&",[caseless,
+ global])),
+?line <<"jJQGABCIRM">> = iolist_to_binary(re:replace("ABC","ab{0,1}?bc","jJQG&IR\\1M",[caseless])),
+?line <<"jJQGABCIRM">> = iolist_to_binary(re:replace("ABC","ab{0,1}?bc","jJQG&IR\\1M",[caseless,
+ global])),
+?line <<"gPABCCho">> = iolist_to_binary(re:replace("ABC","ab??c","gP&Cho",[caseless])),
+?line <<"gPABCCho">> = iolist_to_binary(re:replace("ABC","ab??c","gP&Cho",[caseless,
+ global])),
+?line <<"iNBxUabjwtTABCLABCvXhABC">> = iolist_to_binary(re:replace("ABC","ab{0,1}?c","iNBxUabjw\\1tT&L&vXh&",[caseless])),
+?line <<"iNBxUabjwtTABCLABCvXhABC">> = iolist_to_binary(re:replace("ABC","ab{0,1}?c","iNBxUabjw\\1tT&L&vXh&",[caseless,
+ global])),
+?line <<"iBkpxqXNa">> = iolist_to_binary(re:replace("ABC","^abc$","iBkpxqXNa",[caseless])),
+?line <<"iBkpxqXNa">> = iolist_to_binary(re:replace("ABC","^abc$","iBkpxqXNa",[caseless,
+ global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^abc$","OhTwUeW&yJtn",[caseless])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^abc$","OhTwUeW&yJtn",[caseless,
+ global])),
+?line <<"ABBBBC">> = iolist_to_binary(re:replace("ABBBBC","^abc$","LoawT&xKl\\1&",[caseless])),
+?line <<"ABBBBC">> = iolist_to_binary(re:replace("ABBBBC","^abc$","LoawT&xKl\\1&",[caseless,
+ global])),
+?line <<"ABCC">> = iolist_to_binary(re:replace("ABCC","^abc$","iVcopu",[caseless])),
+?line <<"ABCC">> = iolist_to_binary(re:replace("ABCC","^abc$","iVcopu",[caseless,
+ global])),
+?line <<"ABCtC">> = iolist_to_binary(re:replace("ABCC","^abc","&t",[caseless])),
+?line <<"ABCtC">> = iolist_to_binary(re:replace("ABCC","^abc","&t",[caseless,
+ global])),
+?line <<"AABCWBABCtLipJGm">> = iolist_to_binary(re:replace("AABC","abc$","&W\\1B&tLipJGm",[caseless])),
+?line <<"AABCWBABCtLipJGm">> = iolist_to_binary(re:replace("AABC","abc$","&W\\1B&tLipJGm",[caseless,
+ global])),
+?line <<"wDvJtREmkCGdgtGtgABC">> = iolist_to_binary(re:replace("ABC","^","wDvJt\\1REmk\\1CGdgtGtg",[caseless])),
+?line <<"wDvJtREmkCGdgtGtgABC">> = iolist_to_binary(re:replace("ABC","^","wDvJt\\1REmk\\1CGdgtGtg",[caseless,
+ global])),
+?line <<"ABCWiqpRnpqRRBAD">> = iolist_to_binary(re:replace("ABC","$","W\\1iqpRnpq\\1RRB&\\1AD",[caseless])),
+?line <<"ABCWiqpRnpqRRBAD">> = iolist_to_binary(re:replace("ABC","$","W\\1iqpRnpq\\1RRB&\\1AD",[caseless,
+ global])),
+?line <<"FOABCHABCuJ">> = iolist_to_binary(re:replace("ABC","a.c","FO&H&uJ",[caseless])),
+?line <<"FOABCHABCuJ">> = iolist_to_binary(re:replace("ABC","a.c","FO&H&uJ",[caseless,
+ global])),
+?line <<"mmAXCwHQUmyij">> = iolist_to_binary(re:replace("AXC","a.c","m\\1m&\\1wHQUmyi\\1j",[caseless])),
+?line <<"mmAXCwHQUmyij">> = iolist_to_binary(re:replace("AXC","a.c","m\\1m&\\1wHQUmyi\\1j",[caseless,
+ global])),
+?line <<"vKLhT">> = iolist_to_binary(re:replace("AXYZC","a.*?c","vKLhT",[caseless])),
+?line <<"vKLhT">> = iolist_to_binary(re:replace("AXYZC","a.*?c","vKLhT",[caseless,
+ global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","a.*c","TrBPBlhlCyS&oLwXCYxT",[caseless])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","a.*c","TrBPBlhlCyS&oLwXCYxT",[caseless,
+ global])),
+?line <<"oNBAABC">> = iolist_to_binary(re:replace("AABC","a.*c","oNB&",[caseless])),
+?line <<"oNBAABC">> = iolist_to_binary(re:replace("AABC","a.*c","oNB&",[caseless,
+ global])),
+?line <<"AXYZD">> = iolist_to_binary(re:replace("AXYZD","a.*c","v\\1byeTHd&vaDRL\\1",[caseless])),
+?line <<"AXYZD">> = iolist_to_binary(re:replace("AXYZD","a.*c","v\\1byeTHd&vaDRL\\1",[caseless,
+ global])),
+?line <<"puCobgfLFWkTABD">> = iolist_to_binary(re:replace("ABD","a[bc]d","puCobgf\\1LF\\1W\\1kT&",[caseless])),
+?line <<"puCobgfLFWkTABD">> = iolist_to_binary(re:replace("ABD","a[bc]d","puCobgf\\1LF\\1W\\1kT&",[caseless,
+ global])),
+?line <<"ACELM">> = iolist_to_binary(re:replace("ACE","a[b-d]e","&LM",[caseless])),
+?line <<"ACELM">> = iolist_to_binary(re:replace("ACE","a[b-d]e","&LM",[caseless,
+ global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","a[b-d]e","YsqxG&B&NxQkv\\1RY",[caseless])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","a[b-d]e","YsqxG&B&NxQkv\\1RY",[caseless,
+ global])),
+?line <<"ABC">> = iolist_to_binary(re:replace("ABC","a[b-d]e","o&WeiJHAt\\1vpj",[caseless])),
+?line <<"ABC">> = iolist_to_binary(re:replace("ABC","a[b-d]e","o&WeiJHAt\\1vpj",[caseless,
+ global])),
+?line <<"ABD">> = iolist_to_binary(re:replace("ABD","a[b-d]e","S",[caseless])),
+?line <<"ABD">> = iolist_to_binary(re:replace("ABD","a[b-d]e","S",[caseless,
+ global])),
+?line <<"AgdndBWDnHACACACVgB">> = iolist_to_binary(re:replace("AAC","a[b-d]","gdndBWDnH&&&VgB",[caseless])),
+?line <<"AgdndBWDnHACACACVgB">> = iolist_to_binary(re:replace("AAC","a[b-d]","gdndBWDnH&&&VgB",[caseless,
+ global])),
+?line <<"lpIqxA-sQA-">> = iolist_to_binary(re:replace("A-","a[-b]","lpIqx&sQ&",[caseless])),
+?line <<"lpIqxA-sQA-">> = iolist_to_binary(re:replace("A-","a[-b]","lpIqx&sQ&",[caseless,
+ global])),
+?line <<"NJrfcO">> = iolist_to_binary(re:replace("A-","a[b-]","NJrfc\\1O",[caseless])),
+?line <<"NJrfcO">> = iolist_to_binary(re:replace("A-","a[b-]","NJrfc\\1O",[caseless,
+ global])),
+?line <<"eA]OcbkaA]qQEbtfTQD">> = iolist_to_binary(re:replace("A]","a]","e&Oc\\1bka&qQEbtfTQD",[caseless])),
+?line <<"eA]OcbkaA]qQEbtfTQD">> = iolist_to_binary(re:replace("A]","a]","e&Oc\\1bka&qQEbtfTQD",[caseless,
+ global])),
+?line <<"GqJU">> = iolist_to_binary(re:replace("A]B","a[]]b","GqJU",[caseless])),
+?line <<"GqJU">> = iolist_to_binary(re:replace("A]B","a[]]b","GqJU",[caseless,
+ global])),
+?line <<"AEDdAEDiIAEDCTAEDj">> = iolist_to_binary(re:replace("AED","a[^bc]d","&d&iI&CT&j",[caseless])),
+?line <<"AEDdAEDiIAEDCTAEDj">> = iolist_to_binary(re:replace("AED","a[^bc]d","&d&iI&CT&j",[caseless,
+ global])),
+?line <<"MOKnvQDsS">> = iolist_to_binary(re:replace("ADC","a[^-b]c","MOKn\\1\\1vQDsS\\1",[caseless])),
+?line <<"MOKnvQDsS">> = iolist_to_binary(re:replace("ADC","a[^-b]c","MOKn\\1\\1vQDsS\\1",[caseless,
+ global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","a[^-b]c","dr",[caseless])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","a[^-b]c","dr",[caseless,
+ global])),
+?line <<"ABD">> = iolist_to_binary(re:replace("ABD","a[^-b]c","IMKcT&fF&WXbjs\\1\\1",[caseless])),
+?line <<"ABD">> = iolist_to_binary(re:replace("ABD","a[^-b]c","IMKcT&fF&WXbjs\\1\\1",[caseless,
+ global])),
+?line <<"A-C">> = iolist_to_binary(re:replace("A-C","a[^-b]c","M&xDIfNL\\1W",[caseless])),
+?line <<"A-C">> = iolist_to_binary(re:replace("A-C","a[^-b]c","M&xDIfNL\\1W",[caseless,
+ global])),
+?line <<"wR">> = iolist_to_binary(re:replace("ADC","a[^]b]c","wR",[caseless])),
+?line <<"wR">> = iolist_to_binary(re:replace("ADC","a[^]b]c","wR",[caseless,
+ global])),
+?line <<"HKTAABllCQjRABEnXDqjC">> = iolist_to_binary(re:replace("ABC","ab|cd","HKTA&llCQjR&EnXDqj",[caseless])),
+?line <<"HKTAABllCQjRABEnXDqjC">> = iolist_to_binary(re:replace("ABC","ab|cd","HKTA&llCQjR&EnXDqj",[caseless,
+ global])),
+?line <<"ABCD">> = iolist_to_binary(re:replace("ABCD","ab|cd","&",[caseless])),
+?line <<"ABCD">> = iolist_to_binary(re:replace("ABCD","ab|cd","&",[caseless,
+ global])),
+?line <<"DmgTYsxtpkrXgnoJ">> = iolist_to_binary(re:replace("DEF","()ef","mgTYsxtpkrXgnoJ",[caseless])),
+?line <<"DmgTYsxtpkrXgnoJ">> = iolist_to_binary(re:replace("DEF","()ef","mgTYsxtpkrXgnoJ",[caseless,
+ global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","$b","KN\\1&V",[caseless])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","$b","KN\\1&V",[caseless,
+ global])),
+?line <<"A]C">> = iolist_to_binary(re:replace("A]C","$b","jtB&",[caseless])),
+?line <<"A]C">> = iolist_to_binary(re:replace("A]C","$b","jtB&",[caseless,
+ global])),
+?line <<"B">> = iolist_to_binary(re:replace("B","$b","&pRb",[caseless])),
+?line <<"B">> = iolist_to_binary(re:replace("B","$b","&pRb",[caseless,
+ global])),
+?line <<"lBUQxBtA(BtBeKAEeJq">> = iolist_to_binary(re:replace("A(B","a\\(b","lBUQ\\1xBt&tBeK\\1AEeJq",[caseless])),
+?line <<"lBUQxBtA(BtBeKAEeJq">> = iolist_to_binary(re:replace("A(B","a\\(b","lBUQ\\1xBt&tBeK\\1AEeJq",[caseless,
+ global])),
+?line <<"oXCRABKrhGnMTcHtq">> = iolist_to_binary(re:replace("AB","a\\(*b","oXCR&\\1KrhGnMTcHtq",[caseless])),
+?line <<"oXCRABKrhGnMTcHtq">> = iolist_to_binary(re:replace("AB","a\\(*b","oXCR&\\1KrhGnMTcHtq",[caseless,
+ global])),
+?line <<"VyDjHkfygiNMHC">> = iolist_to_binary(re:replace("A((B","a\\(*b","Vy\\1DjH\\1kfygi\\1NM\\1H\\1C",[caseless])),
+?line <<"VyDjHkfygiNMHC">> = iolist_to_binary(re:replace("A((B","a\\(*b","Vy\\1DjH\\1kfygi\\1NM\\1H\\1C",[caseless,
+ global])),
+?line <<"A">> = iolist_to_binary(re:replace("A","a\\\\b","DhmiARyCBuVi",[caseless,
+ notbol])),
+?line <<"A">> = iolist_to_binary(re:replace("A","a\\\\b","DhmiARyCBuVi",[caseless,
+ notbol,
+ global])),
+?line <<"FArKeEijRRtjoEBC">> = iolist_to_binary(re:replace("ABC","((a))","F\\1rKeEijRRtjoE",[caseless])),
+?line <<"FArKeEijRRtjoEBC">> = iolist_to_binary(re:replace("ABC","((a))","F\\1rKeEijRRtjoE",[caseless,
+ global])),
+?line <<"shGABCXUFAQfAABCy">> = iolist_to_binary(re:replace("ABC","(a)b(c)","shG&XUF\\1Qf\\1&y",[caseless])),
+?line <<"shGABCXUFAQfAABCy">> = iolist_to_binary(re:replace("ABC","(a)b(c)","shG&XUF\\1Qf\\1&y",[caseless,
+ global])),
+?line <<"AABBABCmqnIoEABCugfABCNVyK">> = iolist_to_binary(re:replace("AABBABC","a+b+c","&m\\1qnIoE&\\1ug\\1f&NVyK",[caseless])),
+?line <<"AABBABCmqnIoEABCugfABCNVyK">> = iolist_to_binary(re:replace("AABBABC","a+b+c","&m\\1qnIoE&\\1ug\\1f&NVyK",[caseless,
+ global])),
+?line <<"AABByABCrABC">> = iolist_to_binary(re:replace("AABBABC","a{1,}b{1,}c","y&r\\1&",[caseless])),
+?line <<"AABByABCrABC">> = iolist_to_binary(re:replace("AABBABC","a{1,}b{1,}c","y&r\\1&",[caseless,
+ global])),
+?line <<"tABC">> = iolist_to_binary(re:replace("ABCABC","a.+?c","t",[caseless])),
+?line <<"tt">> = iolist_to_binary(re:replace("ABCABC","a.+?c","t",[caseless,
+ global])),
+?line <<"UABC">> = iolist_to_binary(re:replace("ABCABC","a.*?c","\\1U",[caseless])),
+?line <<"UU">> = iolist_to_binary(re:replace("ABCABC","a.*?c","\\1U",[caseless,
+ global])),
+?line <<"EfjDOiBAosuABC">> = iolist_to_binary(re:replace("ABCABC","a.{0,5}?c","EfjDOiBAosu",[caseless])),
+?line <<"EfjDOiBAosuEfjDOiBAosu">> = iolist_to_binary(re:replace("ABCABC","a.{0,5}?c","EfjDOiBAosu",[caseless,
+ global])),
+?line <<"CBBliVcPcv">> = iolist_to_binary(re:replace("AB","(a+|b)*","C\\1\\1liVcPcv",[caseless])),
+?line <<"CBBliVcPcvCliVcPcv">> = iolist_to_binary(re:replace("AB","(a+|b)*","C\\1\\1liVcPcv",[caseless,
+ global])),
+?line <<"fSc">> = iolist_to_binary(re:replace("AB","(a+|b){0,}","fSc",[caseless])),
+?line <<"fScfSc">> = iolist_to_binary(re:replace("AB","(a+|b){0,}","fSc",[caseless,
+ global])),
+?line <<"sABpDnVVBAB">> = iolist_to_binary(re:replace("AB","(a+|b)+","s&pDnVV\\1&",[caseless])),
+?line <<"sABpDnVVBAB">> = iolist_to_binary(re:replace("AB","(a+|b)+","s&pDnVV\\1&",[caseless,
+ global])),
+?line <<"bnGKKf">> = iolist_to_binary(re:replace("AB","(a+|b){1,}","bnGKKf",[caseless])),
+?line <<"bnGKKf">> = iolist_to_binary(re:replace("AB","(a+|b){1,}","bnGKKf",[caseless,
+ global])),
+?line <<"LpFAjhAtClIGSIAdYAB">> = iolist_to_binary(re:replace("AB","(a+|b)?","LpF&jhAtClIGSI\\1dY\\1",[caseless])),
+?line <<"LpFAjhAtClIGSIAdYALpFBjhAtClIGSIBdYBLpFjhAtClIGSIdY">> = iolist_to_binary(re:replace("AB","(a+|b)?","LpF&jhAtClIGSI\\1dY\\1",[caseless,
+ global])),
+?line <<"qbB">> = iolist_to_binary(re:replace("AB","(a+|b){0,1}","qb",[caseless])),
+?line <<"qbqbqb">> = iolist_to_binary(re:replace("AB","(a+|b){0,1}","qb",[caseless,
+ global])),
+?line <<"vLbrTRIJAB">> = iolist_to_binary(re:replace("AB","(a+|b){0,1}?","v&L\\1brTRIJ\\1\\1",[caseless])),
+?line <<"vLbrTRIJvALAbrTRIJAAvLbrTRIJvBLBbrTRIJBBvLbrTRIJ">> = iolist_to_binary(re:replace("AB","(a+|b){0,1}?","v&L\\1brTRIJ\\1\\1",[caseless,
+ global])),
+?line <<"HtbhHKCDEwOT">> = iolist_to_binary(re:replace("CDE","[^ab]*","Ht\\1\\1bhHK&wOT",[caseless])),
+?line <<"HtbhHKCDEwOTHtbhHKwOT">> = iolist_to_binary(re:replace("CDE","[^ab]*","Ht\\1\\1bhHK&wOT",[caseless,
+ global])),
+?line <<"vOowROtABBBCD">> = iolist_to_binary(re:replace("ABBBCD","([abc])*d","vOowROt&",[caseless])),
+?line <<"vOowROtABBBCD">> = iolist_to_binary(re:replace("ABBBCD","([abc])*d","vOowROt&",[caseless,
+ global])),
+?line <<"TBIuDTLoAqOaABCDMcvVABCDPm">> = iolist_to_binary(re:replace("ABCD","([abc])*bcd","TBIuDTLo\\1qOa&McvV&Pm",[caseless])),
+?line <<"TBIuDTLoAqOaABCDMcvVABCDPm">> = iolist_to_binary(re:replace("ABCD","([abc])*bcd","TBIuDTLo\\1qOa&McvV&Pm",[caseless,
+ global])),
+?line <<"EUpqELAv">> = iolist_to_binary(re:replace("E","a|b|c|d|e","&Upq&LAv",[caseless])),
+?line <<"EUpqELAv">> = iolist_to_binary(re:replace("E","a|b|c|d|e","&Upq&LAv",[caseless,
+ global])),
+?line <<"oViRJMyEkEPtcEFEM">> = iolist_to_binary(re:replace("EF","(a|b|c|d|e)f","oViRJMy\\1k\\1Ptc&\\1M",[caseless])),
+?line <<"oViRJMyEkEPtcEFEM">> = iolist_to_binary(re:replace("EF","(a|b|c|d|e)f","oViRJMy\\1k\\1Ptc&\\1M",[caseless,
+ global])),
+?line <<"ABCDEFGeumABCDEFGxRcjHuSABCDEFGOABCDEFG">> = iolist_to_binary(re:replace("ABCDEFG","abcd*efg","&eum&xRcjHuS&O&",[caseless])),
+?line <<"ABCDEFGeumABCDEFGxRcjHuSABCDEFGOABCDEFG">> = iolist_to_binary(re:replace("ABCDEFG","abcd*efg","&eum&xRcjHuS&O&",[caseless,
+ global])),
+?line <<"XOvpxKbYuFMwABVhYABBBZ">> = iolist_to_binary(re:replace("XABYABBBZ","ab*","OvpxKbYuFMw&Vh",[caseless])),
+?line <<"XOvpxKbYuFMwABVhYOvpxKbYuFMwABBBVhZ">> = iolist_to_binary(re:replace("XABYABBBZ","ab*","OvpxKbYuFMw&Vh",[caseless,
+ global])),
+?line <<"XXbAAHhcmmXVwkYABBBZ">> = iolist_to_binary(re:replace("XAYABBBZ","ab*","Xb&&Hhcmm\\1XVwk",[caseless])),
+?line <<"XXbAAHhcmmXVwkYXbABBBABBBHhcmmXVwkZ">> = iolist_to_binary(re:replace("XAYABBBZ","ab*","Xb&&Hhcmm\\1XVwk",[caseless,
+ global])),
+?line <<"ABPWMPmhUsCDEo">> = iolist_to_binary(re:replace("ABCDE","(ab|cd)e","PWMPmhUs&o",[caseless])),
+?line <<"ABPWMPmhUsCDEo">> = iolist_to_binary(re:replace("ABCDE","(ab|cd)e","PWMPmhUs&o",[caseless,
+ global])),
+?line <<"jHIJ">> = iolist_to_binary(re:replace("HIJ","[abhgefdc]ij","j&",[caseless])),
+?line <<"jHIJ">> = iolist_to_binary(re:replace("HIJ","[abhgefdc]ij","j&",[caseless,
+ global])),
+?line <<"ABCDE">> = iolist_to_binary(re:replace("ABCDE","^(ab|cd)e","Dc&hlOsc\\1EL\\1Vl",[caseless])),
+?line <<"ABCDE">> = iolist_to_binary(re:replace("ABCDE","^(ab|cd)e","Dc&hlOsc\\1EL\\1Vl",[caseless,
+ global])),
+?line <<"ABCDBRPmLBtJGwEFEF">> = iolist_to_binary(re:replace("ABCDEF","(abc|)ef","\\1BRPmLBtJGw\\1&&",[caseless])),
+?line <<"ABCDBRPmLBtJGwEFEF">> = iolist_to_binary(re:replace("ABCDEF","(abc|)ef","\\1BRPmLBtJGw\\1&&",[caseless,
+ global])),
+?line <<"ABdnvuIvc">> = iolist_to_binary(re:replace("ABCD","(a|b)c*d","\\1dnvuIvc",[caseless])),
+?line <<"ABdnvuIvc">> = iolist_to_binary(re:replace("ABCD","(a|b)c*d","\\1dnvuIvc",[caseless,
+ global])),
+?line <<"ACKWkV">> = iolist_to_binary(re:replace("ABC","(ab|ab*)bc","ACKWkV",[caseless])),
+?line <<"ACKWkV">> = iolist_to_binary(re:replace("ABC","(ab|ab*)bc","ACKWkV",[caseless,
+ global])),
+?line <<"LepuBCXf">> = iolist_to_binary(re:replace("ABC","a([bc]*)c*","Lepu\\1Xf",[caseless])),
+?line <<"LepuBCXf">> = iolist_to_binary(re:replace("ABC","a([bc]*)c*","Lepu\\1Xf",[caseless,
+ global])),
+?line <<"NDABCDxHBMEtfBGtV">> = iolist_to_binary(re:replace("ABCD","a([bc]*)(c*d)","ND&xHBMEtfBGtV",[caseless])),
+?line <<"NDABCDxHBMEtfBGtV">> = iolist_to_binary(re:replace("ABCD","a([bc]*)(c*d)","ND&xHBMEtfBGtV",[caseless,
+ global])),
+?line <<"eIDCKdi">> = iolist_to_binary(re:replace("ABCD","a([bc]+)(c*d)","eIDCKdi",[caseless])),
+?line <<"eIDCKdi">> = iolist_to_binary(re:replace("ABCD","a([bc]+)(c*d)","eIDCKdi",[caseless,
+ global])),
+?line <<"fKBQepABCDABCDhHYaRKHjS">> = iolist_to_binary(re:replace("ABCD","a([bc]*)(c+d)","fK\\1Qep&&hHYaRKHjS",[caseless])),
+?line <<"fKBQepABCDABCDhHYaRKHjS">> = iolist_to_binary(re:replace("ABCD","a([bc]*)(c+d)","fK\\1Qep&&hHYaRKHjS",[caseless,
+ global])),
+?line <<"yYx">> = iolist_to_binary(re:replace("ADCDCDE","a[bcd]*dcdcde","yYx",[caseless])),
+?line <<"yYx">> = iolist_to_binary(re:replace("ADCDCDE","a[bcd]*dcdcde","yYx",[caseless,
+ global])),
+?line <<"gCGlfM">> = iolist_to_binary(re:replace("ABC","(ab|a)b*c","gCGlfM",[caseless])),
+?line <<"gCGlfM">> = iolist_to_binary(re:replace("ABC","(ab|a)b*c","gCGlfM",[caseless,
+ global])),
+?line <<"GJGaABCEwhSGeABC">> = iolist_to_binary(re:replace("ABCD","((a)(b)c)(d)","GJGa\\1EwhSGe\\1",[caseless])),
+?line <<"GJGaABCEwhSGeABC">> = iolist_to_binary(re:replace("ABCD","((a)(b)c)(d)","GJGa\\1EwhSGe\\1",[caseless,
+ global])),
+?line <<"GwdBxNJCuOfALPHADSnt">> = iolist_to_binary(re:replace("ALPHA","[a-zA-Z_][a-zA-Z0-9_]*","GwdBxNJCuOf&DSnt",[caseless])),
+?line <<"GwdBxNJCuOfALPHADSnt">> = iolist_to_binary(re:replace("ALPHA","[a-zA-Z_][a-zA-Z0-9_]*","GwdBxNJCuOf&DSnt",[caseless,
+ global])),
+?line <<"AMcmNBHqwYsXdABHJTBH">> = iolist_to_binary(re:replace("ABH","^a(bc+|b[eh])g|.h$","McmN&qwYsX\\1dA&JT&",[caseless])),
+?line <<"AMcmNBHqwYsXdABHJTBH">> = iolist_to_binary(re:replace("ABH","^a(bc+|b[eh])g|.h$","McmN&qwYsX\\1dA&JT&",[caseless,
+ global])),
+?line <<"JEFFGZWDujiGKchTEFFGZd">> = iolist_to_binary(re:replace("EFFGZ","(bc+d$|ef*g.|h?i(j|k))","J&WDujiGKchT&d",[caseless])),
+?line <<"JEFFGZWDujiGKchTEFFGZd">> = iolist_to_binary(re:replace("EFFGZ","(bc+d$|ef*g.|h?i(j|k))","J&WDujiGKchT&d",[caseless,
+ global])),
+?line <<"JIJIJVbIJOWIJT">> = iolist_to_binary(re:replace("IJ","(bc+d$|ef*g.|h?i(j|k))","J\\1\\1Vb\\1OW\\1T",[caseless])),
+?line <<"JIJIJVbIJOWIJT">> = iolist_to_binary(re:replace("IJ","(bc+d$|ef*g.|h?i(j|k))","J\\1\\1Vb\\1OW\\1T",[caseless,
+ global])),
+?line <<"REnKX">> = iolist_to_binary(re:replace("REFFGZ","(bc+d$|ef*g.|h?i(j|k))","EnKX",[caseless])),
+?line <<"REnKX">> = iolist_to_binary(re:replace("REFFGZ","(bc+d$|ef*g.|h?i(j|k))","EnKX",[caseless,
+ global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(bc+d$|ef*g.|h?i(j|k))","&bQK&gYPqvKo\\1Dxq&&&",[caseless])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(bc+d$|ef*g.|h?i(j|k))","&bQK&gYPqvKo\\1Dxq&&&",[caseless,
+ global])),
+?line <<"ADCDCDE">> = iolist_to_binary(re:replace("ADCDCDE","(bc+d$|ef*g.|h?i(j|k))","\\1D&uYGYYB\\1mXY",[caseless])),
+?line <<"ADCDCDE">> = iolist_to_binary(re:replace("ADCDCDE","(bc+d$|ef*g.|h?i(j|k))","\\1D&uYGYYB\\1mXY",[caseless,
+ global])),
+?line <<"EFFG">> = iolist_to_binary(re:replace("EFFG","(bc+d$|ef*g.|h?i(j|k))","bqLaCGT&\\1\\1StNeJTj",[caseless])),
+?line <<"EFFG">> = iolist_to_binary(re:replace("EFFG","(bc+d$|ef*g.|h?i(j|k))","bqLaCGT&\\1\\1StNeJTj",[caseless,
+ global])),
+?line <<"BCDD">> = iolist_to_binary(re:replace("BCDD","(bc+d$|ef*g.|h?i(j|k))","M\\1v\\1T\\1H&OCM\\1",[caseless])),
+?line <<"BCDD">> = iolist_to_binary(re:replace("BCDD","(bc+d$|ef*g.|h?i(j|k))","M\\1v\\1T\\1H&OCM\\1",[caseless,
+ global])),
+?line <<"teSxBAbRcV">> = iolist_to_binary(re:replace("A","((((((((((a))))))))))","teSxB\\1bRcV",[caseless])),
+?line <<"teSxBAbRcV">> = iolist_to_binary(re:replace("A","((((((((((a))))))))))","teSxB\\1bRcV",[caseless,
+ global])),
+?line <<"AAAAA">> = iolist_to_binary(re:replace("AA","((((((((((a))))))))))\\10","&&\\1",[caseless])),
+?line <<"AAAAA">> = iolist_to_binary(re:replace("AA","((((((((((a))))))))))\\10","&&\\1",[caseless,
+ global])),
+?line <<"AAPBpi">> = iolist_to_binary(re:replace("A","(((((((((a)))))))))","&\\1PBpi",[caseless])),
+?line <<"AAPBpi">> = iolist_to_binary(re:replace("A","(((((((((a)))))))))","&\\1PBpi",[caseless,
+ global])),
+?line <<"htagTvaaMIaAkgtdgA">> = iolist_to_binary(re:replace("A","(?:(?:(?:(?:(?:(?:(?:(?:(?:(a))))))))))","htagTvaaMIaAkgtdg&",[caseless])),
+?line <<"htagTvaaMIaAkgtdgA">> = iolist_to_binary(re:replace("A","(?:(?:(?:(?:(?:(?:(?:(?:(?:(a))))))))))","htagTvaaMIaAkgtdg&",[caseless,
+ global])),
+?line <<"iVCeGCCLesCClCCD">> = iolist_to_binary(re:replace("C","(?:(?:(?:(?:(?:(?:(?:(?:(?:(a|b|c))))))))))","iV&eG\\1CLesC&l&\\1D",[caseless])),
+?line <<"iVCeGCCLesCClCCD">> = iolist_to_binary(re:replace("C","(?:(?:(?:(?:(?:(?:(?:(?:(?:(a|b|c))))))))))","iV&eG\\1CLesC&l&\\1D",[caseless,
+ global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","multiple words of text","hKB&NgvvVpXbuP",[caseless])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","multiple words of text","hKB&NgvvVpXbuP",[caseless,
+ global])),
+?line <<"AA">> = iolist_to_binary(re:replace("AA","multiple words of text","V&\\1e&n\\1",[caseless])),
+?line <<"AA">> = iolist_to_binary(re:replace("AA","multiple words of text","V&\\1e&n\\1",[caseless,
+ global])),
+?line <<"UH-UH">> = iolist_to_binary(re:replace("UH-UH","multiple words of text","w\\1JcoWUQlAryay\\1",[caseless])),
+?line <<"UH-UH">> = iolist_to_binary(re:replace("UH-UH","multiple words of text","w\\1JcoWUQlAryay\\1",[caseless,
+ global])),
+?line <<"Ee, YEAH">> = iolist_to_binary(re:replace("MULTIPLE WORDS, YEAH","multiple words","Ee",[caseless])),
+?line <<"Ee, YEAH">> = iolist_to_binary(re:replace("MULTIPLE WORDS, YEAH","multiple words","Ee",[caseless,
+ global])),
+?line <<"uTrQvyABCDEABCDEACeABCDE">> = iolist_to_binary(re:replace("ABCDE","(.*)c(.*)","uTrQvy&&ACe&",[caseless])),
+?line <<"uTrQvyABCDEABCDEACeABCDE">> = iolist_to_binary(re:replace("ABCDE","(.*)c(.*)","uTrQvy&&ACe&",[caseless,
+ global])),
+?line <<"ba(A, B)owqjAHEJ(A, B)qP">> = iolist_to_binary(re:replace("(A, B)","\\((.*), (.*)\\)","ba&owqj\\1HEJ&qP",[caseless])),
+?line <<"ba(A, B)owqjAHEJ(A, B)qP">> = iolist_to_binary(re:replace("(A, B)","\\((.*), (.*)\\)","ba&owqj\\1HEJ&qP",[caseless,
+ global])),
+?line <<"ABCDRIpLJwyEwDArCpanW">> = iolist_to_binary(re:replace("ABCD","abcd","&RIpLJwyEwDA\\1rCpan\\1W",[caseless])),
+?line <<"ABCDRIpLJwyEwDArCpanW">> = iolist_to_binary(re:replace("ABCD","abcd","&RIpLJwyEwDA\\1rCpan\\1W",[caseless,
+ global])),
+?line <<"xykYBC">> = iolist_to_binary(re:replace("ABCD","a(bc)d","xykY\\1",[caseless])),
+?line <<"xykYBC">> = iolist_to_binary(re:replace("ABCD","a(bc)d","xykY\\1",[caseless,
+ global])),
+?line <<"UMfPSTJEqdeS">> = iolist_to_binary(re:replace("AC","a[-]?c","U\\1M\\1\\1fPSTJEqdeS",[caseless])),
+?line <<"UMfPSTJEqdeS">> = iolist_to_binary(re:replace("AC","a[-]?c","U\\1M\\1\\1fPSTJEqdeS",[caseless,
+ global])),
+?line <<"ITABCABCABCnxfDlABCpYAXQvxABCABCE">> = iolist_to_binary(re:replace("ABCABC","(abc)\\1","IT\\1&nxfDl\\1pYAXQvx\\1\\1E",[caseless])),
+?line <<"ITABCABCABCnxfDlABCpYAXQvxABCABCE">> = iolist_to_binary(re:replace("ABCABC","(abc)\\1","IT\\1&nxfDl\\1pYAXQvx\\1\\1E",[caseless,
+ global])),
+?line <<"JXRRQqcKbpvOgISABCT">> = iolist_to_binary(re:replace("ABCABC","([a-c]*)\\1","JXRRQqcKbpvOgIS\\1T",[caseless])),
+?line <<"JXRRQqcKbpvOgISABCTJXRRQqcKbpvOgIST">> = iolist_to_binary(re:replace("ABCABC","([a-c]*)\\1","JXRRQqcKbpvOgIS\\1T",[caseless,
+ global])),
+?line <<"abxuiiVt">> = iolist_to_binary(re:replace("abad","a(?!b).","xuiiVt",[])),
+?line <<"abxuiiVt">> = iolist_to_binary(re:replace("abad","a(?!b).","xuiiVt",[global])),
+?line <<"abMdtNqPOC">> = iolist_to_binary(re:replace("abad","a(?=d).","MdtNqPOC",[])),
+?line <<"abMdtNqPOC">> = iolist_to_binary(re:replace("abad","a(?=d).","MdtNqPOC",[global])),
+?line <<"abmkrHu">> = iolist_to_binary(re:replace("abad","a(?=c|d).","mkrHu",[])),
+?line <<"abmkrHu">> = iolist_to_binary(re:replace("abad","a(?=c|d).","mkrHu",[global])),
+?line <<"JfimtGueeaceUlTKvht">> = iolist_to_binary(re:replace("ace","a(?:b|c|d)(.)","JfimtGu\\1\\1&UlTKvht",[])),
+?line <<"JfimtGueeaceUlTKvht">> = iolist_to_binary(re:replace("ace","a(?:b|c|d)(.)","JfimtGu\\1\\1&UlTKvht",[global])),
+?line <<"IdKeqIicacekGQCace">> = iolist_to_binary(re:replace("ace","a(?:b|c|d)*(.)","IdK\\1qIic&kGQC&",[])),
+?line <<"IdKeqIicacekGQCace">> = iolist_to_binary(re:replace("ace","a(?:b|c|d)*(.)","IdK\\1qIic&kGQC&",[global])),
+?line <<"ovgdwiKdYGGace">> = iolist_to_binary(re:replace("ace","a(?:b|c|d)+?(.)","ovgdwiKdYGG&",[])),
+?line <<"ovgdwiKdYGGace">> = iolist_to_binary(re:replace("ace","a(?:b|c|d)+?(.)","ovgdwiKdYGG&",[global])),
+?line <<"uJgdlOhWXUJpEBdwSbcdbe">> = iolist_to_binary(re:replace("acdbcdbe","a(?:b|c|d)+?(.)","uJg\\1lOhWXUJpEB\\1wS",[])),
+?line <<"uJgdlOhWXUJpEBdwSbcdbe">> = iolist_to_binary(re:replace("acdbcdbe","a(?:b|c|d)+?(.)","uJg\\1lOhWXUJpEB\\1wS",[global])),
+?line <<"UMpmieMJkQH">> = iolist_to_binary(re:replace("acdbcdbe","a(?:b|c|d)+(.)","UMpmi\\1MJkQH",[])),
+?line <<"UMpmieMJkQH">> = iolist_to_binary(re:replace("acdbcdbe","a(?:b|c|d)+(.)","UMpmi\\1MJkQH",[global])),
+?line <<"pCjGheRqYfSacdbhlDAvcdbe">> = iolist_to_binary(re:replace("acdbcdbe","a(?:b|c|d){2}(.)","pCjGheRqYfS&hlDAv",[])),
+?line <<"pCjGheRqYfSacdbhlDAvcdbe">> = iolist_to_binary(re:replace("acdbcdbe","a(?:b|c|d){2}(.)","pCjGheRqYfS&hlDAv",[global])),
+?line <<"yxwYmacdbcdbbAbacdbcdbbGABe">> = iolist_to_binary(re:replace("acdbcdbe","a(?:b|c|d){4,5}(.)","yxwYm&\\1A\\1&bGAB",[])),
+?line <<"yxwYmacdbcdbbAbacdbcdbbGABe">> = iolist_to_binary(re:replace("acdbcdbe","a(?:b|c|d){4,5}(.)","yxwYm&\\1A\\1&bGAB",[global])),
+?line <<"dkoReacdbcdhXacdbcdacdbcdcakNJbe">> = iolist_to_binary(re:replace("acdbcdbe","a(?:b|c|d){4,5}?(.)","\\1koRe&hX&&cakNJ",[])),
+?line <<"dkoReacdbcdhXacdbcdacdbcdcakNJbe">> = iolist_to_binary(re:replace("acdbcdbe","a(?:b|c|d){4,5}?(.)","\\1koRe&hX&&cakNJ",[global])),
+?line <<"nVjVDfoobarOjfoobarfoobareL">> = iolist_to_binary(re:replace("foobar","((foo)|(bar))*","nVjVD&Oj&&eL",[])),
+?line <<"nVjVDfoobarOjfoobarfoobareLnVjVDOjeL">> = iolist_to_binary(re:replace("foobar","((foo)|(bar))*","nVjVD&Oj&&eL",[global])),
+?line <<"bJacdbcdbeMVacdbcdbeFAiPYieyEAI">> = iolist_to_binary(re:replace("acdbcdbe","a(?:b|c|d){6,7}(.)","bJ&MV&FAiPYi\\1yEAI",[])),
+?line <<"bJacdbcdbeMVacdbcdbeFAiPYieyEAI">> = iolist_to_binary(re:replace("acdbcdbe","a(?:b|c|d){6,7}(.)","bJ&MV&FAiPYi\\1yEAI",[global])),
+?line <<"cW">> = iolist_to_binary(re:replace("acdbcdbe","a(?:b|c|d){6,7}?(.)","cW",[])),
+?line <<"cW">> = iolist_to_binary(re:replace("acdbcdbe","a(?:b|c|d){6,7}?(.)","cW",[global])),
+?line <<"EnymbYybacdbcdbeQeCacdbcdbeacdbcdbe">> = iolist_to_binary(re:replace("acdbcdbe","a(?:b|c|d){5,6}(.)","EnymbYyb&Q\\1C&&",[])),
+?line <<"EnymbYybacdbcdbeQeCacdbcdbeacdbcdbe">> = iolist_to_binary(re:replace("acdbcdbe","a(?:b|c|d){5,6}(.)","EnymbYyb&Q\\1C&&",[global])),
+?line <<"XCacdbcdbVjuGQacdbcdbBqmsUJe">> = iolist_to_binary(re:replace("acdbcdbe","a(?:b|c|d){5,6}?(.)","XC&VjuGQ&BqmsUJ",[])),
+?line <<"XCacdbcdbVjuGQacdbcdbBqmsUJe">> = iolist_to_binary(re:replace("acdbcdbe","a(?:b|c|d){5,6}?(.)","XC&VjuGQ&BqmsUJ",[global])),
+?line <<"OacdbcdbeCSMacdbcdbensheuoDP">> = iolist_to_binary(re:replace("acdbcdbe","a(?:b|c|d){5,7}(.)","O&CSM&nsh\\1uoDP",[])),
+?line <<"OacdbcdbeCSMacdbcdbensheuoDP">> = iolist_to_binary(re:replace("acdbcdbe","a(?:b|c|d){5,7}(.)","O&CSM&nsh\\1uoDP",[global])),
+?line <<"YReNTbe">> = iolist_to_binary(re:replace("acdbcdbe","a(?:b|c|d){5,7}?(.)","YReNT\\1",[])),
+?line <<"YReNTbe">> = iolist_to_binary(re:replace("acdbcdbe","a(?:b|c|d){5,7}?(.)","YReNT\\1",[global])),
+?line <<"IJoaceaceHEIicnaaceaceacecq">> = iolist_to_binary(re:replace("ace","a(?:b|(c|e){1,2}?|d)+?(.)","IJo&&HEIi\\1na&&&\\1q",[])),
+?line <<"IJoaceaceHEIicnaaceaceacecq">> = iolist_to_binary(re:replace("ace","a(?:b|(c|e){1,2}?|d)+?(.)","IJo&&HEIi\\1na&&&\\1q",[global])),
+?line <<"PqnTibAldgKNACABm">> = iolist_to_binary(re:replace("AB","^(.+)?B","PqnTib\\1ldgKN\\1C&m",[])),
+?line <<"PqnTibAldgKNACABm">> = iolist_to_binary(re:replace("AB","^(.+)?B","PqnTib\\1ldgKN\\1C&m",[global])),
+?line <<"n.toDyHxNwuj.d.n..l">> = iolist_to_binary(re:replace(".","^([^a-z])|(\\^)$","n\\1toDyHxNwuj\\1d&n\\1\\1l",[])),
+?line <<"n.toDyHxNwuj.d.n..l">> = iolist_to_binary(re:replace(".","^([^a-z])|(\\^)$","n\\1toDyHxNwuj\\1d&n\\1\\1l",[global])),
+?line <<"GOUT">> = iolist_to_binary(re:replace("<&OUT","^[<>]&","G",[])),
+?line <<"GOUT">> = iolist_to_binary(re:replace("<&OUT","^[<>]&","G",[global])),
+?line <<"eQPwy">> = iolist_to_binary(re:replace("aaaaaaaaaa","^(a\\1?){4}$","eQPwy",[])),
+?line <<"eQPwy">> = iolist_to_binary(re:replace("aaaaaaaaaa","^(a\\1?){4}$","eQPwy",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(a\\1?){4}$","fpysabFs",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(a\\1?){4}$","fpysabFs",[global])),
+?line <<"AB">> = iolist_to_binary(re:replace("AB","^(a\\1?){4}$","iySaXMmSpF\\1wGu&i&",[])),
+?line <<"AB">> = iolist_to_binary(re:replace("AB","^(a\\1?){4}$","iySaXMmSpF\\1wGu&i&",[global])),
+?line <<"aaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaa","^(a\\1?){4}$","&E&t",[])),
+?line <<"aaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaa","^(a\\1?){4}$","&E&t",[global])),
+?line <<"aaaaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaaaa","^(a\\1?){4}$","rv\\1nEUYoTcup\\1",[])),
+?line <<"aaaaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaaaa","^(a\\1?){4}$","rv\\1nEUYoTcup\\1",[global])),
+?line <<"Grouf">> = iolist_to_binary(re:replace("aaaaaaaaaa","^(a(?(1)\\1)){4}$","Grouf",[])),
+?line <<"Grouf">> = iolist_to_binary(re:replace("aaaaaaaaaa","^(a(?(1)\\1)){4}$","Grouf",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(a(?(1)\\1)){4}$","xJ\\1D",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(a(?(1)\\1)){4}$","xJ\\1D",[global])),
+?line <<"aaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaa","^(a(?(1)\\1)){4}$","w&PQ&n&C",[])),
+?line <<"aaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaa","^(a(?(1)\\1)){4}$","w&PQ&n&C",[global])),
+?line <<"aaaaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaaaa","^(a(?(1)\\1)){4}$","fXiC",[])),
+?line <<"aaaaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaaaa","^(a(?(1)\\1)){4}$","fXiC",[global])),
+?line <<"fEfoobarodvfoobarmohu">> = iolist_to_binary(re:replace("foobar","(?:(f)(o)(o)|(b)(a)(r))*","\\1E&odv&mohu",[])),
+?line <<"fEfoobarodvfoobarmohuEodvmohu">> = iolist_to_binary(re:replace("foobar","(?:(f)(o)(o)|(b)(a)(r))*","\\1E&odv&mohu",[global])),
+?line <<"aaHgXnnrbsEWfBvCB">> = iolist_to_binary(re:replace("ab","(?<=a)b","aHgXnnr&sEWfBv\\1CB",[])),
+?line <<"aaHgXnnrbsEWfBvCB">> = iolist_to_binary(re:replace("ab","(?<=a)b","aHgXnnr&sEWfBv\\1CB",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?<=a)b","&\\1J\\1qs\\1\\1",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?<=a)b","&\\1J\\1qs\\1\\1",[global])),
+?line <<"cb">> = iolist_to_binary(re:replace("cb","(?<=a)b","PBhSDEP\\1&fa&&FAQ",[])),
+?line <<"cb">> = iolist_to_binary(re:replace("cb","(?<=a)b","PBhSDEP\\1&fa&&FAQ",[global])),
+?line <<"b">> = iolist_to_binary(re:replace("b","(?<=a)b","VGBLJTb\\1",[])),
+?line <<"b">> = iolist_to_binary(re:replace("b","(?<=a)b","VGBLJTb\\1",[global])),
+?line <<"aAjOnQvFo">> = iolist_to_binary(re:replace("ab","(?<!c)b","Aj\\1OnQvFo",[])),
+?line <<"aAjOnQvFo">> = iolist_to_binary(re:replace("ab","(?<!c)b","Aj\\1OnQvFo",[global])),
+?line <<"EcsuQFCLbrqGgAba">> = iolist_to_binary(re:replace("b","(?<!c)b","EcsuQ\\1FCLbrqGgA&a",[])),
+?line <<"EcsuQFCLbrqGgAba">> = iolist_to_binary(re:replace("b","(?<!c)b","EcsuQ\\1FCLbrqGgA&a",[global])),
+?line <<"OLbRynrb">> = iolist_to_binary(re:replace("b","(?<!c)b","OL&R\\1\\1ynr&\\1",[])),
+?line <<"OLbRynrb">> = iolist_to_binary(re:replace("b","(?<!c)b","OL&R\\1\\1ynr&\\1",[global])),
+?line <<"YnabankVVRQtUI">> = iolist_to_binary(re:replace("aba","(?:..)*a","Yn&nkVVRQtUI",[])),
+?line <<"YnabankVVRQtUI">> = iolist_to_binary(re:replace("aba","(?:..)*a","Yn&nkVVRQtUI",[global])),
+?line <<"dtatllgba">> = iolist_to_binary(re:replace("aba","(?:..)*?a","dt&tllg",[])),
+?line <<"dtatllgbdtatllg">> = iolist_to_binary(re:replace("aba","(?:..)*?a","dt&tllg",[global])),
+?line <<"abKyOHc">> = iolist_to_binary(re:replace("abc","^(?:b|a(?=(.)))*\\1","&KyOH",[])),
+?line <<"abKyOHc">> = iolist_to_binary(re:replace("abc","^(?:b|a(?=(.)))*\\1","&KyOH",[global])),
+?line <<"olabc">> = iolist_to_binary(re:replace("abc","^(){3,5}","ol",[])),
+?line <<"olabc">> = iolist_to_binary(re:replace("abc","^(){3,5}","ol",[global])),
+?line <<"tQmIRuA">> = iolist_to_binary(re:replace("aax","^(a+)*ax","tQmIRuA",[])),
+?line <<"tQmIRuA">> = iolist_to_binary(re:replace("aax","^(a+)*ax","tQmIRuA",[global])),
+?line <<"RaaxLDgyKaII">> = iolist_to_binary(re:replace("aax","^((a|b)+)*ax","R&LDgyK\\1II",[])),
+?line <<"RaaxLDgyKaII">> = iolist_to_binary(re:replace("aax","^((a|b)+)*ax","R&LDgyK\\1II",[global])),
+?line <<"jxJdaCNaaxAUxaofKF">> = iolist_to_binary(re:replace("aax","^((a|bc)+)*ax","jxJd\\1CN&AUx\\1ofKF",[])),
+?line <<"jxJdaCNaaxAUxaofKF">> = iolist_to_binary(re:replace("aax","^((a|bc)+)*ax","jxJd\\1CN&AUx\\1ofKF",[global])),
+?line <<"cxMJiMAGvYS">> = iolist_to_binary(re:replace("cab","(a|x)*ab","xMJiMA\\1G\\1vYS",[])),
+?line <<"cxMJiMAGvYS">> = iolist_to_binary(re:replace("cab","(a|x)*ab","xMJiMA\\1G\\1vYS",[global])),
+?line <<"cwXU">> = iolist_to_binary(re:replace("cab","(a)*ab","wXU\\1",[])),
+?line <<"cwXU">> = iolist_to_binary(re:replace("cab","(a)*ab","wXU\\1",[global])),
+?line <<"y">> = iolist_to_binary(re:replace("ab","(?:(?i)a)b","y",[])),
+?line <<"y">> = iolist_to_binary(re:replace("ab","(?:(?i)a)b","y",[global])),
+?line <<"xNpTab">> = iolist_to_binary(re:replace("ab","((?i)a)b","xNpT&",[])),
+?line <<"xNpTab">> = iolist_to_binary(re:replace("ab","((?i)a)b","xNpT&",[global])),
+?line <<"UUhQk">> = iolist_to_binary(re:replace("Ab","(?:(?i)a)b","UU\\1\\1h\\1Qk",[])),
+?line <<"UUhQk">> = iolist_to_binary(re:replace("Ab","(?:(?i)a)b","UU\\1\\1h\\1Qk",[global])),
+?line <<"To">> = iolist_to_binary(re:replace("Ab","((?i)a)b","To",[])),
+?line <<"To">> = iolist_to_binary(re:replace("Ab","((?i)a)b","To",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?:(?i)a)b","Iog\\1kPwXTNA\\1u",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?:(?i)a)b","Iog\\1kPwXTNA\\1u",[global])),
+?line <<"cb">> = iolist_to_binary(re:replace("cb","(?:(?i)a)b","\\1eeor\\1PcpHdMT&rFUGQX",[])),
+?line <<"cb">> = iolist_to_binary(re:replace("cb","(?:(?i)a)b","\\1eeor\\1PcpHdMT&rFUGQX",[global])),
+?line <<"aB">> = iolist_to_binary(re:replace("aB","(?:(?i)a)b","f&&\\1Fnb&nOyDHT&Trng",[])),
+?line <<"aB">> = iolist_to_binary(re:replace("aB","(?:(?i)a)b","f&&\\1Fnb&nOyDHT&Trng",[global])),
+?line <<"SCyJabaabEDejJdabuabG">> = iolist_to_binary(re:replace("ab","(?i:a)b","SCyJ\\1&a&EDejJd&\\1u\\1&G",[])),
+?line <<"SCyJabaabEDejJdabuabG">> = iolist_to_binary(re:replace("ab","(?i:a)b","SCyJ\\1&a&EDejJd&\\1u\\1&G",[global])),
+?line <<"nabMYvlVqabaabvabp">> = iolist_to_binary(re:replace("ab","((?i:a))b","n&MYvlVq&\\1&v&p",[])),
+?line <<"nabMYvlVqabaabvabp">> = iolist_to_binary(re:replace("ab","((?i:a))b","n&MYvlVq&\\1&v&p",[global])),
+?line <<"hQhGlGrAbAbxEKrc">> = iolist_to_binary(re:replace("Ab","(?i:a)b","hQhGlGr&&xEKrc\\1",[])),
+?line <<"hQhGlGrAbAbxEKrc">> = iolist_to_binary(re:replace("Ab","(?i:a)b","hQhGlGr&&xEKrc\\1",[global])),
+?line <<"fSgsAnoYq">> = iolist_to_binary(re:replace("Ab","((?i:a))b","fSgs\\1noYq",[])),
+?line <<"fSgsAnoYq">> = iolist_to_binary(re:replace("Ab","((?i:a))b","fSgs\\1noYq",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?i:a)b","Lsa",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?i:a)b","Lsa",[global])),
+?line <<"aB">> = iolist_to_binary(re:replace("aB","(?i:a)b","&MKfO&mRWgP&yU",[])),
+?line <<"aB">> = iolist_to_binary(re:replace("aB","(?i:a)b","&MKfO&mRWgP&yU",[global])),
+?line <<"aB">> = iolist_to_binary(re:replace("aB","(?i:a)b","S",[])),
+?line <<"aB">> = iolist_to_binary(re:replace("aB","(?i:a)b","S",[global])),
+?line <<"QTabISRDlbwogmSuiJ">> = iolist_to_binary(re:replace("ab","(?:(?-i)a)b","QT&ISRDlbwogmSuiJ",[caseless])),
+?line <<"QTabISRDlbwogmSuiJ">> = iolist_to_binary(re:replace("ab","(?:(?-i)a)b","QT&ISRDlbwogmSuiJ",[caseless,
+ global])),
+?line <<"VabWOeTSwSGwOkyIabf">> = iolist_to_binary(re:replace("ab","((?-i)a)b","V&WOeTSwSGwOkyI&f",[caseless])),
+?line <<"VabWOeTSwSGwOkyIabf">> = iolist_to_binary(re:replace("ab","((?-i)a)b","V&WOeTSwSGwOkyI&f",[caseless,
+ global])),
+?line <<"pNtk">> = iolist_to_binary(re:replace("aB","(?:(?-i)a)b","\\1pNtk",[caseless])),
+?line <<"pNtk">> = iolist_to_binary(re:replace("aB","(?:(?-i)a)b","\\1pNtk",[caseless,
+ global])),
+?line <<"MpdRBTE">> = iolist_to_binary(re:replace("aB","((?-i)a)b","MpdRBTE",[caseless])),
+?line <<"MpdRBTE">> = iolist_to_binary(re:replace("aB","((?-i)a)b","MpdRBTE",[caseless,
+ global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?:(?-i)a)b","RiV",[caseless])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?:(?-i)a)b","RiV",[caseless,
+ global])),
+?line <<"tjEITLaBaBtD">> = iolist_to_binary(re:replace("aB","(?:(?-i)a)b","t\\1jEITL&&tD",[caseless])),
+?line <<"tjEITLaBaBtD">> = iolist_to_binary(re:replace("aB","(?:(?-i)a)b","t\\1jEITL&&tD",[caseless,
+ global])),
+?line <<"Ab">> = iolist_to_binary(re:replace("Ab","(?:(?-i)a)b","hbvOWn",[caseless])),
+?line <<"Ab">> = iolist_to_binary(re:replace("Ab","(?:(?-i)a)b","hbvOWn",[caseless,
+ global])),
+?line <<"s">> = iolist_to_binary(re:replace("aB","(?:(?-i)a)b","s",[caseless])),
+?line <<"s">> = iolist_to_binary(re:replace("aB","(?:(?-i)a)b","s",[caseless,
+ global])),
+?line <<"yfQaBvLFJJQMhKGx">> = iolist_to_binary(re:replace("aB","((?-i)a)b","yfQ&vLFJJQMhKGx",[caseless])),
+?line <<"yfQaBvLFJJQMhKGx">> = iolist_to_binary(re:replace("aB","((?-i)a)b","yfQ&vLFJJQMhKGx",[caseless,
+ global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?:(?-i)a)b","QM&L",[caseless])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?:(?-i)a)b","QM&L",[caseless,
+ global])),
+?line <<"Ab">> = iolist_to_binary(re:replace("Ab","(?:(?-i)a)b","aVF\\1dL&\\1",[caseless])),
+?line <<"Ab">> = iolist_to_binary(re:replace("Ab","(?:(?-i)a)b","aVF\\1dL&\\1",[caseless,
+ global])),
+?line <<"AB">> = iolist_to_binary(re:replace("AB","(?:(?-i)a)b","GSb\\1bvleJ",[caseless])),
+?line <<"AB">> = iolist_to_binary(re:replace("AB","(?:(?-i)a)b","GSb\\1bvleJ",[caseless,
+ global])),
+?line <<"wAW">> = iolist_to_binary(re:replace("ab","(?-i:a)b","wAW",[caseless])),
+?line <<"wAW">> = iolist_to_binary(re:replace("ab","(?-i:a)b","wAW",[caseless,
+ global])),
+?line <<"Atl">> = iolist_to_binary(re:replace("ab","((?-i:a))b","Atl",[caseless])),
+?line <<"Atl">> = iolist_to_binary(re:replace("ab","((?-i:a))b","Atl",[caseless,
+ global])),
+?line <<"gP">> = iolist_to_binary(re:replace("aB","(?-i:a)b","gP\\1",[caseless])),
+?line <<"gP">> = iolist_to_binary(re:replace("aB","(?-i:a)b","gP\\1",[caseless,
+ global])),
+?line <<"LFcaNaJixv">> = iolist_to_binary(re:replace("aB","((?-i:a))b","LFc\\1N\\1Jixv",[caseless])),
+?line <<"LFcaNaJixv">> = iolist_to_binary(re:replace("aB","((?-i:a))b","LFc\\1N\\1Jixv",[caseless,
+ global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?-i:a)b","FRPuPJIi\\1",[caseless])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?-i:a)b","FRPuPJIi\\1",[caseless,
+ global])),
+?line <<"AB">> = iolist_to_binary(re:replace("AB","(?-i:a)b","TYBp\\1aMFRUwXYyGS\\1&tH",[caseless])),
+?line <<"AB">> = iolist_to_binary(re:replace("AB","(?-i:a)b","TYBp\\1aMFRUwXYyGS\\1&tH",[caseless,
+ global])),
+?line <<"Ab">> = iolist_to_binary(re:replace("Ab","(?-i:a)b","s",[caseless])),
+?line <<"Ab">> = iolist_to_binary(re:replace("Ab","(?-i:a)b","s",[caseless,
+ global])),
+?line <<"XBBaBVaBHwVHaBtFl">> = iolist_to_binary(re:replace("aB","(?-i:a)b","XBB\\1&V&H\\1wVH&t\\1Fl",[caseless])),
+?line <<"XBBaBVaBHwVHaBtFl">> = iolist_to_binary(re:replace("aB","(?-i:a)b","XBB\\1&V&H\\1wVH&t\\1Fl",[caseless,
+ global])),
+?line <<"TfbKaBvxl">> = iolist_to_binary(re:replace("aB","((?-i:a))b","TfbK&vxl",[caseless])),
+?line <<"TfbKaBvxl">> = iolist_to_binary(re:replace("aB","((?-i:a))b","TfbK&vxl",[caseless,
+ global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?-i:a)b","\\1B\\1v&LjNSAy",[caseless])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?-i:a)b","\\1B\\1v&LjNSAy",[caseless,
+ global])),
+?line <<"Ab">> = iolist_to_binary(re:replace("Ab","(?-i:a)b","HQTW",[caseless])),
+?line <<"Ab">> = iolist_to_binary(re:replace("Ab","(?-i:a)b","HQTW",[caseless,
+ global])),
+?line <<"AB">> = iolist_to_binary(re:replace("AB","(?-i:a)b","pG",[caseless])),
+?line <<"AB">> = iolist_to_binary(re:replace("AB","(?-i:a)b","pG",[caseless,
+ global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","((?-i:a.))b","U",[caseless])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","((?-i:a.))b","U",[caseless,
+ global])),
+?line <<"AB">> = iolist_to_binary(re:replace("AB","((?-i:a.))b","\\1uBjM&tv&\\1tD\\1UO\\1gVY",[caseless])),
+?line <<"AB">> = iolist_to_binary(re:replace("AB","((?-i:a.))b","\\1uBjM&tv&\\1tD\\1UO\\1gVY",[caseless,
+ global])),
+?line <<"a
+B">> = iolist_to_binary(re:replace("a
+B","((?-i:a.))b","SAx&Io",[caseless])),
+?line <<"a
+B">> = iolist_to_binary(re:replace("a
+B","((?-i:a.))b","SAx&Io",[caseless,global])),
+?line <<"LPyepkdfnqsa
+oa
+a
+Ba
+M">> = iolist_to_binary(re:replace("a
+B","((?s-i:a.))b","LPyepkdfnqs\\1o\\1&\\1M",[caseless])),
+?line <<"LPyepkdfnqsa
+oa
+a
+Ba
+M">> = iolist_to_binary(re:replace("a
+B","((?s-i:a.))b","LPyepkdfnqs\\1o\\1&\\1M",[caseless,global])),
+?line <<"RG">> = iolist_to_binary(re:replace("cabbbb","(?:c|d)(?:)(?:a(?:)(?:b)(?:b(?:))(?:b(?:)(?:b)))","RG",[])),
+?line <<"RG">> = iolist_to_binary(re:replace("cabbbb","(?:c|d)(?:)(?:a(?:)(?:b)(?:b(?:))(?:b(?:)(?:b)))","RG",[global])),
+?line <<"SiMB">> = iolist_to_binary(re:replace("caaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb","(?:c|d)(?:)(?:aaaaaaaa(?:)(?:bbbbbbbb)(?:bbbbbbbb(?:))(?:bbbbbbbb(?:)(?:bbbbbbbb)))","\\1SiMB",[])),
+?line <<"SiMB">> = iolist_to_binary(re:replace("caaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb","(?:c|d)(?:)(?:aaaaaaaa(?:)(?:bbbbbbbb)(?:bbbbbbbb(?:))(?:bbbbbbbb(?:)(?:bbbbbbbb)))","\\1SiMB",[global])),
+?line <<"HNBAb4abYAb4abecqBPfYYBF">> = iolist_to_binary(re:replace("Ab4ab","(ab)\\d\\1","HNB&Y&ecqBPfYYBF",[caseless])),
+?line <<"HNBAb4abYAb4abecqBPfYYBF">> = iolist_to_binary(re:replace("Ab4ab","(ab)\\d\\1","HNB&Y&ecqBPfYYBF",[caseless,
+ global])),
+?line <<"eqbVWgJEcab4Ababe">> = iolist_to_binary(re:replace("ab4Ab","(ab)\\d\\1","eqbVWgJEc&\\1e",[caseless])),
+?line <<"eqbVWgJEcab4Ababe">> = iolist_to_binary(re:replace("ab4Ab","(ab)\\d\\1","eqbVWgJEc&\\1e",[caseless,
+ global])),
+?line <<"HvsmPfoobar1234bazCYfoobar1234bazqih">> = iolist_to_binary(re:replace("foobar1234baz","foo\\w*\\d{4}baz","HvsmP&CY&qih",[])),
+?line <<"HvsmPfoobar1234bazCYfoobar1234bazqih">> = iolist_to_binary(re:replace("foobar1234baz","foo\\w*\\d{4}baz","HvsmP&CY&qih",[global])),
+?line <<"x~~lsTkD~~qWUPtx~~wj~~R">> = iolist_to_binary(re:replace("x~~","x(~~)*(?:(?:F)?)?","&lsTkD\\1qWUPt&wj\\1R",[])),
+?line <<"x~~lsTkD~~qWUPtx~~wj~~R">> = iolist_to_binary(re:replace("x~~","x(~~)*(?:(?:F)?)?","&lsTkD\\1qWUPt&wj\\1R",[global])),
+?line <<"aaacPnBOLPeN">> = iolist_to_binary(re:replace("aaac","^a(?#xxx){3}c","&P\\1n\\1BOLPeN",[])),
+?line <<"aaacPnBOLPeN">> = iolist_to_binary(re:replace("aaac","^a(?#xxx){3}c","&P\\1n\\1BOLPeN",[global])),
+?line <<"Uh">> = iolist_to_binary(re:replace("aaac","^a (?#xxx) (?#yyy) {3}c","Uh",[extended])),
+?line <<"Uh">> = iolist_to_binary(re:replace("aaac","^a (?#xxx) (?#yyy) {3}c","Uh",[extended,
+ global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?<![cd])b","\\1CWOLaTxilNg\\1W",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?<![cd])b","\\1CWOLaTxilNg\\1W",[global])),
+?line <<"B
+B">> = iolist_to_binary(re:replace("B
+B","(?<![cd])b","ruaT\\1JrTa&\\1sLB&iVNCc",[])),
+?line <<"B
+B">> = iolist_to_binary(re:replace("B
+B","(?<![cd])b","ruaT\\1JrTa&\\1sLB&iVNCc",[global])),
+?line <<"dbcb">> = iolist_to_binary(re:replace("dbcb","(?<![cd])b","\\1l\\1yKVtpLoPXXvCkO",[])),
+?line <<"dbcb">> = iolist_to_binary(re:replace("dbcb","(?<![cd])b","\\1l\\1yKVtpLoPXXvCkO",[global])),
+?line <<"dbuWHWJTppUTaMYMjwHAacb">> = iolist_to_binary(re:replace("dbaacb","(?<![cd])[ab]","uWHWJTppUT&\\1MYM\\1jwHA",[])),
+?line <<"dbuWHWJTppUTaMYMjwHAuWHWJTppUTaMYMjwHAcb">> = iolist_to_binary(re:replace("dbaacb","(?<![cd])[ab]","uWHWJTppUT&\\1MYM\\1jwHA",[global])),
+?line <<"dbeacb">> = iolist_to_binary(re:replace("dbaacb","(?<!(c|d))[ab]","e",[])),
+?line <<"dbeecb">> = iolist_to_binary(re:replace("dbaacb","(?<!(c|d))[ab]","e",[global])),
+?line <<"cdaccbtNFbjDlrMmYMBg">> = iolist_to_binary(re:replace("cdaccb","(?<!cd)[ab]","\\1\\1btNF&jDlrM\\1mYMBg",[])),
+?line <<"cdaccbtNFbjDlrMmYMBg">> = iolist_to_binary(re:replace("cdaccb","(?<!cd)[ab]","\\1\\1btNF&jDlrM\\1mYMBg",[global])),
+?line <<"s">> = iolist_to_binary(re:replace("","^(?:a?b?)*$","s",[])),
+?line <<"s">> = iolist_to_binary(re:replace("","^(?:a?b?)*$","s",[global])),
+?line <<"odRhXAvKP">> = iolist_to_binary(re:replace("a","^(?:a?b?)*$","odRhXAvKP",[])),
+?line <<"odRhXAvKP">> = iolist_to_binary(re:replace("a","^(?:a?b?)*$","odRhXAvKP",[global])),
+?line <<"o">> = iolist_to_binary(re:replace("ab","^(?:a?b?)*$","\\1o",[])),
+?line <<"o">> = iolist_to_binary(re:replace("ab","^(?:a?b?)*$","\\1o",[global])),
+?line <<"d">> = iolist_to_binary(re:replace("aaa","^(?:a?b?)*$","d",[])),
+?line <<"d">> = iolist_to_binary(re:replace("aaa","^(?:a?b?)*$","d",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(?:a?b?)*$","fX&M\\1FCCOYOMH\\1lR&ISP",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(?:a?b?)*$","fX&M\\1FCCOYOMH\\1lR&ISP",[global])),
+?line <<"dbcb">> = iolist_to_binary(re:replace("dbcb","^(?:a?b?)*$","d\\1aeAWVouRdylpC",[])),
+?line <<"dbcb">> = iolist_to_binary(re:replace("dbcb","^(?:a?b?)*$","d\\1aeAWVouRdylpC",[global])),
+?line <<"a--">> = iolist_to_binary(re:replace("a--","^(?:a?b?)*$","uM",[])),
+?line <<"a--">> = iolist_to_binary(re:replace("a--","^(?:a?b?)*$","uM",[global])),
+?line <<"aa--">> = iolist_to_binary(re:replace("aa--","^(?:a?b?)*$","EhSvb&jryIv\\1O&oeR",[])),
+?line <<"aa--">> = iolist_to_binary(re:replace("aa--","^(?:a?b?)*$","EhSvb&jryIv\\1O&oeR",[global])),
+?line <<"yobOa
+ba
+ca
+bcItPS
+c">> = iolist_to_binary(re:replace("a
+b
+c","((?s)^a(.))((?m)^b$)","yobO&\\1c&cItPS",[])),
+?line <<"yobOa
+ba
+ca
+bcItPS
+c">> = iolist_to_binary(re:replace("a
+b
+c","((?s)^a(.))((?m)^b$)","yobO&\\1c&cItPS",[global])),
+?line <<"a
+EBbPgb
+c">> = iolist_to_binary(re:replace("a
+b
+c","((?m)^b$)","EB\\1Pg\\1",[])),
+?line <<"a
+EBbPgb
+c">> = iolist_to_binary(re:replace("a
+b
+c","((?m)^b$)","EB\\1Pg\\1",[global])),
+?line <<"a
+AybVFSWPOkP">> = iolist_to_binary(re:replace("a
+b","(?m)^b","Ay\\1&VF\\1SWPOkP\\1",[])),
+?line <<"a
+AybVFSWPOkP">> = iolist_to_binary(re:replace("a
+b","(?m)^b","Ay\\1&VF\\1SWPOkP\\1",[global])),
+?line <<"a
+bbTbKbl">> = iolist_to_binary(re:replace("a
+b","(?m)^(b)","b\\1T&K\\1l",[])),
+?line <<"a
+bbTbKbl">> = iolist_to_binary(re:replace("a
+b","(?m)^(b)","b\\1T&K\\1l",[global])),
+?line <<"a
+bsyUb">> = iolist_to_binary(re:replace("a
+b","((?m)^b)","&syU\\1",[])),
+?line <<"a
+bsyUb">> = iolist_to_binary(re:replace("a
+b","((?m)^b)","&syU\\1",[global])),
+?line <<"abh">> = iolist_to_binary(re:replace("a
+b","\\n((?m)^b)","\\1h",[])),
+?line <<"abh">> = iolist_to_binary(re:replace("a
+b","\\n((?m)^b)","\\1h",[global])),
+?line <<"a
+bEu">> = iolist_to_binary(re:replace("a
+b
+c","((?s).)c(?!.)","Eu",[])),
+?line <<"a
+bEu">> = iolist_to_binary(re:replace("a
+b
+c","((?s).)c(?!.)","Eu",[global])),
+?line <<"a
+bvKqN
+cF
+r
+n">> = iolist_to_binary(re:replace("a
+b
+c","((?s).)c(?!.)","vKqN&F\\1r\\1n",[])),
+?line <<"a
+bvKqN
+cF
+r
+n">> = iolist_to_binary(re:replace("a
+b
+c","((?s).)c(?!.)","vKqN&F\\1r\\1n",[global])),
+?line <<"a
+ctWb
+Kb
+cinb
+FvJ">> = iolist_to_binary(re:replace("a
+b
+c","((?s)b.)c(?!.)","ctW\\1K&in\\1FvJ",[])),
+?line <<"a
+ctWb
+Kb
+cinb
+FvJ">> = iolist_to_binary(re:replace("a
+b
+c","((?s)b.)c(?!.)","ctW\\1K&in\\1FvJ",[global])),
+?line <<"a
+Tb
+cnVEJvb
+Bb
+yG">> = iolist_to_binary(re:replace("a
+b
+c","((?s)b.)c(?!.)","T&nVEJv\\1B\\1yG",[])),
+?line <<"a
+Tb
+cnVEJvb
+Bb
+yG">> = iolist_to_binary(re:replace("a
+b
+c","((?s)b.)c(?!.)","T&nVEJv\\1B\\1yG",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","()^b","&\\1",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","()^b","&\\1",[global])),
+?line <<"a
+b
+c">> = iolist_to_binary(re:replace("a
+b
+c","()^b","ikT\\1",[])),
+?line <<"a
+b
+c">> = iolist_to_binary(re:replace("a
+b
+c","()^b","ikT\\1",[global])),
+?line <<"a
+b
+c">> = iolist_to_binary(re:replace("a
+b
+c","()^b","&i&frU",[])),
+?line <<"a
+b
+c">> = iolist_to_binary(re:replace("a
+b
+c","()^b","&i&frU",[global])),
+?line <<"a
+bDbfDWKbixbSbxsSN
+c">> = iolist_to_binary(re:replace("a
+b
+c","((?m)^b)","bD\\1fDWK\\1ix\\1S\\1xsSN",[])),
+?line <<"a
+bDbfDWKbixbSbxsSN
+c">> = iolist_to_binary(re:replace("a
+b
+c","((?m)^b)","bD\\1fDWK\\1ix\\1S\\1xsSN",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(x)?(?(1)a|b)","s&Rt",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(x)?(?(1)a|b)","s&Rt",[global])),
+?line <<"a">> = iolist_to_binary(re:replace("a","(x)?(?(1)a|b)","S\\1EQcXTxxFE",[])),
+?line <<"a">> = iolist_to_binary(re:replace("a","(x)?(?(1)a|b)","S\\1EQcXTxxFE",[global])),
+?line <<"a">> = iolist_to_binary(re:replace("a","(x)?(?(1)a|b)","JRHc\\1hvpt&&",[])),
+?line <<"a">> = iolist_to_binary(re:replace("a","(x)?(?(1)a|b)","JRHc\\1hvpt&&",[global])),
+?line <<"bQs">> = iolist_to_binary(re:replace("a","(x)?(?(1)b|a)","bQs",[])),
+?line <<"bQs">> = iolist_to_binary(re:replace("a","(x)?(?(1)b|a)","bQs",[global])),
+?line <<"PQeYprqargqfYkWQsJ">> = iolist_to_binary(re:replace("a","()?(?(1)b|a)","PQeY\\1prq&rgqfYk\\1WQsJ",[])),
+?line <<"PQeYprqargqfYkWQsJ">> = iolist_to_binary(re:replace("a","()?(?(1)b|a)","PQeY\\1prq&rgqfYk\\1WQsJ",[global])),
+?line <<"HafNdwOXAFq">> = iolist_to_binary(re:replace("a","()?(?(1)a|b)","H&\\1f\\1NdwOXA\\1Fq",[])),
+?line <<"HafNdwOXAFq">> = iolist_to_binary(re:replace("a","()?(?(1)a|b)","H&\\1f\\1NdwOXA\\1Fq",[global])),
+?line <<"m">> = iolist_to_binary(re:replace("(blah)","^(\\()?blah(?(1)(\\)))$","m",[])),
+?line <<"m">> = iolist_to_binary(re:replace("(blah)","^(\\()?blah(?(1)(\\)))$","m",[global])),
+?line <<"elEwHf">> = iolist_to_binary(re:replace("blah","^(\\()?blah(?(1)(\\)))$","elEwHf",[])),
+?line <<"elEwHf">> = iolist_to_binary(re:replace("blah","^(\\()?blah(?(1)(\\)))$","elEwHf",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(\\()?blah(?(1)(\\)))$","IGewW&v&qpGlghCJe\\1Y",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(\\()?blah(?(1)(\\)))$","IGewW&v&qpGlghCJe\\1Y",[global])),
+?line <<"a">> = iolist_to_binary(re:replace("a","^(\\()?blah(?(1)(\\)))$","mxf",[])),
+?line <<"a">> = iolist_to_binary(re:replace("a","^(\\()?blah(?(1)(\\)))$","mxf",[global])),
+?line <<"blah)">> = iolist_to_binary(re:replace("blah)","^(\\()?blah(?(1)(\\)))$","LxtdV",[])),
+?line <<"blah)">> = iolist_to_binary(re:replace("blah)","^(\\()?blah(?(1)(\\)))$","LxtdV",[global])),
+?line <<"(blah">> = iolist_to_binary(re:replace("(blah","^(\\()?blah(?(1)(\\)))$","Ni\\1CkEtaxcXXYB\\1",[])),
+?line <<"(blah">> = iolist_to_binary(re:replace("(blah","^(\\()?blah(?(1)(\\)))$","Ni\\1CkEtaxcXXYB\\1",[global])),
+?line <<"UaAfN(ELb">> = iolist_to_binary(re:replace("(blah)","^(\\(+)?blah(?(1)(\\)))$","UaAfN\\1ELb",[])),
+?line <<"UaAfN(ELb">> = iolist_to_binary(re:replace("(blah)","^(\\(+)?blah(?(1)(\\)))$","UaAfN\\1ELb",[global])),
+?line <<"XrxQosMn">> = iolist_to_binary(re:replace("blah","^(\\(+)?blah(?(1)(\\)))$","Xrx\\1QosMn\\1",[])),
+?line <<"XrxQosMn">> = iolist_to_binary(re:replace("blah","^(\\(+)?blah(?(1)(\\)))$","Xrx\\1QosMn\\1",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(\\(+)?blah(?(1)(\\)))$","QGGpmf",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(\\(+)?blah(?(1)(\\)))$","QGGpmf",[global])),
+?line <<"blah)">> = iolist_to_binary(re:replace("blah)","^(\\(+)?blah(?(1)(\\)))$","HDFROCUS",[])),
+?line <<"blah)">> = iolist_to_binary(re:replace("blah)","^(\\(+)?blah(?(1)(\\)))$","HDFROCUS",[global])),
+?line <<"(blah">> = iolist_to_binary(re:replace("(blah","^(\\(+)?blah(?(1)(\\)))$","AVrY",[])),
+?line <<"(blah">> = iolist_to_binary(re:replace("(blah","^(\\(+)?blah(?(1)(\\)))$","AVrY",[global])),
+?line <<"HlgBXckVbhp">> = iolist_to_binary(re:replace("a","(?(?!a)b|a)","HlgBXckV\\1bhp",[])),
+?line <<"HlgBXckVbhp">> = iolist_to_binary(re:replace("a","(?(?!a)b|a)","HlgBXckV\\1bhp",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?(?=a)b|a)","&&PIwfc\\1cckXSEYaB",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?(?=a)b|a)","&&PIwfc\\1cckXSEYaB",[global])),
+?line <<"a">> = iolist_to_binary(re:replace("a","(?(?=a)b|a)","vKjGNVI&ySCYE",[])),
+?line <<"a">> = iolist_to_binary(re:replace("a","(?(?=a)b|a)","vKjGNVI&ySCYE",[global])),
+?line <<"a">> = iolist_to_binary(re:replace("a","(?(?=a)b|a)","lAvpym&eEJad\\1RMs\\1CLu",[])),
+?line <<"a">> = iolist_to_binary(re:replace("a","(?(?=a)b|a)","lAvpym&eEJad\\1RMs\\1CLu",[global])),
+?line <<"kHAy">> = iolist_to_binary(re:replace("a","(?(?=a)a|b)","kHAy",[])),
+?line <<"kHAy">> = iolist_to_binary(re:replace("a","(?(?=a)a|b)","kHAy",[global])),
+?line <<"amAyaheaaTPJaVdTAyU">> = iolist_to_binary(re:replace("aaab","(?=(a+?))(\\1ab)","mAyahe\\1\\1TPJ\\1VdTAyU",[])),
+?line <<"amAyaheaaTPJaVdTAyU">> = iolist_to_binary(re:replace("aaab","(?=(a+?))(\\1ab)","mAyahe\\1\\1TPJ\\1VdTAyU",[global])),
+?line <<"pEvYFTwEOhhryoVdG">> = iolist_to_binary(re:replace("one:","(\\w+:)+","pEvYFTwEOhhryoVdG",[])),
+?line <<"pEvYFTwEOhhryoVdG">> = iolist_to_binary(re:replace("one:","(\\w+:)+","pEvYFTwEOhhryoVdG",[global])),
+?line <<"aHho">> = iolist_to_binary(re:replace("a","$(?<=^(a))","Hho",[])),
+?line <<"aHho">> = iolist_to_binary(re:replace("a","$(?<=^(a))","Hho",[global])),
+?line <<"ajuOkagipUraRpaQiaabv">> = iolist_to_binary(re:replace("aaab","(?=(a+?))(\\1ab)","juOk\\1gipUr\\1Rp\\1Qi&v",[])),
+?line <<"ajuOkagipUraRpaQiaabv">> = iolist_to_binary(re:replace("aaab","(?=(a+?))(\\1ab)","juOk\\1gipUr\\1Rp\\1Qi&v",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(?=(a+?))\\1ab","g\\1\\1\\1v",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(?=(a+?))\\1ab","g\\1\\1\\1v",[global])),
+?line <<"aaab">> = iolist_to_binary(re:replace("aaab","^(?=(a+?))\\1ab","dj\\1E&",[])),
+?line <<"aaab">> = iolist_to_binary(re:replace("aaab","^(?=(a+?))\\1ab","dj\\1E&",[global])),
+?line <<"aaab">> = iolist_to_binary(re:replace("aaab","^(?=(a+?))\\1ab","\\1UllJHtwTvaUdSmur",[])),
+?line <<"aaab">> = iolist_to_binary(re:replace("aaab","^(?=(a+?))\\1ab","\\1UllJHtwTvaUdSmur",[global])),
+?line <<"juabcdvJAqaNxcabcdrDs">> = iolist_to_binary(re:replace("abcd","([\\w:]+::)?(\\w+)$","ju&vJAqaNxc&rDs\\1",[])),
+?line <<"juabcdvJAqaNxcabcdrDs">> = iolist_to_binary(re:replace("abcd","([\\w:]+::)?(\\w+)$","ju&vJAqaNxc&rDs\\1",[global])),
+?line <<"unOWEMklEbRjSO">> = iolist_to_binary(re:replace("xy:z:::abcd","([\\w:]+::)?(\\w+)$","unOWEMklEbRjSO",[])),
+?line <<"unOWEMklEbRjSO">> = iolist_to_binary(re:replace("xy:z:::abcd","([\\w:]+::)?(\\w+)$","unOWEMklEbRjSO",[global])),
+?line <<"nGqSeaexycfAmCxmxEaexycd">> = iolist_to_binary(re:replace("aexycd","^[^bcd]*(c+)","nGqSe&fAmCxmxE&",[])),
+?line <<"nGqSeaexycfAmCxmxEaexycd">> = iolist_to_binary(re:replace("aexycd","^[^bcd]*(c+)","nGqSe&fAmCxmxE&",[global])),
+?line <<"cwK">> = iolist_to_binary(re:replace("caab","(a*)b+","wK",[])),
+?line <<"cwK">> = iolist_to_binary(re:replace("caab","(a*)b+","wK",[global])),
+?line <<"VKunDTpabcd">> = iolist_to_binary(re:replace("abcd","([\\w:]+::)?(\\w+)$","VKunD\\1Tp&",[])),
+?line <<"VKunDTpabcd">> = iolist_to_binary(re:replace("abcd","([\\w:]+::)?(\\w+)$","VKunD\\1Tp&",[global])),
+?line <<"xy:z:::SXxy:z:::cMHreuKxy:z:::">> = iolist_to_binary(re:replace("xy:z:::abcd","([\\w:]+::)?(\\w+)$","\\1SX\\1cMHreuK\\1",[])),
+?line <<"xy:z:::SXxy:z:::cMHreuKxy:z:::">> = iolist_to_binary(re:replace("xy:z:::abcd","([\\w:]+::)?(\\w+)$","\\1SX\\1cMHreuK\\1",[global])),
+?line <<"*** FhLAjVJbYFailersvFailersQgrO">> = iolist_to_binary(re:replace("*** Failers","([\\w:]+::)?(\\w+)$","FhLAjVJbY&v&QgrO\\1\\1",[])),
+?line <<"*** FhLAjVJbYFailersvFailersQgrO">> = iolist_to_binary(re:replace("*** Failers","([\\w:]+::)?(\\w+)$","FhLAjVJbY&v&QgrO\\1\\1",[global])),
+?line <<"abcd:">> = iolist_to_binary(re:replace("abcd:","([\\w:]+::)?(\\w+)$","cwV&UpGIKN",[])),
+?line <<"abcd:">> = iolist_to_binary(re:replace("abcd:","([\\w:]+::)?(\\w+)$","cwV&UpGIKN",[global])),
+?line <<"abcd:">> = iolist_to_binary(re:replace("abcd:","([\\w:]+::)?(\\w+)$","S",[])),
+?line <<"abcd:">> = iolist_to_binary(re:replace("abcd:","([\\w:]+::)?(\\w+)$","S",[global])),
+?line <<"Fd">> = iolist_to_binary(re:replace("aexycd","^[^bcd]*(c+)","F",[])),
+?line <<"Fd">> = iolist_to_binary(re:replace("aexycd","^[^bcd]*(c+)","F",[global])),
+?line <<"jBpBHQR">> = iolist_to_binary(re:replace("aaab","(?>a+)b","jBpBHQR",[])),
+?line <<"jBpBHQR">> = iolist_to_binary(re:replace("aaab","(?>a+)b","jBpBHQR",[global])),
+?line <<"a:[J:[:[UyJMIwrPUq:[b]:">> = iolist_to_binary(re:replace("a:[b]:","([[:]+)","\\1J&\\1UyJMIwrPUq\\1",[])),
+?line <<"a:[J:[:[UyJMIwrPUq:[b]:J::UyJMIwrPUq:">> = iolist_to_binary(re:replace("a:[b]:","([[:]+)","\\1J&\\1UyJMIwrPUq\\1",[global])),
+?line <<"asI=[vo=[d=[Y=[nMpb]=">> = iolist_to_binary(re:replace("a=[b]=","([[=]+)","sI\\1vo\\1d\\1Y&nMp",[])),
+?line <<"asI=[vo=[d=[Y=[nMpb]sI=vo=d=Y=nMp">> = iolist_to_binary(re:replace("a=[b]=","([[=]+)","sI\\1vo\\1d\\1Y&nMp",[global])),
+?line <<"aChCrrVW.[ed.[eo.[h.[SYkIb].">> = iolist_to_binary(re:replace("a.[b].","([[.]+)","ChCrrVW\\1ed&eo\\1h\\1SYkI",[])),
+?line <<"aChCrrVW.[ed.[eo.[h.[SYkIb]ChCrrVW.ed.eo.h.SYkI">> = iolist_to_binary(re:replace("a.[b].","([[.]+)","ChCrrVW\\1ed&eo\\1h\\1SYkI",[global])),
+?line <<"BaaabaaabGBaaabJDn">> = iolist_to_binary(re:replace("aaab","((?>a+)b)","B&\\1GB&JDn",[])),
+?line <<"BaaabaaabGBaaabJDn">> = iolist_to_binary(re:replace("aaab","((?>a+)b)","B&\\1GB&JDn",[global])),
+?line <<"kaaabsaaXdPWUBV">> = iolist_to_binary(re:replace("aaab","(?>(a+))b","k&saaXdPWUBV",[])),
+?line <<"kaaabsaaXdPWUBV">> = iolist_to_binary(re:replace("aaab","(?>(a+))b","k&saaXdPWUBV",[global])),
+?line <<"((xpOHCg">> = iolist_to_binary(re:replace("((abc(ade)ufh()()x","((?>[^()]+)|\\([^()]*\\))+","\\1pOHCg",[])),
+?line <<"((xpOHCg">> = iolist_to_binary(re:replace("((abc(ade)ufh()()x","((?>[^()]+)|\\([^()]*\\))+","\\1pOHCg",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","a\\Z","swCtIfMPh&\\1Yr",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","a\\Z","swCtIfMPh&\\1Yr",[global])),
+?line <<"aaab">> = iolist_to_binary(re:replace("aaab","a\\Z","ysA\\1",[])),
+?line <<"aaab">> = iolist_to_binary(re:replace("aaab","a\\Z","ysA\\1",[global])),
+?line <<"a
+b">> = iolist_to_binary(re:replace("a
+b","a\\Z","&ajAlqYVsnk",[])),
+?line <<"a
+b">> = iolist_to_binary(re:replace("a
+b","a\\Z","&ajAlqYVsnk",[global])),
+?line <<"a
+lKbbBrmbgrOVeW">> = iolist_to_binary(re:replace("a
+b","b\\Z","l\\1Kb&Brm&gr\\1OVeW",[])),
+?line <<"a
+lKbbBrmbgrOVeW">> = iolist_to_binary(re:replace("a
+b","b\\Z","l\\1Kb&Brm&gr\\1OVeW",[global])),
+?line <<"a
+gnI">> = iolist_to_binary(re:replace("a
+b","b\\Z","g\\1nI",[])),
+?line <<"a
+gnI">> = iolist_to_binary(re:replace("a
+b","b\\Z","g\\1nI",[global])),
+?line <<"a
+bcbdqlbVGu">> = iolist_to_binary(re:replace("a
+b","b\\z","bc&dql&VGu\\1",[])),
+?line <<"a
+bcbdqlbVGu">> = iolist_to_binary(re:replace("a
+b","b\\z","bc&dql&VGu\\1",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","b\\z","e\\1yg",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","b\\z","e\\1yg",[global])),
+?line <<"ad">> = iolist_to_binary(re:replace("a","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","&d",[])),
+?line <<"ad">> = iolist_to_binary(re:replace("a","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","&d",[global])),
+?line <<"Aq">> = iolist_to_binary(re:replace("abc","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","Aq",[])),
+?line <<"Aq">> = iolist_to_binary(re:replace("abc","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","Aq",[global])),
+?line <<"ca-ba-bhLfWdPLa-boe">> = iolist_to_binary(re:replace("a-b","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","c&&hLfWdPL&oe",[])),
+?line <<"ca-ba-bhLfWdPLa-boe">> = iolist_to_binary(re:replace("a-b","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","c&&hLfWdPL&oe",[global])),
+?line <<"0-90-9YeqrpXMpBjK">> = iolist_to_binary(re:replace("0-9","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","&\\1&YeqrpXMpBjK",[])),
+?line <<"0-90-9YeqrpXMpBjK">> = iolist_to_binary(re:replace("0-9","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","&\\1&YeqrpXMpBjK",[global])),
+?line <<"fa.bPwKXcUgqjJm">> = iolist_to_binary(re:replace("a.b","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","\\1f&PwKX\\1cUgqjJm",[])),
+?line <<"fa.bPwKXcUgqjJm">> = iolist_to_binary(re:replace("a.b","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","\\1f&PwKX\\1cUgqjJm",[global])),
+?line <<"um5.6.7cFpS">> = iolist_to_binary(re:replace("5.6.7","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","um&cFpS\\1",[])),
+?line <<"um5.6.7cFpS">> = iolist_to_binary(re:replace("5.6.7","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","um&cFpS\\1",[global])),
+?line <<"xqtEI">> = iolist_to_binary(re:replace("the.quick.brown.fox","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","xqtEI",[])),
+?line <<"xqtEI">> = iolist_to_binary(re:replace("the.quick.brown.fox","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","xqtEI",[global])),
+?line <<"sga100.b200.300cdqqwa100.b200.300cqSJINVa100.b200.300cOyeI">> = iolist_to_binary(re:replace("a100.b200.300c","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","sg&dqqw&qSJINV&OyeI",[])),
+?line <<"sga100.b200.300cdqqwa100.b200.300cqSJINVa100.b200.300cOyeI">> = iolist_to_binary(re:replace("a100.b200.300c","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","sg&dqqw&qSJINV&OyeI",[global])),
+?line <<"rabe12-ab.1245NInvoPCLW12-ab.1245">> = iolist_to_binary(re:replace("12-ab.1245","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","rabe&NI\\1nvo\\1PCLW&",[])),
+?line <<"rabe12-ab.1245NInvoPCLW12-ab.1245">> = iolist_to_binary(re:replace("12-ab.1245","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","rabe&NI\\1nvo\\1PCLW&",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","jhvaoUW\\1Wye\\1Qkrj",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","jhvaoUW\\1Wye\\1Qkrj",[global])),
+?line <<"">> = iolist_to_binary(re:replace("","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","Q&L\\1qk&QWuvQ\\1o",[])),
+?line <<"">> = iolist_to_binary(re:replace("","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","Q&L\\1qk&QWuvQ\\1o",[global])),
+?line <<".a">> = iolist_to_binary(re:replace(".a","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","j&I&\\1&myXAKjyO&Mw",[])),
+?line <<".a">> = iolist_to_binary(re:replace(".a","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","j&I&\\1&myXAKjyO&Mw",[global])),
+?line <<"-a">> = iolist_to_binary(re:replace("-a","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","yyHkNcANJB",[])),
+?line <<"-a">> = iolist_to_binary(re:replace("-a","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","yyHkNcANJB",[global])),
+?line <<"a-">> = iolist_to_binary(re:replace("a-","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","&\\1tGDVOXc&&\\1aF\\1",[])),
+?line <<"a-">> = iolist_to_binary(re:replace("a-","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","&\\1tGDVOXc&&\\1aF\\1",[global])),
+?line <<"a.">> = iolist_to_binary(re:replace("a.","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","\\1\\1PTJg\\1\\1x",[])),
+?line <<"a.">> = iolist_to_binary(re:replace("a.","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","\\1\\1PTJg\\1\\1x",[global])),
+?line <<"a_b">> = iolist_to_binary(re:replace("a_b","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","w&",[])),
+?line <<"a_b">> = iolist_to_binary(re:replace("a_b","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","w&",[global])),
+?line <<"a.-">> = iolist_to_binary(re:replace("a.-","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","EYTDvAw&\\1hAJjtxh",[])),
+?line <<"a.-">> = iolist_to_binary(re:replace("a.-","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","EYTDvAw&\\1hAJjtxh",[global])),
+?line <<"a..">> = iolist_to_binary(re:replace("a..","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","v&",[])),
+?line <<"a..">> = iolist_to_binary(re:replace("a..","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","v&",[global])),
+?line <<"ab..bc">> = iolist_to_binary(re:replace("ab..bc","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","xi\\1TmyKwF&sc",[])),
+?line <<"ab..bc">> = iolist_to_binary(re:replace("ab..bc","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","xi\\1TmyKwF&sc",[global])),
+?line <<"the.quick.brown.fox-">> = iolist_to_binary(re:replace("the.quick.brown.fox-","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","qbJylT\\1",[])),
+?line <<"the.quick.brown.fox-">> = iolist_to_binary(re:replace("the.quick.brown.fox-","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","qbJylT\\1",[global])),
+?line <<"the.quick.brown.fox.">> = iolist_to_binary(re:replace("the.quick.brown.fox.","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","P&\\1dGVbFGwNJ",[])),
+?line <<"the.quick.brown.fox.">> = iolist_to_binary(re:replace("the.quick.brown.fox.","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","P&\\1dGVbFGwNJ",[global])),
+?line <<"the.quick.brown.fox_">> = iolist_to_binary(re:replace("the.quick.brown.fox_","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","V&e",[])),
+?line <<"the.quick.brown.fox_">> = iolist_to_binary(re:replace("the.quick.brown.fox_","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","V&e",[global])),
+?line <<"the.quick.brown.fox+">> = iolist_to_binary(re:replace("the.quick.brown.fox+","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","\\1",[])),
+?line <<"the.quick.brown.fox+">> = iolist_to_binary(re:replace("the.quick.brown.fox+","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$","\\1",[global])),
+?line <<"alphabetabcdlJabcdabcdabcdWqGabcd">> = iolist_to_binary(re:replace("alphabetabcd","(?>.*)(?<=(abcd|wxyz))","&lJ\\1\\1\\1WqG\\1",[])),
+?line <<"alphabetabcdlJabcdabcdabcdWqGabcdlJabcdabcdabcdWqGabcd">> = iolist_to_binary(re:replace("alphabetabcd","(?>.*)(?<=(abcd|wxyz))","&lJ\\1\\1\\1WqG\\1",[global])),
+?line <<"Q">> = iolist_to_binary(re:replace("endingwxyz","(?>.*)(?<=(abcd|wxyz))","Q",[])),
+?line <<"QQ">> = iolist_to_binary(re:replace("endingwxyz","(?>.*)(?<=(abcd|wxyz))","Q",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?>.*)(?<=(abcd|wxyz))","qTAxLBxW",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?>.*)(?<=(abcd|wxyz))","qTAxLBxW",[global])),
+?line <<"a rather long string that doesn't end with one of them">> = iolist_to_binary(re:replace("a rather long string that doesn't end with one of them","(?>.*)(?<=(abcd|wxyz))","HY\\1",[])),
+?line <<"a rather long string that doesn't end with one of them">> = iolist_to_binary(re:replace("a rather long string that doesn't end with one of them","(?>.*)(?<=(abcd|wxyz))","HY\\1",[global])),
+?line <<"KxMJnKmSMrA">> = iolist_to_binary(re:replace("word cat dog elephant mussel cow horse canary baboon snake shark otherword","word (?>(?:(?!otherword)[a-zA-Z0-9]+ ){0,30})otherword","\\1KxMJnKmSMrA",[])),
+?line <<"KxMJnKmSMrA">> = iolist_to_binary(re:replace("word cat dog elephant mussel cow horse canary baboon snake shark otherword","word (?>(?:(?!otherword)[a-zA-Z0-9]+ ){0,30})otherword","\\1KxMJnKmSMrA",[global])),
+?line <<"word cat dog elephant mussel cow horse canary baboon snake shark">> = iolist_to_binary(re:replace("word cat dog elephant mussel cow horse canary baboon snake shark","word (?>(?:(?!otherword)[a-zA-Z0-9]+ ){0,30})otherword","TgCuE\\1Jnjdu",[])),
+?line <<"word cat dog elephant mussel cow horse canary baboon snake shark">> = iolist_to_binary(re:replace("word cat dog elephant mussel cow horse canary baboon snake shark","word (?>(?:(?!otherword)[a-zA-Z0-9]+ ){0,30})otherword","TgCuE\\1Jnjdu",[global])),
+?line <<"word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope">> = iolist_to_binary(re:replace("word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope","word (?>[a-zA-Z0-9]+ ){0,30}otherword","HJa&S&CWDAtFOINp\\1a",[])),
+?line <<"word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope">> = iolist_to_binary(re:replace("word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope","word (?>[a-zA-Z0-9]+ ){0,30}otherword","HJa&S&CWDAtFOINp\\1a",[global])),
+?line <<"999GSL">> = iolist_to_binary(re:replace("999foo","(?<=\\d{3}(?!999))foo","GSL",[])),
+?line <<"999GSL">> = iolist_to_binary(re:replace("999foo","(?<=\\d{3}(?!999))foo","GSL",[global])),
+?line <<"123999Lxthrb">> = iolist_to_binary(re:replace("123999foo","(?<=\\d{3}(?!999))foo","Lxthrb",[])),
+?line <<"123999Lxthrb">> = iolist_to_binary(re:replace("123999foo","(?<=\\d{3}(?!999))foo","Lxthrb",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?<=\\d{3}(?!999))foo","K&j&h&\\1&&&nJDCN",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?<=\\d{3}(?!999))foo","K&j&h&\\1&&&nJDCN",[global])),
+?line <<"123abcfoo">> = iolist_to_binary(re:replace("123abcfoo","(?<=\\d{3}(?!999))foo","Y&X\\1Oe",[])),
+?line <<"123abcfoo">> = iolist_to_binary(re:replace("123abcfoo","(?<=\\d{3}(?!999))foo","Y&X\\1Oe",[global])),
+?line <<"999lwxfoov">> = iolist_to_binary(re:replace("999foo","(?<=(?!...999)\\d{3})foo","lwx&v",[])),
+?line <<"999lwxfoov">> = iolist_to_binary(re:replace("999foo","(?<=(?!...999)\\d{3})foo","lwx&v",[global])),
+?line <<"123999MgNvfoofooIVfoo">> = iolist_to_binary(re:replace("123999foo","(?<=(?!...999)\\d{3})foo","MgNv\\1&&IV&",[])),
+?line <<"123999MgNvfoofooIVfoo">> = iolist_to_binary(re:replace("123999foo","(?<=(?!...999)\\d{3})foo","MgNv\\1&&IV&",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?<=(?!...999)\\d{3})foo","Iv&\\1uOjnSDBEaj",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?<=(?!...999)\\d{3})foo","Iv&\\1uOjnSDBEaj",[global])),
+?line <<"123abcfoo">> = iolist_to_binary(re:replace("123abcfoo","(?<=(?!...999)\\d{3})foo","sanP",[])),
+?line <<"123abcfoo">> = iolist_to_binary(re:replace("123abcfoo","(?<=(?!...999)\\d{3})foo","sanP",[global])),
+?line <<"123abclcAPWfoouwtMfoofDv">> = iolist_to_binary(re:replace("123abcfoo","(?<=\\d{3}(?!999)...)foo","lcAPW&uwtM&fDv",[])),
+?line <<"123abclcAPWfoouwtMfoofDv">> = iolist_to_binary(re:replace("123abcfoo","(?<=\\d{3}(?!999)...)foo","lcAPW&uwtM&fDv",[global])),
+?line <<"123456nRFsuNto">> = iolist_to_binary(re:replace("123456foo","(?<=\\d{3}(?!999)...)foo","nR\\1FsuNto",[])),
+?line <<"123456nRFsuNto">> = iolist_to_binary(re:replace("123456foo","(?<=\\d{3}(?!999)...)foo","nR\\1FsuNto",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?<=\\d{3}(?!999)...)foo","P&",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?<=\\d{3}(?!999)...)foo","P&",[global])),
+?line <<"123999foo">> = iolist_to_binary(re:replace("123999foo","(?<=\\d{3}(?!999)...)foo","BdprjW\\1hk\\1K\\1",[])),
+?line <<"123999foo">> = iolist_to_binary(re:replace("123999foo","(?<=\\d{3}(?!999)...)foo","BdprjW\\1hk\\1K\\1",[global])),
+?line <<"123abcCB">> = iolist_to_binary(re:replace("123abcfoo","(?<=\\d{3}...)(?<!999)foo","CB",[])),
+?line <<"123abcCB">> = iolist_to_binary(re:replace("123abcfoo","(?<=\\d{3}...)(?<!999)foo","CB",[global])),
+?line <<"123456g">> = iolist_to_binary(re:replace("123456foo","(?<=\\d{3}...)(?<!999)foo","g",[])),
+?line <<"123456g">> = iolist_to_binary(re:replace("123456foo","(?<=\\d{3}...)(?<!999)foo","g",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?<=\\d{3}...)(?<!999)foo","\\1R&",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?<=\\d{3}...)(?<!999)foo","\\1R&",[global])),
+?line <<"123999foo">> = iolist_to_binary(re:replace("123999foo","(?<=\\d{3}...)(?<!999)foo","bh&&&M",[])),
+?line <<"123999foo">> = iolist_to_binary(re:replace("123999foo","(?<=\\d{3}...)(?<!999)foo","bh&&&M",[global])),
+?line <<"E<a href=abcd<a href=abcdTofh xyz">> = iolist_to_binary(re:replace("<a href=abcd xyz","<a[\\s]+href[\\s]*=[\\s]* # find <a href=
+ ([\\\"\\'])? # find single or double quote
+ (?(1) (.*?)\\1 | ([^\\s]+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space","E&&Tofh",[caseless,
+ dotall,
+ extended])),
+?line <<"E<a href=abcd<a href=abcdTofh xyz">> = iolist_to_binary(re:replace("<a href=abcd xyz","<a[\\s]+href[\\s]*=[\\s]* # find <a href=
+ ([\\\"\\'])? # find single or double quote
+ (?(1) (.*?)\\1 | ([^\\s]+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space","E&&Tofh",[caseless,
+ dotall,
+ extended,
+ global])),
+?line <<"<a href=\"abcd xyz pqr\"Y\"ylaR<a href=\"abcd xyz pqr\"bd cats">> = iolist_to_binary(re:replace("<a href=\"abcd xyz pqr\" cats","<a[\\s]+href[\\s]*=[\\s]* # find <a href=
+ ([\\\"\\'])? # find single or double quote
+ (?(1) (.*?)\\1 | ([^\\s]+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space","&Y\\1ylaR&bd",[caseless,
+ dotall,
+ extended])),
+?line <<"<a href=\"abcd xyz pqr\"Y\"ylaR<a href=\"abcd xyz pqr\"bd cats">> = iolist_to_binary(re:replace("<a href=\"abcd xyz pqr\" cats","<a[\\s]+href[\\s]*=[\\s]* # find <a href=
+ ([\\\"\\'])? # find single or double quote
+ (?(1) (.*?)\\1 | ([^\\s]+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space","&Y\\1ylaR&bd",[caseless,
+ dotall,
+ extended,
+ global])),
+?line <<"CdADwL<a href='abcd xyz pqr'b'a'' cats">> = iolist_to_binary(re:replace("<a href='abcd xyz pqr' cats","<a[\\s]+href[\\s]*=[\\s]* # find <a href=
+ ([\\\"\\'])? # find single or double quote
+ (?(1) (.*?)\\1 | ([^\\s]+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space","CdADwL&b\\1a\\1\\1",[caseless,
+ dotall,
+ extended])),
+?line <<"CdADwL<a href='abcd xyz pqr'b'a'' cats">> = iolist_to_binary(re:replace("<a href='abcd xyz pqr' cats","<a[\\s]+href[\\s]*=[\\s]* # find <a href=
+ ([\\\"\\'])? # find single or double quote
+ (?(1) (.*?)\\1 | ([^\\s]+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space","CdADwL&b\\1a\\1\\1",[caseless,
+ dotall,
+ extended,
+ global])),
+?line <<"IAfhYumoIpB xyz">> = iolist_to_binary(re:replace("<a href=abcd xyz","<a\\s+href\\s*=\\s* # find <a href=
+ ([\"'])? # find single or double quote
+ (?(1) (.*?)\\1 | (\\S+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space","\\1\\1IAfhYumoIpB\\1",[caseless,
+ dotall,
+ extended])),
+?line <<"IAfhYumoIpB xyz">> = iolist_to_binary(re:replace("<a href=abcd xyz","<a\\s+href\\s*=\\s* # find <a href=
+ ([\"'])? # find single or double quote
+ (?(1) (.*?)\\1 | (\\S+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space","\\1\\1IAfhYumoIpB\\1",[caseless,
+ dotall,
+ extended,
+ global])),
+?line <<"xrs<a href=\"abcd xyz pqr\"\"tWWeQ\"K<a href=\"abcd xyz pqr\"LjVA\"<a href=\"abcd xyz pqr\" cats">> = iolist_to_binary(re:replace("<a href=\"abcd xyz pqr\" cats","<a\\s+href\\s*=\\s* # find <a href=
+ ([\"'])? # find single or double quote
+ (?(1) (.*?)\\1 | (\\S+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space","xrs&\\1tWWeQ\\1K&LjVA\\1&",[caseless,
+ dotall,
+ extended])),
+?line <<"xrs<a href=\"abcd xyz pqr\"\"tWWeQ\"K<a href=\"abcd xyz pqr\"LjVA\"<a href=\"abcd xyz pqr\" cats">> = iolist_to_binary(re:replace("<a href=\"abcd xyz pqr\" cats","<a\\s+href\\s*=\\s* # find <a href=
+ ([\"'])? # find single or double quote
+ (?(1) (.*?)\\1 | (\\S+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space","xrs&\\1tWWeQ\\1K&LjVA\\1&",[caseless,
+ dotall,
+ extended,
+ global])),
+?line <<"QmbmFDyYfP cats">> = iolist_to_binary(re:replace("<a href = 'abcd xyz pqr' cats","<a\\s+href\\s*=\\s* # find <a href=
+ ([\"'])? # find single or double quote
+ (?(1) (.*?)\\1 | (\\S+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space","QmbmFDyYfP",[caseless,
+ dotall,
+ extended])),
+?line <<"QmbmFDyYfP cats">> = iolist_to_binary(re:replace("<a href = 'abcd xyz pqr' cats","<a\\s+href\\s*=\\s* # find <a href=
+ ([\"'])? # find single or double quote
+ (?(1) (.*?)\\1 | (\\S+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space","QmbmFDyYfP",[caseless,
+ dotall,
+ extended,
+ global])),
+?line <<"EokGsdLETK xyz">> = iolist_to_binary(re:replace("<a href=abcd xyz","<a\\s+href(?>\\s*)=(?>\\s*) # find <a href=
+ ([\"'])? # find single or double quote
+ (?(1) (.*?)\\1 | (\\S+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space","E\\1okGsdLETK",[caseless,
+ dotall,
+ extended])),
+?line <<"EokGsdLETK xyz">> = iolist_to_binary(re:replace("<a href=abcd xyz","<a\\s+href(?>\\s*)=(?>\\s*) # find <a href=
+ ([\"'])? # find single or double quote
+ (?(1) (.*?)\\1 | (\\S+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space","E\\1okGsdLETK",[caseless,
+ dotall,
+ extended,
+ global])),
+?line <<"gy cats">> = iolist_to_binary(re:replace("<a href=\"abcd xyz pqr\" cats","<a\\s+href(?>\\s*)=(?>\\s*) # find <a href=
+ ([\"'])? # find single or double quote
+ (?(1) (.*?)\\1 | (\\S+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space","gy",[caseless,
+ dotall,
+ extended])),
+?line <<"gy cats">> = iolist_to_binary(re:replace("<a href=\"abcd xyz pqr\" cats","<a\\s+href(?>\\s*)=(?>\\s*) # find <a href=
+ ([\"'])? # find single or double quote
+ (?(1) (.*?)\\1 | (\\S+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space","gy",[caseless,
+ dotall,
+ extended,
+ global])),
+?line <<"i cats">> = iolist_to_binary(re:replace("<a href = 'abcd xyz pqr' cats","<a\\s+href(?>\\s*)=(?>\\s*) # find <a href=
+ ([\"'])? # find single or double quote
+ (?(1) (.*?)\\1 | (\\S+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space","i",[caseless,
+ dotall,
+ extended])),
+?line <<"i cats">> = iolist_to_binary(re:replace("<a href = 'abcd xyz pqr' cats","<a\\s+href(?>\\s*)=(?>\\s*) # find <a href=
+ ([\"'])? # find single or double quote
+ (?(1) (.*?)\\1 | (\\S+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space","i",[caseless,
+ dotall,
+ extended,
+ global])),
+?line <<"EZADCywAYhLBCDEFG">> = iolist_to_binary(re:replace("ZABCDEFG","((Z)+|A)*","E&DCywAYhL",[])),
+?line <<"EZADCywAYhLEDCywAYhLBEDCywAYhLCEDCywAYhLDEDCywAYhLEEDCywAYhLFEDCywAYhLGEDCywAYhL">> = iolist_to_binary(re:replace("ZABCDEFG","((Z)+|A)*","E&DCywAYhL",[global])),
+?line <<"nyATkLcbFTgYpAunmMXBCDEFG">> = iolist_to_binary(re:replace("ZABCDEFG","(Z()|A)*","ny\\1TkLcbFTgYp\\1unmMX",[])),
+?line <<"nyATkLcbFTgYpAunmMXnyTkLcbFTgYpunmMXBnyTkLcbFTgYpunmMXCnyTkLcbFTgYpunmMXDnyTkLcbFTgYpunmMXEnyTkLcbFTgYpunmMXFnyTkLcbFTgYpunmMXGnyTkLcbFTgYpunmMX">> = iolist_to_binary(re:replace("ZABCDEFG","(Z()|A)*","ny\\1TkLcbFTgYp\\1unmMX",[global])),
+?line <<"YiJonwVPQAqACHABCDEFG">> = iolist_to_binary(re:replace("ZABCDEFG","(Z(())|A)*","YiJonwVPQ\\1q\\1CH\\1",[])),
+?line <<"YiJonwVPQAqACHAYiJonwVPQqCHBYiJonwVPQqCHCYiJonwVPQqCHDYiJonwVPQqCHEYiJonwVPQqCHFYiJonwVPQqCHGYiJonwVPQqCH">> = iolist_to_binary(re:replace("ZABCDEFG","(Z(())|A)*","YiJonwVPQ\\1q\\1CH\\1",[global])),
+?line <<"bZAEAXcNeNwfBCDEFG">> = iolist_to_binary(re:replace("ZABCDEFG","((?>Z)+|A)*","b&E\\1XcNeNwf",[])),
+?line <<"bZAEAXcNeNwfbEXcNeNwfBbEXcNeNwfCbEXcNeNwfDbEXcNeNwfEbEXcNeNwfFbEXcNeNwfGbEXcNeNwf">> = iolist_to_binary(re:replace("ZABCDEFG","((?>Z)+|A)*","b&E\\1XcNeNwf",[global])),
+?line <<"UeIRbNvamSaniIQYPZABCDEFG">> = iolist_to_binary(re:replace("ZABCDEFG","((?>)+|A)*","UeIRbNv&amSaniIQYP",[])),
+?line <<"UeIRbNvamSaniIQYPZUeIRbNvamSaniIQYPUeIRbNvAamSaniIQYPUeIRbNvamSaniIQYPBUeIRbNvamSaniIQYPCUeIRbNvamSaniIQYPDUeIRbNvamSaniIQYPEUeIRbNvamSaniIQYPFUeIRbNvamSaniIQYPGUeIRbNvamSaniIQYP">> = iolist_to_binary(re:replace("ZABCDEFG","((?>)+|A)*","UeIRbNv&amSaniIQYP",[global])),
+?line <<"AnyTcLbbab">> = iolist_to_binary(re:replace("abbab","a*","AnyTcL",[])),
+?line <<"AnyTcLAnyTcLbAnyTcLbAnyTcLAnyTcLbAnyTcL">> = iolist_to_binary(re:replace("abbab","a*","AnyTcL",[global])),
+?line <<"EfoRdQVibcde">> = iolist_to_binary(re:replace("abcde","^[a-\\d]","EfoRdQVi",[])),
+?line <<"EfoRdQVibcde">> = iolist_to_binary(re:replace("abcde","^[a-\\d]","EfoRdQVi",[global])),
+?line <<"cCcyoUi-GT--drpjthings">> = iolist_to_binary(re:replace("-things","^[a-\\d]","cCcy\\1o\\1Ui&GT&&drpj",[])),
+?line <<"cCcyoUi-GT--drpjthings">> = iolist_to_binary(re:replace("-things","^[a-\\d]","cCcy\\1o\\1Ui&GT&&drpj",[global])),
+?line <<"eddigit">> = iolist_to_binary(re:replace("0digit","^[a-\\d]","ed",[])),
+?line <<"eddigit">> = iolist_to_binary(re:replace("0digit","^[a-\\d]","ed",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^[a-\\d]","\\1wCjwyJQB&COO&&Vyp\\1M",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^[a-\\d]","\\1wCjwyJQB&COO&&Vyp\\1M",[global])),
+?line <<"bcdef">> = iolist_to_binary(re:replace("bcdef","^[a-\\d]","EofOaus",[])),
+?line <<"bcdef">> = iolist_to_binary(re:replace("bcdef","^[a-\\d]","EofOaus",[global])),
+?line <<"kpGVaTiadJVwJbcde">> = iolist_to_binary(re:replace("abcde","^[\\d-a]","kpG\\1V&Ti&dJVwJ",[])),
+?line <<"kpGVaTiadJVwJbcde">> = iolist_to_binary(re:replace("abcde","^[\\d-a]","kpG\\1V&Ti&dJVwJ",[global])),
+?line <<"Chuymdqthings">> = iolist_to_binary(re:replace("-things","^[\\d-a]","Chu\\1ymdq",[])),
+?line <<"Chuymdqthings">> = iolist_to_binary(re:replace("-things","^[\\d-a]","Chu\\1ymdq",[global])),
+?line <<"TpWPVwVtHJWAdigit">> = iolist_to_binary(re:replace("0digit","^[\\d-a]","TpWPVwV\\1tHJWA",[])),
+?line <<"TpWPVwVtHJWAdigit">> = iolist_to_binary(re:replace("0digit","^[\\d-a]","TpWPVwV\\1tHJWA",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^[\\d-a]","WYnxbwypPj",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^[\\d-a]","WYnxbwypPj",[global])),
+?line <<"bcdef">> = iolist_to_binary(re:replace("bcdef","^[\\d-a]","bnUSwwhPJ",[])),
+?line <<"bcdef">> = iolist_to_binary(re:replace("bcdef","^[\\d-a]","bnUSwwhPJ",[global])),
+?line <<">mnfN
+ FbS
+ ghxwsq<">> = iolist_to_binary(re:replace(">
+ <","[[:space:]]+","mnfN&FbS\\1&ghxwsq",[])),
+?line <<">mnfN
+ FbS
+ ghxwsq<">> = iolist_to_binary(re:replace(">
+ <","[[:space:]]+","mnfN&FbS\\1&ghxwsq",[global])),
+?line <<">R
+ <">> = iolist_to_binary(re:replace(">
+ <","[[:blank:]]+","R",[])),
+?line <<">R
+ <">> = iolist_to_binary(re:replace(">
+ <","[[:blank:]]+","R",[global])),
+?line <<">PjX
+ <">> = iolist_to_binary(re:replace(">
+ <","[\\s]+","PjX&",[])),
+?line <<">PjX
+ <">> = iolist_to_binary(re:replace(">
+ <","[\\s]+","PjX&",[global])),
+?line <<">EO
+
+ g
+
+ DMTFYSd
+ <">> = iolist_to_binary(re:replace(">
+ <","\\s+","EO&&g&&DMT\\1FY\\1Sd&",[])),
+?line <<">EO
+
+ g
+
+ DMTFYSd
+ <">> = iolist_to_binary(re:replace(">
+ <","\\s+","EO&&g&&DMT\\1FY\\1Sd&",[global])),
+?line <<"ab">> = iolist_to_binary(re:replace("ab","a b","qihC&Vy",[extended])),
+?line <<"ab">> = iolist_to_binary(re:replace("ab","a b","qihC&Vy",[extended,
+ global])),
+?line <<"a
+dxmjb">> = iolist_to_binary(re:replace("a
+xb","(?!\\A)x","dxmj",[multiline])),
+?line <<"a
+dxmjb">> = iolist_to_binary(re:replace("a
+xb","(?!\\A)x","dxmj",[multiline,global])),
+?line <<"a
+xb">> = iolist_to_binary(re:replace("a
+xb","(?!^)x","\\1tysI\\1v\\1BVwx\\1FOWG\\1&C",[multiline])),
+?line <<"a
+xb">> = iolist_to_binary(re:replace("a
+xb","(?!^)x","\\1tysI\\1v\\1BVwx\\1FOWG\\1&C",[multiline,
+ global])),
+?line <<"MYdx">> = iolist_to_binary(re:replace("abcabcabc","abc\\Qabc\\Eabc","MYdx",[])),
+?line <<"MYdx">> = iolist_to_binary(re:replace("abcabcabc","abc\\Qabc\\Eabc","MYdx",[global])),
+?line <<"abc(*+|abc">> = iolist_to_binary(re:replace("abc(*+|abc","abc\\Q(*+|\\Eabc","&",[])),
+?line <<"abc(*+|abc">> = iolist_to_binary(re:replace("abc(*+|abc","abc\\Q(*+|\\Eabc","&",[global])),
+?line <<"abc abcabcbMSm">> = iolist_to_binary(re:replace("abc abcabc"," abc\\Q abc\\Eabc","&bM\\1Sm",[extended])),
+?line <<"abc abcabcbMSm">> = iolist_to_binary(re:replace("abc abcabc"," abc\\Q abc\\Eabc","&bM\\1Sm",[extended,
+ global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers"," abc\\Q abc\\Eabc","X\\1\\1&",[extended])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers"," abc\\Q abc\\Eabc","X\\1\\1&",[extended,
+ global])),
+?line <<"abcabcabc">> = iolist_to_binary(re:replace("abcabcabc"," abc\\Q abc\\Eabc","qbvwJpk",[extended])),
+?line <<"abcabcabc">> = iolist_to_binary(re:replace("abcabcabc"," abc\\Q abc\\Eabc","qbvwJpk",[extended,
+ global])),
+?line <<"UwGaabc#not comment
+ literal">> = iolist_to_binary(re:replace("abc#not comment
+ literal","abc#comment
+ \\Q#not comment
+ literal\\E","UwGa&",[extended])),
+?line <<"UwGaabc#not comment
+ literal">> = iolist_to_binary(re:replace("abc#not comment
+ literal","abc#comment
+ \\Q#not comment
+ literal\\E","UwGa&",[extended,global])),
+?line <<"abc#not comment
+ literalSCWsV">> = iolist_to_binary(re:replace("abc#not comment
+ literal","abc#comment
+ \\Q#not comment
+ literal","&\\1SCWsV",[extended])),
+?line <<"abc#not comment
+ literalSCWsV">> = iolist_to_binary(re:replace("abc#not comment
+ literal","abc#comment
+ \\Q#not comment
+ literal","&\\1SCWsV",[extended,global])),
+?line <<"T">> = iolist_to_binary(re:replace("abc#not comment
+ literal","abc#comment
+ \\Q#not comment
+ literal\\E #more comment
+ ","T",[extended])),
+?line <<"T">> = iolist_to_binary(re:replace("abc#not comment
+ literal","abc#comment
+ \\Q#not comment
+ literal\\E #more comment
+ ","T",[extended,global])),
+?line <<"abc#not comment
+ literalDFMabc#not comment
+ literaliRRuHyq">> = iolist_to_binary(re:replace("abc#not comment
+ literal","abc#comment
+ \\Q#not comment
+ literal\\E #more comment","&DFM&\\1\\1iR\\1RuHy\\1q",[extended])),
+?line <<"abc#not comment
+ literalDFMabc#not comment
+ literaliRRuHyq">> = iolist_to_binary(re:replace("abc#not comment
+ literal","abc#comment
+ \\Q#not comment
+ literal\\E #more comment","&DFM&\\1\\1iR\\1RuHy\\1q",[extended,
+ global])),
+?line <<"DkSX">> = iolist_to_binary(re:replace("abc\\$xyz","\\Qabc\\$xyz\\E","DkSX",[])),
+?line <<"DkSX">> = iolist_to_binary(re:replace("abc\\$xyz","\\Qabc\\$xyz\\E","DkSX",[global])),
+?line <<"EOaWuCabc$xyzeabc$xyzDrvLP">> = iolist_to_binary(re:replace("abc$xyz","\\Qabc\\E\\$\\Qxyz\\E","EOaWuC&e&DrvLP",[])),
+?line <<"EOaWuCabc$xyzeabc$xyzDrvLP">> = iolist_to_binary(re:replace("abc$xyz","\\Qabc\\E\\$\\Qxyz\\E","EOaWuC&e&DrvLP",[global])),
+?line <<"PUGabcRXWXakpQfboabcw">> = iolist_to_binary(re:replace("abc","\\Gabc","P\\1UG&R\\1XWXakpQfbo&w",[])),
+?line <<"PUGabcRXWXakpQfboabcw">> = iolist_to_binary(re:replace("abc","\\Gabc","P\\1UG&R\\1XWXakpQfbo&w",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","\\Gabc","sssS\\1AVaXM&Is&c",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","\\Gabc","sssS\\1AVaXM&Is&c",[global])),
+?line <<"xyzabc">> = iolist_to_binary(re:replace("xyzabc","\\Gabc","r",[])),
+?line <<"xyzabc">> = iolist_to_binary(re:replace("xyzabc","\\Gabc","r",[global])),
+?line <<"tScabc2xyzabc3">> = iolist_to_binary(re:replace("abc1abc2xyzabc3","\\Gabc.","tSc",[])),
+?line <<"tSctScxyzabc3">> = iolist_to_binary(re:replace("abc1abc2xyzabc3","\\Gabc.","tSc",[global])),
+?line <<"HcJuuopHFgbabc2xyzabc3">> = iolist_to_binary(re:replace("abc1abc2xyzabc3","abc.","HcJuuopHFgb",[])),
+?line <<"HcJuuopHFgbHcJuuopHFgbxyzHcJuuopHFgb">> = iolist_to_binary(re:replace("abc1abc2xyzabc3","abc.","HcJuuopHFgb",[global])),
+?line <<"XMSabcdaDVucwrGDirY">> = iolist_to_binary(re:replace("XabcdY","a(?x: b c )d","MS&aDVucwrGDir",[])),
+?line <<"XMSabcdaDVucwrGDirY">> = iolist_to_binary(re:replace("XabcdY","a(?x: b c )d","MS&aDVucwrGDir",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","a(?x: b c )d","paXT\\1iPxaNPv",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","a(?x: b c )d","paXT\\1iPxaNPv",[global])),
+?line <<"Xa b c d Y">> = iolist_to_binary(re:replace("Xa b c d Y","a(?x: b c )d","FRHntJTvUtt&w\\1Mhj",[])),
+?line <<"Xa b c d Y">> = iolist_to_binary(re:replace("Xa b c d Y","a(?x: b c )d","FRHntJTvUtt&w\\1Mhj",[global])),
+?line <<"XabcY">> = iolist_to_binary(re:replace("XabcY","((?x)x y z | a b c)","\\1",[])),
+?line <<"XabcY">> = iolist_to_binary(re:replace("XabcY","((?x)x y z | a b c)","\\1",[global])),
+?line <<"AxyznocmxyzxyzxyzfWlBxyzPEB">> = iolist_to_binary(re:replace("AxyzB","((?x)x y z | a b c)","&nocm\\1&&fWlB&PE",[])),
+?line <<"AxyznocmxyzxyzxyzfWlBxyzPEB">> = iolist_to_binary(re:replace("AxyzB","((?x)x y z | a b c)","&nocm\\1&&fWlB&PE",[global])),
+?line <<"XqabCRwY">> = iolist_to_binary(re:replace("XabCY","(?i)AB(?-i)C","q&Rw",[])),
+?line <<"XqabCRwY">> = iolist_to_binary(re:replace("XabCY","(?i)AB(?-i)C","q&Rw",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?i)AB(?-i)C","b&Qx",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","(?i)AB(?-i)C","b&Qx",[global])),
+?line <<"XabcY">> = iolist_to_binary(re:replace("XabcY","(?i)AB(?-i)C","VjuCQPxKgGiffeGDHugc",[])),
+?line <<"XabcY">> = iolist_to_binary(re:replace("XabcY","(?i)AB(?-i)C","VjuCQPxKgGiffeGDHugc",[global])),
+?line <<"abCEApGxObicabCaHXabCib">> = iolist_to_binary(re:replace("abCE","((?i)AB(?-i)C|D)E","&ApGxObic\\1aHX\\1ib",[])),
+?line <<"abCEApGxObicabCaHXabCib">> = iolist_to_binary(re:replace("abCE","((?i)AB(?-i)C|D)E","&ApGxObic\\1aHX\\1ib",[global])),
+?line <<"uLoeOQwJDEyFGS">> = iolist_to_binary(re:replace("DE","((?i)AB(?-i)C|D)E","uLoeOQwJ&yFGS",[])),
+?line <<"uLoeOQwJDEyFGS">> = iolist_to_binary(re:replace("DE","((?i)AB(?-i)C|D)E","uLoeOQwJ&yFGS",[global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","((?i)AB(?-i)C|D)E","LUuqtYqP\\1RCe",[])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","((?i)AB(?-i)C|D)E","LUuqtYqP\\1RCe",[global])),
+?line <<"abcE">> = iolist_to_binary(re:replace("abcE","((?i)AB(?-i)C|D)E","\\1sXBxu\\1",[])),
+?line <<"abcE">> = iolist_to_binary(re:replace("abcE","((?i)AB(?-i)C|D)E","\\1sXBxu\\1",[global])),
+?line <<"abCe">> = iolist_to_binary(re:replace("abCe","((?i)AB(?-i)C|D)E","Y\\1Rgo\\1Ican\\1",[])),
+?line <<"abCe">> = iolist_to_binary(re:replace("abCe","((?i)AB(?-i)C|D)E","Y\\1Rgo\\1Ican\\1",[global])),
+?line <<"dE">> = iolist_to_binary(re:replace("dE","((?i)AB(?-i)C|D)E","XvslPbYV&&PG",[])),
+?line <<"dE">> = iolist_to_binary(re:replace("dE","((?i)AB(?-i)C|D)E","XvslPbYV&&PG",[global])),
+?line <<"De">> = iolist_to_binary(re:replace("De","((?i)AB(?-i)C|D)E","Ry\\1rxj\\1\\1dTXtld&\\1D&&",[])),
+?line <<"De">> = iolist_to_binary(re:replace("De","((?i)AB(?-i)C|D)E","Ry\\1rxj\\1\\1dTXtld&\\1D&&",[global])),
+?line <<"vyabc">> = iolist_to_binary(re:replace("abc123abc","(.*)\\d+\\1","vy\\1",[])),
+?line <<"vyabc">> = iolist_to_binary(re:replace("abc123abc","(.*)\\d+\\1","vy\\1",[global])),
+?line <<"aLB">> = iolist_to_binary(re:replace("abc123bc","(.*)\\d+\\1","LB",[])),
+?line <<"aLB">> = iolist_to_binary(re:replace("abc123bc","(.*)\\d+\\1","LB",[global])),
+?line <<"HXjXabc123abcabc123abcabc123abcfUay">> = iolist_to_binary(re:replace("abc123abc","(.*)\\d+\\1","HXjX&&&fUay",[dotall])),
+?line <<"HXjXabc123abcabc123abcabc123abcfUay">> = iolist_to_binary(re:replace("abc123abc","(.*)\\d+\\1","HXjX&&&fUay",[dotall,
+ global])),
+?line <<"aCRabcRSbc123bcbcokUUyuMbc123bcm">> = iolist_to_binary(re:replace("abc123bc","(.*)\\d+\\1","CRa\\1RS&\\1okUUyuM&m",[dotall])),
+?line <<"aCRabcRSbc123bcbcokUUyuMbc123bcm">> = iolist_to_binary(re:replace("abc123bc","(.*)\\d+\\1","CRa\\1RS&\\1okUUyuM&m",[dotall,
+ global])),
+?line <<"RvRabcJIYH">> = iolist_to_binary(re:replace("abc123abc","((.*))\\d+\\1","RvR\\1JIYH",[])),
+?line <<"RvRabcJIYH">> = iolist_to_binary(re:replace("abc123abc","((.*))\\d+\\1","RvR\\1JIYH",[global])),
+?line <<"aRbc123bcmb">> = iolist_to_binary(re:replace("abc123bc","((.*))\\d+\\1","R&mb",[])),
+?line <<"aRbc123bcmb">> = iolist_to_binary(re:replace("abc123bc","((.*))\\d+\\1","R&mb",[global])),
+?line <<"ET">> = iolist_to_binary(re:replace("a123::a123","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ","ET",[extended,caseless])),
+?line <<"ET">> = iolist_to_binary(re:replace("a123::a123","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ","ET",[extended,caseless,global])),
+?line <<"nYalhKtcGgINbn">> = iolist_to_binary(re:replace("a123:b342::abcd","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ","nY\\1a\\1lhKtcGgINbn",[extended,caseless])),
+?line <<"nYalhKtcGgINbn">> = iolist_to_binary(re:replace("a123:b342::abcd","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ","nY\\1a\\1lhKtcGgINbn",[extended,caseless,global])),
+?line <<"xeKa123:b342::324e:abcdRvTn">> = iolist_to_binary(re:replace("a123:b342::324e:abcd","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ","xeK&RvTn",[extended,caseless])),
+?line <<"xeKa123:b342::324e:abcdRvTn">> = iolist_to_binary(re:replace("a123:b342::324e:abcd","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ","xeK&RvTn",[extended,caseless,global])),
+?line <<"JHrQJuCtAvAt">> = iolist_to_binary(re:replace("a123:ddde:b342::324e:abcd","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ","JHrQJuCtAvAt",[extended,caseless])),
+?line <<"JHrQJuCtAvAt">> = iolist_to_binary(re:replace("a123:ddde:b342::324e:abcd","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ","JHrQJuCtAvAt",[extended,caseless,global])),
+?line <<"IphCja">> = iolist_to_binary(re:replace("a123:ddde:b342::324e:dcba:abcd","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ","Ip\\1hCj\\1a",[extended,caseless])),
+?line <<"IphCja">> = iolist_to_binary(re:replace("a123:ddde:b342::324e:dcba:abcd","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ","Ip\\1hCj\\1a",[extended,caseless,global])),
+?line <<"xAGmJctxEa123:ddde:9999:b342::324e:dcba:abcdjhClw">> = iolist_to_binary(re:replace("a123:ddde:9999:b342::324e:dcba:abcd","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ","xAGmJctxE&jhClw",[extended,caseless])),
+?line <<"xAGmJctxEa123:ddde:9999:b342::324e:dcba:abcdjhClw">> = iolist_to_binary(re:replace("a123:ddde:9999:b342::324e:dcba:abcd","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ","xAGmJctxE&jhClw",[extended,caseless,global])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ","&jc&",[extended,caseless])),
+?line <<"*** Failers">> = iolist_to_binary(re:replace("*** Failers","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ","&jc&",[extended,caseless,global])),
+?line <<"1:2:3:4:5:6:7:8">> = iolist_to_binary(re:replace("1:2:3:4:5:6:7:8","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ","xjuUU",[extended,caseless])),
+?line <<"1:2:3:4:5:6:7:8">> = iolist_to_binary(re:replace("1:2:3:4:5:6:7:8","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ","xjuUU",[extended,caseless,global])),
+?line <<"a123:bce:ddde:9999:b342::324e:dcba:abcd">> = iolist_to_binary(re:replace("a123:bce:ddde:9999:b342::324e:dcba:abcd","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ","&\\1gJElxfvxu\\1ly",[extended,caseless])),
+?line <<"a123:bce:ddde:9999:b342::324e:dcba:abcd">> = iolist_to_binary(re:replace("a123:bce:ddde:9999:b342::324e:dcba:abcd","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ","&\\1gJElxfvxu\\1ly",[extended,caseless,global])),
+?line <<"a123::9999:b342::324e:dcba:abcd">> = iolist_to_binary(re:replace("a123::9999:b342::324e:dcba:abcd","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ","r",[extended,caseless])),
+?line <<"a123::9999:b342::324e:dcba:abcd">> = iolist_to_binary(re:replace("a123::9999:b342::324e:dcba:abcd","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ","r",[extended,caseless,global])),
+?line <<"abcde:2:3:4:5:6:7:8">> = iolist_to_binary(re:replace("abcde:2:3:4:5:6:7:8","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ","\\1",[extended,caseless])),
+?line <<"abcde:2:3:4:5:6:7:8">> = iolist_to_binary(re:replace("abcde:2:3:4:5:6:7:8","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ","\\1",[extended,caseless,global])),
+?line <<"::1">> = iolist_to_binary(re:replace("::1","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ","ymau\\1\\1NVl\\1WdO\\1",[extended,caseless])),
+?line <<"::1">> = iolist_to_binary(re:replace("::1","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ","ymau\\1\\1NVl\\1WdO\\1",[extended,caseless,global])),
+?line <<"abcd:fee0:123::">> = iolist_to_binary(re:replace("abcd:fee0:123::","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ","KUuIBK&Px&",[extended,caseless])),
+?line <<"abcd:fee0:123::">> = iolist_to_binary(re:replace("abcd:fee0:123::","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ","KUuIBK&Px&",[extended,caseless,global])),
+?line <<":1">> = iolist_to_binary(re:replace(":1","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ","&BwNOmaJ\\1M&\\1TUCr",[extended,caseless])),
+?line <<":1">> = iolist_to_binary(re:replace(":1","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ","&BwNOmaJ\\1M&\\1TUCr",[extended,caseless,global])),
+?line <<"1:">> = iolist_to_binary(re:replace("1:","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ","J\\1e\\1",[extended,caseless])),
+?line <<"1:">> = iolist_to_binary(re:replace("1:","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ","J\\1e\\1",[extended,caseless,global])),
+?line <<"XpmPL">> = iolist_to_binary(re:replace("z","[z\\Qa-d]\\E]","\\1X\\1pmPL",[])),
+?line <<"XpmPL">> = iolist_to_binary(re:replace("z","[z\\Qa-d]\\E]","\\1X\\1pmPL",[global])),
+?line <<"WrMTefTPBbaVhaDwab">> = iolist_to_binary(re:replace("a","[z\\Qa-d]\\E]","WrMTefTPBb&V\\1\\1h&Dwab",[])),
+?line <<"WrMTefTPBbaVhaDwab">> = iolist_to_binary(re:replace("a","[z\\Qa-d]\\E]","WrMTefTPBb&V\\1\\1h&Dwab",[global])),
+?line <<"uFU-rQ-">> = iolist_to_binary(re:replace("-","[z\\Qa-d]\\E]","uFU\\1\\1&rQ&",[])),
+?line <<"uFU-rQ-">> = iolist_to_binary(re:replace("-","[z\\Qa-d]\\E]","uFU\\1\\1&rQ&",[global])),
+?line <<"QliOKMpfH">> = iolist_to_binary(re:replace("d","[z\\Qa-d]\\E]","QliOKMpfH",[])),
+?line <<"QliOKMpfH">> = iolist_to_binary(re:replace("d","[z\\Qa-d]\\E]","QliOKMpfH",[global])),
+?line <<"t]KdBE">> = iolist_to_binary(re:replace("]","[z\\Qa-d]\\E]","t\\1&KdBE",[])),
+?line <<"t]KdBE">> = iolist_to_binary(re:replace("]","[z\\Qa-d]\\E]","t\\1&KdBE",[global])),
+?line <<"*** FNavaiaOJGqPkBilers">> = iolist_to_binary(re:replace("*** Failers","[z\\Qa-d]\\E]","N&v&i\\1&OJGqPkB",[])),
+?line <<"*** FNavaiaOJGqPkBilers">> = iolist_to_binary(re:replace("*** Failers","[z\\Qa-d]\\E]","N&v&i\\1&OJGqPkB",[global])),
+?line <<"b">> = iolist_to_binary(re:replace("b","[z\\Qa-d]\\E]","R&ba",[])),
+?line <<"b">> = iolist_to_binary(re:replace("b","[z\\Qa-d]\\E]","R&ba",[global])),
+?line <<"sjzSKziFAAJiTVWC">> = iolist_to_binary(re:replace("z","[\\z\\C]","sj&SK&iFAAJiTVWC",[])),
+?line <<"sjzSKziFAAJiTVWC">> = iolist_to_binary(re:replace("z","[\\z\\C]","sj&SK&iFAAJiTVWC",[global])),
+?line <<"DDSbIgCmsBKCTmEuitn">> = iolist_to_binary(re:replace("C","[\\z\\C]","D\\1DSbIg&msBK&TmEuitn",[])),
+?line <<"DDSbIgCmsBKCTmEuitn">> = iolist_to_binary(re:replace("C","[\\z\\C]","D\\1DSbIg&msBK&TmEuitn",[global])),
+?line <<"cY">> = iolist_to_binary(re:replace("M","\\M","cY\\1",[])),
+?line <<"cY">> = iolist_to_binary(re:replace("M","\\M","cY\\1",[global])),
+?line <<"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","(a+)*b","yWOTIFhIX\\1H",[])),
+?line <<"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","(a+)*b","yWOTIFhIX\\1H",[global])),
+?line <<"NREGularsRREGularWEYrVRr">> = iolist_to_binary(re:replace("REGular","(?i)reg(?:ul(?:[a�]|ae)r|ex)","N&\\1sR&WEYrVRr",[])),
+?line <<"NREGularsRREGularWEYrVRr">> = iolist_to_binary(re:replace("REGular","(?i)reg(?:ul(?:[a�]|ae)r|ex)","N&\\1sR&WEYrVRr",[global])),
+?line <<"G">> = iolist_to_binary(re:replace("regulaer","(?i)reg(?:ul(?:[a�]|ae)r|ex)","G",[])),
+?line <<"G">> = iolist_to_binary(re:replace("regulaer","(?i)reg(?:ul(?:[a�]|ae)r|ex)","G",[global])),
+?line <<"PSsXtwlmy">> = iolist_to_binary(re:replace("Regex","(?i)reg(?:ul(?:[a�]|ae)r|ex)","PSsXtwlmy",[])),
+?line <<"PSsXtwlmy">> = iolist_to_binary(re:replace("Regex","(?i)reg(?:ul(?:[a�]|ae)r|ex)","PSsXtwlmy",[global])),
+?line <<"regul�rmiYTi">> = iolist_to_binary(re:replace("regul�r","(?i)reg(?:ul(?:[a�]|ae)r|ex)","&miYTi\\1\\1",[])),
+?line <<"regul�rmiYTi">> = iolist_to_binary(re:replace("regul�r","(?i)reg(?:ul(?:[a�]|ae)r|ex)","&miYTi\\1\\1",[global])),
+?line <<"W�����rxh�����yUoaLOIegmSA">> = iolist_to_binary(re:replace("�����","����[�-��-�]+","W&rxh&yUoaL\\1OIegmS\\1A",[])),
+?line <<"W�����rxh�����yUoaLOIegmSA">> = iolist_to_binary(re:replace("�����","����[�-��-�]+","W&rxh&yUoaL\\1OIegmS\\1A",[global])),
+?line <<"F�����gnWPyHeh�����tXTQ">> = iolist_to_binary(re:replace("�����","����[�-��-�]+","F&gnWPyHe\\1h&tXTQ",[])),
+?line <<"F�����gnWPyHeh�����tXTQ">> = iolist_to_binary(re:replace("�����","����[�-��-�]+","F&gnWPyHe\\1h&tXTQ",[global])),
+?line <<"sHerHnAhAdx">> = iolist_to_binary(re:replace("�����","����[�-��-�]+","sHer\\1HnA\\1h\\1Adx",[])),
+?line <<"sHerHnAhAdx">> = iolist_to_binary(re:replace("�����","����[�-��-�]+","sHer\\1HnA\\1h\\1Adx",[global])),
+?line <<"trobAQoU�����n">> = iolist_to_binary(re:replace("�����","����[�-��-�]+","tr\\1obAQoU&n",[])),
+?line <<"trobAQoU�����n">> = iolist_to_binary(re:replace("�����","����[�-��-�]+","tr\\1obAQoU&n",[global])),
+?line <<"�XAZSd">> = iolist_to_binary(re:replace("�XAZXB","(?<=Z)X.","Sd",[])),
+?line <<"�XAZSd">> = iolist_to_binary(re:replace("�XAZXB","(?<=Z)X.","Sd",[global])),
+?line <<"A">> = iolist_to_binary(re:replace("ab cd defg","ab cd (?x) de fg","\\1A\\1",[])),
+?line <<"A">> = iolist_to_binary(re:replace("ab cd defg","ab cd (?x) de fg","\\1A\\1",[global])),
+?line <<"fab cddefgLdtKCtPab cddefgxvVUHDah">> = iolist_to_binary(re:replace("ab cddefg","ab cd(?x) de fg","f&LdtKC\\1\\1tP&xvVUHDah",[])),
+?line <<"fab cddefgLdtKCtPab cddefgxvVUHDah">> = iolist_to_binary(re:replace("ab cddefg","ab cd(?x) de fg","f&LdtKC\\1\\1tP&xvVUHDah",[global])),
+?line <<"** Failers">> = iolist_to_binary(re:replace("** Failers","ab cd(?x) de fg","BkO\\1dl&WNuvnGhG&Qkl",[])),
+?line <<"** Failers">> = iolist_to_binary(re:replace("** Failers","ab cd(?x) de fg","BkO\\1dl&WNuvnGhG&Qkl",[global])),
+?line <<"abcddefg">> = iolist_to_binary(re:replace("abcddefg","ab cd(?x) de fg","SCJx&",[])),
+?line <<"abcddefg">> = iolist_to_binary(re:replace("abcddefg","ab cd(?x) de fg","SCJx&",[global])),
+?line <<"foobarLvX">> = iolist_to_binary(re:replace("foobarX","(?<![^f]oo)(bar)","&Lv",[])),
+?line <<"foobarLvX">> = iolist_to_binary(re:replace("foobarX","(?<![^f]oo)(bar)","&Lv",[global])),
+?line <<"** Failers">> = iolist_to_binary(re:replace("** Failers","(?<![^f]oo)(bar)","dRgI\\1vl\\1\\1eC\\1RFQ",[])),
+?line <<"** Failers">> = iolist_to_binary(re:replace("** Failers","(?<![^f]oo)(bar)","dRgI\\1vl\\1\\1eC\\1RFQ",[global])),
+?line <<"boobarX">> = iolist_to_binary(re:replace("boobarX","(?<![^f]oo)(bar)","p\\1CU&Q",[])),
+?line <<"boobarX">> = iolist_to_binary(re:replace("boobarX","(?<![^f]oo)(bar)","p\\1CU&Q",[global])),
+?line <<"offmnXHaaIXuXOo">> = iolist_to_binary(re:replace("offX","(?<![^f])X","m\\1n&HaaI\\1&u&Oo",[])),
+?line <<"offmnXHaaIXuXOo">> = iolist_to_binary(re:replace("offX","(?<![^f])X","m\\1n&HaaI\\1&u&Oo",[global])),
+?line <<"** Failers">> = iolist_to_binary(re:replace("** Failers","(?<![^f])X","jhEwy&w\\1mfw\\1H&VBqnX\\1",[])),
+?line <<"** Failers">> = iolist_to_binary(re:replace("** Failers","(?<![^f])X","jhEwy&w\\1mfw\\1H&VBqnX\\1",[global])),
+?line <<"onyX">> = iolist_to_binary(re:replace("onyX","(?<![^f])X","HyLQEU",[])),
+?line <<"onyX">> = iolist_to_binary(re:replace("onyX","(?<![^f])X","HyLQEU",[global])),
+?line <<"onyNXN">> = iolist_to_binary(re:replace("onyX","(?<=[^f])X","\\1N&N",[])),
+?line <<"onyNXN">> = iolist_to_binary(re:replace("onyX","(?<=[^f])X","\\1N&N",[global])),
+?line <<"** Failers">> = iolist_to_binary(re:replace("** Failers","(?<=[^f])X","kt&SCnnaVhTlQMnFltwd",[])),
+?line <<"** Failers">> = iolist_to_binary(re:replace("** Failers","(?<=[^f])X","kt&SCnnaVhTlQMnFltwd",[global])),
+?line <<"offX">> = iolist_to_binary(re:replace("offX","(?<=[^f])X","UsgnsEG\\1LX&DB",[])),
+?line <<"offX">> = iolist_to_binary(re:replace("offX","(?<=[^f])X","UsgnsEG\\1LX&DB",[global])),
+?line <<"FOjOAeQxFFXja
+b
+c">> = iolist_to_binary(re:replace("a
+b
+c","^","FOjO&AeQx&FFXj",[multiline])),
+?line <<"FOjOAeQxFFXja
+FOjOAeQxFFXjb
+FOjOAeQxFFXjc">> = iolist_to_binary(re:replace("a
+b
+c","^","FOjO&AeQx&FFXj",[multiline,global])),
+?line <<"jwIVfrtVCpnVwNgju">> = iolist_to_binary(re:replace("","^","jwIVfrtVCpnVwNgju",[multiline])),
+?line <<"jwIVfrtVCpnVwNgju">> = iolist_to_binary(re:replace("","^","jwIVfrtVCpnVwNgju",[multiline,
+ global])),
+?line <<"A
+C
+sugWOwdKBC">> = iolist_to_binary(re:replace("A
+C
+C","(?<=C\\n)^","sugW&&\\1OwdKB",[multiline])),
+?line <<"A
+C
+sugWOwdKBC">> = iolist_to_binary(re:replace("A
+C
+C","(?<=C\\n)^","sugW&&\\1OwdKB",[multiline,global])),
+?line <<"dIXQXEThebXaXXcLjA">> = iolist_to_binary(re:replace("bXaX","(?:(?(1)a|b)(X))+","dI\\1Q\\1EThe&\\1cLjA",[])),
+?line <<"dIXQXEThebXaXXcLjA">> = iolist_to_binary(re:replace("bXaX","(?:(?(1)a|b)(X))+","dI\\1Q\\1EThe&\\1cLjA",[global])),
+?line <<"AvB">> = iolist_to_binary(re:replace("bXXaYYaY","(?:(?(1)\\1a|b)(X|Y))+","AvB",[])),
+?line <<"AvB">> = iolist_to_binary(re:replace("bXXaYYaY","(?:(?(1)\\1a|b)(X|Y))+","AvB",[global])),
+?line <<"EHtFjtbXESMPhXXYaXXaX">> = iolist_to_binary(re:replace("bXYaXXaX","(?:(?(1)\\1a|b)(X|Y))+","EHtFjt&ESMPh\\1\\1",[])),
+?line <<"EHtFjtbXESMPhXXYaXXaX">> = iolist_to_binary(re:replace("bXYaXXaX","(?:(?(1)\\1a|b)(X|Y))+","EHtFjt&ESMPh\\1\\1",[global])),
+?line <<"bXnIbjbXebXpecwXaYYaY">> = iolist_to_binary(re:replace("bXXaYYaY","()()()()()()()()()(?:(?(10)\\10a|b)(X|Y))+","&nIbj&\\1e&p\\1ecw",[])),
+?line <<"bXnIbjbXebXpecwXaYYaY">> = iolist_to_binary(re:replace("bXXaYYaY","()()()()()()()()()(?:(?(10)\\10a|b)(X|Y))+","&nIbj&\\1e&p\\1ecw",[global])),
+?line <<"Fv">> = iolist_to_binary(re:replace("abc]","[[,abc,]+]","Fv",[])),
+?line <<"Fv">> = iolist_to_binary(re:replace("abc]","[[,abc,]+]","Fv",[global])),
+?line <<"enGFFPGa,b]Vq">> = iolist_to_binary(re:replace("a,b]","[[,abc,]+]","enGFFPG&V\\1q",[])),
+?line <<"enGFFPGa,b]Vq">> = iolist_to_binary(re:replace("a,b]","[[,abc,]+]","enGFFPG&V\\1q",[global])),
+?line <<"SLU[a,b,c]KDFqnru[a,b,c]">> = iolist_to_binary(re:replace("[a,b,c]","[[,abc,]+]","SLU&KDFqnru&",[])),
+?line <<"SLU[a,b,c]KDFqnru[a,b,c]">> = iolist_to_binary(re:replace("[a,b,c]","[[,abc,]+]","SLU&KDFqnru&",[global])),
+?line <<"AFHpB">> = iolist_to_binary(re:replace("A B","(?-x: )","FHp",[extended])),
+?line <<"AFHpB">> = iolist_to_binary(re:replace("A B","(?-x: )","FHp",[extended,
+ global])),
+?line <<"ALptWSVme # # # B">> = iolist_to_binary(re:replace("A # B","(?x)(?-x: \\s*#\\s*)","LptWSVme&\\1&&",[])),
+?line <<"ALptWSVme # # # B">> = iolist_to_binary(re:replace("A # B","(?x)(?-x: \\s*#\\s*)","LptWSVme&\\1&&",[global])),
+?line <<"** Failers">> = iolist_to_binary(re:replace("** Failers","(?x)(?-x: \\s*#\\s*)","enBY&\\1vE&\\1I\\1IhttjD\\1",[])),
+?line <<"** Failers">> = iolist_to_binary(re:replace("** Failers","(?x)(?-x: \\s*#\\s*)","enBY&\\1vE&\\1I\\1IhttjD\\1",[global])),
+?line <<"#">> = iolist_to_binary(re:replace("#","(?x)(?-x: \\s*#\\s*)","c\\1cwAsih",[])),
+?line <<"#">> = iolist_to_binary(re:replace("#","(?x)(?-x: \\s*#\\s*)","c\\1cwAsih",[global])),
+?line <<"ARtjg #includeDy #includeg">> = iolist_to_binary(re:replace("A #include","(?x-is)(?:(?-ixs) \\s*#\\s*) include","Rtjg&Dy\\1&g",[])),
+?line <<"ARtjg #includeDy #includeg">> = iolist_to_binary(re:replace("A #include","(?x-is)(?:(?-ixs) \\s*#\\s*) include","Rtjg&Dy\\1&g",[global])),
+?line <<"** Failers">> = iolist_to_binary(re:replace("** Failers","(?x-is)(?:(?-ixs) \\s*#\\s*) include","tYbpFaHd\\1GjcqHIWx\\1a",[])),
+?line <<"** Failers">> = iolist_to_binary(re:replace("** Failers","(?x-is)(?:(?-ixs) \\s*#\\s*) include","tYbpFaHd\\1GjcqHIWx\\1a",[global])),
+?line <<"A#include">> = iolist_to_binary(re:replace("A#include","(?x-is)(?:(?-ixs) \\s*#\\s*) include","nv\\1tgvlSHVHyKOMPNXVF",[])),
+?line <<"A#include">> = iolist_to_binary(re:replace("A#include","(?x-is)(?:(?-ixs) \\s*#\\s*) include","nv\\1tgvlSHVHyKOMPNXVF",[global])),
+?line <<"A #Include">> = iolist_to_binary(re:replace("A #Include","(?x-is)(?:(?-ixs) \\s*#\\s*) include","kQdv",[])),
+?line <<"A #Include">> = iolist_to_binary(re:replace("A #Include","(?x-is)(?:(?-ixs) \\s*#\\s*) include","kQdv",[global])),
+?line <<"k">> = iolist_to_binary(re:replace("aaabbbb","a*b*\\w","k",[])),
+?line <<"k">> = iolist_to_binary(re:replace("aaabbbb","a*b*\\w","k",[global])),
+?line <<"xaaaa">> = iolist_to_binary(re:replace("aaaa","a*b*\\w","x&",[])),
+?line <<"xaaaa">> = iolist_to_binary(re:replace("aaaa","a*b*\\w","x&",[global])),
+?line <<"pOagbKtJauauHwjM">> = iolist_to_binary(re:replace("a","a*b*\\w","pOagbKtJ&uauHwjM",[])),
+?line <<"pOagbKtJauauHwjM">> = iolist_to_binary(re:replace("a","a*b*\\w","pOagbKtJ&uauHwjM",[global])),
+?line <<"tuaaabbPhWfMuDrCJEUabb">> = iolist_to_binary(re:replace("aaabbbb","a*b?\\w","tu&P\\1h\\1WfMu\\1Dr\\1CJEUa",[])),
+?line <<"tuaaabbPhWfMuDrCJEUatubbPhWfMuDrCJEUa">> = iolist_to_binary(re:replace("aaabbbb","a*b?\\w","tu&P\\1h\\1WfMu\\1Dr\\1CJEUa",[global])),
+?line <<"heEGaaaabPJaaaaaaaakUYNXaaaasNCaaaa">> = iolist_to_binary(re:replace("aaaa","a*b?\\w","heEG&bPJ&&kUYNX&sNC&",[])),
+?line <<"heEGaaaabPJaaaaaaaakUYNXaaaasNCaaaa">> = iolist_to_binary(re:replace("aaaa","a*b?\\w","heEG&bPJ&&kUYNX&sNC&",[global])),
+?line <<"cjDPFiqs">> = iolist_to_binary(re:replace("a","a*b?\\w","cjDPFiq\\1s",[])),
+?line <<"cjDPFiqs">> = iolist_to_binary(re:replace("a","a*b?\\w","cjDPFiq\\1s",[global])),
+?line <<"aaabbbbU">> = iolist_to_binary(re:replace("aaabbbb","a*b{0,4}\\w","&U",[])),
+?line <<"aaabbbbU">> = iolist_to_binary(re:replace("aaabbbb","a*b{0,4}\\w","&U",[global])),
+?line <<"kaaaavgaaaaFaaaa">> = iolist_to_binary(re:replace("aaaa","a*b{0,4}\\w","k&vg&F&",[])),
+?line <<"kaaaavgaaaaFaaaa">> = iolist_to_binary(re:replace("aaaa","a*b{0,4}\\w","k&vg&F&",[global])),
+?line <<"ahHM">> = iolist_to_binary(re:replace("a","a*b{0,4}\\w","&hHM",[])),
+?line <<"ahHM">> = iolist_to_binary(re:replace("a","a*b{0,4}\\w","&hHM",[global])),
+?line <<"aaabbbbkVyXSBUXNHaaabbbbSC">> = iolist_to_binary(re:replace("aaabbbb","a*b{0,}\\w","\\1&kVyXSBUXNH&SC\\1",[])),
+?line <<"aaabbbbkVyXSBUXNHaaabbbbSC">> = iolist_to_binary(re:replace("aaabbbb","a*b{0,}\\w","\\1&kVyXSBUXNH&SC\\1",[global])),
+?line <<"JsaaaaARjP">> = iolist_to_binary(re:replace("aaaa","a*b{0,}\\w","Js&ARjP",[])),
+?line <<"JsaaaaARjP">> = iolist_to_binary(re:replace("aaaa","a*b{0,}\\w","Js&ARjP",[global])),
+?line <<"safA">> = iolist_to_binary(re:replace("a","a*b{0,}\\w","s\\1&fA",[])),
+?line <<"safA">> = iolist_to_binary(re:replace("a","a*b{0,}\\w","s\\1&fA",[global])),
+?line <<"0aGcgVV0aXhLIJ">> = iolist_to_binary(re:replace("0a","a*\\d*\\w","&GcgVV&XhLIJ",[])),
+?line <<"0aGcgVV0aXhLIJ">> = iolist_to_binary(re:replace("0a","a*\\d*\\w","&GcgVV&XhLIJ",[global])),
+?line <<"OWJamuSoHvWtdO">> = iolist_to_binary(re:replace("a","a*\\d*\\w","OWJ&muSoHvWtdO",[])),
+?line <<"OWJamuSoHvWtdO">> = iolist_to_binary(re:replace("a","a*\\d*\\w","OWJ&muSoHvWtdO",[global])),
+?line <<"jLLQBsEdhgm">> = iolist_to_binary(re:replace("a","a*b *\\w","jLLQ\\1BsE\\1dhgm",[extended])),
+?line <<"jLLQBsEdhgm">> = iolist_to_binary(re:replace("a","a*b *\\w","jLLQ\\1BsE\\1dhgm",[extended,
+ global])),
+?line <<"JFKdkakQmYFCpg">> = iolist_to_binary(re:replace("a","a*b#comment
+ *\\w","JFKdk&kQmYFCpg",[extended])),
+?line <<"JFKdkakQmYFCpg">> = iolist_to_binary(re:replace("a","a*b#comment
+ *\\w","JFKdk&kQmYFCpg",[extended,global])),
+?line <<"UeHUaDNFkPaoa">> = iolist_to_binary(re:replace("a","a* b *\\w","UeHU&DNFkP&o&\\1",[extended])),
+?line <<"UeHUaDNFkPaoa">> = iolist_to_binary(re:replace("a","a* b *\\w","UeHU&DNFkP&o&\\1",[extended,
+ global])),
+?line <<"Qomltkg
+pqr">> = iolist_to_binary(re:replace("abc=xyz\\
+pqr","^\\w+=.*(\\\\\\n.*)*","\\1Qomltkg",[])),
+?line <<"Qomltkg
+pqr">> = iolist_to_binary(re:replace("abc=xyz\\
+pqr","^\\w+=.*(\\\\\\n.*)*","\\1Qomltkg",[global])),
+?line <<"abcdVXTDna">> = iolist_to_binary(re:replace("abcd:","(?=(\\w+))\\1:","\\1VXTDna",[])),
+?line <<"abcdVXTDna">> = iolist_to_binary(re:replace("abcd:","(?=(\\w+))\\1:","\\1VXTDna",[global])),
+?line <<"dxHUL">> = iolist_to_binary(re:replace("abcd:","^(?=(\\w+))\\1:","dxHUL",[])),
+?line <<"dxHUL">> = iolist_to_binary(re:replace("abcd:","^(?=(\\w+))\\1:","dxHUL",[global])),
+?line <<"HsivTabcLabcC">> = iolist_to_binary(re:replace("abc","^\\Eabc","H\\1\\1sivT&L&C\\1",[])),
+?line <<"HsivTabcLabcC">> = iolist_to_binary(re:replace("abc","^\\Eabc","H\\1\\1sivT&L&C\\1",[global])),
+?line <<"HaCuWiasgghyJxOoaVMR">> = iolist_to_binary(re:replace("a","^[\\Eabc]","HaCuWi&sgghyJxOo&VMR",[])),
+?line <<"HaCuWiasgghyJxOoaVMR">> = iolist_to_binary(re:replace("a","^[\\Eabc]","HaCuWi&sgghyJxOo&VMR",[global])),
+?line <<"** Failers">> = iolist_to_binary(re:replace("** Failers","^[\\Eabc]","Lc&Jjl&YLfuY",[])),
+?line <<"** Failers">> = iolist_to_binary(re:replace("** Failers","^[\\Eabc]","Lc&Jjl&YLfuY",[global])),
+?line <<"E">> = iolist_to_binary(re:replace("E","^[\\Eabc]","MS\\1e",[])),
+?line <<"E">> = iolist_to_binary(re:replace("E","^[\\Eabc]","MS\\1e",[global])),
+?line <<"rtpBWkcLbtGo">> = iolist_to_binary(re:replace("b","^[a-\\Ec]","rtpBWkcL&\\1tGo",[])),
+?line <<"rtpBWkcLbtGo">> = iolist_to_binary(re:replace("b","^[a-\\Ec]","rtpBWkcL&\\1tGo",[global])),
+?line <<"** Failers">> = iolist_to_binary(re:replace("** Failers","^[a-\\Ec]","IC&T\\1r",[])),
+?line <<"** Failers">> = iolist_to_binary(re:replace("** Failers","^[a-\\Ec]","IC&T\\1r",[global])),
+?line <<"-">> = iolist_to_binary(re:replace("-","^[a-\\Ec]","CoL\\1S\\1d",[])),
+?line <<"-">> = iolist_to_binary(re:replace("-","^[a-\\Ec]","CoL\\1S\\1d",[global])),
+?line <<"E">> = iolist_to_binary(re:replace("E","^[a-\\Ec]","\\1T",[])),
+?line <<"E">> = iolist_to_binary(re:replace("E","^[a-\\Ec]","\\1T",[global])),
+?line <<"nbUnfwIYbbDEgCj">> = iolist_to_binary(re:replace("b","^[a\\E\\E-\\Ec]","n&Un\\1fwIY\\1&&DEgCj",[])),
+?line <<"nbUnfwIYbbDEgCj">> = iolist_to_binary(re:replace("b","^[a\\E\\E-\\Ec]","n&Un\\1fwIY\\1&&DEgCj",[global])),
+?line <<"** Failers">> = iolist_to_binary(re:replace("** Failers","^[a\\E\\E-\\Ec]","P\\1VvOTyOaT",[])),
+?line <<"** Failers">> = iolist_to_binary(re:replace("** Failers","^[a\\E\\E-\\Ec]","P\\1VvOTyOaT",[global])),
+?line <<"-">> = iolist_to_binary(re:replace("-","^[a\\E\\E-\\Ec]","XYUeR",[])),
+?line <<"-">> = iolist_to_binary(re:replace("-","^[a\\E\\E-\\Ec]","XYUeR",[global])),
+?line <<"E">> = iolist_to_binary(re:replace("E","^[a\\E\\E-\\Ec]","PeFBbxifgd",[])),
+?line <<"E">> = iolist_to_binary(re:replace("E","^[a\\E\\E-\\Ec]","PeFBbxifgd",[global])),
+?line <<"pdeFkRdPoflblrWho">> = iolist_to_binary(re:replace("b","^[\\E\\Qa\\E-\\Qz\\E]+","pdeFkRdPofl&lrWho\\1",[])),
+?line <<"pdeFkRdPoflblrWho">> = iolist_to_binary(re:replace("b","^[\\E\\Qa\\E-\\Qz\\E]+","pdeFkRdPofl&lrWho\\1",[global])),
+?line <<"** Failers">> = iolist_to_binary(re:replace("** Failers","^[\\E\\Qa\\E-\\Qz\\E]+","mXYgE\\1\\1",[])),
+?line <<"** Failers">> = iolist_to_binary(re:replace("** Failers","^[\\E\\Qa\\E-\\Qz\\E]+","mXYgE\\1\\1",[global])),
+?line <<"-">> = iolist_to_binary(re:replace("-","^[\\E\\Qa\\E-\\Qz\\E]+","KLdkiRi",[])),
+?line <<"-">> = iolist_to_binary(re:replace("-","^[\\E\\Qa\\E-\\Qz\\E]+","KLdkiRi",[global])),
+?line <<"CAXhbVsbB">> = iolist_to_binary(re:replace("a","^[a\\Q]bc\\E]","CAXh\\1bVsbB",[])),
+?line <<"CAXhbVsbB">> = iolist_to_binary(re:replace("a","^[a\\Q]bc\\E]","CAXh\\1bVsbB",[global])),
+?line <<"YFgJL]GhQVUD]Pbp">> = iolist_to_binary(re:replace("]","^[a\\Q]bc\\E]","YFgJL&GhQVU\\1D&Pbp",[])),
+?line <<"YFgJL]GhQVUD]Pbp">> = iolist_to_binary(re:replace("]","^[a\\Q]bc\\E]","YFgJL&GhQVU\\1D&Pbp",[global])),
+?line <<"waUcGiVGxIcKiccYmjc">> = iolist_to_binary(re:replace("c","^[a\\Q]bc\\E]","waU&GiVGxI&Ki&cYmj&",[])),
+?line <<"waUcGiVGxIcKiccYmjc">> = iolist_to_binary(re:replace("c","^[a\\Q]bc\\E]","waU&GiVGxI&Ki&cYmj&",[global])),
+?line <<"yfaacSB">> = iolist_to_binary(re:replace("a","^[a-\\Q\\E]","yf&\\1acSB",[])),
+?line <<"yfaacSB">> = iolist_to_binary(re:replace("a","^[a-\\Q\\E]","yf&\\1acSB",[global])),
+?line <<"f">> = iolist_to_binary(re:replace("-","^[a-\\Q\\E]","f",[])),
+?line <<"f">> = iolist_to_binary(re:replace("-","^[a-\\Q\\E]","f",[global])),
+?line <<"S">> = iolist_to_binary(re:replace("aaaa","^(a()*)*","S",[])),
+?line <<"S">> = iolist_to_binary(re:replace("aaaa","^(a()*)*","S",[global])),
+?line <<"BPPbuaaaaufIV">> = iolist_to_binary(re:replace("aaaa","^(?:a(?:(?:))*)*","BPPbu&ufIV",[])),
+?line <<"BPPbuaaaaufIV">> = iolist_to_binary(re:replace("aaaa","^(?:a(?:(?:))*)*","BPPbu&ufIV",[global])),
+?line <<"HBMaaaafDaRVOv">> = iolist_to_binary(re:replace("aaaa","^(a()+)+","HBM&fD\\1RVOv",[])),
+?line <<"HBMaaaafDaRVOv">> = iolist_to_binary(re:replace("aaaa","^(a()+)+","HBM&fD\\1RVOv",[global])),
+?line <<"JvvaaaaaaaaXGaaaawkPaaaaNqM">> = iolist_to_binary(re:replace("aaaa","^(?:a(?:(?:))+)+","J\\1vv\\1\\1&&XG&w\\1kP&N\\1qM",[])),
+?line <<"JvvaaaaaaaaXGaaaawkPaaaaNqM">> = iolist_to_binary(re:replace("aaaa","^(?:a(?:(?:))+)+","J\\1vv\\1\\1&&XG&w\\1kP&N\\1qM",[global])),
+?line <<"GlQPoT">> = iolist_to_binary(re:replace("abbD","(a){0,3}(?(1)b|(c|))*D","GlQPoT",[])),
+?line <<"GlQPoT">> = iolist_to_binary(re:replace("abbD","(a){0,3}(?(1)b|(c|))*D","GlQPoT",[global])),
+?line <<"ApBccccD">> = iolist_to_binary(re:replace("ccccD","(a){0,3}(?(1)b|(c|))*D","\\1\\1ApB&",[])),
+?line <<"ApBccccD">> = iolist_to_binary(re:replace("ccccD","(a){0,3}(?(1)b|(c|))*D","\\1\\1ApB&",[global])),
+?line <<"BC">> = iolist_to_binary(re:replace("D","(a){0,3}(?(1)b|(c|))*D","BC",[])),
+?line <<"BC">> = iolist_to_binary(re:replace("D","(a){0,3}(?(1)b|(c|))*D","BC",[global])),
+?line <<"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","(a|)*\\d","gsB\\1",[])),
+?line <<"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","(a|)*\\d","gsB\\1",[global])),
+?line <<"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4FVLiMHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4hlau">> = iolist_to_binary(re:replace("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4","(a|)*\\d","&F\\1VLiMH&hlau",[])),
+?line <<"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4FVLiMHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4hlau">> = iolist_to_binary(re:replace("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4","(a|)*\\d","&F\\1VLiMH&hlau",[global])),
+?line <<"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","(?>a|)*\\d","PkrWG&pe\\1uUD&sBHqm",[])),
+?line <<"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","(?>a|)*\\d","PkrWG&pe\\1uUD&sBHqm",[global])),
+?line <<"KmL">> = iolist_to_binary(re:replace("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4","(?>a|)*\\d","KmL",[])),
+?line <<"KmL">> = iolist_to_binary(re:replace("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4","(?>a|)*\\d","KmL",[global])),
+?line <<"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","(?:a|)*\\d","&HUPIn&&&uUmDmrCoAY",[])),
+?line <<"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa">> = iolist_to_binary(re:replace("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","(?:a|)*\\d","&HUPIn&&&uUmDmrCoAY",[global])),
+?line <<"Q">> = iolist_to_binary(re:replace("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4","(?:a|)*\\d","Q",[])),
+?line <<"Q">> = iolist_to_binary(re:replace("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4","(?:a|)*\\d","Q",[global])),
+?line <<"abcR">> = iolist_to_binary(re:replace("abc","\\Z","R",[])),
+?line <<"abcR">> = iolist_to_binary(re:replace("abc","\\Z","R",[global])),
+?line <<"GwfabcD">> = iolist_to_binary(re:replace("abc","^(?s)(?>.*)(?<!\\n)","Gwf&D",[])),
+?line <<"GwfabcD">> = iolist_to_binary(re:replace("abc","^(?s)(?>.*)(?<!\\n)","Gwf&D",[global])),
+?line <<"EWJHblKuypyqFbP">> = iolist_to_binary(re:replace("abc","^(?s)(?>.*)(?<!\\n)","EWJHblKuypyqFbP",[])),
+?line <<"EWJHblKuypyqFbP">> = iolist_to_binary(re:replace("abc","^(?s)(?>.*)(?<!\\n)","EWJHblKuypyqFbP",[global])),
+?line <<"fabc">> = iolist_to_binary(re:replace("abc","^(?![^\\n]*\\n\\z)","f",[])),
+?line <<"fabc">> = iolist_to_binary(re:replace("abc","^(?![^\\n]*\\n\\z)","f",[global])),
+?line <<"cKyLyGabc">> = iolist_to_binary(re:replace("abc","^(?![^\\n]*\\n\\z)","cKyL\\1yG",[])),
+?line <<"cKyLyGabc">> = iolist_to_binary(re:replace("abc","^(?![^\\n]*\\n\\z)","cKyL\\1yG",[global])),
+?line <<"abcKoYH">> = iolist_to_binary(re:replace("abc","\\z(?<!\\n)","\\1\\1Ko\\1&Y&H",[])),
+?line <<"abcKoYH">> = iolist_to_binary(re:replace("abc","\\z(?<!\\n)","\\1\\1Ko\\1&Y&H",[global])),
+?line <<"abcqWjyPjUTIdbm">> = iolist_to_binary(re:replace("abc","\\z(?<!\\n)","qWjy\\1PjUTIdbm&",[])),
+?line <<"abcqWjyPjUTIdbm">> = iolist_to_binary(re:replace("abc","\\z(?<!\\n)","qWjy\\1PjUTIdbm&",[global])),
+?line <<"labcdJabcdNUhUnH">> = iolist_to_binary(re:replace("abcd","(.*(.)?)*","l&J\\1&NUhUnH",[])),
+?line <<"labcdJabcdNUhUnHlJNUhUnH">> = iolist_to_binary(re:replace("abcd","(.*(.)?)*","l&J\\1&NUhUnH",[global])),
+?line <<"onfTbTLJLVnabcd">> = iolist_to_binary(re:replace("abcd","( (A | (?(1)0|) )* )","onfTbTLJLVn",[extended])),
+?line <<"onfTbTLJLVnaonfTbTLJLVnbonfTbTLJLVnconfTbTLJLVndonfTbTLJLVn">> = iolist_to_binary(re:replace("abcd","( (A | (?(1)0|) )* )","onfTbTLJLVn",[extended,
+ global])),
+?line <<"rilgPabcd">> = iolist_to_binary(re:replace("abcd","( ( (?(1)0|) )* )","ri\\1&lgP",[extended])),
+?line <<"rilgParilgPbrilgPcrilgPdrilgP">> = iolist_to_binary(re:replace("abcd","( ( (?(1)0|) )* )","ri\\1&lgP",[extended,
+ global])),
+?line <<"LjAUxSNabcd">> = iolist_to_binary(re:replace("abcd","( (?(1)0|)* )","L\\1jAUxSN\\1",[extended])),
+?line <<"LjAUxSNaLjAUxSNbLjAUxSNcLjAUxSNdLjAUxSN">> = iolist_to_binary(re:replace("abcd","( (?(1)0|)* )","L\\1jAUxSN\\1",[extended,
+ global])),
+?line <<"xYgnYjja]Bgw">> = iolist_to_binary(re:replace("a]","[[:abcd:xyz]]","\\1xYgnYjj&Bgw",[])),
+?line <<"xYgnYjja]Bgw">> = iolist_to_binary(re:replace("a]","[[:abcd:xyz]]","\\1xYgnYjj&Bgw",[global])),
+?line <<"K:]Y:]tTEIHHPgm">> = iolist_to_binary(re:replace(":]","[[:abcd:xyz]]","K\\1&Y&tT\\1EI\\1H\\1HP\\1gm",[])),
+?line <<"K:]Y:]tTEIHHPgm">> = iolist_to_binary(re:replace(":]","[[:abcd:xyz]]","K\\1&Y&tT\\1EI\\1H\\1HP\\1gm",[global])),
+?line <<"pcaYhpF">> = iolist_to_binary(re:replace("a","[abc[:x\\]pqr]","pc&Y\\1hpF",[])),
+?line <<"pcaYhpF">> = iolist_to_binary(re:replace("a","[abc[:x\\]pqr]","pc&Y\\1hpF",[global])),
+?line <<"I[">> = iolist_to_binary(re:replace("[","[abc[:x\\]pqr]","I\\1&",[])),
+?line <<"I[">> = iolist_to_binary(re:replace("[","[abc[:x\\]pqr]","I\\1&",[global])),
+?line <<"SYn:iPpASU">> = iolist_to_binary(re:replace(":","[abc[:x\\]pqr]","SY\\1n&iP\\1pAS\\1U",[])),
+?line <<"SYn:iPpASU">> = iolist_to_binary(re:replace(":","[abc[:x\\]pqr]","SY\\1n&iP\\1pAS\\1U",[global])),
+?line <<"VwLRsMyuKqCwx">> = iolist_to_binary(re:replace("]","[abc[:x\\]pqr]","VwLRsMyuKqCwx",[])),
+?line <<"VwLRsMyuKqCwx">> = iolist_to_binary(re:replace("]","[abc[:x\\]pqr]","VwLRsMyuKqCwx",[global])),
+?line <<"YqUufuU">> = iolist_to_binary(re:replace("p","[abc[:x\\]pqr]","YqU\\1ufuU",[])),
+?line <<"YqUufuU">> = iolist_to_binary(re:replace("p","[abc[:x\\]pqr]","YqU\\1ufuU",[global])),
+ok.
diff --git a/lib/stdlib/test/re_testoutput1_split_test.erl b/lib/stdlib/test/re_testoutput1_split_test.erl
new file mode 100644
index 0000000000..7e2d3f79ec
--- /dev/null
+++ b/lib/stdlib/test/re_testoutput1_split_test.erl
@@ -0,0 +1,29418 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(re_testoutput1_split_test).
+-compile(export_all).
+-include("test_server.hrl").
+%% This file is generated by running run_pcre_tests:gen_split_test("re_SUITE_data/testoutput1")
+join([]) -> [];
+join([A]) -> [A];
+join([H|T]) -> [H,<<":">>|join(T)].
+run() ->
+?line <<"">> = iolist_to_binary(join(re:split("the quick brown fox","the quick brown fox",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("the quick brown fox","the quick brown fox",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("the quick brown fox","the quick brown fox",[]))),
+?line <<"The quick brown FOX">> = iolist_to_binary(join(re:split("The quick brown FOX","the quick brown fox",[trim]))),
+?line <<"The quick brown FOX">> = iolist_to_binary(join(re:split("The quick brown FOX","the quick brown fox",[{parts,
+ 2}]))),
+?line <<"The quick brown FOX">> = iolist_to_binary(join(re:split("The quick brown FOX","the quick brown fox",[]))),
+?line <<"What do you know about :?">> = iolist_to_binary(join(re:split("What do you know about the quick brown fox?","the quick brown fox",[trim]))),
+?line <<"What do you know about :?">> = iolist_to_binary(join(re:split("What do you know about the quick brown fox?","the quick brown fox",[{parts,
+ 2}]))),
+?line <<"What do you know about :?">> = iolist_to_binary(join(re:split("What do you know about the quick brown fox?","the quick brown fox",[]))),
+?line <<"What do you know about THE QUICK BROWN FOX?">> = iolist_to_binary(join(re:split("What do you know about THE QUICK BROWN FOX?","the quick brown fox",[trim]))),
+?line <<"What do you know about THE QUICK BROWN FOX?">> = iolist_to_binary(join(re:split("What do you know about THE QUICK BROWN FOX?","the quick brown fox",[{parts,
+ 2}]))),
+?line <<"What do you know about THE QUICK BROWN FOX?">> = iolist_to_binary(join(re:split("What do you know about THE QUICK BROWN FOX?","the quick brown fox",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("the quick brown fox","The quick brown fox",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("the quick brown fox","The quick brown fox",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("the quick brown fox","The quick brown fox",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("The quick brown FOX","The quick brown fox",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("The quick brown FOX","The quick brown fox",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("The quick brown FOX","The quick brown fox",[caseless]))),
+?line <<"What do you know about :?">> = iolist_to_binary(join(re:split("What do you know about the quick brown fox?","The quick brown fox",[caseless,
+ trim]))),
+?line <<"What do you know about :?">> = iolist_to_binary(join(re:split("What do you know about the quick brown fox?","The quick brown fox",[caseless,
+ {parts,
+ 2}]))),
+?line <<"What do you know about :?">> = iolist_to_binary(join(re:split("What do you know about the quick brown fox?","The quick brown fox",[caseless]))),
+?line <<"What do you know about :?">> = iolist_to_binary(join(re:split("What do you know about THE QUICK BROWN FOX?","The quick brown fox",[caseless,
+ trim]))),
+?line <<"What do you know about :?">> = iolist_to_binary(join(re:split("What do you know about THE QUICK BROWN FOX?","The quick brown fox",[caseless,
+ {parts,
+ 2}]))),
+?line <<"What do you know about :?">> = iolist_to_binary(join(re:split("What do you know about THE QUICK BROWN FOX?","The quick brown fox",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("abcd
+ 9;$\\?caxyz","abcd\\t\\n\\r\\f\\a\\e\\071\\x3b\\$\\\\\\?caxyz",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abcd
+ 9;$\\?caxyz","abcd\\t\\n\\r\\f\\a\\e\\071\\x3b\\$\\\\\\?caxyz",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abcd
+ 9;$\\?caxyz","abcd\\t\\n\\r\\f\\a\\e\\071\\x3b\\$\\\\\\?caxyz",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aabxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aabxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aabxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaabxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaabxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaabxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaaabxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaabxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaabxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abcxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abcxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abcxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aabcxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aabcxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aabcxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaabcxyzpqrrrabbxyyyypAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaabcxyzpqrrrabbxyyyypAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaabcxyzpqrrrabbxyyyypAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaabcxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaabcxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaabcxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaabcxyzpqrrrabbxyyyypqqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaabcxyzpqrrrabbxyyyypqqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaabcxyzpqrrrabbxyyyypqqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaabcxyzpqrrrabbxyyyypqqqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaabcxyzpqrrrabbxyyyypqqqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaabcxyzpqrrrabbxyyyypqqqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaabcxyzpqrrrabbxyyyypqqqqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaabcxyzpqrrrabbxyyyypqqqqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaabcxyzpqrrrabbxyyyypqqqqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaabcxyzpqrrrabbxyyyypqqqqqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaabcxyzpqrrrabbxyyyypqqqqqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaabcxyzpqrrrabbxyyyypqqqqqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaabcxyzpqrrrabbxyyyypqqqqqqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaabcxyzpqrrrabbxyyyypqqqqqqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaabcxyzpqrrrabbxyyyypqqqqqqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaaabcxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaabcxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaabcxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abxyzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abxyzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abxyzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aabxyzzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aabxyzzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aabxyzzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaabxyzzzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaabxyzzzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaabxyzzzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaaabxyzzzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaabxyzzzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaabxyzzzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abcxyzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abcxyzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abcxyzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aabcxyzzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aabcxyzzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aabcxyzzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaabcxyzzzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaabcxyzzzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaabcxyzzzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaaabcxyzzzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaabcxyzzzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaabcxyzzzzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaaabcxyzzzzpqrrrabbbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaabcxyzzzzpqrrrabbbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaabcxyzzzzpqrrrabbbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaaabcxyzzzzpqrrrabbbxyyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaabcxyzzzzpqrrrabbbxyyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaabcxyzzzzpqrrrabbbxyyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaabcxyzpqrrrabbxyyyypABzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaabcxyzpqrrrabbxyyyypABzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaabcxyzpqrrrabbxyyyypABzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaabcxyzpqrrrabbxyyyypABBzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaabcxyzpqrrrabbxyyyypABBzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaabcxyzpqrrrabbxyyyypABBzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[]))),
+?line <<">>>">> = iolist_to_binary(join(re:split(">>>aaabxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[trim]))),
+?line <<">>>:">> = iolist_to_binary(join(re:split(">>>aaabxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[{parts,
+ 2}]))),
+?line <<">>>:">> = iolist_to_binary(join(re:split(">>>aaabxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[]))),
+?line <<">">> = iolist_to_binary(join(re:split(">aaaabxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[trim]))),
+?line <<">:">> = iolist_to_binary(join(re:split(">aaaabxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[{parts,
+ 2}]))),
+?line <<">:">> = iolist_to_binary(join(re:split(">aaaabxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[]))),
+?line <<">>>>">> = iolist_to_binary(join(re:split(">>>>abcxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[trim]))),
+?line <<">>>>:">> = iolist_to_binary(join(re:split(">>>>abcxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[{parts,
+ 2}]))),
+?line <<">>>>:">> = iolist_to_binary(join(re:split(">>>>abcxyzpqrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[]))),
+?line <<"abxyzpqrrabbxyyyypqAzz">> = iolist_to_binary(join(re:split("abxyzpqrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[trim]))),
+?line <<"abxyzpqrrabbxyyyypqAzz">> = iolist_to_binary(join(re:split("abxyzpqrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[{parts,
+ 2}]))),
+?line <<"abxyzpqrrabbxyyyypqAzz">> = iolist_to_binary(join(re:split("abxyzpqrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[]))),
+?line <<"abxyzpqrrrrabbxyyyypqAzz">> = iolist_to_binary(join(re:split("abxyzpqrrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[trim]))),
+?line <<"abxyzpqrrrrabbxyyyypqAzz">> = iolist_to_binary(join(re:split("abxyzpqrrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[{parts,
+ 2}]))),
+?line <<"abxyzpqrrrrabbxyyyypqAzz">> = iolist_to_binary(join(re:split("abxyzpqrrrrabbxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[]))),
+?line <<"abxyzpqrrrabxyyyypqAzz">> = iolist_to_binary(join(re:split("abxyzpqrrrabxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[trim]))),
+?line <<"abxyzpqrrrabxyyyypqAzz">> = iolist_to_binary(join(re:split("abxyzpqrrrabxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[{parts,
+ 2}]))),
+?line <<"abxyzpqrrrabxyyyypqAzz">> = iolist_to_binary(join(re:split("abxyzpqrrrabxyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[]))),
+?line <<"aaaabcxyzzzzpqrrrabbbxyyyyyypqAzz">> = iolist_to_binary(join(re:split("aaaabcxyzzzzpqrrrabbbxyyyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[trim]))),
+?line <<"aaaabcxyzzzzpqrrrabbbxyyyyyypqAzz">> = iolist_to_binary(join(re:split("aaaabcxyzzzzpqrrrabbbxyyyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[{parts,
+ 2}]))),
+?line <<"aaaabcxyzzzzpqrrrabbbxyyyyyypqAzz">> = iolist_to_binary(join(re:split("aaaabcxyzzzzpqrrrabbbxyyyyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[]))),
+?line <<"aaaabcxyzzzzpqrrrabbbxyyypqAzz">> = iolist_to_binary(join(re:split("aaaabcxyzzzzpqrrrabbbxyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[trim]))),
+?line <<"aaaabcxyzzzzpqrrrabbbxyyypqAzz">> = iolist_to_binary(join(re:split("aaaabcxyzzzzpqrrrabbbxyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[{parts,
+ 2}]))),
+?line <<"aaaabcxyzzzzpqrrrabbbxyyypqAzz">> = iolist_to_binary(join(re:split("aaaabcxyzzzzpqrrrabbbxyyypqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[]))),
+?line <<"aaabcxyzpqrrrabbxyyyypqqqqqqqAzz">> = iolist_to_binary(join(re:split("aaabcxyzpqrrrabbxyyyypqqqqqqqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[trim]))),
+?line <<"aaabcxyzpqrrrabbxyyyypqqqqqqqAzz">> = iolist_to_binary(join(re:split("aaabcxyzpqrrrabbxyyyypqqqqqqqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[{parts,
+ 2}]))),
+?line <<"aaabcxyzpqrrrabbxyyyypqqqqqqqAzz">> = iolist_to_binary(join(re:split("aaabcxyzpqrrrabbxyyyypqqqqqqqAzz","a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz",[]))),
+?line <<":abc">> = iolist_to_binary(join(re:split("abczz","^(abc){1,2}zz",[trim]))),
+?line <<":abc:">> = iolist_to_binary(join(re:split("abczz","^(abc){1,2}zz",[{parts,
+ 2}]))),
+?line <<":abc:">> = iolist_to_binary(join(re:split("abczz","^(abc){1,2}zz",[]))),
+?line <<":abc">> = iolist_to_binary(join(re:split("abcabczz","^(abc){1,2}zz",[trim]))),
+?line <<":abc:">> = iolist_to_binary(join(re:split("abcabczz","^(abc){1,2}zz",[{parts,
+ 2}]))),
+?line <<":abc:">> = iolist_to_binary(join(re:split("abcabczz","^(abc){1,2}zz",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(abc){1,2}zz",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(abc){1,2}zz",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(abc){1,2}zz",[]))),
+?line <<"zz">> = iolist_to_binary(join(re:split("zz","^(abc){1,2}zz",[trim]))),
+?line <<"zz">> = iolist_to_binary(join(re:split("zz","^(abc){1,2}zz",[{parts,
+ 2}]))),
+?line <<"zz">> = iolist_to_binary(join(re:split("zz","^(abc){1,2}zz",[]))),
+?line <<"abcabcabczz">> = iolist_to_binary(join(re:split("abcabcabczz","^(abc){1,2}zz",[trim]))),
+?line <<"abcabcabczz">> = iolist_to_binary(join(re:split("abcabcabczz","^(abc){1,2}zz",[{parts,
+ 2}]))),
+?line <<"abcabcabczz">> = iolist_to_binary(join(re:split("abcabcabczz","^(abc){1,2}zz",[]))),
+?line <<">>abczz">> = iolist_to_binary(join(re:split(">>abczz","^(abc){1,2}zz",[trim]))),
+?line <<">>abczz">> = iolist_to_binary(join(re:split(">>abczz","^(abc){1,2}zz",[{parts,
+ 2}]))),
+?line <<">>abczz">> = iolist_to_binary(join(re:split(">>abczz","^(abc){1,2}zz",[]))),
+?line <<":b">> = iolist_to_binary(join(re:split("bc","^(b+?|a){1,2}?c",[trim]))),
+?line <<":b:">> = iolist_to_binary(join(re:split("bc","^(b+?|a){1,2}?c",[{parts,
+ 2}]))),
+?line <<":b:">> = iolist_to_binary(join(re:split("bc","^(b+?|a){1,2}?c",[]))),
+?line <<":b">> = iolist_to_binary(join(re:split("bbc","^(b+?|a){1,2}?c",[trim]))),
+?line <<":b:">> = iolist_to_binary(join(re:split("bbc","^(b+?|a){1,2}?c",[{parts,
+ 2}]))),
+?line <<":b:">> = iolist_to_binary(join(re:split("bbc","^(b+?|a){1,2}?c",[]))),
+?line <<":bb">> = iolist_to_binary(join(re:split("bbbc","^(b+?|a){1,2}?c",[trim]))),
+?line <<":bb:">> = iolist_to_binary(join(re:split("bbbc","^(b+?|a){1,2}?c",[{parts,
+ 2}]))),
+?line <<":bb:">> = iolist_to_binary(join(re:split("bbbc","^(b+?|a){1,2}?c",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("bac","^(b+?|a){1,2}?c",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("bac","^(b+?|a){1,2}?c",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("bac","^(b+?|a){1,2}?c",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("bbac","^(b+?|a){1,2}?c",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("bbac","^(b+?|a){1,2}?c",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("bbac","^(b+?|a){1,2}?c",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("aac","^(b+?|a){1,2}?c",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aac","^(b+?|a){1,2}?c",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aac","^(b+?|a){1,2}?c",[]))),
+?line <<":bbbbbbbbbbb">> = iolist_to_binary(join(re:split("abbbbbbbbbbbc","^(b+?|a){1,2}?c",[trim]))),
+?line <<":bbbbbbbbbbb:">> = iolist_to_binary(join(re:split("abbbbbbbbbbbc","^(b+?|a){1,2}?c",[{parts,
+ 2}]))),
+?line <<":bbbbbbbbbbb:">> = iolist_to_binary(join(re:split("abbbbbbbbbbbc","^(b+?|a){1,2}?c",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("bbbbbbbbbbbac","^(b+?|a){1,2}?c",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("bbbbbbbbbbbac","^(b+?|a){1,2}?c",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("bbbbbbbbbbbac","^(b+?|a){1,2}?c",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(b+?|a){1,2}?c",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(b+?|a){1,2}?c",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(b+?|a){1,2}?c",[]))),
+?line <<"aaac">> = iolist_to_binary(join(re:split("aaac","^(b+?|a){1,2}?c",[trim]))),
+?line <<"aaac">> = iolist_to_binary(join(re:split("aaac","^(b+?|a){1,2}?c",[{parts,
+ 2}]))),
+?line <<"aaac">> = iolist_to_binary(join(re:split("aaac","^(b+?|a){1,2}?c",[]))),
+?line <<"abbbbbbbbbbbac">> = iolist_to_binary(join(re:split("abbbbbbbbbbbac","^(b+?|a){1,2}?c",[trim]))),
+?line <<"abbbbbbbbbbbac">> = iolist_to_binary(join(re:split("abbbbbbbbbbbac","^(b+?|a){1,2}?c",[{parts,
+ 2}]))),
+?line <<"abbbbbbbbbbbac">> = iolist_to_binary(join(re:split("abbbbbbbbbbbac","^(b+?|a){1,2}?c",[]))),
+?line <<":b">> = iolist_to_binary(join(re:split("bc","^(b+|a){1,2}c",[trim]))),
+?line <<":b:">> = iolist_to_binary(join(re:split("bc","^(b+|a){1,2}c",[{parts,
+ 2}]))),
+?line <<":b:">> = iolist_to_binary(join(re:split("bc","^(b+|a){1,2}c",[]))),
+?line <<":bb">> = iolist_to_binary(join(re:split("bbc","^(b+|a){1,2}c",[trim]))),
+?line <<":bb:">> = iolist_to_binary(join(re:split("bbc","^(b+|a){1,2}c",[{parts,
+ 2}]))),
+?line <<":bb:">> = iolist_to_binary(join(re:split("bbc","^(b+|a){1,2}c",[]))),
+?line <<":bbb">> = iolist_to_binary(join(re:split("bbbc","^(b+|a){1,2}c",[trim]))),
+?line <<":bbb:">> = iolist_to_binary(join(re:split("bbbc","^(b+|a){1,2}c",[{parts,
+ 2}]))),
+?line <<":bbb:">> = iolist_to_binary(join(re:split("bbbc","^(b+|a){1,2}c",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("bac","^(b+|a){1,2}c",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("bac","^(b+|a){1,2}c",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("bac","^(b+|a){1,2}c",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("bbac","^(b+|a){1,2}c",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("bbac","^(b+|a){1,2}c",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("bbac","^(b+|a){1,2}c",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("aac","^(b+|a){1,2}c",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aac","^(b+|a){1,2}c",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aac","^(b+|a){1,2}c",[]))),
+?line <<":bbbbbbbbbbb">> = iolist_to_binary(join(re:split("abbbbbbbbbbbc","^(b+|a){1,2}c",[trim]))),
+?line <<":bbbbbbbbbbb:">> = iolist_to_binary(join(re:split("abbbbbbbbbbbc","^(b+|a){1,2}c",[{parts,
+ 2}]))),
+?line <<":bbbbbbbbbbb:">> = iolist_to_binary(join(re:split("abbbbbbbbbbbc","^(b+|a){1,2}c",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("bbbbbbbbbbbac","^(b+|a){1,2}c",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("bbbbbbbbbbbac","^(b+|a){1,2}c",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("bbbbbbbbbbbac","^(b+|a){1,2}c",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(b+|a){1,2}c",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(b+|a){1,2}c",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(b+|a){1,2}c",[]))),
+?line <<"aaac">> = iolist_to_binary(join(re:split("aaac","^(b+|a){1,2}c",[trim]))),
+?line <<"aaac">> = iolist_to_binary(join(re:split("aaac","^(b+|a){1,2}c",[{parts,
+ 2}]))),
+?line <<"aaac">> = iolist_to_binary(join(re:split("aaac","^(b+|a){1,2}c",[]))),
+?line <<"abbbbbbbbbbbac">> = iolist_to_binary(join(re:split("abbbbbbbbbbbac","^(b+|a){1,2}c",[trim]))),
+?line <<"abbbbbbbbbbbac">> = iolist_to_binary(join(re:split("abbbbbbbbbbbac","^(b+|a){1,2}c",[{parts,
+ 2}]))),
+?line <<"abbbbbbbbbbbac">> = iolist_to_binary(join(re:split("abbbbbbbbbbbac","^(b+|a){1,2}c",[]))),
+?line <<":b">> = iolist_to_binary(join(re:split("bbc","^(b+|a){1,2}?bc",[trim]))),
+?line <<":b:">> = iolist_to_binary(join(re:split("bbc","^(b+|a){1,2}?bc",[{parts,
+ 2}]))),
+?line <<":b:">> = iolist_to_binary(join(re:split("bbc","^(b+|a){1,2}?bc",[]))),
+?line <<":ba">> = iolist_to_binary(join(re:split("babc","^(b*|ba){1,2}?bc",[trim]))),
+?line <<":ba:">> = iolist_to_binary(join(re:split("babc","^(b*|ba){1,2}?bc",[{parts,
+ 2}]))),
+?line <<":ba:">> = iolist_to_binary(join(re:split("babc","^(b*|ba){1,2}?bc",[]))),
+?line <<":ba">> = iolist_to_binary(join(re:split("bbabc","^(b*|ba){1,2}?bc",[trim]))),
+?line <<":ba:">> = iolist_to_binary(join(re:split("bbabc","^(b*|ba){1,2}?bc",[{parts,
+ 2}]))),
+?line <<":ba:">> = iolist_to_binary(join(re:split("bbabc","^(b*|ba){1,2}?bc",[]))),
+?line <<":ba">> = iolist_to_binary(join(re:split("bababc","^(b*|ba){1,2}?bc",[trim]))),
+?line <<":ba:">> = iolist_to_binary(join(re:split("bababc","^(b*|ba){1,2}?bc",[{parts,
+ 2}]))),
+?line <<":ba:">> = iolist_to_binary(join(re:split("bababc","^(b*|ba){1,2}?bc",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(b*|ba){1,2}?bc",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(b*|ba){1,2}?bc",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(b*|ba){1,2}?bc",[]))),
+?line <<"bababbc">> = iolist_to_binary(join(re:split("bababbc","^(b*|ba){1,2}?bc",[trim]))),
+?line <<"bababbc">> = iolist_to_binary(join(re:split("bababbc","^(b*|ba){1,2}?bc",[{parts,
+ 2}]))),
+?line <<"bababbc">> = iolist_to_binary(join(re:split("bababbc","^(b*|ba){1,2}?bc",[]))),
+?line <<"babababc">> = iolist_to_binary(join(re:split("babababc","^(b*|ba){1,2}?bc",[trim]))),
+?line <<"babababc">> = iolist_to_binary(join(re:split("babababc","^(b*|ba){1,2}?bc",[{parts,
+ 2}]))),
+?line <<"babababc">> = iolist_to_binary(join(re:split("babababc","^(b*|ba){1,2}?bc",[]))),
+?line <<":ba">> = iolist_to_binary(join(re:split("babc","^(ba|b*){1,2}?bc",[trim]))),
+?line <<":ba:">> = iolist_to_binary(join(re:split("babc","^(ba|b*){1,2}?bc",[{parts,
+ 2}]))),
+?line <<":ba:">> = iolist_to_binary(join(re:split("babc","^(ba|b*){1,2}?bc",[]))),
+?line <<":ba">> = iolist_to_binary(join(re:split("bbabc","^(ba|b*){1,2}?bc",[trim]))),
+?line <<":ba:">> = iolist_to_binary(join(re:split("bbabc","^(ba|b*){1,2}?bc",[{parts,
+ 2}]))),
+?line <<":ba:">> = iolist_to_binary(join(re:split("bbabc","^(ba|b*){1,2}?bc",[]))),
+?line <<":ba">> = iolist_to_binary(join(re:split("bababc","^(ba|b*){1,2}?bc",[trim]))),
+?line <<":ba:">> = iolist_to_binary(join(re:split("bababc","^(ba|b*){1,2}?bc",[{parts,
+ 2}]))),
+?line <<":ba:">> = iolist_to_binary(join(re:split("bababc","^(ba|b*){1,2}?bc",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(ba|b*){1,2}?bc",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(ba|b*){1,2}?bc",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(ba|b*){1,2}?bc",[]))),
+?line <<"bababbc">> = iolist_to_binary(join(re:split("bababbc","^(ba|b*){1,2}?bc",[trim]))),
+?line <<"bababbc">> = iolist_to_binary(join(re:split("bababbc","^(ba|b*){1,2}?bc",[{parts,
+ 2}]))),
+?line <<"bababbc">> = iolist_to_binary(join(re:split("bababbc","^(ba|b*){1,2}?bc",[]))),
+?line <<"babababc">> = iolist_to_binary(join(re:split("babababc","^(ba|b*){1,2}?bc",[trim]))),
+?line <<"babababc">> = iolist_to_binary(join(re:split("babababc","^(ba|b*){1,2}?bc",[{parts,
+ 2}]))),
+?line <<"babababc">> = iolist_to_binary(join(re:split("babababc","^(ba|b*){1,2}?bc",[]))),
+?line <<"">> = iolist_to_binary(join(re:split(";z","^\\ca\\cA\\c[\\c{\\c:",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split(";z","^\\ca\\cA\\c[\\c{\\c:",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split(";z","^\\ca\\cA\\c[\\c{\\c:",[]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("athing","^[ab\\]cde]",[trim]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("athing","^[ab\\]cde]",[{parts,
+ 2}]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("athing","^[ab\\]cde]",[]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("bthing","^[ab\\]cde]",[trim]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("bthing","^[ab\\]cde]",[{parts,
+ 2}]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("bthing","^[ab\\]cde]",[]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("]thing","^[ab\\]cde]",[trim]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("]thing","^[ab\\]cde]",[{parts,
+ 2}]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("]thing","^[ab\\]cde]",[]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("cthing","^[ab\\]cde]",[trim]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("cthing","^[ab\\]cde]",[{parts,
+ 2}]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("cthing","^[ab\\]cde]",[]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("dthing","^[ab\\]cde]",[trim]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("dthing","^[ab\\]cde]",[{parts,
+ 2}]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("dthing","^[ab\\]cde]",[]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("ething","^[ab\\]cde]",[trim]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("ething","^[ab\\]cde]",[{parts,
+ 2}]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("ething","^[ab\\]cde]",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^[ab\\]cde]",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^[ab\\]cde]",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^[ab\\]cde]",[]))),
+?line <<"fthing">> = iolist_to_binary(join(re:split("fthing","^[ab\\]cde]",[trim]))),
+?line <<"fthing">> = iolist_to_binary(join(re:split("fthing","^[ab\\]cde]",[{parts,
+ 2}]))),
+?line <<"fthing">> = iolist_to_binary(join(re:split("fthing","^[ab\\]cde]",[]))),
+?line <<"[thing">> = iolist_to_binary(join(re:split("[thing","^[ab\\]cde]",[trim]))),
+?line <<"[thing">> = iolist_to_binary(join(re:split("[thing","^[ab\\]cde]",[{parts,
+ 2}]))),
+?line <<"[thing">> = iolist_to_binary(join(re:split("[thing","^[ab\\]cde]",[]))),
+?line <<"\\thing">> = iolist_to_binary(join(re:split("\\thing","^[ab\\]cde]",[trim]))),
+?line <<"\\thing">> = iolist_to_binary(join(re:split("\\thing","^[ab\\]cde]",[{parts,
+ 2}]))),
+?line <<"\\thing">> = iolist_to_binary(join(re:split("\\thing","^[ab\\]cde]",[]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("]thing","^[]cde]",[trim]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("]thing","^[]cde]",[{parts,
+ 2}]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("]thing","^[]cde]",[]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("cthing","^[]cde]",[trim]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("cthing","^[]cde]",[{parts,
+ 2}]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("cthing","^[]cde]",[]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("dthing","^[]cde]",[trim]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("dthing","^[]cde]",[{parts,
+ 2}]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("dthing","^[]cde]",[]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("ething","^[]cde]",[trim]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("ething","^[]cde]",[{parts,
+ 2}]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("ething","^[]cde]",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^[]cde]",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^[]cde]",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^[]cde]",[]))),
+?line <<"athing">> = iolist_to_binary(join(re:split("athing","^[]cde]",[trim]))),
+?line <<"athing">> = iolist_to_binary(join(re:split("athing","^[]cde]",[{parts,
+ 2}]))),
+?line <<"athing">> = iolist_to_binary(join(re:split("athing","^[]cde]",[]))),
+?line <<"fthing">> = iolist_to_binary(join(re:split("fthing","^[]cde]",[trim]))),
+?line <<"fthing">> = iolist_to_binary(join(re:split("fthing","^[]cde]",[{parts,
+ 2}]))),
+?line <<"fthing">> = iolist_to_binary(join(re:split("fthing","^[]cde]",[]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("fthing","^[^ab\\]cde]",[trim]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("fthing","^[^ab\\]cde]",[{parts,
+ 2}]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("fthing","^[^ab\\]cde]",[]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("[thing","^[^ab\\]cde]",[trim]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("[thing","^[^ab\\]cde]",[{parts,
+ 2}]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("[thing","^[^ab\\]cde]",[]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("\\thing","^[^ab\\]cde]",[trim]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("\\thing","^[^ab\\]cde]",[{parts,
+ 2}]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("\\thing","^[^ab\\]cde]",[]))),
+?line <<":** Failers">> = iolist_to_binary(join(re:split("*** Failers","^[^ab\\]cde]",[trim]))),
+?line <<":** Failers">> = iolist_to_binary(join(re:split("*** Failers","^[^ab\\]cde]",[{parts,
+ 2}]))),
+?line <<":** Failers">> = iolist_to_binary(join(re:split("*** Failers","^[^ab\\]cde]",[]))),
+?line <<"athing">> = iolist_to_binary(join(re:split("athing","^[^ab\\]cde]",[trim]))),
+?line <<"athing">> = iolist_to_binary(join(re:split("athing","^[^ab\\]cde]",[{parts,
+ 2}]))),
+?line <<"athing">> = iolist_to_binary(join(re:split("athing","^[^ab\\]cde]",[]))),
+?line <<"bthing">> = iolist_to_binary(join(re:split("bthing","^[^ab\\]cde]",[trim]))),
+?line <<"bthing">> = iolist_to_binary(join(re:split("bthing","^[^ab\\]cde]",[{parts,
+ 2}]))),
+?line <<"bthing">> = iolist_to_binary(join(re:split("bthing","^[^ab\\]cde]",[]))),
+?line <<"]thing">> = iolist_to_binary(join(re:split("]thing","^[^ab\\]cde]",[trim]))),
+?line <<"]thing">> = iolist_to_binary(join(re:split("]thing","^[^ab\\]cde]",[{parts,
+ 2}]))),
+?line <<"]thing">> = iolist_to_binary(join(re:split("]thing","^[^ab\\]cde]",[]))),
+?line <<"cthing">> = iolist_to_binary(join(re:split("cthing","^[^ab\\]cde]",[trim]))),
+?line <<"cthing">> = iolist_to_binary(join(re:split("cthing","^[^ab\\]cde]",[{parts,
+ 2}]))),
+?line <<"cthing">> = iolist_to_binary(join(re:split("cthing","^[^ab\\]cde]",[]))),
+?line <<"dthing">> = iolist_to_binary(join(re:split("dthing","^[^ab\\]cde]",[trim]))),
+?line <<"dthing">> = iolist_to_binary(join(re:split("dthing","^[^ab\\]cde]",[{parts,
+ 2}]))),
+?line <<"dthing">> = iolist_to_binary(join(re:split("dthing","^[^ab\\]cde]",[]))),
+?line <<"ething">> = iolist_to_binary(join(re:split("ething","^[^ab\\]cde]",[trim]))),
+?line <<"ething">> = iolist_to_binary(join(re:split("ething","^[^ab\\]cde]",[{parts,
+ 2}]))),
+?line <<"ething">> = iolist_to_binary(join(re:split("ething","^[^ab\\]cde]",[]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("athing","^[^]cde]",[trim]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("athing","^[^]cde]",[{parts,
+ 2}]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("athing","^[^]cde]",[]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("fthing","^[^]cde]",[trim]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("fthing","^[^]cde]",[{parts,
+ 2}]))),
+?line <<":thing">> = iolist_to_binary(join(re:split("fthing","^[^]cde]",[]))),
+?line <<":** Failers">> = iolist_to_binary(join(re:split("*** Failers","^[^]cde]",[trim]))),
+?line <<":** Failers">> = iolist_to_binary(join(re:split("*** Failers","^[^]cde]",[{parts,
+ 2}]))),
+?line <<":** Failers">> = iolist_to_binary(join(re:split("*** Failers","^[^]cde]",[]))),
+?line <<"]thing">> = iolist_to_binary(join(re:split("]thing","^[^]cde]",[trim]))),
+?line <<"]thing">> = iolist_to_binary(join(re:split("]thing","^[^]cde]",[{parts,
+ 2}]))),
+?line <<"]thing">> = iolist_to_binary(join(re:split("]thing","^[^]cde]",[]))),
+?line <<"cthing">> = iolist_to_binary(join(re:split("cthing","^[^]cde]",[trim]))),
+?line <<"cthing">> = iolist_to_binary(join(re:split("cthing","^[^]cde]",[{parts,
+ 2}]))),
+?line <<"cthing">> = iolist_to_binary(join(re:split("cthing","^[^]cde]",[]))),
+?line <<"dthing">> = iolist_to_binary(join(re:split("dthing","^[^]cde]",[trim]))),
+?line <<"dthing">> = iolist_to_binary(join(re:split("dthing","^[^]cde]",[{parts,
+ 2}]))),
+?line <<"dthing">> = iolist_to_binary(join(re:split("dthing","^[^]cde]",[]))),
+?line <<"ething">> = iolist_to_binary(join(re:split("ething","^[^]cde]",[trim]))),
+?line <<"ething">> = iolist_to_binary(join(re:split("ething","^[^]cde]",[{parts,
+ 2}]))),
+?line <<"ething">> = iolist_to_binary(join(re:split("ething","^[^]cde]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("�","^\\�",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("�","^\\�",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("�","^\\�",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("�","^�",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("�","^�",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("�","^�",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("0","^[0-9]+$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("0","^[0-9]+$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("0","^[0-9]+$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("1","^[0-9]+$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("1","^[0-9]+$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("1","^[0-9]+$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("2","^[0-9]+$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("2","^[0-9]+$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("2","^[0-9]+$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("3","^[0-9]+$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("3","^[0-9]+$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("3","^[0-9]+$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("4","^[0-9]+$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("4","^[0-9]+$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("4","^[0-9]+$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("5","^[0-9]+$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("5","^[0-9]+$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("5","^[0-9]+$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("6","^[0-9]+$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("6","^[0-9]+$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("6","^[0-9]+$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("7","^[0-9]+$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("7","^[0-9]+$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("7","^[0-9]+$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("8","^[0-9]+$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("8","^[0-9]+$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("8","^[0-9]+$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("9","^[0-9]+$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("9","^[0-9]+$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("9","^[0-9]+$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("10","^[0-9]+$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("10","^[0-9]+$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("10","^[0-9]+$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("100","^[0-9]+$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("100","^[0-9]+$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("100","^[0-9]+$",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^[0-9]+$",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^[0-9]+$",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^[0-9]+$",[]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","^[0-9]+$",[trim]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","^[0-9]+$",[{parts,
+ 2}]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","^[0-9]+$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("enter","^.*nter",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("enter","^.*nter",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("enter","^.*nter",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("inter","^.*nter",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("inter","^.*nter",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("inter","^.*nter",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("uponter","^.*nter",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("uponter","^.*nter",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("uponter","^.*nter",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("xxx0","^xxx[0-9]+$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("xxx0","^xxx[0-9]+$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("xxx0","^xxx[0-9]+$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("xxx1234","^xxx[0-9]+$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("xxx1234","^xxx[0-9]+$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("xxx1234","^xxx[0-9]+$",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^xxx[0-9]+$",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^xxx[0-9]+$",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^xxx[0-9]+$",[]))),
+?line <<"xxx">> = iolist_to_binary(join(re:split("xxx","^xxx[0-9]+$",[trim]))),
+?line <<"xxx">> = iolist_to_binary(join(re:split("xxx","^xxx[0-9]+$",[{parts,
+ 2}]))),
+?line <<"xxx">> = iolist_to_binary(join(re:split("xxx","^xxx[0-9]+$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("x123","^.+[0-9][0-9][0-9]$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("x123","^.+[0-9][0-9][0-9]$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("x123","^.+[0-9][0-9][0-9]$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("xx123","^.+[0-9][0-9][0-9]$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("xx123","^.+[0-9][0-9][0-9]$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("xx123","^.+[0-9][0-9][0-9]$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("123456","^.+[0-9][0-9][0-9]$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("123456","^.+[0-9][0-9][0-9]$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("123456","^.+[0-9][0-9][0-9]$",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^.+[0-9][0-9][0-9]$",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^.+[0-9][0-9][0-9]$",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^.+[0-9][0-9][0-9]$",[]))),
+?line <<"123">> = iolist_to_binary(join(re:split("123","^.+[0-9][0-9][0-9]$",[trim]))),
+?line <<"123">> = iolist_to_binary(join(re:split("123","^.+[0-9][0-9][0-9]$",[{parts,
+ 2}]))),
+?line <<"123">> = iolist_to_binary(join(re:split("123","^.+[0-9][0-9][0-9]$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("x1234","^.+[0-9][0-9][0-9]$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("x1234","^.+[0-9][0-9][0-9]$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("x1234","^.+[0-9][0-9][0-9]$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("x123","^.+?[0-9][0-9][0-9]$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("x123","^.+?[0-9][0-9][0-9]$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("x123","^.+?[0-9][0-9][0-9]$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("xx123","^.+?[0-9][0-9][0-9]$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("xx123","^.+?[0-9][0-9][0-9]$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("xx123","^.+?[0-9][0-9][0-9]$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("123456","^.+?[0-9][0-9][0-9]$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("123456","^.+?[0-9][0-9][0-9]$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("123456","^.+?[0-9][0-9][0-9]$",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^.+?[0-9][0-9][0-9]$",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^.+?[0-9][0-9][0-9]$",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^.+?[0-9][0-9][0-9]$",[]))),
+?line <<"123">> = iolist_to_binary(join(re:split("123","^.+?[0-9][0-9][0-9]$",[trim]))),
+?line <<"123">> = iolist_to_binary(join(re:split("123","^.+?[0-9][0-9][0-9]$",[{parts,
+ 2}]))),
+?line <<"123">> = iolist_to_binary(join(re:split("123","^.+?[0-9][0-9][0-9]$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("x1234","^.+?[0-9][0-9][0-9]$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("x1234","^.+?[0-9][0-9][0-9]$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("x1234","^.+?[0-9][0-9][0-9]$",[]))),
+?line <<":abc:pqr">> = iolist_to_binary(join(re:split("abc!pqr=apquxz.ixr.zzz.ac.uk","^([^!]+)!(.+)=apquxz\\.ixr\\.zzz\\.ac\\.uk$",[trim]))),
+?line <<":abc:pqr:">> = iolist_to_binary(join(re:split("abc!pqr=apquxz.ixr.zzz.ac.uk","^([^!]+)!(.+)=apquxz\\.ixr\\.zzz\\.ac\\.uk$",[{parts,
+ 2}]))),
+?line <<":abc:pqr:">> = iolist_to_binary(join(re:split("abc!pqr=apquxz.ixr.zzz.ac.uk","^([^!]+)!(.+)=apquxz\\.ixr\\.zzz\\.ac\\.uk$",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^([^!]+)!(.+)=apquxz\\.ixr\\.zzz\\.ac\\.uk$",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^([^!]+)!(.+)=apquxz\\.ixr\\.zzz\\.ac\\.uk$",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^([^!]+)!(.+)=apquxz\\.ixr\\.zzz\\.ac\\.uk$",[]))),
+?line <<"!pqr=apquxz.ixr.zzz.ac.uk">> = iolist_to_binary(join(re:split("!pqr=apquxz.ixr.zzz.ac.uk","^([^!]+)!(.+)=apquxz\\.ixr\\.zzz\\.ac\\.uk$",[trim]))),
+?line <<"!pqr=apquxz.ixr.zzz.ac.uk">> = iolist_to_binary(join(re:split("!pqr=apquxz.ixr.zzz.ac.uk","^([^!]+)!(.+)=apquxz\\.ixr\\.zzz\\.ac\\.uk$",[{parts,
+ 2}]))),
+?line <<"!pqr=apquxz.ixr.zzz.ac.uk">> = iolist_to_binary(join(re:split("!pqr=apquxz.ixr.zzz.ac.uk","^([^!]+)!(.+)=apquxz\\.ixr\\.zzz\\.ac\\.uk$",[]))),
+?line <<"abc!=apquxz.ixr.zzz.ac.uk">> = iolist_to_binary(join(re:split("abc!=apquxz.ixr.zzz.ac.uk","^([^!]+)!(.+)=apquxz\\.ixr\\.zzz\\.ac\\.uk$",[trim]))),
+?line <<"abc!=apquxz.ixr.zzz.ac.uk">> = iolist_to_binary(join(re:split("abc!=apquxz.ixr.zzz.ac.uk","^([^!]+)!(.+)=apquxz\\.ixr\\.zzz\\.ac\\.uk$",[{parts,
+ 2}]))),
+?line <<"abc!=apquxz.ixr.zzz.ac.uk">> = iolist_to_binary(join(re:split("abc!=apquxz.ixr.zzz.ac.uk","^([^!]+)!(.+)=apquxz\\.ixr\\.zzz\\.ac\\.uk$",[]))),
+?line <<"abc!pqr=apquxz:ixr.zzz.ac.uk">> = iolist_to_binary(join(re:split("abc!pqr=apquxz:ixr.zzz.ac.uk","^([^!]+)!(.+)=apquxz\\.ixr\\.zzz\\.ac\\.uk$",[trim]))),
+?line <<"abc!pqr=apquxz:ixr.zzz.ac.uk">> = iolist_to_binary(join(re:split("abc!pqr=apquxz:ixr.zzz.ac.uk","^([^!]+)!(.+)=apquxz\\.ixr\\.zzz\\.ac\\.uk$",[{parts,
+ 2}]))),
+?line <<"abc!pqr=apquxz:ixr.zzz.ac.uk">> = iolist_to_binary(join(re:split("abc!pqr=apquxz:ixr.zzz.ac.uk","^([^!]+)!(.+)=apquxz\\.ixr\\.zzz\\.ac\\.uk$",[]))),
+?line <<"abc!pqr=apquxz.ixr.zzz.ac.ukk">> = iolist_to_binary(join(re:split("abc!pqr=apquxz.ixr.zzz.ac.ukk","^([^!]+)!(.+)=apquxz\\.ixr\\.zzz\\.ac\\.uk$",[trim]))),
+?line <<"abc!pqr=apquxz.ixr.zzz.ac.ukk">> = iolist_to_binary(join(re:split("abc!pqr=apquxz.ixr.zzz.ac.ukk","^([^!]+)!(.+)=apquxz\\.ixr\\.zzz\\.ac\\.uk$",[{parts,
+ 2}]))),
+?line <<"abc!pqr=apquxz.ixr.zzz.ac.ukk">> = iolist_to_binary(join(re:split("abc!pqr=apquxz.ixr.zzz.ac.ukk","^([^!]+)!(.+)=apquxz\\.ixr\\.zzz\\.ac\\.uk$",[]))),
+?line <<"Well, we need a colon: somewhere">> = iolist_to_binary(join(re:split("Well, we need a colon: somewhere",":",[trim]))),
+?line <<"Well, we need a colon: somewhere">> = iolist_to_binary(join(re:split("Well, we need a colon: somewhere",":",[{parts,
+ 2}]))),
+?line <<"Well, we need a colon: somewhere">> = iolist_to_binary(join(re:split("Well, we need a colon: somewhere",":",[]))),
+?line <<"*** Fail if we don't">> = iolist_to_binary(join(re:split("*** Fail if we don't",":",[trim]))),
+?line <<"*** Fail if we don't">> = iolist_to_binary(join(re:split("*** Fail if we don't",":",[{parts,
+ 2}]))),
+?line <<"*** Fail if we don't">> = iolist_to_binary(join(re:split("*** Fail if we don't",":",[]))),
+?line <<":0abc">> = iolist_to_binary(join(re:split("0abc","([\\da-f:]+)$",[caseless,
+ trim]))),
+?line <<":0abc:">> = iolist_to_binary(join(re:split("0abc","([\\da-f:]+)$",[caseless,
+ {parts,
+ 2}]))),
+?line <<":0abc:">> = iolist_to_binary(join(re:split("0abc","([\\da-f:]+)$",[caseless]))),
+?line <<":abc">> = iolist_to_binary(join(re:split("abc","([\\da-f:]+)$",[caseless,
+ trim]))),
+?line <<":abc:">> = iolist_to_binary(join(re:split("abc","([\\da-f:]+)$",[caseless,
+ {parts,
+ 2}]))),
+?line <<":abc:">> = iolist_to_binary(join(re:split("abc","([\\da-f:]+)$",[caseless]))),
+?line <<":fed">> = iolist_to_binary(join(re:split("fed","([\\da-f:]+)$",[caseless,
+ trim]))),
+?line <<":fed:">> = iolist_to_binary(join(re:split("fed","([\\da-f:]+)$",[caseless,
+ {parts,
+ 2}]))),
+?line <<":fed:">> = iolist_to_binary(join(re:split("fed","([\\da-f:]+)$",[caseless]))),
+?line <<":E">> = iolist_to_binary(join(re:split("E","([\\da-f:]+)$",[caseless,
+ trim]))),
+?line <<":E:">> = iolist_to_binary(join(re:split("E","([\\da-f:]+)$",[caseless,
+ {parts,
+ 2}]))),
+?line <<":E:">> = iolist_to_binary(join(re:split("E","([\\da-f:]+)$",[caseless]))),
+?line <<":::">> = iolist_to_binary(join(re:split("::","([\\da-f:]+)$",[caseless,
+ trim]))),
+?line <<"::::">> = iolist_to_binary(join(re:split("::","([\\da-f:]+)$",[caseless,
+ {parts,
+ 2}]))),
+?line <<"::::">> = iolist_to_binary(join(re:split("::","([\\da-f:]+)$",[caseless]))),
+?line <<":5f03:12C0::932e">> = iolist_to_binary(join(re:split("5f03:12C0::932e","([\\da-f:]+)$",[caseless,
+ trim]))),
+?line <<":5f03:12C0::932e:">> = iolist_to_binary(join(re:split("5f03:12C0::932e","([\\da-f:]+)$",[caseless,
+ {parts,
+ 2}]))),
+?line <<":5f03:12C0::932e:">> = iolist_to_binary(join(re:split("5f03:12C0::932e","([\\da-f:]+)$",[caseless]))),
+?line <<"fed :def">> = iolist_to_binary(join(re:split("fed def","([\\da-f:]+)$",[caseless,
+ trim]))),
+?line <<"fed :def:">> = iolist_to_binary(join(re:split("fed def","([\\da-f:]+)$",[caseless,
+ {parts,
+ 2}]))),
+?line <<"fed :def:">> = iolist_to_binary(join(re:split("fed def","([\\da-f:]+)$",[caseless]))),
+?line <<"Any old stu:ff">> = iolist_to_binary(join(re:split("Any old stuff","([\\da-f:]+)$",[caseless,
+ trim]))),
+?line <<"Any old stu:ff:">> = iolist_to_binary(join(re:split("Any old stuff","([\\da-f:]+)$",[caseless,
+ {parts,
+ 2}]))),
+?line <<"Any old stu:ff:">> = iolist_to_binary(join(re:split("Any old stuff","([\\da-f:]+)$",[caseless]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","([\\da-f:]+)$",[caseless,
+ trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","([\\da-f:]+)$",[caseless,
+ {parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","([\\da-f:]+)$",[caseless]))),
+?line <<"0zzz">> = iolist_to_binary(join(re:split("0zzz","([\\da-f:]+)$",[caseless,
+ trim]))),
+?line <<"0zzz">> = iolist_to_binary(join(re:split("0zzz","([\\da-f:]+)$",[caseless,
+ {parts,
+ 2}]))),
+?line <<"0zzz">> = iolist_to_binary(join(re:split("0zzz","([\\da-f:]+)$",[caseless]))),
+?line <<"gzzz">> = iolist_to_binary(join(re:split("gzzz","([\\da-f:]+)$",[caseless,
+ trim]))),
+?line <<"gzzz">> = iolist_to_binary(join(re:split("gzzz","([\\da-f:]+)$",[caseless,
+ {parts,
+ 2}]))),
+?line <<"gzzz">> = iolist_to_binary(join(re:split("gzzz","([\\da-f:]+)$",[caseless]))),
+?line <<"fed ">> = iolist_to_binary(join(re:split("fed ","([\\da-f:]+)$",[caseless,
+ trim]))),
+?line <<"fed ">> = iolist_to_binary(join(re:split("fed ","([\\da-f:]+)$",[caseless,
+ {parts,
+ 2}]))),
+?line <<"fed ">> = iolist_to_binary(join(re:split("fed ","([\\da-f:]+)$",[caseless]))),
+?line <<"Any old rubbish">> = iolist_to_binary(join(re:split("Any old rubbish","([\\da-f:]+)$",[caseless,
+ trim]))),
+?line <<"Any old rubbish">> = iolist_to_binary(join(re:split("Any old rubbish","([\\da-f:]+)$",[caseless,
+ {parts,
+ 2}]))),
+?line <<"Any old rubbish">> = iolist_to_binary(join(re:split("Any old rubbish","([\\da-f:]+)$",[caseless]))),
+?line <<":1:2:3">> = iolist_to_binary(join(re:split(".1.2.3","^.*\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$",[trim]))),
+?line <<":1:2:3:">> = iolist_to_binary(join(re:split(".1.2.3","^.*\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$",[{parts,
+ 2}]))),
+?line <<":1:2:3:">> = iolist_to_binary(join(re:split(".1.2.3","^.*\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$",[]))),
+?line <<":12:123:0">> = iolist_to_binary(join(re:split("A.12.123.0","^.*\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$",[trim]))),
+?line <<":12:123:0:">> = iolist_to_binary(join(re:split("A.12.123.0","^.*\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$",[{parts,
+ 2}]))),
+?line <<":12:123:0:">> = iolist_to_binary(join(re:split("A.12.123.0","^.*\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^.*\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^.*\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^.*\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$",[]))),
+?line <<".1.2.3333">> = iolist_to_binary(join(re:split(".1.2.3333","^.*\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$",[trim]))),
+?line <<".1.2.3333">> = iolist_to_binary(join(re:split(".1.2.3333","^.*\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$",[{parts,
+ 2}]))),
+?line <<".1.2.3333">> = iolist_to_binary(join(re:split(".1.2.3333","^.*\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$",[]))),
+?line <<"1.2.3">> = iolist_to_binary(join(re:split("1.2.3","^.*\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$",[trim]))),
+?line <<"1.2.3">> = iolist_to_binary(join(re:split("1.2.3","^.*\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$",[{parts,
+ 2}]))),
+?line <<"1.2.3">> = iolist_to_binary(join(re:split("1.2.3","^.*\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$",[]))),
+?line <<"1234.2.3">> = iolist_to_binary(join(re:split("1234.2.3","^.*\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$",[trim]))),
+?line <<"1234.2.3">> = iolist_to_binary(join(re:split("1234.2.3","^.*\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$",[{parts,
+ 2}]))),
+?line <<"1234.2.3">> = iolist_to_binary(join(re:split("1234.2.3","^.*\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$",[]))),
+?line <<":1:non-sp1:non-sp2">> = iolist_to_binary(join(re:split("1 IN SOA non-sp1 non-sp2(","^(\\d+)\\s+IN\\s+SOA\\s+(\\S+)\\s+(\\S+)\\s*\\(\\s*$",[trim]))),
+?line <<":1:non-sp1:non-sp2:">> = iolist_to_binary(join(re:split("1 IN SOA non-sp1 non-sp2(","^(\\d+)\\s+IN\\s+SOA\\s+(\\S+)\\s+(\\S+)\\s*\\(\\s*$",[{parts,
+ 2}]))),
+?line <<":1:non-sp1:non-sp2:">> = iolist_to_binary(join(re:split("1 IN SOA non-sp1 non-sp2(","^(\\d+)\\s+IN\\s+SOA\\s+(\\S+)\\s+(\\S+)\\s*\\(\\s*$",[]))),
+?line <<":1:non-sp1:non-sp2">> = iolist_to_binary(join(re:split("1 IN SOA non-sp1 non-sp2 (","^(\\d+)\\s+IN\\s+SOA\\s+(\\S+)\\s+(\\S+)\\s*\\(\\s*$",[trim]))),
+?line <<":1:non-sp1:non-sp2:">> = iolist_to_binary(join(re:split("1 IN SOA non-sp1 non-sp2 (","^(\\d+)\\s+IN\\s+SOA\\s+(\\S+)\\s+(\\S+)\\s*\\(\\s*$",[{parts,
+ 2}]))),
+?line <<":1:non-sp1:non-sp2:">> = iolist_to_binary(join(re:split("1 IN SOA non-sp1 non-sp2 (","^(\\d+)\\s+IN\\s+SOA\\s+(\\S+)\\s+(\\S+)\\s*\\(\\s*$",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(\\d+)\\s+IN\\s+SOA\\s+(\\S+)\\s+(\\S+)\\s*\\(\\s*$",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(\\d+)\\s+IN\\s+SOA\\s+(\\S+)\\s+(\\S+)\\s*\\(\\s*$",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(\\d+)\\s+IN\\s+SOA\\s+(\\S+)\\s+(\\S+)\\s*\\(\\s*$",[]))),
+?line <<"1IN SOA non-sp1 non-sp2(">> = iolist_to_binary(join(re:split("1IN SOA non-sp1 non-sp2(","^(\\d+)\\s+IN\\s+SOA\\s+(\\S+)\\s+(\\S+)\\s*\\(\\s*$",[trim]))),
+?line <<"1IN SOA non-sp1 non-sp2(">> = iolist_to_binary(join(re:split("1IN SOA non-sp1 non-sp2(","^(\\d+)\\s+IN\\s+SOA\\s+(\\S+)\\s+(\\S+)\\s*\\(\\s*$",[{parts,
+ 2}]))),
+?line <<"1IN SOA non-sp1 non-sp2(">> = iolist_to_binary(join(re:split("1IN SOA non-sp1 non-sp2(","^(\\d+)\\s+IN\\s+SOA\\s+(\\S+)\\s+(\\S+)\\s*\\(\\s*$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a.","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("a.","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("a.","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("Z.","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("Z.","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("Z.","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("2.","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("2.","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("2.","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$",[]))),
+?line <<":.pq-r">> = iolist_to_binary(join(re:split("ab-c.pq-r.","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$",[trim]))),
+?line <<":.pq-r:">> = iolist_to_binary(join(re:split("ab-c.pq-r.","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$",[{parts,
+ 2}]))),
+?line <<":.pq-r:">> = iolist_to_binary(join(re:split("ab-c.pq-r.","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$",[]))),
+?line <<":.uk">> = iolist_to_binary(join(re:split("sxk.zzz.ac.uk.","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$",[trim]))),
+?line <<":.uk:">> = iolist_to_binary(join(re:split("sxk.zzz.ac.uk.","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$",[{parts,
+ 2}]))),
+?line <<":.uk:">> = iolist_to_binary(join(re:split("sxk.zzz.ac.uk.","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$",[]))),
+?line <<":.y-">> = iolist_to_binary(join(re:split("x-.y-.","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$",[trim]))),
+?line <<":.y-:">> = iolist_to_binary(join(re:split("x-.y-.","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$",[{parts,
+ 2}]))),
+?line <<":.y-:">> = iolist_to_binary(join(re:split("x-.y-.","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$",[]))),
+?line <<"-abc.peq.">> = iolist_to_binary(join(re:split("-abc.peq.","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$",[trim]))),
+?line <<"-abc.peq.">> = iolist_to_binary(join(re:split("-abc.peq.","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$",[{parts,
+ 2}]))),
+?line <<"-abc.peq.">> = iolist_to_binary(join(re:split("-abc.peq.","^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("*.a","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$",[trim]))),
+?line <<"::::">> = iolist_to_binary(join(re:split("*.a","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$",[{parts,
+ 2}]))),
+?line <<"::::">> = iolist_to_binary(join(re:split("*.a","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$",[]))),
+?line <<":0-a">> = iolist_to_binary(join(re:split("*.b0-a","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$",[trim]))),
+?line <<":0-a:::">> = iolist_to_binary(join(re:split("*.b0-a","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$",[{parts,
+ 2}]))),
+?line <<":0-a:::">> = iolist_to_binary(join(re:split("*.b0-a","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$",[]))),
+?line <<":3-b:.c">> = iolist_to_binary(join(re:split("*.c3-b.c","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$",[trim]))),
+?line <<":3-b:.c::">> = iolist_to_binary(join(re:split("*.c3-b.c","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$",[{parts,
+ 2}]))),
+?line <<":3-b:.c::">> = iolist_to_binary(join(re:split("*.c3-b.c","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$",[]))),
+?line <<":-a:.b-c:-c">> = iolist_to_binary(join(re:split("*.c-a.b-c","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$",[trim]))),
+?line <<":-a:.b-c:-c:">> = iolist_to_binary(join(re:split("*.c-a.b-c","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$",[{parts,
+ 2}]))),
+?line <<":-a:.b-c:-c:">> = iolist_to_binary(join(re:split("*.c-a.b-c","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$",[]))),
+?line <<"*.0">> = iolist_to_binary(join(re:split("*.0","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$",[trim]))),
+?line <<"*.0">> = iolist_to_binary(join(re:split("*.0","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$",[{parts,
+ 2}]))),
+?line <<"*.0">> = iolist_to_binary(join(re:split("*.0","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$",[]))),
+?line <<"*.a-">> = iolist_to_binary(join(re:split("*.a-","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$",[trim]))),
+?line <<"*.a-">> = iolist_to_binary(join(re:split("*.a-","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$",[{parts,
+ 2}]))),
+?line <<"*.a-">> = iolist_to_binary(join(re:split("*.a-","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$",[]))),
+?line <<"*.a-b.c-">> = iolist_to_binary(join(re:split("*.a-b.c-","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$",[trim]))),
+?line <<"*.a-b.c-">> = iolist_to_binary(join(re:split("*.a-b.c-","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$",[{parts,
+ 2}]))),
+?line <<"*.a-b.c-">> = iolist_to_binary(join(re:split("*.a-b.c-","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$",[]))),
+?line <<"*.c-a.0-c">> = iolist_to_binary(join(re:split("*.c-a.0-c","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$",[trim]))),
+?line <<"*.c-a.0-c">> = iolist_to_binary(join(re:split("*.c-a.0-c","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$",[{parts,
+ 2}]))),
+?line <<"*.c-a.0-c">> = iolist_to_binary(join(re:split("*.c-a.0-c","^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$",[]))),
+?line <<":de:abd:e">> = iolist_to_binary(join(re:split("abde","^(?=ab(de))(abd)(e)",[trim]))),
+?line <<":de:abd:e:">> = iolist_to_binary(join(re:split("abde","^(?=ab(de))(abd)(e)",[{parts,
+ 2}]))),
+?line <<":de:abd:e:">> = iolist_to_binary(join(re:split("abde","^(?=ab(de))(abd)(e)",[]))),
+?line <<"::abd:f">> = iolist_to_binary(join(re:split("abdf","^(?!(ab)de|x)(abd)(f)",[trim]))),
+?line <<"::abd:f:">> = iolist_to_binary(join(re:split("abdf","^(?!(ab)de|x)(abd)(f)",[{parts,
+ 2}]))),
+?line <<"::abd:f:">> = iolist_to_binary(join(re:split("abdf","^(?!(ab)de|x)(abd)(f)",[]))),
+?line <<":abcd:cd:ab:cd">> = iolist_to_binary(join(re:split("abcd","^(?=(ab(cd)))(ab)",[trim]))),
+?line <<":abcd:cd:ab:cd">> = iolist_to_binary(join(re:split("abcd","^(?=(ab(cd)))(ab)",[{parts,
+ 2}]))),
+?line <<":abcd:cd:ab:cd">> = iolist_to_binary(join(re:split("abcd","^(?=(ab(cd)))(ab)",[]))),
+?line <<":.d">> = iolist_to_binary(join(re:split("a.b.c.d","^[\\da-f](\\.[\\da-f])*$",[caseless,
+ trim]))),
+?line <<":.d:">> = iolist_to_binary(join(re:split("a.b.c.d","^[\\da-f](\\.[\\da-f])*$",[caseless,
+ {parts,
+ 2}]))),
+?line <<":.d:">> = iolist_to_binary(join(re:split("a.b.c.d","^[\\da-f](\\.[\\da-f])*$",[caseless]))),
+?line <<":.D">> = iolist_to_binary(join(re:split("A.B.C.D","^[\\da-f](\\.[\\da-f])*$",[caseless,
+ trim]))),
+?line <<":.D:">> = iolist_to_binary(join(re:split("A.B.C.D","^[\\da-f](\\.[\\da-f])*$",[caseless,
+ {parts,
+ 2}]))),
+?line <<":.D:">> = iolist_to_binary(join(re:split("A.B.C.D","^[\\da-f](\\.[\\da-f])*$",[caseless]))),
+?line <<":.C">> = iolist_to_binary(join(re:split("a.b.c.1.2.3.C","^[\\da-f](\\.[\\da-f])*$",[caseless,
+ trim]))),
+?line <<":.C:">> = iolist_to_binary(join(re:split("a.b.c.1.2.3.C","^[\\da-f](\\.[\\da-f])*$",[caseless,
+ {parts,
+ 2}]))),
+?line <<":.C:">> = iolist_to_binary(join(re:split("a.b.c.1.2.3.C","^[\\da-f](\\.[\\da-f])*$",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("\"1234\"","^\\\".*\\\"\\s*(;.*)?$",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("\"1234\"","^\\\".*\\\"\\s*(;.*)?$",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("\"1234\"","^\\\".*\\\"\\s*(;.*)?$",[]))),
+?line <<":;">> = iolist_to_binary(join(re:split("\"abcd\" ;","^\\\".*\\\"\\s*(;.*)?$",[trim]))),
+?line <<":;:">> = iolist_to_binary(join(re:split("\"abcd\" ;","^\\\".*\\\"\\s*(;.*)?$",[{parts,
+ 2}]))),
+?line <<":;:">> = iolist_to_binary(join(re:split("\"abcd\" ;","^\\\".*\\\"\\s*(;.*)?$",[]))),
+?line <<":; rhubarb">> = iolist_to_binary(join(re:split("\"\" ; rhubarb","^\\\".*\\\"\\s*(;.*)?$",[trim]))),
+?line <<":; rhubarb:">> = iolist_to_binary(join(re:split("\"\" ; rhubarb","^\\\".*\\\"\\s*(;.*)?$",[{parts,
+ 2}]))),
+?line <<":; rhubarb:">> = iolist_to_binary(join(re:split("\"\" ; rhubarb","^\\\".*\\\"\\s*(;.*)?$",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^\\\".*\\\"\\s*(;.*)?$",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^\\\".*\\\"\\s*(;.*)?$",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^\\\".*\\\"\\s*(;.*)?$",[]))),
+?line <<"\"1234\" : things">> = iolist_to_binary(join(re:split("\"1234\" : things","^\\\".*\\\"\\s*(;.*)?$",[trim]))),
+?line <<"\"1234\" : things">> = iolist_to_binary(join(re:split("\"1234\" : things","^\\\".*\\\"\\s*(;.*)?$",[{parts,
+ 2}]))),
+?line <<"\"1234\" : things">> = iolist_to_binary(join(re:split("\"1234\" : things","^\\\".*\\\"\\s*(;.*)?$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("","^$",[trim]))),
+?line <<"">> = iolist_to_binary(join(re:split("","^$",[{parts,
+ 2}]))),
+?line <<"">> = iolist_to_binary(join(re:split("","^$",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^$",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^$",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("ab c"," ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)",[extended,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ab c"," ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)",[extended,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ab c"," ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)",[extended]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers"," ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)",[extended,
+ trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers"," ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)",[extended,
+ {parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers"," ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)",[extended]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc"," ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)",[extended,
+ trim]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc"," ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)",[extended,
+ {parts,
+ 2}]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc"," ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)",[extended]))),
+?line <<"ab cde">> = iolist_to_binary(join(re:split("ab cde"," ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)",[extended,
+ trim]))),
+?line <<"ab cde">> = iolist_to_binary(join(re:split("ab cde"," ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)",[extended,
+ {parts,
+ 2}]))),
+?line <<"ab cde">> = iolist_to_binary(join(re:split("ab cde"," ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)",[extended]))),
+?line <<"">> = iolist_to_binary(join(re:split("ab c","(?x) ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ab c","(?x) ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ab c","(?x) ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?x) ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?x) ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?x) ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)",[]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","(?x) ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)",[trim]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","(?x) ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)",[{parts,
+ 2}]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","(?x) ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)",[]))),
+?line <<"ab cde">> = iolist_to_binary(join(re:split("ab cde","(?x) ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)",[trim]))),
+?line <<"ab cde">> = iolist_to_binary(join(re:split("ab cde","(?x) ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)",[{parts,
+ 2}]))),
+?line <<"ab cde">> = iolist_to_binary(join(re:split("ab cde","(?x) ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a bcd","^ a\\ b[c ]d $",[extended,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a bcd","^ a\\ b[c ]d $",[extended,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a bcd","^ a\\ b[c ]d $",[extended]))),
+?line <<"">> = iolist_to_binary(join(re:split("a b d","^ a\\ b[c ]d $",[extended,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a b d","^ a\\ b[c ]d $",[extended,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a b d","^ a\\ b[c ]d $",[extended]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^ a\\ b[c ]d $",[extended,
+ trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^ a\\ b[c ]d $",[extended,
+ {parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^ a\\ b[c ]d $",[extended]))),
+?line <<"abcd">> = iolist_to_binary(join(re:split("abcd","^ a\\ b[c ]d $",[extended,
+ trim]))),
+?line <<"abcd">> = iolist_to_binary(join(re:split("abcd","^ a\\ b[c ]d $",[extended,
+ {parts,
+ 2}]))),
+?line <<"abcd">> = iolist_to_binary(join(re:split("abcd","^ a\\ b[c ]d $",[extended]))),
+?line <<"ab d">> = iolist_to_binary(join(re:split("ab d","^ a\\ b[c ]d $",[extended,
+ trim]))),
+?line <<"ab d">> = iolist_to_binary(join(re:split("ab d","^ a\\ b[c ]d $",[extended,
+ {parts,
+ 2}]))),
+?line <<"ab d">> = iolist_to_binary(join(re:split("ab d","^ a\\ b[c ]d $",[extended]))),
+?line <<":abc:bc:c:def:ef:f:hij:ij:j:klm:lm:m">> = iolist_to_binary(join(re:split("abcdefhijklm","^(a(b(c)))(d(e(f)))(h(i(j)))(k(l(m)))$",[trim]))),
+?line <<":abc:bc:c:def:ef:f:hij:ij:j:klm:lm:m:">> = iolist_to_binary(join(re:split("abcdefhijklm","^(a(b(c)))(d(e(f)))(h(i(j)))(k(l(m)))$",[{parts,
+ 2}]))),
+?line <<":abc:bc:c:def:ef:f:hij:ij:j:klm:lm:m:">> = iolist_to_binary(join(re:split("abcdefhijklm","^(a(b(c)))(d(e(f)))(h(i(j)))(k(l(m)))$",[]))),
+?line <<":bc:c:ef:f:ij:j:lm:m">> = iolist_to_binary(join(re:split("abcdefhijklm","^(?:a(b(c)))(?:d(e(f)))(?:h(i(j)))(?:k(l(m)))$",[trim]))),
+?line <<":bc:c:ef:f:ij:j:lm:m:">> = iolist_to_binary(join(re:split("abcdefhijklm","^(?:a(b(c)))(?:d(e(f)))(?:h(i(j)))(?:k(l(m)))$",[{parts,
+ 2}]))),
+?line <<":bc:c:ef:f:ij:j:lm:m:">> = iolist_to_binary(join(re:split("abcdefhijklm","^(?:a(b(c)))(?:d(e(f)))(?:h(i(j)))(?:k(l(m)))$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a+ Z0+
+","^[\\w][\\W][\\s][\\S][\\d][\\D][\\b][\\n][\\c]][\\022]",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a+ Z0+
+","^[\\w][\\W][\\s][\\S][\\d][\\D][\\b][\\n][\\c]][\\022]",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a+ Z0+
+","^[\\w][\\W][\\s][\\S][\\d][\\D][\\b][\\n][\\c]][\\022]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split(".^$(*+)|{?,?}","^[.^$|()*+?{,}]+",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split(".^$(*+)|{?,?}","^[.^$|()*+?{,}]+",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split(".^$(*+)|{?,?}","^[.^$|()*+?{,}]+",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("z","^a*\\w",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("z","^a*\\w",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("z","^a*\\w",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("az","^a*\\w",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("az","^a*\\w",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("az","^a*\\w",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaaz","^a*\\w",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaz","^a*\\w",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaz","^a*\\w",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a","^a*\\w",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","^a*\\w",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","^a*\\w",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aa","^a*\\w",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aa","^a*\\w",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aa","^a*\\w",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaaa","^a*\\w",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaa","^a*\\w",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaa","^a*\\w",[]))),
+?line <<":+">> = iolist_to_binary(join(re:split("a+","^a*\\w",[trim]))),
+?line <<":+">> = iolist_to_binary(join(re:split("a+","^a*\\w",[{parts,
+ 2}]))),
+?line <<":+">> = iolist_to_binary(join(re:split("a+","^a*\\w",[]))),
+?line <<":+">> = iolist_to_binary(join(re:split("aa+","^a*\\w",[trim]))),
+?line <<":+">> = iolist_to_binary(join(re:split("aa+","^a*\\w",[{parts,
+ 2}]))),
+?line <<":+">> = iolist_to_binary(join(re:split("aa+","^a*\\w",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("z","^a*?\\w",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("z","^a*?\\w",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("z","^a*?\\w",[]))),
+?line <<":z">> = iolist_to_binary(join(re:split("az","^a*?\\w",[trim]))),
+?line <<":z">> = iolist_to_binary(join(re:split("az","^a*?\\w",[{parts,
+ 2}]))),
+?line <<":z">> = iolist_to_binary(join(re:split("az","^a*?\\w",[]))),
+?line <<":aaz">> = iolist_to_binary(join(re:split("aaaz","^a*?\\w",[trim]))),
+?line <<":aaz">> = iolist_to_binary(join(re:split("aaaz","^a*?\\w",[{parts,
+ 2}]))),
+?line <<":aaz">> = iolist_to_binary(join(re:split("aaaz","^a*?\\w",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a","^a*?\\w",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","^a*?\\w",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","^a*?\\w",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("aa","^a*?\\w",[trim]))),
+?line <<":a">> = iolist_to_binary(join(re:split("aa","^a*?\\w",[{parts,
+ 2}]))),
+?line <<":a">> = iolist_to_binary(join(re:split("aa","^a*?\\w",[]))),
+?line <<":aaa">> = iolist_to_binary(join(re:split("aaaa","^a*?\\w",[trim]))),
+?line <<":aaa">> = iolist_to_binary(join(re:split("aaaa","^a*?\\w",[{parts,
+ 2}]))),
+?line <<":aaa">> = iolist_to_binary(join(re:split("aaaa","^a*?\\w",[]))),
+?line <<":+">> = iolist_to_binary(join(re:split("a+","^a*?\\w",[trim]))),
+?line <<":+">> = iolist_to_binary(join(re:split("a+","^a*?\\w",[{parts,
+ 2}]))),
+?line <<":+">> = iolist_to_binary(join(re:split("a+","^a*?\\w",[]))),
+?line <<":a+">> = iolist_to_binary(join(re:split("aa+","^a*?\\w",[trim]))),
+?line <<":a+">> = iolist_to_binary(join(re:split("aa+","^a*?\\w",[{parts,
+ 2}]))),
+?line <<":a+">> = iolist_to_binary(join(re:split("aa+","^a*?\\w",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("az","^a+\\w",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("az","^a+\\w",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("az","^a+\\w",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaaz","^a+\\w",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaz","^a+\\w",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaz","^a+\\w",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aa","^a+\\w",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aa","^a+\\w",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aa","^a+\\w",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaaa","^a+\\w",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaa","^a+\\w",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaa","^a+\\w",[]))),
+?line <<":+">> = iolist_to_binary(join(re:split("aa+","^a+\\w",[trim]))),
+?line <<":+">> = iolist_to_binary(join(re:split("aa+","^a+\\w",[{parts,
+ 2}]))),
+?line <<":+">> = iolist_to_binary(join(re:split("aa+","^a+\\w",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("az","^a+?\\w",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("az","^a+?\\w",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("az","^a+?\\w",[]))),
+?line <<":az">> = iolist_to_binary(join(re:split("aaaz","^a+?\\w",[trim]))),
+?line <<":az">> = iolist_to_binary(join(re:split("aaaz","^a+?\\w",[{parts,
+ 2}]))),
+?line <<":az">> = iolist_to_binary(join(re:split("aaaz","^a+?\\w",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aa","^a+?\\w",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aa","^a+?\\w",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aa","^a+?\\w",[]))),
+?line <<":aa">> = iolist_to_binary(join(re:split("aaaa","^a+?\\w",[trim]))),
+?line <<":aa">> = iolist_to_binary(join(re:split("aaaa","^a+?\\w",[{parts,
+ 2}]))),
+?line <<":aa">> = iolist_to_binary(join(re:split("aaaa","^a+?\\w",[]))),
+?line <<":+">> = iolist_to_binary(join(re:split("aa+","^a+?\\w",[trim]))),
+?line <<":+">> = iolist_to_binary(join(re:split("aa+","^a+?\\w",[{parts,
+ 2}]))),
+?line <<":+">> = iolist_to_binary(join(re:split("aa+","^a+?\\w",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("1234567890","^\\d{8}\\w{2,}",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("1234567890","^\\d{8}\\w{2,}",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("1234567890","^\\d{8}\\w{2,}",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("12345678ab","^\\d{8}\\w{2,}",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("12345678ab","^\\d{8}\\w{2,}",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("12345678ab","^\\d{8}\\w{2,}",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("12345678__","^\\d{8}\\w{2,}",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("12345678__","^\\d{8}\\w{2,}",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("12345678__","^\\d{8}\\w{2,}",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^\\d{8}\\w{2,}",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^\\d{8}\\w{2,}",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^\\d{8}\\w{2,}",[]))),
+?line <<"1234567">> = iolist_to_binary(join(re:split("1234567","^\\d{8}\\w{2,}",[trim]))),
+?line <<"1234567">> = iolist_to_binary(join(re:split("1234567","^\\d{8}\\w{2,}",[{parts,
+ 2}]))),
+?line <<"1234567">> = iolist_to_binary(join(re:split("1234567","^\\d{8}\\w{2,}",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("uoie","^[aeiou\\d]{4,5}$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("uoie","^[aeiou\\d]{4,5}$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("uoie","^[aeiou\\d]{4,5}$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("1234","^[aeiou\\d]{4,5}$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("1234","^[aeiou\\d]{4,5}$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("1234","^[aeiou\\d]{4,5}$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("12345","^[aeiou\\d]{4,5}$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("12345","^[aeiou\\d]{4,5}$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("12345","^[aeiou\\d]{4,5}$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaaaa","^[aeiou\\d]{4,5}$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaaa","^[aeiou\\d]{4,5}$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaaa","^[aeiou\\d]{4,5}$",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^[aeiou\\d]{4,5}$",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^[aeiou\\d]{4,5}$",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^[aeiou\\d]{4,5}$",[]))),
+?line <<"123456">> = iolist_to_binary(join(re:split("123456","^[aeiou\\d]{4,5}$",[trim]))),
+?line <<"123456">> = iolist_to_binary(join(re:split("123456","^[aeiou\\d]{4,5}$",[{parts,
+ 2}]))),
+?line <<"123456">> = iolist_to_binary(join(re:split("123456","^[aeiou\\d]{4,5}$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("uoie","^[aeiou\\d]{4,5}?",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("uoie","^[aeiou\\d]{4,5}?",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("uoie","^[aeiou\\d]{4,5}?",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("1234","^[aeiou\\d]{4,5}?",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("1234","^[aeiou\\d]{4,5}?",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("1234","^[aeiou\\d]{4,5}?",[]))),
+?line <<":5">> = iolist_to_binary(join(re:split("12345","^[aeiou\\d]{4,5}?",[trim]))),
+?line <<":5">> = iolist_to_binary(join(re:split("12345","^[aeiou\\d]{4,5}?",[{parts,
+ 2}]))),
+?line <<":5">> = iolist_to_binary(join(re:split("12345","^[aeiou\\d]{4,5}?",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("aaaaa","^[aeiou\\d]{4,5}?",[trim]))),
+?line <<":a">> = iolist_to_binary(join(re:split("aaaaa","^[aeiou\\d]{4,5}?",[{parts,
+ 2}]))),
+?line <<":a">> = iolist_to_binary(join(re:split("aaaaa","^[aeiou\\d]{4,5}?",[]))),
+?line <<":56">> = iolist_to_binary(join(re:split("123456","^[aeiou\\d]{4,5}?",[trim]))),
+?line <<":56">> = iolist_to_binary(join(re:split("123456","^[aeiou\\d]{4,5}?",[{parts,
+ 2}]))),
+?line <<":56">> = iolist_to_binary(join(re:split("123456","^[aeiou\\d]{4,5}?",[]))),
+?line <<":abc:abc">> = iolist_to_binary(join(re:split("abc=abcabc","\\A(abc|def)=(\\1){2,3}\\Z",[trim]))),
+?line <<":abc:abc:">> = iolist_to_binary(join(re:split("abc=abcabc","\\A(abc|def)=(\\1){2,3}\\Z",[{parts,
+ 2}]))),
+?line <<":abc:abc:">> = iolist_to_binary(join(re:split("abc=abcabc","\\A(abc|def)=(\\1){2,3}\\Z",[]))),
+?line <<":def:def">> = iolist_to_binary(join(re:split("def=defdefdef","\\A(abc|def)=(\\1){2,3}\\Z",[trim]))),
+?line <<":def:def:">> = iolist_to_binary(join(re:split("def=defdefdef","\\A(abc|def)=(\\1){2,3}\\Z",[{parts,
+ 2}]))),
+?line <<":def:def:">> = iolist_to_binary(join(re:split("def=defdefdef","\\A(abc|def)=(\\1){2,3}\\Z",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","\\A(abc|def)=(\\1){2,3}\\Z",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","\\A(abc|def)=(\\1){2,3}\\Z",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","\\A(abc|def)=(\\1){2,3}\\Z",[]))),
+?line <<"abc=defdef">> = iolist_to_binary(join(re:split("abc=defdef","\\A(abc|def)=(\\1){2,3}\\Z",[trim]))),
+?line <<"abc=defdef">> = iolist_to_binary(join(re:split("abc=defdef","\\A(abc|def)=(\\1){2,3}\\Z",[{parts,
+ 2}]))),
+?line <<"abc=defdef">> = iolist_to_binary(join(re:split("abc=defdef","\\A(abc|def)=(\\1){2,3}\\Z",[]))),
+?line <<":a:b:c:d:e:f:g:h:i:j:k:cd">> = iolist_to_binary(join(re:split("abcdefghijkcda2","^(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\\11*(\\3\\4)\\1(?#)2$",[trim]))),
+?line <<":a:b:c:d:e:f:g:h:i:j:k:cd:">> = iolist_to_binary(join(re:split("abcdefghijkcda2","^(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\\11*(\\3\\4)\\1(?#)2$",[{parts,
+ 2}]))),
+?line <<":a:b:c:d:e:f:g:h:i:j:k:cd:">> = iolist_to_binary(join(re:split("abcdefghijkcda2","^(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\\11*(\\3\\4)\\1(?#)2$",[]))),
+?line <<":a:b:c:d:e:f:g:h:i:j:k:cd">> = iolist_to_binary(join(re:split("abcdefghijkkkkcda2","^(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\\11*(\\3\\4)\\1(?#)2$",[trim]))),
+?line <<":a:b:c:d:e:f:g:h:i:j:k:cd:">> = iolist_to_binary(join(re:split("abcdefghijkkkkcda2","^(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\\11*(\\3\\4)\\1(?#)2$",[{parts,
+ 2}]))),
+?line <<":a:b:c:d:e:f:g:h:i:j:k:cd:">> = iolist_to_binary(join(re:split("abcdefghijkkkkcda2","^(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\\11*(\\3\\4)\\1(?#)2$",[]))),
+?line <<":cataract:aract:ract::3">> = iolist_to_binary(join(re:split("cataract cataract23","(cat(a(ract|tonic)|erpillar)) \\1()2(3)",[trim]))),
+?line <<":cataract:aract:ract::3:">> = iolist_to_binary(join(re:split("cataract cataract23","(cat(a(ract|tonic)|erpillar)) \\1()2(3)",[{parts,
+ 2}]))),
+?line <<":cataract:aract:ract::3:">> = iolist_to_binary(join(re:split("cataract cataract23","(cat(a(ract|tonic)|erpillar)) \\1()2(3)",[]))),
+?line <<":catatonic:atonic:tonic::3">> = iolist_to_binary(join(re:split("catatonic catatonic23","(cat(a(ract|tonic)|erpillar)) \\1()2(3)",[trim]))),
+?line <<":catatonic:atonic:tonic::3:">> = iolist_to_binary(join(re:split("catatonic catatonic23","(cat(a(ract|tonic)|erpillar)) \\1()2(3)",[{parts,
+ 2}]))),
+?line <<":catatonic:atonic:tonic::3:">> = iolist_to_binary(join(re:split("catatonic catatonic23","(cat(a(ract|tonic)|erpillar)) \\1()2(3)",[]))),
+?line <<":caterpillar:erpillar:::3">> = iolist_to_binary(join(re:split("caterpillar caterpillar23","(cat(a(ract|tonic)|erpillar)) \\1()2(3)",[trim]))),
+?line <<":caterpillar:erpillar:::3:">> = iolist_to_binary(join(re:split("caterpillar caterpillar23","(cat(a(ract|tonic)|erpillar)) \\1()2(3)",[{parts,
+ 2}]))),
+?line <<":caterpillar:erpillar:::3:">> = iolist_to_binary(join(re:split("caterpillar caterpillar23","(cat(a(ract|tonic)|erpillar)) \\1()2(3)",[]))),
+?line <<":abcd::02 1997">> = iolist_to_binary(join(re:split("From abcd Mon Sep 01 12:33:02 1997","^From +([^ ]+) +[a-zA-Z][a-zA-Z][a-zA-Z] +[a-zA-Z][a-zA-Z][a-zA-Z] +[0-9]?[0-9] +[0-9][0-9]:[0-9][0-9]",[trim]))),
+?line <<":abcd::02 1997">> = iolist_to_binary(join(re:split("From abcd Mon Sep 01 12:33:02 1997","^From +([^ ]+) +[a-zA-Z][a-zA-Z][a-zA-Z] +[a-zA-Z][a-zA-Z][a-zA-Z] +[0-9]?[0-9] +[0-9][0-9]:[0-9][0-9]",[{parts,
+ 2}]))),
+?line <<":abcd::02 1997">> = iolist_to_binary(join(re:split("From abcd Mon Sep 01 12:33:02 1997","^From +([^ ]+) +[a-zA-Z][a-zA-Z][a-zA-Z] +[a-zA-Z][a-zA-Z][a-zA-Z] +[0-9]?[0-9] +[0-9][0-9]:[0-9][0-9]",[]))),
+?line <<":Sep ::02 1997">> = iolist_to_binary(join(re:split("From abcd Mon Sep 01 12:33:02 1997","^From\\s+\\S+\\s+([a-zA-Z]{3}\\s+){2}\\d{1,2}\\s+\\d\\d:\\d\\d",[trim]))),
+?line <<":Sep ::02 1997">> = iolist_to_binary(join(re:split("From abcd Mon Sep 01 12:33:02 1997","^From\\s+\\S+\\s+([a-zA-Z]{3}\\s+){2}\\d{1,2}\\s+\\d\\d:\\d\\d",[{parts,
+ 2}]))),
+?line <<":Sep ::02 1997">> = iolist_to_binary(join(re:split("From abcd Mon Sep 01 12:33:02 1997","^From\\s+\\S+\\s+([a-zA-Z]{3}\\s+){2}\\d{1,2}\\s+\\d\\d:\\d\\d",[]))),
+?line <<":Sep ::02 1997">> = iolist_to_binary(join(re:split("From abcd Mon Sep 1 12:33:02 1997","^From\\s+\\S+\\s+([a-zA-Z]{3}\\s+){2}\\d{1,2}\\s+\\d\\d:\\d\\d",[trim]))),
+?line <<":Sep ::02 1997">> = iolist_to_binary(join(re:split("From abcd Mon Sep 1 12:33:02 1997","^From\\s+\\S+\\s+([a-zA-Z]{3}\\s+){2}\\d{1,2}\\s+\\d\\d:\\d\\d",[{parts,
+ 2}]))),
+?line <<":Sep ::02 1997">> = iolist_to_binary(join(re:split("From abcd Mon Sep 1 12:33:02 1997","^From\\s+\\S+\\s+([a-zA-Z]{3}\\s+){2}\\d{1,2}\\s+\\d\\d:\\d\\d",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^From\\s+\\S+\\s+([a-zA-Z]{3}\\s+){2}\\d{1,2}\\s+\\d\\d:\\d\\d",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^From\\s+\\S+\\s+([a-zA-Z]{3}\\s+){2}\\d{1,2}\\s+\\d\\d:\\d\\d",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^From\\s+\\S+\\s+([a-zA-Z]{3}\\s+){2}\\d{1,2}\\s+\\d\\d:\\d\\d",[]))),
+?line <<"From abcd Sep 01 12:33:02 1997">> = iolist_to_binary(join(re:split("From abcd Sep 01 12:33:02 1997","^From\\s+\\S+\\s+([a-zA-Z]{3}\\s+){2}\\d{1,2}\\s+\\d\\d:\\d\\d",[trim]))),
+?line <<"From abcd Sep 01 12:33:02 1997">> = iolist_to_binary(join(re:split("From abcd Sep 01 12:33:02 1997","^From\\s+\\S+\\s+([a-zA-Z]{3}\\s+){2}\\d{1,2}\\s+\\d\\d:\\d\\d",[{parts,
+ 2}]))),
+?line <<"From abcd Sep 01 12:33:02 1997">> = iolist_to_binary(join(re:split("From abcd Sep 01 12:33:02 1997","^From\\s+\\S+\\s+([a-zA-Z]{3}\\s+){2}\\d{1,2}\\s+\\d\\d:\\d\\d",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("12
+34","^12.34",[dotall,trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("12
+34","^12.34",[dotall,{parts,2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("12
+34","^12.34",[dotall]))),
+?line <<"">> = iolist_to_binary(join(re:split("12 34","^12.34",[dotall,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("12 34","^12.34",[dotall,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("12 34","^12.34",[dotall]))),
+?line <<"the quick : fox">> = iolist_to_binary(join(re:split("the quick brown fox","\\w+(?=\\t)",[trim]))),
+?line <<"the quick : fox">> = iolist_to_binary(join(re:split("the quick brown fox","\\w+(?=\\t)",[{parts,
+ 2}]))),
+?line <<"the quick : fox">> = iolist_to_binary(join(re:split("the quick brown fox","\\w+(?=\\t)",[]))),
+?line <<"foobar is :lish see?">> = iolist_to_binary(join(re:split("foobar is foolish see?","foo(?!bar)(.*)",[trim]))),
+?line <<"foobar is :lish see?:">> = iolist_to_binary(join(re:split("foobar is foolish see?","foo(?!bar)(.*)",[{parts,
+ 2}]))),
+?line <<"foobar is :lish see?:">> = iolist_to_binary(join(re:split("foobar is foolish see?","foo(?!bar)(.*)",[]))),
+?line <<"foobar c: etc">> = iolist_to_binary(join(re:split("foobar crowbar etc","(?:(?!foo)...|^.{0,2})bar(.*)",[trim]))),
+?line <<"foobar c: etc:">> = iolist_to_binary(join(re:split("foobar crowbar etc","(?:(?!foo)...|^.{0,2})bar(.*)",[{parts,
+ 2}]))),
+?line <<"foobar c: etc:">> = iolist_to_binary(join(re:split("foobar crowbar etc","(?:(?!foo)...|^.{0,2})bar(.*)",[]))),
+?line <<":rel">> = iolist_to_binary(join(re:split("barrel","(?:(?!foo)...|^.{0,2})bar(.*)",[trim]))),
+?line <<":rel:">> = iolist_to_binary(join(re:split("barrel","(?:(?!foo)...|^.{0,2})bar(.*)",[{parts,
+ 2}]))),
+?line <<":rel:">> = iolist_to_binary(join(re:split("barrel","(?:(?!foo)...|^.{0,2})bar(.*)",[]))),
+?line <<":rel">> = iolist_to_binary(join(re:split("2barrel","(?:(?!foo)...|^.{0,2})bar(.*)",[trim]))),
+?line <<":rel:">> = iolist_to_binary(join(re:split("2barrel","(?:(?!foo)...|^.{0,2})bar(.*)",[{parts,
+ 2}]))),
+?line <<":rel:">> = iolist_to_binary(join(re:split("2barrel","(?:(?!foo)...|^.{0,2})bar(.*)",[]))),
+?line <<":rel">> = iolist_to_binary(join(re:split("A barrel","(?:(?!foo)...|^.{0,2})bar(.*)",[trim]))),
+?line <<":rel:">> = iolist_to_binary(join(re:split("A barrel","(?:(?!foo)...|^.{0,2})bar(.*)",[{parts,
+ 2}]))),
+?line <<":rel:">> = iolist_to_binary(join(re:split("A barrel","(?:(?!foo)...|^.{0,2})bar(.*)",[]))),
+?line <<":abc:456">> = iolist_to_binary(join(re:split("abc456","^(\\D*)(?=\\d)(?!123)",[trim]))),
+?line <<":abc:456">> = iolist_to_binary(join(re:split("abc456","^(\\D*)(?=\\d)(?!123)",[{parts,
+ 2}]))),
+?line <<":abc:456">> = iolist_to_binary(join(re:split("abc456","^(\\D*)(?=\\d)(?!123)",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(\\D*)(?=\\d)(?!123)",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(\\D*)(?=\\d)(?!123)",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(\\D*)(?=\\d)(?!123)",[]))),
+?line <<"abc123">> = iolist_to_binary(join(re:split("abc123","^(\\D*)(?=\\d)(?!123)",[trim]))),
+?line <<"abc123">> = iolist_to_binary(join(re:split("abc123","^(\\D*)(?=\\d)(?!123)",[{parts,
+ 2}]))),
+?line <<"abc123">> = iolist_to_binary(join(re:split("abc123","^(\\D*)(?=\\d)(?!123)",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("1234","^1234(?# test newlines
+ inside)",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("1234","^1234(?# test newlines
+ inside)",[{parts,2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("1234","^1234(?# test newlines
+ inside)",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("1234","^1234 #comment in extended re
+ ",[extended,trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("1234","^1234 #comment in extended re
+ ",[extended,{parts,2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("1234","^1234 #comment in extended re
+ ",[extended]))),
+?line <<"">> = iolist_to_binary(join(re:split("abcd","#rhubarb
+ abcd",[extended,trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abcd","#rhubarb
+ abcd",[extended,{parts,2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abcd","#rhubarb
+ abcd",[extended]))),
+?line <<"">> = iolist_to_binary(join(re:split("abcd","^abcd#rhubarb",[extended,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abcd","^abcd#rhubarb",[extended,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abcd","^abcd#rhubarb",[extended]))),
+?line <<":a:b">> = iolist_to_binary(join(re:split("aaab","^(a)\\1{2,3}(.)",[trim]))),
+?line <<":a:b:">> = iolist_to_binary(join(re:split("aaab","^(a)\\1{2,3}(.)",[{parts,
+ 2}]))),
+?line <<":a:b:">> = iolist_to_binary(join(re:split("aaab","^(a)\\1{2,3}(.)",[]))),
+?line <<":a:b">> = iolist_to_binary(join(re:split("aaaab","^(a)\\1{2,3}(.)",[trim]))),
+?line <<":a:b:">> = iolist_to_binary(join(re:split("aaaab","^(a)\\1{2,3}(.)",[{parts,
+ 2}]))),
+?line <<":a:b:">> = iolist_to_binary(join(re:split("aaaab","^(a)\\1{2,3}(.)",[]))),
+?line <<":a:a:b">> = iolist_to_binary(join(re:split("aaaaab","^(a)\\1{2,3}(.)",[trim]))),
+?line <<":a:a:b">> = iolist_to_binary(join(re:split("aaaaab","^(a)\\1{2,3}(.)",[{parts,
+ 2}]))),
+?line <<":a:a:b">> = iolist_to_binary(join(re:split("aaaaab","^(a)\\1{2,3}(.)",[]))),
+?line <<":a:a:ab">> = iolist_to_binary(join(re:split("aaaaaab","^(a)\\1{2,3}(.)",[trim]))),
+?line <<":a:a:ab">> = iolist_to_binary(join(re:split("aaaaaab","^(a)\\1{2,3}(.)",[{parts,
+ 2}]))),
+?line <<":a:a:ab">> = iolist_to_binary(join(re:split("aaaaaab","^(a)\\1{2,3}(.)",[]))),
+?line <<"the ">> = iolist_to_binary(join(re:split("the abc","(?!^)abc",[trim]))),
+?line <<"the :">> = iolist_to_binary(join(re:split("the abc","(?!^)abc",[{parts,
+ 2}]))),
+?line <<"the :">> = iolist_to_binary(join(re:split("the abc","(?!^)abc",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?!^)abc",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?!^)abc",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?!^)abc",[]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","(?!^)abc",[trim]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","(?!^)abc",[{parts,
+ 2}]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","(?!^)abc",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc","(?=^)abc",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","(?=^)abc",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","(?=^)abc",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?=^)abc",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?=^)abc",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?=^)abc",[]))),
+?line <<"the abc">> = iolist_to_binary(join(re:split("the abc","(?=^)abc",[trim]))),
+?line <<"the abc">> = iolist_to_binary(join(re:split("the abc","(?=^)abc",[{parts,
+ 2}]))),
+?line <<"the abc">> = iolist_to_binary(join(re:split("the abc","(?=^)abc",[]))),
+?line <<":b:bbb">> = iolist_to_binary(join(re:split("aabbbbb","^[ab]{1,3}(ab*|b)",[trim]))),
+?line <<":b:bbb">> = iolist_to_binary(join(re:split("aabbbbb","^[ab]{1,3}(ab*|b)",[{parts,
+ 2}]))),
+?line <<":b:bbb">> = iolist_to_binary(join(re:split("aabbbbb","^[ab]{1,3}(ab*|b)",[]))),
+?line <<":abbbbb">> = iolist_to_binary(join(re:split("aabbbbb","^[ab]{1,3}?(ab*|b)",[trim]))),
+?line <<":abbbbb:">> = iolist_to_binary(join(re:split("aabbbbb","^[ab]{1,3}?(ab*|b)",[{parts,
+ 2}]))),
+?line <<":abbbbb:">> = iolist_to_binary(join(re:split("aabbbbb","^[ab]{1,3}?(ab*|b)",[]))),
+?line <<":a:bbbbb">> = iolist_to_binary(join(re:split("aabbbbb","^[ab]{1,3}?(ab*?|b)",[trim]))),
+?line <<":a:bbbbb">> = iolist_to_binary(join(re:split("aabbbbb","^[ab]{1,3}?(ab*?|b)",[{parts,
+ 2}]))),
+?line <<":a:bbbbb">> = iolist_to_binary(join(re:split("aabbbbb","^[ab]{1,3}?(ab*?|b)",[]))),
+?line <<":b:bbb">> = iolist_to_binary(join(re:split("aabbbbb","^[ab]{1,3}(ab*?|b)",[trim]))),
+?line <<":b:bbb">> = iolist_to_binary(join(re:split("aabbbbb","^[ab]{1,3}(ab*?|b)",[{parts,
+ 2}]))),
+?line <<":b:bbb">> = iolist_to_binary(join(re:split("aabbbbb","^[ab]{1,3}(ab*?|b)",[]))),
+?line <<"Alan Other <user.ain>">> = iolist_to_binary(join(re:split("Alan Other <user.ain>"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment",[extended,trim]))),
+?line <<"Alan Other <user.ain>">> = iolist_to_binary(join(re:split("Alan Other <user.ain>"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment",[extended,
+ {parts,2}]))),
+?line <<"Alan Other <user.ain>">> = iolist_to_binary(join(re:split("Alan Other <user.ain>"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment",[extended]))),
+?line <<"<user.ain>">> = iolist_to_binary(join(re:split("<user.ain>"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment",[extended,trim]))),
+?line <<"<user.ain>">> = iolist_to_binary(join(re:split("<user.ain>"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment",[extended,
+ {parts,2}]))),
+?line <<"<user.ain>">> = iolist_to_binary(join(re:split("<user.ain>"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment",[extended]))),
+?line <<"user.ain">> = iolist_to_binary(join(re:split("user.ain"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment",[extended,trim]))),
+?line <<"user.ain">> = iolist_to_binary(join(re:split("user.ain"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment",[extended,
+ {parts,2}]))),
+?line <<"user.ain">> = iolist_to_binary(join(re:split("user.ain"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment",[extended]))),
+?line <<"\"A. Other\" <user.1234.ain> (a comment)">> = iolist_to_binary(join(re:split("\"A. Other\" <user.1234.ain> (a comment)"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment",[extended,trim]))),
+?line <<"\"A. Other\" <user.1234.ain> (a comment)">> = iolist_to_binary(join(re:split("\"A. Other\" <user.1234.ain> (a comment)"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment",[extended,
+ {parts,2}]))),
+?line <<"\"A. Other\" <user.1234.ain> (a comment)">> = iolist_to_binary(join(re:split("\"A. Other\" <user.1234.ain> (a comment)"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment",[extended]))),
+?line <<"A. Other <user.1234.ain> (a comment)">> = iolist_to_binary(join(re:split("A. Other <user.1234.ain> (a comment)"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment",[extended,trim]))),
+?line <<"A. Other <user.1234.ain> (a comment)">> = iolist_to_binary(join(re:split("A. Other <user.1234.ain> (a comment)"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment",[extended,
+ {parts,2}]))),
+?line <<"A. Other <user.1234.ain> (a comment)">> = iolist_to_binary(join(re:split("A. Other <user.1234.ain> (a comment)"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment",[extended]))),
+?line <<"\"/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/\"-re.lay">> = iolist_to_binary(join(re:split("\"/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/\"-re.lay"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment",[extended,trim]))),
+?line <<"\"/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/\"-re.lay">> = iolist_to_binary(join(re:split("\"/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/\"-re.lay"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment",[extended,
+ {parts,2}]))),
+?line <<"\"/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/\"-re.lay">> = iolist_to_binary(join(re:split("\"/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/\"-re.lay"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment",[extended]))),
+?line <<"A missing angle <user.where">> = iolist_to_binary(join(re:split("A missing angle <user.where"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment",[extended,trim]))),
+?line <<"A missing angle <user.where">> = iolist_to_binary(join(re:split("A missing angle <user.where"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment",[extended,
+ {parts,2}]))),
+?line <<"A missing angle <user.where">> = iolist_to_binary(join(re:split("A missing angle <user.where"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment",[extended]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment",[extended,trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment",[extended,
+ {parts,2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment",[extended]))),
+?line <<"The quick brown fox">> = iolist_to_binary(join(re:split("The quick brown fox"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment",[extended,trim]))),
+?line <<"The quick brown fox">> = iolist_to_binary(join(re:split("The quick brown fox"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment",[extended,
+ {parts,2}]))),
+?line <<"The quick brown fox">> = iolist_to_binary(join(re:split("The quick brown fox"," (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional leading comment
+(?: (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # one word, optionally followed by....
+(?:
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...
+\\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) | # comments, or...
+
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+# quoted strings
+)*
+< (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # leading <
+(?: @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* , (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+)* # further okay, if led by comma
+: # closing colon
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* )? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) # initial word
+(?: (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\" (?: # opening quote...
+[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote
+| # or
+\\\\ [^\\x80-\\xff] # Escaped something (something != CR)
+)* \" # closing quote
+) )* # further okay, if led by a period
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* @ (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # initial subdomain
+(?: #
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* \\. # if led by a period...
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* (?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+| \\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+) # ...further okay
+)*
+# address spec
+(?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* > # trailing >
+# name and address
+) (?: [\\040\\t] | \\(
+(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*
+\\) )* # optional trailing comment",[extended]))),
+?line <<"Alan Other <user.ain>">> = iolist_to_binary(join(re:split("Alan Other <user.ain>","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)",[extended,trim]))),
+?line <<"Alan Other <user.ain>">> = iolist_to_binary(join(re:split("Alan Other <user.ain>","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)",[extended,{parts,2}]))),
+?line <<"Alan Other <user.ain>">> = iolist_to_binary(join(re:split("Alan Other <user.ain>","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)",[extended]))),
+?line <<"<user.ain>">> = iolist_to_binary(join(re:split("<user.ain>","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)",[extended,trim]))),
+?line <<"<user.ain>">> = iolist_to_binary(join(re:split("<user.ain>","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)",[extended,{parts,2}]))),
+?line <<"<user.ain>">> = iolist_to_binary(join(re:split("<user.ain>","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)",[extended]))),
+?line <<"user.ain">> = iolist_to_binary(join(re:split("user.ain","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)",[extended,trim]))),
+?line <<"user.ain">> = iolist_to_binary(join(re:split("user.ain","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)",[extended,{parts,2}]))),
+?line <<"user.ain">> = iolist_to_binary(join(re:split("user.ain","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)",[extended]))),
+?line <<"\"A. Other\" <user.1234.ain> (a comment)">> = iolist_to_binary(join(re:split("\"A. Other\" <user.1234.ain> (a comment)","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)",[extended,trim]))),
+?line <<"\"A. Other\" <user.1234.ain> (a comment)">> = iolist_to_binary(join(re:split("\"A. Other\" <user.1234.ain> (a comment)","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)",[extended,{parts,2}]))),
+?line <<"\"A. Other\" <user.1234.ain> (a comment)">> = iolist_to_binary(join(re:split("\"A. Other\" <user.1234.ain> (a comment)","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)",[extended]))),
+?line <<"A. Other <user.1234.ain> (a comment)">> = iolist_to_binary(join(re:split("A. Other <user.1234.ain> (a comment)","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)",[extended,trim]))),
+?line <<"A. Other <user.1234.ain> (a comment)">> = iolist_to_binary(join(re:split("A. Other <user.1234.ain> (a comment)","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)",[extended,{parts,2}]))),
+?line <<"A. Other <user.1234.ain> (a comment)">> = iolist_to_binary(join(re:split("A. Other <user.1234.ain> (a comment)","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)",[extended]))),
+?line <<"\"/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/\"-re.lay">> = iolist_to_binary(join(re:split("\"/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/\"-re.lay","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)",[extended,trim]))),
+?line <<"\"/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/\"-re.lay">> = iolist_to_binary(join(re:split("\"/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/\"-re.lay","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)",[extended,{parts,2}]))),
+?line <<"\"/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/\"-re.lay">> = iolist_to_binary(join(re:split("\"/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/\"-re.lay","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)",[extended]))),
+?line <<"A missing angle <user.where">> = iolist_to_binary(join(re:split("A missing angle <user.where","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)",[extended,trim]))),
+?line <<"A missing angle <user.where">> = iolist_to_binary(join(re:split("A missing angle <user.where","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)",[extended,{parts,2}]))),
+?line <<"A missing angle <user.where">> = iolist_to_binary(join(re:split("A missing angle <user.where","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)",[extended]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)",[extended,trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)",[extended,{parts,2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)",[extended]))),
+?line <<"The quick brown fox">> = iolist_to_binary(join(re:split("The quick brown fox","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)",[extended,trim]))),
+?line <<"The quick brown fox">> = iolist_to_binary(join(re:split("The quick brown fox","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)",[extended,{parts,2}]))),
+?line <<"The quick brown fox">> = iolist_to_binary(join(re:split("The quick brown fox","[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+| # or
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+# leading word
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces
+(?:
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+|
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+) # \"special\" comment or quoted string
+[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"
+)*
+<
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# <
+(?:
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)* # additional domains
+:
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)? # optional route
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+# Atom
+| # or
+\" # \"
+[^\\\\\\x80-\\xff\\n\\015\"] * # normal
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*
+\" # \"
+# Quoted string
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\\.
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+(?:
+[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...
+(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom
+|
+\\[ # [
+(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff
+\\] # ]
+)
+[\\040\\t]* # Nab whitespace.
+(?:
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: # (
+(?: \\\\ [^\\x80-\\xff] |
+\\( # (
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*
+\\) # )
+) # special
+[^\\\\\\x80-\\xff\\n\\015()] * # normal*
+)* # )*
+\\) # )
+[\\040\\t]* )* # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address spec
+> # >
+# name and address
+)",[extended]))),
+?line <<"abcdefpqrxyz0AB">> = iolist_to_binary(join(re:split("abcdefpqrxyz0AB","abc\\0def\\00pqr\\000xyz\\0000AB",[trim]))),
+?line <<"abcdefpqrxyz0AB">> = iolist_to_binary(join(re:split("abcdefpqrxyz0AB","abc\\0def\\00pqr\\000xyz\\0000AB",[{parts,
+ 2}]))),
+?line <<"abcdefpqrxyz0AB">> = iolist_to_binary(join(re:split("abcdefpqrxyz0AB","abc\\0def\\00pqr\\000xyz\\0000AB",[]))),
+?line <<"abc456 abcdefpqrxyz0ABCDE">> = iolist_to_binary(join(re:split("abc456 abcdefpqrxyz0ABCDE","abc\\0def\\00pqr\\000xyz\\0000AB",[trim]))),
+?line <<"abc456 abcdefpqrxyz0ABCDE">> = iolist_to_binary(join(re:split("abc456 abcdefpqrxyz0ABCDE","abc\\0def\\00pqr\\000xyz\\0000AB",[{parts,
+ 2}]))),
+?line <<"abc456 abcdefpqrxyz0ABCDE">> = iolist_to_binary(join(re:split("abc456 abcdefpqrxyz0ABCDE","abc\\0def\\00pqr\\000xyz\\0000AB",[]))),
+?line <<"abc efpqr0xyz00AB">> = iolist_to_binary(join(re:split("abc efpqr0xyz00AB","abc\\x0def\\x00pqr\\x000xyz\\x0000AB",[trim]))),
+?line <<"abc efpqr0xyz00AB">> = iolist_to_binary(join(re:split("abc efpqr0xyz00AB","abc\\x0def\\x00pqr\\x000xyz\\x0000AB",[{parts,
+ 2}]))),
+?line <<"abc efpqr0xyz00AB">> = iolist_to_binary(join(re:split("abc efpqr0xyz00AB","abc\\x0def\\x00pqr\\x000xyz\\x0000AB",[]))),
+?line <<"abc456 abc efpqr0xyz00ABCDE">> = iolist_to_binary(join(re:split("abc456 abc efpqr0xyz00ABCDE","abc\\x0def\\x00pqr\\x000xyz\\x0000AB",[trim]))),
+?line <<"abc456 abc efpqr0xyz00ABCDE">> = iolist_to_binary(join(re:split("abc456 abc efpqr0xyz00ABCDE","abc\\x0def\\x00pqr\\x000xyz\\x0000AB",[{parts,
+ 2}]))),
+?line <<"abc456 abc efpqr0xyz00ABCDE">> = iolist_to_binary(join(re:split("abc456 abc efpqr0xyz00ABCDE","abc\\x0def\\x00pqr\\x000xyz\\x0000AB",[]))),
+?line <<"A">> = iolist_to_binary(join(re:split("A","^[\\000-\\037]",[trim]))),
+?line <<"A">> = iolist_to_binary(join(re:split("A","^[\\000-\\037]",[{parts,
+ 2}]))),
+?line <<"A">> = iolist_to_binary(join(re:split("A","^[\\000-\\037]",[]))),
+?line <<":B">> = iolist_to_binary(join(re:split("B","^[\\000-\\037]",[trim]))),
+?line <<":B">> = iolist_to_binary(join(re:split("B","^[\\000-\\037]",[{parts,
+ 2}]))),
+?line <<":B">> = iolist_to_binary(join(re:split("B","^[\\000-\\037]",[]))),
+?line <<":C">> = iolist_to_binary(join(re:split("C","^[\\000-\\037]",[trim]))),
+?line <<":C">> = iolist_to_binary(join(re:split("C","^[\\000-\\037]",[{parts,
+ 2}]))),
+?line <<":C">> = iolist_to_binary(join(re:split("C","^[\\000-\\037]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("","\\0*",[trim]))),
+?line <<"">> = iolist_to_binary(join(re:split("","\\0*",[{parts,
+ 2}]))),
+?line <<"">> = iolist_to_binary(join(re:split("","\\0*",[]))),
+?line <<"The AZ">> = iolist_to_binary(join(re:split("The AZ","A\\x0{2,3}Z",[trim]))),
+?line <<"The AZ">> = iolist_to_binary(join(re:split("The AZ","A\\x0{2,3}Z",[{parts,
+ 2}]))),
+?line <<"The AZ">> = iolist_to_binary(join(re:split("The AZ","A\\x0{2,3}Z",[]))),
+?line <<"An AZ">> = iolist_to_binary(join(re:split("An AZ","A\\x0{2,3}Z",[trim]))),
+?line <<"An AZ">> = iolist_to_binary(join(re:split("An AZ","A\\x0{2,3}Z",[{parts,
+ 2}]))),
+?line <<"An AZ">> = iolist_to_binary(join(re:split("An AZ","A\\x0{2,3}Z",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","A\\x0{2,3}Z",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","A\\x0{2,3}Z",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","A\\x0{2,3}Z",[]))),
+?line <<"AZ">> = iolist_to_binary(join(re:split("AZ","A\\x0{2,3}Z",[trim]))),
+?line <<"AZ">> = iolist_to_binary(join(re:split("AZ","A\\x0{2,3}Z",[{parts,
+ 2}]))),
+?line <<"AZ">> = iolist_to_binary(join(re:split("AZ","A\\x0{2,3}Z",[]))),
+?line <<"AZ">> = iolist_to_binary(join(re:split("AZ","A\\x0{2,3}Z",[trim]))),
+?line <<"AZ">> = iolist_to_binary(join(re:split("AZ","A\\x0{2,3}Z",[{parts,
+ 2}]))),
+?line <<"AZ">> = iolist_to_binary(join(re:split("AZ","A\\x0{2,3}Z",[]))),
+?line <<":cow:bell">> = iolist_to_binary(join(re:split("cowcowbell","^(cow|)\\1(bell)",[trim]))),
+?line <<":cow:bell:">> = iolist_to_binary(join(re:split("cowcowbell","^(cow|)\\1(bell)",[{parts,
+ 2}]))),
+?line <<":cow:bell:">> = iolist_to_binary(join(re:split("cowcowbell","^(cow|)\\1(bell)",[]))),
+?line <<"::bell">> = iolist_to_binary(join(re:split("bell","^(cow|)\\1(bell)",[trim]))),
+?line <<"::bell:">> = iolist_to_binary(join(re:split("bell","^(cow|)\\1(bell)",[{parts,
+ 2}]))),
+?line <<"::bell:">> = iolist_to_binary(join(re:split("bell","^(cow|)\\1(bell)",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(cow|)\\1(bell)",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(cow|)\\1(bell)",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(cow|)\\1(bell)",[]))),
+?line <<"cowbell">> = iolist_to_binary(join(re:split("cowbell","^(cow|)\\1(bell)",[trim]))),
+?line <<"cowbell">> = iolist_to_binary(join(re:split("cowbell","^(cow|)\\1(bell)",[{parts,
+ 2}]))),
+?line <<"cowbell">> = iolist_to_binary(join(re:split("cowbell","^(cow|)\\1(bell)",[]))),
+?line <<":abc">> = iolist_to_binary(join(re:split(" abc","^\\s",[trim]))),
+?line <<":abc">> = iolist_to_binary(join(re:split(" abc","^\\s",[{parts,
+ 2}]))),
+?line <<":abc">> = iolist_to_binary(join(re:split(" abc","^\\s",[]))),
+?line <<":abc">> = iolist_to_binary(join(re:split(" abc","^\\s",[trim]))),
+?line <<":abc">> = iolist_to_binary(join(re:split(" abc","^\\s",[{parts,
+ 2}]))),
+?line <<":abc">> = iolist_to_binary(join(re:split(" abc","^\\s",[]))),
+?line <<":abc">> = iolist_to_binary(join(re:split("
+abc","^\\s",[trim]))),
+?line <<":abc">> = iolist_to_binary(join(re:split("
+abc","^\\s",[{parts,2}]))),
+?line <<":abc">> = iolist_to_binary(join(re:split("
+abc","^\\s",[]))),
+?line <<":abc">> = iolist_to_binary(join(re:split(" abc","^\\s",[trim]))),
+?line <<":abc">> = iolist_to_binary(join(re:split(" abc","^\\s",[{parts,
+ 2}]))),
+?line <<":abc">> = iolist_to_binary(join(re:split(" abc","^\\s",[]))),
+?line <<":abc">> = iolist_to_binary(join(re:split(" abc","^\\s",[trim]))),
+?line <<":abc">> = iolist_to_binary(join(re:split(" abc","^\\s",[{parts,
+ 2}]))),
+?line <<":abc">> = iolist_to_binary(join(re:split(" abc","^\\s",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^\\s",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^\\s",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^\\s",[]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","^\\s",[trim]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","^\\s",[{parts,
+ 2}]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","^\\s",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc","^a b
+ c",[extended,trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","^a b
+ c",[extended,{parts,2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","^a b
+ c",[extended]))),
+?line <<":a">> = iolist_to_binary(join(re:split("ab","^(a|)\\1*b",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("ab","^(a|)\\1*b",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("ab","^(a|)\\1*b",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("aaaab","^(a|)\\1*b",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aaaab","^(a|)\\1*b",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aaaab","^(a|)\\1*b",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("b","^(a|)\\1*b",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("b","^(a|)\\1*b",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("b","^(a|)\\1*b",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(a|)\\1*b",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(a|)\\1*b",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(a|)\\1*b",[]))),
+?line <<"acb">> = iolist_to_binary(join(re:split("acb","^(a|)\\1*b",[trim]))),
+?line <<"acb">> = iolist_to_binary(join(re:split("acb","^(a|)\\1*b",[{parts,
+ 2}]))),
+?line <<"acb">> = iolist_to_binary(join(re:split("acb","^(a|)\\1*b",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("aab","^(a|)\\1+b",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aab","^(a|)\\1+b",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aab","^(a|)\\1+b",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("aaaab","^(a|)\\1+b",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aaaab","^(a|)\\1+b",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aaaab","^(a|)\\1+b",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("b","^(a|)\\1+b",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("b","^(a|)\\1+b",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("b","^(a|)\\1+b",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(a|)\\1+b",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(a|)\\1+b",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(a|)\\1+b",[]))),
+?line <<"ab">> = iolist_to_binary(join(re:split("ab","^(a|)\\1+b",[trim]))),
+?line <<"ab">> = iolist_to_binary(join(re:split("ab","^(a|)\\1+b",[{parts,
+ 2}]))),
+?line <<"ab">> = iolist_to_binary(join(re:split("ab","^(a|)\\1+b",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("ab","^(a|)\\1?b",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("ab","^(a|)\\1?b",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("ab","^(a|)\\1?b",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("aab","^(a|)\\1?b",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aab","^(a|)\\1?b",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aab","^(a|)\\1?b",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("b","^(a|)\\1?b",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("b","^(a|)\\1?b",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("b","^(a|)\\1?b",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(a|)\\1?b",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(a|)\\1?b",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(a|)\\1?b",[]))),
+?line <<"acb">> = iolist_to_binary(join(re:split("acb","^(a|)\\1?b",[trim]))),
+?line <<"acb">> = iolist_to_binary(join(re:split("acb","^(a|)\\1?b",[{parts,
+ 2}]))),
+?line <<"acb">> = iolist_to_binary(join(re:split("acb","^(a|)\\1?b",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("aaab","^(a|)\\1{2}b",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aaab","^(a|)\\1{2}b",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aaab","^(a|)\\1{2}b",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("b","^(a|)\\1{2}b",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("b","^(a|)\\1{2}b",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("b","^(a|)\\1{2}b",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(a|)\\1{2}b",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(a|)\\1{2}b",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(a|)\\1{2}b",[]))),
+?line <<"ab">> = iolist_to_binary(join(re:split("ab","^(a|)\\1{2}b",[trim]))),
+?line <<"ab">> = iolist_to_binary(join(re:split("ab","^(a|)\\1{2}b",[{parts,
+ 2}]))),
+?line <<"ab">> = iolist_to_binary(join(re:split("ab","^(a|)\\1{2}b",[]))),
+?line <<"aab">> = iolist_to_binary(join(re:split("aab","^(a|)\\1{2}b",[trim]))),
+?line <<"aab">> = iolist_to_binary(join(re:split("aab","^(a|)\\1{2}b",[{parts,
+ 2}]))),
+?line <<"aab">> = iolist_to_binary(join(re:split("aab","^(a|)\\1{2}b",[]))),
+?line <<"aaaab">> = iolist_to_binary(join(re:split("aaaab","^(a|)\\1{2}b",[trim]))),
+?line <<"aaaab">> = iolist_to_binary(join(re:split("aaaab","^(a|)\\1{2}b",[{parts,
+ 2}]))),
+?line <<"aaaab">> = iolist_to_binary(join(re:split("aaaab","^(a|)\\1{2}b",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("aaab","^(a|)\\1{2,3}b",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aaab","^(a|)\\1{2,3}b",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aaab","^(a|)\\1{2,3}b",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("aaaab","^(a|)\\1{2,3}b",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aaaab","^(a|)\\1{2,3}b",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aaaab","^(a|)\\1{2,3}b",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("b","^(a|)\\1{2,3}b",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("b","^(a|)\\1{2,3}b",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("b","^(a|)\\1{2,3}b",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(a|)\\1{2,3}b",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(a|)\\1{2,3}b",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(a|)\\1{2,3}b",[]))),
+?line <<"ab">> = iolist_to_binary(join(re:split("ab","^(a|)\\1{2,3}b",[trim]))),
+?line <<"ab">> = iolist_to_binary(join(re:split("ab","^(a|)\\1{2,3}b",[{parts,
+ 2}]))),
+?line <<"ab">> = iolist_to_binary(join(re:split("ab","^(a|)\\1{2,3}b",[]))),
+?line <<"aab">> = iolist_to_binary(join(re:split("aab","^(a|)\\1{2,3}b",[trim]))),
+?line <<"aab">> = iolist_to_binary(join(re:split("aab","^(a|)\\1{2,3}b",[{parts,
+ 2}]))),
+?line <<"aab">> = iolist_to_binary(join(re:split("aab","^(a|)\\1{2,3}b",[]))),
+?line <<"aaaaab">> = iolist_to_binary(join(re:split("aaaaab","^(a|)\\1{2,3}b",[trim]))),
+?line <<"aaaaab">> = iolist_to_binary(join(re:split("aaaaab","^(a|)\\1{2,3}b",[{parts,
+ 2}]))),
+?line <<"aaaaab">> = iolist_to_binary(join(re:split("aaaaab","^(a|)\\1{2,3}b",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abbbbc","ab{1,3}bc",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abbbbc","ab{1,3}bc",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abbbbc","ab{1,3}bc",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abbbc","ab{1,3}bc",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abbbc","ab{1,3}bc",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abbbc","ab{1,3}bc",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abbc","ab{1,3}bc",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abbc","ab{1,3}bc",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abbc","ab{1,3}bc",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","ab{1,3}bc",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","ab{1,3}bc",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","ab{1,3}bc",[]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","ab{1,3}bc",[trim]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","ab{1,3}bc",[{parts,
+ 2}]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","ab{1,3}bc",[]))),
+?line <<"abbbbbc">> = iolist_to_binary(join(re:split("abbbbbc","ab{1,3}bc",[trim]))),
+?line <<"abbbbbc">> = iolist_to_binary(join(re:split("abbbbbc","ab{1,3}bc",[{parts,
+ 2}]))),
+?line <<"abbbbbc">> = iolist_to_binary(join(re:split("abbbbbc","ab{1,3}bc",[]))),
+?line <<":track1:title:Blah blah blah">> = iolist_to_binary(join(re:split("track1.title:TBlah blah blah","([^.]*)\\.([^:]*):[T ]+(.*)",[trim]))),
+?line <<":track1:title:Blah blah blah:">> = iolist_to_binary(join(re:split("track1.title:TBlah blah blah","([^.]*)\\.([^:]*):[T ]+(.*)",[{parts,
+ 2}]))),
+?line <<":track1:title:Blah blah blah:">> = iolist_to_binary(join(re:split("track1.title:TBlah blah blah","([^.]*)\\.([^:]*):[T ]+(.*)",[]))),
+?line <<":track1:title:Blah blah blah">> = iolist_to_binary(join(re:split("track1.title:TBlah blah blah","([^.]*)\\.([^:]*):[T ]+(.*)",[caseless,
+ trim]))),
+?line <<":track1:title:Blah blah blah:">> = iolist_to_binary(join(re:split("track1.title:TBlah blah blah","([^.]*)\\.([^:]*):[T ]+(.*)",[caseless,
+ {parts,
+ 2}]))),
+?line <<":track1:title:Blah blah blah:">> = iolist_to_binary(join(re:split("track1.title:TBlah blah blah","([^.]*)\\.([^:]*):[T ]+(.*)",[caseless]))),
+?line <<":track1:title:Blah blah blah">> = iolist_to_binary(join(re:split("track1.title:TBlah blah blah","([^.]*)\\.([^:]*):[t ]+(.*)",[caseless,
+ trim]))),
+?line <<":track1:title:Blah blah blah:">> = iolist_to_binary(join(re:split("track1.title:TBlah blah blah","([^.]*)\\.([^:]*):[t ]+(.*)",[caseless,
+ {parts,
+ 2}]))),
+?line <<":track1:title:Blah blah blah:">> = iolist_to_binary(join(re:split("track1.title:TBlah blah blah","([^.]*)\\.([^:]*):[t ]+(.*)",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("WXY_^abc","^[W-c]+$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("WXY_^abc","^[W-c]+$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("WXY_^abc","^[W-c]+$",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^[W-c]+$",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^[W-c]+$",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^[W-c]+$",[]))),
+?line <<"wxy">> = iolist_to_binary(join(re:split("wxy","^[W-c]+$",[trim]))),
+?line <<"wxy">> = iolist_to_binary(join(re:split("wxy","^[W-c]+$",[{parts,
+ 2}]))),
+?line <<"wxy">> = iolist_to_binary(join(re:split("wxy","^[W-c]+$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("WXY_^abc","^[W-c]+$",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("WXY_^abc","^[W-c]+$",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("WXY_^abc","^[W-c]+$",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("wxy_^ABC","^[W-c]+$",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("wxy_^ABC","^[W-c]+$",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("wxy_^ABC","^[W-c]+$",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("WXY_^abc","^[\\x3f-\\x5F]+$",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("WXY_^abc","^[\\x3f-\\x5F]+$",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("WXY_^abc","^[\\x3f-\\x5F]+$",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("wxy_^ABC","^[\\x3f-\\x5F]+$",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("wxy_^ABC","^[\\x3f-\\x5F]+$",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("wxy_^ABC","^[\\x3f-\\x5F]+$",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc","^abc$",[multiline,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","^abc$",[multiline,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","^abc$",[multiline]))),
+?line <<"qqq
+">> = iolist_to_binary(join(re:split("qqq
+abc","^abc$",[multiline,trim]))),
+?line <<"qqq
+:">> = iolist_to_binary(join(re:split("qqq
+abc","^abc$",[multiline,{parts,2}]))),
+?line <<"qqq
+:">> = iolist_to_binary(join(re:split("qqq
+abc","^abc$",[multiline]))),
+?line <<":
+zzz">> = iolist_to_binary(join(re:split("abc
+zzz","^abc$",[multiline,trim]))),
+?line <<":
+zzz">> = iolist_to_binary(join(re:split("abc
+zzz","^abc$",[multiline,{parts,2}]))),
+?line <<":
+zzz">> = iolist_to_binary(join(re:split("abc
+zzz","^abc$",[multiline]))),
+?line <<"qqq
+:
+zzz">> = iolist_to_binary(join(re:split("qqq
+abc
+zzz","^abc$",[multiline,trim]))),
+?line <<"qqq
+:
+zzz">> = iolist_to_binary(join(re:split("qqq
+abc
+zzz","^abc$",[multiline,{parts,2}]))),
+?line <<"qqq
+:
+zzz">> = iolist_to_binary(join(re:split("qqq
+abc
+zzz","^abc$",[multiline]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc","^abc$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","^abc$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","^abc$",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^abc$",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^abc$",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^abc$",[]))),
+?line <<"qqq
+abc">> = iolist_to_binary(join(re:split("qqq
+abc","^abc$",[trim]))),
+?line <<"qqq
+abc">> = iolist_to_binary(join(re:split("qqq
+abc","^abc$",[{parts,2}]))),
+?line <<"qqq
+abc">> = iolist_to_binary(join(re:split("qqq
+abc","^abc$",[]))),
+?line <<"abc
+zzz">> = iolist_to_binary(join(re:split("abc
+zzz","^abc$",[trim]))),
+?line <<"abc
+zzz">> = iolist_to_binary(join(re:split("abc
+zzz","^abc$",[{parts,2}]))),
+?line <<"abc
+zzz">> = iolist_to_binary(join(re:split("abc
+zzz","^abc$",[]))),
+?line <<"qqq
+abc
+zzz">> = iolist_to_binary(join(re:split("qqq
+abc
+zzz","^abc$",[trim]))),
+?line <<"qqq
+abc
+zzz">> = iolist_to_binary(join(re:split("qqq
+abc
+zzz","^abc$",[{parts,2}]))),
+?line <<"qqq
+abc
+zzz">> = iolist_to_binary(join(re:split("qqq
+abc
+zzz","^abc$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc","\\Aabc\\Z",[multiline,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","\\Aabc\\Z",[multiline,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","\\Aabc\\Z",[multiline]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc","\\Aabc\\Z",[multiline,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","\\Aabc\\Z",[multiline,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","\\Aabc\\Z",[multiline]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","\\Aabc\\Z",[multiline,
+ trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","\\Aabc\\Z",[multiline,
+ {parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","\\Aabc\\Z",[multiline]))),
+?line <<"qqq
+abc">> = iolist_to_binary(join(re:split("qqq
+abc","\\Aabc\\Z",[multiline,trim]))),
+?line <<"qqq
+abc">> = iolist_to_binary(join(re:split("qqq
+abc","\\Aabc\\Z",[multiline,{parts,2}]))),
+?line <<"qqq
+abc">> = iolist_to_binary(join(re:split("qqq
+abc","\\Aabc\\Z",[multiline]))),
+?line <<"abc
+zzz">> = iolist_to_binary(join(re:split("abc
+zzz","\\Aabc\\Z",[multiline,trim]))),
+?line <<"abc
+zzz">> = iolist_to_binary(join(re:split("abc
+zzz","\\Aabc\\Z",[multiline,{parts,2}]))),
+?line <<"abc
+zzz">> = iolist_to_binary(join(re:split("abc
+zzz","\\Aabc\\Z",[multiline]))),
+?line <<"qqq
+abc
+zzz">> = iolist_to_binary(join(re:split("qqq
+abc
+zzz","\\Aabc\\Z",[multiline,trim]))),
+?line <<"qqq
+abc
+zzz">> = iolist_to_binary(join(re:split("qqq
+abc
+zzz","\\Aabc\\Z",[multiline,{parts,2}]))),
+?line <<"qqq
+abc
+zzz">> = iolist_to_binary(join(re:split("qqq
+abc
+zzz","\\Aabc\\Z",[multiline]))),
+?line <<":f">> = iolist_to_binary(join(re:split("abc
+def","\\A(.)*\\Z",[dotall,trim]))),
+?line <<":f:">> = iolist_to_binary(join(re:split("abc
+def","\\A(.)*\\Z",[dotall,{parts,2}]))),
+?line <<":f:">> = iolist_to_binary(join(re:split("abc
+def","\\A(.)*\\Z",[dotall]))),
+?line <<":s">> = iolist_to_binary(join(re:split("*** Failers","\\A(.)*\\Z",[multiline,
+ trim]))),
+?line <<":s:">> = iolist_to_binary(join(re:split("*** Failers","\\A(.)*\\Z",[multiline,
+ {parts,
+ 2}]))),
+?line <<":s:">> = iolist_to_binary(join(re:split("*** Failers","\\A(.)*\\Z",[multiline]))),
+?line <<"abc
+def">> = iolist_to_binary(join(re:split("abc
+def","\\A(.)*\\Z",[multiline,trim]))),
+?line <<"abc
+def">> = iolist_to_binary(join(re:split("abc
+def","\\A(.)*\\Z",[multiline,{parts,2}]))),
+?line <<"abc
+def">> = iolist_to_binary(join(re:split("abc
+def","\\A(.)*\\Z",[multiline]))),
+?line <<"::c">> = iolist_to_binary(join(re:split("b::c","(?:b)|(?::+)",[trim]))),
+?line <<":::c">> = iolist_to_binary(join(re:split("b::c","(?:b)|(?::+)",[{parts,
+ 2}]))),
+?line <<"::c">> = iolist_to_binary(join(re:split("b::c","(?:b)|(?::+)",[]))),
+?line <<"c">> = iolist_to_binary(join(re:split("c::b","(?:b)|(?::+)",[trim]))),
+?line <<"c:b">> = iolist_to_binary(join(re:split("c::b","(?:b)|(?::+)",[{parts,
+ 2}]))),
+?line <<"c::">> = iolist_to_binary(join(re:split("c::b","(?:b)|(?::+)",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("az-","[-az]+",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("az-","[-az]+",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("az-","[-az]+",[]))),
+?line <<"*** F:ilers">> = iolist_to_binary(join(re:split("*** Failers","[-az]+",[trim]))),
+?line <<"*** F:ilers">> = iolist_to_binary(join(re:split("*** Failers","[-az]+",[{parts,
+ 2}]))),
+?line <<"*** F:ilers">> = iolist_to_binary(join(re:split("*** Failers","[-az]+",[]))),
+?line <<"b">> = iolist_to_binary(join(re:split("b","[-az]+",[trim]))),
+?line <<"b">> = iolist_to_binary(join(re:split("b","[-az]+",[{parts,
+ 2}]))),
+?line <<"b">> = iolist_to_binary(join(re:split("b","[-az]+",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("za-","[az-]+",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("za-","[az-]+",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("za-","[az-]+",[]))),
+?line <<"*** F:ilers">> = iolist_to_binary(join(re:split("*** Failers","[az-]+",[trim]))),
+?line <<"*** F:ilers">> = iolist_to_binary(join(re:split("*** Failers","[az-]+",[{parts,
+ 2}]))),
+?line <<"*** F:ilers">> = iolist_to_binary(join(re:split("*** Failers","[az-]+",[]))),
+?line <<"b">> = iolist_to_binary(join(re:split("b","[az-]+",[trim]))),
+?line <<"b">> = iolist_to_binary(join(re:split("b","[az-]+",[{parts,
+ 2}]))),
+?line <<"b">> = iolist_to_binary(join(re:split("b","[az-]+",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a-z","[a\\-z]+",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a-z","[a\\-z]+",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a-z","[a\\-z]+",[]))),
+?line <<"*** F:ilers">> = iolist_to_binary(join(re:split("*** Failers","[a\\-z]+",[trim]))),
+?line <<"*** F:ilers">> = iolist_to_binary(join(re:split("*** Failers","[a\\-z]+",[{parts,
+ 2}]))),
+?line <<"*** F:ilers">> = iolist_to_binary(join(re:split("*** Failers","[a\\-z]+",[]))),
+?line <<"b">> = iolist_to_binary(join(re:split("b","[a\\-z]+",[trim]))),
+?line <<"b">> = iolist_to_binary(join(re:split("b","[a\\-z]+",[{parts,
+ 2}]))),
+?line <<"b">> = iolist_to_binary(join(re:split("b","[a\\-z]+",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abcdxyz","[a-z]+",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abcdxyz","[a-z]+",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abcdxyz","[a-z]+",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("12-34","[\\d-]+",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("12-34","[\\d-]+",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("12-34","[\\d-]+",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","[\\d-]+",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","[\\d-]+",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","[\\d-]+",[]))),
+?line <<"aaa">> = iolist_to_binary(join(re:split("aaa","[\\d-]+",[trim]))),
+?line <<"aaa">> = iolist_to_binary(join(re:split("aaa","[\\d-]+",[{parts,
+ 2}]))),
+?line <<"aaa">> = iolist_to_binary(join(re:split("aaa","[\\d-]+",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("12-34z","[\\d-z]+",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("12-34z","[\\d-z]+",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("12-34z","[\\d-z]+",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","[\\d-z]+",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","[\\d-z]+",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","[\\d-z]+",[]))),
+?line <<"aaa">> = iolist_to_binary(join(re:split("aaa","[\\d-z]+",[trim]))),
+?line <<"aaa">> = iolist_to_binary(join(re:split("aaa","[\\d-z]+",[{parts,
+ 2}]))),
+?line <<"aaa">> = iolist_to_binary(join(re:split("aaa","[\\d-z]+",[]))),
+?line <<": ">> = iolist_to_binary(join(re:split("\\ ","\\x5c",[trim]))),
+?line <<": ">> = iolist_to_binary(join(re:split("\\ ","\\x5c",[{parts,
+ 2}]))),
+?line <<": ">> = iolist_to_binary(join(re:split("\\ ","\\x5c",[]))),
+?line <<"the:oo">> = iolist_to_binary(join(re:split("the Zoo","\\x20Z",[trim]))),
+?line <<"the:oo">> = iolist_to_binary(join(re:split("the Zoo","\\x20Z",[{parts,
+ 2}]))),
+?line <<"the:oo">> = iolist_to_binary(join(re:split("the Zoo","\\x20Z",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","\\x20Z",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","\\x20Z",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","\\x20Z",[]))),
+?line <<"Zulu">> = iolist_to_binary(join(re:split("Zulu","\\x20Z",[trim]))),
+?line <<"Zulu">> = iolist_to_binary(join(re:split("Zulu","\\x20Z",[{parts,
+ 2}]))),
+?line <<"Zulu">> = iolist_to_binary(join(re:split("Zulu","\\x20Z",[]))),
+?line <<":abc">> = iolist_to_binary(join(re:split("abcabc","(abc)\\1",[caseless,
+ trim]))),
+?line <<":abc:">> = iolist_to_binary(join(re:split("abcabc","(abc)\\1",[caseless,
+ {parts,
+ 2}]))),
+?line <<":abc:">> = iolist_to_binary(join(re:split("abcabc","(abc)\\1",[caseless]))),
+?line <<":ABC">> = iolist_to_binary(join(re:split("ABCabc","(abc)\\1",[caseless,
+ trim]))),
+?line <<":ABC:">> = iolist_to_binary(join(re:split("ABCabc","(abc)\\1",[caseless,
+ {parts,
+ 2}]))),
+?line <<":ABC:">> = iolist_to_binary(join(re:split("ABCabc","(abc)\\1",[caseless]))),
+?line <<":abc">> = iolist_to_binary(join(re:split("abcABC","(abc)\\1",[caseless,
+ trim]))),
+?line <<":abc:">> = iolist_to_binary(join(re:split("abcABC","(abc)\\1",[caseless,
+ {parts,
+ 2}]))),
+?line <<":abc:">> = iolist_to_binary(join(re:split("abcABC","(abc)\\1",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("ab{3cd","ab{3cd",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ab{3cd","ab{3cd",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ab{3cd","ab{3cd",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("ab{3,cd","ab{3,cd",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ab{3,cd","ab{3,cd",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ab{3,cd","ab{3,cd",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("ab{3,4a}cd","ab{3,4a}cd",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ab{3,4a}cd","ab{3,4a}cd",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ab{3,4a}cd","ab{3,4a}cd",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("{4,5a}bc","{4,5a}bc",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("{4,5a}bc","{4,5a}bc",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("{4,5a}bc","{4,5a}bc",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc","abc$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","abc$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","abc$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc","abc$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","abc$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","abc$",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","abc$",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","abc$",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","abc$",[]))),
+?line <<"abc
+def">> = iolist_to_binary(join(re:split("abc
+def","abc$",[trim]))),
+?line <<"abc
+def">> = iolist_to_binary(join(re:split("abc
+def","abc$",[{parts,2}]))),
+?line <<"abc
+def">> = iolist_to_binary(join(re:split("abc
+def","abc$",[]))),
+?line <<":abc">> = iolist_to_binary(join(re:split("abcS","(abc)\\123",[trim]))),
+?line <<":abc:">> = iolist_to_binary(join(re:split("abcS","(abc)\\123",[{parts,
+ 2}]))),
+?line <<":abc:">> = iolist_to_binary(join(re:split("abcS","(abc)\\123",[]))),
+?line <<":abc">> = iolist_to_binary(join(re:split("abc�","(abc)\\223",[trim]))),
+?line <<":abc:">> = iolist_to_binary(join(re:split("abc�","(abc)\\223",[{parts,
+ 2}]))),
+?line <<":abc:">> = iolist_to_binary(join(re:split("abc�","(abc)\\223",[]))),
+?line <<":abc">> = iolist_to_binary(join(re:split("abc�","(abc)\\323",[trim]))),
+?line <<":abc:">> = iolist_to_binary(join(re:split("abc�","(abc)\\323",[{parts,
+ 2}]))),
+?line <<":abc:">> = iolist_to_binary(join(re:split("abc�","(abc)\\323",[]))),
+?line <<":abc">> = iolist_to_binary(join(re:split("abc@","(abc)\\100",[trim]))),
+?line <<":abc:">> = iolist_to_binary(join(re:split("abc@","(abc)\\100",[{parts,
+ 2}]))),
+?line <<":abc:">> = iolist_to_binary(join(re:split("abc@","(abc)\\100",[]))),
+?line <<":abc">> = iolist_to_binary(join(re:split("abc@","(abc)\\100",[trim]))),
+?line <<":abc:">> = iolist_to_binary(join(re:split("abc@","(abc)\\100",[{parts,
+ 2}]))),
+?line <<":abc:">> = iolist_to_binary(join(re:split("abc@","(abc)\\100",[]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","(abc)\\1000",[trim]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","(abc)\\1000",[{parts,
+ 2}]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","(abc)\\1000",[]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","(abc)\\1000",[trim]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","(abc)\\1000",[{parts,
+ 2}]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","(abc)\\1000",[]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","(abc)\\1000",[trim]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","(abc)\\1000",[{parts,
+ 2}]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","(abc)\\1000",[]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","(abc)\\1000",[trim]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","(abc)\\1000",[{parts,
+ 2}]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","(abc)\\1000",[]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","(abc)\\1000",[trim]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","(abc)\\1000",[{parts,
+ 2}]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","(abc)\\1000",[]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","(abc)\\1000",[trim]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","(abc)\\1000",[{parts,
+ 2}]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","(abc)\\1000",[]))),
+?line <<"abc81">> = iolist_to_binary(join(re:split("abc81","abc\\81",[trim]))),
+?line <<"abc81">> = iolist_to_binary(join(re:split("abc81","abc\\81",[{parts,
+ 2}]))),
+?line <<"abc81">> = iolist_to_binary(join(re:split("abc81","abc\\81",[]))),
+?line <<"abc81">> = iolist_to_binary(join(re:split("abc81","abc\\81",[trim]))),
+?line <<"abc81">> = iolist_to_binary(join(re:split("abc81","abc\\81",[{parts,
+ 2}]))),
+?line <<"abc81">> = iolist_to_binary(join(re:split("abc81","abc\\81",[]))),
+?line <<"abc91">> = iolist_to_binary(join(re:split("abc91","abc\\91",[trim]))),
+?line <<"abc91">> = iolist_to_binary(join(re:split("abc91","abc\\91",[{parts,
+ 2}]))),
+?line <<"abc91">> = iolist_to_binary(join(re:split("abc91","abc\\91",[]))),
+?line <<"abc91">> = iolist_to_binary(join(re:split("abc91","abc\\91",[trim]))),
+?line <<"abc91">> = iolist_to_binary(join(re:split("abc91","abc\\91",[{parts,
+ 2}]))),
+?line <<"abc91">> = iolist_to_binary(join(re:split("abc91","abc\\91",[]))),
+?line <<":a:b:c:d:e:f:g:h:i:j:k:l">> = iolist_to_binary(join(re:split("abcdefghijkllS","(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)\\12\\123",[trim]))),
+?line <<":a:b:c:d:e:f:g:h:i:j:k:l:">> = iolist_to_binary(join(re:split("abcdefghijkllS","(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)\\12\\123",[{parts,
+ 2}]))),
+?line <<":a:b:c:d:e:f:g:h:i:j:k:l:">> = iolist_to_binary(join(re:split("abcdefghijkllS","(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)\\12\\123",[]))),
+?line <<":a:b:c:d:e:f:g:h:i:j:k">> = iolist_to_binary(join(re:split("abcdefghijk
+S","(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\\12\\123",[trim]))),
+?line <<":a:b:c:d:e:f:g:h:i:j:k:">> = iolist_to_binary(join(re:split("abcdefghijk
+S","(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\\12\\123",[{parts,2}]))),
+?line <<":a:b:c:d:e:f:g:h:i:j:k:">> = iolist_to_binary(join(re:split("abcdefghijk
+S","(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\\12\\123",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abidef","ab\\idef",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abidef","ab\\idef",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abidef","ab\\idef",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("bc","a{0}bc",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("bc","a{0}bc",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("bc","a{0}bc",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("xyz","(a|(bc)){0,0}?xyz",[trim]))),
+?line <<":::">> = iolist_to_binary(join(re:split("xyz","(a|(bc)){0,0}?xyz",[{parts,
+ 2}]))),
+?line <<":::">> = iolist_to_binary(join(re:split("xyz","(a|(bc)){0,0}?xyz",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abcde","abc[\\10]de",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abcde","abc[\\10]de",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abcde","abc[\\10]de",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abcde","abc[\\1]de",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abcde","abc[\\1]de",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abcde","abc[\\1]de",[]))),
+?line <<":abc">> = iolist_to_binary(join(re:split("abcde","(abc)[\\1]de",[trim]))),
+?line <<":abc:">> = iolist_to_binary(join(re:split("abcde","(abc)[\\1]de",[{parts,
+ 2}]))),
+?line <<":abc:">> = iolist_to_binary(join(re:split("abcde","(abc)[\\1]de",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a
+b","(?s)a.b",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a
+b","(?s)a.b",[{parts,2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a
+b","(?s)a.b",[]))),
+?line <<":b:a:NOT:cccc:d">> = iolist_to_binary(join(re:split("baNOTccccd","^([^a])([^\\b])([^c]*)([^d]{3,4})",[trim]))),
+?line <<":b:a:NOT:cccc:d">> = iolist_to_binary(join(re:split("baNOTccccd","^([^a])([^\\b])([^c]*)([^d]{3,4})",[{parts,
+ 2}]))),
+?line <<":b:a:NOT:cccc:d">> = iolist_to_binary(join(re:split("baNOTccccd","^([^a])([^\\b])([^c]*)([^d]{3,4})",[]))),
+?line <<":b:a:NOT:ccc:d">> = iolist_to_binary(join(re:split("baNOTcccd","^([^a])([^\\b])([^c]*)([^d]{3,4})",[trim]))),
+?line <<":b:a:NOT:ccc:d">> = iolist_to_binary(join(re:split("baNOTcccd","^([^a])([^\\b])([^c]*)([^d]{3,4})",[{parts,
+ 2}]))),
+?line <<":b:a:NOT:ccc:d">> = iolist_to_binary(join(re:split("baNOTcccd","^([^a])([^\\b])([^c]*)([^d]{3,4})",[]))),
+?line <<":b:a:NO:Tcc:d">> = iolist_to_binary(join(re:split("baNOTccd","^([^a])([^\\b])([^c]*)([^d]{3,4})",[trim]))),
+?line <<":b:a:NO:Tcc:d">> = iolist_to_binary(join(re:split("baNOTccd","^([^a])([^\\b])([^c]*)([^d]{3,4})",[{parts,
+ 2}]))),
+?line <<":b:a:NO:Tcc:d">> = iolist_to_binary(join(re:split("baNOTccd","^([^a])([^\\b])([^c]*)([^d]{3,4})",[]))),
+?line <<":b:a::ccc:d">> = iolist_to_binary(join(re:split("bacccd","^([^a])([^\\b])([^c]*)([^d]{3,4})",[trim]))),
+?line <<":b:a::ccc:d">> = iolist_to_binary(join(re:split("bacccd","^([^a])([^\\b])([^c]*)([^d]{3,4})",[{parts,
+ 2}]))),
+?line <<":b:a::ccc:d">> = iolist_to_binary(join(re:split("bacccd","^([^a])([^\\b])([^c]*)([^d]{3,4})",[]))),
+?line <<":*:*:* Fail:ers">> = iolist_to_binary(join(re:split("*** Failers","^([^a])([^\\b])([^c]*)([^d]{3,4})",[trim]))),
+?line <<":*:*:* Fail:ers:">> = iolist_to_binary(join(re:split("*** Failers","^([^a])([^\\b])([^c]*)([^d]{3,4})",[{parts,
+ 2}]))),
+?line <<":*:*:* Fail:ers:">> = iolist_to_binary(join(re:split("*** Failers","^([^a])([^\\b])([^c]*)([^d]{3,4})",[]))),
+?line <<"anything">> = iolist_to_binary(join(re:split("anything","^([^a])([^\\b])([^c]*)([^d]{3,4})",[trim]))),
+?line <<"anything">> = iolist_to_binary(join(re:split("anything","^([^a])([^\\b])([^c]*)([^d]{3,4})",[{parts,
+ 2}]))),
+?line <<"anything">> = iolist_to_binary(join(re:split("anything","^([^a])([^\\b])([^c]*)([^d]{3,4})",[]))),
+?line <<"bc">> = iolist_to_binary(join(re:split("bc","^([^a])([^\\b])([^c]*)([^d]{3,4})",[trim]))),
+?line <<"bc">> = iolist_to_binary(join(re:split("bc","^([^a])([^\\b])([^c]*)([^d]{3,4})",[{parts,
+ 2}]))),
+?line <<"bc">> = iolist_to_binary(join(re:split("bc","^([^a])([^\\b])([^c]*)([^d]{3,4})",[]))),
+?line <<"baccd">> = iolist_to_binary(join(re:split("baccd","^([^a])([^\\b])([^c]*)([^d]{3,4})",[trim]))),
+?line <<"baccd">> = iolist_to_binary(join(re:split("baccd","^([^a])([^\\b])([^c]*)([^d]{3,4})",[{parts,
+ 2}]))),
+?line <<"baccd">> = iolist_to_binary(join(re:split("baccd","^([^a])([^\\b])([^c]*)([^d]{3,4})",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("Abc","[^a]",[trim]))),
+?line <<":bc">> = iolist_to_binary(join(re:split("Abc","[^a]",[{parts,
+ 2}]))),
+?line <<":::">> = iolist_to_binary(join(re:split("Abc","[^a]",[]))),
+?line <<"A">> = iolist_to_binary(join(re:split("Abc","[^a]",[caseless,
+ trim]))),
+?line <<"A:c">> = iolist_to_binary(join(re:split("Abc","[^a]",[caseless,
+ {parts,
+ 2}]))),
+?line <<"A::">> = iolist_to_binary(join(re:split("Abc","[^a]",[caseless]))),
+?line <<":a">> = iolist_to_binary(join(re:split("AAAaAbc","[^a]+",[trim]))),
+?line <<":aAbc">> = iolist_to_binary(join(re:split("AAAaAbc","[^a]+",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("AAAaAbc","[^a]+",[]))),
+?line <<"AAAaA">> = iolist_to_binary(join(re:split("AAAaAbc","[^a]+",[caseless,
+ trim]))),
+?line <<"AAAaA:">> = iolist_to_binary(join(re:split("AAAaAbc","[^a]+",[caseless,
+ {parts,
+ 2}]))),
+?line <<"AAAaA:">> = iolist_to_binary(join(re:split("AAAaAbc","[^a]+",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("bbb
+ccc","[^a]+",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("bbb
+ccc","[^a]+",[{parts,2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("bbb
+ccc","[^a]+",[]))),
+?line <<"ab">> = iolist_to_binary(join(re:split("abc","[^k]$",[trim]))),
+?line <<"ab:">> = iolist_to_binary(join(re:split("abc","[^k]$",[{parts,
+ 2}]))),
+?line <<"ab:">> = iolist_to_binary(join(re:split("abc","[^k]$",[]))),
+?line <<"*** Failer">> = iolist_to_binary(join(re:split("*** Failers","[^k]$",[trim]))),
+?line <<"*** Failer:">> = iolist_to_binary(join(re:split("*** Failers","[^k]$",[{parts,
+ 2}]))),
+?line <<"*** Failer:">> = iolist_to_binary(join(re:split("*** Failers","[^k]$",[]))),
+?line <<"abk">> = iolist_to_binary(join(re:split("abk","[^k]$",[trim]))),
+?line <<"abk">> = iolist_to_binary(join(re:split("abk","[^k]$",[{parts,
+ 2}]))),
+?line <<"abk">> = iolist_to_binary(join(re:split("abk","[^k]$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc","[^k]{2,3}$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","[^k]{2,3}$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","[^k]{2,3}$",[]))),
+?line <<"k">> = iolist_to_binary(join(re:split("kbc","[^k]{2,3}$",[trim]))),
+?line <<"k:">> = iolist_to_binary(join(re:split("kbc","[^k]{2,3}$",[{parts,
+ 2}]))),
+?line <<"k:">> = iolist_to_binary(join(re:split("kbc","[^k]{2,3}$",[]))),
+?line <<"k">> = iolist_to_binary(join(re:split("kabc","[^k]{2,3}$",[trim]))),
+?line <<"k:">> = iolist_to_binary(join(re:split("kabc","[^k]{2,3}$",[{parts,
+ 2}]))),
+?line <<"k:">> = iolist_to_binary(join(re:split("kabc","[^k]{2,3}$",[]))),
+?line <<"*** Fail">> = iolist_to_binary(join(re:split("*** Failers","[^k]{2,3}$",[trim]))),
+?line <<"*** Fail:">> = iolist_to_binary(join(re:split("*** Failers","[^k]{2,3}$",[{parts,
+ 2}]))),
+?line <<"*** Fail:">> = iolist_to_binary(join(re:split("*** Failers","[^k]{2,3}$",[]))),
+?line <<"abk">> = iolist_to_binary(join(re:split("abk","[^k]{2,3}$",[trim]))),
+?line <<"abk">> = iolist_to_binary(join(re:split("abk","[^k]{2,3}$",[{parts,
+ 2}]))),
+?line <<"abk">> = iolist_to_binary(join(re:split("abk","[^k]{2,3}$",[]))),
+?line <<"akb">> = iolist_to_binary(join(re:split("akb","[^k]{2,3}$",[trim]))),
+?line <<"akb">> = iolist_to_binary(join(re:split("akb","[^k]{2,3}$",[{parts,
+ 2}]))),
+?line <<"akb">> = iolist_to_binary(join(re:split("akb","[^k]{2,3}$",[]))),
+?line <<"akk">> = iolist_to_binary(join(re:split("akk","[^k]{2,3}$",[trim]))),
+?line <<"akk">> = iolist_to_binary(join(re:split("akk","[^k]{2,3}$",[{parts,
+ 2}]))),
+?line <<"akk">> = iolist_to_binary(join(re:split("akk","[^k]{2,3}$",[]))),
+?line <<"12345678.b.c.d">> = iolist_to_binary(join(re:split("12345678.b.c.d","^\\d{8,}\\@.+[^k]$",[trim]))),
+?line <<"12345678.b.c.d">> = iolist_to_binary(join(re:split("12345678.b.c.d","^\\d{8,}\\@.+[^k]$",[{parts,
+ 2}]))),
+?line <<"12345678.b.c.d">> = iolist_to_binary(join(re:split("12345678.b.c.d","^\\d{8,}\\@.+[^k]$",[]))),
+?line <<"123456789.y.z">> = iolist_to_binary(join(re:split("123456789.y.z","^\\d{8,}\\@.+[^k]$",[trim]))),
+?line <<"123456789.y.z">> = iolist_to_binary(join(re:split("123456789.y.z","^\\d{8,}\\@.+[^k]$",[{parts,
+ 2}]))),
+?line <<"123456789.y.z">> = iolist_to_binary(join(re:split("123456789.y.z","^\\d{8,}\\@.+[^k]$",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^\\d{8,}\\@.+[^k]$",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^\\d{8,}\\@.+[^k]$",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^\\d{8,}\\@.+[^k]$",[]))),
+?line <<"12345678.y.uk">> = iolist_to_binary(join(re:split("12345678.y.uk","^\\d{8,}\\@.+[^k]$",[trim]))),
+?line <<"12345678.y.uk">> = iolist_to_binary(join(re:split("12345678.y.uk","^\\d{8,}\\@.+[^k]$",[{parts,
+ 2}]))),
+?line <<"12345678.y.uk">> = iolist_to_binary(join(re:split("12345678.y.uk","^\\d{8,}\\@.+[^k]$",[]))),
+?line <<"1234567.b.c.d">> = iolist_to_binary(join(re:split("1234567.b.c.d","^\\d{8,}\\@.+[^k]$",[trim]))),
+?line <<"1234567.b.c.d">> = iolist_to_binary(join(re:split("1234567.b.c.d","^\\d{8,}\\@.+[^k]$",[{parts,
+ 2}]))),
+?line <<"1234567.b.c.d">> = iolist_to_binary(join(re:split("1234567.b.c.d","^\\d{8,}\\@.+[^k]$",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("aaaaaaaaa","(a)\\1{8,}",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aaaaaaaaa","(a)\\1{8,}",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aaaaaaaaa","(a)\\1{8,}",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("aaaaaaaaaa","(a)\\1{8,}",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aaaaaaaaaa","(a)\\1{8,}",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aaaaaaaaaa","(a)\\1{8,}",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(a)\\1{8,}",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(a)\\1{8,}",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(a)\\1{8,}",[]))),
+?line <<"aaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaa","(a)\\1{8,}",[trim]))),
+?line <<"aaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaa","(a)\\1{8,}",[{parts,
+ 2}]))),
+?line <<"aaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaa","(a)\\1{8,}",[]))),
+?line <<"aaaa">> = iolist_to_binary(join(re:split("aaaabcd","[^a]",[trim]))),
+?line <<"aaaa:cd">> = iolist_to_binary(join(re:split("aaaabcd","[^a]",[{parts,
+ 2}]))),
+?line <<"aaaa:::">> = iolist_to_binary(join(re:split("aaaabcd","[^a]",[]))),
+?line <<"aa:a">> = iolist_to_binary(join(re:split("aaAabcd","[^a]",[trim]))),
+?line <<"aa:abcd">> = iolist_to_binary(join(re:split("aaAabcd","[^a]",[{parts,
+ 2}]))),
+?line <<"aa:a:::">> = iolist_to_binary(join(re:split("aaAabcd","[^a]",[]))),
+?line <<"aaaa">> = iolist_to_binary(join(re:split("aaaabcd","[^a]",[caseless,
+ trim]))),
+?line <<"aaaa:cd">> = iolist_to_binary(join(re:split("aaaabcd","[^a]",[caseless,
+ {parts,
+ 2}]))),
+?line <<"aaaa:::">> = iolist_to_binary(join(re:split("aaaabcd","[^a]",[caseless]))),
+?line <<"aaAa">> = iolist_to_binary(join(re:split("aaAabcd","[^a]",[caseless,
+ trim]))),
+?line <<"aaAa:cd">> = iolist_to_binary(join(re:split("aaAabcd","[^a]",[caseless,
+ {parts,
+ 2}]))),
+?line <<"aaAa:::">> = iolist_to_binary(join(re:split("aaAabcd","[^a]",[caseless]))),
+?line <<"aaaa">> = iolist_to_binary(join(re:split("aaaabcd","[^az]",[trim]))),
+?line <<"aaaa:cd">> = iolist_to_binary(join(re:split("aaaabcd","[^az]",[{parts,
+ 2}]))),
+?line <<"aaaa:::">> = iolist_to_binary(join(re:split("aaaabcd","[^az]",[]))),
+?line <<"aa:a">> = iolist_to_binary(join(re:split("aaAabcd","[^az]",[trim]))),
+?line <<"aa:abcd">> = iolist_to_binary(join(re:split("aaAabcd","[^az]",[{parts,
+ 2}]))),
+?line <<"aa:a:::">> = iolist_to_binary(join(re:split("aaAabcd","[^az]",[]))),
+?line <<"aaaa">> = iolist_to_binary(join(re:split("aaaabcd","[^az]",[caseless,
+ trim]))),
+?line <<"aaaa:cd">> = iolist_to_binary(join(re:split("aaaabcd","[^az]",[caseless,
+ {parts,
+ 2}]))),
+?line <<"aaaa:::">> = iolist_to_binary(join(re:split("aaaabcd","[^az]",[caseless]))),
+?line <<"aaAa">> = iolist_to_binary(join(re:split("aaAabcd","[^az]",[caseless,
+ trim]))),
+?line <<"aaAa:cd">> = iolist_to_binary(join(re:split("aaAabcd","[^az]",[caseless,
+ {parts,
+ 2}]))),
+?line <<"aaAa:::">> = iolist_to_binary(join(re:split("aaAabcd","[^az]",[caseless]))),
+?line <<"xxxxxxxxxxx:xxxxxxxxx">> = iolist_to_binary(join(re:split("xxxxxxxxxxxPSTAIREISLLxxxxxxxxx","P[^*]TAIRE[^*]{1,6}?LL",[trim]))),
+?line <<"xxxxxxxxxxx:xxxxxxxxx">> = iolist_to_binary(join(re:split("xxxxxxxxxxxPSTAIREISLLxxxxxxxxx","P[^*]TAIRE[^*]{1,6}?LL",[{parts,
+ 2}]))),
+?line <<"xxxxxxxxxxx:xxxxxxxxx">> = iolist_to_binary(join(re:split("xxxxxxxxxxxPSTAIREISLLxxxxxxxxx","P[^*]TAIRE[^*]{1,6}?LL",[]))),
+?line <<"xxxxxxxxxxx:xxxxxxxxx">> = iolist_to_binary(join(re:split("xxxxxxxxxxxPSTAIREISLLxxxxxxxxx","P[^*]TAIRE[^*]{1,}?LL",[trim]))),
+?line <<"xxxxxxxxxxx:xxxxxxxxx">> = iolist_to_binary(join(re:split("xxxxxxxxxxxPSTAIREISLLxxxxxxxxx","P[^*]TAIRE[^*]{1,}?LL",[{parts,
+ 2}]))),
+?line <<"xxxxxxxxxxx:xxxxxxxxx">> = iolist_to_binary(join(re:split("xxxxxxxxxxxPSTAIREISLLxxxxxxxxx","P[^*]TAIRE[^*]{1,}?LL",[]))),
+?line <<"1:.23">> = iolist_to_binary(join(re:split("1.230003938","(\\.\\d\\d[1-9]?)\\d+",[trim]))),
+?line <<"1:.23:">> = iolist_to_binary(join(re:split("1.230003938","(\\.\\d\\d[1-9]?)\\d+",[{parts,
+ 2}]))),
+?line <<"1:.23:">> = iolist_to_binary(join(re:split("1.230003938","(\\.\\d\\d[1-9]?)\\d+",[]))),
+?line <<"1:.875">> = iolist_to_binary(join(re:split("1.875000282","(\\.\\d\\d[1-9]?)\\d+",[trim]))),
+?line <<"1:.875:">> = iolist_to_binary(join(re:split("1.875000282","(\\.\\d\\d[1-9]?)\\d+",[{parts,
+ 2}]))),
+?line <<"1:.875:">> = iolist_to_binary(join(re:split("1.875000282","(\\.\\d\\d[1-9]?)\\d+",[]))),
+?line <<"1:.23">> = iolist_to_binary(join(re:split("1.235","(\\.\\d\\d[1-9]?)\\d+",[trim]))),
+?line <<"1:.23:">> = iolist_to_binary(join(re:split("1.235","(\\.\\d\\d[1-9]?)\\d+",[{parts,
+ 2}]))),
+?line <<"1:.23:">> = iolist_to_binary(join(re:split("1.235","(\\.\\d\\d[1-9]?)\\d+",[]))),
+?line <<"1:.23::0003938">> = iolist_to_binary(join(re:split("1.230003938","(\\.\\d\\d((?=0)|\\d(?=\\d)))",[trim]))),
+?line <<"1:.23::0003938">> = iolist_to_binary(join(re:split("1.230003938","(\\.\\d\\d((?=0)|\\d(?=\\d)))",[{parts,
+ 2}]))),
+?line <<"1:.23::0003938">> = iolist_to_binary(join(re:split("1.230003938","(\\.\\d\\d((?=0)|\\d(?=\\d)))",[]))),
+?line <<"1:.875:5:000282">> = iolist_to_binary(join(re:split("1.875000282","(\\.\\d\\d((?=0)|\\d(?=\\d)))",[trim]))),
+?line <<"1:.875:5:000282">> = iolist_to_binary(join(re:split("1.875000282","(\\.\\d\\d((?=0)|\\d(?=\\d)))",[{parts,
+ 2}]))),
+?line <<"1:.875:5:000282">> = iolist_to_binary(join(re:split("1.875000282","(\\.\\d\\d((?=0)|\\d(?=\\d)))",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(\\.\\d\\d((?=0)|\\d(?=\\d)))",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(\\.\\d\\d((?=0)|\\d(?=\\d)))",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(\\.\\d\\d((?=0)|\\d(?=\\d)))",[]))),
+?line <<"1.235">> = iolist_to_binary(join(re:split("1.235","(\\.\\d\\d((?=0)|\\d(?=\\d)))",[trim]))),
+?line <<"1.235">> = iolist_to_binary(join(re:split("1.235","(\\.\\d\\d((?=0)|\\d(?=\\d)))",[{parts,
+ 2}]))),
+?line <<"1.235">> = iolist_to_binary(join(re:split("1.235","(\\.\\d\\d((?=0)|\\d(?=\\d)))",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("ab","a(?)b",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ab","a(?)b",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ab","a(?)b",[]))),
+?line <<"Food is on the :foo:table">> = iolist_to_binary(join(re:split("Food is on the foo table","\\b(foo)\\s+(\\w+)",[caseless,
+ trim]))),
+?line <<"Food is on the :foo:table:">> = iolist_to_binary(join(re:split("Food is on the foo table","\\b(foo)\\s+(\\w+)",[caseless,
+ {parts,
+ 2}]))),
+?line <<"Food is on the :foo:table:">> = iolist_to_binary(join(re:split("Food is on the foo table","\\b(foo)\\s+(\\w+)",[caseless]))),
+?line <<"The :d is under the bar in the :n.">> = iolist_to_binary(join(re:split("The food is under the bar in the barn.","foo(.*)bar",[trim]))),
+?line <<"The :d is under the bar in the :n.">> = iolist_to_binary(join(re:split("The food is under the bar in the barn.","foo(.*)bar",[{parts,
+ 2}]))),
+?line <<"The :d is under the bar in the :n.">> = iolist_to_binary(join(re:split("The food is under the bar in the barn.","foo(.*)bar",[]))),
+?line <<"The :d is under the : in the barn.">> = iolist_to_binary(join(re:split("The food is under the bar in the barn.","foo(.*?)bar",[trim]))),
+?line <<"The :d is under the : in the barn.">> = iolist_to_binary(join(re:split("The food is under the bar in the barn.","foo(.*?)bar",[{parts,
+ 2}]))),
+?line <<"The :d is under the : in the barn.">> = iolist_to_binary(join(re:split("The food is under the bar in the barn.","foo(.*?)bar",[]))),
+?line <<":I have 2 numbers: 53147">> = iolist_to_binary(join(re:split("I have 2 numbers: 53147","(.*)(\\d*)",[trim]))),
+?line <<":I have 2 numbers: 53147::">> = iolist_to_binary(join(re:split("I have 2 numbers: 53147","(.*)(\\d*)",[{parts,
+ 2}]))),
+?line <<":I have 2 numbers: 53147::">> = iolist_to_binary(join(re:split("I have 2 numbers: 53147","(.*)(\\d*)",[]))),
+?line <<":I have 2 numbers: 5314:7">> = iolist_to_binary(join(re:split("I have 2 numbers: 53147","(.*)(\\d+)",[trim]))),
+?line <<":I have 2 numbers: 5314:7:">> = iolist_to_binary(join(re:split("I have 2 numbers: 53147","(.*)(\\d+)",[{parts,
+ 2}]))),
+?line <<":I have 2 numbers: 5314:7:">> = iolist_to_binary(join(re:split("I have 2 numbers: 53147","(.*)(\\d+)",[]))),
+?line <<":I::: :::h:::a:::v:::e::: :2:: :::n:::u:::m:::b:::e:::r:::s::::::: :53147">> = iolist_to_binary(join(re:split("I have 2 numbers: 53147","(.*?)(\\d*)",[trim]))),
+?line <<":I:: have 2 numbers: 53147">> = iolist_to_binary(join(re:split("I have 2 numbers: 53147","(.*?)(\\d*)",[{parts,
+ 2}]))),
+?line <<":I::: :::h:::a:::v:::e::: :2:: :::n:::u:::m:::b:::e:::r:::s::::::: :53147:">> = iolist_to_binary(join(re:split("I have 2 numbers: 53147","(.*?)(\\d*)",[]))),
+?line <<":I have :2:: numbers: :53147">> = iolist_to_binary(join(re:split("I have 2 numbers: 53147","(.*?)(\\d+)",[trim]))),
+?line <<":I have :2: numbers: 53147">> = iolist_to_binary(join(re:split("I have 2 numbers: 53147","(.*?)(\\d+)",[{parts,
+ 2}]))),
+?line <<":I have :2:: numbers: :53147:">> = iolist_to_binary(join(re:split("I have 2 numbers: 53147","(.*?)(\\d+)",[]))),
+?line <<":I have 2 numbers: 5314:7">> = iolist_to_binary(join(re:split("I have 2 numbers: 53147","(.*)(\\d+)$",[trim]))),
+?line <<":I have 2 numbers: 5314:7:">> = iolist_to_binary(join(re:split("I have 2 numbers: 53147","(.*)(\\d+)$",[{parts,
+ 2}]))),
+?line <<":I have 2 numbers: 5314:7:">> = iolist_to_binary(join(re:split("I have 2 numbers: 53147","(.*)(\\d+)$",[]))),
+?line <<":I have 2 numbers: :53147">> = iolist_to_binary(join(re:split("I have 2 numbers: 53147","(.*?)(\\d+)$",[trim]))),
+?line <<":I have 2 numbers: :53147:">> = iolist_to_binary(join(re:split("I have 2 numbers: 53147","(.*?)(\\d+)$",[{parts,
+ 2}]))),
+?line <<":I have 2 numbers: :53147:">> = iolist_to_binary(join(re:split("I have 2 numbers: 53147","(.*?)(\\d+)$",[]))),
+?line <<":I have 2 numbers: :53147">> = iolist_to_binary(join(re:split("I have 2 numbers: 53147","(.*)\\b(\\d+)$",[trim]))),
+?line <<":I have 2 numbers: :53147:">> = iolist_to_binary(join(re:split("I have 2 numbers: 53147","(.*)\\b(\\d+)$",[{parts,
+ 2}]))),
+?line <<":I have 2 numbers: :53147:">> = iolist_to_binary(join(re:split("I have 2 numbers: 53147","(.*)\\b(\\d+)$",[]))),
+?line <<":I have 2 numbers: :53147">> = iolist_to_binary(join(re:split("I have 2 numbers: 53147","(.*\\D)(\\d+)$",[trim]))),
+?line <<":I have 2 numbers: :53147:">> = iolist_to_binary(join(re:split("I have 2 numbers: 53147","(.*\\D)(\\d+)$",[{parts,
+ 2}]))),
+?line <<":I have 2 numbers: :53147:">> = iolist_to_binary(join(re:split("I have 2 numbers: 53147","(.*\\D)(\\d+)$",[]))),
+?line <<":C123">> = iolist_to_binary(join(re:split("ABC123","^\\D*(?!123)",[trim]))),
+?line <<":C123">> = iolist_to_binary(join(re:split("ABC123","^\\D*(?!123)",[{parts,
+ 2}]))),
+?line <<":C123">> = iolist_to_binary(join(re:split("ABC123","^\\D*(?!123)",[]))),
+?line <<":ABC:445">> = iolist_to_binary(join(re:split("ABC445","^(\\D*)(?=\\d)(?!123)",[trim]))),
+?line <<":ABC:445">> = iolist_to_binary(join(re:split("ABC445","^(\\D*)(?=\\d)(?!123)",[{parts,
+ 2}]))),
+?line <<":ABC:445">> = iolist_to_binary(join(re:split("ABC445","^(\\D*)(?=\\d)(?!123)",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(\\D*)(?=\\d)(?!123)",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(\\D*)(?=\\d)(?!123)",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(\\D*)(?=\\d)(?!123)",[]))),
+?line <<"ABC123">> = iolist_to_binary(join(re:split("ABC123","^(\\D*)(?=\\d)(?!123)",[trim]))),
+?line <<"ABC123">> = iolist_to_binary(join(re:split("ABC123","^(\\D*)(?=\\d)(?!123)",[{parts,
+ 2}]))),
+?line <<"ABC123">> = iolist_to_binary(join(re:split("ABC123","^(\\D*)(?=\\d)(?!123)",[]))),
+?line <<":789">> = iolist_to_binary(join(re:split("W46]789","^[W-]46]",[trim]))),
+?line <<":789">> = iolist_to_binary(join(re:split("W46]789","^[W-]46]",[{parts,
+ 2}]))),
+?line <<":789">> = iolist_to_binary(join(re:split("W46]789","^[W-]46]",[]))),
+?line <<":789">> = iolist_to_binary(join(re:split("-46]789","^[W-]46]",[trim]))),
+?line <<":789">> = iolist_to_binary(join(re:split("-46]789","^[W-]46]",[{parts,
+ 2}]))),
+?line <<":789">> = iolist_to_binary(join(re:split("-46]789","^[W-]46]",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^[W-]46]",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^[W-]46]",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^[W-]46]",[]))),
+?line <<"Wall">> = iolist_to_binary(join(re:split("Wall","^[W-]46]",[trim]))),
+?line <<"Wall">> = iolist_to_binary(join(re:split("Wall","^[W-]46]",[{parts,
+ 2}]))),
+?line <<"Wall">> = iolist_to_binary(join(re:split("Wall","^[W-]46]",[]))),
+?line <<"Zebra">> = iolist_to_binary(join(re:split("Zebra","^[W-]46]",[trim]))),
+?line <<"Zebra">> = iolist_to_binary(join(re:split("Zebra","^[W-]46]",[{parts,
+ 2}]))),
+?line <<"Zebra">> = iolist_to_binary(join(re:split("Zebra","^[W-]46]",[]))),
+?line <<"42">> = iolist_to_binary(join(re:split("42","^[W-]46]",[trim]))),
+?line <<"42">> = iolist_to_binary(join(re:split("42","^[W-]46]",[{parts,
+ 2}]))),
+?line <<"42">> = iolist_to_binary(join(re:split("42","^[W-]46]",[]))),
+?line <<"[abcd]">> = iolist_to_binary(join(re:split("[abcd]","^[W-]46]",[trim]))),
+?line <<"[abcd]">> = iolist_to_binary(join(re:split("[abcd]","^[W-]46]",[{parts,
+ 2}]))),
+?line <<"[abcd]">> = iolist_to_binary(join(re:split("[abcd]","^[W-]46]",[]))),
+?line <<"]abcd[">> = iolist_to_binary(join(re:split("]abcd[","^[W-]46]",[trim]))),
+?line <<"]abcd[">> = iolist_to_binary(join(re:split("]abcd[","^[W-]46]",[{parts,
+ 2}]))),
+?line <<"]abcd[">> = iolist_to_binary(join(re:split("]abcd[","^[W-]46]",[]))),
+?line <<":46]789">> = iolist_to_binary(join(re:split("W46]789","^[W-\\]46]",[trim]))),
+?line <<":46]789">> = iolist_to_binary(join(re:split("W46]789","^[W-\\]46]",[{parts,
+ 2}]))),
+?line <<":46]789">> = iolist_to_binary(join(re:split("W46]789","^[W-\\]46]",[]))),
+?line <<":all">> = iolist_to_binary(join(re:split("Wall","^[W-\\]46]",[trim]))),
+?line <<":all">> = iolist_to_binary(join(re:split("Wall","^[W-\\]46]",[{parts,
+ 2}]))),
+?line <<":all">> = iolist_to_binary(join(re:split("Wall","^[W-\\]46]",[]))),
+?line <<":ebra">> = iolist_to_binary(join(re:split("Zebra","^[W-\\]46]",[trim]))),
+?line <<":ebra">> = iolist_to_binary(join(re:split("Zebra","^[W-\\]46]",[{parts,
+ 2}]))),
+?line <<":ebra">> = iolist_to_binary(join(re:split("Zebra","^[W-\\]46]",[]))),
+?line <<":ylophone">> = iolist_to_binary(join(re:split("Xylophone","^[W-\\]46]",[trim]))),
+?line <<":ylophone">> = iolist_to_binary(join(re:split("Xylophone","^[W-\\]46]",[{parts,
+ 2}]))),
+?line <<":ylophone">> = iolist_to_binary(join(re:split("Xylophone","^[W-\\]46]",[]))),
+?line <<":2">> = iolist_to_binary(join(re:split("42","^[W-\\]46]",[trim]))),
+?line <<":2">> = iolist_to_binary(join(re:split("42","^[W-\\]46]",[{parts,
+ 2}]))),
+?line <<":2">> = iolist_to_binary(join(re:split("42","^[W-\\]46]",[]))),
+?line <<":abcd]">> = iolist_to_binary(join(re:split("[abcd]","^[W-\\]46]",[trim]))),
+?line <<":abcd]">> = iolist_to_binary(join(re:split("[abcd]","^[W-\\]46]",[{parts,
+ 2}]))),
+?line <<":abcd]">> = iolist_to_binary(join(re:split("[abcd]","^[W-\\]46]",[]))),
+?line <<":abcd[">> = iolist_to_binary(join(re:split("]abcd[","^[W-\\]46]",[trim]))),
+?line <<":abcd[">> = iolist_to_binary(join(re:split("]abcd[","^[W-\\]46]",[{parts,
+ 2}]))),
+?line <<":abcd[">> = iolist_to_binary(join(re:split("]abcd[","^[W-\\]46]",[]))),
+?line <<":backslash">> = iolist_to_binary(join(re:split("\\backslash","^[W-\\]46]",[trim]))),
+?line <<":backslash">> = iolist_to_binary(join(re:split("\\backslash","^[W-\\]46]",[{parts,
+ 2}]))),
+?line <<":backslash">> = iolist_to_binary(join(re:split("\\backslash","^[W-\\]46]",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^[W-\\]46]",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^[W-\\]46]",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^[W-\\]46]",[]))),
+?line <<"-46]789">> = iolist_to_binary(join(re:split("-46]789","^[W-\\]46]",[trim]))),
+?line <<"-46]789">> = iolist_to_binary(join(re:split("-46]789","^[W-\\]46]",[{parts,
+ 2}]))),
+?line <<"-46]789">> = iolist_to_binary(join(re:split("-46]789","^[W-\\]46]",[]))),
+?line <<"well">> = iolist_to_binary(join(re:split("well","^[W-\\]46]",[trim]))),
+?line <<"well">> = iolist_to_binary(join(re:split("well","^[W-\\]46]",[{parts,
+ 2}]))),
+?line <<"well">> = iolist_to_binary(join(re:split("well","^[W-\\]46]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("word cat dog elephant mussel cow horse canary baboon snake shark otherword","word (?:[a-zA-Z0-9]+ ){0,10}otherword",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("word cat dog elephant mussel cow horse canary baboon snake shark otherword","word (?:[a-zA-Z0-9]+ ){0,10}otherword",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("word cat dog elephant mussel cow horse canary baboon snake shark otherword","word (?:[a-zA-Z0-9]+ ){0,10}otherword",[]))),
+?line <<"word cat dog elephant mussel cow horse canary baboon snake shark">> = iolist_to_binary(join(re:split("word cat dog elephant mussel cow horse canary baboon snake shark","word (?:[a-zA-Z0-9]+ ){0,10}otherword",[trim]))),
+?line <<"word cat dog elephant mussel cow horse canary baboon snake shark">> = iolist_to_binary(join(re:split("word cat dog elephant mussel cow horse canary baboon snake shark","word (?:[a-zA-Z0-9]+ ){0,10}otherword",[{parts,
+ 2}]))),
+?line <<"word cat dog elephant mussel cow horse canary baboon snake shark">> = iolist_to_binary(join(re:split("word cat dog elephant mussel cow horse canary baboon snake shark","word (?:[a-zA-Z0-9]+ ){0,10}otherword",[]))),
+?line <<"word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope">> = iolist_to_binary(join(re:split("word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope","word (?:[a-zA-Z0-9]+ ){0,300}otherword",[trim]))),
+?line <<"word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope">> = iolist_to_binary(join(re:split("word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope","word (?:[a-zA-Z0-9]+ ){0,300}otherword",[{parts,
+ 2}]))),
+?line <<"word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope">> = iolist_to_binary(join(re:split("word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope","word (?:[a-zA-Z0-9]+ ){0,300}otherword",[]))),
+?line <<"bcd">> = iolist_to_binary(join(re:split("bcd","^(a){0,0}",[trim]))),
+?line <<"bcd">> = iolist_to_binary(join(re:split("bcd","^(a){0,0}",[{parts,
+ 2}]))),
+?line <<"bcd">> = iolist_to_binary(join(re:split("bcd","^(a){0,0}",[]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","^(a){0,0}",[trim]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","^(a){0,0}",[{parts,
+ 2}]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","^(a){0,0}",[]))),
+?line <<"aab">> = iolist_to_binary(join(re:split("aab","^(a){0,0}",[trim]))),
+?line <<"aab">> = iolist_to_binary(join(re:split("aab","^(a){0,0}",[{parts,
+ 2}]))),
+?line <<"aab">> = iolist_to_binary(join(re:split("aab","^(a){0,0}",[]))),
+?line <<"bcd">> = iolist_to_binary(join(re:split("bcd","^(a){0,1}",[trim]))),
+?line <<"bcd">> = iolist_to_binary(join(re:split("bcd","^(a){0,1}",[{parts,
+ 2}]))),
+?line <<"bcd">> = iolist_to_binary(join(re:split("bcd","^(a){0,1}",[]))),
+?line <<":a:bc">> = iolist_to_binary(join(re:split("abc","^(a){0,1}",[trim]))),
+?line <<":a:bc">> = iolist_to_binary(join(re:split("abc","^(a){0,1}",[{parts,
+ 2}]))),
+?line <<":a:bc">> = iolist_to_binary(join(re:split("abc","^(a){0,1}",[]))),
+?line <<":a:ab">> = iolist_to_binary(join(re:split("aab","^(a){0,1}",[trim]))),
+?line <<":a:ab">> = iolist_to_binary(join(re:split("aab","^(a){0,1}",[{parts,
+ 2}]))),
+?line <<":a:ab">> = iolist_to_binary(join(re:split("aab","^(a){0,1}",[]))),
+?line <<"bcd">> = iolist_to_binary(join(re:split("bcd","^(a){0,2}",[trim]))),
+?line <<"bcd">> = iolist_to_binary(join(re:split("bcd","^(a){0,2}",[{parts,
+ 2}]))),
+?line <<"bcd">> = iolist_to_binary(join(re:split("bcd","^(a){0,2}",[]))),
+?line <<":a:bc">> = iolist_to_binary(join(re:split("abc","^(a){0,2}",[trim]))),
+?line <<":a:bc">> = iolist_to_binary(join(re:split("abc","^(a){0,2}",[{parts,
+ 2}]))),
+?line <<":a:bc">> = iolist_to_binary(join(re:split("abc","^(a){0,2}",[]))),
+?line <<":a:b">> = iolist_to_binary(join(re:split("aab","^(a){0,2}",[trim]))),
+?line <<":a:b">> = iolist_to_binary(join(re:split("aab","^(a){0,2}",[{parts,
+ 2}]))),
+?line <<":a:b">> = iolist_to_binary(join(re:split("aab","^(a){0,2}",[]))),
+?line <<"bcd">> = iolist_to_binary(join(re:split("bcd","^(a){0,3}",[trim]))),
+?line <<"bcd">> = iolist_to_binary(join(re:split("bcd","^(a){0,3}",[{parts,
+ 2}]))),
+?line <<"bcd">> = iolist_to_binary(join(re:split("bcd","^(a){0,3}",[]))),
+?line <<":a:bc">> = iolist_to_binary(join(re:split("abc","^(a){0,3}",[trim]))),
+?line <<":a:bc">> = iolist_to_binary(join(re:split("abc","^(a){0,3}",[{parts,
+ 2}]))),
+?line <<":a:bc">> = iolist_to_binary(join(re:split("abc","^(a){0,3}",[]))),
+?line <<":a:b">> = iolist_to_binary(join(re:split("aab","^(a){0,3}",[trim]))),
+?line <<":a:b">> = iolist_to_binary(join(re:split("aab","^(a){0,3}",[{parts,
+ 2}]))),
+?line <<":a:b">> = iolist_to_binary(join(re:split("aab","^(a){0,3}",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("aaa","^(a){0,3}",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aaa","^(a){0,3}",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aaa","^(a){0,3}",[]))),
+?line <<"bcd">> = iolist_to_binary(join(re:split("bcd","^(a){0,}",[trim]))),
+?line <<"bcd">> = iolist_to_binary(join(re:split("bcd","^(a){0,}",[{parts,
+ 2}]))),
+?line <<"bcd">> = iolist_to_binary(join(re:split("bcd","^(a){0,}",[]))),
+?line <<":a:bc">> = iolist_to_binary(join(re:split("abc","^(a){0,}",[trim]))),
+?line <<":a:bc">> = iolist_to_binary(join(re:split("abc","^(a){0,}",[{parts,
+ 2}]))),
+?line <<":a:bc">> = iolist_to_binary(join(re:split("abc","^(a){0,}",[]))),
+?line <<":a:b">> = iolist_to_binary(join(re:split("aab","^(a){0,}",[trim]))),
+?line <<":a:b">> = iolist_to_binary(join(re:split("aab","^(a){0,}",[{parts,
+ 2}]))),
+?line <<":a:b">> = iolist_to_binary(join(re:split("aab","^(a){0,}",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("aaa","^(a){0,}",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aaa","^(a){0,}",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aaa","^(a){0,}",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("aaaaaaaa","^(a){0,}",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aaaaaaaa","^(a){0,}",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aaaaaaaa","^(a){0,}",[]))),
+?line <<"bcd">> = iolist_to_binary(join(re:split("bcd","^(a){1,1}",[trim]))),
+?line <<"bcd">> = iolist_to_binary(join(re:split("bcd","^(a){1,1}",[{parts,
+ 2}]))),
+?line <<"bcd">> = iolist_to_binary(join(re:split("bcd","^(a){1,1}",[]))),
+?line <<":a:bc">> = iolist_to_binary(join(re:split("abc","^(a){1,1}",[trim]))),
+?line <<":a:bc">> = iolist_to_binary(join(re:split("abc","^(a){1,1}",[{parts,
+ 2}]))),
+?line <<":a:bc">> = iolist_to_binary(join(re:split("abc","^(a){1,1}",[]))),
+?line <<":a:ab">> = iolist_to_binary(join(re:split("aab","^(a){1,1}",[trim]))),
+?line <<":a:ab">> = iolist_to_binary(join(re:split("aab","^(a){1,1}",[{parts,
+ 2}]))),
+?line <<":a:ab">> = iolist_to_binary(join(re:split("aab","^(a){1,1}",[]))),
+?line <<"bcd">> = iolist_to_binary(join(re:split("bcd","^(a){1,2}",[trim]))),
+?line <<"bcd">> = iolist_to_binary(join(re:split("bcd","^(a){1,2}",[{parts,
+ 2}]))),
+?line <<"bcd">> = iolist_to_binary(join(re:split("bcd","^(a){1,2}",[]))),
+?line <<":a:bc">> = iolist_to_binary(join(re:split("abc","^(a){1,2}",[trim]))),
+?line <<":a:bc">> = iolist_to_binary(join(re:split("abc","^(a){1,2}",[{parts,
+ 2}]))),
+?line <<":a:bc">> = iolist_to_binary(join(re:split("abc","^(a){1,2}",[]))),
+?line <<":a:b">> = iolist_to_binary(join(re:split("aab","^(a){1,2}",[trim]))),
+?line <<":a:b">> = iolist_to_binary(join(re:split("aab","^(a){1,2}",[{parts,
+ 2}]))),
+?line <<":a:b">> = iolist_to_binary(join(re:split("aab","^(a){1,2}",[]))),
+?line <<"bcd">> = iolist_to_binary(join(re:split("bcd","^(a){1,3}",[trim]))),
+?line <<"bcd">> = iolist_to_binary(join(re:split("bcd","^(a){1,3}",[{parts,
+ 2}]))),
+?line <<"bcd">> = iolist_to_binary(join(re:split("bcd","^(a){1,3}",[]))),
+?line <<":a:bc">> = iolist_to_binary(join(re:split("abc","^(a){1,3}",[trim]))),
+?line <<":a:bc">> = iolist_to_binary(join(re:split("abc","^(a){1,3}",[{parts,
+ 2}]))),
+?line <<":a:bc">> = iolist_to_binary(join(re:split("abc","^(a){1,3}",[]))),
+?line <<":a:b">> = iolist_to_binary(join(re:split("aab","^(a){1,3}",[trim]))),
+?line <<":a:b">> = iolist_to_binary(join(re:split("aab","^(a){1,3}",[{parts,
+ 2}]))),
+?line <<":a:b">> = iolist_to_binary(join(re:split("aab","^(a){1,3}",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("aaa","^(a){1,3}",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aaa","^(a){1,3}",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aaa","^(a){1,3}",[]))),
+?line <<"bcd">> = iolist_to_binary(join(re:split("bcd","^(a){1,}",[trim]))),
+?line <<"bcd">> = iolist_to_binary(join(re:split("bcd","^(a){1,}",[{parts,
+ 2}]))),
+?line <<"bcd">> = iolist_to_binary(join(re:split("bcd","^(a){1,}",[]))),
+?line <<":a:bc">> = iolist_to_binary(join(re:split("abc","^(a){1,}",[trim]))),
+?line <<":a:bc">> = iolist_to_binary(join(re:split("abc","^(a){1,}",[{parts,
+ 2}]))),
+?line <<":a:bc">> = iolist_to_binary(join(re:split("abc","^(a){1,}",[]))),
+?line <<":a:b">> = iolist_to_binary(join(re:split("aab","^(a){1,}",[trim]))),
+?line <<":a:b">> = iolist_to_binary(join(re:split("aab","^(a){1,}",[{parts,
+ 2}]))),
+?line <<":a:b">> = iolist_to_binary(join(re:split("aab","^(a){1,}",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("aaa","^(a){1,}",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aaa","^(a){1,}",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aaa","^(a){1,}",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("aaaaaaaa","^(a){1,}",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aaaaaaaa","^(a){1,}",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aaaaaaaa","^(a){1,}",[]))),
+?line <<"borfle
+:
+no">> = iolist_to_binary(join(re:split("borfle
+bib.gif
+no",".*\\.gif",[trim]))),
+?line <<"borfle
+:
+no">> = iolist_to_binary(join(re:split("borfle
+bib.gif
+no",".*\\.gif",[{parts,2}]))),
+?line <<"borfle
+:
+no">> = iolist_to_binary(join(re:split("borfle
+bib.gif
+no",".*\\.gif",[]))),
+?line <<"borfle
+:
+no">> = iolist_to_binary(join(re:split("borfle
+bib.gif
+no",".{0,}\\.gif",[trim]))),
+?line <<"borfle
+:
+no">> = iolist_to_binary(join(re:split("borfle
+bib.gif
+no",".{0,}\\.gif",[{parts,2}]))),
+?line <<"borfle
+:
+no">> = iolist_to_binary(join(re:split("borfle
+bib.gif
+no",".{0,}\\.gif",[]))),
+?line <<"borfle
+:
+no">> = iolist_to_binary(join(re:split("borfle
+bib.gif
+no",".*\\.gif",[multiline,trim]))),
+?line <<"borfle
+:
+no">> = iolist_to_binary(join(re:split("borfle
+bib.gif
+no",".*\\.gif",[multiline,{parts,2}]))),
+?line <<"borfle
+:
+no">> = iolist_to_binary(join(re:split("borfle
+bib.gif
+no",".*\\.gif",[multiline]))),
+?line <<":
+no">> = iolist_to_binary(join(re:split("borfle
+bib.gif
+no",".*\\.gif",[dotall,trim]))),
+?line <<":
+no">> = iolist_to_binary(join(re:split("borfle
+bib.gif
+no",".*\\.gif",[dotall,{parts,2}]))),
+?line <<":
+no">> = iolist_to_binary(join(re:split("borfle
+bib.gif
+no",".*\\.gif",[dotall]))),
+?line <<":
+no">> = iolist_to_binary(join(re:split("borfle
+bib.gif
+no",".*\\.gif",[multiline,dotall,trim]))),
+?line <<":
+no">> = iolist_to_binary(join(re:split("borfle
+bib.gif
+no",".*\\.gif",[multiline,dotall,{parts,2}]))),
+?line <<":
+no">> = iolist_to_binary(join(re:split("borfle
+bib.gif
+no",".*\\.gif",[multiline,dotall]))),
+?line <<"borfle
+bib.gif
+">> = iolist_to_binary(join(re:split("borfle
+bib.gif
+no",".*$",[trim]))),
+?line <<"borfle
+bib.gif
+:">> = iolist_to_binary(join(re:split("borfle
+bib.gif
+no",".*$",[{parts,2}]))),
+?line <<"borfle
+bib.gif
+:">> = iolist_to_binary(join(re:split("borfle
+bib.gif
+no",".*$",[]))),
+?line <<":
+:
+">> = iolist_to_binary(join(re:split("borfle
+bib.gif
+no",".*$",[multiline,trim]))),
+?line <<":
+bib.gif
+no">> = iolist_to_binary(join(re:split("borfle
+bib.gif
+no",".*$",[multiline,{parts,2}]))),
+?line <<":
+:
+:">> = iolist_to_binary(join(re:split("borfle
+bib.gif
+no",".*$",[multiline]))),
+?line <<"">> = iolist_to_binary(join(re:split("borfle
+bib.gif
+no",".*$",[dotall,trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("borfle
+bib.gif
+no",".*$",[dotall,{parts,2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("borfle
+bib.gif
+no",".*$",[dotall]))),
+?line <<"">> = iolist_to_binary(join(re:split("borfle
+bib.gif
+no",".*$",[multiline,dotall,trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("borfle
+bib.gif
+no",".*$",[multiline,dotall,{parts,2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("borfle
+bib.gif
+no",".*$",[multiline,dotall]))),
+?line <<"borfle
+bib.gif
+">> = iolist_to_binary(join(re:split("borfle
+bib.gif
+no",".*$",[trim]))),
+?line <<"borfle
+bib.gif
+:">> = iolist_to_binary(join(re:split("borfle
+bib.gif
+no",".*$",[{parts,2}]))),
+?line <<"borfle
+bib.gif
+:">> = iolist_to_binary(join(re:split("borfle
+bib.gif
+no",".*$",[]))),
+?line <<":
+:
+">> = iolist_to_binary(join(re:split("borfle
+bib.gif
+no",".*$",[multiline,trim]))),
+?line <<":
+bib.gif
+no">> = iolist_to_binary(join(re:split("borfle
+bib.gif
+no",".*$",[multiline,{parts,2}]))),
+?line <<":
+:
+:">> = iolist_to_binary(join(re:split("borfle
+bib.gif
+no",".*$",[multiline]))),
+?line <<"">> = iolist_to_binary(join(re:split("borfle
+bib.gif
+no",".*$",[dotall,trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("borfle
+bib.gif
+no",".*$",[dotall,{parts,2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("borfle
+bib.gif
+no",".*$",[dotall]))),
+?line <<"">> = iolist_to_binary(join(re:split("borfle
+bib.gif
+no",".*$",[multiline,dotall,trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("borfle
+bib.gif
+no",".*$",[multiline,dotall,{parts,2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("borfle
+bib.gif
+no",".*$",[multiline,dotall]))),
+?line <<"abcde
+:1234X:yz">> = iolist_to_binary(join(re:split("abcde
+1234Xyz","(.*X|^B)",[trim]))),
+?line <<"abcde
+:1234X:yz">> = iolist_to_binary(join(re:split("abcde
+1234Xyz","(.*X|^B)",[{parts,2}]))),
+?line <<"abcde
+:1234X:yz">> = iolist_to_binary(join(re:split("abcde
+1234Xyz","(.*X|^B)",[]))),
+?line <<":B:arFoo">> = iolist_to_binary(join(re:split("BarFoo","(.*X|^B)",[trim]))),
+?line <<":B:arFoo">> = iolist_to_binary(join(re:split("BarFoo","(.*X|^B)",[{parts,
+ 2}]))),
+?line <<":B:arFoo">> = iolist_to_binary(join(re:split("BarFoo","(.*X|^B)",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(.*X|^B)",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(.*X|^B)",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(.*X|^B)",[]))),
+?line <<"abcde
+Bar">> = iolist_to_binary(join(re:split("abcde
+Bar","(.*X|^B)",[trim]))),
+?line <<"abcde
+Bar">> = iolist_to_binary(join(re:split("abcde
+Bar","(.*X|^B)",[{parts,2}]))),
+?line <<"abcde
+Bar">> = iolist_to_binary(join(re:split("abcde
+Bar","(.*X|^B)",[]))),
+?line <<"abcde
+:1234X:yz">> = iolist_to_binary(join(re:split("abcde
+1234Xyz","(.*X|^B)",[multiline,trim]))),
+?line <<"abcde
+:1234X:yz">> = iolist_to_binary(join(re:split("abcde
+1234Xyz","(.*X|^B)",[multiline,{parts,2}]))),
+?line <<"abcde
+:1234X:yz">> = iolist_to_binary(join(re:split("abcde
+1234Xyz","(.*X|^B)",[multiline]))),
+?line <<":B:arFoo">> = iolist_to_binary(join(re:split("BarFoo","(.*X|^B)",[multiline,
+ trim]))),
+?line <<":B:arFoo">> = iolist_to_binary(join(re:split("BarFoo","(.*X|^B)",[multiline,
+ {parts,
+ 2}]))),
+?line <<":B:arFoo">> = iolist_to_binary(join(re:split("BarFoo","(.*X|^B)",[multiline]))),
+?line <<"abcde
+:B:ar">> = iolist_to_binary(join(re:split("abcde
+Bar","(.*X|^B)",[multiline,trim]))),
+?line <<"abcde
+:B:ar">> = iolist_to_binary(join(re:split("abcde
+Bar","(.*X|^B)",[multiline,{parts,2}]))),
+?line <<"abcde
+:B:ar">> = iolist_to_binary(join(re:split("abcde
+Bar","(.*X|^B)",[multiline]))),
+?line <<":abcde
+1234X:yz">> = iolist_to_binary(join(re:split("abcde
+1234Xyz","(.*X|^B)",[dotall,trim]))),
+?line <<":abcde
+1234X:yz">> = iolist_to_binary(join(re:split("abcde
+1234Xyz","(.*X|^B)",[dotall,{parts,2}]))),
+?line <<":abcde
+1234X:yz">> = iolist_to_binary(join(re:split("abcde
+1234Xyz","(.*X|^B)",[dotall]))),
+?line <<":B:arFoo">> = iolist_to_binary(join(re:split("BarFoo","(.*X|^B)",[dotall,
+ trim]))),
+?line <<":B:arFoo">> = iolist_to_binary(join(re:split("BarFoo","(.*X|^B)",[dotall,
+ {parts,
+ 2}]))),
+?line <<":B:arFoo">> = iolist_to_binary(join(re:split("BarFoo","(.*X|^B)",[dotall]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(.*X|^B)",[dotall,
+ trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(.*X|^B)",[dotall,
+ {parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(.*X|^B)",[dotall]))),
+?line <<"abcde
+Bar">> = iolist_to_binary(join(re:split("abcde
+Bar","(.*X|^B)",[dotall,trim]))),
+?line <<"abcde
+Bar">> = iolist_to_binary(join(re:split("abcde
+Bar","(.*X|^B)",[dotall,{parts,2}]))),
+?line <<"abcde
+Bar">> = iolist_to_binary(join(re:split("abcde
+Bar","(.*X|^B)",[dotall]))),
+?line <<":abcde
+1234X:yz">> = iolist_to_binary(join(re:split("abcde
+1234Xyz","(.*X|^B)",[multiline,dotall,trim]))),
+?line <<":abcde
+1234X:yz">> = iolist_to_binary(join(re:split("abcde
+1234Xyz","(.*X|^B)",[multiline,dotall,{parts,2}]))),
+?line <<":abcde
+1234X:yz">> = iolist_to_binary(join(re:split("abcde
+1234Xyz","(.*X|^B)",[multiline,dotall]))),
+?line <<":B:arFoo">> = iolist_to_binary(join(re:split("BarFoo","(.*X|^B)",[multiline,
+ dotall,
+ trim]))),
+?line <<":B:arFoo">> = iolist_to_binary(join(re:split("BarFoo","(.*X|^B)",[multiline,
+ dotall,
+ {parts,
+ 2}]))),
+?line <<":B:arFoo">> = iolist_to_binary(join(re:split("BarFoo","(.*X|^B)",[multiline,
+ dotall]))),
+?line <<"abcde
+:B:ar">> = iolist_to_binary(join(re:split("abcde
+Bar","(.*X|^B)",[multiline,dotall,trim]))),
+?line <<"abcde
+:B:ar">> = iolist_to_binary(join(re:split("abcde
+Bar","(.*X|^B)",[multiline,dotall,{parts,2}]))),
+?line <<"abcde
+:B:ar">> = iolist_to_binary(join(re:split("abcde
+Bar","(.*X|^B)",[multiline,dotall]))),
+?line <<":abcde
+1234X:yz">> = iolist_to_binary(join(re:split("abcde
+1234Xyz","(?s)(.*X|^B)",[trim]))),
+?line <<":abcde
+1234X:yz">> = iolist_to_binary(join(re:split("abcde
+1234Xyz","(?s)(.*X|^B)",[{parts,2}]))),
+?line <<":abcde
+1234X:yz">> = iolist_to_binary(join(re:split("abcde
+1234Xyz","(?s)(.*X|^B)",[]))),
+?line <<":B:arFoo">> = iolist_to_binary(join(re:split("BarFoo","(?s)(.*X|^B)",[trim]))),
+?line <<":B:arFoo">> = iolist_to_binary(join(re:split("BarFoo","(?s)(.*X|^B)",[{parts,
+ 2}]))),
+?line <<":B:arFoo">> = iolist_to_binary(join(re:split("BarFoo","(?s)(.*X|^B)",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?s)(.*X|^B)",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?s)(.*X|^B)",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?s)(.*X|^B)",[]))),
+?line <<"abcde
+Bar">> = iolist_to_binary(join(re:split("abcde
+Bar","(?s)(.*X|^B)",[trim]))),
+?line <<"abcde
+Bar">> = iolist_to_binary(join(re:split("abcde
+Bar","(?s)(.*X|^B)",[{parts,2}]))),
+?line <<"abcde
+Bar">> = iolist_to_binary(join(re:split("abcde
+Bar","(?s)(.*X|^B)",[]))),
+?line <<":yz">> = iolist_to_binary(join(re:split("abcde
+1234Xyz","(?s:.*X|^B)",[trim]))),
+?line <<":yz">> = iolist_to_binary(join(re:split("abcde
+1234Xyz","(?s:.*X|^B)",[{parts,2}]))),
+?line <<":yz">> = iolist_to_binary(join(re:split("abcde
+1234Xyz","(?s:.*X|^B)",[]))),
+?line <<":arFoo">> = iolist_to_binary(join(re:split("BarFoo","(?s:.*X|^B)",[trim]))),
+?line <<":arFoo">> = iolist_to_binary(join(re:split("BarFoo","(?s:.*X|^B)",[{parts,
+ 2}]))),
+?line <<":arFoo">> = iolist_to_binary(join(re:split("BarFoo","(?s:.*X|^B)",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?s:.*X|^B)",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?s:.*X|^B)",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?s:.*X|^B)",[]))),
+?line <<"abcde
+Bar">> = iolist_to_binary(join(re:split("abcde
+Bar","(?s:.*X|^B)",[trim]))),
+?line <<"abcde
+Bar">> = iolist_to_binary(join(re:split("abcde
+Bar","(?s:.*X|^B)",[{parts,2}]))),
+?line <<"abcde
+Bar">> = iolist_to_binary(join(re:split("abcde
+Bar","(?s:.*X|^B)",[]))),
+?line <<"**** Failers">> = iolist_to_binary(join(re:split("**** Failers","^.*B",[trim]))),
+?line <<"**** Failers">> = iolist_to_binary(join(re:split("**** Failers","^.*B",[{parts,
+ 2}]))),
+?line <<"**** Failers">> = iolist_to_binary(join(re:split("**** Failers","^.*B",[]))),
+?line <<"abc
+B">> = iolist_to_binary(join(re:split("abc
+B","^.*B",[trim]))),
+?line <<"abc
+B">> = iolist_to_binary(join(re:split("abc
+B","^.*B",[{parts,2}]))),
+?line <<"abc
+B">> = iolist_to_binary(join(re:split("abc
+B","^.*B",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc
+B","(?s)^.*B",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc
+B","(?s)^.*B",[{parts,2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc
+B","(?s)^.*B",[]))),
+?line <<"abc
+">> = iolist_to_binary(join(re:split("abc
+B","(?m)^.*B",[trim]))),
+?line <<"abc
+:">> = iolist_to_binary(join(re:split("abc
+B","(?m)^.*B",[{parts,2}]))),
+?line <<"abc
+:">> = iolist_to_binary(join(re:split("abc
+B","(?m)^.*B",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc
+B","(?ms)^.*B",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc
+B","(?ms)^.*B",[{parts,2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc
+B","(?ms)^.*B",[]))),
+?line <<"abc
+">> = iolist_to_binary(join(re:split("abc
+B","(?ms)^B",[trim]))),
+?line <<"abc
+:">> = iolist_to_binary(join(re:split("abc
+B","(?ms)^B",[{parts,2}]))),
+?line <<"abc
+:">> = iolist_to_binary(join(re:split("abc
+B","(?ms)^B",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("B","(?s)B$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("B","(?s)B$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("B","(?s)B$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("123456654321","^[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("123456654321","^[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("123456654321","^[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("123456654321","^\\d\\d\\d\\d\\d\\d\\d\\d\\d\\d\\d\\d",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("123456654321","^\\d\\d\\d\\d\\d\\d\\d\\d\\d\\d\\d\\d",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("123456654321","^\\d\\d\\d\\d\\d\\d\\d\\d\\d\\d\\d\\d",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("123456654321","^[\\d][\\d][\\d][\\d][\\d][\\d][\\d][\\d][\\d][\\d][\\d][\\d]",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("123456654321","^[\\d][\\d][\\d][\\d][\\d][\\d][\\d][\\d][\\d][\\d][\\d][\\d]",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("123456654321","^[\\d][\\d][\\d][\\d][\\d][\\d][\\d][\\d][\\d][\\d][\\d][\\d]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abcabcabcabc","^[abc]{12}",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abcabcabcabc","^[abc]{12}",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abcabcabcabc","^[abc]{12}",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abcabcabcabc","^[a-c]{12}",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abcabcabcabc","^[a-c]{12}",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abcabcabcabc","^[a-c]{12}",[]))),
+?line <<":c">> = iolist_to_binary(join(re:split("abcabcabcabc","^(a|b|c){12}",[trim]))),
+?line <<":c:">> = iolist_to_binary(join(re:split("abcabcabcabc","^(a|b|c){12}",[{parts,
+ 2}]))),
+?line <<":c:">> = iolist_to_binary(join(re:split("abcabcabcabc","^(a|b|c){12}",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("n","^[abcdefghijklmnopqrstuvwxy0123456789]",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("n","^[abcdefghijklmnopqrstuvwxy0123456789]",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("n","^[abcdefghijklmnopqrstuvwxy0123456789]",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^[abcdefghijklmnopqrstuvwxy0123456789]",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^[abcdefghijklmnopqrstuvwxy0123456789]",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^[abcdefghijklmnopqrstuvwxy0123456789]",[]))),
+?line <<"z">> = iolist_to_binary(join(re:split("z","^[abcdefghijklmnopqrstuvwxy0123456789]",[trim]))),
+?line <<"z">> = iolist_to_binary(join(re:split("z","^[abcdefghijklmnopqrstuvwxy0123456789]",[{parts,
+ 2}]))),
+?line <<"z">> = iolist_to_binary(join(re:split("z","^[abcdefghijklmnopqrstuvwxy0123456789]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abcd","abcde{0,0}",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abcd","abcde{0,0}",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abcd","abcde{0,0}",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","abcde{0,0}",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","abcde{0,0}",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","abcde{0,0}",[]))),
+?line <<"abce">> = iolist_to_binary(join(re:split("abce","abcde{0,0}",[trim]))),
+?line <<"abce">> = iolist_to_binary(join(re:split("abce","abcde{0,0}",[{parts,
+ 2}]))),
+?line <<"abce">> = iolist_to_binary(join(re:split("abce","abcde{0,0}",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abe","ab[cd]{0,0}e",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abe","ab[cd]{0,0}e",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abe","ab[cd]{0,0}e",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","ab[cd]{0,0}e",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","ab[cd]{0,0}e",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","ab[cd]{0,0}e",[]))),
+?line <<"abcde">> = iolist_to_binary(join(re:split("abcde","ab[cd]{0,0}e",[trim]))),
+?line <<"abcde">> = iolist_to_binary(join(re:split("abcde","ab[cd]{0,0}e",[{parts,
+ 2}]))),
+?line <<"abcde">> = iolist_to_binary(join(re:split("abcde","ab[cd]{0,0}e",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abd","ab(c){0,0}d",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("abd","ab(c){0,0}d",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("abd","ab(c){0,0}d",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","ab(c){0,0}d",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","ab(c){0,0}d",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","ab(c){0,0}d",[]))),
+?line <<"abcd">> = iolist_to_binary(join(re:split("abcd","ab(c){0,0}d",[trim]))),
+?line <<"abcd">> = iolist_to_binary(join(re:split("abcd","ab(c){0,0}d",[{parts,
+ 2}]))),
+?line <<"abcd">> = iolist_to_binary(join(re:split("abcd","ab(c){0,0}d",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a","a(b*)",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("a","a(b*)",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("a","a(b*)",[]))),
+?line <<":b">> = iolist_to_binary(join(re:split("ab","a(b*)",[trim]))),
+?line <<":b:">> = iolist_to_binary(join(re:split("ab","a(b*)",[{parts,
+ 2}]))),
+?line <<":b:">> = iolist_to_binary(join(re:split("ab","a(b*)",[]))),
+?line <<":bbbb">> = iolist_to_binary(join(re:split("abbbb","a(b*)",[trim]))),
+?line <<":bbbb:">> = iolist_to_binary(join(re:split("abbbb","a(b*)",[{parts,
+ 2}]))),
+?line <<":bbbb:">> = iolist_to_binary(join(re:split("abbbb","a(b*)",[]))),
+?line <<"*** F::ilers">> = iolist_to_binary(join(re:split("*** Failers","a(b*)",[trim]))),
+?line <<"*** F::ilers">> = iolist_to_binary(join(re:split("*** Failers","a(b*)",[{parts,
+ 2}]))),
+?line <<"*** F::ilers">> = iolist_to_binary(join(re:split("*** Failers","a(b*)",[]))),
+?line <<"bbbbb">> = iolist_to_binary(join(re:split("bbbbb","a(b*)",[trim]))),
+?line <<"bbbbb">> = iolist_to_binary(join(re:split("bbbbb","a(b*)",[{parts,
+ 2}]))),
+?line <<"bbbbb">> = iolist_to_binary(join(re:split("bbbbb","a(b*)",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abe","ab\\d{0}e",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abe","ab\\d{0}e",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abe","ab\\d{0}e",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","ab\\d{0}e",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","ab\\d{0}e",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","ab\\d{0}e",[]))),
+?line <<"ab1e">> = iolist_to_binary(join(re:split("ab1e","ab\\d{0}e",[trim]))),
+?line <<"ab1e">> = iolist_to_binary(join(re:split("ab1e","ab\\d{0}e",[{parts,
+ 2}]))),
+?line <<"ab1e">> = iolist_to_binary(join(re:split("ab1e","ab\\d{0}e",[]))),
+?line <<"the :quick: brown fox">> = iolist_to_binary(join(re:split("the \"quick\" brown fox","\"([^\\\\\"]+|\\\\.)*\"",[trim]))),
+?line <<"the :quick: brown fox">> = iolist_to_binary(join(re:split("the \"quick\" brown fox","\"([^\\\\\"]+|\\\\.)*\"",[{parts,
+ 2}]))),
+?line <<"the :quick: brown fox">> = iolist_to_binary(join(re:split("the \"quick\" brown fox","\"([^\\\\\"]+|\\\\.)*\"",[]))),
+?line <<": brown fox">> = iolist_to_binary(join(re:split("\"the \\\"quick\\\" brown fox\"","\"([^\\\\\"]+|\\\\.)*\"",[trim]))),
+?line <<": brown fox:">> = iolist_to_binary(join(re:split("\"the \\\"quick\\\" brown fox\"","\"([^\\\\\"]+|\\\\.)*\"",[{parts,
+ 2}]))),
+?line <<": brown fox:">> = iolist_to_binary(join(re:split("\"the \\\"quick\\\" brown fox\"","\"([^\\\\\"]+|\\\\.)*\"",[]))),
+?line <<"a:b:c">> = iolist_to_binary(join(re:split("abc","",[trim]))),
+?line <<"a:bc">> = iolist_to_binary(join(re:split("abc","",[{parts,
+ 2}]))),
+?line <<"a:b:c:">> = iolist_to_binary(join(re:split("abc","",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("acb","a[^a]b",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("acb","a[^a]b",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("acb","a[^a]b",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a
+b","a[^a]b",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a
+b","a[^a]b",[{parts,2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a
+b","a[^a]b",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("acb","a.b",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("acb","a.b",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("acb","a.b",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a.b",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a.b",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a.b",[]))),
+?line <<"a
+b">> = iolist_to_binary(join(re:split("a
+b","a.b",[trim]))),
+?line <<"a
+b">> = iolist_to_binary(join(re:split("a
+b","a.b",[{parts,2}]))),
+?line <<"a
+b">> = iolist_to_binary(join(re:split("a
+b","a.b",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("acb","a[^a]b",[dotall,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("acb","a[^a]b",[dotall,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("acb","a[^a]b",[dotall]))),
+?line <<"">> = iolist_to_binary(join(re:split("a
+b","a[^a]b",[dotall,trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a
+b","a[^a]b",[dotall,{parts,2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a
+b","a[^a]b",[dotall]))),
+?line <<"">> = iolist_to_binary(join(re:split("acb","a.b",[dotall,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("acb","a.b",[dotall,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("acb","a.b",[dotall]))),
+?line <<"">> = iolist_to_binary(join(re:split("a
+b","a.b",[dotall,trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a
+b","a.b",[dotall,{parts,2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a
+b","a.b",[dotall]))),
+?line <<":a">> = iolist_to_binary(join(re:split("bac","^(b+?|a){1,2}?c",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("bac","^(b+?|a){1,2}?c",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("bac","^(b+?|a){1,2}?c",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("bbac","^(b+?|a){1,2}?c",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("bbac","^(b+?|a){1,2}?c",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("bbac","^(b+?|a){1,2}?c",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("bbbac","^(b+?|a){1,2}?c",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("bbbac","^(b+?|a){1,2}?c",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("bbbac","^(b+?|a){1,2}?c",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("bbbbac","^(b+?|a){1,2}?c",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("bbbbac","^(b+?|a){1,2}?c",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("bbbbac","^(b+?|a){1,2}?c",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("bbbbbac","^(b+?|a){1,2}?c",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("bbbbbac","^(b+?|a){1,2}?c",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("bbbbbac","^(b+?|a){1,2}?c",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("bac","^(b+|a){1,2}?c",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("bac","^(b+|a){1,2}?c",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("bac","^(b+|a){1,2}?c",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("bbac","^(b+|a){1,2}?c",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("bbac","^(b+|a){1,2}?c",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("bbac","^(b+|a){1,2}?c",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("bbbac","^(b+|a){1,2}?c",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("bbbac","^(b+|a){1,2}?c",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("bbbac","^(b+|a){1,2}?c",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("bbbbac","^(b+|a){1,2}?c",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("bbbbac","^(b+|a){1,2}?c",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("bbbbac","^(b+|a){1,2}?c",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("bbbbbac","^(b+|a){1,2}?c",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("bbbbbac","^(b+|a){1,2}?c",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("bbbbbac","^(b+|a){1,2}?c",[]))),
+?line <<"x
+b">> = iolist_to_binary(join(re:split("x
+b","(?!\\A)x",[multiline,trim]))),
+?line <<"x
+b">> = iolist_to_binary(join(re:split("x
+b","(?!\\A)x",[multiline,{parts,2}]))),
+?line <<"x
+b">> = iolist_to_binary(join(re:split("x
+b","(?!\\A)x",[multiline]))),
+?line <<"a">> = iolist_to_binary(join(re:split("ax","(?!\\A)x",[multiline,
+ trim]))),
+?line <<"a:">> = iolist_to_binary(join(re:split("ax","(?!\\A)x",[multiline,
+ {parts,
+ 2}]))),
+?line <<"a:">> = iolist_to_binary(join(re:split("ax","(?!\\A)x",[multiline]))),
+?line <<"{ab}">> = iolist_to_binary(join(re:split("{ab}","\\x0{ab}",[trim]))),
+?line <<"{ab}">> = iolist_to_binary(join(re:split("{ab}","\\x0{ab}",[{parts,
+ 2}]))),
+?line <<"{ab}">> = iolist_to_binary(join(re:split("{ab}","\\x0{ab}",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("CD","(A|B)*?CD",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("CD","(A|B)*?CD",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("CD","(A|B)*?CD",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("CD","(A|B)*CD",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("CD","(A|B)*CD",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("CD","(A|B)*CD",[]))),
+?line <<":AB:AB">> = iolist_to_binary(join(re:split("ABABAB","(AB)*?\\1",[trim]))),
+?line <<":AB:AB">> = iolist_to_binary(join(re:split("ABABAB","(AB)*?\\1",[{parts,
+ 2}]))),
+?line <<":AB:AB">> = iolist_to_binary(join(re:split("ABABAB","(AB)*?\\1",[]))),
+?line <<":AB">> = iolist_to_binary(join(re:split("ABABAB","(AB)*\\1",[trim]))),
+?line <<":AB:">> = iolist_to_binary(join(re:split("ABABAB","(AB)*\\1",[{parts,
+ 2}]))),
+?line <<":AB:">> = iolist_to_binary(join(re:split("ABABAB","(AB)*\\1",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("foo","(?<!bar)foo",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("foo","(?<!bar)foo",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("foo","(?<!bar)foo",[]))),
+?line <<"cat:d">> = iolist_to_binary(join(re:split("catfood","(?<!bar)foo",[trim]))),
+?line <<"cat:d">> = iolist_to_binary(join(re:split("catfood","(?<!bar)foo",[{parts,
+ 2}]))),
+?line <<"cat:d">> = iolist_to_binary(join(re:split("catfood","(?<!bar)foo",[]))),
+?line <<"ar:tle">> = iolist_to_binary(join(re:split("arfootle","(?<!bar)foo",[trim]))),
+?line <<"ar:tle">> = iolist_to_binary(join(re:split("arfootle","(?<!bar)foo",[{parts,
+ 2}]))),
+?line <<"ar:tle">> = iolist_to_binary(join(re:split("arfootle","(?<!bar)foo",[]))),
+?line <<"r:sh">> = iolist_to_binary(join(re:split("rfoosh","(?<!bar)foo",[trim]))),
+?line <<"r:sh">> = iolist_to_binary(join(re:split("rfoosh","(?<!bar)foo",[{parts,
+ 2}]))),
+?line <<"r:sh">> = iolist_to_binary(join(re:split("rfoosh","(?<!bar)foo",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?<!bar)foo",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?<!bar)foo",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?<!bar)foo",[]))),
+?line <<"barfoo">> = iolist_to_binary(join(re:split("barfoo","(?<!bar)foo",[trim]))),
+?line <<"barfoo">> = iolist_to_binary(join(re:split("barfoo","(?<!bar)foo",[{parts,
+ 2}]))),
+?line <<"barfoo">> = iolist_to_binary(join(re:split("barfoo","(?<!bar)foo",[]))),
+?line <<"towbarfoo">> = iolist_to_binary(join(re:split("towbarfoo","(?<!bar)foo",[trim]))),
+?line <<"towbarfoo">> = iolist_to_binary(join(re:split("towbarfoo","(?<!bar)foo",[{parts,
+ 2}]))),
+?line <<"towbarfoo">> = iolist_to_binary(join(re:split("towbarfoo","(?<!bar)foo",[]))),
+?line <<":d">> = iolist_to_binary(join(re:split("catfood","\\w{3}(?<!bar)foo",[trim]))),
+?line <<":d">> = iolist_to_binary(join(re:split("catfood","\\w{3}(?<!bar)foo",[{parts,
+ 2}]))),
+?line <<":d">> = iolist_to_binary(join(re:split("catfood","\\w{3}(?<!bar)foo",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","\\w{3}(?<!bar)foo",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","\\w{3}(?<!bar)foo",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","\\w{3}(?<!bar)foo",[]))),
+?line <<"foo">> = iolist_to_binary(join(re:split("foo","\\w{3}(?<!bar)foo",[trim]))),
+?line <<"foo">> = iolist_to_binary(join(re:split("foo","\\w{3}(?<!bar)foo",[{parts,
+ 2}]))),
+?line <<"foo">> = iolist_to_binary(join(re:split("foo","\\w{3}(?<!bar)foo",[]))),
+?line <<"barfoo">> = iolist_to_binary(join(re:split("barfoo","\\w{3}(?<!bar)foo",[trim]))),
+?line <<"barfoo">> = iolist_to_binary(join(re:split("barfoo","\\w{3}(?<!bar)foo",[{parts,
+ 2}]))),
+?line <<"barfoo">> = iolist_to_binary(join(re:split("barfoo","\\w{3}(?<!bar)foo",[]))),
+?line <<"towbarfoo">> = iolist_to_binary(join(re:split("towbarfoo","\\w{3}(?<!bar)foo",[trim]))),
+?line <<"towbarfoo">> = iolist_to_binary(join(re:split("towbarfoo","\\w{3}(?<!bar)foo",[{parts,
+ 2}]))),
+?line <<"towbarfoo">> = iolist_to_binary(join(re:split("towbarfoo","\\w{3}(?<!bar)foo",[]))),
+?line <<"fooa:foo">> = iolist_to_binary(join(re:split("fooabar","(?<=(foo)a)bar",[trim]))),
+?line <<"fooa:foo:">> = iolist_to_binary(join(re:split("fooabar","(?<=(foo)a)bar",[{parts,
+ 2}]))),
+?line <<"fooa:foo:">> = iolist_to_binary(join(re:split("fooabar","(?<=(foo)a)bar",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?<=(foo)a)bar",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?<=(foo)a)bar",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?<=(foo)a)bar",[]))),
+?line <<"bar">> = iolist_to_binary(join(re:split("bar","(?<=(foo)a)bar",[trim]))),
+?line <<"bar">> = iolist_to_binary(join(re:split("bar","(?<=(foo)a)bar",[{parts,
+ 2}]))),
+?line <<"bar">> = iolist_to_binary(join(re:split("bar","(?<=(foo)a)bar",[]))),
+?line <<"foobbar">> = iolist_to_binary(join(re:split("foobbar","(?<=(foo)a)bar",[trim]))),
+?line <<"foobbar">> = iolist_to_binary(join(re:split("foobbar","(?<=(foo)a)bar",[{parts,
+ 2}]))),
+?line <<"foobbar">> = iolist_to_binary(join(re:split("foobbar","(?<=(foo)a)bar",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc","\\Aabc\\z",[multiline,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","\\Aabc\\z",[multiline,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","\\Aabc\\z",[multiline]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","\\Aabc\\z",[multiline,
+ trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","\\Aabc\\z",[multiline,
+ {parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","\\Aabc\\z",[multiline]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc","\\Aabc\\z",[multiline,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","\\Aabc\\z",[multiline,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","\\Aabc\\z",[multiline]))),
+?line <<"qqq
+abc">> = iolist_to_binary(join(re:split("qqq
+abc","\\Aabc\\z",[multiline,trim]))),
+?line <<"qqq
+abc">> = iolist_to_binary(join(re:split("qqq
+abc","\\Aabc\\z",[multiline,{parts,2}]))),
+?line <<"qqq
+abc">> = iolist_to_binary(join(re:split("qqq
+abc","\\Aabc\\z",[multiline]))),
+?line <<"abc
+zzz">> = iolist_to_binary(join(re:split("abc
+zzz","\\Aabc\\z",[multiline,trim]))),
+?line <<"abc
+zzz">> = iolist_to_binary(join(re:split("abc
+zzz","\\Aabc\\z",[multiline,{parts,2}]))),
+?line <<"abc
+zzz">> = iolist_to_binary(join(re:split("abc
+zzz","\\Aabc\\z",[multiline]))),
+?line <<"qqq
+abc
+zzz">> = iolist_to_binary(join(re:split("qqq
+abc
+zzz","\\Aabc\\z",[multiline,trim]))),
+?line <<"qqq
+abc
+zzz">> = iolist_to_binary(join(re:split("qqq
+abc
+zzz","\\Aabc\\z",[multiline,{parts,2}]))),
+?line <<"qqq
+abc
+zzz">> = iolist_to_binary(join(re:split("qqq
+abc
+zzz","\\Aabc\\z",[multiline]))),
+?line <<"1:.23">> = iolist_to_binary(join(re:split("1.230003938","(?>(\\.\\d\\d[1-9]?))\\d+",[trim]))),
+?line <<"1:.23:">> = iolist_to_binary(join(re:split("1.230003938","(?>(\\.\\d\\d[1-9]?))\\d+",[{parts,
+ 2}]))),
+?line <<"1:.23:">> = iolist_to_binary(join(re:split("1.230003938","(?>(\\.\\d\\d[1-9]?))\\d+",[]))),
+?line <<"1:.875">> = iolist_to_binary(join(re:split("1.875000282","(?>(\\.\\d\\d[1-9]?))\\d+",[trim]))),
+?line <<"1:.875:">> = iolist_to_binary(join(re:split("1.875000282","(?>(\\.\\d\\d[1-9]?))\\d+",[{parts,
+ 2}]))),
+?line <<"1:.875:">> = iolist_to_binary(join(re:split("1.875000282","(?>(\\.\\d\\d[1-9]?))\\d+",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?>(\\.\\d\\d[1-9]?))\\d+",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?>(\\.\\d\\d[1-9]?))\\d+",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?>(\\.\\d\\d[1-9]?))\\d+",[]))),
+?line <<"1.235">> = iolist_to_binary(join(re:split("1.235","(?>(\\.\\d\\d[1-9]?))\\d+",[trim]))),
+?line <<"1.235">> = iolist_to_binary(join(re:split("1.235","(?>(\\.\\d\\d[1-9]?))\\d+",[{parts,
+ 2}]))),
+?line <<"1.235">> = iolist_to_binary(join(re:split("1.235","(?>(\\.\\d\\d[1-9]?))\\d+",[]))),
+?line <<":party">> = iolist_to_binary(join(re:split("now is the time for all good men to come to the aid of the party","^((?>\\w+)|(?>\\s+))*$",[trim]))),
+?line <<":party:">> = iolist_to_binary(join(re:split("now is the time for all good men to come to the aid of the party","^((?>\\w+)|(?>\\s+))*$",[{parts,
+ 2}]))),
+?line <<":party:">> = iolist_to_binary(join(re:split("now is the time for all good men to come to the aid of the party","^((?>\\w+)|(?>\\s+))*$",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^((?>\\w+)|(?>\\s+))*$",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^((?>\\w+)|(?>\\s+))*$",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^((?>\\w+)|(?>\\s+))*$",[]))),
+?line <<"this is not a line with only words and spaces!">> = iolist_to_binary(join(re:split("this is not a line with only words and spaces!","^((?>\\w+)|(?>\\s+))*$",[trim]))),
+?line <<"this is not a line with only words and spaces!">> = iolist_to_binary(join(re:split("this is not a line with only words and spaces!","^((?>\\w+)|(?>\\s+))*$",[{parts,
+ 2}]))),
+?line <<"this is not a line with only words and spaces!">> = iolist_to_binary(join(re:split("this is not a line with only words and spaces!","^((?>\\w+)|(?>\\s+))*$",[]))),
+?line <<":12345:a">> = iolist_to_binary(join(re:split("12345a","(\\d+)(\\w)",[trim]))),
+?line <<":12345:a:">> = iolist_to_binary(join(re:split("12345a","(\\d+)(\\w)",[{parts,
+ 2}]))),
+?line <<":12345:a:">> = iolist_to_binary(join(re:split("12345a","(\\d+)(\\w)",[]))),
+?line <<":1234:5:+">> = iolist_to_binary(join(re:split("12345+","(\\d+)(\\w)",[trim]))),
+?line <<":1234:5:+">> = iolist_to_binary(join(re:split("12345+","(\\d+)(\\w)",[{parts,
+ 2}]))),
+?line <<":1234:5:+">> = iolist_to_binary(join(re:split("12345+","(\\d+)(\\w)",[]))),
+?line <<":12345:a">> = iolist_to_binary(join(re:split("12345a","((?>\\d+))(\\w)",[trim]))),
+?line <<":12345:a:">> = iolist_to_binary(join(re:split("12345a","((?>\\d+))(\\w)",[{parts,
+ 2}]))),
+?line <<":12345:a:">> = iolist_to_binary(join(re:split("12345a","((?>\\d+))(\\w)",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","((?>\\d+))(\\w)",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","((?>\\d+))(\\w)",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","((?>\\d+))(\\w)",[]))),
+?line <<"12345+">> = iolist_to_binary(join(re:split("12345+","((?>\\d+))(\\w)",[trim]))),
+?line <<"12345+">> = iolist_to_binary(join(re:split("12345+","((?>\\d+))(\\w)",[{parts,
+ 2}]))),
+?line <<"12345+">> = iolist_to_binary(join(re:split("12345+","((?>\\d+))(\\w)",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaab","(?>a+)b",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaab","(?>a+)b",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaab","(?>a+)b",[]))),
+?line <<":aaab">> = iolist_to_binary(join(re:split("aaab","((?>a+)b)",[trim]))),
+?line <<":aaab:">> = iolist_to_binary(join(re:split("aaab","((?>a+)b)",[{parts,
+ 2}]))),
+?line <<":aaab:">> = iolist_to_binary(join(re:split("aaab","((?>a+)b)",[]))),
+?line <<":aaa">> = iolist_to_binary(join(re:split("aaab","(?>(a+))b",[trim]))),
+?line <<":aaa:">> = iolist_to_binary(join(re:split("aaab","(?>(a+))b",[{parts,
+ 2}]))),
+?line <<":aaa:">> = iolist_to_binary(join(re:split("aaab","(?>(a+))b",[]))),
+?line <<"aaa:ccc">> = iolist_to_binary(join(re:split("aaabbbccc","(?>b)+",[trim]))),
+?line <<"aaa:ccc">> = iolist_to_binary(join(re:split("aaabbbccc","(?>b)+",[{parts,
+ 2}]))),
+?line <<"aaa:ccc">> = iolist_to_binary(join(re:split("aaabbbccc","(?>b)+",[]))),
+?line <<"::::d">> = iolist_to_binary(join(re:split("aaabbbbccccd","(?>a+|b+|c+)*c",[trim]))),
+?line <<":cccd">> = iolist_to_binary(join(re:split("aaabbbbccccd","(?>a+|b+|c+)*c",[{parts,
+ 2}]))),
+?line <<"::::d">> = iolist_to_binary(join(re:split("aaabbbbccccd","(?>a+|b+|c+)*c",[]))),
+?line <<"((:x">> = iolist_to_binary(join(re:split("((abc(ade)ufh()()x","((?>[^()]+)|\\([^()]*\\))+",[trim]))),
+?line <<"((:x:">> = iolist_to_binary(join(re:split("((abc(ade)ufh()()x","((?>[^()]+)|\\([^()]*\\))+",[{parts,
+ 2}]))),
+?line <<"((:x:">> = iolist_to_binary(join(re:split("((abc(ade)ufh()()x","((?>[^()]+)|\\([^()]*\\))+",[]))),
+?line <<":abc">> = iolist_to_binary(join(re:split("(abc)","\\(((?>[^()]+)|\\([^()]+\\))+\\)",[trim]))),
+?line <<":abc:">> = iolist_to_binary(join(re:split("(abc)","\\(((?>[^()]+)|\\([^()]+\\))+\\)",[{parts,
+ 2}]))),
+?line <<":abc:">> = iolist_to_binary(join(re:split("(abc)","\\(((?>[^()]+)|\\([^()]+\\))+\\)",[]))),
+?line <<":xyz">> = iolist_to_binary(join(re:split("(abc(def)xyz)","\\(((?>[^()]+)|\\([^()]+\\))+\\)",[trim]))),
+?line <<":xyz:">> = iolist_to_binary(join(re:split("(abc(def)xyz)","\\(((?>[^()]+)|\\([^()]+\\))+\\)",[{parts,
+ 2}]))),
+?line <<":xyz:">> = iolist_to_binary(join(re:split("(abc(def)xyz)","\\(((?>[^()]+)|\\([^()]+\\))+\\)",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","\\(((?>[^()]+)|\\([^()]+\\))+\\)",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","\\(((?>[^()]+)|\\([^()]+\\))+\\)",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","\\(((?>[^()]+)|\\([^()]+\\))+\\)",[]))),
+?line <<"((()aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("((()aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","\\(((?>[^()]+)|\\([^()]+\\))+\\)",[trim]))),
+?line <<"((()aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("((()aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","\\(((?>[^()]+)|\\([^()]+\\))+\\)",[{parts,
+ 2}]))),
+?line <<"((()aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("((()aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","\\(((?>[^()]+)|\\([^()]+\\))+\\)",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("ab","a(?-i)b",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ab","a(?-i)b",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ab","a(?-i)b",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("Ab","a(?-i)b",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("Ab","a(?-i)b",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("Ab","a(?-i)b",[caseless]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a(?-i)b",[caseless,
+ trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a(?-i)b",[caseless,
+ {parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a(?-i)b",[caseless]))),
+?line <<"aB">> = iolist_to_binary(join(re:split("aB","a(?-i)b",[caseless,
+ trim]))),
+?line <<"aB">> = iolist_to_binary(join(re:split("aB","a(?-i)b",[caseless,
+ {parts,
+ 2}]))),
+?line <<"aB">> = iolist_to_binary(join(re:split("aB","a(?-i)b",[caseless]))),
+?line <<"AB">> = iolist_to_binary(join(re:split("AB","a(?-i)b",[caseless,
+ trim]))),
+?line <<"AB">> = iolist_to_binary(join(re:split("AB","a(?-i)b",[caseless,
+ {parts,
+ 2}]))),
+?line <<"AB">> = iolist_to_binary(join(re:split("AB","a(?-i)b",[caseless]))),
+?line <<":a bc">> = iolist_to_binary(join(re:split("a bcd e","(a (?x)b c)d e",[trim]))),
+?line <<":a bc:">> = iolist_to_binary(join(re:split("a bcd e","(a (?x)b c)d e",[{parts,
+ 2}]))),
+?line <<":a bc:">> = iolist_to_binary(join(re:split("a bcd e","(a (?x)b c)d e",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(a (?x)b c)d e",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(a (?x)b c)d e",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(a (?x)b c)d e",[]))),
+?line <<"a b cd e">> = iolist_to_binary(join(re:split("a b cd e","(a (?x)b c)d e",[trim]))),
+?line <<"a b cd e">> = iolist_to_binary(join(re:split("a b cd e","(a (?x)b c)d e",[{parts,
+ 2}]))),
+?line <<"a b cd e">> = iolist_to_binary(join(re:split("a b cd e","(a (?x)b c)d e",[]))),
+?line <<"abcd e">> = iolist_to_binary(join(re:split("abcd e","(a (?x)b c)d e",[trim]))),
+?line <<"abcd e">> = iolist_to_binary(join(re:split("abcd e","(a (?x)b c)d e",[{parts,
+ 2}]))),
+?line <<"abcd e">> = iolist_to_binary(join(re:split("abcd e","(a (?x)b c)d e",[]))),
+?line <<"a bcde">> = iolist_to_binary(join(re:split("a bcde","(a (?x)b c)d e",[trim]))),
+?line <<"a bcde">> = iolist_to_binary(join(re:split("a bcde","(a (?x)b c)d e",[{parts,
+ 2}]))),
+?line <<"a bcde">> = iolist_to_binary(join(re:split("a bcde","(a (?x)b c)d e",[]))),
+?line <<":a bcde f">> = iolist_to_binary(join(re:split("a bcde f","(a b(?x)c d (?-x)e f)",[trim]))),
+?line <<":a bcde f:">> = iolist_to_binary(join(re:split("a bcde f","(a b(?x)c d (?-x)e f)",[{parts,
+ 2}]))),
+?line <<":a bcde f:">> = iolist_to_binary(join(re:split("a bcde f","(a b(?x)c d (?-x)e f)",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(a b(?x)c d (?-x)e f)",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(a b(?x)c d (?-x)e f)",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(a b(?x)c d (?-x)e f)",[]))),
+?line <<"abcdef">> = iolist_to_binary(join(re:split("abcdef","(a b(?x)c d (?-x)e f)",[trim]))),
+?line <<"abcdef">> = iolist_to_binary(join(re:split("abcdef","(a b(?x)c d (?-x)e f)",[{parts,
+ 2}]))),
+?line <<"abcdef">> = iolist_to_binary(join(re:split("abcdef","(a b(?x)c d (?-x)e f)",[]))),
+?line <<":ab">> = iolist_to_binary(join(re:split("abc","(a(?i)b)c",[trim]))),
+?line <<":ab:">> = iolist_to_binary(join(re:split("abc","(a(?i)b)c",[{parts,
+ 2}]))),
+?line <<":ab:">> = iolist_to_binary(join(re:split("abc","(a(?i)b)c",[]))),
+?line <<":aB">> = iolist_to_binary(join(re:split("aBc","(a(?i)b)c",[trim]))),
+?line <<":aB:">> = iolist_to_binary(join(re:split("aBc","(a(?i)b)c",[{parts,
+ 2}]))),
+?line <<":aB:">> = iolist_to_binary(join(re:split("aBc","(a(?i)b)c",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(a(?i)b)c",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(a(?i)b)c",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(a(?i)b)c",[]))),
+?line <<"abC">> = iolist_to_binary(join(re:split("abC","(a(?i)b)c",[trim]))),
+?line <<"abC">> = iolist_to_binary(join(re:split("abC","(a(?i)b)c",[{parts,
+ 2}]))),
+?line <<"abC">> = iolist_to_binary(join(re:split("abC","(a(?i)b)c",[]))),
+?line <<"aBC">> = iolist_to_binary(join(re:split("aBC","(a(?i)b)c",[trim]))),
+?line <<"aBC">> = iolist_to_binary(join(re:split("aBC","(a(?i)b)c",[{parts,
+ 2}]))),
+?line <<"aBC">> = iolist_to_binary(join(re:split("aBC","(a(?i)b)c",[]))),
+?line <<"Abc">> = iolist_to_binary(join(re:split("Abc","(a(?i)b)c",[trim]))),
+?line <<"Abc">> = iolist_to_binary(join(re:split("Abc","(a(?i)b)c",[{parts,
+ 2}]))),
+?line <<"Abc">> = iolist_to_binary(join(re:split("Abc","(a(?i)b)c",[]))),
+?line <<"ABc">> = iolist_to_binary(join(re:split("ABc","(a(?i)b)c",[trim]))),
+?line <<"ABc">> = iolist_to_binary(join(re:split("ABc","(a(?i)b)c",[{parts,
+ 2}]))),
+?line <<"ABc">> = iolist_to_binary(join(re:split("ABc","(a(?i)b)c",[]))),
+?line <<"ABC">> = iolist_to_binary(join(re:split("ABC","(a(?i)b)c",[trim]))),
+?line <<"ABC">> = iolist_to_binary(join(re:split("ABC","(a(?i)b)c",[{parts,
+ 2}]))),
+?line <<"ABC">> = iolist_to_binary(join(re:split("ABC","(a(?i)b)c",[]))),
+?line <<"AbC">> = iolist_to_binary(join(re:split("AbC","(a(?i)b)c",[trim]))),
+?line <<"AbC">> = iolist_to_binary(join(re:split("AbC","(a(?i)b)c",[{parts,
+ 2}]))),
+?line <<"AbC">> = iolist_to_binary(join(re:split("AbC","(a(?i)b)c",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc","a(?i:b)c",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","a(?i:b)c",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","a(?i:b)c",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aBc","a(?i:b)c",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aBc","a(?i:b)c",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aBc","a(?i:b)c",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a(?i:b)c",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a(?i:b)c",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a(?i:b)c",[]))),
+?line <<"ABC">> = iolist_to_binary(join(re:split("ABC","a(?i:b)c",[trim]))),
+?line <<"ABC">> = iolist_to_binary(join(re:split("ABC","a(?i:b)c",[{parts,
+ 2}]))),
+?line <<"ABC">> = iolist_to_binary(join(re:split("ABC","a(?i:b)c",[]))),
+?line <<"abC">> = iolist_to_binary(join(re:split("abC","a(?i:b)c",[trim]))),
+?line <<"abC">> = iolist_to_binary(join(re:split("abC","a(?i:b)c",[{parts,
+ 2}]))),
+?line <<"abC">> = iolist_to_binary(join(re:split("abC","a(?i:b)c",[]))),
+?line <<"aBC">> = iolist_to_binary(join(re:split("aBC","a(?i:b)c",[trim]))),
+?line <<"aBC">> = iolist_to_binary(join(re:split("aBC","a(?i:b)c",[{parts,
+ 2}]))),
+?line <<"aBC">> = iolist_to_binary(join(re:split("aBC","a(?i:b)c",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aBc","a(?i:b)*c",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aBc","a(?i:b)*c",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aBc","a(?i:b)*c",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aBBc","a(?i:b)*c",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aBBc","a(?i:b)*c",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aBBc","a(?i:b)*c",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a(?i:b)*c",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a(?i:b)*c",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a(?i:b)*c",[]))),
+?line <<"aBC">> = iolist_to_binary(join(re:split("aBC","a(?i:b)*c",[trim]))),
+?line <<"aBC">> = iolist_to_binary(join(re:split("aBC","a(?i:b)*c",[{parts,
+ 2}]))),
+?line <<"aBC">> = iolist_to_binary(join(re:split("aBC","a(?i:b)*c",[]))),
+?line <<"aBBC">> = iolist_to_binary(join(re:split("aBBC","a(?i:b)*c",[trim]))),
+?line <<"aBBC">> = iolist_to_binary(join(re:split("aBBC","a(?i:b)*c",[{parts,
+ 2}]))),
+?line <<"aBBC">> = iolist_to_binary(join(re:split("aBBC","a(?i:b)*c",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abcd","a(?=b(?i)c)\\w\\wd",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abcd","a(?=b(?i)c)\\w\\wd",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abcd","a(?=b(?i)c)\\w\\wd",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abCd","a(?=b(?i)c)\\w\\wd",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abCd","a(?=b(?i)c)\\w\\wd",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abCd","a(?=b(?i)c)\\w\\wd",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a(?=b(?i)c)\\w\\wd",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a(?=b(?i)c)\\w\\wd",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a(?=b(?i)c)\\w\\wd",[]))),
+?line <<"aBCd">> = iolist_to_binary(join(re:split("aBCd","a(?=b(?i)c)\\w\\wd",[trim]))),
+?line <<"aBCd">> = iolist_to_binary(join(re:split("aBCd","a(?=b(?i)c)\\w\\wd",[{parts,
+ 2}]))),
+?line <<"aBCd">> = iolist_to_binary(join(re:split("aBCd","a(?=b(?i)c)\\w\\wd",[]))),
+?line <<"abcD">> = iolist_to_binary(join(re:split("abcD","a(?=b(?i)c)\\w\\wd",[trim]))),
+?line <<"abcD">> = iolist_to_binary(join(re:split("abcD","a(?=b(?i)c)\\w\\wd",[{parts,
+ 2}]))),
+?line <<"abcD">> = iolist_to_binary(join(re:split("abcD","a(?=b(?i)c)\\w\\wd",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("more than million","(?s-i:more.*than).*million",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("more than million","(?s-i:more.*than).*million",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("more than million","(?s-i:more.*than).*million",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("more than MILLION","(?s-i:more.*than).*million",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("more than MILLION","(?s-i:more.*than).*million",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("more than MILLION","(?s-i:more.*than).*million",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("more
+ than Million","(?s-i:more.*than).*million",[caseless,trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("more
+ than Million","(?s-i:more.*than).*million",[caseless,{parts,2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("more
+ than Million","(?s-i:more.*than).*million",[caseless]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?s-i:more.*than).*million",[caseless,
+ trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?s-i:more.*than).*million",[caseless,
+ {parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?s-i:more.*than).*million",[caseless]))),
+?line <<"MORE THAN MILLION">> = iolist_to_binary(join(re:split("MORE THAN MILLION","(?s-i:more.*than).*million",[caseless,
+ trim]))),
+?line <<"MORE THAN MILLION">> = iolist_to_binary(join(re:split("MORE THAN MILLION","(?s-i:more.*than).*million",[caseless,
+ {parts,
+ 2}]))),
+?line <<"MORE THAN MILLION">> = iolist_to_binary(join(re:split("MORE THAN MILLION","(?s-i:more.*than).*million",[caseless]))),
+?line <<"more
+ than
+ million">> = iolist_to_binary(join(re:split("more
+ than
+ million","(?s-i:more.*than).*million",[caseless,trim]))),
+?line <<"more
+ than
+ million">> = iolist_to_binary(join(re:split("more
+ than
+ million","(?s-i:more.*than).*million",[caseless,{parts,2}]))),
+?line <<"more
+ than
+ million">> = iolist_to_binary(join(re:split("more
+ than
+ million","(?s-i:more.*than).*million",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("more than million","(?:(?s-i)more.*than).*million",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("more than million","(?:(?s-i)more.*than).*million",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("more than million","(?:(?s-i)more.*than).*million",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("more than MILLION","(?:(?s-i)more.*than).*million",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("more than MILLION","(?:(?s-i)more.*than).*million",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("more than MILLION","(?:(?s-i)more.*than).*million",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("more
+ than Million","(?:(?s-i)more.*than).*million",[caseless,trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("more
+ than Million","(?:(?s-i)more.*than).*million",[caseless,{parts,2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("more
+ than Million","(?:(?s-i)more.*than).*million",[caseless]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?:(?s-i)more.*than).*million",[caseless,
+ trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?:(?s-i)more.*than).*million",[caseless,
+ {parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?:(?s-i)more.*than).*million",[caseless]))),
+?line <<"MORE THAN MILLION">> = iolist_to_binary(join(re:split("MORE THAN MILLION","(?:(?s-i)more.*than).*million",[caseless,
+ trim]))),
+?line <<"MORE THAN MILLION">> = iolist_to_binary(join(re:split("MORE THAN MILLION","(?:(?s-i)more.*than).*million",[caseless,
+ {parts,
+ 2}]))),
+?line <<"MORE THAN MILLION">> = iolist_to_binary(join(re:split("MORE THAN MILLION","(?:(?s-i)more.*than).*million",[caseless]))),
+?line <<"more
+ than
+ million">> = iolist_to_binary(join(re:split("more
+ than
+ million","(?:(?s-i)more.*than).*million",[caseless,trim]))),
+?line <<"more
+ than
+ million">> = iolist_to_binary(join(re:split("more
+ than
+ million","(?:(?s-i)more.*than).*million",[caseless,{parts,2}]))),
+?line <<"more
+ than
+ million">> = iolist_to_binary(join(re:split("more
+ than
+ million","(?:(?s-i)more.*than).*million",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc","(?>a(?i)b+)+c",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","(?>a(?i)b+)+c",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","(?>a(?i)b+)+c",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aBbc","(?>a(?i)b+)+c",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aBbc","(?>a(?i)b+)+c",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aBbc","(?>a(?i)b+)+c",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aBBc","(?>a(?i)b+)+c",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aBBc","(?>a(?i)b+)+c",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aBBc","(?>a(?i)b+)+c",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?>a(?i)b+)+c",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?>a(?i)b+)+c",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?>a(?i)b+)+c",[]))),
+?line <<"Abc">> = iolist_to_binary(join(re:split("Abc","(?>a(?i)b+)+c",[trim]))),
+?line <<"Abc">> = iolist_to_binary(join(re:split("Abc","(?>a(?i)b+)+c",[{parts,
+ 2}]))),
+?line <<"Abc">> = iolist_to_binary(join(re:split("Abc","(?>a(?i)b+)+c",[]))),
+?line <<"abAb">> = iolist_to_binary(join(re:split("abAb","(?>a(?i)b+)+c",[trim]))),
+?line <<"abAb">> = iolist_to_binary(join(re:split("abAb","(?>a(?i)b+)+c",[{parts,
+ 2}]))),
+?line <<"abAb">> = iolist_to_binary(join(re:split("abAb","(?>a(?i)b+)+c",[]))),
+?line <<"abbC">> = iolist_to_binary(join(re:split("abbC","(?>a(?i)b+)+c",[trim]))),
+?line <<"abbC">> = iolist_to_binary(join(re:split("abbC","(?>a(?i)b+)+c",[{parts,
+ 2}]))),
+?line <<"abbC">> = iolist_to_binary(join(re:split("abbC","(?>a(?i)b+)+c",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc","(?=a(?i)b)\\w\\wc",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","(?=a(?i)b)\\w\\wc",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","(?=a(?i)b)\\w\\wc",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aBc","(?=a(?i)b)\\w\\wc",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aBc","(?=a(?i)b)\\w\\wc",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aBc","(?=a(?i)b)\\w\\wc",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?=a(?i)b)\\w\\wc",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?=a(?i)b)\\w\\wc",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?=a(?i)b)\\w\\wc",[]))),
+?line <<"Ab">> = iolist_to_binary(join(re:split("Ab","(?=a(?i)b)\\w\\wc",[trim]))),
+?line <<"Ab">> = iolist_to_binary(join(re:split("Ab","(?=a(?i)b)\\w\\wc",[{parts,
+ 2}]))),
+?line <<"Ab">> = iolist_to_binary(join(re:split("Ab","(?=a(?i)b)\\w\\wc",[]))),
+?line <<"abC">> = iolist_to_binary(join(re:split("abC","(?=a(?i)b)\\w\\wc",[trim]))),
+?line <<"abC">> = iolist_to_binary(join(re:split("abC","(?=a(?i)b)\\w\\wc",[{parts,
+ 2}]))),
+?line <<"abC">> = iolist_to_binary(join(re:split("abC","(?=a(?i)b)\\w\\wc",[]))),
+?line <<"aBC">> = iolist_to_binary(join(re:split("aBC","(?=a(?i)b)\\w\\wc",[trim]))),
+?line <<"aBC">> = iolist_to_binary(join(re:split("aBC","(?=a(?i)b)\\w\\wc",[{parts,
+ 2}]))),
+?line <<"aBC">> = iolist_to_binary(join(re:split("aBC","(?=a(?i)b)\\w\\wc",[]))),
+?line <<"ab:xx">> = iolist_to_binary(join(re:split("abxxc","(?<=a(?i)b)(\\w\\w)c",[trim]))),
+?line <<"ab:xx:">> = iolist_to_binary(join(re:split("abxxc","(?<=a(?i)b)(\\w\\w)c",[{parts,
+ 2}]))),
+?line <<"ab:xx:">> = iolist_to_binary(join(re:split("abxxc","(?<=a(?i)b)(\\w\\w)c",[]))),
+?line <<"aB:xx">> = iolist_to_binary(join(re:split("aBxxc","(?<=a(?i)b)(\\w\\w)c",[trim]))),
+?line <<"aB:xx:">> = iolist_to_binary(join(re:split("aBxxc","(?<=a(?i)b)(\\w\\w)c",[{parts,
+ 2}]))),
+?line <<"aB:xx:">> = iolist_to_binary(join(re:split("aBxxc","(?<=a(?i)b)(\\w\\w)c",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?<=a(?i)b)(\\w\\w)c",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?<=a(?i)b)(\\w\\w)c",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?<=a(?i)b)(\\w\\w)c",[]))),
+?line <<"Abxxc">> = iolist_to_binary(join(re:split("Abxxc","(?<=a(?i)b)(\\w\\w)c",[trim]))),
+?line <<"Abxxc">> = iolist_to_binary(join(re:split("Abxxc","(?<=a(?i)b)(\\w\\w)c",[{parts,
+ 2}]))),
+?line <<"Abxxc">> = iolist_to_binary(join(re:split("Abxxc","(?<=a(?i)b)(\\w\\w)c",[]))),
+?line <<"ABxxc">> = iolist_to_binary(join(re:split("ABxxc","(?<=a(?i)b)(\\w\\w)c",[trim]))),
+?line <<"ABxxc">> = iolist_to_binary(join(re:split("ABxxc","(?<=a(?i)b)(\\w\\w)c",[{parts,
+ 2}]))),
+?line <<"ABxxc">> = iolist_to_binary(join(re:split("ABxxc","(?<=a(?i)b)(\\w\\w)c",[]))),
+?line <<"abxxC">> = iolist_to_binary(join(re:split("abxxC","(?<=a(?i)b)(\\w\\w)c",[trim]))),
+?line <<"abxxC">> = iolist_to_binary(join(re:split("abxxC","(?<=a(?i)b)(\\w\\w)c",[{parts,
+ 2}]))),
+?line <<"abxxC">> = iolist_to_binary(join(re:split("abxxC","(?<=a(?i)b)(\\w\\w)c",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("aA","(?:(a)|b)(?(1)A|B)",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aA","(?:(a)|b)(?(1)A|B)",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aA","(?:(a)|b)(?(1)A|B)",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("bB","(?:(a)|b)(?(1)A|B)",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("bB","(?:(a)|b)(?(1)A|B)",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("bB","(?:(a)|b)(?(1)A|B)",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?:(a)|b)(?(1)A|B)",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?:(a)|b)(?(1)A|B)",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?:(a)|b)(?(1)A|B)",[]))),
+?line <<"aB">> = iolist_to_binary(join(re:split("aB","(?:(a)|b)(?(1)A|B)",[trim]))),
+?line <<"aB">> = iolist_to_binary(join(re:split("aB","(?:(a)|b)(?(1)A|B)",[{parts,
+ 2}]))),
+?line <<"aB">> = iolist_to_binary(join(re:split("aB","(?:(a)|b)(?(1)A|B)",[]))),
+?line <<"bA">> = iolist_to_binary(join(re:split("bA","(?:(a)|b)(?(1)A|B)",[trim]))),
+?line <<"bA">> = iolist_to_binary(join(re:split("bA","(?:(a)|b)(?(1)A|B)",[{parts,
+ 2}]))),
+?line <<"bA">> = iolist_to_binary(join(re:split("bA","(?:(a)|b)(?(1)A|B)",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("aa","^(a)?(?(1)a|b)+$",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aa","^(a)?(?(1)a|b)+$",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aa","^(a)?(?(1)a|b)+$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("b","^(a)?(?(1)a|b)+$",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("b","^(a)?(?(1)a|b)+$",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("b","^(a)?(?(1)a|b)+$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("bb","^(a)?(?(1)a|b)+$",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("bb","^(a)?(?(1)a|b)+$",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("bb","^(a)?(?(1)a|b)+$",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(a)?(?(1)a|b)+$",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(a)?(?(1)a|b)+$",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(a)?(?(1)a|b)+$",[]))),
+?line <<"ab">> = iolist_to_binary(join(re:split("ab","^(a)?(?(1)a|b)+$",[trim]))),
+?line <<"ab">> = iolist_to_binary(join(re:split("ab","^(a)?(?(1)a|b)+$",[{parts,
+ 2}]))),
+?line <<"ab">> = iolist_to_binary(join(re:split("ab","^(a)?(?(1)a|b)+$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc:","^(?(?=abc)\\w{3}:|\\d\\d)$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc:","^(?(?=abc)\\w{3}:|\\d\\d)$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc:","^(?(?=abc)\\w{3}:|\\d\\d)$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("12","^(?(?=abc)\\w{3}:|\\d\\d)$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("12","^(?(?=abc)\\w{3}:|\\d\\d)$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("12","^(?(?=abc)\\w{3}:|\\d\\d)$",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(?(?=abc)\\w{3}:|\\d\\d)$",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(?(?=abc)\\w{3}:|\\d\\d)$",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(?(?=abc)\\w{3}:|\\d\\d)$",[]))),
+?line <<"123">> = iolist_to_binary(join(re:split("123","^(?(?=abc)\\w{3}:|\\d\\d)$",[trim]))),
+?line <<"123">> = iolist_to_binary(join(re:split("123","^(?(?=abc)\\w{3}:|\\d\\d)$",[{parts,
+ 2}]))),
+?line <<"123">> = iolist_to_binary(join(re:split("123","^(?(?=abc)\\w{3}:|\\d\\d)$",[]))),
+?line <<"xyz">> = iolist_to_binary(join(re:split("xyz","^(?(?=abc)\\w{3}:|\\d\\d)$",[trim]))),
+?line <<"xyz">> = iolist_to_binary(join(re:split("xyz","^(?(?=abc)\\w{3}:|\\d\\d)$",[{parts,
+ 2}]))),
+?line <<"xyz">> = iolist_to_binary(join(re:split("xyz","^(?(?=abc)\\w{3}:|\\d\\d)$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc:","^(?(?!abc)\\d\\d|\\w{3}:)$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc:","^(?(?!abc)\\d\\d|\\w{3}:)$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc:","^(?(?!abc)\\d\\d|\\w{3}:)$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("12","^(?(?!abc)\\d\\d|\\w{3}:)$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("12","^(?(?!abc)\\d\\d|\\w{3}:)$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("12","^(?(?!abc)\\d\\d|\\w{3}:)$",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(?(?!abc)\\d\\d|\\w{3}:)$",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(?(?!abc)\\d\\d|\\w{3}:)$",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(?(?!abc)\\d\\d|\\w{3}:)$",[]))),
+?line <<"123">> = iolist_to_binary(join(re:split("123","^(?(?!abc)\\d\\d|\\w{3}:)$",[trim]))),
+?line <<"123">> = iolist_to_binary(join(re:split("123","^(?(?!abc)\\d\\d|\\w{3}:)$",[{parts,
+ 2}]))),
+?line <<"123">> = iolist_to_binary(join(re:split("123","^(?(?!abc)\\d\\d|\\w{3}:)$",[]))),
+?line <<"xyz">> = iolist_to_binary(join(re:split("xyz","^(?(?!abc)\\d\\d|\\w{3}:)$",[trim]))),
+?line <<"xyz">> = iolist_to_binary(join(re:split("xyz","^(?(?!abc)\\d\\d|\\w{3}:)$",[{parts,
+ 2}]))),
+?line <<"xyz">> = iolist_to_binary(join(re:split("xyz","^(?(?!abc)\\d\\d|\\w{3}:)$",[]))),
+?line <<"foo">> = iolist_to_binary(join(re:split("foobar","(?(?<=foo)bar|cat)",[trim]))),
+?line <<"foo:">> = iolist_to_binary(join(re:split("foobar","(?(?<=foo)bar|cat)",[{parts,
+ 2}]))),
+?line <<"foo:">> = iolist_to_binary(join(re:split("foobar","(?(?<=foo)bar|cat)",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("cat","(?(?<=foo)bar|cat)",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("cat","(?(?<=foo)bar|cat)",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("cat","(?(?<=foo)bar|cat)",[]))),
+?line <<"f">> = iolist_to_binary(join(re:split("fcat","(?(?<=foo)bar|cat)",[trim]))),
+?line <<"f:">> = iolist_to_binary(join(re:split("fcat","(?(?<=foo)bar|cat)",[{parts,
+ 2}]))),
+?line <<"f:">> = iolist_to_binary(join(re:split("fcat","(?(?<=foo)bar|cat)",[]))),
+?line <<"fo">> = iolist_to_binary(join(re:split("focat","(?(?<=foo)bar|cat)",[trim]))),
+?line <<"fo:">> = iolist_to_binary(join(re:split("focat","(?(?<=foo)bar|cat)",[{parts,
+ 2}]))),
+?line <<"fo:">> = iolist_to_binary(join(re:split("focat","(?(?<=foo)bar|cat)",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?(?<=foo)bar|cat)",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?(?<=foo)bar|cat)",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?(?<=foo)bar|cat)",[]))),
+?line <<"foocat">> = iolist_to_binary(join(re:split("foocat","(?(?<=foo)bar|cat)",[trim]))),
+?line <<"foocat">> = iolist_to_binary(join(re:split("foocat","(?(?<=foo)bar|cat)",[{parts,
+ 2}]))),
+?line <<"foocat">> = iolist_to_binary(join(re:split("foocat","(?(?<=foo)bar|cat)",[]))),
+?line <<"foo">> = iolist_to_binary(join(re:split("foobar","(?(?<!foo)cat|bar)",[trim]))),
+?line <<"foo:">> = iolist_to_binary(join(re:split("foobar","(?(?<!foo)cat|bar)",[{parts,
+ 2}]))),
+?line <<"foo:">> = iolist_to_binary(join(re:split("foobar","(?(?<!foo)cat|bar)",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("cat","(?(?<!foo)cat|bar)",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("cat","(?(?<!foo)cat|bar)",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("cat","(?(?<!foo)cat|bar)",[]))),
+?line <<"f">> = iolist_to_binary(join(re:split("fcat","(?(?<!foo)cat|bar)",[trim]))),
+?line <<"f:">> = iolist_to_binary(join(re:split("fcat","(?(?<!foo)cat|bar)",[{parts,
+ 2}]))),
+?line <<"f:">> = iolist_to_binary(join(re:split("fcat","(?(?<!foo)cat|bar)",[]))),
+?line <<"fo">> = iolist_to_binary(join(re:split("focat","(?(?<!foo)cat|bar)",[trim]))),
+?line <<"fo:">> = iolist_to_binary(join(re:split("focat","(?(?<!foo)cat|bar)",[{parts,
+ 2}]))),
+?line <<"fo:">> = iolist_to_binary(join(re:split("focat","(?(?<!foo)cat|bar)",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?(?<!foo)cat|bar)",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?(?<!foo)cat|bar)",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?(?<!foo)cat|bar)",[]))),
+?line <<"foocat">> = iolist_to_binary(join(re:split("foocat","(?(?<!foo)cat|bar)",[trim]))),
+?line <<"foocat">> = iolist_to_binary(join(re:split("foocat","(?(?<!foo)cat|bar)",[{parts,
+ 2}]))),
+?line <<"foocat">> = iolist_to_binary(join(re:split("foocat","(?(?<!foo)cat|bar)",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abcd","( \\( )? [^()]+ (?(1) \\) |) ",[extended,
+ trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("abcd","( \\( )? [^()]+ (?(1) \\) |) ",[extended,
+ {parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("abcd","( \\( )? [^()]+ (?(1) \\) |) ",[extended]))),
+?line <<":(">> = iolist_to_binary(join(re:split("(abcd)","( \\( )? [^()]+ (?(1) \\) |) ",[extended,
+ trim]))),
+?line <<":(:">> = iolist_to_binary(join(re:split("(abcd)","( \\( )? [^()]+ (?(1) \\) |) ",[extended,
+ {parts,
+ 2}]))),
+?line <<":(:">> = iolist_to_binary(join(re:split("(abcd)","( \\( )? [^()]+ (?(1) \\) |) ",[extended]))),
+?line <<":::(">> = iolist_to_binary(join(re:split("the quick (abcd) fox","( \\( )? [^()]+ (?(1) \\) |) ",[extended,
+ trim]))),
+?line <<"::(abcd) fox">> = iolist_to_binary(join(re:split("the quick (abcd) fox","( \\( )? [^()]+ (?(1) \\) |) ",[extended,
+ {parts,
+ 2}]))),
+?line <<":::(:::">> = iolist_to_binary(join(re:split("the quick (abcd) fox","( \\( )? [^()]+ (?(1) \\) |) ",[extended]))),
+?line <<"(">> = iolist_to_binary(join(re:split("(abcd","( \\( )? [^()]+ (?(1) \\) |) ",[extended,
+ trim]))),
+?line <<"(::">> = iolist_to_binary(join(re:split("(abcd","( \\( )? [^()]+ (?(1) \\) |) ",[extended,
+ {parts,
+ 2}]))),
+?line <<"(::">> = iolist_to_binary(join(re:split("(abcd","( \\( )? [^()]+ (?(1) \\) |) ",[extended]))),
+?line <<"">> = iolist_to_binary(join(re:split("abcd","( \\( )? [^()]+ (?(1) \\) ) ",[extended,
+ trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("abcd","( \\( )? [^()]+ (?(1) \\) ) ",[extended,
+ {parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("abcd","( \\( )? [^()]+ (?(1) \\) ) ",[extended]))),
+?line <<":(">> = iolist_to_binary(join(re:split("(abcd)","( \\( )? [^()]+ (?(1) \\) ) ",[extended,
+ trim]))),
+?line <<":(:">> = iolist_to_binary(join(re:split("(abcd)","( \\( )? [^()]+ (?(1) \\) ) ",[extended,
+ {parts,
+ 2}]))),
+?line <<":(:">> = iolist_to_binary(join(re:split("(abcd)","( \\( )? [^()]+ (?(1) \\) ) ",[extended]))),
+?line <<":::(">> = iolist_to_binary(join(re:split("the quick (abcd) fox","( \\( )? [^()]+ (?(1) \\) ) ",[extended,
+ trim]))),
+?line <<"::(abcd) fox">> = iolist_to_binary(join(re:split("the quick (abcd) fox","( \\( )? [^()]+ (?(1) \\) ) ",[extended,
+ {parts,
+ 2}]))),
+?line <<":::(:::">> = iolist_to_binary(join(re:split("the quick (abcd) fox","( \\( )? [^()]+ (?(1) \\) ) ",[extended]))),
+?line <<"(">> = iolist_to_binary(join(re:split("(abcd","( \\( )? [^()]+ (?(1) \\) ) ",[extended,
+ trim]))),
+?line <<"(::">> = iolist_to_binary(join(re:split("(abcd","( \\( )? [^()]+ (?(1) \\) ) ",[extended,
+ {parts,
+ 2}]))),
+?line <<"(::">> = iolist_to_binary(join(re:split("(abcd","( \\( )? [^()]+ (?(1) \\) ) ",[extended]))),
+?line <<":1:2">> = iolist_to_binary(join(re:split("12","^(?(2)a|(1)(2))+$",[trim]))),
+?line <<":1:2:">> = iolist_to_binary(join(re:split("12","^(?(2)a|(1)(2))+$",[{parts,
+ 2}]))),
+?line <<":1:2:">> = iolist_to_binary(join(re:split("12","^(?(2)a|(1)(2))+$",[]))),
+?line <<":1:2">> = iolist_to_binary(join(re:split("12a","^(?(2)a|(1)(2))+$",[trim]))),
+?line <<":1:2:">> = iolist_to_binary(join(re:split("12a","^(?(2)a|(1)(2))+$",[{parts,
+ 2}]))),
+?line <<":1:2:">> = iolist_to_binary(join(re:split("12a","^(?(2)a|(1)(2))+$",[]))),
+?line <<":1:2">> = iolist_to_binary(join(re:split("12aa","^(?(2)a|(1)(2))+$",[trim]))),
+?line <<":1:2:">> = iolist_to_binary(join(re:split("12aa","^(?(2)a|(1)(2))+$",[{parts,
+ 2}]))),
+?line <<":1:2:">> = iolist_to_binary(join(re:split("12aa","^(?(2)a|(1)(2))+$",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(?(2)a|(1)(2))+$",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(?(2)a|(1)(2))+$",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(?(2)a|(1)(2))+$",[]))),
+?line <<"1234">> = iolist_to_binary(join(re:split("1234","^(?(2)a|(1)(2))+$",[trim]))),
+?line <<"1234">> = iolist_to_binary(join(re:split("1234","^(?(2)a|(1)(2))+$",[{parts,
+ 2}]))),
+?line <<"1234">> = iolist_to_binary(join(re:split("1234","^(?(2)a|(1)(2))+$",[]))),
+?line <<":blah">> = iolist_to_binary(join(re:split("blah blah","((?i)blah)\\s+\\1",[trim]))),
+?line <<":blah:">> = iolist_to_binary(join(re:split("blah blah","((?i)blah)\\s+\\1",[{parts,
+ 2}]))),
+?line <<":blah:">> = iolist_to_binary(join(re:split("blah blah","((?i)blah)\\s+\\1",[]))),
+?line <<":BLAH">> = iolist_to_binary(join(re:split("BLAH BLAH","((?i)blah)\\s+\\1",[trim]))),
+?line <<":BLAH:">> = iolist_to_binary(join(re:split("BLAH BLAH","((?i)blah)\\s+\\1",[{parts,
+ 2}]))),
+?line <<":BLAH:">> = iolist_to_binary(join(re:split("BLAH BLAH","((?i)blah)\\s+\\1",[]))),
+?line <<":Blah">> = iolist_to_binary(join(re:split("Blah Blah","((?i)blah)\\s+\\1",[trim]))),
+?line <<":Blah:">> = iolist_to_binary(join(re:split("Blah Blah","((?i)blah)\\s+\\1",[{parts,
+ 2}]))),
+?line <<":Blah:">> = iolist_to_binary(join(re:split("Blah Blah","((?i)blah)\\s+\\1",[]))),
+?line <<":blaH">> = iolist_to_binary(join(re:split("blaH blaH","((?i)blah)\\s+\\1",[trim]))),
+?line <<":blaH:">> = iolist_to_binary(join(re:split("blaH blaH","((?i)blah)\\s+\\1",[{parts,
+ 2}]))),
+?line <<":blaH:">> = iolist_to_binary(join(re:split("blaH blaH","((?i)blah)\\s+\\1",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","((?i)blah)\\s+\\1",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","((?i)blah)\\s+\\1",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","((?i)blah)\\s+\\1",[]))),
+?line <<"blah BLAH">> = iolist_to_binary(join(re:split("blah BLAH","((?i)blah)\\s+\\1",[trim]))),
+?line <<"blah BLAH">> = iolist_to_binary(join(re:split("blah BLAH","((?i)blah)\\s+\\1",[{parts,
+ 2}]))),
+?line <<"blah BLAH">> = iolist_to_binary(join(re:split("blah BLAH","((?i)blah)\\s+\\1",[]))),
+?line <<"Blah blah">> = iolist_to_binary(join(re:split("Blah blah","((?i)blah)\\s+\\1",[trim]))),
+?line <<"Blah blah">> = iolist_to_binary(join(re:split("Blah blah","((?i)blah)\\s+\\1",[{parts,
+ 2}]))),
+?line <<"Blah blah">> = iolist_to_binary(join(re:split("Blah blah","((?i)blah)\\s+\\1",[]))),
+?line <<"blaH blah">> = iolist_to_binary(join(re:split("blaH blah","((?i)blah)\\s+\\1",[trim]))),
+?line <<"blaH blah">> = iolist_to_binary(join(re:split("blaH blah","((?i)blah)\\s+\\1",[{parts,
+ 2}]))),
+?line <<"blaH blah">> = iolist_to_binary(join(re:split("blaH blah","((?i)blah)\\s+\\1",[]))),
+?line <<":blah">> = iolist_to_binary(join(re:split("blah blah","((?i)blah)\\s+(?i:\\1)",[trim]))),
+?line <<":blah:">> = iolist_to_binary(join(re:split("blah blah","((?i)blah)\\s+(?i:\\1)",[{parts,
+ 2}]))),
+?line <<":blah:">> = iolist_to_binary(join(re:split("blah blah","((?i)blah)\\s+(?i:\\1)",[]))),
+?line <<":BLAH">> = iolist_to_binary(join(re:split("BLAH BLAH","((?i)blah)\\s+(?i:\\1)",[trim]))),
+?line <<":BLAH:">> = iolist_to_binary(join(re:split("BLAH BLAH","((?i)blah)\\s+(?i:\\1)",[{parts,
+ 2}]))),
+?line <<":BLAH:">> = iolist_to_binary(join(re:split("BLAH BLAH","((?i)blah)\\s+(?i:\\1)",[]))),
+?line <<":Blah">> = iolist_to_binary(join(re:split("Blah Blah","((?i)blah)\\s+(?i:\\1)",[trim]))),
+?line <<":Blah:">> = iolist_to_binary(join(re:split("Blah Blah","((?i)blah)\\s+(?i:\\1)",[{parts,
+ 2}]))),
+?line <<":Blah:">> = iolist_to_binary(join(re:split("Blah Blah","((?i)blah)\\s+(?i:\\1)",[]))),
+?line <<":blaH">> = iolist_to_binary(join(re:split("blaH blaH","((?i)blah)\\s+(?i:\\1)",[trim]))),
+?line <<":blaH:">> = iolist_to_binary(join(re:split("blaH blaH","((?i)blah)\\s+(?i:\\1)",[{parts,
+ 2}]))),
+?line <<":blaH:">> = iolist_to_binary(join(re:split("blaH blaH","((?i)blah)\\s+(?i:\\1)",[]))),
+?line <<":blah">> = iolist_to_binary(join(re:split("blah BLAH","((?i)blah)\\s+(?i:\\1)",[trim]))),
+?line <<":blah:">> = iolist_to_binary(join(re:split("blah BLAH","((?i)blah)\\s+(?i:\\1)",[{parts,
+ 2}]))),
+?line <<":blah:">> = iolist_to_binary(join(re:split("blah BLAH","((?i)blah)\\s+(?i:\\1)",[]))),
+?line <<":Blah">> = iolist_to_binary(join(re:split("Blah blah","((?i)blah)\\s+(?i:\\1)",[trim]))),
+?line <<":Blah:">> = iolist_to_binary(join(re:split("Blah blah","((?i)blah)\\s+(?i:\\1)",[{parts,
+ 2}]))),
+?line <<":Blah:">> = iolist_to_binary(join(re:split("Blah blah","((?i)blah)\\s+(?i:\\1)",[]))),
+?line <<":blaH">> = iolist_to_binary(join(re:split("blaH blah","((?i)blah)\\s+(?i:\\1)",[trim]))),
+?line <<":blaH:">> = iolist_to_binary(join(re:split("blaH blah","((?i)blah)\\s+(?i:\\1)",[{parts,
+ 2}]))),
+?line <<":blaH:">> = iolist_to_binary(join(re:split("blaH blah","((?i)blah)\\s+(?i:\\1)",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a","(?>a*)*",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","(?>a*)*",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","(?>a*)*",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aa","(?>a*)*",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aa","(?>a*)*",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aa","(?>a*)*",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaaa","(?>a*)*",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaa","(?>a*)*",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaa","(?>a*)*",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc","(abc|)+",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("abc","(abc|)+",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("abc","(abc|)+",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abcabc","(abc|)+",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("abcabc","(abc|)+",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("abcabc","(abc|)+",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abcabcabc","(abc|)+",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("abcabcabc","(abc|)+",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("abcabcabc","(abc|)+",[]))),
+?line <<"x::y::z">> = iolist_to_binary(join(re:split("xyz","(abc|)+",[trim]))),
+?line <<"x::yz">> = iolist_to_binary(join(re:split("xyz","(abc|)+",[{parts,
+ 2}]))),
+?line <<"x::y::z::">> = iolist_to_binary(join(re:split("xyz","(abc|)+",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a","([a]*)*",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("a","([a]*)*",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("a","([a]*)*",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaaaa","([a]*)*",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("aaaaa","([a]*)*",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("aaaaa","([a]*)*",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a","([ab]*)*",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("a","([ab]*)*",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("a","([ab]*)*",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("b","([ab]*)*",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("b","([ab]*)*",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("b","([ab]*)*",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("ababab","([ab]*)*",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("ababab","([ab]*)*",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("ababab","([ab]*)*",[]))),
+?line <<"::c::d::e">> = iolist_to_binary(join(re:split("aaaabcde","([ab]*)*",[trim]))),
+?line <<"::cde">> = iolist_to_binary(join(re:split("aaaabcde","([ab]*)*",[{parts,
+ 2}]))),
+?line <<"::c::d::e::">> = iolist_to_binary(join(re:split("aaaabcde","([ab]*)*",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("bbbb","([ab]*)*",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("bbbb","([ab]*)*",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("bbbb","([ab]*)*",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("b","([^a]*)*",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("b","([^a]*)*",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("b","([^a]*)*",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("bbbb","([^a]*)*",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("bbbb","([^a]*)*",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("bbbb","([^a]*)*",[]))),
+?line <<"a::a::a">> = iolist_to_binary(join(re:split("aaa","([^a]*)*",[trim]))),
+?line <<"a::aa">> = iolist_to_binary(join(re:split("aaa","([^a]*)*",[{parts,
+ 2}]))),
+?line <<"a::a::a::">> = iolist_to_binary(join(re:split("aaa","([^a]*)*",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("cccc","([^ab]*)*",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("cccc","([^ab]*)*",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("cccc","([^ab]*)*",[]))),
+?line <<"a::b::a::b">> = iolist_to_binary(join(re:split("abab","([^ab]*)*",[trim]))),
+?line <<"a::bab">> = iolist_to_binary(join(re:split("abab","([^ab]*)*",[{parts,
+ 2}]))),
+?line <<"a::b::a::b::">> = iolist_to_binary(join(re:split("abab","([^ab]*)*",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a","([a]*?)*",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("a","([a]*?)*",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("a","([a]*?)*",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaaa","([a]*?)*",[trim]))),
+?line <<"::aaa">> = iolist_to_binary(join(re:split("aaaa","([a]*?)*",[{parts,
+ 2}]))),
+?line <<"::::::::">> = iolist_to_binary(join(re:split("aaaa","([a]*?)*",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a","([ab]*?)*",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("a","([ab]*?)*",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("a","([ab]*?)*",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("b","([ab]*?)*",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("b","([ab]*?)*",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("b","([ab]*?)*",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abab","([ab]*?)*",[trim]))),
+?line <<"::bab">> = iolist_to_binary(join(re:split("abab","([ab]*?)*",[{parts,
+ 2}]))),
+?line <<"::::::::">> = iolist_to_binary(join(re:split("abab","([ab]*?)*",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("baba","([ab]*?)*",[trim]))),
+?line <<"::aba">> = iolist_to_binary(join(re:split("baba","([ab]*?)*",[{parts,
+ 2}]))),
+?line <<"::::::::">> = iolist_to_binary(join(re:split("baba","([ab]*?)*",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("b","([^a]*?)*",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("b","([^a]*?)*",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("b","([^a]*?)*",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("bbbb","([^a]*?)*",[trim]))),
+?line <<"::bbb">> = iolist_to_binary(join(re:split("bbbb","([^a]*?)*",[{parts,
+ 2}]))),
+?line <<"::::::::">> = iolist_to_binary(join(re:split("bbbb","([^a]*?)*",[]))),
+?line <<"a::a::a">> = iolist_to_binary(join(re:split("aaa","([^a]*?)*",[trim]))),
+?line <<"a::aa">> = iolist_to_binary(join(re:split("aaa","([^a]*?)*",[{parts,
+ 2}]))),
+?line <<"a::a::a::">> = iolist_to_binary(join(re:split("aaa","([^a]*?)*",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("c","([^ab]*?)*",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("c","([^ab]*?)*",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("c","([^ab]*?)*",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("cccc","([^ab]*?)*",[trim]))),
+?line <<"::ccc">> = iolist_to_binary(join(re:split("cccc","([^ab]*?)*",[{parts,
+ 2}]))),
+?line <<"::::::::">> = iolist_to_binary(join(re:split("cccc","([^ab]*?)*",[]))),
+?line <<"b::a::b::a">> = iolist_to_binary(join(re:split("baba","([^ab]*?)*",[trim]))),
+?line <<"b::aba">> = iolist_to_binary(join(re:split("baba","([^ab]*?)*",[{parts,
+ 2}]))),
+?line <<"b::a::b::a::">> = iolist_to_binary(join(re:split("baba","([^ab]*?)*",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a","(?>a*)*",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","(?>a*)*",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","(?>a*)*",[]))),
+?line <<":b:c:d:e">> = iolist_to_binary(join(re:split("aaabcde","(?>a*)*",[trim]))),
+?line <<":bcde">> = iolist_to_binary(join(re:split("aaabcde","(?>a*)*",[{parts,
+ 2}]))),
+?line <<":b:c:d:e:">> = iolist_to_binary(join(re:split("aaabcde","(?>a*)*",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaaaa","((?>a*))*",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("aaaaa","((?>a*))*",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("aaaaa","((?>a*))*",[]))),
+?line <<"::b::b">> = iolist_to_binary(join(re:split("aabbaa","((?>a*))*",[trim]))),
+?line <<"::bbaa">> = iolist_to_binary(join(re:split("aabbaa","((?>a*))*",[{parts,
+ 2}]))),
+?line <<"::b::b::">> = iolist_to_binary(join(re:split("aabbaa","((?>a*))*",[]))),
+?line <<"a::a::a::a::a">> = iolist_to_binary(join(re:split("aaaaa","((?>a*?))*",[trim]))),
+?line <<"a::aaaa">> = iolist_to_binary(join(re:split("aaaaa","((?>a*?))*",[{parts,
+ 2}]))),
+?line <<"a::a::a::a::a::">> = iolist_to_binary(join(re:split("aaaaa","((?>a*?))*",[]))),
+?line <<"a::a::b::b::a::a">> = iolist_to_binary(join(re:split("aabbaa","((?>a*?))*",[trim]))),
+?line <<"a::abbaa">> = iolist_to_binary(join(re:split("aabbaa","((?>a*?))*",[{parts,
+ 2}]))),
+?line <<"a::a::b::b::a::a::">> = iolist_to_binary(join(re:split("aabbaa","((?>a*?))*",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("12-sep-98","(?(?=[^a-z]+[a-z]) \\d{2}-[a-z]{3}-\\d{2} | \\d{2}-\\d{2}-\\d{2} ) ",[extended,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("12-sep-98","(?(?=[^a-z]+[a-z]) \\d{2}-[a-z]{3}-\\d{2} | \\d{2}-\\d{2}-\\d{2} ) ",[extended,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("12-sep-98","(?(?=[^a-z]+[a-z]) \\d{2}-[a-z]{3}-\\d{2} | \\d{2}-\\d{2}-\\d{2} ) ",[extended]))),
+?line <<"">> = iolist_to_binary(join(re:split("12-09-98","(?(?=[^a-z]+[a-z]) \\d{2}-[a-z]{3}-\\d{2} | \\d{2}-\\d{2}-\\d{2} ) ",[extended,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("12-09-98","(?(?=[^a-z]+[a-z]) \\d{2}-[a-z]{3}-\\d{2} | \\d{2}-\\d{2}-\\d{2} ) ",[extended,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("12-09-98","(?(?=[^a-z]+[a-z]) \\d{2}-[a-z]{3}-\\d{2} | \\d{2}-\\d{2}-\\d{2} ) ",[extended]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?(?=[^a-z]+[a-z]) \\d{2}-[a-z]{3}-\\d{2} | \\d{2}-\\d{2}-\\d{2} ) ",[extended,
+ trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?(?=[^a-z]+[a-z]) \\d{2}-[a-z]{3}-\\d{2} | \\d{2}-\\d{2}-\\d{2} ) ",[extended,
+ {parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?(?=[^a-z]+[a-z]) \\d{2}-[a-z]{3}-\\d{2} | \\d{2}-\\d{2}-\\d{2} ) ",[extended]))),
+?line <<"sep-12-98">> = iolist_to_binary(join(re:split("sep-12-98","(?(?=[^a-z]+[a-z]) \\d{2}-[a-z]{3}-\\d{2} | \\d{2}-\\d{2}-\\d{2} ) ",[extended,
+ trim]))),
+?line <<"sep-12-98">> = iolist_to_binary(join(re:split("sep-12-98","(?(?=[^a-z]+[a-z]) \\d{2}-[a-z]{3}-\\d{2} | \\d{2}-\\d{2}-\\d{2} ) ",[extended,
+ {parts,
+ 2}]))),
+?line <<"sep-12-98">> = iolist_to_binary(join(re:split("sep-12-98","(?(?=[^a-z]+[a-z]) \\d{2}-[a-z]{3}-\\d{2} | \\d{2}-\\d{2}-\\d{2} ) ",[extended]))),
+?line <<"foo:foo">> = iolist_to_binary(join(re:split("foobarfoo","(?<=(foo))bar\\1",[trim]))),
+?line <<"foo:foo:">> = iolist_to_binary(join(re:split("foobarfoo","(?<=(foo))bar\\1",[{parts,
+ 2}]))),
+?line <<"foo:foo:">> = iolist_to_binary(join(re:split("foobarfoo","(?<=(foo))bar\\1",[]))),
+?line <<"foo:foo:tling">> = iolist_to_binary(join(re:split("foobarfootling","(?<=(foo))bar\\1",[trim]))),
+?line <<"foo:foo:tling">> = iolist_to_binary(join(re:split("foobarfootling","(?<=(foo))bar\\1",[{parts,
+ 2}]))),
+?line <<"foo:foo:tling">> = iolist_to_binary(join(re:split("foobarfootling","(?<=(foo))bar\\1",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?<=(foo))bar\\1",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?<=(foo))bar\\1",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?<=(foo))bar\\1",[]))),
+?line <<"foobar">> = iolist_to_binary(join(re:split("foobar","(?<=(foo))bar\\1",[trim]))),
+?line <<"foobar">> = iolist_to_binary(join(re:split("foobar","(?<=(foo))bar\\1",[{parts,
+ 2}]))),
+?line <<"foobar">> = iolist_to_binary(join(re:split("foobar","(?<=(foo))bar\\1",[]))),
+?line <<"barfoo">> = iolist_to_binary(join(re:split("barfoo","(?<=(foo))bar\\1",[trim]))),
+?line <<"barfoo">> = iolist_to_binary(join(re:split("barfoo","(?<=(foo))bar\\1",[{parts,
+ 2}]))),
+?line <<"barfoo">> = iolist_to_binary(join(re:split("barfoo","(?<=(foo))bar\\1",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("saturday","(?i:saturday|sunday)",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("saturday","(?i:saturday|sunday)",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("saturday","(?i:saturday|sunday)",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("sunday","(?i:saturday|sunday)",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("sunday","(?i:saturday|sunday)",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("sunday","(?i:saturday|sunday)",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("Saturday","(?i:saturday|sunday)",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("Saturday","(?i:saturday|sunday)",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("Saturday","(?i:saturday|sunday)",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("Sunday","(?i:saturday|sunday)",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("Sunday","(?i:saturday|sunday)",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("Sunday","(?i:saturday|sunday)",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("SATURDAY","(?i:saturday|sunday)",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("SATURDAY","(?i:saturday|sunday)",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("SATURDAY","(?i:saturday|sunday)",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("SUNDAY","(?i:saturday|sunday)",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("SUNDAY","(?i:saturday|sunday)",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("SUNDAY","(?i:saturday|sunday)",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("SunDay","(?i:saturday|sunday)",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("SunDay","(?i:saturday|sunday)",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("SunDay","(?i:saturday|sunday)",[]))),
+?line <<":abc">> = iolist_to_binary(join(re:split("abcx","(a(?i)bc|BB)x",[trim]))),
+?line <<":abc:">> = iolist_to_binary(join(re:split("abcx","(a(?i)bc|BB)x",[{parts,
+ 2}]))),
+?line <<":abc:">> = iolist_to_binary(join(re:split("abcx","(a(?i)bc|BB)x",[]))),
+?line <<":aBC">> = iolist_to_binary(join(re:split("aBCx","(a(?i)bc|BB)x",[trim]))),
+?line <<":aBC:">> = iolist_to_binary(join(re:split("aBCx","(a(?i)bc|BB)x",[{parts,
+ 2}]))),
+?line <<":aBC:">> = iolist_to_binary(join(re:split("aBCx","(a(?i)bc|BB)x",[]))),
+?line <<":bb">> = iolist_to_binary(join(re:split("bbx","(a(?i)bc|BB)x",[trim]))),
+?line <<":bb:">> = iolist_to_binary(join(re:split("bbx","(a(?i)bc|BB)x",[{parts,
+ 2}]))),
+?line <<":bb:">> = iolist_to_binary(join(re:split("bbx","(a(?i)bc|BB)x",[]))),
+?line <<":BB">> = iolist_to_binary(join(re:split("BBx","(a(?i)bc|BB)x",[trim]))),
+?line <<":BB:">> = iolist_to_binary(join(re:split("BBx","(a(?i)bc|BB)x",[{parts,
+ 2}]))),
+?line <<":BB:">> = iolist_to_binary(join(re:split("BBx","(a(?i)bc|BB)x",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(a(?i)bc|BB)x",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(a(?i)bc|BB)x",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(a(?i)bc|BB)x",[]))),
+?line <<"abcX">> = iolist_to_binary(join(re:split("abcX","(a(?i)bc|BB)x",[trim]))),
+?line <<"abcX">> = iolist_to_binary(join(re:split("abcX","(a(?i)bc|BB)x",[{parts,
+ 2}]))),
+?line <<"abcX">> = iolist_to_binary(join(re:split("abcX","(a(?i)bc|BB)x",[]))),
+?line <<"aBCX">> = iolist_to_binary(join(re:split("aBCX","(a(?i)bc|BB)x",[trim]))),
+?line <<"aBCX">> = iolist_to_binary(join(re:split("aBCX","(a(?i)bc|BB)x",[{parts,
+ 2}]))),
+?line <<"aBCX">> = iolist_to_binary(join(re:split("aBCX","(a(?i)bc|BB)x",[]))),
+?line <<"bbX">> = iolist_to_binary(join(re:split("bbX","(a(?i)bc|BB)x",[trim]))),
+?line <<"bbX">> = iolist_to_binary(join(re:split("bbX","(a(?i)bc|BB)x",[{parts,
+ 2}]))),
+?line <<"bbX">> = iolist_to_binary(join(re:split("bbX","(a(?i)bc|BB)x",[]))),
+?line <<"BBX">> = iolist_to_binary(join(re:split("BBX","(a(?i)bc|BB)x",[trim]))),
+?line <<"BBX">> = iolist_to_binary(join(re:split("BBX","(a(?i)bc|BB)x",[{parts,
+ 2}]))),
+?line <<"BBX">> = iolist_to_binary(join(re:split("BBX","(a(?i)bc|BB)x",[]))),
+?line <<":ac">> = iolist_to_binary(join(re:split("ac","^([ab](?i)[cd]|[ef])",[trim]))),
+?line <<":ac:">> = iolist_to_binary(join(re:split("ac","^([ab](?i)[cd]|[ef])",[{parts,
+ 2}]))),
+?line <<":ac:">> = iolist_to_binary(join(re:split("ac","^([ab](?i)[cd]|[ef])",[]))),
+?line <<":aC">> = iolist_to_binary(join(re:split("aC","^([ab](?i)[cd]|[ef])",[trim]))),
+?line <<":aC:">> = iolist_to_binary(join(re:split("aC","^([ab](?i)[cd]|[ef])",[{parts,
+ 2}]))),
+?line <<":aC:">> = iolist_to_binary(join(re:split("aC","^([ab](?i)[cd]|[ef])",[]))),
+?line <<":bD">> = iolist_to_binary(join(re:split("bD","^([ab](?i)[cd]|[ef])",[trim]))),
+?line <<":bD:">> = iolist_to_binary(join(re:split("bD","^([ab](?i)[cd]|[ef])",[{parts,
+ 2}]))),
+?line <<":bD:">> = iolist_to_binary(join(re:split("bD","^([ab](?i)[cd]|[ef])",[]))),
+?line <<":e:lephant">> = iolist_to_binary(join(re:split("elephant","^([ab](?i)[cd]|[ef])",[trim]))),
+?line <<":e:lephant">> = iolist_to_binary(join(re:split("elephant","^([ab](?i)[cd]|[ef])",[{parts,
+ 2}]))),
+?line <<":e:lephant">> = iolist_to_binary(join(re:split("elephant","^([ab](?i)[cd]|[ef])",[]))),
+?line <<":E:urope">> = iolist_to_binary(join(re:split("Europe","^([ab](?i)[cd]|[ef])",[trim]))),
+?line <<":E:urope">> = iolist_to_binary(join(re:split("Europe","^([ab](?i)[cd]|[ef])",[{parts,
+ 2}]))),
+?line <<":E:urope">> = iolist_to_binary(join(re:split("Europe","^([ab](?i)[cd]|[ef])",[]))),
+?line <<":f:rog">> = iolist_to_binary(join(re:split("frog","^([ab](?i)[cd]|[ef])",[trim]))),
+?line <<":f:rog">> = iolist_to_binary(join(re:split("frog","^([ab](?i)[cd]|[ef])",[{parts,
+ 2}]))),
+?line <<":f:rog">> = iolist_to_binary(join(re:split("frog","^([ab](?i)[cd]|[ef])",[]))),
+?line <<":F:rance">> = iolist_to_binary(join(re:split("France","^([ab](?i)[cd]|[ef])",[trim]))),
+?line <<":F:rance">> = iolist_to_binary(join(re:split("France","^([ab](?i)[cd]|[ef])",[{parts,
+ 2}]))),
+?line <<":F:rance">> = iolist_to_binary(join(re:split("France","^([ab](?i)[cd]|[ef])",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^([ab](?i)[cd]|[ef])",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^([ab](?i)[cd]|[ef])",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^([ab](?i)[cd]|[ef])",[]))),
+?line <<"Africa">> = iolist_to_binary(join(re:split("Africa","^([ab](?i)[cd]|[ef])",[trim]))),
+?line <<"Africa">> = iolist_to_binary(join(re:split("Africa","^([ab](?i)[cd]|[ef])",[{parts,
+ 2}]))),
+?line <<"Africa">> = iolist_to_binary(join(re:split("Africa","^([ab](?i)[cd]|[ef])",[]))),
+?line <<":ab">> = iolist_to_binary(join(re:split("ab","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)",[trim]))),
+?line <<":ab:">> = iolist_to_binary(join(re:split("ab","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)",[{parts,
+ 2}]))),
+?line <<":ab:">> = iolist_to_binary(join(re:split("ab","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)",[]))),
+?line <<":aBd">> = iolist_to_binary(join(re:split("aBd","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)",[trim]))),
+?line <<":aBd:">> = iolist_to_binary(join(re:split("aBd","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)",[{parts,
+ 2}]))),
+?line <<":aBd:">> = iolist_to_binary(join(re:split("aBd","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)",[]))),
+?line <<":xy">> = iolist_to_binary(join(re:split("xy","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)",[trim]))),
+?line <<":xy:">> = iolist_to_binary(join(re:split("xy","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)",[{parts,
+ 2}]))),
+?line <<":xy:">> = iolist_to_binary(join(re:split("xy","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)",[]))),
+?line <<":xY">> = iolist_to_binary(join(re:split("xY","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)",[trim]))),
+?line <<":xY:">> = iolist_to_binary(join(re:split("xY","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)",[{parts,
+ 2}]))),
+?line <<":xY:">> = iolist_to_binary(join(re:split("xY","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)",[]))),
+?line <<":z:ebra">> = iolist_to_binary(join(re:split("zebra","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)",[trim]))),
+?line <<":z:ebra">> = iolist_to_binary(join(re:split("zebra","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)",[{parts,
+ 2}]))),
+?line <<":z:ebra">> = iolist_to_binary(join(re:split("zebra","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)",[]))),
+?line <<":Z:ambesi">> = iolist_to_binary(join(re:split("Zambesi","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)",[trim]))),
+?line <<":Z:ambesi">> = iolist_to_binary(join(re:split("Zambesi","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)",[{parts,
+ 2}]))),
+?line <<":Z:ambesi">> = iolist_to_binary(join(re:split("Zambesi","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)",[]))),
+?line <<"aCD">> = iolist_to_binary(join(re:split("aCD","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)",[trim]))),
+?line <<"aCD">> = iolist_to_binary(join(re:split("aCD","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)",[{parts,
+ 2}]))),
+?line <<"aCD">> = iolist_to_binary(join(re:split("aCD","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)",[]))),
+?line <<"XY">> = iolist_to_binary(join(re:split("XY","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)",[trim]))),
+?line <<"XY">> = iolist_to_binary(join(re:split("XY","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)",[{parts,
+ 2}]))),
+?line <<"XY">> = iolist_to_binary(join(re:split("XY","^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)",[]))),
+?line <<"foo
+">> = iolist_to_binary(join(re:split("foo
+bar","(?<=foo\\n)^bar",[multiline,trim]))),
+?line <<"foo
+:">> = iolist_to_binary(join(re:split("foo
+bar","(?<=foo\\n)^bar",[multiline,{parts,2}]))),
+?line <<"foo
+:">> = iolist_to_binary(join(re:split("foo
+bar","(?<=foo\\n)^bar",[multiline]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?<=foo\\n)^bar",[multiline,
+ trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?<=foo\\n)^bar",[multiline,
+ {parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?<=foo\\n)^bar",[multiline]))),
+?line <<"bar">> = iolist_to_binary(join(re:split("bar","(?<=foo\\n)^bar",[multiline,
+ trim]))),
+?line <<"bar">> = iolist_to_binary(join(re:split("bar","(?<=foo\\n)^bar",[multiline,
+ {parts,
+ 2}]))),
+?line <<"bar">> = iolist_to_binary(join(re:split("bar","(?<=foo\\n)^bar",[multiline]))),
+?line <<"baz
+bar">> = iolist_to_binary(join(re:split("baz
+bar","(?<=foo\\n)^bar",[multiline,trim]))),
+?line <<"baz
+bar">> = iolist_to_binary(join(re:split("baz
+bar","(?<=foo\\n)^bar",[multiline,{parts,2}]))),
+?line <<"baz
+bar">> = iolist_to_binary(join(re:split("baz
+bar","(?<=foo\\n)^bar",[multiline]))),
+?line <<"bar">> = iolist_to_binary(join(re:split("barbaz","(?<=(?<!foo)bar)baz",[trim]))),
+?line <<"bar:">> = iolist_to_binary(join(re:split("barbaz","(?<=(?<!foo)bar)baz",[{parts,
+ 2}]))),
+?line <<"bar:">> = iolist_to_binary(join(re:split("barbaz","(?<=(?<!foo)bar)baz",[]))),
+?line <<"barbar">> = iolist_to_binary(join(re:split("barbarbaz","(?<=(?<!foo)bar)baz",[trim]))),
+?line <<"barbar:">> = iolist_to_binary(join(re:split("barbarbaz","(?<=(?<!foo)bar)baz",[{parts,
+ 2}]))),
+?line <<"barbar:">> = iolist_to_binary(join(re:split("barbarbaz","(?<=(?<!foo)bar)baz",[]))),
+?line <<"koobar">> = iolist_to_binary(join(re:split("koobarbaz","(?<=(?<!foo)bar)baz",[trim]))),
+?line <<"koobar:">> = iolist_to_binary(join(re:split("koobarbaz","(?<=(?<!foo)bar)baz",[{parts,
+ 2}]))),
+?line <<"koobar:">> = iolist_to_binary(join(re:split("koobarbaz","(?<=(?<!foo)bar)baz",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?<=(?<!foo)bar)baz",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?<=(?<!foo)bar)baz",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?<=(?<!foo)bar)baz",[]))),
+?line <<"baz">> = iolist_to_binary(join(re:split("baz","(?<=(?<!foo)bar)baz",[trim]))),
+?line <<"baz">> = iolist_to_binary(join(re:split("baz","(?<=(?<!foo)bar)baz",[{parts,
+ 2}]))),
+?line <<"baz">> = iolist_to_binary(join(re:split("baz","(?<=(?<!foo)bar)baz",[]))),
+?line <<"foobarbaz">> = iolist_to_binary(join(re:split("foobarbaz","(?<=(?<!foo)bar)baz",[trim]))),
+?line <<"foobarbaz">> = iolist_to_binary(join(re:split("foobarbaz","(?<=(?<!foo)bar)baz",[{parts,
+ 2}]))),
+?line <<"foobarbaz">> = iolist_to_binary(join(re:split("foobarbaz","(?<=(?<!foo)bar)baz",[]))),
+?line <<"a">> = iolist_to_binary(join(re:split("a","^(a\\1?){4}$",[trim]))),
+?line <<"a">> = iolist_to_binary(join(re:split("a","^(a\\1?){4}$",[{parts,
+ 2}]))),
+?line <<"a">> = iolist_to_binary(join(re:split("a","^(a\\1?){4}$",[]))),
+?line <<"aa">> = iolist_to_binary(join(re:split("aa","^(a\\1?){4}$",[trim]))),
+?line <<"aa">> = iolist_to_binary(join(re:split("aa","^(a\\1?){4}$",[{parts,
+ 2}]))),
+?line <<"aa">> = iolist_to_binary(join(re:split("aa","^(a\\1?){4}$",[]))),
+?line <<"aaa">> = iolist_to_binary(join(re:split("aaa","^(a\\1?){4}$",[trim]))),
+?line <<"aaa">> = iolist_to_binary(join(re:split("aaa","^(a\\1?){4}$",[{parts,
+ 2}]))),
+?line <<"aaa">> = iolist_to_binary(join(re:split("aaa","^(a\\1?){4}$",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("aaaa","^(a\\1?){4}$",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aaaa","^(a\\1?){4}$",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aaaa","^(a\\1?){4}$",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("aaaaa","^(a\\1?){4}$",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aaaaa","^(a\\1?){4}$",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aaaaa","^(a\\1?){4}$",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("aaaaaaa","^(a\\1?){4}$",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aaaaaaa","^(a\\1?){4}$",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aaaaaaa","^(a\\1?){4}$",[]))),
+?line <<"aaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaa","^(a\\1?){4}$",[trim]))),
+?line <<"aaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaa","^(a\\1?){4}$",[{parts,
+ 2}]))),
+?line <<"aaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaa","^(a\\1?){4}$",[]))),
+?line <<"aaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaa","^(a\\1?){4}$",[trim]))),
+?line <<"aaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaa","^(a\\1?){4}$",[{parts,
+ 2}]))),
+?line <<"aaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaa","^(a\\1?){4}$",[]))),
+?line <<":aaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaa","^(a\\1?){4}$",[trim]))),
+?line <<":aaaa:">> = iolist_to_binary(join(re:split("aaaaaaaaaa","^(a\\1?){4}$",[{parts,
+ 2}]))),
+?line <<":aaaa:">> = iolist_to_binary(join(re:split("aaaaaaaaaa","^(a\\1?){4}$",[]))),
+?line <<"aaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaa","^(a\\1?){4}$",[trim]))),
+?line <<"aaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaa","^(a\\1?){4}$",[{parts,
+ 2}]))),
+?line <<"aaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaa","^(a\\1?){4}$",[]))),
+?line <<"aaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaa","^(a\\1?){4}$",[trim]))),
+?line <<"aaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaa","^(a\\1?){4}$",[{parts,
+ 2}]))),
+?line <<"aaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaa","^(a\\1?){4}$",[]))),
+?line <<"aaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaa","^(a\\1?){4}$",[trim]))),
+?line <<"aaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaa","^(a\\1?){4}$",[{parts,
+ 2}]))),
+?line <<"aaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaa","^(a\\1?){4}$",[]))),
+?line <<"aaaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaa","^(a\\1?){4}$",[trim]))),
+?line <<"aaaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaa","^(a\\1?){4}$",[{parts,
+ 2}]))),
+?line <<"aaaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaa","^(a\\1?){4}$",[]))),
+?line <<"aaaaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaaa","^(a\\1?){4}$",[trim]))),
+?line <<"aaaaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaaa","^(a\\1?){4}$",[{parts,
+ 2}]))),
+?line <<"aaaaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaaa","^(a\\1?){4}$",[]))),
+?line <<"aaaaaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaaaa","^(a\\1?){4}$",[trim]))),
+?line <<"aaaaaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaaaa","^(a\\1?){4}$",[{parts,
+ 2}]))),
+?line <<"aaaaaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaaaa","^(a\\1?){4}$",[]))),
+?line <<"a">> = iolist_to_binary(join(re:split("a","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[trim]))),
+?line <<"a">> = iolist_to_binary(join(re:split("a","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[{parts,
+ 2}]))),
+?line <<"a">> = iolist_to_binary(join(re:split("a","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[]))),
+?line <<"aa">> = iolist_to_binary(join(re:split("aa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[trim]))),
+?line <<"aa">> = iolist_to_binary(join(re:split("aa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[{parts,
+ 2}]))),
+?line <<"aa">> = iolist_to_binary(join(re:split("aa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[]))),
+?line <<"aaa">> = iolist_to_binary(join(re:split("aaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[trim]))),
+?line <<"aaa">> = iolist_to_binary(join(re:split("aaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[{parts,
+ 2}]))),
+?line <<"aaa">> = iolist_to_binary(join(re:split("aaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[]))),
+?line <<":a:a:a:a">> = iolist_to_binary(join(re:split("aaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[trim]))),
+?line <<":a:a:a:a:">> = iolist_to_binary(join(re:split("aaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[{parts,
+ 2}]))),
+?line <<":a:a:a:a:">> = iolist_to_binary(join(re:split("aaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[]))),
+?line <<":a:aa:a:a">> = iolist_to_binary(join(re:split("aaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[trim]))),
+?line <<":a:aa:a:a:">> = iolist_to_binary(join(re:split("aaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[{parts,
+ 2}]))),
+?line <<":a:aa:a:a:">> = iolist_to_binary(join(re:split("aaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[]))),
+?line <<":a:aa:a:aa">> = iolist_to_binary(join(re:split("aaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[trim]))),
+?line <<":a:aa:a:aa:">> = iolist_to_binary(join(re:split("aaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[{parts,
+ 2}]))),
+?line <<":a:aa:a:aa:">> = iolist_to_binary(join(re:split("aaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[]))),
+?line <<":a:aa:aaa:a">> = iolist_to_binary(join(re:split("aaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[trim]))),
+?line <<":a:aa:aaa:a:">> = iolist_to_binary(join(re:split("aaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[{parts,
+ 2}]))),
+?line <<":a:aa:aaa:a:">> = iolist_to_binary(join(re:split("aaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[]))),
+?line <<"aaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[trim]))),
+?line <<"aaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[{parts,
+ 2}]))),
+?line <<"aaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[]))),
+?line <<"aaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[trim]))),
+?line <<"aaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[{parts,
+ 2}]))),
+?line <<"aaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[]))),
+?line <<":a:aa:aaa:aaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[trim]))),
+?line <<":a:aa:aaa:aaaa:">> = iolist_to_binary(join(re:split("aaaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[{parts,
+ 2}]))),
+?line <<":a:aa:aaa:aaaa:">> = iolist_to_binary(join(re:split("aaaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[]))),
+?line <<"aaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[trim]))),
+?line <<"aaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[{parts,
+ 2}]))),
+?line <<"aaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[]))),
+?line <<"aaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[trim]))),
+?line <<"aaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[{parts,
+ 2}]))),
+?line <<"aaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[]))),
+?line <<"aaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[trim]))),
+?line <<"aaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[{parts,
+ 2}]))),
+?line <<"aaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[]))),
+?line <<"aaaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[trim]))),
+?line <<"aaaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[{parts,
+ 2}]))),
+?line <<"aaaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[]))),
+?line <<"aaaaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[trim]))),
+?line <<"aaaaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[{parts,
+ 2}]))),
+?line <<"aaaaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[]))),
+?line <<"aaaaaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[trim]))),
+?line <<"aaaaaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[{parts,
+ 2}]))),
+?line <<"aaaaaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaaaa","^(a\\1?)(a\\1?)(a\\2?)(a\\3?)$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc","abc",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","abc",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","abc",[]))),
+?line <<"x:y">> = iolist_to_binary(join(re:split("xabcy","abc",[trim]))),
+?line <<"x:y">> = iolist_to_binary(join(re:split("xabcy","abc",[{parts,
+ 2}]))),
+?line <<"x:y">> = iolist_to_binary(join(re:split("xabcy","abc",[]))),
+?line <<"ab">> = iolist_to_binary(join(re:split("ababc","abc",[trim]))),
+?line <<"ab:">> = iolist_to_binary(join(re:split("ababc","abc",[{parts,
+ 2}]))),
+?line <<"ab:">> = iolist_to_binary(join(re:split("ababc","abc",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","abc",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","abc",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","abc",[]))),
+?line <<"xbc">> = iolist_to_binary(join(re:split("xbc","abc",[trim]))),
+?line <<"xbc">> = iolist_to_binary(join(re:split("xbc","abc",[{parts,
+ 2}]))),
+?line <<"xbc">> = iolist_to_binary(join(re:split("xbc","abc",[]))),
+?line <<"axc">> = iolist_to_binary(join(re:split("axc","abc",[trim]))),
+?line <<"axc">> = iolist_to_binary(join(re:split("axc","abc",[{parts,
+ 2}]))),
+?line <<"axc">> = iolist_to_binary(join(re:split("axc","abc",[]))),
+?line <<"abx">> = iolist_to_binary(join(re:split("abx","abc",[trim]))),
+?line <<"abx">> = iolist_to_binary(join(re:split("abx","abc",[{parts,
+ 2}]))),
+?line <<"abx">> = iolist_to_binary(join(re:split("abx","abc",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc","ab*c",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","ab*c",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","ab*c",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc","ab*bc",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","ab*bc",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","ab*bc",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abbc","ab*bc",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abbc","ab*bc",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abbc","ab*bc",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abbbbc","ab*bc",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abbbbc","ab*bc",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abbbbc","ab*bc",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abbbbc",".{1}",[trim]))),
+?line <<":bbbbc">> = iolist_to_binary(join(re:split("abbbbc",".{1}",[{parts,
+ 2}]))),
+?line <<"::::::">> = iolist_to_binary(join(re:split("abbbbc",".{1}",[]))),
+?line <<":bc">> = iolist_to_binary(join(re:split("abbbbc",".{3,4}",[trim]))),
+?line <<":bc">> = iolist_to_binary(join(re:split("abbbbc",".{3,4}",[{parts,
+ 2}]))),
+?line <<":bc">> = iolist_to_binary(join(re:split("abbbbc",".{3,4}",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abbbbc","ab{0,}bc",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abbbbc","ab{0,}bc",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abbbbc","ab{0,}bc",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abbc","ab+bc",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abbc","ab+bc",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abbc","ab+bc",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","ab+bc",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","ab+bc",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","ab+bc",[]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","ab+bc",[trim]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","ab+bc",[{parts,
+ 2}]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","ab+bc",[]))),
+?line <<"abq">> = iolist_to_binary(join(re:split("abq","ab+bc",[trim]))),
+?line <<"abq">> = iolist_to_binary(join(re:split("abq","ab+bc",[{parts,
+ 2}]))),
+?line <<"abq">> = iolist_to_binary(join(re:split("abq","ab+bc",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abbbbc","ab+bc",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abbbbc","ab+bc",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abbbbc","ab+bc",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abbbbc","ab{1,}bc",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abbbbc","ab{1,}bc",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abbbbc","ab{1,}bc",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abbbbc","ab{1,3}bc",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abbbbc","ab{1,3}bc",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abbbbc","ab{1,3}bc",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abbbbc","ab{3,4}bc",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abbbbc","ab{3,4}bc",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abbbbc","ab{3,4}bc",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","ab{4,5}bc",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","ab{4,5}bc",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","ab{4,5}bc",[]))),
+?line <<"abq">> = iolist_to_binary(join(re:split("abq","ab{4,5}bc",[trim]))),
+?line <<"abq">> = iolist_to_binary(join(re:split("abq","ab{4,5}bc",[{parts,
+ 2}]))),
+?line <<"abq">> = iolist_to_binary(join(re:split("abq","ab{4,5}bc",[]))),
+?line <<"abbbbc">> = iolist_to_binary(join(re:split("abbbbc","ab{4,5}bc",[trim]))),
+?line <<"abbbbc">> = iolist_to_binary(join(re:split("abbbbc","ab{4,5}bc",[{parts,
+ 2}]))),
+?line <<"abbbbc">> = iolist_to_binary(join(re:split("abbbbc","ab{4,5}bc",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abbc","ab?bc",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abbc","ab?bc",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abbc","ab?bc",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc","ab?bc",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","ab?bc",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","ab?bc",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc","ab{0,1}bc",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","ab{0,1}bc",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","ab{0,1}bc",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc","ab?c",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","ab?c",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","ab?c",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc","ab{0,1}c",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","ab{0,1}c",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","ab{0,1}c",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc","^abc$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","^abc$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","^abc$",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^abc$",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^abc$",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^abc$",[]))),
+?line <<"abbbbc">> = iolist_to_binary(join(re:split("abbbbc","^abc$",[trim]))),
+?line <<"abbbbc">> = iolist_to_binary(join(re:split("abbbbc","^abc$",[{parts,
+ 2}]))),
+?line <<"abbbbc">> = iolist_to_binary(join(re:split("abbbbc","^abc$",[]))),
+?line <<"abcc">> = iolist_to_binary(join(re:split("abcc","^abc$",[trim]))),
+?line <<"abcc">> = iolist_to_binary(join(re:split("abcc","^abc$",[{parts,
+ 2}]))),
+?line <<"abcc">> = iolist_to_binary(join(re:split("abcc","^abc$",[]))),
+?line <<":c">> = iolist_to_binary(join(re:split("abcc","^abc",[trim]))),
+?line <<":c">> = iolist_to_binary(join(re:split("abcc","^abc",[{parts,
+ 2}]))),
+?line <<":c">> = iolist_to_binary(join(re:split("abcc","^abc",[]))),
+?line <<"a">> = iolist_to_binary(join(re:split("aabc","abc$",[trim]))),
+?line <<"a:">> = iolist_to_binary(join(re:split("aabc","abc$",[{parts,
+ 2}]))),
+?line <<"a:">> = iolist_to_binary(join(re:split("aabc","abc$",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","abc$",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","abc$",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","abc$",[]))),
+?line <<"a">> = iolist_to_binary(join(re:split("aabc","abc$",[trim]))),
+?line <<"a:">> = iolist_to_binary(join(re:split("aabc","abc$",[{parts,
+ 2}]))),
+?line <<"a:">> = iolist_to_binary(join(re:split("aabc","abc$",[]))),
+?line <<"aabcd">> = iolist_to_binary(join(re:split("aabcd","abc$",[trim]))),
+?line <<"aabcd">> = iolist_to_binary(join(re:split("aabcd","abc$",[{parts,
+ 2}]))),
+?line <<"aabcd">> = iolist_to_binary(join(re:split("aabcd","abc$",[]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","^",[trim]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","^",[{parts,
+ 2}]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","^",[]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","$",[trim]))),
+?line <<"abc:">> = iolist_to_binary(join(re:split("abc","$",[{parts,
+ 2}]))),
+?line <<"abc:">> = iolist_to_binary(join(re:split("abc","$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc","a.c",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","a.c",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","a.c",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("axc","a.c",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("axc","a.c",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("axc","a.c",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("axyzc","a.*c",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("axyzc","a.*c",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("axyzc","a.*c",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abd","a[bc]d",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abd","a[bc]d",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abd","a[bc]d",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a[bc]d",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a[bc]d",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a[bc]d",[]))),
+?line <<"axyzd">> = iolist_to_binary(join(re:split("axyzd","a[bc]d",[trim]))),
+?line <<"axyzd">> = iolist_to_binary(join(re:split("axyzd","a[bc]d",[{parts,
+ 2}]))),
+?line <<"axyzd">> = iolist_to_binary(join(re:split("axyzd","a[bc]d",[]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","a[bc]d",[trim]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","a[bc]d",[{parts,
+ 2}]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","a[bc]d",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("ace","a[b-d]e",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ace","a[b-d]e",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ace","a[b-d]e",[]))),
+?line <<"a">> = iolist_to_binary(join(re:split("aac","a[b-d]",[trim]))),
+?line <<"a:">> = iolist_to_binary(join(re:split("aac","a[b-d]",[{parts,
+ 2}]))),
+?line <<"a:">> = iolist_to_binary(join(re:split("aac","a[b-d]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a-","a[-b]",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a-","a[-b]",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a-","a[-b]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a-","a[b-]",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a-","a[b-]",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a-","a[b-]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a]","a]",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a]","a]",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a]","a]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a]b","a[]]b",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a]b","a[]]b",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a]b","a[]]b",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aed","a[^bc]d",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aed","a[^bc]d",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aed","a[^bc]d",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a[^bc]d",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a[^bc]d",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a[^bc]d",[]))),
+?line <<"abd">> = iolist_to_binary(join(re:split("abd","a[^bc]d",[trim]))),
+?line <<"abd">> = iolist_to_binary(join(re:split("abd","a[^bc]d",[{parts,
+ 2}]))),
+?line <<"abd">> = iolist_to_binary(join(re:split("abd","a[^bc]d",[]))),
+?line <<"abd">> = iolist_to_binary(join(re:split("abd","a[^bc]d",[trim]))),
+?line <<"abd">> = iolist_to_binary(join(re:split("abd","a[^bc]d",[{parts,
+ 2}]))),
+?line <<"abd">> = iolist_to_binary(join(re:split("abd","a[^bc]d",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("adc","a[^-b]c",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("adc","a[^-b]c",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("adc","a[^-b]c",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("adc","a[^]b]c",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("adc","a[^]b]c",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("adc","a[^]b]c",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a[^]b]c",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a[^]b]c",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a[^]b]c",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a-c","a[^]b]c",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a-c","a[^]b]c",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a-c","a[^]b]c",[]))),
+?line <<"a]c">> = iolist_to_binary(join(re:split("a]c","a[^]b]c",[trim]))),
+?line <<"a]c">> = iolist_to_binary(join(re:split("a]c","a[^]b]c",[{parts,
+ 2}]))),
+?line <<"a]c">> = iolist_to_binary(join(re:split("a]c","a[^]b]c",[]))),
+?line <<":-">> = iolist_to_binary(join(re:split("a-","\\ba\\b",[trim]))),
+?line <<":-">> = iolist_to_binary(join(re:split("a-","\\ba\\b",[{parts,
+ 2}]))),
+?line <<":-">> = iolist_to_binary(join(re:split("a-","\\ba\\b",[]))),
+?line <<"-">> = iolist_to_binary(join(re:split("-a","\\ba\\b",[trim]))),
+?line <<"-:">> = iolist_to_binary(join(re:split("-a","\\ba\\b",[{parts,
+ 2}]))),
+?line <<"-:">> = iolist_to_binary(join(re:split("-a","\\ba\\b",[]))),
+?line <<"-:-">> = iolist_to_binary(join(re:split("-a-","\\ba\\b",[trim]))),
+?line <<"-:-">> = iolist_to_binary(join(re:split("-a-","\\ba\\b",[{parts,
+ 2}]))),
+?line <<"-:-">> = iolist_to_binary(join(re:split("-a-","\\ba\\b",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","\\by\\b",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","\\by\\b",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","\\by\\b",[]))),
+?line <<"xy">> = iolist_to_binary(join(re:split("xy","\\by\\b",[trim]))),
+?line <<"xy">> = iolist_to_binary(join(re:split("xy","\\by\\b",[{parts,
+ 2}]))),
+?line <<"xy">> = iolist_to_binary(join(re:split("xy","\\by\\b",[]))),
+?line <<"yz">> = iolist_to_binary(join(re:split("yz","\\by\\b",[trim]))),
+?line <<"yz">> = iolist_to_binary(join(re:split("yz","\\by\\b",[{parts,
+ 2}]))),
+?line <<"yz">> = iolist_to_binary(join(re:split("yz","\\by\\b",[]))),
+?line <<"xyz">> = iolist_to_binary(join(re:split("xyz","\\by\\b",[trim]))),
+?line <<"xyz">> = iolist_to_binary(join(re:split("xyz","\\by\\b",[{parts,
+ 2}]))),
+?line <<"xyz">> = iolist_to_binary(join(re:split("xyz","\\by\\b",[]))),
+?line <<"*** F:ilers">> = iolist_to_binary(join(re:split("*** Failers","\\Ba\\B",[trim]))),
+?line <<"*** F:ilers">> = iolist_to_binary(join(re:split("*** Failers","\\Ba\\B",[{parts,
+ 2}]))),
+?line <<"*** F:ilers">> = iolist_to_binary(join(re:split("*** Failers","\\Ba\\B",[]))),
+?line <<"a-">> = iolist_to_binary(join(re:split("a-","\\Ba\\B",[trim]))),
+?line <<"a-">> = iolist_to_binary(join(re:split("a-","\\Ba\\B",[{parts,
+ 2}]))),
+?line <<"a-">> = iolist_to_binary(join(re:split("a-","\\Ba\\B",[]))),
+?line <<"-a">> = iolist_to_binary(join(re:split("-a","\\Ba\\B",[trim]))),
+?line <<"-a">> = iolist_to_binary(join(re:split("-a","\\Ba\\B",[{parts,
+ 2}]))),
+?line <<"-a">> = iolist_to_binary(join(re:split("-a","\\Ba\\B",[]))),
+?line <<"-a-">> = iolist_to_binary(join(re:split("-a-","\\Ba\\B",[trim]))),
+?line <<"-a-">> = iolist_to_binary(join(re:split("-a-","\\Ba\\B",[{parts,
+ 2}]))),
+?line <<"-a-">> = iolist_to_binary(join(re:split("-a-","\\Ba\\B",[]))),
+?line <<"x">> = iolist_to_binary(join(re:split("xy","\\By\\b",[trim]))),
+?line <<"x:">> = iolist_to_binary(join(re:split("xy","\\By\\b",[{parts,
+ 2}]))),
+?line <<"x:">> = iolist_to_binary(join(re:split("xy","\\By\\b",[]))),
+?line <<":z">> = iolist_to_binary(join(re:split("yz","\\by\\B",[trim]))),
+?line <<":z">> = iolist_to_binary(join(re:split("yz","\\by\\B",[{parts,
+ 2}]))),
+?line <<":z">> = iolist_to_binary(join(re:split("yz","\\by\\B",[]))),
+?line <<"x:z">> = iolist_to_binary(join(re:split("xyz","\\By\\B",[trim]))),
+?line <<"x:z">> = iolist_to_binary(join(re:split("xyz","\\By\\B",[{parts,
+ 2}]))),
+?line <<"x:z">> = iolist_to_binary(join(re:split("xyz","\\By\\B",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a","\\w",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","\\w",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","\\w",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("-","\\W",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("-","\\W",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("-","\\W",[]))),
+?line <<"::::Failers">> = iolist_to_binary(join(re:split("*** Failers","\\W",[trim]))),
+?line <<":** Failers">> = iolist_to_binary(join(re:split("*** Failers","\\W",[{parts,
+ 2}]))),
+?line <<"::::Failers">> = iolist_to_binary(join(re:split("*** Failers","\\W",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("-","\\W",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("-","\\W",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("-","\\W",[]))),
+?line <<"a">> = iolist_to_binary(join(re:split("a","\\W",[trim]))),
+?line <<"a">> = iolist_to_binary(join(re:split("a","\\W",[{parts,
+ 2}]))),
+?line <<"a">> = iolist_to_binary(join(re:split("a","\\W",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a b","a\\sb",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a b","a\\sb",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a b","a\\sb",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a-b","a\\Sb",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a-b","a\\Sb",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a-b","a\\Sb",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a\\Sb",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a\\Sb",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a\\Sb",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a-b","a\\Sb",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a-b","a\\Sb",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a-b","a\\Sb",[]))),
+?line <<"a b">> = iolist_to_binary(join(re:split("a b","a\\Sb",[trim]))),
+?line <<"a b">> = iolist_to_binary(join(re:split("a b","a\\Sb",[{parts,
+ 2}]))),
+?line <<"a b">> = iolist_to_binary(join(re:split("a b","a\\Sb",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("1","\\d",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("1","\\d",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("1","\\d",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("-","\\D",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("-","\\D",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("-","\\D",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("*** Failers","\\D",[trim]))),
+?line <<":** Failers">> = iolist_to_binary(join(re:split("*** Failers","\\D",[{parts,
+ 2}]))),
+?line <<":::::::::::">> = iolist_to_binary(join(re:split("*** Failers","\\D",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("-","\\D",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("-","\\D",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("-","\\D",[]))),
+?line <<"1">> = iolist_to_binary(join(re:split("1","\\D",[trim]))),
+?line <<"1">> = iolist_to_binary(join(re:split("1","\\D",[{parts,
+ 2}]))),
+?line <<"1">> = iolist_to_binary(join(re:split("1","\\D",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a","[\\w]",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","[\\w]",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","[\\w]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("-","[\\W]",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("-","[\\W]",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("-","[\\W]",[]))),
+?line <<"::::Failers">> = iolist_to_binary(join(re:split("*** Failers","[\\W]",[trim]))),
+?line <<":** Failers">> = iolist_to_binary(join(re:split("*** Failers","[\\W]",[{parts,
+ 2}]))),
+?line <<"::::Failers">> = iolist_to_binary(join(re:split("*** Failers","[\\W]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("-","[\\W]",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("-","[\\W]",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("-","[\\W]",[]))),
+?line <<"a">> = iolist_to_binary(join(re:split("a","[\\W]",[trim]))),
+?line <<"a">> = iolist_to_binary(join(re:split("a","[\\W]",[{parts,
+ 2}]))),
+?line <<"a">> = iolist_to_binary(join(re:split("a","[\\W]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a b","a[\\s]b",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a b","a[\\s]b",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a b","a[\\s]b",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a-b","a[\\S]b",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a-b","a[\\S]b",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a-b","a[\\S]b",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a[\\S]b",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a[\\S]b",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a[\\S]b",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a-b","a[\\S]b",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a-b","a[\\S]b",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a-b","a[\\S]b",[]))),
+?line <<"a b">> = iolist_to_binary(join(re:split("a b","a[\\S]b",[trim]))),
+?line <<"a b">> = iolist_to_binary(join(re:split("a b","a[\\S]b",[{parts,
+ 2}]))),
+?line <<"a b">> = iolist_to_binary(join(re:split("a b","a[\\S]b",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("1","[\\d]",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("1","[\\d]",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("1","[\\d]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("-","[\\D]",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("-","[\\D]",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("-","[\\D]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("*** Failers","[\\D]",[trim]))),
+?line <<":** Failers">> = iolist_to_binary(join(re:split("*** Failers","[\\D]",[{parts,
+ 2}]))),
+?line <<":::::::::::">> = iolist_to_binary(join(re:split("*** Failers","[\\D]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("-","[\\D]",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("-","[\\D]",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("-","[\\D]",[]))),
+?line <<"1">> = iolist_to_binary(join(re:split("1","[\\D]",[trim]))),
+?line <<"1">> = iolist_to_binary(join(re:split("1","[\\D]",[{parts,
+ 2}]))),
+?line <<"1">> = iolist_to_binary(join(re:split("1","[\\D]",[]))),
+?line <<":c">> = iolist_to_binary(join(re:split("abc","ab|cd",[trim]))),
+?line <<":c">> = iolist_to_binary(join(re:split("abc","ab|cd",[{parts,
+ 2}]))),
+?line <<":c">> = iolist_to_binary(join(re:split("abc","ab|cd",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abcd","ab|cd",[trim]))),
+?line <<":cd">> = iolist_to_binary(join(re:split("abcd","ab|cd",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("abcd","ab|cd",[]))),
+?line <<"d">> = iolist_to_binary(join(re:split("def","()ef",[trim]))),
+?line <<"d::">> = iolist_to_binary(join(re:split("def","()ef",[{parts,
+ 2}]))),
+?line <<"d::">> = iolist_to_binary(join(re:split("def","()ef",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a(b","a\\(b",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a(b","a\\(b",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a(b","a\\(b",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("ab","a\\(*b",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ab","a\\(*b",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ab","a\\(*b",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a((b","a\\(*b",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a((b","a\\(*b",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a((b","a\\(*b",[]))),
+?line <<"a">> = iolist_to_binary(join(re:split("a","a\\\\b",[trim]))),
+?line <<"a">> = iolist_to_binary(join(re:split("a","a\\\\b",[{parts,
+ 2}]))),
+?line <<"a">> = iolist_to_binary(join(re:split("a","a\\\\b",[]))),
+?line <<":a:a:bc">> = iolist_to_binary(join(re:split("abc","((a))",[trim]))),
+?line <<":a:a:bc">> = iolist_to_binary(join(re:split("abc","((a))",[{parts,
+ 2}]))),
+?line <<":a:a:bc">> = iolist_to_binary(join(re:split("abc","((a))",[]))),
+?line <<":a:c">> = iolist_to_binary(join(re:split("abc","(a)b(c)",[trim]))),
+?line <<":a:c:">> = iolist_to_binary(join(re:split("abc","(a)b(c)",[{parts,
+ 2}]))),
+?line <<":a:c:">> = iolist_to_binary(join(re:split("abc","(a)b(c)",[]))),
+?line <<"aabb">> = iolist_to_binary(join(re:split("aabbabc","a+b+c",[trim]))),
+?line <<"aabb:">> = iolist_to_binary(join(re:split("aabbabc","a+b+c",[{parts,
+ 2}]))),
+?line <<"aabb:">> = iolist_to_binary(join(re:split("aabbabc","a+b+c",[]))),
+?line <<"aabb">> = iolist_to_binary(join(re:split("aabbabc","a{1,}b{1,}c",[trim]))),
+?line <<"aabb:">> = iolist_to_binary(join(re:split("aabbabc","a{1,}b{1,}c",[{parts,
+ 2}]))),
+?line <<"aabb:">> = iolist_to_binary(join(re:split("aabbabc","a{1,}b{1,}c",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abcabc","a.+?c",[trim]))),
+?line <<":abc">> = iolist_to_binary(join(re:split("abcabc","a.+?c",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("abcabc","a.+?c",[]))),
+?line <<":b">> = iolist_to_binary(join(re:split("ab","(a+|b)*",[trim]))),
+?line <<":b:">> = iolist_to_binary(join(re:split("ab","(a+|b)*",[{parts,
+ 2}]))),
+?line <<":b:">> = iolist_to_binary(join(re:split("ab","(a+|b)*",[]))),
+?line <<":b">> = iolist_to_binary(join(re:split("ab","(a+|b){0,}",[trim]))),
+?line <<":b:">> = iolist_to_binary(join(re:split("ab","(a+|b){0,}",[{parts,
+ 2}]))),
+?line <<":b:">> = iolist_to_binary(join(re:split("ab","(a+|b){0,}",[]))),
+?line <<":b">> = iolist_to_binary(join(re:split("ab","(a+|b)+",[trim]))),
+?line <<":b:">> = iolist_to_binary(join(re:split("ab","(a+|b)+",[{parts,
+ 2}]))),
+?line <<":b:">> = iolist_to_binary(join(re:split("ab","(a+|b)+",[]))),
+?line <<":b">> = iolist_to_binary(join(re:split("ab","(a+|b){1,}",[trim]))),
+?line <<":b:">> = iolist_to_binary(join(re:split("ab","(a+|b){1,}",[{parts,
+ 2}]))),
+?line <<":b:">> = iolist_to_binary(join(re:split("ab","(a+|b){1,}",[]))),
+?line <<":a::b">> = iolist_to_binary(join(re:split("ab","(a+|b)?",[trim]))),
+?line <<":a:b">> = iolist_to_binary(join(re:split("ab","(a+|b)?",[{parts,
+ 2}]))),
+?line <<":a::b:">> = iolist_to_binary(join(re:split("ab","(a+|b)?",[]))),
+?line <<":a::b">> = iolist_to_binary(join(re:split("ab","(a+|b){0,1}",[trim]))),
+?line <<":a:b">> = iolist_to_binary(join(re:split("ab","(a+|b){0,1}",[{parts,
+ 2}]))),
+?line <<":a::b:">> = iolist_to_binary(join(re:split("ab","(a+|b){0,1}",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("cde","[^ab]*",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("cde","[^ab]*",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("cde","[^ab]*",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","abc",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","abc",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","abc",[]))),
+?line <<"b">> = iolist_to_binary(join(re:split("b","abc",[trim]))),
+?line <<"b">> = iolist_to_binary(join(re:split("b","abc",[{parts,
+ 2}]))),
+?line <<"b">> = iolist_to_binary(join(re:split("b","abc",[]))),
+?line <<":c">> = iolist_to_binary(join(re:split("abbbcd","([abc])*d",[trim]))),
+?line <<":c:">> = iolist_to_binary(join(re:split("abbbcd","([abc])*d",[{parts,
+ 2}]))),
+?line <<":c:">> = iolist_to_binary(join(re:split("abbbcd","([abc])*d",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("abcd","([abc])*bcd",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("abcd","([abc])*bcd",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("abcd","([abc])*bcd",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("e","a|b|c|d|e",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("e","a|b|c|d|e",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("e","a|b|c|d|e",[]))),
+?line <<":e">> = iolist_to_binary(join(re:split("ef","(a|b|c|d|e)f",[trim]))),
+?line <<":e:">> = iolist_to_binary(join(re:split("ef","(a|b|c|d|e)f",[{parts,
+ 2}]))),
+?line <<":e:">> = iolist_to_binary(join(re:split("ef","(a|b|c|d|e)f",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abcdefg","abcd*efg",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abcdefg","abcd*efg",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abcdefg","abcd*efg",[]))),
+?line <<"x:y:z">> = iolist_to_binary(join(re:split("xabyabbbz","ab*",[trim]))),
+?line <<"x:yabbbz">> = iolist_to_binary(join(re:split("xabyabbbz","ab*",[{parts,
+ 2}]))),
+?line <<"x:y:z">> = iolist_to_binary(join(re:split("xabyabbbz","ab*",[]))),
+?line <<"x:y:z">> = iolist_to_binary(join(re:split("xayabbbz","ab*",[trim]))),
+?line <<"x:yabbbz">> = iolist_to_binary(join(re:split("xayabbbz","ab*",[{parts,
+ 2}]))),
+?line <<"x:y:z">> = iolist_to_binary(join(re:split("xayabbbz","ab*",[]))),
+?line <<"ab:cd">> = iolist_to_binary(join(re:split("abcde","(ab|cd)e",[trim]))),
+?line <<"ab:cd:">> = iolist_to_binary(join(re:split("abcde","(ab|cd)e",[{parts,
+ 2}]))),
+?line <<"ab:cd:">> = iolist_to_binary(join(re:split("abcde","(ab|cd)e",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("hij","[abhgefdc]ij",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("hij","[abhgefdc]ij",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("hij","[abhgefdc]ij",[]))),
+?line <<"abcd">> = iolist_to_binary(join(re:split("abcdef","(abc|)ef",[trim]))),
+?line <<"abcd::">> = iolist_to_binary(join(re:split("abcdef","(abc|)ef",[{parts,
+ 2}]))),
+?line <<"abcd::">> = iolist_to_binary(join(re:split("abcdef","(abc|)ef",[]))),
+?line <<"a:b">> = iolist_to_binary(join(re:split("abcd","(a|b)c*d",[trim]))),
+?line <<"a:b:">> = iolist_to_binary(join(re:split("abcd","(a|b)c*d",[{parts,
+ 2}]))),
+?line <<"a:b:">> = iolist_to_binary(join(re:split("abcd","(a|b)c*d",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("abc","(ab|ab*)bc",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("abc","(ab|ab*)bc",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("abc","(ab|ab*)bc",[]))),
+?line <<":bc">> = iolist_to_binary(join(re:split("abc","a([bc]*)c*",[trim]))),
+?line <<":bc:">> = iolist_to_binary(join(re:split("abc","a([bc]*)c*",[{parts,
+ 2}]))),
+?line <<":bc:">> = iolist_to_binary(join(re:split("abc","a([bc]*)c*",[]))),
+?line <<":bc:d">> = iolist_to_binary(join(re:split("abcd","a([bc]*)(c*d)",[trim]))),
+?line <<":bc:d:">> = iolist_to_binary(join(re:split("abcd","a([bc]*)(c*d)",[{parts,
+ 2}]))),
+?line <<":bc:d:">> = iolist_to_binary(join(re:split("abcd","a([bc]*)(c*d)",[]))),
+?line <<":bc:d">> = iolist_to_binary(join(re:split("abcd","a([bc]+)(c*d)",[trim]))),
+?line <<":bc:d:">> = iolist_to_binary(join(re:split("abcd","a([bc]+)(c*d)",[{parts,
+ 2}]))),
+?line <<":bc:d:">> = iolist_to_binary(join(re:split("abcd","a([bc]+)(c*d)",[]))),
+?line <<":b:cd">> = iolist_to_binary(join(re:split("abcd","a([bc]*)(c+d)",[trim]))),
+?line <<":b:cd:">> = iolist_to_binary(join(re:split("abcd","a([bc]*)(c+d)",[{parts,
+ 2}]))),
+?line <<":b:cd:">> = iolist_to_binary(join(re:split("abcd","a([bc]*)(c+d)",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("adcdcde","a[bcd]*dcdcde",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("adcdcde","a[bcd]*dcdcde",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("adcdcde","a[bcd]*dcdcde",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a[bcd]+dcdcde",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a[bcd]+dcdcde",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a[bcd]+dcdcde",[]))),
+?line <<"abcde">> = iolist_to_binary(join(re:split("abcde","a[bcd]+dcdcde",[trim]))),
+?line <<"abcde">> = iolist_to_binary(join(re:split("abcde","a[bcd]+dcdcde",[{parts,
+ 2}]))),
+?line <<"abcde">> = iolist_to_binary(join(re:split("abcde","a[bcd]+dcdcde",[]))),
+?line <<"adcdcde">> = iolist_to_binary(join(re:split("adcdcde","a[bcd]+dcdcde",[trim]))),
+?line <<"adcdcde">> = iolist_to_binary(join(re:split("adcdcde","a[bcd]+dcdcde",[{parts,
+ 2}]))),
+?line <<"adcdcde">> = iolist_to_binary(join(re:split("adcdcde","a[bcd]+dcdcde",[]))),
+?line <<":ab">> = iolist_to_binary(join(re:split("abc","(ab|a)b*c",[trim]))),
+?line <<":ab:">> = iolist_to_binary(join(re:split("abc","(ab|a)b*c",[{parts,
+ 2}]))),
+?line <<":ab:">> = iolist_to_binary(join(re:split("abc","(ab|a)b*c",[]))),
+?line <<":abc:a:b:d">> = iolist_to_binary(join(re:split("abcd","((a)(b)c)(d)",[trim]))),
+?line <<":abc:a:b:d:">> = iolist_to_binary(join(re:split("abcd","((a)(b)c)(d)",[{parts,
+ 2}]))),
+?line <<":abc:a:b:d:">> = iolist_to_binary(join(re:split("abcd","((a)(b)c)(d)",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("alpha","[a-zA-Z_][a-zA-Z0-9_]*",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("alpha","[a-zA-Z_][a-zA-Z0-9_]*",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("alpha","[a-zA-Z_][a-zA-Z0-9_]*",[]))),
+?line <<"a">> = iolist_to_binary(join(re:split("abh","^a(bc+|b[eh])g|.h$",[trim]))),
+?line <<"a::">> = iolist_to_binary(join(re:split("abh","^a(bc+|b[eh])g|.h$",[{parts,
+ 2}]))),
+?line <<"a::">> = iolist_to_binary(join(re:split("abh","^a(bc+|b[eh])g|.h$",[]))),
+?line <<":effgz">> = iolist_to_binary(join(re:split("effgz","(bc+d$|ef*g.|h?i(j|k))",[trim]))),
+?line <<":effgz::">> = iolist_to_binary(join(re:split("effgz","(bc+d$|ef*g.|h?i(j|k))",[{parts,
+ 2}]))),
+?line <<":effgz::">> = iolist_to_binary(join(re:split("effgz","(bc+d$|ef*g.|h?i(j|k))",[]))),
+?line <<":ij:j">> = iolist_to_binary(join(re:split("ij","(bc+d$|ef*g.|h?i(j|k))",[trim]))),
+?line <<":ij:j:">> = iolist_to_binary(join(re:split("ij","(bc+d$|ef*g.|h?i(j|k))",[{parts,
+ 2}]))),
+?line <<":ij:j:">> = iolist_to_binary(join(re:split("ij","(bc+d$|ef*g.|h?i(j|k))",[]))),
+?line <<"r:effgz">> = iolist_to_binary(join(re:split("reffgz","(bc+d$|ef*g.|h?i(j|k))",[trim]))),
+?line <<"r:effgz::">> = iolist_to_binary(join(re:split("reffgz","(bc+d$|ef*g.|h?i(j|k))",[{parts,
+ 2}]))),
+?line <<"r:effgz::">> = iolist_to_binary(join(re:split("reffgz","(bc+d$|ef*g.|h?i(j|k))",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(bc+d$|ef*g.|h?i(j|k))",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(bc+d$|ef*g.|h?i(j|k))",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(bc+d$|ef*g.|h?i(j|k))",[]))),
+?line <<"effg">> = iolist_to_binary(join(re:split("effg","(bc+d$|ef*g.|h?i(j|k))",[trim]))),
+?line <<"effg">> = iolist_to_binary(join(re:split("effg","(bc+d$|ef*g.|h?i(j|k))",[{parts,
+ 2}]))),
+?line <<"effg">> = iolist_to_binary(join(re:split("effg","(bc+d$|ef*g.|h?i(j|k))",[]))),
+?line <<"bcdd">> = iolist_to_binary(join(re:split("bcdd","(bc+d$|ef*g.|h?i(j|k))",[trim]))),
+?line <<"bcdd">> = iolist_to_binary(join(re:split("bcdd","(bc+d$|ef*g.|h?i(j|k))",[{parts,
+ 2}]))),
+?line <<"bcdd">> = iolist_to_binary(join(re:split("bcdd","(bc+d$|ef*g.|h?i(j|k))",[]))),
+?line <<":a:a:a:a:a:a:a:a:a:a">> = iolist_to_binary(join(re:split("a","((((((((((a))))))))))",[trim]))),
+?line <<":a:a:a:a:a:a:a:a:a:a:">> = iolist_to_binary(join(re:split("a","((((((((((a))))))))))",[{parts,
+ 2}]))),
+?line <<":a:a:a:a:a:a:a:a:a:a:">> = iolist_to_binary(join(re:split("a","((((((((((a))))))))))",[]))),
+?line <<":a:a:a:a:a:a:a:a:a:a">> = iolist_to_binary(join(re:split("aa","((((((((((a))))))))))\\10",[trim]))),
+?line <<":a:a:a:a:a:a:a:a:a:a:">> = iolist_to_binary(join(re:split("aa","((((((((((a))))))))))\\10",[{parts,
+ 2}]))),
+?line <<":a:a:a:a:a:a:a:a:a:a:">> = iolist_to_binary(join(re:split("aa","((((((((((a))))))))))\\10",[]))),
+?line <<":a:a:a:a:a:a:a:a:a">> = iolist_to_binary(join(re:split("a","(((((((((a)))))))))",[trim]))),
+?line <<":a:a:a:a:a:a:a:a:a:">> = iolist_to_binary(join(re:split("a","(((((((((a)))))))))",[{parts,
+ 2}]))),
+?line <<":a:a:a:a:a:a:a:a:a:">> = iolist_to_binary(join(re:split("a","(((((((((a)))))))))",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","multiple words of text",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","multiple words of text",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","multiple words of text",[]))),
+?line <<"aa">> = iolist_to_binary(join(re:split("aa","multiple words of text",[trim]))),
+?line <<"aa">> = iolist_to_binary(join(re:split("aa","multiple words of text",[{parts,
+ 2}]))),
+?line <<"aa">> = iolist_to_binary(join(re:split("aa","multiple words of text",[]))),
+?line <<"uh-uh">> = iolist_to_binary(join(re:split("uh-uh","multiple words of text",[trim]))),
+?line <<"uh-uh">> = iolist_to_binary(join(re:split("uh-uh","multiple words of text",[{parts,
+ 2}]))),
+?line <<"uh-uh">> = iolist_to_binary(join(re:split("uh-uh","multiple words of text",[]))),
+?line <<":, yeah">> = iolist_to_binary(join(re:split("multiple words, yeah","multiple words",[trim]))),
+?line <<":, yeah">> = iolist_to_binary(join(re:split("multiple words, yeah","multiple words",[{parts,
+ 2}]))),
+?line <<":, yeah">> = iolist_to_binary(join(re:split("multiple words, yeah","multiple words",[]))),
+?line <<":ab:de">> = iolist_to_binary(join(re:split("abcde","(.*)c(.*)",[trim]))),
+?line <<":ab:de:">> = iolist_to_binary(join(re:split("abcde","(.*)c(.*)",[{parts,
+ 2}]))),
+?line <<":ab:de:">> = iolist_to_binary(join(re:split("abcde","(.*)c(.*)",[]))),
+?line <<":a:b">> = iolist_to_binary(join(re:split("(a, b)","\\((.*), (.*)\\)",[trim]))),
+?line <<":a:b:">> = iolist_to_binary(join(re:split("(a, b)","\\((.*), (.*)\\)",[{parts,
+ 2}]))),
+?line <<":a:b:">> = iolist_to_binary(join(re:split("(a, b)","\\((.*), (.*)\\)",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abcd","abcd",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abcd","abcd",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abcd","abcd",[]))),
+?line <<":bc">> = iolist_to_binary(join(re:split("abcd","a(bc)d",[trim]))),
+?line <<":bc:">> = iolist_to_binary(join(re:split("abcd","a(bc)d",[{parts,
+ 2}]))),
+?line <<":bc:">> = iolist_to_binary(join(re:split("abcd","a(bc)d",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("ac","a[-]?c",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ac","a[-]?c",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ac","a[-]?c",[]))),
+?line <<":abc">> = iolist_to_binary(join(re:split("abcabc","(abc)\\1",[trim]))),
+?line <<":abc:">> = iolist_to_binary(join(re:split("abcabc","(abc)\\1",[{parts,
+ 2}]))),
+?line <<":abc:">> = iolist_to_binary(join(re:split("abcabc","(abc)\\1",[]))),
+?line <<":abc">> = iolist_to_binary(join(re:split("abcabc","([a-c]*)\\1",[trim]))),
+?line <<":abc:">> = iolist_to_binary(join(re:split("abcabc","([a-c]*)\\1",[{parts,
+ 2}]))),
+?line <<":abc:">> = iolist_to_binary(join(re:split("abcabc","([a-c]*)\\1",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("a","(a)|\\1",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("a","(a)|\\1",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("a","(a)|\\1",[]))),
+?line <<"*** F:a:ilers">> = iolist_to_binary(join(re:split("*** Failers","(a)|\\1",[trim]))),
+?line <<"*** F:a:ilers">> = iolist_to_binary(join(re:split("*** Failers","(a)|\\1",[{parts,
+ 2}]))),
+?line <<"*** F:a:ilers">> = iolist_to_binary(join(re:split("*** Failers","(a)|\\1",[]))),
+?line <<":a:b">> = iolist_to_binary(join(re:split("ab","(a)|\\1",[trim]))),
+?line <<":a:b">> = iolist_to_binary(join(re:split("ab","(a)|\\1",[{parts,
+ 2}]))),
+?line <<":a:b">> = iolist_to_binary(join(re:split("ab","(a)|\\1",[]))),
+?line <<"x">> = iolist_to_binary(join(re:split("x","(a)|\\1",[trim]))),
+?line <<"x">> = iolist_to_binary(join(re:split("x","(a)|\\1",[{parts,
+ 2}]))),
+?line <<"x">> = iolist_to_binary(join(re:split("x","(a)|\\1",[]))),
+?line <<":bb:b:b:cbc:c">> = iolist_to_binary(join(re:split("ababbbcbc","(([a-c])b*?\\2)*",[trim]))),
+?line <<":bb:b:bcbc">> = iolist_to_binary(join(re:split("ababbbcbc","(([a-c])b*?\\2)*",[{parts,
+ 2}]))),
+?line <<":bb:b:b:cbc:c:">> = iolist_to_binary(join(re:split("ababbbcbc","(([a-c])b*?\\2)*",[]))),
+?line <<":cbc:c">> = iolist_to_binary(join(re:split("ababbbcbc","(([a-c])b*?\\2){3}",[trim]))),
+?line <<":cbc:c:">> = iolist_to_binary(join(re:split("ababbbcbc","(([a-c])b*?\\2){3}",[{parts,
+ 2}]))),
+?line <<":cbc:c:">> = iolist_to_binary(join(re:split("ababbbcbc","(([a-c])b*?\\2){3}",[]))),
+?line <<"aaaxabaxbaax:bbax:b:a">> = iolist_to_binary(join(re:split("aaaxabaxbaaxbbax","((\\3|b)\\2(a)x)+",[trim]))),
+?line <<"aaaxabaxbaax:bbax:b:a:">> = iolist_to_binary(join(re:split("aaaxabaxbaaxbbax","((\\3|b)\\2(a)x)+",[{parts,
+ 2}]))),
+?line <<"aaaxabaxbaax:bbax:b:a:">> = iolist_to_binary(join(re:split("aaaxabaxbaaxbbax","((\\3|b)\\2(a)x)+",[]))),
+?line <<"bbaababbabaaaaa:bba:b:a">> = iolist_to_binary(join(re:split("bbaababbabaaaaabbaaaabba","((\\3|b)\\2(a)){2,}",[trim]))),
+?line <<"bbaababbabaaaaa:bba:b:a:">> = iolist_to_binary(join(re:split("bbaababbabaaaaabbaaaabba","((\\3|b)\\2(a)){2,}",[{parts,
+ 2}]))),
+?line <<"bbaababbabaaaaa:bba:b:a:">> = iolist_to_binary(join(re:split("bbaababbabaaaaabbaaaabba","((\\3|b)\\2(a)){2,}",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("ABC","abc",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABC","abc",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABC","abc",[caseless]))),
+?line <<"X:Y">> = iolist_to_binary(join(re:split("XABCY","abc",[caseless,
+ trim]))),
+?line <<"X:Y">> = iolist_to_binary(join(re:split("XABCY","abc",[caseless,
+ {parts,
+ 2}]))),
+?line <<"X:Y">> = iolist_to_binary(join(re:split("XABCY","abc",[caseless]))),
+?line <<"AB">> = iolist_to_binary(join(re:split("ABABC","abc",[caseless,
+ trim]))),
+?line <<"AB:">> = iolist_to_binary(join(re:split("ABABC","abc",[caseless,
+ {parts,
+ 2}]))),
+?line <<"AB:">> = iolist_to_binary(join(re:split("ABABC","abc",[caseless]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","abc",[caseless,
+ trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","abc",[caseless,
+ {parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","abc",[caseless]))),
+?line <<"aaxabxbaxbbx">> = iolist_to_binary(join(re:split("aaxabxbaxbbx","abc",[caseless,
+ trim]))),
+?line <<"aaxabxbaxbbx">> = iolist_to_binary(join(re:split("aaxabxbaxbbx","abc",[caseless,
+ {parts,
+ 2}]))),
+?line <<"aaxabxbaxbbx">> = iolist_to_binary(join(re:split("aaxabxbaxbbx","abc",[caseless]))),
+?line <<"XBC">> = iolist_to_binary(join(re:split("XBC","abc",[caseless,
+ trim]))),
+?line <<"XBC">> = iolist_to_binary(join(re:split("XBC","abc",[caseless,
+ {parts,
+ 2}]))),
+?line <<"XBC">> = iolist_to_binary(join(re:split("XBC","abc",[caseless]))),
+?line <<"AXC">> = iolist_to_binary(join(re:split("AXC","abc",[caseless,
+ trim]))),
+?line <<"AXC">> = iolist_to_binary(join(re:split("AXC","abc",[caseless,
+ {parts,
+ 2}]))),
+?line <<"AXC">> = iolist_to_binary(join(re:split("AXC","abc",[caseless]))),
+?line <<"ABX">> = iolist_to_binary(join(re:split("ABX","abc",[caseless,
+ trim]))),
+?line <<"ABX">> = iolist_to_binary(join(re:split("ABX","abc",[caseless,
+ {parts,
+ 2}]))),
+?line <<"ABX">> = iolist_to_binary(join(re:split("ABX","abc",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("ABC","ab*c",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABC","ab*c",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABC","ab*c",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("ABC","ab*bc",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABC","ab*bc",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABC","ab*bc",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("ABBC","ab*bc",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABBC","ab*bc",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABBC","ab*bc",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("ABBBBC","ab*?bc",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABBBBC","ab*?bc",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABBBBC","ab*?bc",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("ABBBBC","ab{0,}?bc",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABBBBC","ab{0,}?bc",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABBBBC","ab{0,}?bc",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("ABBC","ab+?bc",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABBC","ab+?bc",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABBC","ab+?bc",[caseless]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","ab+bc",[caseless,
+ trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","ab+bc",[caseless,
+ {parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","ab+bc",[caseless]))),
+?line <<"ABC">> = iolist_to_binary(join(re:split("ABC","ab+bc",[caseless,
+ trim]))),
+?line <<"ABC">> = iolist_to_binary(join(re:split("ABC","ab+bc",[caseless,
+ {parts,
+ 2}]))),
+?line <<"ABC">> = iolist_to_binary(join(re:split("ABC","ab+bc",[caseless]))),
+?line <<"ABQ">> = iolist_to_binary(join(re:split("ABQ","ab+bc",[caseless,
+ trim]))),
+?line <<"ABQ">> = iolist_to_binary(join(re:split("ABQ","ab+bc",[caseless,
+ {parts,
+ 2}]))),
+?line <<"ABQ">> = iolist_to_binary(join(re:split("ABQ","ab+bc",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("ABBBBC","ab+bc",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABBBBC","ab+bc",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABBBBC","ab+bc",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("ABBBBC","ab{1,}?bc",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABBBBC","ab{1,}?bc",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABBBBC","ab{1,}?bc",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("ABBBBC","ab{1,3}?bc",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABBBBC","ab{1,3}?bc",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABBBBC","ab{1,3}?bc",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("ABBBBC","ab{3,4}?bc",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABBBBC","ab{3,4}?bc",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABBBBC","ab{3,4}?bc",[caseless]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","ab{4,5}?bc",[caseless,
+ trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","ab{4,5}?bc",[caseless,
+ {parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","ab{4,5}?bc",[caseless]))),
+?line <<"ABQ">> = iolist_to_binary(join(re:split("ABQ","ab{4,5}?bc",[caseless,
+ trim]))),
+?line <<"ABQ">> = iolist_to_binary(join(re:split("ABQ","ab{4,5}?bc",[caseless,
+ {parts,
+ 2}]))),
+?line <<"ABQ">> = iolist_to_binary(join(re:split("ABQ","ab{4,5}?bc",[caseless]))),
+?line <<"ABBBBC">> = iolist_to_binary(join(re:split("ABBBBC","ab{4,5}?bc",[caseless,
+ trim]))),
+?line <<"ABBBBC">> = iolist_to_binary(join(re:split("ABBBBC","ab{4,5}?bc",[caseless,
+ {parts,
+ 2}]))),
+?line <<"ABBBBC">> = iolist_to_binary(join(re:split("ABBBBC","ab{4,5}?bc",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("ABBC","ab??bc",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABBC","ab??bc",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABBC","ab??bc",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("ABC","ab??bc",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABC","ab??bc",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABC","ab??bc",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("ABC","ab{0,1}?bc",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABC","ab{0,1}?bc",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABC","ab{0,1}?bc",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("ABC","ab??c",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABC","ab??c",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABC","ab??c",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("ABC","ab{0,1}?c",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABC","ab{0,1}?c",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABC","ab{0,1}?c",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("ABC","^abc$",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABC","^abc$",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABC","^abc$",[caseless]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^abc$",[caseless,
+ trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^abc$",[caseless,
+ {parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^abc$",[caseless]))),
+?line <<"ABBBBC">> = iolist_to_binary(join(re:split("ABBBBC","^abc$",[caseless,
+ trim]))),
+?line <<"ABBBBC">> = iolist_to_binary(join(re:split("ABBBBC","^abc$",[caseless,
+ {parts,
+ 2}]))),
+?line <<"ABBBBC">> = iolist_to_binary(join(re:split("ABBBBC","^abc$",[caseless]))),
+?line <<"ABCC">> = iolist_to_binary(join(re:split("ABCC","^abc$",[caseless,
+ trim]))),
+?line <<"ABCC">> = iolist_to_binary(join(re:split("ABCC","^abc$",[caseless,
+ {parts,
+ 2}]))),
+?line <<"ABCC">> = iolist_to_binary(join(re:split("ABCC","^abc$",[caseless]))),
+?line <<":C">> = iolist_to_binary(join(re:split("ABCC","^abc",[caseless,
+ trim]))),
+?line <<":C">> = iolist_to_binary(join(re:split("ABCC","^abc",[caseless,
+ {parts,
+ 2}]))),
+?line <<":C">> = iolist_to_binary(join(re:split("ABCC","^abc",[caseless]))),
+?line <<"A">> = iolist_to_binary(join(re:split("AABC","abc$",[caseless,
+ trim]))),
+?line <<"A:">> = iolist_to_binary(join(re:split("AABC","abc$",[caseless,
+ {parts,
+ 2}]))),
+?line <<"A:">> = iolist_to_binary(join(re:split("AABC","abc$",[caseless]))),
+?line <<"ABC">> = iolist_to_binary(join(re:split("ABC","^",[caseless,
+ trim]))),
+?line <<"ABC">> = iolist_to_binary(join(re:split("ABC","^",[caseless,
+ {parts,
+ 2}]))),
+?line <<"ABC">> = iolist_to_binary(join(re:split("ABC","^",[caseless]))),
+?line <<"ABC">> = iolist_to_binary(join(re:split("ABC","$",[caseless,
+ trim]))),
+?line <<"ABC:">> = iolist_to_binary(join(re:split("ABC","$",[caseless,
+ {parts,
+ 2}]))),
+?line <<"ABC:">> = iolist_to_binary(join(re:split("ABC","$",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("ABC","a.c",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABC","a.c",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABC","a.c",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("AXC","a.c",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("AXC","a.c",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("AXC","a.c",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("AXYZC","a.*?c",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("AXYZC","a.*?c",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("AXYZC","a.*?c",[caseless]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a.*c",[caseless,
+ trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a.*c",[caseless,
+ {parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a.*c",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("AABC","a.*c",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("AABC","a.*c",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("AABC","a.*c",[caseless]))),
+?line <<"AXYZD">> = iolist_to_binary(join(re:split("AXYZD","a.*c",[caseless,
+ trim]))),
+?line <<"AXYZD">> = iolist_to_binary(join(re:split("AXYZD","a.*c",[caseless,
+ {parts,
+ 2}]))),
+?line <<"AXYZD">> = iolist_to_binary(join(re:split("AXYZD","a.*c",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("ABD","a[bc]d",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABD","a[bc]d",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABD","a[bc]d",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("ACE","a[b-d]e",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ACE","a[b-d]e",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ACE","a[b-d]e",[caseless]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a[b-d]e",[caseless,
+ trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a[b-d]e",[caseless,
+ {parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a[b-d]e",[caseless]))),
+?line <<"ABC">> = iolist_to_binary(join(re:split("ABC","a[b-d]e",[caseless,
+ trim]))),
+?line <<"ABC">> = iolist_to_binary(join(re:split("ABC","a[b-d]e",[caseless,
+ {parts,
+ 2}]))),
+?line <<"ABC">> = iolist_to_binary(join(re:split("ABC","a[b-d]e",[caseless]))),
+?line <<"ABD">> = iolist_to_binary(join(re:split("ABD","a[b-d]e",[caseless,
+ trim]))),
+?line <<"ABD">> = iolist_to_binary(join(re:split("ABD","a[b-d]e",[caseless,
+ {parts,
+ 2}]))),
+?line <<"ABD">> = iolist_to_binary(join(re:split("ABD","a[b-d]e",[caseless]))),
+?line <<"A">> = iolist_to_binary(join(re:split("AAC","a[b-d]",[caseless,
+ trim]))),
+?line <<"A:">> = iolist_to_binary(join(re:split("AAC","a[b-d]",[caseless,
+ {parts,
+ 2}]))),
+?line <<"A:">> = iolist_to_binary(join(re:split("AAC","a[b-d]",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("A-","a[-b]",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("A-","a[-b]",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("A-","a[-b]",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("A-","a[b-]",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("A-","a[b-]",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("A-","a[b-]",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("A]","a]",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("A]","a]",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("A]","a]",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("A]B","a[]]b",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("A]B","a[]]b",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("A]B","a[]]b",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("AED","a[^bc]d",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("AED","a[^bc]d",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("AED","a[^bc]d",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("ADC","a[^-b]c",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ADC","a[^-b]c",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ADC","a[^-b]c",[caseless]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a[^-b]c",[caseless,
+ trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a[^-b]c",[caseless,
+ {parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a[^-b]c",[caseless]))),
+?line <<"ABD">> = iolist_to_binary(join(re:split("ABD","a[^-b]c",[caseless,
+ trim]))),
+?line <<"ABD">> = iolist_to_binary(join(re:split("ABD","a[^-b]c",[caseless,
+ {parts,
+ 2}]))),
+?line <<"ABD">> = iolist_to_binary(join(re:split("ABD","a[^-b]c",[caseless]))),
+?line <<"A-C">> = iolist_to_binary(join(re:split("A-C","a[^-b]c",[caseless,
+ trim]))),
+?line <<"A-C">> = iolist_to_binary(join(re:split("A-C","a[^-b]c",[caseless,
+ {parts,
+ 2}]))),
+?line <<"A-C">> = iolist_to_binary(join(re:split("A-C","a[^-b]c",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("ADC","a[^]b]c",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ADC","a[^]b]c",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ADC","a[^]b]c",[caseless]))),
+?line <<":C">> = iolist_to_binary(join(re:split("ABC","ab|cd",[caseless,
+ trim]))),
+?line <<":C">> = iolist_to_binary(join(re:split("ABC","ab|cd",[caseless,
+ {parts,
+ 2}]))),
+?line <<":C">> = iolist_to_binary(join(re:split("ABC","ab|cd",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("ABCD","ab|cd",[caseless,
+ trim]))),
+?line <<":CD">> = iolist_to_binary(join(re:split("ABCD","ab|cd",[caseless,
+ {parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("ABCD","ab|cd",[caseless]))),
+?line <<"D">> = iolist_to_binary(join(re:split("DEF","()ef",[caseless,
+ trim]))),
+?line <<"D::">> = iolist_to_binary(join(re:split("DEF","()ef",[caseless,
+ {parts,
+ 2}]))),
+?line <<"D::">> = iolist_to_binary(join(re:split("DEF","()ef",[caseless]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","$b",[caseless,
+ trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","$b",[caseless,
+ {parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","$b",[caseless]))),
+?line <<"A]C">> = iolist_to_binary(join(re:split("A]C","$b",[caseless,
+ trim]))),
+?line <<"A]C">> = iolist_to_binary(join(re:split("A]C","$b",[caseless,
+ {parts,
+ 2}]))),
+?line <<"A]C">> = iolist_to_binary(join(re:split("A]C","$b",[caseless]))),
+?line <<"B">> = iolist_to_binary(join(re:split("B","$b",[caseless,
+ trim]))),
+?line <<"B">> = iolist_to_binary(join(re:split("B","$b",[caseless,
+ {parts,
+ 2}]))),
+?line <<"B">> = iolist_to_binary(join(re:split("B","$b",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("A(B","a\\(b",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("A(B","a\\(b",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("A(B","a\\(b",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("AB","a\\(*b",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("AB","a\\(*b",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("AB","a\\(*b",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("A((B","a\\(*b",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("A((B","a\\(*b",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("A((B","a\\(*b",[caseless]))),
+?line <<"A">> = iolist_to_binary(join(re:split("A","a\\\\b",[caseless,
+ notbol,
+ trim]))),
+?line <<"A">> = iolist_to_binary(join(re:split("A","a\\\\b",[caseless,
+ notbol,
+ {parts,
+ 2}]))),
+?line <<"A">> = iolist_to_binary(join(re:split("A","a\\\\b",[caseless,
+ notbol]))),
+?line <<":A:A:BC">> = iolist_to_binary(join(re:split("ABC","((a))",[caseless,
+ trim]))),
+?line <<":A:A:BC">> = iolist_to_binary(join(re:split("ABC","((a))",[caseless,
+ {parts,
+ 2}]))),
+?line <<":A:A:BC">> = iolist_to_binary(join(re:split("ABC","((a))",[caseless]))),
+?line <<":A:C">> = iolist_to_binary(join(re:split("ABC","(a)b(c)",[caseless,
+ trim]))),
+?line <<":A:C:">> = iolist_to_binary(join(re:split("ABC","(a)b(c)",[caseless,
+ {parts,
+ 2}]))),
+?line <<":A:C:">> = iolist_to_binary(join(re:split("ABC","(a)b(c)",[caseless]))),
+?line <<"AABB">> = iolist_to_binary(join(re:split("AABBABC","a+b+c",[caseless,
+ trim]))),
+?line <<"AABB:">> = iolist_to_binary(join(re:split("AABBABC","a+b+c",[caseless,
+ {parts,
+ 2}]))),
+?line <<"AABB:">> = iolist_to_binary(join(re:split("AABBABC","a+b+c",[caseless]))),
+?line <<"AABB">> = iolist_to_binary(join(re:split("AABBABC","a{1,}b{1,}c",[caseless,
+ trim]))),
+?line <<"AABB:">> = iolist_to_binary(join(re:split("AABBABC","a{1,}b{1,}c",[caseless,
+ {parts,
+ 2}]))),
+?line <<"AABB:">> = iolist_to_binary(join(re:split("AABBABC","a{1,}b{1,}c",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("ABCABC","a.+?c",[caseless,
+ trim]))),
+?line <<":ABC">> = iolist_to_binary(join(re:split("ABCABC","a.+?c",[caseless,
+ {parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("ABCABC","a.+?c",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("ABCABC","a.*?c",[caseless,
+ trim]))),
+?line <<":ABC">> = iolist_to_binary(join(re:split("ABCABC","a.*?c",[caseless,
+ {parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("ABCABC","a.*?c",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("ABCABC","a.{0,5}?c",[caseless,
+ trim]))),
+?line <<":ABC">> = iolist_to_binary(join(re:split("ABCABC","a.{0,5}?c",[caseless,
+ {parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("ABCABC","a.{0,5}?c",[caseless]))),
+?line <<":B">> = iolist_to_binary(join(re:split("AB","(a+|b)*",[caseless,
+ trim]))),
+?line <<":B:">> = iolist_to_binary(join(re:split("AB","(a+|b)*",[caseless,
+ {parts,
+ 2}]))),
+?line <<":B:">> = iolist_to_binary(join(re:split("AB","(a+|b)*",[caseless]))),
+?line <<":B">> = iolist_to_binary(join(re:split("AB","(a+|b){0,}",[caseless,
+ trim]))),
+?line <<":B:">> = iolist_to_binary(join(re:split("AB","(a+|b){0,}",[caseless,
+ {parts,
+ 2}]))),
+?line <<":B:">> = iolist_to_binary(join(re:split("AB","(a+|b){0,}",[caseless]))),
+?line <<":B">> = iolist_to_binary(join(re:split("AB","(a+|b)+",[caseless,
+ trim]))),
+?line <<":B:">> = iolist_to_binary(join(re:split("AB","(a+|b)+",[caseless,
+ {parts,
+ 2}]))),
+?line <<":B:">> = iolist_to_binary(join(re:split("AB","(a+|b)+",[caseless]))),
+?line <<":B">> = iolist_to_binary(join(re:split("AB","(a+|b){1,}",[caseless,
+ trim]))),
+?line <<":B:">> = iolist_to_binary(join(re:split("AB","(a+|b){1,}",[caseless,
+ {parts,
+ 2}]))),
+?line <<":B:">> = iolist_to_binary(join(re:split("AB","(a+|b){1,}",[caseless]))),
+?line <<":A::B">> = iolist_to_binary(join(re:split("AB","(a+|b)?",[caseless,
+ trim]))),
+?line <<":A:B">> = iolist_to_binary(join(re:split("AB","(a+|b)?",[caseless,
+ {parts,
+ 2}]))),
+?line <<":A::B:">> = iolist_to_binary(join(re:split("AB","(a+|b)?",[caseless]))),
+?line <<":A::B">> = iolist_to_binary(join(re:split("AB","(a+|b){0,1}",[caseless,
+ trim]))),
+?line <<":A:B">> = iolist_to_binary(join(re:split("AB","(a+|b){0,1}",[caseless,
+ {parts,
+ 2}]))),
+?line <<":A::B:">> = iolist_to_binary(join(re:split("AB","(a+|b){0,1}",[caseless]))),
+?line <<":A::B">> = iolist_to_binary(join(re:split("AB","(a+|b){0,1}?",[caseless,
+ trim]))),
+?line <<":A:B">> = iolist_to_binary(join(re:split("AB","(a+|b){0,1}?",[caseless,
+ {parts,
+ 2}]))),
+?line <<":A::B:">> = iolist_to_binary(join(re:split("AB","(a+|b){0,1}?",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("CDE","[^ab]*",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("CDE","[^ab]*",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("CDE","[^ab]*",[caseless]))),
+?line <<":C">> = iolist_to_binary(join(re:split("ABBBCD","([abc])*d",[caseless,
+ trim]))),
+?line <<":C:">> = iolist_to_binary(join(re:split("ABBBCD","([abc])*d",[caseless,
+ {parts,
+ 2}]))),
+?line <<":C:">> = iolist_to_binary(join(re:split("ABBBCD","([abc])*d",[caseless]))),
+?line <<":A">> = iolist_to_binary(join(re:split("ABCD","([abc])*bcd",[caseless,
+ trim]))),
+?line <<":A:">> = iolist_to_binary(join(re:split("ABCD","([abc])*bcd",[caseless,
+ {parts,
+ 2}]))),
+?line <<":A:">> = iolist_to_binary(join(re:split("ABCD","([abc])*bcd",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("E","a|b|c|d|e",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("E","a|b|c|d|e",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("E","a|b|c|d|e",[caseless]))),
+?line <<":E">> = iolist_to_binary(join(re:split("EF","(a|b|c|d|e)f",[caseless,
+ trim]))),
+?line <<":E:">> = iolist_to_binary(join(re:split("EF","(a|b|c|d|e)f",[caseless,
+ {parts,
+ 2}]))),
+?line <<":E:">> = iolist_to_binary(join(re:split("EF","(a|b|c|d|e)f",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("ABCDEFG","abcd*efg",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABCDEFG","abcd*efg",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABCDEFG","abcd*efg",[caseless]))),
+?line <<"X:Y:Z">> = iolist_to_binary(join(re:split("XABYABBBZ","ab*",[caseless,
+ trim]))),
+?line <<"X:YABBBZ">> = iolist_to_binary(join(re:split("XABYABBBZ","ab*",[caseless,
+ {parts,
+ 2}]))),
+?line <<"X:Y:Z">> = iolist_to_binary(join(re:split("XABYABBBZ","ab*",[caseless]))),
+?line <<"X:Y:Z">> = iolist_to_binary(join(re:split("XAYABBBZ","ab*",[caseless,
+ trim]))),
+?line <<"X:YABBBZ">> = iolist_to_binary(join(re:split("XAYABBBZ","ab*",[caseless,
+ {parts,
+ 2}]))),
+?line <<"X:Y:Z">> = iolist_to_binary(join(re:split("XAYABBBZ","ab*",[caseless]))),
+?line <<"AB:CD">> = iolist_to_binary(join(re:split("ABCDE","(ab|cd)e",[caseless,
+ trim]))),
+?line <<"AB:CD:">> = iolist_to_binary(join(re:split("ABCDE","(ab|cd)e",[caseless,
+ {parts,
+ 2}]))),
+?line <<"AB:CD:">> = iolist_to_binary(join(re:split("ABCDE","(ab|cd)e",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("HIJ","[abhgefdc]ij",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("HIJ","[abhgefdc]ij",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("HIJ","[abhgefdc]ij",[caseless]))),
+?line <<"ABCDE">> = iolist_to_binary(join(re:split("ABCDE","^(ab|cd)e",[caseless,
+ trim]))),
+?line <<"ABCDE">> = iolist_to_binary(join(re:split("ABCDE","^(ab|cd)e",[caseless,
+ {parts,
+ 2}]))),
+?line <<"ABCDE">> = iolist_to_binary(join(re:split("ABCDE","^(ab|cd)e",[caseless]))),
+?line <<"ABCD">> = iolist_to_binary(join(re:split("ABCDEF","(abc|)ef",[caseless,
+ trim]))),
+?line <<"ABCD::">> = iolist_to_binary(join(re:split("ABCDEF","(abc|)ef",[caseless,
+ {parts,
+ 2}]))),
+?line <<"ABCD::">> = iolist_to_binary(join(re:split("ABCDEF","(abc|)ef",[caseless]))),
+?line <<"A:B">> = iolist_to_binary(join(re:split("ABCD","(a|b)c*d",[caseless,
+ trim]))),
+?line <<"A:B:">> = iolist_to_binary(join(re:split("ABCD","(a|b)c*d",[caseless,
+ {parts,
+ 2}]))),
+?line <<"A:B:">> = iolist_to_binary(join(re:split("ABCD","(a|b)c*d",[caseless]))),
+?line <<":A">> = iolist_to_binary(join(re:split("ABC","(ab|ab*)bc",[caseless,
+ trim]))),
+?line <<":A:">> = iolist_to_binary(join(re:split("ABC","(ab|ab*)bc",[caseless,
+ {parts,
+ 2}]))),
+?line <<":A:">> = iolist_to_binary(join(re:split("ABC","(ab|ab*)bc",[caseless]))),
+?line <<":BC">> = iolist_to_binary(join(re:split("ABC","a([bc]*)c*",[caseless,
+ trim]))),
+?line <<":BC:">> = iolist_to_binary(join(re:split("ABC","a([bc]*)c*",[caseless,
+ {parts,
+ 2}]))),
+?line <<":BC:">> = iolist_to_binary(join(re:split("ABC","a([bc]*)c*",[caseless]))),
+?line <<":BC:D">> = iolist_to_binary(join(re:split("ABCD","a([bc]*)(c*d)",[caseless,
+ trim]))),
+?line <<":BC:D:">> = iolist_to_binary(join(re:split("ABCD","a([bc]*)(c*d)",[caseless,
+ {parts,
+ 2}]))),
+?line <<":BC:D:">> = iolist_to_binary(join(re:split("ABCD","a([bc]*)(c*d)",[caseless]))),
+?line <<":BC:D">> = iolist_to_binary(join(re:split("ABCD","a([bc]+)(c*d)",[caseless,
+ trim]))),
+?line <<":BC:D:">> = iolist_to_binary(join(re:split("ABCD","a([bc]+)(c*d)",[caseless,
+ {parts,
+ 2}]))),
+?line <<":BC:D:">> = iolist_to_binary(join(re:split("ABCD","a([bc]+)(c*d)",[caseless]))),
+?line <<":B:CD">> = iolist_to_binary(join(re:split("ABCD","a([bc]*)(c+d)",[caseless,
+ trim]))),
+?line <<":B:CD:">> = iolist_to_binary(join(re:split("ABCD","a([bc]*)(c+d)",[caseless,
+ {parts,
+ 2}]))),
+?line <<":B:CD:">> = iolist_to_binary(join(re:split("ABCD","a([bc]*)(c+d)",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("ADCDCDE","a[bcd]*dcdcde",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ADCDCDE","a[bcd]*dcdcde",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ADCDCDE","a[bcd]*dcdcde",[caseless]))),
+?line <<":AB">> = iolist_to_binary(join(re:split("ABC","(ab|a)b*c",[caseless,
+ trim]))),
+?line <<":AB:">> = iolist_to_binary(join(re:split("ABC","(ab|a)b*c",[caseless,
+ {parts,
+ 2}]))),
+?line <<":AB:">> = iolist_to_binary(join(re:split("ABC","(ab|a)b*c",[caseless]))),
+?line <<":ABC:A:B:D">> = iolist_to_binary(join(re:split("ABCD","((a)(b)c)(d)",[caseless,
+ trim]))),
+?line <<":ABC:A:B:D:">> = iolist_to_binary(join(re:split("ABCD","((a)(b)c)(d)",[caseless,
+ {parts,
+ 2}]))),
+?line <<":ABC:A:B:D:">> = iolist_to_binary(join(re:split("ABCD","((a)(b)c)(d)",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("ALPHA","[a-zA-Z_][a-zA-Z0-9_]*",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ALPHA","[a-zA-Z_][a-zA-Z0-9_]*",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ALPHA","[a-zA-Z_][a-zA-Z0-9_]*",[caseless]))),
+?line <<"A">> = iolist_to_binary(join(re:split("ABH","^a(bc+|b[eh])g|.h$",[caseless,
+ trim]))),
+?line <<"A::">> = iolist_to_binary(join(re:split("ABH","^a(bc+|b[eh])g|.h$",[caseless,
+ {parts,
+ 2}]))),
+?line <<"A::">> = iolist_to_binary(join(re:split("ABH","^a(bc+|b[eh])g|.h$",[caseless]))),
+?line <<":EFFGZ">> = iolist_to_binary(join(re:split("EFFGZ","(bc+d$|ef*g.|h?i(j|k))",[caseless,
+ trim]))),
+?line <<":EFFGZ::">> = iolist_to_binary(join(re:split("EFFGZ","(bc+d$|ef*g.|h?i(j|k))",[caseless,
+ {parts,
+ 2}]))),
+?line <<":EFFGZ::">> = iolist_to_binary(join(re:split("EFFGZ","(bc+d$|ef*g.|h?i(j|k))",[caseless]))),
+?line <<":IJ:J">> = iolist_to_binary(join(re:split("IJ","(bc+d$|ef*g.|h?i(j|k))",[caseless,
+ trim]))),
+?line <<":IJ:J:">> = iolist_to_binary(join(re:split("IJ","(bc+d$|ef*g.|h?i(j|k))",[caseless,
+ {parts,
+ 2}]))),
+?line <<":IJ:J:">> = iolist_to_binary(join(re:split("IJ","(bc+d$|ef*g.|h?i(j|k))",[caseless]))),
+?line <<"R:EFFGZ">> = iolist_to_binary(join(re:split("REFFGZ","(bc+d$|ef*g.|h?i(j|k))",[caseless,
+ trim]))),
+?line <<"R:EFFGZ::">> = iolist_to_binary(join(re:split("REFFGZ","(bc+d$|ef*g.|h?i(j|k))",[caseless,
+ {parts,
+ 2}]))),
+?line <<"R:EFFGZ::">> = iolist_to_binary(join(re:split("REFFGZ","(bc+d$|ef*g.|h?i(j|k))",[caseless]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(bc+d$|ef*g.|h?i(j|k))",[caseless,
+ trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(bc+d$|ef*g.|h?i(j|k))",[caseless,
+ {parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(bc+d$|ef*g.|h?i(j|k))",[caseless]))),
+?line <<"ADCDCDE">> = iolist_to_binary(join(re:split("ADCDCDE","(bc+d$|ef*g.|h?i(j|k))",[caseless,
+ trim]))),
+?line <<"ADCDCDE">> = iolist_to_binary(join(re:split("ADCDCDE","(bc+d$|ef*g.|h?i(j|k))",[caseless,
+ {parts,
+ 2}]))),
+?line <<"ADCDCDE">> = iolist_to_binary(join(re:split("ADCDCDE","(bc+d$|ef*g.|h?i(j|k))",[caseless]))),
+?line <<"EFFG">> = iolist_to_binary(join(re:split("EFFG","(bc+d$|ef*g.|h?i(j|k))",[caseless,
+ trim]))),
+?line <<"EFFG">> = iolist_to_binary(join(re:split("EFFG","(bc+d$|ef*g.|h?i(j|k))",[caseless,
+ {parts,
+ 2}]))),
+?line <<"EFFG">> = iolist_to_binary(join(re:split("EFFG","(bc+d$|ef*g.|h?i(j|k))",[caseless]))),
+?line <<"BCDD">> = iolist_to_binary(join(re:split("BCDD","(bc+d$|ef*g.|h?i(j|k))",[caseless,
+ trim]))),
+?line <<"BCDD">> = iolist_to_binary(join(re:split("BCDD","(bc+d$|ef*g.|h?i(j|k))",[caseless,
+ {parts,
+ 2}]))),
+?line <<"BCDD">> = iolist_to_binary(join(re:split("BCDD","(bc+d$|ef*g.|h?i(j|k))",[caseless]))),
+?line <<":A:A:A:A:A:A:A:A:A:A">> = iolist_to_binary(join(re:split("A","((((((((((a))))))))))",[caseless,
+ trim]))),
+?line <<":A:A:A:A:A:A:A:A:A:A:">> = iolist_to_binary(join(re:split("A","((((((((((a))))))))))",[caseless,
+ {parts,
+ 2}]))),
+?line <<":A:A:A:A:A:A:A:A:A:A:">> = iolist_to_binary(join(re:split("A","((((((((((a))))))))))",[caseless]))),
+?line <<":A:A:A:A:A:A:A:A:A:A">> = iolist_to_binary(join(re:split("AA","((((((((((a))))))))))\\10",[caseless,
+ trim]))),
+?line <<":A:A:A:A:A:A:A:A:A:A:">> = iolist_to_binary(join(re:split("AA","((((((((((a))))))))))\\10",[caseless,
+ {parts,
+ 2}]))),
+?line <<":A:A:A:A:A:A:A:A:A:A:">> = iolist_to_binary(join(re:split("AA","((((((((((a))))))))))\\10",[caseless]))),
+?line <<":A:A:A:A:A:A:A:A:A">> = iolist_to_binary(join(re:split("A","(((((((((a)))))))))",[caseless,
+ trim]))),
+?line <<":A:A:A:A:A:A:A:A:A:">> = iolist_to_binary(join(re:split("A","(((((((((a)))))))))",[caseless,
+ {parts,
+ 2}]))),
+?line <<":A:A:A:A:A:A:A:A:A:">> = iolist_to_binary(join(re:split("A","(((((((((a)))))))))",[caseless]))),
+?line <<":A">> = iolist_to_binary(join(re:split("A","(?:(?:(?:(?:(?:(?:(?:(?:(?:(a))))))))))",[caseless,
+ trim]))),
+?line <<":A:">> = iolist_to_binary(join(re:split("A","(?:(?:(?:(?:(?:(?:(?:(?:(?:(a))))))))))",[caseless,
+ {parts,
+ 2}]))),
+?line <<":A:">> = iolist_to_binary(join(re:split("A","(?:(?:(?:(?:(?:(?:(?:(?:(?:(a))))))))))",[caseless]))),
+?line <<":C">> = iolist_to_binary(join(re:split("C","(?:(?:(?:(?:(?:(?:(?:(?:(?:(a|b|c))))))))))",[caseless,
+ trim]))),
+?line <<":C:">> = iolist_to_binary(join(re:split("C","(?:(?:(?:(?:(?:(?:(?:(?:(?:(a|b|c))))))))))",[caseless,
+ {parts,
+ 2}]))),
+?line <<":C:">> = iolist_to_binary(join(re:split("C","(?:(?:(?:(?:(?:(?:(?:(?:(?:(a|b|c))))))))))",[caseless]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","multiple words of text",[caseless,
+ trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","multiple words of text",[caseless,
+ {parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","multiple words of text",[caseless]))),
+?line <<"AA">> = iolist_to_binary(join(re:split("AA","multiple words of text",[caseless,
+ trim]))),
+?line <<"AA">> = iolist_to_binary(join(re:split("AA","multiple words of text",[caseless,
+ {parts,
+ 2}]))),
+?line <<"AA">> = iolist_to_binary(join(re:split("AA","multiple words of text",[caseless]))),
+?line <<"UH-UH">> = iolist_to_binary(join(re:split("UH-UH","multiple words of text",[caseless,
+ trim]))),
+?line <<"UH-UH">> = iolist_to_binary(join(re:split("UH-UH","multiple words of text",[caseless,
+ {parts,
+ 2}]))),
+?line <<"UH-UH">> = iolist_to_binary(join(re:split("UH-UH","multiple words of text",[caseless]))),
+?line <<":, YEAH">> = iolist_to_binary(join(re:split("MULTIPLE WORDS, YEAH","multiple words",[caseless,
+ trim]))),
+?line <<":, YEAH">> = iolist_to_binary(join(re:split("MULTIPLE WORDS, YEAH","multiple words",[caseless,
+ {parts,
+ 2}]))),
+?line <<":, YEAH">> = iolist_to_binary(join(re:split("MULTIPLE WORDS, YEAH","multiple words",[caseless]))),
+?line <<":AB:DE">> = iolist_to_binary(join(re:split("ABCDE","(.*)c(.*)",[caseless,
+ trim]))),
+?line <<":AB:DE:">> = iolist_to_binary(join(re:split("ABCDE","(.*)c(.*)",[caseless,
+ {parts,
+ 2}]))),
+?line <<":AB:DE:">> = iolist_to_binary(join(re:split("ABCDE","(.*)c(.*)",[caseless]))),
+?line <<":A:B">> = iolist_to_binary(join(re:split("(A, B)","\\((.*), (.*)\\)",[caseless,
+ trim]))),
+?line <<":A:B:">> = iolist_to_binary(join(re:split("(A, B)","\\((.*), (.*)\\)",[caseless,
+ {parts,
+ 2}]))),
+?line <<":A:B:">> = iolist_to_binary(join(re:split("(A, B)","\\((.*), (.*)\\)",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("ABCD","abcd",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABCD","abcd",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ABCD","abcd",[caseless]))),
+?line <<":BC">> = iolist_to_binary(join(re:split("ABCD","a(bc)d",[caseless,
+ trim]))),
+?line <<":BC:">> = iolist_to_binary(join(re:split("ABCD","a(bc)d",[caseless,
+ {parts,
+ 2}]))),
+?line <<":BC:">> = iolist_to_binary(join(re:split("ABCD","a(bc)d",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("AC","a[-]?c",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("AC","a[-]?c",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("AC","a[-]?c",[caseless]))),
+?line <<":ABC">> = iolist_to_binary(join(re:split("ABCABC","(abc)\\1",[caseless,
+ trim]))),
+?line <<":ABC:">> = iolist_to_binary(join(re:split("ABCABC","(abc)\\1",[caseless,
+ {parts,
+ 2}]))),
+?line <<":ABC:">> = iolist_to_binary(join(re:split("ABCABC","(abc)\\1",[caseless]))),
+?line <<":ABC">> = iolist_to_binary(join(re:split("ABCABC","([a-c]*)\\1",[caseless,
+ trim]))),
+?line <<":ABC:">> = iolist_to_binary(join(re:split("ABCABC","([a-c]*)\\1",[caseless,
+ {parts,
+ 2}]))),
+?line <<":ABC:">> = iolist_to_binary(join(re:split("ABCABC","([a-c]*)\\1",[caseless]))),
+?line <<"ab">> = iolist_to_binary(join(re:split("abad","a(?!b).",[trim]))),
+?line <<"ab:">> = iolist_to_binary(join(re:split("abad","a(?!b).",[{parts,
+ 2}]))),
+?line <<"ab:">> = iolist_to_binary(join(re:split("abad","a(?!b).",[]))),
+?line <<"ab">> = iolist_to_binary(join(re:split("abad","a(?=d).",[trim]))),
+?line <<"ab:">> = iolist_to_binary(join(re:split("abad","a(?=d).",[{parts,
+ 2}]))),
+?line <<"ab:">> = iolist_to_binary(join(re:split("abad","a(?=d).",[]))),
+?line <<"ab">> = iolist_to_binary(join(re:split("abad","a(?=c|d).",[trim]))),
+?line <<"ab:">> = iolist_to_binary(join(re:split("abad","a(?=c|d).",[{parts,
+ 2}]))),
+?line <<"ab:">> = iolist_to_binary(join(re:split("abad","a(?=c|d).",[]))),
+?line <<":e">> = iolist_to_binary(join(re:split("ace","a(?:b|c|d)(.)",[trim]))),
+?line <<":e:">> = iolist_to_binary(join(re:split("ace","a(?:b|c|d)(.)",[{parts,
+ 2}]))),
+?line <<":e:">> = iolist_to_binary(join(re:split("ace","a(?:b|c|d)(.)",[]))),
+?line <<":e">> = iolist_to_binary(join(re:split("ace","a(?:b|c|d)*(.)",[trim]))),
+?line <<":e:">> = iolist_to_binary(join(re:split("ace","a(?:b|c|d)*(.)",[{parts,
+ 2}]))),
+?line <<":e:">> = iolist_to_binary(join(re:split("ace","a(?:b|c|d)*(.)",[]))),
+?line <<":e">> = iolist_to_binary(join(re:split("ace","a(?:b|c|d)+?(.)",[trim]))),
+?line <<":e:">> = iolist_to_binary(join(re:split("ace","a(?:b|c|d)+?(.)",[{parts,
+ 2}]))),
+?line <<":e:">> = iolist_to_binary(join(re:split("ace","a(?:b|c|d)+?(.)",[]))),
+?line <<":d:bcdbe">> = iolist_to_binary(join(re:split("acdbcdbe","a(?:b|c|d)+?(.)",[trim]))),
+?line <<":d:bcdbe">> = iolist_to_binary(join(re:split("acdbcdbe","a(?:b|c|d)+?(.)",[{parts,
+ 2}]))),
+?line <<":d:bcdbe">> = iolist_to_binary(join(re:split("acdbcdbe","a(?:b|c|d)+?(.)",[]))),
+?line <<":e">> = iolist_to_binary(join(re:split("acdbcdbe","a(?:b|c|d)+(.)",[trim]))),
+?line <<":e:">> = iolist_to_binary(join(re:split("acdbcdbe","a(?:b|c|d)+(.)",[{parts,
+ 2}]))),
+?line <<":e:">> = iolist_to_binary(join(re:split("acdbcdbe","a(?:b|c|d)+(.)",[]))),
+?line <<":b:cdbe">> = iolist_to_binary(join(re:split("acdbcdbe","a(?:b|c|d){2}(.)",[trim]))),
+?line <<":b:cdbe">> = iolist_to_binary(join(re:split("acdbcdbe","a(?:b|c|d){2}(.)",[{parts,
+ 2}]))),
+?line <<":b:cdbe">> = iolist_to_binary(join(re:split("acdbcdbe","a(?:b|c|d){2}(.)",[]))),
+?line <<":b:e">> = iolist_to_binary(join(re:split("acdbcdbe","a(?:b|c|d){4,5}(.)",[trim]))),
+?line <<":b:e">> = iolist_to_binary(join(re:split("acdbcdbe","a(?:b|c|d){4,5}(.)",[{parts,
+ 2}]))),
+?line <<":b:e">> = iolist_to_binary(join(re:split("acdbcdbe","a(?:b|c|d){4,5}(.)",[]))),
+?line <<":d:be">> = iolist_to_binary(join(re:split("acdbcdbe","a(?:b|c|d){4,5}?(.)",[trim]))),
+?line <<":d:be">> = iolist_to_binary(join(re:split("acdbcdbe","a(?:b|c|d){4,5}?(.)",[{parts,
+ 2}]))),
+?line <<":d:be">> = iolist_to_binary(join(re:split("acdbcdbe","a(?:b|c|d){4,5}?(.)",[]))),
+?line <<":bar:foo:bar">> = iolist_to_binary(join(re:split("foobar","((foo)|(bar))*",[trim]))),
+?line <<":bar:foo:bar:">> = iolist_to_binary(join(re:split("foobar","((foo)|(bar))*",[{parts,
+ 2}]))),
+?line <<":bar:foo:bar:">> = iolist_to_binary(join(re:split("foobar","((foo)|(bar))*",[]))),
+?line <<":e">> = iolist_to_binary(join(re:split("acdbcdbe","a(?:b|c|d){6,7}(.)",[trim]))),
+?line <<":e:">> = iolist_to_binary(join(re:split("acdbcdbe","a(?:b|c|d){6,7}(.)",[{parts,
+ 2}]))),
+?line <<":e:">> = iolist_to_binary(join(re:split("acdbcdbe","a(?:b|c|d){6,7}(.)",[]))),
+?line <<":e">> = iolist_to_binary(join(re:split("acdbcdbe","a(?:b|c|d){6,7}?(.)",[trim]))),
+?line <<":e:">> = iolist_to_binary(join(re:split("acdbcdbe","a(?:b|c|d){6,7}?(.)",[{parts,
+ 2}]))),
+?line <<":e:">> = iolist_to_binary(join(re:split("acdbcdbe","a(?:b|c|d){6,7}?(.)",[]))),
+?line <<":e">> = iolist_to_binary(join(re:split("acdbcdbe","a(?:b|c|d){5,6}(.)",[trim]))),
+?line <<":e:">> = iolist_to_binary(join(re:split("acdbcdbe","a(?:b|c|d){5,6}(.)",[{parts,
+ 2}]))),
+?line <<":e:">> = iolist_to_binary(join(re:split("acdbcdbe","a(?:b|c|d){5,6}(.)",[]))),
+?line <<":b:e">> = iolist_to_binary(join(re:split("acdbcdbe","a(?:b|c|d){5,6}?(.)",[trim]))),
+?line <<":b:e">> = iolist_to_binary(join(re:split("acdbcdbe","a(?:b|c|d){5,6}?(.)",[{parts,
+ 2}]))),
+?line <<":b:e">> = iolist_to_binary(join(re:split("acdbcdbe","a(?:b|c|d){5,6}?(.)",[]))),
+?line <<":e">> = iolist_to_binary(join(re:split("acdbcdbe","a(?:b|c|d){5,7}(.)",[trim]))),
+?line <<":e:">> = iolist_to_binary(join(re:split("acdbcdbe","a(?:b|c|d){5,7}(.)",[{parts,
+ 2}]))),
+?line <<":e:">> = iolist_to_binary(join(re:split("acdbcdbe","a(?:b|c|d){5,7}(.)",[]))),
+?line <<":b:e">> = iolist_to_binary(join(re:split("acdbcdbe","a(?:b|c|d){5,7}?(.)",[trim]))),
+?line <<":b:e">> = iolist_to_binary(join(re:split("acdbcdbe","a(?:b|c|d){5,7}?(.)",[{parts,
+ 2}]))),
+?line <<":b:e">> = iolist_to_binary(join(re:split("acdbcdbe","a(?:b|c|d){5,7}?(.)",[]))),
+?line <<":c:e">> = iolist_to_binary(join(re:split("ace","a(?:b|(c|e){1,2}?|d)+?(.)",[trim]))),
+?line <<":c:e:">> = iolist_to_binary(join(re:split("ace","a(?:b|(c|e){1,2}?|d)+?(.)",[{parts,
+ 2}]))),
+?line <<":c:e:">> = iolist_to_binary(join(re:split("ace","a(?:b|(c|e){1,2}?|d)+?(.)",[]))),
+?line <<":A">> = iolist_to_binary(join(re:split("AB","^(.+)?B",[trim]))),
+?line <<":A:">> = iolist_to_binary(join(re:split("AB","^(.+)?B",[{parts,
+ 2}]))),
+?line <<":A:">> = iolist_to_binary(join(re:split("AB","^(.+)?B",[]))),
+?line <<":.">> = iolist_to_binary(join(re:split(".","^([^a-z])|(\\^)$",[trim]))),
+?line <<":.::">> = iolist_to_binary(join(re:split(".","^([^a-z])|(\\^)$",[{parts,
+ 2}]))),
+?line <<":.::">> = iolist_to_binary(join(re:split(".","^([^a-z])|(\\^)$",[]))),
+?line <<":OUT">> = iolist_to_binary(join(re:split("<&OUT","^[<>]&",[trim]))),
+?line <<":OUT">> = iolist_to_binary(join(re:split("<&OUT","^[<>]&",[{parts,
+ 2}]))),
+?line <<":OUT">> = iolist_to_binary(join(re:split("<&OUT","^[<>]&",[]))),
+?line <<":aaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaa","^(a\\1?){4}$",[trim]))),
+?line <<":aaaa:">> = iolist_to_binary(join(re:split("aaaaaaaaaa","^(a\\1?){4}$",[{parts,
+ 2}]))),
+?line <<":aaaa:">> = iolist_to_binary(join(re:split("aaaaaaaaaa","^(a\\1?){4}$",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(a\\1?){4}$",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(a\\1?){4}$",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(a\\1?){4}$",[]))),
+?line <<"AB">> = iolist_to_binary(join(re:split("AB","^(a\\1?){4}$",[trim]))),
+?line <<"AB">> = iolist_to_binary(join(re:split("AB","^(a\\1?){4}$",[{parts,
+ 2}]))),
+?line <<"AB">> = iolist_to_binary(join(re:split("AB","^(a\\1?){4}$",[]))),
+?line <<"aaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaa","^(a\\1?){4}$",[trim]))),
+?line <<"aaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaa","^(a\\1?){4}$",[{parts,
+ 2}]))),
+?line <<"aaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaa","^(a\\1?){4}$",[]))),
+?line <<"aaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaa","^(a\\1?){4}$",[trim]))),
+?line <<"aaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaa","^(a\\1?){4}$",[{parts,
+ 2}]))),
+?line <<"aaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaa","^(a\\1?){4}$",[]))),
+?line <<":aaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaa","^(a(?(1)\\1)){4}$",[trim]))),
+?line <<":aaaa:">> = iolist_to_binary(join(re:split("aaaaaaaaaa","^(a(?(1)\\1)){4}$",[{parts,
+ 2}]))),
+?line <<":aaaa:">> = iolist_to_binary(join(re:split("aaaaaaaaaa","^(a(?(1)\\1)){4}$",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(a(?(1)\\1)){4}$",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(a(?(1)\\1)){4}$",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(a(?(1)\\1)){4}$",[]))),
+?line <<"aaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaa","^(a(?(1)\\1)){4}$",[trim]))),
+?line <<"aaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaa","^(a(?(1)\\1)){4}$",[{parts,
+ 2}]))),
+?line <<"aaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaa","^(a(?(1)\\1)){4}$",[]))),
+?line <<"aaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaa","^(a(?(1)\\1)){4}$",[trim]))),
+?line <<"aaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaa","^(a(?(1)\\1)){4}$",[{parts,
+ 2}]))),
+?line <<"aaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaa","^(a(?(1)\\1)){4}$",[]))),
+?line <<":f:o:o:b:a:r">> = iolist_to_binary(join(re:split("foobar","(?:(f)(o)(o)|(b)(a)(r))*",[trim]))),
+?line <<":f:o:o:b:a:r:">> = iolist_to_binary(join(re:split("foobar","(?:(f)(o)(o)|(b)(a)(r))*",[{parts,
+ 2}]))),
+?line <<":f:o:o:b:a:r:">> = iolist_to_binary(join(re:split("foobar","(?:(f)(o)(o)|(b)(a)(r))*",[]))),
+?line <<"a">> = iolist_to_binary(join(re:split("ab","(?<=a)b",[trim]))),
+?line <<"a:">> = iolist_to_binary(join(re:split("ab","(?<=a)b",[{parts,
+ 2}]))),
+?line <<"a:">> = iolist_to_binary(join(re:split("ab","(?<=a)b",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?<=a)b",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?<=a)b",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?<=a)b",[]))),
+?line <<"cb">> = iolist_to_binary(join(re:split("cb","(?<=a)b",[trim]))),
+?line <<"cb">> = iolist_to_binary(join(re:split("cb","(?<=a)b",[{parts,
+ 2}]))),
+?line <<"cb">> = iolist_to_binary(join(re:split("cb","(?<=a)b",[]))),
+?line <<"b">> = iolist_to_binary(join(re:split("b","(?<=a)b",[trim]))),
+?line <<"b">> = iolist_to_binary(join(re:split("b","(?<=a)b",[{parts,
+ 2}]))),
+?line <<"b">> = iolist_to_binary(join(re:split("b","(?<=a)b",[]))),
+?line <<"a">> = iolist_to_binary(join(re:split("ab","(?<!c)b",[trim]))),
+?line <<"a:">> = iolist_to_binary(join(re:split("ab","(?<!c)b",[{parts,
+ 2}]))),
+?line <<"a:">> = iolist_to_binary(join(re:split("ab","(?<!c)b",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("b","(?<!c)b",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("b","(?<!c)b",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("b","(?<!c)b",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("b","(?<!c)b",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("b","(?<!c)b",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("b","(?<!c)b",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aba","(?:..)*a",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aba","(?:..)*a",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aba","(?:..)*a",[]))),
+?line <<":b">> = iolist_to_binary(join(re:split("aba","(?:..)*?a",[trim]))),
+?line <<":ba">> = iolist_to_binary(join(re:split("aba","(?:..)*?a",[{parts,
+ 2}]))),
+?line <<":b:">> = iolist_to_binary(join(re:split("aba","(?:..)*?a",[]))),
+?line <<":b:c">> = iolist_to_binary(join(re:split("abc","^(?:b|a(?=(.)))*\\1",[trim]))),
+?line <<":b:c">> = iolist_to_binary(join(re:split("abc","^(?:b|a(?=(.)))*\\1",[{parts,
+ 2}]))),
+?line <<":b:c">> = iolist_to_binary(join(re:split("abc","^(?:b|a(?=(.)))*\\1",[]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","^(){3,5}",[trim]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","^(){3,5}",[{parts,
+ 2}]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","^(){3,5}",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("aax","^(a+)*ax",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aax","^(a+)*ax",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aax","^(a+)*ax",[]))),
+?line <<":a:a">> = iolist_to_binary(join(re:split("aax","^((a|b)+)*ax",[trim]))),
+?line <<":a:a:">> = iolist_to_binary(join(re:split("aax","^((a|b)+)*ax",[{parts,
+ 2}]))),
+?line <<":a:a:">> = iolist_to_binary(join(re:split("aax","^((a|b)+)*ax",[]))),
+?line <<":a:a">> = iolist_to_binary(join(re:split("aax","^((a|bc)+)*ax",[trim]))),
+?line <<":a:a:">> = iolist_to_binary(join(re:split("aax","^((a|bc)+)*ax",[{parts,
+ 2}]))),
+?line <<":a:a:">> = iolist_to_binary(join(re:split("aax","^((a|bc)+)*ax",[]))),
+?line <<"c">> = iolist_to_binary(join(re:split("cab","(a|x)*ab",[trim]))),
+?line <<"c::">> = iolist_to_binary(join(re:split("cab","(a|x)*ab",[{parts,
+ 2}]))),
+?line <<"c::">> = iolist_to_binary(join(re:split("cab","(a|x)*ab",[]))),
+?line <<"c">> = iolist_to_binary(join(re:split("cab","(a)*ab",[trim]))),
+?line <<"c::">> = iolist_to_binary(join(re:split("cab","(a)*ab",[{parts,
+ 2}]))),
+?line <<"c::">> = iolist_to_binary(join(re:split("cab","(a)*ab",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("ab","(?:(?i)a)b",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ab","(?:(?i)a)b",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ab","(?:(?i)a)b",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("ab","((?i)a)b",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("ab","((?i)a)b",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("ab","((?i)a)b",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("Ab","(?:(?i)a)b",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("Ab","(?:(?i)a)b",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("Ab","(?:(?i)a)b",[]))),
+?line <<":A">> = iolist_to_binary(join(re:split("Ab","((?i)a)b",[trim]))),
+?line <<":A:">> = iolist_to_binary(join(re:split("Ab","((?i)a)b",[{parts,
+ 2}]))),
+?line <<":A:">> = iolist_to_binary(join(re:split("Ab","((?i)a)b",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?:(?i)a)b",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?:(?i)a)b",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?:(?i)a)b",[]))),
+?line <<"cb">> = iolist_to_binary(join(re:split("cb","(?:(?i)a)b",[trim]))),
+?line <<"cb">> = iolist_to_binary(join(re:split("cb","(?:(?i)a)b",[{parts,
+ 2}]))),
+?line <<"cb">> = iolist_to_binary(join(re:split("cb","(?:(?i)a)b",[]))),
+?line <<"aB">> = iolist_to_binary(join(re:split("aB","(?:(?i)a)b",[trim]))),
+?line <<"aB">> = iolist_to_binary(join(re:split("aB","(?:(?i)a)b",[{parts,
+ 2}]))),
+?line <<"aB">> = iolist_to_binary(join(re:split("aB","(?:(?i)a)b",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("ab","(?i:a)b",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ab","(?i:a)b",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ab","(?i:a)b",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("ab","((?i:a))b",[trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("ab","((?i:a))b",[{parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("ab","((?i:a))b",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("Ab","(?i:a)b",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("Ab","(?i:a)b",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("Ab","(?i:a)b",[]))),
+?line <<":A">> = iolist_to_binary(join(re:split("Ab","((?i:a))b",[trim]))),
+?line <<":A:">> = iolist_to_binary(join(re:split("Ab","((?i:a))b",[{parts,
+ 2}]))),
+?line <<":A:">> = iolist_to_binary(join(re:split("Ab","((?i:a))b",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?i:a)b",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?i:a)b",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?i:a)b",[]))),
+?line <<"aB">> = iolist_to_binary(join(re:split("aB","(?i:a)b",[trim]))),
+?line <<"aB">> = iolist_to_binary(join(re:split("aB","(?i:a)b",[{parts,
+ 2}]))),
+?line <<"aB">> = iolist_to_binary(join(re:split("aB","(?i:a)b",[]))),
+?line <<"aB">> = iolist_to_binary(join(re:split("aB","(?i:a)b",[trim]))),
+?line <<"aB">> = iolist_to_binary(join(re:split("aB","(?i:a)b",[{parts,
+ 2}]))),
+?line <<"aB">> = iolist_to_binary(join(re:split("aB","(?i:a)b",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("ab","(?:(?-i)a)b",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ab","(?:(?-i)a)b",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ab","(?:(?-i)a)b",[caseless]))),
+?line <<":a">> = iolist_to_binary(join(re:split("ab","((?-i)a)b",[caseless,
+ trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("ab","((?-i)a)b",[caseless,
+ {parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("ab","((?-i)a)b",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("aB","(?:(?-i)a)b",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aB","(?:(?-i)a)b",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aB","(?:(?-i)a)b",[caseless]))),
+?line <<":a">> = iolist_to_binary(join(re:split("aB","((?-i)a)b",[caseless,
+ trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aB","((?-i)a)b",[caseless,
+ {parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aB","((?-i)a)b",[caseless]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?:(?-i)a)b",[caseless,
+ trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?:(?-i)a)b",[caseless,
+ {parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?:(?-i)a)b",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("aB","(?:(?-i)a)b",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aB","(?:(?-i)a)b",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aB","(?:(?-i)a)b",[caseless]))),
+?line <<"Ab">> = iolist_to_binary(join(re:split("Ab","(?:(?-i)a)b",[caseless,
+ trim]))),
+?line <<"Ab">> = iolist_to_binary(join(re:split("Ab","(?:(?-i)a)b",[caseless,
+ {parts,
+ 2}]))),
+?line <<"Ab">> = iolist_to_binary(join(re:split("Ab","(?:(?-i)a)b",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("aB","(?:(?-i)a)b",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aB","(?:(?-i)a)b",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aB","(?:(?-i)a)b",[caseless]))),
+?line <<":a">> = iolist_to_binary(join(re:split("aB","((?-i)a)b",[caseless,
+ trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aB","((?-i)a)b",[caseless,
+ {parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aB","((?-i)a)b",[caseless]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?:(?-i)a)b",[caseless,
+ trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?:(?-i)a)b",[caseless,
+ {parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?:(?-i)a)b",[caseless]))),
+?line <<"Ab">> = iolist_to_binary(join(re:split("Ab","(?:(?-i)a)b",[caseless,
+ trim]))),
+?line <<"Ab">> = iolist_to_binary(join(re:split("Ab","(?:(?-i)a)b",[caseless,
+ {parts,
+ 2}]))),
+?line <<"Ab">> = iolist_to_binary(join(re:split("Ab","(?:(?-i)a)b",[caseless]))),
+?line <<"AB">> = iolist_to_binary(join(re:split("AB","(?:(?-i)a)b",[caseless,
+ trim]))),
+?line <<"AB">> = iolist_to_binary(join(re:split("AB","(?:(?-i)a)b",[caseless,
+ {parts,
+ 2}]))),
+?line <<"AB">> = iolist_to_binary(join(re:split("AB","(?:(?-i)a)b",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("ab","(?-i:a)b",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ab","(?-i:a)b",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ab","(?-i:a)b",[caseless]))),
+?line <<":a">> = iolist_to_binary(join(re:split("ab","((?-i:a))b",[caseless,
+ trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("ab","((?-i:a))b",[caseless,
+ {parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("ab","((?-i:a))b",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("aB","(?-i:a)b",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aB","(?-i:a)b",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aB","(?-i:a)b",[caseless]))),
+?line <<":a">> = iolist_to_binary(join(re:split("aB","((?-i:a))b",[caseless,
+ trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aB","((?-i:a))b",[caseless,
+ {parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aB","((?-i:a))b",[caseless]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?-i:a)b",[caseless,
+ trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?-i:a)b",[caseless,
+ {parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?-i:a)b",[caseless]))),
+?line <<"AB">> = iolist_to_binary(join(re:split("AB","(?-i:a)b",[caseless,
+ trim]))),
+?line <<"AB">> = iolist_to_binary(join(re:split("AB","(?-i:a)b",[caseless,
+ {parts,
+ 2}]))),
+?line <<"AB">> = iolist_to_binary(join(re:split("AB","(?-i:a)b",[caseless]))),
+?line <<"Ab">> = iolist_to_binary(join(re:split("Ab","(?-i:a)b",[caseless,
+ trim]))),
+?line <<"Ab">> = iolist_to_binary(join(re:split("Ab","(?-i:a)b",[caseless,
+ {parts,
+ 2}]))),
+?line <<"Ab">> = iolist_to_binary(join(re:split("Ab","(?-i:a)b",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("aB","(?-i:a)b",[caseless,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aB","(?-i:a)b",[caseless,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aB","(?-i:a)b",[caseless]))),
+?line <<":a">> = iolist_to_binary(join(re:split("aB","((?-i:a))b",[caseless,
+ trim]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aB","((?-i:a))b",[caseless,
+ {parts,
+ 2}]))),
+?line <<":a:">> = iolist_to_binary(join(re:split("aB","((?-i:a))b",[caseless]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?-i:a)b",[caseless,
+ trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?-i:a)b",[caseless,
+ {parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?-i:a)b",[caseless]))),
+?line <<"Ab">> = iolist_to_binary(join(re:split("Ab","(?-i:a)b",[caseless,
+ trim]))),
+?line <<"Ab">> = iolist_to_binary(join(re:split("Ab","(?-i:a)b",[caseless,
+ {parts,
+ 2}]))),
+?line <<"Ab">> = iolist_to_binary(join(re:split("Ab","(?-i:a)b",[caseless]))),
+?line <<"AB">> = iolist_to_binary(join(re:split("AB","(?-i:a)b",[caseless,
+ trim]))),
+?line <<"AB">> = iolist_to_binary(join(re:split("AB","(?-i:a)b",[caseless,
+ {parts,
+ 2}]))),
+?line <<"AB">> = iolist_to_binary(join(re:split("AB","(?-i:a)b",[caseless]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","((?-i:a.))b",[caseless,
+ trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","((?-i:a.))b",[caseless,
+ {parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","((?-i:a.))b",[caseless]))),
+?line <<"AB">> = iolist_to_binary(join(re:split("AB","((?-i:a.))b",[caseless,
+ trim]))),
+?line <<"AB">> = iolist_to_binary(join(re:split("AB","((?-i:a.))b",[caseless,
+ {parts,
+ 2}]))),
+?line <<"AB">> = iolist_to_binary(join(re:split("AB","((?-i:a.))b",[caseless]))),
+?line <<"a
+B">> = iolist_to_binary(join(re:split("a
+B","((?-i:a.))b",[caseless,trim]))),
+?line <<"a
+B">> = iolist_to_binary(join(re:split("a
+B","((?-i:a.))b",[caseless,{parts,2}]))),
+?line <<"a
+B">> = iolist_to_binary(join(re:split("a
+B","((?-i:a.))b",[caseless]))),
+?line <<":a
+">> = iolist_to_binary(join(re:split("a
+B","((?s-i:a.))b",[caseless,trim]))),
+?line <<":a
+:">> = iolist_to_binary(join(re:split("a
+B","((?s-i:a.))b",[caseless,{parts,2}]))),
+?line <<":a
+:">> = iolist_to_binary(join(re:split("a
+B","((?s-i:a.))b",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("cabbbb","(?:c|d)(?:)(?:a(?:)(?:b)(?:b(?:))(?:b(?:)(?:b)))",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("cabbbb","(?:c|d)(?:)(?:a(?:)(?:b)(?:b(?:))(?:b(?:)(?:b)))",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("cabbbb","(?:c|d)(?:)(?:a(?:)(?:b)(?:b(?:))(?:b(?:)(?:b)))",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("caaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb","(?:c|d)(?:)(?:aaaaaaaa(?:)(?:bbbbbbbb)(?:bbbbbbbb(?:))(?:bbbbbbbb(?:)(?:bbbbbbbb)))",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("caaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb","(?:c|d)(?:)(?:aaaaaaaa(?:)(?:bbbbbbbb)(?:bbbbbbbb(?:))(?:bbbbbbbb(?:)(?:bbbbbbbb)))",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("caaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb","(?:c|d)(?:)(?:aaaaaaaa(?:)(?:bbbbbbbb)(?:bbbbbbbb(?:))(?:bbbbbbbb(?:)(?:bbbbbbbb)))",[]))),
+?line <<":Ab">> = iolist_to_binary(join(re:split("Ab4ab","(ab)\\d\\1",[caseless,
+ trim]))),
+?line <<":Ab:">> = iolist_to_binary(join(re:split("Ab4ab","(ab)\\d\\1",[caseless,
+ {parts,
+ 2}]))),
+?line <<":Ab:">> = iolist_to_binary(join(re:split("Ab4ab","(ab)\\d\\1",[caseless]))),
+?line <<":ab">> = iolist_to_binary(join(re:split("ab4Ab","(ab)\\d\\1",[caseless,
+ trim]))),
+?line <<":ab:">> = iolist_to_binary(join(re:split("ab4Ab","(ab)\\d\\1",[caseless,
+ {parts,
+ 2}]))),
+?line <<":ab:">> = iolist_to_binary(join(re:split("ab4Ab","(ab)\\d\\1",[caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("foobar1234baz","foo\\w*\\d{4}baz",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("foobar1234baz","foo\\w*\\d{4}baz",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("foobar1234baz","foo\\w*\\d{4}baz",[]))),
+?line <<":~~">> = iolist_to_binary(join(re:split("x~~","x(~~)*(?:(?:F)?)?",[trim]))),
+?line <<":~~:">> = iolist_to_binary(join(re:split("x~~","x(~~)*(?:(?:F)?)?",[{parts,
+ 2}]))),
+?line <<":~~:">> = iolist_to_binary(join(re:split("x~~","x(~~)*(?:(?:F)?)?",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaac","^a(?#xxx){3}c",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaac","^a(?#xxx){3}c",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaac","^a(?#xxx){3}c",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaac","^a (?#xxx) (?#yyy) {3}c",[extended,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaac","^a (?#xxx) (?#yyy) {3}c",[extended,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaac","^a (?#xxx) (?#yyy) {3}c",[extended]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?<![cd])b",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?<![cd])b",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?<![cd])b",[]))),
+?line <<"B
+B">> = iolist_to_binary(join(re:split("B
+B","(?<![cd])b",[trim]))),
+?line <<"B
+B">> = iolist_to_binary(join(re:split("B
+B","(?<![cd])b",[{parts,2}]))),
+?line <<"B
+B">> = iolist_to_binary(join(re:split("B
+B","(?<![cd])b",[]))),
+?line <<"dbcb">> = iolist_to_binary(join(re:split("dbcb","(?<![cd])b",[trim]))),
+?line <<"dbcb">> = iolist_to_binary(join(re:split("dbcb","(?<![cd])b",[{parts,
+ 2}]))),
+?line <<"dbcb">> = iolist_to_binary(join(re:split("dbcb","(?<![cd])b",[]))),
+?line <<"db::cb">> = iolist_to_binary(join(re:split("dbaacb","(?<![cd])[ab]",[trim]))),
+?line <<"db:acb">> = iolist_to_binary(join(re:split("dbaacb","(?<![cd])[ab]",[{parts,
+ 2}]))),
+?line <<"db::cb">> = iolist_to_binary(join(re:split("dbaacb","(?<![cd])[ab]",[]))),
+?line <<"db::::cb">> = iolist_to_binary(join(re:split("dbaacb","(?<!(c|d))[ab]",[trim]))),
+?line <<"db::acb">> = iolist_to_binary(join(re:split("dbaacb","(?<!(c|d))[ab]",[{parts,
+ 2}]))),
+?line <<"db::::cb">> = iolist_to_binary(join(re:split("dbaacb","(?<!(c|d))[ab]",[]))),
+?line <<"cdacc">> = iolist_to_binary(join(re:split("cdaccb","(?<!cd)[ab]",[trim]))),
+?line <<"cdacc:">> = iolist_to_binary(join(re:split("cdaccb","(?<!cd)[ab]",[{parts,
+ 2}]))),
+?line <<"cdacc:">> = iolist_to_binary(join(re:split("cdaccb","(?<!cd)[ab]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("","^(?:a?b?)*$",[trim]))),
+?line <<"">> = iolist_to_binary(join(re:split("","^(?:a?b?)*$",[{parts,
+ 2}]))),
+?line <<"">> = iolist_to_binary(join(re:split("","^(?:a?b?)*$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a","^(?:a?b?)*$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","^(?:a?b?)*$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","^(?:a?b?)*$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("ab","^(?:a?b?)*$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ab","^(?:a?b?)*$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ab","^(?:a?b?)*$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaa","^(?:a?b?)*$",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaa","^(?:a?b?)*$",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaa","^(?:a?b?)*$",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(?:a?b?)*$",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(?:a?b?)*$",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(?:a?b?)*$",[]))),
+?line <<"dbcb">> = iolist_to_binary(join(re:split("dbcb","^(?:a?b?)*$",[trim]))),
+?line <<"dbcb">> = iolist_to_binary(join(re:split("dbcb","^(?:a?b?)*$",[{parts,
+ 2}]))),
+?line <<"dbcb">> = iolist_to_binary(join(re:split("dbcb","^(?:a?b?)*$",[]))),
+?line <<"a--">> = iolist_to_binary(join(re:split("a--","^(?:a?b?)*$",[trim]))),
+?line <<"a--">> = iolist_to_binary(join(re:split("a--","^(?:a?b?)*$",[{parts,
+ 2}]))),
+?line <<"a--">> = iolist_to_binary(join(re:split("a--","^(?:a?b?)*$",[]))),
+?line <<"aa--">> = iolist_to_binary(join(re:split("aa--","^(?:a?b?)*$",[trim]))),
+?line <<"aa--">> = iolist_to_binary(join(re:split("aa--","^(?:a?b?)*$",[{parts,
+ 2}]))),
+?line <<"aa--">> = iolist_to_binary(join(re:split("aa--","^(?:a?b?)*$",[]))),
+?line <<":a
+:
+:b:
+c">> = iolist_to_binary(join(re:split("a
+b
+c","((?s)^a(.))((?m)^b$)",[trim]))),
+?line <<":a
+:
+:b:
+c">> = iolist_to_binary(join(re:split("a
+b
+c","((?s)^a(.))((?m)^b$)",[{parts,2}]))),
+?line <<":a
+:
+:b:
+c">> = iolist_to_binary(join(re:split("a
+b
+c","((?s)^a(.))((?m)^b$)",[]))),
+?line <<"a
+:b:
+c">> = iolist_to_binary(join(re:split("a
+b
+c","((?m)^b$)",[trim]))),
+?line <<"a
+:b:
+c">> = iolist_to_binary(join(re:split("a
+b
+c","((?m)^b$)",[{parts,2}]))),
+?line <<"a
+:b:
+c">> = iolist_to_binary(join(re:split("a
+b
+c","((?m)^b$)",[]))),
+?line <<"a
+">> = iolist_to_binary(join(re:split("a
+b","(?m)^b",[trim]))),
+?line <<"a
+:">> = iolist_to_binary(join(re:split("a
+b","(?m)^b",[{parts,2}]))),
+?line <<"a
+:">> = iolist_to_binary(join(re:split("a
+b","(?m)^b",[]))),
+?line <<"a
+:b">> = iolist_to_binary(join(re:split("a
+b","(?m)^(b)",[trim]))),
+?line <<"a
+:b:">> = iolist_to_binary(join(re:split("a
+b","(?m)^(b)",[{parts,2}]))),
+?line <<"a
+:b:">> = iolist_to_binary(join(re:split("a
+b","(?m)^(b)",[]))),
+?line <<"a
+:b">> = iolist_to_binary(join(re:split("a
+b","((?m)^b)",[trim]))),
+?line <<"a
+:b:">> = iolist_to_binary(join(re:split("a
+b","((?m)^b)",[{parts,2}]))),
+?line <<"a
+:b:">> = iolist_to_binary(join(re:split("a
+b","((?m)^b)",[]))),
+?line <<"a:b">> = iolist_to_binary(join(re:split("a
+b","\\n((?m)^b)",[trim]))),
+?line <<"a:b:">> = iolist_to_binary(join(re:split("a
+b","\\n((?m)^b)",[{parts,2}]))),
+?line <<"a:b:">> = iolist_to_binary(join(re:split("a
+b","\\n((?m)^b)",[]))),
+?line <<"a
+b:
+">> = iolist_to_binary(join(re:split("a
+b
+c","((?s).)c(?!.)",[trim]))),
+?line <<"a
+b:
+:">> = iolist_to_binary(join(re:split("a
+b
+c","((?s).)c(?!.)",[{parts,2}]))),
+?line <<"a
+b:
+:">> = iolist_to_binary(join(re:split("a
+b
+c","((?s).)c(?!.)",[]))),
+?line <<"a
+b:
+">> = iolist_to_binary(join(re:split("a
+b
+c","((?s).)c(?!.)",[trim]))),
+?line <<"a
+b:
+:">> = iolist_to_binary(join(re:split("a
+b
+c","((?s).)c(?!.)",[{parts,2}]))),
+?line <<"a
+b:
+:">> = iolist_to_binary(join(re:split("a
+b
+c","((?s).)c(?!.)",[]))),
+?line <<"a
+:b
+">> = iolist_to_binary(join(re:split("a
+b
+c","((?s)b.)c(?!.)",[trim]))),
+?line <<"a
+:b
+:">> = iolist_to_binary(join(re:split("a
+b
+c","((?s)b.)c(?!.)",[{parts,2}]))),
+?line <<"a
+:b
+:">> = iolist_to_binary(join(re:split("a
+b
+c","((?s)b.)c(?!.)",[]))),
+?line <<"a
+:b
+">> = iolist_to_binary(join(re:split("a
+b
+c","((?s)b.)c(?!.)",[trim]))),
+?line <<"a
+:b
+:">> = iolist_to_binary(join(re:split("a
+b
+c","((?s)b.)c(?!.)",[{parts,2}]))),
+?line <<"a
+:b
+:">> = iolist_to_binary(join(re:split("a
+b
+c","((?s)b.)c(?!.)",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","()^b",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","()^b",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","()^b",[]))),
+?line <<"a
+b
+c">> = iolist_to_binary(join(re:split("a
+b
+c","()^b",[trim]))),
+?line <<"a
+b
+c">> = iolist_to_binary(join(re:split("a
+b
+c","()^b",[{parts,2}]))),
+?line <<"a
+b
+c">> = iolist_to_binary(join(re:split("a
+b
+c","()^b",[]))),
+?line <<"a
+b
+c">> = iolist_to_binary(join(re:split("a
+b
+c","()^b",[trim]))),
+?line <<"a
+b
+c">> = iolist_to_binary(join(re:split("a
+b
+c","()^b",[{parts,2}]))),
+?line <<"a
+b
+c">> = iolist_to_binary(join(re:split("a
+b
+c","()^b",[]))),
+?line <<"a
+:b:
+c">> = iolist_to_binary(join(re:split("a
+b
+c","((?m)^b)",[trim]))),
+?line <<"a
+:b:
+c">> = iolist_to_binary(join(re:split("a
+b
+c","((?m)^b)",[{parts,2}]))),
+?line <<"a
+:b:
+c">> = iolist_to_binary(join(re:split("a
+b
+c","((?m)^b)",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(x)?(?(1)a|b)",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(x)?(?(1)a|b)",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(x)?(?(1)a|b)",[]))),
+?line <<"a">> = iolist_to_binary(join(re:split("a","(x)?(?(1)a|b)",[trim]))),
+?line <<"a">> = iolist_to_binary(join(re:split("a","(x)?(?(1)a|b)",[{parts,
+ 2}]))),
+?line <<"a">> = iolist_to_binary(join(re:split("a","(x)?(?(1)a|b)",[]))),
+?line <<"a">> = iolist_to_binary(join(re:split("a","(x)?(?(1)a|b)",[trim]))),
+?line <<"a">> = iolist_to_binary(join(re:split("a","(x)?(?(1)a|b)",[{parts,
+ 2}]))),
+?line <<"a">> = iolist_to_binary(join(re:split("a","(x)?(?(1)a|b)",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a","(x)?(?(1)b|a)",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("a","(x)?(?(1)b|a)",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("a","(x)?(?(1)b|a)",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a","()?(?(1)b|a)",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("a","()?(?(1)b|a)",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("a","()?(?(1)b|a)",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a","()?(?(1)a|b)",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("a","()?(?(1)a|b)",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("a","()?(?(1)a|b)",[]))),
+?line <<":(:)">> = iolist_to_binary(join(re:split("(blah)","^(\\()?blah(?(1)(\\)))$",[trim]))),
+?line <<":(:):">> = iolist_to_binary(join(re:split("(blah)","^(\\()?blah(?(1)(\\)))$",[{parts,
+ 2}]))),
+?line <<":(:):">> = iolist_to_binary(join(re:split("(blah)","^(\\()?blah(?(1)(\\)))$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("blah","^(\\()?blah(?(1)(\\)))$",[trim]))),
+?line <<":::">> = iolist_to_binary(join(re:split("blah","^(\\()?blah(?(1)(\\)))$",[{parts,
+ 2}]))),
+?line <<":::">> = iolist_to_binary(join(re:split("blah","^(\\()?blah(?(1)(\\)))$",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(\\()?blah(?(1)(\\)))$",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(\\()?blah(?(1)(\\)))$",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(\\()?blah(?(1)(\\)))$",[]))),
+?line <<"a">> = iolist_to_binary(join(re:split("a","^(\\()?blah(?(1)(\\)))$",[trim]))),
+?line <<"a">> = iolist_to_binary(join(re:split("a","^(\\()?blah(?(1)(\\)))$",[{parts,
+ 2}]))),
+?line <<"a">> = iolist_to_binary(join(re:split("a","^(\\()?blah(?(1)(\\)))$",[]))),
+?line <<"blah)">> = iolist_to_binary(join(re:split("blah)","^(\\()?blah(?(1)(\\)))$",[trim]))),
+?line <<"blah)">> = iolist_to_binary(join(re:split("blah)","^(\\()?blah(?(1)(\\)))$",[{parts,
+ 2}]))),
+?line <<"blah)">> = iolist_to_binary(join(re:split("blah)","^(\\()?blah(?(1)(\\)))$",[]))),
+?line <<"(blah">> = iolist_to_binary(join(re:split("(blah","^(\\()?blah(?(1)(\\)))$",[trim]))),
+?line <<"(blah">> = iolist_to_binary(join(re:split("(blah","^(\\()?blah(?(1)(\\)))$",[{parts,
+ 2}]))),
+?line <<"(blah">> = iolist_to_binary(join(re:split("(blah","^(\\()?blah(?(1)(\\)))$",[]))),
+?line <<":(:)">> = iolist_to_binary(join(re:split("(blah)","^(\\(+)?blah(?(1)(\\)))$",[trim]))),
+?line <<":(:):">> = iolist_to_binary(join(re:split("(blah)","^(\\(+)?blah(?(1)(\\)))$",[{parts,
+ 2}]))),
+?line <<":(:):">> = iolist_to_binary(join(re:split("(blah)","^(\\(+)?blah(?(1)(\\)))$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("blah","^(\\(+)?blah(?(1)(\\)))$",[trim]))),
+?line <<":::">> = iolist_to_binary(join(re:split("blah","^(\\(+)?blah(?(1)(\\)))$",[{parts,
+ 2}]))),
+?line <<":::">> = iolist_to_binary(join(re:split("blah","^(\\(+)?blah(?(1)(\\)))$",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(\\(+)?blah(?(1)(\\)))$",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(\\(+)?blah(?(1)(\\)))$",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(\\(+)?blah(?(1)(\\)))$",[]))),
+?line <<"blah)">> = iolist_to_binary(join(re:split("blah)","^(\\(+)?blah(?(1)(\\)))$",[trim]))),
+?line <<"blah)">> = iolist_to_binary(join(re:split("blah)","^(\\(+)?blah(?(1)(\\)))$",[{parts,
+ 2}]))),
+?line <<"blah)">> = iolist_to_binary(join(re:split("blah)","^(\\(+)?blah(?(1)(\\)))$",[]))),
+?line <<"(blah">> = iolist_to_binary(join(re:split("(blah","^(\\(+)?blah(?(1)(\\)))$",[trim]))),
+?line <<"(blah">> = iolist_to_binary(join(re:split("(blah","^(\\(+)?blah(?(1)(\\)))$",[{parts,
+ 2}]))),
+?line <<"(blah">> = iolist_to_binary(join(re:split("(blah","^(\\(+)?blah(?(1)(\\)))$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a","(?(?!a)b|a)",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","(?(?!a)b|a)",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","(?(?!a)b|a)",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?(?=a)b|a)",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?(?=a)b|a)",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?(?=a)b|a)",[]))),
+?line <<"a">> = iolist_to_binary(join(re:split("a","(?(?=a)b|a)",[trim]))),
+?line <<"a">> = iolist_to_binary(join(re:split("a","(?(?=a)b|a)",[{parts,
+ 2}]))),
+?line <<"a">> = iolist_to_binary(join(re:split("a","(?(?=a)b|a)",[]))),
+?line <<"a">> = iolist_to_binary(join(re:split("a","(?(?=a)b|a)",[trim]))),
+?line <<"a">> = iolist_to_binary(join(re:split("a","(?(?=a)b|a)",[{parts,
+ 2}]))),
+?line <<"a">> = iolist_to_binary(join(re:split("a","(?(?=a)b|a)",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a","(?(?=a)a|b)",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","(?(?=a)a|b)",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","(?(?=a)a|b)",[]))),
+?line <<"a:a:aab">> = iolist_to_binary(join(re:split("aaab","(?=(a+?))(\\1ab)",[trim]))),
+?line <<"a:a:aab:">> = iolist_to_binary(join(re:split("aaab","(?=(a+?))(\\1ab)",[{parts,
+ 2}]))),
+?line <<"a:a:aab:">> = iolist_to_binary(join(re:split("aaab","(?=(a+?))(\\1ab)",[]))),
+?line <<":one:">> = iolist_to_binary(join(re:split("one:","(\\w+:)+",[trim]))),
+?line <<":one::">> = iolist_to_binary(join(re:split("one:","(\\w+:)+",[{parts,
+ 2}]))),
+?line <<":one::">> = iolist_to_binary(join(re:split("one:","(\\w+:)+",[]))),
+?line <<"a:a">> = iolist_to_binary(join(re:split("a","$(?<=^(a))",[trim]))),
+?line <<"a:a:">> = iolist_to_binary(join(re:split("a","$(?<=^(a))",[{parts,
+ 2}]))),
+?line <<"a:a:">> = iolist_to_binary(join(re:split("a","$(?<=^(a))",[]))),
+?line <<"a:a:aab">> = iolist_to_binary(join(re:split("aaab","(?=(a+?))(\\1ab)",[trim]))),
+?line <<"a:a:aab:">> = iolist_to_binary(join(re:split("aaab","(?=(a+?))(\\1ab)",[{parts,
+ 2}]))),
+?line <<"a:a:aab:">> = iolist_to_binary(join(re:split("aaab","(?=(a+?))(\\1ab)",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(?=(a+?))\\1ab",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(?=(a+?))\\1ab",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(?=(a+?))\\1ab",[]))),
+?line <<"aaab">> = iolist_to_binary(join(re:split("aaab","^(?=(a+?))\\1ab",[trim]))),
+?line <<"aaab">> = iolist_to_binary(join(re:split("aaab","^(?=(a+?))\\1ab",[{parts,
+ 2}]))),
+?line <<"aaab">> = iolist_to_binary(join(re:split("aaab","^(?=(a+?))\\1ab",[]))),
+?line <<"aaab">> = iolist_to_binary(join(re:split("aaab","^(?=(a+?))\\1ab",[trim]))),
+?line <<"aaab">> = iolist_to_binary(join(re:split("aaab","^(?=(a+?))\\1ab",[{parts,
+ 2}]))),
+?line <<"aaab">> = iolist_to_binary(join(re:split("aaab","^(?=(a+?))\\1ab",[]))),
+?line <<"::abcd">> = iolist_to_binary(join(re:split("abcd","([\\w:]+::)?(\\w+)$",[trim]))),
+?line <<"::abcd:">> = iolist_to_binary(join(re:split("abcd","([\\w:]+::)?(\\w+)$",[{parts,
+ 2}]))),
+?line <<"::abcd:">> = iolist_to_binary(join(re:split("abcd","([\\w:]+::)?(\\w+)$",[]))),
+?line <<":xy:z::::abcd">> = iolist_to_binary(join(re:split("xy:z:::abcd","([\\w:]+::)?(\\w+)$",[trim]))),
+?line <<":xy:z::::abcd:">> = iolist_to_binary(join(re:split("xy:z:::abcd","([\\w:]+::)?(\\w+)$",[{parts,
+ 2}]))),
+?line <<":xy:z::::abcd:">> = iolist_to_binary(join(re:split("xy:z:::abcd","([\\w:]+::)?(\\w+)$",[]))),
+?line <<":c:d">> = iolist_to_binary(join(re:split("aexycd","^[^bcd]*(c+)",[trim]))),
+?line <<":c:d">> = iolist_to_binary(join(re:split("aexycd","^[^bcd]*(c+)",[{parts,
+ 2}]))),
+?line <<":c:d">> = iolist_to_binary(join(re:split("aexycd","^[^bcd]*(c+)",[]))),
+?line <<"c:aa">> = iolist_to_binary(join(re:split("caab","(a*)b+",[trim]))),
+?line <<"c:aa:">> = iolist_to_binary(join(re:split("caab","(a*)b+",[{parts,
+ 2}]))),
+?line <<"c:aa:">> = iolist_to_binary(join(re:split("caab","(a*)b+",[]))),
+?line <<"::abcd">> = iolist_to_binary(join(re:split("abcd","([\\w:]+::)?(\\w+)$",[trim]))),
+?line <<"::abcd:">> = iolist_to_binary(join(re:split("abcd","([\\w:]+::)?(\\w+)$",[{parts,
+ 2}]))),
+?line <<"::abcd:">> = iolist_to_binary(join(re:split("abcd","([\\w:]+::)?(\\w+)$",[]))),
+?line <<":xy:z::::abcd">> = iolist_to_binary(join(re:split("xy:z:::abcd","([\\w:]+::)?(\\w+)$",[trim]))),
+?line <<":xy:z::::abcd:">> = iolist_to_binary(join(re:split("xy:z:::abcd","([\\w:]+::)?(\\w+)$",[{parts,
+ 2}]))),
+?line <<":xy:z::::abcd:">> = iolist_to_binary(join(re:split("xy:z:::abcd","([\\w:]+::)?(\\w+)$",[]))),
+?line <<"*** ::Failers">> = iolist_to_binary(join(re:split("*** Failers","([\\w:]+::)?(\\w+)$",[trim]))),
+?line <<"*** ::Failers:">> = iolist_to_binary(join(re:split("*** Failers","([\\w:]+::)?(\\w+)$",[{parts,
+ 2}]))),
+?line <<"*** ::Failers:">> = iolist_to_binary(join(re:split("*** Failers","([\\w:]+::)?(\\w+)$",[]))),
+?line <<"abcd:">> = iolist_to_binary(join(re:split("abcd:","([\\w:]+::)?(\\w+)$",[trim]))),
+?line <<"abcd:">> = iolist_to_binary(join(re:split("abcd:","([\\w:]+::)?(\\w+)$",[{parts,
+ 2}]))),
+?line <<"abcd:">> = iolist_to_binary(join(re:split("abcd:","([\\w:]+::)?(\\w+)$",[]))),
+?line <<"abcd:">> = iolist_to_binary(join(re:split("abcd:","([\\w:]+::)?(\\w+)$",[trim]))),
+?line <<"abcd:">> = iolist_to_binary(join(re:split("abcd:","([\\w:]+::)?(\\w+)$",[{parts,
+ 2}]))),
+?line <<"abcd:">> = iolist_to_binary(join(re:split("abcd:","([\\w:]+::)?(\\w+)$",[]))),
+?line <<":c:d">> = iolist_to_binary(join(re:split("aexycd","^[^bcd]*(c+)",[trim]))),
+?line <<":c:d">> = iolist_to_binary(join(re:split("aexycd","^[^bcd]*(c+)",[{parts,
+ 2}]))),
+?line <<":c:d">> = iolist_to_binary(join(re:split("aexycd","^[^bcd]*(c+)",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaab","(?>a+)b",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaab","(?>a+)b",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaab","(?>a+)b",[]))),
+?line <<"a::[:b]::">> = iolist_to_binary(join(re:split("a:[b]:","([[:]+)",[trim]))),
+?line <<"a::[:b]:">> = iolist_to_binary(join(re:split("a:[b]:","([[:]+)",[{parts,
+ 2}]))),
+?line <<"a::[:b]:::">> = iolist_to_binary(join(re:split("a:[b]:","([[:]+)",[]))),
+?line <<"a:=[:b]:=">> = iolist_to_binary(join(re:split("a=[b]=","([[=]+)",[trim]))),
+?line <<"a:=[:b]=">> = iolist_to_binary(join(re:split("a=[b]=","([[=]+)",[{parts,
+ 2}]))),
+?line <<"a:=[:b]:=:">> = iolist_to_binary(join(re:split("a=[b]=","([[=]+)",[]))),
+?line <<"a:.[:b]:.">> = iolist_to_binary(join(re:split("a.[b].","([[.]+)",[trim]))),
+?line <<"a:.[:b].">> = iolist_to_binary(join(re:split("a.[b].","([[.]+)",[{parts,
+ 2}]))),
+?line <<"a:.[:b]:.:">> = iolist_to_binary(join(re:split("a.[b].","([[.]+)",[]))),
+?line <<":aaab">> = iolist_to_binary(join(re:split("aaab","((?>a+)b)",[trim]))),
+?line <<":aaab:">> = iolist_to_binary(join(re:split("aaab","((?>a+)b)",[{parts,
+ 2}]))),
+?line <<":aaab:">> = iolist_to_binary(join(re:split("aaab","((?>a+)b)",[]))),
+?line <<":aaa">> = iolist_to_binary(join(re:split("aaab","(?>(a+))b",[trim]))),
+?line <<":aaa:">> = iolist_to_binary(join(re:split("aaab","(?>(a+))b",[{parts,
+ 2}]))),
+?line <<":aaa:">> = iolist_to_binary(join(re:split("aaab","(?>(a+))b",[]))),
+?line <<"((:x">> = iolist_to_binary(join(re:split("((abc(ade)ufh()()x","((?>[^()]+)|\\([^()]*\\))+",[trim]))),
+?line <<"((:x:">> = iolist_to_binary(join(re:split("((abc(ade)ufh()()x","((?>[^()]+)|\\([^()]*\\))+",[{parts,
+ 2}]))),
+?line <<"((:x:">> = iolist_to_binary(join(re:split("((abc(ade)ufh()()x","((?>[^()]+)|\\([^()]*\\))+",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a\\Z",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a\\Z",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a\\Z",[]))),
+?line <<"aaab">> = iolist_to_binary(join(re:split("aaab","a\\Z",[trim]))),
+?line <<"aaab">> = iolist_to_binary(join(re:split("aaab","a\\Z",[{parts,
+ 2}]))),
+?line <<"aaab">> = iolist_to_binary(join(re:split("aaab","a\\Z",[]))),
+?line <<"a
+b">> = iolist_to_binary(join(re:split("a
+b","a\\Z",[trim]))),
+?line <<"a
+b">> = iolist_to_binary(join(re:split("a
+b","a\\Z",[{parts,2}]))),
+?line <<"a
+b">> = iolist_to_binary(join(re:split("a
+b","a\\Z",[]))),
+?line <<"a
+">> = iolist_to_binary(join(re:split("a
+b","b\\Z",[trim]))),
+?line <<"a
+:">> = iolist_to_binary(join(re:split("a
+b","b\\Z",[{parts,2}]))),
+?line <<"a
+:">> = iolist_to_binary(join(re:split("a
+b","b\\Z",[]))),
+?line <<"a
+">> = iolist_to_binary(join(re:split("a
+b","b\\Z",[trim]))),
+?line <<"a
+:">> = iolist_to_binary(join(re:split("a
+b","b\\Z",[{parts,2}]))),
+?line <<"a
+:">> = iolist_to_binary(join(re:split("a
+b","b\\Z",[]))),
+?line <<"a
+">> = iolist_to_binary(join(re:split("a
+b","b\\z",[trim]))),
+?line <<"a
+:">> = iolist_to_binary(join(re:split("a
+b","b\\z",[{parts,2}]))),
+?line <<"a
+:">> = iolist_to_binary(join(re:split("a
+b","b\\z",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","b\\z",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","b\\z",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","b\\z",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("a","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("a","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("abc","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("abc","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a-b","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("a-b","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("a-b","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("0-9","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("0-9","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("0-9","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a.b","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("a.b","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("a.b","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("5.6.7","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("5.6.7","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("5.6.7","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("the.quick.brown.fox","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("the.quick.brown.fox","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("the.quick.brown.fox","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a100.b200.300c","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("a100.b200.300c","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("a100.b200.300c","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("12-ab.1245","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("12-ab.1245","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("12-ab.1245","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[trim]))),
+?line <<"">> = iolist_to_binary(join(re:split("","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[{parts,
+ 2}]))),
+?line <<"">> = iolist_to_binary(join(re:split("","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[]))),
+?line <<".a">> = iolist_to_binary(join(re:split(".a","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[trim]))),
+?line <<".a">> = iolist_to_binary(join(re:split(".a","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[{parts,
+ 2}]))),
+?line <<".a">> = iolist_to_binary(join(re:split(".a","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[]))),
+?line <<"-a">> = iolist_to_binary(join(re:split("-a","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[trim]))),
+?line <<"-a">> = iolist_to_binary(join(re:split("-a","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[{parts,
+ 2}]))),
+?line <<"-a">> = iolist_to_binary(join(re:split("-a","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[]))),
+?line <<"a-">> = iolist_to_binary(join(re:split("a-","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[trim]))),
+?line <<"a-">> = iolist_to_binary(join(re:split("a-","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[{parts,
+ 2}]))),
+?line <<"a-">> = iolist_to_binary(join(re:split("a-","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[]))),
+?line <<"a.">> = iolist_to_binary(join(re:split("a.","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[trim]))),
+?line <<"a.">> = iolist_to_binary(join(re:split("a.","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[{parts,
+ 2}]))),
+?line <<"a.">> = iolist_to_binary(join(re:split("a.","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[]))),
+?line <<"a_b">> = iolist_to_binary(join(re:split("a_b","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[trim]))),
+?line <<"a_b">> = iolist_to_binary(join(re:split("a_b","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[{parts,
+ 2}]))),
+?line <<"a_b">> = iolist_to_binary(join(re:split("a_b","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[]))),
+?line <<"a.-">> = iolist_to_binary(join(re:split("a.-","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[trim]))),
+?line <<"a.-">> = iolist_to_binary(join(re:split("a.-","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[{parts,
+ 2}]))),
+?line <<"a.-">> = iolist_to_binary(join(re:split("a.-","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[]))),
+?line <<"a..">> = iolist_to_binary(join(re:split("a..","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[trim]))),
+?line <<"a..">> = iolist_to_binary(join(re:split("a..","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[{parts,
+ 2}]))),
+?line <<"a..">> = iolist_to_binary(join(re:split("a..","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[]))),
+?line <<"ab..bc">> = iolist_to_binary(join(re:split("ab..bc","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[trim]))),
+?line <<"ab..bc">> = iolist_to_binary(join(re:split("ab..bc","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[{parts,
+ 2}]))),
+?line <<"ab..bc">> = iolist_to_binary(join(re:split("ab..bc","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[]))),
+?line <<"the.quick.brown.fox-">> = iolist_to_binary(join(re:split("the.quick.brown.fox-","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[trim]))),
+?line <<"the.quick.brown.fox-">> = iolist_to_binary(join(re:split("the.quick.brown.fox-","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[{parts,
+ 2}]))),
+?line <<"the.quick.brown.fox-">> = iolist_to_binary(join(re:split("the.quick.brown.fox-","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[]))),
+?line <<"the.quick.brown.fox.">> = iolist_to_binary(join(re:split("the.quick.brown.fox.","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[trim]))),
+?line <<"the.quick.brown.fox.">> = iolist_to_binary(join(re:split("the.quick.brown.fox.","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[{parts,
+ 2}]))),
+?line <<"the.quick.brown.fox.">> = iolist_to_binary(join(re:split("the.quick.brown.fox.","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[]))),
+?line <<"the.quick.brown.fox_">> = iolist_to_binary(join(re:split("the.quick.brown.fox_","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[trim]))),
+?line <<"the.quick.brown.fox_">> = iolist_to_binary(join(re:split("the.quick.brown.fox_","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[{parts,
+ 2}]))),
+?line <<"the.quick.brown.fox_">> = iolist_to_binary(join(re:split("the.quick.brown.fox_","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[]))),
+?line <<"the.quick.brown.fox+">> = iolist_to_binary(join(re:split("the.quick.brown.fox+","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[trim]))),
+?line <<"the.quick.brown.fox+">> = iolist_to_binary(join(re:split("the.quick.brown.fox+","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[{parts,
+ 2}]))),
+?line <<"the.quick.brown.fox+">> = iolist_to_binary(join(re:split("the.quick.brown.fox+","^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$",[]))),
+?line <<":abcd">> = iolist_to_binary(join(re:split("alphabetabcd","(?>.*)(?<=(abcd|wxyz))",[trim]))),
+?line <<":abcd:">> = iolist_to_binary(join(re:split("alphabetabcd","(?>.*)(?<=(abcd|wxyz))",[{parts,
+ 2}]))),
+?line <<":abcd:">> = iolist_to_binary(join(re:split("alphabetabcd","(?>.*)(?<=(abcd|wxyz))",[]))),
+?line <<":wxyz">> = iolist_to_binary(join(re:split("endingwxyz","(?>.*)(?<=(abcd|wxyz))",[trim]))),
+?line <<":wxyz:">> = iolist_to_binary(join(re:split("endingwxyz","(?>.*)(?<=(abcd|wxyz))",[{parts,
+ 2}]))),
+?line <<":wxyz:">> = iolist_to_binary(join(re:split("endingwxyz","(?>.*)(?<=(abcd|wxyz))",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?>.*)(?<=(abcd|wxyz))",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?>.*)(?<=(abcd|wxyz))",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?>.*)(?<=(abcd|wxyz))",[]))),
+?line <<"a rather long string that doesn't end with one of them">> = iolist_to_binary(join(re:split("a rather long string that doesn't end with one of them","(?>.*)(?<=(abcd|wxyz))",[trim]))),
+?line <<"a rather long string that doesn't end with one of them">> = iolist_to_binary(join(re:split("a rather long string that doesn't end with one of them","(?>.*)(?<=(abcd|wxyz))",[{parts,
+ 2}]))),
+?line <<"a rather long string that doesn't end with one of them">> = iolist_to_binary(join(re:split("a rather long string that doesn't end with one of them","(?>.*)(?<=(abcd|wxyz))",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("word cat dog elephant mussel cow horse canary baboon snake shark otherword","word (?>(?:(?!otherword)[a-zA-Z0-9]+ ){0,30})otherword",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("word cat dog elephant mussel cow horse canary baboon snake shark otherword","word (?>(?:(?!otherword)[a-zA-Z0-9]+ ){0,30})otherword",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("word cat dog elephant mussel cow horse canary baboon snake shark otherword","word (?>(?:(?!otherword)[a-zA-Z0-9]+ ){0,30})otherword",[]))),
+?line <<"word cat dog elephant mussel cow horse canary baboon snake shark">> = iolist_to_binary(join(re:split("word cat dog elephant mussel cow horse canary baboon snake shark","word (?>(?:(?!otherword)[a-zA-Z0-9]+ ){0,30})otherword",[trim]))),
+?line <<"word cat dog elephant mussel cow horse canary baboon snake shark">> = iolist_to_binary(join(re:split("word cat dog elephant mussel cow horse canary baboon snake shark","word (?>(?:(?!otherword)[a-zA-Z0-9]+ ){0,30})otherword",[{parts,
+ 2}]))),
+?line <<"word cat dog elephant mussel cow horse canary baboon snake shark">> = iolist_to_binary(join(re:split("word cat dog elephant mussel cow horse canary baboon snake shark","word (?>(?:(?!otherword)[a-zA-Z0-9]+ ){0,30})otherword",[]))),
+?line <<"word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope">> = iolist_to_binary(join(re:split("word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope","word (?>[a-zA-Z0-9]+ ){0,30}otherword",[trim]))),
+?line <<"word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope">> = iolist_to_binary(join(re:split("word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope","word (?>[a-zA-Z0-9]+ ){0,30}otherword",[{parts,
+ 2}]))),
+?line <<"word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope">> = iolist_to_binary(join(re:split("word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope","word (?>[a-zA-Z0-9]+ ){0,30}otherword",[]))),
+?line <<"999">> = iolist_to_binary(join(re:split("999foo","(?<=\\d{3}(?!999))foo",[trim]))),
+?line <<"999:">> = iolist_to_binary(join(re:split("999foo","(?<=\\d{3}(?!999))foo",[{parts,
+ 2}]))),
+?line <<"999:">> = iolist_to_binary(join(re:split("999foo","(?<=\\d{3}(?!999))foo",[]))),
+?line <<"123999">> = iolist_to_binary(join(re:split("123999foo","(?<=\\d{3}(?!999))foo",[trim]))),
+?line <<"123999:">> = iolist_to_binary(join(re:split("123999foo","(?<=\\d{3}(?!999))foo",[{parts,
+ 2}]))),
+?line <<"123999:">> = iolist_to_binary(join(re:split("123999foo","(?<=\\d{3}(?!999))foo",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?<=\\d{3}(?!999))foo",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?<=\\d{3}(?!999))foo",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?<=\\d{3}(?!999))foo",[]))),
+?line <<"123abcfoo">> = iolist_to_binary(join(re:split("123abcfoo","(?<=\\d{3}(?!999))foo",[trim]))),
+?line <<"123abcfoo">> = iolist_to_binary(join(re:split("123abcfoo","(?<=\\d{3}(?!999))foo",[{parts,
+ 2}]))),
+?line <<"123abcfoo">> = iolist_to_binary(join(re:split("123abcfoo","(?<=\\d{3}(?!999))foo",[]))),
+?line <<"999">> = iolist_to_binary(join(re:split("999foo","(?<=(?!...999)\\d{3})foo",[trim]))),
+?line <<"999:">> = iolist_to_binary(join(re:split("999foo","(?<=(?!...999)\\d{3})foo",[{parts,
+ 2}]))),
+?line <<"999:">> = iolist_to_binary(join(re:split("999foo","(?<=(?!...999)\\d{3})foo",[]))),
+?line <<"123999">> = iolist_to_binary(join(re:split("123999foo","(?<=(?!...999)\\d{3})foo",[trim]))),
+?line <<"123999:">> = iolist_to_binary(join(re:split("123999foo","(?<=(?!...999)\\d{3})foo",[{parts,
+ 2}]))),
+?line <<"123999:">> = iolist_to_binary(join(re:split("123999foo","(?<=(?!...999)\\d{3})foo",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?<=(?!...999)\\d{3})foo",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?<=(?!...999)\\d{3})foo",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?<=(?!...999)\\d{3})foo",[]))),
+?line <<"123abcfoo">> = iolist_to_binary(join(re:split("123abcfoo","(?<=(?!...999)\\d{3})foo",[trim]))),
+?line <<"123abcfoo">> = iolist_to_binary(join(re:split("123abcfoo","(?<=(?!...999)\\d{3})foo",[{parts,
+ 2}]))),
+?line <<"123abcfoo">> = iolist_to_binary(join(re:split("123abcfoo","(?<=(?!...999)\\d{3})foo",[]))),
+?line <<"123abc">> = iolist_to_binary(join(re:split("123abcfoo","(?<=\\d{3}(?!999)...)foo",[trim]))),
+?line <<"123abc:">> = iolist_to_binary(join(re:split("123abcfoo","(?<=\\d{3}(?!999)...)foo",[{parts,
+ 2}]))),
+?line <<"123abc:">> = iolist_to_binary(join(re:split("123abcfoo","(?<=\\d{3}(?!999)...)foo",[]))),
+?line <<"123456">> = iolist_to_binary(join(re:split("123456foo","(?<=\\d{3}(?!999)...)foo",[trim]))),
+?line <<"123456:">> = iolist_to_binary(join(re:split("123456foo","(?<=\\d{3}(?!999)...)foo",[{parts,
+ 2}]))),
+?line <<"123456:">> = iolist_to_binary(join(re:split("123456foo","(?<=\\d{3}(?!999)...)foo",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?<=\\d{3}(?!999)...)foo",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?<=\\d{3}(?!999)...)foo",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?<=\\d{3}(?!999)...)foo",[]))),
+?line <<"123999foo">> = iolist_to_binary(join(re:split("123999foo","(?<=\\d{3}(?!999)...)foo",[trim]))),
+?line <<"123999foo">> = iolist_to_binary(join(re:split("123999foo","(?<=\\d{3}(?!999)...)foo",[{parts,
+ 2}]))),
+?line <<"123999foo">> = iolist_to_binary(join(re:split("123999foo","(?<=\\d{3}(?!999)...)foo",[]))),
+?line <<"123abc">> = iolist_to_binary(join(re:split("123abcfoo","(?<=\\d{3}...)(?<!999)foo",[trim]))),
+?line <<"123abc:">> = iolist_to_binary(join(re:split("123abcfoo","(?<=\\d{3}...)(?<!999)foo",[{parts,
+ 2}]))),
+?line <<"123abc:">> = iolist_to_binary(join(re:split("123abcfoo","(?<=\\d{3}...)(?<!999)foo",[]))),
+?line <<"123456">> = iolist_to_binary(join(re:split("123456foo","(?<=\\d{3}...)(?<!999)foo",[trim]))),
+?line <<"123456:">> = iolist_to_binary(join(re:split("123456foo","(?<=\\d{3}...)(?<!999)foo",[{parts,
+ 2}]))),
+?line <<"123456:">> = iolist_to_binary(join(re:split("123456foo","(?<=\\d{3}...)(?<!999)foo",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?<=\\d{3}...)(?<!999)foo",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?<=\\d{3}...)(?<!999)foo",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?<=\\d{3}...)(?<!999)foo",[]))),
+?line <<"123999foo">> = iolist_to_binary(join(re:split("123999foo","(?<=\\d{3}...)(?<!999)foo",[trim]))),
+?line <<"123999foo">> = iolist_to_binary(join(re:split("123999foo","(?<=\\d{3}...)(?<!999)foo",[{parts,
+ 2}]))),
+?line <<"123999foo">> = iolist_to_binary(join(re:split("123999foo","(?<=\\d{3}...)(?<!999)foo",[]))),
+?line <<":::abcd: xyz">> = iolist_to_binary(join(re:split("<a href=abcd xyz","<a[\\s]+href[\\s]*=[\\s]* # find <a href=
+ ([\\\"\\'])? # find single or double quote
+ (?(1) (.*?)\\1 | ([^\\s]+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space",[caseless,
+ dotall,
+ extended,
+ trim]))),
+?line <<":::abcd: xyz">> = iolist_to_binary(join(re:split("<a href=abcd xyz","<a[\\s]+href[\\s]*=[\\s]* # find <a href=
+ ([\\\"\\'])? # find single or double quote
+ (?(1) (.*?)\\1 | ([^\\s]+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space",[caseless,
+ dotall,
+ extended,
+ {parts,
+ 2}]))),
+?line <<":::abcd: xyz">> = iolist_to_binary(join(re:split("<a href=abcd xyz","<a[\\s]+href[\\s]*=[\\s]* # find <a href=
+ ([\\\"\\'])? # find single or double quote
+ (?(1) (.*?)\\1 | ([^\\s]+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space",[caseless,
+ dotall,
+ extended]))),
+?line <<":\":abcd xyz pqr:: cats">> = iolist_to_binary(join(re:split("<a href=\"abcd xyz pqr\" cats","<a[\\s]+href[\\s]*=[\\s]* # find <a href=
+ ([\\\"\\'])? # find single or double quote
+ (?(1) (.*?)\\1 | ([^\\s]+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space",[caseless,
+ dotall,
+ extended,
+ trim]))),
+?line <<":\":abcd xyz pqr:: cats">> = iolist_to_binary(join(re:split("<a href=\"abcd xyz pqr\" cats","<a[\\s]+href[\\s]*=[\\s]* # find <a href=
+ ([\\\"\\'])? # find single or double quote
+ (?(1) (.*?)\\1 | ([^\\s]+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space",[caseless,
+ dotall,
+ extended,
+ {parts,
+ 2}]))),
+?line <<":\":abcd xyz pqr:: cats">> = iolist_to_binary(join(re:split("<a href=\"abcd xyz pqr\" cats","<a[\\s]+href[\\s]*=[\\s]* # find <a href=
+ ([\\\"\\'])? # find single or double quote
+ (?(1) (.*?)\\1 | ([^\\s]+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space",[caseless,
+ dotall,
+ extended]))),
+?line <<":':abcd xyz pqr:: cats">> = iolist_to_binary(join(re:split("<a href='abcd xyz pqr' cats","<a[\\s]+href[\\s]*=[\\s]* # find <a href=
+ ([\\\"\\'])? # find single or double quote
+ (?(1) (.*?)\\1 | ([^\\s]+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space",[caseless,
+ dotall,
+ extended,
+ trim]))),
+?line <<":':abcd xyz pqr:: cats">> = iolist_to_binary(join(re:split("<a href='abcd xyz pqr' cats","<a[\\s]+href[\\s]*=[\\s]* # find <a href=
+ ([\\\"\\'])? # find single or double quote
+ (?(1) (.*?)\\1 | ([^\\s]+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space",[caseless,
+ dotall,
+ extended,
+ {parts,
+ 2}]))),
+?line <<":':abcd xyz pqr:: cats">> = iolist_to_binary(join(re:split("<a href='abcd xyz pqr' cats","<a[\\s]+href[\\s]*=[\\s]* # find <a href=
+ ([\\\"\\'])? # find single or double quote
+ (?(1) (.*?)\\1 | ([^\\s]+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space",[caseless,
+ dotall,
+ extended]))),
+?line <<":::abcd: xyz">> = iolist_to_binary(join(re:split("<a href=abcd xyz","<a\\s+href\\s*=\\s* # find <a href=
+ ([\"'])? # find single or double quote
+ (?(1) (.*?)\\1 | (\\S+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space",[caseless,
+ dotall,
+ extended,
+ trim]))),
+?line <<":::abcd: xyz">> = iolist_to_binary(join(re:split("<a href=abcd xyz","<a\\s+href\\s*=\\s* # find <a href=
+ ([\"'])? # find single or double quote
+ (?(1) (.*?)\\1 | (\\S+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space",[caseless,
+ dotall,
+ extended,
+ {parts,
+ 2}]))),
+?line <<":::abcd: xyz">> = iolist_to_binary(join(re:split("<a href=abcd xyz","<a\\s+href\\s*=\\s* # find <a href=
+ ([\"'])? # find single or double quote
+ (?(1) (.*?)\\1 | (\\S+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space",[caseless,
+ dotall,
+ extended]))),
+?line <<":\":abcd xyz pqr:: cats">> = iolist_to_binary(join(re:split("<a href=\"abcd xyz pqr\" cats","<a\\s+href\\s*=\\s* # find <a href=
+ ([\"'])? # find single or double quote
+ (?(1) (.*?)\\1 | (\\S+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space",[caseless,
+ dotall,
+ extended,
+ trim]))),
+?line <<":\":abcd xyz pqr:: cats">> = iolist_to_binary(join(re:split("<a href=\"abcd xyz pqr\" cats","<a\\s+href\\s*=\\s* # find <a href=
+ ([\"'])? # find single or double quote
+ (?(1) (.*?)\\1 | (\\S+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space",[caseless,
+ dotall,
+ extended,
+ {parts,
+ 2}]))),
+?line <<":\":abcd xyz pqr:: cats">> = iolist_to_binary(join(re:split("<a href=\"abcd xyz pqr\" cats","<a\\s+href\\s*=\\s* # find <a href=
+ ([\"'])? # find single or double quote
+ (?(1) (.*?)\\1 | (\\S+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space",[caseless,
+ dotall,
+ extended]))),
+?line <<":':abcd xyz pqr:: cats">> = iolist_to_binary(join(re:split("<a href = 'abcd xyz pqr' cats","<a\\s+href\\s*=\\s* # find <a href=
+ ([\"'])? # find single or double quote
+ (?(1) (.*?)\\1 | (\\S+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space",[caseless,
+ dotall,
+ extended,
+ trim]))),
+?line <<":':abcd xyz pqr:: cats">> = iolist_to_binary(join(re:split("<a href = 'abcd xyz pqr' cats","<a\\s+href\\s*=\\s* # find <a href=
+ ([\"'])? # find single or double quote
+ (?(1) (.*?)\\1 | (\\S+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space",[caseless,
+ dotall,
+ extended,
+ {parts,
+ 2}]))),
+?line <<":':abcd xyz pqr:: cats">> = iolist_to_binary(join(re:split("<a href = 'abcd xyz pqr' cats","<a\\s+href\\s*=\\s* # find <a href=
+ ([\"'])? # find single or double quote
+ (?(1) (.*?)\\1 | (\\S+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space",[caseless,
+ dotall,
+ extended]))),
+?line <<":::abcd: xyz">> = iolist_to_binary(join(re:split("<a href=abcd xyz","<a\\s+href(?>\\s*)=(?>\\s*) # find <a href=
+ ([\"'])? # find single or double quote
+ (?(1) (.*?)\\1 | (\\S+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space",[caseless,
+ dotall,
+ extended,
+ trim]))),
+?line <<":::abcd: xyz">> = iolist_to_binary(join(re:split("<a href=abcd xyz","<a\\s+href(?>\\s*)=(?>\\s*) # find <a href=
+ ([\"'])? # find single or double quote
+ (?(1) (.*?)\\1 | (\\S+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space",[caseless,
+ dotall,
+ extended,
+ {parts,
+ 2}]))),
+?line <<":::abcd: xyz">> = iolist_to_binary(join(re:split("<a href=abcd xyz","<a\\s+href(?>\\s*)=(?>\\s*) # find <a href=
+ ([\"'])? # find single or double quote
+ (?(1) (.*?)\\1 | (\\S+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space",[caseless,
+ dotall,
+ extended]))),
+?line <<":\":abcd xyz pqr:: cats">> = iolist_to_binary(join(re:split("<a href=\"abcd xyz pqr\" cats","<a\\s+href(?>\\s*)=(?>\\s*) # find <a href=
+ ([\"'])? # find single or double quote
+ (?(1) (.*?)\\1 | (\\S+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space",[caseless,
+ dotall,
+ extended,
+ trim]))),
+?line <<":\":abcd xyz pqr:: cats">> = iolist_to_binary(join(re:split("<a href=\"abcd xyz pqr\" cats","<a\\s+href(?>\\s*)=(?>\\s*) # find <a href=
+ ([\"'])? # find single or double quote
+ (?(1) (.*?)\\1 | (\\S+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space",[caseless,
+ dotall,
+ extended,
+ {parts,
+ 2}]))),
+?line <<":\":abcd xyz pqr:: cats">> = iolist_to_binary(join(re:split("<a href=\"abcd xyz pqr\" cats","<a\\s+href(?>\\s*)=(?>\\s*) # find <a href=
+ ([\"'])? # find single or double quote
+ (?(1) (.*?)\\1 | (\\S+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space",[caseless,
+ dotall,
+ extended]))),
+?line <<":':abcd xyz pqr:: cats">> = iolist_to_binary(join(re:split("<a href = 'abcd xyz pqr' cats","<a\\s+href(?>\\s*)=(?>\\s*) # find <a href=
+ ([\"'])? # find single or double quote
+ (?(1) (.*?)\\1 | (\\S+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space",[caseless,
+ dotall,
+ extended,
+ trim]))),
+?line <<":':abcd xyz pqr:: cats">> = iolist_to_binary(join(re:split("<a href = 'abcd xyz pqr' cats","<a\\s+href(?>\\s*)=(?>\\s*) # find <a href=
+ ([\"'])? # find single or double quote
+ (?(1) (.*?)\\1 | (\\S+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space",[caseless,
+ dotall,
+ extended,
+ {parts,
+ 2}]))),
+?line <<":':abcd xyz pqr:: cats">> = iolist_to_binary(join(re:split("<a href = 'abcd xyz pqr' cats","<a\\s+href(?>\\s*)=(?>\\s*) # find <a href=
+ ([\"'])? # find single or double quote
+ (?(1) (.*?)\\1 | (\\S+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space",[caseless,
+ dotall,
+ extended]))),
+?line <<":A:Z:B:::C:::D:::E:::F:::G">> = iolist_to_binary(join(re:split("ZABCDEFG","((Z)+|A)*",[trim]))),
+?line <<":A:Z:BCDEFG">> = iolist_to_binary(join(re:split("ZABCDEFG","((Z)+|A)*",[{parts,
+ 2}]))),
+?line <<":A:Z:B:::C:::D:::E:::F:::G:::">> = iolist_to_binary(join(re:split("ZABCDEFG","((Z)+|A)*",[]))),
+?line <<":A::B:::C:::D:::E:::F:::G">> = iolist_to_binary(join(re:split("ZABCDEFG","(Z()|A)*",[trim]))),
+?line <<":A::BCDEFG">> = iolist_to_binary(join(re:split("ZABCDEFG","(Z()|A)*",[{parts,
+ 2}]))),
+?line <<":A::B:::C:::D:::E:::F:::G:::">> = iolist_to_binary(join(re:split("ZABCDEFG","(Z()|A)*",[]))),
+?line <<":A:::B::::C::::D::::E::::F::::G">> = iolist_to_binary(join(re:split("ZABCDEFG","(Z(())|A)*",[trim]))),
+?line <<":A:::BCDEFG">> = iolist_to_binary(join(re:split("ZABCDEFG","(Z(())|A)*",[{parts,
+ 2}]))),
+?line <<":A:::B::::C::::D::::E::::F::::G::::">> = iolist_to_binary(join(re:split("ZABCDEFG","(Z(())|A)*",[]))),
+?line <<":A:B::C::D::E::F::G">> = iolist_to_binary(join(re:split("ZABCDEFG","((?>Z)+|A)*",[trim]))),
+?line <<":A:BCDEFG">> = iolist_to_binary(join(re:split("ZABCDEFG","((?>Z)+|A)*",[{parts,
+ 2}]))),
+?line <<":A:B::C::D::E::F::G::">> = iolist_to_binary(join(re:split("ZABCDEFG","((?>Z)+|A)*",[]))),
+?line <<"Z::::B::C::D::E::F::G">> = iolist_to_binary(join(re:split("ZABCDEFG","((?>)+|A)*",[trim]))),
+?line <<"Z::ABCDEFG">> = iolist_to_binary(join(re:split("ZABCDEFG","((?>)+|A)*",[{parts,
+ 2}]))),
+?line <<"Z::::B::C::D::E::F::G::">> = iolist_to_binary(join(re:split("ZABCDEFG","((?>)+|A)*",[]))),
+?line <<":b:b:b">> = iolist_to_binary(join(re:split("abbab","a*",[trim]))),
+?line <<":bbab">> = iolist_to_binary(join(re:split("abbab","a*",[{parts,
+ 2}]))),
+?line <<":b:b:b:">> = iolist_to_binary(join(re:split("abbab","a*",[]))),
+?line <<":bcde">> = iolist_to_binary(join(re:split("abcde","^[a-\\d]",[trim]))),
+?line <<":bcde">> = iolist_to_binary(join(re:split("abcde","^[a-\\d]",[{parts,
+ 2}]))),
+?line <<":bcde">> = iolist_to_binary(join(re:split("abcde","^[a-\\d]",[]))),
+?line <<":things">> = iolist_to_binary(join(re:split("-things","^[a-\\d]",[trim]))),
+?line <<":things">> = iolist_to_binary(join(re:split("-things","^[a-\\d]",[{parts,
+ 2}]))),
+?line <<":things">> = iolist_to_binary(join(re:split("-things","^[a-\\d]",[]))),
+?line <<":digit">> = iolist_to_binary(join(re:split("0digit","^[a-\\d]",[trim]))),
+?line <<":digit">> = iolist_to_binary(join(re:split("0digit","^[a-\\d]",[{parts,
+ 2}]))),
+?line <<":digit">> = iolist_to_binary(join(re:split("0digit","^[a-\\d]",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^[a-\\d]",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^[a-\\d]",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^[a-\\d]",[]))),
+?line <<"bcdef">> = iolist_to_binary(join(re:split("bcdef","^[a-\\d]",[trim]))),
+?line <<"bcdef">> = iolist_to_binary(join(re:split("bcdef","^[a-\\d]",[{parts,
+ 2}]))),
+?line <<"bcdef">> = iolist_to_binary(join(re:split("bcdef","^[a-\\d]",[]))),
+?line <<":bcde">> = iolist_to_binary(join(re:split("abcde","^[\\d-a]",[trim]))),
+?line <<":bcde">> = iolist_to_binary(join(re:split("abcde","^[\\d-a]",[{parts,
+ 2}]))),
+?line <<":bcde">> = iolist_to_binary(join(re:split("abcde","^[\\d-a]",[]))),
+?line <<":things">> = iolist_to_binary(join(re:split("-things","^[\\d-a]",[trim]))),
+?line <<":things">> = iolist_to_binary(join(re:split("-things","^[\\d-a]",[{parts,
+ 2}]))),
+?line <<":things">> = iolist_to_binary(join(re:split("-things","^[\\d-a]",[]))),
+?line <<":digit">> = iolist_to_binary(join(re:split("0digit","^[\\d-a]",[trim]))),
+?line <<":digit">> = iolist_to_binary(join(re:split("0digit","^[\\d-a]",[{parts,
+ 2}]))),
+?line <<":digit">> = iolist_to_binary(join(re:split("0digit","^[\\d-a]",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^[\\d-a]",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^[\\d-a]",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^[\\d-a]",[]))),
+?line <<"bcdef">> = iolist_to_binary(join(re:split("bcdef","^[\\d-a]",[trim]))),
+?line <<"bcdef">> = iolist_to_binary(join(re:split("bcdef","^[\\d-a]",[{parts,
+ 2}]))),
+?line <<"bcdef">> = iolist_to_binary(join(re:split("bcdef","^[\\d-a]",[]))),
+?line <<">:<">> = iolist_to_binary(join(re:split(">
+ <","[[:space:]]+",[trim]))),
+?line <<">:<">> = iolist_to_binary(join(re:split(">
+ <","[[:space:]]+",[{parts,2}]))),
+?line <<">:<">> = iolist_to_binary(join(re:split(">
+ <","[[:space:]]+",[]))),
+?line <<">:
+ <">> = iolist_to_binary(join(re:split(">
+ <","[[:blank:]]+",[trim]))),
+?line <<">:
+ <">> = iolist_to_binary(join(re:split(">
+ <","[[:blank:]]+",[{parts,2}]))),
+?line <<">:
+ <">> = iolist_to_binary(join(re:split(">
+ <","[[:blank:]]+",[]))),
+?line <<">: <">> = iolist_to_binary(join(re:split(">
+ <","[\\s]+",[trim]))),
+?line <<">: <">> = iolist_to_binary(join(re:split(">
+ <","[\\s]+",[{parts,2}]))),
+?line <<">: <">> = iolist_to_binary(join(re:split(">
+ <","[\\s]+",[]))),
+?line <<">: <">> = iolist_to_binary(join(re:split(">
+ <","\\s+",[trim]))),
+?line <<">: <">> = iolist_to_binary(join(re:split(">
+ <","\\s+",[{parts,2}]))),
+?line <<">: <">> = iolist_to_binary(join(re:split(">
+ <","\\s+",[]))),
+?line <<"ab">> = iolist_to_binary(join(re:split("ab","a b",[extended,
+ trim]))),
+?line <<"ab">> = iolist_to_binary(join(re:split("ab","a b",[extended,
+ {parts,
+ 2}]))),
+?line <<"ab">> = iolist_to_binary(join(re:split("ab","a b",[extended]))),
+?line <<"a
+:b">> = iolist_to_binary(join(re:split("a
+xb","(?!\\A)x",[multiline,trim]))),
+?line <<"a
+:b">> = iolist_to_binary(join(re:split("a
+xb","(?!\\A)x",[multiline,{parts,2}]))),
+?line <<"a
+:b">> = iolist_to_binary(join(re:split("a
+xb","(?!\\A)x",[multiline]))),
+?line <<"a
+xb">> = iolist_to_binary(join(re:split("a
+xb","(?!^)x",[multiline,trim]))),
+?line <<"a
+xb">> = iolist_to_binary(join(re:split("a
+xb","(?!^)x",[multiline,{parts,2}]))),
+?line <<"a
+xb">> = iolist_to_binary(join(re:split("a
+xb","(?!^)x",[multiline]))),
+?line <<"">> = iolist_to_binary(join(re:split("abcabcabc","abc\\Qabc\\Eabc",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abcabcabc","abc\\Qabc\\Eabc",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abcabcabc","abc\\Qabc\\Eabc",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc(*+|abc","abc\\Q(*+|\\Eabc",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc(*+|abc","abc\\Q(*+|\\Eabc",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc(*+|abc","abc\\Q(*+|\\Eabc",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc abcabc"," abc\\Q abc\\Eabc",[extended,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc abcabc"," abc\\Q abc\\Eabc",[extended,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc abcabc"," abc\\Q abc\\Eabc",[extended]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers"," abc\\Q abc\\Eabc",[extended,
+ trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers"," abc\\Q abc\\Eabc",[extended,
+ {parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers"," abc\\Q abc\\Eabc",[extended]))),
+?line <<"abcabcabc">> = iolist_to_binary(join(re:split("abcabcabc"," abc\\Q abc\\Eabc",[extended,
+ trim]))),
+?line <<"abcabcabc">> = iolist_to_binary(join(re:split("abcabcabc"," abc\\Q abc\\Eabc",[extended,
+ {parts,
+ 2}]))),
+?line <<"abcabcabc">> = iolist_to_binary(join(re:split("abcabcabc"," abc\\Q abc\\Eabc",[extended]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc#not comment
+ literal","abc#comment
+ \\Q#not comment
+ literal\\E",[extended,trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc#not comment
+ literal","abc#comment
+ \\Q#not comment
+ literal\\E",[extended,{parts,2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc#not comment
+ literal","abc#comment
+ \\Q#not comment
+ literal\\E",[extended]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc#not comment
+ literal","abc#comment
+ \\Q#not comment
+ literal",[extended,trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc#not comment
+ literal","abc#comment
+ \\Q#not comment
+ literal",[extended,{parts,2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc#not comment
+ literal","abc#comment
+ \\Q#not comment
+ literal",[extended]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc#not comment
+ literal","abc#comment
+ \\Q#not comment
+ literal\\E #more comment
+ ",[extended,trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc#not comment
+ literal","abc#comment
+ \\Q#not comment
+ literal\\E #more comment
+ ",[extended,{parts,2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc#not comment
+ literal","abc#comment
+ \\Q#not comment
+ literal\\E #more comment
+ ",[extended]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc#not comment
+ literal","abc#comment
+ \\Q#not comment
+ literal\\E #more comment",[extended,trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc#not comment
+ literal","abc#comment
+ \\Q#not comment
+ literal\\E #more comment",[extended,{parts,2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc#not comment
+ literal","abc#comment
+ \\Q#not comment
+ literal\\E #more comment",[extended]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc\\$xyz","\\Qabc\\$xyz\\E",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc\\$xyz","\\Qabc\\$xyz\\E",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc\\$xyz","\\Qabc\\$xyz\\E",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc$xyz","\\Qabc\\E\\$\\Qxyz\\E",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc$xyz","\\Qabc\\E\\$\\Qxyz\\E",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc$xyz","\\Qabc\\E\\$\\Qxyz\\E",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc","\\Aabc",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","\\Aabc",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","\\Aabc",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","\\Aabc",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","\\Aabc",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","\\Aabc",[]))),
+?line <<"xyzabc">> = iolist_to_binary(join(re:split("xyzabc","\\Aabc",[trim]))),
+?line <<"xyzabc">> = iolist_to_binary(join(re:split("xyzabc","\\Aabc",[{parts,
+ 2}]))),
+?line <<"xyzabc">> = iolist_to_binary(join(re:split("xyzabc","\\Aabc",[]))),
+?line <<":abc2xyzabc3">> = iolist_to_binary(join(re:split("abc1abc2xyzabc3","\\Aabc.",[trim]))),
+?line <<":abc2xyzabc3">> = iolist_to_binary(join(re:split("abc1abc2xyzabc3","\\Aabc.",[{parts,
+ 2}]))),
+?line <<":abc2xyzabc3">> = iolist_to_binary(join(re:split("abc1abc2xyzabc3","\\Aabc.",[]))),
+?line <<"::xyz">> = iolist_to_binary(join(re:split("abc1abc2xyzabc3","abc.",[trim]))),
+?line <<":abc2xyzabc3">> = iolist_to_binary(join(re:split("abc1abc2xyzabc3","abc.",[{parts,
+ 2}]))),
+?line <<"::xyz:">> = iolist_to_binary(join(re:split("abc1abc2xyzabc3","abc.",[]))),
+?line <<"X:Y">> = iolist_to_binary(join(re:split("XabcdY","a(?x: b c )d",[trim]))),
+?line <<"X:Y">> = iolist_to_binary(join(re:split("XabcdY","a(?x: b c )d",[{parts,
+ 2}]))),
+?line <<"X:Y">> = iolist_to_binary(join(re:split("XabcdY","a(?x: b c )d",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a(?x: b c )d",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a(?x: b c )d",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","a(?x: b c )d",[]))),
+?line <<"Xa b c d Y">> = iolist_to_binary(join(re:split("Xa b c d Y","a(?x: b c )d",[trim]))),
+?line <<"Xa b c d Y">> = iolist_to_binary(join(re:split("Xa b c d Y","a(?x: b c )d",[{parts,
+ 2}]))),
+?line <<"Xa b c d Y">> = iolist_to_binary(join(re:split("Xa b c d Y","a(?x: b c )d",[]))),
+?line <<"X:abc:Y">> = iolist_to_binary(join(re:split("XabcY","((?x)x y z | a b c)",[trim]))),
+?line <<"X:abc:Y">> = iolist_to_binary(join(re:split("XabcY","((?x)x y z | a b c)",[{parts,
+ 2}]))),
+?line <<"X:abc:Y">> = iolist_to_binary(join(re:split("XabcY","((?x)x y z | a b c)",[]))),
+?line <<"A:xyz:B">> = iolist_to_binary(join(re:split("AxyzB","((?x)x y z | a b c)",[trim]))),
+?line <<"A:xyz:B">> = iolist_to_binary(join(re:split("AxyzB","((?x)x y z | a b c)",[{parts,
+ 2}]))),
+?line <<"A:xyz:B">> = iolist_to_binary(join(re:split("AxyzB","((?x)x y z | a b c)",[]))),
+?line <<"X:Y">> = iolist_to_binary(join(re:split("XabCY","(?i)AB(?-i)C",[trim]))),
+?line <<"X:Y">> = iolist_to_binary(join(re:split("XabCY","(?i)AB(?-i)C",[{parts,
+ 2}]))),
+?line <<"X:Y">> = iolist_to_binary(join(re:split("XabCY","(?i)AB(?-i)C",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?i)AB(?-i)C",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?i)AB(?-i)C",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","(?i)AB(?-i)C",[]))),
+?line <<"XabcY">> = iolist_to_binary(join(re:split("XabcY","(?i)AB(?-i)C",[trim]))),
+?line <<"XabcY">> = iolist_to_binary(join(re:split("XabcY","(?i)AB(?-i)C",[{parts,
+ 2}]))),
+?line <<"XabcY">> = iolist_to_binary(join(re:split("XabcY","(?i)AB(?-i)C",[]))),
+?line <<":abC">> = iolist_to_binary(join(re:split("abCE","((?i)AB(?-i)C|D)E",[trim]))),
+?line <<":abC:">> = iolist_to_binary(join(re:split("abCE","((?i)AB(?-i)C|D)E",[{parts,
+ 2}]))),
+?line <<":abC:">> = iolist_to_binary(join(re:split("abCE","((?i)AB(?-i)C|D)E",[]))),
+?line <<":D">> = iolist_to_binary(join(re:split("DE","((?i)AB(?-i)C|D)E",[trim]))),
+?line <<":D:">> = iolist_to_binary(join(re:split("DE","((?i)AB(?-i)C|D)E",[{parts,
+ 2}]))),
+?line <<":D:">> = iolist_to_binary(join(re:split("DE","((?i)AB(?-i)C|D)E",[]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","((?i)AB(?-i)C|D)E",[trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","((?i)AB(?-i)C|D)E",[{parts,
+ 2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","((?i)AB(?-i)C|D)E",[]))),
+?line <<"abcE">> = iolist_to_binary(join(re:split("abcE","((?i)AB(?-i)C|D)E",[trim]))),
+?line <<"abcE">> = iolist_to_binary(join(re:split("abcE","((?i)AB(?-i)C|D)E",[{parts,
+ 2}]))),
+?line <<"abcE">> = iolist_to_binary(join(re:split("abcE","((?i)AB(?-i)C|D)E",[]))),
+?line <<"abCe">> = iolist_to_binary(join(re:split("abCe","((?i)AB(?-i)C|D)E",[trim]))),
+?line <<"abCe">> = iolist_to_binary(join(re:split("abCe","((?i)AB(?-i)C|D)E",[{parts,
+ 2}]))),
+?line <<"abCe">> = iolist_to_binary(join(re:split("abCe","((?i)AB(?-i)C|D)E",[]))),
+?line <<"dE">> = iolist_to_binary(join(re:split("dE","((?i)AB(?-i)C|D)E",[trim]))),
+?line <<"dE">> = iolist_to_binary(join(re:split("dE","((?i)AB(?-i)C|D)E",[{parts,
+ 2}]))),
+?line <<"dE">> = iolist_to_binary(join(re:split("dE","((?i)AB(?-i)C|D)E",[]))),
+?line <<"De">> = iolist_to_binary(join(re:split("De","((?i)AB(?-i)C|D)E",[trim]))),
+?line <<"De">> = iolist_to_binary(join(re:split("De","((?i)AB(?-i)C|D)E",[{parts,
+ 2}]))),
+?line <<"De">> = iolist_to_binary(join(re:split("De","((?i)AB(?-i)C|D)E",[]))),
+?line <<":abc">> = iolist_to_binary(join(re:split("abc123abc","(.*)\\d+\\1",[trim]))),
+?line <<":abc:">> = iolist_to_binary(join(re:split("abc123abc","(.*)\\d+\\1",[{parts,
+ 2}]))),
+?line <<":abc:">> = iolist_to_binary(join(re:split("abc123abc","(.*)\\d+\\1",[]))),
+?line <<"a:bc">> = iolist_to_binary(join(re:split("abc123bc","(.*)\\d+\\1",[trim]))),
+?line <<"a:bc:">> = iolist_to_binary(join(re:split("abc123bc","(.*)\\d+\\1",[{parts,
+ 2}]))),
+?line <<"a:bc:">> = iolist_to_binary(join(re:split("abc123bc","(.*)\\d+\\1",[]))),
+?line <<":abc">> = iolist_to_binary(join(re:split("abc123abc","(.*)\\d+\\1",[dotall,
+ trim]))),
+?line <<":abc:">> = iolist_to_binary(join(re:split("abc123abc","(.*)\\d+\\1",[dotall,
+ {parts,
+ 2}]))),
+?line <<":abc:">> = iolist_to_binary(join(re:split("abc123abc","(.*)\\d+\\1",[dotall]))),
+?line <<"a:bc">> = iolist_to_binary(join(re:split("abc123bc","(.*)\\d+\\1",[dotall,
+ trim]))),
+?line <<"a:bc:">> = iolist_to_binary(join(re:split("abc123bc","(.*)\\d+\\1",[dotall,
+ {parts,
+ 2}]))),
+?line <<"a:bc:">> = iolist_to_binary(join(re:split("abc123bc","(.*)\\d+\\1",[dotall]))),
+?line <<":abc:abc">> = iolist_to_binary(join(re:split("abc123abc","((.*))\\d+\\1",[trim]))),
+?line <<":abc:abc:">> = iolist_to_binary(join(re:split("abc123abc","((.*))\\d+\\1",[{parts,
+ 2}]))),
+?line <<":abc:abc:">> = iolist_to_binary(join(re:split("abc123abc","((.*))\\d+\\1",[]))),
+?line <<"a:bc:bc">> = iolist_to_binary(join(re:split("abc123bc","((.*))\\d+\\1",[trim]))),
+?line <<"a:bc:bc:">> = iolist_to_binary(join(re:split("abc123bc","((.*))\\d+\\1",[{parts,
+ 2}]))),
+?line <<"a:bc:bc:">> = iolist_to_binary(join(re:split("abc123bc","((.*))\\d+\\1",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a123::a123","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless,trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("a123::a123","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless,{parts,2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("a123::a123","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("a123:b342::abcd","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless,trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("a123:b342::abcd","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless,{parts,2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("a123:b342::abcd","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("a123:b342::324e:abcd","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless,trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("a123:b342::324e:abcd","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless,{parts,2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("a123:b342::324e:abcd","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("a123:ddde:b342::324e:abcd","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless,trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("a123:ddde:b342::324e:abcd","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless,{parts,2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("a123:ddde:b342::324e:abcd","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("a123:ddde:b342::324e:dcba:abcd","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless,trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("a123:ddde:b342::324e:dcba:abcd","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless,{parts,2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("a123:ddde:b342::324e:dcba:abcd","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("a123:ddde:9999:b342::324e:dcba:abcd","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless,trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("a123:ddde:9999:b342::324e:dcba:abcd","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless,{parts,2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("a123:ddde:9999:b342::324e:dcba:abcd","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless,trim]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless,{parts,2}]))),
+?line <<"*** Failers">> = iolist_to_binary(join(re:split("*** Failers","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless]))),
+?line <<"1:2:3:4:5:6:7:8">> = iolist_to_binary(join(re:split("1:2:3:4:5:6:7:8","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless,trim]))),
+?line <<"1:2:3:4:5:6:7:8">> = iolist_to_binary(join(re:split("1:2:3:4:5:6:7:8","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless,{parts,2}]))),
+?line <<"1:2:3:4:5:6:7:8">> = iolist_to_binary(join(re:split("1:2:3:4:5:6:7:8","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless]))),
+?line <<"a123:bce:ddde:9999:b342::324e:dcba:abcd">> = iolist_to_binary(join(re:split("a123:bce:ddde:9999:b342::324e:dcba:abcd","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless,trim]))),
+?line <<"a123:bce:ddde:9999:b342::324e:dcba:abcd">> = iolist_to_binary(join(re:split("a123:bce:ddde:9999:b342::324e:dcba:abcd","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless,{parts,2}]))),
+?line <<"a123:bce:ddde:9999:b342::324e:dcba:abcd">> = iolist_to_binary(join(re:split("a123:bce:ddde:9999:b342::324e:dcba:abcd","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless]))),
+?line <<"a123::9999:b342::324e:dcba:abcd">> = iolist_to_binary(join(re:split("a123::9999:b342::324e:dcba:abcd","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless,trim]))),
+?line <<"a123::9999:b342::324e:dcba:abcd">> = iolist_to_binary(join(re:split("a123::9999:b342::324e:dcba:abcd","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless,{parts,2}]))),
+?line <<"a123::9999:b342::324e:dcba:abcd">> = iolist_to_binary(join(re:split("a123::9999:b342::324e:dcba:abcd","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless]))),
+?line <<"abcde:2:3:4:5:6:7:8">> = iolist_to_binary(join(re:split("abcde:2:3:4:5:6:7:8","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless,trim]))),
+?line <<"abcde:2:3:4:5:6:7:8">> = iolist_to_binary(join(re:split("abcde:2:3:4:5:6:7:8","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless,{parts,2}]))),
+?line <<"abcde:2:3:4:5:6:7:8">> = iolist_to_binary(join(re:split("abcde:2:3:4:5:6:7:8","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless]))),
+?line <<"::1">> = iolist_to_binary(join(re:split("::1","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless,trim]))),
+?line <<"::1">> = iolist_to_binary(join(re:split("::1","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless,{parts,2}]))),
+?line <<"::1">> = iolist_to_binary(join(re:split("::1","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless]))),
+?line <<"abcd:fee0:123::">> = iolist_to_binary(join(re:split("abcd:fee0:123::","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless,trim]))),
+?line <<"abcd:fee0:123::">> = iolist_to_binary(join(re:split("abcd:fee0:123::","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless,{parts,2}]))),
+?line <<"abcd:fee0:123::">> = iolist_to_binary(join(re:split("abcd:fee0:123::","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless]))),
+?line <<":1">> = iolist_to_binary(join(re:split(":1","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless,trim]))),
+?line <<":1">> = iolist_to_binary(join(re:split(":1","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless,{parts,2}]))),
+?line <<":1">> = iolist_to_binary(join(re:split(":1","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless]))),
+?line <<"1:">> = iolist_to_binary(join(re:split("1:","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless,trim]))),
+?line <<"1:">> = iolist_to_binary(join(re:split("1:","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless,{parts,2}]))),
+?line <<"1:">> = iolist_to_binary(join(re:split("1:","^(?!:) # colon disallowed at start
+ (?: # start of item
+ (?: [0-9a-f]{1,4} | # 1-4 hex digits or
+ (?(1)0 | () ) ) # if null previously matched, fail; else null
+ : # followed by colon
+ ){1,7} # end item; 1-7 of them required
+ [0-9a-f]{1,4} $ # final hex number at end of string
+ (?(1)|.) # check that there was an empty component
+ ",[extended,caseless]))),
+?line <<"">> = iolist_to_binary(join(re:split("z","[z\\Qa-d]\\E]",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("z","[z\\Qa-d]\\E]",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("z","[z\\Qa-d]\\E]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a","[z\\Qa-d]\\E]",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","[z\\Qa-d]\\E]",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","[z\\Qa-d]\\E]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("-","[z\\Qa-d]\\E]",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("-","[z\\Qa-d]\\E]",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("-","[z\\Qa-d]\\E]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("d","[z\\Qa-d]\\E]",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("d","[z\\Qa-d]\\E]",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("d","[z\\Qa-d]\\E]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("]","[z\\Qa-d]\\E]",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("]","[z\\Qa-d]\\E]",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("]","[z\\Qa-d]\\E]",[]))),
+?line <<"*** F:ilers">> = iolist_to_binary(join(re:split("*** Failers","[z\\Qa-d]\\E]",[trim]))),
+?line <<"*** F:ilers">> = iolist_to_binary(join(re:split("*** Failers","[z\\Qa-d]\\E]",[{parts,
+ 2}]))),
+?line <<"*** F:ilers">> = iolist_to_binary(join(re:split("*** Failers","[z\\Qa-d]\\E]",[]))),
+?line <<"b">> = iolist_to_binary(join(re:split("b","[z\\Qa-d]\\E]",[trim]))),
+?line <<"b">> = iolist_to_binary(join(re:split("b","[z\\Qa-d]\\E]",[{parts,
+ 2}]))),
+?line <<"b">> = iolist_to_binary(join(re:split("b","[z\\Qa-d]\\E]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("z","[\\z\\C]",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("z","[\\z\\C]",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("z","[\\z\\C]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("C","[\\z\\C]",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("C","[\\z\\C]",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("C","[\\z\\C]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("M","\\M",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("M","\\M",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("M","\\M",[]))),
+?line <<"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","(a+)*b",[trim]))),
+?line <<"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","(a+)*b",[{parts,
+ 2}]))),
+?line <<"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","(a+)*b",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("REGular","(?i)reg(?:ul(?:[a�]|ae)r|ex)",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("REGular","(?i)reg(?:ul(?:[a�]|ae)r|ex)",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("REGular","(?i)reg(?:ul(?:[a�]|ae)r|ex)",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("regulaer","(?i)reg(?:ul(?:[a�]|ae)r|ex)",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("regulaer","(?i)reg(?:ul(?:[a�]|ae)r|ex)",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("regulaer","(?i)reg(?:ul(?:[a�]|ae)r|ex)",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("Regex","(?i)reg(?:ul(?:[a�]|ae)r|ex)",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("Regex","(?i)reg(?:ul(?:[a�]|ae)r|ex)",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("Regex","(?i)reg(?:ul(?:[a�]|ae)r|ex)",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("regul�r","(?i)reg(?:ul(?:[a�]|ae)r|ex)",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("regul�r","(?i)reg(?:ul(?:[a�]|ae)r|ex)",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("regul�r","(?i)reg(?:ul(?:[a�]|ae)r|ex)",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("�����","����[�-��-�]+",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("�����","����[�-��-�]+",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("�����","����[�-��-�]+",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("�����","����[�-��-�]+",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("�����","����[�-��-�]+",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("�����","����[�-��-�]+",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("�����","����[�-��-�]+",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("�����","����[�-��-�]+",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("�����","����[�-��-�]+",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("�����","����[�-��-�]+",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("�����","����[�-��-�]+",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("�����","����[�-��-�]+",[]))),
+?line <<"�XAZ">> = iolist_to_binary(join(re:split("�XAZXB","(?<=Z)X.",[trim]))),
+?line <<"�XAZ:">> = iolist_to_binary(join(re:split("�XAZXB","(?<=Z)X.",[{parts,
+ 2}]))),
+?line <<"�XAZ:">> = iolist_to_binary(join(re:split("�XAZXB","(?<=Z)X.",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("ab cd defg","ab cd (?x) de fg",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ab cd defg","ab cd (?x) de fg",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ab cd defg","ab cd (?x) de fg",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("ab cddefg","ab cd(?x) de fg",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("ab cddefg","ab cd(?x) de fg",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("ab cddefg","ab cd(?x) de fg",[]))),
+?line <<"** Failers">> = iolist_to_binary(join(re:split("** Failers","ab cd(?x) de fg",[trim]))),
+?line <<"** Failers">> = iolist_to_binary(join(re:split("** Failers","ab cd(?x) de fg",[{parts,
+ 2}]))),
+?line <<"** Failers">> = iolist_to_binary(join(re:split("** Failers","ab cd(?x) de fg",[]))),
+?line <<"abcddefg">> = iolist_to_binary(join(re:split("abcddefg","ab cd(?x) de fg",[trim]))),
+?line <<"abcddefg">> = iolist_to_binary(join(re:split("abcddefg","ab cd(?x) de fg",[{parts,
+ 2}]))),
+?line <<"abcddefg">> = iolist_to_binary(join(re:split("abcddefg","ab cd(?x) de fg",[]))),
+?line <<"foo:bar:X">> = iolist_to_binary(join(re:split("foobarX","(?<![^f]oo)(bar)",[trim]))),
+?line <<"foo:bar:X">> = iolist_to_binary(join(re:split("foobarX","(?<![^f]oo)(bar)",[{parts,
+ 2}]))),
+?line <<"foo:bar:X">> = iolist_to_binary(join(re:split("foobarX","(?<![^f]oo)(bar)",[]))),
+?line <<"** Failers">> = iolist_to_binary(join(re:split("** Failers","(?<![^f]oo)(bar)",[trim]))),
+?line <<"** Failers">> = iolist_to_binary(join(re:split("** Failers","(?<![^f]oo)(bar)",[{parts,
+ 2}]))),
+?line <<"** Failers">> = iolist_to_binary(join(re:split("** Failers","(?<![^f]oo)(bar)",[]))),
+?line <<"boobarX">> = iolist_to_binary(join(re:split("boobarX","(?<![^f]oo)(bar)",[trim]))),
+?line <<"boobarX">> = iolist_to_binary(join(re:split("boobarX","(?<![^f]oo)(bar)",[{parts,
+ 2}]))),
+?line <<"boobarX">> = iolist_to_binary(join(re:split("boobarX","(?<![^f]oo)(bar)",[]))),
+?line <<"off">> = iolist_to_binary(join(re:split("offX","(?<![^f])X",[trim]))),
+?line <<"off:">> = iolist_to_binary(join(re:split("offX","(?<![^f])X",[{parts,
+ 2}]))),
+?line <<"off:">> = iolist_to_binary(join(re:split("offX","(?<![^f])X",[]))),
+?line <<"** Failers">> = iolist_to_binary(join(re:split("** Failers","(?<![^f])X",[trim]))),
+?line <<"** Failers">> = iolist_to_binary(join(re:split("** Failers","(?<![^f])X",[{parts,
+ 2}]))),
+?line <<"** Failers">> = iolist_to_binary(join(re:split("** Failers","(?<![^f])X",[]))),
+?line <<"onyX">> = iolist_to_binary(join(re:split("onyX","(?<![^f])X",[trim]))),
+?line <<"onyX">> = iolist_to_binary(join(re:split("onyX","(?<![^f])X",[{parts,
+ 2}]))),
+?line <<"onyX">> = iolist_to_binary(join(re:split("onyX","(?<![^f])X",[]))),
+?line <<"ony">> = iolist_to_binary(join(re:split("onyX","(?<=[^f])X",[trim]))),
+?line <<"ony:">> = iolist_to_binary(join(re:split("onyX","(?<=[^f])X",[{parts,
+ 2}]))),
+?line <<"ony:">> = iolist_to_binary(join(re:split("onyX","(?<=[^f])X",[]))),
+?line <<"** Failers">> = iolist_to_binary(join(re:split("** Failers","(?<=[^f])X",[trim]))),
+?line <<"** Failers">> = iolist_to_binary(join(re:split("** Failers","(?<=[^f])X",[{parts,
+ 2}]))),
+?line <<"** Failers">> = iolist_to_binary(join(re:split("** Failers","(?<=[^f])X",[]))),
+?line <<"offX">> = iolist_to_binary(join(re:split("offX","(?<=[^f])X",[trim]))),
+?line <<"offX">> = iolist_to_binary(join(re:split("offX","(?<=[^f])X",[{parts,
+ 2}]))),
+?line <<"offX">> = iolist_to_binary(join(re:split("offX","(?<=[^f])X",[]))),
+?line <<"a
+:b
+:c">> = iolist_to_binary(join(re:split("a
+b
+c","^",[multiline,trim]))),
+?line <<"a
+:b
+c">> = iolist_to_binary(join(re:split("a
+b
+c","^",[multiline,{parts,2}]))),
+?line <<"a
+:b
+:c">> = iolist_to_binary(join(re:split("a
+b
+c","^",[multiline]))),
+?line <<"">> = iolist_to_binary(join(re:split("","^",[multiline,
+ trim]))),
+?line <<"">> = iolist_to_binary(join(re:split("","^",[multiline,
+ {parts,
+ 2}]))),
+?line <<"">> = iolist_to_binary(join(re:split("","^",[multiline]))),
+?line <<"A
+C
+:C">> = iolist_to_binary(join(re:split("A
+C
+C","(?<=C\\n)^",[multiline,trim]))),
+?line <<"A
+C
+:C">> = iolist_to_binary(join(re:split("A
+C
+C","(?<=C\\n)^",[multiline,{parts,2}]))),
+?line <<"A
+C
+:C">> = iolist_to_binary(join(re:split("A
+C
+C","(?<=C\\n)^",[multiline]))),
+?line <<":X">> = iolist_to_binary(join(re:split("bXaX","(?:(?(1)a|b)(X))+",[trim]))),
+?line <<":X:">> = iolist_to_binary(join(re:split("bXaX","(?:(?(1)a|b)(X))+",[{parts,
+ 2}]))),
+?line <<":X:">> = iolist_to_binary(join(re:split("bXaX","(?:(?(1)a|b)(X))+",[]))),
+?line <<":Y">> = iolist_to_binary(join(re:split("bXXaYYaY","(?:(?(1)\\1a|b)(X|Y))+",[trim]))),
+?line <<":Y:">> = iolist_to_binary(join(re:split("bXXaYYaY","(?:(?(1)\\1a|b)(X|Y))+",[{parts,
+ 2}]))),
+?line <<":Y:">> = iolist_to_binary(join(re:split("bXXaYYaY","(?:(?(1)\\1a|b)(X|Y))+",[]))),
+?line <<":X:YaXXaX">> = iolist_to_binary(join(re:split("bXYaXXaX","(?:(?(1)\\1a|b)(X|Y))+",[trim]))),
+?line <<":X:YaXXaX">> = iolist_to_binary(join(re:split("bXYaXXaX","(?:(?(1)\\1a|b)(X|Y))+",[{parts,
+ 2}]))),
+?line <<":X:YaXXaX">> = iolist_to_binary(join(re:split("bXYaXXaX","(?:(?(1)\\1a|b)(X|Y))+",[]))),
+?line <<"::::::::::X:XaYYaY">> = iolist_to_binary(join(re:split("bXXaYYaY","()()()()()()()()()(?:(?(10)\\10a|b)(X|Y))+",[trim]))),
+?line <<"::::::::::X:XaYYaY">> = iolist_to_binary(join(re:split("bXXaYYaY","()()()()()()()()()(?:(?(10)\\10a|b)(X|Y))+",[{parts,
+ 2}]))),
+?line <<"::::::::::X:XaYYaY">> = iolist_to_binary(join(re:split("bXXaYYaY","()()()()()()()()()(?:(?(10)\\10a|b)(X|Y))+",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc]","[[,abc,]+]",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc]","[[,abc,]+]",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc]","[[,abc,]+]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a,b]","[[,abc,]+]",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a,b]","[[,abc,]+]",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a,b]","[[,abc,]+]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("[a,b,c]","[[,abc,]+]",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("[a,b,c]","[[,abc,]+]",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("[a,b,c]","[[,abc,]+]",[]))),
+?line <<"A:B">> = iolist_to_binary(join(re:split("A B","(?-x: )",[extended,
+ trim]))),
+?line <<"A:B">> = iolist_to_binary(join(re:split("A B","(?-x: )",[extended,
+ {parts,
+ 2}]))),
+?line <<"A:B">> = iolist_to_binary(join(re:split("A B","(?-x: )",[extended]))),
+?line <<"A:B">> = iolist_to_binary(join(re:split("A # B","(?x)(?-x: \\s*#\\s*)",[trim]))),
+?line <<"A:B">> = iolist_to_binary(join(re:split("A # B","(?x)(?-x: \\s*#\\s*)",[{parts,
+ 2}]))),
+?line <<"A:B">> = iolist_to_binary(join(re:split("A # B","(?x)(?-x: \\s*#\\s*)",[]))),
+?line <<"** Failers">> = iolist_to_binary(join(re:split("** Failers","(?x)(?-x: \\s*#\\s*)",[trim]))),
+?line <<"** Failers">> = iolist_to_binary(join(re:split("** Failers","(?x)(?-x: \\s*#\\s*)",[{parts,
+ 2}]))),
+?line <<"** Failers">> = iolist_to_binary(join(re:split("** Failers","(?x)(?-x: \\s*#\\s*)",[]))),
+?line <<"#">> = iolist_to_binary(join(re:split("#","(?x)(?-x: \\s*#\\s*)",[trim]))),
+?line <<"#">> = iolist_to_binary(join(re:split("#","(?x)(?-x: \\s*#\\s*)",[{parts,
+ 2}]))),
+?line <<"#">> = iolist_to_binary(join(re:split("#","(?x)(?-x: \\s*#\\s*)",[]))),
+?line <<"A">> = iolist_to_binary(join(re:split("A #include","(?x-is)(?:(?-ixs) \\s*#\\s*) include",[trim]))),
+?line <<"A:">> = iolist_to_binary(join(re:split("A #include","(?x-is)(?:(?-ixs) \\s*#\\s*) include",[{parts,
+ 2}]))),
+?line <<"A:">> = iolist_to_binary(join(re:split("A #include","(?x-is)(?:(?-ixs) \\s*#\\s*) include",[]))),
+?line <<"** Failers">> = iolist_to_binary(join(re:split("** Failers","(?x-is)(?:(?-ixs) \\s*#\\s*) include",[trim]))),
+?line <<"** Failers">> = iolist_to_binary(join(re:split("** Failers","(?x-is)(?:(?-ixs) \\s*#\\s*) include",[{parts,
+ 2}]))),
+?line <<"** Failers">> = iolist_to_binary(join(re:split("** Failers","(?x-is)(?:(?-ixs) \\s*#\\s*) include",[]))),
+?line <<"A#include">> = iolist_to_binary(join(re:split("A#include","(?x-is)(?:(?-ixs) \\s*#\\s*) include",[trim]))),
+?line <<"A#include">> = iolist_to_binary(join(re:split("A#include","(?x-is)(?:(?-ixs) \\s*#\\s*) include",[{parts,
+ 2}]))),
+?line <<"A#include">> = iolist_to_binary(join(re:split("A#include","(?x-is)(?:(?-ixs) \\s*#\\s*) include",[]))),
+?line <<"A #Include">> = iolist_to_binary(join(re:split("A #Include","(?x-is)(?:(?-ixs) \\s*#\\s*) include",[trim]))),
+?line <<"A #Include">> = iolist_to_binary(join(re:split("A #Include","(?x-is)(?:(?-ixs) \\s*#\\s*) include",[{parts,
+ 2}]))),
+?line <<"A #Include">> = iolist_to_binary(join(re:split("A #Include","(?x-is)(?:(?-ixs) \\s*#\\s*) include",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaabbbb","a*b*\\w",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaabbbb","a*b*\\w",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaabbbb","a*b*\\w",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaaa","a*b*\\w",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaa","a*b*\\w",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaa","a*b*\\w",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a","a*b*\\w",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","a*b*\\w",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","a*b*\\w",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaabbbb","a*b?\\w",[trim]))),
+?line <<":bb">> = iolist_to_binary(join(re:split("aaabbbb","a*b?\\w",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("aaabbbb","a*b?\\w",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaaa","a*b?\\w",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaa","a*b?\\w",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaa","a*b?\\w",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a","a*b?\\w",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","a*b?\\w",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","a*b?\\w",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaabbbb","a*b{0,4}\\w",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaabbbb","a*b{0,4}\\w",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaabbbb","a*b{0,4}\\w",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaaa","a*b{0,4}\\w",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaa","a*b{0,4}\\w",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaa","a*b{0,4}\\w",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a","a*b{0,4}\\w",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","a*b{0,4}\\w",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","a*b{0,4}\\w",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaabbbb","a*b{0,}\\w",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaabbbb","a*b{0,}\\w",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaabbbb","a*b{0,}\\w",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaaa","a*b{0,}\\w",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaa","a*b{0,}\\w",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaa","a*b{0,}\\w",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a","a*b{0,}\\w",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","a*b{0,}\\w",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","a*b{0,}\\w",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("0a","a*\\d*\\w",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("0a","a*\\d*\\w",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("0a","a*\\d*\\w",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a","a*\\d*\\w",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","a*\\d*\\w",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","a*\\d*\\w",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a","a*b *\\w",[extended,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","a*b *\\w",[extended,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","a*b *\\w",[extended]))),
+?line <<"">> = iolist_to_binary(join(re:split("a","a*b#comment
+ *\\w",[extended,trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","a*b#comment
+ *\\w",[extended,{parts,2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","a*b#comment
+ *\\w",[extended]))),
+?line <<"">> = iolist_to_binary(join(re:split("a","a* b *\\w",[extended,
+ trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","a* b *\\w",[extended,
+ {parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","a* b *\\w",[extended]))),
+?line <<"::
+pqr">> = iolist_to_binary(join(re:split("abc=xyz\\
+pqr","^\\w+=.*(\\\\\\n.*)*",[trim]))),
+?line <<"::
+pqr">> = iolist_to_binary(join(re:split("abc=xyz\\
+pqr","^\\w+=.*(\\\\\\n.*)*",[{parts,2}]))),
+?line <<"::
+pqr">> = iolist_to_binary(join(re:split("abc=xyz\\
+pqr","^\\w+=.*(\\\\\\n.*)*",[]))),
+?line <<":abcd">> = iolist_to_binary(join(re:split("abcd:","(?=(\\w+))\\1:",[trim]))),
+?line <<":abcd:">> = iolist_to_binary(join(re:split("abcd:","(?=(\\w+))\\1:",[{parts,
+ 2}]))),
+?line <<":abcd:">> = iolist_to_binary(join(re:split("abcd:","(?=(\\w+))\\1:",[]))),
+?line <<":abcd">> = iolist_to_binary(join(re:split("abcd:","^(?=(\\w+))\\1:",[trim]))),
+?line <<":abcd:">> = iolist_to_binary(join(re:split("abcd:","^(?=(\\w+))\\1:",[{parts,
+ 2}]))),
+?line <<":abcd:">> = iolist_to_binary(join(re:split("abcd:","^(?=(\\w+))\\1:",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc","^\\Eabc",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","^\\Eabc",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","^\\Eabc",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a","^[\\Eabc]",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","^[\\Eabc]",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","^[\\Eabc]",[]))),
+?line <<"** Failers">> = iolist_to_binary(join(re:split("** Failers","^[\\Eabc]",[trim]))),
+?line <<"** Failers">> = iolist_to_binary(join(re:split("** Failers","^[\\Eabc]",[{parts,
+ 2}]))),
+?line <<"** Failers">> = iolist_to_binary(join(re:split("** Failers","^[\\Eabc]",[]))),
+?line <<"E">> = iolist_to_binary(join(re:split("E","^[\\Eabc]",[trim]))),
+?line <<"E">> = iolist_to_binary(join(re:split("E","^[\\Eabc]",[{parts,
+ 2}]))),
+?line <<"E">> = iolist_to_binary(join(re:split("E","^[\\Eabc]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("b","^[a-\\Ec]",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("b","^[a-\\Ec]",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("b","^[a-\\Ec]",[]))),
+?line <<"** Failers">> = iolist_to_binary(join(re:split("** Failers","^[a-\\Ec]",[trim]))),
+?line <<"** Failers">> = iolist_to_binary(join(re:split("** Failers","^[a-\\Ec]",[{parts,
+ 2}]))),
+?line <<"** Failers">> = iolist_to_binary(join(re:split("** Failers","^[a-\\Ec]",[]))),
+?line <<"-">> = iolist_to_binary(join(re:split("-","^[a-\\Ec]",[trim]))),
+?line <<"-">> = iolist_to_binary(join(re:split("-","^[a-\\Ec]",[{parts,
+ 2}]))),
+?line <<"-">> = iolist_to_binary(join(re:split("-","^[a-\\Ec]",[]))),
+?line <<"E">> = iolist_to_binary(join(re:split("E","^[a-\\Ec]",[trim]))),
+?line <<"E">> = iolist_to_binary(join(re:split("E","^[a-\\Ec]",[{parts,
+ 2}]))),
+?line <<"E">> = iolist_to_binary(join(re:split("E","^[a-\\Ec]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("b","^[a\\E\\E-\\Ec]",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("b","^[a\\E\\E-\\Ec]",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("b","^[a\\E\\E-\\Ec]",[]))),
+?line <<"** Failers">> = iolist_to_binary(join(re:split("** Failers","^[a\\E\\E-\\Ec]",[trim]))),
+?line <<"** Failers">> = iolist_to_binary(join(re:split("** Failers","^[a\\E\\E-\\Ec]",[{parts,
+ 2}]))),
+?line <<"** Failers">> = iolist_to_binary(join(re:split("** Failers","^[a\\E\\E-\\Ec]",[]))),
+?line <<"-">> = iolist_to_binary(join(re:split("-","^[a\\E\\E-\\Ec]",[trim]))),
+?line <<"-">> = iolist_to_binary(join(re:split("-","^[a\\E\\E-\\Ec]",[{parts,
+ 2}]))),
+?line <<"-">> = iolist_to_binary(join(re:split("-","^[a\\E\\E-\\Ec]",[]))),
+?line <<"E">> = iolist_to_binary(join(re:split("E","^[a\\E\\E-\\Ec]",[trim]))),
+?line <<"E">> = iolist_to_binary(join(re:split("E","^[a\\E\\E-\\Ec]",[{parts,
+ 2}]))),
+?line <<"E">> = iolist_to_binary(join(re:split("E","^[a\\E\\E-\\Ec]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("b","^[\\E\\Qa\\E-\\Qz\\E]+",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("b","^[\\E\\Qa\\E-\\Qz\\E]+",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("b","^[\\E\\Qa\\E-\\Qz\\E]+",[]))),
+?line <<"** Failers">> = iolist_to_binary(join(re:split("** Failers","^[\\E\\Qa\\E-\\Qz\\E]+",[trim]))),
+?line <<"** Failers">> = iolist_to_binary(join(re:split("** Failers","^[\\E\\Qa\\E-\\Qz\\E]+",[{parts,
+ 2}]))),
+?line <<"** Failers">> = iolist_to_binary(join(re:split("** Failers","^[\\E\\Qa\\E-\\Qz\\E]+",[]))),
+?line <<"-">> = iolist_to_binary(join(re:split("-","^[\\E\\Qa\\E-\\Qz\\E]+",[trim]))),
+?line <<"-">> = iolist_to_binary(join(re:split("-","^[\\E\\Qa\\E-\\Qz\\E]+",[{parts,
+ 2}]))),
+?line <<"-">> = iolist_to_binary(join(re:split("-","^[\\E\\Qa\\E-\\Qz\\E]+",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a","^[a\\Q]bc\\E]",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","^[a\\Q]bc\\E]",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","^[a\\Q]bc\\E]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("]","^[a\\Q]bc\\E]",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("]","^[a\\Q]bc\\E]",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("]","^[a\\Q]bc\\E]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("c","^[a\\Q]bc\\E]",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("c","^[a\\Q]bc\\E]",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("c","^[a\\Q]bc\\E]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a","^[a-\\Q\\E]",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","^[a-\\Q\\E]",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","^[a-\\Q\\E]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("-","^[a-\\Q\\E]",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("-","^[a-\\Q\\E]",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("-","^[a-\\Q\\E]",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("aaaa","^(a()*)*",[trim]))),
+?line <<":a::">> = iolist_to_binary(join(re:split("aaaa","^(a()*)*",[{parts,
+ 2}]))),
+?line <<":a::">> = iolist_to_binary(join(re:split("aaaa","^(a()*)*",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaaa","^(?:a(?:(?:))*)*",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaa","^(?:a(?:(?:))*)*",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaa","^(?:a(?:(?:))*)*",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("aaaa","^(a()+)+",[trim]))),
+?line <<":a::">> = iolist_to_binary(join(re:split("aaaa","^(a()+)+",[{parts,
+ 2}]))),
+?line <<":a::">> = iolist_to_binary(join(re:split("aaaa","^(a()+)+",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaaa","^(?:a(?:(?:))+)+",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaa","^(?:a(?:(?:))+)+",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaa","^(?:a(?:(?:))+)+",[]))),
+?line <<":a">> = iolist_to_binary(join(re:split("abbD","(a){0,3}(?(1)b|(c|))*D",[trim]))),
+?line <<":a::">> = iolist_to_binary(join(re:split("abbD","(a){0,3}(?(1)b|(c|))*D",[{parts,
+ 2}]))),
+?line <<":a::">> = iolist_to_binary(join(re:split("abbD","(a){0,3}(?(1)b|(c|))*D",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("ccccD","(a){0,3}(?(1)b|(c|))*D",[trim]))),
+?line <<":::">> = iolist_to_binary(join(re:split("ccccD","(a){0,3}(?(1)b|(c|))*D",[{parts,
+ 2}]))),
+?line <<":::">> = iolist_to_binary(join(re:split("ccccD","(a){0,3}(?(1)b|(c|))*D",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("D","(a){0,3}(?(1)b|(c|))*D",[trim]))),
+?line <<":::">> = iolist_to_binary(join(re:split("D","(a){0,3}(?(1)b|(c|))*D",[{parts,
+ 2}]))),
+?line <<":::">> = iolist_to_binary(join(re:split("D","(a){0,3}(?(1)b|(c|))*D",[]))),
+?line <<"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","(a|)*\\d",[trim]))),
+?line <<"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","(a|)*\\d",[{parts,
+ 2}]))),
+?line <<"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","(a|)*\\d",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4","(a|)*\\d",[trim]))),
+?line <<"::">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4","(a|)*\\d",[{parts,
+ 2}]))),
+?line <<"::">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4","(a|)*\\d",[]))),
+?line <<"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","(?>a|)*\\d",[trim]))),
+?line <<"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","(?>a|)*\\d",[{parts,
+ 2}]))),
+?line <<"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","(?>a|)*\\d",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4","(?>a|)*\\d",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4","(?>a|)*\\d",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4","(?>a|)*\\d",[]))),
+?line <<"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","(?:a|)*\\d",[trim]))),
+?line <<"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","(?:a|)*\\d",[{parts,
+ 2}]))),
+?line <<"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","(?:a|)*\\d",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4","(?:a|)*\\d",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4","(?:a|)*\\d",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4","(?:a|)*\\d",[]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","\\Z",[trim]))),
+?line <<"abc:">> = iolist_to_binary(join(re:split("abc","\\Z",[{parts,
+ 2}]))),
+?line <<"abc:">> = iolist_to_binary(join(re:split("abc","\\Z",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc","^(?s)(?>.*)(?<!\\n)",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","^(?s)(?>.*)(?<!\\n)",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","^(?s)(?>.*)(?<!\\n)",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abc","^(?s)(?>.*)(?<!\\n)",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","^(?s)(?>.*)(?<!\\n)",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("abc","^(?s)(?>.*)(?<!\\n)",[]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","^(?![^\\n]*\\n\\z)",[trim]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","^(?![^\\n]*\\n\\z)",[{parts,
+ 2}]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","^(?![^\\n]*\\n\\z)",[]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","^(?![^\\n]*\\n\\z)",[trim]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","^(?![^\\n]*\\n\\z)",[{parts,
+ 2}]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","^(?![^\\n]*\\n\\z)",[]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","\\z(?<!\\n)",[trim]))),
+?line <<"abc:">> = iolist_to_binary(join(re:split("abc","\\z(?<!\\n)",[{parts,
+ 2}]))),
+?line <<"abc:">> = iolist_to_binary(join(re:split("abc","\\z(?<!\\n)",[]))),
+?line <<"abc">> = iolist_to_binary(join(re:split("abc","\\z(?<!\\n)",[trim]))),
+?line <<"abc:">> = iolist_to_binary(join(re:split("abc","\\z(?<!\\n)",[{parts,
+ 2}]))),
+?line <<"abc:">> = iolist_to_binary(join(re:split("abc","\\z(?<!\\n)",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("abcd","(.*(.)?)*",[trim]))),
+?line <<":::">> = iolist_to_binary(join(re:split("abcd","(.*(.)?)*",[{parts,
+ 2}]))),
+?line <<":::">> = iolist_to_binary(join(re:split("abcd","(.*(.)?)*",[]))),
+?line <<"a:::b:::c:::d">> = iolist_to_binary(join(re:split("abcd","( (A | (?(1)0|) )* )",[extended,
+ trim]))),
+?line <<"a:::bcd">> = iolist_to_binary(join(re:split("abcd","( (A | (?(1)0|) )* )",[extended,
+ {parts,
+ 2}]))),
+?line <<"a:::b:::c:::d:::">> = iolist_to_binary(join(re:split("abcd","( (A | (?(1)0|) )* )",[extended]))),
+?line <<"a:::b:::c:::d">> = iolist_to_binary(join(re:split("abcd","( ( (?(1)0|) )* )",[extended,
+ trim]))),
+?line <<"a:::bcd">> = iolist_to_binary(join(re:split("abcd","( ( (?(1)0|) )* )",[extended,
+ {parts,
+ 2}]))),
+?line <<"a:::b:::c:::d:::">> = iolist_to_binary(join(re:split("abcd","( ( (?(1)0|) )* )",[extended]))),
+?line <<"a::b::c::d">> = iolist_to_binary(join(re:split("abcd","( (?(1)0|)* )",[extended,
+ trim]))),
+?line <<"a::bcd">> = iolist_to_binary(join(re:split("abcd","( (?(1)0|)* )",[extended,
+ {parts,
+ 2}]))),
+?line <<"a::b::c::d::">> = iolist_to_binary(join(re:split("abcd","( (?(1)0|)* )",[extended]))),
+?line <<"">> = iolist_to_binary(join(re:split("a]","[[:abcd:xyz]]",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a]","[[:abcd:xyz]]",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a]","[[:abcd:xyz]]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split(":]","[[:abcd:xyz]]",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split(":]","[[:abcd:xyz]]",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split(":]","[[:abcd:xyz]]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("a","[abc[:x\\]pqr]",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","[abc[:x\\]pqr]",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("a","[abc[:x\\]pqr]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("[","[abc[:x\\]pqr]",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("[","[abc[:x\\]pqr]",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("[","[abc[:x\\]pqr]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split(":","[abc[:x\\]pqr]",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split(":","[abc[:x\\]pqr]",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split(":","[abc[:x\\]pqr]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("]","[abc[:x\\]pqr]",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("]","[abc[:x\\]pqr]",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("]","[abc[:x\\]pqr]",[]))),
+?line <<"">> = iolist_to_binary(join(re:split("p","[abc[:x\\]pqr]",[trim]))),
+?line <<":">> = iolist_to_binary(join(re:split("p","[abc[:x\\]pqr]",[{parts,
+ 2}]))),
+?line <<":">> = iolist_to_binary(join(re:split("p","[abc[:x\\]pqr]",[]))),
+ok.
diff --git a/lib/stdlib/test/run_pcre_tests.erl b/lib/stdlib/test/run_pcre_tests.erl
new file mode 100644
index 0000000000..0ef3986918
--- /dev/null
+++ b/lib/stdlib/test/run_pcre_tests.erl
@@ -0,0 +1,1201 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(run_pcre_tests).
+
+-compile(export_all).
+
+test(RootDir) ->
+ put(verbose,false),
+ erts_debug:set_internal_state(available_internal_state,true),
+ io:format("oldlimit: ~p~n",[ erts_debug:set_internal_state(re_loop_limit,10)]),
+ Testfiles0 = ["testoutput1", "testoutput2", "testoutput3", "testoutput4",
+ "testoutput5", "testoutput6", "testoutput10"],
+ Testfiles = [ filename:join([RootDir,FN]) || FN <- Testfiles0 ],
+ Res = [ begin io:format("~s~n",[X]), t(X) end || X <- Testfiles ],
+ io:format("limit was: ~p~n",[ erts_debug:set_internal_state(re_loop_limit,default)]),
+ Res2 = Res ++ [ begin io:format("~s~n",[X]), t(X) end || X <- Testfiles ],
+ erts_debug:set_internal_state(available_internal_state,false),
+ put(verbose,true),
+ Res2.
+t(OneFile) ->
+ t(OneFile,infinite).
+t(OneFile,Num) ->
+ {ok,Bin} = file:read_file(OneFile),
+ Lines = splitfile(0,Bin,1),
+ Structured = stru(Lines),
+ put(error_limit,Num),
+ put(skipped,0),
+ Res =
+ [test(Structured,true,index),
+ test(Structured,false,index),
+ test(Structured,true,binary),
+ test(Structured,false,binary),
+ test(Structured,true,list),
+ test(Structured,false,list)],
+ {lists:sum(Res),length(Structured)*6,get(skipped)}.
+
+
+pick_exec_options([{exec_option,Opt}|T]) ->
+ {O,E} = pick_exec_options(T),
+ {O,[Opt|E]};
+pick_exec_options([unicode|T]) ->
+ {O,E} = pick_exec_options(T),
+ {[unicode|O],[unicode|E]};
+pick_exec_options([Opt|T]) ->
+ {O,E} = pick_exec_options(T),
+ {[Opt|O],E};
+pick_exec_options([]) ->
+ {[],[]}.
+
+test([],_,_) ->
+ 0;
+test([{RE,Line,Options0,Tests}|T],PreCompile,XMode) ->
+ %io:format("."),
+ %case RE of <<>> -> io:format("Empty re:~w~n",[Line]); _ -> ok end,
+ {Options,ExecOptions} = pick_exec_options(Options0),
+ {Cres, Xopt} = case PreCompile of
+ true ->
+ {re:compile(RE,Options),[]};
+ _ ->
+ {{ok,RE},Options}
+ end,
+ case Cres of
+ {ok,P} ->
+ %erlang:display({testrun,RE,P,Tests,ExecOptions,Xopt,XMode}),
+ case (catch testrun(RE,P,Tests,ExecOptions,Xopt,XMode)) of
+ N when is_integer(N) ->
+ N + test(T,PreCompile,XMode);
+ limit ->
+ io:format("Error limit reached.~n"),
+ 1;
+ skip ->
+ case get(skipped) of
+ N when is_integer(N) ->
+ put(skipped,N+1);
+ _ ->
+ put(skipped,1)
+ end,
+ test(T,PreCompile,XMode)
+ end;
+ {error,Err} ->
+ io:format("Compile error(~w): ~w~n",[Line,Err]),
+ case get(error_limit) of
+ infinite -> 1 + test(T,PreCompile,XMode);
+ X ->
+ case X-1 of
+ Y when Y =< 0 ->
+ io:format("Error limit reached.~n"),
+ 1;
+ Y ->
+ put(error_limit,Y),
+ 1 + test(T,PreCompile,XMode)
+ end
+ end
+ end.
+
+loopexec(_,_,X,Y,_,_) when X > Y ->
+ {match,[]};
+loopexec(P,Chal,X,Y,Unicode,Xopt) ->
+ %io:format("~p~n",[X]),
+ case re:run(Chal,P,[{offset,X}]++Xopt) of
+ nomatch ->
+ %io:format(" re:exec(~p,~p,[{offset,~p}]) -> ~p~n",
+ % [P,Chal,X,no]),
+ {match,[]};
+ %loopexec(P,Chal,X+1,Y);
+ {match,[{A,B}|More]} ->
+ %io:format(" re:exec(~p,~p,[{offset,~p}]) -> ~p~n",
+ % [P,Chal,X,{match,[{A,B}|More]}]),
+ {match,Rest} =
+ case B>0 of
+ true ->
+ loopexec(P,Chal,A+B,Y,Unicode,Xopt);
+ false ->
+ {match,M} = case re:run(Chal,P,[{offset,X},notempty,anchored]++Xopt) of
+ nomatch ->
+ {match,[]};
+ {match,Other} ->
+ {match,fixup(Chal,Other,0)}
+ end,
+ NewA = forward(Chal,A,1,Unicode),
+ {match,MM} = loopexec(P,Chal,NewA,Y,Unicode,Xopt),
+ {match,M ++ MM}
+ end,
+ {match,fixup(Chal,[{A,B}|More],0)++Rest}
+ end.
+
+forward(_Chal,A,0,_) ->
+ A;
+forward(_Chal,A,N,false) ->
+ A+N;
+forward(Chal,A,N,true) ->
+ <<_:A/binary,Tl/binary>> = Chal,
+ Forw = case Tl of
+ <<1:1,1:1,0:1,_:5,_/binary>> ->
+ 2;
+ <<1:1,1:1,1:1,0:1,_:4,_/binary>> ->
+ 3;
+ <<1:1,1:1,1:1,1:1,0:1,_:3,_/binary>> ->
+ 4;
+ _ ->
+ 1
+ end,
+ %io:format("Forward ~p~n",[Forw]),
+ forward(Chal,A+Forw,N-1,true).
+
+contains_eightbit(<<>>) ->
+ false;
+contains_eightbit(<<X:8,_/binary>>) when X >= 128 ->
+ true;
+contains_eightbit(<<_,R/binary>>) ->
+ contains_eightbit(R).
+
+clean_duplicates([],_) ->
+ [];
+clean_duplicates([{X,Y}|T],L) ->
+ case lists:keymember(X,1,L) of
+ true ->
+ clean_duplicates(T,L);
+ false ->
+ [{X,Y}|clean_duplicates(T,L)]
+ end;
+clean_duplicates([bsr_anycrlf|T],L) ->
+ case (lists:member(bsr_anycrlf,L) orelse lists:member(bsr_unicode,L)) of
+ true ->
+ clean_duplicates(T,L);
+ false ->
+ [bsr_anycrlf|clean_duplicates(T,L)]
+ end;
+clean_duplicates([bsr_unicode|T],L) ->
+ case (lists:member(bsr_anycrlf,L) orelse lists:member(bsr_unicode,L)) of
+ true ->
+ clean_duplicates(T,L);
+ false ->
+ [bsr_unicode|clean_duplicates(T,L)]
+ end;
+clean_duplicates([X|T],L) ->
+ case lists:member(X,L) of
+ true ->
+ clean_duplicates(T,L);
+ false ->
+ [X|clean_duplicates(T,L)]
+ end.
+
+
+global_fixup(_,nomatch) ->
+ nomatch;
+global_fixup(P,{match,M}) ->
+ {match,lists:flatten(global_fixup2(P,M))}.
+
+global_fixup2(_,[]) ->
+ [];
+global_fixup2(P,[H|T]) ->
+ [gfixup_one(P,0,H)|global_fixup2(P,T)].
+
+gfixup_one(_,_,[]) ->
+ [];
+gfixup_one(P,I,[{Start,Len}|T]) ->
+ <<_:Start/binary,R:Len/binary,_/binary>> = P,
+ [{I,R}|gfixup_one(P,I+1,T)].
+
+
+press([]) ->
+ [];
+press([H|T]) ->
+ H++press(T).
+
+testrun(_,_,[],_,_,_) ->
+ 0;
+testrun(RE,P,[{Chal,Line,ExecOpt,Responses}|T],EO,Xopt0,XMode) ->
+ Xopt = clean_duplicates(Xopt0,ExecOpt),
+
+ case lists:keymember(newline,1,Xopt) of
+ true ->
+ info("skipping inconsistent newlines "
+ "when compiling and running in one go (~p)~n",
+ [Line]),
+ throw(skip);
+ false ->
+ ok
+ end,
+
+ Res =
+ case lists:member(g,EO) of
+ true ->
+ case XMode of
+ binary ->
+ case re:run(Chal,P,ExecOpt++Xopt++
+ [global,{capture,all,binary}]) of
+ nomatch ->
+ nomatch;
+ {match, Reslist} ->
+ {match,press([bfix(R)|| R <- Reslist])}
+ end;
+ list ->
+ case re:run(Chal,P,ExecOpt++Xopt++
+ [global,{capture,all,list}]) of
+ nomatch ->
+ nomatch;
+ {match, Reslist} ->
+ UFix = lists:member(unicode,EO),
+ {match,press([bfix([if UFix =:= true -> list_to_utf8(L); true -> list_to_binary(L) end || L <- R]) || R <- Reslist])}
+ end;
+ index ->
+ case re:run(Chal,P,ExecOpt++Xopt++[global]) of
+ nomatch ->
+ nomatch;
+ {match, Reslist} ->
+ {match,press([fixup(Chal,R,0) || R <- Reslist])}
+ end
+ end;
+ false ->
+ case EO -- [accept_nonascii] of
+ EO ->
+ case contains_eightbit(Chal) of
+ true ->
+ info("skipping 8bit without LANG (~p)~n",
+ [Line]),
+ throw(skip);
+ false ->
+ ok
+ end,
+
+ case XMode of
+ binary ->
+ case re:run(Chal,P,ExecOpt++Xopt++
+ [{capture,all,binary}]) of
+ nomatch ->
+ nomatch;
+ {match, Reslist} ->
+ {match,bfix(Reslist)}
+ end;
+ list ->
+ case re:run(Chal,P,ExecOpt++Xopt++
+ [{capture,all,list}]) of
+ nomatch ->
+ nomatch;
+ {match, Reslist} ->
+ UFix = lists:member(unicode,EO),
+ {match,bfix([if
+ UFix =:= true -> list_to_utf8(L);
+ true -> list_to_binary(L)
+ end || L <- Reslist])}
+ end;
+ index ->
+ case re:run(Chal,P,ExecOpt++Xopt) of
+ nomatch ->
+ nomatch;
+ {match, Reslist} ->
+ {match,fixup(Chal,Reslist,0)}
+ end
+ end;
+ _LesserOpt ->
+ case XMode of
+ binary ->
+ case re:run(Chal,P,ExecOpt++Xopt++
+ [{capture,all,binary}]) of
+ nomatch ->
+ nomatch;
+ {match, Reslist} ->
+ {match,bfix(Reslist)}
+ end;
+ list ->
+ case re:run(Chal,P,ExecOpt++Xopt++
+ [{capture,all,list}]) of
+ nomatch ->
+ nomatch;
+ {match, Reslist} ->
+ %io:format("re:run(~w,~w,~w) -> ~w~n",[Chal,P,ExecOpt++Xopt++
+ % [{capture,all,list}],Reslist]),
+ UFix = lists:member(unicode,EO),
+ {match,bfix([if
+ UFix =:= true -> list_to_utf8(L);
+ true -> list_to_binary(L)
+ end || L <- Reslist])}
+ end;
+ index ->
+ case re:run(Chal,P,ExecOpt++Xopt) of
+ nomatch ->
+ nomatch;
+ {match, Reslist} ->
+ {match,fixup(Chal,Reslist,0)}
+ end
+ end
+ end
+ end,
+ case compare_sloppy(Res,Responses) of
+ true ->
+ testrun(RE,P,T,EO,Xopt0,XMode);
+ false ->
+ io:format("FAIL(~w): re = ~p, ~nmatched against = ~p(~w), ~nwith options = ~p. ~nexpected = ~p, ~ngot = ~p~n",
+ [Line,RE,Chal,binary_to_list(Chal),{ExecOpt,EO,Xopt},Responses,Res]),
+ case get(error_limit) of
+ infinite -> ok;
+ X ->
+ case X-1 of
+ Y when Y =< 0 ->
+ throw(limit);
+ Y ->
+ put(error_limit,Y)
+ end
+ end,
+ 1
+ end.
+compare_sloppy({A,L1},{A,L2}) ->
+ compare_sloppy(L1,L2);
+compare_sloppy(A,A) ->
+ true;
+compare_sloppy([{X,Y}|T1],[{X,Y}|T2]) ->
+ compare_sloppy(T1,T2);
+compare_sloppy([{X,[Y,_]}|T1],[{X,Y}|T2]) ->
+ compare_sloppy(T1,T2);
+compare_sloppy([{X,[_,Y]}|T1],[{X,Y}|T2]) ->
+ compare_sloppy(T1,T2);
+compare_sloppy(_,_) ->
+ false.
+
+bfix(RL) ->
+ bfix(RL,0).
+bfix([],_) ->
+ [];
+bfix([<<>>|T],N) ->
+ [{N,[<<>>,<<"<unset>">>]}|bfix(T,N+1)]; % indeterminable
+bfix([H|T],N) ->
+ [{N,H}|bfix(T,N+1)].
+
+fixup(List,Any,Any2) when is_list(List)->
+ fixup(unicode:characters_to_binary(List,unicode,unicode),Any,Any2);
+fixup(_,[],_) ->
+ [];
+fixup(Bin,[{-1,0}|T],N) ->
+ [{N,<<"<unset>">>}|fixup(Bin,T,N+1)];
+fixup(Bin,[{X,Y}|T],N) ->
+ <<_:X/binary,Res:Y/binary,_/binary>> = Bin,
+ [{N,Res}|fixup(Bin,T,N+1)].
+
+splitfile(N,Bin,_Line) when N >= size(Bin) ->
+ [];
+splitfile(N,Bin,Line) ->
+ {Res,NewN} = pickline(N,N,Bin),
+ case emptyline(Res) of
+ true ->
+ [{Line,<<>>}|splitfile(NewN,Bin,Line+1)];
+ false ->
+ [{Line,Res}|splitfile(NewN,Bin,Line+1)]
+ end.
+
+emptyline(<<>>) ->
+ true;
+emptyline(<<$ ,R/binary>>) ->
+ emptyline(R);
+emptyline(_) ->
+ false.
+pickline(Start,Stop,Bin) when Stop >= size(Bin) ->
+ Len = Stop - Start - 1,
+ <<_:Start/binary,Res:Len/binary,_/binary>> = Bin,
+ {Res,Stop};
+
+pickline(Start,Stop,Bin) ->
+ %erlang:display({Start,Stop,size(Bin)}),
+ <<_:Stop/binary,Ch,_/binary>> = Bin,
+ case Ch of
+ $\n ->
+ Len = Stop - Start,
+ <<_:Start/binary,Res:Len/binary,_/binary>> = Bin,
+ {Res,Stop+1};
+ _ ->
+ pickline(Start,Stop+1,Bin)
+ end.
+
+skip_until_empty([]) ->
+ [];
+skip_until_empty([{_,<<>>}|T]) ->
+ T;
+skip_until_empty([{_,_}|T]) ->
+ skip_until_empty(T).
+
+skip_debug([{_,<<$-,_/binary>>}|Con]) ->
+ Con;
+skip_debug([_|T]) ->
+ skip_debug(T);
+skip_debug([]) ->
+ [].
+
+skip_extra_info([{_,<<$ ,$ ,$ ,_/binary>>}=H|Con]) ->
+ [H|Con];
+skip_extra_info([{_,<<>>}|Con]) ->
+ Con;
+skip_extra_info([_|T]) ->
+ skip_extra_info(T);
+skip_extra_info([]) ->
+ [].
+
+stru([]) ->
+ [];
+stru([{_,<<>>}|T]) ->
+ stru(T);
+stru([{Line,<<Ch,Re0/binary>>}|T0]) ->
+ {T,Re} = find_rest_re(Ch,[{Line,Re0}|T0]),
+ %io:format("DBG: ~p~n",[Re]),
+ {NewRe,<< Ch, Options/binary >>} = end_of_re(Ch,Re),
+ case interpret_options_x(backstrip(frontstrip(Options)),NewRe) of
+ {Olist,<<>>} ->
+ case T of
+ [{_,<<$-,_/binary>>}|Con] ->
+ %Debug output, we skip those
+ %io:format("Skipping debug (~w)~n",[Line]),
+ TmpT = skip_debug(Con),
+ {NewT,Matches} = stru2(TmpT),
+ [{NewRe,Line,Olist,Matches}|stru(NewT)];
+ [{_,<<$C,$a,$p,$t,$u,$r,$i,$n,$g,_/binary>>}|_] ->
+ NewT0 = skip_extra_info(T),
+ {NewT,Matches} = stru2(NewT0),
+ [{NewRe,Line,Olist,Matches}|stru(NewT)];
+ [{_,<<Bla,_/binary>>}|_] when Bla =/= $ ->
+ %io:format("Skipping blabla (~w)~n",[Line]),
+ NewT = skip_until_empty(T),
+ stru(NewT);
+ _ ->
+ {NewT,Matches} = stru2(T),
+ %erlang:display({NewRe,Line,Olist,Matches}),
+ Matches1 = case lists:member(unicode,Olist) of
+ true ->
+ Matches ++
+ [ {unicode:characters_to_list(E1,unicode),E2,E3,E4} ||
+ {E1,E2,E3,E4} <- Matches];
+ false ->
+ Matches
+ end,
+ %erlang:display({NewRe,Line,Olist,Matches1}),
+ [{NewRe,Line,Olist,Matches1}|stru(NewT)]
+ end;
+ {_,Rest} ->
+%% case T of
+%% [{_,<<Bla,_/binary>>}|_] when Bla =/= $ ->
+%% io:format("Skipping blabla (~w)~n",[Line]);
+%% _ ->
+%% ok
+%% end,
+ NewT = skip_until_empty(T),
+ %{NewT,_Matches} = stru2(T),
+ info("Skipping options ~s for now (~w)~n",[binary_to_list(Rest),Line]),
+ case NewT of
+ [{Li,_}|_] ->
+ info("Skip to line ~p~n",[Li]);
+ _ ->
+ ok
+ end,
+ stru(NewT)
+ end.
+
+contains_lang_sens(<<>>) ->
+ false;
+contains_lang_sens(<<$\\,$W,_/binary>>) ->
+ true;
+contains_lang_sens(<<$\\,$w,_/binary>>) ->
+ true;
+contains_lang_sens(<<$\\,$b,_/binary>>) ->
+ true;
+contains_lang_sens(<<_,R/binary>>) ->
+ contains_lang_sens(R).
+
+
+interpret_options_x(Options,RE) ->
+ {O,R} = interpret_options(Options),
+ case (contains_lang_sens(RE) or lists:member(caseless,O)) of
+ false ->
+ {[{exec_option,accept_nonascii}|O],R};
+ true ->
+ case lists:member(unicode,O) of
+ true ->
+ {[{exec_option,accept_nonascii}|O],R};
+ false ->
+ {O,R}
+ end
+ end.
+tr_option($i) ->
+ [caseless];
+tr_option($I) ->
+ [];
+tr_option($B) ->
+ [];
+tr_option($Z) ->
+ [];
+tr_option($x) ->
+ [extended];
+tr_option($s) ->
+ [dotall];
+tr_option($m) ->
+ [multiline];
+tr_option($J) ->
+ [dupnames];
+tr_option($N) ->
+ [no_auto_capture];
+tr_option($8) ->
+ [unicode];
+tr_option($g) ->
+ [{exec_option,g}];
+tr_option(_) ->
+ false.
+
+interpret_options(<<$<,Rest0/binary>>) ->
+ {Option,Rest} = pinch_cr(Rest0),
+ {Olist,NRest} = interpret_options(Rest),
+ {[Option | Olist], NRest};
+interpret_options(<<$L,$f,$r,$_,$F,$R,Rest/binary>>) ->
+ info("Accepting (and ignoring) french locale~n",[]),
+ {Olist,NRest} = interpret_options(Rest),
+ {[{exec_option, accept_nonascii}|Olist],NRest};
+interpret_options(<<Ch,Rest/binary>>) ->
+ {Olist,NRest} = interpret_options(Rest),
+ case tr_option(Ch) of
+ false ->
+ {Olist,<<Ch,NRest/binary>>};
+ Option ->
+ {Option ++ Olist, NRest}
+ end;
+interpret_options(<<>>) ->
+ {[],<<>>}.
+
+find_unsupported([{not_supported,X}|T]) ->
+ [X | find_unsupported(T)];
+find_unsupported([_|T]) ->
+ find_unsupported(T);
+find_unsupported([]) ->
+ [].
+
+backslash_end(<<>>) ->
+ false;
+backslash_end(<<$\\>>) ->
+ true;
+backslash_end(<<_>>) ->
+ false;
+backslash_end(<<_,R/binary>>) ->
+ backslash_end(R).
+
+%stru2([<<$ ,$ ,$ ,$ , $*,$*,$*,$ ,_/binary>> | T]) ->
+% stru2(T);
+stru2([{Line,<<$ ,Rest/binary>>} | T]) ->
+ % A challenge
+ case (catch responses(T)) of
+ {NewT,Rlist} ->
+ {NewNewT,StrList} = stru2(NewT),
+ %% Hack...
+ FS = case backstrip(frontstrip(Rest)) of
+ <<"\\">> ->
+ %% Single backslash is to be considered
+ %% an empty line in challenge
+ <<>>;
+ OFS ->
+ case backslash_end(OFS) of
+ true ->
+ <<OFS/binary,$ >>;
+ _ ->
+ OFS
+ end
+ end,
+ {ExecOpts,NFS} = escape(FS),
+ case find_unsupported(ExecOpts) of
+ [] ->
+ {NewNewT,[{NFS,Line,ExecOpts,
+ case
+ Rlist of nomatch -> nomatch;
+ RR -> {match,RR}
+ end} | StrList]};
+ UList ->
+ info("WARNING(~w): the exec-option(s) ~p are unsupported, skipping challenge.~n",[Line,UList]),
+ {NewNewT,StrList}
+ end;
+ fail ->
+ NewT = skip_until_empty(T),
+ {NewT,[]}
+ end;
+
+stru2(X) ->
+ {X,[]}.
+%responses([<< $ ,$ ,$ ,$ ,$*,$*,$*,$ ,_/binary>>|T]) ->
+% responses(T);
+responses([{_Line,<< X:2/binary,$:,$ ,Resp/binary>>}|T]) ->
+ {NT,R2} = responses(T),
+ NX=list_to_integer(binary_to_list(frontstrip(X))),
+ {NT,[{NX,escape2(Resp)} | R2]};
+responses([{_Line,<< X:3/binary,$:,$ ,Resp/binary>>}|T]) ->
+ {NT,R2} = responses(T),
+ NX=list_to_integer(binary_to_list(frontstrip(X))),
+ {NT,[{NX,escape2(Resp)} | R2]};
+responses([{_Line,<<$N,$o,$ ,$m,$a,$t,$c,$h,_/binary>>}|T]) ->
+ {T,nomatch};
+responses([{Line,<<$ ,No,Ch,_/binary>>}|T]) when No >= $0, No =< $9, Ch >= $A, Ch =< $Z ->
+ info("Skipping strange debug response at line ~p~n",[Line]),
+ responses(T);
+responses([{Line,<<$ ,$ ,Ch,_/binary>>}|T]) when Ch =:= $G; Ch =:= $C ->
+ info("Skipping stranger debug response at line ~p~n",[Line]),
+ responses(T);
+responses([{Line,<<C,_/binary>>=X}|_]) when C =/= $ ->
+ info("Offending response line(~w)! ~p~n",[Line,X]),
+ throw(fail);
+responses(X) ->
+ {X,[]}.
+
+
+end_of_re(_,<<>>) ->
+ {<<>>,<<>>};
+end_of_re(C,<<C,_Rest/binary>> = R) ->
+ {<<>>,R};
+end_of_re(C,<<$\\,C,Rest/binary>>) ->
+ {Sub,Rest2} = end_of_re(C,Rest),
+ {<<C,Sub/binary>>,Rest2};
+end_of_re(C,<<Ch,Rest/binary>>) ->
+ {Sub,Rest2} = end_of_re(C,Rest),
+ {<<Ch,Sub/binary>>,Rest2}.
+
+frontstrip(<<>>) ->
+ <<>>;
+frontstrip(<< $ ,Rest/binary>>) ->
+ frontstrip(Rest);
+frontstrip(Bin) ->
+ Bin.
+
+backstrip(<<>>) ->
+ <<>>;
+backstrip(<<$ >>) ->
+ <<>>;
+backstrip(<<X,Rest/binary>>) ->
+ case backstrip(Rest) of
+ Rest ->
+ <<X,Rest/binary>>;
+ Other ->
+ NRest = backstrip(Other),
+ <<X,NRest/binary>>
+ end.
+
+find_rest_re(_,[]) ->
+ {<<>>,<<>>};
+find_rest_re(Ch,[{_,H}|T]) ->
+ case end_of_re(Ch,H) of
+ {_,<<>>} ->
+ {NewT,Rest} = find_rest_re(Ch,T),
+ {NewT,<<H/binary,$\n,Rest/binary>>};
+ {_,_} ->
+ {T,H}
+ end.
+
+eopt($A) ->
+ [anchored];
+eopt($B) ->
+ [notbol];
+eopt(X) ->
+ [{not_supported,X}].
+
+pinch_cr(<<$c,$r,$>,Rest/binary>>) ->
+ {{newline,cr},Rest};
+pinch_cr(<<$l,$f,$>,Rest/binary>>) ->
+ {{newline,lf},Rest};
+pinch_cr(<<$c,$r,$l,$f,$>,Rest/binary>>) ->
+ {{newline,crlf},Rest};
+pinch_cr(<<$C,$R,$>,Rest/binary>>) ->
+ {{newline,cr},Rest};
+pinch_cr(<<$L,$F,$>,Rest/binary>>) ->
+ {{newline,lf},Rest};
+pinch_cr(<<$C,$R,$L,$F,$>,Rest/binary>>) ->
+ {{newline,crlf},Rest};
+pinch_cr(<<$a,$n,$y,$c,$r,$l,$f,$>,Rest/binary>>) ->
+ {{newline,anycrlf},Rest};
+pinch_cr(<<$b,$s,$r,$_,$a,$n,$y,$c,$r,$l,$f,$>,Rest/binary>>) ->
+ {bsr_anycrlf,Rest};
+pinch_cr(<<$b,$s,$r,$_,$u,$n,$i,$c,$o,$d,$e,$>,Rest/binary>>) ->
+ {bsr_unicode,Rest};
+pinch_cr(<<$a,$n,$y,$>,Rest/binary>>) ->
+ {{newline,any},Rest};
+pinch_cr(<<$A,$N,$Y,$>,Rest/binary>>) ->
+ {{newline,any},Rest};
+pinch_cr(Other) ->
+ case splitby($>,Other,<<>>) of
+ {Unk,Rest} ->
+ {{not_supported,{newline,Unk}},Rest};
+ no ->
+ {{not_supported,$<},Other}
+ end.
+
+splitby(_,<<>>,_) ->
+ no;
+splitby(Ch,<<Ch,Rest/binary>>,Acc) ->
+ {Acc,Rest};
+splitby(Ch,<<OCh,Rest/binary>>,Acc) ->
+ splitby(Ch,Rest,<<Acc/binary,OCh>>).
+
+
+escape(<<>>) ->
+ {[],<<>>};
+escape(<<$\\, Ch, Rest/binary>>) when Ch >= $A, Ch =< $Z; Ch =:= $? ->
+ %Options in the string...
+ NewOpts = eopt(Ch),
+ {MoreOpts,Tail} = escape(Rest),
+ {NewOpts ++ MoreOpts,Tail};
+escape(<<$\\, $<, Rest/binary>>) ->
+ %CR Options in the string...
+ {NewOpt,NewRest} = pinch_cr(Rest),
+ {MoreOpts,Tail} = escape(NewRest),
+ {[NewOpt|MoreOpts],Tail};
+escape(<<$\\, Ch, Rest/binary>>) ->
+ {C,NR} = case single_esc(Ch) of
+ no ->
+ case multi_esc(<<Ch,Rest/binary>>) of
+ {CharBin,NewRest} ->
+ {CharBin,NewRest};
+ no ->
+ {<<$\\>>,<<Ch,Rest/binary>>}
+ end;
+ CCC ->
+ %erlang:display({escape,CCC}),
+ {<<CCC>>,Rest}
+ end,
+ {MoreOpts,Tail} = escape(NR),
+ {MoreOpts,<<C/binary,Tail/binary>>};
+%escape(<<$\\,Rest/binary>>) ->
+% escape(<<Rest/binary>>);
+escape(<<Ch,Rest/binary>>) ->
+ {X,RR} = escape(<<Rest/binary>>),
+ {X,<<Ch,RR/binary>>};
+escape(Any) ->
+ {[],Any}.
+escape2(<<>>) ->
+ <<>>;
+escape2(<<$\\, Ch, Rest/binary>>) ->
+ {C,NR} = case multi_esc(<<Ch,Rest/binary>>) of
+ {CharBin,NewRest} ->
+ {CharBin,NewRest};
+ no ->
+ {<<$\\>>,<<Ch,Rest/binary>>}
+ end,
+ Tail = escape2(NR),
+ <<C/binary,Tail/binary>>;
+escape2(<<Ch,Rest/binary>>) ->
+ RR = escape2(<<Rest/binary>>),
+ <<Ch,RR/binary>>;
+escape2(Any) ->
+ Any.
+
+
+trx(N) when ((N >= $0) and (N =< $9)) ->
+ N - $0;
+trx($A) -> 10;
+trx($B) -> 11;
+trx($C) -> 12;
+trx($D) -> 13;
+trx($E) -> 14;
+trx($F) -> 15;
+trx($a) -> 10;
+trx($b) -> 11;
+trx($c) -> 12;
+trx($d) -> 13;
+trx($e) -> 14;
+trx($f) -> 15.
+
+
+int_to_utf8(I) when I =< 16#7F ->
+ <<I>>;
+int_to_utf8(I) when I =< 16#7FF ->
+ B2 = I band 16#3f,
+ B1 = (I bsr 6) band 16#1f,
+ <<1:1,1:1,0:1,B1:5,1:1,0:1,B2:6>>;
+int_to_utf8(I) when I =< 16#FFFF ->
+ B3 = I band 16#3f,
+ B2 = (I bsr 6) band 16#3f,
+ B1 = (I bsr 12) band 16#f,
+ <<1:1,1:1,1:1,0:1,B1:4,1:1,0:1,B2:6,1:1,0:1,B3:6>>;
+int_to_utf8(I) when I =< 16#10FFFF ->
+ B4 = I band 16#3f,
+ B3 = (I bsr 6) band 16#3f,
+ B2 = (I bsr 12) band 16#3f,
+ B1 = (I bsr 18) band 16#7,
+ <<1:1,1:1,1:1,1:1,0:1,B1:3,1:1,0:1,B2:6,1:1,0:1,B3:6,1:1,0:1,B4:6>>;
+int_to_utf8(_) ->
+ exit(unsupported_utf8).
+
+list_to_utf8(L) when is_list(L); is_binary(L) ->
+ iolist_to_binary([int_to_utf8(I) || I <- L]);
+list_to_utf8({Tag,_,_}) when Tag =:= incomplete ; Tag =:= error ->
+ throw(skip).
+
+multi_esc(<<M,N,O,Rest/binary>>)
+ when M >= $0, M =< $7, N >= $0, N =< $7, O >= $0, O =< $7 ->
+ Cha = ((M - $0) bsl 6) bor ((N - $0) bsl 3) bor (O - $0),
+ {<<Cha>>,Rest};
+multi_esc(<<N,O,Rest/binary>>)
+ when N >= $0, N =< $7, O >= $0, O =< $7 ->
+ Cha = ((N - $0) bsl 3) bor (O - $0),
+ {<<Cha>>,Rest};
+multi_esc(<<O,Rest/binary>>)
+ when O >= $0, O =< $7 ->
+ Cha = (O - $0),
+ {<<Cha>>,Rest};
+
+
+multi_esc(<<$x,${,N,O,$},Rest/binary>>)
+ when ((((N >= $0) and (N =< $9)) or ((N >= $A) and (N =< $F)) or
+ ((N >= $a) and (N =< $f))) and
+ (((O >= $0) and (O =< $9)) or ((O >= $A) and (O =< $F)) or
+ ((O >= $a) and (O =< $f)))) ->
+ Cha = (trx(N) bsl 4) bor trx(O),
+ {int_to_utf8(Cha),Rest};
+multi_esc(<<$x,${,N,O,P,$},Rest/binary>>)
+ when ((((N >= $0) and (N =< $9)) or ((N >= $A) and (N =< $F)) or
+ ((N >= $a) and (N =< $f))) and
+ (((O >= $0) and (O =< $9)) or ((O >= $A) and (O =< $F)) or
+ ((O >= $a) and (O =< $f)))and
+ (((P >= $0) and (P =< $9)) or ((P >= $A) and (P =< $F)) or
+ ((P >= $a) and (P =< $f)))) ->
+ Cha = (trx(N) bsl 8) bor (trx(O) bsl 4) bor trx(P),
+ {int_to_utf8(Cha),Rest};
+multi_esc(<<$x,${,N,O,P,Q,$},Rest/binary>>)
+ when ((((N >= $0) and (N =< $9)) or ((N >= $A) and (N =< $F)) or
+ ((N >= $a) and (N =< $f))) and
+ (((O >= $0) and (O =< $9)) or ((O >= $A) and (O =< $F)) or
+ ((O >= $a) and (O =< $f))) and
+ (((P >= $0) and (P =< $9)) or ((P >= $A) and (P =< $F)) or
+ ((P >= $a) and (P =< $f))) and
+ (((Q >= $0) and (Q =< $9)) or ((Q >= $A) and (Q =< $F)) or
+ ((Q >= $a) and (Q =< $f)))) ->
+ Cha = (trx(N) bsl 12) bor (trx(O) bsl 8) bor (trx(P) bsl 4) bor trx(Q),
+ {int_to_utf8(Cha),Rest};
+multi_esc(<<$x,${,N,O,P,Q,R,$},Rest/binary>>)
+ when ((((N >= $0) and (N =< $9)) or ((N >= $A) and (N =< $F)) or
+ ((N >= $a) and (N =< $f))) and
+ (((O >= $0) and (O =< $9)) or ((O >= $A) and (O =< $F)) or
+ ((O >= $a) and (O =< $f))) and
+ (((P >= $0) and (P =< $9)) or ((P >= $A) and (P =< $F)) or
+ ((P >= $a) and (P =< $f))) and
+ (((Q >= $0) and (Q =< $9)) or ((Q >= $A) and (Q =< $F)) or
+ ((Q >= $a) and (Q =< $f))) and
+ (((R >= $0) and (R =< $9)) or ((R >= $A) and (R =< $F)) or
+ ((R >= $a) and (R =< $f)))) ->
+ Cha = (trx(N) bsl 16) bor (trx(O) bsl 12) bor (trx(P) bsl 8) bor (trx(Q) bsl 4) bor trx(R),
+ {int_to_utf8(Cha),Rest};
+multi_esc(<<$x,${,N,O,P,Q,R,S,$},Rest/binary>>)
+ when ((((N >= $0) and (N =< $9)) or ((N >= $A) and (N =< $F)) or
+ ((N >= $a) and (N =< $f))) and
+ (((O >= $0) and (O =< $9)) or ((O >= $A) and (O =< $F)) or
+ ((O >= $a) and (O =< $f))) and
+ (((P >= $0) and (P =< $9)) or ((P >= $A) and (P =< $F)) or
+ ((P >= $a) and (P =< $f))) and
+ (((Q >= $0) and (Q =< $9)) or ((Q >= $A) and (Q =< $F)) or
+ ((Q >= $a) and (Q =< $f))) and
+ (((R >= $0) and (R =< $9)) or ((R >= $A) and (R =< $F)) or
+ ((R >= $a) and (R =< $f))) and
+ (((S >= $0) and (S =< $9)) or ((S >= $A) and (S =< $F)) or
+ ((S >= $a) and (S =< $f)))) ->
+ Cha = (trx(N) bsl 20) bor (trx(O) bsl 16) bor (trx(P) bsl 12) bor (trx(Q) bsl 8) bor (trx(R) bsl 4) bor trx(S),
+ {int_to_utf8(Cha),Rest};
+multi_esc(<<$x,N,O,Rest/binary>>)
+ when ((((N >= $0) and (N =< $9)) or ((N >= $A) and (N =< $F)) or
+ ((N >= $a) and (N =< $f))) and
+ (((O >= $0) and (O =< $9)) or ((O >= $A) and (O =< $F)) or
+ ((O >= $a) and (O =< $f)))) ->
+ Cha = (trx(N) bsl 4) bor trx(O),
+ {<<Cha>>,Rest};
+multi_esc(<<$x,N,Rest/binary>>)
+ when (((N >= $0) and (N =< $9)) or ((N >= $A) and (N =< $F)) or
+ ((N >= $a) and (N =< $f))) ->
+ Cha = trx(N),
+ {<<Cha>>,Rest};
+multi_esc(_) ->
+ no.
+
+single_esc($") ->
+ $";
+single_esc($ ) ->
+ $ ;
+single_esc($') ->
+ $';
+single_esc($@) ->
+ $@;
+single_esc($t) ->
+ $\t;
+single_esc($n) ->
+ $\n;
+single_esc($r) ->
+ $\r;
+single_esc($f) ->
+ $\f;
+single_esc($e) ->
+ $\e;
+single_esc($b) ->
+ $\b;
+single_esc($$) ->
+ $$;
+single_esc($\\) ->
+ $\\;
+single_esc($a) ->
+ 7;
+%single_esc(Ch) when Ch >= $A, Ch =< $Z -> % eh?
+% Ch;
+
+single_esc(_) ->
+ no.
+
+info(Str,Lst) ->
+ case get(verbose) of
+ true ->
+ io:format(Str,Lst);
+ _ ->
+ ok
+ end.
+
+
+%% Generate split tests from indatafile,
+%% you will need perl on the machine
+gen_split_test(OneFile) ->
+ {ok,Bin} = file:read_file(OneFile),
+ Lines = splitfile(0,Bin,1),
+ Structured = stru(Lines),
+ PerlShellScript = OneFile++"_split_test_gen.sh",
+ dumpsplit(Structured,PerlShellScript),
+ PerlShellScript,
+ ErlModule = "re_"++filename:basename(OneFile)++"_split_test",
+ ErlFileName = ErlModule++".erl",
+ {ok,F}= file:open(ErlFileName,[write]),
+ io:format(F,"-module(~s).~n",[ErlModule]),
+ io:format(F,"-compile(export_all).~n",[]),
+ io:format(F,"-include(\"test_server.hrl\").~n",[]),
+ %io:format(F,"-define(line,erlang:display(?LINE),).~n",[]),
+ io:format(F,"%% This file is generated by running ~w:gen_split_test(~p)~n",
+ [?MODULE,OneFile]),
+ io:format(F,"join([]) -> [];~n",[]),
+ io:format(F,"join([A]) -> [A];~n",[]),
+ io:format(F,"join([H|T]) -> [H,<<\":\">>|join(T)].~n",[]),
+ io:format(F,"run() ->~n",[]),
+ file:close(F),
+ os:cmd("sh "++ PerlShellScript++" 2>/dev/null >> "++ErlFileName),
+ {ok,F2}= file:open(ErlFileName,[append]),
+ io:format(F2,"ok.~n",[]),
+ file:close(F2),
+ io:format("~s~n",[os:cmd("wc -l "++ErlFileName)]),
+ ok.
+
+dumpsplit(S,Fname) ->
+ {ok,F}= file:open(Fname,[write]),
+ dodumpsplit(F,S),
+ file:close(F).
+
+dodumpsplit(_,[]) ->
+ ok;
+dodumpsplit(F,[H|T]) ->
+ dumponesplit(F,H),
+ dodumpsplit(F,T).
+
+dumponesplit(F,{RE,_,O,TS}) ->
+ [begin
+ {NO,_} = pick_exec_options(O++Op),
+ SSS = opt_to_string(NO),
+ io:format(F,"perl -e '$x = join(\":\",split(/~s/~s,\"~s\")); "
+ "$x =~~ s/\\\\/\\\\\\\\/g; $x =~~ s/\\\"/\\\\\"/g; "
+ "print \"?line <<\\\"$x\\\">> = "
+ "iolist_to_binary(join(re:split(\\\"~s\\\","
+ "\\\"~s\\\",~p))), \\n\";'~n",
+ [zsafe(safe(RE)),
+ SSS,
+ ysafe(safe(Str)),
+ dsafe(safe(Str)),
+ dsafe2(safe(RE)),
+ NO++[trim]]),
+ io:format(F,"perl -e '$x = join(\":\",split(/~s/~s,\"~s\",2)); "
+ "$x =~~ s/\\\\/\\\\\\\\/g; $x =~~ s/\\\"/\\\\\"/g; "
+ "print \"?line <<\\\"$x\\\">> = "
+ "iolist_to_binary(join(re:split(\\\"~s\\\","
+ "\\\"~s\\\",~p))), \\n\";'~n",
+ [zsafe(safe(RE)),
+ SSS,
+ ysafe(safe(Str)),
+ dsafe(safe(Str)),
+ dsafe2(safe(RE)),
+ NO++[{parts,2}]]),
+ io:format(F,"perl -e '$x = join(\":\",split(/~s/~s,\"~s\",-1)); "
+ "$x =~~ s/\\\\/\\\\\\\\/g; $x =~~ s/\\\"/\\\\\"/g; "
+ "print \"?line <<\\\"$x\\\">> = "
+ "iolist_to_binary(join(re:split(\\\"~s\\\","
+ "\\\"~s\\\",~p))), \\n\";'~n",
+ [zsafe(safe(RE)),
+ SSS,
+ ysafe(safe(Str)),
+ dsafe(safe(Str)),
+ dsafe2(safe(RE)),
+ NO])
+ end ||
+ {Str,_,Op,_} <- TS].
+
+%% Generate replacement tests from indatafile,
+%% you will need perl on the machine
+gen_repl_test(OneFile) ->
+ random:seed(1219,687731,62804),
+ {ok,Bin} = file:read_file(OneFile),
+ Lines = splitfile(0,Bin,1),
+ Structured = stru(Lines),
+ PerlShellScript = OneFile++"_replacement_test_gen.sh",
+ dump(Structured,PerlShellScript),
+ ErlModule = "re_"++filename:basename(OneFile)++"_replacement_test",
+ ErlFileName = ErlModule++".erl",
+ {ok,F}= file:open(ErlFileName,[write]),
+ io:format(F,"-module(~s).~n",[ErlModule]),
+ io:format(F,"-compile(export_all).~n",[]),
+ io:format(F,"-include(\"test_server.hrl\").~n",[]),
+ io:format(F,"%% This file is generated by running ~w:gen_repl_test(~p)~n",
+ [?MODULE,OneFile]),
+ io:format(F,"run() ->~n",[]),
+ file:close(F),
+ os:cmd("sh "++ PerlShellScript++" 2>/dev/null >> "++ErlFileName),
+ {ok,F2}= file:open(ErlFileName,[append]),
+ io:format(F2,"ok.~n",[]),
+ file:close(F2),
+ io:format("~s~n",[os:cmd("wc -l "++ErlFileName)]),
+ ok.
+dump(S,Fname) ->
+ {ok,F}= file:open(Fname,[write]),
+ dodump(F,S),
+ file:close(F).
+
+dodump(_,[]) ->
+ ok;
+dodump(F,[H|T]) ->
+ dumpone(F,H),
+ dodump(F,T).
+
+dumpone(F,{RE,_,O,TS}) ->
+ [begin
+ {NO,_} = pick_exec_options(O++Op),
+ SSS = opt_to_string(NO),
+ RS = ranstring(),
+ io:format(F,"perl -e '$x = \"~s\"; $x =~~ s/~s/~s/~s; $x =~~ s/\\\\/\\\\\\\\/g; $x =~~ s/\\\"/\\\\\"/g; print \"?line <<\\\"$x\\\">> = iolist_to_binary(re:replace(\\\"~s\\\",\\\"~s\\\",\\\"~s\\\",~p)), \\n\";'~n",[ysafe(safe(Str)),zsafe(safe(RE)),perlify(binary_to_list(RS)),SSS,dsafe(safe(Str)),dsafe(safe(RE)),xsafe(RS),NO]),
+ io:format(F,"perl -e '$x = \"~s\"; $x =~~ s/~s/~s/g~s; $x =~~ s/\\\\/\\\\\\\\/g; $x =~~ s/\\\"/\\\\\"/g; print \"?line <<\\\"$x\\\">> = iolist_to_binary(re:replace(\\\"~s\\\",\\\"~s\\\",\\\"~s\\\",~p)), \\n\";'~n",[ysafe(safe(Str)),zsafe(safe(RE)),perlify(binary_to_list(RS)),SSS,dsafe(safe(Str)),dsafe(safe(RE)),xsafe(RS),NO++[global]])
+ end ||
+ {Str,_,Op,_} <- TS].
+
+dsafe2([]) ->
+ [];
+dsafe2([$\',$\",$\',$\",$\'|T]) ->
+ [$\',$\",$\',$\",$\' |dsafe2(T)];
+dsafe2([$\"|T]) ->
+ [$\\,$\\,$\\,$\" |dsafe2(T)];
+dsafe2([$\\, $G|T]) ->
+ [$\\,$\\,$\\,$\\,$A |dsafe2(T)];
+dsafe2([$\\|T]) ->
+ [$\\,$\\,$\\,$\\ |dsafe2(T)];
+dsafe2([$$|T]) ->
+ [$\\,$$|dsafe2(T)];
+dsafe2([H|T]) ->
+ [H|dsafe2(T)].
+
+dsafe([]) ->
+ [];
+dsafe([$\',$\",$\',$\",$\'|T]) ->
+ [$\',$\",$\',$\",$\' |dsafe(T)];
+dsafe([$\"|T]) ->
+ [$\\,$\\,$\\,$\" |dsafe(T)];
+dsafe([$\\|T]) ->
+ [$\\,$\\,$\\,$\\ |dsafe(T)];
+dsafe([$$|T]) ->
+ [$\\,$$|dsafe(T)];
+dsafe([H|T]) ->
+ [H|dsafe(T)].
+
+xsafe(<<>>) ->
+ [];
+xsafe(<<$\\,R/binary>>) ->
+ [$\\,$\\,$\\,$\\ | xsafe(R)];
+xsafe(<<X,R/binary>>) ->
+ [X|xsafe(R)].
+
+zsafe([]) ->
+ [];
+zsafe([$$, $b|T]) ->
+ [$\\,$$, $b | zsafe(T)];
+zsafe([X|R]) ->
+ [X|zsafe(R)].
+
+ysafe([]) ->
+ [];
+ysafe([$\',$\",$\',$\",$\'|T]) ->
+ [$\',$\",$\',$\",$\' |ysafe(T)];
+ysafe([$\"|T]) ->
+ [$\\,$\" |ysafe(T)];
+ysafe([$\\|T]) ->
+ [$\\,$\\ |ysafe(T)];
+ysafe([$$|T]) ->
+ [$\\,$$|ysafe(T)];
+ysafe([H|T]) ->
+ [H|ysafe(T)].
+
+safe(<<>>) ->
+ [];
+safe(<<$\n>>) -> %chomp
+ [];
+safe(<<$\',R/binary>>) ->
+ [$\',$\",$\',$\",$\' | safe(R)];
+safe(<<X,R/binary>>) ->
+ [X|safe(R)].
+perlify([$\\,N|Rest]) when N >= $0, N =< $9 ->
+ [$$,N|perlify(Rest)];
+perlify([$& | Rest]) ->
+ [$$,$& | perlify(Rest)];
+perlify([H|T]) ->
+ [H|perlify(T)];
+perlify([]) ->
+ [].
+
+opt_to_string([]) ->
+ [];
+opt_to_string([A|T]) ->
+ case btr(A) of
+ false ->
+ opt_to_string(T);
+ Ch ->
+ [Ch | opt_to_string(T)]
+ end.
+
+btr(caseless) ->
+ $i;
+btr(extended) ->
+ $x;
+btr(dotall) ->
+ $s;
+btr(multiline) ->
+ $m;
+btr(dupnames) ->
+ $J;
+btr(no_auto_capture) ->
+ $N;
+btr(unicode) ->
+ $8;
+btr(_) ->
+ false.
+
+
+ranchar() ->
+ case random:uniform(10) of
+ 9 -> $&;
+ 10 -> <<"\\1">>;
+ N when N < 5 ->
+ random:uniform($Z-$A)+$A-1;
+ M when M < 9 ->
+ random:uniform($z-$a)+$a-1
+ end.
+
+ranstring() ->
+ iolist_to_binary([ranchar() || _ <- lists:duplicate(random:uniform(20),0) ]).
+
diff --git a/lib/stdlib/test/select_SUITE.erl b/lib/stdlib/test/select_SUITE.erl
new file mode 100644
index 0000000000..54664fbb00
--- /dev/null
+++ b/lib/stdlib/test/select_SUITE.erl
@@ -0,0 +1,804 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(select_SUITE).
+-author('[email protected]').
+
+-export([test/0]).
+
+%%
+%% Define to run outside of test server
+%%
+%%-define(STANDALONE,1).
+
+%%
+%% Define for debug output
+%%
+%%-define(debug,1).
+
+-ifdef(STANDALONE).
+-define(config(A,B),config(A,B)).
+-export([config/2]).
+-define(fmt(A,B),io:format(A,B)).
+-else.
+-include("test_server.hrl").
+-define(fmt(A,B),test_server:format(A,B)).
+-endif.
+
+-ifdef(debug).
+-ifdef(STANDALONE).
+-define(line, erlang:display({?MODULE,?LINE}), ).
+-endif.
+-define(dbgformat(A,B),io:format(A,B)).
+-else.
+-ifdef(STANDALONE).
+-define(line, noop, ).
+-endif.
+-define(dbgformat(A,B),noop).
+-endif.
+
+-ifdef(STANDALONE).
+config(priv_dir,_) ->
+ ".".
+-else.
+%% When run in test server.
+-export([all/1,select_test/1,init_per_testcase/2, fin_per_testcase/2,
+ return_values/1]).
+
+init_per_testcase(_Case, Config) when is_list(Config) ->
+ ?line Dog=test_server:timetrap(test_server:seconds(1200)),
+ [{watchdog, Dog}|Config].
+
+fin_per_testcase(_Case, Config) ->
+ Dog=?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+all(doc) ->
+ ["Test ets:select"];
+all(suite) ->
+ [return_values, select_test].
+
+select_test(suite) ->
+ [];
+select_test(doc) ->
+ ["Tests select in numerous ways"];
+select_test(Config) when list(Config) ->
+ do_test(Config).
+
+return_values(suite) ->
+ [];
+return_values(doc) ->
+ ["Tests return values in specific situations for select/3 and select/1"];
+return_values(Config) when list(Config) ->
+ do_return_values().
+
+-endif.
+
+
+table_factor({dets,_}) ->
+ 1;
+table_factor({ets,_}) ->
+ 100.
+
+gen_dets_filename(Config,N) ->
+ filename:join(?config(priv_dir,Config),
+ "testdets_" ++ integer_to_list(N) ++ ".dets").
+
+create_tables(Config) ->
+ Hash = ets:new(xxx, []),
+ Tree = ets:new(yyy, [ordered_set]),
+ Bag = ets:new(yyy, [bag]),
+ DBag = ets:new(yyy, [duplicate_bag]),
+ F1 = gen_dets_filename(Config,1),
+ (catch file:delete(F1)),
+ {ok,DetsPlain} = dets:open_file(testdets_1,
+ [{file, F1}]),
+ F3 = gen_dets_filename(Config,3),
+ (catch file:delete(F3)),
+ {ok,DetsBag} = dets:open_file(testdets_3,
+ [{file, F3},{type, bag}]),
+ F4 = gen_dets_filename(Config,4),
+ (catch file:delete(F4)),
+ {ok,DetsDBag} = dets:open_file(testdets_4,
+ [{file, F4},{type, duplicate_bag}]),
+ [{ets,Hash}, {ets,Tree}, {ets,Bag}, {ets,DBag},
+ {dets, DetsPlain}, {dets, DetsBag}, {dets, DetsDBag}].
+
+
+gen_key(N,list) ->
+ [N,N+1,N+2];
+gen_key(N,tuple) ->
+ {N,N+1,N+2};
+gen_key(N,complex) ->
+ {[N,N+1],N+2}.
+
+gen_fun(N) ->
+ fun() ->
+ N
+ end.
+
+gen_bin(N) ->
+ list_to_binary(integer_to_list(N)).
+
+gen_object(N,Type) ->
+ L = integer_to_list(N),
+ A = list_to_atom("a" ++ L),
+ {gen_key(N,Type), L, A, gen_fun(N), gen_bin(N)}.
+gen_object1(N,Type) ->
+ L = integer_to_list(N),
+ A = list_to_atom("a" ++ L),
+ {gen_key(N,Type), A, L, gen_fun(N), gen_bin(N)}.
+
+fill_table(_,0,_) ->
+ ok;
+fill_table({Mod,Tab},N,Type) ->
+ Obj1 = gen_object1(N,Type),
+ Obj = gen_object(N,Type),
+ Mod:insert(Tab, Obj1),
+ case Mod:info(Tab,type) of
+ bag ->
+ Mod:insert(Tab, Obj);
+ duplicate_bag ->
+ Mod:insert(Tab, Obj),
+ Mod:insert(Tab, Obj1);
+ _ ->
+ ok
+ end,
+ fill_table({Mod,Tab},N-1,Type).
+
+table_size(Tab) ->
+ 15 *table_factor(Tab).
+
+build_tables(Config,Type) ->
+ L = create_tables(Config),
+ ?dbgformat("Tables: ~p~n",[L]),
+ lists:foreach(fun(TD) ->
+ fill_table(TD,table_size(TD),Type)
+ end,
+ L),
+ L.
+
+destroy_tables([]) ->
+ ok;
+destroy_tables([{ets,Tab}|T]) ->
+ ets:delete(Tab),
+ destroy_tables(T);
+destroy_tables([{dets,Tab}|T]) ->
+ dets:close(Tab),
+ destroy_tables(T).
+
+
+init_random(Config) ->
+ WriteDir = ReadDir = ?config(priv_dir,Config),
+ (catch file:make_dir(WriteDir)),
+ Seed = case file:consult(filename:join([ReadDir,
+ "preset_random_seed2.txt"])) of
+ {ok,[X]} ->
+ X;
+ _ ->
+ {A,B,C} = erlang:now(),
+ random:seed(A,B,C),
+ get(random_seed)
+ end,
+ put(random_seed,Seed),
+ {ok, F} = file:open(filename:join([WriteDir, "last_random_seed2.txt"]),
+ [write]),
+ io:format(F,"~p. ~n",[Seed]),
+ file:close(F),
+ ok.
+
+create_random_key(N,Type) ->
+ gen_key(random:uniform(N),Type).
+
+create_pb_key(N,list) ->
+ X = random:uniform(N),
+ case random:uniform(4) of
+ 3 -> {[X, X+1, '_'], fun([Z,Z1,P1]) ->
+ [Z,Z1,P1] =:= [X,X+1,P1] end};
+ 2 -> {[X, '_', '_'], fun([Z,P1,P2]) -> [Z,P1,P2] =:= [X,P1,P2] end};
+ 1 -> {[X, X+1, '$1'], fun([Z,Z1,P1]) ->
+ [Z,Z1,P1] =:= [X,X+1,P1] end};
+ _ -> {[X, '$1', '$2'], fun([Z,P1,P2]) -> [Z,P1,P2] =:= [X,P1,P2] end}
+ end;
+create_pb_key(N, tuple) ->
+ X = random:uniform(N),
+ case random:uniform(2) of
+ 1 -> {{X, X+1, '$1'},fun({Z,Z1,P1}) -> {Z,Z1,P1} =:= {X,X+1,P1} end};
+ _ -> {{X, '$1', '$2'},fun({Z,P1,P2}) -> {Z,P1,P2} =:= {X,P1,P2} end}
+ end;
+create_pb_key(N, complex) ->
+ X = random:uniform(N),
+ case random:uniform(2) of
+ 1 -> {{[X, X+1], '$1'}, fun({[Z,Z1],P1}) ->
+ {[Z,Z1],P1} =:= {[X,X+1],P1} end};
+ _ -> {{[X, '$1'], '$2'},fun({[Z,P1],P2}) ->
+ {[Z,P1],P2} =:= {[X,P1],P2} end}
+ end.
+table_foldl(_Fun, Acc,{_Mod,_Tab},'$end_of_table') ->
+ Acc;
+table_foldl(Fun, Acc,{Mod,Tab},Key) ->
+ Objs = Mod:lookup(Tab,Key),
+ Acc2 = lists:foldl(Fun,Acc,Objs),
+ ?dbgformat("Objs: ~p, Acc2: ~p~n",[Objs,Acc2]),
+ table_foldl(Fun, Acc2, {Mod,Tab}, Mod:next(Tab,Key)).
+table_foldl(Fun, Acc,{Mod,Tab}) ->
+ table_foldl(Fun, Acc,{Mod,Tab},Mod:first(Tab)).
+
+chunked_select(Mod,Tab,MS,0) ->
+ Mod:select(Tab,MS);
+chunked_select(Mod,Tab,MS,Chunk) when Chunk > 0->
+ do_chunk_select(Mod, Mod:select(Tab,MS,Chunk),[]);
+chunked_select(Mod,Tab,MS,Chunk) when Chunk < 0->
+ case Mod of
+ ets ->
+ do_chunk_select_reverse(Mod,
+ Mod:select_reverse(Tab,MS,-Chunk),[]);
+ _ ->
+ chunked_select(Mod,Tab,MS,-Chunk)
+ end.
+
+
+do_chunk_select_reverse(_Mod, '$end_of_table',Acc) ->
+ %% OK, all this reversing is only needed for ordered_set, but
+ %% this is only testcases, right?
+ erlang:display(did_chunked_select_reverse),
+ Acc;
+do_chunk_select_reverse(Mod, {L,C},Acc) ->
+ NewAcc = lists:reverse(L)++Acc,
+ do_chunk_select(Mod, Mod:select(C), NewAcc).
+
+do_chunk_select(_Mod, '$end_of_table',Acc) ->
+ %% OK, all this reversing is only needed for ordered_set, but
+ %% this is only testcases, right?
+ lists:reverse(Acc);
+do_chunk_select(Mod, {L,C},Acc) ->
+ NewAcc = lists:reverse(L)++Acc,
+ do_chunk_select(Mod, Mod:select(C), NewAcc).
+
+cmp_ms_to_fun({Mod,Tab}, MS, Fun1, Fun2) ->
+ cmp_ms_to_fun({Mod,Tab}, MS, Fun1, Fun2, 0).
+
+cmp_ms_to_fun({Mod,Tab}, MS, Fun1, Fun2, ChunkSize) ->
+ MSRes = lists:sort(chunked_select(Mod,Tab,MS,ChunkSize)),
+ FunRes0 = table_foldl(Fun1,[],{Mod,Tab}),
+ FunRes = case Fun2 of
+ F when function(F) ->
+ FunRes1 = table_foldl(F,[],{Mod,Tab}),
+ lists:merge(FunRes0,FunRes1);
+ [] ->
+ lists:sort(FunRes0)
+ end,
+ case MSRes =:= FunRes of
+ true ->
+ true;
+ false ->
+ ?fmt("Match_spec result differs from fun result:~n",[]),
+ ?fmt("Parameters: ~p,~p,~p,~p~n",
+ [{Mod,Tab}, MS, Fun1, Fun2]),
+ ?fmt("Match_spec Result: ~p~n", [MSRes]),
+ ?fmt("Fun Result: ~p~n", [FunRes]),
+ Info = (catch Mod:info(Tab)),
+ ?fmt("Table info:~p~n", [Info]),
+ {'EXIT', {hej, ST}} = (catch erlang:error(hej)),
+ ?fmt("Stack backtrace: ~p~n", [ST]),
+ erlang:error(badmatch)
+ end.
+
+do_n(0,_) -> ok;
+do_n(N,Fun) ->
+ Fun(),
+ do_n(N-1,Fun).
+
+%%
+%% We want some misses too, so pretend the tables are slightly
+%% larger than they really are.
+%%
+num_els(Tab) ->
+ 16 * table_factor(Tab).
+
+
+test() ->
+ do_return_values(),
+ do_test([]).
+
+do_test(Config) ->
+ init_random(Config),
+ whitebox(),
+ lists:foreach(fun(Type) ->
+ Tabs = build_tables(Config,Type),
+ basic_key(Tabs,Type),
+ ?fmt("basic_key done for type ~w~n",[Type]),
+ basic_pb_key(Tabs,Type),
+ ?fmt("basic_pb_key done for type ~w~n",[Type]),
+ double_pb_key(Tabs,Type),
+ ?fmt("double_pb_key done for type ~w~n",[Type]),
+ multi_key(Tabs,Type),
+ ?fmt("multi_key done for type ~w~n",[Type]),
+ multi_mixed_key(Tabs,Type),
+ ?fmt("multi_mixed_key done for type ~w~n",
+ [Type]),
+ destroy_tables(Tabs)
+ end,
+ [tuple, list, complex]),
+ ok.
+
+basic_key(Tabs,Type) ->
+ Fun = fun() ->
+ lists:map(fun(Tab) ->
+ ?line Key =
+ create_random_key(num_els(Tab),Type),
+ ?line MS =
+ [{{Key,'_','_','_','_'},[],['$_']}],
+ MF = fun({Key0,A,B,F,Bi},Acc) ->
+ case Key =:= Key0 of
+ true ->
+ [{Key0,A,B,F,Bi} |
+ Acc];
+ _ ->
+ Acc
+ end
+ end,
+ ?line cmp_ms_to_fun(Tab,MS,MF,[])
+ end,
+ Tabs)
+ end,
+ ?line do_n(50,Fun),
+ ok.
+
+basic_pb_key(Tabs,Type) ->
+ InnerFun = fun(Tab) ->
+ ?line {Key,KeyFun} =
+ create_pb_key(num_els(Tab),Type),
+ ?line MS = [{{Key,'_','_','_','_'},[],['$_']}],
+ MF = fun({Key0,A,B,F,Bi},Acc) ->
+ case KeyFun(Key0) of
+ true ->
+ [{Key0,A,B,F,Bi} |
+ Acc];
+ _ ->
+ Acc
+ end
+ end,
+ ?line cmp_ms_to_fun(Tab,MS,MF,[])
+ end,
+ ?line {Etses, Detses} = split_by_type(Tabs),
+
+ ?line FunEts = fun() ->
+ ?line lists:foreach(InnerFun,
+ Etses)
+ end,
+ ?line FunDets = fun() ->
+ ?line lists:foreach(InnerFun,
+ Detses)
+ end,
+ ?line do_n(table_factor(hd(Etses)) div 2,FunEts),
+ ?line do_n(10,FunDets),
+ ok.
+
+double_pb_key(Tabs,Type) ->
+ InnerFun = fun(Tab) ->
+ ?line {KeyA,KeyFunA} =
+ create_pb_key(num_els(Tab),Type),
+ ?line {KeyB,KeyFunB} =
+ create_pb_key(num_els(Tab),Type),
+ MS = [{{KeyA,'_','_','_','_'},[],['$_']},
+ {{KeyB,'_','_','_','_'},[],['$_']}],
+ ?dbgformat("Tab: ~p, MS: ~p~n",
+ [Tab,MS]),
+ MF = fun({Key0,A,B,F,Bi},Acc) ->
+ case KeyFunA(Key0) of
+ true ->
+ ?dbgformat
+ ("FunMatched:"
+ " ~p~n",
+ [{Key0,A,
+ B,F,Bi}]),
+ [{Key0,A,B,F,Bi} |
+ Acc];
+ _ ->
+ case KeyFunB(Key0) of
+ true ->
+ ?dbgformat
+ ("Fun"
+ "Matched:"
+ " ~p~n",
+ [{Key0,A,
+ B,F,
+ Bi}]),
+ [{Key0,A,B,
+ F,Bi} |
+ Acc];
+ _ ->
+ Acc
+ end
+ end
+ end,
+ ?line cmp_ms_to_fun(Tab,MS,MF,[])
+ end,
+ ?line {Etses, Detses} = split_by_type(Tabs),
+
+ ?line FunEts = fun() ->
+ ?line lists:foreach(InnerFun,
+ Etses)
+ end,
+ ?line FunDets = fun() ->
+ ?line lists:foreach(InnerFun,
+ Detses)
+ end,
+ ?line do_n(table_factor(hd(Etses)) div 2,FunEts),
+ ?line do_n(10,FunDets),
+ ok.
+
+
+multi_key(Tabs,Type) ->
+ Fun = fun() ->
+ lists:map(fun(Tab) ->
+ ?line KeyA =
+ create_random_key(num_els(Tab),Type),
+ ?line KeyB =
+ create_random_key(num_els(Tab),Type),
+ ?line KeyC =
+ create_random_key(num_els(Tab),Type),
+ ?line KeyD =
+ create_random_key(num_els(Tab),Type),
+ ?line KeyE =
+ create_random_key(num_els(Tab),Type),
+ ?line KeyF =
+ create_random_key(num_els(Tab),Type),
+ ?line KeyG =
+ create_random_key(num_els(Tab),Type),
+ ?line KeyH =
+ create_random_key(num_els(Tab),Type),
+ ?line KeyI =
+ create_random_key(num_els(Tab),Type),
+ ?line KeyJ =
+ create_random_key(num_els(Tab),Type),
+ ?line KeyK =
+ create_random_key(num_els(Tab),Type),
+ ?line KeyL =
+ create_random_key(num_els(Tab),Type),
+
+ MS = [{{KeyA,'$1','_','$2','_'},[],
+ [{{'$1','$2'}}]},
+ {{KeyB,'$1','_','$2','_'},[],
+ [{{'$1','$2'}}]},
+ {{KeyC,'$1','_','$2','_'},[],
+ [{{'$1','$2'}}]},
+ {{KeyD,'$1','_','$2','_'},[],
+ [{{'$1','$2'}}]},
+ {{KeyE,'$1','_','$2','_'},[],
+ [{{'$1','$2'}}]},
+ {{KeyF,'$1','_','$2','_'},[],
+ [{{'$1','$2'}}]},
+ {{KeyG,'$1','_','$2','_'},[],
+ [{{'$1','$2'}}]},
+ {{KeyH,'$1','_','$2','_'},[],
+ [{{'$1','$2'}}]},
+ {{KeyI,'$1','_','$2','_'},[],
+ [{{'$1','$2'}}]},
+ {{KeyJ,'$1','_','$2','_'},[],
+ [{{'$1','$2'}}]},
+ {{KeyK,'$1','_','$2','_'},[],
+ [{{'$1','$2'}}]},
+ {{KeyL,'$1','_','$2','_'},[],
+ [{{'$1','$2'}}]}
+ ],
+ ?dbgformat("Tab: ~p, MS: ~p~n",
+ [Tab,MS]),
+ MF = fun({Key0,A,_B,F,_Bi},Acc) ->
+ case Key0 of
+ KeyA ->
+ [ {A,F} |
+ Acc];
+ KeyB ->
+ [ {A,F} |
+ Acc];
+ KeyC ->
+ [ {A,F} |
+ Acc];
+ KeyD ->
+ [ {A,F} |
+ Acc];
+ KeyE ->
+ [ {A,F} |
+ Acc];
+ KeyF ->
+ [ {A,F} |
+ Acc];
+ KeyG ->
+ [ {A,F} |
+ Acc];
+ KeyH ->
+ [ {A,F} |
+ Acc];
+ KeyI ->
+ [ {A,F} |
+ Acc];
+ KeyJ ->
+ [ {A,F} |
+ Acc];
+ KeyK ->
+ [ {A,F} |
+ Acc];
+ KeyL ->
+ [ {A,F} |
+ Acc];
+ _ ->
+ Acc
+ end
+ end,
+ ?line cmp_ms_to_fun(Tab,MS,MF,[])
+ end,
+ Tabs)
+ end,
+ ?line do_n(33,Fun),
+ ok.
+
+multi_mixed_key(Tabs,Type) ->
+ InnerFun = fun(Tab) ->
+ ?line KeyA =
+ create_random_key(num_els(Tab),Type),
+ ?line KeyB =
+ create_random_key(num_els(Tab),Type),
+ ?line KeyC =
+ create_random_key(num_els(Tab),Type),
+ ?line KeyD =
+ create_random_key(num_els(Tab),Type),
+ ?line {KeyE, FunE} =
+ create_pb_key(num_els(Tab),Type),
+ ?line KeyF =
+ create_random_key(num_els(Tab),Type),
+ ?line {KeyG, FunG} =
+ create_pb_key(num_els(Tab),Type),
+ ?line KeyH =
+ create_random_key(num_els(Tab),Type),
+ ?line KeyI =
+ create_random_key(num_els(Tab),Type),
+ ?line {KeyJ, FunJ} =
+ create_pb_key(num_els(Tab),Type),
+ ?line KeyK =
+ create_random_key(num_els(Tab),Type),
+ ?line KeyL =
+ create_random_key(num_els(Tab),Type),
+
+ MS = [{{KeyA,'$1','_','$2','_'},[],
+ [{{'$1','$2'}}]},
+ {{KeyB,'$1','_','$2','_'},[],
+ [{{'$1','$2'}}]},
+ {{KeyC,'$1','_','$2','_'},[],
+ [{{'$1','$2'}}]},
+ {{KeyD,'$1','_','$2','_'},[],
+ [{{'$1','$2'}}]},
+ {{KeyE,'$100','_','$200','_'},[],
+ [{{'$100','$200'}}]},
+ {{KeyF,'$1','_','$2','_'},[],
+ [{{'$1','$2'}}]},
+ {{KeyG,'$100','_','$200','_'},[],
+ [{{'$100','$200'}}]},
+ {{KeyH,'$1','_','$2','_'},[],
+ [{{'$1','$2'}}]},
+ {{KeyI,'$1','_','$2','_'},[],
+ [{{'$1','$2'}}]},
+ {{KeyJ,'$100','_','$200','_'},[],
+ [{{'$100','$200'}}]},
+ {{KeyK,'$1','_','$2','_'},[],
+ [{{'$1','$2'}}]},
+ {{KeyL,'$1','_','$2','_'},[],
+ [{{'$1','$2'}}]}
+ ],
+ ?dbgformat("Tab: ~p, MS: ~p~n",
+ [Tab,MS]),
+ MF = fun({Key0,A,_B,F,_Bi},Acc) ->
+ case Key0 of
+ KeyA ->
+ [ {A,F} |
+ Acc];
+ KeyB ->
+ [ {A,F} |
+ Acc];
+ KeyC ->
+ [ {A,F} |
+ Acc];
+ KeyD ->
+ [ {A,F} |
+ Acc];
+ KeyF ->
+ [ {A,F} |
+ Acc];
+ KeyH ->
+ [ {A,F} |
+ Acc];
+ KeyI ->
+ [ {A,F} |
+ Acc];
+ KeyK ->
+ [ {A,F} |
+ Acc];
+ KeyL ->
+ [ {A,F} |
+ Acc];
+ Else ->
+ case FunE(Else) or
+ FunG(Else) or
+ FunJ(Else) of
+ true ->
+ [ {A,F} |
+ Acc];
+ _ ->
+ Acc
+ end
+ end
+ end,
+ ?line cmp_ms_to_fun(Tab,MS,MF,[]),
+ ?line case Tab of
+ {ets,_} ->
+ ?line cmp_ms_to_fun(Tab,MS,MF,[],1),
+ ?line cmp_ms_to_fun(Tab,MS,MF,[],10),
+ ?line cmp_ms_to_fun(Tab,MS,MF,[],1000000),
+ ?line cmp_ms_to_fun(Tab,MS,MF,[],-1),
+ ?line cmp_ms_to_fun(Tab,MS,MF,[],-10),
+ ?line cmp_ms_to_fun(Tab,MS,MF,[],-1000000);
+ _ ->
+ ok
+ end
+ end,
+ ?line {Etses, Detses} = split_by_type(Tabs),
+
+ ?line FunEts = fun() ->
+ ?line lists:foreach(InnerFun,
+ Etses)
+ end,
+ ?line FunDets = fun() ->
+ ?line lists:foreach(InnerFun,
+ Detses)
+ end,
+ ?line do_n(table_factor(hd(Etses)) div 2,FunEts),
+ ?line do_n(table_factor(hd(Detses)) div 2,FunDets),
+ ok.
+
+
+split_by_type(List) ->
+ split_by_type(List,[],[]).
+split_by_type([],AccEts,AccDets) ->
+ {AccEts,AccDets};
+split_by_type([{dets,Tab}|T],AccEts,AccDets) ->
+ split_by_type(T,AccEts,[{dets,Tab}|AccDets]);
+split_by_type([{ets,Tab}|T],AccEts,AccDets) ->
+ split_by_type(T,[{ets,Tab}|AccEts],AccDets).
+
+whitebox() ->
+ ?line ets:new(xxx,[named_table, ordered_set]),
+ ?line ets:new(yyy,[named_table]),
+ ?line E = fun(0,_)->ok;
+ (N,F) ->
+ ?line ets:insert(xxx,{N,N rem 10}),
+ ?line ets:insert(yyy,{N,N rem 10}),
+ F(N-1,F)
+ end,
+ ?line E(10000,E),
+
+ ?line G = fun(F,C,A) ->
+ ?line case ets:select(C) of
+ {L,C2} ->
+ ?line F(F,C2,A+length(L));
+ '$end_of_table' ->
+ ?line A
+ end
+ end,
+ ?line H=fun({L,C}) ->
+ ?line G(G,C,length(L))
+ end,
+
+ ?line 1 = H(ets:select(xxx,[{{'$1','$2'},[{'<','$1',2}],['$_']}],7)),
+ ?line 10000 = H(ets:select(xxx,[{{'$1','$2'},[],['$_']}],1)),
+ ?line 1 = H(ets:select(yyy,[{{'$1','$2'},[{'<','$1',2}],['$_']}],7)),
+ ?line 10000 = H(ets:select(yyy,[{{'$1','$2'},[],['$_']}],1)),
+
+ ?line {[{5,5}],_} = ets:select(xxx,[{{5,'$2'},[],['$_']}],1),
+ ?line {[{5,5}],_} = ets:select(yyy,[{{5,'$2'},[],['$_']}],1),
+
+ ?line I = fun(_,0) ->
+ ok;
+ (I,N) ->
+ ?line 10000 =
+ H(ets:select(xxx,[{{'$1','$2'},[],['$_']}],N)),
+ I(I,N-1)
+ end,
+ ?line I(I,2000),
+ ?line J = fun(F,C,A) ->
+ ?line case ets:select(C) of
+ {L,C2} ->
+ ?line F(F,C2,lists:reverse(L)++A);
+ '$end_of_table' ->
+ ?line lists:reverse(A)
+ end
+ end,
+ ?line K = fun({L,C}) ->
+ ?line J(J,C,lists:reverse(L))
+ end,
+ ?line M = fun(_, _, 0) ->
+ ok;
+ (F, What, N) ->
+ ?line What =
+ K(ets:select(xxx,[{{'$1','$2'},[],['$_']}],N)),
+ F(F, What, N-1)
+ end,
+ ?line N = fun(HM) ->
+ ?line What = ets:select(xxx,[{{'$1','$2'},[],['$_']}]),
+ ?line What = lists:sort(What),
+ M(M, What, HM)
+ end,
+ ?line N(2000),
+ ?line ets:delete(xxx),
+ ?line ets:delete(yyy).
+
+
+do_return_values() ->
+ ?line T = ets:new(xxx,[ordered_set]),
+ ?line U = ets:new(xxx,[]),
+ ?line '$end_of_table' = ets:select(T,[{'_',[],['$_']}],1),
+ ?line '$end_of_table' = ets:select(U,[{'_',[],['$_']}],1),
+ ?line ets:insert(T,{ett,1}),
+ ?line ets:insert(U,{ett,1}),
+ ?line {[{ett,1}],C1} = ets:select(T,[{'_',[],['$_']}],1),
+ ?line '$end_of_table' = ets:select(C1),
+ ?line {[{ett,1}],C2} = ets:select(U,[{'_',[],['$_']}],1),
+ ?line '$end_of_table' = ets:select(C2),
+ ?line {[{ett,1}],C3} = ets:select(T,[{'_',[],['$_']}],2),
+ ?line '$end_of_table' = ets:select(C3),
+ ?line {[{ett,1}],C4} = ets:select(U,[{'_',[],['$_']}],2),
+ ?line '$end_of_table' = ets:select(C4),
+ ?line E = fun(0,_)->ok;
+ (N,F) ->
+ ?line ets:insert(T,{N,N rem 10}),
+ ?line ets:insert(U,{N,N rem 10}),
+ F(N-1,F)
+ end,
+ ?line E(10000,E),
+ ?line '$end_of_table' = ets:select(T,[{{hej, hopp},[],['$_']}],1),
+ ?line '$end_of_table' = ets:select(U,[{{hej,hopp},[],['$_']}],1),
+ ?line {[{ett,1}],CC1} = ets:select(T,[{{'$1','_'},[{is_atom, '$1'}],
+ ['$_']}],1),
+ ?line '$end_of_table' = ets:select(CC1),
+ ?line {[{ett,1}],CC2} = ets:select(U,[{{'$1','_'},[{is_atom, '$1'}],
+ ['$_']}],1),
+ ?line '$end_of_table' = ets:select(CC2),
+ ?line {[{ett,1}],CC3} = ets:select(T,[{{'$1','_'},[{is_atom, '$1'}],
+ ['$_']}],2),
+ ?line '$end_of_table' = ets:select(CC3),
+ ?line {[{ett,1}],CC4} = ets:select(U,[{{'$1','_'},[{is_atom, '$1'}],
+ ['$_']}],2),
+ ?line '$end_of_table' = ets:select(CC4),
+ ?line ets:delete(T),
+ ?line ets:delete(U),
+ ?line V = ets:new(xxx,[{keypos, 4}]),
+ ?line X = ets:new(xxx,[ordered_set, {keypos, 4}]),
+ ?line ets:insert(V,{1,1,1,ett}),
+ ?line ets:insert(X,{1,1,1,ett}),
+ ?line '$end_of_table' = ets:select(V,[{{1,1,1},[],['$_']}],1),
+ ?line '$end_of_table' = ets:select(X,[{{1,1,1},[],['$_']}],1),
+ ?line ets:delete(V),
+ ?line ets:delete(X),
+ ok.
+
+
+
+
+
diff --git a/lib/stdlib/test/sets_SUITE.erl b/lib/stdlib/test/sets_SUITE.erl
new file mode 100644
index 0000000000..c9f1a03598
--- /dev/null
+++ b/lib/stdlib/test/sets_SUITE.erl
@@ -0,0 +1,495 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%% This module tests the ordsets, sets, and gb_sets modules.
+%%
+
+-module(sets_SUITE).
+
+-export([all/1,init_per_testcase/2,fin_per_testcase/2,
+ create/1,add_element/1,del_element/1,
+ subtract/1,intersection/1,union/1,is_subset/1,
+ is_set/1,fold/1,filter/1,
+ take_smallest/1,take_largest/1]).
+
+-include("test_server.hrl").
+
+-import(lists, [foldl/3,reverse/1]).
+
+init_per_testcase(_Case, Config) ->
+ ?line Dog = ?t:timetrap(?t:minutes(5)),
+ [{watchdog,Dog}|Config].
+
+fin_per_testcase(_Case, Config) ->
+ Dog = ?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+all(suite) ->
+ [create,add_element,del_element,subtract,
+ intersection,union,is_subset,is_set,fold,filter,
+ take_smallest,take_largest].
+
+create(Config) when is_list(Config) ->
+ test_all(fun create_1/1).
+
+create_1(M) ->
+ ?line S0 = M:empty(),
+ ?line [] = M:to_list(S0),
+ ?line 0 = M:size(S0),
+ ?line true = M:is_empty(S0),
+ E = make_ref(),
+ ?line One = M:singleton(E),
+ ?line 1 = M:size(One),
+ ?line false = M:is_empty(One),
+ [E] = M:to_list(One),
+ S0.
+
+add_element(Config) when is_list(Config) ->
+ test_all([{0,132},{253,258},{510,514}], fun add_element_1/2).
+
+add_element_1(List, M) ->
+ ?line S = M:from_list(List),
+ ?line SortedSet = lists:usort(List),
+ ?line SortedSet = lists:sort(M:to_list(S)),
+
+ %% Make sure that we get the same result by inserting
+ %% elements one at the time.
+ ?line S2 = foldl(fun(El, Set) -> M:add_element(El, Set) end,
+ M:empty(), List),
+ ?line true = M:equal(S, S2),
+
+ %% Insert elements, randomly delete inserted elements,
+ %% and re-inserted all deleted elements at the end.
+ ?line S3 = add_element_del(List, M, M:empty(), [], []),
+ ?line true = M:equal(S2, S3),
+ ?line true = M:equal(S, S3),
+ S.
+
+add_element_del([H|T], M, S, Del, []) ->
+ add_element_del(T, M, M:add_element(H, S), Del, [H]);
+add_element_del([H|T], M, S0, Del, Inserted) ->
+ S1 = M:add_element(H, S0),
+ case random:uniform(3) of
+ 1 ->
+ OldEl = lists:nth(random:uniform(length(Inserted)), Inserted),
+ S = M:del_element(OldEl, S1),
+ add_element_del(T, M, S, [OldEl|Del], [H|Inserted]);
+ _ ->
+ add_element_del(T, M, S1, Del, [H|Inserted])
+ end;
+add_element_del([], M, S, Del, _) ->
+ M:union(S, M:from_list(Del)).
+
+del_element(Config) when is_list(Config) ->
+ test_all([{0,132},{253,258},{510,514},{1022,1026}], fun del_element_1/2).
+
+del_element_1(List, M) ->
+ ?line S0 = M:from_list(List),
+ ?line Empty = foldl(fun(El, Set) -> M:del_element(El, Set) end, S0, List),
+ ?line Empty = M:empty(),
+ ?line M:is_empty(Empty),
+ ?line S1 = foldl(fun(El, Set) ->
+ M:add_element(El, Set)
+ end, S0, reverse(List)),
+ ?line true = M:equal(S0, S1),
+ S1.
+
+subtract(Config) when is_list(Config) ->
+ test_all(fun subtract_empty/1),
+
+ %% Note: No empty set.
+ test_all([{2,69},{126,130},{253,258},511,512,{1023,1030}], fun subtract_1/2).
+
+subtract_empty(M) ->
+ ?line Empty = M:empty(),
+ ?line true = M:is_empty(M:subtract(Empty, Empty)),
+ M:subtract(Empty, Empty).
+
+subtract_1(List, M) ->
+ ?line S0 = M:from_list(List),
+ ?line Empty = M:empty(),
+
+ %% Trivial cases.
+ ?line true = M:is_empty(M:subtract(Empty, S0)),
+ ?line true = M:equal(S0, M:subtract(S0, Empty)),
+
+ %% Not so trivial.
+ ?line subtract_check(List, mutate_some(remove_some(List, 0.4)), M),
+ ?line subtract_check(List, rnd_list(length(List) div 2 + 5), M),
+ ?line subtract_check(List, rnd_list(length(List) div 7 + 9), M),
+ ?line subtract_check(List, mutate_some(List), M).
+
+subtract_check(A, B, M) ->
+ one_subtract_check(B, A, M),
+ one_subtract_check(A, B, M).
+
+one_subtract_check(A, B, M) ->
+ ASorted = lists:usort(A),
+ BSorted = lists:usort(B),
+ ASet = M:from_list(A),
+ BSet = M:from_list(B),
+ DiffSet = M:subtract(ASet, BSet),
+ Diff = ASorted -- BSorted,
+ true = M:equal(DiffSet, M:from_list(Diff)),
+ Diff = lists:sort(M:to_list(DiffSet)),
+ DiffSet.
+
+intersection(Config) when is_list(Config) ->
+ %% Note: No empty set.
+ test_all([{1,65},{126,130},{253,259},{499,513},{1023,1025}], fun intersection_1/2).
+
+intersection_1(List, M) ->
+ ?line S0 = M:from_list(List),
+
+ %% Intersection with self.
+ ?line true = M:equal(S0, M:intersection(S0, S0)),
+ ?line true = M:equal(S0, M:intersection([S0,S0])),
+ ?line true = M:equal(S0, M:intersection([S0,S0,S0])),
+ ?line true = M:equal(S0, M:intersection([S0])),
+
+ %% Intersection with empty.
+ ?line Empty = M:empty(),
+ ?line true = M:equal(Empty, M:intersection(S0, Empty)),
+ ?line true = M:equal(Empty, M:intersection([S0,Empty,S0,Empty])),
+
+ %% The intersection of no sets is undefined.
+ ?line {'EXIT',_} = (catch M:intersection([])),
+
+ %% Disjoint sets.
+ ?line Disjoint = [{El} || El <- List],
+ ?line DisjointSet = M:from_list(Disjoint),
+ ?line M:is_empty(M:intersection(S0, DisjointSet)),
+
+ %% Disjoint, different sizes.
+ ?line M:is_empty(M:intersection(S0, M:from_list(remove_some(Disjoint, 0.3)))),
+ ?line M:is_empty(M:intersection(S0, M:from_list(remove_some(Disjoint, 0.7)))),
+ ?line M:is_empty(M:intersection(S0, M:from_list(remove_some(Disjoint, 0.9)))),
+ ?line M:is_empty(M:intersection(M:from_list(remove_some(List, 0.3)), DisjointSet)),
+ ?line M:is_empty(M:intersection(M:from_list(remove_some(List, 0.5)), DisjointSet)),
+ ?line M:is_empty(M:intersection(M:from_list(remove_some(List, 0.9)), DisjointSet)),
+
+ %% Partial overlap (one or more elements in result set).
+ %% The sets have almost the same size. (Almost because a duplicated
+ %% element in the original list could be mutated and not mutated
+ %% at the same time.)
+ ?line PartialOverlap = mutate_some(List, []),
+ ?line IntersectionSet = check_intersection(List, PartialOverlap, M),
+ ?line false = M:is_empty(IntersectionSet),
+
+ %% Partial overlap, different set sizes. (Intersection possibly empty.)
+ ?line check_intersection(List, remove_some(PartialOverlap, 0.1), M),
+ ?line check_intersection(List, remove_some(PartialOverlap, 0.3), M),
+ ?line check_intersection(List, remove_some(PartialOverlap, 0.5), M),
+ ?line check_intersection(List, remove_some(PartialOverlap, 0.7), M),
+ ?line check_intersection(List, remove_some(PartialOverlap, 0.9), M),
+
+ IntersectionSet.
+
+check_intersection(Orig, Mutated, M) ->
+ OrigSet = M:from_list(Orig),
+ MutatedSet = M:from_list(Mutated),
+ Intersection = [El || El <- Mutated, not is_tuple(El)],
+ SortedIntersection = lists:usort(Intersection),
+ IntersectionSet = M:intersection(OrigSet, MutatedSet),
+ true = M:equal(IntersectionSet, M:from_list(SortedIntersection)),
+ SortedIntersection = lists:sort(M:to_list(IntersectionSet)),
+
+ IntersectionSet.
+
+
+union(Config) when is_list(Config) ->
+ %% Note: No empty set.
+ test_all([{1,71},{125,129},{254,259},{510,513},{1023,1025}], fun union_1/2).
+
+union_1(List, M) ->
+ ?line S = M:from_list(List),
+
+ %% Union with self and empty.
+ ?line Empty = M:empty(),
+ ?line true = M:equal(S, M:union(S, S)),
+ ?line true = M:equal(S, M:union([S,S])),
+ ?line true = M:equal(S, M:union([S,S,Empty])),
+ ?line true = M:equal(S, M:union([S,Empty,S])),
+ ?line true = M:equal(S, M:union(S, Empty)),
+ ?line true = M:equal(S, M:union([S])),
+ ?line true = M:is_empty(M:union([])),
+
+ %% Partial overlap.
+ ?line check_union(List, remove_some(mutate_some(List), 0.9), M),
+ ?line check_union(List, remove_some(mutate_some(List), 0.7), M),
+ ?line check_union(List, remove_some(mutate_some(List), 0.5), M),
+ ?line check_union(List, remove_some(mutate_some(List), 0.3), M),
+ ?line check_union(List, remove_some(mutate_some(List), 0.1), M),
+
+ ?line check_union(List, mutate_some(remove_some(List, 0.9)), M),
+ ?line check_union(List, mutate_some(remove_some(List, 0.7)), M),
+ ?line check_union(List, mutate_some(remove_some(List, 0.5)), M),
+ ?line check_union(List, mutate_some(remove_some(List, 0.3)), M),
+ ?line check_union(List, mutate_some(remove_some(List, 0.1)), M).
+
+check_union(Orig, Other, M) ->
+ OrigSet = M:from_list(Orig),
+ OtherSet = M:from_list(Other),
+ Union = Orig++Other,
+ SortedUnion = lists:usort(Union),
+ UnionSet = M:union(OrigSet, OtherSet),
+ SortedUnion = lists:sort(M:to_list(UnionSet)),
+ M:equal(UnionSet, M:from_list(Union)),
+ UnionSet.
+
+is_subset(Config) when is_list(Config) ->
+ test_all([{1,132},{253,270},{299,311}], fun is_subset_1/2).
+
+is_subset_1(List, M) ->
+ ?line S = M:from_list(List),
+ ?line Empty = M:empty(),
+
+ %% Subset of empty and self.
+ ?line true = M:is_subset(Empty, Empty),
+ ?line true = M:is_subset(Empty, S),
+ ?line false = M:is_subset(S, Empty),
+ ?line true = M:is_subset(S, S),
+
+ %% Other cases.
+ Res = [?line false = M:is_subset(M:singleton(make_ref()), S),
+ ?line true = M:is_subset(M:singleton(hd(List)), S),
+ ?line true = check_subset(remove_some(List, 0.1), List, M),
+ ?line true = check_subset(remove_some(List, 0.5), List, M),
+ ?line true = check_subset(remove_some(List, 0.9), List, M),
+ ?line check_subset(mutate_some(List), List, M),
+ ?line check_subset(rnd_list(length(List) div 2 + 5), List, M),
+ ?line subtract_check(List, rnd_list(length(List) div 7 + 9), M)
+ ],
+ res_to_set(Res, M, 0, []).
+
+check_subset(X, Y, M) ->
+ check_one_subset(Y, X, M),
+ check_one_subset(X, Y, M).
+
+check_one_subset(X, Y, M) ->
+ XSet = M:from_list(X),
+ YSet = M:from_list(Y),
+ SortedX = lists:usort(X),
+ SortedY = lists:usort(Y),
+ IsSubSet = length(SortedY--SortedX) =:= length(SortedY) - length(SortedX),
+ IsSubSet = M:is_subset(XSet, YSet),
+ IsSubSet.
+
+%% Encode all test results as a set to return.
+res_to_set([true|T], M, I, Acc) ->
+ res_to_set(T, M, I+1, [I|Acc]);
+res_to_set([_|T], M, I, Acc) ->
+ res_to_set(T, M, I+1, Acc);
+res_to_set([], M, _, Acc) -> M:from_list(Acc).
+
+is_set(Config) when is_list(Config) ->
+ %% is_set/1 is tested in the other test cases when its argument
+ %% is a set. Here test some arguments that makes it return false.
+
+ ?line false = gb_sets:is_set([a,b]),
+ ?line false = gb_sets:is_set({a,very,bad,tuple}),
+
+ ?line false = sets:is_set([a,b]),
+ ?line false = sets:is_set({a,very,bad,tuple}),
+
+ ?line false = ordsets:is_set([b,a]),
+ ?line false = ordsets:is_set({bad,tuple}),
+
+ %% Now test values that are known to be bad for all set representations.
+ test_all(fun is_set_1/1).
+
+is_set_1(M) ->
+ ?line false = M:is_set(self()),
+ ?line false = M:is_set(blurf),
+ ?line false = M:is_set(make_ref()),
+ ?line false = M:is_set(<<1,2,3>>),
+ ?line false = M:is_set(42),
+ ?line false = M:is_set(math:pi()),
+ ?line false = M:is_set({}),
+ M:empty().
+
+fold(Config) when is_list(Config) ->
+ test_all([{0,71},{125,129},{254,259},{510,513},{1023,1025},{9999,10001}],
+ fun fold_1/2).
+
+fold_1(List, M) ->
+ ?line S = M:from_list(List),
+ ?line L = M:fold(fun(E, A) -> [E|A] end, [], S),
+ ?line true = lists:sort(L) =:= lists:usort(List),
+ M:empty().
+
+filter(Config) when is_list(Config) ->
+ test_all([{0,69},{126,130},{254,259},{510,513},{1023,1025},{7999,8000}],
+ fun filter_1/2).
+
+filter_1(List, M) ->
+ ?line S = M:from_list(List),
+ IsNumber = fun(X) -> is_number(X) end,
+ ?line M:equal(M:from_list(lists:filter(IsNumber, List)),
+ M:filter(IsNumber, S)),
+ ?line M:filter(fun(X) -> is_atom(X) end, S).
+
+%%%
+%%% Test specifics for gb_sets.
+%%%
+
+take_smallest(Config) when is_list(Config) ->
+ test_all([{1,71},{125,129},{254,259},{510,513},{1023,1025}],
+ fun take_smallest_1/2).
+
+take_smallest_1(List, M) ->
+ case M:module() of
+ gb_sets -> take_smallest_2(List, M);
+ _ -> ok
+ end,
+ M:empty().
+
+take_smallest_2(List0, M) ->
+ ?line List = lists:usort(List0),
+ ?line S = M:from_list(List0),
+ take_smallest_3(S, List, M).
+
+take_smallest_3(S0, List0, M) ->
+ case M:is_empty(S0) of
+ true -> ok;
+ false ->
+ ?line Smallest = hd(List0),
+ ?line Smallest = gb_sets:smallest(S0),
+ ?line {Smallest,S} = gb_sets:take_smallest(S0),
+ ?line List = tl(List0),
+ ?line true = gb_sets:to_list(S) =:= List,
+ take_smallest_3(S, List, M)
+ end.
+
+take_largest(Config) when is_list(Config) ->
+ test_all([{1,71},{125,129},{254,259},{510,513},{1023,1025}],
+ fun take_largest_1/2).
+
+take_largest_1(List, M) ->
+ case M:module() of
+ gb_sets -> take_largest_2(List, M);
+ _ -> ok
+ end,
+ M:empty().
+
+take_largest_2(List0, M) ->
+ ?line List = reverse(lists:usort(List0)),
+ ?line S = M:from_list(List0),
+ take_largest_3(S, List, M).
+
+take_largest_3(S0, List0, M) ->
+ case M:is_empty(S0) of
+ true -> ok;
+ false ->
+ ?line Largest = hd(List0),
+ ?line Largest = gb_sets:largest(S0),
+ ?line {Largest,S} = gb_sets:take_largest(S0),
+ ?line List = tl(List0),
+ ?line true = gb_sets:to_list(S) =:= reverse(List),
+ take_largest_3(S, List, M)
+ end.
+
+%%%
+%%% Helper functions.
+%%%
+
+sets_mods() ->
+ Ordsets = sets_test_lib:new(ordsets, fun(X, Y) -> X == Y end),
+ Sets = sets_test_lib:new(sets, fun(X, Y) ->
+ lists:sort(sets:to_list(X)) ==
+ lists:sort(sets:to_list(Y)) end),
+ Gb = sets_test_lib:new(gb_sets, fun(X, Y) ->
+ gb_sets:to_list(X) ==
+ gb_sets:to_list(Y) end),
+ [Ordsets,Sets,Gb].
+
+test_all(Tester) ->
+ ?line Res = [begin
+ random:seed(1, 2, 42),
+ S = Tester(M),
+ {M:size(S),lists:sort(M:to_list(S))}
+ end || M <- sets_mods()],
+ ?line all_same(Res).
+
+test_all([{Low,High}|T], Tester) ->
+ test_all(lists:seq(Low, High)++T, Tester);
+test_all([Sz|T], Tester) when is_integer(Sz) ->
+ List = rnd_list(Sz),
+ ?line Res = [begin
+ random:seed(19, 2, Sz),
+ S = Tester(List, M),
+ {M:size(S),lists:sort(M:to_list(S))}
+ end || M <- sets_mods()],
+ ?line all_same(Res),
+ test_all(T, Tester);
+test_all([], _) -> ok.
+
+
+all_same([H|T]) ->
+ all_same_1(T, H).
+
+all_same_1([H|T], H) ->
+ all_same_1(T, H);
+all_same_1([], _) -> ok.
+
+rnd_list(Sz) ->
+ rnd_list_1(Sz, []).
+
+atomic_rnd_term() ->
+ case random:uniform(3) of
+ 1 -> list_to_atom(integer_to_list($\s+random:uniform(94))++"rnd");
+ 2 -> random:uniform();
+ 3 -> random:uniform(50)-37
+ end.
+
+rnd_list_1(0, Acc) -> Acc;
+rnd_list_1(N, Acc) -> rnd_list_1(N-1, [atomic_rnd_term()|Acc]).
+
+mutate_some(List) ->
+ mutate_some(List, []).
+
+mutate_some([X,Y,Z|T], Acc) ->
+ %% Intentionally change order. (Order should not matter.)
+ mutate_some(T, [{X},Z,Y|Acc]);
+mutate_some([H|T], Acc) ->
+ mutate_some(T, [H|Acc]);
+mutate_some([], Acc) ->
+ %% Intentionally not reversing.
+ Acc.
+
+%% Removes at least one element.
+remove_some(List0, P) ->
+ case remove_some(List0, P, []) of
+ List when length(List0) =:= length(List) ->
+ tl(List);
+ List ->
+ List
+ end.
+
+remove_some([H|T], P, Acc) ->
+ case random:uniform() of
+ F when F < P -> %Remove.
+ remove_some(T, P, Acc);
+ _ ->
+ remove_some(T, P, [H|Acc])
+ end;
+remove_some([], _, Acc) ->
+ %% Intentionally no reverse. Order should not matter.
+ Acc.
diff --git a/lib/stdlib/test/sets_test_lib.erl b/lib/stdlib/test/sets_test_lib.erl
new file mode 100644
index 0000000000..6b6fb00550
--- /dev/null
+++ b/lib/stdlib/test/sets_test_lib.erl
@@ -0,0 +1,124 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(sets_test_lib, [Mod,Equal]).
+
+-export([module/0,equal/2,empty/0,from_list/1,to_list/1,singleton/1,
+ add_element/2,del_element/2,size/1,is_empty/1,is_set/1,
+ intersection/1,intersection/2,subtract/2,
+ union/1,union/2,is_subset/2,fold/3,filter/2]).
+
+module() ->
+ Mod.
+
+equal(X, Y) ->
+ Equal(X, Y).
+
+empty() ->
+ Mod:new().
+
+from_list(L) ->
+ Mod:from_list(L).
+
+to_list(S) ->
+ Mod:to_list(S).
+
+singleton(E) ->
+ case erlang:function_exported(Mod, singleton, 1) of
+ true -> Mod:singleton(E);
+ false -> from_list([E])
+ end.
+
+add_element(El, S0) ->
+ S = Mod:add_element(El, S0),
+ true = Mod:is_element(El, S),
+ false = is_empty(S),
+ true = Mod:is_set(S),
+ S.
+
+del_element(El, S0) ->
+ S = Mod:del_element(El, S0),
+ false = Mod:is_element(El, S),
+ true = Mod:is_set(S),
+ S.
+
+size(S) ->
+ Mod:size(S).
+
+is_empty(S) ->
+ true = Mod:is_set(S),
+ case erlang:function_exported(Mod, is_empty, 1) of
+ true -> Mod:is_empty(S);
+ false -> Mod:size(S) == 0
+ end.
+
+is_set(S) ->
+ Mod:is_set(S).
+
+intersection(S1, S2) ->
+ S = Mod:intersection(S1, S2),
+ true = Equal(S, Mod:intersection(S2, S1)),
+ Disjoint = is_empty(S),
+ Disjoint = Mod:is_disjoint(S1, S2),
+ Disjoint = Mod:is_disjoint(S2, S1),
+ S.
+
+intersection(Ss) ->
+ S = Mod:intersection(Ss),
+ true = Equal(S, Mod:intersection(lists:reverse(Ss))),
+ S.
+
+subtract(S1, S2) ->
+ S = Mod:subtract(S1, S2),
+ true = Mod:is_set(S),
+ true = Mod:size(S) =< Mod:size(S1),
+ S.
+
+union(S1, S2) ->
+ S = Mod:union(S1, S2),
+ true = Equal(S, Mod:union(S2, S1)),
+ true = Mod:is_set(S),
+ S.
+
+union(Ss) ->
+ S = Mod:union(Ss),
+ true = Equal(S, Mod:union(lists:reverse(Ss))),
+ S.
+
+is_subset(S, Set) ->
+ case Mod:is_subset(S, Set) of
+ false -> false;
+ true ->
+ case Mod:is_subset(Set, S) of
+ false -> ok;
+ true ->
+ %% The sets are subsets of each other.
+ %% They must be equal.
+ true = Equal(S, Set)
+ end,
+ true
+ end.
+
+fold(F, A, S) ->
+ true = Mod:is_set(S),
+ Mod:fold(F, A, S).
+
+filter(F, S) ->
+ true = Mod:is_set(S),
+ Mod:filter(F, S).
diff --git a/lib/stdlib/test/shell_SUITE.erl b/lib/stdlib/test/shell_SUITE.erl
new file mode 100644
index 0000000000..5827d5f332
--- /dev/null
+++ b/lib/stdlib/test/shell_SUITE.erl
@@ -0,0 +1,2822 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(shell_SUITE).
+-export([all/1]).
+
+-export([forget/1, records/1, known_bugs/1, otp_5226/1, otp_5327/1,
+ otp_5435/1, otp_5195/1, otp_5915/1, otp_5916/1,
+ bits/1, bs_match_misc_SUITE/1, bs_match_int_SUITE/1,
+ bs_match_tail_SUITE/1, bs_match_bin_SUITE/1,
+ bs_construct_SUITE/1,
+ refman/1, refman_bit_syntax/1,
+ progex/1, progex_bit_syntax/1, progex_records/1,
+ progex_lc/1, progex_funs/1,
+ tickets/1, otp_5990/1, otp_6166/1, otp_6554/1, otp_6785/1,
+ otp_7184/1, otp_7232/1]).
+
+-export([restricted/1, start_restricted_from_shell/1,
+ start_restricted_on_command_line/1,restricted_local/1]).
+
+%% Internal export.
+-export([otp_5435_2/0]).
+
+%%
+%% Define to run outside of test server
+%%
+%% -define(STANDALONE,1).
+
+-ifdef(STANDALONE).
+-define(config(A,B),config(A,B)).
+-define(t,test_server).
+-export([config/2]).
+-define(line, noop, ).
+config(priv_dir,_) ->
+ ".".
+-else.
+-include("test_server.hrl").
+-export([init_per_testcase/2, fin_per_testcase/2]).
+% Default timetrap timeout (set in init_per_testcase).
+-define(default_timeout, ?t:minutes(2)).
+init_per_testcase(_Case, Config) ->
+ ?line Dog = ?t:timetrap(?default_timeout),
+ ?line OrigPath = code:get_path(),
+ ?line code:add_patha(?config(priv_dir,Config)),
+ [{orig_path,OrigPath}, {watchdog, Dog} | Config].
+
+fin_per_testcase(_Case, Config) ->
+ ?line Dog = ?config(watchdog, Config),
+ ?line test_server:timetrap_cancel(Dog),
+ ?line OrigPath = ?config(orig_path,Config),
+ ?line code:set_path(OrigPath),
+ ?line application:unset_env(stdlib, restricted_shell),
+ ?line (catch code:purge(user_default)),
+ ?line (catch code:delete(user_default)),
+ ok.
+-endif.
+
+all(doc) ->
+ ["Test cases for the 'shell' module."];
+all(suite) ->
+ [forget, records, known_bugs, otp_5226, otp_5327, otp_5435, otp_5195,
+ otp_5915, otp_5916, bits, refman, progex, tickets, restricted].
+
+-record(state, {bin, reply, leader}).
+
+restricted(doc) ->
+ ["Test restricted_shell"];
+restricted(suite) ->
+ [start_restricted_from_shell,start_restricted_on_command_line,restricted_local].
+
+start_restricted_from_shell(doc) ->
+ ["Test that a restricted shell can be started from the normal shell"];
+start_restricted_from_shell(suite) ->
+ [];
+start_restricted_from_shell(Config) when is_list(Config) ->
+ ?line [{error,nofile}] = scan(<<"begin shell:start_restricted("
+ "nonexisting_module) end.">>),
+ ?line Test = filename:join(?config(priv_dir, Config),
+ "test_restricted.erl"),
+ Contents = <<"-module(test_restricted).
+ -export([local_allowed/3, non_local_allowed/3]).
+ local_allowed(i,[],State) ->
+ {true,State};
+ local_allowed(ugly,[],_State) ->
+ non_conforming_reply;
+ local_allowed(_,_,State) ->
+ {false,State}.
+
+ non_local_allowed({shell,stop_restricted},[],State) ->
+ {true,State};
+ non_local_allowed({erlang,'+'},[_],State) ->
+ {true,State};
+ non_local_allowed({erlang,'-'},[_,_],_State) ->
+ non_conforming_reply;
+ non_local_allowed({h, d}, [Arg], S) ->
+ {{redirect, {erlang,hd}, [Arg]}, S};
+ non_local_allowed(_,_,State) ->
+ {false,State}.
+ ">>,
+ ?line ok = compile_file(Config, Test, Contents, []),
+ ?line "exception exit: restricted shell starts now" =
+ comm_err(<<"begin shell:start_restricted("
+ "test_restricted) end.">>),
+ ?line {ok, test_restricted} =
+ application:get_env(stdlib, restricted_shell),
+ ?line "Pid" ++ _ = t(<<"begin i() end.">>),
+ ?line "exception exit: restricted shell does not allow c(foo)" =
+ comm_err(<<"begin c(foo) end.">>),
+ ?line "exception exit: restricted shell does not allow init:stop()" =
+ comm_err(<<"begin init:stop() end.">>),
+ ?line "exception exit: restricted shell does not allow init:stop()" =
+ comm_err(<<"begin F = fun() -> init:stop() end, F() end.">>),
+ ?line "exception error: bad argument in an arithmetic expression" =
+ comm_err(<<"begin +a end.">>),
+ ?line "exception exit: restricted shell does not allow a + b" =
+ comm_err(<<"begin a+b end.">>),
+ ?line "exception exit: restricted shell does not allow - b" =
+ comm_err(<<"begin -b end.">>),
+ ?line "exception exit: restricted shell does not allow 1 + 2" =
+ comm_err(<<"begin if atom(1 + 2> 0) -> 1; true -> 2 end end.">>),
+ ?line "exception exit: restricted shell does not allow 1 + 2" =
+ comm_err(<<"begin if is_atom(1 + 2> 0) -> 1; true -> 2 end end.">>),
+ ?line "exception exit: restricted shell does not allow - 2" =
+ comm_err(<<"begin if - 2 -> 1; true -> 2 end end.">>),
+ ?line "exception exit: restricted shell does not allow - 2" =
+ comm_err(<<"begin if (- 2 > 0) andalso true -> 1; true -> 2 end end.">>),
+ ?line "exception exit: restricted shell does not allow - 2" =
+ comm_err(<<"begin if (- 2 > 0) orelse true -> 1; true -> 2 end end.">>),
+ ?line "exception exit: restricted shell does not allow 1 + 2" =
+ comm_err(<<"begin if 1 + 2 > 0 -> 1; true -> 2 end end.">>),
+ ?line "exception exit: restricted shell does not allow 1 + 2" =
+ comm_err(<<"begin if erlang:is_atom(1 + 2> 0) -> 1; true -> 2 end end.">>),
+ ?line "exception exit: restricted shell does not allow is_integer(1)" =
+ comm_err(<<"begin if is_integer(1) -> 1; true -> 2 end end.">>),
+ ?line "exception exit: restricted shell does not allow is_integer(1)" =
+ comm_err(<<"begin if integer(1) -> 1; true -> 2 end end.">>),
+ ?line "exception exit: "
+ "restricted shell module returned bad value non_conforming_reply" =
+ comm_err(<<"ugly().">>),
+ ?line [one] = scan(<<"h:d([one,two]).">>),
+ ?line "exception exit: "
+ "restricted shell module returned bad value non_conforming_reply" =
+ comm_err(<<"1 - 2.">>),
+ ?line "exception exit: restricted shell stopped"=
+ comm_err(<<"begin shell:stop_restricted() end.">>),
+ ?line undefined =
+ application:get_env(stdlib, restricted_shell),
+ ok.
+
+start_restricted_on_command_line(doc) ->
+ ["Check restricted shell when started from the command line"];
+start_restricted_on_command_line(suite) ->
+ [];
+start_restricted_on_command_line(Config) when is_list(Config) ->
+ ?line {ok,Node} = start_node(shell_suite_helper_1,
+ "-pa "++?config(priv_dir,Config)++
+ " -stdlib restricted_shell foo"),
+ ?line "Warning! Restricted shell module foo not found: nofile"++_ =
+ t({Node, <<"begin i() end.">>}),
+ ?line "exception exit: restricted shell does not allow i()" =
+ comm_err({Node, <<"begin i() end.">>}),
+ ?line [ok] =
+ (catch scan({Node, <<"begin q() end.">>})),
+ ?line test_server:stop_node(Node),
+ ?line Test = filename:join(?config(priv_dir, Config),
+ "test_restricted2.erl"),
+ Contents = <<"-module(test_restricted2).
+ -export([local_allowed/3, non_local_allowed/3]).
+ local_allowed(i,[],State) ->
+ {true,State};
+ local_allowed(_,_,State) ->
+ {false,State}.
+
+ non_local_allowed({shell,stop_restricted},[],State) ->
+ {true,State};
+ non_local_allowed({erlang,node},[],State) ->
+ {true,State};
+ non_local_allowed(_,_,State) ->
+ {false,State}.
+ ">>,
+ ?line ok = compile_file(Config, Test, Contents, []),
+ ?line {ok,Node2} = start_node(shell_suite_helper_2,
+ "-pa "++?config(priv_dir,Config)++
+ " -stdlib restricted_shell test_restricted2"),
+ ?line "Pid" ++ _ = t({Node2,<<"begin i() end.">>}),
+ ?line "exception exit: restricted shell does not allow c(foo)" =
+ comm_err({Node2,<<"begin c(foo) end.">>}),
+ ?line "exception exit: restricted shell does not allow init:stop()" =
+ comm_err({Node2,<<"begin init:stop() end.">>}),
+ ?line "exception exit: restricted shell does not allow init:stop()" =
+ comm_err({Node2,<<"begin F = fun() -> init:stop() end, F() end.">>}),
+ ?line [Node2] =
+ scan({Node2, <<"begin erlang:node() end.">>}),
+ ?line [Node2] =
+ scan({Node2, <<"begin node() end.">>}),
+ ?line "exception exit: restricted shell stopped"=
+ comm_err({Node2,<<"begin shell:stop_restricted() end.">>}),
+ ?line [ok] =
+ scan({Node2, <<"begin q() end.">>}),
+ ?line test_server:stop_node(Node2),
+ ok.
+
+restricted_local(suite) ->
+ [];
+restricted_local(doc) ->
+ ["Tests calling local shell functions with spectacular arguments in restricted shell"];
+restricted_local(Config) when is_list(Config) ->
+ ?line [{error,nofile}] = scan(<<"begin shell:start_restricted("
+ "nonexisting_module) end.">>),
+ ?line Test = filename:join(?config(priv_dir, Config),
+ "test_restricted_local.erl"),
+ Contents = <<"-module(test_restricted_local).
+ -export([local_allowed/3, non_local_allowed/3]).
+ local_allowed(i,[],State) ->
+ {true,State};
+ local_allowed(banan,_,State) ->
+ {true,State};
+ local_allowed(funkis,_,State) ->
+ {true,State};
+ local_allowed(c,_,State) ->
+ {true,State};
+ local_allowed(_,_,State) ->
+ {false,State}.
+
+ non_local_allowed({shell,stop_restricted},[],State) ->
+ {true,State};
+ non_local_allowed(_,_,State) ->
+ {false,State}.
+ ">>,
+ ?line ok = compile_file(Config, Test, Contents, []),
+ ?line Test2 = filename:join(?config(priv_dir, Config),
+ "user_default.erl"),
+ Contents2 = <<"-module(user_default).
+ -export([funkis/1,apple/1]).
+ funkis(F) when is_function(F) ->
+ funkis;
+ funkis(_) ->
+ nofunkis.
+ apple(_) ->
+ apple.
+ ">>,
+ ?line ok = compile_file(Config, Test2, Contents2, []),
+ ?line "exception exit: restricted shell starts now" =
+ comm_err(<<"begin shell:start_restricted("
+ "test_restricted_local) end.">>),
+ ?line {ok, test_restricted_local} =
+ application:get_env(stdlib, restricted_shell),
+ ?line "exception exit: restricted shell does not allow foo(" ++ _ =
+ comm_err(<<"begin F=fun() -> hello end, foo(F) end.">>),
+ ?line "exception error: undefined shell command banan/1" =
+ comm_err(<<"begin F=fun() -> hello end, banan(F) end.">>),
+ ?line "{error,"++_ = t(<<"begin F=fun() -> hello end, c(F) end.">>),
+ ?line "exception exit: restricted shell does not allow l(" ++ _ =
+ comm_err(<<"begin F=fun() -> hello end, l(F) end.">>),
+ ?line "exception error: variable 'F' is unbound" =
+ comm_err(<<"begin F=fun() -> hello end, f(F), F end.">>),
+ ?line [funkis] =
+ scan(<<"begin F=fun() -> hello end, funkis(F) end.">>),
+ ?line "exception exit: restricted shell does not allow apple(" ++ _ =
+ comm_err(<<"begin F=fun() -> hello end, apple(F) end.">>),
+ ?line "exception exit: restricted shell stopped"=
+ comm_err(<<"begin shell:stop_restricted() end.">>),
+ ?line undefined =
+ application:get_env(stdlib, restricted_shell),
+ ?line (catch code:purge(user_default)),
+ ?line true = (catch code:delete(user_default)),
+ ok.
+
+
+forget(doc) ->
+ ["f/0 and f/1"];
+forget(suite) ->
+ [];
+forget(Config) when is_list(Config) ->
+ %% f/0
+ ?line [ok] = scan(<<"begin f() end.">>),
+ ?line "1: variable 'A' is unbound" =
+ comm_err(<<"A = 3, f(), A.">>),
+ ?line [ok] = scan(<<"A = 3, A = f(), A.">>),
+
+ %% f/1
+ ?line [ok] = scan(<<"begin f(A) end.">>),
+ ?line "1: variable 'A' is unbound" =
+ comm_err(<<"A = 3, f(A), A.">>),
+ ?line [ok] = scan(<<"A = 3, A = f(A), A.">>),
+ ?line "exception error: no function clause matching call to f/1" =
+ comm_err(<<"f(a).">>),
+ ok.
+
+records(doc) ->
+ ["Test of the record support. OTP-5063."];
+records(suite) ->
+ [];
+records(Config) when is_list(Config) ->
+ %% rd/2
+ ?line [{attribute,_,record,{bar,_}},ok] =
+ scan(<<"rd(foo,{bar}),
+ rd(bar,{foo = (#foo{})#foo.bar}),
+ rl(bar).">>),
+ ?line "variable 'R' is unbound" = % used to work (before OTP-5878, R11B)
+ exit_string(<<"rd(foo,{bar}),
+ R = #foo{},
+ rd(bar,{foo = R#foo.bar}).">>),
+ ?line "exception error: no function clause matching call to rd/2" =
+ comm_err(<<"rd({foo},{bar}).">>),
+ ?line "bad record declaration" = exit_string(<<"A = bar, rd(foo,A).">>),
+ ?line [foo] = scan(<<"begin rd(foo,{bar}) end.">>),
+ ?line "1: record foo undefined" =
+ comm_err(<<"begin rd(foo,{bar}), #foo{} end.">>),
+ ?line ['f o o'] = scan(<<"rd('f o o', {bar}).">>),
+ ?line [foo] = scan(<<"rd(foo,{bar}), rd(foo,{foo = #foo{}}).">>),
+
+ %% rf/0,1
+ ?line [_, {attribute,_,record,{foo,_}},ok] =
+ scan(<<"rf('_'). rd(foo,{bar}),rl().">>),
+ ?line "1: record foo undefined" =
+ comm_err(<<"rd(foo,{bar}), #foo{}, rf(foo), #foo{}.">>),
+ ?line [ok,{foo,undefined}] =
+ scan(<<"rd(foo,{bar}), A = #foo{}, rf(foo). A.">>),
+ ?line [_] = scan(<<"begin rf() end.">>),
+ ?line [ok] = scan(<<"begin rf(foo) end.">>),
+
+ %% rp/1
+ ?line "#foo{bar = undefined}.\nok.\n" =
+ t(<<"rd(foo,{bar}), rp(#foo{}).">>),
+ ?line [{foo,3,4,3},ok] = scan(<<"rd(foo,{a = 3, b}), rp({foo,3,4,3}).">>),
+ ?line "#foo{a = 12}.\nok.\n" = t(<<"rd(foo,{a = 3}), rp({foo,12}).">>),
+ ?line [{[{foo}],12},ok] = scan(<<"rd(foo,{a = 3}), rp({[{foo}],12}).">>),
+
+ %% rr/1,2,3
+ MS = ?MODULE_STRING,
+ RR1 = "rr(" ++ MS ++ "). #state{}.",
+ ?line "[state]\n"
+ "#state{bin = undefined,reply = undefined,leader = undefined}.\n" =
+ t(RR1),
+ RR2 = "rr(" ++ MS ++ ",[state]). #state{}.",
+ ?line "[state]\n"
+ "#state{bin = undefined,reply = undefined,leader = undefined}.\n" =
+ t(RR2),
+ RR3 = "rr(" ++ MS ++ ",'_'). #state{}.",
+ ?line "[state]\n"
+ "#state{bin = undefined,reply = undefined,leader = undefined}.\n" =
+ t(RR3),
+ RR4 = "rr(" ++ MS ++ ", '_', {d,test1}).",
+ ?line [[state]] = scan(RR4),
+
+ Test = filename:join(?config(priv_dir, Config), "test.erl"),
+ Contents = <<"-module(test).
+ -record(state, {bin, reply, leader}).
+
+ -ifdef(test1).
+ -record(test1, {f}).
+ -endif.
+
+ -ifdef(test2).
+ -record(test2, {g}).
+ -endif.">>,
+ ?line ok = file:write_file(Test, Contents),
+
+ RR5 = "rr(\"" ++ Test ++ "\", '_', {d,test1}), rl([test1,test2]).",
+ ?line [{attribute,1,record,{test1,_}},ok] = scan(RR5),
+ RR6 = "rr(\"" ++ Test ++ "\", '_', {d,test2}), rl([test1,test2]).",
+ ?line [{attribute,1,record,{test2,_}},ok] = scan(RR6),
+ RR7 = "rr(\"" ++ Test ++
+ "\", '_', [{d,test1},{d,test2,17}]), rl([test1,test2]).",
+ ?line [{attribute,1,record,{test1,_}},{attribute,1,record,{test2,_}},
+ ok] = scan(RR7),
+ ?line PreReply = scan(<<"rr(prim_file).">>), % preloaded...
+ ?line true = is_list(PreReply),
+ ?line Dir = filename:join(?config(priv_dir, Config), "*.erl"),
+ ?line RR8 = "rp(rr(\"" ++ Dir ++ "\")).",
+ ?line [_,ok] = scan(RR8),
+ file:delete(Test),
+
+ RR1000 = "begin rr(" ++ MS ++ ") end.",
+ ?line [_] = scan(RR1000),
+ RR1001 = "begin rr(" ++ MS ++ ", state) end.",
+ ?line [_] = scan(RR1001),
+ RR1002 = "begin rr(" ++ MS ++ ", state,{i,'.'}) end.",
+ ?line [_] = scan(RR1002),
+
+ ?line [{error,nofile}] = scan(<<"rr(not_a_module).">>),
+ ?line [{error,invalid_filename}] = scan(<<"rr({foo}).">>),
+ ?line [[]] = scan(<<"rr(\"not_a_file\").">>),
+
+ %% using records
+ ?line [2] = scan(<<"rd(foo,{bar}), record_info(size, foo).">>),
+ ?line [true] = scan(<<"rd(foo,{bar}), is_record(#foo{}, foo).">>),
+ ?line [true] = scan(<<"rd(foo,{bar}), erlang:is_record(#foo{}, foo).">>),
+ ?line [true] = scan(<<"rd(foo,{bar}),
+ fun() when record(#foo{},foo) -> true end().">>),
+ ?line [2] = scan(<<"rd(foo,{bar}), #foo.bar.">>),
+ ?line "#foo{bar = 17}.\n" =
+ t(<<"rd(foo,{bar}), A = #foo{}, A#foo{bar = 17}.">>),
+
+ %% test of is_record/2 in lc
+ ?line "[#foo{bar = 3}].\n" =
+ t(<<"rd(foo,{bar}), [X || X <- [#foo{bar=3},x,[],{a,b}],"
+ "is_record(X, foo)].">>),
+ ?line "[x,[],{a,b}].\n" =
+ t(<<"rd(foo,{bar}), [X || X <- [#foo{bar=3},x,[],{a,b}],"
+ "not is_record(X, foo)].">>),
+ ?line "[#foo{bar = 3}].\n" =
+ t(<<"rd(foo,{bar}), [X || X <- [#foo{bar=3},x,[],{a,b}],"
+ "begin is_record(X, foo) end].">>),
+ ?line "[x,[],{a,b}].\n" =
+ t(<<"rd(foo,{bar}), [X || X <- [#foo{bar=3},x,[],{a,b}],"
+ "begin not is_record(X, foo) end].">>),
+
+ ?line "[#foo{bar = 3},x,[],{a,b}].\n" =
+ t(<<"rd(foo,{bar}), [X || X <- [#foo{bar=3},x,[],{a,b}],"
+ "is_record(X, foo) or not is_binary(X)].">>),
+ ?line "[#foo{bar = 3},x,[],{a,b}].\n" =
+ t(<<"rd(foo,{bar}), [X || X <- [#foo{bar=3},x,[],{a,b}],"
+ "not is_record(X, foo) or not is_binary(X)].">>),
+ ?line "[#foo{bar = 3}].\n" =
+ t(<<"rd(foo,{bar}), [X || X <- [#foo{bar=3},x,[],{a,b}],"
+ "is_record(X, foo) or is_reference(X)].">>),
+ ?line "[x,[],{a,b}].\n" =
+ t(<<"rd(foo,{bar}), [X || X <- [#foo{bar=3},x,[],{a,b}],"
+ "not is_record(X, foo) or is_reference(X)].">>),
+
+ ?line "[#foo{bar = 3},x,[],{a,b}].\n" =
+ t(<<"rd(foo,{bar}), [X || X <- [#foo{bar=3},x,[],{a,b}],"
+ "begin is_record(X, foo) or not is_binary(X) end].">>),
+ ?line "[#foo{bar = 3},x,[],{a,b}].\n" =
+ t(<<"rd(foo,{bar}), [X || X <- [#foo{bar=3},x,[],{a,b}],"
+ "begin not is_record(X, foo) or not is_binary(X) end].">>),
+ ?line "[#foo{bar = 3}].\n" =
+ t(<<"rd(foo,{bar}), [X || X <- [#foo{bar=3},x,[],{a,b}],"
+ "begin is_record(X, foo) or is_reference(X) end].">>),
+ ?line "[x,[],{a,b}].\n" =
+ t(<<"rd(foo,{bar}), [X || X <- [#foo{bar=3},x,[],{a,b}],"
+ "begin not is_record(X, foo) or is_reference(X) end].">>),
+
+ ?line [ok] =
+ scan(<<"rd(a,{}), is_record({a},a) andalso true, b().">>),
+
+ %% nested record defs
+ ?line "#b{a = #a{}}.\n" = t(<<"rd(a,{}), rd(b, {a = #a{}}), #b{}.">>),
+
+ ?line [ok,ok,ok] = scan(<<"rf('_'), rp(rp(rl(rf(rf(rf(rl())))))).">>),
+
+ ok.
+
+known_bugs(doc) ->
+ ["Known bugs."];
+known_bugs(suite) ->
+ [];
+known_bugs(Config) when is_list(Config) ->
+ %% erl_eval:merge_bindings/2 cannot handle _removal_ of bindings.
+ ?line [3] = scan(<<"A = 3, length(begin f(A), [3] end), A.">>),
+ ok.
+
+otp_5226(doc) ->
+ ["OTP-5226. Wildcards accepted when reading BEAM files using rr/1,2,3."];
+otp_5226(suite) ->
+ [];
+otp_5226(Config) when is_list(Config) ->
+ Test1 = <<"-module(test1).
+ -record('_test1', {a,b}).">>,
+ Test2 = <<"-module(test2).
+ -record('_test2', {c,d}).">>,
+ ?line File1 = filename("test1.erl", Config),
+ ?line File2 = filename("test2.erl", Config),
+ ?line Beam = filename("*.beam", Config),
+ ?line ok = compile_file(Config, File1, Test1, [no_debug_info]),
+ ?line ok = compile_file(Config, File2, Test2, [no_debug_info]),
+ RR = "rr(\"" ++ Beam ++ "\").",
+ ?line [Recs] = scan(RR),
+ ?line true = lists:member('_test1', Recs),
+ ?line true = lists:member('_test2', Recs),
+ file:delete(filename("test1.beam", Config)),
+ file:delete(filename("test2.beam", Config)),
+ file:delete(File1),
+ file:delete(File2),
+ ok.
+
+otp_5327(doc) ->
+ ["OTP-5226. Test of eval_bits, mostly."];
+otp_5327(suite) ->
+ [];
+otp_5327(Config) when is_list(Config) ->
+ ?line "exception error: bad argument" =
+ comm_err(<<"<<\"hej\":default>>.">>),
+ ?line <<"abc">> =
+ erl_parse:normalise({bin,1,[{bin_element,1,{string,1,"abc"},
+ default,default}]}),
+ ?line [<<"abc">>] = scan(<<"<<(<<\"abc\">>):3/binary>>.">>),
+ ?line [<<"abc">>] = scan(<<"<<(<<\"abc\">>)/binary>>.">>),
+ ?line "exception error: bad argument" =
+ comm_err(<<"<<(<<\"abc\">>):4/binary>>.">>),
+ ?line true = byte_size(hd(scan("<<3.14:64/float>>."))) =:= 8,
+ ?line true = byte_size(hd(scan("<<3.14:32/float>>."))) =:= 4,
+ ?line "exception error: bad argument" =
+ comm_err(<<"<<3.14:128/float>>.">>),
+ ?line "exception error: bad argument" =
+ comm_err(<<"<<10:default>>.">>),
+ ?line [<<98,1:1>>] = scan(<<"<<3:3,5:6>>.">>),
+ ?line {'EXIT',{badarg,_}} =
+ (catch erl_parse:normalise({bin,1,[{bin_element,1,{integer,1,17},
+ {atom,1,all},
+ default}]})),
+ ?line [<<-20/signed>>] = scan(<<"<<-20/signed>> = <<-20>>.">>),
+ ?line [<<-300:16/signed>>] =
+ scan(<<"<<-300:16/signed>> = <<-300:16>>.">>),
+ ?line [<<-1000:24/signed>>] =
+ scan(<<"<<-1000:24/signed>> = <<-1000:24>>.">>),
+ ?line [<<-(1 bsl 29):32/signed>>] =
+ scan(<<"<<-(1 bsl 29):32/signed>> = <<-(1 bsl 29):32>>.">>),
+
+ ?line "exception error: no match of right hand side value <<0,0,0>>" =
+ comm_err(<<"<<B:3/unit:7-binary,_/binary>> = <<0:24>>.">>),
+ ?line true = [<<103133:64/float>>] =:=
+ scan(<<"<<103133:64/float>> = <<103133:64/float>>.">>),
+ ?line true = [<<103133.0:64/float>>] =:=
+ scan(<<"<<103133.0:64/float>> = <<103133:64/float>>.">>),
+ ?line true = [<<103133:64/float>>] =:= scan(<<"<<103133:64/float>>.">>),
+ Int = 17,
+ ?line true = [<<Int:64/float>>] =:= scan(<<"Int = 17, <<Int:64/float>>.">>),
+ ?line "exception error: no match of right hand side value" ++ _ =
+ comm_err(<<"<<103133:64/binary>> = <<103133:64/float>>.">>),
+ ?line "exception error: interpreted function with arity 1 called with two arguments" =
+ comm_err(<<"(fun(X) -> X end)(a,b).">>),
+ ?line {'EXIT', {{illegal_pattern,_}, _}} =
+ (catch evaluate("<<A:a>> = <<17:32>>.", [])),
+ C = <<"
+ <<A:4,B:4,C:4,D:4,E:4,F:4>> = <<\"hej\">>,
+ case <<7:4,A:4,B:4,C:4,D:4,E:4,F:4,3:4>> of
+ <<_:4,\"hej\",3:4>> -> 1;
+ _ -> 2
+ end.
+ ">>,
+ ?line 1 = evaluate(C, []),
+ %% unbound_var would be nicer...
+ ?line {'EXIT',{{illegal_pattern,_},_}} =
+ (catch evaluate(<<"<<A:B>> = <<17:32>>.">>, [])),
+ %% undefined_bittype is turned into badmatch:
+ ?line {'EXIT',{{badmatch,<<17:32>>},_}} =
+ (catch evaluate(<<"<<A/apa>> = <<17:32>>.">>, [])),
+ ?line {'EXIT',_} =
+ (catch evaluate(<<"<<17/binary-unit:8-unit:16>>.">>, [])),
+ ?line {'EXIT',_} =
+ (catch evaluate(<<"<<17:32/unsigned-signed>> = <<17:32>>.">>, [])),
+ ?line {'EXIT',_} =
+ (catch evaluate(<<"<<17:32/unsigned-signed>>.">>, [])),
+ ?line <<17:32>> = evaluate(<<"<<17:32/signed-signed>>.">>, []),
+ ?line {'EXIT',_} =
+ (catch evaluate(<<"<<32/unit:8>>.">>, [])),
+ ok.
+
+otp_5435(doc) ->
+ ["OTP-5435. sys_pre_expand not in the path."];
+otp_5435(suite) ->
+ [];
+otp_5435(Config) when is_list(Config) ->
+ ?line true = <<103133:64/float>> =:=
+ evaluate(<<"<<103133:64/float>> = <<103133:64/float>>.">>, []),
+ ?line true = <<103133.0:64/float>> =:=
+ evaluate(<<"<<103133.0:64/float>> = <<103133:64/float>>.">>, []),
+ ?line true = is_alive(),
+ ?line {ok, Node} = start_node(shell_SUITE_otp_5435),
+ ?line ok = rpc:call(Node, ?MODULE, otp_5435_2, []),
+ ?line ?t:stop_node(Node),
+ ok.
+
+start_node(Name) ->
+ ?line PA = filename:dirname(code:which(?MODULE)),
+ ?t:start_node(Name, slave, [{args, "-pa " ++ PA}]).
+
+otp_5435_2() ->
+ ?line true = code:del_path(compiler),
+ %% sys_pre_expand can no longer be found
+ %% OTP-5876. But erl_expand_records can!
+ ?line [{attribute,_,record,{bar,_}},ok] =
+ scan(<<"rd(foo,{bar}),
+ rd(bar,{foo = (#foo{})#foo.bar}),
+ rl(bar).">>),
+ ok.
+
+otp_5195(doc) ->
+ ["OTP-5195. QLC, mostly."];
+otp_5195(suite) ->
+ [];
+otp_5195(Config) when is_list(Config) ->
+ %% QLC. It was easier to put these cases here than in qlc_SUITE.
+ ?line "[#a{b = undefined}].\n" =
+ t(<<"rd(a,{b}), qlc:e(qlc:q([X || X <- [#a{}],is_record(X, a)])).">>),
+
+ %% An experimental shell used to translate error tuples:
+ %% "(qlc) \"1: generated variable 'X' must not be used in "
+ %% "list expression\".\n" =
+ %% t(<<"qlc:q([X || X <- [{a}], Y <- [X]]).">>),
+ %% Same as last one (if the shell does not translate error tuples):
+ ?line [{error,qlc,{1,qlc,{used_generator_variable,'X'}}}] =
+ scan(<<"qlc:q([X || X <- [{a}], Y <- [X]]).">>),
+ ?line {error,qlc,{1,qlc,{used_generator_variable,'X'}}} =
+ evaluate(<<"qlc:q([X || X <- [{a}], Y <- [X]]).">>, []),
+ Ugly = <<"qlc:e(qlc:q([X || X <- qlc:append([[1,2,3],ugly()])])).">>,
+ ?line "undefined shell command ugly/0" = error_string(Ugly),
+ ?line {'EXIT',{undef,_}} = (catch evaluate(Ugly, [])),
+
+ V_1 = <<"qlc:e(qlc:q([X || X <- qlc:append([[1,2,3],v(-1)])])).">>,
+ ?line "- 1: command not found" = comm_err(V_1),
+ ?line {'EXIT', {undef,_}} = (catch evaluate(V_1, [])),
+
+ ?line "1\n2\n3\n3.\n" =
+ t(<<"1. 2. 3. 3 = fun(A) when A =:= 2 -> v(3) end(v(2)).">>),
+
+ ?line List4 = t(<<"[a,list]. A = [1,2]. "
+ "qlc:q([X || X <- qlc:append(A, v(1))]). "
+ "[1,2,a,list] = qlc:e(v(-1)).">>),
+ ?line "[1,2,a,list].\n" = string:substr(List4, string:len(List4)-13),
+
+ ok.
+
+otp_5915(doc) ->
+ ["OTP-5915. Strict record tests in guards."];
+otp_5915(suite) ->
+ [];
+otp_5915(Config) when is_list(Config) ->
+ C = <<"
+ rd(r, {a = 4,b}),
+ rd(r1, {a,b}),
+ rd(r2, {a = #r1{},b,c=length([1,2,3])}),
+ rd(r3, {a = fun(_) -> #r1{} end(1), b}),
+
+ foo = fun(A) when A#r1.a > A#r1.b -> foo end(#r1{b = 2}),
+ 0 = fun(A) when A#r2.a -> 0 end(#r2{a = true}),
+ 1 = fun(A) when (#r1{a = A})#r1.a > 2 -> 1 end(3),
+ 2 = fun(N) when ((#r2{a = #r{a = 4}, b = length([a,b,c])})#r2.a)#r.a > N ->
+ 2 end(2),
+ 3 = fun(A) when (A#r2.a)#r1.a =:= 3 -> 3 end(#r2{a = #r1{a = 3}}),
+ ok = fun() ->
+ F = fun(A) when record(A#r.a, r1) -> 4;
+ (A) when record(A#r1.a, r1) -> 5
+ end,
+ 5 = F(#r1{a = #r1{}}),
+ 4 = F(#r{a = #r1{}}),
+ ok
+ end(),
+ 3 = fun(A) when record(A#r1.a, r),
+ (A#r1.a)#r.a > 3 -> 3
+ end(#r1{a = #r{a = 4}}),
+ 7 = fun(A) when record(A#r3.a, r1) -> 7 end(#r3{}),
+ [#r1{a = 2,b = 1}] =
+ fun() ->
+ [A || A <- [#r1{a = 1, b = 3},
+ #r2{a = 2,b = 1},
+ #r1{a = 2, b = 1}],
+ A#r1.a >
+ A#r1.b]
+ end(),
+ {[_],b} =
+ fun(L) ->
+ %% A is checked only once:
+ R1 = [{A,B} || A <- L, A#r1.a, B <- L, A#r1.b],
+ A = #r2{a = true},
+ %% A is checked again:
+ B = if A#r1.a -> a; true -> b end,
+ {R1,B}
+ end([#r1{a = true, b = true}]),
+
+ p = fun(A) when (A#r1.a =:= 2) or (A#r2.a =:= 1) -> o;
+ (_) -> p
+ end(#r1{a = 2}),
+
+ o = fun(A) when (A#r1.a =:= 2) orelse (A#r2.a =:= 1) -> o;
+ (_) -> p
+ end(#r1{a = 2}),
+
+ 3 = fun(A) when A#r1.a > 3,
+ record(A, r1) -> 3
+ end(#r1{a = 5}),
+
+ ok = fun() ->
+ F = fun(A) when (A#r2.a =:= 1) orelse (A#r2.a) -> 2;
+ (A) when (A#r1.a =:= 1) orelse (A#r1.a) -> 1;
+ (A) when (A#r2.a =:= 2) andalso (A#r2.b) -> 3
+ end,
+ 1 = F(#r1{a = 1}),
+ 2 = F(#r2{a = true}),
+ 3 = F(#r2{a = 2, b = true}),
+ ok
+ end(),
+
+ b = fun(A) when false or not (A#r.a =:= 1) -> a;
+ (_) -> b
+ end(#r1{a = 1}),
+ b = fun(A) when not (A#r.a =:= 1) or false -> a;
+ (_) -> b
+ end(#r1{a = 1}),
+
+ ok = fun() ->
+ F = fun(A) when not (A#r.a =:= 1) -> yes;
+ (_) -> no
+ end,
+ no = F(#r1{a = 2}),
+ yes = F(#r{a = 2}),
+ no = F(#r{a = 1}),
+ ok
+ end(),
+
+ a = fun(A) when record(A, r),
+ A#r.a =:= 1,
+ A#r.b =:= 2 ->a
+ end(#r{a = 1, b = 2}),
+ a = fun(A) when erlang:is_record(A, r),
+ A#r.a =:= 1,
+ A#r.b =:= 2 -> a
+ end(#r{a = 1, b = 2}),
+ a = fun(A) when is_record(A, r),
+ A#r.a =:= 1,
+ A#r.b =:= 2 -> a
+ end(#r{a = 1, b = 2}),
+
+ nop = fun(A) when (is_record(A, r1) and (A#r1.a > 3)) or (A#r2.a < 1) ->
+ japp;
+ (_) ->
+ nop
+ end(#r2{a = 0}),
+ nop = fun(A) when (A#r1.a > 3) or (A#r2.a < 1) -> japp;
+ (_) ->
+ nop
+ end(#r2{a = 0}),
+
+ ok = fun() ->
+ F = fun(A) when (A#r1.a =:= 2) or (A#r2.a =:= 1) -> o;
+ (_) -> p
+ end,
+ p = F(#r2{a = 1}),
+ p = F(#r1{a = 2}),
+ ok
+ end(),
+
+ ok = fun() ->
+ F = fun(A) when fail, A#r1.a; A#r1.a -> ab;
+ (_) -> bu
+ end,
+ ab = F(#r1{a = true}),
+ bu = F(#r2{a = true}),
+ ok
+ end(),
+
+ both = fun(A) when A#r.a, A#r.b -> both
+ end(#r{a = true, b = true}),
+
+ ok = fun() ->
+ F = fun(A, B) when ((A#r1.a) orelse (B#r2.a))
+ or (B#r2.b) or (A#r1.b) -> true;
+ (_, _) -> false
+ end,
+ true = F(#r1{a = false, b = false}, #r2{a = false, b = true}),
+ false = F(#r1{a = true, b = true}, #r1{a = false, b = true}),
+ ok
+ end(),
+
+ ok.">>,
+ [ok] = scan(C),
+ ok.
+
+otp_5916(doc) ->
+ ["OTP-5916. erlang:is_record/3 allowed in guards."];
+otp_5916(suite) ->
+ [];
+otp_5916(Config) when is_list(Config) ->
+ C = <<"
+ rd(r1, {a,b}),
+ rd(r2, {a,b}),
+
+ true = if erlang:is_record(#r1{},r1,3) -> true; true -> false end,
+ false = if erlang:is_record(#r2{},r1,3) -> true; true -> false end,
+
+ true = if is_record(#r1{},r1,3) -> true; true -> false end,
+ false = if is_record(#r2{},r1,3) -> true; true -> false end,
+
+ true = if {erlang,is_record}(#r1{},r1,3) -> true; true -> false end,
+ false = if {erlang,is_record}(#r2{},r1,3) -> true; true -> false end,
+
+ ok.">>,
+ [ok] = scan(C),
+ ok.
+
+bits(suite) ->
+ [bs_match_misc_SUITE, % bs_match_int_SUITE/,
+ bs_match_tail_SUITE, bs_match_bin_SUITE, bs_construct_SUITE].
+
+bs_match_misc_SUITE(doc) ->
+ ["OTP-5327. Adopted from parts of emulator/test/bs_match_misc_SUITE.erl."];
+bs_match_misc_SUITE(suite) ->
+ [];
+bs_match_misc_SUITE(Config) when is_list(Config) ->
+ C = <<"
+ F1 = fun() -> 3.1415 end,
+
+ FOne = fun() -> 1.0 end,
+
+ Fcmp = fun(F1, F2) when (F1 - F2) / F2 < 0.0000001 -> ok end,
+
+ MakeSubBin = fun(Bin0) ->
+ Sz = size(Bin0),
+ Bin1 = <<37,Bin0/binary,38,39>>,
+ <<_:8,Bin:Sz/binary,_:8,_:8>> = Bin1,
+ Bin
+ end,
+
+ MatchFloat =
+ fun(Bin0, Fsz, I) ->
+ Bin = MakeSubBin(Bin0),
+ Bsz = size(Bin) * 8,
+ Tsz = Bsz - Fsz - I,
+ <<_:I,F:Fsz/float,_:Tsz>> = Bin,
+ F
+ end,
+
+ TFloat = fun() ->
+ F = F1(),
+ G = FOne(),
+
+ G = MatchFloat(<<63,128,0,0>>, 32, 0),
+ G = MatchFloat(<<63,240,0,0,0,0,0,0>>, 64, 0),
+
+ Fcmp(F, MatchFloat(<<F:32/float>>, 32, 0)),
+ Fcmp(F, MatchFloat(<<F:64/float>>, 64, 0)),
+ Fcmp(F, MatchFloat(<<1:1,F:32/float,127:7>>, 32, 1)),
+ Fcmp(F, MatchFloat(<<1:1,F:64/float,127:7>>, 64, 1)),
+ Fcmp(F, MatchFloat(<<1:13,F:32/float,127:3>>, 32, 13)),
+ Fcmp(F, MatchFloat(<<1:13,F:64/float,127:3>>, 64, 13))
+ end,
+ TFloat(),
+
+ F2 = fun() -> 2.7133 end,
+
+ MatchFloatLittle = fun(Bin0, Fsz, I) ->
+ Bin = MakeSubBin(Bin0),
+ Bsz = size(Bin) * 8,
+ Tsz = Bsz - Fsz - I,
+ <<_:I,F:Fsz/float-little,_:Tsz>> = Bin,
+ F
+ end,
+
+ LittleFloat = fun() ->
+ F = F2(),
+ G = FOne(),
+
+ G = MatchFloatLittle(<<0,0,0,0,0,0,240,63>>, 64, 0),
+ G = MatchFloatLittle(<<0,0,128,63>>, 32, 0),
+
+ Fcmp(F, MatchFloatLittle(<<F:32/float-little>>, 32, 0)),
+ Fcmp(F, MatchFloatLittle(<<F:64/float-little>>, 64, 0)),
+ Fcmp(F, MatchFloatLittle(<<1:1,F:32/float-little,127:7>>, 32, 1)),
+ Fcmp(F, MatchFloatLittle(<<1:1,F:64/float-little,127:7>>, 64, 1)),
+ Fcmp(F, MatchFloatLittle(<<1:13,F:32/float-little,127:3>>, 32, 13)),
+ Fcmp(F, MatchFloatLittle(<<1:13,F:64/float-little,127:3>>, 64, 13))
+ end,
+ LittleFloat(),
+
+ Sean1 = fun(<<B/binary>>) when size(B) < 4 -> small;
+ (<<1, _B/binary>>) -> large
+ end,
+
+ Sean = fun() ->
+ small = Sean1(<<>>),
+ small = Sean1(<<1>>),
+ small = Sean1(<<1,2>>),
+ small = Sean1(<<1,2,3>>),
+ large = Sean1(<<1,2,3,4>>),
+
+ small = Sean1(<<4>>),
+ small = Sean1(<<4,5>>),
+ small = Sean1(<<4,5,6>>),
+ {'EXIT',{function_clause,_}} = (catch Sean1(<<4,5,6,7>>))
+ end,
+ Sean(),
+
+ NativeBig = fun() ->
+ <<37.33:64/native-float>> = <<37.33:64/big-float>>,
+ <<3974:16/native-integer>> = <<3974:16/big-integer>>
+ end,
+
+ NativeLittle = fun() ->
+ <<37869.32343:64/native-float>> = <<37869.32343:64/little-float>>,
+ <<7974:16/native-integer>> = <<7974:16/little-integer>>
+ end,
+
+ Native = fun() ->
+ <<3.14:64/native-float>> = <<3.14:64/native-float>>,
+ <<333:16/native>> = <<333:16/native>>,
+ <<38658345:32/native>> = <<38658345:32/native>>,
+ case <<1:16/native>> of
+ <<0,1>> -> NativeBig();
+ <<1,0>> -> NativeLittle()
+ end
+ end,
+ Native(),
+
+ Split = fun(<<N:16,B:N/binary,T/binary>>) -> {B,T} end,
+
+ Split2 = fun(N, <<N:16,B:N/binary,T/binary>>) -> {B,T} end,
+
+ Split_2 = fun(<<N0:8,N:N0,B:N/binary,T/binary>>) -> {B,T} end,
+
+ Skip = fun(<<N:8,_:N/binary,T/binary>>) -> T end,
+
+ SizeVar = fun() ->
+ {<<45>>,<<>>} = Split(<<1:16,45>>),
+ {<<45>>,<<46,47>>} = Split(<<1:16,45,46,47>>),
+ {<<45,46>>,<<47>>} = Split(<<2:16,45,46,47>>),
+
+ {<<45,46,47>>,<<48>>} = Split_2(<<16:8,3:16,45,46,47,48>>),
+
+ {<<45,46>>,<<47>>} = Split2(2, <<2:16,45,46,47>>),
+ {'EXIT',{function_clause,_}} =
+ (catch Split2(42, <<2:16,45,46,47>>)),
+
+ <<\"cdef\">> = Skip(<<2:8,\"abcdef\">>)
+ end,
+ SizeVar(),
+
+ Wcheck = fun(<<A>>) when A==3-> ok1;
+ (<<_,_:2/binary>>) -> ok2;
+ (<<_>>) -> ok3;
+ (Other) -> {error,Other}
+ end,
+
+ Wiger = fun() ->
+ ok1 = Wcheck(<<3>>),
+ ok2 = Wcheck(<<1,2,3>>),
+ ok3 = Wcheck(<<4>>),
+ {error,<<1,2,3,4>>} = Wcheck(<<1,2,3,4>>),
+ {error,<<>>} = Wcheck(<<>>)
+ end,
+ Wiger(),
+
+ ok.
+ ">>,
+ [ok] = scan(C),
+ ok = evaluate(C, []).
+
+%% This one is not run during night builds since it takes several minutes.
+bs_match_int_SUITE(doc) ->
+ ["OTP-5327. Adopted from emulator/test/bs_match_int_SUITE.erl."];
+bs_match_int_SUITE(suite) ->
+ [];
+bs_match_int_SUITE(Config) when is_list(Config) ->
+ C = <<"
+ FunClause = fun({'EXIT',{function_clause,_}}) -> ok end,
+
+ Mkbin = fun(L) when list(L) -> list_to_binary(L) end,
+
+ GetInt1 = fun(<<I:0>>) -> I;
+ (<<I:8>>) -> I;
+ (<<I:16>>) -> I;
+ (<<I:24>>) -> I;
+ (<<I:32>>) -> I
+ end,
+
+ GetInt2 = fun(Bin0, I, F) when size(Bin0) < 4 ->
+ Bin = <<0,Bin0/binary>>,
+ I = GetInt1(Bin),
+ F(Bin, I, F);
+ (_, I, _F) -> I
+ end,
+
+ GetInt = fun(Bin) ->
+ I = GetInt1(Bin),
+ GetInt2(Bin, I, GetInt2)
+ end,
+
+
+ Cmp128 = fun(<<I:128>>, I) -> equal;
+ (_, _) -> not_equal
+ end,
+
+ Uint2 = fun([H|T], Acc, F) -> F(T, Acc bsl 8 bor H, F);
+ ([], Acc, _F) -> Acc
+ end,
+
+ Uint = fun(L) -> Uint2(L, 0, Uint2) end,
+
+ Integer = fun() ->
+ 0 = GetInt(Mkbin([])),
+ 0 = GetInt(Mkbin([0])),
+ 42 = GetInt(Mkbin([42])),
+ 255 = GetInt(Mkbin([255])),
+ 256 = GetInt(Mkbin([1,0])),
+ 257 = GetInt(Mkbin([1,1])),
+ 258 = GetInt(Mkbin([1,2])),
+ 258 = GetInt(Mkbin([1,2])),
+ 65534 = GetInt(Mkbin([255,254])),
+ 16776455 = GetInt(Mkbin([255,253,7])),
+ 4245492555 = GetInt(Mkbin([253,13,19,75])),
+ 4294967294 = GetInt(Mkbin([255,255,255,254])),
+ 4294967295 = GetInt(Mkbin([255,255,255,255])),
+ Eight = [200,1,19,128,222,42,97,111],
+ Cmp128(Eight, Uint(Eight)),
+ FunClause(catch GetInt(Mkbin(lists:seq(1,5))))
+ end,
+ Integer(),
+
+ Sint = fun(Bin) ->
+ case Bin of
+ <<I:8/signed>> -> I;
+ <<I:8/signed,_:3,_:5>> -> I;
+ Other -> {no_match,Other}
+ end
+ end,
+
+ SignedInteger = fun() ->
+ {no_match,_} = Sint(Mkbin([])),
+ {no_match,_} = Sint(Mkbin([1,2,3])),
+ 127 = Sint(Mkbin([127])),
+ -1 = Sint(Mkbin([255])),
+ -128 = Sint(Mkbin([128])),
+ 42 = Sint(Mkbin([42,255])),
+ 127 = Sint(Mkbin([127,255]))
+ end,
+ SignedInteger(),
+
+ Dynamic5 = fun(Bin, S1, S2, A, B) ->
+ case Bin of
+ <<A:S1,B:S2>> ->
+ % io:format(\"~p ~p ~p ~p~n\", [S1,S2,A,B]),
+ ok;
+ _Other -> erlang:error(badmatch, [Bin,S1,S2,A,B])
+ end
+ end,
+
+ Dynamic2 = fun(Bin, S1, F) when S1 >= 0 ->
+ S2 = size(Bin) * 8 - S1,
+ Dynamic5(Bin, S1, S2, (1 bsl S1) - 1, (1 bsl S2) - 1),
+ F(Bin, S1-1, F);
+ (_, _, _) -> ok
+ end,
+
+ Dynamic = fun(Bin, S1) ->
+ Dynamic2(Bin, S1, Dynamic2)
+ end,
+
+ Dynamic(Mkbin([255]), 8),
+ Dynamic(Mkbin([255,255]), 16),
+ Dynamic(Mkbin([255,255,255]), 24),
+ Dynamic(Mkbin([255,255,255,255]), 32),
+
+ BigToLittle4 =
+ fun([B0,B1,B2,B3,B4,B5,B6,B7|T], N, Acc, F) when N >= 8 ->
+ F(T, N-8, [B0,B1,B2,B3,B4,B5,B6,B7|Acc], F);
+ (List, N, Acc, _F) -> lists:sublist(List, 1, N) ++ Acc
+ end,
+
+ BigToLittle =
+ fun(List, N) -> BigToLittle4(List, N, [], BigToLittle4) end,
+
+ ReversedSublist =
+ fun(_List, 0, Acc, _F) -> Acc;
+ ([H|T], N, Acc, F) -> F(T, N-1, [H|Acc], F)
+ end,
+
+ TwoComplementAndReverse =
+ fun([H|T], Carry, Acc, F) ->
+ Sum = 1-H+Carry,
+ F(T, Sum div 2, [Sum rem 2|Acc], F);
+ ([], Carry, Acc, _F) -> [Carry|Acc]
+ end,
+
+ MakeInt = fun(_List, 0, Acc, _F) -> Acc;
+ ([H|T], N, Acc, F) -> F(T, N-1, Acc bsl 1 bor H, F)
+ end,
+
+ MakeSignedInt =
+ fun(_List, 0) -> 0;
+ ([0|_]=List, N) -> MakeInt(List, N, 0, MakeInt);
+ ([1|_]=List0, N) ->
+ List1 = ReversedSublist(List0, N, [], ReversedSublist),
+ List2 = TwoComplementAndReverse(List1, 1, [],
+ TwoComplementAndReverse),
+ -MakeInt(List2, length(List2), 0, MakeInt)
+ end,
+
+ BitsToList =
+ fun([H|T], 0, F) -> F(T, 16#80, F);
+ ([H|_]=List, Mask, F) ->
+ [case H band Mask of
+ 0 -> 0;
+ _ -> 1
+ end | F(List, Mask bsr 1, F)];
+ ([], _, _F) -> []
+ end,
+
+ MoreDynamic3 =
+ fun(Action, Bin, List, Bef, Aft, F) when Bef =< Aft ->
+ Action(Bin, List, Bef, Aft-Bef),
+ F(Action, Bin, List, Bef, Aft-1, F);
+ (_, _, _, _, _, _) -> ok
+ end,
+
+ MoreDynamic2 =
+ fun(Action, Bin, [_|T]=List, Bef, F) ->
+ MoreDynamic3(Action, Bin, List, Bef, size(Bin)*8,
+ MoreDynamic3),
+ F(Action, Bin, T, Bef+1, F);
+ (_, _, [], _, _F) -> ok
+ end,
+
+ MoreDynamic1 =
+ fun(Action, Bin) ->
+ BitList = BitsToList(binary_to_list(Bin),16#80,BitsToList),
+ MoreDynamic2(Action, Bin, BitList, 0, MoreDynamic2)
+ end,
+
+ MoreDynamic = fun() ->
+ % Unsigned big-endian numbers.
+ Unsigned = fun(Bin, List, SkipBef, N) ->
+ SkipAft = 8*size(Bin) - N - SkipBef,
+ <<_:SkipBef,Int:N,_:SkipAft>> = Bin,
+ Int = MakeInt(List, N, 0, MakeInt)
+ end,
+ MoreDynamic1(Unsigned, erlang:md5(Mkbin([42]))),
+
+ %% Signed big-endian numbers.
+ Signed = fun(Bin, List, SkipBef, N) ->
+ SkipAft = 8*size(Bin) - N - SkipBef,
+ <<_:SkipBef,Int:N/signed,_:SkipAft>> = Bin,
+ case MakeSignedInt(List, N) of
+ Int -> ok;
+ Other ->
+ io:format(\"Bin = ~p,\", [Bin]),
+ io:format(\"SkipBef = ~p, N = ~p\",
+ [SkipBef,N]),
+ io:format(\"Expected ~p, got ~p\",
+ [Int,Other])
+ end
+ end,
+ MoreDynamic1(Signed, erlang:md5(Mkbin([43]))),
+
+ %% Unsigned little-endian numbers.
+ UnsLittle = fun(Bin, List, SkipBef, N) ->
+ SkipAft = 8*size(Bin) - N - SkipBef,
+ <<_:SkipBef,Int:N/little,_:SkipAft>> = Bin,
+ Int = MakeInt(BigToLittle(List, N), N, 0,
+ MakeInt)
+ end,
+ MoreDynamic1(UnsLittle, erlang:md5(Mkbin([44]))),
+
+ %% Signed little-endian numbers.
+ SignLittle = fun(Bin, List, SkipBef, N) ->
+ SkipAft = 8*size(Bin) - N - SkipBef,
+ <<_:SkipBef,Int:N/signed-little,_:SkipAft>> = Bin,
+ Little = BigToLittle(List, N),
+ Int = MakeSignedInt(Little, N)
+ end,
+ MoreDynamic1(SignLittle, erlang:md5(Mkbin([45])))
+ end,
+ MoreDynamic(),
+
+ ok.
+ ">>,
+ [ok] = scan(C),
+ ok = evaluate(C, []).
+
+bs_match_tail_SUITE(doc) ->
+ ["OTP-5327. Adopted from emulator/test/bs_match_tail_SUITE.erl."];
+bs_match_tail_SUITE(suite) ->
+ [];
+bs_match_tail_SUITE(Config) when is_list(Config) ->
+ C = <<"
+ GetTailUsed = fun(<<A:1,T/binary>>) -> {A,T} end,
+
+ GetTailUnused = fun(<<A:15,_/binary>>) -> A end,
+
+ GetDynTailUsed = fun(Bin, Sz) ->
+ <<A:Sz,T/binary>> = Bin,
+ {A,T}
+ end,
+
+ GetDynTailUnused = fun(Bin, Sz) ->
+ <<A:Sz,_/binary>> = Bin,
+ A
+ end,
+
+ Mkbin = fun(L) when list(L) -> list_to_binary(L) end,
+
+ TestZeroTail = fun(<<A:8>>) -> A end,
+
+ TestZeroTail2 = fun(<<_A:4,_B:4>>) -> ok end,
+
+ ZeroTail = fun() ->
+ 7 = (catch TestZeroTail(Mkbin([7]))),
+ {'EXIT',{function_clause,_}} =
+ (catch TestZeroTail(Mkbin([1,2]))),
+ {'EXIT',{function_clause,_}} =
+ (catch TestZeroTail2(Mkbin([1,2,3])))
+ end,
+ ZeroTail(),
+
+ AlGetTailUsed = fun(<<A:16,T/binary>>) -> {A,T} end,
+
+ AlGetTailUnused = fun(<<A:16,_/binary>>) -> A end,
+
+ Aligned = fun() ->
+ Tail1 = Mkbin([]),
+ {258,Tail1} = AlGetTailUsed(Mkbin([1,2])),
+ Tail2 = Mkbin(lists:seq(1, 127)),
+ {35091,Tail2} = AlGetTailUsed(Mkbin([137,19|Tail2])),
+
+ 64896 = AlGetTailUnused(Mkbin([253,128])),
+ 64895 = AlGetTailUnused(Mkbin([253,127|lists:seq(42, 255)])),
+
+ Tail3 = Mkbin(lists:seq(0, 19)),
+ {0,Tail1} = GetDynTailUsed(Tail1, 0),
+ {0,Tail3} = GetDynTailUsed(Mkbin([Tail3]), 0),
+ {73,Tail3} = GetDynTailUsed(Mkbin([73|Tail3]), 8),
+
+ 0 = GetDynTailUnused(Mkbin([]), 0),
+ 233 = GetDynTailUnused(Mkbin([233]), 8),
+ 23 = GetDynTailUnused(Mkbin([23,22,2]), 8)
+ end,
+ Aligned(),
+
+ UnAligned = fun() ->
+ {'EXIT',{function_clause,_}} =
+ (catch GetTailUsed(Mkbin([42]))),
+ {'EXIT',{{badmatch,_},_}} =
+ (catch GetDynTailUsed(Mkbin([137]), 3)),
+ {'EXIT',{function_clause,_}} =
+ (catch GetTailUnused(Mkbin([42,33]))),
+ {'EXIT',{{badmatch,_},_}} =
+ (catch GetDynTailUnused(Mkbin([44]), 7))
+ end,
+ UnAligned(),
+ ok.
+ ">>,
+ [ok] = scan(C),
+ ok = evaluate(C, []).
+
+bs_match_bin_SUITE(doc) ->
+ ["OTP-5327. Adopted from emulator/test/bs_match_bin_SUITE.erl."];
+bs_match_bin_SUITE(suite) ->
+ [];
+bs_match_bin_SUITE(Config) when is_list(Config) ->
+ ByteSplitBinary =
+ <<"ByteSplit =
+ fun(L, B, Pos, Fun) when Pos >= 0 ->
+ Sz1 = Pos,
+ Sz2 = size(B) - Pos,
+ <<B1:Sz1/binary,B2:Sz2/binary>> = B,
+ B1 = list_to_binary(lists:sublist(L, 1, Pos)),
+ B2 = list_to_binary(lists:nthtail(Pos, L)),
+ Fun(L, B, Pos-1, Fun);
+ (L, B, _, _Fun) -> ok
+ end,
+ Mkbin = fun(L) when list(L) -> list_to_binary(L) end,
+ L = lists:seq(0, 57),
+ B = Mkbin(L),
+ ByteSplit(L, B, size(B), ByteSplit),
+ Id = fun(I) -> I end,
+ MakeUnalignedSubBinary =
+ fun(Bin0) ->
+ Bin1 = <<0:3,Bin0/binary,31:5>>,
+ Sz = size(Bin0),
+ <<0:3,Bin:Sz/binary,31:5>> = Id(Bin1),
+ Bin
+ end,
+ Unaligned = MakeUnalignedSubBinary(B),
+ ByteSplit(L, Unaligned, size(Unaligned), ByteSplit),
+ ok.
+ ">>,
+ [ok] = scan(ByteSplitBinary),
+ ok = evaluate(ByteSplitBinary, []),
+ BitSplitBinary =
+ <<"Mkbin = fun(L) when list(L) -> list_to_binary(L) end,
+
+ MakeInt =
+ fun(List, 0, Acc, _F) -> Acc;
+ ([H|T], N, Acc, F) -> F(T, N-1, Acc bsl 1 bor H, F)
+ end,
+
+ MakeBinFromList =
+ fun(List, 0, _F) -> Mkbin([]);
+ (List, N, F) ->
+ list_to_binary([MakeInt(List, 8, 0, MakeInt),
+ F(lists:nthtail(8, List), N-8, F)])
+ end,
+
+ BitSplitBinary3 =
+ fun(Action, Bin, List, Bef, Aft, F) when Bef =< Aft ->
+ Action(Bin, List, Bef, (Aft-Bef) div 8 * 8),
+ F(Action, Bin, List, Bef, Aft-8, F);
+ (_, _, _, _, _, _) -> ok
+ end,
+
+ BitSplitBinary2 =
+ fun(Action, Bin, [_|T]=List, Bef, F) ->
+ BitSplitBinary3(Action, Bin, List, Bef, size(Bin)*8,
+ BitSplitBinary3),
+ F(Action, Bin, T, Bef+1, F);
+ (Action, Bin, [], Bef, F) -> ok
+ end,
+
+ BitsToList =
+ fun([H|T], 0, F) -> F(T, 16#80, F);
+ ([H|_]=List, Mask, F) ->
+ [case H band Mask of
+ 0 -> 0;
+ _ -> 1
+ end | F(List, Mask bsr 1, F)];
+ ([], _, _F) -> []
+ end,
+
+ BitSplitBinary1 =
+ fun(Action, Bin) ->
+ BitList = BitsToList(binary_to_list(Bin), 16#80,
+ BitsToList),
+ BitSplitBinary2(Action, Bin, BitList, 0, BitSplitBinary2)
+ end,
+
+ Fun = fun(Bin, List, SkipBef, N) ->
+ SkipAft = 8*size(Bin) - N - SkipBef,
+ <<I1:SkipBef,OutBin:N/binary-unit:1,I2:SkipAft>> = Bin,
+ OutBin = MakeBinFromList(List, N, MakeBinFromList)
+ end,
+
+ BitSplitBinary1(Fun, erlang:md5(<<1,2,3>>)),
+ Id = fun(I) -> I end,
+ MakeUnalignedSubBinary =
+ fun(Bin0) ->
+ Bin1 = <<0:3,Bin0/binary,31:5>>,
+ Sz = size(Bin0),
+ <<0:3,Bin:Sz/binary,31:5>> = Id(Bin1),
+ Bin
+ end,
+ BitSplitBinary1(Fun, MakeUnalignedSubBinary(erlang:md5(<<1,2,3>>))),
+ ok.
+ ">>,
+ [ok] = scan(BitSplitBinary),
+ ok = evaluate(BitSplitBinary, []).
+
+-define(FAIL(Expr), "{'EXIT',{badarg,_}} = (catch " ??Expr ")").
+
+-define(COF(Int0),
+ "(fun(Int) ->
+ true = <<Int:32/float>> =:= <<(float(Int)):32/float>>,
+ true = <<Int:64/float>> =:= <<(float(Int)):64/float>>
+ end)(Nonliteral(" ??Int0 ")),
+ true = <<" ??Int0 ":32/float>> =:= <<(float("??Int0")):32/float>>,
+ true = <<" ??Int0 ":64/float>> =:= <<(float("??Int0")):64/float>>").
+
+-define(COF64(Int0),
+ "(fun(Int) ->
+ true = <<Int:64/float>> =:= <<(float(Int)):64/float>>
+ end)(Nonliteral(" ??Int0 ")),
+ true = <<" ??Int0 ":64/float>> =:= <<(float("??Int0")):64/float>>").
+
+bs_construct_SUITE(doc) ->
+ ["OTP-5327. Adopted from parts of emulator/test/bs_construct_SUITE.erl."];
+bs_construct_SUITE(suite) ->
+ [];
+bs_construct_SUITE(Config) when is_list(Config) ->
+ C1 = <<"
+
+ Testf_1 = fun(W, B) -> "
+ ?FAIL(<<42:W>>) ","
+ ?FAIL(<<3.14:W/float>>) ","
+ ?FAIL(<<B:W/binary>>) "
+ end,
+
+ TestF = fun() -> "
+ ?FAIL(<<3.14>>) ","
+ ?FAIL(<<<<1,2>>>>) ","
+
+ ?FAIL(<<2.71/binary>>) ","
+ ?FAIL(<<24334/binary>>) ","
+ ?FAIL(<<24334344294788947129487129487219847/binary>>) ","
+
+ ?FAIL(<<<<1,2,3>>/float>>) ",
+
+ %% Negative field widths.
+ Testf_1(-8, <<1,2,3,4,5>>),"
+
+ ?FAIL(<<42:(-16)>>) ","
+ ?FAIL(<<3.14:(-8)/float>>) ","
+ ?FAIL(<<<<23,56,0,2>>:(-16)/binary>>) ","
+ ?FAIL(<<<<23,56,0,2>>:(2.5)/binary>>) ","
+ ?FAIL(<<<<23,56,0,2>>:(anka)>>) "
+ end,
+ TestF(),
+
+ NotUsed1 = fun(I, BinString) -> <<I:32,BinString/binary>>, ok end,
+
+ NotUsed2 = fun(I, Sz) -> <<I:Sz>>, ok end,
+
+ NotUsed3 = fun(I) -><<I:(-8)>>, ok end,
+
+ NotUsed = fun() ->
+ ok = NotUsed1(3, <<\"dum\">>),
+ {'EXIT',{badarg,_}} = (catch NotUsed1(3, \"dum\")), "
+ ?FAIL(NotUsed2(444, -2)) ","
+ ?FAIL(NotUsed2(444, anka)) ","
+ ?FAIL(NotUsed3(444)) "
+ end,
+ NotUsed(),
+
+ InGuard3 = fun(Bin, A, B) when <<A:13,B:3>> == Bin -> 1;
+ (Bin, A, B) when <<A:16,B/binary>> == Bin -> 2;
+ (Bin, A, B) when <<A:14,B/float,3:2>> == Bin -> 3;
+ (Bin, A, B) when {a,b,<<A:14,B/float,3:2>>} == Bin ->
+ cant_happen;
+ (_, _, _) -> nope
+ end,
+
+ InGuard = fun() ->
+ 1 = InGuard3(<<16#74ad:16>>, 16#e95, 5),
+ 2 = InGuard3(<<16#3A,16#F7,\"hello\">>, 16#3AF7, <<\"hello\">>),
+ 3 = InGuard3(<<16#FBCD:14,3.1415/float,3:2>>, 16#FBCD, 3.1415),
+ nope = InGuard3(<<1>>, 42, b),
+ nope = InGuard3(<<1>>, a, b),
+ nope = InGuard3(<<1,2>>, 1, 1),
+ nope = InGuard3(<<4,5>>, 1, 2.71),
+ nope = InGuard3(<<4,5>>, 1, <<12,13>>)
+ end,
+ InGuard(),
+
+ Nonliteral = fun(X) -> X end,
+
+ CoerceToFloat = fun() -> "
+ ?COF(0) ","
+ ?COF(-1) ","
+ ?COF(1) ","
+ ?COF(42) ","
+ ?COF(255) ","
+ ?COF(-255) ","
+ ?COF64(298748888888888888888888888883478264866528467367364766666666666666663) ","
+ ?COF64(-367546729879999999999947826486652846736736476555566666663) "
+ end,
+ CoerceToFloat(),
+ ok.
+ ">>,
+ [ok] = scan(C1),
+ ok = evaluate(C1, []),
+
+ %% There is another one, lib/compiler/test/bs_construct_SUITE.erl...
+ C2 = <<"
+ I = fun(X) -> X end,
+
+ Fail = fun() ->
+
+ I_minus_777 = I(-777),
+ I_minus_2047 = I(-2047),
+
+ %% One negative field size, but the sum of field sizes will be 1 byte.
+ %% Make sure that we reject that properly.
+
+ {'EXIT',{badarg,_}} = (catch <<I_minus_777:2048/unit:8,
+ 57:I_minus_2047/unit:8>>),
+
+ %% Same thing, but use literals.
+ {'EXIT',{badarg,_}} = (catch <<I_minus_777:2048/unit:8,
+ 57:(-2047)/unit:8>>),
+
+ %% Bad alignment.
+ I_one = I(1),
+ <<1:1>> = <<2375:I_one>>,
+ <<3:2>> = <<45:1,2375:I_one>>,
+ <<14:4>> = <<45:1,2375:I_one,918:2>>,
+ <<118:7>> = <<45:1,2375:I_one,918:5>>,
+
+ %% Not numbers.
+ {'EXIT',{badarg,_}} = (catch <<45:(I(not_a_number))>>),
+ {'EXIT',{badarg,_}} = (catch <<13:8,45:(I(not_a_number))>>),
+
+ %% Unaligned sizes.
+ BadSz = I(7),
+ <<2:4>> = <<34:4>>,
+ <<34:7>> = <<34:BadSz>>,
+
+ [] = [X || {X} <- [], X == <<3:BadSz>>],
+ [] = [X || {X} <- [], X == <<3:4>>]
+ end,
+ Fail(),
+
+ FloatBin1 = fun(F) ->
+ {<<1,2,3>>,F+3.0}
+ end,
+
+ FloatBin = fun() ->
+ %% Some more coverage.
+ {<<1,2,3>>,7.0} = FloatBin1(4)
+ end,
+ FloatBin(),
+
+ ok.
+ ">>,
+ [ok] = scan(C2),
+ ok = evaluate(C2, []).
+
+evaluate(B, Vars) when is_binary(B) ->
+ evaluate(binary_to_list(B), Vars);
+evaluate(Str, Vars) ->
+ {ok,Tokens,_} =
+ erl_scan:string(Str),
+ {ok, Exprs} = erl_parse:parse_exprs(Tokens),
+ case erl_eval:exprs(Exprs, Vars, none) of
+ {value, Result, _} ->
+ Result
+ end.
+
+refman(suite) ->
+ [refman_bit_syntax].
+
+refman_bit_syntax(doc) ->
+ ["Bit syntax examples from the Reference Manual. OTP-5237."];
+refman_bit_syntax(suite) ->
+ [];
+refman_bit_syntax(Config) when is_list(Config) ->
+ %% Reference Manual "Bit Syntax Expressions"
+ ?line Bin1 = <<1,17,42>>,
+ ?line true = [1,17,42] =:= binary_to_list(Bin1),
+ ?line Bin2 = <<"abc">>,
+ ?line true = "abc" =:= binary_to_list(Bin2),
+ ?line Bin3 = <<1,17,42:16>>,
+ ?line true = [1,17,0,42] =:= binary_to_list(Bin3),
+ ?line <<_A,_B,C:16>> = <<1,17,42:16>>,
+ ?line true = C =:= 42,
+ ?line <<D:16,_E,F>> = <<1,17,42:16>>,
+ ?line true = D =:= 273,
+ ?line true = F =:= 42,
+ <<_G,H/binary>> = <<1,17,42:16>>,
+ ?line true = H =:= <<17,0,42>>,
+
+ ?line [ok] =
+ scan(<<"Bin1 = <<1,17,42>>,
+ true = [1,17,42] =:= binary_to_list(Bin1),
+ Bin2 = <<\"abc\">>,
+ true = \"abc\" =:= binary_to_list(Bin2),
+ Bin3 = <<1,17,42:16>>,
+ true =
+ [1,17,0,42] =:= binary_to_list(Bin3),
+ <<A,B,C:16>> = <<1,17,42:16>>,
+ true = C =:= 42,
+ <<D:16,E,F>> = <<1,17,42:16>>,
+ true = D =:= 273,
+ true = F =:= 42,
+ <<G,H/binary>> = <<1,17,42:16>>,
+ true = H =:= <<17,0,42>>,
+ ok.">>),
+
+ %% Binary comprehensions.
+ ?line <<2,4,6>> = << << (X*2) >> || <<X>> <= << 1,2,3 >> >>,
+ ok.
+
+progex(suite) ->
+ [progex_bit_syntax, progex_records, progex_lc, progex_funs].
+
+-define(IP_VERSION, 4).
+-define(IP_MIN_HDR_LEN, 5).
+progex_bit_syntax(doc) ->
+ ["Bit syntax examples from Programming Examples. OTP-5237."];
+progex_bit_syntax(suite) ->
+ [];
+progex_bit_syntax(Config) when is_list(Config) ->
+ Bin11 = <<1, 17, 42>>,
+ true = [1, 17, 42] =:= binary_to_list(Bin11),
+ Bin12 = <<"abc">>,
+ true = [97, 98, 99] =:= binary_to_list(Bin12),
+
+ A = 1, B = 17, C = 42,
+ Bin2 = <<A, B, C:16>>,
+ true = [1, 17, 00, 42] =:= binary_to_list(Bin2),
+ <<D:16, E, F/binary>> = Bin2,
+ true = D =:= 273,
+ true = E =:= 00,
+ true = [42] =:= binary_to_list(F),
+
+ Fun4 = fun(Dgram) ->
+ DgramSize = byte_size(Dgram),
+ case Dgram of
+ <<?IP_VERSION:4, HLen:4, SrvcType:8, TotLen:16,
+ ID:16, Flgs:3, FragOff:13,
+ TTL:8, Proto:8, HdrChkSum:16,
+ SrcIP:32, DestIP:32,
+ RestDgram/binary>> when HLen>=5, 4*HLen=<DgramSize ->
+ OptsLen = 4*(HLen - ?IP_MIN_HDR_LEN),
+ <<Opts:OptsLen/binary,Data/binary>> = RestDgram,
+ {SrvcType, TotLen, Flgs, FragOff, ID, HdrChkSum,
+ Proto, TTL, SrcIP, DestIP, Data, Opts};
+ _ ->
+ not_ok
+ end
+ end,
+ true = Fun4(<<>>) =:= not_ok,
+ true = is_tuple(Fun4(list_to_binary([<<?IP_VERSION:4,5:4>>,
+ list_to_binary(lists:seq(1,255))]))),
+
+ X = 23432324, Y = 24324234,
+ <<10:7>> = <<X:1, Y:6>>,
+ Z = 234324324,
+ XYZ = <<X:1, Y:6, Z:1>>,
+ true = [20] =:= binary_to_list(XYZ),
+ Hello1 = <<"hello">>,
+ Hello2 = <<$h,$e,$l,$l,$o>>,
+ true = "hello" =:= binary_to_list(Hello1),
+ true = "hello" =:= binary_to_list(Hello2),
+
+ FunM1 = fun(<<X1:7/binary, Y1:1/binary>>) -> {X1,Y1} end,
+ true = {<<"1234567">>,<<"8">>} =:= FunM1(<<"12345678">>),
+
+ FunM2 = fun(<<_X1:7/binary-unit:7, _Y1:1/binary-unit:1>>) -> ok;
+ (_) -> not_ok end,
+ true = not_ok =:= FunM2(<<"1">>),
+
+ BL = [{3,4,5},{6,7,8}],
+ Lst = [0,0,0,3,0,0,0,4,0,0,0,5,0,0,0,6,0,0,0,7,0,0,0,8],
+ B1 = triples_to_bin1(BL),
+ true = Lst =:= binary_to_list(B1),
+ B2 = triples_to_bin2(BL),
+ true = Lst =:= binary_to_list(B2),
+
+ ?line [ok] = scan(
+ <<"Bin11 = <<1, 17, 42>>,
+ true = [1, 17, 42] =:= binary_to_list(Bin11),
+ Bin12 = <<\"abc\">>,
+ true = [97, 98, 99] =:= binary_to_list(Bin12),
+
+ A = 1, B = 17, C = 42,
+ Bin2 = <<A, B, C:16>>,
+ true = [1, 17, 00, 42] =:= binary_to_list(Bin2),
+ <<D:16, E, F/binary>> = Bin2,
+ true = D =:= 273,
+ true = E =:= 00,
+ true = [42] =:= binary_to_list(F),
+
+ Fun4 = fun(Dgram) ->
+ DgramSize = byte_size(Dgram),
+ case Dgram of
+ <<4:4, HLen:4, SrvcType:8, TotLen:16,
+ ID:16, Flgs:3, FragOff:13,
+ TTL:8, Proto:8, HdrChkSum:16,
+ SrcIP:32, DestIP:32,
+ RestDgram/binary>> when HLen>=5,
+ 4*HLen=<DgramSize ->
+ OptsLen = 4*(HLen - 5),
+ <<Opts:OptsLen/binary,Data/binary>> = RestDgram,
+ {SrvcType, TotLen, Flgs, FragOff, ID, HdrChkSum,
+ Proto, TTL, SrcIP, DestIP, Data, Opts};
+ _ ->
+ not_ok
+ end
+ end,
+ true = Fun4(<<>>) =:= not_ok,
+ true = is_tuple(Fun4(list_to_binary
+ ([<<4:4,5:4>>,list_to_binary(lists:seq(1,255))]))),
+
+ X = 23432324, Y = 24324234,
+ <<10:7>> = <<X:1, Y:6>>,
+ Z = 234324324,
+ XYZ = <<X:1, Y:6, Z:1>>,
+ true = [20] =:= binary_to_list(XYZ),
+ Hello1 = <<\"hello\">>,
+ Hello2 = <<$h,$e,$l,$l,$o>>,
+ true = \"hello\" =:= binary_to_list(Hello1),
+ true = \"hello\" =:= binary_to_list(Hello2),
+
+ FunM1 = fun(<<X1:7/binary, Y1:1/binary>>) -> {X1,Y1} end,
+ true = {<<\"1234567\">>,<<\"8\">>} =:= FunM1(<<\"12345678\">>),
+
+ FunM2 = fun(<<_X1:7/binary-unit:7, _Y1:1/binary-unit:1>>) -> ok;
+ (_) -> not_ok end,
+ true = not_ok =:= FunM2(<<\"1\">>),
+ ok.">>),
+
+ ok.
+
+triples_to_bin1(T) ->
+ triples_to_bin1(T, <<>>).
+
+triples_to_bin1([{X,Y,Z} | T], Acc) ->
+ triples_to_bin1(T, <<Acc/binary, X:32, Y:32, Z:32>>); % inefficient
+triples_to_bin1([], Acc) ->
+ Acc.
+
+triples_to_bin2(T) ->
+ triples_to_bin2(T, []).
+
+triples_to_bin2([{X,Y,Z} | T], Acc) ->
+ triples_to_bin2(T, [<<X:32, Y:32, Z:32>> | Acc]);
+triples_to_bin2([], Acc) ->
+ list_to_binary(lists:reverse(Acc)).
+
+progex_records(doc) ->
+ ["Record examples from Programming Examples. OTP-5237."];
+progex_records(suite) ->
+ [];
+progex_records(Config) when is_list(Config) ->
+ Test1 =
+ <<"-module(recs).
+ -record(person, {name = \"\", phone = [], address}).
+ -record(name, {first = \"Robert\", last = \"Ericsson\"}).
+ -record(person2, {name = #name{}, phone}).
+ -export([t/0]).
+
+ t() ->
+ _P1 = #person{phone=[0,8,2,3,4,3,1,2], name=\"Robert\"},
+ \"Robert\" = _P1#person.name,
+ [0,8,2,3,4,3,1,2] = _P1#person.phone,
+ undefined = _P1#person.address,
+
+ _P2 = #person{name = \"Jakob\", _ = '_'},
+ \"Jakob\" = _P2#person.name,
+ '_' = _P2#person.phone,
+ '_' = _P2#person.address,
+
+ P = #person{name = \"Joe\", phone = [0,8,2,3,4,3,1,2]},
+ \"Joe\" = P#person.name,
+ [0,8,2,3,4,3,1,2] = P#person.phone,
+ undefined = P#person.address,
+
+ P1 = #person{name=\"Joe\", phone=[1,2,3], address=\"A street\"},
+ P2 = P1#person{name=\"Robert\"},
+ \"Robert\" = P2#person.name,
+ [1,2,3] = P2#person.phone,
+ \"A street\" = P2#person.address,
+ a_person = foo(P1),
+
+ {found, [1,2,3]} =
+ find_phone([#person{name = a},
+ #person{name = b, phone = [3,2,1]},
+ #person{name = c, phone = [1,2,3]}],
+ c),
+
+ P3 = #person{name=\"Joe\", phone=[0,0,7], address=\"A street\"},
+ #person{name = Name} = P3,
+ \"Joe\" = Name,
+
+ \"Robert\" = demo(),
+ ok.
+
+ foo(P) when is_record(P, person) -> a_person;
+ foo(_) -> not_a_person.
+
+ find_phone([#person{name=Name, phone=Phone} | _], Name) ->
+ {found, Phone};
+ find_phone([_| T], Name) ->
+ find_phone(T, Name);
+ find_phone([], _Name) ->
+ not_found.
+
+ demo() ->
+ P = #person2{name= #name{first=\"Robert\",last=\"Virding\"},
+ phone=123},
+ _First = (P#person2.name)#name.first.
+ ">>,
+ ?line ok = run_file(Config, recs, Test1),
+
+ Test1_shell =
+ <<"rd(person, {name = \"\", phone = [], address}),
+ rd(name, {first = \"Robert\", last = \"Ericsson\"}),
+ rd(person2, {name = #name{}, phone}),
+
+ _P1 = #person{phone=[0,8,2,3,4,3,1,2], name=\"Robert\"},
+ \"Robert\" = _P1#person.name,
+ [0,8,2,3,4,3,1,2] = _P1#person.phone,
+ undefined = _P1#person.address,
+
+ _P2 = #person{name = \"Jakob\", _ = '_'},
+ \"Jakob\" = _P2#person.name,
+ '_' = _P2#person.phone,
+ '_' = _P2#person.address,
+
+ P = #person{name = \"Joe\", phone = [0,8,2,3,4,3,1,2]},
+ \"Joe\" = P#person.name,
+ [0,8,2,3,4,3,1,2] = P#person.phone,
+ undefined = P#person.address,
+
+ P1 = #person{name=\"Joe\", phone=[1,2,3], address=\"A street\"},
+ P2 = P1#person{name=\"Robert\"},
+ \"Robert\" = P2#person.name,
+ [1,2,3] = P2#person.phone,
+ \"A street\" = P2#person.address,
+ Foo = fun(P) when is_record(P, person) -> a_person;
+ (_) -> not_a_person
+ end,
+ a_person = Foo(P1),
+
+ Find = fun([#person{name=Name, phone=Phone} | _], Name, Fn) ->
+ {found, Phone};
+ ([_| T], Name, Fn) ->
+ Fn(T, Name, Fn);
+ ([], _Name, _Fn) ->
+ not_found
+ end,
+
+ {found, [1,2,3]} = Find([#person{name = a},
+ #person{name = b, phone = [3,2,1]},
+ #person{name = c, phone = [1,2,3]}],
+ c,
+ Find),
+
+ P3 = #person{name=\"Joe\", phone=[0,0,7], address=\"A street\"},
+ #person{name = Name} = P3,
+ \"Joe\" = Name,
+
+ Demo = fun() ->
+ P17 = #person2{name= #name{first=\"Robert\",last=\"Virding\"},
+ phone=123},
+ _First = (P17#person2.name)#name.first
+ end,
+
+ \"Robert\" = Demo(),
+ ok.
+ ">>,
+ ?line [ok] = scan(Test1_shell),
+
+ Test2 =
+ <<"-module(recs).
+ -record(person, {name, age, phone = [], dict = []}).
+ -compile(export_all).
+
+ t() -> ok.
+
+ make_hacker_without_phone(Name, Age) ->
+ #person{name = Name, age = Age,
+ dict = [{computer_knowledge, excellent},
+ {drinks, coke}]}.
+ print(#person{name = Name, age = Age,
+ phone = Phone, dict = Dict}) ->
+ io:format(\"Name: ~s, Age: ~w, Phone: ~w ~n\"
+ \"Dictionary: ~w.~n\", [Name, Age, Phone, Dict]).
+
+ birthday(P) when record(P, person) ->
+ P#person{age = P#person.age + 1}.
+
+ register_two_hackers() ->
+ Hacker1 = make_hacker_without_phone(\"Joe\", 29),
+ OldHacker = birthday(Hacker1),
+ % The central_register_server should have
+ % an interface function for this.
+ central_register_server ! {register_person, Hacker1},
+ central_register_server ! {register_person,
+ OldHacker#person{name = \"Robert\",
+ phone = [0,8,3,2,4,5,3,1]}}.
+ ">>,
+ ?line ok = run_file(Config, recs, Test2),
+ ok.
+
+progex_lc(doc) ->
+ ["List comprehension examples from Programming Examples. OTP-5237."];
+progex_lc(suite) ->
+ [];
+progex_lc(Config) when is_list(Config) ->
+ Test1 =
+ <<"-module(lc).
+ -export([t/0]).
+
+ t() ->
+ [a,4,b,5,6] = [X || X <- [1,2,a,3,4,b,5,6], X > 3],
+ [4,5,6] = [X || X <- [1,2,a,3,4,b,5,6], integer(X), X > 3],
+ [{1,a},{1,b},{2,a},{2,b},{3,a},{3,b}] =
+ [{X, Y} || X <- [1,2,3], Y <- [a,b]],
+
+ [1,2,3,4,5,6,7,8] = sort([4,5,1,8,3,6,7,2]),
+ [[b,u,g],[b,g,u],[u,b,g],[u,g,b],[g,b,u],[g,u,b]] =
+ perms([b,u,g]),
+ [] = pyth(11),
+ [{3,4,5},{4,3,5}] = pyth(12),
+ [{3,4,5},{4,3,5},{5,12,13},{6,8,10},{8,6,10},{8,15,17},
+ {9,12,15},{12,5,13},{12,9,15},{12,16,20},{15,8,17},
+ {16,12,20}] = pyth(50),
+ [] = pyth1(11),
+ [{3,4,5},{4,3,5}] = pyth1(12),
+ [{3,4,5},{4,3,5},{5,12,13},{6,8,10},{8,6,10},{8,15,17},
+ {9,12,15},{12,5,13},{12,9,15},{12,16,20},{15,8,17},
+ {16,12,20}] = pyth1(50),
+ [1,2,3,4,5] = append([[1,2,3],[4,5]]),
+ [2,3,4] = map(fun(X) -> X + 1 end, [1,2,3]),
+ [2,4] = filter(fun(X) -> X > 1 end, [0,2,4]),
+ [1,2,3,7] = select(b,[{a,1},{b,2},{c,3},{b,7}]),
+ [2,7] = select2(b,[{a,1},{b,2},{c,3},{b,7}]),
+ ok.
+
+ sort([Pivot|T]) ->
+ sort([ X || X <- T, X < Pivot]) ++
+ [Pivot] ++
+ sort([ X || X <- T, X >= Pivot]);
+ sort([]) -> [].
+
+ perms([]) -> [[]];
+ perms(L) -> [[H|T] || H <- L, T <- perms(L--[H])].
+
+ pyth(N) ->
+ [ {A,B,C} ||
+ A <- lists:seq(1,N),
+ B <- lists:seq(1,N),
+ C <- lists:seq(1,N),
+ A+B+C =< N,
+ A*A+B*B == C*C
+ ].
+
+ pyth1(N) ->
+ [{A,B,C} ||
+ A <- lists:seq(1,N),
+ B <- lists:seq(1,N-A+1),
+ C <- lists:seq(1,N-A-B+2),
+ A+B+C =< N,
+ A*A+B*B == C*C ].
+
+ append(L) -> [X || L1 <- L, X <- L1].
+ map(Fun, L) -> [Fun(X) || X <- L].
+ filter(Pred, L) -> [X || X <- L, Pred(X)].
+
+ select(X, L) -> [Y || {X, Y} <- L].
+ select2(X, L) -> [Y || {X1, Y} <- L, X == X1].
+ ">>,
+ ?line ok = run_file(Config, lc, Test1),
+
+ Test1_shell =
+ <<"[a,4,b,5,6] = [X || X <- [1,2,a,3,4,b,5,6], X > 3],
+ [4,5,6] = [X || X <- [1,2,a,3,4,b,5,6], integer(X), X > 3],
+ [{1,a},{1,b},{2,a},{2,b},{3,a},{3,b}] =
+ [{X, Y} || X <- [1,2,3], Y <- [a,b]],
+
+ Sort = fun([Pivot|T], Fn) ->
+ Fn([ X || X <- T, X < Pivot], Fn) ++
+ [Pivot] ++
+ Fn([ X || X <- T, X >= Pivot], Fn);
+ ([], _Fn) -> []
+ end,
+
+ [1,2,3,4,5,6,7,8] = Sort([4,5,1,8,3,6,7,2], Sort),
+ Perms = fun([], _Fn) -> [[]];
+ (L, Fn) -> [[H|T] || H <- L, T <- Fn(L--[H], Fn)]
+ end,
+ [[b,u,g],[b,g,u],[u,b,g],[u,g,b],[g,b,u],[g,u,b]] =
+ Perms([b,u,g], Perms),
+
+ Pyth = fun(N) ->
+ [ {A,B,C} ||
+ A <- lists:seq(1,N),
+ B <- lists:seq(1,N),
+ C <- lists:seq(1,N),
+ A+B+C =< N,
+ A*A+B*B == C*C
+ ]
+ end,
+
+ [] = Pyth(11),
+ [{3,4,5},{4,3,5}] = Pyth(12),
+ %[{3,4,5},{4,3,5},{5,12,13},{6,8,10},{8,6,10},{8,15,17},
+ % {9,12,15},{12,5,13},{12,9,15},{12,16,20},{15,8,17},
+ % {16,12,20}] = Pyth(50),
+
+ Pyth1 = fun(N) ->
+ [{A,B,C} ||
+ A <- lists:seq(1,N),
+ B <- lists:seq(1,N-A+1),
+ C <- lists:seq(1,N-A-B+2),
+ A+B+C =< N,
+ A*A+B*B == C*C ]
+ end,
+
+ [] = Pyth1(11),
+ [{3,4,5},{4,3,5}] = Pyth1(12),
+ [{3,4,5},{4,3,5},{5,12,13},{6,8,10},{8,6,10},{8,15,17},
+ {9,12,15},{12,5,13},{12,9,15},{12,16,20},{15,8,17},
+ {16,12,20}] = Pyth1(50),
+
+ Append = fun(L) -> [X || L1 <- L, X <- L1] end,
+ [1,2,3,4,5] = Append([[1,2,3],[4,5]]),
+ Map = fun(Fun, L) -> [Fun(X) || X <- L] end,
+ [2,3,4] = Map(fun(X) -> X + 1 end, [1,2,3]),
+ Filter = fun(Pred, L) -> [X || X <- L, Pred(X)] end,
+ [2,4] = Filter(fun(X) -> X > 1 end, [0,2,4]),
+
+ Select = fun(X, L) -> [Y || {X, Y} <- L] end,
+ [1,2,3,7] = Select(b,[{a,1},{b,2},{c,3},{b,7}]),
+ Select2 = fun(X, L) -> [Y || {X1, Y} <- L, X == X1] end,
+ [2,7] = Select2(b,[{a,1},{b,2},{c,3},{b,7}]),
+ ok.
+ ">>,
+ ?line [ok] = scan(Test1_shell),
+ ok.
+
+progex_funs(doc) ->
+ ["Funs examples from Programming Examples. OTP-5237."];
+progex_funs(suite) ->
+ [];
+progex_funs(Config) when is_list(Config) ->
+ Test1 =
+ <<"-module(funs).
+ -compile(export_all).
+
+ double([H|T]) -> [2*H|double(T)];
+ double([]) -> [].
+
+ add_one([H|T]) -> [H+1|add_one(T)];
+ add_one([]) -> [].
+
+ map(F, [H|T]) -> [F(H)|map(F, T)];
+ map(F, []) -> [].
+
+ double2(L) -> map(fun(X) -> 2*X end, L).
+ add_one2(L) -> map(fun(X) -> 1 + X end, L).
+
+ print_list(Stream, [H|T]) ->
+ io:format(Stream, \"~p~n\", [H]),
+ print_list(Stream, T);
+ print_list(Stream, []) ->
+ true.
+
+ broadcast(Msg, [Pid|Pids]) ->
+ Pid ! Msg,
+ broadcast(Msg, Pids);
+ broadcast(_, []) ->
+ true.
+
+ foreach(F, [H|T]) ->
+ F(H),
+ foreach(F, T);
+ foreach(F, []) ->
+ ok.
+
+ print_list2(S, L) ->
+ foreach(fun(H) -> io:format(S, \"~p~n\",[H]) end, L).
+
+ broadcast2(M, L) -> foreach(fun(Pid) -> Pid ! M end, L).
+
+ t1() -> map(fun(X) -> 2 * X end, [1,2,3,4,5]).
+
+ t2() -> map(fun double/1, [1,2,3,4,5]).
+
+ t3() -> map({?MODULE, double3}, [1,2,3,4,5]).
+
+ double3(X) -> X * 2.
+
+ f(F, Args) when function(F) ->
+ apply(F, Args);
+ f(N, _) when integer(N) ->
+ N.
+
+ print_list3(File, List) ->
+ {ok, Stream} = file:open(File, write),
+ foreach(fun(X) -> io:format(Stream,\"~p~n\",[X]) end, List),
+ file:close(Stream).
+
+ print_list4(File, List) ->
+ {ok, Stream} = file:open(File, write),
+ foreach(fun(File) ->
+ io:format(Stream,\"~p~n\",[File])
+ end, List),
+ file:close(Stream).
+
+ any(Pred, [H|T]) ->
+ case Pred(H) of
+ true -> true;
+ false -> any(Pred, T)
+ end;
+ any(Pred, []) ->
+ false.
+
+ all(Pred, [H|T]) ->
+ case Pred(H) of
+ true -> all(Pred, T);
+ false -> false
+ end;
+ all(Pred, []) ->
+ true.
+
+ foldl(F, Accu, [Hd|Tail]) ->
+ foldl(F, F(Hd, Accu), Tail);
+ foldl(F, Accu, []) -> Accu.
+
+ mapfoldl(F, Accu0, [Hd|Tail]) ->
+ {R,Accu1} = F(Hd, Accu0),
+ {Rs,Accu2} = mapfoldl(F, Accu1, Tail),
+ {[R|Rs], Accu2};
+ mapfoldl(F, Accu, []) -> {[], Accu}.
+
+ filter(F, [H|T]) ->
+ case F(H) of
+ true -> [H|filter(F, T)];
+ false -> filter(F, T)
+ end;
+ filter(F, []) -> [].
+
+ diff(L1, L2) ->
+ filter(fun(X) -> not lists:member(X, L2) end, L1).
+
+ intersection(L1,L2) -> filter(fun(X) -> lists:member(X,L1) end, L2).
+
+ takewhile(Pred, [H|T]) ->
+ case Pred(H) of
+ true -> [H|takewhile(Pred, T)];
+ false -> []
+ end;
+ takewhile(Pred, []) ->
+ [].
+
+ dropwhile(Pred, [H|T]) ->
+ case Pred(H) of
+ true -> dropwhile(Pred, T);
+ false -> [H|T]
+ end;
+ dropwhile(Pred, []) ->
+ [].
+
+ splitlist(Pred, L) ->
+ splitlist(Pred, L, []).
+
+ splitlist(Pred, [H|T], L) ->
+ case Pred(H) of
+ true -> splitlist(Pred, T, [H|L]);
+ false -> {lists:reverse(L), [H|T]}
+ end;
+ splitlist(Pred, [], L) ->
+ {lists:reverse(L), []}.
+
+ first(Pred, [H|T]) ->
+ case Pred(H) of
+ true ->
+ {true, H};
+ false ->
+ first(Pred, T)
+ end;
+ first(Pred, []) ->
+ false.
+
+ ints_from(N) ->
+ fun() ->
+ [N|ints_from(N+1)]
+ end.
+
+ pconst(X) ->
+ fun (T) ->
+ case T of
+ [X|T1] -> {ok, {const, X}, T1};
+ _ -> fail
+ end
+ end.
+
+ pand(P1, P2) ->
+ fun (T) ->
+ case P1(T) of
+ {ok, R1, T1} ->
+ case P2(T1) of
+ {ok, R2, T2} ->
+ {ok, {'and', R1, R2}};
+ fail ->
+ fail
+ end;
+ fail ->
+ fail
+ end
+ end.
+
+ por(P1, P2) ->
+ fun (T) ->
+ case P1(T) of
+ {ok, R, T1} ->
+ {ok, {'or',1,R}, T1};
+ fail ->
+ case P2(T) of
+ {ok, R1, T1} ->
+ {ok, {'or',2,R1}, T1};
+ fail ->
+ fail
+ end
+ end
+ end.
+
+ grammar() ->
+ pand(
+ por(pconst(a), pconst(b)),
+ por(pconst(c), pconst(d))).
+
+ parse(List) ->
+ (grammar())(List).
+
+
+ t() ->
+ [2,4,6,8] = double([1,2,3,4]),
+ [2,3,4,5] = add_one([1,2,3,4]),
+ [2,4,6,8] = double2([1,2,3,4]),
+ [2,3,4,5] = add_one2([1,2,3,4]),
+ XX = ints_from(1),
+ [1 | _] = XX(),
+ 1 = hd(XX()),
+ Y = tl(XX()),
+ 2 = hd(Y()),
+
+ P1 = pconst(a),
+ {ok,{const,a},[b,c]} = P1([a,b,c]),
+ fail = P1([x,y,z]),
+
+ {ok,{'and',{'or',1,{const,a}},{'or',1,{const,c}}}} =
+ parse([a,c]),
+ {ok,{'and',{'or',1,{const,a}},{'or',2,{const,d}}}} =
+ parse([a,d]),
+ {ok,{'and',{'or',2,{const,b}},{'or',1,{const,c}}}} =
+ parse([b,c]),
+ {ok,{'and',{'or',2,{const,b}},{'or',2,{const,d}}}} =
+ parse([b,d]),
+ fail = parse([a,b]),
+ ok.
+ ">>,
+ ?line ok = run_file(Config, funs, Test1),
+
+ Test2_shell =
+ <<"Double = fun(X) -> 2 * X end,
+ [2,4,6,8,10] = lists:map(Double, [1,2,3,4,5]),
+
+ Big = fun(X) -> if X > 10 -> true; true -> false end end,
+ false = lists:any(Big, [1,2,3,4]),
+ true = lists:any(Big, [1,2,3,12,5]),
+ false = lists:all(Big, [1,2,3,4,12,6]),
+ true = lists:all(Big, [12,13,14,15]),
+ L = [\"I\",\"like\",\"Erlang\"],
+ 11 = lists:foldl(fun(X, Sum) -> length(X) + Sum end, 0, L),
+ Upcase = fun(X) when $a =< X, X =< $z -> X + $A - $a;
+ (X) -> X
+ end,
+ Upcase_word = fun(X) -> lists:map(Upcase, X) end,
+ \"ERLANG\" = Upcase_word(\"Erlang\"),
+ [\"I\",\"LIKE\",\"ERLANG\"] = lists:map(Upcase_word, L),
+ {[\"I\",\"LIKE\",\"ERLANG\"],11} =
+ lists:mapfoldl(fun(Word, Sum) ->
+ {Upcase_word(Word), Sum + length(Word)}
+ end, 0, L),
+ [500,12,45] = lists:filter(Big, [500,12,2,45,6,7]),
+ [200,500,45] = lists:takewhile(Big, [200,500,45,5,3,45,6]),
+ [5,3,45,6] = lists:dropwhile(Big, [200,500,45,5,3,45,6]),
+ {[200,500,45],[5,3,45,6]} =
+ lists:splitwith(Big, [200,500,45,5,3,45,6]),
+ %% {true,45} = lists:first(Big, [1,2,45,6,123]),
+ %% false = lists:first(Big, [1,2,4,5]),
+
+ Adder = fun(X) -> fun(Y) -> X + Y end end,
+ Add6 = Adder(6),
+ 16 = Add6(10),
+ ok.
+ ">>,
+ ?line [ok] = scan(Test2_shell),
+ ok.
+
+tickets(suite) ->
+ [otp_5990, otp_6166, otp_6554, otp_6785, otp_7184, otp_7232].
+
+otp_5990(doc) ->
+ "OTP-5990. {erlang,is_record}.";
+otp_5990(suite) -> [];
+otp_5990(Config) when is_list(Config) ->
+ ?line [true] =
+ scan(<<"rd(foo,{bar}), {erlang,is_record}(#foo{}, foo).">>),
+ ?line [3] =
+ scan(<<"rd(foo,{bar}), A = #foo{}, "
+ "{if {erlang,is_record}(A, foo) -> erlang; "
+ "true -> not_a_module end, length}([1,2,3]).">>),
+ ?line [true] =
+ scan(<<"rd('OrdSet', {orddata = {},ordtype = type}), "
+ "S = #'OrdSet'{ordtype = {}}, "
+ "if tuple(S#'OrdSet'.ordtype) -> true; true -> false end.">>),
+ ok.
+
+otp_6166(doc) ->
+ "OTP-6166. Order of record definitions.";
+otp_6166(suite) -> [];
+otp_6166(Config) when is_list(Config) ->
+ Test1 = filename:join(?config(priv_dir, Config), "test1.hrl"),
+ Contents1 = <<"-module(test1).
+ -record(r5, {f}). -record(r3, {f = #r5{}}). "
+ "-record(r1, {f = #r3{}}). -record(r4, {f = #r1{}}). "
+ "-record(r2, {f = #r4{}}).">>,
+ ?line ok = file:write_file(Test1, Contents1),
+
+ Test2 = filename:join(?config(priv_dir, Config), "test2.hrl"),
+ Contents2 = <<"-module(test2).
+ -record(r5, {f}). -record(r3, {f = #r5{}}). "
+ "-record(r1, {f = #r3{}}). -record(r4, {f = #r1{}}). "
+ "-record(r2, {f = #r4{}}).
+ -record(r6, {f = #r5{}}). % r6 > r0
+ -record(r0, {f = #r5{}, g = #r5{}}). % r0 < r5">>,
+ ?line ok = file:write_file(Test2, Contents2),
+
+ RR12 = "[r1,r2,r3,r4,r5] = rr(\"" ++ Test1 ++ "\"),
+ [r0,r1,r2,r3,r4,r5,r6] = rr(\"" ++ Test2 ++ "\"),
+ R0 = #r0{}, R6 = #r6{},
+ true = is_record(R0, r0),
+ true = is_record(R6, r6),
+ ok. ",
+ ?line [ok] = scan(RR12),
+
+ file:delete(Test1),
+ file:delete(Test2),
+ ok.
+
+otp_6554(doc) ->
+ "OTP-6554. Formatted exits and error messages.";
+otp_6554(suite) -> [];
+otp_6554(Config) when is_list(Config) ->
+ %% Should check the stacktrace as well...
+ ?line "exception error: bad argument" =
+ comm_err(<<"math:sqrt(a).">>),
+ ?line "exception error: bad argument" =
+ comm_err(<<"fun(X, Y) -> X ++ Y end(a, b).">>),
+ ?line "exception error: bad argument" =
+ comm_err(<<"math:sqrt(lists:seq(1,40)).">>),
+ ?line "exception error: bad argument" =
+ comm_err(<<"math:sqrt(lists:seq(1,10)).">>),
+ ?line "exception error: bad argument" =
+ comm_err(<<"a ++ b.">>),
+ ?line "exception error: bad argument" =
+ comm_err(<<"I = {file_info,undefined,undefined,undefined,undefined,
+ undefined,undefined,undefined,undefined,undefined,
+ undefined,undefined,undefined,undefined},
+ aa ++ I.">>),
+ ?line "exception error: bad argument" =
+ comm_err(<<"I = {file_info,undefined,undefined,undefined,undefined,
+ undefined,undefined,undefined,undefined,undefined,
+ undefined,undefined,undefined,undefined},
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ++ I.">>),
+ ?line "exception error: bad argument" =
+ comm_err(<<"I = {file_info,undefined,undefined,undefined,undefined,
+ undefined,undefined,undefined,undefined,undefined,
+ undefined,undefined,undefined,undefined},
+ I ++ I.">>),
+ ?line "exception error: bad argument" =
+ comm_err(<<"fun(X) -> not X end(a).">>),
+ ?line "exception error: bad argument: a" =
+ comm_err(<<"fun(A, B) -> A orelse B end(a, b).">>),
+ ?line "exception error: bad argument in an arithmetic expression" =
+ comm_err(<<"math:sqrt(2)/round(math:sqrt(0)).">>),
+ ?line "exception error: interpreted function with arity 1 called with no arguments" =
+ comm_err(<<"fun(V) -> V end().">>),
+ ?line "exception error: interpreted function with arity 1 called with two arguments" =
+ comm_err(<<"fun(V) -> V end(1,2).">>),
+ ?line "exception error: interpreted function with arity 0 called with one argument" =
+ comm_err(<<"fun() -> v end(1).">>),
+ ?line "exception error: interpreted function with arity 0 called with 4 arguments" =
+ comm_err(<<"fun() -> v end(1,2,3,4).">>),
+ ?line "exception error: math:sqrt/1 called with two arguments" =
+ comm_err(<<"fun math:sqrt/1(1,2).">>),
+ ?line "exception error: bad function 1." ++ _ =
+ comm_err(<<"(math:sqrt(2))().">>),
+ ?line "exception error: bad function [1," ++ _ =
+ comm_err(<<"(lists:seq(1, 100))().">>),
+ ?line "exception error: no match of right hand side value 1" ++ _ =
+ comm_err(<<"a = math:sqrt(2).">>),
+ ?line "exception error: no match of right hand side value" ++ _ =
+ comm_err(<<"I = {file_info,undefined,undefined,undefined,undefined,
+ undefined,undefined,undefined,undefined,undefined,
+ undefined,undefined,undefined,undefined},
+ a = I.">>),
+ ?line "exception error: no case clause matching 1" ++ _ =
+ comm_err(<<"case math:sqrt(2) of a -> ok end.">>),
+ ?line "exception error: no case clause matching [1," ++ _ =
+ comm_err(<<"V = lists:seq(1, 20), case V of a -> ok end.">>),
+ ?line "exception error: no function clause matching" =
+ comm_err(<<"fun(P) when is_pid(P) -> true end(a).">>),
+ ?line "exception error: {function_clause,[{erl_eval,do_apply,[unproper|list]}"++_ =
+ comm_err(<<"erlang:error(function_clause, [unproper | list]).">>),
+ ?line "exception error: function_clause" =
+ comm_err(<<"erlang:error(function_clause, 4).">>),
+ %% Cheating:
+ ?line "exception error: no function clause matching erl_eval:do_apply(4)" =
+ comm_err(<<"erlang:error(function_clause, [4]).">>),
+ ?line "exception error: no function clause matching" ++ _ =
+ comm_err(<<"fun(a, b, c, d) -> foo end"
+ " (lists:seq(1,17),"
+ " lists:seq(1, 18),"
+ " lists:seq(1, 40),"
+ " lists:seq(1, 5)).">>),
+
+ ?line "exception error: no function clause matching" =
+ comm_err(<<"fun(P, q) when is_pid(P) -> true end(a, b).">>),
+ ?line "exception error: no function clause matching lists:reverse(" ++ _ =
+ comm_err(<<"F=fun() -> hello end, lists:reverse(F).">>),
+ ?line "exception error: no function clause matching lists:reverse(34)" =
+ comm_err(<<"lists:reverse(34).">>),
+ ?line "exception error: no true branch found when evaluating an if expression" =
+ comm_err(<<"if length([a,b]) > 17 -> a end.">>),
+ ?line "exception error: no such process or port" =
+ comm_err(<<"Pid = spawn(fun() -> a end),"
+ "timer:sleep(1),"
+ "link(Pid).">>),
+ ?line "exception error: a system limit has been reached" =
+ comm_err(<<"list_to_atom(lists:duplicate(300,$a)).">>),
+ ?line "exception error: bad receive timeout value" =
+ comm_err(<<"receive after a -> foo end.">>),
+ ?line "exception error: no try clause matching 1" ++ _ =
+ comm_err(<<"try math:sqrt(2) of bar -> yes after 3 end.">>),
+ ?line "exception error: no try clause matching [1" ++ _ =
+ comm_err(<<"V = lists:seq(1, 20),"
+ "try V of bar -> yes after 3 end.">>),
+ ?line "exception error: undefined function math:sqrt/2" =
+ comm_err(<<"math:sqrt(2, 2).">>),
+ ?line "exception error: limit of number of arguments to interpreted function "
+ "exceeded" =
+ comm_err(<<"fun(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U) ->"
+ " a end().">>),
+ ?line "exception error: bad filter a" =
+ comm_err(<<"[b || begin a end].">>),
+ ?line "exception error: bad generator a" =
+ comm_err(<<"[X || X <- a].">>),
+ ?line "exception throw: undef" = comm_err(<<"throw(undef).">>),
+ ?line "exception exit: undef" = comm_err(<<"exit(undef).">>),
+
+ ?line "exception exit: foo" =
+ comm_err(<<"catch spawn_link(fun() ->"
+ " timer:sleep(300), exit(foo) "
+ " end),"
+ "timer:sleep(500).">>),
+ ?line [ok] = scan(
+ <<"begin process_flag(trap_exit, true),"
+ " Pid = spawn_link(fun() ->"
+ " timer:sleep(300), exit(foo) "
+ " end),"
+ " timer:sleep(500),"
+ " receive {'EXIT', Pid, foo} -> ok end end.">>),
+ ?line "exception exit: badarith" =
+ comm_err(<<"catch spawn_link(fun() ->"
+ " timer:sleep(300), 1/0 "
+ " end),"
+ "timer:sleep(500).">>),
+ ?line "exception exit: {nocatch,foo}" =
+ comm_err(<<"catch spawn_link(fun() ->"
+ " timer:sleep(300), throw(foo) "
+ " end),"
+ "timer:sleep(500).">>),
+ ?line [ok] = scan(
+ <<"begin process_flag(trap_exit, true),"
+ " Pid = spawn_link(fun() ->"
+ " timer:sleep(300), throw(foo) "
+ " end),"
+ " timer:sleep(500),"
+ " receive {'EXIT', Pid, {{nocatch,foo},_}} -> ok end "
+ "end.">>),
+
+ ?line "exception error: bad argument in an arithmetic expression" =
+ comm_err(<<"begin catch_exception(true), 1/0 end.">>),
+ ?line "exception error: bad argument in an arithmetic expression" =
+ comm_err(<<"begin catch_exception(false), 1/0 end.">>),
+ ?line "exception error: no function clause matching call to catch_exception/1" =
+ comm_err(<<"catch_exception(1).">>),
+
+ %% A bug was corrected (expansion of 'try'):
+ ?line "2: command not found" =
+ comm_err(<<"try 1 of 1 -> v(2) after 3 end.">>),
+ %% Cover a few lines:
+ ?line "3: command not found" =
+ comm_err(<<"receive foo -> foo after 0 -> v(3) end.">>),
+ ?line "3: command not found" =
+ comm_err(<<"receive foo -> foo after 0 -> e(3) end.">>),
+ ?line "1 / 0: command not found" = comm_err(<<"v(1/0).">>),
+ ?line "1\n1.\n" = t(<<"1. e(1).">>),
+ ?line [ok] = scan(<<"h().">>),
+ ?line "exception exit: normal" = comm_err(<<"exit(normal).">>),
+ ?line [foo] = scan(<<"begin history(0), foo end.">>),
+ ?line application:unset_env(stdlib, shell_history_length),
+ ?line [true] = scan(<<"begin <<10:(1024*1024*10)>>,"
+ "<<10:(1024*1024*10)>>, garbage_collect() end.">>),
+ ?line "1: syntax error before: '.'" = comm_err("1-."),
+ %% ?line comm_err(<<"exit().">>), % would hang
+ ?line "exception error: no function clause matching call to history/1" =
+ comm_err(<<"history(foo).">>),
+ ?line "exception error: no function clause matching call to results/1" =
+ comm_err(<<"results(foo).">>),
+
+ ?line Test = filename:join(?config(priv_dir, Config),
+ "otp_6554.erl"),
+ Contents = <<"-module(otp_6554).
+ -export([local_allowed/3, non_local_allowed/3]).
+ local_allowed(_,_,State) ->
+ {true,State}.
+
+ non_local_allowed(_,_,State) ->
+ {true,State}.
+ ">>,
+ ?line ok = compile_file(Config, Test, Contents, []),
+ ?line "exception exit: restricted shell starts now" =
+ comm_err(<<"begin shell:start_restricted(otp_6554) end.">>),
+ ?line "-record(r,{}).\n1.\nok.\n" =
+ t(<<"f(), f(B), h(), b(), history(20), results(20),"
+ "rd(r, {}), rl(r), rf('_'), rl(), rf(),"
+ "rp(1), _ = rr({foo}), _ = rr({foo}, []),"
+ "rr({foo}, [], []), ok.">>),
+ ?line "false.\n" = t(<<"catch_exception(true).">>),
+ ?line "exception exit: restricted shell stopped"=
+ comm_err(<<"begin shell:stop_restricted() end.">>),
+ ?line "true.\n" = t(<<"catch_exception(false).">>),
+
+ ?line "20\n1\n1\n1: results(2)\n2: 1\n-> 1\n3: v(2)\n-> 1.\nok.\n" =
+ t(<<"results(2). 1. v(2). h().">>),
+ ?line application:unset_env(stdlib, shell_saved_results),
+ ?line "1\nfoo\n17\nB = foo\nC = 17\nF = fun() ->\n foo"
+ "\n end.\nok.\n" =
+ t(<<"begin F = fun() -> foo end, 1 end. B = F(). C = 17. b().">>),
+
+ %% Tests I'd like to do: (you should try them manually)
+ %% "catch spawn_link(fun() -> timer:sleep(1000), exit(foo) end)."
+ %% "** exception error: foo" should be output after 1 second
+ %% "catch spawn_link(fun() -> timer:sleep(1000), 1/0 end)."
+ %% "** exception error: bad argument..." should be output after 1 second
+ %% "1/0", "exit(foo)", "throw(foo)".
+ %% "h()." should show {'EXIT', {badarith,..}}, {'EXIT',{foo,...}},
+ %% and {'EXIT',{{nocatch,foo},...}}.
+
+ ok.
+
+otp_6785(doc) ->
+ "OTP-6785. Parameterized modules.";
+otp_6785(suite) -> [];
+otp_6785(Config) when is_list(Config) ->
+ MFile = filename:join(?config(priv_dir, Config), "parameterized.erl"),
+ Contents = <<"-module(parameterized, [A]). "
+ "-export([test/0]). "
+ "test() -> A. ">>,
+ ?line ok = compile_file(Config, MFile, Contents, []),
+ ?line (parameterized:new(adsf)):test(),
+ file:delete(MFile),
+ ok.
+
+otp_7184(doc) ->
+ "OTP-7184. Propagate exit signals from dying evaluator process.";
+otp_7184(suite) -> [];
+otp_7184(Config) when is_list(Config) ->
+ register(otp_7184, self()),
+ ?line catch
+ t(<<"P = self(),
+ spawn_link(fun() -> process_flag(trap_exit,true),
+ P ! up,
+ receive X ->
+ otp_7184 ! {otp_7184, X}
+ end
+ end),
+ receive up -> ok end,
+ erlang:raise(throw, thrown, []).">>),
+ receive {otp_7184,{'EXIT',_,{{nocatch,thrown},[]}}} -> ok end,
+
+ ?line catch
+ t(<<"P = self(),
+ spawn_link(fun() -> process_flag(trap_exit,true),
+ P ! up,
+ receive X ->
+ otp_7184 ! {otp_7184, X}
+ end
+ end),
+ receive up -> ok end,
+ erlang:raise(exit, fini, []).">>),
+ receive {otp_7184,{'EXIT',_,{fini,[]}}} -> ok end,
+
+ ?line catch
+ t(<<"P = self(),
+ spawn_link(fun() -> process_flag(trap_exit,true),
+ P ! up,
+ receive X ->
+ otp_7184 ! {otp_7184,X}
+ end
+ end),
+ receive up -> ok end,
+ erlang:raise(error, bad, []).">>),
+ receive {otp_7184,{'EXIT',_,{bad,[]}}} -> ok end,
+
+ unregister(otp_7184),
+
+ %% v/1, a few missed cases
+ ?line "17\n<<0,0,0,64>>.\nok.\n" =
+ t(<<"17. "
+ "<<64:32>>. "
+ "<<64>> = << << X >> || << X >> <= v(2), X > v(1) >>, ok.">>),
+
+ ?line "17\n<<0,17>>.\n" =t(<<"17. <<(v(1)):16>>.">>),
+
+ ok.
+
+otp_7232(doc) ->
+ "OTP-7232. qlc:info() bug.";
+otp_7232(suite) -> [];
+otp_7232(Config) when is_list(Config) ->
+ Info = <<"qlc:info(qlc:sort(qlc:q([X || X <- [1000,2000]]), "
+ "{order, fun(A,B)-> A>B end})).">>,
+ "qlc:sort([1000,2000],\n"
+ " [{order,\n"
+ " fun(A, B) ->\n"
+ " A > B\n"
+ " end}])" = evaluate(Info, []),
+ ok.
+
+-ifdef(not_used).
+exit_term(B) ->
+ "** exception exit:" ++ Reply = t(B),
+ S0 = string:left(Reply, string:chr(Reply, $\n)-1),
+ S = string:strip(S0, right, $*),
+ {ok,Ts,_} = erl_scan:string(S),
+ {ok,Term} = erl_parse:parse_term(Ts),
+ Term.
+-endif.
+
+error_string(B) ->
+ "** exception error:" ++ Reply = t(B),
+ caught_string(Reply).
+
+exit_string(B) ->
+ "** exception exit:" ++ Reply = t(B),
+ caught_string(Reply).
+
+caught_string(Reply) ->
+ S0 = string:left(Reply, string:chr(Reply, $\n)-1),
+ S1 = string:strip(S0, right, $.),
+ S2 = string:strip(S1, left, $*),
+ S = string:strip(S2, both, $ ),
+ string:strip(S, both, $").
+
+comm_err(B) ->
+ Reply = t(B),
+ S0 = string:left(Reply, string:chr(Reply, $\n)-1),
+ S1 = string:strip(S0, left, $*),
+ S2 = string:strip(S1, both, $ ),
+ S = string:strip(S2, both, $"),
+ string:strip(S, right, $.).
+
+scan(B) ->
+ F = fun(Ts) ->
+ case erl_parse:parse_term(Ts) of
+ {ok,Term} ->
+ Term;
+ _Error ->
+ {ok,Form} = erl_parse:parse_form(Ts),
+ Form
+ end
+ end,
+ scan(t(B), F).
+
+scan(S0, F) ->
+ case erl_scan:tokens([], S0, 1) of
+ {done,{ok,Ts,_},S} ->
+ [F(Ts) | scan(S, F)];
+ _Else ->
+ []
+ end.
+
+t({Node,Bin}) when is_atom(Node),is_binary(Bin) ->
+ t0(Bin, fun() -> start_new_shell(Node) end);
+t(Bin) when is_binary(Bin) ->
+ t0(Bin, fun() -> start_new_shell() end);
+t(L) ->
+ t(list_to_binary(L)).
+
+t0(Bin, F) ->
+ %% Spawn a process so that io_request messages do not interfer.
+ P = self(),
+ C = spawn(fun() -> t1(P, Bin, F) end),
+ receive {C, R} -> R end.
+
+t1(Parent, Bin, F) ->
+ %% io:format("*** Testing ~s~n", [binary_to_list(Bin)]),
+ S = #state{bin = Bin, reply = [], leader = group_leader()},
+ group_leader(self(), self()),
+ _Shell = F(),
+ try
+ server_loop(S)
+ catch exit:R -> Parent ! {self(), R};
+ throw:{?MODULE,LoopReply} ->
+ L0 = binary_to_list(list_to_binary(LoopReply)),
+ [$\n | L1] = lists:dropwhile(fun(X) -> X =/= $\n end, L0),
+ Parent ! {self(), dotify(L1)}
+ after group_leader(S#state.leader, self())
+ end.
+
+dotify([$., $\n | L]) ->
+ [$., $\n | dotify(L)];
+dotify([$,, $\n | L]) ->
+ [$,, $\n | dotify(L)];
+dotify("ok\n" ++ L) ->
+ "ok.\n" ++ dotify(L);
+dotify("\nok\n" ++ L) ->
+ ".\nok.\n" ++ dotify(L);
+dotify([$\n]) ->
+ [$., $\n];
+dotify([C | L]) ->
+ [C | dotify(L)];
+dotify([]) ->
+ [].
+
+start_new_shell() ->
+ Shell = shell:start(),
+ link(Shell),
+ Shell.
+
+start_new_shell(Node) ->
+ Shell = rpc:call(Node,shell,start,[]),
+ link(Shell),
+ Shell.
+
+%% This is a very minimal implementation of the IO protocol...
+
+server_loop(S) ->
+ receive
+ {io_request, From, ReplyAs, Request} when is_pid(From) ->
+ server_loop(do_io_request(Request, From, S, ReplyAs));
+ NotExpected ->
+ exit(NotExpected)
+ end.
+
+do_io_request(Req, From, S, ReplyAs) ->
+ case io_requests([Req], [], S) of
+ {_Status,{eof,_},S1} ->
+ io_reply(From, ReplyAs, {error,terminated}),
+ throw({?MODULE,S1#state.reply});
+ {_Status,Reply,S1} ->
+ io_reply(From, ReplyAs, Reply),
+ S1
+ end.
+
+io_reply(From, ReplyAs, Reply) ->
+ From ! {io_reply, ReplyAs, Reply}.
+
+io_requests([{requests, Rs1} | Rs], Cont, S) ->
+ io_requests(Rs1, [Rs | Cont], S);
+io_requests([R | Rs], Cont, S) ->
+ case io_request(R, S) of
+ {ok, ok, S1} ->
+ io_requests(Rs, Cont, S1);
+ Reply ->
+ Reply
+ end;
+io_requests([], [Rs|Cont], S) ->
+ io_requests(Rs, Cont, S);
+io_requests([], [], S) ->
+ {ok,ok,S}.
+
+io_request({get_geometry,columns}, S) ->
+ {ok,80,S};
+io_request({get_geometry,rows}, S) ->
+ {ok,24,S};
+io_request({put_chars,Chars}, S) ->
+ {ok,ok,S#state{reply = [S#state.reply | Chars]}};
+io_request({put_chars,_,Chars}, S) ->
+ {ok,ok,S#state{reply = [S#state.reply | Chars]}};
+io_request({put_chars,Mod,Func,Args}, S) ->
+ case catch apply(Mod, Func, Args) of
+ Chars when is_list(Chars) ->
+ io_request({put_chars,Chars}, S)
+ end;
+io_request({put_chars,Enc,Mod,Func,Args}, S) ->
+ case catch apply(Mod, Func, Args) of
+ Chars when is_list(Chars) ->
+ io_request({put_chars,Enc,Chars}, S)
+ end;
+io_request({get_until,_Prompt,Mod,Func,ExtraArgs}, S) ->
+ get_until(Mod, Func, ExtraArgs, S, latin1);
+io_request({get_until,Enc,_Prompt,Mod,Func,ExtraArgs}, S) ->
+ get_until(Mod, Func, ExtraArgs, S, Enc).
+
+get_until(Mod, Func, ExtraArgs, S, Enc) ->
+ get_until_loop(Mod, Func, ExtraArgs, S, {more,[]}, Enc).
+
+get_until_loop(M, F, As, S, {more,Cont}, Enc) ->
+ Bin = S#state.bin,
+ case byte_size(Bin) of
+ 0 ->
+ get_until_loop(M, F, As, S,
+ catch apply(M, F, [Cont,eof|As]), Enc);
+ _ ->
+ get_until_loop(M, F, As, S#state{bin = <<>>},
+ catch apply(M, F, [Cont,binary_to_list(Bin)|As]), Enc)
+ end;
+get_until_loop(_M, _F, _As, S, {done,Res,Buf}, Enc) ->
+ {ok,Res,S#state{bin = buf2bin(Buf, Enc)}};
+get_until_loop(_M, F, _As, S, _Other, _Enc) ->
+ {error,{error,F},S}.
+
+buf2bin(eof,_) ->
+ <<>>;
+buf2bin(Buf,latin1) ->
+ list_to_binary(Buf);
+buf2bin(Buf,unicode) ->
+ unicode:characters_to_binary(Buf,unicode,unicode).
+
+run_file(Config, Module, Test) ->
+ FileName = filename(lists:concat([Module, ".erl"]), Config),
+ BeamFile = filename(lists:concat([Module, ".beam"]), Config),
+ LoadBeamFile = filename(Module, Config),
+ ok = file:write_file(FileName, Test),
+ ok = compile_file(Config, FileName, Test, []),
+ code:purge(Module),
+ {module, Module} = code:load_abs(LoadBeamFile),
+ ok = Module:t(),
+ file:delete(FileName),
+ file:delete(BeamFile),
+ ok.
+
+compile_file(Config, File, Test, Opts0) ->
+ ?line Opts = [export_all,return,{outdir,?config(priv_dir, Config)}|Opts0],
+ ?line ok = file:write_file(File, Test),
+ ?line case compile:file(File, Opts) of
+ {ok, _M, _Ws} -> ok;
+ _ -> error
+ end.
+
+filename(Name, Config) when is_atom(Name) ->
+ filename(atom_to_list(Name), Config);
+filename(Name, Config) ->
+ filename:join(?config(priv_dir, Config), Name).
+
+start_node(Name, Xargs) ->
+ ?line N = test_server:start_node(Name, slave, [{args, " " ++ Xargs}]),
+ global:sync(),
+ N.
+
diff --git a/lib/stdlib/test/slave_SUITE.erl b/lib/stdlib/test/slave_SUITE.erl
new file mode 100644
index 0000000000..3b737af64d
--- /dev/null
+++ b/lib/stdlib/test/slave_SUITE.erl
@@ -0,0 +1,261 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(slave_SUITE).
+
+-include("test_server.hrl").
+
+-export([all/1, t_start/1, t_start_link/1,
+ start_link_nodedown/1, errors/1]).
+
+%% Internal exports.
+-export([fun_init/1, test_errors/1]).
+-export([timeout_test/1, auth_test/1, rsh_test/1, start_a_slave/3]).
+
+all(suite) ->
+ [t_start_link, start_link_nodedown, t_start, errors].
+
+t_start_link(suite) -> [];
+t_start_link(Config) when list(Config) ->
+ ?line Dog = test_server:timetrap(test_server:seconds(20)),
+
+ %% Define useful variables.
+
+ ?line Host = host(),
+ ?line Slave1 = node_name(Host, slave1),
+ ?line Slave2 = node_name(Host, slave2),
+
+ %% Test slave:start_link() with one, two, and three arguments.
+
+ ?line ThisNode = node(),
+ ?line {error, {already_running, ThisNode}} = slave:start_link(Host),
+ ?line {ok, Slave1} = slave:start_link(Host, slave1),
+ ?line {ok, Slave2} = slave:start_link(Host, slave2, "-my_option 42"),
+ ?line {ok, [["42"]]} = rpc:call(Slave2, init, get_argument, [my_option]),
+
+ %% Kill the two slave nodes and verify that they are dead.
+
+ ?line rpc:cast(Slave1, erlang, halt, []),
+ ?line rpc:cast(Slave2, erlang, halt, []),
+ ?line is_dead(Slave1),
+ ?line is_dead(Slave2),
+
+ %% Start two slave nodes from another process and verify that
+ %% the slaves die when that process terminates.
+
+ Parent = self(),
+ Pid = fun_spawn(fun () ->
+ {ok, Slave1} = slave:start_link(Host, slave1),
+ {ok, Slave2} = slave:start_link(Host, slave2),
+ Parent ! slaves_started,
+ receive never -> ok end
+ end),
+ ?line receive slaves_started -> ok end,
+ ?line process_flag(trap_exit, true),
+ ?line wait_alive(Slave1),
+ ?line wait_alive(Slave2),
+ ?line exit(Pid, kill),
+ ?line receive {'EXIT', Pid, killed} -> ok end,
+ ?line test_server:sleep(250),
+ ?line is_dead(Slave1),
+ ?line is_dead(Slave2),
+
+ ?line test_server:timetrap_cancel(Dog),
+ ok.
+
+%% Test that slave:start_link() works when the master exits.
+
+start_link_nodedown(suite) -> [];
+start_link_nodedown(Config) when list(Config) ->
+ ?line Dog = test_server:timetrap(test_server:seconds(20)),
+
+ %% Define useful variables.
+
+ ?line Host = host(),
+ ?line Master = node_name(Host, my_master),
+ ?line Slave = node_name(Host, my_slave),
+
+ ?line Pa = "-pa " ++ filename:dirname(code:which(?MODULE)),
+ ?line {ok, Master} = slave:start_link(Host, my_master, Pa),
+ ?line spawn(Master, ?MODULE, start_a_slave, [self(), Host, my_slave]),
+ ?line {reply, {ok, _Node}} = receive Any -> Any end,
+
+ ?line rpc:call(Master, erlang, halt, []),
+ ?line receive after 200 -> ok end,
+ ?line pang = net_adm:ping(Slave),
+
+ ?line test_server:timetrap_cancel(Dog),
+ ok.
+
+start_a_slave(ReplyTo, Host, Name) ->
+ ReplyTo ! {reply, slave:start_link(Host, Name)},
+ receive never -> ok end.
+
+%% Test slave:start().
+
+t_start(suite) -> [];
+t_start(Config) when list(Config) ->
+ ?line Dog = test_server:timetrap(test_server:seconds(20)),
+
+ %% Define useful variables.
+
+ ?line Host = host(),
+ ?line Slave1 = node_name(Host, slave1),
+ ?line Slave2 = node_name(Host, slave2),
+
+ %% By running all tests from this master node which is linked
+ %% to this test case, we ensure that all slaves are killed
+ %% if this test case fails. (If they are not, and therefore further
+ %% test cases fail, there is a bug in slave.)
+
+ ?line {ok, Master} = slave:start_link(Host, master),
+
+ %% Test slave:start() with one, two, and three arguments.
+
+ ?line ThisNode = node(),
+ ?line {error, {already_running, ThisNode}} = slave:start(Host),
+ ?line {ok, Slave1} = rpc:call(Master, slave, start, [Host, slave1]),
+ ?line {ok, Slave2} = rpc:call(Master, slave, start,
+ [Host, slave2, "-my_option 42"]),
+ ?line {ok, [["42"]]} = rpc:call(Slave2, init, get_argument, [my_option]),
+
+ %% Test that a slave terminates when its master node terminates.
+
+ ?line ok = slave:stop(Slave2),
+ ?line is_dead(Slave2),
+ ?line {ok, Slave2} = rpc:call(Slave1, slave, start, [Host, slave2]),
+ ?line is_alive(Slave2),
+ ?line rpc:call(Slave1, erlang, halt, []), % Kill master.
+ receive after 1000 -> ok end, % Make sure slaves have noticed
+ % their dead master.
+ ?line is_dead(Slave1),
+ ?line is_dead(Slave2), % Slave should be dead, too.
+
+ %% Kill all slaves and verify that they are dead.
+
+ ?line ok = slave:stop(Slave1),
+ ?line ok = slave:stop(Slave2),
+ ?line is_dead(Slave1),
+ ?line is_dead(Slave2),
+
+ ?line test_server:timetrap_cancel(Dog),
+ ok.
+
+%% Test the various error conditions in parallell (since the timeout
+%% in slave is 32 seconds).
+
+errors(suite) -> [];
+errors(Config) when list(Config) ->
+ ?line Dog = test_server:timetrap(test_server:seconds(50)),
+
+ ?line process_flag(trap_exit, true),
+ ?line Pa = filename:dirname(code:which(?MODULE)),
+ ?line {ok, Master} = slave_start_link(host(), master,
+ "-rsh no_rsh_program -pa "++Pa++
+ " -env ERL_CRASH_DUMP erl_crash_dump.master"),
+ ?line Pids = rpc:call(Master, ?MODULE, test_errors, [self()]),
+ ?line wait_for_result(Pids),
+
+ ?line test_server:timetrap_cancel(Dog),
+ ok.
+
+wait_for_result([]) ->
+ ok;
+wait_for_result(Pids) ->
+ ?line receive
+ {'EXIT', Pid, normal} ->
+ io:format("Process ~p terminated", [Pid]),
+ wait_for_result(lists:delete(Pid, Pids));
+ {'EXIT', _, Reason} ->
+ exit(Reason)
+ end.
+
+show_process_info(Pid) ->
+ io:format("~p: ~p", [Pid, catch process_info(Pid, initial_call)]).
+
+test_errors(ResultTo) ->
+ %% Sigh! We use ordinary spawn instead of fun_spawn/1 to be able
+ %% identify the processes by their initial call.
+ ?line P1 = spawn(?MODULE, timeout_test, [ResultTo]),
+ ?line P2 = spawn(?MODULE, auth_test, [ResultTo]),
+ ?line P3 = spawn(?MODULE, rsh_test, [ResultTo]),
+ Pids =[P1, P2, P3],
+ ?line lists:foreach(fun show_process_info/1, Pids),
+ Pids.
+
+timeout_test(ResultTo) ->
+ link(ResultTo),
+ ?line {error, timeout} = slave:start(host(), slave1, "-boot no_boot_script").
+
+auth_test(ResultTo) ->
+ link(ResultTo),
+ ?line {error, timeout} = slave:start(host(), slave2,
+ "-setcookie definitely_not_a_cookie").
+
+rsh_test(ResultTo) ->
+ link(ResultTo),
+ ?line {error, no_rsh} = slave:start(super, slave3).
+
+
+%%% Utilities.
+
+
+wait_alive(Node) ->
+ wait_alive_1(10, Node).
+
+wait_alive_1(0, Node) ->
+ ?t:fail({still_not_alive,Node});
+wait_alive_1(N, Node) ->
+ case rpc:call(Node, init, get_status, []) of
+ {started,_} ->
+ ok;
+ {starting,_} ->
+ receive after 1 -> ok end,
+ wait_alive_1(N-1, Node)
+ end.
+
+is_alive(Node) ->
+ {started, _} = rpc:call(Node, init, get_status, []).
+
+is_dead(Node) ->
+ {badrpc, nodedown} = rpc:call(Node, init, get_status, []).
+
+node_name(Host, Name) ->
+ list_to_atom(lists:concat([Name, "@", Host])).
+
+host() ->
+ from($@, atom_to_list(node())).
+
+from(H, [H | T]) -> T;
+from(H, [_ | T]) -> from(H, T);
+from(_H, []) -> [].
+
+slave_start_link(Host, Name, Args) ->
+ case slave:start_link(Host, Name, Args) of
+ {ok, Node} ->
+ {ok, Node};
+ Other ->
+ io:format("slave:start_link(~p, ~p, ~p) -> ~p",
+ [Host, Name, Args, Other])
+ end.
+
+fun_spawn(Fun) ->
+ spawn_link(?MODULE, fun_init, [Fun]).
+
+fun_init(Fun) ->
+ Fun().
diff --git a/lib/stdlib/test/sofs_SUITE.erl b/lib/stdlib/test/sofs_SUITE.erl
new file mode 100644
index 0000000000..0849e0f59c
--- /dev/null
+++ b/lib/stdlib/test/sofs_SUITE.erl
@@ -0,0 +1,2374 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(sofs_SUITE).
+
+%-define(debug, true).
+
+-ifdef(debug).
+-define(format(S, A), io:format(S, A)).
+-define(line, put(line, ?LINE), ).
+-define(config(X,Y), foo).
+-define(t, test_server).
+-else.
+-include("test_server.hrl").
+-define(format(S, A), ok).
+-endif.
+
+-export([all/1]).
+
+-export([sofs/1, from_term_1/1, set_1/1, from_sets_1/1, relation_1/1,
+ a_function_1/1, family_1/1, projection/1,
+ relation_to_family_1/1, domain_1/1, range_1/1, image/1,
+ inverse_image/1, inverse_1/1, converse_1/1, no_elements_1/1,
+ substitution/1, restriction/1, drestriction/1,
+ strict_relation_1/1, extension/1, weak_relation_1/1,
+ to_sets_1/1, specification/1, union_1/1, intersection_1/1,
+ difference/1, symdiff/1, symmetric_partition/1,
+ is_sofs_set_1/1, is_set_1/1, is_equal/1, is_subset/1,
+ is_a_function_1/1, is_disjoint/1, join/1, canonical/1,
+ composite_1/1, relative_product_1/1, relative_product_2/1,
+ product_1/1, partition_1/1, partition_3/1,
+ multiple_relative_product/1, digraph/1, constant_function/1,
+ misc/1]).
+
+-export([sofs_family/1, family_specification/1,
+ family_domain_1/1, family_range_1/1,
+ family_to_relation_1/1,
+ union_of_family_1/1, intersection_of_family_1/1,
+ family_projection/1, family_difference/1,
+ family_intersection_1/1, family_union_1/1,
+ family_intersection_2/1, family_union_2/1,
+ partition_family/1]).
+
+-import(sofs,
+ [a_function/1, a_function/2, constant_function/2,
+ canonical_relation/1, composite/2,
+ converse/1, extension/3, from_term/1, from_term/2,
+ difference/2, domain/1, empty_set/0, family_difference/2,
+ family_intersection/1, family_intersection/2, family_union/1,
+ family_union/2, family/1, family/2, family_specification/2,
+ family_domain/1, family_range/1, family_field/1,
+ family_projection/2, family_to_relation/1, union_of_family/1,
+ field/1, from_external/2, image/2, intersection/1,
+ intersection/2, intersection_of_family/1, inverse/1,
+ inverse_image/2, is_disjoint/2, is_empty_set/1, is_equal/2,
+ is_a_function/1, is_set/1, is_sofs_set/1, is_subset/2,
+ join/4, from_sets/1, multiple_relative_product/2,
+ no_elements/1, partition/1, partition/2, partition/3,
+ partition_family/2, product/1, product/2, projection/2,
+ range/1, relation/1, relation/2, relation_to_family/1,
+ relative_product/1, relative_product/2, relative_product1/2,
+ strict_relation/1, weak_relation/1, restriction/2,
+ restriction/3, drestriction/2, drestriction/3, to_sets/1,
+ is_type/1, set/1, set/2, specification/2, substitution/2,
+ symdiff/2, symmetric_partition/2, to_external/1, type/1,
+ union/1, union/2, family_to_digraph/1, family_to_digraph/2,
+ digraph_to_family/1, digraph_to_family/2]).
+
+-export([init_per_testcase/2, fin_per_testcase/2]).
+
+-compile({inline,[{eval,2}]}).
+
+all(suite) ->
+ [sofs, sofs_family].
+
+init_per_testcase(_Case, Config) ->
+ Dog=?t:timetrap(?t:minutes(2)),
+ [{watchdog, Dog}|Config].
+
+fin_per_testcase(_Case, Config) ->
+ Dog=?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+%% [{2,b},{1,a,b}] == lists:sort([{2,b},{1,a,b}])
+%% [{1,a,b},{2,b}] == lists:keysort(1,[{2,b},{1,a,b}])
+
+sofs(suite) ->
+ [from_term_1, set_1, from_sets_1, relation_1, a_function_1,
+ family_1, relation_to_family_1, domain_1, range_1, image,
+ inverse_image, inverse_1, converse_1, no_elements_1,
+ substitution, restriction, drestriction, projection,
+ strict_relation_1, extension, weak_relation_1, to_sets_1,
+ specification, union_1, intersection_1, difference, symdiff,
+ symmetric_partition, is_sofs_set_1, is_set_1, is_equal,
+ is_subset, is_a_function_1, is_disjoint, join, canonical,
+ composite_1, relative_product_1, relative_product_2, product_1,
+ partition_1, partition_3, multiple_relative_product, digraph,
+ constant_function, misc].
+
+from_term_1(suite) -> [];
+from_term_1(doc) -> [""];
+from_term_1(Conf) when list(Conf) ->
+ %% would go wrong: projection(1,from_term([{2,b},{1,a,b}])),
+
+ ?line {'EXIT', {badarg, _}} = (catch from_term([], {atom,'_',atom})),
+ ?line {'EXIT', {badarg, _}} = (catch from_term([], [])),
+ ?line {'EXIT', {badarg, _}} = (catch from_term([], [atom,atom])),
+
+ ?line [] = to_external(from_term([])),
+ ?line eval(from_term([]), empty_set()),
+ ?line [] = to_external(from_term([], ['_'])),
+ ?line eval(from_term([], ['_']), empty_set()),
+ ?line [[]] = to_external(from_term([[]])),
+ ?line [[['_']]] = type(from_term([[],[[]]])),
+ ?line [[],[[]]] = to_external(from_term([[],[[]]])),
+ ?line [[['_']]] = type(from_term([[],[[]]])),
+ ?line eval(from_term([a],['_']), set([a])),
+ ?line [[],[a]] = to_external(from_term([[],[a]])),
+ ?line [[],[{a}]] = to_external(from_term([[{a}],[]])),
+ ?line [{[],[{a,b,[d]}]},{[{a,b}],[]}] =
+ to_external(from_term([{[],[{a,b,[d]}]},{[{a,b}],[]}])),
+
+ ?line [{[a,b],[c,d]}] = to_external(from_term([{[a,b],[c,d]}])),
+ ?line [{{a,b},[a,b],{{a},{b}}}] =
+ to_external(from_term([{{a,b},[a,b],{{a},{b}}}])),
+ ?line [{{a,{[a,b]},a}},{{z,{[y,z]},z}}] =
+ to_external(from_term([{{a,{[a,b,a]},a}},{{z,{[y,y,z]},z}}])),
+ ?line {'EXIT', {badarg, _}} =
+ (catch from_term([{m1,[{m1,f1,1},{m1,f2,2}]},{m2,[]},{m3,[a]}])),
+ ?line MS1 = [{m1,[{m1,f1,1},{m1,f2,2}]},{m2,[]},{m3,[{m3,f3,3}]}],
+ ?line eval(to_external(from_term(MS1)), MS1),
+
+ ?line eval(to_external(from_term(a)), a),
+ ?line eval(to_external(from_term({a})), {a}),
+
+ ?line eval(to_external(from_term([[a],[{b,c}]],[[atomic]])),
+ [[a],[{b,c}]]),
+ ?line eval(type(from_term([[a],[{b,c}]],[[atomic]])),
+ [[atomic]]),
+
+ ?line {'EXIT', {badarg, _}} = (catch from_term([[],[],a])),
+ ?line {'EXIT', {badarg, _}} = (catch from_term([{[a,b],[c,{d}]}])),
+ ?line {'EXIT', {badarg, _}} = (catch from_term([[],[a],[{a}]])),
+ ?line {'EXIT', {badarg, _}} = (catch from_term([a,{a,b}])),
+ ?line {'EXIT', {badarg, _}} = (catch from_term([[a],[{b,c}]],[['_']])),
+ ?line {'EXIT', {badarg, _}} = (catch from_term([a | {a,b}])),
+ ?line {'EXIT', {badarg, _}} =
+ (catch from_term([{{a},b,c},{d,e,f}],[{{atom},atom,atom}])),
+ ?line {'EXIT', {badarg, _}} =
+ (catch from_term([{a,{b,c}} | tail], [{atom,{atom,atom}}])),
+ ?line {'EXIT', {badarg, _}} = (catch from_term({})),
+ ?line {'EXIT', {badarg, _}} = (catch from_term([{}])),
+
+ ?line [{foo,bar},[b,a]] =
+ to_external(from_term([[b,a],{foo,bar},[b,a]], [atom])),
+ ?line [{[atom],{atom,atom}}] =
+ type(from_term([{[], {a,b}},{[a,b],{e,f}}])),
+ ?line [{[atom],{atom,atom}}] =
+ type(from_term([{[], {a,b}},{[a,b],{e,f}}], [{[atom],{atom,atom}}])),
+ ?line [[atom]] = type(from_term([[a],[{b,c}]],[[atom]])),
+
+ ?line {atom, atom} = type(from_term({a,b}, {atom, atom})),
+ ?line atom = type(from_term(a, atom)),
+ ?line {'EXIT', {badarg, _}} = (catch from_term({a,b},{atom})),
+ ?line [{{a},b,c},{{d},e,f}] =
+ to_external(from_term([{{a},b,c},{{a},b,c},{{d},e,f}],
+ [{{atom},atom,atom}])),
+
+ %% from_external too...
+ ?line e = to_external(from_external(e, atom)),
+ ?line {e} = to_external(from_external({e}, {atom})),
+ ?line [e] = to_external(from_external([e], [atom])),
+
+ %% and is_type...
+ ?line true = is_type(['_']),
+ ?line false = is_type('_'),
+ ?line true = is_type([['_']]),
+ ?line false = is_type({atom,[],atom}),
+ ?line false = is_type({atom,'_',atom}),
+ ?line true = is_type({atom,atomic,atom}),
+ ?line true = is_type({atom,atom}),
+ ?line true = is_type(atom),
+ ?line true = is_type([atom]),
+ ?line true = is_type(type),
+
+ ok.
+
+set_1(suite) -> [];
+set_1(doc) -> [""];
+set_1(Conf) when list(Conf) ->
+ %% set/1
+ ?line {'EXIT', {badarg, _}} = (catch set(a)),
+ ?line {'EXIT', {badarg, _}} = (catch set({a})),
+ ?line eval(set([]), from_term([],[atom])),
+ ?line eval(set([a,b,c]), from_term([a,b,c])),
+ ?line eval(set([a,b,a,a,b]), from_term([a,b])),
+ ?line eval(set([a,b,c,a,d,d,c,1]), from_term([1,a,b,c,d])),
+ ?line eval(set([a,b,d,a,c]), from_term([a,b,c,d])),
+ ?line eval(set([f,e,d,c,d]), from_term([c,d,e,f])),
+ ?line eval(set([h,f,d,g,g,d,c]), from_term([c,d,f,g,h])),
+ ?line eval(set([h,e,d,k,l]), from_term([d,e,h,k,l])),
+ ?line eval(set([h,e,c,k,d]), from_term([c,d,e,h,k])),
+
+ %% set/2
+ ?line {'EXIT', {badarg, _}} = (catch set(a, [a])),
+ ?line {'EXIT', {badarg, _}} = (catch set({a}, [a])),
+ ?line {'EXIT', {badarg, _}} = (catch set([a], {a})),
+ ?line {'EXIT', {badarg, _}} = (catch set([a], a)),
+ ?line {'EXIT', {badarg, _}} = (catch set([a], [a,b])),
+ ?line {'EXIT', {badarg, _}} = (catch set([a | b],[foo])),
+ ?line {'EXIT', {badarg, _}} = (catch set([a | b],['_'])),
+ ?line {'EXIT', {badarg, _}} = (catch set([a | b],[[atom]])),
+ ?line {'EXIT', {badarg, _}} = (catch set([{}],[{}])),
+ ?line eval(set([a],['_']), from_term([a],['_'])),
+ ?line eval(set([], ['_']), empty_set()),
+ ?line eval(set([a,b,a,b],[foo]), from_term([a,b],[foo])),
+
+ ok.
+
+from_sets_1(suite) -> [];
+from_sets_1(doc) -> [""];
+from_sets_1(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+
+ %% unordered
+ ?line eval(from_sets([]), E),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch from_sets([from_term([{a,b}]),
+ E,
+ from_term([{a,b,c}])])),
+ ?line eval(from_sets([from_term([{a,b}]), E]),
+ from_term([[],[{a,b}]])),
+
+ ?line eval(from_sets([from_term({a,b},{atom,atom}),
+ from_term({b,c},{atom,atom})]),
+ relation([{a,b}, {b,c}])),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch from_sets([from_term({a,b},{atom,atom}),
+ from_term({a,b,c},{atom,atom,atom})])),
+ ?line {'EXIT', {badarg, _}} = (catch from_sets(foo)),
+ ?line eval(from_sets([E]), from_term([[]])),
+ ?line eval(from_sets([E,E]), from_term([[]])),
+ ?line eval(from_sets([E,set([a])]), from_term([[],[a]])),
+ ?line {'EXIT', {badarg, _}} = (catch from_sets([E,{a}])),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch from_sets([E,from_term({a}),E])),
+ ?line {'EXIT', {type_mismatch, _}} = (catch from_sets([from_term({a}),E])),
+
+ %% ordered
+ ?line O = {from_term(a,atom), from_term({b}, {atom}), set([c,d])},
+ ?line eval(from_sets(O), from_term({a,{b},[c,d]}, {atom,{atom},[atom]})),
+ ?line {'EXIT', {badarg, _}} = (catch from_sets([a,b])),
+ ?line {'EXIT', {badarg, _}} = (catch from_sets({a,b})),
+ ?line eval(from_sets({from_term({a}),E}), from_term({{a},[]})),
+ ok.
+
+relation_1(suite) -> [];
+relation_1(doc) -> [""];
+relation_1(Conf) when list(Conf) ->
+ %% relation/1
+ ?line eval(relation([]), from_term([], [{atom,atom}])),
+ ?line eval(from_term([{a}]), relation([{a}])),
+ ?line {'EXIT', {badarg, _}} = (catch relation(a)),
+ ?line {'EXIT', {badarg, _}} = (catch relation([{a} | a])),
+ ?line {'EXIT', {badarg, _}} = (catch relation([{}])),
+ ?line {'EXIT', {badarg, _}} = (catch relation([],0)),
+ ?line {'EXIT', {badarg, _}} = (catch relation([{a}],a)),
+
+ %% relation/2
+ ?line eval(relation([{a},{b}], 1), from_term([{a},{b}])),
+ ?line eval(relation([{1,a},{2,b},{1,a}], [{x,y}]),
+ from_term([{1,a},{2,b}], [{x,y}])),
+ ?line eval(relation([{[1,2],a},{[2,1],b},{[2,1],a}], [{[x],y}]),
+ from_term([{[1,2],a},{[1,2],b}], [{[x],y}])),
+ ?line {'EXIT', {badarg, _}} = (catch relation([{1,a},{2,b}], [{[x],y}])),
+ ?line {'EXIT', {badarg, _}} = (catch relation([{1,a},{1,a,b}], [{x,y}])),
+ ?line {'EXIT', {badarg, _}} = (catch relation([{a}], 2)),
+ ?line {'EXIT', {badarg, _}} = (catch relation([{a},{b},{c,d}], 1)),
+ ?line eval(relation([{{a},[{foo,bar}]}], ['_']),
+ from_term([{{a},[{foo,bar}]}], ['_'])),
+ ?line eval(relation([], ['_']), from_term([], ['_'])),
+ ?line {'EXIT', {badarg, _}} = (catch relation([[a]],['_'])),
+ ?line eval(relation([{[a,b,a]}], [{[atom]}]), from_term([{[a,b,a]}])),
+ ?line eval(relation([{[a,b,a],[[d,e,d]]}], [{[atom],[[atom]]}]),
+ from_term([{[a,b,a],[[d,e,d]]}])),
+ ?line eval(relation([{[a,b,a],[[d,e,d]]}], [{atom,[[atom]]}]),
+ from_term([{[a,b,a],[[d,e,d]]}], [{atom,[[atom]]}])),
+ ok.
+
+a_function_1(suite) -> [];
+a_function_1(doc) -> [""];
+a_function_1(Conf) when list(Conf) ->
+ %% a_function/1
+ ?line eval(a_function([]), from_term([], [{atom,atom}])),
+ ?line eval(a_function([{a,b},{a,b},{b,c}]), from_term([{a,b},{b,c}])),
+ ?line {'EXIT', {badarg, _}} = (catch a_function([{a}])),
+ ?line {'EXIT', {badarg, _}} = (catch a_function([{a},{b},{c,d}])),
+ ?line {'EXIT', {badarg, _}} = (catch a_function(a)),
+ ?line {'EXIT', {badarg, _}} = (catch a_function([{a,b} | a])),
+ ?line {'EXIT', {bad_function, _}} =
+ (catch a_function([{a,b},{b,c},{a,c}])),
+ F = 0.0, I = round(F),
+ if
+ F == I -> % term ordering
+ ?line {'EXIT', {bad_function, _}} =
+ (catch a_function([{I,a},{F,b}])),
+ ?line {'EXIT', {bad_function, _}} =
+ (catch a_function([{[I],a},{[F],b}],[{[a],b}]));
+ true ->
+ ?line 2 = no_elements(a_function([{I,a},{F,b}])),
+ ?line 2 = no_elements(a_function([{[I],a},{[F],b}],[{[a],b}]))
+ end,
+
+ %% a_function/2
+ FT = [{atom,atom}],
+ ?line eval(a_function([], FT), from_term([], FT)),
+ ?line eval(a_function([{a,b},{b,c},{b,c}], FT),
+ from_term([{a,b},{b,c}], FT)),
+ ?line {'EXIT', {badarg, _}} = (catch a_function([{a,b}], [{a}])),
+ ?line {'EXIT', {badarg, _}} = (catch a_function([{a,b}], [{a,[b,c]}])),
+ ?line {'EXIT', {badarg, _}} = (catch a_function([{a}], FT)),
+ ?line {'EXIT', {badarg, _}} = (catch a_function([{a},{b},{c,d}], FT)),
+ ?line {'EXIT', {badarg, _}} = (catch a_function(a, FT)),
+ ?line {'EXIT', {badarg, _}} = (catch a_function([{a,b} | a], FT)),
+ ?line eval(a_function([{{a},[{foo,bar}]}], ['_']),
+ from_term([{{a},[{foo,bar}]}], ['_'])),
+ ?line eval(a_function([], ['_']), from_term([], ['_'])),
+ ?line {'EXIT', {badarg, _}} = (catch a_function([[a]],['_'])),
+ ?line {'EXIT', {bad_function, _}} =
+ (catch a_function([{a,b},{b,c},{a,c}], FT)),
+ ?line eval(a_function([{a,[a]},{a,[a,a]}], [{atom,[atom]}]),
+ from_term([{a,[a]}])),
+ ?line eval(a_function([{[b,a],c},{[a,b],c}], [{[atom],atom}]),
+ from_term([{[a,b],c}])),
+ ok.
+
+family_1(suite) -> [];
+family_1(doc) -> [""];
+family_1(Conf) when list(Conf) ->
+ %% family/1
+ ?line eval(family([]), from_term([],[{atom,[atom]}])),
+ ?line {'EXIT', {badarg, _}} = (catch family(a)),
+ ?line {'EXIT', {badarg, _}} = (catch family([a])),
+ ?line {'EXIT', {badarg, _}} = (catch family([{a,b}])),
+ ?line {'EXIT', {badarg, _}} = (catch family([{a,[]} | a])),
+ ?line {'EXIT', {badarg, _}} = (catch family([{a,[a|b]}])),
+ ?line {'EXIT', {bad_function, _}} =
+ (catch family([{a,[a]},{a,[]}])),
+ ?line {'EXIT', {bad_function, _}} =
+ (catch family([{a,[]},{b,[]},{a,[a]}])),
+ F = 0.0, I = round(F),
+ if
+ F == I -> % term ordering
+ ?line {'EXIT', {bad_function, _}} =
+ (catch family([{I,[a]},{F,[b]}])),
+ ?line true = (1 =:= no_elements(family([{a,[I]},{a,[F]}])));
+ true ->
+ ?line {'EXIT', {bad_function, _}} =
+ (catch family([{a,[I]},{a,[F]}]))
+ end,
+ ?line eval(family([{a,[]},{b,[b]},{a,[]}]), from_term([{a,[]},{b,[b]}])),
+ ?line eval(to_external(family([{b,[{hej,san},tjo]},{a,[]}])),
+ [{a,[]},{b,[tjo,{hej,san}]}]),
+ ?line eval(family([{a,[a]},{a,[a,a]}]), family([{a,[a]}])),
+
+ %% family/2
+ FT = [{a,[a]}],
+ ?line eval(family([], FT), from_term([],FT)),
+ ?line {'EXIT', {badarg, _}} = (catch family(a,FT)),
+ ?line {'EXIT', {badarg, _}} = (catch family([a],FT)),
+ ?line {'EXIT', {badarg, _}} = (catch family([{a,b}],FT)),
+ ?line {'EXIT', {badarg, _}} = (catch family([{a,[]} | a],FT)),
+ ?line {'EXIT', {badarg, _}} = (catch family([{a,[a|b]}], FT)),
+ ?line {'EXIT', {bad_function, _}} =
+ (catch family([{a,[a]},{a,[]}], FT)),
+ ?line {'EXIT', {bad_function, _}} =
+ (catch family([{a,[]},{b,[]},{a,[a]}], FT)),
+ ?line eval(family([{a,[]},{b,[b,b]},{a,[]}], FT),
+ from_term([{a,[]},{b,[b]}], FT)),
+ ?line eval(to_external(family([{b,[{hej,san},tjo]},{a,[]}], FT)),
+ [{a,[]},{b,[tjo,{hej,san}]}]),
+
+ ?line eval(family([{{a},[{foo,bar}]}], ['_']),
+ from_term([{{a},[{foo,bar}]}], ['_'])),
+ ?line eval(family([], ['_']), from_term([], ['_'])),
+ ?line {'EXIT', {badarg, _}} = (catch family([[a]],['_'])),
+ ?line {'EXIT', {badarg, _}} = (catch family([{a,b}],['_'])),
+ ?line {'EXIT', {badarg, _}} =
+ (catch family([{a,[foo]}], [{atom,atom}])),
+ ?line eval(family([{{a},[{foo,bar}]}], [{{dt},[{r1,t2}]}]),
+ from_term([{{a},[{foo,bar}]}], [{{dt},[{r1,t2}]}])),
+ ?line eval(family([{a,[a]},{a,[a,a]}],[{atom,[atom]}]),
+ family([{a,[a]}])),
+ ?line eval(family([{[a,b],[a]},{[b,a],[a,a]}],[{[atom],[atom]}]),
+ from_term([{[a,b],[a]},{[b,a],[a,a]}])),
+ ok.
+
+projection(suite) -> [];
+projection(doc) -> [""];
+projection(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line ER = relation([]),
+
+ %% set of ordered sets
+ ?line S1 = relation([{a,1},{b,2},{b,22},{c,0}]),
+ ?line S2 = relation([{a,1},{a,2},{a,3},{b,4},{b,5},{b,6}]),
+
+ ?line eval(projection(1, E), E),
+ ?line eval(projection(1, ER), set([])),
+ ?line eval(projection(1, relation([{a,1}])), set([a])),
+ ?line eval(projection(1, S1), set([a,b,c])),
+ ?line eval(projection(1, S2), set([a,b])),
+ ?line eval(projection(2, S1), set([0,1,2,22])),
+ ?line eval(projection(2, relation([{1,a},{2,a},{3,b}])), set([a,b])),
+ ?line eval(projection(1, relation([{a},{b},{c}])), set([a,b,c])),
+
+ Fun1 = {external, fun({A,B,C}) -> {A,{B,C}} end},
+ ?line eval(projection(Fun1, E), E),
+ %% No check here:
+ ?line eval(projection(3, projection(Fun1, empty_set())), E),
+ ?line E2 = relation([], 3),
+ ?line eval(projection(Fun1, E2), from_term([], [{atom,{atom,atom}}])),
+
+ Fun2 = {external, fun({A,_B}) -> {A} end},
+ ?line eval(projection(Fun2, ER), from_term([], [{atom}])),
+ ?line eval(projection(Fun2, relation([{a,1}])), relation([{a}])),
+ ?line eval(projection(Fun2, relation([{a,1},{b,3},{a,2}])),
+ relation([{a},{b}])),
+ Fun3 = {external, fun({A,_B,C}) -> {C,{A},C} end},
+ ?line eval(projection(Fun3, relation([{a,1,x},{b,3,y},{a,2,z}])),
+ from_term([{x,{a},x},{y,{b},y},{z,{a},z}])),
+ Fun4 = {external, fun(A={B,_C,_D}) -> {B, A} end},
+ ?line eval(projection(Fun4, relation([{a,1,x},{b,3,y},{a,2,z}])),
+ from_term([{a,{a,1,x}},{b,{b,3,y}},{a,{a,2,z}}])),
+
+ ?line eval(projection({external, fun({A,B,_C,D}) -> {A,B,A,D} end},
+ relation([{1,1,1,2}, {1,1,3,1}])),
+ relation([{1,1,1,1}, {1,1,1,2}])),
+
+ ?line {'EXIT', {badarg, _}} = (catch projection(1, set([]))),
+ ?line {'EXIT', {function_clause, _}} =
+ (catch projection({external, fun({A}) -> A end}, S1)),
+ ?line {'EXIT', {badarg, _}} =
+ (catch projection({external, fun({A,_}) -> {A,0} end},
+ from_term([{1,a}]))),
+
+ %% {} is not an ordered set
+ ?line {'EXIT', {badarg, _}} =
+ (catch projection({external, fun(_) -> {} end}, ER)),
+ ?line {'EXIT', {badarg, _}} =
+ (catch projection({external, fun(_) -> {{}} end}, ER)),
+ ?line eval(projection({external, fun({T,_}) -> T end},
+ relation([{{},a},{{},b}])),
+ set([{}])),
+ ?line eval(projection({external, fun({T}) -> T end}, relation([{{}}])),
+ set([{}])),
+
+ ?line eval(projection({external, fun(A) -> {A} end},
+ relation([{1,a},{2,b}])),
+ from_term([{{1,a}},{{2,b}}])),
+ ?line eval(projection({external, fun({A,B}) -> {B,A} end},
+ relation([{1,a},{2,b}])),
+ relation([{a,1},{b,2}])),
+ ?line eval(projection({external, fun(X=Y=A) -> {X,Y,A} end}, set([a,b,c])),
+ relation([{a,a,a},{b,b,b},{c,c,c}])),
+
+ ?line eval(projection({external, fun({A,{_},B}) -> {A,B} end},
+ from_term([{a,{a},b},{a,{b},c}])),
+ relation([{a,b},{a,c}])),
+ ?line eval(projection({external, fun({A,_,B}) -> {A,B} end},
+ relation([{a,{},b},{a,{},c}])),
+ relation([{a,b},{a,c}])),
+ Fun5 = fun(S) -> from_term({to_external(S),0}, {type(S),atom}) end,
+ ?line eval(projection(Fun5, E), E),
+ ?line eval(projection(Fun5, set([a,b])), from_term([{a,0},{b,0}])),
+ ?line eval(projection(Fun5, relation([{a,1},{b,2}])),
+ from_term([{{a,1},0},{{b,2},0}])),
+ ?line eval(projection(Fun5, from_term([[a],[b]])),
+ from_term([{[a],0},{[b],0}])),
+
+ F = 0.0, I = round(F),
+ ?line FR = relation([{I},{F}]),
+ if
+ F == I -> % term ordering
+ true = (no_elements(projection(1, FR)) =:= 1);
+ true ->
+ eval(projection(1, FR), set([I,F]))
+ end,
+
+ %% set of sets
+ ?line {'EXIT', {badarg, _}} =
+ (catch projection({external, fun(X) -> X end},
+ from_term([], [[atom]]))),
+ ?line {'EXIT', {badarg, _}} =
+ (catch projection({external, fun(X) -> X end}, from_term([[a]]))),
+ ?line eval(projection({sofs,union},
+ from_term([[[1,2],[2,3]], [[a,b],[b,c]]])),
+ from_term([[1,2,3], [a,b,c]])),
+ ?line eval(projection(fun(_) -> from_term([a]) end,
+ from_term([[b]], [[a]])),
+ from_term([[a]])),
+ ?line eval(projection(fun(_) -> from_term([a]) end,
+ from_term([[1,2],[3,4]])),
+ from_term([[a]])),
+ Fun10 = fun(S) ->
+ %% Cheating a lot...
+ case to_external(S) of
+ [1] -> from_term({1,1});
+ _ -> S
+ end
+ end,
+ ?line eval(projection(Fun10, from_term([[1]])), from_term([{1,1}])),
+ ?line eval(projection(fun(_) -> from_term({a}) end, from_term([[a]])),
+ from_term([{a}])),
+ ?line {'EXIT', {badarg, _}} =
+ (catch projection(fun(_) -> {a} end, from_term([[a]]))),
+
+ ok.
+
+substitution(suite) -> [];
+substitution(doc) -> [""];
+substitution(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line ER = relation([]),
+
+ %% set of ordered sets
+ ?line S1 = relation([{a,1},{b,2},{b,22},{c,0}]),
+ ?line S2 = relation([{a,1},{a,2},{a,3},{b,4},{b,5},{b,6}]),
+
+ ?line eval(substitution(1, E), E),
+ %% No check here:
+ Fun0 = {external, fun({A,B,C}) -> {A,{B,C}} end},
+ ?line eval(substitution(3, substitution(Fun0, empty_set())), E),
+ ?line eval(substitution(1, ER), from_term([],[{{atom,atom},atom}])),
+ ?line eval(substitution(1, relation([{a,1}])), from_term([{{a,1},a}])),
+ ?line eval(substitution(1, S1),
+ from_term([{{a,1},a},{{b,2},b},{{b,22},b},{{c,0},c}])),
+ ?line eval(substitution(1, S2),
+ from_term([{{a,1},a},{{a,2},a},{{a,3},a},{{b,4},b},
+ {{b,5},b},{{b,6},b}])),
+ ?line eval(substitution(2, S1),
+ from_term([{{a,1},1},{{b,2},2},{{b,22},22},{{c,0},0}])),
+
+ Fun1 = fun({A,_B}) -> {A} end,
+ XFun1 = {external, Fun1},
+ ?line eval(substitution(XFun1, E), E),
+ ?line eval(substitution(Fun1, E), E),
+ ?line eval(substitution(XFun1, ER), from_term([], [{{atom,atom},{atom}}])),
+ ?line eval(substitution(XFun1, relation([{a,1}])),
+ from_term([{{a,1},{a}}])),
+ ?line eval(substitution(XFun1, relation([{a,1},{b,3},{a,2}])),
+ from_term([{{a,1},{a}},{{a,2},{a}},{{b,3},{b}}])),
+ ?line eval(substitution({external, fun({A,_B,C}) -> {C,A,C} end},
+ relation([{a,1,x},{b,3,y},{a,2,z}])),
+ from_term([{{a,1,x},{x,a,x}},{{a,2,z},{z,a,z}},
+ {{b,3,y},{y,b,y}}])),
+ Fun2 = fun(S) -> {A,_B} = to_external(S), from_term({A}) end,
+ ?line eval(substitution(Fun2, ER), E),
+ ?line eval(substitution(Fun2, relation([{a,1}])),
+ from_term([{{a,1},{a}}])),
+ Fun3 = fun(S) -> from_term({to_external(S),0}, {type(S),atom}) end,
+ ?line eval(substitution(Fun3, E), E),
+ ?line eval(substitution(Fun3, set([a,b])),
+ from_term([{a,{a,0}},{b,{b,0}}])),
+ ?line eval(substitution(Fun3, relation([{a,1},{b,2}])),
+ from_term([{{a,1},{{a,1},0}},{{b,2},{{b,2},0}}])),
+ ?line eval(substitution(Fun3, from_term([[a],[b]])),
+ from_term([{[a],{[a],0}},{[b],{[b],0}}])),
+
+ ?line eval(substitution(fun(_) -> E end, from_term([[a],[b]])),
+ from_term([{[a],[]},{[b],[]}])),
+
+ ?line {'EXIT', {badarg, _}} = (catch substitution(1, set([]))),
+ ?line eval(substitution(1, ER), from_term([], [{{atom,atom},atom}])),
+ ?line {'EXIT', {function_clause, _}} =
+ (catch substitution({external, fun({A,_}) -> A end}, set([]))),
+ ?line {'EXIT', {badarg, _}} =
+ (catch substitution({external, fun({A,_}) -> {A,0} end},
+ from_term([{1,a}]))),
+
+ %% set of sets
+ ?line {'EXIT', {badarg, _}} =
+ (catch substitution({external, fun(X) -> X end},
+ from_term([], [[atom]]))),
+ ?line {'EXIT', {badarg, _}} =
+ (catch substitution({external, fun(X) -> X end}, from_term([[a]]))),
+ ?line eval(substitution(fun(X) -> X end, from_term([], [[atom]])), E),
+ ?line eval(substitution({sofs,union},
+ from_term([[[1,2],[2,3]], [[a,b],[b,c]]])),
+ from_term([{[[1,2],[2,3]],[1,2,3]}, {[[a,b],[b,c]],[a,b,c]}])),
+ ?line eval(substitution(fun(_) -> from_term([a]) end,
+ from_term([[b]], [[a]])),
+ from_term([{[b],[a]}], [{[a],[atom]}])),
+ ?line eval(substitution(fun(_) -> from_term([a]) end,
+ from_term([[1,2],[3,4]])),
+ from_term([{[1,2],[a]},{[3,4],[a]}])),
+ Fun10 = fun(S) ->
+ %% Cheating a lot...
+ case to_external(S) of
+ [1] -> from_term({1,1});
+ _ -> S
+ end
+ end,
+ ?line eval(substitution(Fun10, from_term([[1]])),
+ from_term([{[1],{1,1}}])),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch substitution(Fun10, from_term([[1],[2]]))),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch substitution(Fun10, from_term([[1],[0]]))),
+
+ ?line eval(substitution(fun(_) -> from_term({a}) end, from_term([[a]])),
+ from_term([{[a],{a}}])),
+ ?line {'EXIT', {badarg, _}} =
+ (catch substitution(fun(_) -> {a} end, from_term([[a]]))),
+
+ ok.
+
+restriction(suite) -> [];
+restriction(doc) -> [""];
+restriction(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line ER = relation([], 2),
+
+ %% set of ordered sets
+ ?line S1 = relation([{a,1},{b,2},{b,22},{c,0}]),
+ ?line eval(restriction(S1, set([a,b])),
+ relation([{a,1},{b,2},{b,22}])),
+ ?line eval(restriction(2, S1, set([1,2])),
+ relation([{a,1},{b,2}])),
+ ?line eval(restriction(S1, set([a,b,c])), S1),
+ ?line eval(restriction(1, S1, set([0,1,d,e])), ER),
+ ?line eval(restriction(1, S1, E), ER),
+ ?line eval(restriction({external, fun({_A,B,C}) -> {B,C} end},
+ relation([{a,aa,1},{b,bb,2},{c,cc,3}]),
+ relation([{bb,2},{cc,3}])),
+ relation([{b,bb,2},{c,cc,3}])),
+ R1 = relation([],[{a,b}]),
+ ?line eval(restriction(2, R1,sofs:set([],[b])), R1),
+ Id = fun(X) -> X end,
+ XId = {external, Id},
+ ?line eval(restriction(XId, relation([{a,b}]), E), ER),
+ ?line eval(restriction(XId, E, relation([{b,d}])), E),
+ Fun1 = fun(S) -> {_A,B,C} = to_external(S), from_term({B,C}) end,
+ ?line eval(restriction(Fun1,
+ relation([{a,aa,1},{b,bb,2},{c,cc,3}]),
+ relation([{bb,2},{cc,3}])),
+ relation([{b,bb,2},{c,cc,3}])),
+ ?line eval(restriction({external, fun({_,{A},B}) -> {A,B} end},
+ from_term([{a,{aa},1},{b,{bb},2},{c,{cc},3}]),
+ from_term([{bb,2},{cc,3}])),
+ from_term([{b,{bb},2},{c,{cc},3}])),
+ S5 = relation([{1,a},{2,b},{3,c}]),
+ ?line eval(restriction(2, S5, set([b,c])), relation([{2,b},{3,c}])),
+ S4 = relation([{a,1},{b,2},{b,27},{c,0}]),
+ ?line eval(restriction(2, S4, E), ER),
+ S6 = relation([{1,a},{2,c},{3,b}]),
+ ?line eval(restriction(2, S6, set([d,e])), ER),
+ ?line eval(restriction(2,
+ relation([{1,d},{2,c},{3,b},{4,a},{5,e}]),
+ set([c])),
+ relation([{2,c}])),
+ ?line eval(restriction(XId,
+ relation([{1,a},{3,b},{4,c},{4,d}]),
+ relation([{2,a},{2,c},{4,c}])),
+ relation([{4,c}])),
+ ?line eval(restriction(2, relation([{a,b}]), E), ER),
+ ?line eval(restriction(2, E, relation([{b,d}])), E),
+ ?line eval(restriction(2, relation([{b,d}]), E), ER),
+ ?line eval(restriction(XId, E, set([a])), E),
+ ?line eval(restriction(1, S1, E), ER),
+ ?line {'EXIT', {badarg, _}} =
+ (catch restriction(3, relation([{a,b}]), E)),
+ ?line {'EXIT', {badarg, _}} =
+ (catch restriction(3, relation([{a,b}]), relation([{b,d}]))),
+ ?line {'EXIT', {badarg, _}} =
+ (catch restriction(3, relation([{a,b}]), set([{b,d}]))),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch restriction(2, relation([{a,b}]), relation([{b,d}]))),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch restriction({external, fun({A,_B}) -> A end},
+ relation([{a,b}]), relation([{b,d}]))),
+ ?line {'EXIT', {badarg, _}} =
+ (catch restriction({external, fun({A,_}) -> {A,0} end},
+ from_term([{1,a}]),
+ from_term([{1,0}]))),
+ ?line eval(restriction(2, relation([{a,d},{b,e},{c,b},{d,c}]), set([b,d])),
+ relation([{a,d},{c,b}])),
+ ?line {'EXIT', {function_clause, _}} =
+ (catch restriction({external, fun({A,_B}) -> A end}, set([]), E)),
+
+ Fun3 = fun(S) -> from_term({to_external(S),0}, {type(S),atom}) end,
+ ?line eval(restriction(Fun3, set([1,2]), from_term([{1,0}])),
+ from_term([1])),
+
+ %% set of sets
+ ?line {'EXIT', {badarg, _}} =
+ (catch restriction({external, fun(X) -> X end},
+ from_term([], [[atom]]), set([a]))),
+ S2 = from_term([], [[atom]]),
+ ?line eval(restriction(Id, S2, E), E),
+ S3 = from_term([[a],[b]], [[atom]]),
+ ?line eval(restriction(Id, S3, E), E),
+ ?line eval(restriction(Id, from_term([], [[atom]]), set([a])),
+ from_term([], [[atom]])),
+ ?line eval(restriction({sofs,union},
+ from_term([[[a],[b]], [[b],[c]],
+ [[], [a,b]], [[1],[2]]]),
+ from_term([[a,b],[1,2,3],[b,c]])),
+ from_term([[[],[a,b]], [[a],[b]],[[b],[c]]])),
+ ?line eval(restriction(fun(_) -> from_term([a]) end,
+ from_term([], [[atom]]),
+ from_term([], [[a]])),
+ from_term([], [[atom]])),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch restriction(fun(_) -> from_term([a]) end,
+ from_term([[1,2],[3,4]]),
+ from_term([], [atom]))),
+ Fun10 = fun(S) ->
+ %% Cheating a lot...
+ case to_external(S) of
+ [1] -> from_term({1,1});
+ _ -> S
+ end
+ end,
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch restriction(Fun10, from_term([[1]]), from_term([], [[atom]]))),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch restriction(fun(_) -> from_term({a}) end,
+ from_term([[a]]),
+ from_term([], [atom]))),
+ ?line {'EXIT', {badarg, _}} =
+ (catch restriction(fun(_) -> {a} end,
+ from_term([[a]]),
+ from_term([], [atom]))),
+ ok.
+
+drestriction(suite) -> [];
+drestriction(doc) -> [""];
+drestriction(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line ER = relation([], 2),
+
+ %% set of ordered sets
+ ?line S1 = relation([{a,1},{b,2},{b,22},{c,0}]),
+ ?line eval(drestriction(S1, set([a,b])), relation([{c,0}])),
+ ?line eval(drestriction(2, S1, set([1,2])),
+ relation([{b,22},{c,0}])),
+ ?line eval(drestriction(S1, set([a,b,c])), ER),
+ ?line eval(drestriction(2, ER, set([a,b])), ER),
+ ?line eval(drestriction(1, S1, set([0,1,d,e])), S1),
+ ?line eval(drestriction(1, S1, E), S1),
+ ?line eval(drestriction({external, fun({_A,B,C}) -> {B,C} end},
+ relation([{a,aa,1},{b,bb,2},{c,cc,3}]),
+ relation([{bb,2},{cc,3}])),
+ relation([{a,aa,1}])),
+ Id = fun(X) -> X end,
+ XId = {external, Id},
+ ?line eval(drestriction(XId, relation([{a,b}]), E), relation([{a,b}])),
+ ?line eval(drestriction(XId, E, relation([{b,d}])), E),
+ Fun1 = fun(S) -> {_A,B,C} = to_external(S), from_term({B,C}) end,
+ ?line eval(drestriction(Fun1,
+ relation([{a,aa,1},{b,bb,2},{c,cc,3}]),
+ relation([{bb,2},{cc,3}])),
+ relation([{a,aa,1}])),
+ ?line eval(drestriction({external, fun({_,{A},B}) -> {A,B} end},
+ from_term([{a,{aa},1},{b,{bb},2},{c,{cc},3}]),
+ from_term([{bb,2},{cc,3}])),
+ from_term([{a,{aa},1}])),
+ S5 = relation([{1,a},{2,b},{3,c}]),
+ ?line eval(drestriction(2, S5, set([b,c])), relation([{1,a}])),
+ S4 = relation([{a,1},{b,2},{b,27},{c,0}]),
+ ?line eval(drestriction(2, S4, set([])), S4),
+ S6 = relation([{1,a},{2,c},{3,b}]),
+ ?line eval(drestriction(2, S6, set([d,e])), S6),
+ ?line eval(drestriction(2,
+ relation([{1,d},{2,c},{3,b},{4,a},{5,e}]),
+ set([c])),
+ relation([{1,d},{3,b},{4,a},{5,e}])),
+ ?line eval(drestriction(XId,
+ relation([{1,a},{3,b},{4,c},{4,d}]),
+ relation([{2,a},{2,c},{4,c}])),
+ relation([{1,a},{3,b},{4,d}])),
+ ?line eval(drestriction(2, relation([{a,b}]), E), relation([{a,b}])),
+ ?line eval(drestriction(2, E, relation([{b,d}])), E),
+ ?line eval(drestriction(2, relation([{b,d}]), E), relation([{b,d}])),
+ ?line eval(drestriction(XId, E, set([a])), E),
+ ?line eval(drestriction(1, S1, E), S1),
+ ?line {'EXIT', {badarg, _}} =
+ (catch drestriction(3, relation([{a,b}]), E)),
+ ?line {'EXIT', {badarg, _}} =
+ (catch drestriction(3, relation([{a,b}]), relation([{b,d}]))),
+ ?line {'EXIT', {badarg, _}} =
+ (catch drestriction(3, relation([{a,b}]), set([{b,d}]))),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch drestriction(2, relation([{a,b}]), relation([{b,d}]))),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch drestriction({external, fun({A,_B}) -> A end},
+ relation([{a,b}]), relation([{b,d}]))),
+ ?line {'EXIT', {badarg, _}} =
+ (catch drestriction({external, fun({A,_}) -> {A,0} end},
+ from_term([{1,a}]),
+ from_term([{1,0}]))),
+ ?line eval(drestriction(2, relation([{a,d},{b,e},{c,b},{d,c}]), set([b,d])),
+ relation([{b,e},{d,c}])),
+ ?line {'EXIT', {function_clause, _}} =
+ (catch drestriction({external, fun({A,_B}) -> A end}, set([]), E)),
+
+ Fun3 = fun(S) -> from_term({to_external(S),0}, {type(S),atom}) end,
+ ?line eval(drestriction(Fun3, set([1,2]), from_term([{1,0}])),
+ from_term([2])),
+
+ %% set of sets
+ ?line {'EXIT', {badarg, _}} =
+ (catch drestriction({external, fun(X) -> X end},
+ from_term([], [[atom]]), set([a]))),
+ S2 = from_term([], [[atom]]),
+ ?line eval(drestriction(Id, S2, E), S2),
+ S3 = from_term([[a],[b]], [[atom]]),
+ ?line eval(drestriction(Id, S3, E), S3),
+ ?line eval(drestriction(Id, from_term([], [[atom]]), set([a])),
+ from_term([], [[atom]])),
+ ?line eval(drestriction({sofs,union},
+ from_term([[[a],[b]], [[b],[c]],
+ [[], [a,b]], [[1],[2]]]),
+ from_term([[a,b],[1,2,3],[b,c]])),
+ from_term([[[1],[2]]])),
+ ?line eval(drestriction(fun(_) -> from_term([a]) end,
+ from_term([], [[atom]]),
+ from_term([], [[a]])),
+ from_term([], [[atom]])),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch drestriction(fun(_) -> from_term([a]) end,
+ from_term([[1,2],[3,4]]),
+ from_term([], [atom]))),
+ Fun10 = fun(S) ->
+ %% Cheating a lot...
+ case to_external(S) of
+ [1] -> from_term({1,1});
+ _ -> S
+ end
+ end,
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch drestriction(Fun10, from_term([[1]]), from_term([], [[atom]]))),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch drestriction(fun(_) -> from_term({a}) end,
+ from_term([[a]]),
+ from_term([], [atom]))),
+ ?line {'EXIT', {badarg, _}} =
+ (catch drestriction(fun(_) -> {a} end,
+ from_term([[a]]),
+ from_term([], [atom]))),
+ ok.
+
+strict_relation_1(suite) -> [];
+strict_relation_1(doc) -> [""];
+strict_relation_1(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line ER = relation([], 2),
+ ?line eval(strict_relation(E), E),
+ ?line eval(strict_relation(ER), ER),
+ ?line eval(strict_relation(relation([{1,a},{a,a},{2,b}])),
+ relation([{1,a},{2,b}])),
+ ?line {'EXIT', {badarg, _}} =
+ (catch strict_relation(relation([{1,2,3}]))),
+ F = 0.0, I = round(F),
+ ?line FR = relation([{F,I}]),
+ if
+ F == I -> % term ordering
+ eval(strict_relation(FR), ER);
+ true ->
+ eval(strict_relation(FR), FR)
+ end,
+ ok.
+
+extension(suite) -> [];
+extension(doc) -> [""];
+extension(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line ER = relation([], 2),
+ ?line EF = family([]),
+ ?line C1 = from_term(3),
+ ?line C2 = from_term([3]),
+ ?line {'EXIT', {function_clause, _}} = (catch extension(foo, E, C1)),
+ ?line {'EXIT', {function_clause, _}} = (catch extension(ER, foo, C1)),
+ ?line {'EXIT', {{case_clause, _},_}} = (catch extension(ER, E, foo)),
+ ?line {'EXIT', {type_mismatch, _}} = (catch extension(ER, E, E)),
+ ?line {'EXIT', {badarg, _}} = (catch extension(C2, E, E)),
+ ?line eval(E, extension(E, E, E)),
+ ?line eval(EF, extension(EF, E, E)),
+ ?line eval(family([{3,[]}]), extension(EF, set([3]), E)),
+ ?line eval(ER, extension(ER, E, C1)),
+ ?line eval(E, extension(E, ER, E)),
+ ?line eval(from_term([],[{{atom,atom},type(ER)}]), extension(E, ER, ER)),
+
+ ?line R1 = relation([{c,7},{c,9},{c,11},{d,17},{f,20}]),
+ ?line S1 = set([a,c,d,e]),
+ ?line eval(extension(R1, S1, C1), lextension(R1, S1, C1)),
+
+ ?line S2 = set([1,2,3]),
+ ?line eval(extension(ER, S2, C1), lextension(ER, S2, C1)),
+
+ ?line R3 = relation([{4,a},{8,b}]),
+ ?line S3 = set([1,2,3,4,5,6,7,8,9,10,11]),
+ ?line eval(extension(R3, S3, C1), lextension(R3, S3, C1)),
+
+ ?line R4 = relation([{2,b},{4,d},{6,f}]),
+ ?line S4 = set([1,3,5,7]),
+ ?line eval(extension(R4, S4, C1), lextension(R4, S4, C1)),
+
+ ?line F1 = family([{a,[1]},{c,[2]}]),
+ ?line S5 = set([a,b,c,d]),
+ ?line eval(extension(F1, S5, C2), lextension(F1, S5, C2)),
+ ok.
+
+lextension(R, S, C) ->
+ union(R, drestriction(1, constant_function(S, C), domain(R))).
+
+weak_relation_1(suite) -> [];
+weak_relation_1(doc) -> [""];
+weak_relation_1(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line ER = relation([], 2),
+ ?line eval(weak_relation(E), E),
+ ?line eval(weak_relation(ER), ER),
+ ?line eval(weak_relation(relation([{a,1},{a,2},{b,2},{c,c}])),
+ relation([{1,1},{2,2},{a,1},{a,2},{a,a},{b,2},{b,b},{c,c}])),
+ ?line eval(weak_relation(relation([{a,1},{a,a},{a,b}])),
+ relation([{1,1},{a,1},{a,a},{a,b},{b,b}])),
+ ?line eval(weak_relation(relation([{a,1},{a,b},{7,w}])),
+ relation([{1,1},{7,7},{7,w},{a,1},{a,a},{a,b},{b,b},{w,w}])),
+ ?line {'EXIT', {badarg, _}} =
+ (catch weak_relation(from_term([{{a},a}]))),
+ ?line {'EXIT', {badarg, _}} =
+ (catch weak_relation(from_term([{a,a}],[{d,r}]))),
+ ?line {'EXIT', {badarg, _}} = (catch weak_relation(relation([{1,2,3}]))),
+
+ F = 0.0, I = round(F),
+ if
+ F == I -> % term ordering
+ ?line FR1 = relation([{F,I}]),
+ eval(weak_relation(FR1), FR1),
+ ?line FR2 = relation([{F,2},{I,1}]),
+ true = no_elements(weak_relation(FR2)) =:= 5,
+ ?line FR3 = relation([{1,0},{1.0,1}]),
+ true = no_elements(weak_relation(FR3)) =:= 3;
+ true ->
+ ok
+ end,
+ ok.
+
+to_sets_1(suite) -> [];
+to_sets_1(doc) -> [""];
+to_sets_1(Conf) when list(Conf) ->
+ ?line {'EXIT', {badarg, _}} = (catch to_sets(from_term(a))),
+ ?line {'EXIT', {function_clause, _}} = (catch to_sets(a)),
+ %% unordered
+ ?line [] = to_sets(empty_set()),
+ ?line eval(to_sets(from_term([a])), [from_term(a)]),
+ ?line eval(to_sets(from_term([[]],[[atom]])), [set([])]),
+
+ ?line L = [from_term([a,b]),from_term([c,d])],
+ ?line eval(to_sets(from_sets(L)), L),
+
+ ?line eval(to_sets(relation([{a,1},{b,2}])),
+ [from_term({a,1},{atom,atom}), from_term({b,2},{atom,atom})]),
+
+ %% ordered
+ ?line O = {from_term(a,atom), from_term({b}, {atom}), set([c,d])},
+ ?line eval(to_sets(from_sets(O)), O),
+ ok.
+
+
+specification(suite) -> [];
+specification(doc) -> [""];
+specification(Conf) when list(Conf) ->
+ Fun = {external, fun(I) when integer(I) -> true; (_) -> false end},
+ ?line [1,2,3] = to_external(specification(Fun, set([a,1,b,2,c,3]))),
+
+ Fun2 = fun(S) -> is_subset(S, set([1,3,5,7,9])) end,
+ S2 = from_term([[1],[2],[3],[4],[5],[6],[7]]),
+ ?line eval(specification(Fun2, S2), from_term([[1],[3],[5],[7]])),
+ Fun2x = fun([1]) -> true;
+ ([3]) -> true;
+ (_) -> false
+ end,
+ ?line eval(specification({external,Fun2x}, S2), from_term([[1],[3]])),
+
+ Fun3 = fun(_) -> neither_true_or_false end,
+ ?line {'EXIT', {badarg, _}} =
+ (catch specification(Fun3, set([a]))),
+ ?line {'EXIT', {badarg, _}} =
+ (catch specification({external, Fun3}, set([a]))),
+ ?line {'EXIT', {badarg, _}} =
+ (catch specification(Fun3, from_term([[a]]))),
+ ?line {'EXIT', {function_clause, _}} =
+ (catch specification(Fun, a)),
+ ok.
+
+union_1(suite) -> [];
+union_1(doc) -> [""];
+union_1(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line ER = relation([], 2),
+ ?line {'EXIT', {badarg, _}} = (catch union(ER)),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch union(relation([{a,b}]), relation([{a,b,c}]))),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch union(from_term([{a,b}]), from_term([{c,[x]}]))),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch union(from_term([{a,b}]), from_term([{c,d}], [{d,r}]))),
+ ?line {'EXIT', {badarg, _}} = (catch union(set([a,b,c]))),
+ ?line eval(union(E), E),
+ ?line eval(union(from_term([[]],[[atom]])), set([])),
+ ?line eval(union(from_term([[{a,b},{b,c}],[{b,c}]])),
+ relation([{a,b},{b,c}])),
+ ?line eval(union(from_term([[1,2,3],[2,3,4],[3,4,5]])),
+ set([1,2,3,4,5])),
+
+ ?line eval(union(from_term([{[a],[],c}]), from_term([{[],[],q}])),
+ from_term([{[a],[],c},{[],[],q}])),
+
+ ?line eval(union(E, E), E),
+ ?line eval(union(set([a,b]), E), set([a,b])),
+ ?line eval(union(E, set([a,b])), set([a,b])),
+
+ ?line eval(union(from_term([[a,b]])), from_term([a,b])),
+ ok.
+
+intersection_1(suite) -> [];
+intersection_1(doc) -> [""];
+intersection_1(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line {'EXIT', {badarg, _}} = (catch intersection(from_term([a,b]))),
+ ?line {'EXIT', {badarg, _}} = (catch intersection(E)),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch intersection(relation([{a,b}]), relation([{a,b,c}]))),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch intersection(relation([{a,b}]), from_term([{a,b}],[{d,r}]))),
+
+ ?line eval(intersection(from_term([[a,b,c],[d,e,f],[g,h,i]])), set([])),
+
+ ?line eval(intersection(E, E), E),
+ ?line eval(intersection(set([a,b,c]),set([0,b,q])),
+ set([b])),
+ ?line eval(intersection(set([0,b,q]),set([a,b,c])),
+ set([b])),
+ ?line eval(intersection(set([a,b,c]),set([a,b,c])),
+ set([a,b,c])),
+ ?line eval(intersection(set([a,b,d]),set([c,d])),
+ set([d])),
+ ok.
+
+difference(suite) -> [];
+difference(doc) -> [""];
+difference(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch difference(relation([{a,b}]), relation([{a,b,c}]))),
+ ?line eval(difference(E, E), E),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch difference(relation([{a,b}]), from_term([{a,c}],[{d,r}]))),
+ ?line eval(difference(set([a,b,c,d,f]), set([a,d,e,g])),
+ set([b,c,f])),
+ ?line eval(difference(set([a,b,c]), set([d,e,f])),
+ set([a,b,c])),
+ ?line eval(difference(set([a,b,c]), set([a,b,c,d,e,f])),
+ set([])),
+ ?line eval(difference(set([e,f,g]), set([a,b,c,e])),
+ set([f,g])),
+ ?line eval(difference(set([a,b,d,e,f]), set([c])),
+ set([a,b,d,e,f])),
+ ok.
+
+symdiff(suite) -> [];
+symdiff(doc) -> [""];
+symdiff(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch symdiff(relation([{a,b}]), relation([{a,b,c}]))),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch symdiff(relation([{a,b}]), from_term([{a,b}], [{d,r}]))),
+ ?line eval(symdiff(E, E), E),
+ ?line eval(symdiff(set([a,b,c,d,e,f]), set([0,1,a,c])),
+ union(set([b,d,e,f]), set([0,1]))),
+ ?line eval(symdiff(set([a,b,c]), set([q,v,w,x,y])),
+ union(set([a,b,c]), set([q,v,w,x,y]))),
+ ?line eval(symdiff(set([a,b,c,d,e,f]), set([a,b,c])),
+ set([d,e,f])),
+ ?line eval(symdiff(set([c,e,g,h,i]), set([b,d,f])),
+ union(set([c,e,g,h,i]), set([b,d,f]))),
+ ?line eval(symdiff(set([c,d,g,h,k,l]),
+ set([a,b,e,f,i,j,m,n])),
+ union(set([c,d,g,h,k,l]), set([a,b,e,f,i,j,m,n]))),
+ ?line eval(symdiff(set([c,d,g,h,k,l]),
+ set([d,e,h,i,l,m,n,o,p])),
+ union(set([c,g,k]), set([e,i,m,n,o,p]))),
+ ok.
+
+symmetric_partition(suite) -> [];
+symmetric_partition(doc) -> [""];
+symmetric_partition(Conf) when list(Conf) ->
+ ?line E = set([]),
+ ?line S1 = set([1,2,3,4]),
+ ?line S2 = set([3,4,5,6]),
+ ?line S3 = set([3,4]),
+ ?line S4 = set([1,2,3,4,5,6]),
+ ?line T1 = set([1,2]),
+ ?line T2 = set([3,4]),
+ ?line T3 = set([5,6]),
+ ?line T4 = set([1,2,5,6]),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch symmetric_partition(relation([{a,b}]), relation([{a,b,c}]))),
+ ?line {E, E, E} = symmetric_partition(E, E),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch symmetric_partition(relation([{a,b}]),
+ from_term([{a,c}],[{d,r}]))),
+ ?line {E, E, S1} = symmetric_partition(E, S1),
+ ?line {S1, E, E} = symmetric_partition(S1, E),
+ ?line {T1, T2, T3} = symmetric_partition(S1, S2),
+ ?line {T3, T2, T1} = symmetric_partition(S2, S1),
+ ?line {E, T2, T4} = symmetric_partition(S3, S4),
+ ?line {T4, T2, E} = symmetric_partition(S4, S3),
+
+ ?line S5 = set([1,3,5]),
+ ?line S6 = set([2,4,6,7,8]),
+ ?line {S5, E, S6} = symmetric_partition(S5, S6),
+ ?line {S6, E, S5} = symmetric_partition(S6, S5),
+ ?line EE = empty_set(),
+ ?line {EE, EE, EE} = symmetric_partition(EE, EE),
+
+ ok.
+
+is_sofs_set_1(suite) -> [];
+is_sofs_set_1(doc) -> [""];
+is_sofs_set_1(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line true = is_sofs_set(E),
+ ?line true = is_sofs_set(from_term([a])),
+ ?line true = is_sofs_set(from_term({a})),
+ ?line true = is_sofs_set(from_term(a)),
+ ?line false = is_sofs_set(a),
+ ok.
+
+is_set_1(suite) -> [];
+is_set_1(doc) -> [""];
+is_set_1(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line true = is_set(E),
+ ?line true = is_set(from_term([a])),
+ ?line false = is_set(from_term({a})),
+ ?line false = is_set(from_term(a)),
+ ?line {'EXIT', _} = (catch is_set(a)),
+
+ ?line true = is_empty_set(E),
+ ?line false = is_empty_set(from_term([a])),
+ ?line false = is_empty_set(from_term({a})),
+ ?line false = is_empty_set(from_term(a)),
+ ?line {'EXIT', _} = (catch is_empty_set(a)),
+
+ ok.
+
+is_equal(suite) -> [];
+is_equal(doc) -> [""];
+is_equal(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line true = is_equal(E, E),
+ ?line false = is_equal(from_term([a]), E),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch is_equal(intersection(set([a]), set([b])),
+ intersection(from_term([{a}]), from_term([{b}])))),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch is_equal(from_term([],[{[atom],atom,[atom]}]),
+ from_term([],[{[atom],{atom},[atom]}]))),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch is_equal(set([a]), from_term([a],[type]))),
+
+ ?line E2 = from_sets({from_term(a,atom)}),
+ ?line true = is_equal(E2, E2),
+ ?line true = is_equal(from_term({a}, {atom}), E2),
+ ?line false = is_equal(from_term([{[a],[],c}]),
+ from_term([{[],[],q}])),
+
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch is_equal(E, E2)),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch is_equal(E2, E)),
+ ?line true = is_equal(from_term({[],a,[]},{[atom],atom,[atom]}),
+ from_term({[],a,[]},{[atom],atom,[atom]})),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch is_equal(from_term({[],a,[]},{[atom],atom,[atom]}),
+ from_term({[],{a},[]},{[atom],{atom},[atom]}))),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch is_equal(from_term({a}), from_term({a},{type}))),
+
+ ok.
+
+is_subset(suite) -> [];
+is_subset(doc) -> [""];
+is_subset(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line true = is_subset(E, E),
+ ?line true = is_subset(set([a,c,e]), set([a,b,c,d,e])),
+ ?line false = is_subset(set([a,b]), E),
+ ?line false = is_subset(set([d,e,f]), set([b,c,d,e])),
+ ?line false = is_subset(set([a,b,c]), set([b,c])),
+ ?line false = is_subset(set([b,c]), set([a,c])),
+ ?line false = is_subset(set([d,e]), set([a,b])),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch is_subset(intersection(set([a]), set([b])),
+ intersection(from_term([{a}]), from_term([{b}])))),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch is_subset(set([a]), from_term([a,b], [at]))),
+ ok.
+
+is_a_function_1(suite) -> [];
+is_a_function_1(doc) -> [""];
+is_a_function_1(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line ER = relation([], 2),
+ ?line {'EXIT', {badarg, _}} = (catch is_a_function(set([a,b]))),
+ ?line true = is_a_function(E),
+ ?line true = is_a_function(ER),
+ ?line true = is_a_function(relation([])),
+ ?line true = is_a_function(relation([],2)),
+ ?line true = is_a_function(relation([{a,b},{b,c}])),
+ ?line false = is_a_function(relation([{a,b},{b,c},{b,d},{e,f}])),
+ ?line IS = relation([{{a,b},c},{{a,b},d}]),
+ ?line false = is_a_function(IS),
+ F = 0.0, I = round(F),
+ ?line FR = relation([{I,F},{F,1}]),
+ if
+ F == I -> % term ordering
+ false = is_a_function(FR);
+ true ->
+ true = is_a_function(FR)
+ end,
+ ok.
+
+is_disjoint(suite) -> [];
+is_disjoint(doc) -> [""];
+is_disjoint(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch is_disjoint(relation([{a,1}]), set([a,b]))),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch is_disjoint(set([a]), from_term([a],[mota]))),
+ ?line true = is_disjoint(E, E),
+ ?line false = is_disjoint(set([a,b,c]),set([b,c,d])),
+ ?line false = is_disjoint(set([b,c,d]),set([a,b,c])),
+ ?line true = is_disjoint(set([a,c,e]),set([b,d,f])),
+ ok.
+
+join(suite) -> [];
+join(doc) -> [""];
+join(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+
+ ?line {'EXIT', {badarg, _}} = (catch join(relation([{a,1}]), 3, E, 5)),
+ ?line {'EXIT', {badarg, _}} = (catch join(E, 1, relation([{a,1}]), 3)),
+ ?line {'EXIT', {badarg, _}} = (catch join(E, 1, from_term([a]), 1)),
+
+ ?line eval(join(E, 1, E, 2), E),
+ ?line eval(join(E, 1, from_term([{{a},b}]), 2), E),
+ ?line eval(join(from_term([{{a},b}]), 2, E, 1), E),
+ ?line eval(join(from_term([{{a},b,e}]), 2, from_term([{c,{d}}]), 1),
+ from_term([], [{{atom},atom,atom,{atom}}])),
+ ?line eval(join(relation([{a}]), 1, relation([{1,a},{2,a}]), 2),
+ relation([{a,1},{a,2}])),
+ ?line eval(join(relation([{a,b,c},{b,c,d}]), 2,
+ relation([{1,b},{2,a},{3,c}]), 2),
+ relation([{a,b,c,1},{b,c,d,3}])),
+ ?line eval(join(relation([{1,a,aa},{1,b,bb},{1,c,cc},{2,a,aa},{2,b,bb}]),
+ 1,
+ relation([{1,c,cc},{1,d,dd},{1,e,ee},{2,c,cc},{2,d,dd}]),
+ 1),
+ relation([{1,a,aa,c,cc},{1,a,aa,d,dd},{1,a,aa,e,ee},{1,b,bb,c,cc},
+ {1,b,bb,d,dd},{1,b,bb,e,ee},{1,c,cc,c,cc},{1,c,cc,d,dd},
+ {1,c,cc,e,ee},{2,a,aa,c,cc},{2,a,aa,d,dd},{2,b,bb,c,cc},
+ {2,b,bb,d,dd}])),
+
+ R1 = relation([{a,b},{b,c}]),
+ R2 = relation([{b,1},{a,2},{c,3},{c,4}]),
+ ?line eval(join(R1, 1, R2, 1), from_term([{a,b,2},{b,c,1}])),
+ ?line eval(join(R1, 2, R2, 1), from_term([{a,b,1},{b,c,3},{b,c,4}])),
+ ?line eval(join(R1, 1, converse(R2), 2),
+ from_term([{a,b,2},{b,c,1}])),
+ ?line eval(join(R1, 2, converse(R2), 2),
+ from_term([{a,b,1},{b,c,3},{b,c,4}])),
+ ok.
+
+canonical(suite) -> [];
+canonical(doc) -> [""];
+canonical(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line {'EXIT', {badarg, _}} =
+ (catch canonical_relation(set([a,b]))),
+ ?line eval(canonical_relation(E), E),
+ ?line eval(canonical_relation(from_term([[]])), E),
+ ?line eval(canonical_relation(from_term([[a,b,c]])),
+ from_term([{a,[a,b,c]},{b,[a,b,c]},{c,[a,b,c]}])),
+ ok.
+
+relation_to_family_1(suite) -> [];
+relation_to_family_1(doc) -> [""];
+relation_to_family_1(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line EF = family([]),
+ ?line eval(relation_to_family(E), E),
+ ?line eval(relation_to_family(relation([])), EF),
+ ?line eval(relation_to_family(relation([], 2)), EF),
+ ?line R = relation([{b,1},{c,7},{c,9},{c,11}]),
+ ?line F = family([{b,[1]},{c,[7,9,11]}]),
+ ?line eval(relation_to_family(R), F),
+ ?line eval(sofs:rel2fam(R), F),
+ ?line {'EXIT', {badarg, _}} = (catch relation_to_family(set([a]))),
+ ok.
+
+domain_1(suite) -> [];
+domain_1(doc) -> [""];
+domain_1(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line ER = relation([]),
+ ?line {'EXIT', {badarg, _}} = (catch domain(relation([],3))),
+ ?line eval(domain(E), E),
+ ?line eval(domain(ER), set([])),
+ ?line eval(domain(relation([{1,a},{1,b},{2,a},{2,b}])), set([1,2])),
+ ?line eval(domain(relation([{a,1},{b,2},{c,3}])), set([a,b,c])),
+ ?line eval(field(relation([{a,1},{b,2},{c,3}])),
+ set([a,b,c,1,2,3])),
+ F = 0.0, I = round(F),
+ ?line FR = relation([{I,a},{F,b}]),
+ if
+ F == I -> % term ordering
+ ?line true = (1 =:= no_elements(domain(FR)));
+ true ->
+ ?line true = (2 =:= no_elements(domain(FR)))
+ end,
+ ok.
+
+range_1(suite) -> [];
+range_1(doc) -> [""];
+range_1(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line ER = relation([]),
+ ?line {'EXIT', {badarg, _}} = (catch range(relation([],3))),
+ ?line eval(range(E), E),
+ ?line eval(range(ER), set([])),
+ ?line eval(range(relation([{1,a},{1,b},{2,a},{2,b}])), set([a,b])),
+ ?line eval(range(relation([{a,1},{b,2},{c,3}])), set([1,2,3])),
+ ok.
+
+inverse_1(suite) -> [];
+inverse_1(doc) -> [""];
+inverse_1(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line ER = relation([]),
+ ?line {'EXIT', {badarg, _}} = (catch inverse(relation([],3))),
+ ?line {'EXIT', {bad_function, _}} =
+ (catch inverse(relation([{1,a},{1,b}]))),
+ ?line {'EXIT', {bad_function, _}} =
+ (catch inverse(relation([{1,a},{2,a}]))),
+ ?line eval(inverse(E), E),
+ ?line eval(inverse(ER), ER),
+ ?line eval(inverse(relation([{a,1},{b,2},{c,3}])),
+ relation([{1,a},{2,b},{3,c}])),
+ F = 0.0, I = round(F),
+ ?line FR = relation([{I,a},{F,b}]),
+ if
+ F == I -> % term ordering
+ ?line {'EXIT', {bad_function, _}} = (catch inverse(FR));
+ true ->
+ ?line eval(inverse(FR), relation([{a,I},{b,F}]))
+ end,
+ ok.
+
+converse_1(suite) -> [];
+converse_1(doc) -> [""];
+converse_1(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line ER = relation([]),
+ ?line {'EXIT', {badarg, _}} = (catch converse(relation([],3))),
+ ?line eval(converse(ER), ER),
+ ?line eval(converse(E), E),
+ ?line eval(converse(relation([{a,1},{b,2},{c,3}])),
+ relation([{1,a},{2,b},{3,c}])),
+ ?line eval(converse(relation([{1,a},{1,b}])),
+ relation([{a,1},{b,1}])),
+ ?line eval(converse(relation([{1,a},{2,a}])),
+ relation([{a,1},{a,2}])),
+ ok.
+
+no_elements_1(suite) -> [];
+no_elements_1(doc) -> [""];
+no_elements_1(Conf) when list(Conf) ->
+ ?line 0 = no_elements(empty_set()),
+ ?line 0 = no_elements(set([])),
+ ?line 1 = no_elements(from_term([a])),
+ ?line 10 = no_elements(from_term(lists:seq(1,10))),
+ ?line 3 = no_elements(from_term({a,b,c},{atom,atom,atom})),
+ ?line {'EXIT', {badarg, _}} = (catch no_elements(from_term(a))),
+ ?line {'EXIT', {function_clause, _}} = (catch no_elements(a)),
+ ok.
+
+image(suite) -> [];
+image(doc) -> [""];
+image(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line ER = relation([]),
+ ?line eval(image(E, E), E),
+ ?line eval(image(ER, E), set([])),
+ ?line eval(image(relation([{a,1},{b,2},{c,3},{f,6}]), set([a,b,c,d,f])),
+ set([1,2,3,6])),
+ ?line eval(image(relation([{a,1},{b,2},{c,3},{d,4},{r,17}]),
+ set([b,c,q,r])),
+ set([2,3,17])),
+ ?line eval(image(from_term([{[a],{1}},{[b],{2}}]), from_term([[a]])),
+ from_term([{1}])),
+ ?line eval(image(relation([{1,a},{2,a},{3,a},{4,b},{2,b}]), set([1,2,4])),
+ set([a,b])),
+ ?line {'EXIT', {badarg, _}} =
+ (catch image(from_term([a,b]), E)),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch image(from_term([{[a],1}]), set([[a]]))),
+ ok.
+
+inverse_image(suite) -> [];
+inverse_image(doc) -> [""];
+inverse_image(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line ER = relation([]),
+ ?line eval(inverse_image(E, E), E),
+ ?line eval(inverse_image(ER, E), set([])),
+ ?line eval(inverse_image(converse(relation([{a,1},{b,2},{c,3},{f,6}])),
+ set([a,b,c,d,f])),
+ set([1,2,3,6])),
+ ?line eval(inverse_image(converse(relation([{a,1},{b,2},{c,3},
+ {d,4},{r,17}])),
+ set([b,c,q,r])),
+ set([2,3,17])),
+ ?line eval(inverse_image(converse(from_term([{[a],{1}},{[b],{2}}])),
+ from_term([[a]])),
+ from_term([{1}])),
+ ?line eval(inverse_image(converse(relation([{1,a},{2,a},
+ {3,a},{4,b},{2,b}])),
+ set([1,2,4])),
+ set([a,b])),
+ ?line {'EXIT', {badarg, _}} =
+ (catch inverse_image(from_term([a,b]), E)),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch inverse_image(converse(from_term([{[a],1}])), set([[a]]))),
+ ok.
+
+composite_1(suite) -> [];
+composite_1(doc) -> [""];
+composite_1(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line EF = a_function([]),
+ ?line eval(composite(E, E), E),
+ ?line eval(composite(E, a_function([{a,b}])), E),
+ ?line eval(composite(relation([{a,b}]), E), E),
+ ?line {'EXIT', {bad_function, _}} =
+ (catch composite(EF, relation([{a,b},{a,c}]))),
+ ?line {'EXIT', {bad_function, _}} =
+ (catch composite(a_function([{b,a}]), EF)),
+ ?line {'EXIT', {bad_function, _}} =
+ (catch composite(relation([{1,a},{2,b},{2,a}]),
+ a_function([{a,1},{b,3}]))),
+ ?line {'EXIT', {bad_function, _}} =
+ (catch composite(a_function([{1,a},{2,b}]), a_function([{b,3}]))),
+ ?line eval(composite(EF, EF), EF),
+ ?line eval(composite(a_function([{b,a}]), from_term([{a,{b,c}}])),
+ from_term([{b,{b,c}}])),
+ ?line eval(composite(a_function([{q,1},{z,2}]),
+ a_function([{1,a},{2,a}])),
+ a_function([{q,a},{z,a}])),
+ ?line eval(composite(a_function([{a,0},{b,0},{c,1},{d,1},{e,2},{f,3}]),
+ a_function([{0,p},{1,q},{2,r},{3,w},{4,aa}])),
+ a_function([{c,q},{d,q},{f,w},{e,r},{a,p},{b,p}])),
+ ?line eval(composite(a_function([{1,c}]),
+ a_function([{a,1},{b,3},{c,4}])),
+ a_function([{1,4}])),
+ ?line {'EXIT', {bad_function, _}} =
+ (catch composite(a_function([{1,a},{2,b}]),
+ a_function([{a,1},{c,3}]))),
+ ?line {'EXIT', {badarg, _}} =
+ (catch composite(from_term([a,b]), E)),
+ ?line {'EXIT', {badarg, _}} =
+ (catch composite(E, from_term([a,b]))),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch composite(from_term([{a,b}]), from_term([{{a},b}]))),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch composite(from_term([{a,b}]),
+ from_term([{b,c}], [{d,r}]))),
+ F = 0.0, I = round(F),
+ ?line FR1 = relation([{1,c}]),
+ ?line FR2 = relation([{I,1},{F,3},{c,4}]),
+ if
+ F == I -> % term ordering
+ ?line {'EXIT', {bad_function, _}} = (catch composite(FR1, FR2));
+ true ->
+ ?line eval(composite(FR1, FR2), a_function([{1,4}]))
+ end,
+ ok.
+
+relative_product_1(suite) -> [];
+relative_product_1(doc) -> [""];
+relative_product_1(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line ER = relation([]),
+ ?line eval(relative_product1(E, E), E),
+ ?line eval(relative_product1(E, relation([{a,b}])), E),
+ ?line eval(relative_product1(relation([{a,b}]), E), E),
+ ?line eval(relative_product1(relation([{a,b}]), from_term([{a,{b,c}}])),
+ from_term([{b,{b,c}}])),
+ ?line eval(relative_product1(relation([{1,z},{1,q},{2,z}]),
+ relation([{1,a},{1,b},{2,a}])),
+ relation([{q,a},{q,b},{z,a},{z,b}])),
+ ?line eval(relative_product1(relation([{0,a},{0,b},{1,c},
+ {1,d},{2,e},{3,f}]),
+ relation([{1,q},{3,w}])),
+ relation([{c,q},{d,q},{f,w}])),
+ ?line {'EXIT', {badarg, _}} =
+ (catch relative_product1(from_term([a,b]), ER)),
+ ?line {'EXIT', {badarg, _}} =
+ (catch relative_product1(ER, from_term([a,b]))),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch relative_product1(from_term([{a,b}]), from_term([{{a},b}]))),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch relative_product1(from_term([{a,b}]),
+ from_term([{b,c}], [{d,r}]))),
+ ok.
+
+relative_product_2(suite) -> [];
+relative_product_2(doc) -> [""];
+relative_product_2(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line ER = relation([]),
+
+ ?line {'EXIT', {badarg, _}} = (catch relative_product({from_term([a,b])})),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch relative_product({from_term([{a,b}]), from_term([{{a},b}])})),
+ ?line {'EXIT', {badarg, _}} = (catch relative_product({})),
+ ?line true = is_equal(relative_product({ER}),
+ from_term([], [{atom,{atom}}])),
+ ?line eval(relative_product({relation([{a,b},{c,a}]),
+ relation([{a,1},{a,2}]),
+ relation([{a,aa},{c,1}])}),
+ from_term([{a,{b,1,aa}},{a,{b,2,aa}}])),
+ ?line eval(relative_product({relation([{a,b}])}, E), E),
+ ?line eval(relative_product({E}, relation([{a,b}])), E),
+ ?line eval(relative_product({E,from_term([], [{{atom,atom,atom},atom}])}),
+ E),
+ ?line {'EXIT', {badarg, _}} =
+ (catch relative_product({from_term([a,b])}, E)),
+ ?line {'EXIT', {badarg, _}} =
+ (catch relative_product({relation([])}, set([]))),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch relative_product({from_term([{a,b}]),
+ from_term([{{a},b}])}, ER)),
+
+ ?line {'EXIT', {badarg, _}} = (catch relative_product({}, ER)),
+ ?line eval(relative_product({relation([{a,b}])},
+ from_term([],[{{atom},atom}])),
+ ER),
+ ?line eval(relative_product({relation([{a,b}]),relation([{a,1}])},
+ from_term([{{b,1},{tjo,hej,sa}}])),
+ from_term([{a,{tjo,hej,sa}}])),
+ ?line eval(relative_product({relation([{a,b}]), ER},
+ from_term([{{a,b},b}])),
+ ER),
+ ?line eval(relative_product({relation([{a,b},{c,a}]),
+ relation([{a,1},{a,2}])},
+ from_term([{{b,1},b1},{{b,2},b2}])),
+ relation([{a,b1},{a,b2}])),
+ ?line eval(relative_product({relation([{a,b}]), ER}),
+ from_term([],[{atom,{atom,atom}}])),
+ ?line eval(relative_product({from_term([{{a,[a,b]},[a]}]),
+ from_term([{{a,[a,b]},[[a,b]]}])}),
+ from_term([{{a,[a,b]},{[a],[[a,b]]}}])),
+ ok.
+
+product_1(suite) -> [];
+product_1(doc) -> [""];
+product_1(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line eval(product(E, E), E),
+ ?line eval(product(relation([]), E), E),
+ ?line eval(product(E, relation([])), E),
+ ?line eval(product(relation([{a,b}]),relation([{c,d}])),
+ from_term([{{a,b},{c,d}}],[{{atom,atom},{atom,atom}}])),
+
+ ?line eval(product({E, set([a,b,c])}), E),
+ ?line eval(product({set([a,b,c]), E}), E),
+ ?line eval(product({set([a,b,c]), E, E}), E),
+ ?line eval(product({E,E}), E),
+ ?line eval(product({set([a,b]),set([1,2])}),
+ relation([{a,1},{a,2},{b,1},{b,2}])),
+ ?line eval(product({from_term([a,b]), from_term([{a,b},{c,d}]),
+ from_term([1])}),
+ from_term([{a,{a,b},1},{a,{c,d},1},{b,{a,b},1},{b,{c,d},1}])),
+ ?line {'EXIT', {badarg, _}} = (catch product({})),
+ ?line {'EXIT', {badarg, _}} = (catch product({foo})),
+ ?line eval(product({E}), E),
+ ?line eval(product({E, E}), E),
+ ?line eval(product(set([a,b]), set([1,2])),
+ relation([{a,1},{a,2},{b,1},{b,2}])),
+ ?line eval(product({relation([]), E}), E),
+ ok.
+
+partition_1(suite) -> [];
+partition_1(doc) -> [""];
+partition_1(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line ER = relation([]),
+ ?line Id = fun(A) -> A end,
+ ?line S1 = relation([{a,1},{b,2},{b,22},{c,0}]),
+ ?line eval(partition(1, E), E),
+ ?line eval(partition(2, E), E),
+ ?line eval(partition(1, ER), from_term([], [type(ER)])),
+ ?line eval(partition(2, ER), from_term([], [type(ER)])),
+ ?line eval(partition(1, relation([{1,a},{1,b},{2,c},{2,d}])),
+ from_term([[{1,a},{1,b}],[{2,c},{2,d}]])),
+ ?line eval(partition(2, relation([{1,a},{1,b},{2,a},{2,b},{3,c}])),
+ from_term([[{1,a},{2,a}],[{1,b},{2,b}],[{3,c}]])),
+ ?line eval(partition(2, relation([{1,a}])), from_term([[{1,a}]])),
+ ?line eval(partition(2, relation([{1,a},{2,b}])),
+ from_term([[{1,a}],[{2,b}]])),
+ ?line eval(partition(2, relation([{1,a},{2,a},{3,a}])),
+ from_term([[{1,a},{2,a},{3,a}]])),
+ ?line eval(partition(2, relation([{1,b},{2,a}])), % OTP-4516
+ from_term([[{1,b}],[{2,a}]])),
+ ?line eval(union(partition(Id, S1)), S1),
+ ?line eval(partition({external, fun({A,{B,_}}) -> {A,B} end},
+ from_term([{a,{b,c}},{b,{c,d}},{a,{b,f}}])),
+ from_term([[{a,{b,c}},{a,{b,f}}],[{b,{c,d}}]])),
+ F = 0.0, I = round(F),
+ ?line FR = relation([{I,a},{F,b}]),
+ if
+ F == I -> % term ordering
+ ?line eval(partition(1, FR), from_term([[{I,a},{F,b}]]));
+ true ->
+ ?line eval(partition(1, FR), from_term([[{I,a}],[{F,b}]]))
+ end,
+ ?line {'EXIT', {badarg, _}} = (catch partition(2, set([a]))),
+ ?line {'EXIT', {badarg, _}} = (catch partition(1, set([a]))),
+ ?line eval(partition(Id, set([a])), from_term([[a]])),
+
+ ?line eval(partition(E), E),
+ ?line P1 = from_term([[a,b,c],[d,e,f],[g,h]]),
+ ?line P2 = from_term([[a,d],[b,c,e,f,q,v]]),
+ ?line eval(partition(union(P1, P2)),
+ from_term([[a],[b,c],[d],[e,f],[g,h],[q,v]])),
+ ?line {'EXIT', {badarg, _}} = (catch partition(from_term([a]))),
+ ok.
+
+partition_3(suite) -> [];
+partition_3(doc) -> [""];
+partition_3(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line ER = relation([]),
+
+ %% set of ordered sets
+ ?line S1 = relation([{a,1},{b,2},{b,22},{c,0}]),
+ ?line eval(partition(1, S1, set([0,1,d,e])),
+ lpartition(1, S1, set([0,1,d,e]))),
+ ?line eval(partition(1, S1, E), lpartition(1, S1, E)),
+ ?line eval(partition(2, ER, set([a,b])), lpartition(2, ER, set([a,b]))),
+
+ XFun1 = {external, fun({_A,B,C}) -> {B,C} end},
+ R1a = relation([{a,aa,1},{b,bb,2},{c,cc,3}]),
+ R1b = relation([{bb,2},{cc,3}]),
+ ?line eval(partition(XFun1, R1a, R1b), lpartition(XFun1, R1a, R1b)),
+
+ Id = fun(X) -> X end,
+ XId = {external, Id},
+ R2 = relation([{a,b}]),
+ ?line eval(partition(XId, R2, E), lpartition(XId, R2, E)),
+
+ R3 = relation([{b,d}]),
+ ?line eval(partition(XId, E, R3), lpartition(XId, E, R3)),
+
+ Fun1 = fun(S) -> {_A,B,C} = to_external(S), from_term({B,C}) end,
+ R4a = relation([{a,aa,1},{b,bb,2},{c,cc,3}]),
+ R4b = relation([{bb,2},{cc,3}]),
+ ?line eval(partition(Fun1,R4a,R4b), lpartition(Fun1,R4a,R4b)),
+
+ XFun2 = {external, fun({_,{A},B}) -> {A,B} end},
+ R5a = from_term([{a,{aa},1},{b,{bb},2},{c,{cc},3}]),
+ R5b = from_term([{bb,2},{cc,3}]),
+ ?line eval(partition(XFun2,R5a, R5b), lpartition(XFun2,R5a, R5b)),
+
+ R6 = relation([{a,b}]),
+ ?line eval(partition(2, R6, E), lpartition(2, R6, E)),
+
+ R7 = relation([{b,d}]),
+ ?line eval(partition(2, E, R7), lpartition(2, E, R7)),
+
+ S2 = set([a]),
+ ?line eval(partition(XId, E, S2), lpartition(XId, E, S2)),
+ ?line eval(partition(XId, S1, E), lpartition(XId, S1, E)),
+ ?line {'EXIT', {badarg, _}} =
+ (catch partition(3, relation([{a,b}]), E)),
+ ?line {'EXIT', {badarg, _}} =
+ (catch partition(3, relation([{a,b}]), relation([{b,d}]))),
+ ?line {'EXIT', {badarg, _}} =
+ (catch partition(3, relation([{a,b}]), set([{b,d}]))),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch partition(2, relation([{a,b}]), relation([{b,d}]))),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch partition({external, fun({A,_B}) -> A end},
+ relation([{a,b}]), relation([{b,d}]))),
+ ?line {'EXIT', {badarg, _}} =
+ (catch partition({external, fun({A,_}) -> {A,0} end},
+ from_term([{1,a}]),
+ from_term([{1,0}]))),
+
+ S18a = relation([{1,e},{2,b},{3,c},{4,b},{5,a},{6,0}]),
+ S18b = set([b,d,f]),
+ ?line eval(partition({external,fun({_,X}) -> X end}, S18a, S18b),
+ lpartition({external,fun({_,X}) -> X end}, S18a, S18b)),
+ S19a = sofs:relation([{3,a},{8,b}]),
+ S19b = set([2,6,7]),
+ ?line eval(partition({external,fun({X,_}) -> X end}, S19a, S19b),
+ lpartition({external,fun({X,_}) -> X end}, S19a, S19b)),
+
+ R8a = relation([{a,d},{b,e},{c,b},{d,c}]),
+ S8 = set([b,d]),
+ ?line eval(partition(2, R8a, S8), lpartition(2, R8a, S8)),
+
+ S16a = relation([{1,e},{2,b},{3,c},{4,b},{5,a},{6,0}]),
+ S16b = set([b,c,d]),
+ ?line eval(partition(2, S16a, S16b), lpartition(2, S16a, S16b)),
+ S17a = relation([{e,1},{b,2},{c,3},{b,4},{a,5},{0,6}]),
+ S17b = set([b,c,d]),
+ ?line eval(partition(1, S17a, S17b), lpartition(1, S17a, S17b)),
+
+ ?line {'EXIT', {function_clause, _}} =
+ (catch partition({external, fun({A,_B}) -> A end}, set([]), E)),
+
+ Fun3 = fun(S) -> from_term({to_external(S),0}, {type(S),atom}) end,
+ S9a = set([1,2]),
+ S9b = from_term([{1,0}]),
+ ?line eval(partition(Fun3, S9a, S9b), lpartition(Fun3, S9a, S9b)),
+
+ S14a = relation([{1,a},{2,b},{3,c},{0,0}]),
+ S14b = set([b,c]),
+ ?line eval(partition(2, S14a, S14b), lpartition(2, S14a, S14b)),
+ S15a = relation([{a,1},{b,2},{c,3},{0,0}]),
+ S15b = set([b,c]),
+ ?line eval(partition(1, S15a, S15b), lpartition(1, S15a, S15b)),
+
+ %% set of sets
+ ?line {'EXIT', {badarg, _}} =
+ (catch partition({external, fun(X) -> X end},
+ from_term([], [[atom]]), set([a]))),
+
+ S10 = from_term([], [[atom]]),
+ ?line eval(partition(Id, S10, E), lpartition(Id, S10, E)),
+
+ S10e = from_term([[a],[b]], [[atom]]),
+ ?line eval(partition(Id, S10e, E), lpartition(Id, S10e, E)),
+
+ S11a = from_term([], [[atom]]),
+ S11b = set([a]),
+ ?line eval(partition(Id, S11a, S11b), lpartition(Id, S11a, S11b)),
+
+ S12a = from_term([[[a],[b]], [[b],[c]], [[], [a,b]], [[1],[2]]]),
+ S12b = from_term([[a,b],[1,2,3],[b,c]]),
+ ?line eval(partition({sofs,union}, S12a, S12b),
+ lpartition({sofs,union}, S12a, S12b)),
+
+ Fun13 = fun(_) -> from_term([a]) end,
+ S13a = from_term([], [[atom]]),
+ S13b = from_term([], [[a]]),
+ ?line eval(partition(Fun13, S13a, S13b), lpartition(Fun13, S13a, S13b)),
+
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch partition(fun(_) -> from_term([a]) end,
+ from_term([[1,2],[3,4]]),
+ from_term([], [atom]))),
+ Fun10 = fun(S) ->
+ %% Cheating a lot...
+ case to_external(S) of
+ [1] -> from_term({1,1});
+ _ -> S
+ end
+ end,
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch partition(Fun10, from_term([[1]]), from_term([], [[atom]]))),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch partition(fun(_) -> from_term({a}) end,
+ from_term([[a]]),
+ from_term([], [atom]))),
+ ?line {'EXIT', {badarg, _}} =
+ (catch partition(fun(_) -> {a} end,
+ from_term([[a]]),
+ from_term([], [atom]))),
+ ok.
+
+lpartition(F, S1, S2) ->
+ {restriction(F, S1, S2), drestriction(F, S1, S2)}.
+
+multiple_relative_product(suite) -> [];
+multiple_relative_product(doc) -> [""];
+multiple_relative_product(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line ER = relation([]),
+ ?line T = relation([{a,1},{a,11},{b,2},{c,3},{c,33},{d,4}]),
+ ?line {'EXIT', {badarg, _}} =
+ (catch multiple_relative_product({}, ER)),
+ ?line {'EXIT', {badarg, _}} =
+ (catch multiple_relative_product({}, relation([{a,b}]))),
+ ?line eval(multiple_relative_product({E,T,T}, relation([], 3)), E),
+ ?line eval(multiple_relative_product({T,T,T}, E), E),
+ ?line eval(multiple_relative_product({T,T,T}, relation([],3)),
+ from_term([],[{{atom,atom,atom},{atom,atom,atom}}])),
+ ?line eval(multiple_relative_product({T,T,T},
+ relation([{a,b,c},{c,d,a}])),
+ from_term([{{a,b,c},{1,2,3}}, {{a,b,c},{1,2,33}},
+ {{a,b,c},{11,2,3}}, {{a,b,c},{11,2,33}},
+ {{c,d,a},{3,4,1}}, {{c,d,a},{3,4,11}},
+ {{c,d,a},{33,4,1}}, {{c,d,a},{33,4,11}}])),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch multiple_relative_product({T}, from_term([{{a}}]))),
+ ok.
+
+digraph(suite) -> [];
+digraph(doc) -> [""];
+digraph(Conf) when list(Conf) ->
+ ?line T0 = ets:all(),
+ ?line E = empty_set(),
+ ?line R = relation([{a,b},{b,c},{c,d},{d,a}]),
+ ?line F = relation_to_family(R),
+ Type = type(F),
+
+ ?line {'EXIT', {badarg, _}} =
+ (catch family_to_digraph(set([a]))),
+ ?line {'EXIT', {badarg, [{sofs,family_to_digraph,[_,_]}|_]}} =
+ (catch family_to_digraph(set([a]), [foo])),
+ ?line {'EXIT', {badarg, [{sofs,family_to_digraph,[_,_]}|_]}} =
+ (catch family_to_digraph(F, [foo])),
+ ?line {'EXIT', {cyclic, [{sofs,family_to_digraph,[_,_]}|_]}} =
+ (catch family_to_digraph(family([{a,[a]}]),[acyclic])),
+
+ ?line G1 = family_to_digraph(E),
+ ?line {'EXIT', {badarg, _}} = (catch digraph_to_family(G1, foo)),
+ ?line {'EXIT', {badarg, _}} = (catch digraph_to_family(G1, atom)),
+ ?line true = [] == to_external(digraph_to_family(G1)),
+ ?line true = [] == to_external(digraph_to_family(G1, Type)),
+ ?line true = digraph:delete(G1),
+
+ ?line G1a = family_to_digraph(E, [protected]),
+ ?line true = [] == to_external(digraph_to_family(G1a)),
+ ?line true = [] == to_external(digraph_to_family(G1a, Type)),
+ ?line true = digraph:delete(G1a),
+
+ ?line G2 = family_to_digraph(F),
+ ?line true = F == digraph_to_family(G2),
+ ?line true = F == digraph_to_family(G2, type(F)),
+ ?line true = digraph:delete(G2),
+
+ ?line R2 = from_term([{{a},b},{{c},d}]),
+ ?line F2 = relation_to_family(R2),
+ ?line Type2 = type(F2),
+ ?line G3 = family_to_digraph(F2, [protected]),
+ ?line true = is_subset(F2, digraph_to_family(G3, Type2)),
+ ?line true = digraph:delete(G3),
+
+ Fl = 0.0, I = round(Fl),
+ if
+ Fl == I -> % term ordering
+ ?line G4 = digraph:new(),
+ digraph:add_vertex(G4, Fl),
+ digraph:add_vertex(G4, I),
+ ?line {'EXIT', {badarg, _}} =
+ (catch digraph_to_family(G4, Type)),
+ ?line {'EXIT', {badarg, _}} =
+ (catch digraph_to_family(G4)),
+ ?line true = digraph:delete(G4);
+ true -> ok
+ end,
+
+ ?line true = T0 == ets:all(),
+ ok.
+
+constant_function(suite) -> [];
+constant_function(doc) -> [""];
+constant_function(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line C = from_term(3),
+ ?line eval(constant_function(E, C), E),
+ ?line eval(constant_function(set([a,b]), E), from_term([{a,[]},{b,[]}])),
+ ?line eval(constant_function(set([a,b]), C), from_term([{a,3},{b,3}])),
+ ?line {'EXIT', {badarg, _}} = (catch constant_function(C, C)),
+ ?line {'EXIT', {badarg, _}} = (catch constant_function(set([]), foo)),
+ ok.
+
+misc(suite) -> [];
+misc(doc) -> [""];
+misc(Conf) when list(Conf) ->
+ % find "relational" part of relation:
+ ?line S = relation([{a,b},{b,c},{b,d},{c,d}]),
+ Id = fun(A) -> A end,
+ ?line RR = relational_restriction(S),
+ ?line eval(union(difference(partition(Id,S), partition(1,S))), RR),
+ ?line eval(union(difference(partition(1,S), partition(Id,S))), RR),
+
+ % the "functional" part:
+ ?line eval(union(intersection(partition(1,S), partition(Id,S))),
+ difference(S, RR)),
+
+ %% The function external:foo/1 is undefined.
+ ?line {'EXIT', {undef, _}} =
+ (catch projection({external,foo}, set([a,b,c]))),
+ ok.
+
+relational_restriction(R) ->
+ Fun = fun(S) -> no_elements(S) > 1 end,
+ family_to_relation(family_specification(Fun, relation_to_family(R))).
+
+sofs_family(suite) ->
+ [family_specification, family_domain_1, family_range_1,
+ family_to_relation_1, union_of_family_1, intersection_of_family_1,
+ family_projection, family_difference,
+ family_intersection_1, family_intersection_2,
+ family_union_1, family_union_2, partition_family].
+
+family_specification(suite) -> [];
+family_specification(doc) -> [""];
+family_specification(Conf) when list(Conf) ->
+ E = empty_set(),
+ %% internal
+ ?line eval(family_specification({sofs, is_set}, E), E),
+ ?line {'EXIT', {badarg, _}} =
+ (catch family_specification({sofs,is_set}, set([]))),
+ ?line F1 = from_term([{1,[1]}]),
+ ?line eval(family_specification({sofs,is_set}, F1), F1),
+ Fun = fun(S) -> is_subset(S, set([0,1,2,3,4])) end,
+ ?line F2 = family([{a,[1,2]},{b,[3,4,5]}]),
+ ?line eval(family_specification(Fun, F2), family([{a,[1,2]}])),
+ ?line F3 = from_term([{a,[]},{b,[]}]),
+ ?line eval(family_specification({sofs,is_set}, F3), F3),
+ Fun2 = fun(_) -> throw(fippla) end,
+ ?line fippla = (catch family_specification(Fun2, family([{a,[1]}]))),
+ Fun3 = fun(_) -> neither_true_or_false end,
+ ?line {'EXIT', {badarg, _}} =
+ (catch family_specification(Fun3, F3)),
+
+ %% external
+ IsList = {external, fun(L) when list(L) -> true; (_) -> false end},
+ ?line eval(family_specification(IsList, E), E),
+ ?line eval(family_specification(IsList, F1), F1),
+ MF = {external, fun(L) -> lists:member(3, L) end},
+ ?line eval(family_specification(MF, F2), family([{b,[3,4,5]}])),
+ ?line fippla = (catch family_specification(Fun2, family([{a,[1]}]))),
+ ?line {'EXIT', {badarg, _}} =
+ (catch family_specification({external, Fun3}, F3)),
+ ok.
+
+family_domain_1(suite) -> [];
+family_domain_1(doc) -> [""];
+family_domain_1(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line ER = from_term([{a,[]},{b,[]}],[{atom,[{atom,atom}]}]),
+ ?line EF = from_term([{a,[]},{b,[]}],[{atom,[atom]}]),
+ ?line eval(family_domain(E), E),
+ ?line eval(family_domain(ER), EF),
+ ?line FR = from_term([{a,[{1,a},{2,b},{3,c}]},{b,[]},{c,[{4,d},{5,e}]}]),
+ ?line eval(family_domain(FR), from_term([{a,[1,2,3]},{b,[]},{c,[4,5]}])),
+ ?line eval(family_field(E), E),
+ ?line eval(family_field(FR),
+ from_term([{a,[a,b,c,1,2,3]},{b,[]},{c,[d,e,4,5]}])),
+ ?line eval(family_domain(from_term([{{a},[{{1,[]},c}]}])),
+ from_term([{{a},[{1,[]}]}])),
+ ?line eval(family_domain(from_term([{{a},[{{1,[a]},c}]}])),
+ from_term([{{a},[{1,[a]}]}])),
+ ?line eval(family_domain(from_term([{{a},[]}])),
+ from_term([{{a},[]}])),
+ ?line eval(family_domain(from_term([], type(FR))),
+ from_term([], [{atom,[atom]}])),
+ ?line {'EXIT', {badarg, _}} = (catch family_domain(set([a]))),
+ ?line {'EXIT', {badarg, _}} = (catch family_field(set([a]))),
+ ?line {'EXIT', {badarg, _}} = (catch family_domain(set([{a,[b]}]))),
+ ok.
+
+family_range_1(suite) -> [];
+family_range_1(doc) -> [""];
+family_range_1(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line ER = from_term([{a,[]},{b,[]}],[{atom,[{atom,atom}]}]),
+ ?line EF = from_term([{a,[]},{b,[]}],[{atom,[atom]}]),
+ ?line eval(family_range(E), E),
+ ?line eval(family_range(ER), EF),
+ ?line FR = from_term([{a,[{1,a},{2,b},{3,c}]},{b,[]},{c,[{4,d},{5,e}]}]),
+ ?line eval(family_range(FR), from_term([{a,[a,b,c]},{b,[]},{c,[d,e]}])),
+ ?line eval(family_range(from_term([{{a},[{c,{1,[a]}}]}])),
+ from_term([{{a},[{1,[a]}]}])),
+ ?line eval(family_range(from_term([{{a},[{c,{1,[]}}]}])),
+ from_term([{{a},[{1,[]}]}])),
+ ?line eval(family_range(from_term([{{a},[]}])),
+ from_term([{{a},[]}])),
+ ?line eval(family_range(from_term([], type(FR))),
+ from_term([], [{atom,[atom]}])),
+ ?line {'EXIT', {badarg, _}} = (catch family_range(set([a]))),
+ ?line {'EXIT', {badarg, _}} = (catch family_range(set([{a,[b]}]))),
+ ok.
+
+family_to_relation_1(suite) -> [];
+family_to_relation_1(doc) -> [""];
+family_to_relation_1(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line ER = relation([]),
+ ?line EF = family([]),
+ ?line eval(family_to_relation(E), E),
+ ?line eval(family_to_relation(EF), ER),
+ ?line eval(sofs:fam2rel(EF), ER),
+ ?line F = family([{a,[]},{b,[1]},{c,[7,9,11]}]),
+ ?line eval(family_to_relation(F), relation([{b,1},{c,7},{c,9},{c,11}])),
+ ?line {'EXIT', {badarg, _}} = (catch family_to_relation(set([a]))),
+ ok.
+
+union_of_family_1(suite) -> [];
+union_of_family_1(doc) -> [""];
+union_of_family_1(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line EF = from_term([{a,[]},{b,[]}],[{atom,[atom]}]),
+ ?line eval(union_of_family(E), E),
+ ?line eval(union_of_family(EF), set([])),
+ ?line eval(union_of_family(family([])), set([])),
+ ?line FR = from_term([{a,[1,2,3]},{b,[]},{c,[4,5]}]),
+ ?line eval(union_of_family(FR), set([1,2,3,4,5])),
+ ?line eval(union_of_family(sofs:family([{a,[1,2]},{b,[1,2]}])),
+ set([1,2])),
+ ?line {'EXIT', {badarg, _}} = (catch union_of_family(set([a]))),
+ ok.
+
+intersection_of_family_1(suite) -> [];
+intersection_of_family_1(doc) -> [""];
+intersection_of_family_1(Conf) when list(Conf) ->
+ ?line EF = from_term([{a,[]},{b,[]}],[{atom,[atom]}]),
+ ?line eval(intersection_of_family(EF), set([])),
+ ?line FR = from_term([{a,[1,2,3]},{b,[2,3]},{c,[3,4,5]}]),
+ ?line eval(intersection_of_family(FR), set([3])),
+ ?line {'EXIT', {badarg, _}} =
+ (catch intersection_of_family(family([]))),
+ ?line EE = from_term([], [[atom]]),
+ ?line {'EXIT', {badarg, _}} = (catch intersection_of_family(EE)),
+ ?line {'EXIT', {badarg, _}} = (catch intersection_of_family(set([a]))),
+ ok.
+
+family_projection(suite) -> [];
+family_projection(doc) -> [""];
+family_projection(Conf) when list(Conf) ->
+ SSType = [{atom,[[atom]]}],
+ SRType = [{atom,[{atom,atom}]}],
+ ?line E = empty_set(),
+
+ ?line eval(family_projection(fun(X) -> X end, family([])), E),
+ ?line L1 = [{a,[]}],
+ ?line eval(family_projection({sofs,union}, E), E),
+ ?line eval(family_projection({sofs,union}, from_term(L1, SSType)),
+ family(L1)),
+ ?line {'EXIT', {badarg, _}} =
+ (catch family_projection({sofs,union}, set([]))),
+ ?line {'EXIT', {badarg, _}} =
+ (catch family_projection({sofs,union}, from_term([{1,[1]}]))),
+
+ ?line F2 = from_term([{a,[[1],[2]]},{b,[[3,4],[5]]}], SSType),
+ ?line eval(family_projection({sofs,union}, F2),
+ family_union(F2)),
+
+ ?line F3 = from_term([{1,[{a,b},{b,c},{c,d}]},{3,[]},{5,[{3,5}]}],
+ SRType),
+ ?line eval(family_projection({sofs,domain}, F3), family_domain(F3)),
+ ?line eval(family_projection({sofs,range}, F3), family_range(F3)),
+
+ ?line eval(family_projection(fun(_) -> E end, family([{a,[b,c]}])),
+ from_term([{a,[]}])),
+
+ Fun1 = fun(S) ->
+ case to_external(S) of
+ [1] -> from_term({1,1});
+ _ -> S
+ end
+ end,
+ ?line eval(family_projection(Fun1, family([{a,[1]}])),
+ from_term([{a,{1,1}}])),
+ Fun2 = fun(_) -> throw(fippla) end,
+ ?line fippla =
+ (catch family_projection(Fun2, family([{a,[1]}]))),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch family_projection(Fun1, from_term([{1,[1]},{2,[2]}]))),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch family_projection(Fun1, from_term([{1,[1]},{0,[0]}]))),
+
+ ?line eval(family_projection(fun(_) -> E end, from_term([{a,[]}])),
+ from_term([{a,[]}])),
+ F4 = from_term([{a,[{1,2,3}]},{b,[{4,5,6}]},{c,[]},{m3,[]}]),
+ Z = from_term(0),
+ ?line eval(family_projection(fun(S) -> local_adjoin(S, Z) end, F4),
+ from_term([{a,[{{1,2,3},0}]},{b,[{{4,5,6},0}]},{c,[]},{m3,[]}])),
+ ?line {'EXIT', {badarg, _}} =
+ (catch family_projection({external, fun(X) -> X end},
+ from_term([{1,[1]}]))),
+
+ %% ordered set element
+ ?line eval(family_projection(fun(_) -> from_term(a, atom) end,
+ from_term([{1,[a]}])),
+ from_term([{1,a}])),
+ ok.
+
+family_difference(suite) -> [];
+family_difference(doc) -> [""];
+family_difference(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line EF = family([]),
+ ?line F9 = from_term([{b,[b,c]}]),
+ ?line F10 = from_term([{a,[b,c]}]),
+ ?line eval(family_difference(E, E), E),
+ ?line eval(family_difference(E, F10), from_term([], type(F10))),
+ ?line eval(family_difference(F10, E), F10),
+ ?line eval(family_difference(F9, F10), F9),
+ ?line eval(family_difference(F10, F10), family([{a,[]}])),
+ ?line F20 = from_term([{a,[1,2,3]},{b,[1,2,3]},{c,[1,2,3]}]),
+ ?line F21 = from_term([{b,[1,2,3]},{c,[1,2,3]}]),
+ ?line eval(family_difference(F20, from_term([{a,[2]}])),
+ from_term([{a,[1,3]},{b,[1,2,3]},{c,[1,2,3]}])),
+ ?line eval(family_difference(F20, from_term([{0,[2]},{q,[1,2]}])), F20),
+ ?line eval(family_difference(F20, F21),
+ from_term([{a,[1,2,3]},{b,[]},{c,[]}])),
+
+ ?line eval(family_difference(from_term([{e,[f,g]}]), family([])),
+ from_term([{e,[f,g]}])),
+ ?line eval(family_difference(from_term([{e,[f,g]}]), EF),
+ from_term([{e,[f,g]}])),
+ ?line eval(family_difference(from_term([{a,[a,b,c,d]},{c,[b,c]}]),
+ from_term([{a,[b,c]},{b,[d]},{d,[e,f]}])),
+ from_term([{a,[a,d]},{c,[b,c]}])),
+ ?line {'EXIT', {badarg, _}} =
+ (catch family_difference(set([]), set([]))),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch family_difference(from_term([{a,[b,c]}]),
+ from_term([{e,[{f}]}]))),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch family_difference(from_term([{a,[b]}]),
+ from_term([{c,[d]}], [{i,[s]}]))),
+ ok.
+
+family_intersection_1(suite) -> [];
+family_intersection_1(doc) -> [""];
+family_intersection_1(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line EF = family([]),
+ ?line ES = from_term([], [{atom,[[atom]]}]),
+ ?line eval(family_intersection(E), E),
+ ?line {'EXIT', {badarg, _}} = (catch family_intersection(EF)),
+ ?line eval(family_intersection(ES), EF),
+ ?line {'EXIT', {badarg, _}} = (catch family_intersection(set([]))),
+ ?line {'EXIT', {badarg, _}} =
+ (catch family_intersection(from_term([{a,[1,2]}]))),
+ ?line F1 = from_term([{a,[[1],[2],[2,3]]},{b,[]},{c,[[4]]}]),
+ ?line {'EXIT', {badarg, _}} = (catch family_intersection(F1)),
+ ?line F2 = from_term([{b,[[1],[2],[2,3]]},{a,[]},{c,[[4]]}]),
+ ?line {'EXIT', {badarg, _}} = (catch family_intersection(F2)),
+ ?line F3 = from_term([{a,[[1,2,3],[2],[2,3]]},{c,[[4,5,6],[5,6,7]]}]),
+ ?line eval(family_intersection(F3), family([{a,[2]},{c,[5,6]}])),
+ ok.
+
+family_intersection_2(suite) -> [];
+family_intersection_2(doc) -> [""];
+family_intersection_2(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line EF = family([]),
+ ?line F1 = from_term([{a,[1,2]},{b,[4,5]},{c,[7,8]},{d,[10,11]}]),
+ ?line F2 = from_term([{c,[6,7]},{d,[9,10,11]},{q,[1]}]),
+ ?line F3 = from_term([{a,[1,2]},{b,[4,5]},{c,[6,7,8]},{d,[9,10,11]},
+ {q,[1]}]),
+
+ ?line eval(family_intersection(E, E), E),
+ ?line eval(family_intersection(EF, EF), EF),
+ ?line eval(family_intersection(F1, F2),
+ from_term([{c,[7]},{d,[10,11]}])),
+ ?line eval(family_intersection(F1, F3), F1),
+ ?line eval(family_intersection(F2, F3), F2),
+
+ ?line eval(family_intersection(EF, from_term([{e,[f,g]}])), EF),
+ ?line eval(family_intersection(E, from_term([{e,[f,g]}])), EF),
+ ?line eval(family_intersection(from_term([{e,[f,g]}]), EF), EF),
+ ?line eval(family_intersection(from_term([{e,[f,g]}]), E), EF),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch family_intersection(from_term([{a,[b,c]}]),
+ from_term([{e,[{f}]}]))),
+
+ ?line F11 = family([{a,[1,2,3]},{b,[0,2,4]},{c,[0,3,6,9]}]),
+ ?line eval(union_of_family(F11), set([0,1,2,3,4,6,9])),
+ ?line F12 = from_term([{a,[1,2,3,4]},{b,[0,2,4]},{c,[2,3,4,5]}]),
+ ?line eval(intersection_of_family(F12), set([2,4])),
+ ok.
+
+family_union_1(suite) -> [];
+family_union_1(doc) -> [""];
+family_union_1(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line EF = family([]),
+ ?line ES = from_term([], [{atom,[[atom]]}]),
+ ?line eval(family_union(E), E),
+ ?line eval(family_union(ES), EF),
+ ?line {'EXIT', {badarg, _}} = (catch family_union(set([]))),
+ ?line {'EXIT', {badarg, _}} =
+ (catch family_union(from_term([{a,[1,2]}]))),
+ ?line eval(family_union(from_term([{a,[[1],[2],[2,3]]},{b,[]},{c,[[4]]}])),
+ family([{a,[1,2,3]},{b,[]},{c,[4]}])),
+ ok.
+
+family_union_2(suite) -> [];
+family_union_2(doc) -> [""];
+family_union_2(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+ ?line EF = family([]),
+ ?line F1 = from_term([{a,[1,2]},{b,[4,5]},{c,[7,8]},{d,[10,11]}]),
+ ?line F2 = from_term([{c,[6,7]},{d,[9,10,11]},{q,[1]}]),
+ ?line F3 = from_term([{a,[1,2]},{b,[4,5]},{c,[6,7,8]},{d,[9,10,11]},
+ {q,[1]}]),
+
+ ?line eval(family_union(E, E), E),
+ ?line eval(family_union(F1, E), F1),
+ ?line eval(family_union(E, F2), F2),
+ ?line eval(family_union(F1, F2), F3),
+ ?line eval(family_union(F2, F1), F3),
+
+ ?line eval(family_union(E, from_term([{e,[f,g]}])),
+ from_term([{e,[f,g]}])),
+ ?line eval(family_union(EF, from_term([{e,[f,g]}])),
+ from_term([{e,[f,g]}])),
+ ?line eval(family_union(from_term([{e,[f,g]}]), E),
+ from_term([{e,[f,g]}])),
+ ?line {'EXIT', {badarg, _}} =
+ (catch family_union(set([]),set([]))),
+ ?line {'EXIT', {type_mismatch, _}} =
+ (catch family_union(from_term([{a,[b,c]}]),
+ from_term([{e,[{f}]}]))),
+ ok.
+
+partition_family(suite) -> [];
+partition_family(doc) -> [""];
+partition_family(Conf) when list(Conf) ->
+ ?line E = empty_set(),
+
+ %% set of ordered sets
+ ?line ER = relation([]),
+ ?line EF = from_term([], [{atom,[{atom,atom}]}]),
+
+ ?line eval(partition_family(1, E), E),
+ ?line eval(partition_family(2, E), E),
+ ?line eval(partition_family({sofs,union}, E), E),
+ ?line eval(partition_family(1, ER), EF),
+ ?line eval(partition_family(2, ER), EF),
+ ?line {'EXIT', {badarg, _}} = (catch partition_family(1, set([]))),
+ ?line {'EXIT', {badarg, _}} = (catch partition_family(2, set([]))),
+ ?line {'EXIT', {function_clause, _}} =
+ (catch partition_family(fun({_A,B}) -> {B} end, from_term([{1}]))),
+ ?line eval(partition_family(1, relation([{1,a},{1,b},{2,c},{2,d}])),
+ from_term([{1,[{1,a},{1,b}]},{2,[{2,c},{2,d}]}])),
+ ?line eval(partition_family(1, relation([{1,a},{2,b}])),
+ from_term([{1,[{1,a}]},{2,[{2,b}]}])),
+ ?line eval(partition_family(2, relation([{1,a},{1,b},{2,a},{2,b},{3,c}])),
+ from_term([{a,[{1,a},{2,a}]},{b,[{1,b},{2,b}]},{c,[{3,c}]}])),
+ ?line eval(partition_family(2, relation([{1,a}])),
+ from_term([{a,[{1,a}]}])),
+ ?line eval(partition_family(2, relation([{1,a},{2,a},{3,a}])),
+ from_term([{a,[{1,a},{2,a},{3,a}]}])),
+ ?line eval(partition_family(2, relation([{1,a},{2,b}])),
+ from_term([{a,[{1,a}]},{b,[{2,b}]}])),
+ ?line F13 = from_term([{a,b,c},{a,b,d},{b,b,c},{a,c,c},{a,c,d},{b,c,c}]),
+ ?line eval(partition_family(2, F13),
+ from_term([{b,[{a,b,c},{a,b,d},{b,b,c}]},
+ {c,[{a,c,c},{a,c,d},{b,c,c}]}])),
+
+ Fun1 = {external, fun({A,_B}) -> {A} end},
+ ?line eval(partition_family(Fun1, relation([{a,1},{a,2},{b,3}])),
+ from_term([{{a},[{a,1},{a,2}]},{{b},[{b,3}]}])),
+ Fun2 = fun(S) -> {A,_B} = to_external(S), from_term({A}) end,
+ ?line eval(partition_family(Fun2, relation([{a,1},{a,2},{b,3}])),
+ from_term([{{a},[{a,1},{a,2}]},{{b},[{b,3}]}])),
+
+ ?line {'EXIT', {badarg, _}} =
+ (catch partition_family({external, fun({A,_}) -> {A,0} end},
+ from_term([{1,a}]))),
+ ?line [{{atom,atom},[{atom,atom,atom,atom}]}] =
+ type(partition_family({external, fun({A,_B,C,_D}) -> {C,A} end},
+ relation([],4))),
+
+ Fun3 = fun(S) -> from_term({to_external(S),0}, {type(S),atom}) end,
+ ?line eval(partition_family(Fun3, E), E),
+ ?line eval(partition_family(Fun3, set([a,b])),
+ from_term([{{a,0},[a]}, {{b,0},[b]}])),
+ ?line eval(partition_family(Fun3, relation([{a,1},{b,2}])),
+ from_term([{{{a,1},0},[{a,1}]},{{{b,2},0},[{b,2}]}])),
+ ?line eval(partition_family(Fun3, from_term([[a],[b]])),
+ from_term([{{[a],0},[[a]]}, {{[b],0},[[b]]}])),
+ ?line partition_family({external, fun(X) -> X end}, E),
+
+ F = 0.0, I = round(F),
+ ?line FR = relation([{I,a},{F,b}]),
+ if
+ F == I -> % term ordering
+ ?line true = (1 =:= no_elements(partition_family(1, FR)));
+ true ->
+ ?line eval(partition_family(1, FR),
+ from_term([{I,[{I,a}]},{F,[{F,b}]}]))
+ end,
+ %% set of sets
+ ?line {'EXIT', {badarg, _}} =
+ (catch partition_family({external, fun(X) -> X end},
+ from_term([], [[atom]]))),
+ ?line {'EXIT', {badarg, _}} =
+ (catch partition_family({external, fun(X) -> X end},
+ from_term([[a]]))),
+ ?line eval(partition_family({sofs,union},
+ from_term([[[1],[1,2]], [[1,2]]])),
+ from_term([{[1,2], [[[1],[1,2]],[[1,2]]]}])),
+ ?line eval(partition_family(fun(X) -> X end,
+ from_term([[1],[1,2],[1,2,3]])),
+ from_term([{[1],[[1]]},{[1,2],[[1,2]]},{[1,2,3],[[1,2,3]]}])),
+
+ ?line eval(partition_family(fun(_) -> from_term([a]) end,
+ from_term([], [[atom]])),
+ E),
+ Fun10 = fun(S) ->
+ %% Cheating a lot...
+ case to_external(S) of
+ [1] -> from_term({1,1});
+ _ -> S
+ end
+ end,
+
+ ?line eval(partition_family(Fun10, from_term([[1]])),
+ from_term([{{1,1},[[1]]}])),
+ ?line eval(partition_family(fun(_) -> from_term({a}) end,
+ from_term([[a]])),
+ from_term([{{a},[[a]]}])),
+ ?line {'EXIT', {badarg, _}} =
+ (catch partition_family(fun(_) -> {a} end, from_term([[a]]))),
+ ok.
+
+%% Not meant to be efficient...
+local_adjoin(S, C) ->
+ X = to_external(C),
+ T = type(C),
+ F = fun(Y) -> from_term({to_external(Y),X}, {type(Y),T}) end,
+ projection(F, S).
+
+eval(R, E) when R == E ->
+ R;
+eval(R, E) ->
+ io:format("expected ~p~n got ~p~n", [E, R]),
+ exit({R,E}).
+
diff --git a/lib/stdlib/test/stdlib.cover b/lib/stdlib/test/stdlib.cover
new file mode 100644
index 0000000000..b98d949889
--- /dev/null
+++ b/lib/stdlib/test/stdlib.cover
@@ -0,0 +1,10 @@
+%% -*- erlang -*-
+{exclude,
+ [erl_parse,
+ ets,
+ filename,
+ gen_event,
+ gen_server,
+ gen,
+ lists,
+ proc_lib]}.
diff --git a/lib/stdlib/test/stdlib.spec b/lib/stdlib/test/stdlib.spec
new file mode 100644
index 0000000000..bbfb43bd15
--- /dev/null
+++ b/lib/stdlib/test/stdlib.spec
@@ -0,0 +1,4 @@
+{topcase, {dir, "../stdlib_test"}}.
+%{skip,{dets_SUITE,open_file_1,"Crashes Windows tests"}}.
+%{skip,{dets_SUITE,fold,"Crashes Windows tests"}}.
+%{skip,{dets_SUITE,match,"Crashes Windows tests"}}.
diff --git a/lib/stdlib/test/stdlib.spec.vxworks b/lib/stdlib/test/stdlib.spec.vxworks
new file mode 100644
index 0000000000..ddc804b831
--- /dev/null
+++ b/lib/stdlib/test/stdlib.spec.vxworks
@@ -0,0 +1,8 @@
+{topcase, {dir, "../stdlib_test"}}.
+{skip,{dets_SUITE,"Not runnable VxWorks/NFS"}}.
+{skip,{slave_SUITE,"VxWorks: slave nodes are not supported"}}.
+{skip,{tar_SUITE,errors,"VxWorks filesystem too primitive"}}.
+{skip,{tar_SUITE,create_long_names,"VxWorks names too short"}}.
+{skip,{epp_SUITE,"Test not adopted to VxWorks"}}.
+{skip,{select_SUITE,"Test too memory consuming for VxWorks"}}.
+{skip,{beam_lib_SUITE,error,"All sections not present in stripped beam files"}}.
diff --git a/lib/stdlib/test/stdlib_SUITE.erl b/lib/stdlib/test/stdlib_SUITE.erl
new file mode 100644
index 0000000000..d46a2caf90
--- /dev/null
+++ b/lib/stdlib/test/stdlib_SUITE.erl
@@ -0,0 +1,64 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%%----------------------------------------------------------------
+%%% Purpose:Stdlib application test suite.
+%%%-----------------------------------------------------------------
+-module(stdlib_SUITE).
+-include("test_server.hrl").
+
+
+% Default timetrap timeout (set in init_per_testcase).
+-define(default_timeout, ?t:minutes(1)).
+-define(application, stdlib).
+
+% Test server specific exports
+-export([all/1]).
+-export([init_per_testcase/2, fin_per_testcase/2]).
+
+% Test cases must be exported.
+-export([app_test/1]).
+-define(cases, [app_test]).
+
+%%
+%% all/1
+%%
+all(doc) ->
+ [];
+all(suite) ->
+ [?cases].
+
+init_per_testcase(_Case, Config) ->
+ ?line Dog=test_server:timetrap(?default_timeout),
+ [{watchdog, Dog}|Config].
+fin_per_testcase(_Case, Config) ->
+ Dog=?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+%
+% Test cases starts here.
+%
+app_test(suite) ->
+ [];
+app_test(doc) ->
+ ["Application consistency test."];
+app_test(Config) when list(Config) ->
+ ?t:app_test(stdlib),
+ ok.
+
diff --git a/lib/stdlib/test/string_SUITE.erl b/lib/stdlib/test/string_SUITE.erl
new file mode 100644
index 0000000000..3171b87c44
--- /dev/null
+++ b/lib/stdlib/test/string_SUITE.erl
@@ -0,0 +1,511 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%%----------------------------------------------------------------
+%%% Purpose: string test suite.
+%%%-----------------------------------------------------------------
+-module(string_SUITE).
+-include("test_server.hrl").
+
+
+% Default timetrap timeout (set in init_per_testcase).
+-define(default_timeout, ?t:minutes(1)).
+
+% Test server specific exports
+-export([all/1]).
+-export([init_per_testcase/2, fin_per_testcase/2]).
+
+% Test cases must be exported.
+-export([len/1,equal/1,concat/1,chr_rchr/1,str_rstr/1]).
+-export([span_cspan/1,substr/1,tokens/1,chars/1]).
+-export([copies/1,words/1,strip/1,sub_word/1,left_right/1]).
+-export([sub_string/1,centre/1, join/1]).
+-export([to_integer/1,to_float/1]).
+-export([to_upper_to_lower/1]).
+%%
+%% all/1
+%%
+all(doc) ->
+ [];
+all(suite) ->
+ [len,equal,concat,chr_rchr,str_rstr,
+ span_cspan,substr,tokens,chars,
+ copies,words,strip,sub_word,left_right,
+ sub_string,centre, join,
+ to_integer,to_float,to_upper_to_lower].
+
+init_per_testcase(_Case, Config) ->
+ ?line Dog=test_server:timetrap(?default_timeout),
+ [{watchdog, Dog}|Config].
+fin_per_testcase(_Case, Config) ->
+ Dog=?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+%
+% Test cases starts here.
+%
+
+len(suite) ->
+ [];
+len(doc) ->
+ [];
+len(Config) when is_list(Config) ->
+ ?line 0 = string:len(""),
+ ?line L = tuple_size(list_to_tuple(atom_to_list(?MODULE))),
+ ?line L = string:len(atom_to_list(?MODULE)),
+ %% invalid arg type
+ ?line {'EXIT',_} = (catch string:len({})),
+ ok.
+
+equal(suite) ->
+ [];
+equal(doc) ->
+ [];
+equal(Config) when is_list(Config) ->
+ ?line true = string:equal("", ""),
+ ?line false = string:equal("", " "),
+ ?line true = string:equal("laban", "laban"),
+ ?line false = string:equal("skvimp", "skvump"),
+ %% invalid arg type
+ ?line true = string:equal(2, 2), % not good, should crash
+ ok.
+
+concat(suite) ->
+ [];
+concat(doc) ->
+ [];
+concat(Config) when is_list(Config) ->
+ ?line "erlang rules" = string:concat("erlang ", "rules"),
+ ?line "" = string:concat("", ""),
+ ?line "x" = string:concat("x", ""),
+ ?line "y" = string:concat("", "y"),
+ %% invalid arg type
+ ?line {'EXIT',_} = (catch string:concat(hello, please)),
+ ok.
+
+chr_rchr(suite) ->
+ [];
+chr_rchr(doc) ->
+ [];
+chr_rchr(Config) when is_list(Config) ->
+ ?line {_,_,X} = now(),
+ ?line 0 = string:chr("", (X rem (255-32)) + 32),
+ ?line 0 = string:rchr("", (X rem (255-32)) + 32),
+ ?line 1 = string:chr("x", $x),
+ ?line 1 = string:rchr("x", $x),
+ ?line 1 = string:chr("xx", $x),
+ ?line 2 = string:rchr("xx", $x),
+ ?line 3 = string:chr("xyzyx", $z),
+ ?line 3 = string:rchr("xyzyx", $z),
+ %% invalid arg type
+ ?line {'EXIT',_} = (catch string:chr(hello, $h)),
+ %% invalid arg type
+ ?line {'EXIT',_} = (catch string:chr("hello", h)),
+ %% invalid arg type
+ ?line {'EXIT',_} = (catch string:rchr(hello, $h)),
+ %% invalid arg type
+ ?line {'EXIT',_} = (catch string:rchr("hello", h)),
+ ok.
+
+str_rstr(suite) ->
+ [];
+str_rstr(doc) ->
+ [];
+str_rstr(Config) when is_list(Config) ->
+ ?line {_,_,X} = now(),
+ ?line 0 = string:str("", [(X rem (255-32)) + 32]),
+ ?line 0 = string:rstr("", [(X rem (255-32)) + 32]),
+ ?line 1 = string:str("x", "x"),
+ ?line 1 = string:rstr("x", "x"),
+ ?line 0 = string:str("hello", ""),
+ ?line 0 = string:rstr("hello", ""),
+ ?line 1 = string:str("xxxx", "xx"),
+ ?line 3 = string:rstr("xxxx", "xx"),
+ ?line 3 = string:str("xy z yx", " z"),
+ ?line 3 = string:rstr("xy z yx", " z"),
+ %% invalid arg type
+ ?line {'EXIT',_} = (catch string:str(hello, "he")),
+ %% invalid arg type
+ ?line {'EXIT',_} = (catch string:str("hello", he)),
+ %% invalid arg type
+ ?line {'EXIT',_} = (catch string:rstr(hello, "he")),
+ %% invalid arg type
+ ?line {'EXIT',_} = (catch string:rstr("hello", he)),
+ ok.
+
+span_cspan(suite) ->
+ [];
+span_cspan(doc) ->
+ [];
+span_cspan(Config) when is_list(Config) ->
+ ?line 0 = string:span("", "1"),
+ ?line 0 = string:span("1", ""),
+ ?line 0 = string:cspan("", "1"),
+ ?line 1 = string:cspan("1", ""),
+ ?line 1 = string:span("1 ", "1"),
+ ?line 5 = string:span(" 1 ", "12 "),
+ ?line 6 = string:span("1231234", "123"),
+ ?line 0 = string:cspan("1 ", "1"),
+ ?line 1 = string:cspan("3 ", "12 "),
+ ?line 6 = string:cspan("1231234", "4"),
+ %% invalid arg type
+ ?line {'EXIT',_} = (catch string:span(1234, "1")),
+ %% invalid arg type
+ ?line {'EXIT',_} = (catch string:span(1234, "1")),
+ %% invalid arg type
+ ?line {'EXIT',_} = (catch string:cspan("1234", 1)),
+ %% invalid arg type
+ ?line {'EXIT',_} = (catch string:cspan("1234", 4)),
+ ok.
+
+
+substr(suite) ->
+ [];
+substr(doc) ->
+ [];
+substr(Config) when is_list(Config) ->
+ ?line {'EXIT',_} = (catch string:substr("", 0)),
+ ?line [] = string:substr("", 1),
+ ?line {'EXIT',_} = (catch string:substr("", 2)),
+ ?line [] = string:substr("1", 2),
+ ?line {'EXIT',_} = (catch string:substr("", 0, 1)),
+ ?line [] = string:substr("", 1, 1),
+ ?line [] = string:substr("", 1, 2),
+ ?line {'EXIT',_} = (catch string:substr("", 2, 2)),
+ ?line "1234" = string:substr("1234", 1),
+ ?line "1234" = string:substr("1234", 1, 4),
+ ?line "1234" = string:substr("1234", 1, 5),
+ ?line "23" = string:substr("1234", 2, 2),
+ ?line "4" = string:substr("1234", 4),
+ ?line "" = string:substr("1234", 4, 0),
+ ?line "4" = string:substr("1234", 4, 1),
+ %% invalid arg type
+ ?line {'EXIT',_} = (catch string:substr(1234, 1)),
+ %% invalid arg type
+ ?line {'EXIT',_} = (catch string:substr("1234", "1")),
+ ok.
+
+tokens(suite) ->
+ [];
+tokens(doc) ->
+ [];
+tokens(Config) when is_list(Config) ->
+ ?line [] = string:tokens("",""),
+ ?line [] = string:tokens("abc","abc"),
+ ?line ["abc"] = string:tokens("abc", ""),
+ ?line ["1","2 34","4","5"] = string:tokens("1,2 34,4;5", ";,"),
+ %% invalid arg type
+ ?line {'EXIT',_} = (catch string:tokens('x,y', ",")),
+ %% invalid arg type
+ ?line {'EXIT',_} = (catch string:tokens("x,y", ',')),
+ ok.
+
+
+chars(suite) ->
+ [];
+chars(doc) ->
+ [];
+chars(Config) when is_list(Config) ->
+ ?line [] = string:chars($., 0),
+ ?line [] = string:chars($., 0, []),
+ ?line 10 = length(string:chars(32, 10, [])),
+ ?line "aaargh" = string:chars($a, 3, "rgh"),
+ %% invalid arg type
+ ?line {'EXIT',_} = (catch string:chars($x, [])),
+ ok.
+
+copies(suite) ->
+ [];
+copies(doc) ->
+ [];
+copies(Config) when is_list(Config) ->
+ ?line "" = string:copies("", 10),
+ ?line "" = string:copies(".", 0),
+ ?line "." = string:copies(".", 1),
+ ?line 30 = length(string:copies("123", 10)),
+ %% invalid arg type
+ ?line {'EXIT',_} = (catch string:chars("hej", -1)),
+ ok.
+
+words(suite) ->
+ [];
+words(doc) ->
+ [];
+words(Config) when is_list(Config) ->
+ ?line 1 = string:words(""),
+ ?line 1 = string:words("", $,),
+ ?line 1 = string:words("hello"),
+ ?line 1 = string:words("hello", $,),
+ ?line 1 = string:words("...", $.),
+ ?line 2 = string:words("2.35", $.),
+ ?line 100 = string:words(string:copies(". ", 100)),
+ %% invalid arg type
+ ?line {'EXIT',_} = (catch string:chars(hej)),
+ %% invalid arg type
+ ?line {'EXIT',_} = (catch string:chars("hej", " ")),
+ ok.
+
+
+strip(suite) ->
+ [];
+strip(doc) ->
+ [];
+strip(Config) when is_list(Config) ->
+ ?line "" = string:strip(""),
+ ?line "" = string:strip("", both),
+ ?line "" = string:strip("", both, $.),
+ ?line "hej" = string:strip(" hej "),
+ ?line "hej " = string:strip(" hej ", left),
+ ?line " hej" = string:strip(" hej ", right),
+ ?line " hej " = string:strip(" hej ", right, $.),
+ ?line "hej hopp" = string:strip(" hej hopp ", both),
+ %% invalid arg type
+ ?line {'EXIT',_} = (catch string:strip(hej)),
+ %% invalid arg type
+ ?line {'EXIT',_} = (catch string:strip(" hej", up)),
+ %% invalid arg type
+ ?line {'EXIT',_} = (catch string:strip(" hej", left, " ")), % not good
+ ok.
+
+sub_word(suite) ->
+ [];
+sub_word(doc) ->
+ [];
+sub_word(Config) when is_list(Config) ->
+ ?line "" = string:sub_word("", 1),
+ ?line "" = string:sub_word("", 1, $,),
+ ?line {'EXIT',_} = (catch string:sub_word("1 2 3", 0)),
+ ?line "" = string:sub_word("1 2 3", 4),
+ ?line "llo th" = string:sub_word("but hello there", 2, $e),
+ %% invalid arg type
+ ?line {'EXIT',_} = (catch string:sub_word('hello there', 1)),
+ %% invalid arg type
+ ?line {'EXIT',_} = (catch string:sub_word("hello there", 1, "e")),
+ ok.
+
+left_right(suite) ->
+ [];
+left_right(doc) ->
+ [];
+left_right(Config) when is_list(Config) ->
+ ?line "" = string:left("", 0),
+ ?line "" = string:left("hej", 0),
+ ?line "" = string:left("hej", 0, $.),
+ ?line "" = string:right("", 0),
+ ?line "" = string:right("hej", 0),
+ ?line "" = string:right("hej", 0, $.),
+ ?line "123 " = string:left("123 ", 5),
+ ?line " 123" = string:right(" 123", 5),
+ ?line "123!!" = string:left("123!", 5, $!),
+ ?line "==123" = string:right("=123", 5, $=),
+ ?line "1" = string:left("123", 1, $.),
+ ?line "3" = string:right("123", 1, $.),
+ %% invalid arg type
+ ?line {'EXIT',_} = (catch string:left(hello, 5)),
+ %% invalid arg type
+ ?line {'EXIT',_} = (catch string:right(hello, 5)),
+ %% invalid arg type
+ ?line {'EXIT',_} = (catch string:left("hello", 5, ".")),
+ %% invalid arg type
+ ?line {'EXIT',_} = (catch string:right("hello", 5, ".")),
+ ok.
+
+sub_string(suite) ->
+ [];
+sub_string(doc) ->
+ [];
+sub_string(Config) when is_list(Config) ->
+ ?line {'EXIT',_} = (catch string:sub_string("", 0)),
+ ?line [] = string:sub_string("", 1),
+ ?line {'EXIT',_} = (catch string:sub_string("", 2)),
+ ?line [] = string:sub_string("1", 2),
+ ?line {'EXIT',_} = (catch string:sub_string("", 0, 1)),
+ ?line [] = string:sub_string("", 1, 1),
+ ?line [] = string:sub_string("", 1, 2),
+ ?line {'EXIT',_} = (catch string:sub_string("", 2, 2)),
+ ?line "1234" = string:sub_string("1234", 1),
+ ?line "1234" = string:sub_string("1234", 1, 4),
+ ?line "1234" = string:sub_string("1234", 1, 5),
+ ?line "23" = string:sub_string("1234", 2, 3),
+ ?line "4" = string:sub_string("1234", 4),
+ ?line "4" = string:sub_string("1234", 4, 4),
+ ?line "4" = string:sub_string("1234", 4, 5),
+ %% invalid arg type
+ ?line {'EXIT',_} = (catch string:sub_string(1234, 1)),
+ %% invalid arg type
+ ?line {'EXIT',_} = (catch string:sub_string("1234", "1")),
+ ok.
+
+centre(suite) ->
+ [];
+centre(doc) ->
+ [];
+centre(Config) when is_list(Config) ->
+ ?line "" = string:centre("", 0),
+ ?line "" = string:centre("1", 0),
+ ?line "" = string:centre("", 0, $-),
+ ?line "" = string:centre("1", 0, $-),
+ ?line "gd" = string:centre("agda", 2),
+ ?line "agda " = string:centre("agda", 5),
+ ?line " agda " = string:centre("agda", 6),
+ ?line "agda." = string:centre("agda", 5, $.),
+ ?line "--agda--" = string:centre("agda", 8, $-),
+ ?line "agda" = string:centre("agda", 4),
+ %% invalid arg type
+ ?line {'EXIT',_} = (catch string:centre(hello, 10)),
+ ok.
+
+to_integer(suite) ->
+ [];
+to_integer(doc) ->
+ [];
+to_integer(Config) when is_list(Config) ->
+ ?line {1,""} = test_to_integer("1"),
+ ?line {1,""} = test_to_integer("+1"),
+ ?line {-1,""} = test_to_integer("-1"),
+ ?line {1,"="} = test_to_integer("1="),
+ ?line {7,"F"} = test_to_integer("7F"),
+ ?line {709,""} = test_to_integer("709"),
+ ?line {709,"*2"} = test_to_integer("709*2"),
+ ?line {0,"xAB"} = test_to_integer("0xAB"),
+ ?line {16,"#FF"} = test_to_integer("16#FF"),
+ ?line {error,no_integer} = test_to_integer(""),
+ ?line {error,no_integer} = test_to_integer("!1"),
+ ?line {error,no_integer} = test_to_integer("F1"),
+ ?line {error,not_a_list} = test_to_integer('23'),
+ ?line {3,[[]]} = test_to_integer([$3,[]]),
+ ?line {3,[hello]} = test_to_integer([$3,hello]),
+ ok.
+
+test_to_integer(Str) ->
+ io:format("Checking ~p~n", [Str]),
+ case string:to_integer(Str) of
+ {error,_Reason} = Bad ->
+ ?line {'EXIT',_} = (catch list_to_integer(Str)),
+ Bad;
+ {F,_Rest} = Res ->
+ ?line _ = integer_to_list(F),
+ Res
+ end.
+
+to_float(suite) ->
+ [];
+to_float(doc) ->
+ [];
+to_float(Config) when is_list(Config) ->
+ ?line {1.2,""} = test_to_float("1.2"),
+ ?line {1.2,""} = test_to_float("1,2"),
+ ?line {120.0,""} = test_to_float("1.2e2"),
+ ?line {120.0,""} = test_to_float("+1,2e2"),
+ ?line {-120.0,""} = test_to_float("-1.2e2"),
+ ?line {-120.0,""} = test_to_float("-1,2e+2"),
+ ?line {-1.2e-2,""} = test_to_float("-1.2e-2"),
+ ?line {1.2,"="} = test_to_float("1.2="),
+ ?line {7.9,"e"} = test_to_float("7.9e"),
+ ?line {7.9,"ee"} = test_to_float("7.9ee"),
+ ?line {7.9,"e+"} = test_to_float("7.9e+"),
+ ?line {7.9,"e-"} = test_to_float("7.9e-"),
+ ?line {7.9,"e++"} = test_to_float("7.9e++"),
+ ?line {7.9,"e--"} = test_to_float("7.9e--"),
+ ?line {7.9,"e+e"} = test_to_float("7.9e+e"),
+ ?line {7.9,"e-e"} = test_to_float("7.9e-e"),
+ ?line {7.9,"e+."} = test_to_float("7.9e+."),
+ ?line {7.9,"e-."} = test_to_float("7.9e-."),
+ ?line {7.9,"e+,"} = test_to_float("7.9e+,"),
+ ?line {7.9,"e-,"} = test_to_float("7.9e-,"),
+ ?line {error,no_float} = test_to_float(""),
+ ?line {error,no_float} = test_to_float("e1,0"),
+ ?line {error,no_float} = test_to_float("1;0"),
+ ?line {error,no_float} = test_to_float("1"),
+ ?line {error,no_float} = test_to_float("1e"),
+ ?line {error,no_float} = test_to_float("2."),
+ ?line {error,not_a_list} = test_to_float('2.3'),
+ ?line {2.3,[[]]} = test_to_float([$2,$.,$3,[]]),
+ ?line {2.3,[hello]} = test_to_float([$2,$.,$3,hello]),
+ ok.
+
+test_to_float(Str) ->
+ io:format("Checking ~p~n", [Str]),
+ case string:to_float(Str) of
+ {error,_Reason} = Bad ->
+ ?line {'EXIT',_} = (catch list_to_float(Str)),
+ Bad;
+ {F,_Rest} = Res ->
+ ?line _ = float_to_list(F),
+ Res
+ end.
+
+to_upper_to_lower(suite) ->
+ [];
+to_upper_to_lower(doc) ->
+ [];
+to_upper_to_lower(Config) when is_list(Config) ->
+ ?line "1234ABCDEF���=" = string:to_upper("1234abcdef���="),
+ ?line "����������abc()" = string:to_lower("����������abc()"),
+ ?line All = lists:seq(0, 255),
+
+ ?line UC = string:to_upper(All),
+ ?line 256 = length(UC),
+ ?line all_upper_latin1(UC, 0),
+
+ ?line LC = string:to_lower(All),
+ ?line all_lower_latin1(LC, 0),
+
+ ?line LC = string:to_lower(string:to_upper(LC)),
+ ?line LC = string:to_lower(string:to_upper(UC)),
+ ?line UC = string:to_upper(string:to_lower(LC)),
+ ?line UC = string:to_upper(string:to_lower(UC)),
+ ok.
+
+all_upper_latin1([C|T], C) when 0 =< C, C < $a;
+ $z < C, C < 16#E0;
+ C =:= 16#F7; C =:= 16#FF ->
+ all_upper_latin1(T, C+1);
+all_upper_latin1([H|T], C) when $a =< C, C =< $z;
+ 16#E0 =< C, C =< 16#F6;
+ 16#F8 =< C, C =< 16#FE ->
+ H = C - 32,
+ all_upper_latin1(T, C+1);
+all_upper_latin1([], 256) -> ok.
+
+all_lower_latin1([C|T], C) when 0 =< C, C < $A;
+ $Z < C, C < 16#C0;
+ C =:= 16#D7;
+ 16#DF =< C, C =< 255 ->
+ all_lower_latin1(T, C+1);
+all_lower_latin1([H|T], C) when $A =< C, C =< $Z;
+ 16#C0 =< C, C =< 16#F6;
+ 16#C8 =< C, C =< 16#DE ->
+ io:format("~p\n", [{H,C}]),
+ H = C + 32,
+ all_lower_latin1(T, C+1);
+all_lower_latin1([], 256) -> ok.
+
+join(suite) ->
+ [];
+join(doc) ->
+ [];
+join(Config) when is_list(Config) ->
+ ?line "erlang rules" = string:join(["erlang", "rules"], " "),
+ ?line "a,-,b,-,c" = string:join(["a", "b", "c"], ",-,"),
+ ?line "1234" = string:join(["1", "2", "3", "4"], ""),
+ ?line [] = string:join([], ""), % OTP-7231
+ %% invalid arg type
+ ?line {'EXIT',_} = (catch string:join([apa], "")),
+ ok.
diff --git a/lib/stdlib/test/suite_release.exclude b/lib/stdlib/test/suite_release.exclude
new file mode 100644
index 0000000000..ecad6e9c08
--- /dev/null
+++ b/lib/stdlib/test/suite_release.exclude
@@ -0,0 +1,4 @@
+tar_SUITE.erl
+tar_SUITE_data
+{skip,{ets_SUITE,partly_bound,"System dependent"}}.
+{skip,{gen_server_SUITE,multicall_down,"Network dependent"}}.
diff --git a/lib/stdlib/test/supervisor_1.erl b/lib/stdlib/test/supervisor_1.erl
new file mode 100644
index 0000000000..297550b230
--- /dev/null
+++ b/lib/stdlib/test/supervisor_1.erl
@@ -0,0 +1,79 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%% Description: Simulates the behaviour that a child process may have.
+%% Is used by the supervisor_SUITE test suite.
+-module(supervisor_1).
+
+-export([start_child/0, start_child/1, init/1]).
+
+-export([handle_call/3, handle_info/2, terminate/2]).
+
+start_child(ignore) ->
+ case get(child_ignored) of
+ true ->
+ start_child();
+ _ ->
+ put(child_ignored, true),
+ ignore
+ end;
+
+start_child(error) ->
+ case get(start_child_error) of
+ undefined ->
+ put(start_child_error, set),
+ start_child();
+ set -> gen_server:start_link(?MODULE, error, [])
+ end;
+
+
+start_child(Extra) ->
+ {ok, Pid} = gen_server:start_link(?MODULE, normal, []),
+ {ok, Pid, Extra}.
+
+start_child() ->
+ gen_server:start_link(?MODULE, normal, []).
+
+init(normal) ->
+ process_flag(trap_exit, true),
+ {ok, {}}.
+
+handle_call(Req, _From, State) ->
+ {reply, Req, State}.
+
+handle_info(die, State) ->
+ {stop, died, State};
+
+handle_info(stop, State) ->
+ {stop, normal, State};
+
+handle_info({sleep, Time}, State) ->
+ io:format("FOO: ~p~n", [Time]),
+ timer:sleep(Time),
+ io:format("FOO: sleept~n", []),
+ handle_info({sleep, Time}, State);
+
+handle_info(_, State) ->
+ {noreply, State}.
+
+terminate(_Reason, _State) ->
+ ok.
+
+
+
+
diff --git a/lib/stdlib/test/supervisor_SUITE.erl b/lib/stdlib/test/supervisor_SUITE.erl
new file mode 100644
index 0000000000..b5d9ca44bf
--- /dev/null
+++ b/lib/stdlib/test/supervisor_SUITE.erl
@@ -0,0 +1,1203 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%% Description: Tests supervisor.erl
+
+-module(supervisor_SUITE).
+
+-include("test_server.hrl").
+
+%% Testserver specific export
+-export([all/1]).
+
+%% Indirect spawn export
+-export([init/1]).
+
+%% API tests
+-export([sup_start/1, sup_start_normal/1, sup_start_ignore_init/1,
+ sup_start_ignore_child/1, sup_start_error_return/1,
+ sup_start_fail/1, sup_stop/1, sup_stop_infinity/1,
+ sup_stop_timeout/1, sup_stop_brutal_kill/1, child_adm/1,
+ child_adm_simple/1, child_specs/1, extra_return/1]).
+
+%% Tests concept permanent, transient and temporary
+-export([normal_termination/1, permanent_normal/1, transient_normal/1,
+ temporary_normal/1, abnormal_termination/1,
+ permanent_abnormal/1, transient_abnormal/1,
+ temporary_abnormal/1]).
+
+%% Restart strategy tests
+-export([restart_one_for_one/1, one_for_one/1,
+ one_for_one_escalation/1, restart_one_for_all/1, one_for_all/1,
+ one_for_all_escalation/1, restart_simple_one_for_one/1,
+ simple_one_for_one/1, simple_one_for_one_escalation/1,
+ restart_rest_for_one/1, rest_for_one/1, rest_for_one_escalation/1,
+ simple_one_for_one_extra/1]).
+
+%% Misc tests
+-export([child_unlink/1, tree/1]).
+
+%-------------------------------------------------------------------------
+
+all(suite) ->
+ {req,[stdlib],
+ [sup_start, sup_stop, child_adm,
+ child_adm_simple, extra_return, child_specs,
+ restart_one_for_one, restart_one_for_all,
+ restart_simple_one_for_one, restart_rest_for_one,
+ normal_termination, abnormal_termination, child_unlink, tree]}.
+
+
+start(InitResult) ->
+ supervisor:start_link({local, sup_test}, ?MODULE, InitResult).
+
+%% Simulate different supervisors callback.
+init(fail) ->
+ erlang:error({badmatch,2});
+init(InitResult) ->
+ InitResult.
+
+%-------------------------------------------------------------------------
+%
+% Test cases starts here.
+%
+%-------------------------------------------------------------------------
+
+sup_start(doc) ->
+ ["Test start of a supervisor."];
+sup_start(suite) ->
+ [sup_start_normal, sup_start_ignore_init, sup_start_ignore_child,
+ sup_start_error_return, sup_start_fail].
+
+%-------------------------------------------------------------------------
+sup_start_normal(doc) ->
+ ["Tests that the supervisor process starts correctly and that it "
+ "can be terminated gracefully."];
+sup_start_normal(suite) -> [];
+sup_start_normal(Config) when list(Config) ->
+ process_flag(trap_exit, true),
+ ?line {ok, Pid} = start({ok, {{one_for_one, 2, 3600}, []}}),
+ ?line exit(Pid, shutdown),
+ receive
+ {'EXIT', Pid, shutdown} ->
+ ok;
+ {'EXIT', Pid, Else} ->
+ ?line test_server:fail({bad_exit_reason, Else})
+ after
+ 2000 ->
+ ?line test_server:fail(no_exit_reason)
+ end,
+ ok.
+%-------------------------------------------------------------------------
+sup_start_ignore_init(doc) ->
+ ["Tests what happens if init-callback returns ignore"];
+sup_start_ignore_init(suite) -> [];
+sup_start_ignore_init(Config) when list(Config) ->
+ process_flag(trap_exit, true),
+ ?line ignore = start(ignore),
+
+ receive
+ {'EXIT', _Pid, normal} ->
+ ok;
+ {'EXIT', _Pid, Else} ->
+ ?line test_server:fail({bad_exit_reason, Else})
+ after
+ 2000 ->
+ ?line test_server:fail(no_exit_reason)
+ end,
+ ok.
+
+
+%-------------------------------------------------------------------------
+sup_start_ignore_child(doc) ->
+ ["Tests what happens if init-callback returns ignore"];
+sup_start_ignore_child(suite) -> [];
+sup_start_ignore_child(Config) when list(Config) ->
+ process_flag(trap_exit, true),
+ ?line {ok, _Pid} = start({ok, {{one_for_one, 2, 3600}, []}}),
+ Child1 = {child1, {supervisor_1, start_child, [ignore]},
+ permanent, 1000, worker, []},
+ Child2 = {child2, {supervisor_1, start_child, []}, permanent,
+ 1000, worker, []},
+
+ ?line {ok, undefined} = supervisor:start_child(sup_test, Child1),
+ ?line {ok, CPid2} = supervisor:start_child(sup_test, Child2),
+
+ ?line [{child2, CPid2, worker, []},{child1, undefined, worker, []}]
+ = supervisor:which_children(sup_test),
+ ok.
+
+%-------------------------------------------------------------------------
+sup_start_error_return(doc) ->
+ ["Tests what happens if init-callback returns a invalid value"];
+sup_start_error_return(suite) -> [];
+sup_start_error_return(Config) when list(Config) ->
+ process_flag(trap_exit, true),
+ ?line {error, Term} = start(invalid),
+
+ receive
+ {'EXIT', _Pid, Term} ->
+ ok;
+ {'EXIT', _Pid, Else} ->
+ ?line test_server:fail({bad_exit_reason, Else})
+ after
+ 2000 ->
+ ?line test_server:fail(no_exit_reason)
+ end,
+ ok.
+
+%-------------------------------------------------------------------------
+sup_start_fail(doc) ->
+ ["Tests what happens if init-callback fails"];
+sup_start_fail(suite) -> [];
+sup_start_fail(Config) when list(Config) ->
+ process_flag(trap_exit, true),
+ ?line {error, Term} = start(fail),
+
+ receive
+ {'EXIT', _Pid, Term} ->
+ ok;
+ {'EXIT', _Pid, Else} ->
+ ?line test_server:fail({bad_exit_reason, Else})
+ after
+ 2000 ->
+ ?line test_server:fail(no_exit_reason)
+ end,
+ ok.
+%-------------------------------------------------------------------------
+sup_stop(doc) ->
+ ["Tests that the supervisor shoutdowns its children if it is "
+ "shutdown itself."];
+sup_stop(suite) -> [sup_stop_infinity, sup_stop_timeout, sup_stop_brutal_kill].
+
+%-------------------------------------------------------------------------
+
+sup_stop_infinity(doc) ->
+ ["See sup_stop/1 when Shutdown = infinity, this walue is only allowed "
+ "for children of type supervisor"];
+sup_stop_infinity(suite) -> [];
+
+sup_stop_infinity(Config) when list(Config) ->
+ process_flag(trap_exit, true),
+ ?line {ok, Pid} = start({ok, {{one_for_one, 2, 3600}, []}}),
+ Child1 = {child1, {supervisor_1, start_child, []},
+ permanent, infinity, supervisor, []},
+ Child2 = {child2, {supervisor_1, start_child, []}, permanent,
+ infinity, worker, []},
+ ?line {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+ link(CPid1),
+ ?line {error, {invalid_shutdown,infinity}} =
+ supervisor:start_child(sup_test, Child2),
+
+ ?line exit(Pid, shutdown),
+
+ receive
+ {'EXIT', Pid, shutdown} ->
+ ok;
+ {'EXIT', Pid, Else} ->
+ ?line test_server:fail({bad_exit_reason, Else})
+ after
+ 5000 ->
+ ?line test_server:fail(no_exit_reason)
+ end,
+ receive
+ {'EXIT', CPid1, shutdown} -> ok;
+ {'EXIT', CPid1, Reason} ->
+ ?line test_server:fail({bad_exit_reason, Reason})
+ after
+ 2000 -> ?line test_server:fail(no_exit_reason)
+ end,
+ ok.
+
+%-------------------------------------------------------------------------
+
+sup_stop_timeout(doc) ->
+ ["See sup_stop/1 when Shutdown = 1000"];
+sup_stop_timeout(suite) -> [];
+
+sup_stop_timeout(Config) when list(Config) ->
+ process_flag(trap_exit, true),
+ ?line {ok, Pid} = start({ok, {{one_for_one, 2, 3600}, []}}),
+ Child1 = {child1, {supervisor_1, start_child, []},
+ permanent, 1000, worker, []},
+ Child2 = {child2, {supervisor_1, start_child, []}, permanent,
+ 1000, worker, []},
+ ?line {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+ link(CPid1),
+ ?line {ok, CPid2} = supervisor:start_child(sup_test, Child2),
+ link(CPid2),
+
+ CPid2 ! {sleep, 200000},
+
+ ?line exit(Pid, shutdown),
+
+ receive
+ {'EXIT', Pid, shutdown} ->
+ ok;
+ {'EXIT', Pid, Else} ->
+ ?line test_server:fail({bad_exit_reason, Else})
+ after
+ 5000 ->
+ ?line test_server:fail(no_exit_reason)
+ end,
+
+ receive
+ {'EXIT', CPid1, shutdown} -> ok;
+ {'EXIT', CPid1, Reason} ->
+ ?line test_server:fail({bad_exit_reason,Reason})
+ after
+ 2000 -> ?line test_server:fail(no_exit_reason)
+ end,
+
+ receive
+ {'EXIT', CPid2, killed} -> ok;
+ {'EXIT', CPid2, Reason2} ->
+ ?line test_server:fail({bad_exit_reason, Reason2})
+ after
+ 2000 -> ?line test_server:fail(no_exit_reason)
+ end,
+ ok.
+
+%-------------------------------------------------------------------------
+sup_stop_brutal_kill(doc) ->
+ ["See sup_stop/1 when Shutdown = brutal_kill"];
+sup_stop_brutal_kill(suite) -> [];
+
+sup_stop_brutal_kill(Config) when list(Config) ->
+ process_flag(trap_exit, true),
+ ?line {ok, Pid} = start({ok, {{one_for_one, 2, 3600}, []}}),
+ Child1 = {child1, {supervisor_1, start_child, []},
+ permanent, 1000, worker, []},
+ Child2 = {child2, {supervisor_1, start_child, []}, permanent,
+ brutal_kill, worker, []},
+ ?line {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+ link(CPid1),
+ ?line {ok, CPid2} = supervisor:start_child(sup_test, Child2),
+ link(CPid2),
+
+ ?line exit(Pid, shutdown),
+
+ receive
+ {'EXIT', Pid, shutdown} ->
+ ok;
+ {'EXIT', Pid, Else} ->
+ ?line test_server:fail({bad_exit_reason, Else})
+ after
+ 5000 ->
+ ?line test_server:fail(no_exit_reason)
+ end,
+
+ receive
+ {'EXIT', CPid1, shutdown} -> ok;
+ {'EXIT', CPid1, Reason} ->
+ ?line test_server:fail({bad_exit_reason, Reason})
+ after
+ 2000 -> ?line test_server:fail(no_exit_reason)
+ end,
+ receive
+ {'EXIT', CPid2, killed} -> ok;
+ {'EXIT', CPid2, Reason2} ->
+ ?line test_server:fail({bad_exit_reason, Reason2})
+ after
+ 2000 -> ?line test_server:fail(no_exit_reason)
+ end,
+ ok.
+
+%-------------------------------------------------------------------------
+extra_return(doc) ->
+ ["The start function provided to start a child may "
+ "return {ok, Pid} or {ok, Pid, Info}, if it returns "
+ "the later check that the supervisor ignores the Info, "
+ "and includes it unchanged in return from start_child/2 "
+ "and restart_child/2"];
+extra_return(suite) -> [];
+
+extra_return(Config) when list(Config) ->
+ process_flag(trap_exit, true),
+ Child = {child1, {supervisor_1, start_child, [extra_return]},
+ permanent, 1000,
+ worker, []},
+ ?line {ok, _Pid} = start({ok, {{one_for_one, 2, 3600}, [Child]}}),
+ ?line [{child1, CPid, worker, []}] = supervisor:which_children(sup_test),
+ link(CPid),
+ ?line {error, not_found} = supervisor:terminate_child(sup_test, hej),
+ ?line {error, not_found} = supervisor:delete_child(sup_test, hej),
+ ?line {error, not_found} = supervisor:restart_child(sup_test, hej),
+ ?line {error, running} = supervisor:delete_child(sup_test, child1),
+ ?line {error, running} = supervisor:restart_child(sup_test, child1),
+ ?line [{child1, CPid, worker, []}] = supervisor:which_children(sup_test),
+ ?line ok = supervisor:terminate_child(sup_test, child1),
+ receive
+ {'EXIT', CPid, shutdown} -> ok;
+ {'EXIT', CPid, Reason} ->
+ ?line test_server:fail({bad_reason, Reason})
+ after 1000 ->
+ ?line test_server:fail(no_child_termination)
+ end,
+ ?line [{child1,undefined,worker,[]}] = supervisor:which_children(sup_test),
+ ?line {ok, CPid2,extra_return} =
+ supervisor:restart_child(sup_test, child1),
+ ?line [{child1, CPid2, worker, []}] = supervisor:which_children(sup_test),
+ ?line ok = supervisor:terminate_child(sup_test, child1),
+ ?line ok = supervisor:terminate_child(sup_test, child1),
+ ?line ok = supervisor:delete_child(sup_test, child1),
+ ?line {error, not_found} = supervisor:restart_child(sup_test, child1),
+ ?line [] = supervisor:which_children(sup_test),
+ ?line {ok, CPid3, extra_return} = supervisor:start_child(sup_test, Child),
+ ?line [{child1, CPid3, worker, []}] = supervisor:which_children(sup_test),
+ ok.
+%-------------------------------------------------------------------------
+child_adm(doc)->
+ ["Test API functions start_child/2, terminate_child/2, delete_child/2 "
+ "restart_child/2, which_children/1. Only correct childspecs are used, "
+ "handling of incorrect childspecs is tested in child_specs/1"];
+child_adm(suite) -> [];
+child_adm(Config) when list(Config) ->
+ process_flag(trap_exit, true),
+ Child = {child1, {supervisor_1, start_child, []}, permanent, 1000,
+ worker, []},
+ ?line {ok, _Pid} = start({ok, {{one_for_one, 2, 3600}, [Child]}}),
+ ?line [{child1, CPid, worker, []}] = supervisor:which_children(sup_test),
+ link(CPid),
+
+ %% Start of an already runnig process
+ ?line {error,{already_started, CPid}} =
+ supervisor:start_child(sup_test, Child),
+
+ %% Termination
+ ?line {error, not_found} = supervisor:terminate_child(sup_test, hej),
+ ?line {'EXIT',{noproc,{gen_server,call, _}}} =
+ (catch supervisor:terminate_child(foo, child1)),
+ ?line ok = supervisor:terminate_child(sup_test, child1),
+ receive
+ {'EXIT', CPid, shutdown} -> ok;
+ {'EXIT', CPid, Reason} ->
+ ?line test_server:fail({bad_reason, Reason})
+ after 1000 ->
+ ?line test_server:fail(no_child_termination)
+ end,
+ ?line [{child1,undefined,worker,[]}] = supervisor:which_children(sup_test),
+ %% Like deleting something that does not exist, it will succeed!
+ ?line ok = supervisor:terminate_child(sup_test, child1),
+
+ %% Start of already existing but not running process
+ ?line {error,already_present} =
+ supervisor:start_child(sup_test, Child),
+
+ %% Restart
+ ?line {ok, CPid2} = supervisor:restart_child(sup_test, child1),
+ ?line [{child1, CPid2, worker, []}] = supervisor:which_children(sup_test),
+ ?line {error, running} = supervisor:restart_child(sup_test, child1),
+ ?line {error, not_found} = supervisor:restart_child(sup_test, child2),
+
+ %% Deletion
+ ?line {error, running} = supervisor:delete_child(sup_test, child1),
+ ?line {error, not_found} = supervisor:delete_child(sup_test, hej),
+ ?line {'EXIT',{noproc,{gen_server,call, _}}} =
+ (catch supervisor:delete_child(foo, child1)),
+ ?line ok = supervisor:terminate_child(sup_test, child1),
+ ?line ok = supervisor:delete_child(sup_test, child1),
+ ?line {error, not_found} = supervisor:restart_child(sup_test, child1),
+ ?line [] = supervisor:which_children(sup_test),
+
+ %% Start
+ ?line {'EXIT',{noproc,{gen_server,call, _}}} =
+ (catch supervisor:start_child(foo, Child)),
+ ?line {ok, CPid3} = supervisor:start_child(sup_test, Child),
+ ?line [{child1, CPid3, worker, []}] = supervisor:which_children(sup_test),
+
+ ?line {'EXIT',{noproc,{gen_server,call,[foo,which_children,infinity]}}}
+ = (catch supervisor:which_children(foo)),
+ ok.
+%-------------------------------------------------------------------------
+child_adm_simple(doc) ->
+ ["The API functions terminate_child/2, delete_child/2 "
+ "restart_child/2 are not valid for a simple_one_for_one supervisor "
+ "check that the correct error message is returned."];
+child_adm_simple(suite) -> [];
+child_adm_simple(Config) when list(Config) ->
+ Child = {child, {supervisor_1, start_child, []}, permanent, 1000,
+ worker, []},
+ ?line {ok, _Pid} = start({ok, {{simple_one_for_one, 2, 3600}, [Child]}}),
+ %% In simple_one_for_one all children are added dynamically
+ ?line [] = supervisor:which_children(sup_test),
+
+ %% Start
+ ?line {'EXIT',{noproc,{gen_server,call, _}}} =
+ (catch supervisor:start_child(foo, [])),
+ ?line {ok, CPid1} = supervisor:start_child(sup_test, []),
+ ?line [{undefined, CPid1, worker, []}] =
+ supervisor:which_children(sup_test),
+
+ ?line {ok, CPid2} = supervisor:start_child(sup_test, []),
+ ?line Children = supervisor:which_children(sup_test),
+ ?line 2 = length(Children),
+ ?line true = lists:member({undefined, CPid2, worker, []}, Children),
+ ?line true = lists:member({undefined, CPid1, worker, []}, Children),
+
+ %% Termination
+ ?line {error, simple_one_for_one} =
+ supervisor:terminate_child(sup_test, child1),
+
+ %% Restart
+ ?line {error, simple_one_for_one} =
+ supervisor:restart_child(sup_test, child1),
+
+ %% Deletion
+ ?line {error, simple_one_for_one} =
+ supervisor:delete_child(sup_test, child1),
+ ok.
+
+%-------------------------------------------------------------------------
+child_specs(doc) ->
+ ["Tests child specs, invalid formats should be rejected."];
+child_specs(suite) -> [];
+child_specs(Config) when list(Config) ->
+ process_flag(trap_exit, true),
+ ?line {ok, _Pid} = start({ok, {{one_for_one, 2, 3600}, []}}),
+ ?line {error, _} = supervisor:start_child(sup_test, hej),
+
+ %% Bad child specs
+ B1 = {child, mfa, permanent, 1000, worker, []},
+ B2 = {child, {m,f,[a]}, prmanent, 1000, worker, []},
+ B3 = {child, {m,f,[a]}, permanent, -10, worker, []},
+ B4 = {child, {m,f,[a]}, permanent, 10, wrker, []},
+ B5 = {child, {m,f,[a]}, permanent, infinity, worker, []},
+ B6 = {child, {m,f,[a]}, permanent, 1000, worker, dy},
+ B7 = {child, {m,f,[a]}, permanent, 1000, worker, [1,2,3]},
+
+ %% Correct child specs!
+ %% <Modules> (last parameter in a child spec) can be [] as we do
+ %% not test code upgrade here.
+ C1 = {child, {m,f,[a]}, permanent, infinity, supervisor, []},
+ C2 = {child, {m,f,[a]}, permanent, 1000, supervisor, []},
+ C3 = {child, {m,f,[a]}, temporary, 1000, worker, dynamic},
+ C4 = {child, {m,f,[a]}, transient, 1000, worker, [m]},
+
+ ?line {error, {invalid_mfa,mfa}} = supervisor:start_child(sup_test, B1),
+ ?line {error, {invalid_restart_type, prmanent}} =
+ supervisor:start_child(sup_test, B2),
+ ?line {error, {invalid_shutdown,-10}}
+ = supervisor:start_child(sup_test, B3),
+ ?line {error, {invalid_child_type,wrker}}
+ = supervisor:start_child(sup_test, B4),
+ ?line {error, _} = supervisor:start_child(sup_test, B5),
+ ?line {error, {invalid_modules,dy}}
+ = supervisor:start_child(sup_test, B6),
+
+ ?line {error, {invalid_mfa,mfa}} = supervisor:check_childspecs([B1]),
+ ?line {error, {invalid_restart_type,prmanent}} =
+ supervisor:check_childspecs([B2]),
+ ?line {error, {invalid_shutdown,-10}} = supervisor:check_childspecs([B3]),
+ ?line {error, {invalid_child_type,wrker}}
+ = supervisor:check_childspecs([B4]),
+ ?line {error, _} = supervisor:check_childspecs([B5]),
+ ?line {error, {invalid_modules,dy}} = supervisor:check_childspecs([B6]),
+ ?line {error, {invalid_module, 1}} =
+ supervisor:check_childspecs([B7]),
+
+ ?line ok = supervisor:check_childspecs([C1]),
+ ?line ok = supervisor:check_childspecs([C2]),
+ ?line ok = supervisor:check_childspecs([C3]),
+ ?line ok = supervisor:check_childspecs([C4]),
+ ok.
+%-------------------------------------------------------------------------
+normal_termination(doc) ->
+ ["Testes the supervisors behaviour if a child dies with reason normal"];
+normal_termination(suite) ->
+ [permanent_normal, transient_normal, temporary_normal].
+
+%-------------------------------------------------------------------------
+permanent_normal(doc) ->
+ ["A permanent child should always be restarted"];
+permanent_normal(suite) -> [];
+permanent_normal(Config) when list(Config) ->
+ ?line {ok, _SupPid} = start({ok, {{one_for_one, 2, 3600}, []}}),
+ Child1 = {child1, {supervisor_1, start_child, []}, permanent, 1000,
+ worker, []},
+
+ ?line {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+
+ CPid1 ! stop,
+ test_server:sleep(100),
+ ?line [{child1, Pid ,worker,[]}] = supervisor:which_children(sup_test),
+ case is_pid(Pid) of
+ true ->
+ ok;
+ false ->
+ ?line test_server:fail({permanent_child_not_restarted, Child1})
+ end.
+
+%-------------------------------------------------------------------------
+transient_normal(doc) ->
+ ["A transient child should not be restarted if it exits with "
+ "reason normal"];
+transient_normal(suite) -> [];
+transient_normal(Config) when list(Config) ->
+ ?line {ok, _SupPid} = start({ok, {{one_for_one, 2, 3600}, []}}),
+ Child1 = {child1, {supervisor_1, start_child, []}, transient, 1000,
+ worker, []},
+
+ ?line {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+
+ CPid1 ! stop,
+ test_server:sleep(100),
+
+ ?line [{child1,undefined,worker,[]}] = supervisor:which_children(sup_test).
+
+%-------------------------------------------------------------------------
+temporary_normal(doc) ->
+ ["A temporary process should never be restarted"];
+temporary_normal(suite) -> [];
+temporary_normal(Config) when list(Config) ->
+ ?line {ok, _SupPid} = start({ok, {{one_for_one, 2, 3600}, []}}),
+ Child1 = {child1, {supervisor_1, start_child, []}, temporary, 1000,
+ worker, []},
+
+ ?line {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+
+ CPid1 ! stop,
+ test_server:sleep(100),
+
+ ?line [{child1,undefined,worker,[]}] = supervisor:which_children(sup_test).
+
+%-------------------------------------------------------------------------
+abnormal_termination(doc) ->
+ ["Testes the supervisors behaviour if a child dies with reason abnormal"];
+abnormal_termination(suite) ->
+ [permanent_abnormal, transient_abnormal, temporary_abnormal].
+
+%-------------------------------------------------------------------------
+permanent_abnormal(doc) ->
+ ["A permanent child should always be restarted"];
+permanent_abnormal(suite) -> [];
+permanent_abnormal(Config) when list(Config) ->
+ ?line {ok, _SupPid} = start({ok, {{one_for_one, 2, 3600}, []}}),
+ Child1 = {child1, {supervisor_1, start_child, []}, permanent, 1000,
+ worker, []},
+
+ ?line {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+
+ CPid1 ! die,
+ test_server:sleep(100),
+ ?line [{child1, Pid ,worker,[]}] = supervisor:which_children(sup_test),
+ case is_pid(Pid) of
+ true ->
+ ok;
+ false ->
+ ?line test_server:fail({permanent_child_not_restarted, Child1})
+ end.
+
+%-------------------------------------------------------------------------
+transient_abnormal(doc) ->
+ ["A transient child should be restarted if it exits with "
+ "reason abnormal"];
+transient_abnormal(suite) -> [];
+transient_abnormal(Config) when list(Config) ->
+ ?line {ok, _SupPid} = start({ok, {{one_for_one, 2, 3600}, []}}),
+ Child1 = {child1, {supervisor_1, start_child, []}, transient, 1000,
+ worker, []},
+
+ ?line {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+
+ CPid1 ! die,
+ test_server:sleep(100),
+
+ ?line [{child1, Pid ,worker,[]}] = supervisor:which_children(sup_test),
+ case is_pid(Pid) of
+ true ->
+ ok;
+ false ->
+ ?line test_server:fail({transient_child_not_restarted, Child1})
+ end.
+
+
+%-------------------------------------------------------------------------
+temporary_abnormal(doc) ->
+ ["A temporary process should never be restarted"];
+temporary_abnormal(suite) -> [];
+temporary_abnormal(Config) when list(Config) ->
+ ?line {ok, _SupPid} = start({ok, {{one_for_one, 2, 3600}, []}}),
+ Child1 = {child1, {supervisor_1, start_child, []}, temporary, 1000,
+ worker, []},
+
+ ?line {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+
+ CPid1 ! die,
+ test_server:sleep(100),
+
+ ?line [{child1,undefined,worker,[]}] = supervisor:which_children(sup_test).
+
+%-------------------------------------------------------------------------
+restart_one_for_one(doc) ->
+ ["Test that the one_for_one strategy works."];
+
+restart_one_for_one(suite) -> [one_for_one, one_for_one_escalation].
+
+%-------------------------------------------------------------------------
+one_for_one(doc) ->
+ ["Test the one_for_one base case."];
+one_for_one(suite) -> [];
+one_for_one(Config) when list(Config) ->
+ process_flag(trap_exit, true),
+ Child1 = {child1, {supervisor_1, start_child, []}, permanent, 1000,
+ worker, []},
+ Child2 = {child2, {supervisor_1, start_child, []}, permanent, 1000,
+ worker, []},
+ ?line {ok, Pid} = start({ok, {{one_for_one, 2, 3600}, []}}),
+ ?line {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+ link(CPid1),
+ ?line {ok, CPid2} = supervisor:start_child(sup_test, Child2),
+ link(CPid2),
+ CPid1 ! die,
+ receive
+ {'EXIT', CPid1, died} -> ok;
+ {'EXIT', CPid1, Reason} ->
+ ?line test_server:fail({bad_exit_reason, Reason})
+ end,
+ test_server:sleep(100),
+ Children = supervisor:which_children(sup_test),
+ if length(Children) == 2 ->
+ case lists:keysearch(CPid2, 2, Children) of
+ {value, _} -> ok;
+ _ -> ?line test_server:fail(bad_child)
+ end;
+ true -> ?line test_server:fail({bad_child_list, Children})
+ end,
+
+ %% Test restart frequency property
+ CPid2 ! die,
+ receive
+ {'EXIT', CPid2, _} -> ok
+ end,
+ test_server:sleep(100),
+ [{_, Pid4, _, _}|_] = supervisor:which_children(sup_test),
+ Pid4 ! die,
+ receive
+ {'EXIT', Pid, _} -> ok
+ after 3000 -> ?line test_server:fail(restart_failed)
+ end,
+ ok.
+%-------------------------------------------------------------------------
+one_for_one_escalation(doc) ->
+ ["Test restart escalation on a one_for_one supervisor."];
+one_for_one_escalation(suite) -> [];
+one_for_one_escalation(Config) when list(Config) ->
+ process_flag(trap_exit, true),
+ Child1 = {child1, {supervisor_1, start_child, [error]},
+ permanent, 1000,
+ worker, []},
+ Child2 = {child2, {supervisor_1, start_child, []}, permanent, 1000,
+ worker, []},
+ ?line {ok, Pid} = start({ok, {{one_for_one, 4, 3600}, []}}),
+ ?line {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+ link(CPid1),
+ ?line {ok, CPid2} = supervisor:start_child(sup_test, Child2),
+ link(CPid2),
+ CPid1 ! die,
+ receive
+ {'EXIT', CPid1, died} -> ok;
+ {'EXIT', CPid1, Reason} ->
+ ?line test_server:fail({bad_exit_reason, Reason})
+ end,
+ receive
+ {'EXIT', Pid, _} -> ok
+ after
+ 2000 -> ?line test_server:fail(supervisor_alive)
+ end,
+ receive
+ {'EXIT', CPid2, _} -> ok
+ after
+ 4000 -> ?line test_server:fail(all_not_terminated)
+ end,
+ ok.
+%-------------------------------------------------------------------------
+restart_one_for_all(doc) ->
+ ["Test that the one_for_all strategy works."];
+
+restart_one_for_all(suite) ->
+ [one_for_all, one_for_all_escalation].
+
+%-------------------------------------------------------------------------
+one_for_all(doc) ->
+ ["Test the one_for_all base case."];
+one_for_all(suite) -> [];
+one_for_all(Config) when list(Config) ->
+ process_flag(trap_exit, true),
+ Child1 = {child1, {supervisor_1, start_child, []}, permanent, 1000,
+ worker, []},
+ Child2 = {child2, {supervisor_1, start_child, []}, permanent, 1000,
+ worker, []},
+ ?line {ok, Pid} = start({ok, {{one_for_all, 2, 3600}, []}}),
+ ?line {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+ link(CPid1),
+ ?line {ok, CPid2} = supervisor:start_child(sup_test, Child2),
+ link(CPid2),
+ CPid1 ! die,
+ receive
+ {'EXIT', CPid1, died} -> ok;
+ {'EXIT', CPid1, Reason} ->
+ ?line test_server:fail({bad_exit_reason, Reason})
+ end,
+ receive
+ {'EXIT', CPid2, _} -> ok
+ end,
+ test_server:sleep(100),
+ Children = supervisor:which_children(sup_test),
+ if length(Children) == 2 -> ok;
+ true -> ?line test_server:fail({bad_child_list, Children})
+ end,
+ %% Test that no old children is still alive
+ SCh = lists:map(fun({_,P,_,_}) -> P end, Children),
+ case lists:member(CPid1, SCh) of
+ true -> ?line test_server:fail(bad_child);
+ false -> ok
+ end,
+ case lists:member(CPid2, SCh) of
+ true -> ?line test_server:fail(bad_child);
+ false -> ok
+ end,
+ %%% Test restart frequency property
+ [{_, Pid3, _, _}|_] = supervisor:which_children(sup_test),
+ Pid3 ! die,
+ test_server:sleep(100),
+ [{_, Pid4, _, _}|_] = supervisor:which_children(sup_test),
+ Pid4 ! die,
+ receive
+ {'EXIT', Pid, _} -> ok
+ after 3000 -> ?line test_server:fail(restart_failed)
+ end,
+ exit(Pid, shutdown).
+
+%-------------------------------------------------------------------------
+one_for_all_escalation(doc) ->
+ ["Test restart escalation on a one_for_all supervisor."];
+one_for_all_escalation(suite) -> [];
+one_for_all_escalation(Config) when list(Config) ->
+ process_flag(trap_exit, true),
+ Child1 = {child1, {supervisor_1, start_child, []}, permanent, 1000,
+ worker, []},
+ Child2 = {child2, {supervisor_1, start_child, [error]},
+ permanent, 1000,
+ worker, []},
+ ?line {ok, Pid} = start({ok, {{one_for_all, 4, 3600}, []}}),
+ ?line {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+ link(CPid1),
+ ?line {ok, CPid2} = supervisor:start_child(sup_test, Child2),
+ link(CPid2),
+ CPid1 ! die,
+ receive
+ {'EXIT', CPid1, died} -> ok;
+ {'EXIT', CPid1, Reason} ->
+ ?line test_server:fail({bad_exit_reason, Reason})
+ end,
+ receive
+ {'EXIT', CPid2, _} -> ok
+ after
+ 2000 -> ?line test_server:fail(all_not_terminated)
+ end,
+ receive
+ {'EXIT', Pid, _} -> ok
+ after
+ 4000 -> ?line test_server:fail(supervisor_alive)
+ end,
+ ok.
+
+%-------------------------------------------------------------------------
+restart_simple_one_for_one(doc) ->
+ ["Test that the simple_one_for_one strategy works."];
+
+restart_simple_one_for_one(suite) ->
+ [simple_one_for_one, simple_one_for_one_extra,
+ simple_one_for_one_escalation].
+
+%-------------------------------------------------------------------------
+simple_one_for_one(doc) ->
+ ["Test the simple_one_for_one base case."];
+simple_one_for_one(suite) -> [];
+simple_one_for_one(Config) when list(Config) ->
+ process_flag(trap_exit, true),
+ Child = {child, {supervisor_1, start_child, []}, permanent, 1000,
+ worker, []},
+ ?line {ok, Pid} = start({ok, {{simple_one_for_one, 2, 3600}, [Child]}}),
+ ?line {ok, CPid1} = supervisor:start_child(sup_test, []),
+ link(CPid1),
+ ?line {ok, CPid2} = supervisor:start_child(sup_test, []),
+ link(CPid2),
+ CPid1 ! die,
+ receive
+ {'EXIT', CPid1, died} -> ok;
+ {'EXIT', CPid1, Reason} ->
+ ?line test_server:fail({bad_exit_reason, Reason})
+ end,
+ test_server:sleep(100),
+ Children = supervisor:which_children(sup_test),
+ if length(Children) == 2 ->
+ case lists:keysearch(CPid2, 2, Children) of
+ {value, _} -> ok;
+ _ -> ?line test_server:fail(bad_child)
+ end;
+ true -> ?line test_server:fail({bad_child_list, Children})
+ end,
+ %% Test restart frequency property
+ CPid2 ! die,
+ receive
+ {'EXIT', CPid2, _} -> ok
+ end,
+ test_server:sleep(100),
+ [{_, Pid4, _, _}|_] = supervisor:which_children(sup_test),
+ Pid4 ! die,
+ receive
+ {'EXIT', Pid, _} -> ok
+ after 3000 -> ?line test_server:fail(restart_failed)
+ end,
+ ok.
+%-------------------------------------------------------------------------
+simple_one_for_one_extra(doc) ->
+ ["Tests automatic restart of children "
+ "who's start function return extra info."];
+simple_one_for_one_extra(suite) -> [];
+simple_one_for_one_extra(Config) when list(Config) ->
+ process_flag(trap_exit, true),
+ Child = {child, {supervisor_1, start_child, [extra_info]},
+ permanent, 1000, worker, []},
+ ?line {ok, Pid} = start({ok, {{simple_one_for_one, 2, 3600}, [Child]}}),
+ ?line {ok, CPid1, extra_info} = supervisor:start_child(sup_test, []),
+ link(CPid1),
+ ?line {ok, CPid2, extra_info} = supervisor:start_child(sup_test, []),
+ link(CPid2),
+ CPid1 ! die,
+ receive
+ {'EXIT', CPid1, died} -> ok;
+ {'EXIT', CPid1, Reason} ->
+ ?line test_server:fail({bad_exit_reason, Reason})
+ end,
+ test_server:sleep(100),
+ Children = supervisor:which_children(sup_test),
+ if length(Children) == 2 ->
+ case lists:keysearch(CPid2, 2, Children) of
+ {value, _} -> ok;
+ _ -> ?line test_server:fail(bad_child)
+ end;
+ true -> ?line test_server:fail({bad_child_list, Children})
+ end,
+ CPid2 ! die,
+ receive
+ {'EXIT', CPid2, _} -> ok
+ end,
+ test_server:sleep(100),
+ [{_, Pid4, _, _}|_] = supervisor:which_children(sup_test),
+ Pid4 ! die,
+ receive
+ {'EXIT', Pid, _} -> ok
+ after 3000 -> ?line test_server:fail(restart_failed)
+ end,
+ ok.
+%-------------------------------------------------------------------------
+simple_one_for_one_escalation(doc) ->
+ ["Test restart escalation on a simple_one_for_one supervisor."];
+simple_one_for_one_escalation(suite) -> [];
+simple_one_for_one_escalation(Config) when list(Config) ->
+ process_flag(trap_exit, true),
+ Child = {child, {supervisor_1, start_child, []}, permanent, 1000,
+ worker, []},
+ ?line {ok, Pid} = start({ok, {{simple_one_for_one, 4, 3600}, [Child]}}),
+ ?line {ok, CPid1} = supervisor:start_child(sup_test, [error]),
+ link(CPid1),
+ ?line {ok, CPid2} = supervisor:start_child(sup_test, []),
+ link(CPid2),
+ CPid1 ! die,
+ receive
+ {'EXIT', CPid1, died} -> ok;
+ {'EXIT', CPid1, Reason} ->
+ ?line test_server:fail({bad_exit_reason, Reason})
+ end,
+ receive
+ {'EXIT', Pid, _} -> ok
+ after
+ 2000 -> ?line test_server:fail(supervisor_alive)
+ end,
+ receive
+ {'EXIT', CPid2, _} -> ok
+ after
+ 2000 -> ?line test_server:fail(all_not_terminated)
+ end,
+ ok.
+%-------------------------------------------------------------------------
+restart_rest_for_one(doc) ->
+ ["Test that the rest_for_one strategy works."];
+restart_rest_for_one(suite) -> [rest_for_one, rest_for_one_escalation].
+
+%-------------------------------------------------------------------------
+rest_for_one(doc) ->
+ ["Test the rest_for_one base case."];
+rest_for_one(suite) -> [];
+rest_for_one(Config) when list(Config) ->
+ process_flag(trap_exit, true),
+ Child1 = {child1, {supervisor_1, start_child, []}, permanent, 1000,
+ worker, []},
+ Child2 = {child2, {supervisor_1, start_child, []}, permanent, 1000,
+ worker, []},
+ Child3 = {child3, {supervisor_1, start_child, []}, permanent, 1000,
+ worker, []},
+ ?line {ok, Pid} = start({ok, {{rest_for_one, 2, 3600}, []}}),
+ ?line {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+ link(CPid1),
+ ?line {ok, CPid2} = supervisor:start_child(sup_test, Child2),
+ link(CPid2),
+ ?line {ok, CPid3} = supervisor:start_child(sup_test, Child3),
+ link(CPid3),
+ CPid2 ! die,
+ receive
+ {'EXIT', CPid2, died} -> ok;
+ {'EXIT', CPid2, Reason} ->
+ ?line test_server:fail({bad_exit_reason, Reason})
+ after 2000 ->
+ ?line test_server:fail(no_exit)
+ end,
+ %% Check that Cpid3 did die
+ receive
+ {'EXIT', CPid3, _} -> ok
+ after 2000 ->
+ ?line test_server:fail(no_exit)
+ end,
+ %% Check that Cpid1 didn't die
+ receive
+ {'EXIT', CPid1, _} ->
+ ?line test_server:fail(bad_exit)
+ after
+ 100 -> ok
+ end,
+ Children = supervisor:which_children(sup_test),
+ if length(Children) == 3 -> ok;
+ true -> ?line test_server:fail({bad_child_list, Children})
+ end,
+ %% Test that no old children is still alive
+ SCh = lists:map(fun({_,P,_,_}) -> P end, Children),
+ case lists:member(CPid1, SCh) of
+ true -> ok;
+ false -> ?line test_server:fail(bad_child)
+ end,
+ case lists:member(CPid2, SCh) of
+ true -> ?line test_server:fail(bad_child);
+ false -> ok
+ end,
+ case lists:member(CPid3, SCh) of
+ true -> ?line test_server:fail(bad_child);
+ false -> ok
+ end,
+
+ %% Test restart frequency property
+ [{child3, Pid3, _, _}|_] = supervisor:which_children(sup_test),
+ Pid3 ! die,
+ test_server:sleep(100),
+ [_,{child2, Pid4, _, _}|_] = supervisor:which_children(sup_test),
+ Pid4 ! die,
+ receive
+ {'EXIT', Pid, _} -> ok
+ after 3000 -> ?line test_server:fail(restart_failed)
+ end,
+ exit(Pid, shutdown).
+
+%-------------------------------------------------------------------------
+rest_for_one_escalation(doc) ->
+ ["Test restart escalation on a rest_for_one supervisor."];
+rest_for_one_escalation(suite) -> [];
+rest_for_one_escalation(Config) when list(Config) ->
+ process_flag(trap_exit, true),
+ Child1 = {child1, {supervisor_1, start_child, []}, permanent, 1000,
+ worker, []},
+ Child2 = {child2, {supervisor_1, start_child, [error]},
+ permanent, 1000,
+ worker, []},
+ ?line {ok, Pid} = start({ok, {{rest_for_one, 4, 3600}, []}}),
+ ?line {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+ link(CPid1),
+ ?line {ok, CPid2} = supervisor:start_child(sup_test, Child2),
+ link(CPid2),
+ CPid1 ! die,
+ receive
+ {'EXIT', CPid1, died} -> ok;
+ {'EXIT', CPid1, Reason} ->
+ ?line test_server:fail({bad_exit_reason, Reason})
+ end,
+ receive
+ {'EXIT', CPid2, _} -> ok
+ after
+ 2000 -> ?line test_server:fail(not_terminated)
+ end,
+ receive
+ {'EXIT', Pid, _} -> ok
+ after
+ 4000 -> ?line test_server:fail(supervisor_alive)
+ end,
+ ok.
+
+%-------------------------------------------------------------------------
+child_unlink(doc)-> ["Test that the supervisor does not hang forever if "
+ "the child unliks and then is terminated by the supervisor."];
+child_unlink(suite) -> [];
+child_unlink(Config) when list(Config) ->
+
+ ?line {ok, SupPid} = start({ok, {{one_for_one, 2, 3600}, []}}),
+
+ Child = {naughty_child, {naughty_child,
+ start_link, [SupPid]}, permanent,
+ 1000, worker, [supervisor_SUITE]},
+
+ ?line {ok, _ChildPid} = supervisor:start_child(sup_test, Child),
+
+ Pid = spawn(supervisor, terminate_child, [SupPid, naughty_child]),
+
+ SupPid ! foo,
+ timer:sleep(5000),
+ %% If the supervisor did not hang it will have got rid of the
+ %% foo message that we sent.
+ case erlang:process_info(SupPid, message_queue_len) of
+ {message_queue_len, 0}->
+ ok;
+ _ ->
+ exit(Pid, kill),
+ ?line test_server:fail(supervisor_hangs)
+ end.
+%-------------------------------------------------------------------------
+
+tree(doc) ->
+ ["Test a basic supervison tree."];
+tree(suite) ->
+ [];
+tree(Config) when list(Config) ->
+ process_flag(trap_exit, true),
+
+ Child1 = {child1, {supervisor_1, start_child, []},
+ permanent, 1000,
+ worker, []},
+ Child2 = {child2, {supervisor_1, start_child, []},
+ permanent, 1000,
+ worker, []},
+ Child3 = {child3, {supervisor_1, start_child, [error]},
+ permanent, 1000,
+ worker, []},
+ Child4 = {child4, {supervisor_1, start_child, []},
+ permanent, 1000,
+ worker, []},
+
+ ChildSup1 = {supchild1,
+ {supervisor, start_link,
+ [?MODULE, {ok, {{one_for_one, 4, 3600}, [Child1, Child2]}}]},
+ permanent, infinity,
+ supervisor, []},
+ ChildSup2 = {supchild2,
+ {supervisor, start_link,
+ [?MODULE, {ok, {{one_for_one, 4, 3600}, []}}]},
+ permanent, infinity,
+ supervisor, []},
+
+ %% Top supervisor
+ ?line {ok, Pid} = start({ok, {{one_for_all, 4, 3600}, []}}),
+
+ %% Child supervisors
+ ?line {ok, Sup1} = supervisor:start_child(Pid, ChildSup1),
+ ?line {ok, Sup2} = supervisor:start_child(Pid, ChildSup2),
+
+ %% Workers
+
+ ?line [{_, CPid2, _, _},{_, CPid1, _, _}] =
+ supervisor:which_children(Sup1),
+
+ %% Dynamic children
+ ?line {ok, CPid3} = supervisor:start_child(Sup2, Child3),
+ ?line {ok, CPid4} = supervisor:start_child(Sup2, Child4),
+
+ link(Sup1),
+ link(Sup2),
+ link(CPid1),
+ link(CPid2),
+ link(CPid3),
+ link(CPid4),
+
+ %% Test that the only the process that dies is restarted
+ CPid4 ! die,
+
+ receive
+ {'EXIT', CPid4, _} -> ?line ok
+ after 10000 ->
+ ?line test_server:fail(child_was_not_killed)
+ end,
+
+ test_server:sleep(100),
+
+ ?line [{_, CPid2, _, _},{_, CPid1, _, _}] =
+ supervisor:which_children(Sup1),
+
+ ?line [{_, NewCPid4, _, _},{_, CPid3, _, _}] =
+ supervisor:which_children(Sup2),
+
+ link(NewCPid4),
+
+ %% Test that supervisor tree is restarted, but not dynamic children.
+ CPid3 ! die,
+
+ receive
+ {'EXIT', CPid3, died} -> ?line ok;
+ {'EXIT', CPid3, Reason} ->
+ ?line test_server:fail({bad_exit_reason, Reason})
+ after 1000 ->
+ ?line test_server:fail(child_was_not_killed)
+ end,
+
+ test_server:sleep(1000),
+
+ receive
+ {'EXIT', NewCPid4, _} -> ?line ok
+ after 1000 ->
+ ?line test_server:fail(child_was_not_killed)
+ end,
+
+ receive
+ {'EXIT', Sup2, _} -> ?line ok
+ after 1000 ->
+ ?line test_server:fail(child_was_not_killed)
+ end,
+
+ receive
+ {'EXIT', CPid1, _} -> ?line ok
+ after 1000 ->
+ ?line test_server:fail(child_was_not_killed)
+ end,
+
+ receive
+ {'EXIT', CPid2, _} -> ?line ok
+ after 1000 ->
+ ?line test_server:fail(child_was_not_killed)
+ end,
+
+ receive
+ {'EXIT', Sup1, _} -> ?line ok
+ after 1000 ->
+ ?line test_server:fail(child_was_not_killed)
+ end,
+
+ ?line [{supchild2, NewSup2, _, _},{supchild1, NewSup1, _, _}] =
+ supervisor:which_children(Pid),
+
+ ?line [{child2, _, _, _},{child1, _, _, _}] =
+ supervisor:which_children(NewSup1),
+ ?line [] = supervisor:which_children(NewSup2),
+
+ ok.
diff --git a/lib/stdlib/test/supervisor_bridge_SUITE.erl b/lib/stdlib/test/supervisor_bridge_SUITE.erl
new file mode 100644
index 0000000000..b23bac2d44
--- /dev/null
+++ b/lib/stdlib/test/supervisor_bridge_SUITE.erl
@@ -0,0 +1,178 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(supervisor_bridge_SUITE).
+-export([all/1,starting/1,mini_terminate/1,mini_die/1,badstart/1]).
+-export([client/1,init/1,internal_loop_init/1,terminate/2]).
+
+-include("test_server.hrl").
+-define(bridge_name,supervisor_bridge_SUITE_server).
+-define(work_bridge_name,work_supervisor_bridge_SUITE_server).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+all(suite) -> [starting,mini_terminate,mini_die,badstart].
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+starting(suite) -> [];
+starting(Config) when is_list(Config) ->
+ process_flag(trap_exit,true),
+
+ ?line ignore = start(1),
+ ?line {error,testing} = start(2),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+mini_terminate(suite) -> [];
+mini_terminate(Config) when is_list(Config) ->
+ miniappl(1),
+ ok.
+
+mini_die(suite) -> [];
+mini_die(Config) when is_list(Config) ->
+ miniappl(2),
+ ok.
+
+miniappl(N) ->
+ process_flag(trap_exit,true),
+ ?line {ok,Server} = start(3),
+ ?line Client = spawn_link(?MODULE,client,[N]),
+ ?line Handle = test_server:timetrap(2000),
+ ?line miniappl_loop(Client,Server),
+ ?line test_server:timetrap_cancel(Handle).
+
+miniappl_loop([],[]) ->
+ ok;
+miniappl_loop(Client,Server) ->
+ io:format("Client ~p, Server ~p\n",[Client,Server]),
+ receive
+ {'EXIT',Client,_} ->
+ ?line miniappl_loop([],Server);
+ {'EXIT',Server,killed} -> %% terminate
+ ?line miniappl_loop(Client,[]);
+ {'EXIT',Server,died} -> %% die
+ ?line miniappl_loop(Client,[]);
+ {dying,_Reason} ->
+ ?line miniappl_loop(Client, Server);
+ Other ->
+ ?line exit({failed,Other})
+ end.
+
+%%%%%%%%%%%%%%%%%%%%
+% Client
+
+client(N) ->
+ io:format("Client starting...\n"),
+ ok = public_request(),
+ case N of
+ 1 -> public_kill();
+ 2 -> ?work_bridge_name ! die
+ end,
+ io:format("Killed server, terminating client...\n"),
+ exit(fine).
+
+%%%%%%%%%%%%%%%%%%%%
+% Non compliant server
+
+start(N) ->
+ supervisor_bridge:start_link({local,?bridge_name},?MODULE,N).
+
+public_request() ->
+ ?work_bridge_name ! {non_compliant_message,self()},
+ io:format("Client waiting for answer...\n"),
+ receive
+ non_compliant_answer ->
+ ok
+ end,
+ io:format("Client got answer...\n").
+
+public_kill() ->
+ %% This func knows about supervisor_bridge
+ exit(whereis(?work_bridge_name),kill).
+
+init(1) ->
+ ignore;
+init(2) ->
+ {error,testing};
+init(3) ->
+ %% This func knows about supervisor_bridge
+ InternalPid = spawn_link(?MODULE,internal_loop_init,[self()]),
+ receive
+ {InternalPid,init_done} ->
+ {ok,InternalPid,self()}
+ end.
+
+internal_loop_init(Parent) ->
+ register(?work_bridge_name, self()),
+ Parent ! {self(),init_done},
+ internal_loop({Parent,self()}).
+
+internal_loop(State) ->
+ receive
+ {non_compliant_message,From} ->
+ io:format("Got request from ~p\n",[From]),
+ From ! non_compliant_answer,
+ internal_loop(State);
+ die ->
+ exit(died)
+ end.
+
+terminate(Reason,{Parent,Worker}) ->
+ %% This func knows about supervisor_bridge
+ io:format("Terminating bridge...\n"),
+ exit(kill,Worker),
+ Parent ! {dying,Reason},
+ anything.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+badstart(suite) -> [];
+badstart(doc) -> "Test various bad ways of starting a supervisor bridge.";
+badstart(Config) when is_list(Config) ->
+ ?line Dog = test_server:timetrap(test_server:minutes(1)),
+
+ %% Various bad arguments.
+
+ ?line {'EXIT',_} =
+ (catch supervisor_bridge:start_link({xxx,?bridge_name},?MODULE,1)),
+ ?line {'EXIT',_} =
+ (catch supervisor_bridge:start_link({local,"foo"},?MODULE,1)),
+ ?line {'EXIT',_} =
+ (catch supervisor_bridge:start_link(?bridge_name,?MODULE,1)),
+ ?line [] = test_server:messages_get(), % No messages waiting
+
+ %% Already started.
+
+ ?line process_flag(trap_exit, true),
+ ?line {ok,Pid} =
+ supervisor_bridge:start_link({local,?bridge_name},?MODULE,3),
+ ?line {error,{already_started,Pid}} =
+ supervisor_bridge:start_link({local,?bridge_name},?MODULE,3),
+ ?line public_kill(),
+
+ %% We used to wait 1 ms before retrieving the message queue,
+ %% but that might not always be enough if the machine is overloaded.
+ ?line receive
+ {'EXIT', Pid, killed} -> ok
+ end,
+ ?line test_server:timetrap_cancel(Dog),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/stdlib/test/sys_SUITE.erl b/lib/stdlib/test/sys_SUITE.erl
new file mode 100644
index 0000000000..e44fd56403
--- /dev/null
+++ b/lib/stdlib/test/sys_SUITE.erl
@@ -0,0 +1,173 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(sys_SUITE).
+-export([all/1,log/1,log_to_file/1,stats/1,trace/1,suspend/1,install/1]).
+-export([handle_call/3,terminate/2,init/1]).
+-include("test_server.hrl").
+
+-define(server,sys_SUITE_server).
+
+
+%% Doesn't look into change_code at all
+%% Doesn't address writing your own process that understands
+%% system messages at all.
+
+
+all(suite) -> [log,log_to_file,stats,trace,suspend,install].
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+log(suite) -> [];
+log(Config) when is_list(Config) ->
+ ?line {ok,_Server} = start(),
+ ?line ok = sys:log(?server,true),
+ ?line {ok,-44} = public_call(44),
+ ?line ok = sys:log(?server,false),
+ ?line ok = sys:log(?server,print),
+ ?line stop(),
+ ok.
+
+log_to_file(suite) -> [];
+log_to_file(Config) when is_list(Config) ->
+ TempName = test_server:temp_name(?config(priv_dir,Config) ++ "sys."),
+ ?line {ok,_Server} = start(),
+ ?line ok = sys:log_to_file(?server,TempName),
+ ?line {ok,-44} = public_call(44),
+ ?line ok = sys:log_to_file(?server,false),
+ ?line {ok,Fd} = file:open(TempName,read),
+ ?line Msg1 = io:get_line(Fd,''),
+ ?line Msg2 = io:get_line(Fd,''),
+ ?line file:close(Fd),
+ ?line lists:prefix("*DBG* sys_SUITE_server got call {req,44} from ",Msg1),
+ ?line lists:prefix("*DBG* sys_SUITE_server sent {ok,-44} to ",Msg2),
+ ?line stop(),
+ ok.
+
+stats(suite) -> [];
+stats(Config) when is_list(Config) ->
+ ?line Self = self(),
+ ?line {ok,_Server} = start(),
+ ?line ok = sys:statistics(?server,true),
+ ?line {ok,-44} = public_call(44),
+ ?line {ok,Stats} = sys:statistics(?server,get),
+ ?line lists:member({messages_in,1},Stats),
+ ?line lists:member({messages_out,1},Stats),
+ ?line ok = sys:statistics(?server,false),
+ ?line {status,_Pid,{module,_Mod},[_PDict,running,Self,_,_]} =
+ sys:get_status(?server),
+ ?line {ok,no_statistics} = sys:statistics(?server,get),
+ ?line stop(),
+ ok.
+
+trace(suite) -> [];
+trace(Config) when is_list(Config) ->
+ ?line {ok,_Server} = start(),
+ case os:type() of
+ vxworks ->
+ ?line test_server:sleep(20000);
+ _ ->
+ ?line test_server:sleep(2000)
+ end,
+ ?line test_server:capture_start(),
+ ?line sys:trace(?server,true),
+ ?line {ok,-44} = public_call(44),
+ %% ho, hum, allow for the io to reach us..
+ case os:type() of
+ vxworks ->
+ ?line test_server:sleep(10000);
+ _ ->
+ ?line test_server:sleep(1000)
+ end,
+ ?line test_server:capture_stop(),
+ ?line [Msg1,Msg2] = test_server:capture_get(),
+ ?line lists:prefix("*DBG* sys_SUITE_server got call {req,44} from ",Msg1),
+ ?line lists:prefix("*DBG* sys_SUITE_server sent {ok,-44} to ",Msg2),
+ ?line stop(),
+ ok.
+
+suspend(suite) -> [];
+suspend(Config) when is_list(Config) ->
+ ?line {ok,_Server} = start(),
+ ?line sys:suspend(?server,1000),
+ ?line {'EXIT',_} = (catch public_call(48)),
+ ?line {status,_,_,[_,suspended,_,_,_]} = sys:get_status(?server),
+ ?line sys:suspend(?server,1000), %% doing it twice is no error
+ ?line {'EXIT',_} = (catch public_call(48)),
+ ?line sys:resume(?server),
+ ?line {status,_,_,[_,running,_,_,_]} = sys:get_status(?server),
+ ?line {ok,-48} = (catch public_call(48)),
+ ?line sys:resume(?server), %% doing it twice is no error
+ ?line {ok,-48} = (catch public_call(48)),
+ ?line stop(),
+ ok.
+
+install(suite) -> [];
+install(Config) when is_list(Config) ->
+ ?line {ok,_Server} = start(),
+ ?line Master = self(),
+ ?line SpyFun =
+ fun(func_state,Event,ProcState) ->
+ case Event of
+ {in,{'$gen_call',_From,{req,Arg}}} ->
+ io:format("Trigged\n"),
+ Master ! {spy_got,{request,Arg},ProcState};
+ Other ->
+ io:format("Trigged other=~p\n",[Other])
+ end
+ end,
+ ?line sys:install(?server,{SpyFun,func_state}),
+ ?line {ok,-1} = (catch public_call(1)),
+ ?line sys:no_debug(?server),
+ ?line {ok,-2} = (catch public_call(2)),
+ ?line sys:install(?server,{SpyFun,func_state}),
+ ?line sys:install(?server,{SpyFun,func_state}),
+ ?line {ok,-3} = (catch public_call(3)),
+ ?line sys:remove(?server,SpyFun),
+ ?line {ok,-4} = (catch public_call(4)),
+ ?line Msgs = test_server:messages_get(),
+ ?line [{spy_got,{request,1},sys_SUITE_server},
+ {spy_got,{request,3},sys_SUITE_server}] = Msgs,
+ ?line stop(),
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%
+%% Dummy server
+
+public_call(Arg) ->
+ gen_server:call(?server,{req,Arg},1000).
+
+start() ->
+ gen_server:start_link({local,?server},?MODULE,[],[]).
+
+stop() ->
+ gen_server:call(?server,stop,1000).
+
+init([]) ->
+ {ok,0}.
+
+handle_call({req,Arg},_From,State) ->
+ NewState = State+1,
+ {reply,{ok,-Arg},NewState};
+handle_call(stop,_From,State) ->
+ {stop,normal,ok,State}.
+
+terminate(_Reason, _State) ->
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/stdlib/test/tar_SUITE.erl b/lib/stdlib/test/tar_SUITE.erl
new file mode 100644
index 0000000000..af687ed2e1
--- /dev/null
+++ b/lib/stdlib/test/tar_SUITE.erl
@@ -0,0 +1,718 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(tar_SUITE).
+
+-export([all/1, borderline/1, atomic/1, long_names/1,
+ create_long_names/1, bad_tar/1, errors/1, extract_from_binary/1,
+ extract_from_binary_compressed/1,
+ extract_from_open_file/1, symlinks/1, open_add_close/1, cooked_compressed/1,
+ memory/1]).
+
+-include("test_server.hrl").
+-include_lib("kernel/include/file.hrl").
+
+all(suite) -> [borderline, atomic, long_names, create_long_names,
+ bad_tar, errors,
+ extract_from_binary, extract_from_binary_compressed,
+ extract_from_open_file,
+ symlinks, open_add_close, cooked_compressed,
+ memory].
+
+borderline(doc) ->
+ ["Test creating, listing and extracting one file from an archive",
+ "multiple times with different file sizes. ",
+ "Also check that the file attributes of the extracted file has survived."];
+borderline(Config) when is_list(Config) ->
+
+ %% Note: We cannot use absolute paths, because the pathnames will be
+ %% too long for the limit allowed in tar files (100 characters).
+ %% Therefore, strip off the current working directory from the front
+ %% of the private directory path.
+
+ ?line {ok, Cwd} = file:get_cwd(),
+ ?line RootDir = ?config(priv_dir, Config),
+ ?line TempDir = remove_prefix(Cwd++"/", filename:join(RootDir, borderline)),
+ ?line ok = file:make_dir(TempDir),
+
+ ?line Record = 512,
+ ?line Block = 20 * Record,
+
+ ?line lists:foreach(fun(Size) -> borderline_test(Size, TempDir) end,
+ [0, 1, 10, 13, 127, 333, Record-1, Record, Record+1,
+ Block-Record-1, Block-Record, Block-Record+1,
+ Block-1, Block, Block+1,
+ Block+Record-1, Block+Record, Block+Record+1]),
+
+ %% Clean up.
+ ?line delete_files([TempDir]),
+
+ ok.
+
+borderline_test(Size, TempDir) ->
+ ?line Archive = filename:join(TempDir, "ar_"++integer_to_list(Size)++".tar"),
+ ?line Name = filename:join(TempDir, "file_"++integer_to_list(Size)),
+ ?line io:format("Testing size ~p", [Size]),
+
+ %% Create a file and archive it.
+ ?line {_, _, X0} = erlang:now(),
+ ?line file:write_file(Name, random_byte_list(X0, Size)),
+ ?line ok = erl_tar:create(Archive, [Name]),
+ ?line ok = file:delete(Name),
+
+ %% Verify listing and extracting.
+ ?line {ok, [Name]} = erl_tar:table(Archive),
+ ?line ok = erl_tar:extract(Archive, [verbose]),
+
+ %% Verify contents of extracted file.
+ ?line {ok, Bin} = file:read_file(Name),
+ ?line true = match_byte_list(X0, binary_to_list(Bin)),
+
+ %% Verify that Unix tar can read it.
+ ?line tar_tf(Archive, Name),
+
+ ok.
+
+tar_tf(Archive, Name) ->
+ case os:type() of
+ {unix, _} ->
+ tar_tf1(Archive, Name);
+ _ ->
+ ok
+ end.
+
+tar_tf1(Archive, Name) ->
+ ?line Expect = Name ++ "\n",
+ ?line cmd_expect("tar tf " ++ Archive, Expect).
+
+%% We can't use os:cmd/1, because Unix 'tar tf Name' on Solaris never
+%% terminates when given an archive of a size it doesn't like.
+
+cmd_expect(Cmd, Expect) ->
+ ?line Port = open_port({spawn, make_cmd(Cmd)}, [stream, in, eof]),
+ ?line get_data(Port, Expect).
+
+get_data(Port, Expect) ->
+ receive
+ {Port, {data, Bytes}} ->
+ ?line get_data(Port, match_output(Bytes, Expect, Port));
+ {Port, eof} ->
+ Port ! {self(), close},
+ receive
+ {Port, closed} ->
+ true
+ end,
+ receive
+ {'EXIT', Port, _} ->
+ ok
+ after 1 -> % force context switch
+ ok
+ end,
+ ?line match_output(eof, Expect, Port)
+ end.
+
+match_output([C|Output], [C|Expect], Port) ->
+ ?line match_output(Output, Expect, Port);
+match_output([_|_], [_|_], Port) ->
+ ?line kill_port_and_fail(Port, badmatch);
+match_output([X|Output], [], Port) ->
+ ?line kill_port_and_fail(Port, {too_much_data, [X|Output]});
+match_output([], Expect, _Port) ->
+ Expect;
+match_output(eof, [], _Port) ->
+ [];
+match_output(eof, _Expect, Port) ->
+ ?line kill_port_and_fail(Port, unexpected_end_of_input).
+
+kill_port_and_fail(Port, Reason) ->
+ unlink(Port),
+ exit(Port, die),
+ test_server:fail(Reason).
+
+make_cmd(Cmd) ->
+ case os:type() of
+ {win32, _} -> lists:concat(["cmd /c", Cmd]);
+ {unix, _} -> lists:concat(["sh -c '", Cmd, "'"])
+ end.
+
+%% Verifies a random byte list.
+
+match_byte_list(X0, [Byte|Rest]) ->
+ X = next_random(X0),
+ case (X bsr 26) band 16#ff of
+ Byte -> match_byte_list(X, Rest);
+ _ -> false
+ end;
+match_byte_list(_, []) ->
+ true.
+
+%% Generates a random byte list.
+
+random_byte_list(X0, Count) ->
+ random_byte_list(X0, Count, []).
+
+random_byte_list(X0, Count, Result) when Count > 0->
+ X = next_random(X0),
+ random_byte_list(X, Count-1, [(X bsr 26) band 16#ff|Result]);
+random_byte_list(_X, 0, Result) ->
+ lists:reverse(Result).
+
+%% This RNG is from line 21 on page 102 in Knuth: The Art of Computer Programming,
+%% Volume II, Seminumerical Algorithms.
+
+next_random(X) ->
+ (X*17059465+1) band 16#fffffffff.
+
+atomic(doc) ->
+ ["Test the 'atomic' operations: create/extract/table, on compressed "
+ "and uncompressed archives."
+ "Also test the 'cooked' option."];
+atomic(suite) -> [];
+atomic(Config) when list(Config) ->
+ ?line ok = file:set_cwd(?config(priv_dir, Config)),
+ ?line DataFiles = data_files(),
+ ?line Names = [Name || {Name,_,_} <- DataFiles],
+ io:format("Names: ~p", [Names]),
+
+ %% Create an uncompressed archive. The compressed flag should still be
+ %% allowed when listing contents or extracting.
+
+ ?line Tar1 = "uncompressed.tar",
+ ?line erl_tar:create(Tar1, Names, []),
+ ?line {ok, Names} = erl_tar:table(Tar1, []),
+ ?line {ok, Names} = erl_tar:table(Tar1, [compressed]),
+ ?line {ok, Names} = erl_tar:table(Tar1, [cooked]),
+ ?line {ok, Names} = erl_tar:table(Tar1, [compressed,cooked]),
+
+ %% Create a compressed archive.
+
+ ?line Tar2 = "compressed.tar",
+ ?line erl_tar:create(Tar2, Names, [compressed]),
+ ?line {ok, Names} = erl_tar:table(Tar2, [compressed]),
+ ?line {error, Reason} = erl_tar:table(Tar2, []),
+ ?line {ok, Names} = erl_tar:table(Tar2, [compressed,cooked]),
+ ?line {error, Reason} = erl_tar:table(Tar2, [cooked]),
+ ?line ok = io:format("No compressed option: ~p, ~s",
+ [Reason, erl_tar:format_error(Reason)]),
+
+ %% Same test again, but this time created with 'cooked'
+
+ ?line Tar3 = "uncompressed_cooked.tar",
+ ?line erl_tar:create(Tar3, Names, [cooked]),
+ ?line {ok, Names} = erl_tar:table(Tar3, []),
+ ?line {ok, Names} = erl_tar:table(Tar3, [compressed]),
+ ?line {ok, Names} = erl_tar:table(Tar3, [cooked]),
+ ?line {ok, Names} = erl_tar:table(Tar3, [compressed,cooked]),
+
+ ?line Tar4 = "compressed_cooked.tar",
+ ?line erl_tar:create(Tar4, Names, [compressed,cooked]),
+ ?line {ok, Names} = erl_tar:table(Tar4, [compressed]),
+ ?line {error, Reason} = erl_tar:table(Tar4, []),
+ ?line {ok, Names} = erl_tar:table(Tar4, [compressed,cooked]),
+ ?line {error, Reason} = erl_tar:table(Tar4, [cooked]),
+ ?line ok = io:format("No compressed option: ~p, ~s",
+ [Reason, erl_tar:format_error(Reason)]),
+
+ %% Clean up.
+ ?line delete_files([Tar1,Tar2,Tar3,Tar4|Names]),
+
+ ok.
+
+%% Returns a sequence of characters.
+
+char_seq(N, First) ->
+ char_seq(N, First, []).
+
+char_seq(0, _, Result) ->
+ Result;
+char_seq(N, C, Result) when C < 127 ->
+ char_seq(N-1, C+1, [C|Result]);
+char_seq(N, _, Result) ->
+ char_seq(N, $!, Result).
+
+data_files() ->
+ Files = [{"first_file", 1555, $a},
+ {"small_file", 7, $d},
+ {"big_file", 23875, $e},
+ {"last_file", 7500, $g}],
+ create_files(Files),
+ Files.
+
+create_files([{Name, Size, First}|Rest]) ->
+ ok = file:write_file(Name, char_seq(Size, First)),
+ create_files(Rest);
+create_files([]) ->
+ ok.
+
+long_names(doc) ->
+ ["Test to extract an Unix tar file containing filenames longer than 100 ",
+ "characters and empty directories."];
+long_names(Config) when is_list(Config) ->
+ ?line DataDir = ?config(data_dir, Config),
+ ?line Long = filename:join(DataDir, "long_names.tar"),
+
+ %% Try table/2 and extract/2.
+ ?line case erl_tar:table(Long, [verbose]) of
+ {ok,List} when is_list(List) ->
+ ?line io:format("~p\n", [List])
+ end,
+
+
+ %% To avoid getting too long paths for Windows to handle, extract into
+ %% the current directory (which is the test_server directory). Its path
+ %% is quite a bit shorter than the path to priv_dir.
+ ?line {ok,Cwd} = file:get_cwd(),
+ ?line ok = erl_tar:extract(Long),
+ ?line Base = filename:join([Cwd, "original_software", "written_by",
+ "a_bunch_of_hackers",
+ "spending_all_their_nights",
+ "still", "not_long_enough",
+ "but_soon_it_will_be"]),
+
+ %% Verify that the empty directory was created.
+ ?line EmptyDir = filename:join(Base, "empty_directory"),
+ ?line {ok, #file_info{type=directory}} = file:read_file_info(EmptyDir),
+
+ %% Verify that the files were created.
+ ?line {ok,First} = file:read_file(filename:join(Base, "first_file")),
+ ?line {ok,Second} = file:read_file(filename:join(Base, "second_file")),
+ ?line "Here"++_ = binary_to_list(First),
+ ?line "And"++_ = binary_to_list(Second),
+
+ %% Clean up.
+ ?line delete_files([filename:join(Cwd, "original_software"),EmptyDir]),
+
+ ok.
+
+create_long_names(doc) ->
+ ["Creates a tar file from a deep directory structure (filenames are ",
+ "longer than 100 characters)."];
+create_long_names(Config) when is_list(Config) ->
+ ?line PrivDir = ?config(priv_dir, Config),
+ ?line ok = file:set_cwd(PrivDir),
+ Dirs = [aslfjkshjkhliuf,
+ asdhjfehnbfsky,
+ sahajfskdfhsz,
+ asldfkdlfy4y8rchg,
+ f7nafhjgffagkhsfkhsjk,
+ dfjasldkfjsdkfjashbv],
+
+ ?line DeepDir = make_dirs(Dirs, []),
+ ?line AFile = filename:join(DeepDir, "a_file"),
+ ?line Hello = "hello, world\n",
+ ?line ok = file:write_file(AFile, Hello),
+ ?line TarName = filename:join(PrivDir, "my_tar_with_long_names.tar"),
+ ?line ok = erl_tar:create(TarName, [AFile]),
+
+ %% Print contents.
+ ?line ok = erl_tar:tt(TarName),
+
+ %% Extract and verify.
+ ?line ExtractDir = "extract_dir",
+ ?line ok = file:make_dir(ExtractDir),
+ ?line ok = erl_tar:extract(TarName, [{cwd,ExtractDir}]),
+ ?line {ok, Bin} = file:read_file(filename:join(ExtractDir, AFile)),
+ ?line Hello = binary_to_list(Bin),
+
+ %% Clean up.
+ ?line delete_files([ExtractDir,TarName,hd(Dirs)]),
+
+ ok.
+
+make_dirs([Dir|Rest], []) ->
+ ?line ok = file:make_dir(Dir),
+ ?line make_dirs(Rest, Dir);
+make_dirs([Dir|Rest], Parent) ->
+ ?line Name = filename:join(Parent, Dir),
+ ?line ok = file:make_dir(Name),
+ ?line make_dirs(Rest, Name);
+make_dirs([], Dir) ->
+ Dir.
+
+bad_tar(doc) ->
+ ["Try erl_tar:table/2 and erl_tar:extract/2 on some corrupted tar files."];
+bad_tar(Config) when is_list(Config) ->
+ ?line try_bad("bad_checksum", bad_header, Config),
+ ?line try_bad("bad_octal", bad_header, Config),
+ ?line try_bad("bad_too_short", eof, Config),
+ ?line try_bad("bad_even_shorter", eof, Config),
+ ok.
+
+try_bad(Name0, Reason, Config) ->
+ %% Intentionally no ?line macros here.
+
+ DataDir = ?config(data_dir, Config),
+ PrivDir = ?config(priv_dir, Config),
+ Name = Name0 ++ ".tar",
+ io:format("~nTrying ~s", [Name]),
+ Full = filename:join(DataDir, Name),
+ Opts = [verbose, {cwd, PrivDir}],
+ Expected = {error, Reason},
+ case {erl_tar:table(Full, Opts), erl_tar:extract(Full, Opts)} of
+ {Expected, Expected} ->
+ io:format("Result: ~p", [Expected]),
+ case catch erl_tar:format_error(Reason) of
+ {'EXIT', CrashReason} ->
+ test_server:fail({format_error, crashed, CrashReason});
+ String when list(String) ->
+ io:format("format_error(~p) -> ~s", [Reason, String]);
+ Other ->
+ test_server:fail({format_error, returned, Other})
+ end;
+ {Other1, Other2} ->
+ io:format("table/2 returned ~p", [Other1]),
+ io:format("extract/2 returned ~p", [Other2]),
+ test_server:fail({bad_return_value, Other1, Other2})
+ end.
+
+errors(doc) ->
+ ["Tests that some common errors return correct error codes ",
+ "and that format_error/1 handles them correctly."];
+errors(Config) when is_list(Config) ->
+ ?line PrivDir = ?config(priv_dir, Config),
+
+ %% Give the tar file the same name as a directory.
+ ?line BadTar = filename:join(PrivDir, "bad_tarfile.tar"),
+ ?line ok = file:make_dir(BadTar),
+ ?line try_error(erl_tar, create, [BadTar, []], {BadTar, eisdir}),
+
+ %% Try including non-existent files in the tar file.
+ ?line NonExistent = "non_existent_file",
+ ?line GoodTar = filename:join(PrivDir, "a_good_tarfile.tar"),
+ ?line try_error(erl_tar, create, [GoodTar, [NonExistent]],
+ {NonExistent, enoent}),
+
+ %% Clean up.
+ ?line delete_files([GoodTar,BadTar]),
+
+ ok.
+
+try_error(M, F, A, Error) ->
+ io:format("Trying ~p:~p(~p)", [M, F, A]),
+ case catch apply(M, F, A) of
+ {'EXIT', Reason} ->
+ exit(Reason);
+ ok ->
+ test_server:fail(unexpected_success);
+ {error, Error} ->
+ case catch erl_tar:format_error(Error) of
+ {'EXIT', FReason} ->
+ test_server:fail({format_error, crashed, FReason});
+ String when list(String) ->
+ io:format("format_error(~p) -> ~s", [Error, String]);
+ Other ->
+ test_server:fail({format_error, returned, Other})
+ end;
+ Other ->
+ test_server:fail({expected, {error, Error}, actual, Other})
+ end.
+
+%% remove_prefix(Prefix, List) -> ListWithoutPrefix.
+
+remove_prefix([C|Rest1], [C|Rest2]) ->
+ remove_prefix(Rest1, Rest2);
+remove_prefix(_, Result) ->
+ Result.
+
+extract_from_binary(doc) ->
+ "Test extracting a tar archive from a binary.";
+extract_from_binary(Config) when list(Config) ->
+ ?line DataDir = ?config(data_dir, Config),
+ ?line PrivDir = ?config(priv_dir, Config),
+ ?line Long = filename:join(DataDir, "no_fancy_stuff.tar"),
+ ?line ExtractDir = filename:join(PrivDir, "extract_from_binary"),
+ ?line ok = file:make_dir(ExtractDir),
+
+ %% Read a tar file into a binary and extract from the binary.
+ ?line {ok, Bin} = file:read_file(Long),
+ ?line ok = erl_tar:extract({binary, Bin}, [{cwd,ExtractDir}]),
+
+ %% Verify.
+ Dir = filename:join(ExtractDir, "no_fancy_stuff"),
+ ?line true = filelib:is_dir(Dir),
+ ?line true = filelib:is_file(filename:join(Dir, "a_dir_list")),
+ ?line true = filelib:is_file(filename:join(Dir, "EPLICENCE")),
+
+ %% Clean up.
+ ?line delete_files([ExtractDir]),
+
+ ok.
+
+extract_from_binary_compressed(Config) when is_list(Config) ->
+ %% Test extracting a compressed tar archive from a binary.
+ ?line DataDir = ?config(data_dir, Config),
+ ?line PrivDir = ?config(priv_dir, Config),
+ ?line Name = filename:join(DataDir, "cooked_tar_problem.tar.gz"),
+ ?line ExtractDir = filename:join(PrivDir, "extract_from_binary_compressed"),
+ ?line ok = file:make_dir(ExtractDir),
+ ?line {ok,Bin} = file:read_file(Name),
+
+ %% Try taking contents.
+ ?line {ok,Files} = erl_tar:table({binary,Bin}, [compressed]),
+ ?line io:format("~p\n", [Files]),
+ ?line 19 = length(Files),
+
+ %% Trying extracting from a binary.
+ ?line ok = erl_tar:extract({binary,Bin}, [compressed,{cwd,ExtractDir}]),
+ ?line {ok,List} = file:list_dir(filename:join(ExtractDir, ddll_SUITE_data)),
+ ?line io:format("~p\n", [List]),
+ ?line 19 = length(List),
+
+ %% Clean up while at the same time testing that all file
+ %% were extracted as expected.
+ lists:foreach(fun(N) ->
+ File = filename:join(ExtractDir, N),
+ io:format("Deleting: ~p\n", [File]),
+ ?line ok = file:delete(File)
+ end, Files),
+
+ %% Clean up the rest.
+ ?line delete_files([ExtractDir]),
+
+ ok.
+
+extract_from_open_file(doc) ->
+ "Test extracting a tar archive from an open file.";
+extract_from_open_file(Config) when is_list(Config) ->
+ ?line DataDir = ?config(data_dir, Config),
+ ?line PrivDir = ?config(priv_dir, Config),
+ ?line Long = filename:join(DataDir, "no_fancy_stuff.tar"),
+ ?line ExtractDir = filename:join(PrivDir, "extract_from_open_file"),
+ ?line ok = file:make_dir(ExtractDir),
+
+ ?line {ok, File} = file:open(Long, [read]),
+ ?line ok = erl_tar:extract({file, File}, [{cwd,ExtractDir}]),
+
+ %% Verify.
+ Dir = filename:join(ExtractDir, "no_fancy_stuff"),
+ ?line true = filelib:is_dir(Dir),
+ ?line true = filelib:is_file(filename:join(Dir, "a_dir_list")),
+ ?line true = filelib:is_file(filename:join(Dir, "EPLICENCE")),
+
+ %% Close open file.
+ ?line ok = file:close(File),
+
+ %% Clean up.
+ ?line delete_files([ExtractDir]),
+
+ ok.
+
+symlinks(doc) ->
+ "Test that archives containing symlinks can be created and extracted.";
+symlinks(Config) when is_list(Config) ->
+ ?line PrivDir = ?config(priv_dir, Config),
+ ?line Dir = filename:join(PrivDir, "symlinks"),
+ ?line ok = file:make_dir(Dir),
+ ?line ABadSymlink = filename:join(Dir, "bad_symlink"),
+ ?line PointsTo = "/a/definitely/non_existing/path",
+ ?line Res = case file:make_symlink("/a/definitely/non_existing/path", ABadSymlink) of
+ {error, enotsup} ->
+ {skip, "Symbolic links not supported on this platform"};
+ ok ->
+ symlinks(Dir, "bad_symlink", PointsTo),
+ long_symlink(Dir)
+ end,
+
+ %% Clean up.
+ ?line delete_files([Dir]),
+ Res.
+
+symlinks(Dir, BadSymlink, PointsTo) ->
+ ?line Tar = filename:join(Dir, "symlink.tar"),
+ ?line DerefTar = filename:join(Dir, "dereference.tar"),
+
+ %% Create the archive.
+
+ ?line ok = file:set_cwd(Dir),
+ ?line GoodSymlink = "good_symlink",
+ ?line AFile = "a_good_file",
+ ?line ALine = "A line of text for a file.",
+ ?line ok = file:write_file(AFile, ALine),
+ ?line ok = file:make_symlink(AFile, GoodSymlink),
+ ?line ok = erl_tar:create(Tar, [BadSymlink, GoodSymlink, AFile], [verbose]),
+
+ %% List contents of tar file.
+
+ ?line ok = erl_tar:tt(Tar),
+
+ %% Also create another archive with the dereference flag.
+
+ ?line ok = erl_tar:create(DerefTar, [AFile, GoodSymlink], [dereference, verbose]),
+
+ %% Extract files to a new directory.
+
+ ?line NewDir = filename:join(Dir, "extracted"),
+ ?line ok = file:make_dir(NewDir),
+ ?line ok = erl_tar:extract(Tar, [{cwd, NewDir}, verbose]),
+
+ %% Verify that the files are there.
+
+ ?line ok = file:set_cwd(NewDir),
+ ?line {ok, #file_info{type=symlink}} = file:read_link_info(BadSymlink),
+ ?line {ok, PointsTo} = file:read_link(BadSymlink),
+ ?line {ok, #file_info{type=symlink}} = file:read_link_info(GoodSymlink),
+ ?line {ok, AFile} = file:read_link(GoodSymlink),
+ ?line Expected = list_to_binary(ALine),
+ ?line {ok, Expected} = file:read_file(GoodSymlink),
+
+ %% Extract the "dereferenced archive" to a new directory.
+
+ ?line NewDirDeref = filename:join(Dir, "extracted_deref"),
+ ?line ok = file:make_dir(NewDirDeref),
+ ?line ok = erl_tar:extract(DerefTar, [{cwd, NewDirDeref}, verbose]),
+
+ %% Verify that the files are there.
+
+ ?line ok = file:set_cwd(NewDirDeref),
+ ?line {ok, #file_info{type=regular}} = file:read_link_info(GoodSymlink),
+ ?line {ok, #file_info{type=regular}} = file:read_link_info(AFile),
+ ?line {ok, Expected} = file:read_file(GoodSymlink),
+ ?line {ok, Expected} = file:read_file(AFile),
+
+ ok.
+
+long_symlink(Dir) ->
+ ?line Tar = filename:join(Dir, "long_symlink.tar"),
+ ?line ok = file:set_cwd(Dir),
+
+ ?line AFile = "long_symlink",
+ ?line FarTooLong = "/tmp/aarrghh/this/path/is/far/longer/than/one/hundred/characters/which/is/the/maximum/number/of/characters/allowed",
+ ?line ok = file:make_symlink(FarTooLong, AFile),
+ ?line {error,Error} = erl_tar:create(Tar, [AFile], [verbose]),
+ ?line io:format("Error: ~s\n", [erl_tar:format_error(Error)]),
+ ?line {FarTooLong,symbolic_link_too_long} = Error,
+ ok.
+
+open_add_close(Config) when is_list(Config) ->
+ ?line PrivDir = ?config(priv_dir, Config),
+ ?line ok = file:set_cwd(PrivDir),
+ ?line Dir = filename:join(PrivDir, "open_add_close"),
+ ?line ok = file:make_dir(Dir),
+
+ ?line [{FileOne,_,_},{FileTwo,_,_},{FileThree,_,_}] = oac_files(),
+ ?line ADir = "empty_dir",
+ ?line AnotherDir = "another_dir",
+ ?line SomeContent = filename:join(AnotherDir, "some_content"),
+ ?line ok = file:make_dir(ADir),
+ ?line ok = file:make_dir(AnotherDir),
+ ?line ok = file:make_dir(SomeContent),
+
+ ?line TarOne = filename:join(Dir, "archive1.tar"),
+ ?line {ok,AD} = erl_tar:open(TarOne, [write]),
+ ?line ok = erl_tar:add(AD, FileOne, []),
+ ?line ok = erl_tar:add(AD, FileTwo, "second file", []),
+ ?line ok = erl_tar:add(AD, FileThree, [verbose]),
+ ?line ok = erl_tar:add(AD, ADir, [verbose]),
+ ?line ok = erl_tar:add(AD, AnotherDir, [verbose]),
+ ?line ok = erl_tar:close(AD),
+
+ ?line ok = erl_tar:t(TarOne),
+ ?line ok = erl_tar:tt(TarOne),
+
+ ?line {ok,[FileOne,"second file",FileThree,ADir,SomeContent]} = erl_tar:table(TarOne),
+
+ ?line delete_files(["oac_file","oac_small","oac_big",Dir,AnotherDir,ADir]),
+
+ ok.
+
+oac_files() ->
+ Files = [{"oac_file", 1459, $x},
+ {"oac_small", 99, $w},
+ {"oac_big", 33896, $A}],
+ create_files(Files),
+ Files.
+
+cooked_compressed(Config) when is_list(Config) ->
+ %% Test that a compressed archive can be read in cooked mode.
+ ?line DataDir = ?config(data_dir, Config),
+ ?line PrivDir = ?config(priv_dir, Config),
+ ?line Name = filename:join(DataDir, "cooked_tar_problem.tar.gz"),
+
+ %% Try table/2 and extract/2.
+ ?line {ok,List} = erl_tar:table(Name, [cooked,compressed]),
+ ?line io:format("~p\n", [List]),
+ ?line 19 = length(List),
+ ?line ok = erl_tar:extract(Name, [cooked,compressed,{cwd,PrivDir}]),
+
+ %% Clean up while at the same time testing that all file
+ %% were extracted as expected.
+ lists:foreach(fun(N) ->
+ File = filename:join(PrivDir, N),
+ io:format("Deleting: ~p\n", [File]),
+ ?line ok = file:delete(File)
+ end, List),
+
+ %% Clean up.
+ ?line delete_files([filename:join(PrivDir, ddll_SUITE_data)]),
+ ok.
+
+memory(doc) ->
+ ["Test that an archive can be created directly from binaries and "
+ "that an archive can be extracted into binaries."];
+memory(Config) when is_list(Config) ->
+ ?line DataDir = ?config(data_dir, Config),
+
+ ?line FileBins = [{"bar/fum", <<"BARFUM">>},{"foo", <<"FOO">>}],
+ ?line Name1 = filename:join(DataDir, "memory.tar"),
+ ?line ok = erl_tar:create(Name1, FileBins, [write,verbose]),
+ ?line {ok,Extracted1} = erl_tar:extract(Name1, [memory,verbose]),
+ ?line FileBins1 = lists:sort(Extracted1),
+
+ ?line io:format("FileBins: ~p\n", [FileBins]),
+ ?line io:format("FileBins1: ~p\n", [FileBins1]),
+ ?line FileBins = FileBins1,
+
+ ?line Name2 = filename:join(DataDir, "memory2.tar"),
+ ?line {ok,Fd} = erl_tar:open(Name2, [write]),
+ ?line [ok,ok] = [erl_tar:add(Fd, B, N, [write,verbose]) || {N,B} <- FileBins],
+ ?line ok = erl_tar:close(Fd),
+ ?line {ok,Extracted2} = erl_tar:extract(Name2, [memory,verbose]),
+ ?line FileBins2 = lists:sort(Extracted2),
+ ?line io:format("FileBins2: ~p\n", [FileBins2]),
+ ?line FileBins = FileBins2,
+
+ %% Clean up.
+ ?line ok = delete_files([Name1,Name2]),
+ ok.
+
+%% Delete the given list of files.
+delete_files([]) -> ok;
+delete_files([Item|Rest]) ->
+ case file:delete(Item) of
+ ok ->
+ delete_files(Rest);
+ {error,eperm} ->
+ file:change_mode(Item, 8#777),
+ delete_files(filelib:wildcard(filename:join(Item, "*"))),
+ file:del_dir(Item),
+ ok;
+ {error,eacces} ->
+ %% We'll see about that!
+ file:change_mode(Item, 8#777),
+ case file:delete(Item) of
+ ok -> ok;
+ {error,_} ->
+ erlang:yield(),
+ file:change_mode(Item, 8#777),
+ file:delete(Item),
+ ok
+ end;
+ {error,_} -> ok
+ end,
+ delete_files(Rest).
+
diff --git a/lib/stdlib/test/tar_SUITE_data/bad_checksum.tar b/lib/stdlib/test/tar_SUITE_data/bad_checksum.tar
new file mode 100644
index 0000000000..05a60c5ca9
--- /dev/null
+++ b/lib/stdlib/test/tar_SUITE_data/bad_checksum.tar
Binary files differ
diff --git a/lib/stdlib/test/tar_SUITE_data/bad_even_shorter.tar b/lib/stdlib/test/tar_SUITE_data/bad_even_shorter.tar
new file mode 100644
index 0000000000..142935c49d
--- /dev/null
+++ b/lib/stdlib/test/tar_SUITE_data/bad_even_shorter.tar
Binary files differ
diff --git a/lib/stdlib/test/tar_SUITE_data/bad_octal.tar b/lib/stdlib/test/tar_SUITE_data/bad_octal.tar
new file mode 100644
index 0000000000..85e63e3ea2
--- /dev/null
+++ b/lib/stdlib/test/tar_SUITE_data/bad_octal.tar
Binary files differ
diff --git a/lib/stdlib/test/tar_SUITE_data/bad_too_short.tar b/lib/stdlib/test/tar_SUITE_data/bad_too_short.tar
new file mode 100644
index 0000000000..052b8b0e85
--- /dev/null
+++ b/lib/stdlib/test/tar_SUITE_data/bad_too_short.tar
Binary files differ
diff --git a/lib/stdlib/test/tar_SUITE_data/cooked_tar_problem.tar.gz b/lib/stdlib/test/tar_SUITE_data/cooked_tar_problem.tar.gz
new file mode 100644
index 0000000000..92b66bc6d3
--- /dev/null
+++ b/lib/stdlib/test/tar_SUITE_data/cooked_tar_problem.tar.gz
Binary files differ
diff --git a/lib/stdlib/test/tar_SUITE_data/long_names.tar b/lib/stdlib/test/tar_SUITE_data/long_names.tar
new file mode 100644
index 0000000000..431ea982c8
--- /dev/null
+++ b/lib/stdlib/test/tar_SUITE_data/long_names.tar
Binary files differ
diff --git a/lib/stdlib/test/tar_SUITE_data/make_tar b/lib/stdlib/test/tar_SUITE_data/make_tar
new file mode 100755
index 0000000000..733a7ec2df
--- /dev/null
+++ b/lib/stdlib/test/tar_SUITE_data/make_tar
@@ -0,0 +1,21 @@
+#! /bin/sh
+
+#
+# This script creates the test tar file in this directory.
+# Not needed for running any test case, but useful if you need
+# to update the test cases and create a new tar file.
+#
+
+first=original_software/written_by/a_bunch_of_hackers/spending_all_their_nights
+second=still/not_long_enough/but_soon_it_will_be
+base=$first/$second
+
+mkdir -p $base
+
+mkdir $base/empty_directory
+
+echo "Here is the first file." > $base/first_file
+echo "And here is the second file." > $base/second_file
+
+tar cf long_names.tar original_software
+rm -rf original_software
diff --git a/lib/stdlib/test/tar_SUITE_data/no_fancy_stuff.tar b/lib/stdlib/test/tar_SUITE_data/no_fancy_stuff.tar
new file mode 100644
index 0000000000..a45b7e0068
--- /dev/null
+++ b/lib/stdlib/test/tar_SUITE_data/no_fancy_stuff.tar
Binary files differ
diff --git a/lib/stdlib/test/timer_SUITE.erl b/lib/stdlib/test/timer_SUITE.erl
new file mode 100644
index 0000000000..86d8612b56
--- /dev/null
+++ b/lib/stdlib/test/timer_SUITE.erl
@@ -0,0 +1,391 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(timer_SUITE).
+
+-export([all/1]).
+-export([do_big_test/1]).
+-export([big_test/1, collect/3, i_t/3, a_t/2]).
+-export([do_nrev/1, internal_watchdog/2]).
+
+-include("test_server.hrl").
+
+%% Test suite for timer module. This is a really nasty test it runs a
+%% lot of timeouts and then checks in the end if any of them was
+%% trigggered too early or if any late timeouts was much too
+%% late. What should be added is more testing of the interface
+%% functions I guess. But I don't have time for that now.
+%%
+%% Expect it to run for at least 5-10 minutes!
+%% Except for VxWorks of course, where a couple of hours is more apropriate...
+
+
+%% The main test case in this module is "do_big_test", which
+%% orders a large number of timeouts and measures how
+%% exact the timeouts arrives. To simulate a system under load there is
+%% also a number of other concurrent processes running "nrev" at the same
+%% time. The result is analyzed afterwards by trying to check if the
+%% measured values are reasonable. It is hard to determine what is
+%% reasonable on different machines therefore the test can sometimes
+%% fail, even though the timer module is ok. I have checked against
+%% previous versions of the timer module (which contained bugs) and it
+%% seems it fails every time when running the buggy timer modules.
+%%
+%% The solution is to rewrite the test suite. Possible strategies for a
+%% rewrite: smarter math on the measuring data, test cases with varying
+%% amount of load. The test suite should also include tests that test the
+%% interface of the timer module.
+
+all(suite) -> [do_big_test].
+
+%% ------------------------------------------------------- %%
+
+do_big_test(TConfig) when is_list(TConfig) ->
+ Dog = ?t:timetrap(?t:minutes(20)),
+ Save = process_flag(trap_exit, true),
+ Result = case os:type() of
+ vxworks ->
+ big_test(10);
+ _ ->
+ big_test(200)
+ end,
+ process_flag(trap_exit, Save),
+ ?t:timetrap_cancel(Dog),
+ report_result(Result).
+
+report_result(ok) -> ok;
+report_result(Error) -> ?line test_server:fail(Error).
+
+%% ------------------------------------------------------- %%
+
+big_test(N) ->
+ C = start_collect(),
+ system_time(), system_time(), system_time(),
+ A1 = element(2, erlang:now()),
+ A2 = A1 * 3,
+ A3 = element(3, erlang:now()),
+ random:seed(A1, A2, A3),
+ random:uniform(100),random:uniform(100),random:uniform(100),
+
+ big_loop(C, N, []),
+
+ %%C ! print_report,
+ C ! {self(), get_report},
+ Report = receive
+ {report, R} ->
+ R
+ end,
+ C ! stop,
+ receive
+ {'EXIT', C, normal} ->
+ ok
+ end,
+ print_report(Report),
+ Result = analyze_report(Report),
+ %%io:format("big_test is done: ~w~n", [Result]),
+ Result.
+
+big_loop(_C, 0, []) ->
+ %%io:format("All processes are done!~n", []),
+ ok;
+big_loop(C, 0, Pids) ->
+ %%ok = io:format("Loop done, ~w processes remaining~n", [length(Pids)]),
+ %% wait for remaining processes
+ receive
+ {'EXIT', Pid, done} ->
+ big_loop(C, 0, lists:delete(Pid, Pids));
+ {'EXIT', Pid, Error} ->
+ ?line ok = io:format("XXX Pid ~w died with reason ~p~n",
+ [Pid, Error]),
+ big_loop(C, 0, lists:delete(Pid, Pids))
+ end;
+big_loop(C, N, Pids) ->
+ %% First reap any processes that are done.
+ receive
+ {'EXIT', Pid, done} ->
+ big_loop(C, N, lists:delete(Pid, Pids));
+ {'EXIT', Pid, Error} ->
+ ?line ok =io:format("XXX Internal error: Pid ~w died, reason ~p~n",
+ [Pid, Error]),
+ big_loop(C, N, lists:delete(Pid, Pids))
+ after 0 ->
+
+ %% maybe start an interval timer test
+ Pids1 = maybe_start_i_test(Pids, C, random:uniform(4)),
+
+ %% start 1-4 "after" tests
+ Pids2 = start_after_test(Pids1, C, random:uniform(4)),
+ %%Pids2=Pids1,
+
+ %% wait a little while
+ timer:sleep(random:uniform(200)*10),
+
+ %% spawn zero, one or two nrev to get some load ;-/
+ Pids3 = start_nrev(Pids2, random:uniform(100)),
+
+ big_loop(C, N-1, Pids3)
+ end.
+
+
+start_nrev(Pids, N) when N < 25 ->
+ Pids;
+start_nrev(Pids, N) when N < 75 ->
+ [spawn_link(timer_SUITE, do_nrev, [1])|Pids];
+start_nrev(Pids, _N) ->
+ NrevPid1 = spawn_link(timer_SUITE, do_nrev, [random:uniform(1000)*10]),
+ NrevPid2 = spawn_link(timer_SUITE, do_nrev, [1]),
+ [NrevPid1,NrevPid2|Pids].
+
+
+start_after_test(Pids, C, 1) ->
+ TO1 = random:uniform(100)*100,
+ [s_a_t(C, TO1)|Pids];
+start_after_test(Pids, C, 2) ->
+ TO1 = random:uniform(100)*100,
+ TO2 = TO1 div random:uniform(3) + 200,
+ [s_a_t(C, TO1),s_a_t(C, TO2)|Pids];
+start_after_test(Pids, C, N) ->
+ TO1 = random:uniform(100)*100,
+ start_after_test([s_a_t(C, TO1)|Pids], C, N-1).
+
+s_a_t(C, TimeOut) ->
+ spawn_link(timer_SUITE, a_t, [C, TimeOut]).
+
+a_t(C, TimeOut) ->
+ start_watchdog(self(), TimeOut),
+ Start = system_time(),
+ timer:send_after(TimeOut, self(), now),
+ receive
+ now ->
+ Stop = system_time(),
+ report(C, Start,Stop,TimeOut),
+ exit(done);
+ watchdog ->
+ Stop = system_time(),
+ report(C, Start,Stop,TimeOut),
+ ?line ok = io:format("Internal watchdog timeout (a), not good!!~n",
+ []),
+ exit(done)
+ end.
+
+
+maybe_start_i_test(Pids, C, 1) ->
+ %% ok do it
+ TOI = random:uniform(100)*100,
+ CountI = random:uniform(10) + 3, % at least 4 times
+ [spawn_link(timer_SUITE, i_t, [C, TOI, CountI])|Pids];
+maybe_start_i_test(Pids, _C, _) ->
+ Pids.
+
+i_t(C, TimeOut, Times) ->
+ start_watchdog(self(), TimeOut*Times),
+ Start = system_time(),
+ {ok, Ref} = timer:send_interval(TimeOut, interval),
+ i_wait(Start, Start, 1, TimeOut, Times, Ref, C).
+
+i_wait(Start, Prev, Times, TimeOut, Times, Ref, C) ->
+ receive
+ interval ->
+ Now = system_time(),
+ report_interval(C, {final,Times}, Start, Prev, Now, TimeOut),
+ timer:cancel(Ref),
+ exit(done);
+ watchdog ->
+ Now = system_time(),
+ report_interval(C, {final,Times}, Start, Prev, Now, TimeOut),
+ timer:cancel(Ref),
+ ?line ok = io:format("Internal watchdog timeout (i), not good!!~n",
+ []),
+ exit(done)
+ end;
+i_wait(Start, Prev, Count, TimeOut, Times, Ref, C) ->
+ receive
+ interval ->
+ Now = system_time(),
+ report_interval(C, Count, Start, Prev, Now, TimeOut),
+ i_wait(Start, Now, Count+1, TimeOut, Times, Ref, C);
+ watchdog ->
+ Now = system_time(),
+ report_interval(C, {final,Count}, Start, Prev, Now, TimeOut),
+ ?line ok = io:format("Internal watchdog timeout (j), not good!!~n",
+ []),
+ exit(done)
+ end.
+
+report(C, Start, Stop, Time) ->
+ C ! {a_sample, Start, Stop, Time}.
+report_interval(C, Count, Start, Prev, Now, TimeOut) ->
+ C ! {i_sample, Count, Start, Prev, Now, TimeOut}.
+
+%% ------------------------------------------------------- %%
+
+%% internal watchdog
+start_watchdog(Pid, TimeOut) ->
+ spawn_link(timer_SUITE, internal_watchdog, [Pid, 3*TimeOut+1000]).
+
+internal_watchdog(Pid, TimeOut) ->
+ receive
+ after TimeOut ->
+ Pid ! watchdog,
+ exit(normal)
+ end.
+
+%% ------------------------------------------------------- %%
+
+-record(stat, {n=0,max=0,min=min,avg=0}).
+
+start_collect() ->
+ spawn_link(timer_SUITE, collect, [0,{0,new_update(),new_update()},[]]).
+
+collect(N, {E,A,B}, I) ->
+ receive
+ {a_sample, Start, Stop, Time} when Stop - Start > Time ->
+ collect(N+1, {E,update(Stop-Start-Time,A),B}, I);
+ {a_sample, Start, Stop, Time} when Stop - Start < Time ->
+ collect(N+1, {E,A,update(Time-Stop+Start,B)}, I);
+ {a_sample, _Start, _Stop, _Time} ->
+ collect(N+1, {E+1,A,B}, I);
+ {i_sample, {final,Count}, Start, Prev, Now, TimeOut} ->
+ IntervDiff = Now - Prev - TimeOut,
+ Drift = Now - (Count*TimeOut) - Start,
+ collect(N, {E,A,B}, [{{final,Count},IntervDiff,Drift}|I]);
+ {i_sample, Count, Start, Prev, Now, TimeOut} ->
+ IntervDiff = Now - Prev - TimeOut,
+ Drift = Now - (Count*TimeOut) - Start,
+ collect(N, {E,A,B}, [{Count,IntervDiff,Drift}|I]);
+ print_report ->
+ print_report({E,A,B,I}),
+ collect(N,{E,A,B}, I);
+ {Pid, get_report} when pid(Pid) ->
+ Pid ! {report, {E, A, B, I}},
+ collect(N,{E,A,B}, I);
+ reset ->
+ collect(0, {0,new_update(),new_update()}, []);
+ stop ->
+ exit(normal);
+ _Other ->
+ collect(N, {E,A,B}, I)
+ end.
+
+new_update() -> #stat{}.
+update(New, Stat) when New > Stat#stat.max ->
+ Stat#stat{n=Stat#stat.n + 1, max=New, avg=(New+Stat#stat.avg) div 2};
+update(New, Stat) when New < Stat#stat.min ->
+ Stat#stat{n=Stat#stat.n + 1, min=New, avg=(New+Stat#stat.avg) div 2};
+update(New, Stat) ->
+ Stat#stat{n=Stat#stat.n + 1, avg=(New+Stat#stat.avg) div 2}.
+
+%update(New, {N,Max,Min,Avg}) when New>Max ->
+% {N+1,New,Min,(New+Avg) div 2};
+%update(New, {N,Max,Min,Avg}) when New<Min ->
+% {N+1,Max,New,(New+Avg) div 2};
+%update(New, {N,Max,Min,Avg}) ->
+% {N+1,Max,Min,(New+Avg) div 2}.
+
+print_report({E,LateS,EarlyS,I}) ->
+ Early = EarlyS#stat.n, Late = LateS#stat.n,
+ Total = E + Early + Late,
+ io:format("~nOn total of ~w timeouts, there were ~w exact, ~w "
+ "late and ~w early.~n", [Total, E, Late, Early]),
+ io:format("Late stats (N,Max,Min,Avg): ~w~nEarly stats: ~w~n",
+ [LateS, EarlyS]),
+ IntervS = collect_interval_final_stats(I),
+ io:format("Interval stats (Max,Min,Avg): ~w~n", [IntervS]),
+ ok.
+
+collect_interval_final_stats(I) ->
+ collect_interval_final_stats(I, 0, min, 0).
+collect_interval_final_stats([], Max, Min, Avg) ->
+ {Max, Min, Avg};
+collect_interval_final_stats([{{final,_Count},_,Dev}|T], Max, Min, Avg) ->
+ NMax = if Dev>Max -> Dev; true -> Max end,
+ NMin = if Dev<Min -> Dev; true -> Min end,
+ collect_interval_final_stats(T, NMax, NMin, (Dev+Avg) div 2);
+collect_interval_final_stats([_|T], Max, Min, Avg) ->
+ collect_interval_final_stats(T, Max, Min, Avg).
+
+analyze_report({E,LateS,EarlyS,I}) ->
+ Early = EarlyS#stat.n, Late = LateS#stat.n,
+ IntervS = collect_interval_final_stats(I),
+ Res1 = min_and_early_check(E, Early, Late, element(2,IntervS)),
+ Res2 = abnormal_max_check(LateS#stat.max, element(1,IntervS)),
+ res_combine(ok, [Res1, Res2]).
+
+-define(ok_i_min, -100).
+-define(ok_max, 8000).
+-define(ok_i_max, 4000).
+
+%% ok as long as Early == 0 and IntervMin >= ok_interv_min
+min_and_early_check(_Exact, 0, _Late, IntervMin) when IntervMin >= ?ok_i_min ->
+ ok;
+min_and_early_check(_Exact, Early, _Late, IntervMin) when IntervMin >= ?ok_i_min ->
+ {error, {early_timeouts, Early}};
+min_and_early_check(_Exact, 0, _Late, _IntervMin) ->
+ {error, early_interval_timeout};
+min_and_early_check(_Exact, Early, _Late, _IntervMin) ->
+ {error, [{early_timeouts, Early},{error, early_interval_timeout}]}.
+
+abnormal_max_check(LateMax, IntMax) when LateMax < ?ok_max,
+ IntMax < ?ok_i_max ->
+ ok;
+abnormal_max_check(LateMax, IntMax) when IntMax < ?ok_i_max ->
+ {error, {big_late_max, LateMax}};
+abnormal_max_check(LateMax, IntMax) when LateMax < ?ok_max ->
+ {error, {big_interval_max, IntMax}};
+abnormal_max_check(LateMax, IntMax) ->
+ {error, [{big_late_max, LateMax},{big_interval_max, IntMax}]}.
+
+res_combine(Res, []) ->
+ Res;
+res_combine(Res, [ok|T]) ->
+ res_combine(Res, T);
+res_combine(ok, [{error,What}|T]) ->
+ res_combine({error,What}, T);
+res_combine({error,Es}, [{error,E}|T]) ->
+ res_combine({error,lists:flatten([E,Es])}, T).
+
+
+system_time() ->
+ %%element(1, statistics(wall_clock)).
+ {M,S,U} = erlang:now(),
+ 1000000000 * M + 1000 * S + (U div 1000).
+
+%% ------------------------------------------------------- %%
+
+do_nrev(Sleep) ->
+ timer:sleep(Sleep),
+ test(1000,"abcdefghijklmnopqrstuvxyz1234"),
+ exit(done).
+
+test(0,_) ->
+ true;
+test(N,L) ->
+ nrev(L),
+ test(N - 1, L).
+
+nrev([]) ->
+ [];
+nrev([H|T]) ->
+ append(nrev(T), [H]).
+
+append([H|T],Z) ->
+ [H|append(T,Z)];
+append([],X) ->
+ X.
+
+%% ------------------------------------------------------- %%
diff --git a/lib/stdlib/test/timer_simple_SUITE.erl b/lib/stdlib/test/timer_simple_SUITE.erl
new file mode 100644
index 0000000000..021a22c61b
--- /dev/null
+++ b/lib/stdlib/test/timer_simple_SUITE.erl
@@ -0,0 +1,551 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%% Purpose : Test the timer module a simpler/faster test than timer_SUITE
+
+-module(timer_simple_SUITE).
+
+%% external
+-export([all/1,
+ init_per_testcase/2,
+ apply_after/1,
+ send_after1/1,
+ send_after2/1,
+ send_after3/1,
+ exit_after1/1,
+ exit_after2/1,
+ kill_after1/1,
+ kill_after2/1,
+ apply_interval/1,
+ send_interval1/1,
+ send_interval2/1,
+ send_interval3/1,
+ send_interval4/1,
+ cancel1/1,
+ cancel2/1,
+ tc/1,
+ unique_refs/1,
+ timer_perf/1]).
+
+%% internal
+-export([forever/0,
+ do_nrev/2,
+ send/2,
+ timer/4,
+ timer/5]).
+
+-include("test_server.hrl").
+
+-define(MAXREF, (1 bsl 18)).
+-define(REFMARG, 30).
+
+all(doc) -> "Test of the timer module.";
+all(suite) ->
+ [apply_after,
+ send_after1,
+ send_after2,
+ send_after3,
+ exit_after1,
+ exit_after2,
+ kill_after1,
+ kill_after2,
+ apply_interval,
+ send_interval1,
+ send_interval2,
+ send_interval3,
+ send_interval4,
+ cancel1,
+ cancel2,
+ tc,
+ unique_refs,
+ timer_perf].
+
+init_per_testcase(_, Config) when is_list(Config) ->
+ timer:start(),
+ Config.
+
+%% Testing timer interface!!
+
+apply_after(doc) -> "Test of apply_after, with sending of message.";
+apply_after(suite) -> [];
+apply_after(Config) when is_list(Config) ->
+ ?line timer:apply_after(500, ?MODULE, send, [self(), ok_apply]),
+ ?line ok = get_mess(1000, ok_apply).
+
+send_after1(doc) -> "Test of send_after with time = 0.";
+send_after1(suite) -> [];
+send_after1(Config) when is_list(Config) ->
+ ?line timer:send_after(0, ok_send1),
+ ?line ok = get_mess(1000, ok_send1).
+
+send_after2(doc) -> "Test of send_after with time = 500.";
+send_after2(suite) -> [];
+send_after2(Config) when is_list(Config) ->
+ ?line timer:send_after(500, self(), ok_send2),
+ ?line ok = get_mess(2000, ok_send2).
+
+send_after3(doc) -> "Test of send_after with time = 500, with receiver "
+ "a registered process. [OTP-2735]";
+send_after3(suite) -> [];
+send_after3(Config) when is_list(Config) ->
+ ?line Name = list_to_atom(pid_to_list(self())),
+ ?line register(Name, self()),
+ ?line timer:send_after(500, Name, ok_send3),
+ ?line ok = get_mess(2000, ok_send3),
+ ?line unregister(Name).
+
+exit_after1(doc) -> "Test of exit_after with time = 1000.";
+exit_after1(suite) -> [];
+exit_after1(Config) when is_list(Config) ->
+ ?line process_flag(trap_exit, true),
+ ?line Pid = spawn_link(?MODULE, forever, []),
+ ?line timer:exit_after(1000, Pid, exit_test1),
+ ?line ok = get_mess(5000, {'EXIT', Pid, exit_test1}).
+
+exit_after2(doc) -> "Test of exit_after with time = 1000. The process to "
+ "exit is the name of a registered process. "
+ "[OTP-2735]";
+exit_after2(suite) -> [];
+exit_after2(Config) when is_list(Config) ->
+ ?line process_flag(trap_exit, true),
+ ?line Pid = spawn_link(?MODULE, forever, []),
+ ?line Name = list_to_atom(pid_to_list(Pid)),
+ ?line register(Name, Pid),
+ ?line timer:exit_after(1000, Name, exit_test2),
+ ?line ok = get_mess(2000, {'EXIT', Pid, exit_test2}).
+
+kill_after1(doc) -> "Test of kill_after with time = 1000.";
+kill_after1(suite) -> [];
+kill_after1(Config) when is_list(Config) ->
+ ?line process_flag(trap_exit, true),
+ ?line Pid = spawn_link(?MODULE, forever, []),
+ ?line timer:kill_after(1000, Pid),
+ ?line ok = get_mess(2000, {'EXIT', Pid, killed}).
+
+kill_after2(doc) -> "Test of kill_after with time = 1000. The process to "
+ "exit is the name of a registered process. "
+ "[OTP-2735]";
+kill_after2(suite) -> [];
+kill_after2(Config) when is_list(Config) ->
+ ?line process_flag(trap_exit, true),
+ ?line Pid = spawn_link(?MODULE, forever, []),
+ ?line Name = list_to_atom(pid_to_list(Pid)),
+ ?line register(Name, Pid),
+ ?line timer:kill_after(1000, Name),
+ ?line ok = get_mess(2000, {'EXIT', Pid, killed}).
+
+apply_interval(doc) -> "Test of apply_interval by sending messages. Receive "
+ "3 messages, cancel the timer, and check that we do "
+ "not get any more messages.";
+apply_interval(suite) -> [];
+apply_interval(Config) when is_list(Config) ->
+ ?line {ok, Ref} = timer:apply_interval(1000, ?MODULE, send,
+ [self(), apply_int]),
+ ?line ok = get_mess(1500, apply_int, 3),
+ ?line timer:cancel(Ref),
+ ?line nor = get_mess(1000, apply_int).
+
+send_interval1(doc) -> "Test of send_interval/2. Receive 5 messages, cancel "
+ "the timer, and check that we do not get any more "
+ "messages.";
+send_interval1(suite) -> [];
+send_interval1(Config) when is_list(Config) ->
+ {ok, Ref} = timer:send_interval(1000, send_int),
+ ?line ok = get_mess(1500, send_int, 5),
+ timer:cancel(Ref),
+ ?line nor = get_mess(1000, send_int). % We should receive only five
+
+send_interval2(doc) -> "Test of send_interval/3. Receive 2 messages, cancel "
+ "the timer, and check that we do not get any more "
+ "messages.";
+send_interval2(suite) -> [];
+send_interval2(Config) when is_list(Config) ->
+ {ok, Ref} = timer:send_interval(1000, self(), send_int2),
+ ?line ok = get_mess(1500, send_int2, 2),
+ timer:cancel(Ref),
+ ?line nor = get_mess(1000, send_int2). % We should receive only two
+
+send_interval3(doc) -> "Test of send_interval/3. Receive 2 messages, cancel "
+ "the timer, and check that we do not get any more "
+ "messages. The receiver is the name of a registered "
+ "process. [OTP-2735]";
+send_interval3(suite) -> [];
+send_interval3(Config) when is_list(Config) ->
+ ?line process_flag(trap_exit, true),
+ ?line Name = list_to_atom(pid_to_list(self())),
+ ?line register(Name, self()),
+ ?line {ok, Ref} = timer:send_interval(1000, Name, send_int3),
+ ?line ok = get_mess(1500, send_int3, 2),
+ timer:cancel(Ref),
+ ?line nor = get_mess(1000, send_int3), % We should receive only two
+ ?line unregister(Name).
+
+send_interval4(doc) -> "Test that send interval stops sending msg when the "
+ "receiving process terminates.";
+send_interval4(suite) -> [];
+send_interval4(Config) when is_list(Config) ->
+ ?line timer:send_interval(500, one_time_only),
+ receive
+ one_time_only -> ok
+ end,
+ ?line timer_server ! {'EXIT', self(), normal}, % Should remove the timer
+ ?line timer:send_after(600, send_intv_ok),
+ ?line send_intv_ok = receive
+ Msg -> Msg
+ end.
+
+cancel1(doc) -> "Test that we can cancel a timer.";
+cancel1(suite) -> [];
+cancel1(Config) when is_list(Config) ->
+ ?line {ok, Ref} = timer:send_after(1000, this_should_be_canceled),
+ ?line timer:cancel(Ref),
+ ?line nor = get_mess(2000, this_should_be_canceled). % We should rec 0 msgs
+
+cancel2(doc) -> "Test cancel/1 with bad argument.";
+cancel2(suite) -> [];
+cancel2(Config) when is_list(Config) ->
+ ?line {error, badarg} = timer:cancel(no_reference).
+
+tc(doc) -> "Test sleep/1 and tc/3.";
+tc(suite) -> [];
+tc(Config) when is_list(Config) ->
+ % This should both sleep and tc
+ ?line {Res, ok} = timer:tc(timer, sleep, [500]),
+ ?line ok = if
+ Res < 500*1000 -> {too_early, Res}; % Too early
+ Res > 800*1000 -> {too_late, Res}; % Too much time
+ true -> ok
+ end,
+
+ ?line Sec = timer:seconds(4),
+ ?line Min = timer:minutes(4),
+ ?line Hour = timer:hours(4),
+ ?line MyRes = 4*1000 + 4*60*1000 + 4*60*60*1000,
+ ?line if MyRes == Sec + Min + Hour -> ok end,
+ ?line TimerRes = timer:hms(4,4,4),
+ ?line if MyRes == TimerRes -> ok end,
+ ok.
+
+unique_refs(doc) ->
+ "Tests that cancellations of one-shot timers do not accidentally "
+ "cancel interval timers [OTP-2771].";
+unique_refs(suite) ->
+ [];
+unique_refs(Config) when is_list(Config) ->
+ ?line ITimers = repeat_send_interval(10), % 10 interval timers
+ ?line eat_refs(?MAXREF - ?REFMARG),
+ ?line set_and_cancel_one_shots(?REFMARG),
+ ?line NumLeft = num_timers(),
+ ?line io:format("~w timers left, should be 10\n", [NumLeft]),
+ ?line cancel(ITimers),
+ ?line receive_nisse(),
+ ?line 10 = NumLeft.
+
+
+repeat_send_interval(0) ->
+ [];
+repeat_send_interval(M) ->
+ ?line {ok, Ref} = timer:send_interval(6000,self(), nisse),
+ ?line [Ref| repeat_send_interval(M - 1)].
+
+eat_refs(0) ->
+ 0;
+eat_refs(N) ->
+ _ = make_ref(),
+ eat_refs(N-1).
+
+set_and_cancel_one_shots(0) ->
+ 0;
+set_and_cancel_one_shots(N) ->
+ {ok, Ref} = timer:send_after(7000, self(), kalle),
+ %% Cancel twice
+ timer:cancel(Ref),
+ timer:cancel(Ref),
+ set_and_cancel_one_shots(N-1).
+
+cancel([T| Ts]) ->
+ ?line timer:cancel(T),
+ ?line cancel(Ts);
+cancel([]) ->
+ ok.
+
+num_timers() ->
+ {{_, TotalTimers},{_, _IntervalTimers}} = timer:get_status(),
+ TotalTimers.
+
+receive_nisse() ->
+ receive
+ nisse ->
+ receive_nisse()
+ after 0 ->
+ ok
+ end.
+
+
+get_mess(Time, Mess) -> get_mess(Time, Mess, 1).
+get_mess(_, _, 0) -> ok; % Received
+get_mess(Time, Mess, N) ->
+ receive
+ Mess -> get_mess(Time, Mess, N-1)
+ after Time
+ -> nor % Not Received
+ end.
+
+forever() ->
+ timer:sleep(1000),
+ forever().
+
+
+%
+% Testing for performance (on different implementations) of timers
+%
+
+timer_perf(suite) -> [];
+timer_perf(Config) when is_list(Config) ->
+ Dog = ?t:timetrap(?t:minutes(10)),
+ Res = performance(timer),
+ ?t:timetrap_cancel(Dog),
+ Res.
+
+performance(Mod) ->
+ process_flag(trap_exit, true),
+ {Y,Mo,D} = date(),
+ {H,M,S} = time(),
+ io:format("Testing module '~p' Date: ~w/~w/~w ~w:~w:~w~n",
+ [Mod,Y,Mo,D,H,M,S]),
+ Result = big_test(Mod),
+ report_result(Result).
+
+big_test(M) ->
+ Load_Pids = start_nrev(20, M), % Increase if more load wanted :)
+
+ apply(M, sleep, [9000]),
+ LPids = spawn_timers(5, M, 10000, 5),
+
+ apply(M, sleep, [4000]),
+ MPids = spawn_timers(10, M, 1000, 6),
+
+ apply(M, sleep, [3500]),
+ SPids = spawn_timers(15, M, 100, 3),
+
+ Res = wait(SPids ++ MPids ++ LPids, [], 0, M),
+
+ lists:foreach(fun(Pid) -> exit(Pid, kill) end, Load_Pids),
+ Res.
+
+wait([], Res, N, _) ->
+ {Res, N};
+wait(Pids, ResList, N, M) ->
+ receive
+ {Pid, ok, Res, T} ->
+ wait(lists:delete(Pid, Pids), [{T, Res} | ResList], N, M);
+ {Pid, Error}->
+ ?line test_server:fail(Error),
+ wait(lists:delete(Pid, Pids), ResList, N+1, M);
+ {'EXIT', Pid, normal} ->
+ wait(lists:delete(Pid, Pids), ResList, N, M);
+ {'EXIT', Pid, Reason} ->
+ ?line test_server:fail({Pid,Reason})
+ end.
+
+spawn_timers(0, _, _, _) ->
+ [];
+spawn_timers(N, M, T, NumIter) ->
+ apply(M, sleep, [120*N]),
+ Pid1 = spawn_link(?MODULE, timer, [apply, M, T, self()]),
+ Pid2 = spawn_link(?MODULE, timer, [interval, M, T, self(), NumIter]),
+ [Pid1, Pid2 | spawn_timers(N-1, M, T, NumIter)].
+
+timer(apply, Mod, T, Pid) ->
+ Before = system_time(),
+ {ok, Ref} = apply(Mod, apply_after, [T, ?MODULE, send, [self(), done]]),
+ receive
+ done ->
+ After = system_time(),
+ Pid ! {self(), ok, (After-Before) div 1000, T}
+ after T*3 + 300 -> % Watch dog
+ io:format("WARNING TIMER WATCHDOG timed out: ~w ~n", [T]),
+ timer:cancel(Ref),
+ Pid ! {self(), watch_dog_timed_out}
+ end.
+
+timer(interval, Mod, T, Pid, NumIter) ->
+ Before = system_time(),
+ {ok, Ref} = apply(Mod, apply_interval, [T, ?MODULE, send, [self(), done]]),
+ timer_irec(Before, T, {0, NumIter}, [], {Pid, Mod, Ref}).
+
+timer_irec(_Start, T, {N, N}, Res, {Pid, Mod, Ref}) ->
+ apply(Mod, cancel, [Ref]),
+ Min = lists:min(Res),
+ Max = lists:max(Res),
+ Tot = lists:sum(Res),
+ Pid ! {self(), ok, {N, Tot, Tot div N, Min, Max}, T};
+timer_irec(Start, T, {N, Max}, Res, {Pid, Mod, Ref}) ->
+ receive
+ done ->
+ Now = system_time(),
+ Elapsed = (Now - (Start + (N*T*1000))) div 1000,
+% io:format("~w Now ~w Started ~w Elap ~w~n", [T,Now,Start,Elapsed]),
+ timer_irec(Start, T,
+ {N+1, Max},
+ [Elapsed | Res],
+ {Pid, Mod, Ref})
+ after T*3 + 300 ->
+ apply(Mod, cancel, [Ref]),
+ io:format("WARNING: TIMER WATCHDOG timed out <Interval>~w~n",[T]),
+ Pid ! {self(), timer_watchdog_timed_out_in_interlval_test}
+ end.
+
+%% ------------------------------------------------------- %%
+%% Small last generator
+
+start_nrev(0, _) ->
+ [];
+
+start_nrev(N, M) ->
+ Pid = spawn_link(?MODULE, do_nrev, [N, M]),
+ [Pid | start_nrev(N-1, M)].
+
+do_nrev(Sleep, Mod) ->
+ apply(Mod, sleep, [50 * Sleep]),
+ test(1000,"abcdefghijklmnopqrstuvxyz1234"),
+ ok.
+
+test(0,_) ->
+ true;
+test(N,L) ->
+ nrev(L),
+ test(N - 1, L).
+
+nrev([]) ->
+ [];
+nrev([H|T]) ->
+ append(nrev(T), [H]).
+
+append([H|T],Z) ->
+ [H|append(T,Z)];
+append([],X) ->
+ X.
+
+system_time() ->
+ {M,S,U} = erlang:now(),
+ 1000000*(M*1000000 + S) + U.
+
+%% ------------------------------------------------------- %%
+
+report_result({Res, 0}) ->
+% io:format("DEBUG0 all ~p ~n", [Res]),
+ {A_List, I_List} = split_list(Res, [], []),
+ A_val = calc_a_val(A_List),
+ I_val = calc_i_val(I_List),
+ print_report(A_val, I_val),
+ ok;
+
+report_result({Head, N}) ->
+ io:format("Test Failed: Number of internal tmo ~w~n", [N]),
+ ?line test_server:fail({Head, N}).
+
+split_list([], AL, IL) ->
+ {AL, IL};
+split_list([{T, {N, Tot, A, Min, Max}} | Rest], AL, IL) ->
+ split_list(Rest, AL, [{T, {N, Tot, A, Min, Max}} | IL]);
+split_list([Head | Rest], AL, IL) ->
+ split_list(Rest, [Head | AL], IL).
+
+split([{T, Res} | R]) ->
+ split(R, {{T,[Res]}, {T*10,[]}, {T*100,[]}}).
+
+split([{T, Res} | R], {{T,S}, M, L}) ->
+ split(R, {{T,[Res|S]}, M, L});
+
+split([{T, Res} | R], {S, {T,M}, L}) ->
+ split(R, {S, {T, [Res|M]}, L});
+
+split([{T, Res} | R], {S, M, {T,L}}) ->
+ split(R, {S, M, {T, [Res|L]}});
+
+split(_Done, Vals) ->
+ Vals.
+
+calc_a_val(List) ->
+ New = lists:sort(List),
+ {{T1, S}, {T2, M}, {T3, L}} = split(New),
+ S2 = {length(S), lists:max(S), lists:min(S),
+ lists:sum(S) div length(S)},
+ M2 = {length(M), lists:max(M), lists:min(M),
+ lists:sum(M) div length(M)},
+ L2 = {length(L), lists:max(L), lists:min(L),
+ lists:sum(L) div length(L)},
+ [{T1, S2}, {T2, M2}, {T3, L2}].
+
+calc_i_val(List) ->
+ New = lists:sort(List),
+ {{T1, S}, {T2, M}, {T3, L}} = split(New),
+ S2 = get_ivals(S),
+ M2 = get_ivals(M),
+ L2 = get_ivals(L),
+ [{T1, S2}, {T2, M2}, {T3, L2}].
+
+get_ivals(List) ->
+ Len = length(List),
+ Num = element(1, hd(List)), % Number of iterations
+
+ LTot = lists:map(fun(X) -> element(2, X) end, List),
+ LMin = lists:map(fun(X) -> element(4, X) end, List),
+ LMax = lists:map(fun(X) -> element(5, X) end, List),
+
+ MaxTot = lists:max(LTot),
+ MinTot = lists:min(LTot),
+ AverTot = lists:sum(LTot) div Len,
+
+ IterMax = lists:max(LMax),
+ IterMin = lists:min(LMin),
+ IterAver= AverTot div Num,
+
+ {Len, Num,
+ {MaxTot, MinTot, AverTot},
+ {IterMax, IterMin, IterAver}}.
+
+
+print_report(A_L, I_L) ->
+ io:format("~nRESULTS from timer test~n~n",[]),
+ io:format("Time out times for send_after~n~n", []),
+ io:format("Time No of tests Max Min Average~n",[]),
+ print_aval(A_L),
+ io:format("Time out times for send_interval~n~n", []),
+ io:format("Time No.tests No.intvals TotMax TotMin TotAver MaxI MinI AverI~n", []),
+ print_ival(I_L).
+
+print_aval([]) ->
+ io:format("~n~n", []);
+print_aval([{T, {L, Max, Min, Aver}}|R]) ->
+ io:format("~5w ~8w ~6w ~6w ~8w ~n",
+ [T,L,Max,Min,Aver]),
+ print_aval(R).
+
+print_ival([]) ->
+ io:format("~n", []);
+print_ival([{T, {Len, Num,
+ {MaxT, MinT, AverT},
+ {MaxI, MinI, AverI}}}|R]) ->
+ io:format("~5w ~6w ~10w ~8w ~6w ~6w ~6w ~6w ~6w~n",
+ [T,Len,Num,MaxT,MinT,AverT, MaxI, MinI, AverI]),
+ print_ival(R).
+
+send(Pid, Msg) ->
+ Pid ! Msg.
diff --git a/lib/stdlib/test/unicode_SUITE.erl b/lib/stdlib/test/unicode_SUITE.erl
new file mode 100644
index 0000000000..706445005c
--- /dev/null
+++ b/lib/stdlib/test/unicode_SUITE.erl
@@ -0,0 +1,1241 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(unicode_SUITE).
+
+-include("test_server.hrl").
+
+-export([all/1,
+ init_per_testcase/2,
+ fin_per_testcase/2,
+ utf8_illegal_sequences_bif/1,
+ utf16_illegal_sequences_bif/1,
+ random_lists/1,
+ roundtrips/1,
+ latin1/1,
+ exceptions/1]).
+
+init_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
+ Dog=?t:timetrap(?t:minutes(20)),
+ [{watchdog, Dog}|Config].
+
+fin_per_testcase(_Case, Config) ->
+ Dog = ?config(watchdog, Config),
+ ?t:timetrap_cancel(Dog).
+
+all(suite) ->
+ [utf8_illegal_sequences_bif,utf16_illegal_sequences_bif,random_lists,roundtrips,latin1,exceptions].
+
+
+exceptions(Config) when is_list(Config) ->
+ setlimit(10),
+ ex_exceptions(Config),
+ setlimit(default),
+ ex_exceptions(Config).
+
+ex_exceptions(Config) when is_list(Config) ->
+ ?line L = lists:seq(0,255),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary(L++255,unicode)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary({1,2,3},unicode)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary(1,unicode)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary(1.0,unicode)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary('1',unicode)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary([1,2,3,apa],unicode)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary([1,2,3,4.0],unicode)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary(L++255,latin1)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary({1,2,3},latin1)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary(1,latin1)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary(1.0,latin1)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary('1',latin1)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary([1,2,3,apa],latin1)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary([1,2,3,4.0],latin1)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary(L,gnarfl)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary(L,L)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary(L,{latin1})),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary(L,[latin1])),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary(L,1)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary(L,1.0)),
+ Encodings = [unicode, utf8,utf16,utf32,{utf16,big},
+ {utf16,little},{utf32,big},{utf32,little}],
+ [ begin
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary(L++255,unicode,Enc)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary({1,2,3},unicode,Enc)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary(1,unicode,Enc)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary(1.0,unicode,Enc)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary('1',unicode,Enc)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary([1,2,3,apa],unicode,
+ Enc)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary([1,2,3,4.0],unicode,
+ Enc)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary(L++255,latin1,Enc)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary({1,2,3},latin1,Enc)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary(1,latin1,Enc)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary(1.0,latin1,Enc)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary('1',latin1,Enc)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary([1,2,3,apa],latin1,
+ Enc)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary([1,2,3,4.0],latin1,
+ Enc)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary(L,gnarfl,Enc)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary(L,L,Enc)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary(L,{latin1},Enc)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary(L,[latin1],Enc)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary(L,1,Enc)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_binary(L,1.0,Enc))
+ end || Enc <- Encodings ],
+
+
+ Encodings2 = [latin1, unicode, utf8,utf16,utf32,{utf16,big},
+ {utf16,little},{utf32,big},{utf32,little}],
+ [ begin
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_list(L++255,Enc)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_list({1,2,3},Enc)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_list(1,Enc)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_list(1.0,Enc)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_list('1',Enc)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_list([1,2,3,apa],Enc)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_list([1,2,3,4.0],Enc)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_list(L,{Enc})),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_list(L,[Enc]))
+ end || Enc <- Encodings2 ],
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_list(L,gnarfl)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_list(L,L)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_list(L,1)),
+ ?line {'EXIT',{badarg,_}} = (catch unicode:characters_to_list(L,1.0)),
+ [ begin
+ ?line Bx = unicode:characters_to_binary(L,latin1, Enc),
+ ?line L = unicode:characters_to_list(Bx,Enc)
+ end || Enc <- Encodings ],
+ ?line B = unicode:characters_to_binary(L,latin1),
+ ?line L = unicode:characters_to_list(B,unicode),
+ ?line L = unicode:characters_to_list(list_to_binary(L),latin1),
+ ?line More = <<B/binary,0,1,2>>,
+ ?line B2 = list_to_binary([254,255]),
+ ?line B3 = list_to_binary([0,1,2,254,255]),
+ ?line {error,B,Rest1} = unicode:characters_to_binary([L,B2],unicode),
+ ?line B2 = iolist_to_binary(Rest1),
+ ?line {error,More,Rest2} = unicode:characters_to_binary([L,B3],unicode),
+ [ begin ?line {error,_,_} = unicode:characters_to_binary([L,B2],unicode,Enc) end
+ || Enc <- Encodings ],
+ ?line Valid0 = unicode:characters_to_binary([L,254,255],unicode),
+ ?line Valid1 = unicode:characters_to_binary([L,254,255],latin1),
+ ?line Valid2 = unicode:characters_to_binary([L,254,255,256,257],unicode),
+ ?line Valid3 = unicode:characters_to_binary([L,B2],latin1),
+ ?line true = is_binary(Valid0),
+ ?line true = is_binary(Valid1),
+ ?line true = is_binary(Valid2),
+ ?line true = is_binary(Valid3),
+ ?line Valid4 = unicode:characters_to_binary([L,B3],latin1),
+ ?line true = is_binary(Valid4),
+ ?line B2 = iolist_to_binary(Rest2),
+ ?line true = (L ++ [254,255] =:= unicode:characters_to_list(Valid0,unicode)),
+ ?line true = (L ++ [254,255,256,257] =:= unicode:characters_to_list(Valid2,unicode)),
+ lists:foreach(fun(Enco) ->
+ ?line Valid0x = unicode:characters_to_binary([L,254,255],unicode,Enco),
+ ?line Valid1x = unicode:characters_to_binary([L,254,255],latin1,Enco),
+ ?line Valid2x = unicode:characters_to_binary([L,254,255,256,257],unicode,Enco),
+ ?line Valid3x = unicode:characters_to_binary([L,B2],latin1,Enco),
+ ?line true = is_binary(Valid0x),
+ ?line true = is_binary(Valid1x),
+ ?line true = is_binary(Valid2x),
+ ?line true = is_binary(Valid3x)
+
+ end, Encodings),
+ ok.
+
+
+latin1(Config) when is_list(Config) ->
+ setlimit(10),
+ ex_latin1(Config),
+ setlimit(default),
+ ex_latin1(Config).
+
+ex_latin1(Config) when is_list(Config) ->
+ ?line All = lists:seq(0,255),
+ ?line AllBin = list_to_binary(All),
+ ?line AllUtf8 = unicode:characters_to_binary(All,latin1),
+ ?line AllUtf8 = unicode:characters_to_binary(AllBin,latin1),
+ ?line AllUtf8 = unicode:characters_to_binary([AllBin],latin1),
+ ?line AllUtf8 = unicode:characters_to_binary(make_unaligned(AllBin),latin1),
+ ?line AllUtf8 = unicode:characters_to_binary([make_unaligned(AllBin)],latin1),
+ ?line AllUtf8 = list_to_utf8_bsyntax([AllBin],latin1),
+ ?line AllUtf8 = list_to_utf8_bsyntax([make_unaligned(AllBin)],latin1),
+ ?line AllUtf8 = unicode_mixed_to_utf8_1(All),
+
+ ?line AllUtf16_Big = unicode:characters_to_binary(All,latin1,utf16),
+ ?line AllUtf16_Big = unicode:characters_to_binary(AllBin,latin1,utf16),
+ ?line AllUtf16_Big = unicode:characters_to_binary([AllBin],latin1,utf16),
+ ?line AllUtf16_Big = unicode:characters_to_binary(make_unaligned(AllBin),latin1,utf16),
+ ?line AllUtf16_Big = unicode:characters_to_binary([make_unaligned(AllBin)],latin1,utf16),
+ ?line AllUtf16_Big = list_to_utf16_big_bsyntax([AllBin],latin1),
+ ?line AllUtf16_Big = list_to_utf16_big_bsyntax([make_unaligned(AllBin)],latin1),
+
+ ?line AllUtf16_Little = unicode:characters_to_binary(All,latin1,{utf16,little}),
+ ?line AllUtf16_Little = unicode:characters_to_binary(AllBin,latin1,{utf16,little}),
+ ?line AllUtf16_Little = unicode:characters_to_binary([AllBin],latin1,{utf16,little}),
+ ?line AllUtf16_Little = unicode:characters_to_binary(make_unaligned(AllBin),latin1,
+ {utf16,little}),
+ ?line AllUtf16_Little = unicode:characters_to_binary([make_unaligned(AllBin)],latin1,
+ {utf16,little}),
+ ?line AllUtf16_Little = list_to_utf16_little_bsyntax([AllBin],latin1),
+ ?line AllUtf16_Little = list_to_utf16_little_bsyntax([make_unaligned(AllBin)],latin1),
+
+ ?line AllUtf32_Big = unicode:characters_to_binary(All,latin1,utf32),
+ ?line AllUtf32_Big = unicode:characters_to_binary(AllBin,latin1,utf32),
+ ?line AllUtf32_Big = unicode:characters_to_binary([AllBin],latin1,utf32),
+ ?line AllUtf32_Big = unicode:characters_to_binary(make_unaligned(AllBin),latin1,utf32),
+ ?line AllUtf32_Big = unicode:characters_to_binary([make_unaligned(AllBin)],latin1,utf32),
+ ?line AllUtf32_Big = list_to_utf32_big_bsyntax([AllBin],latin1),
+ ?line AllUtf32_Big = list_to_utf32_big_bsyntax([make_unaligned(AllBin)],latin1),
+
+ ?line AllUtf32_Little = unicode:characters_to_binary(All,latin1,{utf32,little}),
+ ?line AllUtf32_Little = unicode:characters_to_binary(AllBin,latin1,{utf32,little}),
+ ?line AllUtf32_Little = unicode:characters_to_binary([AllBin],latin1,{utf32,little}),
+ ?line AllUtf32_Little = unicode:characters_to_binary(make_unaligned(AllBin),latin1,
+ {utf32,little}),
+ ?line AllUtf32_Little = unicode:characters_to_binary([make_unaligned(AllBin)],latin1,
+ {utf32,little}),
+ ?line AllUtf32_Little = list_to_utf32_little_bsyntax([AllBin],latin1),
+ ?line AllUtf32_Little = list_to_utf32_little_bsyntax([make_unaligned(AllBin)],latin1),
+
+ ?line DoubleUtf8 = <<AllUtf8/binary,AllUtf8/binary>>,
+ ?line DoubleUtf8 = unicode:characters_to_binary([All,AllBin],latin1),
+ ?line DoubleUtf8 =
+ unicode:characters_to_binary([All,make_unaligned(AllBin)],latin1),
+ ?line DoubleUtf8 = unicode:characters_to_binary([All|AllBin],latin1),
+ ?line DoubleUtf8 =
+ unicode:characters_to_binary([All|make_unaligned(AllBin)],latin1),
+ ?line DoubleUtf8 = unicode:characters_to_binary([AllBin,All],latin1),
+ ?line DoubleUtf8 = unicode:characters_to_binary([AllBin|All],latin1),
+ ?line DoubleUtf8 = list_to_utf8_bsyntax([AllBin|All],latin1),
+
+ ?line DoubleUtf16 = <<AllUtf16_Big/binary,AllUtf16_Big/binary>>,
+ ?line DoubleUtf16 = unicode:characters_to_binary([All,AllBin],latin1,{utf16,big}),
+ ?line DoubleUtf16 =
+ unicode:characters_to_binary([All,make_unaligned(AllBin)],latin1,{utf16,big}),
+ ?line DoubleUtf16 = unicode:characters_to_binary([All|AllBin],latin1,{utf16,big}),
+ ?line DoubleUtf16 =
+ unicode:characters_to_binary([All|make_unaligned(AllBin)],latin1,{utf16,big}),
+ ?line DoubleUtf16 = unicode:characters_to_binary([AllBin,All],latin1,{utf16,big}),
+ ?line DoubleUtf16 = unicode:characters_to_binary([AllBin|All],latin1,{utf16,big}),
+ ?line DoubleUtf16 = list_to_utf16_big_bsyntax([AllBin|All],latin1),
+
+ ?line All = unicode:characters_to_list(AllUtf8,unicode),
+ ?line All = unicode:characters_to_list(make_unaligned(AllUtf8),unicode),
+ ?line All = utf8_to_list_bsyntax(AllUtf8),
+ ?line AllAll = All ++ All,
+ ?line AllAll = unicode:characters_to_list(DoubleUtf8,unicode),
+ ?line AllAll = unicode:characters_to_list(make_unaligned(DoubleUtf8),unicode),
+ ?line AllAll = utf8_to_list_bsyntax(DoubleUtf8),
+ ?line {error,AllUtf8,Rest1} = unicode:characters_to_binary(All++[16#FFF],latin1),
+ ?line [16#FFF] = lists:flatten(Rest1),
+ ?line {error,DoubleUtf8,Rest2} =
+ unicode:characters_to_binary([All,AllBin,16#FFF],latin1),
+ ?line {error,DoubleUtf16,Rest2x} =
+ unicode:characters_to_binary([All,AllBin,16#FFF],latin1,utf16),
+ ?line [16#FFF] = lists:flatten(Rest2),
+ ?line [16#FFF] = lists:flatten(Rest2x),
+ ?line {error,AllUtf8,Rest3} =
+ unicode:characters_to_binary([All,16#FFF,AllBin,16#FFF],
+ latin1),
+ ?line {error,AllUtf8,Rest3} =
+ unicode:characters_to_binary([All,16#FFF,make_unaligned(AllBin),16#FFF],
+ latin1),
+ ?line {error,AllUtf16_Big,Rest3x} =
+ unicode:characters_to_binary([All,16#FFF,AllBin,16#FFF],
+ latin1,{utf16,big}),
+ ?line {error,AllUtf16_Big,Rest3x} =
+ unicode:characters_to_binary([All,16#FFF,make_unaligned(AllBin),16#FFF],
+ latin1,{utf16,big}),
+ ?line [16#FFF,AllBin,16#FFF] = lists:flatten(Rest3),
+ ?line [16#FFF,AllBin,16#FFF] = lists:flatten(Rest3x),
+ ?line DoubleSize = byte_size(DoubleUtf8),
+ ?line AllBut1 = DoubleSize - 1,
+ ?line AllBut2 = DoubleSize - 2,
+ ?line <<MissingLastByte:AllBut1/binary,_>> = DoubleUtf8,
+ ?line <<_:AllBut2/binary,MissingStart:1/binary,_>> = DoubleUtf8,
+ ?line {ChompedList,_} = lists:split(length(AllAll) - 1,AllAll),
+ ?line {incomplete,ChompedList,MissingStart} =
+ unicode:characters_to_list(MissingLastByte,unicode),
+ ?line {incomplete,ChompedList,MissingStart} =
+ unicode:characters_to_list(make_unaligned(MissingLastByte),unicode),
+
+ ?line DoubleSize16 = byte_size(DoubleUtf16),
+ ?line DoubleUtf16_2 = erlang:concat_binary([DoubleUtf16,<<16#FFFFF/utf16-big>>]),
+ ?line DoubleSize16_2 = byte_size(DoubleUtf16_2),
+ ?line AllBut1_16 = DoubleSize16 - 1,
+ ?line AllBut2_16_2 = DoubleSize16_2 - 2,
+ ?line <<MissingLastBytes16:AllBut2_16_2/binary,_,_>> = DoubleUtf16_2,
+ ?line <<MissingLastByte16:AllBut1_16/binary,_>> = DoubleUtf16,
+ ?line {incomplete,AllAll,_} =
+ unicode:characters_to_list(MissingLastBytes16,utf16),
+ ?line {incomplete,AllAll,_} =
+ unicode:characters_to_list(make_unaligned(MissingLastBytes16),utf16),
+ ?line {incomplete,ChompedList,_} =
+ unicode:characters_to_list(MissingLastByte16,utf16),
+ ?line {incomplete,ChompedList,_} =
+ unicode:characters_to_list(make_unaligned(MissingLastByte16),utf16),
+ ok.
+
+roundtrips(Config) when is_list(Config) ->
+ setlimit(10),
+ ex_roundtrips(Config),
+ setlimit(default),
+ ex_roundtrips(Config).
+
+ex_roundtrips(Config) when is_list(Config) ->
+ ?line L1 = ranges(0, 16#D800 - 1,
+ erlang:system_info(context_reductions) * 11),
+ ?line L2 = ranges(16#DFFF + 1, 16#FFFE - 1,
+ erlang:system_info(context_reductions) * 11),
+ %?line L3 = ranges(16#FFFF + 1, 16#10FFFF,
+ % erlang:system_info(context_reductions) * 11),
+ ?line L3 = ranges(16#FFFFF, 16#10FFFF,
+ erlang:system_info(context_reductions) * 11),
+ ?line L = L1 ++ L2 ++ L3,
+ ?line LLen = length(L),
+ ?line Parts = erlang:system_info(schedulers),
+ ?line Lists = splitup(L,LLen,Parts),
+ ?line PidRefs = [spawn_monitor(fun() ->
+ do_roundtrips(MyPart)
+ end) || MyPart <- Lists],
+ ?line [receive {'DOWN',Ref,process,Pid,Reason} -> normal=Reason end ||
+ {Pid,Ref} <- PidRefs],
+ ok.
+
+do_roundtrips([]) ->
+ ok;
+do_roundtrips([{Start,Stop}|T]) ->
+ erlang:display({Start,Stop}),
+ List = lists:seq(Start,Stop),
+ Utf = unicode:characters_to_binary(List,unicode),
+ Utf16_Big = unicode:characters_to_binary(List,unicode,{utf16,big}),
+ Utf16_Little = unicode:characters_to_binary(List,unicode,{utf16,little}),
+ Utf32_Big = unicode:characters_to_binary(List,unicode,{utf32,big}),
+ Utf32_Little = unicode:characters_to_binary(List,unicode,{utf32,little}),
+
+ Utf = unicode:characters_to_binary([Utf],unicode),
+ Utf16_Big = unicode:characters_to_binary([Utf16_Big],{utf16,big},{utf16,big}),
+ Utf16_Little = unicode:characters_to_binary([Utf16_Little],{utf16,little},{utf16,little}),
+ Utf32_Big = unicode:characters_to_binary([Utf32_Big],{utf32,big},{utf32,big}),
+ Utf32_Little = unicode:characters_to_binary([Utf32_Little],{utf32,little},{utf32,little}),
+
+ Utf = list_to_utf8_bsyntax(List,unicode),
+ Utf16_Big = list_to_utf16_big_bsyntax(List,{utf16,big}),
+ Utf16_Little = list_to_utf16_little_bsyntax(List,{utf16,little}),
+ Utf32_Big = list_to_utf32_big_bsyntax(List,{utf32,big}),
+ Utf32_Little = list_to_utf32_little_bsyntax(List,{utf32,little}),
+
+ Utf = unicode_mixed_to_utf8_1(List),
+
+ List = unicode:characters_to_list(Utf,unicode),
+ List = unicode:characters_to_list(Utf16_Big,{utf16,big}),
+ List = unicode:characters_to_list(Utf16_Little,{utf16,little}),
+ List = unicode:characters_to_list(Utf32_Big,{utf32,big}),
+ List = unicode:characters_to_list(Utf32_Little,{utf32,little}),
+ List = utf8_to_list_bsyntax(Utf),
+ List = utf16_big_to_list_bsyntax(Utf16_Big),
+ List = utf16_little_to_list_bsyntax(Utf16_Little),
+ List = utf32_big_to_list_bsyntax(Utf32_Big),
+ List = utf32_little_to_list_bsyntax(Utf32_Little),
+ List = utf8_to_list(Utf),
+ List = utf16_big_to_list(Utf16_Big),
+ List = utf16_little_to_list(Utf16_Little),
+ List = utf32_big_to_list(Utf32_Big),
+ List = utf32_little_to_list(Utf32_Little),
+ do_roundtrips(T).
+
+
+random_lists(Config) when is_list(Config) ->
+ setlimit(10),
+ ex_random_lists(Config),
+ setlimit(default),
+ ex_random_lists(Config).
+ex_random_lists(Config) when is_list(Config) ->
+ PlainFlatten1 = fun(L) ->
+ unicode:characters_to_binary(flat(L),latin1)
+ end,
+ PlainFlatten2 = fun(L) ->
+ unicode:characters_to_binary(L,latin1)
+ end,
+ PlainFlatten3 = fun(L) ->
+ unicode:characters_to_binary(flatb(L),latin1)
+ end,
+ PlainFlatten4 = fun(L) ->
+ iolist_to_binary([int_to_utf8(X) || X <- unicode:characters_to_list(flatb(L),latin1)])
+ end,
+ ?line random_iolist:run(150, PlainFlatten1, PlainFlatten3),
+ ?line random_iolist:run(150, PlainFlatten2, PlainFlatten3),
+ ?line random_iolist:run(150, PlainFlatten1, PlainFlatten2),
+ ?line random_iolist:run(150, PlainFlatten1, PlainFlatten4),
+ SelfMade = fun(L) ->
+ iolist_to_binary(lists:map(fun(X) ->
+ int_to_utf8(X)
+ end,
+ flatb(L)))
+ end,
+ SelfMadeA = fun(L) ->
+ case (catch list_to_utf8_bsyntax(L,latin1)) of
+ {'EXIT', Reason} ->
+ io:format("Exit: ~p (~w)~n",[Reason,L]),
+ exit(Reason);
+ Other ->
+ Other
+ end
+ end,
+ ?line random_iolist:run(150, PlainFlatten1, SelfMade),
+ ?line random_iolist:run(150, PlainFlatten2, SelfMadeA),
+
+ RoundTrip11 = fun(L) ->
+ unicode:characters_to_list(unicode:characters_to_binary(L,latin1),unicode)
+ end,
+ RoundTrip21 = fun(L) ->
+ utf8_to_list_bsyntax(unicode:characters_to_binary(L,latin1))
+ end,
+ RoundTrip31 = fun(L) ->
+ unicode:characters_to_list(list_to_utf8_bsyntax(L,latin1),unicode)
+ end,
+ RoundTrip41 = fun(L) ->
+ utf8_to_list_bsyntax(list_to_utf8_bsyntax(L,latin1))
+ end,
+ RoundTrip51 = fun(L) ->
+ unicode:characters_to_list(L,latin1)
+ end,
+ ?line random_iolist:run(150, RoundTrip11,RoundTrip21),
+ ?line random_iolist:run(150, RoundTrip21,RoundTrip31),
+ ?line random_iolist:run(150, RoundTrip31,RoundTrip41),
+ ?line random_iolist:run(150, RoundTrip11,RoundTrip41),
+ ?line random_iolist:run(150, RoundTrip21,RoundTrip41),
+ ?line random_iolist:run(150, RoundTrip11,RoundTrip31),
+ ?line random_iolist:run(150, RoundTrip11,RoundTrip51),
+
+
+ UniFlatten1 = fun(L) ->
+ unicode:characters_to_binary(flat(L),unicode)
+ end,
+ UniFlatten2 = fun(L) ->
+ unicode:characters_to_binary(L,unicode)
+ end,
+ UniFlatten3 = fun(L) ->
+ unicode:characters_to_binary(flatx(L),unicode)
+ end,
+ UniFlatten4 = fun(L) ->
+ unicode:characters_to_binary(unicode:characters_to_list(L,unicode),unicode)
+ end,
+ ?line random_unicode_list:run(150, UniFlatten1,UniFlatten2),
+ ?line random_unicode_list:run(150, UniFlatten1,UniFlatten3),
+ ?line random_unicode_list:run(150, UniFlatten2,UniFlatten4),
+ ?line random_unicode_list:run(150, UniFlatten2,UniFlatten3),
+
+ ?line Encodings = [utf8,{utf16,big},
+ {utf16,little},{utf32,big},{utf32,little}],
+ lists:foreach(fun(OutEnc1) ->
+ lists:foreach(fun(InEnc1) ->
+ Uni16BigFlatten1 = fun(L) ->
+ unicode:characters_to_binary(flat(L),InEnc1,OutEnc1)
+ end,
+ Uni16BigFlatten2 = fun(L) ->
+ unicode:characters_to_binary(L,InEnc1,OutEnc1)
+ end,
+ Uni16BigFlatten3 = fun(L) ->
+ unicode:characters_to_binary(flatx(L),InEnc1,OutEnc1)
+ end,
+ Uni16BigFlatten4 = fun(L) ->
+ unicode:characters_to_binary(unicode:characters_to_list(L,InEnc1),InEnc1,OutEnc1)
+ end,
+ %erlang:display({InEnc1,OutEnc1}),
+ ?line random_unicode_list:run(150, Uni16BigFlatten1,Uni16BigFlatten2,InEnc1),
+ ?line random_unicode_list:run(150, Uni16BigFlatten1,Uni16BigFlatten3,InEnc1),
+ ?line random_unicode_list:run(150, Uni16BigFlatten2,Uni16BigFlatten4,InEnc1),
+ ?line random_unicode_list:run(150, Uni16BigFlatten2,Uni16BigFlatten3,InEnc1)
+ end, Encodings)
+ end, Encodings),
+ SelfMade1 = fun(L) ->
+ unicode_mixed_to_utf8_1(L)
+ end,
+ SelfMade2 = fun(L) ->
+ unicode_mixed_to_utf8_2(L)
+ end,
+ SelfMade3 = fun(L) ->
+ list_to_utf8_bsyntax(L,unicode)
+ end,
+ ?line random_unicode_list:run(150, SelfMade1,SelfMade2),
+ ?line random_unicode_list:run(150, UniFlatten2, SelfMade1),
+ ?line random_unicode_list:run(150, UniFlatten2, SelfMade2),
+ ?line random_unicode_list:run(150, UniFlatten2, SelfMade3),
+ RoundTrip1 = fun(L) ->
+ unicode:characters_to_list(unicode:characters_to_binary(L,unicode),unicode)
+ end,
+ RoundTrip2 = fun(L) ->
+ utf8_to_list_bsyntax(unicode:characters_to_binary(L,unicode))
+ end,
+ RoundTrip3 = fun(L) ->
+ unicode:characters_to_list(list_to_utf8_bsyntax(L,unicode),unicode)
+ end,
+ RoundTrip4 = fun(L) ->
+ utf8_to_list_bsyntax(list_to_utf8_bsyntax(L,unicode))
+ end,
+ ?line random_unicode_list:run(150, RoundTrip1,RoundTrip2),
+ ?line random_unicode_list:run(150, RoundTrip2,RoundTrip3),
+ ?line random_unicode_list:run(150, RoundTrip3,RoundTrip4),
+ ?line random_unicode_list:run(150, RoundTrip1,RoundTrip4),
+ ?line random_unicode_list:run(150, RoundTrip2,RoundTrip4),
+ ?line random_unicode_list:run(150, RoundTrip1,RoundTrip3),
+ lists:foreach(fun(OutEnc2) ->
+ lists:foreach(fun(InEnc2) ->
+ RoundTripUtf16_Big_1 = fun(L) ->
+ unicode:characters_to_list(unicode:characters_to_binary(L,InEnc2,OutEnc2),OutEnc2)
+ end,
+ RoundTripUtf16_Big_2 = fun(L) ->
+ x_to_list_bsyntax(OutEnc2,unicode:characters_to_binary(L,InEnc2,OutEnc2))
+ end,
+ RoundTripUtf16_Big_3 = fun(L) ->
+ unicode:characters_to_list(list_to_x_bsyntax(InEnc2,L,InEnc2),InEnc2)
+ end,
+ RoundTripUtf16_Big_4 = fun(L) ->
+ x_to_list_bsyntax(InEnc2,list_to_x_bsyntax(InEnc2,L,InEnc2))
+ end,
+ ?line random_unicode_list:run(150, RoundTripUtf16_Big_1,RoundTripUtf16_Big_2,InEnc2),
+ ?line random_unicode_list:run(150, RoundTripUtf16_Big_2,RoundTripUtf16_Big_3,InEnc2),
+ ?line random_unicode_list:run(150, RoundTripUtf16_Big_3,RoundTripUtf16_Big_4,InEnc2),
+ ?line random_unicode_list:run(150, RoundTripUtf16_Big_1,RoundTripUtf16_Big_4,InEnc2),
+ ?line random_unicode_list:run(150, RoundTripUtf16_Big_2,RoundTripUtf16_Big_4,InEnc2),
+ ?line random_unicode_list:run(150, RoundTripUtf16_Big_1,RoundTripUtf16_Big_3,InEnc2)
+ end, Encodings)
+ end, Encodings),
+ ToList1 = fun(L) ->
+ unicode:characters_to_list(L,unicode)
+ end,
+ ToList2 = fun(L) ->
+ unicode:characters_to_list(unicode:characters_to_binary(L,unicode),unicode)
+ end,
+ ToList3 = fun(L) ->
+ unicode:characters_to_list(unicode_mixed_to_utf8_2(L),unicode)
+ end,
+ ToList4 = fun(L) ->
+ utf8_to_list(unicode_mixed_to_utf8_2(L))
+ end,
+ ?line random_unicode_list:run(150, ToList1,ToList2),
+ ?line random_unicode_list:run(150, ToList2,ToList3),
+ ?line random_unicode_list:run(150, ToList3,ToList4),
+ ?line random_unicode_list:run(150, ToList1,ToList4),
+ ?line random_unicode_list:run(150, ToList2,ToList4),
+ ?line random_unicode_list:run(150, ToList1,ToList3),
+
+ ok.
+
+utf16_illegal_sequences_bif(Config) when is_list(Config) ->
+ setlimit(10),
+ ex_utf16_illegal_sequences_bif(Config),
+ setlimit(default),
+ ex_utf16_illegal_sequences_bif(Config).
+
+ex_utf16_illegal_sequences_bif(Config) when is_list(Config) ->
+ ?line utf16_fail_range_bif_simple(16#10FFFF+1, 16#10FFFF+512), %Too large.
+ ?line utf16_fail_range_bif(16#D800, 16#DFFF), %Reserved for UTF-16.
+ ?line utf16_fail_range_bif(16#FFFE, 16#FFFF), %Non-characters.
+
+ ?line lonely_hi_surrogate_bif(16#D800, 16#DBFF,incomplete),
+ ?line lonely_hi_surrogate_bif(16#DC00, 16#DFFF,error),
+ ?line leading_lo_surrogate_bif(16#DC00, 16#DFFF),
+
+ ok.
+
+utf16_fail_range_bif(Char, End) when Char =< End ->
+ {error,_,_} = unicode:characters_to_binary([Char],{utf16,big}),
+ BigBin = int_to_utf16_big(Char),
+ fail_bif(BigBin,{utf16,big}),
+ {error,_,_} = unicode:characters_to_binary([Char],{utf16,little}),
+ LittleBin = int_to_utf16_little(Char),
+ fail_bif(LittleBin,{utf16,little}),
+ utf16_fail_range_bif(Char+1, End);
+utf16_fail_range_bif(_, _) -> ok.
+
+utf16_fail_range_bif_simple(Char, End) when Char =< End ->
+ {error,_,_} = unicode:characters_to_binary([Char],{utf16,big}),
+ {error,_,_} = unicode:characters_to_binary([Char],{utf16,little}),
+ utf16_fail_range_bif_simple(Char+1, End);
+utf16_fail_range_bif_simple(_, _) -> ok.
+
+
+lonely_hi_surrogate_bif(Char, End, EType) when Char =< End ->
+ BinBig = <<Char:16/big>>,
+ BinLittle = <<Char:16/little>>,
+ case unicode:characters_to_binary(BinBig,{utf16,big}) of
+ {EType,_,_} ->
+ ok;
+ Other ->
+ exit({lonely_hi_surrogate_accepted,BinBig,{utf16,big},Other})
+ end,
+ case unicode:characters_to_binary(BinLittle,{utf16,little}) of
+ {EType,_,_} ->
+ ok;
+ Other2 ->
+ exit({lonely_hi_surrogate_accepted,BinLittle,{utf16,little},Other2})
+ end,
+ lonely_hi_surrogate_bif(Char+1, End, EType);
+lonely_hi_surrogate_bif(_, _, _) -> ok.
+
+leading_lo_surrogate_bif(Char, End) when Char =< End ->
+ leading_lo_surrogate_bif(Char, 16#D800, 16#DFFF),
+ leading_lo_surrogate_bif(Char+1, End);
+leading_lo_surrogate_bif(_, _) -> ok.
+
+leading_lo_surrogate_bif(HiSurr, LoSurr, End) when LoSurr =< End ->
+ BinBig = <<HiSurr:16/big,LoSurr:16/big>>,
+ BinLittle = <<HiSurr:16/little,LoSurr:16/little>>,
+ case unicode:characters_to_binary(BinBig,{utf16,big}) of
+ {error,_,_} ->
+ ok;
+ Other ->
+ exit({leading_lo_surrogate_accepted,BinBig,{utf16,big},Other})
+ end,
+ case unicode:characters_to_binary(BinLittle,{utf16,little}) of
+ {error,_,_} ->
+ ok;
+ Other2 ->
+ exit({leading_lo_surrogate_accepted,BinLittle,{utf16,little},Other2})
+ end,
+ leading_lo_surrogate_bif(HiSurr, LoSurr+1, End);
+leading_lo_surrogate_bif(_, _, _) -> ok.
+
+utf8_illegal_sequences_bif(Config) when is_list(Config) ->
+ setlimit(10),
+ ex_utf8_illegal_sequences_bif(Config),
+ setlimit(default),
+ ex_utf8_illegal_sequences_bif(Config).
+
+ex_utf8_illegal_sequences_bif(Config) when is_list(Config) ->
+ ?line fail_range_bif(16#10FFFF+1, 16#10FFFF+512), %Too large.
+ ?line fail_range_bif(16#D800, 16#DFFF), %Reserved for UTF-16.
+ ?line fail_range_bif(16#FFFE, 16#FFFF), %Reserved (BOM).
+
+ %% Illegal first character.
+ ?line [fail_bif(<<I,16#8F,16#8F,16#8F>>,unicode) || I <- lists:seq(16#80, 16#BF)],
+
+ %% Short sequences.
+ ?line short_sequences_bif(16#80, 16#10FFFF),
+
+ %% Overlong sequences. (Using more bytes than necessary
+ %% is not allowed.)
+ ?line overlong_bif(0, 127, 2),
+ ?line overlong_bif(128, 16#7FF, 3),
+ ?line overlong_bif(16#800, 16#FFFF, 4),
+ ok.
+
+fail_range_bif(Char, End) when Char =< End ->
+ {error,_,_} = unicode:characters_to_binary([Char],unicode),
+ {error,_,_} = unicode:characters_to_binary([Char],unicode,utf16),
+ {error,_,_} = unicode:characters_to_binary([Char],unicode,utf32),
+ Bin = int_to_utf8(Char),
+ fail_bif(Bin,unicode),
+ fail_range_bif(Char+1, End);
+fail_range_bif(_, _) -> ok.
+
+short_sequences_bif(Char, End) ->
+ Step = (End - Char) div erlang:system_info(schedulers) + 1,
+% Step = (End - Char) + 1,
+ PidRefs = short_sequences_bif_1(Char, Step, End),
+ [receive {'DOWN',Ref,process,Pid,Reason} -> normal=Reason end ||
+ {Pid,Ref} <- PidRefs],
+ ok.
+
+short_sequences_bif_1(Char, Step, End) when Char =< End ->
+ CharEnd = lists:min([Char+Step-1,End]),
+ [spawn_monitor(fun() ->
+ io:format("~p - ~p\n", [Char,CharEnd]),
+ do_short_sequences_bif(Char, CharEnd)
+ end)|short_sequences_bif_1(Char+Step, Step, End)];
+short_sequences_bif_1(_, _, _) -> [].
+
+do_short_sequences_bif(Char, End) when Char =< End ->
+ short_sequence_bif(Char),
+ do_short_sequences_bif(Char+1, End);
+do_short_sequences_bif(_, _) -> ok.
+
+short_sequence_bif(I) ->
+ case int_to_utf8(I) of
+ <<S0:3/binary,_:8>> ->
+ <<S1:2/binary,R1:8>> = S0,
+ <<S2:1/binary,_:8>> = S1,
+ incomplete_bif(S0,S0),
+ incomplete_bif(S1,S1),
+ incomplete_bif(S2,S2),
+ only_fail_bif(<<S2/binary,16#7F,R1,R1>>,unicode),
+ only_fail_bif(<<S1/binary,16#7F,R1>>,unicode),
+ only_fail_bif(<<S0/binary,16#7F>>,unicode);
+ <<S0:2/binary,_:8>> ->
+ <<S1:1/binary,R1:8>> = S0,
+ incomplete_bif(S0,S0),
+ incomplete_bif(S1,S1),
+ only_fail_bif(<<S0/binary,16#7F>>,unicode),
+ only_fail_bif(<<S1/binary,16#7F>>,unicode),
+ only_fail_bif(<<S1/binary,16#7F,R1>>,unicode);
+ <<S:1/binary,_:8>> ->
+ incomplete_bif(S,S),
+ only_fail_bif(<<S/binary,16#7F>>,unicode)
+ end.
+
+
+overlong_bif(Char, Last, NumBytes) when Char =< Last ->
+ overlong_bif(Char, NumBytes),
+ overlong_bif(Char+1, Last, NumBytes);
+overlong_bif(_, _, _) -> ok.
+
+overlong_bif(Char, NumBytes) when NumBytes < 5 ->
+ case unicode:characters_to_binary([int_to_utf8(Char, NumBytes)],unicode) of
+ {error,_,_} ->
+ ok;
+ Other->
+ exit({illegal_encoding_accepted,Char,NumBytes,Other})
+ end,
+ overlong_bif(Char, NumBytes+1);
+overlong_bif(_, _) -> ok.
+
+incomplete_bif(Bin,Tail) ->
+ incomplete_bif_1(Bin,Tail),
+ incomplete_bif_1(make_unaligned(Bin),Tail),
+ incomplete_bif_r_1(Bin,Tail),
+ incomplete_bif_r_1(make_unaligned(Bin),Tail),
+ ok.
+
+incomplete_bif_1(Bin,Tail) ->
+ case unicode:characters_to_binary([Bin],unicode) of
+ {incomplete,_,Tail} ->
+ case unicode:characters_to_binary(Bin,unicode) of
+ {incomplete,_,Tail} ->
+ ok;
+ Other0 ->
+ exit({incomplete_encoding_accepted,Bin,Other0})
+ end;
+ Other ->
+ exit({incomplete_encoding_accepted,[Bin],Other})
+ end.
+incomplete_bif_r_1(Bin,Tail) ->
+ case unicode:characters_to_list([Bin],unicode) of
+ {incomplete,_,Tail} ->
+ case unicode:characters_to_list(Bin,unicode) of
+ {incomplete,_,Tail} ->
+ ok;
+ Other ->
+ exit({incomplete_encoding_accepted_r,[Bin],Other})
+ end;
+ Other ->
+ exit({incomplete_encoding_accepted_r,[Bin],Other})
+ end.
+
+only_fail_bif(Bin,Coding) ->
+ only_fail_bif_1(Bin,Coding),
+ only_fail_bif_1(make_unaligned(Bin),Coding),
+ only_fail_bif_r_1(Bin,Coding),
+ only_fail_bif_r_1(make_unaligned(Bin),Coding),
+ ok.
+
+only_fail_bif_r_1(Bin,Coding) ->
+ case unicode:characters_to_list([Bin],Coding) of
+ {error,_,_} ->
+ case unicode:characters_to_list(Bin,Coding) of
+ {error,_,_} ->
+ ok;
+ Other ->
+ exit({faulty_encoding_accepted_r,Bin,Coding,Other})
+ end;
+ Other ->
+ exit({faulty_encoding_accepted_r,Bin,Coding,Other})
+ end.
+only_fail_bif_1(Bin,Coding) ->
+ case unicode:characters_to_binary([Bin],Coding) of
+ {error,_,_} ->
+ case unicode:characters_to_binary(Bin,Coding) of
+ {error,_,_} ->
+ ok;
+ Other0 ->
+ exit({faulty_encoding_accepted,Bin,Coding,Other0})
+ end;
+ Other ->
+ exit({faulty_encoding_accepted,[Bin],Coding,Other})
+ end.
+
+
+
+
+fail_bif(Bin,Coding) ->
+ fail_bif_1(Bin,Coding),
+ fail_bif_1(make_unaligned(Bin),Coding),
+ fail_bif_r_1(Bin,Coding),
+ fail_bif_r_1(make_unaligned(Bin),Coding),
+ ok.
+fail_bif_r_1(Bin,Coding) ->
+ case unicode:characters_to_list(Bin,Coding) of
+ L when is_list(L) ->
+ exit({illegal_encoding_accepted,Bin,Coding});
+ _ ->
+ ok
+ end.
+
+fail_bif_1(Bin,Coding) ->
+ case unicode:characters_to_binary([Bin],Coding) of
+ Bin2 when is_binary(Bin2) ->
+ exit({illegal_encoding_accepted,Bin,Coding});
+ _ ->
+ ok
+ end.
+
+%%
+%% Diverse utilities
+%%
+
+ranges(X,Y,_N) when X >= Y ->
+ [];
+ranges(X,Y,N) when X + N > Y ->
+ [{X,Y}];
+ranges(X,Y,N) ->
+ Upper = X+N,
+ [{X,Upper}|ranges(Upper+1,Y,N)].
+
+splitup(L,_Len,1) ->
+ [L];
+splitup(L,Len,Parts) ->
+ Num = Len div Parts,
+ {A,B} = lists:split(Num,L),
+ [A| splitup(B,Len - Num,Parts - 1)].
+
+flat(List) ->
+ lists:reverse(flat(List,[])).
+
+flat([H|T],Acc) ->
+ NewAcc = flat(H,Acc),
+ flat(T,NewAcc);
+flat([],Acc) ->
+ Acc;
+flat(X,Acc) ->
+ [X|Acc].
+
+flatb(List) ->
+ lists:reverse(flatb(List,[])).
+
+flatb(<<X:8,Rest/binary>>,Acc) ->
+ flatb(Rest,[X|Acc]);
+flatb(<<>>,Acc) ->
+ Acc;
+flatb([H|T],Acc) ->
+ NewAcc = flatb(H,Acc),
+ flatb(T,NewAcc);
+flatb([],Acc) ->
+ Acc;
+flatb(X,Acc) ->
+ [X|Acc].
+flatx(List) ->
+ lists:reverse(flatx(List,[])).
+
+flatx([B1,B2|T],Acc) when is_binary(B1), is_binary(B2) ->
+ flatx([<<B1/binary,B2/binary>>|T],Acc);
+flatx([H|T],Acc) ->
+ NewAcc = flatx(H,Acc),
+ flatx(T,NewAcc);
+flatx([],Acc) ->
+ Acc;
+flatx(X,Acc) ->
+ [X|Acc].
+
+
+unicode_mixed_to_utf8_1(L) ->
+ Flist = flatx([L]),
+ ExpList = [ case is_binary(E) of
+ true ->
+ utf8_to_list(E);
+ false ->
+ E
+ end || E <- Flist ],
+ iolist_to_binary([int_to_utf8(I) || I <- flat(ExpList)]).
+
+unicode_mixed_to_utf8_2(L) ->
+ Flist = flatx([L]),
+ ExpList = [ case is_binary(E) of
+ true ->
+ E;
+ false ->
+ int_to_utf8(E)
+ end || E <- Flist ],
+ iolist_to_binary([ExpList]).
+
+
+
+
+utf8_to_list_bsyntax(<<>>) ->
+ [];
+utf8_to_list_bsyntax(<<C/utf8,R/binary>>) ->
+ [C|utf8_to_list_bsyntax(R)].
+
+list_to_utf8_bsyntax(List,unicode) ->
+ FList = flatx(List),
+ erlang:concat_binary([ if
+ is_binary(E) ->
+ E;
+ true ->
+ <<E/utf8>>
+ end || E <- FList ]);
+list_to_utf8_bsyntax(List,latin1) ->
+ FList = flatb(List),
+ erlang:concat_binary([ <<E/utf8>> || E <- FList ]).
+
+
+
+
+
+%%
+%% Conversion utilities
+%%
+
+int_to_utf16_big(U) when U < 16#10000 ->
+ <<U:16/big>>;
+int_to_utf16_big(U) when U >= 16#10000, U =< 16#10FFFF ->
+ UPrim = U - 16#10000,
+ HI = (16#D800 bor (UPrim bsr 10)),
+ LO = (16#DC00 bor (UPrim band 16#3FF)),
+ <<HI:16/big,LO:16/big>>.
+
+int_to_utf16_little(U) when U < 16#10000 ->
+ <<U:16/little>>;
+int_to_utf16_little(U) when U >= 16#10000, U =< 16#10FFFF ->
+ UPrim = U - 16#10000,
+ HI = (16#D800 bor (UPrim bsr 10)),
+ LO = (16#DC00 bor (UPrim band 16#3FF)),
+ <<HI:16/little,LO:16/little>>.
+
+
+%% This function intentionally allows construction of
+%% UTF-8 sequence in illegal ranges.
+int_to_utf8(I) when I =< 16#7F ->
+ <<I>>;
+int_to_utf8(I) when I =< 16#7FF ->
+ B2 = I,
+ B1 = (I bsr 6),
+ <<1:1,1:1,0:1,B1:5,1:1,0:1,B2:6>>;
+int_to_utf8(I) when I =< 16#FFFF ->
+ B3 = I,
+ B2 = (I bsr 6),
+ B1 = (I bsr 12),
+ <<1:1,1:1,1:1,0:1,B1:4,1:1,0:1,B2:6,1:1,0:1,B3:6>>;
+int_to_utf8(I) when I =< 16#3FFFFF ->
+ B4 = I,
+ B3 = (I bsr 6),
+ B2 = (I bsr 12),
+ B1 = (I bsr 18),
+ <<1:1,1:1,1:1,1:1,0:1,B1:3,1:1,0:1,B2:6,1:1,0:1,B3:6,1:1,0:1,B4:6>>;
+int_to_utf8(I) when I =< 16#3FFFFFF ->
+ B5 = I,
+ B4 = (I bsr 6),
+ B3 = (I bsr 12),
+ B2 = (I bsr 18),
+ B1 = (I bsr 24),
+ <<1:1,1:1,1:1,1:1,1:1,0:1,B1:2,1:1,0:1,B2:6,1:1,0:1,B3:6,1:1,0:1,B4:6,
+ 1:1,0:1,B5:6>>.
+
+utf16_big_to_list_bsyntax(<<>>) ->
+ [];
+utf16_big_to_list_bsyntax(<<C/utf16-big,R/binary>>) ->
+ [C|utf16_big_to_list_bsyntax(R)].
+
+list_to_utf16_big_bsyntax(List,{utf16,big}) ->
+ FList = flatx(List),
+ erlang:concat_binary([ if
+ is_binary(E) ->
+ E;
+ true ->
+ <<E/utf16-big>>
+ end || E <- FList ]);
+list_to_utf16_big_bsyntax(List,latin1) ->
+ FList = flatb(List),
+ erlang:concat_binary([ <<E/utf16-big>> || E <- FList ]).
+
+
+utf16_little_to_list_bsyntax(<<>>) ->
+ [];
+utf16_little_to_list_bsyntax(<<C/utf16-little,R/binary>>) ->
+ [C|utf16_little_to_list_bsyntax(R)].
+
+list_to_utf16_little_bsyntax(List,{utf16,little}) ->
+ FList = flatx(List),
+ erlang:concat_binary([ if
+ is_binary(E) ->
+ E;
+ true ->
+ <<E/utf16-little>>
+ end || E <- FList ]);
+list_to_utf16_little_bsyntax(List,latin1) ->
+ FList = flatb(List),
+ erlang:concat_binary([ <<E/utf16-little>> || E <- FList ]).
+
+
+
+utf32_big_to_list_bsyntax(<<>>) ->
+ [];
+utf32_big_to_list_bsyntax(<<C/utf32-big,R/binary>>) ->
+ [C|utf32_big_to_list_bsyntax(R)].
+
+list_to_utf32_big_bsyntax(List,{utf32,big}) ->
+ FList = flatx(List),
+ erlang:concat_binary([ if
+ is_binary(E) ->
+ E;
+ true ->
+ <<E/utf32-big>>
+ end || E <- FList ]);
+list_to_utf32_big_bsyntax(List,latin1) ->
+ FList = flatb(List),
+ erlang:concat_binary([ <<E/utf32-big>> || E <- FList ]).
+
+
+utf32_little_to_list_bsyntax(<<>>) ->
+ [];
+utf32_little_to_list_bsyntax(<<C/utf32-little,R/binary>>) ->
+ [C|utf32_little_to_list_bsyntax(R)].
+
+list_to_utf32_little_bsyntax(List,{utf32,little}) ->
+ FList = flatx(List),
+ erlang:concat_binary([ if
+ is_binary(E) ->
+ E;
+ true ->
+ <<E/utf32-little>>
+ end || E <- FList ]);
+list_to_utf32_little_bsyntax(List,latin1) ->
+ FList = flatb(List),
+ erlang:concat_binary([ <<E/utf32-little>> || E <- FList ]).
+
+
+
+%% int_to_utf8(I, NumberOfBytes) -> Binary.
+%% This function can be used to construct overlong sequences.
+int_to_utf8(I, 1) ->
+ <<I>>;
+int_to_utf8(I, 2) ->
+ B2 = I,
+ B1 = (I bsr 6),
+ <<1:1,1:1,0:1,B1:5,1:1,0:1,B2:6>>;
+int_to_utf8(I, 3) ->
+ B3 = I,
+ B2 = (I bsr 6),
+ B1 = (I bsr 12),
+ <<1:1,1:1,1:1,0:1,B1:4,1:1,0:1,B2:6,1:1,0:1,B3:6>>;
+int_to_utf8(I, 4) ->
+ B4 = I,
+ B3 = (I bsr 6),
+ B2 = (I bsr 12),
+ B1 = (I bsr 18),
+ <<1:1,1:1,1:1,1:1,0:1,B1:3,1:1,0:1,B2:6,1:1,0:1,B3:6,1:1,0:1,B4:6>>.
+
+utf8_to_list(<<>>) ->
+ [];
+utf8_to_list(Bin) ->
+ N = utf8_siz(Bin),
+ <<X:N/binary,Rest/binary>> = Bin,
+ [utf8_to_int(X) | utf8_to_list(Rest)].
+utf8_siz(<<0:1,_:7,_/binary>>) ->
+ 1;
+utf8_siz(<<1:1,1:1,0:1,_:5,_/binary>>) ->
+ 2;
+utf8_siz(<<1:1,1:1,1:1,0:1,_:4,_/binary>>) ->
+ 3;
+utf8_siz(<<1:1,1:1,1:1,1:1,0:1,_:3,_/binary>>) ->
+ 4.
+
+utf8_to_int(<<0:1,B:7>>) ->
+ B;
+utf8_to_int(<<1:1,1:1,0:1,B1:5,1:1,0:1,B2:6>>) ->
+ (B1 bsl 6) bor B2;
+utf8_to_int(<<1:1,1:1,1:1,0:1,B1:4,1:1,0:1,B2:6,1:1,0:1,B3:6>>) ->
+ (B1 bsl 12) bor (B2 bsl 6) bor B3;
+utf8_to_int(<<1:1,1:1,1:1,1:1,0:1,B1:3,1:1,0:1,
+ B2:6,1:1,0:1,B3:6,1:1,0:1,B4:6>>) ->
+ Res = (B1 bsl 18) bor (B2 bsl 12) bor (B3 bsl 6) bor B4,
+ case Res of
+ X when X > 16#10FFFF ->
+ exit(unsupported_utf8);
+ Other ->
+ Other
+ end;
+utf8_to_int(_) ->
+ exit(unsupported_utf8).
+
+
+utf16_big_to_list(<<>>) ->
+ [];
+utf16_big_to_list(Bin) ->
+ N = utf16_big_siz(Bin),
+ <<X:N/binary,Rest/binary>> = Bin,
+ [utf16_big_to_int(X) | utf16_big_to_list(Rest)].
+
+utf16_big_siz(<<1:1,1:1,0:1,1:1,1:1,0:1,_:1,_:1,_/binary>>) ->
+ 4;
+utf16_big_siz(_) ->
+ 2.
+
+utf16_big_to_int(<<1:1,1:1,0:1,1:1,1:1,0:1,W1:10,1:1,1:1,0:1,1:1,1:1,1:1,W2:10>>) ->
+ ((W1 bsl 10) bor W2) + 16#10000;
+utf16_big_to_int(<<W:16>>) ->
+ W;
+utf16_big_to_int(_) ->
+ exit(unsupported_utf16_big).
+
+utf16_little_to_list(<<>>) ->
+ [];
+utf16_little_to_list(Bin) ->
+ N = utf16_little_siz(Bin),
+ <<X:N/binary,Rest/binary>> = Bin,
+ [utf16_little_to_int(X) | utf16_little_to_list(Rest)].
+utf16_little_siz(<<_:8,1:1,1:1,0:1,1:1,1:1,0:1,_:1,_:1,_/binary>>) ->
+ 4;
+utf16_little_siz(_) ->
+ 2.
+
+utf16_little_to_int(<<W1B:8,1:1,1:1,0:1,1:1,1:1,0:1,W1A:2,W2B:8,1:1,1:1,0:1,1:1,1:1,1:1,W2A:2>>) ->
+ W1 = (W1A bsl 8) bor W1B,
+ W2 = (W2A bsl 8) bor W2B,
+ ((W1 bsl 10) bor W2) + 16#10000;
+utf16_little_to_int(<<W:16/little>>) ->
+ W;
+utf16_little_to_int(_) ->
+ exit(unsupported_utf16_little).
+
+utf32_big_to_list(<<>>) ->
+ [];
+utf32_big_to_list(<<I:32,Rest/binary>>) ->
+ [ I | utf32_big_to_list(Rest)].
+utf32_little_to_list(<<>>) ->
+ [];
+utf32_little_to_list(<<I:32/little,Rest/binary>>) ->
+ [ I | utf32_little_to_list(Rest)].
+
+
+x_to_list_bsyntax(utf8,Bin) ->
+ utf8_to_list_bsyntax(Bin);
+x_to_list_bsyntax({utf16,big},Bin) ->
+ utf16_big_to_list_bsyntax(Bin);
+x_to_list_bsyntax({utf16,little},Bin) ->
+ utf16_little_to_list_bsyntax(Bin);
+x_to_list_bsyntax({utf32,big},Bin) ->
+ utf32_big_to_list_bsyntax(Bin);
+x_to_list_bsyntax({utf32,little},Bin) ->
+ utf32_little_to_list_bsyntax(Bin).
+
+list_to_x_bsyntax(utf8,L,utf8) ->
+ list_to_utf8_bsyntax(L,unicode);
+list_to_x_bsyntax(utf8,L,Enc) ->
+ list_to_utf8_bsyntax(L,Enc);
+list_to_x_bsyntax({utf16,big},L,Enc) ->
+ list_to_utf16_big_bsyntax(L,Enc);
+list_to_x_bsyntax({utf16,little},L,Enc) ->
+ list_to_utf16_little_bsyntax(L,Enc);
+list_to_x_bsyntax({utf32,big},L,Enc) ->
+ list_to_utf32_big_bsyntax(L,Enc);
+list_to_x_bsyntax({utf32,little},L,Enc) ->
+ list_to_utf32_little_bsyntax(L,Enc).
+
+
+make_unaligned(Bin0) when is_binary(Bin0) ->
+% put(c_count,get(c_count)+1),
+ Bin1 = <<0:3,Bin0/binary,31:5>>,
+ Sz = byte_size(Bin0),
+ <<0:3,Bin:Sz/binary,31:5>> = id(Bin1),
+ Bin.
+
+id(I) -> I.
+
+setlimit(X) ->
+ erts_debug:set_internal_state(available_internal_state,true),
+ io:format("Setting loop limit, old: ~p, now set to ~p~n",
+ [erts_debug:set_internal_state(unicode_loop_limit,X),X]).
+
+
+%%
+%% Tracing utility
+%%
+
+%% tr_dump() ->
+%% erlang:display(lists:sort(ets:tab2list(values))).
+
+%% tr_off(Pid) ->
+%% receive after 10000 -> ok end,
+%% tr_dump(),
+%% Ref = erlang:monitor(process,Pid),
+%% exit(Pid,kill),
+%% receive
+%% {'DOWN',Ref,_,_,_} -> ok
+%% end,
+%% ok.
+
+%% tr_on() ->
+%% catch ets:delete(values),
+%% ets:new(values,[named_table,public]),
+%% ets:insert(values,{traps,0}),
+%% catch ets:delete(state),
+%% ets:new(state,[named_table,public]),
+%% Pid = spawn(?MODULE,trace_recv,[values,state]),
+%% erlang:trace(new,true,[garbage_collection,{tracer,Pid},timestamp,call]),
+%% erlang:trace_pattern({erlang,list_to_utf8,2},[{'_',[],[{return_trace}]}],[global]),
+%% Pid.
+
+%% ts_to_int({Mega,Sec,Micro}) ->
+%% ((Mega * 1000000) + Sec) * 1000000 + Micro.
+
+%% trace_recv(Values,State) ->
+%% receive
+%% {trace_ts,Pid,call,_,TS} ->
+%% case ets:lookup(State,{call,Pid}) of
+%% [{{call,Pid},_}] ->
+%% ets:update_counter(values,traps,1);
+%% _ ->
+%% ok
+%% end,
+%% ets:insert(State,{{call,Pid},ts_to_int(TS)});
+%% {trace_ts,Pid,return_from,_,_,TS} ->
+%% case ets:lookup(State,{call,Pid}) of
+%% [{{call,Pid},TS2}] ->
+%% ets:delete(State,{call,Pid}),
+%% Elapsed = ts_to_int(TS) - TS2,
+%% case ets:lookup(Values,Pid) of
+%% [{Pid,GCNum,CallNum,GCTime,CallTime}] ->
+%% ets:insert(Values,{Pid,GCNum,CallNum+1,GCTime,CallTime+Elapsed});
+%% [] ->
+%% ets:insert(Values,{Pid,0,1,0,Elapsed})
+%% end;
+%% _Other ->
+%% erlang:display({what2,Pid})
+%% end;
+%% {trace_ts,Pid,gc_start,_,TS} ->
+%% ets:insert(State,{{gc,Pid},ts_to_int(TS)});
+%% {trace_ts,Pid,gc_end,_,TS} ->
+%% case ets:lookup(State,{gc,Pid}) of
+%% [{{gc,Pid},TS2}] ->
+%% ets:delete(State,{gc,Pid}),
+%% Elapsed = ts_to_int(TS) - TS2,
+%% case ets:lookup(Values,Pid) of
+%% [{Pid,Num,CNum,Time,CTime}] ->
+%% ets:insert(Values,{Pid,Num+1,CNum,Time+Elapsed,CTime});
+%% [] ->
+%% ets:insert(Values,{Pid,1,0,Elapsed,0})
+%% end;
+%% _Other ->
+%% erlang:display({what,Pid})
+%% end;
+%% X ->
+%% erlang:display({trace_recv,X})
+%% end,
+%% trace_recv(Values,State).
diff --git a/lib/stdlib/test/win32reg_SUITE.erl b/lib/stdlib/test/win32reg_SUITE.erl
new file mode 100644
index 0000000000..3ad58eba03
--- /dev/null
+++ b/lib/stdlib/test/win32reg_SUITE.erl
@@ -0,0 +1,89 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(win32reg_SUITE).
+
+-export([all/1,long/1,evil_write/1]).
+-export([ostype/1,fini/1]).
+
+-include("test_server.hrl").
+
+all(suite) ->
+ [{conf,ostype,[long,evil_write],fini}].
+
+ostype(Config) when is_list(Config) ->
+ case os:type() of
+ {win32, _} ->
+ Config;
+ _ ->
+ {skip,"Doesn't run on UNIX."}
+ end.
+fini(Config) when is_list(Config) ->
+ Config.
+
+long(doc) -> "Test long keys and entries (OTP-3446).";
+long(Config) when list(Config) ->
+ ?line Dog = test_server:timetrap(test_server:seconds(10)),
+
+ ?line LongKey = "software\\" ++
+ lists:flatten(lists:duplicate(10, "..\\software\\")) ++
+ "Ericsson\\Erlang",
+ ?line {ok,Reg} = win32reg:open([read,write]),
+ ?line ok = win32reg:change_key(Reg, "\\hklm"),
+ ?line ok = win32reg:change_key(Reg, LongKey),
+ ?line {ok,ErlangKey} = win32reg:current_key(Reg),
+ io:format("Erlang key: ~s", [ErlangKey]),
+
+ %% Write a long value and read it back.
+ ?line TestKey = "test_key",
+ ?line LongValue = lists:concat(["This is a long value generated by the test case ",?MODULE,":long/1. "|lists:duplicate(128, "a")]),
+ ?line ok = win32reg:set_value(Reg, TestKey, LongValue),
+ ?line {ok,LongValue} = win32reg:value(Reg, TestKey),
+
+ %% Done.
+
+ ?line ok = win32reg:close(Reg),
+ ?line test_server:timetrap_cancel(Dog),
+ ok.
+
+evil_write(Config) when list(Config) ->
+ ?line Dog = test_server:timetrap(test_server:seconds(10)),
+
+ ?line Key = "Software\\Ericsson\\Erlang",
+ ?line {ok,Reg} = win32reg:open([read,write]),
+ ?line ok = win32reg:change_key(Reg, "\\hklm"),
+ ?line ok = win32reg:change_key(Reg, Key),
+ ?line {ok,ErlangKey} = win32reg:current_key(Reg),
+ io:format("Erlang key: ~s", [ErlangKey]),
+
+ %% Write keys with different length and read it back.
+ ?line TestKey = "test_key " ++ lists:duplicate(128, $a),
+ evil_write_1(Reg, TestKey),
+
+ %% Done.
+ ?line ok = win32reg:close(Reg),
+ ?line test_server:timetrap_cancel(Dog),
+ ok.
+
+evil_write_1(Reg, [_|[_|_]=Key]=Key0) ->
+ ?line io:format("Key = ~p\n", [Key0]),
+ ?line ok = win32reg:set_value(Reg, Key0, "A good value for me"),
+ ?line {ok,_Val} = win32reg:value(Reg, Key0),
+ ?line ok = win32reg:delete_value(Reg, Key0),
+ evil_write_1(Reg, Key);
+evil_write_1(_, [_]) -> ok.
diff --git a/lib/stdlib/test/y2k_SUITE.erl b/lib/stdlib/test/y2k_SUITE.erl
new file mode 100644
index 0000000000..a574d5e36e
--- /dev/null
+++ b/lib/stdlib/test/y2k_SUITE.erl
@@ -0,0 +1,185 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1998-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%% File: y2k_SUITE.erl
+%% Purpose: Year 2000 tests.
+
+-module(y2k_SUITE).
+
+-include("test_server.hrl").
+
+-export([all/1,
+ date_1999_01_01/1, date_1999_02_28/1,
+ date_1999_09_09/1, date_2000_01_01/1,
+ date_2000_02_29/1, date_2001_01_01/1,
+ date_2001_02_29/1, date_2004_02_29/1
+ ]).
+
+all(doc) ->
+ "This is the test suite for year 2000. Eight dates according "
+ "to Ericsson Corporate Millennium Test Specification "
+ "(LME/DT-98:1097 are tested.";
+
+all(suite) ->
+ [date_1999_01_01,
+ date_1999_02_28,
+ date_1999_09_09,
+ date_2000_01_01,
+ date_2000_02_29,
+ date_2001_01_01,
+ date_2001_02_29,
+ date_2004_02_29
+ ].
+
+date_1999_01_01(doc) ->
+ "#1 : 1999-01-01: test roll-over from 1998-12-31 to 1999-01-01.";
+date_1999_01_01(suite) ->
+ [];
+date_1999_01_01(Config) when is_list(Config) ->
+ ?line Date = {1998, 12, 31}, NextDate = {1999, 1, 1},
+ ?line match(next_date(Date), NextDate),
+ TZD = tzd(Date),
+ if
+ TZD > 0 ->
+ ?line Time = {24 - TZD, 0, 0},
+ ?line {NDate, _NTime} =
+ erlang:localtime_to_universaltime({Date, Time}),
+ ?line match(NDate, NextDate);
+ TZD < 0 ->
+ ?line Time = {24 + TZD, 0, 0},
+ ?line {NDate, _NTime} =
+ erlang:universaltime_to_localtime({Date, Time}),
+ ?line match(NDate, NextDate);
+ true ->
+ ok
+ end.
+
+date_1999_02_28(doc) ->
+ "#2 : 1999-02-28: test roll-over from 1999-02-28 to 1999-03-01.";
+date_1999_02_28(suite) ->
+ [];
+date_1999_02_28(Config) when is_list(Config) ->
+ ?line Date = {1999, 2, 28}, NextDate = {1999, 3, 1},
+ ?line match(next_date(Date), NextDate),
+ ?line match(tz_next_date(Date), NextDate).
+
+date_1999_09_09(doc) ->
+ "#3 : 1999-09-09: test roll-over from 1999-09-08 to 1999-09-09.";
+date_1999_09_09(suite) ->
+ [];
+date_1999_09_09(Config) when is_list(Config) ->
+ ?line Date = {1999, 9, 8}, NextDate = {1999, 9, 9},
+ ?line match(next_date(Date), NextDate),
+ ?line match(tz_next_date(Date), NextDate).
+
+date_2000_01_01(doc) ->
+ "#4 : 2000-01-01: test roll-over from 1999-12-31 to 2000-01-01 to "
+ "2000-01-02.";
+date_2000_01_01(suite) ->
+ [];
+date_2000_01_01(Config) when is_list(Config) ->
+ ?line Date = {1999, 12, 31}, NextDate = {2000, 1, 1},
+ ?line match(next_date(Date), NextDate),
+ ?line match(tz_next_date(Date), NextDate),
+ ?line NextDate1 = {2000, 1, 2},
+ ?line match(next_date(NextDate), NextDate1),
+ ?line match(tz_next_date(NextDate), NextDate1).
+
+date_2000_02_29(doc) ->
+ "#5 : 2000-02-29: test roll-over from 2000-02-28 to 2000-02-29 to "
+ "2000-03-01.";
+date_2000_02_29(suite) ->
+ [];
+date_2000_02_29(Config) when is_list(Config) ->
+ ?line Date = {2000, 2, 28}, NextDate = {2000, 2, 29},
+ ?line match(next_date(Date), NextDate),
+ ?line match(tz_next_date(Date), NextDate),
+ ?line NextDate1 = {2000, 3, 1},
+ ?line match(next_date(NextDate), NextDate1),
+ ?line match(tz_next_date(NextDate), NextDate1).
+
+date_2001_01_01(doc) ->
+ "#6 : 2001-01-01: test roll-over from 2000-12-31 to 2001-01-01.";
+date_2001_01_01(suite) ->
+ [];
+date_2001_01_01(Config) when is_list(Config) ->
+ ?line Date = {2000, 12, 31}, NextDate = {2001, 1, 1},
+ ?line match(next_date(Date), NextDate),
+ ?line match(tz_next_date(Date), NextDate).
+
+date_2001_02_29(doc) ->
+ "#7 : 2001-02-29: test roll-over from 2001-02-28 to 2001-03-01.";
+date_2001_02_29(suite) ->
+ [];
+date_2001_02_29(Config) when is_list(Config) ->
+ ?line Date = {2001, 2, 28}, NextDate = {2001, 3, 1},
+ ?line match(next_date(Date), NextDate),
+ ?line match(tz_next_date(Date), NextDate).
+
+date_2004_02_29(doc) ->
+ "#8 : 2004-02-29: test roll-over from 2004-02-28 to 2004-02-29 to "
+ "2004-03-01.";
+date_2004_02_29(suite) ->
+ [];
+date_2004_02_29(Config) when is_list(Config) ->
+ ?line Date = {2004, 2, 28}, NextDate = {2004, 2, 29},
+ ?line match(next_date(Date), NextDate),
+ ?line match(tz_next_date(Date), NextDate),
+ ?line NextDate1 = {2004, 3, 1},
+ ?line match(next_date(NextDate), NextDate1),
+ ?line match(tz_next_date(NextDate), NextDate1).
+
+%%
+%% Local functions
+%%
+next_date(Date) ->
+ calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(Date) + 1).
+%%
+%% timezonediff
+%%
+tzd(Date) ->
+ ?line {_LDate, {LH, _LM, _LS}} =
+ erlang:universaltime_to_localtime({Date, {12, 0, 0}}),
+ 12 - LH.
+
+tz_next_date(Date) ->
+ TZD = tzd(Date),
+ if
+ TZD > 0 ->
+ ?line Time = {24 - TZD, 0, 0},
+ ?line {NDate, _NTime} =
+ erlang:localtime_to_universaltime({Date, Time}),
+ ?line NDate;
+ TZD < 0 ->
+ ?line Time = {24 + TZD, 0, 0},
+ ?line {NDate, _NTime} =
+ erlang:universaltime_to_localtime({Date, Time}),
+ ?line NDate;
+ true ->
+ Date
+ end.
+
+%%
+%% match({X, X}) ->
+%% ok.
+
+match(X, X) ->
+ ok.
+
+
+
diff --git a/lib/stdlib/test/zip_SUITE.erl b/lib/stdlib/test/zip_SUITE.erl
new file mode 100644
index 0000000000..55cbd277ef
--- /dev/null
+++ b/lib/stdlib/test/zip_SUITE.erl
@@ -0,0 +1,759 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(zip_SUITE).
+
+-export([all/1, borderline/1, atomic/1,
+ bad_zip/1, unzip_from_binary/1, unzip_to_binary/1,
+ zip_to_binary/1,
+ unzip_options/1, zip_options/1, list_dir_options/1, aliases/1,
+ openzip_api/1, zip_api/1, unzip_jar/1,
+ compress_control/1]).
+
+-include("test_server.hrl").
+-include("test_server_line.hrl").
+-include_lib("kernel/include/file.hrl").
+-include_lib("stdlib/include/zip.hrl").
+
+all(suite) -> [borderline, atomic, bad_zip,
+ unzip_from_binary, unzip_to_binary,
+ zip_to_binary,
+ unzip_options, zip_options, list_dir_options, aliases,
+ openzip_api, zip_api, unzip_jar,
+ compress_control].
+
+borderline(doc) ->
+ ["Test creating, listing and extracting one file from an archive "
+ "multiple times with different file sizes. Also check that the "
+ "modification date of the extracted file has survived."];
+borderline(Config) when is_list(Config) ->
+ RootDir = ?config(priv_dir, Config),
+ TempDir = filename:join(RootDir, "borderline"),
+ ok = file:make_dir(TempDir),
+
+ Record = 512,
+ Block = 20 * Record,
+
+ lists:foreach(fun(Size) -> borderline_test(Size, TempDir) end,
+ [0, 1, 10, 13, 127, 333, Record-1, Record, Record+1,
+ Block-Record-1, Block-Record, Block-Record+1,
+ Block-1, Block, Block+1,
+ Block+Record-1, Block+Record, Block+Record+1]),
+
+ %% Clean up.
+ delete_files([TempDir]),
+ ok.
+
+borderline_test(Size, TempDir) ->
+ Archive = filename:join(TempDir, "ar_"++integer_to_list(Size)++".zip"),
+ Name = filename:join(TempDir, "file_"++integer_to_list(Size)),
+ io:format("Testing size ~p", [Size]),
+
+ %% Create a file and archive it.
+ {_, _, X0} = erlang:now(),
+ file:write_file(Name, random_byte_list(X0, Size)),
+ {ok, Archive} = zip:zip(Archive, [Name]),
+ ok = file:delete(Name),
+
+ %% Verify listing and extracting.
+ {ok, [#zip_comment{comment = []},
+ #zip_file{name = Name,
+ info = Info,
+ offset = 0,
+ comp_size = _}]} = zip:list_dir(Archive),
+ Size = Info#file_info.size,
+ {ok, [Name]} = zip:extract(Archive, [verbose]),
+
+ %% Verify contents of extracted file.
+ {ok, Bin} = file:read_file(Name),
+ true = match_byte_list(X0, binary_to_list(Bin)),
+
+
+ %% Verify that Unix zip can read it. (if we have a unix zip that is!)
+ unzip_list(Archive, Name),
+
+ ok.
+
+unzip_list(Archive, Name) ->
+ case os:find_executable("unzip") of
+ Unzip when is_list(Unzip) ->
+ unzip_list1(Archive, Name);
+ _ ->
+ ok
+ end.
+
+unzip_list1(Archive, Name) ->
+ Expect = Name ++ "\n",
+ cmd_expect("unzip -Z -1 " ++ Archive, Expect).
+
+cmd_expect(Cmd, Expect) ->
+ Port = open_port({spawn, make_cmd(Cmd)}, [stream, in, eof]),
+ get_data(Port, Expect).
+
+get_data(Port, Expect) ->
+ receive
+ {Port, {data, Bytes}} ->
+ get_data(Port, match_output(Bytes, Expect, Port));
+ {Port, eof} ->
+ Port ! {self(), close},
+ receive
+ {Port, closed} ->
+ true
+ end,
+ receive
+ {'EXIT', Port, _} ->
+ ok
+ after 1 -> % force context switch
+ ok
+ end,
+ match_output(eof, Expect, Port)
+ end.
+
+match_output([C|Output], [C|Expect], Port) ->
+ match_output(Output, Expect, Port);
+match_output([_|_], [_|_], Port) ->
+ kill_port_and_fail(Port, badmatch);
+match_output([X|Output], [], Port) ->
+ kill_port_and_fail(Port, {too_much_data, [X|Output]});
+match_output([], Expect, _Port) ->
+ Expect;
+match_output(eof, [], _Port) ->
+ [];
+match_output(eof, Expect, Port) ->
+ kill_port_and_fail(Port, {unexpected_end_of_input, Expect}).
+
+kill_port_and_fail(Port, Reason) ->
+ unlink(Port),
+ exit(Port, die),
+ test_server:fail(Reason).
+
+make_cmd(Cmd) ->
+ Cmd.
+%% case os:type() of
+%% {win32, _} -> lists:concat(["cmd /c", Cmd]);
+%% {unix, _} -> lists:concat(["sh -c '", Cmd, "'"])
+%% end.
+
+%% Verifies a random byte list.
+
+match_byte_list(X0, [Byte|Rest]) ->
+ X = next_random(X0),
+ case (X bsr 26) band 16#ff of
+ Byte -> match_byte_list(X, Rest);
+ _ -> false
+ end;
+match_byte_list(_, []) ->
+ true.
+
+%% Generates a random byte list.
+
+random_byte_list(X0, Count) ->
+ random_byte_list(X0, Count, []).
+
+random_byte_list(X0, Count, Result) when Count > 0->
+ X = next_random(X0),
+ random_byte_list(X, Count-1, [(X bsr 26) band 16#ff|Result]);
+random_byte_list(_X, 0, Result) ->
+ lists:reverse(Result).
+
+%% This RNG is from line 21 on page 102 in Knuth: The Art of Computer Programming,
+%% Volume II, Seminumerical Algorithms.
+
+next_random(X) ->
+ (X*17059465+1) band 16#fffffffff.
+
+atomic(doc) ->
+ ["Test the 'atomic' operations: zip/unzip/list_dir, on archives."
+ "Also test the 'cooked' option."];
+atomic(suite) -> [];
+atomic(Config) when list(Config) ->
+ ok = file:set_cwd(?config(priv_dir, Config)),
+ DataFiles = data_files(),
+ Names = [Name || {Name,_,_} <- DataFiles],
+ io:format("Names: ~p", [Names]),
+
+ %% Create a zip archive.
+
+ Zip2 = "zip.zip",
+ {ok, Zip2} = zip:zip(Zip2, Names, []),
+ Names = names_from_list_dir(zip:list_dir(Zip2)),
+
+ %% Same test again, but this time created with 'cooked'
+
+ Zip3 = "cooked.zip",
+ {ok, Zip3} = zip:zip(Zip3, Names, [cooked]),
+ Names = names_from_list_dir(zip:list_dir(Zip3)),
+ Names = names_from_list_dir(zip:list_dir(Zip3, [cooked])),
+
+ %% Clean up.
+ delete_files([Zip2,Zip3|Names]),
+
+ ok.
+
+openzip_api(doc) ->
+ ["Test the openzip_open/2, openzip_get/1, openzip_get/2, openzip_close/1 "
+ "and openzip_list_dir/1 functions."];
+openzip_api(suite) -> [];
+openzip_api(Config) when list(Config) ->
+ ok = file:set_cwd(?config(priv_dir, Config)),
+ DataFiles = data_files(),
+ Names = [Name || {Name, _, _} <- DataFiles],
+ io:format("Names: ~p", [Names]),
+
+ %% Create a zip archive
+
+ Zip = "zip.zip",
+ {ok, Zip} = zip:zip(Zip, Names, []),
+
+ %% Open archive
+ {ok, OpenZip} = zip:openzip_open(Zip, [memory]),
+
+ %% List dir
+ Names = names_from_list_dir(zip:openzip_list_dir(OpenZip)),
+
+ %% Get a file
+ Name1 = hd(Names),
+ {ok, Data1} = file:read_file(Name1),
+ {ok, {Name1, Data1}} = zip:openzip_get(Name1, OpenZip),
+
+ %% Get all files
+ FilesDatas = lists:map(fun(Name) -> {ok, B} = file:read_file(Name),
+ {Name, B} end, Names),
+ {ok, FilesDatas} = zip:openzip_get(OpenZip),
+
+ %% Close
+ ok = zip:openzip_close(OpenZip),
+
+ %% Clean up.
+ delete_files([Names]),
+
+ ok.
+
+zip_api(doc) ->
+ ["Test the zip_open/2, zip_get/1, zip_get/2, zip_close/1 "
+ "and zip_list_dir/1 functions."];
+zip_api(suite) -> [];
+zip_api(Config) when list(Config) ->
+ ok = file:set_cwd(?config(priv_dir, Config)),
+ DataFiles = data_files(),
+ Names = [Name || {Name, _, _} <- DataFiles],
+ io:format("Names: ~p", [Names]),
+
+ %% Create a zip archive
+ Zip = "zip.zip",
+ {ok, Zip} = zip:zip(Zip, Names, []),
+
+ %% Open archive
+ {ok, ZipSrv} = zip:zip_open(Zip, [memory]),
+
+ %% List dir
+ Names = names_from_list_dir(zip:zip_list_dir(ZipSrv)),
+
+ %% Get a file
+ Name1 = hd(Names),
+ {ok, Data1} = file:read_file(Name1),
+ {ok, {Name1, Data1}} = zip:zip_get(Name1, ZipSrv),
+
+ %% Get all files
+ FilesDatas = lists:map(fun(Name) -> {ok, B} = file:read_file(Name),
+ {Name, B} end, Names),
+ {ok, FilesDatas} = zip:zip_get(ZipSrv),
+
+ %% Close
+ ok = zip:zip_close(ZipSrv),
+
+ %% Clean up.
+ delete_files([Names]),
+
+ ok.
+
+unzip_options(doc) ->
+ ["Test options for unzip, only cwd and file_list currently"];
+unzip_options(suite) ->
+ [];
+unzip_options(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+ PrivDir = ?config(priv_dir, Config),
+ Long = filename:join(DataDir, "abc.zip"),
+
+ %% create a temp directory
+ Subdir = filename:join(PrivDir, "t"),
+ ok = file:make_dir(Subdir),
+
+ FList = ["quotes/rain.txt","wikipedia.txt"],
+
+ %% Unzip a zip file in Subdir
+ ?line {ok, RetList} = zip:unzip(Long, [{cwd, Subdir},
+ {file_list, FList}]),
+
+ %% Verify.
+ ?line true = (length(FList) =:= length(RetList)),
+ ?line lists:foreach(fun(F)-> {ok,B} = file:read_file(filename:join(DataDir, F)),
+ {ok,B} = file:read_file(filename:join(Subdir, F)) end,
+ FList),
+ ?line lists:foreach(fun(F)-> ok = file:delete(F) end,
+ RetList),
+
+ %% Clean up and verify no more files.
+ ?line 0 = delete_files([Subdir]),
+ ok.
+
+unzip_jar(doc) ->
+ ["Test unzip a jar file (OTP-7382)"];
+unzip_jar(suite) ->
+ [];
+unzip_jar(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+ PrivDir = ?config(priv_dir, Config),
+ JarFile = filename:join(DataDir, "test.jar"),
+
+ %% create a temp directory
+ Subdir = filename:join(PrivDir, "jartest"),
+ ok = file:make_dir(Subdir),
+ ok = file:set_cwd(Subdir),
+
+ FList = ["META-INF/MANIFEST.MF","test.txt"],
+
+ {ok, RetList} = zip:unzip(JarFile),
+
+ %% Verify.
+ ?line lists:foreach(fun(F)-> {ok,B} = file:read_file(filename:join(DataDir, F)),
+ {ok,B} = file:read_file(filename:join(Subdir, F)) end,
+ FList),
+ ?line lists:foreach(fun(F)-> ok = file:delete(F) end,
+ RetList),
+
+ %% Clean up and verify no more files.
+ ?line 0 = delete_files([Subdir]),
+ ok.
+
+zip_options(doc) ->
+ ["Test the options for unzip, only cwd currently"];
+zip_options(suite) ->
+ [];
+zip_options(Config) when is_list(Config) ->
+ PrivDir = ?config(priv_dir, Config),
+ ok = file:set_cwd(PrivDir),
+ DataFiles = data_files(),
+ Names = [Name || {Name, _, _} <- DataFiles],
+
+ %% Make sure cwd is not where we get the files
+ ok = file:set_cwd(?config(data_dir, Config)),
+
+ %% Create a zip archive
+ {ok, Zip} = zip:zip("filename_not_used.zip", Names, [memory, {cwd, PrivDir}]),
+
+ %% Open archive
+ {ok, ZipSrv} = zip:zip_open(Zip, [memory]),
+
+ %% List dir
+ Names = names_from_list_dir(zip:zip_list_dir(ZipSrv)),
+
+ %% Get a file
+ Name1 = hd(Names),
+ {ok, Data1} = file:read_file(filename:join(PrivDir, Name1)),
+ {ok, {Name1, Data1}} = zip:zip_get(Name1, ZipSrv),
+
+ %% Get all files
+ FilesDatas = lists:map(fun(Name) -> {ok, B} = file:read_file(filename:join(PrivDir, Name)),
+ {Name, B} end, Names),
+ {ok, FilesDatas} = zip:zip_get(ZipSrv),
+
+ %% Close
+ ok = zip:zip_close(ZipSrv),
+
+ %% Clean up.
+ delete_files([Names]),
+
+ ok.
+
+list_dir_options(doc) ->
+ ["Test the options for list_dir... one day"];
+list_dir_options(suite) ->
+ [];
+list_dir_options(Config) when is_list(Config) ->
+ ok.
+
+
+
+
+%% convert zip_info as returned from list_dir to a list of names
+names_from_list_dir({ok, Info}) ->
+ names_from_list_dir(Info);
+names_from_list_dir(Info) ->
+ tl(lists:map(fun(#zip_file{name = Name}) -> Name;
+ (_) -> ok end, Info)).
+
+%% Returns a sequence of characters.
+char_seq(N, First) ->
+ char_seq(N, First, []).
+
+char_seq(0, _, Result) ->
+ Result;
+char_seq(N, C, Result) when C < 127 ->
+ char_seq(N-1, C+1, [C|Result]);
+char_seq(N, _, Result) ->
+ char_seq(N, $!, Result).
+
+data_files() ->
+ Files = [{"first_file", 1555, $a},
+ {"small_file", 7, $d},
+ {"big_file", 23875, $e},
+ {"last_file", 7500, $g}],
+ create_files(Files),
+ Files.
+
+create_files([{Name, dir, _First}|Rest]) ->
+ ok = file:make_dir(Name),
+ create_files(Rest);
+create_files([{Name, Size, First}|Rest]) when is_integer(Size) ->
+ ok = file:write_file(Name, char_seq(Size, First)),
+ create_files(Rest);
+create_files([]) ->
+ ok.
+
+%% make_dirs([Dir|Rest], []) ->
+%% ok = file:make_dir(Dir),
+%% make_dirs(Rest, Dir);
+%% make_dirs([Dir|Rest], Parent) ->
+%% Name = filename:join(Parent, Dir),
+%% ok = file:make_dir(Name),
+%% make_dirs(Rest, Name);
+%% make_dirs([], Dir) ->
+%% Dir.
+
+bad_zip(doc) ->
+ ["Try zip:unzip/1 on some corrupted zip files."];
+bad_zip(Config) when is_list(Config) ->
+ ok = file:set_cwd(?config(priv_dir, Config)),
+ try_bad("bad_crc", {bad_crc, "abc.txt"}, Config),
+ try_bad("bad_central_directory", bad_central_directory, Config),
+ try_bad("bad_file_header", bad_file_header, Config),
+ try_bad("bad_eocd", bad_eocd, Config),
+ try_bad("enoent", enoent, Config),
+ GetNotFound = fun(A) ->
+ {ok, O} = zip:openzip_open(A, []),
+ zip:openzip_get("not_here", O)
+ end,
+ try_bad("abc", file_not_found, GetNotFound, Config),
+ ok.
+
+try_bad(N, R, Config) ->
+ try_bad(N, R, fun(A) -> io:format("name : ~p\n", [A]),
+ zip:unzip(A, [verbose]) end, Config).
+
+try_bad(Name0, Reason, What, Config) ->
+ %% Intentionally no macros here.
+
+ DataDir = ?config(data_dir, Config),
+ Name = Name0 ++ ".zip",
+ io:format("~nTrying ~s", [Name]),
+ Full = filename:join(DataDir, Name),
+ Expected = {error, Reason},
+ case What(Full) of
+ Expected ->
+ io:format("Result: ~p\n", [Expected]);
+ Other ->
+ io:format("unzip/2 returned ~p (expected ~p)\n", [Other, Expected]),
+ test_server:fail({bad_return_value, Other})
+ end.
+
+unzip_to_binary(doc) ->
+ ["Test extracting to binary with memory option."];
+unzip_to_binary(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+ PrivDir = ?config(priv_dir, Config),
+
+ delete_all_in(PrivDir),
+ file:set_cwd(PrivDir),
+ Long = filename:join(DataDir, "abc.zip"),
+
+ %% Unzip a zip file into a binary
+ {ok, FBList} = zip:unzip(Long, [memory]),
+
+ %% Verify.
+ lists:foreach(fun({F,B}) -> {ok,B}=file:read_file(filename:join(DataDir, F))
+ end, FBList),
+
+ %% Make sure no files created in cwd
+ {ok,[]} = file:list_dir(PrivDir),
+
+ ok.
+
+zip_to_binary(doc) ->
+ ["Test compressing to binary with memory option."];
+zip_to_binary(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+ PrivDir = ?config(priv_dir, Config),
+ delete_all_in(PrivDir),
+ file:set_cwd(PrivDir),
+ FileName = "abc.txt",
+ ZipName = "t.zip",
+ FilePath = filename:join(DataDir, FileName),
+ {ok, _Size} = file:copy(FilePath, FileName),
+
+ %% Zip to a binary archive
+ {ok, {ZipName, ZipB}} = zip:zip(ZipName, [FileName], [memory]),
+
+ %% Make sure no files created in cwd
+ {ok,[FileName]} = file:list_dir(PrivDir),
+
+ %% Zip to a file
+ {ok, ZipName} = zip:zip(ZipName, [FileName]),
+
+ %% Verify.
+ {ok, ZipB} = file:read_file(ZipName),
+ {ok, FData} = file:read_file(FileName),
+ {ok, [{FileName, FData}]} = zip:unzip(ZipB, [memory]),
+
+ %% Clean up.
+ delete_files([FileName, ZipName]),
+
+ ok.
+
+aliases(doc) ->
+ ["Test using the aliases, extract/2, table/2 and create/3"];
+aliases(Config) when is_list(Config) ->
+ {_, _, X0} = erlang:now(),
+ Size = 100,
+ B = list_to_binary(random_byte_list(X0, Size)),
+ %% create
+ {ok, {"z.zip", ZArchive}} = zip:create("z.zip", [{"b", B}], [memory]),
+ %% extract
+ {ok, [{"b", B}]} = zip:extract(ZArchive, [memory]),
+ %% table
+ {ok, [#zip_comment{comment = _}, #zip_file{name = "b",
+ info = FI,
+ comp_size = _,
+ offset = 0}]} =
+ zip:table(ZArchive),
+ Size = FI#file_info.size,
+
+ ok.
+
+
+
+unzip_from_binary(doc) ->
+ ["Test extracting a zip archive from a binary."];
+unzip_from_binary(Config) when list(Config) ->
+ DataDir = ?config(data_dir, Config),
+ PrivDir = ?config(priv_dir, Config),
+ ExtractDir = filename:join(PrivDir, "extract_from_binary"),
+ ok = file:make_dir(ExtractDir),
+ Archive = filename:join(ExtractDir, "abc.zip"),
+ {ok, _Size} = file:copy(filename:join(DataDir, "abc.zip"), Archive),
+ FileName = "abc.txt",
+ Quote = "quotes/rain.txt",
+ Wikipedia = "wikipedia.txt",
+ EmptyFile = "emptyFile",
+ file:set_cwd(ExtractDir),
+
+ %% Read a zip file into a binary and extract from the binary.
+ {ok, Bin} = file:read_file(Archive),
+ {ok, [FileName,Quote,Wikipedia,EmptyFile]} = zip:unzip(Bin),
+
+ %% Verify.
+ DestFilename = filename:join(ExtractDir, "abc.txt"),
+ {ok, Data} = file:read_file(filename:join(DataDir, FileName)),
+ {ok, Data} = file:read_file(DestFilename),
+
+ DestQuote = filename:join([ExtractDir, "quotes", "rain.txt"]),
+ {ok, QuoteData} = file:read_file(filename:join(DataDir, Quote)),
+ {ok, QuoteData} = file:read_file(DestQuote),
+
+ %% Clean up.
+ delete_files([DestFilename, DestQuote, Archive, ExtractDir]),
+ ok.
+
+%% oac_files() ->
+%% Files = [{"oac_file", 1459, $x},
+%% {"oac_small", 99, $w},
+%% {"oac_big", 33896, $A}],
+%% create_files(Files),
+%% Files.
+
+%% Delete the given list of files and directories.
+%% Return total number of deleted files (not directories)
+delete_files(List) ->
+ do_delete_files(List, 0).
+do_delete_files([],Cnt) ->
+ Cnt;
+do_delete_files([Item|Rest], Cnt) ->
+ case file:delete(Item) of
+ ok ->
+ DelCnt = 1;
+ {error,eperm} ->
+ file:change_mode(Item, 8#777),
+ DelCnt = delete_files(filelib:wildcard(filename:join(Item, "*"))),
+ file:del_dir(Item);
+ {error,eacces} ->
+ %% We'll see about that!
+ file:change_mode(Item, 8#777),
+ case file:delete(Item) of
+ ok ->
+ DelCnt = 1;
+ {error,_} ->
+ erlang:yield(),
+ file:change_mode(Item, 8#777),
+ file:delete(Item),
+ DelCnt = 1
+ end;
+ {error,_} ->
+ DelCnt = 0
+ end,
+ do_delete_files(Rest, Cnt + DelCnt).
+
+delete_all_in(Dir) ->
+ {ok, Files} = file:list_dir(Dir),
+ delete_files(lists:map(fun(F) -> filename:join(Dir,F) end,
+ Files)).
+
+compress_control(doc) ->
+ ["Test control of which files that should be compressed"];
+compress_control(suite) -> [];
+compress_control(Config) when list(Config) ->
+ ok = file:set_cwd(?config(priv_dir, Config)),
+ Dir = "compress_control",
+ Files = [
+ {Dir, dir, $d},
+ {filename:join([Dir, "first_file.txt"]), 10000, $f},
+ {filename:join([Dir, "a_dir"]), dir, $d},
+ {filename:join([Dir, "a_dir", "zzz.zip"]), 10000, $z},
+ {filename:join([Dir, "a_dir", "lll.lzh"]), 10000, $l},
+ {filename:join([Dir, "a_dir", "eee.exe"]), 10000, $e},
+ {filename:join([Dir, "a_dir", "ggg.arj"]), 10000, $g},
+ {filename:join([Dir, "a_dir", "b_dir"]), dir, $d},
+ {filename:join([Dir, "a_dir", "b_dir", "ggg.arj"]), 10000, $a},
+ {filename:join([Dir, "last_file.txt"]), 10000, $l}
+ ],
+
+ test_compress_control(Dir,
+ Files,
+ [{compress, []}],
+ []),
+
+ test_compress_control(Dir,
+ Files,
+ [{uncompress, all}],
+ []),
+
+ test_compress_control(Dir,
+ Files,
+ [{uncompress, []}],
+ [".txt", ".exe", ".zip", ".lzh", ".arj"]),
+
+ test_compress_control(Dir,
+ Files,
+ [],
+ [".txt", ".exe"]),
+
+ test_compress_control(Dir,
+ Files,
+ [{uncompress, {add, [".exe"]}},
+ {uncompress, {del, [".zip", "arj"]}}],
+ [".txt", ".zip", "arj"]),
+
+ test_compress_control(Dir,
+ Files,
+ [{uncompress, []},
+ {uncompress, {add, [".exe"]}},
+ {uncompress, {del, [".zip", "arj"]}}],
+ [".txt", ".zip", ".lzh", ".arj"]),
+
+ ok.
+
+test_compress_control(Dir, Files, ZipOptions, Expected) ->
+ %% Cleanup
+ Zip = "zip.zip",
+ Names = [N || {N, _, _} <- Files],
+ delete_files([Zip]),
+ delete_files(lists:reverse(Names)),
+
+ create_files(Files),
+ {ok, Zip} = zip:create(Zip, [Dir], ZipOptions),
+
+ {ok, OpenZip} = zip:openzip_open(Zip, [memory]),
+ {ok,[#zip_comment{comment = ""} | ZipList]} = zip:openzip_list_dir(OpenZip),
+ io:format("compress_control: -> ~p -> ~p\n -> ~pn", [Expected, ZipOptions, ZipList]),
+ verify_compression(Files, ZipList, OpenZip, ZipOptions, Expected),
+ ok = zip:openzip_close(OpenZip),
+
+ %% Cleanup
+ delete_files([Zip]),
+ delete_files(lists:reverse(Names)), % Remove plain files before directories
+
+ ok.
+
+verify_compression([{Name, Kind, _Filler} | Files], ZipList, OpenZip, ZipOptions, Expected) ->
+ {Name2, BinSz} =
+ case Kind of
+ dir ->
+ {Name ++ "/", 0};
+ _ ->
+ {ok, {Name, Bin}} = zip:openzip_get(Name, OpenZip),
+ {Name, size(Bin)}
+ end,
+ {Name2, {value, ZipFile}} = {Name2, lists:keysearch(Name2, #zip_file.name, ZipList)},
+ #zip_file{info = #file_info{size = InfoSz, type = InfoType}, comp_size = InfoCompSz} = ZipFile,
+
+ Ext = filename:extension(Name),
+ IsComp = is_compressed(Ext, Kind, ZipOptions),
+ ExpComp = lists:member(Ext, Expected),
+ case {Name, Kind, InfoType, IsComp, ExpComp, BinSz, InfoSz, InfoCompSz} of
+ {_, dir, directory, false, _, Sz, Sz, Sz} when Sz =:= BinSz -> ok;
+ {_, Sz, regular, false, false, Sz, Sz, Sz} when Sz =:= BinSz -> ok;
+ {_, Sz, regular, true, true, Sz, Sz, OtherSz} when Sz =:= BinSz, OtherSz =/= BinSz -> ok
+ end,
+ verify_compression(Files, ZipList -- [ZipFile], OpenZip, ZipOptions, Expected);
+verify_compression([], [], _OpenZip, _ZipOptions, _Expected) ->
+ ok.
+
+is_compressed(_Ext, dir, _Options) ->
+ false;
+is_compressed(Ext, _Sz, Options) ->
+ CompressOpt =
+ case [What || {compress, What} <- Options] of
+ [] -> all;
+ CompressOpts-> extensions(CompressOpts, all)
+ end,
+ DoCompress = (CompressOpt =:= all) orelse lists:member(Ext, CompressOpt),
+ Default = [".Z", ".zip", ".zoo", ".arc", ".lzh", ".arj"],
+ UncompressOpt =
+ case [What || {uncompress, What} <- Options] of
+ [] -> Default;
+ UncompressOpts-> extensions(UncompressOpts, Default)
+ end,
+ DoUncompress = (UncompressOpt =:= all) orelse lists:member(Ext, UncompressOpt),
+ DoCompress andalso not DoUncompress.
+
+extensions([H | T], Old) ->
+ case H of
+ all ->
+ extensions(T, H);
+ H when is_list(H) ->
+ extensions(T, H);
+ {add, New} when is_list(New), is_list(Old) ->
+ extensions(T, Old ++ New);
+ {del, New} when is_list(New), is_list(Old) ->
+ extensions(T, Old -- New);
+ _ ->
+ extensions(T, Old)
+ end;
+extensions([], Old) ->
+ Old.
+
diff --git a/lib/stdlib/test/zip_SUITE_data/META-INF/MANIFEST.MF b/lib/stdlib/test/zip_SUITE_data/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..f334c5d368
--- /dev/null
+++ b/lib/stdlib/test/zip_SUITE_data/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Created-By: 1.4.2_08 (Sun Microsystems Inc.)
+
diff --git a/lib/stdlib/test/zip_SUITE_data/abc.txt b/lib/stdlib/test/zip_SUITE_data/abc.txt
new file mode 100644
index 0000000000..da0202e539
--- /dev/null
+++ b/lib/stdlib/test/zip_SUITE_data/abc.txt
@@ -0,0 +1,23 @@
+Introduction
+
+abc is a language designed to notate tunes in an ascii
+format. It was designed primarily for folk and traditional tunes of
+Western European origin (such as English, Irish and Scottish) which
+can be written on one stave in standard classical notation. However,
+it is extendible to many other types of music and recently Steve Allen
+has coded Beethoven's Symphony No. 7, Movement 2 in abc! Since its
+introduction at the end of 1991 it has become very popular and there
+now exist several Windows, Mac, Palmtop and UNIX based tools which can
+read abc notation and either process it into staff notation or play it
+through the speakers of a computer.
+
+One of the most important aims of abc notation, and perhaps one that
+distinguishes it from most, if not all, computer-readable musical
+languages is that it can be easily read by humans. In other words,
+with a little practice, it is possible to play a tune directly from
+the abc notation without having to process and print it out. Even if
+this isn't of interest, the resulting clarity of the notation makes it
+fairly easy to notate tunes. In addition, the ability to write music
+in abc notation means that it can be easily and portably stored or
+transported electronically hence enabling the discussion and
+dissemination of music via email. \ No newline at end of file
diff --git a/lib/stdlib/test/zip_SUITE_data/abc.zip b/lib/stdlib/test/zip_SUITE_data/abc.zip
new file mode 100644
index 0000000000..e78558f9a5
--- /dev/null
+++ b/lib/stdlib/test/zip_SUITE_data/abc.zip
Binary files differ
diff --git a/lib/stdlib/test/zip_SUITE_data/bad_central_directory.zip b/lib/stdlib/test/zip_SUITE_data/bad_central_directory.zip
new file mode 100644
index 0000000000..ae92173f71
--- /dev/null
+++ b/lib/stdlib/test/zip_SUITE_data/bad_central_directory.zip
Binary files differ
diff --git a/lib/stdlib/test/zip_SUITE_data/bad_crc.zip b/lib/stdlib/test/zip_SUITE_data/bad_crc.zip
new file mode 100644
index 0000000000..1cfae6c0c5
--- /dev/null
+++ b/lib/stdlib/test/zip_SUITE_data/bad_crc.zip
Binary files differ
diff --git a/lib/stdlib/test/zip_SUITE_data/bad_eocd.zip b/lib/stdlib/test/zip_SUITE_data/bad_eocd.zip
new file mode 100644
index 0000000000..c40ca4f85c
--- /dev/null
+++ b/lib/stdlib/test/zip_SUITE_data/bad_eocd.zip
Binary files differ
diff --git a/lib/stdlib/test/zip_SUITE_data/bad_file_header.zip b/lib/stdlib/test/zip_SUITE_data/bad_file_header.zip
new file mode 100644
index 0000000000..4b14a0eb34
--- /dev/null
+++ b/lib/stdlib/test/zip_SUITE_data/bad_file_header.zip
Binary files differ
diff --git a/lib/stdlib/test/zip_SUITE_data/emptyFile b/lib/stdlib/test/zip_SUITE_data/emptyFile
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/stdlib/test/zip_SUITE_data/emptyFile
diff --git a/lib/stdlib/test/zip_SUITE_data/quotes/rain.txt b/lib/stdlib/test/zip_SUITE_data/quotes/rain.txt
new file mode 100644
index 0000000000..19946d2f0e
--- /dev/null
+++ b/lib/stdlib/test/zip_SUITE_data/quotes/rain.txt
@@ -0,0 +1 @@
+The rain in Spain stays mainly in the plain
diff --git a/lib/stdlib/test/zip_SUITE_data/test.jar b/lib/stdlib/test/zip_SUITE_data/test.jar
new file mode 100644
index 0000000000..53b9939c0b
--- /dev/null
+++ b/lib/stdlib/test/zip_SUITE_data/test.jar
Binary files differ
diff --git a/lib/stdlib/test/zip_SUITE_data/test.txt b/lib/stdlib/test/zip_SUITE_data/test.txt
new file mode 100644
index 0000000000..0c452d43fb
--- /dev/null
+++ b/lib/stdlib/test/zip_SUITE_data/test.txt
@@ -0,0 +1 @@
+Lorem Ipsum osv osv \ No newline at end of file
diff --git a/lib/stdlib/test/zip_SUITE_data/wikipedia.txt b/lib/stdlib/test/zip_SUITE_data/wikipedia.txt
new file mode 100644
index 0000000000..83ebb6fbf9
--- /dev/null
+++ b/lib/stdlib/test/zip_SUITE_data/wikipedia.txt
@@ -0,0 +1,30 @@
+The ZIP file format is a popular lossless data compression and
+archival format. A ZIP file contains one or more files that have been
+compressed, to reduce their file size, or stored as-is. A number of
+compression algorithms are permitted in zip files but as of 2008 only
+DEFLATE is widely used and supported.
+
+The format was originally evolved by Phil Katz for PKZIP from the
+previous ARC compression format by Thom Henderson. However, many
+software utilities other than PKZIP itself are now available to
+create, modify, or open (unzip, decompress) ZIP files, notably WinZip,
+BOMArchiveHelper, KGB Archiver, PicoZip, Info-ZIP, WinRAR, IZArc,
+7-Zip, ALZip, TUGZip, PeaZip, Universal Extractor and Zip
+Genius. Microsoft has included built-in ZIP support (under the name
+"compressed folders") in later versions of its Windows operating
+system. Apple has included built-in ZIP support in Mac OS X 10.3 and
+later via the BOMArchiveHelper utility.
+
+ZIP files generally use the file extensions ".zip" or ".ZIP" and the
+MIME media type application/zip. Some software uses the ZIP file
+format as a wrapper for a large number of small items in a specific
+structure. Generally when this is done a different file extension is
+used. Examples of this usage are Java JAR files, id Software .pk3/.pk4
+files, package files for StepMania and Winamp/Windows Media Player
+skins, XPInstall, as well as OpenDocument and Office Open XML office
+formats. Both OpenDocument and Office Open XML formats use the JAR
+file format internally, so files can be easily uncompressed and
+compressed using tools for ZIP files. Google Earth makes use of KMZ
+files, which are just KML files in ZIP format. Mozilla Firefox Add-ons
+are zip files with extension "xpi". Nokia's mobile phone themes are
+zipped with extension "nth".