anchor.diff:  err_to_atom({error, {Error, _}})        -> Error;
   err_to_atom(Else)                       -> Else.
   
  -% Write -ve tests seperately
  -
  -%% TODO : tests for delete candidate APIs
  -%% - fold_test_() ->
  -%% -     TestFun = fun(_,_,Acc) -> Acc+1 end,
  -%% -     {inparallel
  -%% -      , [{"proplist", ?_assertEqual(5, fold(TestFun,0,?TEST_PROP))}
  -%% -         , {"map", ?_assertEqual(5, fold(TestFun,0,?TEST_MAP))}
  -%% -         , {"json", ?_assertEqual(5, fold(TestFun,0,?TEST_JSON))}]}.
  -%% -
  -%% - has_key_test_() ->
  -%% -     {inparallel
  -%% -      , [{"proplist_success", ?_assert(has_key(<<"surname">>,?TEST_PROP))}
  -%% -         , {"map_success",?_assert(has_key(<<"surname">>,?TEST_MAP))}
  -%% -         , {"json_success",?_assert(has_key(<<"surname">>,?TEST_JSON))}
  -%% -         , {"proplist_fail",?_assert(not has_key(<<"sname">>,?TEST_PROP))}
  -%% -         , {"map_fail",?_assert(not has_key(<<"sname">>,?TEST_MAP))}
  -%% -         , {"json_fail",?_assert(not has_key(<<"sname">>,?TEST_JSON))}]}.
  -%% -
  -%% - map_map_test_() -> 
  -%% -     Job = fun(<<"age">>,_) -> 8000;
  -%% -              (_,true) -> false;
  -%% -              (_,V) -> V end,
  -%% -     PropOut = map(Job,?TEST_PROP),
  -%% -     MapOut = map(Job,?TEST_MAP),
  -%% -     JsonOut = map(Job,?TEST_JSON),
  -%% -     {inparallel
  -%% -      , [{"proplist"
  -%% -          , ?_assertEqual(8000, proplists:get_value(<<"age">>,PropOut))}
  -%% -         , {"proplist"
  -%% -            , ?_assertEqual(false
  -%% -                            , proplists:get_value(<<"earthling">>,PropOut))}
  -%% -         , {"map",?_assertEqual(8000, maps:get(<<"age">>,MapOut))}
  -%% -         , {"map",?_assertEqual(false,maps:get(<<"earthling">>,MapOut))}
  -%% -         , {"json",?_assertEqual(8000, ?MODULE:get(<<"age">>,JsonOut))}
  -%% -         , {"json",?_assertEqual(false,?MODULE:get(<<"earthling">>,JsonOut))}
  -%% -        ]}.
  -%% - 
  -%% - new_test_() -> 
  -%% -     %% Depends on default type setting
  -%% -     Test = [],
  -%% -     {inparallel
  -%% -      , [{"proplist",?_assertEqual([],new(proplist))}
  -%% -         , {"map",?_assertEqual(#{},new(map))}
  -%% -         , {"json",?_assertEqual(<<"{}">>,new(json))}
  -%% -         , {"default",?_assertEqual(Test,new())}]}.
  -
  -%% - remove_test_() ->
  -%% -     PropOut = remove(<<"age">>,?TEST_PROP),
  -%% -     MapOut =  remove(<<"age">>,?TEST_MAP),
  -%% -     JsonOut = remove(<<"age">>,?TEST_JSON),
  -%% -     {inparallel
  -%% -      , [{"proplist"
  -%% -          ,?_assertEqual(undefined
  -%% -                         , proplists:get_value(<<"age">>,PropOut,undefined))}
  -%% -         , {"map",?_assertEqual(undefined, ?MODULE:get(<<"age">>,MapOut))}
  -%% -         , {"json",?_assertEqual(undefined,?MODULE:get(<<"age">>,JsonOut))}
  -%% -        ]}.
  -%% -
  -%% - update_test_() ->
  -%% -     PropOut = update(<<"age">>,8000,?TEST_PROP),
  -%% -     MapOut =  update(<<"age">>,8000,?TEST_MAP),
  -%% -     JsonOut = update(<<"age">>,8000,?TEST_JSON),
  -%% -     {inparallel
  -%% -      , [{"proplist"
  -%% -          ,?_assertEqual(8000, proplists:get_value(<<"age">>,PropOut))}
  -%% -         , {"map",?_assertEqual(8000, maps:get(<<"age">>,MapOut))}
  -%% -         , {"json",?_assertEqual(8000,?MODULE:get(<<"age">>,JsonOut))}
  -%% -         , {"error_prop"
  -%% -            ,?_assertError(badarg,update(<<"not_there">>,true,?TEST_PROP))}
  -%% -         , {"error_map"
  -%% -            ,?_assertError(badarg,update(<<"not_there">>,true,?TEST_MAP))}]}.
  -%% - 
  -%% - to_proplist_deep_test_() ->
  -%% -     TestProp = [{<<"first">>,[{<<"second">>,true}]}],
  -%% -     TestMap = #{<<"first">> => #{<<"second">> => true}},
  -%% -     TestJson = <<"{\"first\":{\"second\":true}}">>,
  -%% -     {inparallel
  -%% -      , [{"proplist",?_assertEqual(TestProp,to_proplist(TestProp,deep))}
  -%% -         , {"map",?_assertEqual(TestProp,to_proplist(TestMap,deep))}
  -%% -         , {"json",?_assertEqual(TestProp,to_proplist(TestJson,deep))}]}.
  -%% -
  -%% - to_map_test_() ->
  -%% -     {inparallel
  -%% -      , [{"proplist",?_assert(is_map(to_map(?TEST_PROP)))}
  -%% -         , {"map",?_assert(is_map(to_map(?TEST_MAP)))}
  -%% -         , {"json",?_assert(is_map(to_map(clean_null_values(?TEST_JSON))))}]}.
  -%% -
  -%% - to_binary_test_() ->
  -%% -     {inparallel
  -%% -      , [{"proplist",?_assert(is_binary(to_binary(?TEST_PROP)))}
  -%% -         , {"map",?_assert(is_binary(to_binary(?TEST_MAP)))}
  -%% -         , {"json",?_assert(is_binary(to_binary(?TEST_JSON)))}]}.
  -%% - 
  -%% - filter_test_() -> 
  -%% -     FilterFun = fun(<<"age">>,_) -> true;
  -%% -                    (_,true) -> true;
  -%% -                    (_,_) -> false end,
  -%% -     PropOut = filter(FilterFun,?TEST_PROP),
  -%% -     MapOut =  filter(FilterFun,?TEST_MAP),
  -%% -     JsonOut = filter(FilterFun,?TEST_JSON),
  -%% -     {inparallel
  -%% -      , [{"proplist"
  -%% -          , ?_assertEqual(981, proplists:get_value(<<"age">>,PropOut))}
  -%% -         , {"proplist"
  -%% -            , ?_assertEqual(true
  -%% -                            , proplists:get_value(<<"earthling">>,PropOut))}
  -%% -         , {"map",?_assertEqual(981, maps:get(<<"age">>,MapOut))}
  -%% -         , {"map",?_assertEqual(true,maps:get(<<"earthling">>,MapOut))}
  -%% -         , {"json",?_assertEqual(981, ?MODULE:get(<<"age">>,JsonOut))}
  -%% -         , {"json",?_assertEqual(true,?MODULE:get(<<"earthling">>,JsonOut))}
  -%% -        ]}.
  -%% - 
  -%% - include_test_() ->
  -%% -     Json_Ok = <<"{\"name\":\"John\"}">>,
  -%% -     Prop_Ok = [{<<"surname">>,<<"Doe">>},{<<"foo">>,<<"bar">>}],
  -%% -     Map_Ok = #{<<"earthling">> => true, <<"age">> => 981},
  -%% -     {inparallel
  -%% -      , [{"proplist"
  -%% -          , ?_assertEqual(Prop_Ok
  -%% -                         , include([<<"surname">>,<<"foo">>],?TEST_PROP))}
  -%% -         , {"map"
  -%% -            , ?_assertEqual(Map_Ok
  -%% -                            , include([<<"earthling">>,<<"age">>],?TEST_MAP))}
  -%% -         , {"json", ?_assertEqual(Json_Ok, include([<<"name">>],?TEST_JSON))}
  -%% -        ]}.
  -%% - 
  -%% - exclude_test_() ->
  -%% -     Json_Ok = <<"{\"name\":\"John\"}">>,
  -%% -     Prop_Ok = [{<<"name">>,<<"John">>}],
  -%% -     Map_Ok = #{<<"name">> => <<"John">>},
  -%% -     ExcFields = [<<"surname">>,<<"foo">>,<<"earthling">>,<<"age">>,<<"empty">>],
  -%% -     {inparallel
  -%% -      , [{"proplist",?_assertEqual(Prop_Ok, exclude(ExcFields,?TEST_PROP))}
  -%% -         , {"map",?_assertEqual(Map_Ok, exclude(ExcFields,?TEST_MAP))}
  -%% -         , {"json",?_assertEqual(Json_Ok, exclude(ExcFields,?TEST_JSON))}]}.
  -%% - 
  -%% - merge_test_() ->
  -%% -     Json_1 = <<"{\"test\":\"true\"}">>,
  -%% -     Prop_1 = [{<<"test">>,<<"true">>}],
  -%% -     Map_1 = #{<<"test">> => <<"true">>},
  -%% -     JsonOut = merge(Json_1,?TEST_JSON),
  -%% -     PropOut = merge(Prop_1,?TEST_PROP),
  -%% -     MapOut = merge(Map_1,?TEST_MAP),
  -%% -     {inparallel
  -%% -      , [{"proplist"
  -%% -          , ?_assertEqual(<<"true">>, ?MODULE:get(<<"test">>,PropOut))}
  -%% -         , {"proplist"
  -%% -            , ?_assertEqual(<<"Doe">>, ?MODULE:get(<<"surname">>,PropOut))}
  -%% -         , {"map"
  -%% -            , ?_assertEqual(<<"true">>, ?MODULE:get(<<"test">>,MapOut))}
  -%% -         , {"map"
  -%% -            , ?_assertEqual(<<"Doe">>, ?MODULE:get(<<"surname">>,MapOut))}
  -%% -         , {"json"
  -%% -            , ?_assertEqual(<<"true">>, ?MODULE:get(<<"test">>,JsonOut))}
  -%% -         , {"json"
  -%% -            , ?_assertEqual(<<"Doe">>, ?MODULE:get(<<"surname">>,JsonOut))}
  -%% -        ]}.
  -%% - 
  -%% - project_test_() ->
  -%% -     Data1 = <<"{\"name\":{\"first\":false,\"list\":[{\"any\":1}]}, \"test\":true}">>,
  -%% -     Data2 = <<"{\"list\":[{\"any\":{\"sub\":true}},{\"any\":{\"sub\":false}}],\"empty\":[]}">>,
  -%% -     {inparallel
  -%% -      , [?_assertEqual([1],project("name:list[*]:any",Data1))
  -%% -         , ?_assertEqual(true,project("test",Data1))
  -%% -         , ?_assertEqual(false,project("name:first",Data1))
  -%% -         , ?_assertEqual([[1],true]
  -%% -                         , project(["name:list[*]:any","test"],Data1))
  -%% -         , ?_assertEqual([true,false],project("list[*]:any:sub",Data2))
  -%% -         , ?_assertEqual(true,project("list[1]:any:sub",Data2))
  -%% -         , ?_assertEqual([<<"first">>,<<"list">>]
  -%% -                         , project("name:$keys$",Data1))
  -%% -         , ?_assertEqual([[<<"first">>,<<"list">>],[1],false]
  -%% -                         , project(["name:$keys$", "name:list[*]:any"
  -%% -                                    , "name:first"],Data1))
  -%% -         , ?_assertEqual(nomatch, project(["name:$keys$", "name:list[*]:any"
  -%% -                                           , "name:not_there"],Data1))
  -%% -         , ?_assertEqual(nomatch,project("list[10]:any:sub",Data2))
  -%% -         , ?_assertEqual(nomatch,project("unlist[1]:any:sub",Data2))
  -%% -         , ?_assertEqual(nomatch,project("empty[1]",Data2))
  -%% -         , ?_assertEqual(nomatch,project("empty[*]",Data2))
  -%% -         , ?_assertEqual(nomatch,project("unexistant",Data2))
  -%% -         , ?_assertEqual(nomatch,project("unexistant[*]",Data2))
  -%% -     ]}.
  -%% - 
  -%% - diff_test_() ->
  -%% -     PropBefore = [{<<"surname">>,<<"Doe">>}, {<<"age">>,981}
  -%% -                   , {<<"empty">>,null},{<<"unmod">>,true}],
  -%% -     PropAfter  = [{<<"surname">>,<<"DoeDoe">>}, {<<"ega">>,981}
  -%% -                   , {<<"newval">>,<<"one">>}, {<<"empty">>,null}
  -%% -                   , {<<"unmod">>,true}],
  -%% -     PropDiffOut = [{added,[{<<"ega">>,981},{<<"newval">>,<<"one">>}]},
  -%% -                    {removed,[{<<"age">>,981}]},
  -%% -                    {updated,[{<<"surname">>,<<"DoeDoe">>}]},
  -%% -                    {replaced,[{<<"surname">>,<<"Doe">>}]},
  -%% -                    {changes,4}],
  -%% - 
  -%% -     MapsBefore = #{<<"age">> => 981, <<"empty">> => null
  -%% -                    , <<"surname">> => <<"Doe">>,<<"unmod">> => true},
  -%% -     MapsAfter = #{<<"ega">> => 981, <<"empty">> => null
  -%% -                   , <<"newval">> => <<"one">>
  -%% -                   , <<"surname">> => <<"DoeDoe">>, <<"unmod">> => true},
  -%% -     MapsDiffOut = #{added => #{<<"ega">> => 981,<<"newval">> => <<"one">>},
  -%% -                    removed => #{<<"age">> => 981},
  -%% -                    replaced => #{<<"surname">> => <<"Doe">>},
  -%% -                    updated => #{<<"surname">> => <<"DoeDoe">>},
  -%% -                    changes => 4},
  -%% - 
  -%% -     JsonBefore = <<"{\"surname\":\"Doe\",\"age\":981,\"empty\":null}">>,
  -%% -     JsonAfter = <<"{\"surname\":\"DoeDoe\",\"ega\":981,\"newval\":\"one\","
  -%% -                   "\"empty\":null}">>,
  -%% -     JsonDiffOut = <<"{\"added\":{\"ega\":981,\"newval\":\"one\"},\"removed\":"
  -%% -                     "{\"age\":981},\"updated\":{\"surname\":\"DoeDoe\"},"
  -%% -                     "\"replaced\":{\"surname\":\"Doe\"},\"changes\":4}">>,
  -%% -     {inparallel
  -%% -      , [{"proplist",?_assertEqual(PropDiffOut, diff(PropBefore,PropAfter))}
  -%% -         , {"map",?_assertEqual(MapsDiffOut, diff(MapsBefore,MapsAfter))}
  -%% -         , {"json",?_assertEqual(JsonDiffOut, diff(JsonBefore,JsonAfter))}]}.
  -%% - 
  -%% - equal_test_() -> 
  -%% -     Json_Ok = <<"{\"name\":\"John\",\"surname\":\"Doe\",\"foo\":\"bar\","
  -%% -                 "\"earthling\":true,\"age\":981,\"other\":null}">>,
  -%% -     Prop_Ok = [{<<"surname">>,<<"Doe">>},{<<"foo">>,<<"bar">>}
  -%% -                , {<<"earthling">>,true}, {<<"name">>,<<"John">>}
  -%% -                , {<<"age">>,981}],
  -%% -     Map_Ok = #{<<"earthling">> => true, <<"age">> => 981
  -%% -                , <<"name">> => <<"John">>, <<"foo">> => <<"bar">>
  -%% -                , <<"surname">> => <<"Doe">>, <<"empty">> => null},
  -%% -     Json_Nook = <<"{\"name\":\"John\",\"surname\":null,\"foo\":\"bar\","
  -%% -                   "\"earthling\":true,\"age\":981,\"other\":null}">>,
  -%% -     Prop_Nook = [{<<"surname">>,<<"Doe">>},{<<"foo">>,<<"barbara">>}
  -%% -                  , {<<"earthling">>,true}, {<<"name">>,<<"John">>}
  -%% -                  , {<<"age">>,981}],
  -%% -     Map_Nook = #{<<"earthling">> => true, <<"age">> => 981
  -%% -                  , <<"name">> => <<"John">>,  <<"foo">> => <<"bar">>
  -%% -                  , <<"empty">> => null},
  -%% -     {inparallel
  -%% -      , [{"map_success",?_assert(equal(Map_Ok,?TEST_MAP))}
  -%% -         , {"prop_success",?_assert(equal(Prop_Ok,?TEST_PROP))}
  -%% -         , {"json_success",?_assert(equal(Json_Ok,?TEST_JSON))}
  -%% -         , {"map_fail",?_assert(not equal(Map_Nook,?TEST_MAP))}
  -%% -         , {"prop_fail",?_assert(not equal(Prop_Nook,?TEST_PROP))}
  -%% -         , {"json_fail",?_assert(not equal(Json_Nook,?TEST_JSON))}]}.
  -%% - 
  -%% - is_subset_test_() -> 
  -%% -     Sub_Ok_Json =  <<"{\"surname\":\"Doe\",\"age\":981,\"nothing\":null}">>,
  -%% -     Sub_Ok_Prop = [{<<"surname">>,<<"Doe">>}, {<<"age">>,981}
  -%% -                    , {<<"nothing">>,null}],
  -%% -     Sub_Ok_Map  = #{<<"age">> => 981, <<"surname">> => <<"Doe">>
  -%% -                     , <<"nothing">> => null},
  -%% -     Sub_Nook_Json =  <<"{\"suame\":\"Doe\",\"age\":981}">>,
  -%% -     Sub_Nook_Prop = [{<<"surname">>,<<"Doe">>}, {<<"age">>,91}],
  -%% -     Sub_Nook_Map  = #{<<"age">> => 981, <<"surname">> => <<"De">>},
  -%% -     {inparallel
  -%% -      , [{"map_success",?_assert(is_subset(Sub_Ok_Map ,?TEST_MAP))}
  -%% -         , {"proplist_success",?_assert(is_subset(Sub_Ok_Prop,?TEST_PROP))}
  -%% -         , {"json_success",?_assert(is_subset(Sub_Ok_Json,?TEST_JSON))}
  -%% -         , {"map_fail",?_assert(not is_subset(Sub_Nook_Map ,?TEST_MAP))}
  -%% -         , {"proplist_fail"
  -%% -            ,?_assert(not is_subset(Sub_Nook_Prop,?TEST_PROP))}
  -%% -         , {"json_fail",?_assert(not is_subset(Sub_Nook_Json,?TEST_JSON))}]}.
  -%% - 
  -%% - is_disjoint_test_() -> 
  -%% -     Sub_Ok_Json =  <<"{\"suame\":\"Doe\",\"age\":91}">>,
  -%% -     Sub_Ok_Prop = [{<<"surname">>,<<"De">>}, {<<"ae">>,981}],
  -%% -     Sub_Ok_Map  = #{<<"ag">> => 981, <<"surname">> => <<"De">>},
  -%% -     Sub_Nook_Json =  <<"{\"suame\":\"Doe\",\"age\":981}">>,
  -%% -     Sub_Nook_Prop = [{<<"surname">>,<<"Doe">>}, {<<"age">>,981}],
  -%% -     Sub_Nook_Map  = #{<<"age">> => 981, <<"surname">> => <<"De">>},
  -%% -     {inparallel
  -%% -      , [{"map_success",?_assert(is_disjoint(Sub_Ok_Map ,?TEST_MAP))}
  -%% -         , {"proplist_success",?_assert(is_disjoint(Sub_Ok_Prop,?TEST_PROP))}
  -%% -         , {"json_success",?_assert(is_disjoint(Sub_Ok_Json,?TEST_JSON))}
  -%% -         , {"map_fail",?_assert(not is_disjoint(Sub_Nook_Map ,?TEST_MAP))}
  -%% -         , {"proplist_fail"
  -%% -            ,?_assert(not is_disjoint(Sub_Nook_Prop,?TEST_PROP))}
  -%% -         , {"json_fail",?_assert(not is_disjoint(Sub_Nook_Json,?TEST_JSON))}
  -%% -        ]}.
  -
  -%% - to_map_test() ->
  -%% -     ?assertEqual(?TEST_MAP,to_map(?TEST_JSON)).
  -
  -%% - map_test_() -> 
  -%% -     Job = fun(<<"age">>,_) -> 8000;
  -%% -              (_,true) -> false;
  -%% -              (_,V) -> V end,
  -%% -     {inparallel
  -%% -      , [{"proplist"
  -%% -          , ?_assertEqual(8000
  -%% -                          , proplists:get_value(<<"age">>
  -%% -                                                , map(Job,?TEST_PROP)))}
  -%% -         , {"proplist"
  -%% -            , ?_assertEqual(false
  -%% -                            , proplists:get_value(<<"earthling">>
  -%% -                                                  ,map(Job,?TEST_PROP)))}
  -%% -         , {"json"
  -%% -            , ?_assertEqual(8000, ?MODULE:get(<<"age">>
  -%% -                                              , map(Job,?TEST_JSON)))}
  -%% -         , {"json"
  -%% -            , ?_assertEqual(false, ?MODULE:get(<<"earthling">>
  -%% -                                               , map(Job,?TEST_JSON)))}]}.
  -%% - 
  -%% - parse_path_test_() ->
  -%% -     Path1 = "name.list[*].any",
  -%% -     Path2 = <<"name.list[*].any">>,
  -%% -     Path3 = lists:concat(["name",?JSON_PATH_SEPARATOR
  -%% -                           ,"list[*]",?JSON_PATH_SEPARATOR,"any"]),
  -%% -     Res1  = ["name","list[*]","any"],
  -%% -     {inparallel
  -%% -      , [?_assertEqual(Res1,parse_path(Path1,"."))
  -%% -         , ?_assertEqual(Res1,parse_path(Path2,"."))
  -%% -         , ?_assertEqual(Res1,parse_path(Path3))]}.
  -%% - 
  -%% walk_path_test_() ->
  -%%     Path1 = ["name","list[*]","any"],
  -%%     Object1 = [{<<"name">>, [{<<"list">>
  -%%                               , [[{<<"any">>,1}],[{<<"any">>,2}]]}]}],
  -%%     Result1 = [1,2],
  -%%     [?_assertEqual(Result1,walk_path(Path1,Object1))].
   -endif.
  
positive.code: diff([{A,AV}|R1], [{B,BV}|R2], Acc) when A < B ->  diff(R1, [{B,BV}|R2], [{A,[{<<"v1">>,AV},{<<"v2">>,null}]} | Acc]);
  diff([{A,AV}|R1], [{B,null}|R2], Acc) when A > B ->  diff([{A,AV}|R1], R2, Acc);  % missing equals null
  diff([{A,AV}|R1], [{B,BV}|R2], Acc) when A > B ->  diff([{A,AV}|R1], R2, [{B,[{<<"v1">>,null},{<<"v2">>,BV}]} | Acc]).
  
  %% - 
  %% - %% @doc creates a diff data object between the first (old) and second (new) provided data
  %% - %% objects. null values are ignored. Resulting data object will have 5 root keys, each containg
  %% - %% corresponding key/value pairs. Outgoing format is the same as ingoing format.
  %% - %%
  %% - %% added : contains key/value pairs who were in data object 2 but not in data object 1
  %% - %% removed : contains key/value pairs who were in data object 1 but not in data objec 2
  %% - %% updated : containts key/value pairs who are not indentical between data object 1 and 2,
  %% - %%           with the values from data object 2
  %% - %% replaced : containts key/value pairs who are not indentical between data object 1 and 2,
  %% - %%            with the values from data object 1
  %% - -spec diff(data_object(), data_object()) -> diff_object().
  %% - diff(RawDataObject1, Data2) when is_list(RawDataObject1), is_list(RawDataObject2) ->
  %% -     DataObject1 = clean_null_values(RawDataObject1),
  %% -     DataObject2 = clean_null_values(RawDataObject2),
  %% -     Object1Keys = proplists:get_keys(DataObject1),
  %% -     Object2Keys = proplists:get_keys(DataObject2),
  %% -     CommonKeys = lists:filter(fun(K) -> lists:member(K,Object1Keys) end, Object2Keys),
  %% - 
  %% -     UpdatedJob = fun(K,Acc) -> 
  %% -                     case {proplists:get_value(K,DataObject1),
  %% -                           proplists:get_value(K,DataObject2)} of
  %% -                           {__Same,__Same} -> Acc;
  %% -                           {__Old,__New}   -> [{K,__Old,__New} | Acc]
  %% -                     end end,
  %% -     UpdatedTuples = lists:foldl(UpdatedJob,
  %% -                                 [],
  %% -                                 CommonKeys),
  %% - 
  %% -     Added = lists:filter(fun({K,_}) -> lists:member(K,Object1Keys) =:= false end, DataObject2),
  %% -     Removed = lists:filter(fun({K,_}) -> lists:member(K,Object2Keys) =:= false end, DataObject1),
  %% -     Updated = [{K,V} || {K,_,V} <- UpdatedTuples],
  %% -     Replaced = [{K,V} || {K,V,_} <- UpdatedTuples],
  %% - 
  %% -     [{added,Added},
  %% -      {removed,Removed},
  %% -      {updated,Updated},
  %% -      {replaced,Replaced},
  %% -      {changes, length(Added) + length(Removed) + length(Updated)}];
  %% - diff(RawDataObject1, RawDataObject2) when is_map(RawDataObject1), is_map(RawDataObject2) ->
  %% -     DataObject1 = clean_null_values(RawDataObject1),
  %% -     DataObject2 = clean_null_values(RawDataObject2),
  %% - 
  %% -     Object1Keys = maps:keys(DataObject1),
  %% -     Object2Keys = maps:keys(DataObject2),
  %% -     CommonKeys = lists:filter(fun(K) -> lists:member(K,Object1Keys) end, Object2Keys),
  %% - 
  %% -     UpdatedJob = fun(K,Acc) -> 
  %% -                     case {maps:get(K,DataObject1),
  %% -                           maps:get(K,DataObject2)} of
  %% -                           {__Same,__Same} -> Acc;
  %% -                           {__Old,__New}   -> [{K,__Old,__New} | Acc]
  %% -                     end end,
  %% -     UpdatedTuples = lists:foldl(UpdatedJob,
  %% -                                 [],
  %% -                                 CommonKeys),
  %% -     Added = lists:foldl(fun(K,MapIn) -> 
  %% -                          case lists:member(K,Object1Keys) of
  %% -                                 false -> maps:put(K,maps:get(K,DataObject2),MapIn);
  %% -                                 true  -> MapIn
  %% -                          end end,
  %% -                         #{},
  %% -                         Object2Keys),
  %% -     Removed = lists:foldl(fun(K,MapIn) -> 
  %% -                            case lists:member(K,Object2Keys) of
  %% -                                   false -> maps:put(K,maps:get(K,DataObject1),MapIn);
  %% -                                   true  -> MapIn
  %% -                            end end,
  %% -                           #{},
  %% -                           Object1Keys),
  %% -     Updated = lists:foldl(fun({K,_,V},MapIn) -> maps:put(K,V,MapIn) end,
  %% -                           #{},
  %% -                           UpdatedTuples),
  %% -     Replaced = lists:foldl(fun({K,V,_},MapIn) -> maps:put(K,V,MapIn) end,
  %% -                            #{},
  %% -                            UpdatedTuples),
  %% - 
  %% -     #{added => Added,
  %% -       removed => Removed,
  %% -       updated => Updated,
  %% -       replaced => Replaced,
  %% -       changes =>  maps:size(Added) + maps:size(Removed) + maps:size(Updated)};
  %% - diff(DataObject1, DataObject2) ->
  %% -     encode(diff(decode(DataObject1),decode(DataObject2))).
  %% - 
  %% - %% @doc Compare data objects for equality (null values are ignored)
  %% - -spec equal(data_object(), data_object()) -> boolean().
  %% - equal(DataObject1, DataObject2) when is_list(DataObject1), is_list(DataObject2) -> 
  %% -     lists:sort(clean_null_values(DataObject1)) =:= lists:sort(clean_null_values(DataObject2));
  %% - equal(DataObject1, DataObject2) when is_map(DataObject1), is_map(DataObject2) ->
  %% -     clean_null_values(DataObject1) =:= clean_null_values(DataObject2);
  %% - equal(DataObject1, DataObject2) ->
  %% -     equal(decode(DataObject1),decode(DataObject2)).
  %% - 
  %% - 
  %% - %% @doc Returns true when every element of data_object1 is also a member of data_object2, otherwise false.
  %% - -spec is_subset(data_object(), data_object()) -> boolean().
  %% - is_subset(DataObject1, DataObject2) when is_list(DataObject1), is_list(DataObject2) ->
  %% -     Is_Member = fun ({_,null}) -> true;
  %% -                     ({K1,V1}) -> V1 =:= proplists:get_value(K1,DataObject2) end,
  %% -     lists:all(Is_Member,DataObject1);
  %% - is_subset(DataObject1, DataObject2) when is_map(DataObject1), is_map(DataObject2) ->
  %% -     Is_Member = fun(_,_,false) -> false;
  %% -                    (_,null,true) -> true;
  %% -                    (K1,V1,true) -> {ok,V1} =:= maps:find(K1,DataObject2)
  %% -                    end,
  %% -     maps:fold(Is_Member,true,DataObject1);
  %% - is_subset(DataObject1, DataObject2) ->
  %% -     is_subset(decode(DataObject1), decode(DataObject2)).
  %% - 
  %% - 
  %% - %% @doc Returns true when no element of data_object1 is a member of data_object2, otherwise false.
  %% - -spec is_disjoint(data_object(), data_object()) -> boolean().
  %% - is_disjoint(DataObject1, DataObject2) when is_list(DataObject1), is_list(DataObject2) ->
  %% -     Is_Member = fun({K1,V1}) ->
  %% -                     V1 =:= proplists:get_value(K1,DataObject2)
  %% -                     end,
  %% -     not lists:any(Is_Member,DataObject1);
  %% - is_disjoint(DataObject1, DataObject2) when is_map(DataObject1), is_map(DataObject2) ->
  %% -     No_Common_Element = fun(_,_,false) -> false;
  %% -                         (K1,V1,true) -> {ok,V1} =/= maps:find(K1,DataObject2)
  %% -                    end,
  %% -     maps:fold(No_Common_Element,true,DataObject1);
  %% - is_disjoint(DataObject1, DataObject2) ->
  %% -     is_disjoint(decode(DataObject1), decode(DataObject2)).
  %% - 
  %% - %% @doc Projection of a path, or of multiple paths, from a Json nested object.
  %% - %% returns nomatch if path is not found, or if one of the paths is not found.
  %% - %%
  %% - %% Because projection used imem_json primitives, function is format-neutral.
  %% - -spec project(Path,data_object()) -> value() | ListOfValues | nomatch 
  %% -            when Path :: list() | binary(),
  %% -                 ListOfValues :: [value() | ListOfValues].
  %% - project([T|_] = Paths,DataObject) when is_list(T) ->
  %% -     All = [walk_path(parse_path(Path),DataObject) || Path <- Paths],
  %% -     case lists:any(fun(nomatch) -> true; (_) -> false end,All) of
  %% -         true -> nomatch;
  %% -         false -> All
  %% -     end;
  %% - project(Path,DataObject) ->
  %% -     walk_path(parse_path(Path),DataObject).
  %% - 
  %% - %% @doc Tokenizes a path in a series of tokens
  %% - -spec parse_path(Path) -> list()
  %% -             when Path :: list() | binary().
  %% - parse_path(Path)  ->
  %% -     parse_path(Path,?JSON_PATH_SEPARATOR).
  %% - 
  %% - -spec parse_path(Path,list()) -> list()
  %% -             when Path :: list() | binary().
  %% - parse_path(Path,Separator) when is_list(Path) ->
  %% -     string:tokens(Path,Separator);
  %% - parse_path(Path,Separator) when is_binary(Path) ->
  %% -     parse_path(binary_to_list(Path),Separator).
  %% - 
  %% - %% @doc Walks a tokenized path to extract the corresponding values
  %% - -spec walk_path(list(),data_object()) -> value() | ListOfValues | nomatch
  %% -             when ListOfValues :: [value() | ListOfValues].
  %% - walk_path([],LastLevel) -> LastLevel;
  %% - walk_path(["$keys$"],CurrentLevel) ->
  %% -     keys(CurrentLevel);
  %% - walk_path([Filter|Tail],CurrentLevel) ->
  %% -     {ok,Mask} = re:compile("^(.*)\\[([^\\]]+)\\]$"),
  %% -     case re:run(Filter,Mask,[{capture,[2],list}]) of
  %% -         nomatch -> NextLevel = ?MODULE:get(list_to_binary(Filter),CurrentLevel),
  %% -                    case ?MODULE:get(list_to_binary(Filter),CurrentLevel) of
  %% -                     undefined -> nomatch;
  %% -                     NextLevel -> walk_path(Tail,NextLevel)
  %% -                    end;
  %% -         {match,["*"]} -> {match,[Field]} = re:run(Filter,Mask,[{capture,[1],binary}]),
  %% -                          case ?MODULE:get(Field,CurrentLevel) of
  %% -                             undefined -> nomatch;
  %% -                             [] -> nomatch;
  %% -                             NextLevels -> lists:flatten([walk_path(Tail,NextLevel) || 
  %% -                                             NextLevel <- NextLevels])
  %% -                          end;
  %% -         {match,[_lstIndex]} -> {match,[Field]} = re:run(Filter,Mask,[{capture,[1],binary}]),
  %% -                                Index = list_to_integer(_lstIndex),
  %% -                                case ?MODULE:get(Field,CurrentLevel) of
  %% -                                 undefined -> nomatch;
  %% -                                 [] -> nomatch;
  %% -                                 List -> Length = length(List),
  %% -                                         if Index > Length -> nomatch;
  %% -                                            true -> NextLevel = lists:nth(Index,List),
  %% -                                                    walk_path(Tail,NextLevel)
  %% -                                         end
  %% -                                end
  %% -     end.
  
  %% ===================================================================
  %% JSON Binary Handling Power Functions
  %% ===================================================================
  %
  %binary_include(Keys,DataObject) ->
  %    binary_include_walking(walking,DataObject,Keys,<<"">>,{undefined,undefined}).
  %    
  %    binary_include_walking(walking,_,[],<<"">>,_) -> <<"">>;
  %    binary_include_walking(walking,_,[],GroupAcc,_) -> <<GroupAcc/binary,"}">>;
  %    binary_include_walking(walking,<<"">>,_,<<"">>,_) -> <<"">>;
  %    binary_include_walking(walking,<<"">>,_,GroupAcc,_) -> <<GroupAcc/binary,"}">>;
  %
  %    binary_include_walking(walking,<<"{\"",R/binary>>,Keys,<<"">>,_) ->
  %        binary_include_walking(reading_key,R,Keys,<<"">>,{<<"">>,<<"">>});
  %       
  %    binary_include_walking(walking,<<",\"",R/binary>>,Keys,GroupAcc,_) ->
  %        binary_include_walking(reading_key,R,Keys,GroupAcc,{<<"">>,<<"">>});
  %    binary_include_walking(walking,<<_,R/binary>>,Keys,GroupAcc,TAcc) ->
  %        binary_include_walking(walking,R,Keys,GroupAcc,TAcc);
  %
  %    binary_include_walking(reading_key,<<"\":",R/binary>>,Keys,GroupAcc,{KeyAcc,_}) ->
  %        case lists:member(KeyAcc,Keys) of
  %            true -> binary_include_walking(reading_value,R,lists:delete(KeyAcc,Keys),GroupAcc,{KeyAcc,<<"">>});
  %            false -> binary_include_walking(walking,R,Keys,GroupAcc,{undefined,undefined}) end;
  %
  %    binary_include_walking(reading_key,<<H,R/binary>>,Keys,GroupAcc,{KeyAcc,_}) ->
  %        binary_include_walking(reading_key,R,Keys,GroupAcc,{<<KeyAcc/binary,H>>,undefined});
  %
  %    binary_include_walking(reading_value,<<"\"",R/binary>>,Keys,GroupAcc,{KeyAcc,<<"">>}) ->
  %        binary_include_walking(reading_value,R,Keys,GroupAcc,{KeyAcc,<<"">>});
  %    binary_include_walking(reading_value,<<"\"",R/binary>>,Keys,<<"">>,{KeyAcc,ValueAcc}) ->
  %        binary_include_walking(walking,R,Keys,<<"{\"",KeyAcc/binary,"\":\"",ValueAcc/binary,"\"">>,{undefined,undefined});
  %    binary_include_walking(reading_value,<<"\"",R/binary>>,Keys,GroupAcc,{KeyAcc,ValueAcc}) ->
  %        binary_include_walking(walking,R,Keys,<<GroupAcc/binary,",\"",KeyAcc/binary,"\":\"",ValueAcc/binary,"\"">>,{undefined,undefined});
  %    binary_include_walking(reading_value,<<"[",R/binary>>,Keys,<<"">>,{KeyAcc,<<"">>}) ->
  %        {NewR,ValueAcc} = binary_include_walking_catch_list(R,<<"[">>,1),
  %        binary_include_walking(walking,NewR,Keys,<<"{\"",KeyAcc/binary,"\":\"",ValueAcc/binary,"\"">>,{undefined,undefined});
  %    binary_include_walking(reading_value,<<"[",R/binary>>,Keys,GroupAcc,{KeyAcc,<<"">>}) ->
  %        {NewR,ValueAcc} = binary_include_walking_catch_list(R,<<"[">>,1),
  %        binary_include_walking(walking,NewR,Keys,<<GroupAcc/binary,",\"",KeyAcc/binary,"\":\"",ValueAcc/binary,"\"">>,{undefined,undefined});
  %    binary_include_walking(reading_value,<<H,R/binary>>,Keys,GroupAcc,{KeyAcc,ValueAcc}) ->
  %        binary_include_walking(reading_value,R,Keys,GroupAcc,{KeyAcc,<<ValueAcc/binary,H>>}).
  %
  %    binary_include_walking_catch_list(<<"]",R/binary>>,Acc,0) -> {R,<<Acc/binary,"]">>};
  %    binary_include_walking_catch_list(<<"]",R/binary>>,Acc,Level) ->
  %        binary_include_walking_catch_list(R,<<Acc/binary,"]">>,Level-1);
  %    binary_include_walking_catch_list(<<"[",R/binary>>,Acc,Level) ->
  %        binary_include_walking_catch_list(R,<<Acc/binary,"[">>,Level+1);
  %    binary_include_walking_catch_list(<<H,R/binary>>,Acc,Level) ->
  %        binary_include_walking_catch_list(R,<<Acc/binary,H>>,Level).
  %
  
  %% ===================================================================
  %% TESTS
  
negative.code:         Obj ->            
              V = ?MODULE:get(R,Obj),
              if V =:= undefined ->
                     exit({nomatch, {property_not_found, R, Obj}});
                 true ->
                     [{Pt, V} | Binds]
              end
      end;
  