├── include ├── liver_rules.hrl ├── liver.hrl └── unicode.hrl ├── tests ├── cover.spec ├── liver_internals_SUITE.erl ├── livr_rules_maps_SUITE.erl └── livr_rules_proplists_SUITE.erl ├── .gitignore ├── ebin └── liver.app ├── Makefile ├── .github └── workflows │ └── ci.yml ├── LICENSE ├── src ├── liver_maps.erl ├── liver_rules.erl ├── liver_bstring.erl ├── liver.erl ├── sets │ ├── liver_strict_rules.erl │ └── liver_livr_rules.erl └── liver_float.erl └── README.md /include/liver_rules.hrl: -------------------------------------------------------------------------------- 1 | -define(MISSED_FIELD_VALUE, '$missed_field'). 2 | -------------------------------------------------------------------------------- /tests/cover.spec: -------------------------------------------------------------------------------- 1 | %% -*- mode: erlang -*- 2 | {incl_app, liver, details}. 3 | {export, "logs/all.coverdata"}. 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .eunit 2 | deps 3 | *.o 4 | *.beam 5 | *.plt 6 | erl_crash.dump 7 | ebin/*.beam 8 | .rebar 9 | .erlang.mk/ 10 | .swp 11 | logs/ 12 | liver.d 13 | src/*.swp 14 | src/sets/*.swp 15 | tests/*.swp 16 | -------------------------------------------------------------------------------- /ebin/liver.app: -------------------------------------------------------------------------------- 1 | {application, 'liver', [ 2 | {description, "Lightweight Erlang validator based on LIVR specification"}, 3 | {vsn, "1.0.0"}, 4 | {modules, ['liver','liver_bstring','liver_float','liver_livr_rules','liver_maps','liver_rules','liver_strict_rules']}, 5 | {registered, []}, 6 | {applications, [kernel,stdlib]}, 7 | {env, []} 8 | ]}. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PROJECT = liver 2 | PROJECT_DESCRIPTION = Lightweight Erlang validator based on LIVR specification 3 | PROJECT_VERSION = 1.0.0 4 | 5 | BUILD_DEPS = ci.erlang.mk 6 | DEP_PLUGINS = coveralls.mk 7 | DEP_EARLY_PLUGINS = ci.erlang.mk 8 | 9 | AUTO_CI_OTP ?= OTP-LATEST-24+ 10 | AUTO_CI_WINDOWS ?= OTP-LATEST-21+ 11 | 12 | CT_OPTS = -cover ./tests/cover.spec 13 | TEST_DEPS = LIVR jsx iso8601 coveralls.mk 14 | TEST_DIR = tests 15 | COVER=1 16 | 17 | DIALYZER_OPTS += -I include 18 | 19 | dep_ci.erlang.mk = git https://github.com/ninenines/ci.erlang.mk master 20 | dep_coveralls.mk = git https://github.com/erlangbureau/coveralls.mk master 21 | dep_jsx = git https://github.com/talentdeficit/jsx v2.8.3 22 | dep_LIVR = git https://github.com/koorchik/LIVR master 23 | dep_iso8601 = git https://github.com/erlsci/iso8601 1.3.4 24 | 25 | 26 | include erlang.mk 27 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Liver build 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | schedule: 11 | ## Every Monday at 2am. 12 | - cron: 0 2 * * 1 13 | 14 | concurrency: 15 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} 16 | cancel-in-progress: true 17 | 18 | jobs: 19 | build: 20 | name: Liver 21 | if: ${{ !cancelled() }} 22 | uses: ninenines/ci.erlang.mk/.github/workflows/ci.yaml@master 23 | 24 | coverage: 25 | name: Coverage Report 26 | runs-on: ubuntu-latest 27 | if: github.ref == 'refs/heads/master' || github.event_name == 'pull_request' 28 | 29 | steps: 30 | - name: Checkout repository 31 | uses: actions/checkout@v4 32 | 33 | - name: Set up Erlang/OTP 34 | uses: erlef/setup-beam@v1 35 | with: 36 | otp-version: 27.2.2 37 | 38 | - name: Install dependencies 39 | run: make 40 | 41 | - name: Run tests with coverage 42 | run: make tests 43 | 44 | - name: Upload coverage to Coveralls 45 | run: make coveralls-send 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017, Serhii Kostiushkin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/liver_maps.erl: -------------------------------------------------------------------------------- 1 | -module(liver_maps). 2 | 3 | %% 4 | %% This is a wrapper-module for maps and proplists modules 5 | %% 6 | 7 | %% API 8 | -export([new/1]). 9 | -export([type/1]). 10 | -export([get/2, get/3]). 11 | -export([reverse/1]). 12 | -export([keys/1]). 13 | -export([is_empty/1]). 14 | -export([put/3]). 15 | -export([map/2]). 16 | 17 | 18 | %% API 19 | new(map) -> 20 | #{}; 21 | new(proplist) -> 22 | [{}]. 23 | 24 | type(Value) when is_map(Value) -> 25 | map; 26 | type(Value) when is_list(Value) -> 27 | proplist. 28 | 29 | get(Key, List)-> 30 | get(Key, List, undefined). 31 | 32 | get(Key, Map, Default) when is_map(Map) -> 33 | maps:get(Key, Map, Default); 34 | get(Key, List, Default) when is_list(List) -> 35 | case lists:keyfind(Key, 1, List) of 36 | {_, Value} -> Value; 37 | _ -> Default 38 | end; 39 | get(_Key, _Map, Default) -> 40 | Default. 41 | 42 | reverse(Map) when is_map(Map) -> 43 | Map; 44 | reverse(List) when is_list(List) -> 45 | lists:reverse(List). 46 | 47 | keys(Map) when is_map(Map) -> 48 | maps:keys(Map); 49 | keys(List) when is_list(List) -> 50 | [K || {K, _V} <- List]. 51 | 52 | is_empty(Map) when is_map(Map) -> 53 | maps:size(Map) =:= 0; 54 | is_empty(List) when is_list(List) -> 55 | case List of 56 | [{}] -> true; 57 | _ -> false 58 | end. 59 | 60 | put(Key, Value, Map) when is_map(Map) -> 61 | maps:put(Key, Value, Map); 62 | put(Key, Value, [{}]) -> 63 | [{Key, Value}]; 64 | put(Key, Value, List) when is_list(List) -> 65 | [{Key, Value}|List]. 66 | 67 | map(Fun, Map) when is_map(Map) -> 68 | maps:map(Fun, Map); 69 | map(Fun, List) when is_list(List) -> 70 | [{K, Fun(K, V)}|| {K, V} <- List]. 71 | -------------------------------------------------------------------------------- /src/liver_rules.erl: -------------------------------------------------------------------------------- 1 | -module(liver_rules). 2 | 3 | %% API 4 | -export([normalize/2]). 5 | -export([has_required/1]). 6 | -export([execute/2, execute/3]). 7 | 8 | -include("liver_rules.hrl"). 9 | 10 | %% API 11 | normalize(Rules, Data) -> 12 | Result = normalize(Rules, Data, []), 13 | lists:reverse(Result). 14 | 15 | has_required([{R, _A}|Rules]) -> 16 | case is_required(R) of 17 | true -> true; 18 | false -> has_required(Rules) 19 | end; 20 | has_required([]) -> 21 | false. 22 | 23 | execute(Rules, Opts) -> 24 | Rules2 = [Rule || {R, _Args} = Rule <- Rules, is_required(R)], 25 | execute(Rules2, ?MISSED_FIELD_VALUE, Opts). 26 | 27 | execute([{Rule, Args}|Rules], Value, Opts) -> 28 | Module = liver:which(Rule), 29 | try Module:Rule(Args, Value, Opts) of 30 | {ok, Value2} -> execute(Rules, Value2, Opts); 31 | Error -> Error 32 | catch 33 | error:undef -> 34 | {error, {unimplemented_rule, Rule}}; 35 | _Type:_Reason -> 36 | {error, format_error} 37 | end; 38 | execute([], Value, _Opts) -> 39 | {ok, Value}. 40 | 41 | %% internal 42 | normalize([{K, V} = Rule|Rules], Data, Acc) when is_atom(K) -> 43 | case K of 44 | equal_to_field -> 45 | Name = case V of 46 | [FieldName|_] -> FieldName; 47 | FieldName -> FieldName 48 | end, 49 | FieldValue = liver_maps:get(Name, Data, undefined), 50 | normalize(Rules, Data, [{equal_to_field, FieldValue}|Acc]); 51 | _ -> 52 | normalize(Rules, Data, [Rule|Acc]) 53 | end; 54 | normalize(Rules, Data, Acc) when is_map(Rules) -> 55 | Rules2 = maps:to_list(Rules), 56 | normalize(Rules2, Data, Acc); 57 | normalize([{K, V}|Rules], Data, Acc) when is_binary(K) -> 58 | K2 = binary_to_atom(K, utf8), 59 | normalize([{K2, V}|Rules], Data, Acc); 60 | normalize(K, Data, Acc) when is_atom(K) -> 61 | normalize([{K, []}], Data, Acc); 62 | normalize(Rule, Data, Acc) when is_binary(Rule) -> 63 | K2 = binary_to_atom(Rule, utf8), 64 | normalize([{K2, []}], Data, Acc); 65 | normalize({K, V}, Data, Acc) when is_atom(K) -> 66 | normalize([{K, V}], Data, Acc); 67 | normalize({K, V}, Data, Acc) when is_binary(K) -> 68 | K2 = binary_to_atom(K, utf8), 69 | normalize([{K2, V}], Data, Acc); 70 | normalize([Rule|Rules], Data, Acc) when is_map(Rule) -> 71 | Rules2 = maps:to_list(Rule), 72 | Acc2 = normalize(Rules2, Data, Acc), 73 | normalize(Rules, Data, Acc2); 74 | normalize([Rules|Rules2], Data, Acc) when is_list(Rules) -> 75 | Acc2 = normalize(Rules, Data, Acc), 76 | normalize(Rules2, Data, Acc2); 77 | normalize([K|Rules], Data, Acc) when is_atom(K) -> 78 | normalize([{K, []}|Rules], Data, Acc); 79 | normalize([K|Rules], Data, Acc) when is_binary(K) -> 80 | K2 = binary_to_atom(K, utf8), 81 | normalize([{K2, []}|Rules], Data, Acc); 82 | normalize([], _Data, Acc) -> 83 | Acc. 84 | 85 | is_required(required) -> true; 86 | is_required(not_empty_list) -> true; 87 | is_required(default) -> true; 88 | is_required(_) -> false. 89 | -------------------------------------------------------------------------------- /include/liver.hrl: -------------------------------------------------------------------------------- 1 | -define(DEFAULT_RULES, #{ 2 | %% LIVR common rules 3 | required => liver_livr_rules, 4 | not_empty => liver_livr_rules, 5 | not_empty_list => liver_livr_rules, 6 | any_object => liver_livr_rules, 7 | 8 | %% LIVR string rules 9 | string => liver_livr_rules, 10 | eq => liver_livr_rules, 11 | one_of => liver_livr_rules, 12 | max_length => liver_livr_rules, 13 | min_length => liver_livr_rules, 14 | length_between => liver_livr_rules, 15 | length_equal => liver_livr_rules, 16 | like => liver_livr_rules, 17 | 18 | %% LIVR numeric rules 19 | integer => liver_livr_rules, 20 | positive_integer => liver_livr_rules, 21 | decimal => liver_livr_rules, 22 | positive_decimal => liver_livr_rules, 23 | max_number => liver_livr_rules, 24 | min_number => liver_livr_rules, 25 | number_between => liver_livr_rules, 26 | 27 | %% LIVR special rules 28 | email => liver_livr_rules, 29 | url => liver_livr_rules, 30 | iso_date => liver_livr_rules, 31 | equal_to_field => liver_livr_rules, 32 | 33 | %% LIVR meta rules 34 | nested_object => liver_livr_rules, 35 | variable_object => liver_livr_rules, 36 | list_of => liver_livr_rules, 37 | list_of_objects => liver_livr_rules, 38 | list_of_different_objects => liver_livr_rules, 39 | 'or' => liver_livr_rules, 40 | 41 | %% LIVR modifiers (previously - "filter rules") 42 | trim => liver_livr_rules, 43 | to_lc => liver_livr_rules, 44 | to_uc => liver_livr_rules, 45 | remove => liver_livr_rules, 46 | leave_only => liver_livr_rules, 47 | default => liver_livr_rules, 48 | 49 | %% liver strict rules 50 | is_null => liver_strict_rules, 51 | is_undefined => liver_strict_rules, 52 | is_integer => liver_strict_rules, 53 | is_boolean => liver_strict_rules, 54 | is_list => liver_strict_rules, 55 | is_string => liver_strict_rules, 56 | is_bstring => liver_strict_rules, 57 | is_atom => liver_strict_rules, 58 | to_integer => liver_strict_rules, 59 | to_boolean => liver_strict_rules 60 | }). 61 | 62 | -define(DEFAULT_ERRORS, #{ 63 | required => <<"REQUIRED">>, 64 | format_error => <<"FORMAT_ERROR">>, 65 | cannot_be_empty => <<"CANNOT_BE_EMPTY">>, 66 | too_long => <<"TOO_LONG">>, 67 | too_short => <<"TOO_SHORT">>, 68 | too_high => <<"TOO_HIGH">>, 69 | too_low => <<"TOO_LOW">>, 70 | not_allowed_value => <<"NOT_ALLOWED_VALUE">>, 71 | not_number => <<"NOT_NUMBER">>, 72 | not_integer => <<"NOT_INTEGER">>, 73 | not_positive_integer => <<"NOT_POSITIVE_INTEGER">>, 74 | not_decimal => <<"NOT_DECIMAL">>, 75 | not_positive_decimal => <<"NOT_POSITIVE_DECIMAL">>, 76 | wrong_format => <<"WRONG_FORMAT">>, 77 | wrong_date => <<"WRONG_DATE">>, 78 | wrong_email => <<"WRONG_EMAIL">>, 79 | wrong_url => <<"WRONG_URL">>, 80 | fields_not_equal => <<"FIELDS_NOT_EQUAL">>, 81 | unknown_field => <<"UNKNOWN_FIELD">> 82 | }). 83 | -------------------------------------------------------------------------------- /src/liver_bstring.erl: -------------------------------------------------------------------------------- 1 | -module(liver_bstring). 2 | 3 | %% API 4 | -export([split/2]). 5 | -export([split_global/2]). 6 | -export([remove_chars/2]). 7 | -export([leave_chars/2]). 8 | -export([trim/1]). 9 | -export([trim_left/1]). 10 | -export([trim_right/1]). 11 | -export([to_lower/1]). 12 | -export([to_upper/1]). 13 | 14 | -include("unicode.hrl"). 15 | 16 | -define(IS_BLANK(Blank), 17 | Blank == $\s; 18 | Blank == $\t; 19 | Blank == $\n; 20 | Blank == $\r 21 | ). 22 | 23 | -type binary_string() :: unicode:unicode_binary(). 24 | 25 | 26 | %% API 27 | -spec split(BinString, Pattern) -> {PartBeforePattern, PartAfterPattern} 28 | when 29 | BinString :: binary_string(), 30 | Pattern :: binary_string(), 31 | PartBeforePattern :: binary_string(), 32 | PartAfterPattern :: binary_string(). 33 | split(BinString, Pattern) -> 34 | case binary:match(BinString, Pattern) of 35 | {A, B} -> 36 | <> = BinString, 37 | {Before, After}; 38 | nomatch -> 39 | {BinString, <<>>} 40 | end. 41 | 42 | -spec split_global(BinString, Pattern) -> [BinStringPart] 43 | when 44 | BinString :: binary_string(), 45 | Pattern :: binary_string(), 46 | BinStringPart :: binary_string(). 47 | split_global(BinString, Pattern) -> 48 | split_global(BinString, Pattern, []). 49 | 50 | split_global(BinString, Pattern, Acc) -> 51 | case binary:match(BinString, Pattern) of 52 | {A,B} -> 53 | <> = BinString, 54 | split_global(After, Pattern, [Before|Acc]); 55 | nomatch -> 56 | lists:reverse([BinString|Acc]) 57 | end. 58 | 59 | remove_chars(BinString, Pattern) -> 60 | Pattern2 = unicode:characters_to_list(Pattern), 61 | Pattern3 = [unicode:characters_to_binary([P]) || P <- Pattern2], 62 | remove_chars(BinString, Pattern3, <<>>). 63 | 64 | remove_chars(BinString, Pattern, Acc) -> 65 | case binary:match(BinString, Pattern) of 66 | {0, B} -> 67 | <<_:B/binary, After/binary>> = BinString, 68 | remove_chars(After, Pattern, Acc); 69 | {A, B} -> 70 | <> = BinString, 71 | remove_chars(After, Pattern, <>); 72 | nomatch -> 73 | <> 74 | end. 75 | 76 | leave_chars(BinString, Pattern) -> 77 | Pattern2 = unicode:characters_to_list(Pattern), 78 | Pattern3 = [unicode:characters_to_binary([P]) || P <- Pattern2], 79 | leave_chars(BinString, Pattern3, <<>>). 80 | 81 | leave_chars(BinString, Pattern, Acc) -> 82 | case binary:match(BinString, Pattern) of 83 | {A, B} -> 84 | <<_:A/binary, Match:B/binary, After/binary>> = BinString, 85 | leave_chars(After, Pattern, <>); 86 | nomatch -> 87 | <> 88 | end. 89 | 90 | -spec trim(BinString1) -> BinString2 91 | when 92 | BinString1 :: binary_string(), 93 | BinString2 :: binary_string(). 94 | trim(Binary) -> 95 | trim_right(trim_left(Binary)). 96 | 97 | -spec trim_left(BinString1) -> BinString2 98 | when 99 | BinString1 :: binary_string(), 100 | BinString2 :: binary_string(). 101 | trim_left(<<$\s, BinString/binary>>) -> 102 | trim_left(BinString); 103 | trim_left(<<$\t, BinString/binary>>) -> 104 | trim_left(BinString); 105 | trim_left(<<$\n, BinString/binary>>) -> 106 | trim_left(BinString); 107 | trim_left(<<$\r, BinString/binary>>) -> 108 | trim_left(BinString); 109 | trim_left(BinString) -> 110 | BinString. 111 | 112 | -spec trim_right(BinString1) -> BinString2 113 | when 114 | BinString1 :: binary_string(), 115 | BinString2 :: binary_string(). 116 | trim_right(<<>>) -> 117 | <<>>; 118 | trim_right(BinString) -> 119 | case binary:last(BinString) of 120 | Blank when ?IS_BLANK(Blank) -> 121 | Size = size(BinString) - 1, 122 | <> = BinString, 123 | trim_right(Part); 124 | _ -> 125 | BinString 126 | end. 127 | 128 | -spec to_lower(BinString1) -> BinString2 129 | when 130 | BinString1 :: binary_string(), 131 | BinString2 :: binary_string(). 132 | to_lower(BinString) -> 133 | << <<(maps:get(C, ?TO_LOWER, C))/utf8>> || <> <= BinString>>. 134 | 135 | -spec to_upper(BinString1) -> BinString2 136 | when 137 | BinString1 :: binary_string(), 138 | BinString2 :: binary_string(). 139 | to_upper(BinString) -> 140 | << <<(maps:get(C, ?TO_UPPER, C))/utf8>> || <> <= BinString>>. 141 | -------------------------------------------------------------------------------- /tests/liver_internals_SUITE.erl: -------------------------------------------------------------------------------- 1 | -module(liver_internals_SUITE). 2 | 3 | -compile(export_all). 4 | 5 | all() -> 6 | [ 7 | float_to_binary, 8 | split, 9 | split_global, 10 | trim_left, 11 | trim_right, 12 | trim, 13 | to_lower, 14 | to_upper 15 | ]. 16 | 17 | float_to_binary(_Config) -> 18 | <> = <<0,0,0,0,0,0,0,1>>, 19 | <> = <<0,15,255,255,255,255,255,255>>, 20 | <> = <<0,16,0,0,0,0,0,0>>, 21 | <> = <<127,239,255,255,255,255,255,255>>, 22 | TestCases = [ 23 | {0.0, <<"0.0">>}, 24 | {1.0, <<"1.0">>}, 25 | {-1.0, <<"-1.0">>}, 26 | {0.01, <<"0.01">>}, 27 | {0.001, <<"0.001">>}, 28 | {0.000001, <<"0.000001">>}, 29 | {0.0000001, <<"1.0e-7">>}, 30 | {100000.0, <<"100000.0">>}, 31 | {1000000.0, <<"1.0e+6">>}, 32 | {0.5, <<"0.5">>}, 33 | {4503599627370496.0, <<"4503599627370496.0">>}, 34 | {math:pow(2, -1074), <<"5.0e-324">>}, 35 | %% small denormalized number 36 | %% 4.94065645841246544177e-324 =:= 5.0e-324 37 | {SmallDenorm, <<"5.0e-324">>}, 38 | {SmallDenorm, SmallDenorm}, 39 | %% large denormalized number 40 | %% 2.22507385850720088902e-308 41 | {BigDenorm, <<"2.225073858507201e-308">>}, 42 | {BigDenorm, BigDenorm}, 43 | %% small normalized number 44 | %% 2.22507385850720138309e-308 45 | {SmallNorm, <<"2.2250738585072014e-308">>}, 46 | {SmallNorm, SmallNorm}, 47 | %% large normalized number 48 | %% 1.79769313486231570815e+308 49 | {LargeNorm, <<"1.7976931348623157e+308">>}, 50 | {LargeNorm, LargeNorm} 51 | ], 52 | float_to_binary_tests(TestCases). 53 | 54 | split(_Config) -> 55 | TestCases = [ 56 | {<<"Before After">>, {<<"Before">>, <<"After">>}}, 57 | {<<"До Після"/utf8>>, {<<"До"/utf8>>, <<"Після"/utf8>>}}, 58 | {<<" Після"/utf8>>, {<<>>, <<"Після"/utf8>>}}, 59 | {<<"До "/utf8>>, {<<"До"/utf8>>, <<>>}}, 60 | {<<"БезСпівпадінь"/utf8>>, {<<"БезСпівпадінь"/utf8>>, <<>>}} 61 | ], 62 | Fun = fun(Text) -> liver_bstring:split(Text, <<" ">>) end, 63 | run_tests(TestCases, Fun). 64 | 65 | split_global(_Config) -> 66 | TestCases = [ 67 | {<<"One,two,three">>, [<<"One">>,<<"two">>,<<"three">>]}, 68 | {<<"Один,Два,Три"/utf8>>, [<<"Один"/utf8>>,<<"Два"/utf8>>,<<"Три"/utf8>>]}, 69 | {<<",Один,Два,Три"/utf8>>, [<<>>, <<"Один"/utf8>>,<<"Два"/utf8>>,<<"Три"/utf8>>]} 70 | ], 71 | Fun = fun(Text) -> liver_bstring:split_global(Text, <<",">>) end, 72 | run_tests(TestCases, Fun). 73 | 74 | trim_left(_Config) -> 75 | TestCases = [ 76 | {<<>>, <<>>}, 77 | {<<" test "/utf8>>, <<"test "/utf8>>}, 78 | {<<" Тест "/utf8>>, <<"Тест "/utf8>>}, 79 | {<<"\n\t\r Тест "/utf8>>, <<"Тест "/utf8>>} 80 | ], 81 | run_tests(TestCases, fun liver_bstring:trim_left/1). 82 | 83 | trim_right(_Config) -> 84 | TestCases = [ 85 | {<<>>, <<>>}, 86 | {<<" test "/utf8>>, <<" test"/utf8>>}, 87 | {<<" Тест "/utf8>>, <<" Тест"/utf8>>}, 88 | {<<" Тест \n\t\r"/utf8>>, <<" Тест"/utf8>>} 89 | ], 90 | run_tests(TestCases, fun liver_bstring:trim_right/1). 91 | 92 | trim(_Config) -> 93 | TestCases = [ 94 | {<<" test "/utf8>>, <<"test"/utf8>>}, 95 | {<<" Тест "/utf8>>, <<"Тест"/utf8>>} 96 | ], 97 | run_tests(TestCases, fun liver_bstring:trim/1). 98 | 99 | to_lower(_Config) -> 100 | TestCases = [ 101 | {<<" TEST "/utf8>>, <<" test "/utf8>>}, 102 | {<<" ТЕСТ "/utf8>>, <<" тест "/utf8>>} 103 | ], 104 | run_tests(TestCases, fun liver_bstring:to_lower/1). 105 | 106 | to_upper(_Config) -> 107 | TestCases = [ 108 | {<<" test "/utf8>>, <<" TEST ">>}, 109 | {<<" тест "/utf8>>, <<" ТЕСТ "/utf8>>} 110 | ], 111 | run_tests(TestCases, fun liver_bstring:to_upper/1). 112 | 113 | 114 | %% internal 115 | float_to_binary_tests([{Float, Binary}|TestCases]) when is_binary(Binary) -> 116 | case liver_float:to_binary(Float) =:= Binary of 117 | true -> float_to_binary_tests(TestCases); 118 | false -> 119 | ct:log("liver_float:to_binary(~p) =:= ~p~n", [Float, Binary]), 120 | {fail, unsuccessful} 121 | end; 122 | float_to_binary_tests([{Float, Float2}|TestCases]) when is_float(Float2) -> 123 | case binary_to_float(liver_float:to_binary(Float)) =:= Float2 of 124 | true -> float_to_binary_tests(TestCases); 125 | false -> 126 | ct:log("binary_to_float(liver_float:to_binary(~p)) =:= ~p~n", [Float, Float2]), 127 | {fail, unsuccessful} 128 | end; 129 | float_to_binary_tests([]) -> 130 | ok. 131 | 132 | run_tests([{From, To}|TestCases], Fun) -> 133 | case Fun(From) =:= To of 134 | true -> run_tests(TestCases, Fun); 135 | false -> 136 | {fail, unsuccessful} 137 | end; 138 | run_tests([], _Fun) -> 139 | ok. 140 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Liver 2 | [![Build Status](https://github.com/erlangbureau/liver/actions/workflows/ci.yml/badge.svg)](https://github.com/erlangbureau/liver/actions) 3 | [![Coverage Status](https://coveralls.io/repos/github/erlangbureau/liver/badge.svg?branch=master)](https://coveralls.io/github/erlangbureau/liver?branch=master) 4 | 5 | ## Summary 6 | [![Logo](https://upload.wikimedia.org/wikipedia/commons/d/d4/Liver.svg)]() 7 | 8 | Liver is a lightweight Erlang validator based on LIVR Specification (See http://livr-spec.org for details) 9 | 10 | ## Table of Contents 11 | * [Description](#description) 12 | * [Geting Started](#geting-started) 13 | * [Usage Examples](#usage-examples) 14 | * [Exports](#exports) 15 | * [License](#license) 16 | 17 | ## Description 18 | **LIVR specification features:** 19 | 20 | 1. Rules are declarative and language independent 21 | 2. Any number of rules for each field 22 | 3. Validator should return together errors for all fields 23 | 4. Exclude all fields that do not have validation rules described 24 | 5. Possibility to validate complex hierarchical structures 25 | 6. Easy to describe and understand validation 26 | 7. Returns understandable error codes (neither error messages nor numeric codes) 27 | 8. Easy to implement own rules (usually you will have several in every project) 28 | 9. Rules should be able to change results output ("trim", "nested_object", for example) 29 | 10. Multipurpose (user input validation, configs validation, contracts programming etc) 30 | 11. Unicode support 31 | 32 | **This implementation specific features:** 33 | 1. Strict Mode (returns errors on all fields that do not have validation rules) 34 | 2. Support on-the-fly conversion from proplist to map and vice versa 35 | 3. Support list as root element, what is missing in the original specification 36 | 4. Support on-the-fly conversion keys from string to atom 37 | 5. Ability to return custom error codes 38 | 6. Additional set of strict rules (without implicit conversion of types) 39 | 40 | 41 | 42 | ## Geting Started 43 | 1. Add as a dependency in your project: 44 | * For **rebar** add to rebar.config 45 | ```erl 46 | {deps, [ 47 | {liver, ".*", 48 | {git, "https://github.com/erlangbureau/liver.git", {branch, "0.9.0"}} 49 | } 50 | ]}. 51 | ``` 52 | 53 | * For **erlang.mk** add to make file: 54 | ```erl 55 | DEPS = liver 56 | dep_liver = git https://github.com/erlangbureau/liver.git 0.9.0 57 | ``` 58 | 59 | 2. Add liver in **your_project.app.src** file in tuple **applications**: 60 | ```erl 61 | {applications, [ 62 | kernel, 63 | stdlib, 64 | liver 65 | ]}, 66 | ``` 67 | 3. Thats all, now you can validate data, register your own rules or add aliases for built-in rules. 68 | 69 | ## Usage Examples 70 | 71 | Example of simple validation for object (map or proplist): 72 | ```erl 73 | 1> Schema1 = [{<<"first_name">>,[{length_between,[4,6]}]}]. 74 | 75 | 2> Input1 = [{<<"first_name">>,<<"Vasya">>}]. 76 | 77 | 3> liver:validate(Schema1, Input1). 78 | {ok, [{<<"first_name">>,<<"Vasya">>}]} 79 | 80 | 4> Schema2 = [{<<"number1">>,integer}]. 81 | 82 | 5> Input2 = [{<<"number1">>,-1.12}]. 83 | 84 | 6> liver:validate(Schema2, Input2). 85 | {error,[{<<"number1">>,<<"NOT_INTEGER">>}]} 86 | ``` 87 | 88 | Example of simple validation for list: 89 | ```erl 90 | 1> Schema = [{nested_object, #{pool_name => [required, is_atom]}}]. 91 | 92 | 2> liver:validate(Schema, [[{pool_name, test1}], [{pool_name, test2}]], #{return => map}). 93 | {ok,[#{pool_name => test1},#{pool_name => test2}]} 94 | 95 | 3> liver:validate(Schema, [[{pool_name, test1}], [{pool_nam, test2}]], #{return => map}). 96 | {error,[null,#{pool_name => <<"REQUIRED">>}]} 97 | ``` 98 | 99 | Example of more complex validation for object (map or proplist): 100 | ```erl 101 | 7> Schema = #{ 102 | <<"address">> => [required, {nested_object, #{ 103 | <<"country">> => [required,{one_of,[[<<"Ukraine">>,<<"USA">>]]}], 104 | <<"zip">> => positive_integer, 105 | <<"street">> => required, 106 | <<"building">> => [required,positive_integer] 107 | }}] 108 | }. 109 | 110 | 8> Input = #{ 111 | <<"address">> => #{ 112 | <<"country">> => <<"Ukraine">>, 113 | <<"zip">> => <<"12345">>, 114 | <<"street">> => <<"10">>, 115 | <<"building">> => <<"10">>, 116 | <<"extra_field">> => <<"will be removed">> 117 | }, 118 | <<"extra_field">> => <<"will be removed">> 119 | }. 120 | 121 | 9> liver:validate(Schema, Input). 122 | {ok,#{<<"address">> => #{<<"building">> => 10, 123 | <<"country">> => <<"Ukraine">>, 124 | <<"street">> => <<"10">>, 125 | <<"zip">> => 12345}}} 126 | ``` 127 | 128 | Example of strict validation (fields that are not specified in the scheme are forbidden): 129 | ```erl 130 | 10> liver:validate(Schema, Input, [{strict, true}]). 131 | {error,#{<<"address">> => #{<<"extra_field">> => <<"UNKNOWN_FIELD">>}, 132 | <<"extra_field">> => <<"UNKNOWN_FIELD">>}} 133 | ``` 134 | ## Exports 135 | 136 | ### `validate/2` 137 | 138 | ```erlang 139 | validate(Schema, Input) -> {ok, Output} | {error, ErrorList} 140 | 141 | Schema, Input, Output, ErrorList = proplist() | map() 142 | ``` 143 | Equivalent to `validate(Schema, Input, []).` 144 | 145 | ### `validate/3` 146 | 147 | ```erlang 148 | validate(Schema, Input, Opts) -> {ok, Output} | {error, ErrorList} 149 | 150 | Schema, Input, Output, ErrorList, Opts = proplist() | map() 151 | ``` 152 | Parameter Opts is a proplist or map that specifies return type and validation strictness. Default values are used for omitted options. This means that not specifying any options `([])` is the same as specifying `[{return, as_is}, {strict, false}]`. 153 | 154 | `{return, ReturnType}` 155 | 156 | If set to `as_is` the type of `Output` wiil be the same as type of `Input`. If set to `map` the `Output` will be map. If set to `proplist` the `Output` will be proplist. Defaults to `as_is` 157 | 158 | `{strict, boolean()}` 159 | 160 | If set to `false` deletes from `Input` all fields that not defined in `Schema`. Or if set to `true` and `Input` has fields that not defined in `Schema` returns error. Defaults to `false` 161 | 162 | ## License 163 | 164 | Liver is released under the MIT License 165 | -------------------------------------------------------------------------------- /src/liver.erl: -------------------------------------------------------------------------------- 1 | -module(liver). 2 | 3 | %% API 4 | -export([validate/2, validate/3]). 5 | -export([validate_map/3]). 6 | -export([validate_list/3]). 7 | -export([validate_term/3]). 8 | -export([which/1]). 9 | -export([add_rule/2]). 10 | -export([custom_error/2]). 11 | 12 | -include("liver.hrl"). 13 | 14 | -define(IsKV(Data), 15 | (is_map(Data) orelse is_list(Data)) 16 | ). 17 | 18 | %% API 19 | validate(Schema, Data) -> 20 | validate(Schema, Data, #{}). 21 | 22 | validate(Schema, Data, Opts) -> 23 | case detect_datatype_by_schema(Schema) of 24 | jsobject -> 25 | validate_map(Schema, Data, Opts); 26 | list -> 27 | validate_list(Schema, Data, Opts); 28 | _ -> 29 | validate_term(Schema, Data, Opts) 30 | end. 31 | 32 | validate_map(Schema, In, Opts) 33 | when ?IsKV(Schema) andalso ?IsKV(In) andalso ?IsKV(Opts) -> 34 | SchemaKeys = liver_maps:keys(Schema), 35 | DataKeys = liver_maps:keys(In), 36 | Keys = sift(SchemaKeys, DataKeys, []), 37 | ReturnType = get_return_type(Opts, In), 38 | Out = liver_maps:new(ReturnType), 39 | Errors = liver_maps:new(ReturnType), 40 | validate(Keys, Schema, In, Out, Errors, Opts); 41 | validate_map(_Schema, _In, _Opts) -> 42 | ErrorMsg = custom_error_message(format_error), 43 | {error, ErrorMsg}. 44 | 45 | validate_list(Schema, Data, Opts) when is_list(Data) andalso ?IsKV(Opts) -> 46 | Results = [validate_term(Schema, Value, Opts) || Value <- Data], 47 | case lists:keymember(error, 1, Results) of 48 | false -> 49 | ListOfValues2 = [Val || {ok, Val} <- Results], 50 | {ok, ListOfValues2}; 51 | true -> 52 | ListOfErrors = [begin 53 | case Result of 54 | {ok, _} -> null; 55 | {error, Err} -> Err 56 | end 57 | end || Result <- Results], 58 | {error, ListOfErrors} 59 | end. 60 | 61 | validate_term(Schema, Data, Opts) when ?IsKV(Opts) -> 62 | case validate_map(#{'$fake_key' => Schema}, #{'$fake_key' => Data}, Opts) of 63 | {ok, #{'$fake_key' := Val}} -> 64 | {ok, Val}; 65 | {error, #{'$fake_key' := Err}} -> 66 | {error, Err} 67 | end. 68 | 69 | which(Rule) -> 70 | AvailableRules = application:get_env(?MODULE, rules, ?DEFAULT_RULES), 71 | maps:get(Rule, AvailableRules, undefined_module). 72 | 73 | add_rule(Rule, Module) when is_atom(Rule), is_atom(Module) -> 74 | OldRules = application:get_env(?MODULE, rules, ?DEFAULT_RULES), 75 | NewRules = liver_maps:put(Rule, Module, OldRules), 76 | application:set_env(?MODULE, rules, NewRules). 77 | 78 | custom_error(ErrCode, ErrMsg) when is_atom(ErrCode) -> 79 | OldErrors = application:get_env(?MODULE, errors, ?DEFAULT_ERRORS), 80 | NewErrors = liver_maps:put(ErrCode, ErrMsg, OldErrors), 81 | application:set_env(?MODULE, errors, NewErrors). 82 | 83 | 84 | %% internal 85 | validate([{K, intersection}|Keys], Schema, In, Out, Errors, Opts) -> 86 | %% Key from Schema exists in Data 87 | Rules = liver_maps:get(K, Schema), 88 | Value = liver_maps:get(K, In), 89 | Rules2 = liver_rules:normalize(Rules, In), 90 | case liver_rules:execute(Rules2, Value, Opts) of 91 | {ok, Value2} -> 92 | Out2 = liver_maps:put(K, Value2, Out), 93 | validate(Keys, Schema, In, Out2, Errors, Opts); 94 | {error, Err} -> 95 | ErrorCode = custom_error_message(Err), 96 | Errors2 = liver_maps:put(K, ErrorCode, Errors), 97 | validate(Keys, Schema, In, Out, Errors2, Opts) 98 | end; 99 | validate([{K, schema}|Keys], Schema, In, Out, Errors, Opts) -> 100 | %% Key from Schema doesn't exist in Data 101 | Rules = liver_maps:get(K, Schema), 102 | Rules2 = liver_rules:normalize(Rules, In), 103 | case liver_rules:has_required(Rules2) of 104 | true -> 105 | case liver_rules:execute(Rules2, Opts) of 106 | {ok, Value2} -> 107 | Out2 = liver_maps:put(K, Value2, Out), 108 | validate(Keys, Schema, In, Out2, Errors, Opts); 109 | {error, Err} -> 110 | ErrorCode = custom_error_message(Err), 111 | Errors2 = liver_maps:put(K, ErrorCode, Errors), 112 | validate(Keys, Schema, In, Out, Errors2, Opts) 113 | end; 114 | false -> 115 | validate(Keys, Schema, In, Out, Errors, Opts) 116 | end; 117 | validate([{K, data}|Keys], Schema, In, Out, Errors, Opts) -> 118 | %% Key from Data doesn't exist in Schema 119 | case liver_maps:get(strict, Opts, false) of 120 | false -> 121 | %% Strict validation disabled 122 | validate(Keys, Schema, In, Out, Errors, Opts); 123 | true -> 124 | %% Strict validation enabled 125 | ErrorCode = custom_error_message(unknown_field), 126 | Errors2 = liver_maps:put(K, ErrorCode, Errors), 127 | validate(Keys, Schema, In, Out, Errors2, Opts) 128 | end; 129 | validate([], _Schema, _In, Out, Errors, _Opts) -> 130 | case liver_maps:is_empty(Errors) of 131 | true -> 132 | {ok, liver_maps:reverse(Out)}; 133 | false -> 134 | {error, liver_maps:reverse(Errors)} 135 | end. 136 | 137 | sift([K|SchemaKeys], DataKeys, Acc) -> 138 | case lists:member(K, DataKeys) of 139 | true -> 140 | DataKeys2 = lists:delete(K, DataKeys), 141 | Acc2 = [{K, intersection}|Acc], 142 | sift(SchemaKeys, DataKeys2, Acc2); 143 | false -> 144 | Acc2 = [{K, schema}|Acc], 145 | sift(SchemaKeys, DataKeys, Acc2) 146 | end; 147 | sift([], [K|DataKeys], Acc) -> 148 | Acc2 = [{K, data}|Acc], 149 | sift([], DataKeys, Acc2); 150 | sift([], [], Acc) -> 151 | lists:reverse(Acc). 152 | 153 | get_return_type(Opts, InData) -> 154 | case liver_maps:get(return, Opts, as_is) of 155 | map -> map; 156 | proplist -> proplist; 157 | as_is -> liver_maps:type(InData) 158 | end. 159 | 160 | custom_error_message(Code) -> 161 | Errors = application:get_env(?MODULE, errors, ?DEFAULT_ERRORS), 162 | maps:get(Code, Errors, Code). 163 | 164 | detect_datatype_by_schema(Schema) when is_map(Schema) -> 165 | jsobject; 166 | detect_datatype_by_schema(Schema) when is_list(Schema) -> 167 | Schema2 = liver_rules:normalize(Schema, []), 168 | Schema3 = [T || {K, _} = T <- Schema2, is_valid_rule(K)], 169 | case Schema2 =:= Schema3 of 170 | true -> 171 | list; 172 | false -> 173 | jsobject 174 | end; 175 | detect_datatype_by_schema(_Schema) -> 176 | term. 177 | 178 | is_valid_rule(Rule) -> 179 | which(Rule) /= undefined_module. 180 | -------------------------------------------------------------------------------- /src/sets/liver_strict_rules.erl: -------------------------------------------------------------------------------- 1 | -module(liver_strict_rules). 2 | 3 | %% API 4 | %% common rules 5 | -export([required/3]). 6 | -export([default/3]). 7 | -export([is_null/3]). 8 | -export([is_not_null/3]). 9 | -export([is_undefined/3]). 10 | -export([is_not_undefined/3]). 11 | 12 | %% string rules 13 | -export([is_string/3, to_string/3]). 14 | -export([is_bstring/3, to_bstring/3]). 15 | -export([is_atom/3, to_atom/3]). 16 | 17 | %% numeric rules 18 | -export([is_integer/3, to_integer/3]). 19 | 20 | %% boolean rules 21 | -export([is_boolean/3, to_boolean/3]). 22 | 23 | %% list rules 24 | -export([is_list/3]). 25 | 26 | %% proplist rules 27 | -export([is_proplist/3]). 28 | 29 | %% map rules 30 | -export([is_map/3]). 31 | 32 | %% nested elements 33 | -export([nested_map/3]). 34 | -export([nested_list/3]). 35 | -export([nested_proplist/3]). 36 | 37 | 38 | -include("liver_rules.hrl"). 39 | 40 | 41 | %% API 42 | required(_Args, ?MISSED_FIELD_VALUE, _Opts) -> 43 | {error, required}; 44 | required(_Args, Value, _Opts) -> 45 | {ok, Value}. 46 | 47 | default([Default], _Value, Opts) -> 48 | default(Default, _Value, Opts); 49 | default(Default, ?MISSED_FIELD_VALUE, _Opts) -> 50 | {ok, Default}; 51 | default(_Default, Value, _Opts) -> 52 | {ok, Value}. 53 | 54 | 55 | 56 | is_null(_Args, Value = null, _Opts) -> 57 | {ok, Value}; 58 | is_null(_Args, _Value, _Opts) -> 59 | {error, not_null}. 60 | 61 | is_not_null(_Args, null, _Opts) -> 62 | {error, cannot_be_null}; 63 | is_not_null(_Args, Value, _Opts) -> 64 | {ok, Value}. 65 | 66 | is_undefined(_Args, Value = undefined, _Opts) -> 67 | {ok, Value}; 68 | is_undefined(_Args, _Value, _Opts) -> 69 | {error, not_undefined}. 70 | 71 | is_not_undefined(_Args, undefined, _Opts) -> 72 | {error, cannot_be_undefined}; 73 | is_not_undefined(_Args, Value, _Opts) -> 74 | {ok, Value}. 75 | 76 | is_integer([positive], Value, _Opts) when is_integer(Value), Value > 0 -> 77 | {ok, Value}; 78 | is_integer([negative], Value, _Opts) when is_integer(Value), Value < 0 -> 79 | {ok, Value}; 80 | is_integer(_Args, Value, _Opts) when is_integer(Value) -> 81 | {ok, Value}; 82 | is_integer(_Args, _Value, _Opts) -> 83 | {error, not_integer}. 84 | 85 | is_boolean(_Args, Value, _Opts) when is_boolean(Value) -> 86 | {ok, Value}; 87 | is_boolean(_Args, _Value, _Opts) -> 88 | {error, not_boolean}. 89 | 90 | is_list([not_empty], [], _Opts) -> 91 | {error, cannot_be_empty}; 92 | is_list([empty], [_|_], _Opts) -> 93 | {error, not_empty}; 94 | is_list(_Args, Value, _Opts) when is_list(Value) -> 95 | {ok, Value}; 96 | is_list(_Args, _Value, _Opts) -> 97 | {error, not_list}. 98 | 99 | is_string([not_empty], "", _Opts) -> 100 | {error, cannot_be_empty}; 101 | is_string([empty], [_|_], _Opts) -> 102 | {error, not_empty}; 103 | is_string(_Args, Value, _Opts) when is_list(Value) -> 104 | case is_char_list(Value) of 105 | true -> 106 | {ok, Value}; 107 | false -> 108 | {error, not_string} 109 | end; 110 | is_string(_Args, _Value, _Opts) -> 111 | {error, not_string}. 112 | 113 | is_bstring([not_empty], <<"">>, _Opts) -> 114 | {error, cannot_be_empty}; 115 | is_bstring([empty], <<_, _/binary>>, _Opts) -> 116 | {error, not_empty}; 117 | is_bstring(_Args, Value, _Opts) when is_binary(Value) -> 118 | case is_char_binary(Value) of 119 | true -> 120 | {ok, Value}; 121 | false -> 122 | {error, not_string} 123 | end; 124 | is_bstring(_Args, _Value, _Opts) -> 125 | {error, not_bstring}. 126 | 127 | is_atom(_Args, Value, _Opts) when is_atom(Value) -> 128 | {ok, Value}; 129 | is_atom(_Args, _Value, _Opts) -> 130 | {error, not_atom}. 131 | 132 | to_integer(_Args, Value, _Opts) when is_binary(Value) -> 133 | try binary_to_integer(Value) of 134 | Int -> {ok, Int} 135 | catch 136 | _:_ -> {error, not_integer} 137 | end; 138 | to_integer(_Args, Value, _Opts) when is_list(Value) -> 139 | try list_to_integer(Value) of 140 | Int -> {ok, Int} 141 | catch 142 | _:_ -> {error, not_integer} 143 | end; 144 | to_integer(_Args, Value, _Opts) when is_float(Value) -> 145 | try trunc(Value) of 146 | Int -> {ok, Int} 147 | catch 148 | _:_ -> {error, not_integer} 149 | end; 150 | to_integer(_Args, _Value, _Opts) -> 151 | {error, not_integer}. 152 | 153 | to_boolean(_Args, 0, _Opts) -> 154 | {ok, false}; 155 | to_boolean(_Args, "", _Opts) -> 156 | {ok, false}; 157 | to_boolean(_Args, "0", _Opts) -> 158 | {ok, false}; 159 | to_boolean(_Args, "false", _Opts) -> 160 | {ok, false}; 161 | to_boolean(_Args, <<"">>, _Opts) -> 162 | {ok, false}; 163 | to_boolean(_Args, <<"0">>, _Opts) -> 164 | {ok, false}; 165 | to_boolean(_Args, <<"false">>, _Opts) -> 166 | {ok, false}; 167 | to_boolean(_Args, undefined, _Opts) -> 168 | {ok, false}; 169 | to_boolean(_Args, null, _Opts) -> 170 | {ok, false}; 171 | to_boolean(_Args, _, _Opts) -> 172 | {ok, true}. 173 | 174 | to_string(_Args, Value, _Opts) when is_binary(Value) -> 175 | try unicode:characters_to_list(Value) of 176 | Value2 -> {ok, Value2} 177 | catch 178 | _:_ -> {error, cant_be_string} 179 | end; 180 | to_string(_Args, Value,_Opts) when is_atom(Value) -> 181 | try atom_to_list(Value) of 182 | Value2 -> {ok, Value2} 183 | catch 184 | _:_ -> {error, cant_be_string} 185 | end; 186 | to_string(_Args, _Value, _Opts) -> 187 | {error, cant_be_string}. 188 | 189 | to_bstring(_Args, Value, _Opts) when is_list(Value) -> 190 | try unicode:characters_to_binary(Value) of 191 | Value2 -> {ok, Value2} 192 | catch 193 | _:_ -> {error, cant_be_string} 194 | end; 195 | to_bstring(_Args, Value, _Opts) when is_atom(Value) -> 196 | try atom_to_binary(Value, utf8) of 197 | Value2 -> {ok, Value2} 198 | catch 199 | _:_ -> {error, cant_be_string} 200 | end; 201 | to_bstring(_Args, _Value, _Opts) -> 202 | {error, cant_be_string}. 203 | 204 | to_atom(_Args, Value, _Opts) when is_binary(Value) -> 205 | try binary_to_atom(Value, utf8) of 206 | Value2 -> {ok, Value2} 207 | catch 208 | _:_ -> {error, cant_be_atom} 209 | end; 210 | to_atom(_Args, Value, _Opts) when is_list(Value) -> 211 | try list_to_atom(Value) of 212 | Value2 -> {ok, Value2} 213 | catch 214 | _:_ -> {error, cant_be_atom} 215 | end. 216 | 217 | is_proplist(_Args, Value, _Opts) when is_list(Value) -> 218 | Value2 = [Tuple || {_, _} = Tuple <- Value], 219 | case Value =:= Value2 of 220 | true -> 221 | {ok, Value}; 222 | false -> 223 | {error, not_proplist} 224 | end; 225 | is_proplist(_Args, _Value, _Opts) -> 226 | {error, not_proplist}. 227 | 228 | is_map(_Args, Value, _Opts) when is_map(Value) -> 229 | {ok, Value}; 230 | is_map(_Args, _Value, _Opts) -> 231 | {error, not_map}. 232 | 233 | nested_map(Args, Value, Opts) when is_map(Args), is_map(Value) -> 234 | liver:validate_map(Args, Value, Opts). 235 | 236 | nested_proplist(Args, Value, Opts) when is_list(Args), is_list(Value) -> 237 | liver:validate_map(Args, Value, Opts). 238 | 239 | nested_list(Args, Value, Opts) when is_list(Args), is_list(Value) -> 240 | liver:validate_list(Args, Value, Opts). 241 | 242 | %% internal 243 | is_char_list([C|Cs]) when 244 | is_integer(C), C >= 0, C < 16#D800; 245 | is_integer(C), C > 16#DFFF, C < 16#FFFE; 246 | is_integer(C), C > 16#FFFF, C =< 16#10FFFF -> 247 | is_char_list(Cs); 248 | is_char_list([]) -> 249 | true; 250 | is_char_list(_) -> 251 | false. 252 | 253 | is_char_binary(<>) when 254 | is_integer(C), C >= 0, C < 16#D800; 255 | is_integer(C), C > 16#DFFF, C < 16#FFFE; 256 | is_integer(C), C > 16#FFFF, C =< 16#10FFFF -> 257 | is_char_binary(Cs); 258 | is_char_binary(<<>>) -> 259 | true; 260 | is_char_binary(_) -> 261 | false. 262 | -------------------------------------------------------------------------------- /src/liver_float.erl: -------------------------------------------------------------------------------- 1 | %% @copyright 2007 Mochi Media, Inc. 2 | %% @author Bob Ippolito 3 | %% @reworked_by Serhii Kostiushkin 4 | %% see original version at https://github.com/basho/mochiweb/blob/master/src/mochinum.erl 5 | 6 | %% Permission is hereby granted, free of charge, to any person obtaining a 7 | %% copy of this software and associated documentation files (the "Software"), 8 | %% to deal in the Software without restriction, including without limitation 9 | %% the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | %% and/or sell copies of the Software, and to permit persons to whom the 11 | %% Software is furnished to do so, subject to the following conditions: 12 | %% 13 | %% The above copyright notice and this permission notice shall be included in 14 | %% all copies or substantial portions of the Software. 15 | %% 16 | %% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | %% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | %% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | %% THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | %% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | %% FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 | %% DEALINGS IN THE SOFTWARE. 23 | 24 | %% @doc Useful numeric algorithms for floats that cover some deficiencies 25 | %% in the math module. More interesting is digits/1, which implements 26 | %% the algorithm from: 27 | %% http://www.cs.indiana.edu/~burger/fp/index.html 28 | %% See also "Printing Floating-Point Numbers Quickly and Accurately" 29 | %% in Proceedings of the SIGPLAN '96 Conference on Programming Language 30 | %% Design and Implementation. 31 | 32 | -module(liver_float). 33 | 34 | %% API 35 | -export([to_binary/1]). 36 | 37 | %% IEEE 754 Float exponent bias 38 | -define(FLOAT_BIAS, 1022). 39 | -define(MIN_EXP, -1074). 40 | -define(BIG_POW, 4503599627370496). 41 | 42 | -define(ZEROS, <<"0000000000000000">>). 43 | 44 | %% API 45 | %% TODO 46 | %% See http://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf 47 | %% See https://www.cs.indiana.edu/~dyb/pubs/FP-Printing-PLDI96.pdf 48 | 49 | %% To understand why the implementation for Erlang/OTP27 and above is different, see here: 50 | %% https://erlangforums.com/t/in-erlang-otp-27-0-0-will-no-longer-be-exactly-equal-to-0-0/2586 51 | %% and here: https://github.com/erlang/otp/issues/7168 52 | 53 | -if(?OTP_RELEASE >= 27). 54 | 55 | to_binary(+0.0) -> 56 | <<"0.0">>; 57 | to_binary(-0.0) -> 58 | <<"0.0">>; 59 | to_binary(Float) when is_float(Float) -> 60 | BinFloat = <>, %% to binary (double precision) 61 | <> = BinFloat, %% unpack 62 | Est = int_ceil(math:log10(abs(Float)) - 1.0e-10), 63 | {PointPlace, Digits} = to_printable_digits(Exp, Frac, Est), 64 | Digits2 = apply_decimal_part(PointPlace, Digits), 65 | add_sign(Sign, Digits2). 66 | 67 | -else. 68 | 69 | to_binary(0.0) -> 70 | <<"0.0">>; 71 | to_binary(Float) when is_float(Float) -> 72 | BinFloat = <>, %% to binary (double precision) 73 | <> = BinFloat, %% unpack 74 | Est = int_ceil(math:log10(abs(Float)) - 1.0e-10), 75 | {PointPlace, Digits} = to_printable_digits(Exp, Frac, Est), 76 | Digits2 = apply_decimal_part(PointPlace, Digits), 77 | add_sign(Sign, Digits2). 78 | 79 | -endif. 80 | 81 | %% internal 82 | int_ceil(Float) -> 83 | Int = trunc(Float), 84 | case (Float - Int) > 0 of 85 | true -> Int + 1; 86 | false -> Int 87 | end. 88 | 89 | to_printable_digits(Exp, Frac, Est) -> 90 | {Exp2, Frac2} = if 91 | Exp =:= 0 -> 92 | {?MIN_EXP, Frac}; 93 | true -> 94 | {Exp - 53 - ?FLOAT_BIAS, Frac + (1 bsl 52)} 95 | end, 96 | Round = ((Frac2 band 1) =:= 0), 97 | case Exp2 >= 0 of 98 | true -> 99 | BExp2 = 1 bsl Exp2, 100 | case (Frac2 =/= ?BIG_POW) of 101 | true -> 102 | scale((Frac2 * BExp2 * 2), 2, BExp2, BExp2, Round, Round, Est); 103 | false -> 104 | scale((Frac2 * BExp2 * 4), 4, (BExp2 * 2), BExp2, Round, Round, Est) 105 | end; 106 | false -> 107 | case (Exp2 =:= ?MIN_EXP) orelse (Frac2 =/= ?BIG_POW) of 108 | true -> 109 | scale((Frac2 * 2), 1 bsl (1 - Exp2), 1, 1, Round, Round, Est); 110 | false -> 111 | scale((Frac2 * 4), 1 bsl (2 - Exp2), 2, 1, Round, Round, Est) 112 | end 113 | end. 114 | 115 | scale(R, S, MPlus, MMinus, LowOk, HighOk, Est) -> 116 | case Est >= 0 of 117 | true -> 118 | Scale = int_pow(10, Est), 119 | fixup(R, S * Scale, MPlus, MMinus, Est, LowOk, HighOk); 120 | false -> 121 | Scale = int_pow(10, -Est), 122 | fixup(R * Scale, S, MPlus * Scale, MMinus * Scale, Est, LowOk, HighOk) 123 | end. 124 | 125 | fixup(R, S, MPlus, MMinus, K, LowOk, HighOk) -> 126 | TooLow = case HighOk of 127 | true -> (R + MPlus) >= S; 128 | false -> (R + MPlus) > S 129 | end, 130 | {K2, Digits} = case TooLow of 131 | true -> 132 | {K + 1, (generate(R, S, MPlus, MMinus, LowOk, HighOk))}; 133 | false -> 134 | {K, (generate(R * 10, S, MPlus * 10, MMinus * 10, LowOk, HighOk))} 135 | end, 136 | {K2, trim_leading_zeros(Digits)}. 137 | 138 | trim_leading_zeros(<<"0", Rest/binary>>) -> 139 | trim_leading_zeros(Rest); 140 | trim_leading_zeros(Rest) -> 141 | Rest. 142 | 143 | generate(R0, S, MPlus, MMinus, LowOk, HighOk) -> 144 | Digit = R0 div S, 145 | Rest = R0 rem S, 146 | TC1 = case LowOk of 147 | true -> Rest =< MMinus; 148 | false -> Rest < MMinus 149 | end, 150 | TC2 = case HighOk of 151 | true -> (Rest + MPlus) >= S; 152 | false -> (Rest + MPlus) > S 153 | end, 154 | case TC1 of 155 | false -> 156 | case TC2 of 157 | false -> 158 | <<(to_char(Digit)), (generate(Rest * 10, S, MPlus * 10, MMinus * 10, LowOk, HighOk))/binary>>; 159 | true -> 160 | <<(to_char(Digit+1))>> 161 | end; 162 | true -> 163 | case TC2 of 164 | false -> 165 | <<(to_char(Digit))>>; 166 | true -> 167 | case Rest * 2 < S of 168 | true -> <<(to_char(Digit))>>; 169 | false -> <<(to_char(Digit+1))>> 170 | end 171 | end 172 | end. 173 | 174 | to_char(Digit) -> $0 + Digit. 175 | 176 | apply_decimal_part(0, S) -> 177 | <<"0.", S/binary>>; 178 | apply_decimal_part(PointPlace, S) when PointPlace > 0 -> 179 | L = byte_size(S), 180 | case PointPlace - L of 181 | 0 -> 182 | <>; 183 | N when N < 0 -> 184 | Size = L + N, 185 | <> = S, 186 | <>; 187 | N when N < 6 -> 188 | <>; 189 | _ -> 190 | apply_exp(PointPlace, S) 191 | end; 192 | apply_decimal_part(PointPlace, S) when PointPlace > -6 -> 193 | N = abs(PointPlace), 194 | <<"0.", ?ZEROS:N/binary, S/binary>>; 195 | apply_decimal_part(PointPlace, S) -> 196 | apply_exp(PointPlace, S). 197 | 198 | apply_exp(PointPlace, S) -> 199 | <> = S, 200 | S1 = case S0 of 201 | <<>> -> <<"0">>; 202 | _ -> S0 203 | end, 204 | Exp = case PointPlace < 0 of 205 | true -> <<"e-">>; 206 | false -> <<"e+">> 207 | end, 208 | ExpIndex = integer_to_binary(abs(PointPlace - 1)), 209 | <>. 210 | 211 | add_sign(0, Result) -> 212 | Result; 213 | add_sign(1, Result) -> 214 | <<"-", Result/binary>>. 215 | 216 | int_pow(10, 0) -> 217 | 1; 218 | int_pow(10, N) -> 219 | int_pow(10, abs(N), 1). 220 | 221 | int_pow(X, N, R) when N < 2 -> 222 | R * X; 223 | int_pow(X, N, R) -> 224 | R2 = case N band 1 of 225 | 1 -> R * X; 226 | 0 -> R 227 | end, 228 | int_pow(X * X, N bsr 1, R2). 229 | -------------------------------------------------------------------------------- /tests/livr_rules_maps_SUITE.erl: -------------------------------------------------------------------------------- 1 | -module(livr_rules_maps_SUITE). 2 | 3 | -compile(export_all). 4 | 5 | -include_lib("common_test/include/ct.hrl"). 6 | 7 | -define(LIVR_TEST_PATH, "../../deps/LIVR/test_suite"). 8 | -define(EXAMPLE, "liver:validate(~p, ~p) =:= ~p.~n"). 9 | -define(TEST_CASES, [ 10 | 11 | %% common rules 12 | required, 13 | not_empty, 14 | not_empty_list, 15 | any_object, 16 | 17 | %% string rules 18 | string, 19 | eq, 20 | one_of, 21 | max_length, 22 | min_length, 23 | length_between, 24 | length_equal, 25 | like, 26 | 27 | %% numeric rules 28 | integer, 29 | positive_integer, 30 | decimal, 31 | positive_decimal, 32 | max_number, 33 | min_number, 34 | number_between, 35 | 36 | %% special rules 37 | email, 38 | url, 39 | iso_date, 40 | equal_to_field, 41 | 42 | %% meta rules 43 | nested_object, 44 | variable_object, 45 | list_of, 46 | list_of_objects, 47 | list_of_different_objects, 48 | 'or', 49 | 50 | %% modifiers (previously - "filter rules") 51 | trim, 52 | to_lc, 53 | to_uc, 54 | remove, 55 | leave_only, 56 | default 57 | 58 | ]). 59 | -define(RUN(Config), 60 | Type = ?config(init_type, Config), 61 | {Rules, Input, Output} = ?config(conditions, Config), 62 | Expected = expected_output(Type, Output), 63 | case liver:validate(Rules, Input) =:= Expected of 64 | true -> 65 | ok; 66 | false -> 67 | io:format(?EXAMPLE, [Rules, Input, Expected]), 68 | {fail, unsuccessful} 69 | end 70 | ). 71 | 72 | all() -> 73 | [ 74 | {group, positive}, 75 | {group, negative} 76 | ]. 77 | 78 | groups() -> 79 | [ 80 | {positive, [parallel], ?TEST_CASES}, 81 | {negative, [parallel], ?TEST_CASES} 82 | ]. 83 | 84 | init_per_group(Name, Config) -> 85 | [{init_type, Name}|Config]. 86 | 87 | end_per_group(_Name, Config) -> 88 | lists:keydelete(init_type, 1, Config). 89 | 90 | init_per_testcase(Name, Config) -> 91 | Type = ?config(init_type, Config), 92 | case read_conditions(Name, Type) of 93 | {ok, Conditions} -> 94 | Conditions2 = parse_hack(Name, Conditions), 95 | [{conditions, Conditions2}|Config]; 96 | skip -> 97 | {skipped, no_data} 98 | end. 99 | 100 | end_per_testcase(_Name, Config) -> 101 | lists:keydelete(conditions, 1, Config). 102 | 103 | required(Config) -> 104 | ?RUN(Config). 105 | 106 | not_empty(Config) -> 107 | ?RUN(Config). 108 | 109 | not_empty_list(Config) -> 110 | ?RUN(Config). 111 | 112 | any_object(Config) -> 113 | ?RUN(Config). 114 | 115 | string(Config) -> 116 | ?RUN(Config). 117 | 118 | eq(Config) -> 119 | ?RUN(Config). 120 | 121 | one_of(Config) -> 122 | ?RUN(Config). 123 | 124 | max_length(Config) -> 125 | ?RUN(Config). 126 | 127 | min_length(Config) -> 128 | ?RUN(Config). 129 | 130 | length_between(Config) -> 131 | ?RUN(Config). 132 | 133 | length_equal(Config) -> 134 | ?RUN(Config). 135 | 136 | like(Config) -> 137 | ?RUN(Config). 138 | 139 | integer(Config) -> 140 | ?RUN(Config). 141 | 142 | positive_integer(Config) -> 143 | ?RUN(Config). 144 | 145 | decimal(Config) -> 146 | ?RUN(Config). 147 | 148 | positive_decimal(Config) -> 149 | ?RUN(Config). 150 | 151 | max_number(Config) -> 152 | ?RUN(Config). 153 | 154 | min_number(Config) -> 155 | ?RUN(Config). 156 | 157 | number_between(Config) -> 158 | ?RUN(Config). 159 | 160 | email(Config) -> 161 | ?RUN(Config). 162 | 163 | url(Config) -> 164 | ?RUN(Config). 165 | 166 | iso_date(Config) -> 167 | ?RUN(Config). 168 | 169 | equal_to_field(Config) -> 170 | ?RUN(Config). 171 | 172 | nested_object(Config) -> 173 | ?RUN(Config). 174 | 175 | variable_object(Config) -> 176 | ?RUN(Config). 177 | 178 | list_of(Config) -> 179 | ?RUN(Config). 180 | 181 | list_of_objects(Config) -> 182 | ?RUN(Config). 183 | 184 | list_of_different_objects(Config) -> 185 | ?RUN(Config). 186 | 187 | 'or'(Config) -> 188 | ?RUN(Config). 189 | 190 | trim(Config) -> 191 | ?RUN(Config). 192 | 193 | to_lc(Config) -> 194 | ?RUN(Config). 195 | 196 | to_uc(Config) -> 197 | ?RUN(Config). 198 | 199 | remove(Config) -> 200 | ?RUN(Config). 201 | 202 | leave_only(Config) -> 203 | ?RUN(Config). 204 | 205 | default(Config) -> 206 | ?RUN(Config). 207 | 208 | %% internal 209 | read_conditions(TestCase, Option) -> 210 | case case_to_path(TestCase, Option) of 211 | {ok, Path} -> 212 | OutputPath = case Option of 213 | positive -> "output.json"; 214 | negative -> "errors.json" 215 | end, 216 | {ok, Rules} = file:read_file(Path ++ "rules.json"), 217 | {ok, Input} = file:read_file(Path ++ "input.json"), 218 | {ok, Output} = file:read_file(Path ++ OutputPath), 219 | {ok, {decode(Rules), decode(Input), decode(Output)}}; 220 | skip -> 221 | skip 222 | end. 223 | 224 | case_to_path(required, positive) -> 225 | {ok, ?LIVR_TEST_PATH ++ "/positive/01-required/"}; 226 | case_to_path(required, negative) -> 227 | {ok, ?LIVR_TEST_PATH ++ "/negative/01-required/"}; 228 | case_to_path(not_empty, positive) -> 229 | {ok, ?LIVR_TEST_PATH ++ "/positive/02-not_empty/"}; 230 | case_to_path(not_empty, negative) -> 231 | {ok, ?LIVR_TEST_PATH ++ "/negative/02-not_empty/"}; 232 | case_to_path(one_of, positive) -> 233 | {ok, ?LIVR_TEST_PATH ++ "/positive/03-one_of/"}; 234 | case_to_path(one_of, negative) -> 235 | {ok, ?LIVR_TEST_PATH ++ "/negative/03-one_of/"}; 236 | case_to_path(min_length, positive) -> 237 | {ok, ?LIVR_TEST_PATH ++ "/positive/04-min_length/"}; 238 | case_to_path(min_length, negative) -> 239 | {ok, ?LIVR_TEST_PATH ++ "/negative/04-min_length/"}; 240 | case_to_path(max_length, positive) -> 241 | {ok, ?LIVR_TEST_PATH ++ "/positive/05-max_length/"}; 242 | case_to_path(max_length, negative) -> 243 | {ok, ?LIVR_TEST_PATH ++ "/negative/05-max_length/"}; 244 | case_to_path(length_equal, positive) -> 245 | {ok, ?LIVR_TEST_PATH ++ "/positive/06-length_equal/"}; 246 | case_to_path(length_equal, negative) -> 247 | {ok, ?LIVR_TEST_PATH ++ "/negative/06-length_equal/"}; 248 | case_to_path(length_between, positive) -> 249 | {ok, ?LIVR_TEST_PATH ++ "/positive/07-length_between/"}; 250 | case_to_path(length_between, negative) -> 251 | {ok, ?LIVR_TEST_PATH ++ "/negative/07-length_between/"}; 252 | case_to_path(like, positive) -> 253 | {ok, ?LIVR_TEST_PATH ++ "/positive/08-like/"}; 254 | case_to_path(like, negative) -> 255 | {ok, ?LIVR_TEST_PATH ++ "/negative/08-like/"}; 256 | case_to_path(integer, positive) -> 257 | {ok, ?LIVR_TEST_PATH ++ "/positive/09-integer/"}; 258 | case_to_path(integer, negative) -> 259 | {ok, ?LIVR_TEST_PATH ++ "/negative/09-integer/"}; 260 | case_to_path(positive_integer, positive) -> 261 | {ok, ?LIVR_TEST_PATH ++ "/positive/10-positive_integer/"}; 262 | case_to_path(positive_integer, negative) -> 263 | {ok, ?LIVR_TEST_PATH ++ "/negative/10-positive_integer/"}; 264 | case_to_path(decimal, positive) -> 265 | {ok, ?LIVR_TEST_PATH ++ "/positive/11-decimal/"}; 266 | case_to_path(decimal, negative) -> 267 | {ok, ?LIVR_TEST_PATH ++ "/negative/11-decimal/"}; 268 | case_to_path(positive_decimal, positive) -> 269 | {ok, ?LIVR_TEST_PATH ++ "/positive/12-positive_decimal/"}; 270 | case_to_path(positive_decimal, negative) -> 271 | {ok, ?LIVR_TEST_PATH ++ "/negative/12-positive_decimal/"}; 272 | case_to_path(max_number, positive) -> 273 | {ok, ?LIVR_TEST_PATH ++ "/positive/13-max_number/"}; 274 | case_to_path(max_number, negative) -> 275 | {ok, ?LIVR_TEST_PATH ++ "/negative/13-max_number/"}; 276 | case_to_path(min_number, positive) -> 277 | {ok, ?LIVR_TEST_PATH ++ "/positive/14-min_number/"}; 278 | case_to_path(min_number, negative) -> 279 | {ok, ?LIVR_TEST_PATH ++ "/negative/14-min_number/"}; 280 | case_to_path(number_between, positive) -> 281 | {ok, ?LIVR_TEST_PATH ++ "/positive/15-number_between/"}; 282 | case_to_path(number_between, negative) -> 283 | {ok, ?LIVR_TEST_PATH ++ "/negative/15-number_beetween/"}; 284 | case_to_path(email, positive) -> 285 | {ok, ?LIVR_TEST_PATH ++ "/positive/16-email/"}; 286 | case_to_path(email, negative) -> 287 | {ok, ?LIVR_TEST_PATH ++ "/negative/16-email/"}; 288 | case_to_path(equal_to_field, positive) -> 289 | {ok, ?LIVR_TEST_PATH ++ "/positive/17-equal_to_field/"}; 290 | case_to_path(equal_to_field, negative) -> 291 | {ok, ?LIVR_TEST_PATH ++ "/negative/17-equal_to_field/"}; 292 | case_to_path(nested_object, positive) -> 293 | {ok, ?LIVR_TEST_PATH ++ "/positive/18-nested_object/"}; 294 | case_to_path(nested_object, negative) -> 295 | {ok, ?LIVR_TEST_PATH ++ "/negative/18-nested_object/"}; 296 | case_to_path(list_of, positive) -> 297 | {ok, ?LIVR_TEST_PATH ++ "/positive/19-list_of/"}; 298 | case_to_path(list_of, negative) -> 299 | {ok, ?LIVR_TEST_PATH ++ "/negative/19-list_of/"}; 300 | case_to_path(list_of_objects, positive) -> 301 | {ok, ?LIVR_TEST_PATH ++ "/positive/20-list_of_objects/"}; 302 | case_to_path(list_of_objects, negative) -> 303 | {ok, ?LIVR_TEST_PATH ++ "/negative/20-list_of_objects/"}; 304 | case_to_path(list_of_different_objects, positive) -> 305 | {ok, ?LIVR_TEST_PATH ++ "/positive/21-list_of_different_objects/"}; 306 | case_to_path(list_of_different_objects, negative) -> 307 | {ok, ?LIVR_TEST_PATH ++ "/negative/21-list_of_different_objects/"}; 308 | case_to_path(not_empty_list, positive) -> 309 | {ok, ?LIVR_TEST_PATH ++ "/positive/22-not_empty_list/"}; 310 | case_to_path(not_empty_list, negative) -> 311 | {ok, ?LIVR_TEST_PATH ++ "/negative/22-not_empty_list/"}; 312 | case_to_path(url, positive) -> 313 | {ok, ?LIVR_TEST_PATH ++ "/positive/23-url/"}; 314 | case_to_path(url, negative) -> 315 | {ok, ?LIVR_TEST_PATH ++ "/negative/23-url/"}; 316 | case_to_path(iso_date, positive) -> 317 | {ok, ?LIVR_TEST_PATH ++ "/positive/24-iso_date/"}; 318 | case_to_path(iso_date, negative) -> 319 | {ok, ?LIVR_TEST_PATH ++ "/negative/24-iso_date/"}; 320 | case_to_path(eq, positive) -> 321 | {ok, ?LIVR_TEST_PATH ++ "/positive/25-eq/"}; 322 | case_to_path(eq, negative) -> 323 | {ok, ?LIVR_TEST_PATH ++ "/negative/25-eq/"}; 324 | case_to_path(string, positive) -> 325 | {ok, ?LIVR_TEST_PATH ++ "/positive/26-string/"}; 326 | case_to_path(string, negative) -> 327 | {ok, ?LIVR_TEST_PATH ++ "/negative/26-string/"}; 328 | case_to_path(any_object, positive) -> 329 | {ok, ?LIVR_TEST_PATH ++ "/positive/27-any_object/"}; 330 | case_to_path(any_object, negative) -> 331 | {ok, ?LIVR_TEST_PATH ++ "/negative/27-any_object/"}; 332 | case_to_path(variable_object, positive) -> 333 | {ok, ?LIVR_TEST_PATH ++ "/positive/28-variable_object/"}; 334 | case_to_path(variable_object, negative) -> 335 | {ok, ?LIVR_TEST_PATH ++ "/negative/28-variable_object/"}; 336 | case_to_path('or', positive) -> 337 | {ok, ?LIVR_TEST_PATH ++ "/positive/29-or/"}; 338 | case_to_path('or', negative) -> 339 | {ok, ?LIVR_TEST_PATH ++ "/negative/29-or/"}; 340 | case_to_path(trim, positive) -> 341 | {ok, ?LIVR_TEST_PATH ++ "/positive/30-trim/"}; 342 | case_to_path(to_lc, positive) -> 343 | {ok, ?LIVR_TEST_PATH ++ "/positive/31-to_lc/"}; 344 | case_to_path(to_uc, positive) -> 345 | {ok, ?LIVR_TEST_PATH ++ "/positive/32-to_uc/"}; 346 | case_to_path(remove, positive) -> 347 | {ok, ?LIVR_TEST_PATH ++ "/positive/33-remove/"}; 348 | case_to_path(leave_only, positive) -> 349 | {ok, ?LIVR_TEST_PATH ++ "/positive/34-leave_only/"}; 350 | case_to_path(default, positive) -> 351 | {ok, ?LIVR_TEST_PATH ++ "/positive/35-default/"}; 352 | case_to_path(_, _) -> 353 | skip. 354 | 355 | expected_output(positive, Output) -> 356 | {ok, Output}; 357 | expected_output(negative, Output) -> 358 | {error, Output}. 359 | 360 | parse_hack(iso_date, {Rules, Input, Output}) -> 361 | Fun = fun(_K, V) -> 362 | try {Date, _Time} = iso8601:parse(V), Date 363 | catch _:_ -> V 364 | end 365 | end, 366 | Output2 = liver_maps:map(Fun, Output), 367 | {Rules, Input, Output2}; 368 | parse_hack(_, Conditions) -> 369 | Conditions. 370 | 371 | decode(Json) -> 372 | try 373 | jsx:decode(Json, [return_maps]) 374 | catch 375 | _:_ -> json_parsing_error 376 | end. 377 | -------------------------------------------------------------------------------- /tests/livr_rules_proplists_SUITE.erl: -------------------------------------------------------------------------------- 1 | -module(livr_rules_proplists_SUITE). 2 | 3 | -compile(export_all). 4 | 5 | -include_lib("common_test/include/ct.hrl"). 6 | 7 | -define(LIVR_TEST_PATH, "../../deps/LIVR/test_suite"). 8 | -define(EXAMPLE, "liver:validate(~p, ~p) =:= ~p.~n"). 9 | -define(TEST_CASES, [ 10 | 11 | %% common rules 12 | required, 13 | not_empty, 14 | not_empty_list, 15 | any_object, 16 | 17 | %% string rules 18 | string, 19 | eq, 20 | one_of, 21 | max_length, 22 | min_length, 23 | length_between, 24 | length_equal, 25 | like, 26 | 27 | %% numeric rules 28 | integer, 29 | positive_integer, 30 | decimal, 31 | positive_decimal, 32 | max_number, 33 | min_number, 34 | number_between, 35 | 36 | %% special rules 37 | email, 38 | url, 39 | iso_date, 40 | equal_to_field, 41 | 42 | %% meta rules 43 | nested_object, 44 | variable_object, 45 | list_of, 46 | list_of_objects, 47 | list_of_different_objects, 48 | 'or', 49 | 50 | %% modifiers (previously - "filter rules") 51 | trim, 52 | to_lc, 53 | to_uc, 54 | remove, 55 | leave_only, 56 | default 57 | 58 | ]). 59 | -define(RUN(Config), 60 | Type = ?config(init_type, Config), 61 | {Rules, Input, Output} = ?config(conditions, Config), 62 | Expected = expected_output(Type, Output), 63 | case liver:validate(Rules, Input) =:= Expected of 64 | true -> 65 | ok; 66 | false -> 67 | io:format(?EXAMPLE, [Rules, Input, Expected]), 68 | {fail, unsuccessful} 69 | end 70 | ). 71 | 72 | all() -> 73 | [ 74 | {group, positive}, 75 | {group, negative} 76 | ]. 77 | 78 | groups() -> 79 | [ 80 | {positive, [parallel], ?TEST_CASES}, 81 | {negative, [parallel], ?TEST_CASES} 82 | ]. 83 | 84 | init_per_group(Name, Config) -> 85 | [{init_type, Name}|Config]. 86 | 87 | end_per_group(_Name, Config) -> 88 | lists:keydelete(init_type, 1, Config). 89 | 90 | init_per_testcase(Name, Config) -> 91 | Type = ?config(init_type, Config), 92 | case read_conditions(Name, Type) of 93 | {ok, Conditions} -> 94 | Conditions2 = parse_hack(Name, Conditions), 95 | [{conditions, Conditions2}|Config]; 96 | skip -> 97 | {skipped, no_data} 98 | end. 99 | 100 | end_per_testcase(_Name, Config) -> 101 | lists:keydelete(conditions, 1, Config). 102 | 103 | required(Config) -> 104 | ?RUN(Config). 105 | 106 | not_empty(Config) -> 107 | ?RUN(Config). 108 | 109 | not_empty_list(Config) -> 110 | ?RUN(Config). 111 | 112 | any_object(Config) -> 113 | ?RUN(Config). 114 | 115 | string(Config) -> 116 | ?RUN(Config). 117 | 118 | eq(Config) -> 119 | ?RUN(Config). 120 | 121 | one_of(Config) -> 122 | ?RUN(Config). 123 | 124 | max_length(Config) -> 125 | ?RUN(Config). 126 | 127 | min_length(Config) -> 128 | ?RUN(Config). 129 | 130 | length_between(Config) -> 131 | ?RUN(Config). 132 | 133 | length_equal(Config) -> 134 | ?RUN(Config). 135 | 136 | like(Config) -> 137 | ?RUN(Config). 138 | 139 | integer(Config) -> 140 | ?RUN(Config). 141 | 142 | positive_integer(Config) -> 143 | ?RUN(Config). 144 | 145 | decimal(Config) -> 146 | ?RUN(Config). 147 | 148 | positive_decimal(Config) -> 149 | ?RUN(Config). 150 | 151 | max_number(Config) -> 152 | ?RUN(Config). 153 | 154 | min_number(Config) -> 155 | ?RUN(Config). 156 | 157 | number_between(Config) -> 158 | ?RUN(Config). 159 | 160 | email(Config) -> 161 | ?RUN(Config). 162 | 163 | url(Config) -> 164 | ?RUN(Config). 165 | 166 | iso_date(Config) -> 167 | ?RUN(Config). 168 | 169 | equal_to_field(Config) -> 170 | ?RUN(Config). 171 | 172 | nested_object(Config) -> 173 | ?RUN(Config). 174 | 175 | variable_object(Config) -> 176 | ?RUN(Config). 177 | 178 | list_of(Config) -> 179 | ?RUN(Config). 180 | 181 | list_of_objects(Config) -> 182 | ?RUN(Config). 183 | 184 | list_of_different_objects(Config) -> 185 | ?RUN(Config). 186 | 187 | 'or'(Config) -> 188 | ?RUN(Config). 189 | 190 | trim(Config) -> 191 | ?RUN(Config). 192 | 193 | to_lc(Config) -> 194 | ?RUN(Config). 195 | 196 | to_uc(Config) -> 197 | ?RUN(Config). 198 | 199 | remove(Config) -> 200 | ?RUN(Config). 201 | 202 | leave_only(Config) -> 203 | ?RUN(Config). 204 | 205 | default(Config) -> 206 | ?RUN(Config). 207 | 208 | %% internal 209 | read_conditions(TestCase, Option) -> 210 | case case_to_path(TestCase, Option) of 211 | {ok, Path} -> 212 | OutputPath = case Option of 213 | positive -> "output.json"; 214 | negative -> "errors.json" 215 | end, 216 | {ok, Rules} = file:read_file(Path ++ "rules.json"), 217 | {ok, Input} = file:read_file(Path ++ "input.json"), 218 | {ok, Output} = file:read_file(Path ++ OutputPath), 219 | {ok, {decode(Rules), decode(Input), decode(Output)}}; 220 | skip -> 221 | skip 222 | end. 223 | 224 | case_to_path(required, positive) -> 225 | {ok, ?LIVR_TEST_PATH ++ "/positive/01-required/"}; 226 | case_to_path(required, negative) -> 227 | {ok, ?LIVR_TEST_PATH ++ "/negative/01-required/"}; 228 | case_to_path(not_empty, positive) -> 229 | {ok, ?LIVR_TEST_PATH ++ "/positive/02-not_empty/"}; 230 | case_to_path(not_empty, negative) -> 231 | {ok, ?LIVR_TEST_PATH ++ "/negative/02-not_empty/"}; 232 | case_to_path(one_of, positive) -> 233 | {ok, ?LIVR_TEST_PATH ++ "/positive/03-one_of/"}; 234 | case_to_path(one_of, negative) -> 235 | {ok, ?LIVR_TEST_PATH ++ "/negative/03-one_of/"}; 236 | case_to_path(min_length, positive) -> 237 | {ok, ?LIVR_TEST_PATH ++ "/positive/04-min_length/"}; 238 | case_to_path(min_length, negative) -> 239 | {ok, ?LIVR_TEST_PATH ++ "/negative/04-min_length/"}; 240 | case_to_path(max_length, positive) -> 241 | {ok, ?LIVR_TEST_PATH ++ "/positive/05-max_length/"}; 242 | case_to_path(max_length, negative) -> 243 | {ok, ?LIVR_TEST_PATH ++ "/negative/05-max_length/"}; 244 | case_to_path(length_equal, positive) -> 245 | {ok, ?LIVR_TEST_PATH ++ "/positive/06-length_equal/"}; 246 | case_to_path(length_equal, negative) -> 247 | {ok, ?LIVR_TEST_PATH ++ "/negative/06-length_equal/"}; 248 | case_to_path(length_between, positive) -> 249 | {ok, ?LIVR_TEST_PATH ++ "/positive/07-length_between/"}; 250 | case_to_path(length_between, negative) -> 251 | {ok, ?LIVR_TEST_PATH ++ "/negative/07-length_between/"}; 252 | case_to_path(like, positive) -> 253 | {ok, ?LIVR_TEST_PATH ++ "/positive/08-like/"}; 254 | case_to_path(like, negative) -> 255 | {ok, ?LIVR_TEST_PATH ++ "/negative/08-like/"}; 256 | case_to_path(integer, positive) -> 257 | {ok, ?LIVR_TEST_PATH ++ "/positive/09-integer/"}; 258 | case_to_path(integer, negative) -> 259 | {ok, ?LIVR_TEST_PATH ++ "/negative/09-integer/"}; 260 | case_to_path(positive_integer, positive) -> 261 | {ok, ?LIVR_TEST_PATH ++ "/positive/10-positive_integer/"}; 262 | case_to_path(positive_integer, negative) -> 263 | {ok, ?LIVR_TEST_PATH ++ "/negative/10-positive_integer/"}; 264 | case_to_path(decimal, positive) -> 265 | {ok, ?LIVR_TEST_PATH ++ "/positive/11-decimal/"}; 266 | case_to_path(decimal, negative) -> 267 | {ok, ?LIVR_TEST_PATH ++ "/negative/11-decimal/"}; 268 | case_to_path(positive_decimal, positive) -> 269 | {ok, ?LIVR_TEST_PATH ++ "/positive/12-positive_decimal/"}; 270 | case_to_path(positive_decimal, negative) -> 271 | {ok, ?LIVR_TEST_PATH ++ "/negative/12-positive_decimal/"}; 272 | case_to_path(max_number, positive) -> 273 | {ok, ?LIVR_TEST_PATH ++ "/positive/13-max_number/"}; 274 | case_to_path(max_number, negative) -> 275 | {ok, ?LIVR_TEST_PATH ++ "/negative/13-max_number/"}; 276 | case_to_path(min_number, positive) -> 277 | {ok, ?LIVR_TEST_PATH ++ "/positive/14-min_number/"}; 278 | case_to_path(min_number, negative) -> 279 | {ok, ?LIVR_TEST_PATH ++ "/negative/14-min_number/"}; 280 | case_to_path(number_between, positive) -> 281 | {ok, ?LIVR_TEST_PATH ++ "/positive/15-number_between/"}; 282 | case_to_path(number_between, negative) -> 283 | {ok, ?LIVR_TEST_PATH ++ "/negative/15-number_beetween/"}; 284 | case_to_path(email, positive) -> 285 | {ok, ?LIVR_TEST_PATH ++ "/positive/16-email/"}; 286 | case_to_path(email, negative) -> 287 | {ok, ?LIVR_TEST_PATH ++ "/negative/16-email/"}; 288 | case_to_path(equal_to_field, positive) -> 289 | {ok, ?LIVR_TEST_PATH ++ "/positive/17-equal_to_field/"}; 290 | case_to_path(equal_to_field, negative) -> 291 | {ok, ?LIVR_TEST_PATH ++ "/negative/17-equal_to_field/"}; 292 | case_to_path(nested_object, positive) -> 293 | {ok, ?LIVR_TEST_PATH ++ "/positive/18-nested_object/"}; 294 | case_to_path(nested_object, negative) -> 295 | {ok, ?LIVR_TEST_PATH ++ "/negative/18-nested_object/"}; 296 | case_to_path(list_of, positive) -> 297 | {ok, ?LIVR_TEST_PATH ++ "/positive/19-list_of/"}; 298 | case_to_path(list_of, negative) -> 299 | {ok, ?LIVR_TEST_PATH ++ "/negative/19-list_of/"}; 300 | case_to_path(list_of_objects, positive) -> 301 | {ok, ?LIVR_TEST_PATH ++ "/positive/20-list_of_objects/"}; 302 | case_to_path(list_of_objects, negative) -> 303 | {ok, ?LIVR_TEST_PATH ++ "/negative/20-list_of_objects/"}; 304 | case_to_path(list_of_different_objects, positive) -> 305 | {ok, ?LIVR_TEST_PATH ++ "/positive/21-list_of_different_objects/"}; 306 | case_to_path(list_of_different_objects, negative) -> 307 | {ok, ?LIVR_TEST_PATH ++ "/negative/21-list_of_different_objects/"}; 308 | case_to_path(not_empty_list, positive) -> 309 | {ok, ?LIVR_TEST_PATH ++ "/positive/22-not_empty_list/"}; 310 | case_to_path(not_empty_list, negative) -> 311 | {ok, ?LIVR_TEST_PATH ++ "/negative/22-not_empty_list/"}; 312 | case_to_path(url, positive) -> 313 | {ok, ?LIVR_TEST_PATH ++ "/positive/23-url/"}; 314 | case_to_path(url, negative) -> 315 | {ok, ?LIVR_TEST_PATH ++ "/negative/23-url/"}; 316 | case_to_path(iso_date, positive) -> 317 | {ok, ?LIVR_TEST_PATH ++ "/positive/24-iso_date/"}; 318 | case_to_path(iso_date, negative) -> 319 | {ok, ?LIVR_TEST_PATH ++ "/negative/24-iso_date/"}; 320 | case_to_path(eq, positive) -> 321 | {ok, ?LIVR_TEST_PATH ++ "/positive/25-eq/"}; 322 | case_to_path(eq, negative) -> 323 | {ok, ?LIVR_TEST_PATH ++ "/negative/25-eq/"}; 324 | case_to_path(string, positive) -> 325 | {ok, ?LIVR_TEST_PATH ++ "/positive/26-string/"}; 326 | case_to_path(string, negative) -> 327 | {ok, ?LIVR_TEST_PATH ++ "/negative/26-string/"}; 328 | case_to_path(any_object, positive) -> 329 | {ok, ?LIVR_TEST_PATH ++ "/positive/27-any_object/"}; 330 | case_to_path(any_object, negative) -> 331 | {ok, ?LIVR_TEST_PATH ++ "/negative/27-any_object/"}; 332 | case_to_path(variable_object, positive) -> 333 | {ok, ?LIVR_TEST_PATH ++ "/positive/28-variable_object/"}; 334 | case_to_path(variable_object, negative) -> 335 | {ok, ?LIVR_TEST_PATH ++ "/negative/28-variable_object/"}; 336 | case_to_path('or', positive) -> 337 | {ok, ?LIVR_TEST_PATH ++ "/positive/29-or/"}; 338 | %case_to_path('or', negative) -> 339 | % {ok, ?LIVR_TEST_PATH ++ "/negative/29-or/"}; 340 | case_to_path(trim, positive) -> 341 | {ok, ?LIVR_TEST_PATH ++ "/positive/30-trim/"}; 342 | case_to_path(to_lc, positive) -> 343 | {ok, ?LIVR_TEST_PATH ++ "/positive/31-to_lc/"}; 344 | case_to_path(to_uc, positive) -> 345 | {ok, ?LIVR_TEST_PATH ++ "/positive/32-to_uc/"}; 346 | case_to_path(remove, positive) -> 347 | {ok, ?LIVR_TEST_PATH ++ "/positive/33-remove/"}; 348 | case_to_path(leave_only, positive) -> 349 | {ok, ?LIVR_TEST_PATH ++ "/positive/34-leave_only/"}; 350 | case_to_path(default, positive) -> 351 | {ok, ?LIVR_TEST_PATH ++ "/positive/35-default/"}; 352 | case_to_path(_, _) -> 353 | skip. 354 | 355 | expected_output(positive, Output) -> 356 | {ok, Output}; 357 | expected_output(negative, Output) -> 358 | {error, Output}. 359 | 360 | parse_hack(iso_date, {Rules, Input, Output}) -> 361 | Fun = fun(_K, V) -> 362 | try {Date, _Time} = iso8601:parse(V), Date 363 | catch _:_ -> V 364 | end 365 | end, 366 | Output2 = liver_maps:map(Fun, Output), 367 | {Rules, Input, Output2}; 368 | parse_hack(_, Conditions) -> 369 | Conditions. 370 | 371 | decode(Json) -> 372 | try 373 | jsx:decode(Json, []) 374 | catch 375 | _:_ -> json_parsing_error 376 | end. 377 | -------------------------------------------------------------------------------- /src/sets/liver_livr_rules.erl: -------------------------------------------------------------------------------- 1 | -module(liver_livr_rules). 2 | 3 | %% API 4 | %% common rules 5 | -export([required/3]). 6 | -export([not_empty/3]). 7 | -export([not_empty_list/3]). 8 | -export([any_object/3]). 9 | 10 | %% string rules 11 | -export([string/3]). 12 | -export([eq/3]). 13 | -export([one_of/3]). 14 | -export([max_length/3]). 15 | -export([min_length/3]). 16 | -export([length_between/3]). 17 | -export([length_equal/3]). 18 | -export([like/3]). 19 | 20 | %% numeric rules 21 | -export([integer/3]). 22 | -export([positive_integer/3]). 23 | -export([decimal/3]). 24 | -export([positive_decimal/3]). 25 | -export([max_number/3]). 26 | -export([min_number/3]). 27 | -export([number_between/3]). 28 | 29 | %% special rules 30 | -export([email/3]). 31 | -export([url/3]). 32 | -export([iso_date/3]). 33 | -export([equal_to_field/3]). 34 | 35 | %% meta rules 36 | -export([nested_object/3]). 37 | -export([variable_object/3]). 38 | -export([list_of/3]). 39 | -export([list_of_objects/3]). 40 | -export([list_of_different_objects/3]). 41 | -export(['or'/3]). 42 | 43 | %% modifiers (previously - "filter rules") 44 | -export([trim/3]). 45 | -export([to_lc/3]). 46 | -export([to_uc/3]). 47 | -export([remove/3]). 48 | -export([leave_only/3]). 49 | -export([default/3]). 50 | 51 | -include("liver_rules.hrl"). 52 | 53 | %% API 54 | %% common rules 55 | required(_Args, <<>>, _Opts) -> 56 | {error, required}; 57 | required(_Args, null, _Opts) -> 58 | {error, required}; 59 | required(_Args, undefined, _Opts) -> 60 | {error, required}; 61 | required(_Args, ?MISSED_FIELD_VALUE, _Opts) -> 62 | {error, required}; 63 | required(_Args, Value, _Opts) -> 64 | {ok, Value}. 65 | 66 | not_empty(_Args, Value, _Opts) -> 67 | case Value of 68 | <<>> -> {error, cannot_be_empty}; 69 | _ -> {ok, Value} 70 | end. 71 | 72 | not_empty_list(_Args, Value, _Opts) -> 73 | case Value of 74 | <<>> -> {error, cannot_be_empty}; 75 | [{}] -> {error, format_error}; 76 | [] -> {error, cannot_be_empty}; 77 | [_|_] -> {ok, Value}; 78 | ?MISSED_FIELD_VALUE -> {error, cannot_be_empty}; 79 | _ -> {error, format_error} 80 | end. 81 | 82 | any_object(_Args, Value, _Opts) -> 83 | case Value of 84 | <<>> -> 85 | {ok, Value}; 86 | #{} -> 87 | {ok, Value}; 88 | [{}] -> 89 | {ok, Value}; 90 | [_|_] -> 91 | case is_proplist(Value) of 92 | true -> 93 | {ok, Value}; 94 | false -> 95 | {error, format_error} 96 | end; 97 | _ -> 98 | {error, format_error} 99 | end. 100 | 101 | %% string rules 102 | string(_Args, Value, _Opts) when is_binary(Value) -> 103 | {ok, Value}; 104 | string(_Args, Value, Opts) when is_number(Value) -> 105 | Value2 = number_to_binary(Value), 106 | string(_Args, Value2, Opts); 107 | string(_Args, _Value, _Opts) -> 108 | {error, format_error}. 109 | 110 | eq(_Args, <<>>, _Opts) -> 111 | {ok, <<>>}; 112 | eq([Equivalent], Value, Opts) -> 113 | eq(Equivalent, Value, Opts); 114 | eq(Value, Value, _Opts) -> 115 | {ok, Value}; 116 | %eq(Equivalent, Value, _Opts) when Equivalent == Value -> 117 | % Value2 = trunc(Value), 118 | % {ok, Value2}; 119 | eq(Equivalent, Value, Opts) when is_binary(Equivalent), is_number(Value) -> 120 | Value2 = number_to_binary(Value), 121 | eq(Equivalent, Value2, Opts); 122 | eq(Equivalent, Value, Opts) when is_number(Equivalent), is_binary(Value) -> 123 | try binary_to_number(Value) of 124 | Value2 -> 125 | eq(Equivalent, Value2, Opts) 126 | catch 127 | error:badarg -> 128 | {error, not_allowed_value} 129 | end; 130 | eq(_Equivalent, Value, _Opts) when is_map(Value); is_list(Value) -> 131 | {error, format_error}; 132 | eq(_Equivalent, _Value, _Opts) -> 133 | {error, not_allowed_value}. 134 | 135 | one_of([List|_], Value, Opts) when is_list(List) -> 136 | one_of(List, Value, Opts); 137 | one_of([Equivalent|List], Value, Opts) -> 138 | case eq(Equivalent, Value, Opts) of 139 | {error, not_allowed_value} -> 140 | one_of(List, Value, Opts); 141 | {ok, Value2} -> 142 | {ok, Value2} 143 | end; 144 | one_of([], _Value, _Opts) -> 145 | {error, not_allowed_value}; 146 | one_of(Equivalent, Value, Opts) -> 147 | eq(Equivalent, Value, Opts). 148 | 149 | max_length([MaxLength|_], Value, Opts) -> 150 | max_length(MaxLength, Value, Opts); 151 | max_length(MaxLength, Value, _Opts) when is_binary(Value) -> 152 | StrValue = unicode:characters_to_list(Value), 153 | case length(StrValue) > MaxLength of 154 | false -> {ok, Value}; 155 | true -> {error, too_long} 156 | end; 157 | max_length(MaxLength, Value, Opts) when is_number(Value) -> 158 | Value2 = number_to_binary(Value), 159 | max_length(MaxLength, Value2, Opts); 160 | max_length(_MaxLength, _Value, _Opts) -> 161 | {error, format_error}. 162 | 163 | min_length(_Args, <<>>, _Opts) -> 164 | {ok, <<>>}; 165 | min_length([MinLength|_], Value, _Opts) -> 166 | min_length(MinLength, Value, _Opts); 167 | min_length(MinLength, Value, _Opts) when is_binary(Value) -> 168 | StrValue = unicode:characters_to_list(Value), 169 | case length(StrValue) < MinLength of 170 | false -> {ok, Value}; 171 | true -> {error, too_short} 172 | end; 173 | min_length(MinLength, Value, _Opts) when is_number(Value) -> 174 | Value2 = number_to_binary(Value), 175 | min_length(MinLength, Value2, _Opts); 176 | min_length(_MinLength, _Value, _Opts) -> 177 | {error, format_error}. 178 | 179 | length_between(_Args, <<>>, _Opts) -> 180 | {ok, <<>>}; 181 | length_between([[Min, Max]|_], Value, _Opts) -> 182 | length_between([Min, Max], Value, _Opts); 183 | length_between([Min, Max|_], Value, _Opts) when is_binary(Value) -> 184 | StrValue = unicode:characters_to_list(Value), 185 | Length = length(StrValue), 186 | if 187 | Length < Min -> {error, too_short}; 188 | Length > Max -> {error, too_long}; 189 | true -> {ok, Value} 190 | end; 191 | length_between([Min, Max|_], Value, Opts) when is_number(Value) -> 192 | Value2 = number_to_binary(Value), 193 | length_between([Min, Max], Value2, Opts); 194 | length_between(_Args, _Value, _Opts) -> 195 | {error, format_error}. 196 | 197 | length_equal(_Args, <<>>, _Opts) -> 198 | {ok, <<>>}; 199 | length_equal([Length|_], Value, Opts) -> 200 | length_equal(Length, Value, Opts); 201 | length_equal(Length, Value, _Opts) when is_binary(Value) -> 202 | StrValue = unicode:characters_to_list(Value), 203 | ActualLength = length(StrValue), 204 | if 205 | ActualLength < Length -> {error, too_short}; 206 | ActualLength > Length -> {error, too_long}; 207 | ActualLength == Length -> {ok, Value} 208 | end; 209 | length_equal(Length, Value, Opts) when is_number(Value) -> 210 | Value2 = number_to_binary(Value), 211 | min_length(Length, Value2, Opts); 212 | length_equal(_Args, _Value, _Opts) -> 213 | {error, format_error}. 214 | 215 | like(_Args, <<>>, _Opts) -> 216 | {ok, <<>>}; 217 | like(Args, Value, _Opts) when is_binary(Value); is_number(Value) -> 218 | Value2 = to_binary(Value), 219 | {Pattern, ReOpts} = case Args of 220 | [RegEx, <<"i">>|_] -> {RegEx, [unicode, caseless]}; 221 | [RegEx|_] -> {RegEx, [unicode]}; 222 | RegEx -> {RegEx, [unicode]} 223 | end, 224 | case re:compile(Pattern, ReOpts) of 225 | {ok, MP} -> 226 | case re:run(Value2, MP) of 227 | nomatch -> {error, wrong_format}; 228 | _ -> {ok, Value2} 229 | end; 230 | {error, _} -> 231 | {error, invalid_pattern} 232 | end; 233 | like(_Args, _Value, _Opts) -> 234 | {error, format_error}. 235 | 236 | %% numeric rules 237 | integer(_Args, <<>>, _Opts) -> 238 | {ok, <<>>}; 239 | integer(_Args, Value, _Opts) when is_integer(Value) -> 240 | {ok, Value}; 241 | integer(_Args, Value, _Opts) when is_binary(Value) -> 242 | convert(binary_to_integer, Value, not_integer); 243 | integer(_Args, Value, _Opts) when is_float(Value) -> 244 | {error, not_integer}; 245 | integer(_Args, _Value, _Opts) -> 246 | {error, format_error}. 247 | 248 | positive_integer(_Args, <<>>, _Opts) -> 249 | {ok, <<>>}; 250 | positive_integer(_Args, Value, _Opts) when is_integer(Value), Value > 0 -> 251 | {ok, Value}; 252 | positive_integer(_Args, Value, _Opts) when is_binary(Value) -> 253 | case convert(binary_to_integer, Value, not_positive_integer) of 254 | {ok, Value2} = OK when Value2 > 0 -> 255 | OK; 256 | _Err -> 257 | {error, not_positive_integer} 258 | end; 259 | positive_integer(_Args, Value, _Opts) when is_integer(Value); is_float(Value) -> 260 | {error, not_positive_integer}; 261 | positive_integer(_Args, _Value, _Opts) -> 262 | {error, format_error}. 263 | 264 | decimal(_Args, <<>>, _Opts) -> 265 | {ok, <<>>}; 266 | decimal(_Args, Value, _Opts) when is_float(Value) -> 267 | {ok, Value}; 268 | decimal(_Args, Value, _Opts) when is_binary(Value) -> 269 | try binary_to_number(Value) of 270 | Value2 -> 271 | {ok, Value2} 272 | catch 273 | _:_ -> 274 | {error, not_decimal} 275 | end; 276 | decimal(_Args, Value, _Opts) when is_integer(Value) -> 277 | {error, not_decimal}; 278 | decimal(_Args, _Value, _Opts) -> 279 | {error, format_error}. 280 | 281 | positive_decimal(_Args, <<>>, _Opts) -> 282 | {ok, <<>>}; 283 | positive_decimal(_Args, Value, _Opts) when is_float(Value), Value > 0 -> 284 | {ok, Value}; 285 | positive_decimal(_Args, Value, _Opts) when is_binary(Value) -> 286 | try binary_to_number(Value) of 287 | Value2 when Value2 > 0 -> 288 | {ok, Value2}; 289 | _Err -> 290 | {error, not_positive_decimal} 291 | catch 292 | _:_ -> 293 | {error, not_positive_decimal} 294 | end; 295 | positive_decimal(_Args, Value, _Opts) when is_float(Value); is_integer(Value) -> 296 | {error, not_positive_decimal}; 297 | positive_decimal(_Args, _Value, _Opts) -> 298 | {error, format_error}. 299 | 300 | max_number(_Args, <<>>, _Opts) -> 301 | {ok, <<>>}; 302 | max_number([Max|_], Value, Opts) -> 303 | max_number(Max, Value, Opts); 304 | max_number(Max, Value, _Opts) when is_number(Value) -> 305 | case Max >= Value of 306 | true -> 307 | {ok, Value}; 308 | false -> 309 | {error, too_high} 310 | end; 311 | max_number(Max, Value, _Opts) when is_binary(Value) -> 312 | try binary_to_number(Value) of 313 | Value2 when Max >= Value2 -> 314 | {ok, Value2}; 315 | _Value2 -> 316 | {error, too_high} 317 | catch 318 | error:badarg -> 319 | {error, not_number} 320 | end; 321 | max_number(_Args, _Value, _Opts) -> 322 | {error, format_error}. 323 | 324 | min_number(_Args, <<>>, _Opts) -> 325 | {ok, <<>>}; 326 | min_number([Min|_], Value, Opts) -> 327 | min_number(Min, Value, Opts); 328 | min_number(Min, Value, _Opts) when is_number(Value) -> 329 | case Min =< Value of 330 | true -> 331 | {ok, Value}; 332 | false -> 333 | {error, too_low} 334 | end; 335 | min_number(Min, Value, _Opts) when is_binary(Value) -> 336 | try binary_to_number(Value) of 337 | Value2 when Min =< Value2 -> 338 | {ok, Value2}; 339 | _Value2 -> 340 | {error, too_low} 341 | catch 342 | error:badarg -> 343 | {error, not_number} 344 | end; 345 | min_number(_Args, _Value, _Opts) -> 346 | {error, format_error}. 347 | 348 | number_between(_Args, <<>>, _Opts) -> 349 | {ok, <<>>}; 350 | number_between([[Min, Max]|_], Value, Opts) -> 351 | number_between([Min, Max], Value, Opts); 352 | number_between([Min, Max|_], Value, _Opts) when is_number(Value) -> 353 | case {Min =< Value, Value =< Max} of 354 | {true, true} -> {ok, Value}; 355 | {false, true} -> {error, too_low}; 356 | {true, false} -> {error, too_high} 357 | end; 358 | number_between([Min, Max|_], Value, _Opts) when is_binary(Value) -> 359 | try binary_to_number(Value) of 360 | Value2 when Min =< Value2, Value2 =< Max -> 361 | {ok, Value2}; 362 | Value2 when Min > Value2 -> 363 | {error, too_low}; 364 | Value2 when Max < Value2 -> 365 | {error, too_high} 366 | catch 367 | _:_ -> 368 | {error, not_number} 369 | end; 370 | number_between(_Args, _Value, _Opts) -> 371 | {error, format_error}. 372 | 373 | %% special rules 374 | %% TODO add support for emails like: 375 | %% 用户@例子.广告 (Chinese, Unicode) 376 | %% अजय@डाटा.भारत (Hindi, Unicode) 377 | %% квіточка@пошта.укр (Ukrainian, Unicode) 378 | %% θσερ@εχαμπλε.ψομ (Greek, Unicode) 379 | %% Dörte@Sörensen.example.com (German, Unicode) 380 | %% аджай@экзампл.рус (Russian, Unicode) 381 | email(_Args, <<>> = Value, _Opts) -> 382 | {ok, Value}; 383 | email(_Args, Value, _Opts) when is_binary(Value) -> 384 | Pattern = "^(([^<>()\\[\\]\\\\.,;:\s@\"]+(\\.[^<>()\\[\\]\\.,;:\s@\"]+)*)" 385 | "|(\".+\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\])" 386 | "|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$", 387 | case re:run(Value, Pattern, [caseless, anchored]) of 388 | nomatch -> {error, wrong_email}; 389 | _ -> {ok, Value} 390 | end; 391 | email(_Args, _Value, _Opts) -> 392 | {error, format_error}. 393 | 394 | 395 | -if(?OTP_RELEASE >= 24). 396 | 397 | url(_Args, <<>> = Value, _Opts) -> 398 | {ok, Value}; 399 | url(_Args, Value, _Opts) when is_binary(Value) -> 400 | Value2 = unicode:characters_to_list(Value), 401 | X = uri_string:parse(Value2), 402 | Host = case X of 403 | #{scheme := Scheme, host := Host0} -> 404 | Scheme1 = string:lowercase(Scheme), 405 | if 406 | Scheme1 == "http"; Scheme1 == "https" -> 407 | Host0; 408 | true -> 409 | "" 410 | end; 411 | _ -> 412 | "" 413 | end, 414 | Pattern = "^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])" 415 | "(\\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$", 416 | case re:run(Host, Pattern, [caseless, {capture, none}]) of 417 | nomatch -> {error, wrong_url}; 418 | _ -> {ok, Value} 419 | end; 420 | url(_Args, _Value, _Opts) -> 421 | {error, format_error}. 422 | 423 | -else. 424 | 425 | url(_Args, <<>> = Value, _Opts) -> 426 | {ok, Value}; 427 | url(_Args, Value, _Opts) when is_binary(Value) -> 428 | Value2 = unicode:characters_to_list(Value), 429 | Host = case http_uri:parse(Value2) of 430 | {ok, {http, _UserInfo, Host0, _Port, _Path, _Query}} -> Host0; 431 | {ok, {https, _UserInfo, Host0, _Port, _Path, _Query}} -> Host0; 432 | _ -> "" 433 | end, 434 | Pattern = "^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])" 435 | "(\\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$", 436 | case re:run(Host, Pattern, [caseless, {capture, none}]) of 437 | nomatch -> {error, wrong_url}; 438 | _ -> {ok, Value} 439 | end; 440 | url(_Args, _Value, _Opts) -> 441 | {error, format_error}. 442 | 443 | -endif. 444 | 445 | iso_date(_Args, <<>> = Value, _Opts) -> 446 | {ok, Value}; 447 | iso_date(_Args, <>, _Opts) -> 448 | Date = try 449 | Year = binary_to_integer(Y), 450 | Month = binary_to_integer(M), 451 | Day = binary_to_integer(D), 452 | {Year, Month, Day} 453 | catch 454 | _:_ -> {0, 0, 0} 455 | end, 456 | case calendar:valid_date(Date) of 457 | true -> 458 | {ok, Date}; 459 | false -> 460 | {error, wrong_date} 461 | end; 462 | iso_date(_Args, Value, _Opts) when is_binary(Value) -> 463 | {error, wrong_date}; 464 | iso_date(_Args, _Value, _Opts) -> 465 | {error, format_error}. 466 | 467 | equal_to_field(_Args, <<>> = Value, _Opts) -> 468 | {ok, Value}; 469 | equal_to_field(FieldValue, Value, _Opts) 470 | when is_binary(Value); is_integer(Value); is_float(Value) -> 471 | case Value =:= FieldValue of 472 | true -> {ok, Value}; 473 | false -> {error, fields_not_equal} 474 | end; 475 | equal_to_field(_Args, _Value, _Opts) -> 476 | {error, format_error}. 477 | 478 | %% meta rules 479 | nested_object([List|_], Value, Opts) when is_list(List); is_map(List) -> 480 | nested_object(List, Value, Opts); 481 | nested_object(_Args, <<>>, _Opts) -> 482 | {ok, <<>>}; 483 | nested_object(Args, Value, Opts) -> 484 | liver:validate_map(Args, Value, Opts). 485 | 486 | variable_object([List|_], Value, Opts) when is_list(List); is_map(List) -> 487 | variable_object(List, Value, Opts); 488 | variable_object([Field, Schemas|_], Object, Opts) -> 489 | Type = liver_maps:get(Field, Object, undefined), 490 | Schema = liver_maps:get(Type, Schemas, undefined), 491 | liver:validate_map(Schema, Object, Opts). 492 | 493 | list_of(_Args, <<>>, _Opts) -> 494 | {ok, <<>>}; 495 | list_of([Rules|_], Value, Opts) when is_list(Rules); is_map(Rules) -> 496 | list_of(Rules, Value, Opts); 497 | list_of(Rules, ListOfValues, Opts) when is_list(ListOfValues) -> 498 | liver:validate_list(Rules, ListOfValues, Opts); 499 | list_of(_Args, _Value, _Opts) -> 500 | {error, format_error}. 501 | 502 | list_of_objects(_Args, <<>>, _Opts) -> 503 | {ok, <<>>}; 504 | list_of_objects([List|_], Value, Opts) when is_list(List); is_map(List) -> 505 | list_of_objects(List, Value, Opts); 506 | list_of_objects(Schema, Objects, Opts) when is_list(Objects) -> 507 | Results = [liver:validate_map(Schema, Object, Opts) || Object <- Objects], 508 | case lists:keymember(error, 1, Results) of 509 | false -> 510 | ListOfValues2 = [Val || {ok, Val} <- Results], 511 | {ok, ListOfValues2}; 512 | true -> 513 | ListOfErrors = [begin 514 | case Result of 515 | {ok, _} -> null; 516 | {error, Err} -> Err 517 | end 518 | end || Result <- Results], 519 | {error, ListOfErrors} 520 | end; 521 | list_of_objects(_Args, _Value, _Opts) -> 522 | {error, format_error}. 523 | 524 | list_of_different_objects(_Args, <<>>, _Opts) -> 525 | {ok, <<>>}; 526 | list_of_different_objects([List|_], Value, Opts) when is_list(List) -> 527 | list_of_different_objects(List, Value, Opts); 528 | list_of_different_objects(Args, Objects, Opts) when is_list(Objects) -> 529 | Results = [variable_object(Args, Object, Opts) || Object <- Objects], 530 | case lists:keymember(error, 1, Results) of 531 | false -> 532 | ListOfValues2 = [Val || {ok, Val} <- Results], 533 | {ok, ListOfValues2}; 534 | true -> 535 | ListOfErrors = [begin 536 | case Result of 537 | {ok, _} -> null; 538 | {error, Err} -> Err 539 | end 540 | end || Result <- Results], 541 | {error, ListOfErrors} 542 | end; 543 | list_of_different_objects(_Args, _Value, _Opts) -> 544 | {error, format_error}. 545 | 546 | 'or'([Rule|Rules], Value, Opts) -> 547 | case liver:validate_term(Rule, Value, Opts) of 548 | {ok, _} = Ok -> 549 | Ok; 550 | {error, _} = Err -> 551 | case Rules of 552 | [] -> Err; 553 | _ -> 'or'(Rules, Value, Opts) 554 | end 555 | end; 556 | 'or'([], Value, _Opts) -> 557 | {ok, Value}. 558 | 559 | %% modifiers (previously - "filter rules") 560 | trim(_Args, Value, _Opts) when is_binary(Value) -> 561 | Value2 = liver_bstring:trim(Value), 562 | {ok, Value2}; 563 | trim(Args, Value, Opts) when is_number(Value) -> 564 | Value2 = number_to_binary(Value), 565 | trim(Args, Value2, Opts); 566 | trim(_Args, Value, _Opts) -> 567 | {ok, Value}. 568 | 569 | to_lc(_Args, Value, _Opts) when is_binary(Value) -> 570 | Value2 = liver_bstring:to_lower(Value), 571 | {ok, Value2}; 572 | to_lc(_Args, Value, _Opts) when is_number(Value) -> 573 | Value2 = number_to_binary(Value), 574 | {ok, Value2}; 575 | to_lc(_Args, Value, _Opts) -> 576 | {ok, Value}. 577 | 578 | to_uc(_Args, Value, _Opts) when is_binary(Value) -> 579 | Value2 = liver_bstring:to_upper(Value), 580 | {ok, Value2}; 581 | to_uc(_Args, Value, _Opts) when is_number(Value) -> 582 | Value2 = number_to_binary(Value), 583 | {ok, Value2}; 584 | to_uc(_Args, Value, _Opts) -> 585 | {ok, Value}. 586 | 587 | remove([Pattern|_], Value, _Opts) -> 588 | remove(Pattern, Value, _Opts); 589 | remove(Pattern, Value, _Opts) when is_binary(Pattern), is_binary(Value) -> 590 | Value2 = liver_bstring:remove_chars(Value, Pattern), 591 | {ok, Value2}; 592 | remove(_Args, Value, _Opts) -> 593 | {ok, Value}. 594 | 595 | leave_only([Pattern|_], Value, Opts) -> 596 | leave_only(Pattern, Value, Opts); 597 | leave_only(Pattern, Value, _Opts) when is_binary(Pattern), is_binary(Value) -> 598 | Value2 = liver_bstring:leave_chars(Value, Pattern), 599 | {ok, Value2}; 600 | leave_only(_Args, Value, _Opts) -> 601 | {ok, Value}. 602 | 603 | default([{}], _Value, _Opts) -> 604 | {ok, [{}]}; 605 | default([Default], _Value, Opts) -> 606 | default(Default, _Value, Opts); 607 | default(Default, <<>>, _Opts) -> 608 | {ok, Default}; 609 | default(Default, undefined, _Opts) -> 610 | {ok, Default}; 611 | default(Default, null, _Opts) -> 612 | {ok, Default}; 613 | default(Default, ?MISSED_FIELD_VALUE, _Opts) -> 614 | {ok, Default}; 615 | default(_Default, Value, _Opts) -> 616 | {ok, Value}. 617 | 618 | %% internal 619 | is_proplist([{_, _}|T]) -> 620 | is_proplist(T); 621 | is_proplist([_|_]) -> 622 | false; 623 | is_proplist([]) -> 624 | true. 625 | 626 | to_binary(Value) when is_number(Value) -> 627 | number_to_binary(Value); 628 | to_binary(Value) when is_binary(Value) -> 629 | Value. 630 | 631 | number_to_binary(Value) when is_integer(Value) -> 632 | integer_to_binary(Value); 633 | number_to_binary(Value) when is_float(Value) -> 634 | liver_float:to_binary(Value). 635 | 636 | binary_to_number(Value) -> 637 | case binary:match(Value, <<",">>) of 638 | nomatch -> 639 | try erlang:binary_to_integer(Value) 640 | catch 641 | error:badarg -> erlang:binary_to_float(Value) 642 | end 643 | end. 644 | 645 | convert(FromTo, Value, Err) -> 646 | try erlang:FromTo(Value) of 647 | Value2 -> {ok, Value2} 648 | catch 649 | error:badarg -> {error, Err} 650 | end. 651 | -------------------------------------------------------------------------------- /include/unicode.hrl: -------------------------------------------------------------------------------- 1 | %% Data was exported from https://unicode.org/Public/UNIDATA/UnicodeData.txt 2 | %% DataFile version of 07-Mar-2017 19:35 3 | %% Exported 08-Dec-2017 4 | -define(TO_LOWER, #{ 5 | 65 => 97, 6 | 66 => 98, 7 | 67 => 99, 8 | 68 => 100, 9 | 69 => 101, 10 | 70 => 102, 11 | 71 => 103, 12 | 72 => 104, 13 | 73 => 105, 14 | 74 => 106, 15 | 75 => 107, 16 | 76 => 108, 17 | 77 => 109, 18 | 78 => 110, 19 | 79 => 111, 20 | 80 => 112, 21 | 81 => 113, 22 | 82 => 114, 23 | 83 => 115, 24 | 84 => 116, 25 | 85 => 117, 26 | 86 => 118, 27 | 87 => 119, 28 | 88 => 120, 29 | 89 => 121, 30 | 90 => 122, 31 | 192 => 224, 32 | 193 => 225, 33 | 194 => 226, 34 | 195 => 227, 35 | 196 => 228, 36 | 197 => 229, 37 | 198 => 230, 38 | 199 => 231, 39 | 200 => 232, 40 | 201 => 233, 41 | 202 => 234, 42 | 203 => 235, 43 | 204 => 236, 44 | 205 => 237, 45 | 206 => 238, 46 | 207 => 239, 47 | 208 => 240, 48 | 209 => 241, 49 | 210 => 242, 50 | 211 => 243, 51 | 212 => 244, 52 | 213 => 245, 53 | 214 => 246, 54 | 216 => 248, 55 | 217 => 249, 56 | 218 => 250, 57 | 219 => 251, 58 | 220 => 252, 59 | 221 => 253, 60 | 222 => 254, 61 | 256 => 257, 62 | 258 => 259, 63 | 260 => 261, 64 | 262 => 263, 65 | 264 => 265, 66 | 266 => 267, 67 | 268 => 269, 68 | 270 => 271, 69 | 272 => 273, 70 | 274 => 275, 71 | 276 => 277, 72 | 278 => 279, 73 | 280 => 281, 74 | 282 => 283, 75 | 284 => 285, 76 | 286 => 287, 77 | 288 => 289, 78 | 290 => 291, 79 | 292 => 293, 80 | 294 => 295, 81 | 296 => 297, 82 | 298 => 299, 83 | 300 => 301, 84 | 302 => 303, 85 | 304 => 105, 86 | 306 => 307, 87 | 308 => 309, 88 | 310 => 311, 89 | 313 => 314, 90 | 315 => 316, 91 | 317 => 318, 92 | 319 => 320, 93 | 321 => 322, 94 | 323 => 324, 95 | 325 => 326, 96 | 327 => 328, 97 | 330 => 331, 98 | 332 => 333, 99 | 334 => 335, 100 | 336 => 337, 101 | 338 => 339, 102 | 340 => 341, 103 | 342 => 343, 104 | 344 => 345, 105 | 346 => 347, 106 | 348 => 349, 107 | 350 => 351, 108 | 352 => 353, 109 | 354 => 355, 110 | 356 => 357, 111 | 358 => 359, 112 | 360 => 361, 113 | 362 => 363, 114 | 364 => 365, 115 | 366 => 367, 116 | 368 => 369, 117 | 370 => 371, 118 | 372 => 373, 119 | 374 => 375, 120 | 376 => 255, 121 | 377 => 378, 122 | 379 => 380, 123 | 381 => 382, 124 | 385 => 595, 125 | 386 => 387, 126 | 388 => 389, 127 | 390 => 596, 128 | 391 => 392, 129 | 393 => 598, 130 | 394 => 599, 131 | 395 => 396, 132 | 398 => 477, 133 | 399 => 601, 134 | 400 => 603, 135 | 401 => 402, 136 | 403 => 608, 137 | 404 => 611, 138 | 406 => 617, 139 | 407 => 616, 140 | 408 => 409, 141 | 412 => 623, 142 | 413 => 626, 143 | 415 => 629, 144 | 416 => 417, 145 | 418 => 419, 146 | 420 => 421, 147 | 422 => 640, 148 | 423 => 424, 149 | 425 => 643, 150 | 428 => 429, 151 | 430 => 648, 152 | 431 => 432, 153 | 433 => 650, 154 | 434 => 651, 155 | 435 => 436, 156 | 437 => 438, 157 | 439 => 658, 158 | 440 => 441, 159 | 444 => 445, 160 | 452 => 454, 161 | 453 => 454, 162 | 455 => 457, 163 | 456 => 457, 164 | 458 => 460, 165 | 459 => 460, 166 | 461 => 462, 167 | 463 => 464, 168 | 465 => 466, 169 | 467 => 468, 170 | 469 => 470, 171 | 471 => 472, 172 | 473 => 474, 173 | 475 => 476, 174 | 478 => 479, 175 | 480 => 481, 176 | 482 => 483, 177 | 484 => 485, 178 | 486 => 487, 179 | 488 => 489, 180 | 490 => 491, 181 | 492 => 493, 182 | 494 => 495, 183 | 497 => 499, 184 | 498 => 499, 185 | 500 => 501, 186 | 502 => 405, 187 | 503 => 447, 188 | 504 => 505, 189 | 506 => 507, 190 | 508 => 509, 191 | 510 => 511, 192 | 512 => 513, 193 | 514 => 515, 194 | 516 => 517, 195 | 518 => 519, 196 | 520 => 521, 197 | 522 => 523, 198 | 524 => 525, 199 | 526 => 527, 200 | 528 => 529, 201 | 530 => 531, 202 | 532 => 533, 203 | 534 => 535, 204 | 536 => 537, 205 | 538 => 539, 206 | 540 => 541, 207 | 542 => 543, 208 | 544 => 414, 209 | 546 => 547, 210 | 548 => 549, 211 | 550 => 551, 212 | 552 => 553, 213 | 554 => 555, 214 | 556 => 557, 215 | 558 => 559, 216 | 560 => 561, 217 | 562 => 563, 218 | 570 => 11365, 219 | 571 => 572, 220 | 573 => 410, 221 | 574 => 11366, 222 | 577 => 578, 223 | 579 => 384, 224 | 580 => 649, 225 | 581 => 652, 226 | 582 => 583, 227 | 584 => 585, 228 | 586 => 587, 229 | 588 => 589, 230 | 590 => 591, 231 | 880 => 881, 232 | 882 => 883, 233 | 886 => 887, 234 | 895 => 1011, 235 | 902 => 940, 236 | 904 => 941, 237 | 905 => 942, 238 | 906 => 943, 239 | 908 => 972, 240 | 910 => 973, 241 | 911 => 974, 242 | 913 => 945, 243 | 914 => 946, 244 | 915 => 947, 245 | 916 => 948, 246 | 917 => 949, 247 | 918 => 950, 248 | 919 => 951, 249 | 920 => 952, 250 | 921 => 953, 251 | 922 => 954, 252 | 923 => 955, 253 | 924 => 956, 254 | 925 => 957, 255 | 926 => 958, 256 | 927 => 959, 257 | 928 => 960, 258 | 929 => 961, 259 | 931 => 963, 260 | 932 => 964, 261 | 933 => 965, 262 | 934 => 966, 263 | 935 => 967, 264 | 936 => 968, 265 | 937 => 969, 266 | 938 => 970, 267 | 939 => 971, 268 | 975 => 983, 269 | 984 => 985, 270 | 986 => 987, 271 | 988 => 989, 272 | 990 => 991, 273 | 992 => 993, 274 | 994 => 995, 275 | 996 => 997, 276 | 998 => 999, 277 | 1000 => 1001, 278 | 1002 => 1003, 279 | 1004 => 1005, 280 | 1006 => 1007, 281 | 1012 => 952, 282 | 1015 => 1016, 283 | 1017 => 1010, 284 | 1018 => 1019, 285 | 1021 => 891, 286 | 1022 => 892, 287 | 1023 => 893, 288 | 1024 => 1104, 289 | 1025 => 1105, 290 | 1026 => 1106, 291 | 1027 => 1107, 292 | 1028 => 1108, 293 | 1029 => 1109, 294 | 1030 => 1110, 295 | 1031 => 1111, 296 | 1032 => 1112, 297 | 1033 => 1113, 298 | 1034 => 1114, 299 | 1035 => 1115, 300 | 1036 => 1116, 301 | 1037 => 1117, 302 | 1038 => 1118, 303 | 1039 => 1119, 304 | 1040 => 1072, 305 | 1041 => 1073, 306 | 1042 => 1074, 307 | 1043 => 1075, 308 | 1044 => 1076, 309 | 1045 => 1077, 310 | 1046 => 1078, 311 | 1047 => 1079, 312 | 1048 => 1080, 313 | 1049 => 1081, 314 | 1050 => 1082, 315 | 1051 => 1083, 316 | 1052 => 1084, 317 | 1053 => 1085, 318 | 1054 => 1086, 319 | 1055 => 1087, 320 | 1056 => 1088, 321 | 1057 => 1089, 322 | 1058 => 1090, 323 | 1059 => 1091, 324 | 1060 => 1092, 325 | 1061 => 1093, 326 | 1062 => 1094, 327 | 1063 => 1095, 328 | 1064 => 1096, 329 | 1065 => 1097, 330 | 1066 => 1098, 331 | 1067 => 1099, 332 | 1068 => 1100, 333 | 1069 => 1101, 334 | 1070 => 1102, 335 | 1071 => 1103, 336 | 1120 => 1121, 337 | 1122 => 1123, 338 | 1124 => 1125, 339 | 1126 => 1127, 340 | 1128 => 1129, 341 | 1130 => 1131, 342 | 1132 => 1133, 343 | 1134 => 1135, 344 | 1136 => 1137, 345 | 1138 => 1139, 346 | 1140 => 1141, 347 | 1142 => 1143, 348 | 1144 => 1145, 349 | 1146 => 1147, 350 | 1148 => 1149, 351 | 1150 => 1151, 352 | 1152 => 1153, 353 | 1162 => 1163, 354 | 1164 => 1165, 355 | 1166 => 1167, 356 | 1168 => 1169, 357 | 1170 => 1171, 358 | 1172 => 1173, 359 | 1174 => 1175, 360 | 1176 => 1177, 361 | 1178 => 1179, 362 | 1180 => 1181, 363 | 1182 => 1183, 364 | 1184 => 1185, 365 | 1186 => 1187, 366 | 1188 => 1189, 367 | 1190 => 1191, 368 | 1192 => 1193, 369 | 1194 => 1195, 370 | 1196 => 1197, 371 | 1198 => 1199, 372 | 1200 => 1201, 373 | 1202 => 1203, 374 | 1204 => 1205, 375 | 1206 => 1207, 376 | 1208 => 1209, 377 | 1210 => 1211, 378 | 1212 => 1213, 379 | 1214 => 1215, 380 | 1216 => 1231, 381 | 1217 => 1218, 382 | 1219 => 1220, 383 | 1221 => 1222, 384 | 1223 => 1224, 385 | 1225 => 1226, 386 | 1227 => 1228, 387 | 1229 => 1230, 388 | 1232 => 1233, 389 | 1234 => 1235, 390 | 1236 => 1237, 391 | 1238 => 1239, 392 | 1240 => 1241, 393 | 1242 => 1243, 394 | 1244 => 1245, 395 | 1246 => 1247, 396 | 1248 => 1249, 397 | 1250 => 1251, 398 | 1252 => 1253, 399 | 1254 => 1255, 400 | 1256 => 1257, 401 | 1258 => 1259, 402 | 1260 => 1261, 403 | 1262 => 1263, 404 | 1264 => 1265, 405 | 1266 => 1267, 406 | 1268 => 1269, 407 | 1270 => 1271, 408 | 1272 => 1273, 409 | 1274 => 1275, 410 | 1276 => 1277, 411 | 1278 => 1279, 412 | 1280 => 1281, 413 | 1282 => 1283, 414 | 1284 => 1285, 415 | 1286 => 1287, 416 | 1288 => 1289, 417 | 1290 => 1291, 418 | 1292 => 1293, 419 | 1294 => 1295, 420 | 1296 => 1297, 421 | 1298 => 1299, 422 | 1300 => 1301, 423 | 1302 => 1303, 424 | 1304 => 1305, 425 | 1306 => 1307, 426 | 1308 => 1309, 427 | 1310 => 1311, 428 | 1312 => 1313, 429 | 1314 => 1315, 430 | 1316 => 1317, 431 | 1318 => 1319, 432 | 1320 => 1321, 433 | 1322 => 1323, 434 | 1324 => 1325, 435 | 1326 => 1327, 436 | 1329 => 1377, 437 | 1330 => 1378, 438 | 1331 => 1379, 439 | 1332 => 1380, 440 | 1333 => 1381, 441 | 1334 => 1382, 442 | 1335 => 1383, 443 | 1336 => 1384, 444 | 1337 => 1385, 445 | 1338 => 1386, 446 | 1339 => 1387, 447 | 1340 => 1388, 448 | 1341 => 1389, 449 | 1342 => 1390, 450 | 1343 => 1391, 451 | 1344 => 1392, 452 | 1345 => 1393, 453 | 1346 => 1394, 454 | 1347 => 1395, 455 | 1348 => 1396, 456 | 1349 => 1397, 457 | 1350 => 1398, 458 | 1351 => 1399, 459 | 1352 => 1400, 460 | 1353 => 1401, 461 | 1354 => 1402, 462 | 1355 => 1403, 463 | 1356 => 1404, 464 | 1357 => 1405, 465 | 1358 => 1406, 466 | 1359 => 1407, 467 | 1360 => 1408, 468 | 1361 => 1409, 469 | 1362 => 1410, 470 | 1363 => 1411, 471 | 1364 => 1412, 472 | 1365 => 1413, 473 | 1366 => 1414, 474 | 4256 => 11520, 475 | 4257 => 11521, 476 | 4258 => 11522, 477 | 4259 => 11523, 478 | 4260 => 11524, 479 | 4261 => 11525, 480 | 4262 => 11526, 481 | 4263 => 11527, 482 | 4264 => 11528, 483 | 4265 => 11529, 484 | 4266 => 11530, 485 | 4267 => 11531, 486 | 4268 => 11532, 487 | 4269 => 11533, 488 | 4270 => 11534, 489 | 4271 => 11535, 490 | 4272 => 11536, 491 | 4273 => 11537, 492 | 4274 => 11538, 493 | 4275 => 11539, 494 | 4276 => 11540, 495 | 4277 => 11541, 496 | 4278 => 11542, 497 | 4279 => 11543, 498 | 4280 => 11544, 499 | 4281 => 11545, 500 | 4282 => 11546, 501 | 4283 => 11547, 502 | 4284 => 11548, 503 | 4285 => 11549, 504 | 4286 => 11550, 505 | 4287 => 11551, 506 | 4288 => 11552, 507 | 4289 => 11553, 508 | 4290 => 11554, 509 | 4291 => 11555, 510 | 4292 => 11556, 511 | 4293 => 11557, 512 | 4295 => 11559, 513 | 4301 => 11565, 514 | 5024 => 43888, 515 | 5025 => 43889, 516 | 5026 => 43890, 517 | 5027 => 43891, 518 | 5028 => 43892, 519 | 5029 => 43893, 520 | 5030 => 43894, 521 | 5031 => 43895, 522 | 5032 => 43896, 523 | 5033 => 43897, 524 | 5034 => 43898, 525 | 5035 => 43899, 526 | 5036 => 43900, 527 | 5037 => 43901, 528 | 5038 => 43902, 529 | 5039 => 43903, 530 | 5040 => 43904, 531 | 5041 => 43905, 532 | 5042 => 43906, 533 | 5043 => 43907, 534 | 5044 => 43908, 535 | 5045 => 43909, 536 | 5046 => 43910, 537 | 5047 => 43911, 538 | 5048 => 43912, 539 | 5049 => 43913, 540 | 5050 => 43914, 541 | 5051 => 43915, 542 | 5052 => 43916, 543 | 5053 => 43917, 544 | 5054 => 43918, 545 | 5055 => 43919, 546 | 5056 => 43920, 547 | 5057 => 43921, 548 | 5058 => 43922, 549 | 5059 => 43923, 550 | 5060 => 43924, 551 | 5061 => 43925, 552 | 5062 => 43926, 553 | 5063 => 43927, 554 | 5064 => 43928, 555 | 5065 => 43929, 556 | 5066 => 43930, 557 | 5067 => 43931, 558 | 5068 => 43932, 559 | 5069 => 43933, 560 | 5070 => 43934, 561 | 5071 => 43935, 562 | 5072 => 43936, 563 | 5073 => 43937, 564 | 5074 => 43938, 565 | 5075 => 43939, 566 | 5076 => 43940, 567 | 5077 => 43941, 568 | 5078 => 43942, 569 | 5079 => 43943, 570 | 5080 => 43944, 571 | 5081 => 43945, 572 | 5082 => 43946, 573 | 5083 => 43947, 574 | 5084 => 43948, 575 | 5085 => 43949, 576 | 5086 => 43950, 577 | 5087 => 43951, 578 | 5088 => 43952, 579 | 5089 => 43953, 580 | 5090 => 43954, 581 | 5091 => 43955, 582 | 5092 => 43956, 583 | 5093 => 43957, 584 | 5094 => 43958, 585 | 5095 => 43959, 586 | 5096 => 43960, 587 | 5097 => 43961, 588 | 5098 => 43962, 589 | 5099 => 43963, 590 | 5100 => 43964, 591 | 5101 => 43965, 592 | 5102 => 43966, 593 | 5103 => 43967, 594 | 5104 => 5112, 595 | 5105 => 5113, 596 | 5106 => 5114, 597 | 5107 => 5115, 598 | 5108 => 5116, 599 | 5109 => 5117, 600 | 7680 => 7681, 601 | 7682 => 7683, 602 | 7684 => 7685, 603 | 7686 => 7687, 604 | 7688 => 7689, 605 | 7690 => 7691, 606 | 7692 => 7693, 607 | 7694 => 7695, 608 | 7696 => 7697, 609 | 7698 => 7699, 610 | 7700 => 7701, 611 | 7702 => 7703, 612 | 7704 => 7705, 613 | 7706 => 7707, 614 | 7708 => 7709, 615 | 7710 => 7711, 616 | 7712 => 7713, 617 | 7714 => 7715, 618 | 7716 => 7717, 619 | 7718 => 7719, 620 | 7720 => 7721, 621 | 7722 => 7723, 622 | 7724 => 7725, 623 | 7726 => 7727, 624 | 7728 => 7729, 625 | 7730 => 7731, 626 | 7732 => 7733, 627 | 7734 => 7735, 628 | 7736 => 7737, 629 | 7738 => 7739, 630 | 7740 => 7741, 631 | 7742 => 7743, 632 | 7744 => 7745, 633 | 7746 => 7747, 634 | 7748 => 7749, 635 | 7750 => 7751, 636 | 7752 => 7753, 637 | 7754 => 7755, 638 | 7756 => 7757, 639 | 7758 => 7759, 640 | 7760 => 7761, 641 | 7762 => 7763, 642 | 7764 => 7765, 643 | 7766 => 7767, 644 | 7768 => 7769, 645 | 7770 => 7771, 646 | 7772 => 7773, 647 | 7774 => 7775, 648 | 7776 => 7777, 649 | 7778 => 7779, 650 | 7780 => 7781, 651 | 7782 => 7783, 652 | 7784 => 7785, 653 | 7786 => 7787, 654 | 7788 => 7789, 655 | 7790 => 7791, 656 | 7792 => 7793, 657 | 7794 => 7795, 658 | 7796 => 7797, 659 | 7798 => 7799, 660 | 7800 => 7801, 661 | 7802 => 7803, 662 | 7804 => 7805, 663 | 7806 => 7807, 664 | 7808 => 7809, 665 | 7810 => 7811, 666 | 7812 => 7813, 667 | 7814 => 7815, 668 | 7816 => 7817, 669 | 7818 => 7819, 670 | 7820 => 7821, 671 | 7822 => 7823, 672 | 7824 => 7825, 673 | 7826 => 7827, 674 | 7828 => 7829, 675 | 7838 => 223, 676 | 7840 => 7841, 677 | 7842 => 7843, 678 | 7844 => 7845, 679 | 7846 => 7847, 680 | 7848 => 7849, 681 | 7850 => 7851, 682 | 7852 => 7853, 683 | 7854 => 7855, 684 | 7856 => 7857, 685 | 7858 => 7859, 686 | 7860 => 7861, 687 | 7862 => 7863, 688 | 7864 => 7865, 689 | 7866 => 7867, 690 | 7868 => 7869, 691 | 7870 => 7871, 692 | 7872 => 7873, 693 | 7874 => 7875, 694 | 7876 => 7877, 695 | 7878 => 7879, 696 | 7880 => 7881, 697 | 7882 => 7883, 698 | 7884 => 7885, 699 | 7886 => 7887, 700 | 7888 => 7889, 701 | 7890 => 7891, 702 | 7892 => 7893, 703 | 7894 => 7895, 704 | 7896 => 7897, 705 | 7898 => 7899, 706 | 7900 => 7901, 707 | 7902 => 7903, 708 | 7904 => 7905, 709 | 7906 => 7907, 710 | 7908 => 7909, 711 | 7910 => 7911, 712 | 7912 => 7913, 713 | 7914 => 7915, 714 | 7916 => 7917, 715 | 7918 => 7919, 716 | 7920 => 7921, 717 | 7922 => 7923, 718 | 7924 => 7925, 719 | 7926 => 7927, 720 | 7928 => 7929, 721 | 7930 => 7931, 722 | 7932 => 7933, 723 | 7934 => 7935, 724 | 7944 => 7936, 725 | 7945 => 7937, 726 | 7946 => 7938, 727 | 7947 => 7939, 728 | 7948 => 7940, 729 | 7949 => 7941, 730 | 7950 => 7942, 731 | 7951 => 7943, 732 | 7960 => 7952, 733 | 7961 => 7953, 734 | 7962 => 7954, 735 | 7963 => 7955, 736 | 7964 => 7956, 737 | 7965 => 7957, 738 | 7976 => 7968, 739 | 7977 => 7969, 740 | 7978 => 7970, 741 | 7979 => 7971, 742 | 7980 => 7972, 743 | 7981 => 7973, 744 | 7982 => 7974, 745 | 7983 => 7975, 746 | 7992 => 7984, 747 | 7993 => 7985, 748 | 7994 => 7986, 749 | 7995 => 7987, 750 | 7996 => 7988, 751 | 7997 => 7989, 752 | 7998 => 7990, 753 | 7999 => 7991, 754 | 8008 => 8000, 755 | 8009 => 8001, 756 | 8010 => 8002, 757 | 8011 => 8003, 758 | 8012 => 8004, 759 | 8013 => 8005, 760 | 8025 => 8017, 761 | 8027 => 8019, 762 | 8029 => 8021, 763 | 8031 => 8023, 764 | 8040 => 8032, 765 | 8041 => 8033, 766 | 8042 => 8034, 767 | 8043 => 8035, 768 | 8044 => 8036, 769 | 8045 => 8037, 770 | 8046 => 8038, 771 | 8047 => 8039, 772 | 8072 => 8064, 773 | 8073 => 8065, 774 | 8074 => 8066, 775 | 8075 => 8067, 776 | 8076 => 8068, 777 | 8077 => 8069, 778 | 8078 => 8070, 779 | 8079 => 8071, 780 | 8088 => 8080, 781 | 8089 => 8081, 782 | 8090 => 8082, 783 | 8091 => 8083, 784 | 8092 => 8084, 785 | 8093 => 8085, 786 | 8094 => 8086, 787 | 8095 => 8087, 788 | 8104 => 8096, 789 | 8105 => 8097, 790 | 8106 => 8098, 791 | 8107 => 8099, 792 | 8108 => 8100, 793 | 8109 => 8101, 794 | 8110 => 8102, 795 | 8111 => 8103, 796 | 8120 => 8112, 797 | 8121 => 8113, 798 | 8122 => 8048, 799 | 8123 => 8049, 800 | 8124 => 8115, 801 | 8136 => 8050, 802 | 8137 => 8051, 803 | 8138 => 8052, 804 | 8139 => 8053, 805 | 8140 => 8131, 806 | 8152 => 8144, 807 | 8153 => 8145, 808 | 8154 => 8054, 809 | 8155 => 8055, 810 | 8168 => 8160, 811 | 8169 => 8161, 812 | 8170 => 8058, 813 | 8171 => 8059, 814 | 8172 => 8165, 815 | 8184 => 8056, 816 | 8185 => 8057, 817 | 8186 => 8060, 818 | 8187 => 8061, 819 | 8188 => 8179, 820 | 8486 => 969, 821 | 8490 => 107, 822 | 8491 => 229, 823 | 8498 => 8526, 824 | 8544 => 8560, 825 | 8545 => 8561, 826 | 8546 => 8562, 827 | 8547 => 8563, 828 | 8548 => 8564, 829 | 8549 => 8565, 830 | 8550 => 8566, 831 | 8551 => 8567, 832 | 8552 => 8568, 833 | 8553 => 8569, 834 | 8554 => 8570, 835 | 8555 => 8571, 836 | 8556 => 8572, 837 | 8557 => 8573, 838 | 8558 => 8574, 839 | 8559 => 8575, 840 | 8579 => 8580, 841 | 9398 => 9424, 842 | 9399 => 9425, 843 | 9400 => 9426, 844 | 9401 => 9427, 845 | 9402 => 9428, 846 | 9403 => 9429, 847 | 9404 => 9430, 848 | 9405 => 9431, 849 | 9406 => 9432, 850 | 9407 => 9433, 851 | 9408 => 9434, 852 | 9409 => 9435, 853 | 9410 => 9436, 854 | 9411 => 9437, 855 | 9412 => 9438, 856 | 9413 => 9439, 857 | 9414 => 9440, 858 | 9415 => 9441, 859 | 9416 => 9442, 860 | 9417 => 9443, 861 | 9418 => 9444, 862 | 9419 => 9445, 863 | 9420 => 9446, 864 | 9421 => 9447, 865 | 9422 => 9448, 866 | 9423 => 9449, 867 | 11264 => 11312, 868 | 11265 => 11313, 869 | 11266 => 11314, 870 | 11267 => 11315, 871 | 11268 => 11316, 872 | 11269 => 11317, 873 | 11270 => 11318, 874 | 11271 => 11319, 875 | 11272 => 11320, 876 | 11273 => 11321, 877 | 11274 => 11322, 878 | 11275 => 11323, 879 | 11276 => 11324, 880 | 11277 => 11325, 881 | 11278 => 11326, 882 | 11279 => 11327, 883 | 11280 => 11328, 884 | 11281 => 11329, 885 | 11282 => 11330, 886 | 11283 => 11331, 887 | 11284 => 11332, 888 | 11285 => 11333, 889 | 11286 => 11334, 890 | 11287 => 11335, 891 | 11288 => 11336, 892 | 11289 => 11337, 893 | 11290 => 11338, 894 | 11291 => 11339, 895 | 11292 => 11340, 896 | 11293 => 11341, 897 | 11294 => 11342, 898 | 11295 => 11343, 899 | 11296 => 11344, 900 | 11297 => 11345, 901 | 11298 => 11346, 902 | 11299 => 11347, 903 | 11300 => 11348, 904 | 11301 => 11349, 905 | 11302 => 11350, 906 | 11303 => 11351, 907 | 11304 => 11352, 908 | 11305 => 11353, 909 | 11306 => 11354, 910 | 11307 => 11355, 911 | 11308 => 11356, 912 | 11309 => 11357, 913 | 11310 => 11358, 914 | 11360 => 11361, 915 | 11362 => 619, 916 | 11363 => 7549, 917 | 11364 => 637, 918 | 11367 => 11368, 919 | 11369 => 11370, 920 | 11371 => 11372, 921 | 11373 => 593, 922 | 11374 => 625, 923 | 11375 => 592, 924 | 11376 => 594, 925 | 11378 => 11379, 926 | 11381 => 11382, 927 | 11390 => 575, 928 | 11391 => 576, 929 | 11392 => 11393, 930 | 11394 => 11395, 931 | 11396 => 11397, 932 | 11398 => 11399, 933 | 11400 => 11401, 934 | 11402 => 11403, 935 | 11404 => 11405, 936 | 11406 => 11407, 937 | 11408 => 11409, 938 | 11410 => 11411, 939 | 11412 => 11413, 940 | 11414 => 11415, 941 | 11416 => 11417, 942 | 11418 => 11419, 943 | 11420 => 11421, 944 | 11422 => 11423, 945 | 11424 => 11425, 946 | 11426 => 11427, 947 | 11428 => 11429, 948 | 11430 => 11431, 949 | 11432 => 11433, 950 | 11434 => 11435, 951 | 11436 => 11437, 952 | 11438 => 11439, 953 | 11440 => 11441, 954 | 11442 => 11443, 955 | 11444 => 11445, 956 | 11446 => 11447, 957 | 11448 => 11449, 958 | 11450 => 11451, 959 | 11452 => 11453, 960 | 11454 => 11455, 961 | 11456 => 11457, 962 | 11458 => 11459, 963 | 11460 => 11461, 964 | 11462 => 11463, 965 | 11464 => 11465, 966 | 11466 => 11467, 967 | 11468 => 11469, 968 | 11470 => 11471, 969 | 11472 => 11473, 970 | 11474 => 11475, 971 | 11476 => 11477, 972 | 11478 => 11479, 973 | 11480 => 11481, 974 | 11482 => 11483, 975 | 11484 => 11485, 976 | 11486 => 11487, 977 | 11488 => 11489, 978 | 11490 => 11491, 979 | 11499 => 11500, 980 | 11501 => 11502, 981 | 11506 => 11507, 982 | 42560 => 42561, 983 | 42562 => 42563, 984 | 42564 => 42565, 985 | 42566 => 42567, 986 | 42568 => 42569, 987 | 42570 => 42571, 988 | 42572 => 42573, 989 | 42574 => 42575, 990 | 42576 => 42577, 991 | 42578 => 42579, 992 | 42580 => 42581, 993 | 42582 => 42583, 994 | 42584 => 42585, 995 | 42586 => 42587, 996 | 42588 => 42589, 997 | 42590 => 42591, 998 | 42592 => 42593, 999 | 42594 => 42595, 1000 | 42596 => 42597, 1001 | 42598 => 42599, 1002 | 42600 => 42601, 1003 | 42602 => 42603, 1004 | 42604 => 42605, 1005 | 42624 => 42625, 1006 | 42626 => 42627, 1007 | 42628 => 42629, 1008 | 42630 => 42631, 1009 | 42632 => 42633, 1010 | 42634 => 42635, 1011 | 42636 => 42637, 1012 | 42638 => 42639, 1013 | 42640 => 42641, 1014 | 42642 => 42643, 1015 | 42644 => 42645, 1016 | 42646 => 42647, 1017 | 42648 => 42649, 1018 | 42650 => 42651, 1019 | 42786 => 42787, 1020 | 42788 => 42789, 1021 | 42790 => 42791, 1022 | 42792 => 42793, 1023 | 42794 => 42795, 1024 | 42796 => 42797, 1025 | 42798 => 42799, 1026 | 42802 => 42803, 1027 | 42804 => 42805, 1028 | 42806 => 42807, 1029 | 42808 => 42809, 1030 | 42810 => 42811, 1031 | 42812 => 42813, 1032 | 42814 => 42815, 1033 | 42816 => 42817, 1034 | 42818 => 42819, 1035 | 42820 => 42821, 1036 | 42822 => 42823, 1037 | 42824 => 42825, 1038 | 42826 => 42827, 1039 | 42828 => 42829, 1040 | 42830 => 42831, 1041 | 42832 => 42833, 1042 | 42834 => 42835, 1043 | 42836 => 42837, 1044 | 42838 => 42839, 1045 | 42840 => 42841, 1046 | 42842 => 42843, 1047 | 42844 => 42845, 1048 | 42846 => 42847, 1049 | 42848 => 42849, 1050 | 42850 => 42851, 1051 | 42852 => 42853, 1052 | 42854 => 42855, 1053 | 42856 => 42857, 1054 | 42858 => 42859, 1055 | 42860 => 42861, 1056 | 42862 => 42863, 1057 | 42873 => 42874, 1058 | 42875 => 42876, 1059 | 42877 => 7545, 1060 | 42878 => 42879, 1061 | 42880 => 42881, 1062 | 42882 => 42883, 1063 | 42884 => 42885, 1064 | 42886 => 42887, 1065 | 42891 => 42892, 1066 | 42893 => 613, 1067 | 42896 => 42897, 1068 | 42898 => 42899, 1069 | 42902 => 42903, 1070 | 42904 => 42905, 1071 | 42906 => 42907, 1072 | 42908 => 42909, 1073 | 42910 => 42911, 1074 | 42912 => 42913, 1075 | 42914 => 42915, 1076 | 42916 => 42917, 1077 | 42918 => 42919, 1078 | 42920 => 42921, 1079 | 42922 => 614, 1080 | 42923 => 604, 1081 | 42924 => 609, 1082 | 42925 => 620, 1083 | 42926 => 618, 1084 | 42928 => 670, 1085 | 42929 => 647, 1086 | 42930 => 669, 1087 | 42931 => 43859, 1088 | 42932 => 42933, 1089 | 42934 => 42935, 1090 | 65313 => 65345, 1091 | 65314 => 65346, 1092 | 65315 => 65347, 1093 | 65316 => 65348, 1094 | 65317 => 65349, 1095 | 65318 => 65350, 1096 | 65319 => 65351, 1097 | 65320 => 65352, 1098 | 65321 => 65353, 1099 | 65322 => 65354, 1100 | 65323 => 65355, 1101 | 65324 => 65356, 1102 | 65325 => 65357, 1103 | 65326 => 65358, 1104 | 65327 => 65359, 1105 | 65328 => 65360, 1106 | 65329 => 65361, 1107 | 65330 => 65362, 1108 | 65331 => 65363, 1109 | 65332 => 65364, 1110 | 65333 => 65365, 1111 | 65334 => 65366, 1112 | 65335 => 65367, 1113 | 65336 => 65368, 1114 | 65337 => 65369, 1115 | 65338 => 65370, 1116 | 66560 => 66600, 1117 | 66561 => 66601, 1118 | 66562 => 66602, 1119 | 66563 => 66603, 1120 | 66564 => 66604, 1121 | 66565 => 66605, 1122 | 66566 => 66606, 1123 | 66567 => 66607, 1124 | 66568 => 66608, 1125 | 66569 => 66609, 1126 | 66570 => 66610, 1127 | 66571 => 66611, 1128 | 66572 => 66612, 1129 | 66573 => 66613, 1130 | 66574 => 66614, 1131 | 66575 => 66615, 1132 | 66576 => 66616, 1133 | 66577 => 66617, 1134 | 66578 => 66618, 1135 | 66579 => 66619, 1136 | 66580 => 66620, 1137 | 66581 => 66621, 1138 | 66582 => 66622, 1139 | 66583 => 66623, 1140 | 66584 => 66624, 1141 | 66585 => 66625, 1142 | 66586 => 66626, 1143 | 66587 => 66627, 1144 | 66588 => 66628, 1145 | 66589 => 66629, 1146 | 66590 => 66630, 1147 | 66591 => 66631, 1148 | 66592 => 66632, 1149 | 66593 => 66633, 1150 | 66594 => 66634, 1151 | 66595 => 66635, 1152 | 66596 => 66636, 1153 | 66597 => 66637, 1154 | 66598 => 66638, 1155 | 66599 => 66639, 1156 | 66736 => 66776, 1157 | 66737 => 66777, 1158 | 66738 => 66778, 1159 | 66739 => 66779, 1160 | 66740 => 66780, 1161 | 66741 => 66781, 1162 | 66742 => 66782, 1163 | 66743 => 66783, 1164 | 66744 => 66784, 1165 | 66745 => 66785, 1166 | 66746 => 66786, 1167 | 66747 => 66787, 1168 | 66748 => 66788, 1169 | 66749 => 66789, 1170 | 66750 => 66790, 1171 | 66751 => 66791, 1172 | 66752 => 66792, 1173 | 66753 => 66793, 1174 | 66754 => 66794, 1175 | 66755 => 66795, 1176 | 66756 => 66796, 1177 | 66757 => 66797, 1178 | 66758 => 66798, 1179 | 66759 => 66799, 1180 | 66760 => 66800, 1181 | 66761 => 66801, 1182 | 66762 => 66802, 1183 | 66763 => 66803, 1184 | 66764 => 66804, 1185 | 66765 => 66805, 1186 | 66766 => 66806, 1187 | 66767 => 66807, 1188 | 66768 => 66808, 1189 | 66769 => 66809, 1190 | 66770 => 66810, 1191 | 66771 => 66811, 1192 | 68736 => 68800, 1193 | 68737 => 68801, 1194 | 68738 => 68802, 1195 | 68739 => 68803, 1196 | 68740 => 68804, 1197 | 68741 => 68805, 1198 | 68742 => 68806, 1199 | 68743 => 68807, 1200 | 68744 => 68808, 1201 | 68745 => 68809, 1202 | 68746 => 68810, 1203 | 68747 => 68811, 1204 | 68748 => 68812, 1205 | 68749 => 68813, 1206 | 68750 => 68814, 1207 | 68751 => 68815, 1208 | 68752 => 68816, 1209 | 68753 => 68817, 1210 | 68754 => 68818, 1211 | 68755 => 68819, 1212 | 68756 => 68820, 1213 | 68757 => 68821, 1214 | 68758 => 68822, 1215 | 68759 => 68823, 1216 | 68760 => 68824, 1217 | 68761 => 68825, 1218 | 68762 => 68826, 1219 | 68763 => 68827, 1220 | 68764 => 68828, 1221 | 68765 => 68829, 1222 | 68766 => 68830, 1223 | 68767 => 68831, 1224 | 68768 => 68832, 1225 | 68769 => 68833, 1226 | 68770 => 68834, 1227 | 68771 => 68835, 1228 | 68772 => 68836, 1229 | 68773 => 68837, 1230 | 68774 => 68838, 1231 | 68775 => 68839, 1232 | 68776 => 68840, 1233 | 68777 => 68841, 1234 | 68778 => 68842, 1235 | 68779 => 68843, 1236 | 68780 => 68844, 1237 | 68781 => 68845, 1238 | 68782 => 68846, 1239 | 68783 => 68847, 1240 | 68784 => 68848, 1241 | 68785 => 68849, 1242 | 68786 => 68850, 1243 | 71840 => 71872, 1244 | 71841 => 71873, 1245 | 71842 => 71874, 1246 | 71843 => 71875, 1247 | 71844 => 71876, 1248 | 71845 => 71877, 1249 | 71846 => 71878, 1250 | 71847 => 71879, 1251 | 71848 => 71880, 1252 | 71849 => 71881, 1253 | 71850 => 71882, 1254 | 71851 => 71883, 1255 | 71852 => 71884, 1256 | 71853 => 71885, 1257 | 71854 => 71886, 1258 | 71855 => 71887, 1259 | 71856 => 71888, 1260 | 71857 => 71889, 1261 | 71858 => 71890, 1262 | 71859 => 71891, 1263 | 71860 => 71892, 1264 | 71861 => 71893, 1265 | 71862 => 71894, 1266 | 71863 => 71895, 1267 | 71864 => 71896, 1268 | 71865 => 71897, 1269 | 71866 => 71898, 1270 | 71867 => 71899, 1271 | 71868 => 71900, 1272 | 71869 => 71901, 1273 | 71870 => 71902, 1274 | 71871 => 71903, 1275 | 125184 => 125218, 1276 | 125185 => 125219, 1277 | 125186 => 125220, 1278 | 125187 => 125221, 1279 | 125188 => 125222, 1280 | 125189 => 125223, 1281 | 125190 => 125224, 1282 | 125191 => 125225, 1283 | 125192 => 125226, 1284 | 125193 => 125227, 1285 | 125194 => 125228, 1286 | 125195 => 125229, 1287 | 125196 => 125230, 1288 | 125197 => 125231, 1289 | 125198 => 125232, 1290 | 125199 => 125233, 1291 | 125200 => 125234, 1292 | 125201 => 125235, 1293 | 125202 => 125236, 1294 | 125203 => 125237, 1295 | 125204 => 125238, 1296 | 125205 => 125239, 1297 | 125206 => 125240, 1298 | 125207 => 125241, 1299 | 125208 => 125242, 1300 | 125209 => 125243, 1301 | 125210 => 125244, 1302 | 125211 => 125245, 1303 | 125212 => 125246, 1304 | 125213 => 125247, 1305 | 125214 => 125248, 1306 | 125215 => 125249, 1307 | 125216 => 125250, 1308 | 125217 => 125251 1309 | }). 1310 | -define(TO_UPPER, #{ 1311 | 97 => 65, 1312 | 98 => 66, 1313 | 99 => 67, 1314 | 100 => 68, 1315 | 101 => 69, 1316 | 102 => 70, 1317 | 103 => 71, 1318 | 104 => 72, 1319 | 105 => 73, 1320 | 106 => 74, 1321 | 107 => 75, 1322 | 108 => 76, 1323 | 109 => 77, 1324 | 110 => 78, 1325 | 111 => 79, 1326 | 112 => 80, 1327 | 113 => 81, 1328 | 114 => 82, 1329 | 115 => 83, 1330 | 116 => 84, 1331 | 117 => 85, 1332 | 118 => 86, 1333 | 119 => 87, 1334 | 120 => 88, 1335 | 121 => 89, 1336 | 122 => 90, 1337 | 181 => 924, 1338 | 224 => 192, 1339 | 225 => 193, 1340 | 226 => 194, 1341 | 227 => 195, 1342 | 228 => 196, 1343 | 229 => 197, 1344 | 230 => 198, 1345 | 231 => 199, 1346 | 232 => 200, 1347 | 233 => 201, 1348 | 234 => 202, 1349 | 235 => 203, 1350 | 236 => 204, 1351 | 237 => 205, 1352 | 238 => 206, 1353 | 239 => 207, 1354 | 240 => 208, 1355 | 241 => 209, 1356 | 242 => 210, 1357 | 243 => 211, 1358 | 244 => 212, 1359 | 245 => 213, 1360 | 246 => 214, 1361 | 248 => 216, 1362 | 249 => 217, 1363 | 250 => 218, 1364 | 251 => 219, 1365 | 252 => 220, 1366 | 253 => 221, 1367 | 254 => 222, 1368 | 255 => 376, 1369 | 257 => 256, 1370 | 259 => 258, 1371 | 261 => 260, 1372 | 263 => 262, 1373 | 265 => 264, 1374 | 267 => 266, 1375 | 269 => 268, 1376 | 271 => 270, 1377 | 273 => 272, 1378 | 275 => 274, 1379 | 277 => 276, 1380 | 279 => 278, 1381 | 281 => 280, 1382 | 283 => 282, 1383 | 285 => 284, 1384 | 287 => 286, 1385 | 289 => 288, 1386 | 291 => 290, 1387 | 293 => 292, 1388 | 295 => 294, 1389 | 297 => 296, 1390 | 299 => 298, 1391 | 301 => 300, 1392 | 303 => 302, 1393 | 305 => 73, 1394 | 307 => 306, 1395 | 309 => 308, 1396 | 311 => 310, 1397 | 314 => 313, 1398 | 316 => 315, 1399 | 318 => 317, 1400 | 320 => 319, 1401 | 322 => 321, 1402 | 324 => 323, 1403 | 326 => 325, 1404 | 328 => 327, 1405 | 331 => 330, 1406 | 333 => 332, 1407 | 335 => 334, 1408 | 337 => 336, 1409 | 339 => 338, 1410 | 341 => 340, 1411 | 343 => 342, 1412 | 345 => 344, 1413 | 347 => 346, 1414 | 349 => 348, 1415 | 351 => 350, 1416 | 353 => 352, 1417 | 355 => 354, 1418 | 357 => 356, 1419 | 359 => 358, 1420 | 361 => 360, 1421 | 363 => 362, 1422 | 365 => 364, 1423 | 367 => 366, 1424 | 369 => 368, 1425 | 371 => 370, 1426 | 373 => 372, 1427 | 375 => 374, 1428 | 378 => 377, 1429 | 380 => 379, 1430 | 382 => 381, 1431 | 383 => 83, 1432 | 384 => 579, 1433 | 387 => 386, 1434 | 389 => 388, 1435 | 392 => 391, 1436 | 396 => 395, 1437 | 402 => 401, 1438 | 405 => 502, 1439 | 409 => 408, 1440 | 410 => 573, 1441 | 414 => 544, 1442 | 417 => 416, 1443 | 419 => 418, 1444 | 421 => 420, 1445 | 424 => 423, 1446 | 429 => 428, 1447 | 432 => 431, 1448 | 436 => 435, 1449 | 438 => 437, 1450 | 441 => 440, 1451 | 445 => 444, 1452 | 447 => 503, 1453 | 453 => 452, 1454 | 454 => 452, 1455 | 456 => 455, 1456 | 457 => 455, 1457 | 459 => 458, 1458 | 460 => 458, 1459 | 462 => 461, 1460 | 464 => 463, 1461 | 466 => 465, 1462 | 468 => 467, 1463 | 470 => 469, 1464 | 472 => 471, 1465 | 474 => 473, 1466 | 476 => 475, 1467 | 477 => 398, 1468 | 479 => 478, 1469 | 481 => 480, 1470 | 483 => 482, 1471 | 485 => 484, 1472 | 487 => 486, 1473 | 489 => 488, 1474 | 491 => 490, 1475 | 493 => 492, 1476 | 495 => 494, 1477 | 498 => 497, 1478 | 499 => 497, 1479 | 501 => 500, 1480 | 505 => 504, 1481 | 507 => 506, 1482 | 509 => 508, 1483 | 511 => 510, 1484 | 513 => 512, 1485 | 515 => 514, 1486 | 517 => 516, 1487 | 519 => 518, 1488 | 521 => 520, 1489 | 523 => 522, 1490 | 525 => 524, 1491 | 527 => 526, 1492 | 529 => 528, 1493 | 531 => 530, 1494 | 533 => 532, 1495 | 535 => 534, 1496 | 537 => 536, 1497 | 539 => 538, 1498 | 541 => 540, 1499 | 543 => 542, 1500 | 547 => 546, 1501 | 549 => 548, 1502 | 551 => 550, 1503 | 553 => 552, 1504 | 555 => 554, 1505 | 557 => 556, 1506 | 559 => 558, 1507 | 561 => 560, 1508 | 563 => 562, 1509 | 572 => 571, 1510 | 575 => 11390, 1511 | 576 => 11391, 1512 | 578 => 577, 1513 | 583 => 582, 1514 | 585 => 584, 1515 | 587 => 586, 1516 | 589 => 588, 1517 | 591 => 590, 1518 | 592 => 11375, 1519 | 593 => 11373, 1520 | 594 => 11376, 1521 | 595 => 385, 1522 | 596 => 390, 1523 | 598 => 393, 1524 | 599 => 394, 1525 | 601 => 399, 1526 | 603 => 400, 1527 | 604 => 42923, 1528 | 608 => 403, 1529 | 609 => 42924, 1530 | 611 => 404, 1531 | 613 => 42893, 1532 | 614 => 42922, 1533 | 616 => 407, 1534 | 617 => 406, 1535 | 618 => 42926, 1536 | 619 => 11362, 1537 | 620 => 42925, 1538 | 623 => 412, 1539 | 625 => 11374, 1540 | 626 => 413, 1541 | 629 => 415, 1542 | 637 => 11364, 1543 | 640 => 422, 1544 | 643 => 425, 1545 | 647 => 42929, 1546 | 648 => 430, 1547 | 649 => 580, 1548 | 650 => 433, 1549 | 651 => 434, 1550 | 652 => 581, 1551 | 658 => 439, 1552 | 669 => 42930, 1553 | 670 => 42928, 1554 | 837 => 921, 1555 | 881 => 880, 1556 | 883 => 882, 1557 | 887 => 886, 1558 | 891 => 1021, 1559 | 892 => 1022, 1560 | 893 => 1023, 1561 | 940 => 902, 1562 | 941 => 904, 1563 | 942 => 905, 1564 | 943 => 906, 1565 | 945 => 913, 1566 | 946 => 914, 1567 | 947 => 915, 1568 | 948 => 916, 1569 | 949 => 917, 1570 | 950 => 918, 1571 | 951 => 919, 1572 | 952 => 920, 1573 | 953 => 921, 1574 | 954 => 922, 1575 | 955 => 923, 1576 | 956 => 924, 1577 | 957 => 925, 1578 | 958 => 926, 1579 | 959 => 927, 1580 | 960 => 928, 1581 | 961 => 929, 1582 | 962 => 931, 1583 | 963 => 931, 1584 | 964 => 932, 1585 | 965 => 933, 1586 | 966 => 934, 1587 | 967 => 935, 1588 | 968 => 936, 1589 | 969 => 937, 1590 | 970 => 938, 1591 | 971 => 939, 1592 | 972 => 908, 1593 | 973 => 910, 1594 | 974 => 911, 1595 | 976 => 914, 1596 | 977 => 920, 1597 | 981 => 934, 1598 | 982 => 928, 1599 | 983 => 975, 1600 | 985 => 984, 1601 | 987 => 986, 1602 | 989 => 988, 1603 | 991 => 990, 1604 | 993 => 992, 1605 | 995 => 994, 1606 | 997 => 996, 1607 | 999 => 998, 1608 | 1001 => 1000, 1609 | 1003 => 1002, 1610 | 1005 => 1004, 1611 | 1007 => 1006, 1612 | 1008 => 922, 1613 | 1009 => 929, 1614 | 1010 => 1017, 1615 | 1011 => 895, 1616 | 1013 => 917, 1617 | 1016 => 1015, 1618 | 1019 => 1018, 1619 | 1072 => 1040, 1620 | 1073 => 1041, 1621 | 1074 => 1042, 1622 | 1075 => 1043, 1623 | 1076 => 1044, 1624 | 1077 => 1045, 1625 | 1078 => 1046, 1626 | 1079 => 1047, 1627 | 1080 => 1048, 1628 | 1081 => 1049, 1629 | 1082 => 1050, 1630 | 1083 => 1051, 1631 | 1084 => 1052, 1632 | 1085 => 1053, 1633 | 1086 => 1054, 1634 | 1087 => 1055, 1635 | 1088 => 1056, 1636 | 1089 => 1057, 1637 | 1090 => 1058, 1638 | 1091 => 1059, 1639 | 1092 => 1060, 1640 | 1093 => 1061, 1641 | 1094 => 1062, 1642 | 1095 => 1063, 1643 | 1096 => 1064, 1644 | 1097 => 1065, 1645 | 1098 => 1066, 1646 | 1099 => 1067, 1647 | 1100 => 1068, 1648 | 1101 => 1069, 1649 | 1102 => 1070, 1650 | 1103 => 1071, 1651 | 1104 => 1024, 1652 | 1105 => 1025, 1653 | 1106 => 1026, 1654 | 1107 => 1027, 1655 | 1108 => 1028, 1656 | 1109 => 1029, 1657 | 1110 => 1030, 1658 | 1111 => 1031, 1659 | 1112 => 1032, 1660 | 1113 => 1033, 1661 | 1114 => 1034, 1662 | 1115 => 1035, 1663 | 1116 => 1036, 1664 | 1117 => 1037, 1665 | 1118 => 1038, 1666 | 1119 => 1039, 1667 | 1121 => 1120, 1668 | 1123 => 1122, 1669 | 1125 => 1124, 1670 | 1127 => 1126, 1671 | 1129 => 1128, 1672 | 1131 => 1130, 1673 | 1133 => 1132, 1674 | 1135 => 1134, 1675 | 1137 => 1136, 1676 | 1139 => 1138, 1677 | 1141 => 1140, 1678 | 1143 => 1142, 1679 | 1145 => 1144, 1680 | 1147 => 1146, 1681 | 1149 => 1148, 1682 | 1151 => 1150, 1683 | 1153 => 1152, 1684 | 1163 => 1162, 1685 | 1165 => 1164, 1686 | 1167 => 1166, 1687 | 1169 => 1168, 1688 | 1171 => 1170, 1689 | 1173 => 1172, 1690 | 1175 => 1174, 1691 | 1177 => 1176, 1692 | 1179 => 1178, 1693 | 1181 => 1180, 1694 | 1183 => 1182, 1695 | 1185 => 1184, 1696 | 1187 => 1186, 1697 | 1189 => 1188, 1698 | 1191 => 1190, 1699 | 1193 => 1192, 1700 | 1195 => 1194, 1701 | 1197 => 1196, 1702 | 1199 => 1198, 1703 | 1201 => 1200, 1704 | 1203 => 1202, 1705 | 1205 => 1204, 1706 | 1207 => 1206, 1707 | 1209 => 1208, 1708 | 1211 => 1210, 1709 | 1213 => 1212, 1710 | 1215 => 1214, 1711 | 1218 => 1217, 1712 | 1220 => 1219, 1713 | 1222 => 1221, 1714 | 1224 => 1223, 1715 | 1226 => 1225, 1716 | 1228 => 1227, 1717 | 1230 => 1229, 1718 | 1231 => 1216, 1719 | 1233 => 1232, 1720 | 1235 => 1234, 1721 | 1237 => 1236, 1722 | 1239 => 1238, 1723 | 1241 => 1240, 1724 | 1243 => 1242, 1725 | 1245 => 1244, 1726 | 1247 => 1246, 1727 | 1249 => 1248, 1728 | 1251 => 1250, 1729 | 1253 => 1252, 1730 | 1255 => 1254, 1731 | 1257 => 1256, 1732 | 1259 => 1258, 1733 | 1261 => 1260, 1734 | 1263 => 1262, 1735 | 1265 => 1264, 1736 | 1267 => 1266, 1737 | 1269 => 1268, 1738 | 1271 => 1270, 1739 | 1273 => 1272, 1740 | 1275 => 1274, 1741 | 1277 => 1276, 1742 | 1279 => 1278, 1743 | 1281 => 1280, 1744 | 1283 => 1282, 1745 | 1285 => 1284, 1746 | 1287 => 1286, 1747 | 1289 => 1288, 1748 | 1291 => 1290, 1749 | 1293 => 1292, 1750 | 1295 => 1294, 1751 | 1297 => 1296, 1752 | 1299 => 1298, 1753 | 1301 => 1300, 1754 | 1303 => 1302, 1755 | 1305 => 1304, 1756 | 1307 => 1306, 1757 | 1309 => 1308, 1758 | 1311 => 1310, 1759 | 1313 => 1312, 1760 | 1315 => 1314, 1761 | 1317 => 1316, 1762 | 1319 => 1318, 1763 | 1321 => 1320, 1764 | 1323 => 1322, 1765 | 1325 => 1324, 1766 | 1327 => 1326, 1767 | 1377 => 1329, 1768 | 1378 => 1330, 1769 | 1379 => 1331, 1770 | 1380 => 1332, 1771 | 1381 => 1333, 1772 | 1382 => 1334, 1773 | 1383 => 1335, 1774 | 1384 => 1336, 1775 | 1385 => 1337, 1776 | 1386 => 1338, 1777 | 1387 => 1339, 1778 | 1388 => 1340, 1779 | 1389 => 1341, 1780 | 1390 => 1342, 1781 | 1391 => 1343, 1782 | 1392 => 1344, 1783 | 1393 => 1345, 1784 | 1394 => 1346, 1785 | 1395 => 1347, 1786 | 1396 => 1348, 1787 | 1397 => 1349, 1788 | 1398 => 1350, 1789 | 1399 => 1351, 1790 | 1400 => 1352, 1791 | 1401 => 1353, 1792 | 1402 => 1354, 1793 | 1403 => 1355, 1794 | 1404 => 1356, 1795 | 1405 => 1357, 1796 | 1406 => 1358, 1797 | 1407 => 1359, 1798 | 1408 => 1360, 1799 | 1409 => 1361, 1800 | 1410 => 1362, 1801 | 1411 => 1363, 1802 | 1412 => 1364, 1803 | 1413 => 1365, 1804 | 1414 => 1366, 1805 | 5112 => 5104, 1806 | 5113 => 5105, 1807 | 5114 => 5106, 1808 | 5115 => 5107, 1809 | 5116 => 5108, 1810 | 5117 => 5109, 1811 | 7296 => 1042, 1812 | 7297 => 1044, 1813 | 7298 => 1054, 1814 | 7299 => 1057, 1815 | 7300 => 1058, 1816 | 7301 => 1058, 1817 | 7302 => 1066, 1818 | 7303 => 1122, 1819 | 7304 => 42570, 1820 | 7545 => 42877, 1821 | 7549 => 11363, 1822 | 7681 => 7680, 1823 | 7683 => 7682, 1824 | 7685 => 7684, 1825 | 7687 => 7686, 1826 | 7689 => 7688, 1827 | 7691 => 7690, 1828 | 7693 => 7692, 1829 | 7695 => 7694, 1830 | 7697 => 7696, 1831 | 7699 => 7698, 1832 | 7701 => 7700, 1833 | 7703 => 7702, 1834 | 7705 => 7704, 1835 | 7707 => 7706, 1836 | 7709 => 7708, 1837 | 7711 => 7710, 1838 | 7713 => 7712, 1839 | 7715 => 7714, 1840 | 7717 => 7716, 1841 | 7719 => 7718, 1842 | 7721 => 7720, 1843 | 7723 => 7722, 1844 | 7725 => 7724, 1845 | 7727 => 7726, 1846 | 7729 => 7728, 1847 | 7731 => 7730, 1848 | 7733 => 7732, 1849 | 7735 => 7734, 1850 | 7737 => 7736, 1851 | 7739 => 7738, 1852 | 7741 => 7740, 1853 | 7743 => 7742, 1854 | 7745 => 7744, 1855 | 7747 => 7746, 1856 | 7749 => 7748, 1857 | 7751 => 7750, 1858 | 7753 => 7752, 1859 | 7755 => 7754, 1860 | 7757 => 7756, 1861 | 7759 => 7758, 1862 | 7761 => 7760, 1863 | 7763 => 7762, 1864 | 7765 => 7764, 1865 | 7767 => 7766, 1866 | 7769 => 7768, 1867 | 7771 => 7770, 1868 | 7773 => 7772, 1869 | 7775 => 7774, 1870 | 7777 => 7776, 1871 | 7779 => 7778, 1872 | 7781 => 7780, 1873 | 7783 => 7782, 1874 | 7785 => 7784, 1875 | 7787 => 7786, 1876 | 7789 => 7788, 1877 | 7791 => 7790, 1878 | 7793 => 7792, 1879 | 7795 => 7794, 1880 | 7797 => 7796, 1881 | 7799 => 7798, 1882 | 7801 => 7800, 1883 | 7803 => 7802, 1884 | 7805 => 7804, 1885 | 7807 => 7806, 1886 | 7809 => 7808, 1887 | 7811 => 7810, 1888 | 7813 => 7812, 1889 | 7815 => 7814, 1890 | 7817 => 7816, 1891 | 7819 => 7818, 1892 | 7821 => 7820, 1893 | 7823 => 7822, 1894 | 7825 => 7824, 1895 | 7827 => 7826, 1896 | 7829 => 7828, 1897 | 7835 => 7776, 1898 | 7841 => 7840, 1899 | 7843 => 7842, 1900 | 7845 => 7844, 1901 | 7847 => 7846, 1902 | 7849 => 7848, 1903 | 7851 => 7850, 1904 | 7853 => 7852, 1905 | 7855 => 7854, 1906 | 7857 => 7856, 1907 | 7859 => 7858, 1908 | 7861 => 7860, 1909 | 7863 => 7862, 1910 | 7865 => 7864, 1911 | 7867 => 7866, 1912 | 7869 => 7868, 1913 | 7871 => 7870, 1914 | 7873 => 7872, 1915 | 7875 => 7874, 1916 | 7877 => 7876, 1917 | 7879 => 7878, 1918 | 7881 => 7880, 1919 | 7883 => 7882, 1920 | 7885 => 7884, 1921 | 7887 => 7886, 1922 | 7889 => 7888, 1923 | 7891 => 7890, 1924 | 7893 => 7892, 1925 | 7895 => 7894, 1926 | 7897 => 7896, 1927 | 7899 => 7898, 1928 | 7901 => 7900, 1929 | 7903 => 7902, 1930 | 7905 => 7904, 1931 | 7907 => 7906, 1932 | 7909 => 7908, 1933 | 7911 => 7910, 1934 | 7913 => 7912, 1935 | 7915 => 7914, 1936 | 7917 => 7916, 1937 | 7919 => 7918, 1938 | 7921 => 7920, 1939 | 7923 => 7922, 1940 | 7925 => 7924, 1941 | 7927 => 7926, 1942 | 7929 => 7928, 1943 | 7931 => 7930, 1944 | 7933 => 7932, 1945 | 7935 => 7934, 1946 | 7936 => 7944, 1947 | 7937 => 7945, 1948 | 7938 => 7946, 1949 | 7939 => 7947, 1950 | 7940 => 7948, 1951 | 7941 => 7949, 1952 | 7942 => 7950, 1953 | 7943 => 7951, 1954 | 7952 => 7960, 1955 | 7953 => 7961, 1956 | 7954 => 7962, 1957 | 7955 => 7963, 1958 | 7956 => 7964, 1959 | 7957 => 7965, 1960 | 7968 => 7976, 1961 | 7969 => 7977, 1962 | 7970 => 7978, 1963 | 7971 => 7979, 1964 | 7972 => 7980, 1965 | 7973 => 7981, 1966 | 7974 => 7982, 1967 | 7975 => 7983, 1968 | 7984 => 7992, 1969 | 7985 => 7993, 1970 | 7986 => 7994, 1971 | 7987 => 7995, 1972 | 7988 => 7996, 1973 | 7989 => 7997, 1974 | 7990 => 7998, 1975 | 7991 => 7999, 1976 | 8000 => 8008, 1977 | 8001 => 8009, 1978 | 8002 => 8010, 1979 | 8003 => 8011, 1980 | 8004 => 8012, 1981 | 8005 => 8013, 1982 | 8017 => 8025, 1983 | 8019 => 8027, 1984 | 8021 => 8029, 1985 | 8023 => 8031, 1986 | 8032 => 8040, 1987 | 8033 => 8041, 1988 | 8034 => 8042, 1989 | 8035 => 8043, 1990 | 8036 => 8044, 1991 | 8037 => 8045, 1992 | 8038 => 8046, 1993 | 8039 => 8047, 1994 | 8048 => 8122, 1995 | 8049 => 8123, 1996 | 8050 => 8136, 1997 | 8051 => 8137, 1998 | 8052 => 8138, 1999 | 8053 => 8139, 2000 | 8054 => 8154, 2001 | 8055 => 8155, 2002 | 8056 => 8184, 2003 | 8057 => 8185, 2004 | 8058 => 8170, 2005 | 8059 => 8171, 2006 | 8060 => 8186, 2007 | 8061 => 8187, 2008 | 8064 => 8072, 2009 | 8065 => 8073, 2010 | 8066 => 8074, 2011 | 8067 => 8075, 2012 | 8068 => 8076, 2013 | 8069 => 8077, 2014 | 8070 => 8078, 2015 | 8071 => 8079, 2016 | 8080 => 8088, 2017 | 8081 => 8089, 2018 | 8082 => 8090, 2019 | 8083 => 8091, 2020 | 8084 => 8092, 2021 | 8085 => 8093, 2022 | 8086 => 8094, 2023 | 8087 => 8095, 2024 | 8096 => 8104, 2025 | 8097 => 8105, 2026 | 8098 => 8106, 2027 | 8099 => 8107, 2028 | 8100 => 8108, 2029 | 8101 => 8109, 2030 | 8102 => 8110, 2031 | 8103 => 8111, 2032 | 8112 => 8120, 2033 | 8113 => 8121, 2034 | 8115 => 8124, 2035 | 8126 => 921, 2036 | 8131 => 8140, 2037 | 8144 => 8152, 2038 | 8145 => 8153, 2039 | 8160 => 8168, 2040 | 8161 => 8169, 2041 | 8165 => 8172, 2042 | 8179 => 8188, 2043 | 8526 => 8498, 2044 | 8560 => 8544, 2045 | 8561 => 8545, 2046 | 8562 => 8546, 2047 | 8563 => 8547, 2048 | 8564 => 8548, 2049 | 8565 => 8549, 2050 | 8566 => 8550, 2051 | 8567 => 8551, 2052 | 8568 => 8552, 2053 | 8569 => 8553, 2054 | 8570 => 8554, 2055 | 8571 => 8555, 2056 | 8572 => 8556, 2057 | 8573 => 8557, 2058 | 8574 => 8558, 2059 | 8575 => 8559, 2060 | 8580 => 8579, 2061 | 9424 => 9398, 2062 | 9425 => 9399, 2063 | 9426 => 9400, 2064 | 9427 => 9401, 2065 | 9428 => 9402, 2066 | 9429 => 9403, 2067 | 9430 => 9404, 2068 | 9431 => 9405, 2069 | 9432 => 9406, 2070 | 9433 => 9407, 2071 | 9434 => 9408, 2072 | 9435 => 9409, 2073 | 9436 => 9410, 2074 | 9437 => 9411, 2075 | 9438 => 9412, 2076 | 9439 => 9413, 2077 | 9440 => 9414, 2078 | 9441 => 9415, 2079 | 9442 => 9416, 2080 | 9443 => 9417, 2081 | 9444 => 9418, 2082 | 9445 => 9419, 2083 | 9446 => 9420, 2084 | 9447 => 9421, 2085 | 9448 => 9422, 2086 | 9449 => 9423, 2087 | 11312 => 11264, 2088 | 11313 => 11265, 2089 | 11314 => 11266, 2090 | 11315 => 11267, 2091 | 11316 => 11268, 2092 | 11317 => 11269, 2093 | 11318 => 11270, 2094 | 11319 => 11271, 2095 | 11320 => 11272, 2096 | 11321 => 11273, 2097 | 11322 => 11274, 2098 | 11323 => 11275, 2099 | 11324 => 11276, 2100 | 11325 => 11277, 2101 | 11326 => 11278, 2102 | 11327 => 11279, 2103 | 11328 => 11280, 2104 | 11329 => 11281, 2105 | 11330 => 11282, 2106 | 11331 => 11283, 2107 | 11332 => 11284, 2108 | 11333 => 11285, 2109 | 11334 => 11286, 2110 | 11335 => 11287, 2111 | 11336 => 11288, 2112 | 11337 => 11289, 2113 | 11338 => 11290, 2114 | 11339 => 11291, 2115 | 11340 => 11292, 2116 | 11341 => 11293, 2117 | 11342 => 11294, 2118 | 11343 => 11295, 2119 | 11344 => 11296, 2120 | 11345 => 11297, 2121 | 11346 => 11298, 2122 | 11347 => 11299, 2123 | 11348 => 11300, 2124 | 11349 => 11301, 2125 | 11350 => 11302, 2126 | 11351 => 11303, 2127 | 11352 => 11304, 2128 | 11353 => 11305, 2129 | 11354 => 11306, 2130 | 11355 => 11307, 2131 | 11356 => 11308, 2132 | 11357 => 11309, 2133 | 11358 => 11310, 2134 | 11361 => 11360, 2135 | 11365 => 570, 2136 | 11366 => 574, 2137 | 11368 => 11367, 2138 | 11370 => 11369, 2139 | 11372 => 11371, 2140 | 11379 => 11378, 2141 | 11382 => 11381, 2142 | 11393 => 11392, 2143 | 11395 => 11394, 2144 | 11397 => 11396, 2145 | 11399 => 11398, 2146 | 11401 => 11400, 2147 | 11403 => 11402, 2148 | 11405 => 11404, 2149 | 11407 => 11406, 2150 | 11409 => 11408, 2151 | 11411 => 11410, 2152 | 11413 => 11412, 2153 | 11415 => 11414, 2154 | 11417 => 11416, 2155 | 11419 => 11418, 2156 | 11421 => 11420, 2157 | 11423 => 11422, 2158 | 11425 => 11424, 2159 | 11427 => 11426, 2160 | 11429 => 11428, 2161 | 11431 => 11430, 2162 | 11433 => 11432, 2163 | 11435 => 11434, 2164 | 11437 => 11436, 2165 | 11439 => 11438, 2166 | 11441 => 11440, 2167 | 11443 => 11442, 2168 | 11445 => 11444, 2169 | 11447 => 11446, 2170 | 11449 => 11448, 2171 | 11451 => 11450, 2172 | 11453 => 11452, 2173 | 11455 => 11454, 2174 | 11457 => 11456, 2175 | 11459 => 11458, 2176 | 11461 => 11460, 2177 | 11463 => 11462, 2178 | 11465 => 11464, 2179 | 11467 => 11466, 2180 | 11469 => 11468, 2181 | 11471 => 11470, 2182 | 11473 => 11472, 2183 | 11475 => 11474, 2184 | 11477 => 11476, 2185 | 11479 => 11478, 2186 | 11481 => 11480, 2187 | 11483 => 11482, 2188 | 11485 => 11484, 2189 | 11487 => 11486, 2190 | 11489 => 11488, 2191 | 11491 => 11490, 2192 | 11500 => 11499, 2193 | 11502 => 11501, 2194 | 11507 => 11506, 2195 | 11520 => 4256, 2196 | 11521 => 4257, 2197 | 11522 => 4258, 2198 | 11523 => 4259, 2199 | 11524 => 4260, 2200 | 11525 => 4261, 2201 | 11526 => 4262, 2202 | 11527 => 4263, 2203 | 11528 => 4264, 2204 | 11529 => 4265, 2205 | 11530 => 4266, 2206 | 11531 => 4267, 2207 | 11532 => 4268, 2208 | 11533 => 4269, 2209 | 11534 => 4270, 2210 | 11535 => 4271, 2211 | 11536 => 4272, 2212 | 11537 => 4273, 2213 | 11538 => 4274, 2214 | 11539 => 4275, 2215 | 11540 => 4276, 2216 | 11541 => 4277, 2217 | 11542 => 4278, 2218 | 11543 => 4279, 2219 | 11544 => 4280, 2220 | 11545 => 4281, 2221 | 11546 => 4282, 2222 | 11547 => 4283, 2223 | 11548 => 4284, 2224 | 11549 => 4285, 2225 | 11550 => 4286, 2226 | 11551 => 4287, 2227 | 11552 => 4288, 2228 | 11553 => 4289, 2229 | 11554 => 4290, 2230 | 11555 => 4291, 2231 | 11556 => 4292, 2232 | 11557 => 4293, 2233 | 11559 => 4295, 2234 | 11565 => 4301, 2235 | 42561 => 42560, 2236 | 42563 => 42562, 2237 | 42565 => 42564, 2238 | 42567 => 42566, 2239 | 42569 => 42568, 2240 | 42571 => 42570, 2241 | 42573 => 42572, 2242 | 42575 => 42574, 2243 | 42577 => 42576, 2244 | 42579 => 42578, 2245 | 42581 => 42580, 2246 | 42583 => 42582, 2247 | 42585 => 42584, 2248 | 42587 => 42586, 2249 | 42589 => 42588, 2250 | 42591 => 42590, 2251 | 42593 => 42592, 2252 | 42595 => 42594, 2253 | 42597 => 42596, 2254 | 42599 => 42598, 2255 | 42601 => 42600, 2256 | 42603 => 42602, 2257 | 42605 => 42604, 2258 | 42625 => 42624, 2259 | 42627 => 42626, 2260 | 42629 => 42628, 2261 | 42631 => 42630, 2262 | 42633 => 42632, 2263 | 42635 => 42634, 2264 | 42637 => 42636, 2265 | 42639 => 42638, 2266 | 42641 => 42640, 2267 | 42643 => 42642, 2268 | 42645 => 42644, 2269 | 42647 => 42646, 2270 | 42649 => 42648, 2271 | 42651 => 42650, 2272 | 42787 => 42786, 2273 | 42789 => 42788, 2274 | 42791 => 42790, 2275 | 42793 => 42792, 2276 | 42795 => 42794, 2277 | 42797 => 42796, 2278 | 42799 => 42798, 2279 | 42803 => 42802, 2280 | 42805 => 42804, 2281 | 42807 => 42806, 2282 | 42809 => 42808, 2283 | 42811 => 42810, 2284 | 42813 => 42812, 2285 | 42815 => 42814, 2286 | 42817 => 42816, 2287 | 42819 => 42818, 2288 | 42821 => 42820, 2289 | 42823 => 42822, 2290 | 42825 => 42824, 2291 | 42827 => 42826, 2292 | 42829 => 42828, 2293 | 42831 => 42830, 2294 | 42833 => 42832, 2295 | 42835 => 42834, 2296 | 42837 => 42836, 2297 | 42839 => 42838, 2298 | 42841 => 42840, 2299 | 42843 => 42842, 2300 | 42845 => 42844, 2301 | 42847 => 42846, 2302 | 42849 => 42848, 2303 | 42851 => 42850, 2304 | 42853 => 42852, 2305 | 42855 => 42854, 2306 | 42857 => 42856, 2307 | 42859 => 42858, 2308 | 42861 => 42860, 2309 | 42863 => 42862, 2310 | 42874 => 42873, 2311 | 42876 => 42875, 2312 | 42879 => 42878, 2313 | 42881 => 42880, 2314 | 42883 => 42882, 2315 | 42885 => 42884, 2316 | 42887 => 42886, 2317 | 42892 => 42891, 2318 | 42897 => 42896, 2319 | 42899 => 42898, 2320 | 42903 => 42902, 2321 | 42905 => 42904, 2322 | 42907 => 42906, 2323 | 42909 => 42908, 2324 | 42911 => 42910, 2325 | 42913 => 42912, 2326 | 42915 => 42914, 2327 | 42917 => 42916, 2328 | 42919 => 42918, 2329 | 42921 => 42920, 2330 | 42933 => 42932, 2331 | 42935 => 42934, 2332 | 43859 => 42931, 2333 | 43888 => 5024, 2334 | 43889 => 5025, 2335 | 43890 => 5026, 2336 | 43891 => 5027, 2337 | 43892 => 5028, 2338 | 43893 => 5029, 2339 | 43894 => 5030, 2340 | 43895 => 5031, 2341 | 43896 => 5032, 2342 | 43897 => 5033, 2343 | 43898 => 5034, 2344 | 43899 => 5035, 2345 | 43900 => 5036, 2346 | 43901 => 5037, 2347 | 43902 => 5038, 2348 | 43903 => 5039, 2349 | 43904 => 5040, 2350 | 43905 => 5041, 2351 | 43906 => 5042, 2352 | 43907 => 5043, 2353 | 43908 => 5044, 2354 | 43909 => 5045, 2355 | 43910 => 5046, 2356 | 43911 => 5047, 2357 | 43912 => 5048, 2358 | 43913 => 5049, 2359 | 43914 => 5050, 2360 | 43915 => 5051, 2361 | 43916 => 5052, 2362 | 43917 => 5053, 2363 | 43918 => 5054, 2364 | 43919 => 5055, 2365 | 43920 => 5056, 2366 | 43921 => 5057, 2367 | 43922 => 5058, 2368 | 43923 => 5059, 2369 | 43924 => 5060, 2370 | 43925 => 5061, 2371 | 43926 => 5062, 2372 | 43927 => 5063, 2373 | 43928 => 5064, 2374 | 43929 => 5065, 2375 | 43930 => 5066, 2376 | 43931 => 5067, 2377 | 43932 => 5068, 2378 | 43933 => 5069, 2379 | 43934 => 5070, 2380 | 43935 => 5071, 2381 | 43936 => 5072, 2382 | 43937 => 5073, 2383 | 43938 => 5074, 2384 | 43939 => 5075, 2385 | 43940 => 5076, 2386 | 43941 => 5077, 2387 | 43942 => 5078, 2388 | 43943 => 5079, 2389 | 43944 => 5080, 2390 | 43945 => 5081, 2391 | 43946 => 5082, 2392 | 43947 => 5083, 2393 | 43948 => 5084, 2394 | 43949 => 5085, 2395 | 43950 => 5086, 2396 | 43951 => 5087, 2397 | 43952 => 5088, 2398 | 43953 => 5089, 2399 | 43954 => 5090, 2400 | 43955 => 5091, 2401 | 43956 => 5092, 2402 | 43957 => 5093, 2403 | 43958 => 5094, 2404 | 43959 => 5095, 2405 | 43960 => 5096, 2406 | 43961 => 5097, 2407 | 43962 => 5098, 2408 | 43963 => 5099, 2409 | 43964 => 5100, 2410 | 43965 => 5101, 2411 | 43966 => 5102, 2412 | 43967 => 5103, 2413 | 65345 => 65313, 2414 | 65346 => 65314, 2415 | 65347 => 65315, 2416 | 65348 => 65316, 2417 | 65349 => 65317, 2418 | 65350 => 65318, 2419 | 65351 => 65319, 2420 | 65352 => 65320, 2421 | 65353 => 65321, 2422 | 65354 => 65322, 2423 | 65355 => 65323, 2424 | 65356 => 65324, 2425 | 65357 => 65325, 2426 | 65358 => 65326, 2427 | 65359 => 65327, 2428 | 65360 => 65328, 2429 | 65361 => 65329, 2430 | 65362 => 65330, 2431 | 65363 => 65331, 2432 | 65364 => 65332, 2433 | 65365 => 65333, 2434 | 65366 => 65334, 2435 | 65367 => 65335, 2436 | 65368 => 65336, 2437 | 65369 => 65337, 2438 | 65370 => 65338, 2439 | 66600 => 66560, 2440 | 66601 => 66561, 2441 | 66602 => 66562, 2442 | 66603 => 66563, 2443 | 66604 => 66564, 2444 | 66605 => 66565, 2445 | 66606 => 66566, 2446 | 66607 => 66567, 2447 | 66608 => 66568, 2448 | 66609 => 66569, 2449 | 66610 => 66570, 2450 | 66611 => 66571, 2451 | 66612 => 66572, 2452 | 66613 => 66573, 2453 | 66614 => 66574, 2454 | 66615 => 66575, 2455 | 66616 => 66576, 2456 | 66617 => 66577, 2457 | 66618 => 66578, 2458 | 66619 => 66579, 2459 | 66620 => 66580, 2460 | 66621 => 66581, 2461 | 66622 => 66582, 2462 | 66623 => 66583, 2463 | 66624 => 66584, 2464 | 66625 => 66585, 2465 | 66626 => 66586, 2466 | 66627 => 66587, 2467 | 66628 => 66588, 2468 | 66629 => 66589, 2469 | 66630 => 66590, 2470 | 66631 => 66591, 2471 | 66632 => 66592, 2472 | 66633 => 66593, 2473 | 66634 => 66594, 2474 | 66635 => 66595, 2475 | 66636 => 66596, 2476 | 66637 => 66597, 2477 | 66638 => 66598, 2478 | 66639 => 66599, 2479 | 66776 => 66736, 2480 | 66777 => 66737, 2481 | 66778 => 66738, 2482 | 66779 => 66739, 2483 | 66780 => 66740, 2484 | 66781 => 66741, 2485 | 66782 => 66742, 2486 | 66783 => 66743, 2487 | 66784 => 66744, 2488 | 66785 => 66745, 2489 | 66786 => 66746, 2490 | 66787 => 66747, 2491 | 66788 => 66748, 2492 | 66789 => 66749, 2493 | 66790 => 66750, 2494 | 66791 => 66751, 2495 | 66792 => 66752, 2496 | 66793 => 66753, 2497 | 66794 => 66754, 2498 | 66795 => 66755, 2499 | 66796 => 66756, 2500 | 66797 => 66757, 2501 | 66798 => 66758, 2502 | 66799 => 66759, 2503 | 66800 => 66760, 2504 | 66801 => 66761, 2505 | 66802 => 66762, 2506 | 66803 => 66763, 2507 | 66804 => 66764, 2508 | 66805 => 66765, 2509 | 66806 => 66766, 2510 | 66807 => 66767, 2511 | 66808 => 66768, 2512 | 66809 => 66769, 2513 | 66810 => 66770, 2514 | 66811 => 66771, 2515 | 68800 => 68736, 2516 | 68801 => 68737, 2517 | 68802 => 68738, 2518 | 68803 => 68739, 2519 | 68804 => 68740, 2520 | 68805 => 68741, 2521 | 68806 => 68742, 2522 | 68807 => 68743, 2523 | 68808 => 68744, 2524 | 68809 => 68745, 2525 | 68810 => 68746, 2526 | 68811 => 68747, 2527 | 68812 => 68748, 2528 | 68813 => 68749, 2529 | 68814 => 68750, 2530 | 68815 => 68751, 2531 | 68816 => 68752, 2532 | 68817 => 68753, 2533 | 68818 => 68754, 2534 | 68819 => 68755, 2535 | 68820 => 68756, 2536 | 68821 => 68757, 2537 | 68822 => 68758, 2538 | 68823 => 68759, 2539 | 68824 => 68760, 2540 | 68825 => 68761, 2541 | 68826 => 68762, 2542 | 68827 => 68763, 2543 | 68828 => 68764, 2544 | 68829 => 68765, 2545 | 68830 => 68766, 2546 | 68831 => 68767, 2547 | 68832 => 68768, 2548 | 68833 => 68769, 2549 | 68834 => 68770, 2550 | 68835 => 68771, 2551 | 68836 => 68772, 2552 | 68837 => 68773, 2553 | 68838 => 68774, 2554 | 68839 => 68775, 2555 | 68840 => 68776, 2556 | 68841 => 68777, 2557 | 68842 => 68778, 2558 | 68843 => 68779, 2559 | 68844 => 68780, 2560 | 68845 => 68781, 2561 | 68846 => 68782, 2562 | 68847 => 68783, 2563 | 68848 => 68784, 2564 | 68849 => 68785, 2565 | 68850 => 68786, 2566 | 71872 => 71840, 2567 | 71873 => 71841, 2568 | 71874 => 71842, 2569 | 71875 => 71843, 2570 | 71876 => 71844, 2571 | 71877 => 71845, 2572 | 71878 => 71846, 2573 | 71879 => 71847, 2574 | 71880 => 71848, 2575 | 71881 => 71849, 2576 | 71882 => 71850, 2577 | 71883 => 71851, 2578 | 71884 => 71852, 2579 | 71885 => 71853, 2580 | 71886 => 71854, 2581 | 71887 => 71855, 2582 | 71888 => 71856, 2583 | 71889 => 71857, 2584 | 71890 => 71858, 2585 | 71891 => 71859, 2586 | 71892 => 71860, 2587 | 71893 => 71861, 2588 | 71894 => 71862, 2589 | 71895 => 71863, 2590 | 71896 => 71864, 2591 | 71897 => 71865, 2592 | 71898 => 71866, 2593 | 71899 => 71867, 2594 | 71900 => 71868, 2595 | 71901 => 71869, 2596 | 71902 => 71870, 2597 | 71903 => 71871, 2598 | 125218 => 125184, 2599 | 125219 => 125185, 2600 | 125220 => 125186, 2601 | 125221 => 125187, 2602 | 125222 => 125188, 2603 | 125223 => 125189, 2604 | 125224 => 125190, 2605 | 125225 => 125191, 2606 | 125226 => 125192, 2607 | 125227 => 125193, 2608 | 125228 => 125194, 2609 | 125229 => 125195, 2610 | 125230 => 125196, 2611 | 125231 => 125197, 2612 | 125232 => 125198, 2613 | 125233 => 125199, 2614 | 125234 => 125200, 2615 | 125235 => 125201, 2616 | 125236 => 125202, 2617 | 125237 => 125203, 2618 | 125238 => 125204, 2619 | 125239 => 125205, 2620 | 125240 => 125206, 2621 | 125241 => 125207, 2622 | 125242 => 125208, 2623 | 125243 => 125209, 2624 | 125244 => 125210, 2625 | 125245 => 125211, 2626 | 125246 => 125212, 2627 | 125247 => 125213, 2628 | 125248 => 125214, 2629 | 125249 => 125215, 2630 | 125250 => 125216, 2631 | 125251 => 125217 2632 | }). 2633 | --------------------------------------------------------------------------------