1% ===================================================================
    2% File 'logicmoo_module_aiml_eval.pl'
    3% Purpose: An Implementation in SWI-Prolog of AIML
    4% Maintainer: Douglas Miles
    5% Contact: $Author: dmiles $@users.sourceforge.net ;
    6% Version: 'logicmoo_module_aiml.pl' 1.0.0
    7% Revision:  $Revision: 1.7 $
    8% Revised At:   $Date: 2002/07/11 21:57:28 $
    9% ===================================================================
   10
   11%:-module()
   12%:-include('logicmoo_utils_header.pl'). %<?
   13%:- style_check(-singleton).
   14%%:- style_check(-discontiguous).
   15/*:- if((current_prolog_flag(version,MMmmPP),MMmmPP<70000)).
   16:- style_check(-atom).
   17:- style_check(-string).
   18:- endif.
   19*/

   20
   21:-discontiguous(tag_eval/3).
   22
   23% ===================================================================
   24%  Prolog-like call
   25% ===================================================================
   26
   27aiml_call(Ctx,_ - Calls):- must(nonvar(Calls)), !,aiml_call(Ctx,Calls),!.
   28
   29aiml_call(Ctx,[Atomic|Rest]):- atom(Atomic),!, %%atrace, 
   30            aiml_eval(Ctx,[Atomic|Rest],Output),!,
   31            debugFmt(resultOf(aiml_call(Ctx,[Atomic|Rest]),Output)),!.
   32
   33aiml_call(Ctx,[Atomic|Rest]):- !, %%atrace, 
   34            aiml_eval(Ctx,[Atomic|Rest],Output),!,
   35            debugFmt(resultOf(aiml_call(Ctx,[Atomic|Rest]),Output)),!.
   36
   37% ============================================
   38% Test Suite  
   39% ============================================
   40:-dynamic(unitTestResult/2).
   41aiml_call(Ctx,element('testsuite',ATTRIBS,LIST)):-
   42     withAttributes(Ctx,ATTRIBS,maplist_safe(aiml_call(Ctx),LIST)),
   43     unify_listing(unitTestResult(unit_passed,PRINTRESULT),Passed),
   44     unify_listing(unitTestResult(unit_failed,PRINTRESULT),Failed),
   45     dmsg(testsuite_passed_failed(Passed,Failed)),!.
   46
   47aiml_call(Ctx,Current):- Current=element(TC,ATTRIBS,_LIST), member(TC,['testcase','TestCase']),!,
   48  prolog_must((
   49     attributeValue(Ctx,Current,['name'],Name,'SomeName'),
   50     attributeValue(Ctx,Current,['Input','Pattern'],Input,'ERROR Input'),
   51     attributeValue(Ctx,Current,['Description'],Description,'No Description'),
   52     attributeValue(Ctx,Current,['ExpectedAnswer'],ExpectedAnswer,['noExpectedAnswer']),
   53     findall(ExpectedKeywords0,(attributeValue(Ctx,Current,['ExpectedKeywords'],ExpectedKeywords,['noExpectedKeywords']),
   54                                listify(ExpectedKeywords,ExpectedKeywords0)),ExpectedKeywordsList),
   55     testIt(ATTRIBS,Input,ExpectedAnswer,ExpectedKeywordsList,_Result,Name,Description,Ctx))),!.
   56
   57aiml_call(Ctx,element(A, B, C)):-tagType(A, immediate), prolog_must(nonvar(C)),
   58      convert_name(A,AA),
   59      convert_attributes(Ctx,B,BB),
   60      convert_template(Ctx,C,CC),
   61      (element(A, B, C) \== element(AA, BB, CC)),!,      aiml_call(Ctx,element(AA, BB, C)),!.
   62
   63
   64aiml_call(Ctx,element(A, B, C)):- prolog_must(nonvar(C)),
   65      convert_name(A,AA),
   66      convert_attributes(Ctx,B,BB),
   67      convert_template(Ctx,C,CC),
   68      (element(A, B, C) \== element(AA, BB, CC)),!,atrace,
   69      aiml_call(Ctx,element(AA, BB, C)),!.
   70
   71aiml_call(Ctx,element(Learn, ATTRIBS, Value)):-  member(Learn,[load,learn]),!,
   72 prolog_must((
   73     attributeValue(Ctx,ATTRIBS,[graph],Graph,'$current_value'),
   74     pathAttrib(PathAttrib),
   75     attributeValue(Ctx,ATTRIBS,PathAttrib,Filename,'$value'(Value)),
   76      withAttributes(Ctx,[srcfile=Filename,graph=Graph|ATTRIBS],
   77      load_aiml_files(Ctx,Filename)))).
   78
   79aiml_call(Ctx,Call):- Call \= element(_,_,_), callEachElement(Ctx,Call),!.
   80
   81aiml_call(Ctx,INNER_XML):-aiml_eval(Ctx,INNER_XML,Rendered),!, debugFmt(Rendered),!.
   82
   83aiml_call(Ctx,element(genlmt,TOFROM,_)):-
   84 prolog_must((
   85      attributeValue(Ctx,TOFROM,[to,name],TO,'$error'),
   86      attributeValue(Ctx,TOFROM,[graph,from],FROM,'$current_value'),
   87      immediateCall(Ctx,assertz(genlMtGraph(TO,FROM))))),!.
   88
   89 aiml_call(Ctx,element(Learn, ATTRIBS, Value)):- aiml_error(aiml_call(Ctx,element(Learn, ATTRIBS, Value))),!.
   90
   91
   92% ===================================================================
   93%  Prolog-like call
   94% ===================================================================
   95
   96callEachElement(Ctx,[C|Calls]):-!, callEachElement(Ctx,C),callEachElement(Ctx,Calls).
   97callEachElement(Ctx,element(A,B,C)):- convert_element(Ctx,element(A,B,C),ELE),callEachElement(Ctx,ELE),!.
   98callEachElement(_Ctx,C):-callInteractive(C,_).
   99
  100% ===================================================================
  101%  render templates
  102% ===================================================================
  103
  104aiml_eval_to_unit(Ctx,ValueI,ValueO):-is_list(ValueI),!,aiml_eval_each(Ctx,ValueI,ValueO),!.
  105aiml_eval_to_unit(Ctx,ValueI,ValueO):-aiml_eval0(Ctx,ValueI,ValueO),!.
  106
  107render_value(template,ListOut,Render):-aiml_eval(_Ctx,ListOut,Render),!.
  108
  109aiml_eval_each(Ctx,In,Out):-prolog_must((prolog_mostly_ground(In),var(Out))),aiml_eval_each_l(Ctx,In,Out).
  110aiml_eval_each_l(Ctx,[A|ATTRXML],Output):-aiml_eval0(Ctx,A,R),!,aiml_eval_each_l(Ctx,ATTRXML,RESULT),prolog_must(Output=[R|RESULT]).
  111aiml_eval_each_l(_Ctx,[],[]):-!.
  112
  113aiml_eval(_Ctx,TAGATTRXML,RESULT):- TAGATTRXML == [],!,RESULT=TAGATTRXML.
  114aiml_eval(_Ctx,TAGATTRXML,_RESULT):- prolog_must(nonvar(TAGATTRXML)),fail.
  115aiml_eval(Ctx,TAGATTRXML,RESULT):- 
  116           immediateCall(Ctx,aiml_eval_now(Ctx,TAGATTRXML)),
  117           aiml_eval0(Ctx,TAGATTRXML,RESULT),!.
  118
  119aiml_eval_now(Ctx,TAGATTRXML):-Ctx==[[fctx]],!,aiml_eval_now0(_,TAGATTRXML).
  120aiml_eval_now(Ctx,TAGATTRXML):-aiml_eval_now0(Ctx,TAGATTRXML).
  121aiml_eval_now0(Ctx,TAGATTRXML):-aiml_eval(Ctx,TAGATTRXML,RESULT),!,debugFmt(aiml_eval_now(Ctx,TAGATTRXML,RESULT)).
  122
  123
  124immediateCall(Ctx,:-(Call)):-!,immediateCall0(Ctx,:-(Call)),!.
  125immediateCall(Ctx,Call):-immediateCall0(Ctx,:-(Call)),!.
  126
  127immediateCall0(Ctx,C):-functor(C,call,_),prolog_mustEach((C=..[call,A|Args],A=..L,append(L,Args,Out),Call=..Out,!,immediateCall0(Ctx,Call))).
  128immediateCall0(Ctx,C):-toReadableObject(C,Call),immediateCall1(Ctx,Call),!.
  129%%immediateCall1(_Ctx,C):- prolog_mostly_ground((C)),fail.
  130immediateCall1(_Ctx,_Call):- noConsoleDebug,isConsole,!.
  131immediateCall1(_Ctx,Call):- fresh_line,(format('~q.',[Call])),fresh_line. %%,debugFmt(Call),!.
  132
  133%aiml_eval0(Ctx,[ValueI],ValueO):-atom(ValueI),!,aiml_eval(Ctx,ValueI,ValueO),!.
  134%aiml_eval0(Ctx,[Value|I],ValueO):-atom(Value),atomic_list_concat_aiml([Value|I],' ',ValueI),!,aiml_eval(Ctx,ValueI,ValueO),!.
  135%aiml_eval0(Ctx,ValueI,ValueO):- !,ValueI=ValueO,!.
  136
  137aiml_eval0(Ctx,I,R):- nonvar(R),throw_safe(var(R=aiml_eval0(Ctx,I,R))),!.
  138aiml_eval0(Ctx,_ - Calls,_):- var(Calls),throw_safe(var(Ctx=Calls)),!.
  139
  140aiml_eval0(Ctx,_Num - Msg,Result):-is_list(Msg),!,aiml_eval_each(Ctx,Msg,Result),!.
  141
  142aiml_eval0(Ctx,_Num - Msg,Result):-!,aiml_eval(Ctx,Msg,Result),!.
  143
  144%aiml_evalL(_Ctx,[],[]):-!.
  145%aiml_evalL(Ctx,[Atomic|Rest],[Atomic|Output]):-atomic(Atomic),!,aiml_eval_each(Ctx,Rest,Output),!.
  146
  147aiml_eval0(_Ctx,A,B):-atomic(A),!,B=A.
  148
  149aiml_eval0(Ctx,element(Srai,ATTRIBS,DOIT),RETURN):- memberchk(Srai,[srai,template]),
  150      withAttributes(Ctx,ATTRIBS,
  151         (hotrace((aiml_eval_each(Ctx,DOIT,INNER),
  152          computeAnswer(Ctx,1,element(Srai,ATTRIBS,INNER),RMID,_Votes))))),
  153       RMID=RETURN.
  154
  155aiml_eval0(Ctx,element(A, B, C), XML):-tagType(A, immediate),
  156      convert_name(A,AA),
  157      convert_attributes(Ctx,B,BB),
  158      aiml_eval_each(Ctx,C,CC),
  159      (element(A, B, C) \== element(AA, BB, CC)),!,
  160      aiml_eval(Ctx,element(AA, BB, CC),XML),!.
  161
  162
  163% NEXT aiml_evalL(Ctx,[A|AA], [B|BB]):- aiml_eval(Ctx,A,B),convert_template(Ctx,AA,BB),!.
  164%aiml_eval(Ctx,[A|AA], [B|BB]):- convert_element(Ctx,A,B),aiml_eval(Ctx,AA,BB),!.
  165%%aiml_eval(Ctx,[A|AA], [B|BB]):- convert_element(Ctx,A,B),convert_template(Ctx,AA,BB),!.
  166
  167
  168
  169% ===================================================================
  170%  template tag impl
  171% ===================================================================
  172
  173
  174%aiml_eval(Ctx,INNER_XML,[debugFmt(Rendered)]):-aiml_eval(Ctx,INNER_XML,Rendered),!.
  175
  176
  177% ===================================================================
  178%  MISSING tag impl
  179% ===================================================================
  180%%aiml_eval(Ctx,AIML,[debugFmt(aiml_eval_missing(AIML))]):-!.
  181
  182
  183aiml_eval0(_Ctx,element(In, ATTRIBS, Value),element(In, ATTRIBS, Value)):- preserveTag(In,_Out),!.
  184aiml_eval0(Ctx,element(Learn, ATTRIBS, Value),RESULT):- tag_eval(Ctx,element(Learn, ATTRIBS, Value),RESULT),!.
  185
  186aiml_eval0(Ctx,TAGATTRXML,RESULT):-TAGATTRXML=..[TAG,ATTR,[]],isAimlTag(TAG),!,tag_eval(Ctx,element(TAG,ATTR,[]),RESULT),!.
  187aiml_eval0(Ctx,TAGATTRXML,RESULT):-TAGATTRXML=..[TAG,ATTR,[X|ML]],isAimlTag(TAG),!,tag_eval(Ctx,element(TAG,ATTR,[X|ML]),RESULT),!.
  188
  189aiml_eval0(Ctx,element(In, ATTRIBS, Value),Result):- convert_element(Ctx,element(In, ATTRIBS, Value),Result),!.
  190
  191aiml_eval0(Ctx,element(Learn, ATTRIBS, Value),_):- aiml_error(aiml_eval(Ctx,element(Learn, ATTRIBS, Value))),!.
  192
  193aiml_eval0(_Ctx,RESULT,RESULT):-!.
  194
  195
  196% ===================================================================
  197%  eval tag impl
  198% ===================================================================
  199tag_eval(Ctx,In,Out):-isGenTemplate(Ctx,[]),!,Out=eval(In).
  200
  201tag_eval(Ctx,element(eval,ATTRIBS,INNER_XML),Rendered):-!,
  202   withAttributes(Ctx,ATTRIBS,aiml_eval_each(Ctx,INNER_XML,Rendered)),!.
  203
  204% ===================================================================
  205%  system tag impl
  206% ===================================================================
  207tag_eval(Ctx,I,R):- nonvar(R),throw_safe(var(R=tag_eval(Ctx,I,R))),!.
  208tag_eval(Ctx,_ - Calls,_):- var(Calls),throw_safe(var(tag_eval(Ctx=Calls))),!.
  209
  210tag_eval(Ctx,element(system,ATTRIBS,INNER_XML),Output):-
  211         aiml_eval_each(Ctx,INNER_XML,Rendered),
  212         attributeValue(Ctx,ATTRIBS,[lang],Lang,['bot']),        
  213         systemCall(Ctx,Lang,Rendered,Output),!.
  214
  215
  216systemCall(Ctx,[Lang],Eval,Out):- nonvar(Lang),!, systemCall(Ctx,Lang,Eval,Out).
  217
  218systemCall(_Ctx,_Lang,[],[]):-!.
  219systemCall(Ctx,Lang,[Skipable|REST],DONE):-isWhiteWord(Skipable),!,systemCall(Ctx,Lang,REST,DONE).
  220systemCall(Ctx,Lang,[FIRST|REST],DONE):-atom_concat_safe('@',CMD,FIRST),!,systemCall(Ctx,Lang,[CMD|REST],DONE).
  221systemCall(Ctx,Lang,[FIRST|REST],DONE):-atom_contains(FIRST,' '),atomWSplit(FIRST,CMD),append(CMD,REST,CMDREST),!,systemCall(Ctx,Lang,CMDREST,DONE).
  222systemCall(Ctx,'bot',REST,OUT):-!,prolog_must(systemCall_Bot(Ctx,REST,OUT)),!.
  223systemCall(Ctx,Lang,[Eval],Out):-systemCall(Ctx,Lang,Eval,Out).
  224systemCall(Ctx,Lang,Eval,Out):-once((atom(Eval),atomWSplit(Eval,Atoms))),Atoms=[_,_|_],!,atrace,systemCall(Ctx,Lang,Atoms,Out).
  225systemCall(_Ctx,Lang,Eval,writeq(evaled(Lang,Eval))):- aiml_error(evaled(Lang,Eval)).
  226
  227systemCall_Bot(Ctx,['@'|REST],DONE):-!,systemCall_Bot(Ctx,REST,DONE).
  230systemCall_Bot(Ctx,ALLREST,template([mutiple,DONE1,DONE])):-append([F|IRST],['@'|REST],ALLREST),!,
  231      systemCall_Bot(Ctx,[F|IRST],DONE1),systemCall_Bot(Ctx,REST,DONE).
  232
  233systemCall_Bot(Ctx,[Skipable|REST],DONE):-isWhiteWord(Skipable),!,systemCall_Bot(Ctx,REST,DONE).
  234systemCall_Bot(Ctx,[FIRST|REST],DONE):-atom_concat_safe('@',CMD,FIRST),CMD\=='',!,systemCall_Bot(Ctx,['@',CMD|REST],DONE).
  235systemCall_Bot(_Ctx,['eval'|DONE],template([evaled,DONE])):-!.
  236systemCall_Bot(_Ctx,['echo'|DONE],DONE):-!.
  237systemCall_Bot(Ctx,['set'],template([setted,Ctx])):-!,unify_listing(getUserDicts(_User,_Name,_Value)),!.
  238systemCall_Bot(Ctx,['set',Dict,Name,'='|Value],template([setted,Name,Value])):- setAliceMem(Ctx,Dict,Name,Value),!.
  239systemCall_Bot(Ctx,['set',Name,'='|Value],template([setted,Name,Value])):- setAliceMem(Ctx,'user',Name,Value),!.
  240systemCall_Bot(Ctx,['set',Name|Value],template([setted,Name,Value])):- setAliceMem(Ctx,'user',Name,Value),!.
  241
  242systemCall_Bot(Ctx,['get',Name|MajorMinor],template([getted,Dict,Value,Found1])):- getDictFromAttributes(Ctx,evalsrai,[],SYM),
  243  list_to_set_preserve_order([SYM,user,robot,Name],List),
  244  debugFmt(getIndexedValue(Ctx,List,Name,MajorMinor,values)),
  245  forall(member(Dict,List),ignore((unify_listing(getIndexedValue(Ctx,Dict,Name,MajorMinor,Value),Found),Found>0,Found1=Found))),!.
  246
  247systemCall_Bot(Ctx,['get'],template([getted,Passed])):- unify_listing(getContextStoredValue(Ctx,_,_,_),Passed).
  248systemCall_Bot(Ctx,['ctx'],template([ctxed,Atom])):-!,term_to_atom(Ctx,Atom),!.
  249systemCall_Bot(Ctx,['ctx'],template([ctxed,prologCall(Atom,term_to_atom(Ctx,Atom))])):-!,showCtx(Ctx).
  250systemCall_Bot(Ctx,['load'|REST],OUT):- !, prolog_must(systemCall_Load(Ctx,REST,OUT)),!.
  251systemCall_Bot(Ctx,['find'|REST],OUT):- !, prolog_must(systemCall_Find(Ctx,REST,OUT)),!.
  252systemCall_Bot(Ctx,['chgraph',Graph],['successfully','set','to','graph',Graph]):- setAliceMem(Ctx,user,graph,Graph),!.
  253systemCall_Bot(_Ctx,['substs',DictName],['substsof',DictName]):- unify_listing(dictReplace(DictName,_,_)),!.
  254systemCall_Bot(_Ctx,['substs'],['substsof','all']):- unify_listing(dictReplace(_DictName,_,_)),!.
  255
  256
  257systemCall_Bot(Ctx,['ctxlist'],template([ctxed])):-!,showCtx(Ctx),!.
  258systemCall_Bot(Ctx,['ctxlist'],template([ctxed,current_value(Ctx,Name,Value),Count])):-!,unify_listing(getCtxValue_nd(Ctx,Name,Value),Count),!.
  259
  260
  261
  262
  263systemCall_Bot(Ctx,[FIRST|REST],DONE):-toLowerIfAtom(FIRST,CMD),FIRST\==CMD,!,systemCall_Bot(Ctx,[CMD|REST],DONE).
  264systemCall_Bot(Ctx,List,YN):- append(New,[('.')],List),!,systemCall_Bot(Ctx,New,YN).
  265
  266systemCall_Bot(_Ctx,[prolog],YN):- prolog  -> YN=['Yes.'] ; YN=['No.'].
  267systemCall_Bot(_Ctx,[prolog,Call],YN):- predicate_property(Call,defined),!,call(Call)-> YN=['Yes.'] ; YN=['No.'].
  268systemCall_Bot(_Ctx,DONE,template([delayed,DONE])).
  269
  270showCtx(Ctx):-forall(
  271  (get_ctx_frame_holder(Ctx,Dict,Frame,Held)),
  272  writeq(get_ctx_frame_holder(Ctx,Dict,Frame,Held))).
  273
  274systemCall_Load(Ctx,[],template([loaded,Ctx])):-!.
  275systemCall_Load(Ctx,[File,Name|S],Output):-joinAtoms([File,Name|S],'',Filename),!,systemCall(Ctx,'bot',['load',Filename],Output).
  276systemCall_Load(Ctx,[Filename],template([loaded,Filename])):-
  277    peekNameValue(Ctx,_,graph,GraphI,'$first'(['$current_value','$value'('*')])), 
  278    (GraphI=='*'->Graph=default; Graph=GraphI),
  279    ATTRIBS=[srcfile=Filename,graph=Graph],
  280    gather_aiml_graph(Ctx,ATTRIBS,Graph,Filename,AIML),
  281    warnIf(not(atomic(Graph))),
  282    warnIf(not(atomic(Filename))),
  283    withAttributes(Ctx,ATTRIBS,load_aiml_structure(Ctx,AIML)),!.
  284
  285systemCall_Find(_Ctx,REST,proof(CateSig,REST)):-
  286         findall(U,(member(L,REST),literal_atom(L,U)),UUs),
  287         aimlCateSig(CateSig),
  288         findall(CateSig,
  289             (CateSig,once((term_to_atom(CateSig,Atom),literal_atom(Atom,U1),member(U2,UUs),sub_atom(U1,_,_,_,U2),
  290              debugFmt(CateSig)))),_List),!.
  291
  292% ===================================================================
  293%  learn tag impl
  294% ===================================================================
  295
  296% 0.9 version
  297tag_eval(Ctx,element(Learn, ATTRIBS, EXTRA),[loaded,Filename,via,Learn,into,Graph]/*NEW*/):- 
  298  member(Learn,[load,learn]),
  299 prolog_must((
  300     attributeValue(Ctx,ATTRIBS,[graph],Graph,'$current_value'),
  301     pathAttribS(PathAttribS),
  302     attributeValue(Ctx,ATTRIBS,PathAttribS,Filename,EXTRA),
  303      gather_aiml_graph(Ctx,ATTRIBS,Graph,Filename,MOREXML),
  304      append(EXTRA,MOREXML,NEWXML),      
  305      ATTRIBSNEW=[srcfile=Filename,graph=Graph|ATTRIBS],
  306       NEW = element(aiml,ATTRIBSNEW,NEWXML),  
  307        withAttributes(Ctx,ATTRIBSNEW,
  308            load_aiml_structure(Ctx,NEW)))),!.
  309
  310
  311gather_aiml_graph(Ctx,XML,Graph,Filename,AIML):-
  312 ATTRIBS=[srcfile=Filename,graph=Graph|XML],
  313 withAttributes(Ctx,ATTRIBS,graph_or_file(Ctx,ATTRIBS, Filename, AIML)),!.
  314
  315% ============================================
  316% Test Suite  (now uses aiml_call/2 instead of tag_eval/3)
  317% ============================================
  318:-dynamic(unitTestResult/2).
  319
  320tagIsCall('testsuite').
  321tagIsCall('testcase').
  322tagIsCall('TestCase').
  323
  324tag_eval(Ctx,element(CallTag,ATTRIBS,LIST),prologCall(aiml_call(Ctx,element(CallTag,ATTRIBS,LIST)))):-tagIsCall(CallTag),!.
  325
  326prologCall(Call):-catch(prolog_must(Call),E,debugFmt(failed_prologCall(Call,E))),!.
  327
  328testIt(ATTRIBS,Input,ExpectedAnswer,ExpectedKeywords,Result,Name,Description,Ctx):- 
  329   notrace(ExpectedKeywords==[[noExpectedKeywords]] -> PASSGOAL = sameBinding(Resp,ExpectedAnswer);  PASSGOAL = containsEachBinding(Resp,ExpectedKeywords)),
  331    withAttributes(Ctx,ATTRIBS,(( runUnitTest(alicebotCTX(Ctx,Input,Resp),PASSGOAL,Result),
  332     prolog_must(ground(Resp)),
  333    toReadableObject(testIt(Input,Name,Description,PASSGOAL),PRINTRESULT),
  334    toReadableObject([Result,Name,Description,Input], STORERESULT),
  335    debugFmt(PRINTRESULT)))),flush_output,
  336    once(
  337     contains_term(STORERESULT,unit_failed) ->
  338      (assert(unitTestResult(unit_failed,f(PRINTRESULT,PASSGOAL))), true );
  339      assert(unitTestResult(unit_passed,PRINTRESULT))),!
  339.
  340
  341
  342containsEachBinding(_-Resp,ExpectedList):-!,containsEachBinding(Resp,ExpectedList).
  343containsEachBinding(Resp,ExpectedList):-maplist_safe(containsSubBinding(Resp),ExpectedList).
  344
  345containsSubBinding(X,Y):-hotrace((sameBinding_listify(X,X1),sameBinding_listify(Y,Y1))),!,subList(X1,Y1),!.
  346
  347sameBinding_listify(X,X1):-sameBinding1(X,X0),listify(X0,X1),!.
  348
  349subList(X1,Y1):-append(Y1,_,Y1Opened),!,append(_,Y1Opened,X1),!.
  350
  351
  352tag_eval(_Ctx,element(In, ATTRIBS, Value),element(In, ATTRIBS, Value)):- preserveTag(In,_Out),!.
  353tag_eval(_Ctx,LIST1,LIST2):-debugFmt(tag_eval(LIST1->LIST1)),!,prolog_must(LIST1=LIST2),!.
  354
  355
  356preserveTag(In,Out):- member(Out,['input','description',expectedAnswer,expectedkeywords,'Name']),atomsSameCI(In,Out),!.
  357
  358runUnitTest(Call,Req,Result):-runUnitTest1(Call,Result1),!,runUnitTest2(Req,Result2),!,Result=unit(Result1,Result2),debugFmt(Result),!.
  359
  360runUnitTest1(Req,Result):-hotrace(error_catch((Req-> Result=unit_passed(Req); Result=unit_failed(Req)),E,Result=unit_error(E,Req))).
  361runUnitTest2(Req,Result):-hotrace(error_catch((Req-> Result=unit_passed(Req); Result=unit_failed(Req)),E,Result=unit_error(E,Req))).
  362
  363sameBinding(X,Y):-hotrace((sameBinding1(X,X1),sameBinding1(Y,Y1),!,X1=Y1)),!.
  364
  365sameBinding1(X,X):-var(X),!.
  366sameBinding1(_-X,Y):-nonvar(X),!,sameBinding1(X,Y).
  367sameBinding1(X,Z):- convertToMatchableCS(X,Y),X\==Y,!,sameBinding1(Y,Z).
  368%sameBinding1([A|B],AB):-convertToMatchableCS([A|B],AB),!.
  369sameBinding1(X,X):-!.
  370sameBinding1(X,Y):- balanceBinding(X,Y),!.
  371
  372
  373sameBindingIC(X,Y):-hotrace((sameBinding1(X,X1),convertToMatchable(X1,X2),sameBinding1(Y,Y1),convertToMatchable(Y1,Y2),!,closeEnough1(X2,Y2))),!.
  374
  375closeEnough1(X,Y):-X=Y,!.
  376closeEnough1(X,Y):-X\=[],Y\=[],closeEnough2(X,Y),!.
  377closeEnough2(X,Y):-starMatch(Y,X,_) ; starMatch(X,Y,_).
  378
  379
  380
  381/*
  382sameBindingIC([yes,i,agree],[no,i,dont,agree]).
  383sameBindingIC([yes,i,agree],[*,agree])
  384sameBindingIC([*,agree,*],[yes,i,agree,to]).
  385
  386
  387*/