diff --git a/.hypothesis/examples/0a3a13c375cbef58/5d0ee50bbc9e81ca b/.hypothesis/examples/0a3a13c375cbef58/5d0ee50bbc9e81ca new file mode 100644 index 0000000..5c5cc7c Binary files /dev/null and b/.hypothesis/examples/0a3a13c375cbef58/5d0ee50bbc9e81ca differ diff --git a/.hypothesis/examples/103600e47f6e6c10/7ef3a58363360a70 b/.hypothesis/examples/103600e47f6e6c10/7ef3a58363360a70 new file mode 100644 index 0000000..8f61ee3 Binary files /dev/null and b/.hypothesis/examples/103600e47f6e6c10/7ef3a58363360a70 differ diff --git a/.hypothesis/examples/1d47f825b95ef0c4/106f0f267bad0256 b/.hypothesis/examples/1d47f825b95ef0c4/106f0f267bad0256 new file mode 100644 index 0000000..ecdc089 Binary files /dev/null and b/.hypothesis/examples/1d47f825b95ef0c4/106f0f267bad0256 differ diff --git a/.hypothesis/examples/1d525299ac17004b/2f5427605d3e198d b/.hypothesis/examples/1d525299ac17004b/2f5427605d3e198d new file mode 100644 index 0000000..31dfa6c Binary files /dev/null and b/.hypothesis/examples/1d525299ac17004b/2f5427605d3e198d differ diff --git a/.hypothesis/examples/1d525299ac17004b/9a3c1667a531b1ac b/.hypothesis/examples/1d525299ac17004b/9a3c1667a531b1ac new file mode 100644 index 0000000..654be01 Binary files /dev/null and b/.hypothesis/examples/1d525299ac17004b/9a3c1667a531b1ac differ diff --git a/.hypothesis/examples/1d525299ac17004b/cd6bd1dcfebeffe9 b/.hypothesis/examples/1d525299ac17004b/cd6bd1dcfebeffe9 new file mode 100644 index 0000000..4227ca4 Binary files /dev/null and b/.hypothesis/examples/1d525299ac17004b/cd6bd1dcfebeffe9 differ diff --git a/.hypothesis/examples/2813a5e94c6b3fc8/35ad336a2a6fdfd2 b/.hypothesis/examples/2813a5e94c6b3fc8/35ad336a2a6fdfd2 new file mode 100644 index 0000000..7923a2f Binary files /dev/null and b/.hypothesis/examples/2813a5e94c6b3fc8/35ad336a2a6fdfd2 differ diff --git a/.hypothesis/examples/2c39b0652528389a/20a2763cdf3874b1 b/.hypothesis/examples/2c39b0652528389a/20a2763cdf3874b1 new file mode 100644 index 0000000..e4dbaad Binary files /dev/null and b/.hypothesis/examples/2c39b0652528389a/20a2763cdf3874b1 differ diff --git a/.hypothesis/examples/30c35e01a9722884/cd6bd1dcfebeffe9 b/.hypothesis/examples/30c35e01a9722884/cd6bd1dcfebeffe9 new file mode 100644 index 0000000..4227ca4 Binary files /dev/null and b/.hypothesis/examples/30c35e01a9722884/cd6bd1dcfebeffe9 differ diff --git a/.hypothesis/examples/3bb842c8650c896a/b7cf276e1892438c b/.hypothesis/examples/3bb842c8650c896a/b7cf276e1892438c new file mode 100644 index 0000000..114ed4e Binary files /dev/null and b/.hypothesis/examples/3bb842c8650c896a/b7cf276e1892438c differ diff --git a/.hypothesis/examples/474f3ad49262d3ec/2f5427605d3e198d b/.hypothesis/examples/474f3ad49262d3ec/2f5427605d3e198d new file mode 100644 index 0000000..31dfa6c Binary files /dev/null and b/.hypothesis/examples/474f3ad49262d3ec/2f5427605d3e198d differ diff --git a/.hypothesis/examples/4b6d35316b9dfb2c/3192aedc13e9fb94 b/.hypothesis/examples/4b6d35316b9dfb2c/3192aedc13e9fb94 new file mode 100644 index 0000000..eb4fd09 Binary files /dev/null and b/.hypothesis/examples/4b6d35316b9dfb2c/3192aedc13e9fb94 differ diff --git a/.hypothesis/examples/4b6d35316b9dfb2c/69dca6a561a1acfd b/.hypothesis/examples/4b6d35316b9dfb2c/69dca6a561a1acfd new file mode 100644 index 0000000..3bedc8e Binary files /dev/null and b/.hypothesis/examples/4b6d35316b9dfb2c/69dca6a561a1acfd differ diff --git a/.hypothesis/examples/4b6d35316b9dfb2c/85c0272697d6fd5e b/.hypothesis/examples/4b6d35316b9dfb2c/85c0272697d6fd5e new file mode 100644 index 0000000..f848076 Binary files /dev/null and b/.hypothesis/examples/4b6d35316b9dfb2c/85c0272697d6fd5e differ diff --git a/.hypothesis/examples/4b6d35316b9dfb2c/b1d05b1a4f5d57d8 b/.hypothesis/examples/4b6d35316b9dfb2c/b1d05b1a4f5d57d8 new file mode 100644 index 0000000..4988797 Binary files /dev/null and b/.hypothesis/examples/4b6d35316b9dfb2c/b1d05b1a4f5d57d8 differ diff --git a/.hypothesis/examples/4b6d35316b9dfb2c/cd6bd1dcfebeffe9 b/.hypothesis/examples/4b6d35316b9dfb2c/cd6bd1dcfebeffe9 new file mode 100644 index 0000000..4227ca4 Binary files /dev/null and b/.hypothesis/examples/4b6d35316b9dfb2c/cd6bd1dcfebeffe9 differ diff --git a/.hypothesis/examples/4e607744a84e246b/2f5427605d3e198d b/.hypothesis/examples/4e607744a84e246b/2f5427605d3e198d new file mode 100644 index 0000000..31dfa6c Binary files /dev/null and b/.hypothesis/examples/4e607744a84e246b/2f5427605d3e198d differ diff --git a/.hypothesis/examples/531cc7355cff42c2/9a3c1667a531b1ac b/.hypothesis/examples/531cc7355cff42c2/9a3c1667a531b1ac new file mode 100644 index 0000000..654be01 Binary files /dev/null and b/.hypothesis/examples/531cc7355cff42c2/9a3c1667a531b1ac differ diff --git a/.hypothesis/examples/532a94be90c9efd0/b8231a7f06bee7f9 b/.hypothesis/examples/532a94be90c9efd0/b8231a7f06bee7f9 new file mode 100644 index 0000000..df77930 Binary files /dev/null and b/.hypothesis/examples/532a94be90c9efd0/b8231a7f06bee7f9 differ diff --git a/.hypothesis/examples/532a94be90c9efd0/de2f4e902ceb702d b/.hypothesis/examples/532a94be90c9efd0/de2f4e902ceb702d new file mode 100644 index 0000000..ea09397 Binary files /dev/null and b/.hypothesis/examples/532a94be90c9efd0/de2f4e902ceb702d differ diff --git a/.hypothesis/examples/532a94be90c9efd0/ffd3c03363776c1f b/.hypothesis/examples/532a94be90c9efd0/ffd3c03363776c1f new file mode 100644 index 0000000..566fcd5 Binary files /dev/null and b/.hypothesis/examples/532a94be90c9efd0/ffd3c03363776c1f differ diff --git a/.hypothesis/examples/55c0f1b47133aa5d/20a2763cdf3874b1 b/.hypothesis/examples/55c0f1b47133aa5d/20a2763cdf3874b1 new file mode 100644 index 0000000..e4dbaad Binary files /dev/null and b/.hypothesis/examples/55c0f1b47133aa5d/20a2763cdf3874b1 differ diff --git a/.hypothesis/examples/55c0f1b47133aa5d/576822a319690cfa b/.hypothesis/examples/55c0f1b47133aa5d/576822a319690cfa new file mode 100644 index 0000000..c78cf54 Binary files /dev/null and b/.hypothesis/examples/55c0f1b47133aa5d/576822a319690cfa differ diff --git a/.hypothesis/examples/5841fbe83c75a177/085f80daee6d089f b/.hypothesis/examples/5841fbe83c75a177/085f80daee6d089f new file mode 100644 index 0000000..01670af Binary files /dev/null and b/.hypothesis/examples/5841fbe83c75a177/085f80daee6d089f differ diff --git a/.hypothesis/examples/5841fbe83c75a177/96784e8d40b82570 b/.hypothesis/examples/5841fbe83c75a177/96784e8d40b82570 new file mode 100644 index 0000000..0bc649f Binary files /dev/null and b/.hypothesis/examples/5841fbe83c75a177/96784e8d40b82570 differ diff --git a/.hypothesis/examples/5841fbe83c75a177/975b2cb9b044b541 b/.hypothesis/examples/5841fbe83c75a177/975b2cb9b044b541 new file mode 100644 index 0000000..7ebee0c Binary files /dev/null and b/.hypothesis/examples/5841fbe83c75a177/975b2cb9b044b541 differ diff --git a/.hypothesis/examples/6007eaac0644fd1b/7ef3a58363360a70 b/.hypothesis/examples/6007eaac0644fd1b/7ef3a58363360a70 new file mode 100644 index 0000000..8f61ee3 Binary files /dev/null and b/.hypothesis/examples/6007eaac0644fd1b/7ef3a58363360a70 differ diff --git a/.hypothesis/examples/610f0d49a7f18187/015ec5d979c41511 b/.hypothesis/examples/610f0d49a7f18187/015ec5d979c41511 new file mode 100644 index 0000000..044eb50 Binary files /dev/null and b/.hypothesis/examples/610f0d49a7f18187/015ec5d979c41511 differ diff --git a/.hypothesis/examples/610f0d49a7f18187/085f80daee6d089f b/.hypothesis/examples/610f0d49a7f18187/085f80daee6d089f new file mode 100644 index 0000000..01670af Binary files /dev/null and b/.hypothesis/examples/610f0d49a7f18187/085f80daee6d089f differ diff --git a/.hypothesis/examples/610f0d49a7f18187/93fd353b208e5ead b/.hypothesis/examples/610f0d49a7f18187/93fd353b208e5ead new file mode 100644 index 0000000..290567d Binary files /dev/null and b/.hypothesis/examples/610f0d49a7f18187/93fd353b208e5ead differ diff --git a/.hypothesis/examples/65c7e04feb03f2b7/9a3c1667a531b1ac b/.hypothesis/examples/65c7e04feb03f2b7/9a3c1667a531b1ac new file mode 100644 index 0000000..654be01 Binary files /dev/null and b/.hypothesis/examples/65c7e04feb03f2b7/9a3c1667a531b1ac differ diff --git a/.hypothesis/examples/65c7e04feb03f2b7/cd6bd1dcfebeffe9 b/.hypothesis/examples/65c7e04feb03f2b7/cd6bd1dcfebeffe9 new file mode 100644 index 0000000..4227ca4 Binary files /dev/null and b/.hypothesis/examples/65c7e04feb03f2b7/cd6bd1dcfebeffe9 differ diff --git a/.hypothesis/examples/8198d84e326634dc/576822a319690cfa b/.hypothesis/examples/8198d84e326634dc/576822a319690cfa new file mode 100644 index 0000000..c78cf54 Binary files /dev/null and b/.hypothesis/examples/8198d84e326634dc/576822a319690cfa differ diff --git a/.hypothesis/examples/8b486cb1c1c9d7c3/03dbd1ea1be639b7 b/.hypothesis/examples/8b486cb1c1c9d7c3/03dbd1ea1be639b7 new file mode 100644 index 0000000..759447a Binary files /dev/null and b/.hypothesis/examples/8b486cb1c1c9d7c3/03dbd1ea1be639b7 differ diff --git a/.hypothesis/examples/8b486cb1c1c9d7c3/1fd86b90f6bbea95 b/.hypothesis/examples/8b486cb1c1c9d7c3/1fd86b90f6bbea95 new file mode 100644 index 0000000..44f9e18 Binary files /dev/null and b/.hypothesis/examples/8b486cb1c1c9d7c3/1fd86b90f6bbea95 differ diff --git a/.hypothesis/examples/8b486cb1c1c9d7c3/257652cbe85ac09a b/.hypothesis/examples/8b486cb1c1c9d7c3/257652cbe85ac09a new file mode 100644 index 0000000..730e702 Binary files /dev/null and b/.hypothesis/examples/8b486cb1c1c9d7c3/257652cbe85ac09a differ diff --git a/.hypothesis/examples/8b486cb1c1c9d7c3/27b9d366cd0f55da b/.hypothesis/examples/8b486cb1c1c9d7c3/27b9d366cd0f55da new file mode 100644 index 0000000..bec2f3c Binary files /dev/null and b/.hypothesis/examples/8b486cb1c1c9d7c3/27b9d366cd0f55da differ diff --git a/.hypothesis/examples/8b486cb1c1c9d7c3/2c81b700510fb88e b/.hypothesis/examples/8b486cb1c1c9d7c3/2c81b700510fb88e new file mode 100644 index 0000000..07e24b9 Binary files /dev/null and b/.hypothesis/examples/8b486cb1c1c9d7c3/2c81b700510fb88e differ diff --git a/.hypothesis/examples/8b486cb1c1c9d7c3/3e88606e87e29819 b/.hypothesis/examples/8b486cb1c1c9d7c3/3e88606e87e29819 new file mode 100644 index 0000000..c9ff3e8 Binary files /dev/null and b/.hypothesis/examples/8b486cb1c1c9d7c3/3e88606e87e29819 differ diff --git a/.hypothesis/examples/8b486cb1c1c9d7c3/42cc1e1b7ee552b3 b/.hypothesis/examples/8b486cb1c1c9d7c3/42cc1e1b7ee552b3 new file mode 100644 index 0000000..34c65dd Binary files /dev/null and b/.hypothesis/examples/8b486cb1c1c9d7c3/42cc1e1b7ee552b3 differ diff --git a/.hypothesis/examples/8b486cb1c1c9d7c3/4dbdf3ffa933d826 b/.hypothesis/examples/8b486cb1c1c9d7c3/4dbdf3ffa933d826 new file mode 100644 index 0000000..a72b038 Binary files /dev/null and b/.hypothesis/examples/8b486cb1c1c9d7c3/4dbdf3ffa933d826 differ diff --git a/.hypothesis/examples/8b486cb1c1c9d7c3/5ffd6c3d14f086fd b/.hypothesis/examples/8b486cb1c1c9d7c3/5ffd6c3d14f086fd new file mode 100644 index 0000000..5b3b737 Binary files /dev/null and b/.hypothesis/examples/8b486cb1c1c9d7c3/5ffd6c3d14f086fd differ diff --git a/.hypothesis/examples/8b486cb1c1c9d7c3/706826b5897c8f21 b/.hypothesis/examples/8b486cb1c1c9d7c3/706826b5897c8f21 new file mode 100644 index 0000000..8bb9334 Binary files /dev/null and b/.hypothesis/examples/8b486cb1c1c9d7c3/706826b5897c8f21 differ diff --git a/.hypothesis/examples/8b486cb1c1c9d7c3/804d8ecdedfea816 b/.hypothesis/examples/8b486cb1c1c9d7c3/804d8ecdedfea816 new file mode 100644 index 0000000..b09f681 Binary files /dev/null and b/.hypothesis/examples/8b486cb1c1c9d7c3/804d8ecdedfea816 differ diff --git a/.hypothesis/examples/8b486cb1c1c9d7c3/93f9de22a832f630 b/.hypothesis/examples/8b486cb1c1c9d7c3/93f9de22a832f630 new file mode 100644 index 0000000..5a63ed2 Binary files /dev/null and b/.hypothesis/examples/8b486cb1c1c9d7c3/93f9de22a832f630 differ diff --git a/.hypothesis/examples/8b486cb1c1c9d7c3/9af922df7ed31887 b/.hypothesis/examples/8b486cb1c1c9d7c3/9af922df7ed31887 new file mode 100644 index 0000000..3c3019c Binary files /dev/null and b/.hypothesis/examples/8b486cb1c1c9d7c3/9af922df7ed31887 differ diff --git a/.hypothesis/examples/8b486cb1c1c9d7c3/a72db87782dbdd7c b/.hypothesis/examples/8b486cb1c1c9d7c3/a72db87782dbdd7c new file mode 100644 index 0000000..6f5f7c2 Binary files /dev/null and b/.hypothesis/examples/8b486cb1c1c9d7c3/a72db87782dbdd7c differ diff --git a/.hypothesis/examples/8b486cb1c1c9d7c3/aa9286fee73e0130 b/.hypothesis/examples/8b486cb1c1c9d7c3/aa9286fee73e0130 new file mode 100644 index 0000000..e82480a Binary files /dev/null and b/.hypothesis/examples/8b486cb1c1c9d7c3/aa9286fee73e0130 differ diff --git a/.hypothesis/examples/8b486cb1c1c9d7c3/b105d4471d0d7757 b/.hypothesis/examples/8b486cb1c1c9d7c3/b105d4471d0d7757 new file mode 100644 index 0000000..9b5d5d7 Binary files /dev/null and b/.hypothesis/examples/8b486cb1c1c9d7c3/b105d4471d0d7757 differ diff --git a/.hypothesis/examples/8b486cb1c1c9d7c3/c8e87fefbd74d073 b/.hypothesis/examples/8b486cb1c1c9d7c3/c8e87fefbd74d073 new file mode 100644 index 0000000..02831a9 Binary files /dev/null and b/.hypothesis/examples/8b486cb1c1c9d7c3/c8e87fefbd74d073 differ diff --git a/.hypothesis/examples/8b486cb1c1c9d7c3/e154e84c6030c3e3 b/.hypothesis/examples/8b486cb1c1c9d7c3/e154e84c6030c3e3 new file mode 100644 index 0000000..45a7155 Binary files /dev/null and b/.hypothesis/examples/8b486cb1c1c9d7c3/e154e84c6030c3e3 differ diff --git a/.hypothesis/examples/8b486cb1c1c9d7c3/f3250b332e873f95 b/.hypothesis/examples/8b486cb1c1c9d7c3/f3250b332e873f95 new file mode 100644 index 0000000..0b84973 Binary files /dev/null and b/.hypothesis/examples/8b486cb1c1c9d7c3/f3250b332e873f95 differ diff --git a/.hypothesis/examples/8b486cb1c1c9d7c3/fa791b5038e8176b b/.hypothesis/examples/8b486cb1c1c9d7c3/fa791b5038e8176b new file mode 100644 index 0000000..bb094d9 Binary files /dev/null and b/.hypothesis/examples/8b486cb1c1c9d7c3/fa791b5038e8176b differ diff --git a/.hypothesis/examples/8b486cb1c1c9d7c3/fc8970907eab2821 b/.hypothesis/examples/8b486cb1c1c9d7c3/fc8970907eab2821 new file mode 100644 index 0000000..6daf709 Binary files /dev/null and b/.hypothesis/examples/8b486cb1c1c9d7c3/fc8970907eab2821 differ diff --git a/.hypothesis/examples/8c20b63c7c3ee2a0/2f5427605d3e198d b/.hypothesis/examples/8c20b63c7c3ee2a0/2f5427605d3e198d new file mode 100644 index 0000000..31dfa6c Binary files /dev/null and b/.hypothesis/examples/8c20b63c7c3ee2a0/2f5427605d3e198d differ diff --git a/.hypothesis/examples/8c20b63c7c3ee2a0/9a3c1667a531b1ac b/.hypothesis/examples/8c20b63c7c3ee2a0/9a3c1667a531b1ac new file mode 100644 index 0000000..654be01 Binary files /dev/null and b/.hypothesis/examples/8c20b63c7c3ee2a0/9a3c1667a531b1ac differ diff --git a/.hypothesis/examples/8c20b63c7c3ee2a0/cd6bd1dcfebeffe9 b/.hypothesis/examples/8c20b63c7c3ee2a0/cd6bd1dcfebeffe9 new file mode 100644 index 0000000..4227ca4 Binary files /dev/null and b/.hypothesis/examples/8c20b63c7c3ee2a0/cd6bd1dcfebeffe9 differ diff --git a/.hypothesis/examples/926adf2f773b1de7/9a3c1667a531b1ac b/.hypothesis/examples/926adf2f773b1de7/9a3c1667a531b1ac new file mode 100644 index 0000000..654be01 Binary files /dev/null and b/.hypothesis/examples/926adf2f773b1de7/9a3c1667a531b1ac differ diff --git a/.hypothesis/examples/95fbd6c8090ecb40/cd6bd1dcfebeffe9 b/.hypothesis/examples/95fbd6c8090ecb40/cd6bd1dcfebeffe9 new file mode 100644 index 0000000..4227ca4 Binary files /dev/null and b/.hypothesis/examples/95fbd6c8090ecb40/cd6bd1dcfebeffe9 differ diff --git a/.hypothesis/examples/95fbd6c8090ecb40/dc11c3cd8814f97f b/.hypothesis/examples/95fbd6c8090ecb40/dc11c3cd8814f97f new file mode 100644 index 0000000..a2f0401 Binary files /dev/null and b/.hypothesis/examples/95fbd6c8090ecb40/dc11c3cd8814f97f differ diff --git a/.hypothesis/examples/988fff622301a798/86b12aeace201491 b/.hypothesis/examples/988fff622301a798/86b12aeace201491 new file mode 100644 index 0000000..8fd7371 Binary files /dev/null and b/.hypothesis/examples/988fff622301a798/86b12aeace201491 differ diff --git a/.hypothesis/examples/a9e8fc16f19e74e6/7ef3a58363360a70 b/.hypothesis/examples/a9e8fc16f19e74e6/7ef3a58363360a70 new file mode 100644 index 0000000..8f61ee3 Binary files /dev/null and b/.hypothesis/examples/a9e8fc16f19e74e6/7ef3a58363360a70 differ diff --git a/.hypothesis/examples/aa9db1092bd86c43/b7cf276e1892438c b/.hypothesis/examples/aa9db1092bd86c43/b7cf276e1892438c new file mode 100644 index 0000000..114ed4e Binary files /dev/null and b/.hypothesis/examples/aa9db1092bd86c43/b7cf276e1892438c differ diff --git a/.hypothesis/examples/b37a28bfb88d7d9a/0d491ebeb6bcc34b b/.hypothesis/examples/b37a28bfb88d7d9a/0d491ebeb6bcc34b new file mode 100644 index 0000000..3390ddd Binary files /dev/null and b/.hypothesis/examples/b37a28bfb88d7d9a/0d491ebeb6bcc34b differ diff --git a/.hypothesis/examples/b37a28bfb88d7d9a/7abd2938b62a02d9 b/.hypothesis/examples/b37a28bfb88d7d9a/7abd2938b62a02d9 new file mode 100644 index 0000000..606a865 Binary files /dev/null and b/.hypothesis/examples/b37a28bfb88d7d9a/7abd2938b62a02d9 differ diff --git a/.hypothesis/examples/bfe2da22a2bb6466/3d12246dfa6c2702 b/.hypothesis/examples/bfe2da22a2bb6466/3d12246dfa6c2702 new file mode 100644 index 0000000..d4ba96b Binary files /dev/null and b/.hypothesis/examples/bfe2da22a2bb6466/3d12246dfa6c2702 differ diff --git a/.hypothesis/examples/bfe2da22a2bb6466/bb557a3de7bf606a b/.hypothesis/examples/bfe2da22a2bb6466/bb557a3de7bf606a new file mode 100644 index 0000000..f642da0 Binary files /dev/null and b/.hypothesis/examples/bfe2da22a2bb6466/bb557a3de7bf606a differ diff --git a/.hypothesis/examples/bfe2da22a2bb6466/cd6bd1dcfebeffe9 b/.hypothesis/examples/bfe2da22a2bb6466/cd6bd1dcfebeffe9 new file mode 100644 index 0000000..4227ca4 Binary files /dev/null and b/.hypothesis/examples/bfe2da22a2bb6466/cd6bd1dcfebeffe9 differ diff --git a/.hypothesis/examples/c0f5d5372d68b6e6/9a3c1667a531b1ac b/.hypothesis/examples/c0f5d5372d68b6e6/9a3c1667a531b1ac new file mode 100644 index 0000000..654be01 Binary files /dev/null and b/.hypothesis/examples/c0f5d5372d68b6e6/9a3c1667a531b1ac differ diff --git a/.hypothesis/examples/c1d126aa4d876ecb/20a2763cdf3874b1 b/.hypothesis/examples/c1d126aa4d876ecb/20a2763cdf3874b1 new file mode 100644 index 0000000..e4dbaad Binary files /dev/null and b/.hypothesis/examples/c1d126aa4d876ecb/20a2763cdf3874b1 differ diff --git a/.hypothesis/examples/c653ccb42395525a/cd6bd1dcfebeffe9 b/.hypothesis/examples/c653ccb42395525a/cd6bd1dcfebeffe9 new file mode 100644 index 0000000..4227ca4 Binary files /dev/null and b/.hypothesis/examples/c653ccb42395525a/cd6bd1dcfebeffe9 differ diff --git a/.hypothesis/examples/ce5beca553078037/7abd2938b62a02d9 b/.hypothesis/examples/ce5beca553078037/7abd2938b62a02d9 new file mode 100644 index 0000000..606a865 Binary files /dev/null and b/.hypothesis/examples/ce5beca553078037/7abd2938b62a02d9 differ diff --git a/.hypothesis/examples/d467e571ca193666/9c37882aff0161aa b/.hypothesis/examples/d467e571ca193666/9c37882aff0161aa new file mode 100644 index 0000000..eb078fa Binary files /dev/null and b/.hypothesis/examples/d467e571ca193666/9c37882aff0161aa differ diff --git a/.hypothesis/examples/d467e571ca193666/cd6bd1dcfebeffe9 b/.hypothesis/examples/d467e571ca193666/cd6bd1dcfebeffe9 new file mode 100644 index 0000000..4227ca4 Binary files /dev/null and b/.hypothesis/examples/d467e571ca193666/cd6bd1dcfebeffe9 differ diff --git a/.hypothesis/examples/ea046fba42e7e6df/5d0ee50bbc9e81ca b/.hypothesis/examples/ea046fba42e7e6df/5d0ee50bbc9e81ca new file mode 100644 index 0000000..5c5cc7c Binary files /dev/null and b/.hypothesis/examples/ea046fba42e7e6df/5d0ee50bbc9e81ca differ diff --git a/.hypothesis/examples/ea046fba42e7e6df/9a3c1667a531b1ac b/.hypothesis/examples/ea046fba42e7e6df/9a3c1667a531b1ac new file mode 100644 index 0000000..654be01 Binary files /dev/null and b/.hypothesis/examples/ea046fba42e7e6df/9a3c1667a531b1ac differ diff --git a/.hypothesis/examples/ea046fba42e7e6df/cd6bd1dcfebeffe9 b/.hypothesis/examples/ea046fba42e7e6df/cd6bd1dcfebeffe9 new file mode 100644 index 0000000..4227ca4 Binary files /dev/null and b/.hypothesis/examples/ea046fba42e7e6df/cd6bd1dcfebeffe9 differ diff --git a/.hypothesis/examples/f110168263c9473c/0d491ebeb6bcc34b b/.hypothesis/examples/f110168263c9473c/0d491ebeb6bcc34b new file mode 100644 index 0000000..3390ddd Binary files /dev/null and b/.hypothesis/examples/f110168263c9473c/0d491ebeb6bcc34b differ diff --git a/.hypothesis/unicode_data/13.0.0/charmap.json.gz b/.hypothesis/unicode_data/13.0.0/charmap.json.gz new file mode 100644 index 0000000..59be8a4 Binary files /dev/null and b/.hypothesis/unicode_data/13.0.0/charmap.json.gz differ diff --git a/.hypothesis/unicode_data/13.0.0/codec-utf-8.json.gz b/.hypothesis/unicode_data/13.0.0/codec-utf-8.json.gz new file mode 100644 index 0000000..35fdea6 Binary files /dev/null and b/.hypothesis/unicode_data/13.0.0/codec-utf-8.json.gz differ diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c94556..a5fd32c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,14 @@ # Changelog +## 0.19.0 + +* If an empty string is passed in as a pattern, `AhoCorasick()` will now raise a `ValueError`. + Previously using empty patterns could result in garbage results or exceptions when matching. +* Upgraded to `aho-corasick` v1.1.1. + ## 0.18.0 -* Upgrade to `aho-corasick` v1.1.0, which can run faster on ARM machines like newer Macs. +* Upgraded to `aho-corasick` v1.1.0, which can run faster on ARM machines like newer Macs. ## 0.17.0 diff --git a/Cargo.lock b/Cargo.lock index 699169f..da85bda 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,16 +4,16 @@ version = 3 [[package]] name = "aho-corasick" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f2135563fb5c609d2b2b87c1e8ce7bc41b0b45430fa9661f457981503dd5bf0" +checksum = "ea5d730647d4fadd988536d06fecce94b7b4f2a7efdae548f1cf4b63205518ab" dependencies = [ "memchr", ] [[package]] name = "ahocorasick_rs" -version = "0.18.0" +version = "0.19.0" dependencies = [ "aho-corasick", "itertools", @@ -214,9 +214,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "smallvec" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" +checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" [[package]] name = "syn" diff --git a/Cargo.toml b/Cargo.toml index 7a4ab49..b59cca2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ahocorasick_rs" -version = "0.18.0" +version = "0.19.0" edition = "2021" authors = ["G-Research ", "Itamar Turner-Trauring "] description = "Search a string for multiple substrings at once" diff --git a/justfile b/justfile index 576b6d4..b3714e6 100644 --- a/justfile +++ b/justfile @@ -19,9 +19,12 @@ install-dev-dependencies: setup: venv install-dev-dependencies -test: +lint: flake8 tests/ black --check tests/ + mypy --strict tests + +test: pytest tests/ # Prepare for benchmarking; will only work on Linux: diff --git a/rust-toolchain.toml b/rust-toolchain.toml index c319e66..f0f6043 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "1.72" +channel = "1.72.1" components = ["rustfmt", "clippy"] \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 69b271b..a2a32f7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,6 @@ -use std::sync::{Arc, Mutex}; +use std::{sync::{ + Arc, Mutex, +}, cell::Cell}; use aho_corasick::{ AhoCorasick, AhoCorasickBuilder, AhoCorasickKind, Match, MatchError, MatchKind, @@ -14,7 +16,9 @@ use pyo3::{ /// /// Takes three arguments: /// -/// * ``patterns``: A list of strings, the patterns to match against. +/// * ``patterns``: A list of strings, the patterns to match against. Empty +/// patterns are not supported and will result in a ``ValueError`` exception +/// being raised. /// * ``matchkind``: Defaults to ``"MATCHKING_STANDARD"``. /// * ``store_patterns``: If ``True``, keep a reference to the patterns, which /// will speed up ``find_matches_as_strings()`` but will use more memory. If @@ -177,27 +181,39 @@ impl PyAhoCorasick { None }; - let result = Ok(Self { - ac_impl: AhoCorasickBuilder::new() - .kind(implementation.map(|i| i.into())) - .match_kind(matchkind.into()) - .build( - first_few_patterns - .into_iter() - .chain(patterns_iter) - .chunks(10 * 1024) - .into_iter() - .flat_map(|chunk| { - let result = chunk.filter_map(|s| s.extract::().ok()); - // Release the GIL in case some other thread wants to do work: - py.allow_threads(|| ()); - result - }), - ) - // TODO make sure this error is menaingful to Python users - .map_err(|e| PyValueError::new_err(e.to_string()))?, - patterns, - }); + let has_empty_patterns = Cell::new(false); + let ac_impl = AhoCorasickBuilder::new() + .kind(implementation.map(|i| i.into())) + .match_kind(matchkind.into()) + .build( + first_few_patterns + .into_iter() + .chain(patterns_iter) + .chunks(10 * 1024) + .into_iter() + .flat_map(|chunk| { + let result = + chunk + .filter_map(|s| s.extract::().ok()) + .inspect(|s| { + if s.is_empty() { + has_empty_patterns.set(true); + } + }); + // Release the GIL in case some other thread wants to do work: + py.allow_threads(|| ()); + result + }), + ) // TODO make sure this error is menaingful to Python users + .map_err(|e| PyValueError::new_err(e.to_string()))?; + + if has_empty_patterns.get() { + return Err(PyValueError::new_err( + "You passed in an empty string as a pattern", + )); + } + + let result = Ok(Self { ac_impl, patterns }); if let Ok(mut guard) = patterns_error.lock() { if let Some(err) = guard.take() { return Err(err); diff --git a/tests/test_ac.py b/tests/test_ac.py index 0c67b49..9a73845 100644 --- a/tests/test_ac.py +++ b/tests/test_ac.py @@ -155,6 +155,45 @@ def test_unicode_extensive( assert ac.find_matches_as_strings(haystack) == [pattern] +@pytest.mark.parametrize("bad_patterns", [[""], ["", "xx"], ["xx", ""]]) +@pytest.mark.parametrize("store_patterns", [True, False]) +def test_empty_patterns_are_not_legal( + bad_patterns: list[str], store_patterns: bool +) -> None: + """ + Passing in an empty pattern suggests a bug in user code, and the outputs + are bad when you do have that, so raise an error. + """ + with pytest.raises(ValueError) as e: + AhoCorasick(bad_patterns, store_patterns=store_patterns) + assert "You passed in an empty string as a pattern" in str(e.value) + + +@given(st.text(min_size=1), st.text(), st.sampled_from([True, False, None])) +def test_unicode_totally_random( + pattern: str, haystack: str, store_patterns: Optional[bool] +) -> None: + """ + Catch more edge cases of patterns and haystacks. + """ + if store_patterns is None: + ac = AhoCorasick([pattern]) + else: + ac = AhoCorasick([pattern], store_patterns=store_patterns) + + index_matches = ac.find_matches_as_indexes(haystack) + string_matches = ac.find_matches_as_strings(haystack) + + expected_index = haystack.find(pattern) + if expected_index == -1: + assert index_matches == [] + assert string_matches == [] + else: + assert index_matches[0][1] == expected_index + assert [haystack[s:e] for (_, s, e) in index_matches][0] == pattern + assert string_matches[0] == pattern + + def test_matchkind() -> None: """ Different matchkinds give different results.