PXRMFF ;SLC/PKR - Clinical Reminders function finding evaluation. ;05/31/2022
 ;;2.0;CLINICAL REMINDERS;**4,6,11,18,22,24,26,47,42,65**;Feb 04, 2005;Build 438
 ;===========================================
EVAL(DEFARR,FIEVAL) ;Evaluate function findings.
 N ARGLIST,FFIND,FFN,FN,FUN,FUNIND,FUNN,FVALUE,JND
 N LOGIC,LOGVAL,NL,ROUTINE,TEMP
 I '$D(DEFARR(25)) Q
 S FFN="FF"
 F  S FFN=$O(DEFARR(25,FFN)) Q:FFN'["FF"  D
 . K FN
 . S FUNIND=0
 . F  S FUNIND=+$O(DEFARR(25,FFN,5,FUNIND)) Q:FUNIND=0  D
 .. S FUNN=$P(DEFARR(25,FFN,5,FUNIND,0),U,1)
 .. S FUN=$P(DEFARR(25,FFN,5,FUNIND,0),U,2)
 .. S TEMP=^PXRMD(802.4,FUN,0)
 .. S ROUTINE=$P(TEMP,U,2,3)_"(.ARGLIST,.FIEVAL,.FVALUE)"
 .. K ARGLIST
 .. S (JND,NL)=0
 .. F  S JND=+$O(DEFARR(25,FFN,5,FUNIND,20,JND)) Q:JND=0  D
 ... S NL=NL+1
 ... S ARGLIST(NL)=DEFARR(25,FFN,5,FUNIND,20,JND,0)
 .. S ARGLIST(0)=NL
 .. D @ROUTINE
 .. S FN(FUNIND)=FVALUE
 . S LOGIC=$G(DEFARR(25,FFN,10))
 . S LOGIC=$S(LOGIC'="":LOGIC,1:0)
 . S LOGVAL=$$EVALLOG(LOGIC,.FN)
 . S FIEVAL(FFN)=LOGVAL
 . S FIEVAL(FFN,"NUMBER")=$P(FFN,"FF",2)
 . S FIEVAL(FFN,"FINDING")=$G(FUN)_";PXRMD(802.4,"
 . I $G(PXRMDEBG) D
 .. S ^TMP(PXRMPID,$J,"FFDEB",FFN,"DETAIL")=FIEVAL(FFN)_U_$G(DEFARR(25,FFN,3))_U_$$NLOGIC(LOGIC,.FN)
 .. I $G(PXRMFFSS) D SBSDISP(LOGIC,FFN,.FN)
 Q
 ;
 ;===========================================
EVALLOG(LOGIC,FN) ;Evaluate the logic string.
 N DIVBY0,DIVOP,IND,NLOGIC,NODIV,NUMSTACK,OP1,OP1C,OP2,OP2C
 N OPER,OPERS,PFSTACK,RES,TEMP,UNARY
 I LOGIC="" Q 0
 S NODIV=$S(LOGIC["/":0,LOGIC["\":0,LOGIC["#":0,1:1)
 I NODIV Q @LOGIC
 S DIVBY0=0,DIVOP="/\#"
 S OPERS=$$GETOPERS^PXRMFFDB
 S NLOGIC=$$NLOGIC(LOGIC,.FN)
 D POSTFIX^PXRMSTAC(NLOGIC,OPERS,.PFSTACK)
 F IND=1:1:PFSTACK(0) D
 . S TEMP=PFSTACK(IND)
 .;Check for a unary operator.
 . S UNARY=$S(TEMP="+U":1,TEMP="-U":1,TEMP="'U":1,1:0)
 . S OPER=$S(UNARY:$E(TEMP,1),1:TEMP)
 . I OPERS'[OPER D PUSH^PXRMSTAC(.NUMSTACK,TEMP) Q
 .;If control gets to here we have an operator.
 . S OP2=$$POP^PXRMSTAC(.NUMSTACK)
 . S OP2=$$STRCLEAN(OP2)
 . S OP2C=$S(OP2="{NULL}":"",1:OP2)
 . I UNARY S TEMP="S RES="_OPER_"OP2C"
 . I 'UNARY D
 .. S OP1=$$POP^PXRMSTAC(.NUMSTACK)
 .. S OP1=$$STRCLEAN(OP1)
 ..;Flag division by 0 with ~
 .. I DIVOP[OPER,+OP2=0 S DIVBY0=1,TEMP="S RES=""~"""
 .. E  S OP1C=$S(OP1="{NULL}":"",1:OP1),TEMP="S RES=OP1C"_OPER_"OP2C"
 .;Do the math and put the result on the stack. The result of division
 .;by 0 with any operator is 0.
 . I ($G(OP1)="~")!(OP2="~") S RES=0
 . E  X TEMP
 . D PUSH^PXRMSTAC(.NUMSTACK,RES)
 S RES=$$POP^PXRMSTAC(.NUMSTACK)
 I PFSTACK(0)=1 D
 . I @NLOGIC S RES=1
 . E  S RES=0
 Q RES
 ;
 ;===========================================
EVALPL(DEFARR,FFIND,PLIST) ;Build a list of patients based on a function
 ;finding.
 N ARGL,ARGLIST,AT,COUNT,DAS,DATE,DFN
 N FI,FIEVAL,FIEVT,FILIST,FILENUM,FINDPA,FN
 N FUN,FUNCTION,FUNNM,FUNN,FUNNUM,FVALUE
 N IND,ITEM,JND,LOGIC,LNAME,NARG,NFI,NFUN
 N ROUTINE,TEMP,TERMARR,UNIQFIL
 S LOGIC=DEFARR(25,FFIND,10)
 I LOGIC="" Q
 ;Build the list of functions and findings used by the function finding.
 S (FUNNUM,NFUN)=0
 F  S FUNNUM=+$O(DEFARR(25,FFIND,5,FUNNUM)) Q:FUNNUM=0  D
 . S NFUN=NFUN+1
 . S FUNN=$P(DEFARR(25,FFIND,5,FUNNUM,0),U,1)
 . S FUN=$P(DEFARR(25,FFIND,5,FUNNUM,0),U,2)
 . S TEMP=^PXRMD(802.4,FUN,0)
 . S FUN=$P(TEMP,U,1)
 . S FUNCTION(NFUN)=$TR(FUN,"_","")
 . S ROUTINE(NFUN)=$P(TEMP,U,2,3)_"(.ARGL,.FIEVAL,.FVALUE)"
 . S (FI,NARG,NFI)=0
 . F  S FI=+$O(DEFARR(25,FFIND,5,FUNNUM,20,FI)) Q:FI=0  D
 .. S NARG=NARG+1,ARGLIST(NFUN,NARG)=DEFARR(25,FFIND,5,FUNNUM,20,FI,0)
 .. S AT=$$ARGTYPE^PXRMFFAT(FUNCTION(NFUN),FI)
 .. I AT="F" S NFI=NFI+1,FILIST(NFUN,NFI)=ARGLIST(NFUN,NARG)
 . S ARGLIST(NFUN,0)=NARG
 . S FILIST(NFUN,0)=NFI
 ;A finding may be used in more than one function in the function
 ;finding so build a list of the unique findings.
 F IND=1:1:NFUN D
 . F JND=1:1:FILIST(IND,0) D
 .. S TEMP=$P(DEFARR(20,FILIST(IND,JND),0),U,1)
 .. S ITEM=$P(TEMP,";",1)
 .. S FILENUM=$$GETFNUM^PXRMDATA($P(TEMP,";",2))
 .. S UNIQFIL(FILIST(IND,JND))=""
 K ^TMP($J,"PXRMFFDFN")
 S IND=0
 F  S IND=$O(UNIQFIL(IND)) Q:IND=""  D
 . S FINDPA(0)=DEFARR(20,IND,0)
 . S FINDPA(3)=DEFARR(20,IND,3)
 . S FINDPA(10)=DEFARR(20,IND,10)
 . S FINDPA(11)=DEFARR(20,IND,11)
 . D GENTERM^PXRMPLST(FINDPA(0),IND,.TERMARR)
 . S LNAME(IND)="PXRMFF"_IND
 . K ^TMP($J,LNAME(IND))
 . D EVALPL^PXRMTERL(.FINDPA,.TERMARR,LNAME(IND))
 .;Get rid of the false part of the list.
 . K ^TMP($J,LNAME(IND),0)
 .;Build a complete list of patients.
 . S DFN=0
 . F  S DFN=$O(^TMP($J,LNAME(IND),1,DFN)) Q:DFN=""  S ^TMP($J,"PXRMFFDFN",DFN)=""
 ;Evaluate the function finding for each patient. If the function
 ;finding is true then add the patient to PLIST.
 S DFN=0
 F  S DFN=$O(^TMP($J,"PXRMFFDFN",DFN)) Q:DFN=""  D
 . K FIEVAL
 . S IND=""
 . F  S IND=$O(UNIQFIL(IND)) Q:IND=""  D
 .. S FIEVAL(IND)=0
 .. S ITEM=""
 .. F  S ITEM=$O(^TMP($J,LNAME(IND),1,DFN,ITEM)) Q:ITEM=""  D
 ... S COUNT=0
 ... F  S COUNT=$O(^TMP($J,LNAME(IND),1,DFN,ITEM,COUNT)) Q:COUNT=""  D
 .... S FILENUM=$O(^TMP($J,LNAME(IND),1,DFN,ITEM,COUNT,""))
 .... S TEMP=^TMP($J,LNAME(IND),1,DFN,ITEM,COUNT,FILENUM)
 .... S DAS=$P(TEMP,U,1)
 .... S DATE=$P(TEMP,U,2)
 .... K FIEVT
 .... D GETDATA^PXRMDATA(FILENUM,DAS,.FIEVT)
 .... M FIEVAL(IND,COUNT)=FIEVT
 .... S FIEVAL(IND,COUNT,"DATE")=DATE,FIEVAL(IND,COUNT)=1
 .;Save the top level results for each finding.
 . S IND=0
 . F  S IND=$O(FIEVAL(IND)) Q:IND=""  D
 .. K FIEVT M FIEVT=FIEVAL(IND)
 .. S NFI=+$O(FIEVT(""),-1)
 .. D SFRES^PXRMUTIL(-1,NFI,.FIEVT)
 .. K FIEVAL(IND) M FIEVAL(IND)=FIEVT
 .;Evaluate the function finding for this patient.
 . K FN
 . F IND=1:1:NFUN D
 .. K ARGL M ARGL=ARGLIST(IND)
 .. D @ROUTINE(IND)
 .. S FN(IND)=FVALUE
 . I @LOGIC S ^TMP($J,PLIST,1,DFN,1,FFIND)=""
 ;Clean up.
 K ^TMP($J,"PXRMFFDFN")
 S IND=""
 F  S IND=$O(UNIQFIL(IND)) Q:IND=""  K ^TMP($J,LNAME(IND))
 Q
 ;
 ;===========================================
MHVOUT(INDENT,IFIEVAL,NLINES,TEXT) ;Produce the MHV output.
 ;None currently defined.
 Q
 ;
 ;===========================================
NLOGIC(LOGIC,FN) ;Replace the symbols in the logic string with their values.
 N IND,NLOGIC,TEMP
 I LOGIC="" Q 0
 S NLOGIC=LOGIC
 I NLOGIC["$P" S NLOGIC=$$PRP(NLOGIC)
 I $D(PXRMAGE) S NLOGIC=$$STRREP^PXRMUTIL(NLOGIC,"PXRMAGE",PXRMAGE)
 I $D(PXRMDATE) S NLOGIC=$$STRREP^PXRMUTIL(NLOGIC,"PXRMDATE",PXRMDATE)
 I $D(PXRMDOB) S NLOGIC=$$STRREP^PXRMUTIL(NLOGIC,"PXRMDOB",PXRMDOB)
 I $D(PXRMDOD) S NLOGIC=$$STRREP^PXRMUTIL(NLOGIC,"PXRMDOD",PXRMDOD)
 I $D(PXRMLAD) S NLOGIC=$$STRREP^PXRMUTIL(NLOGIC,"PXRMLAD",PXRMLAD)
 I $D(PXRMSEX) S NLOGIC=$$STRREP^PXRMUTIL(NLOGIC,"PXRMSEX",""""_PXRMSEX_"""")
 I $D(PXRMSIG) S NLOGIC=$$STRREP^PXRMUTIL(NLOGIC,"PXRMSIG",""""_PXRMSIG_"""")
 S IND=""
 F  S IND=$O(FN(IND)) Q:IND=""  D
 . S TEMP=$S(FN(IND)="":"{NULL}",1:FN(IND))
 . S NLOGIC=$$STRREP^PXRMUTIL(NLOGIC,"FN("_IND_")",TEMP)
 Q NLOGIC
 ;
 ;===========================================
OUTPUT(INDENT,IFIEVAL,NLINES,TEXT) ;Produce the clinical
 ;maintenance output. None currently defined.
 Q
 ;
 ;===========================================
PRP(LOGIC) ;Process $P in logic.
 N IND,PFSTACK,RES,T1,TEMP
 D POSTFIX^PXRMSTAC(LOGIC,"",.PFSTACK)
 F IND=1:1:PFSTACK(0) D
 . I PFSTACK(IND)'="$P" Q
 . S IND=IND+1,T1=PFSTACK(IND)
 . I T1="FN" S IND=IND+1,T1=T1_"("_PFSTACK(IND)_")",IND=IND+1,T1=T1_PFSTACK(IND)
 . S TEMP="$P("_T1_")"
 . S T1="S RES="_TEMP
 . X T1
 . I RES="" S RES="NULL"
 . S LOGIC=$$STRREP^PXRMUTIL(LOGIC,TEMP,RES)
 Q LOGIC
 ;
 ;===========================================
SBSDISP(LOGIC,FFN,FN) ;Create a step-by-step display of the function finding
 ;evaluation for reminder test.
 I LOGIC="" Q 0
 N DIVOP,IND,NLOGIC,NSTEPS,NUMSTACK,OP1,OP1C,OP1P,OP2,OP2C,OP2P
 N OPER,OPERS,PFSTACK,RES,TEMP,TEXT,UNARY
 S NSTEPS=0
 S DIVOP="/\#"
 S OPERS=$$GETOPERS^PXRMFFDB
 S NLOGIC=$$NLOGIC(LOGIC,.FN)
 K ^TMP("PXRMFFSS",$J,FFN)
 S ^TMP("PXRMFFSS",$J,FFN,0)=NLOGIC
 D POSTFIX^PXRMSTAC(NLOGIC,OPERS,.PFSTACK)
 F IND=1:1:PFSTACK(0) D
 . S TEMP=PFSTACK(IND)
 .;Check for a unary operator.
 . S UNARY=$S(TEMP="+U":1,TEMP="-U":1,TEMP="'U":1,1:0)
 . S OPER=$S(UNARY:$E(TEMP,1),1:TEMP)
 . I OPERS'[OPER D PUSH^PXRMSTAC(.NUMSTACK,TEMP) Q
 .;If control gets to here we have an operator.
 . S OP2=$$POP^PXRMSTAC(.NUMSTACK)
 . S OP2=$$STRCLEAN(OP2)
 . S OP2C=$S(OP2="{NULL}":"",1:OP2)
 . S OP2P=$S(OP2="":"{NULL}",1:OP2)
 . I UNARY S TEMP="S RES="_OPER_"OP2C",TEXT=OPER_OP2P
 . I 'UNARY D
 .. S OP1=$$POP^PXRMSTAC(.NUMSTACK)
 .. S OP1=$$STRCLEAN(OP1)
 ..;Flag division by 0 with ~
 .. I DIVOP[OPER,+OP2=0 S TEMP="S RES=""~""",TEXT="0/0"
 .. E  D
 ... S OP1C=$S(OP1="{NULL}":"",1:OP1)
 ... S OP1P=$S(OP1="":"{NULL}",1:OP1)
 ... S TEMP="S RES=OP1C"_OPER_"OP2C",TEXT=OP1P_OPER_OP2P
 .;Do the math and put the result on the stack. The result of division
 .;by 0 with any operator is 0.
 . I ($G(OP1)="~")!(OP2="~") S RES=0
 . E  X TEMP
 . S NSTEPS=NSTEPS+1
 . S ^TMP("PXRMFFSS",$J,FFN,NSTEPS)=TEXT_"="_RES
 . D PUSH^PXRMSTAC(.NUMSTACK,RES)
 S RES=$$POP^PXRMSTAC(.NUMSTACK)
 I PFSTACK(0)=1 D
 . S RES=$S(NLOGIC:1,1:0)
 . S ^TMP("PXRMFFSS",$J,FFN,1)=PFSTACK(1)_"="_RES
 Q
 ;
 ;===========================================
STRCLEAN(STRING) ;Remove extra quotes from strings.
 I +STRING=STRING Q STRING
 N LEN,QUOTE
 S QUOTE=$C(34)
 S LEN=$L(STRING)
 I ($E(STRING,1)=QUOTE),($E(STRING,LEN)=QUOTE) Q $E(STRING,2,LEN-1)
 Q STRING
 ;
 
--- Routine Detail   --- with STRUCTURED ROUTINE LISTING ---[H[J[2J[HPXRMFF   9577     printed  Sep 23, 2025@19:21:22                                                                                                                                                                                                      Page 2
PXRMFF    ;SLC/PKR - Clinical Reminders function finding evaluation. ;05/31/2022
 +1       ;;2.0;CLINICAL REMINDERS;**4,6,11,18,22,24,26,47,42,65**;Feb 04, 2005;Build 438
 +2       ;===========================================
EVAL(DEFARR,FIEVAL) ;Evaluate function findings.
 +1        NEW ARGLIST,FFIND,FFN,FN,FUN,FUNIND,FUNN,FVALUE,JND
 +2        NEW LOGIC,LOGVAL,NL,ROUTINE,TEMP
 +3        IF '$DATA(DEFARR(25))
               QUIT 
 +4        SET FFN="FF"
 +5        FOR 
               SET FFN=$ORDER(DEFARR(25,FFN))
               if FFN'["FF"
                   QUIT 
               Begin DoDot:1
 +6                KILL FN
 +7                SET FUNIND=0
 +8                FOR 
                       SET FUNIND=+$ORDER(DEFARR(25,FFN,5,FUNIND))
                       if FUNIND=0
                           QUIT 
                       Begin DoDot:2
 +9                        SET FUNN=$PIECE(DEFARR(25,FFN,5,FUNIND,0),U,1)
 +10                       SET FUN=$PIECE(DEFARR(25,FFN,5,FUNIND,0),U,2)
 +11                       SET TEMP=^PXRMD(802.4,FUN,0)
 +12                       SET ROUTINE=$PIECE(TEMP,U,2,3)_"(.ARGLIST,.FIEVAL,.FVALUE)"
 +13                       KILL ARGLIST
 +14                       SET (JND,NL)=0
 +15                       FOR 
                               SET JND=+$ORDER(DEFARR(25,FFN,5,FUNIND,20,JND))
                               if JND=0
                                   QUIT 
                               Begin DoDot:3
 +16                               SET NL=NL+1
 +17                               SET ARGLIST(NL)=DEFARR(25,FFN,5,FUNIND,20,JND,0)
                               End DoDot:3
 +18                       SET ARGLIST(0)=NL
 +19                       DO @ROUTINE
 +20                       SET FN(FUNIND)=FVALUE
                       End DoDot:2
 +21               SET LOGIC=$GET(DEFARR(25,FFN,10))
 +22               SET LOGIC=$SELECT(LOGIC'="":LOGIC,1:0)
 +23               SET LOGVAL=$$EVALLOG(LOGIC,.FN)
 +24               SET FIEVAL(FFN)=LOGVAL
 +25               SET FIEVAL(FFN,"NUMBER")=$PIECE(FFN,"FF",2)
 +26               SET FIEVAL(FFN,"FINDING")=$GET(FUN)_";PXRMD(802.4,"
 +27               IF $GET(PXRMDEBG)
                       Begin DoDot:2
 +28                       SET ^TMP(PXRMPID,$JOB,"FFDEB",FFN,"DETAIL")=FIEVAL(FFN)_U_$GET(DEFARR(25,FFN,3))_U_$$NLOGIC(LOGIC,.FN)
 +29                       IF $GET(PXRMFFSS)
                               DO SBSDISP(LOGIC,FFN,.FN)
                       End DoDot:2
               End DoDot:1
 +30       QUIT 
 +31      ;
 +32      ;===========================================
EVALLOG(LOGIC,FN) ;Evaluate the logic string.
 +1        NEW DIVBY0,DIVOP,IND,NLOGIC,NODIV,NUMSTACK,OP1,OP1C,OP2,OP2C
 +2        NEW OPER,OPERS,PFSTACK,RES,TEMP,UNARY
 +3        IF LOGIC=""
               QUIT 0
 +4        SET NODIV=$SELECT(LOGIC["/":0,LOGIC["\":0,LOGIC["#":0,1:1)
 +5        IF NODIV
               QUIT @LOGIC
 +6        SET DIVBY0=0
           SET DIVOP="/\#"
 +7        SET OPERS=$$GETOPERS^PXRMFFDB
 +8        SET NLOGIC=$$NLOGIC(LOGIC,.FN)
 +9        DO POSTFIX^PXRMSTAC(NLOGIC,OPERS,.PFSTACK)
 +10       FOR IND=1:1:PFSTACK(0)
               Begin DoDot:1
 +11               SET TEMP=PFSTACK(IND)
 +12      ;Check for a unary operator.
 +13               SET UNARY=$SELECT(TEMP="+U":1,TEMP="-U":1,TEMP="'U":1,1:0)
 +14               SET OPER=$SELECT(UNARY:$EXTRACT(TEMP,1),1:TEMP)
 +15               IF OPERS'[OPER
                       DO PUSH^PXRMSTAC(.NUMSTACK,TEMP)
                       QUIT 
 +16      ;If control gets to here we have an operator.
 +17               SET OP2=$$POP^PXRMSTAC(.NUMSTACK)
 +18               SET OP2=$$STRCLEAN(OP2)
 +19               SET OP2C=$SELECT(OP2="{NULL}":"",1:OP2)
 +20               IF UNARY
                       SET TEMP="S RES="_OPER_"OP2C"
 +21               IF 'UNARY
                       Begin DoDot:2
 +22                       SET OP1=$$POP^PXRMSTAC(.NUMSTACK)
 +23                       SET OP1=$$STRCLEAN(OP1)
 +24      ;Flag division by 0 with ~
 +25                       IF DIVOP[OPER
                               IF +OP2=0
                                   SET DIVBY0=1
                                   SET TEMP="S RES=""~"""
 +26                      IF '$TEST
                               SET OP1C=$SELECT(OP1="{NULL}":"",1:OP1)
                               SET TEMP="S RES=OP1C"_OPER_"OP2C"
                       End DoDot:2
 +27      ;Do the math and put the result on the stack. The result of division
 +28      ;by 0 with any operator is 0.
 +29               IF ($GET(OP1)="~")!(OP2="~")
                       SET RES=0
 +30              IF '$TEST
                       XECUTE TEMP
 +31               DO PUSH^PXRMSTAC(.NUMSTACK,RES)
               End DoDot:1
 +32       SET RES=$$POP^PXRMSTAC(.NUMSTACK)
 +33       IF PFSTACK(0)=1
               Begin DoDot:1
 +34               IF @NLOGIC
                       SET RES=1
 +35              IF '$TEST
                       SET RES=0
               End DoDot:1
 +36       QUIT RES
 +37      ;
 +38      ;===========================================
EVALPL(DEFARR,FFIND,PLIST) ;Build a list of patients based on a function
 +1       ;finding.
 +2        NEW ARGL,ARGLIST,AT,COUNT,DAS,DATE,DFN
 +3        NEW FI,FIEVAL,FIEVT,FILIST,FILENUM,FINDPA,FN
 +4        NEW FUN,FUNCTION,FUNNM,FUNN,FUNNUM,FVALUE
 +5        NEW IND,ITEM,JND,LOGIC,LNAME,NARG,NFI,NFUN
 +6        NEW ROUTINE,TEMP,TERMARR,UNIQFIL
 +7        SET LOGIC=DEFARR(25,FFIND,10)
 +8        IF LOGIC=""
               QUIT 
 +9       ;Build the list of functions and findings used by the function finding.
 +10       SET (FUNNUM,NFUN)=0
 +11       FOR 
               SET FUNNUM=+$ORDER(DEFARR(25,FFIND,5,FUNNUM))
               if FUNNUM=0
                   QUIT 
               Begin DoDot:1
 +12               SET NFUN=NFUN+1
 +13               SET FUNN=$PIECE(DEFARR(25,FFIND,5,FUNNUM,0),U,1)
 +14               SET FUN=$PIECE(DEFARR(25,FFIND,5,FUNNUM,0),U,2)
 +15               SET TEMP=^PXRMD(802.4,FUN,0)
 +16               SET FUN=$PIECE(TEMP,U,1)
 +17               SET FUNCTION(NFUN)=$TRANSLATE(FUN,"_","")
 +18               SET ROUTINE(NFUN)=$PIECE(TEMP,U,2,3)_"(.ARGL,.FIEVAL,.FVALUE)"
 +19               SET (FI,NARG,NFI)=0
 +20               FOR 
                       SET FI=+$ORDER(DEFARR(25,FFIND,5,FUNNUM,20,FI))
                       if FI=0
                           QUIT 
                       Begin DoDot:2
 +21                       SET NARG=NARG+1
                           SET ARGLIST(NFUN,NARG)=DEFARR(25,FFIND,5,FUNNUM,20,FI,0)
 +22                       SET AT=$$ARGTYPE^PXRMFFAT(FUNCTION(NFUN),FI)
 +23                       IF AT="F"
                               SET NFI=NFI+1
                               SET FILIST(NFUN,NFI)=ARGLIST(NFUN,NARG)
                       End DoDot:2
 +24               SET ARGLIST(NFUN,0)=NARG
 +25               SET FILIST(NFUN,0)=NFI
               End DoDot:1
 +26      ;A finding may be used in more than one function in the function
 +27      ;finding so build a list of the unique findings.
 +28       FOR IND=1:1:NFUN
               Begin DoDot:1
 +29               FOR JND=1:1:FILIST(IND,0)
                       Begin DoDot:2
 +30                       SET TEMP=$PIECE(DEFARR(20,FILIST(IND,JND),0),U,1)
 +31                       SET ITEM=$PIECE(TEMP,";",1)
 +32                       SET FILENUM=$$GETFNUM^PXRMDATA($PIECE(TEMP,";",2))
 +33                       SET UNIQFIL(FILIST(IND,JND))=""
                       End DoDot:2
               End DoDot:1
 +34       KILL ^TMP($JOB,"PXRMFFDFN")
 +35       SET IND=0
 +36       FOR 
               SET IND=$ORDER(UNIQFIL(IND))
               if IND=""
                   QUIT 
               Begin DoDot:1
 +37               SET FINDPA(0)=DEFARR(20,IND,0)
 +38               SET FINDPA(3)=DEFARR(20,IND,3)
 +39               SET FINDPA(10)=DEFARR(20,IND,10)
 +40               SET FINDPA(11)=DEFARR(20,IND,11)
 +41               DO GENTERM^PXRMPLST(FINDPA(0),IND,.TERMARR)
 +42               SET LNAME(IND)="PXRMFF"_IND
 +43               KILL ^TMP($JOB,LNAME(IND))
 +44               DO EVALPL^PXRMTERL(.FINDPA,.TERMARR,LNAME(IND))
 +45      ;Get rid of the false part of the list.
 +46               KILL ^TMP($JOB,LNAME(IND),0)
 +47      ;Build a complete list of patients.
 +48               SET DFN=0
 +49               FOR 
                       SET DFN=$ORDER(^TMP($JOB,LNAME(IND),1,DFN))
                       if DFN=""
                           QUIT 
                       SET ^TMP($JOB,"PXRMFFDFN",DFN)=""
               End DoDot:1
 +50      ;Evaluate the function finding for each patient. If the function
 +51      ;finding is true then add the patient to PLIST.
 +52       SET DFN=0
 +53       FOR 
               SET DFN=$ORDER(^TMP($JOB,"PXRMFFDFN",DFN))
               if DFN=""
                   QUIT 
               Begin DoDot:1
 +54               KILL FIEVAL
 +55               SET IND=""
 +56               FOR 
                       SET IND=$ORDER(UNIQFIL(IND))
                       if IND=""
                           QUIT 
                       Begin DoDot:2
 +57                       SET FIEVAL(IND)=0
 +58                       SET ITEM=""
 +59                       FOR 
                               SET ITEM=$ORDER(^TMP($JOB,LNAME(IND),1,DFN,ITEM))
                               if ITEM=""
                                   QUIT 
                               Begin DoDot:3
 +60                               SET COUNT=0
 +61                               FOR 
                                       SET COUNT=$ORDER(^TMP($JOB,LNAME(IND),1,DFN,ITEM,COUNT))
                                       if COUNT=""
                                           QUIT 
                                       Begin DoDot:4
 +62                                       SET FILENUM=$ORDER(^TMP($JOB,LNAME(IND),1,DFN,ITEM,COUNT,""))
 +63                                       SET TEMP=^TMP($JOB,LNAME(IND),1,DFN,ITEM,COUNT,FILENUM)
 +64                                       SET DAS=$PIECE(TEMP,U,1)
 +65                                       SET DATE=$PIECE(TEMP,U,2)
 +66                                       KILL FIEVT
 +67                                       DO GETDATA^PXRMDATA(FILENUM,DAS,.FIEVT)
 +68                                       MERGE FIEVAL(IND,COUNT)=FIEVT
 +69                                       SET FIEVAL(IND,COUNT,"DATE")=DATE
                                           SET FIEVAL(IND,COUNT)=1
                                       End DoDot:4
                               End DoDot:3
                       End DoDot:2
 +70      ;Save the top level results for each finding.
 +71               SET IND=0
 +72               FOR 
                       SET IND=$ORDER(FIEVAL(IND))
                       if IND=""
                           QUIT 
                       Begin DoDot:2
 +73                       KILL FIEVT
                           MERGE FIEVT=FIEVAL(IND)
 +74                       SET NFI=+$ORDER(FIEVT(""),-1)
 +75                       DO SFRES^PXRMUTIL(-1,NFI,.FIEVT)
 +76                       KILL FIEVAL(IND)
                           MERGE FIEVAL(IND)=FIEVT
                       End DoDot:2
 +77      ;Evaluate the function finding for this patient.
 +78               KILL FN
 +79               FOR IND=1:1:NFUN
                       Begin DoDot:2
 +80                       KILL ARGL
                           MERGE ARGL=ARGLIST(IND)
 +81                       DO @ROUTINE(IND)
 +82                       SET FN(IND)=FVALUE
                       End DoDot:2
 +83               IF @LOGIC
                       SET ^TMP($JOB,PLIST,1,DFN,1,FFIND)=""
               End DoDot:1
 +84      ;Clean up.
 +85       KILL ^TMP($JOB,"PXRMFFDFN")
 +86       SET IND=""
 +87       FOR 
               SET IND=$ORDER(UNIQFIL(IND))
               if IND=""
                   QUIT 
               KILL ^TMP($JOB,LNAME(IND))
 +88       QUIT 
 +89      ;
 +90      ;===========================================
MHVOUT(INDENT,IFIEVAL,NLINES,TEXT) ;Produce the MHV output.
 +1       ;None currently defined.
 +2        QUIT 
 +3       ;
 +4       ;===========================================
NLOGIC(LOGIC,FN) ;Replace the symbols in the logic string with their values.
 +1        NEW IND,NLOGIC,TEMP
 +2        IF LOGIC=""
               QUIT 0
 +3        SET NLOGIC=LOGIC
 +4        IF NLOGIC["$P"
               SET NLOGIC=$$PRP(NLOGIC)
 +5        IF $DATA(PXRMAGE)
               SET NLOGIC=$$STRREP^PXRMUTIL(NLOGIC,"PXRMAGE",PXRMAGE)
 +6        IF $DATA(PXRMDATE)
               SET NLOGIC=$$STRREP^PXRMUTIL(NLOGIC,"PXRMDATE",PXRMDATE)
 +7        IF $DATA(PXRMDOB)
               SET NLOGIC=$$STRREP^PXRMUTIL(NLOGIC,"PXRMDOB",PXRMDOB)
 +8        IF $DATA(PXRMDOD)
               SET NLOGIC=$$STRREP^PXRMUTIL(NLOGIC,"PXRMDOD",PXRMDOD)
 +9        IF $DATA(PXRMLAD)
               SET NLOGIC=$$STRREP^PXRMUTIL(NLOGIC,"PXRMLAD",PXRMLAD)
 +10       IF $DATA(PXRMSEX)
               SET NLOGIC=$$STRREP^PXRMUTIL(NLOGIC,"PXRMSEX",""""_PXRMSEX_"""")
 +11       IF $DATA(PXRMSIG)
               SET NLOGIC=$$STRREP^PXRMUTIL(NLOGIC,"PXRMSIG",""""_PXRMSIG_"""")
 +12       SET IND=""
 +13       FOR 
               SET IND=$ORDER(FN(IND))
               if IND=""
                   QUIT 
               Begin DoDot:1
 +14               SET TEMP=$SELECT(FN(IND)="":"{NULL}",1:FN(IND))
 +15               SET NLOGIC=$$STRREP^PXRMUTIL(NLOGIC,"FN("_IND_")",TEMP)
               End DoDot:1
 +16       QUIT NLOGIC
 +17      ;
 +18      ;===========================================
OUTPUT(INDENT,IFIEVAL,NLINES,TEXT) ;Produce the clinical
 +1       ;maintenance output. None currently defined.
 +2        QUIT 
 +3       ;
 +4       ;===========================================
PRP(LOGIC) ;Process $P in logic.
 +1        NEW IND,PFSTACK,RES,T1,TEMP
 +2        DO POSTFIX^PXRMSTAC(LOGIC,"",.PFSTACK)
 +3        FOR IND=1:1:PFSTACK(0)
               Begin DoDot:1
 +4                IF PFSTACK(IND)'="$P"
                       QUIT 
 +5                SET IND=IND+1
                   SET T1=PFSTACK(IND)
 +6                IF T1="FN"
                       SET IND=IND+1
                       SET T1=T1_"("_PFSTACK(IND)_")"
                       SET IND=IND+1
                       SET T1=T1_PFSTACK(IND)
 +7                SET TEMP="$P("_T1_")"
 +8                SET T1="S RES="_TEMP
 +9                XECUTE T1
 +10               IF RES=""
                       SET RES="NULL"
 +11               SET LOGIC=$$STRREP^PXRMUTIL(LOGIC,TEMP,RES)
               End DoDot:1
 +12       QUIT LOGIC
 +13      ;
 +14      ;===========================================
SBSDISP(LOGIC,FFN,FN) ;Create a step-by-step display of the function finding
 +1       ;evaluation for reminder test.
 +2        IF LOGIC=""
               QUIT 0
 +3        NEW DIVOP,IND,NLOGIC,NSTEPS,NUMSTACK,OP1,OP1C,OP1P,OP2,OP2C,OP2P
 +4        NEW OPER,OPERS,PFSTACK,RES,TEMP,TEXT,UNARY
 +5        SET NSTEPS=0
 +6        SET DIVOP="/\#"
 +7        SET OPERS=$$GETOPERS^PXRMFFDB
 +8        SET NLOGIC=$$NLOGIC(LOGIC,.FN)
 +9        KILL ^TMP("PXRMFFSS",$JOB,FFN)
 +10       SET ^TMP("PXRMFFSS",$JOB,FFN,0)=NLOGIC
 +11       DO POSTFIX^PXRMSTAC(NLOGIC,OPERS,.PFSTACK)
 +12       FOR IND=1:1:PFSTACK(0)
               Begin DoDot:1
 +13               SET TEMP=PFSTACK(IND)
 +14      ;Check for a unary operator.
 +15               SET UNARY=$SELECT(TEMP="+U":1,TEMP="-U":1,TEMP="'U":1,1:0)
 +16               SET OPER=$SELECT(UNARY:$EXTRACT(TEMP,1),1:TEMP)
 +17               IF OPERS'[OPER
                       DO PUSH^PXRMSTAC(.NUMSTACK,TEMP)
                       QUIT 
 +18      ;If control gets to here we have an operator.
 +19               SET OP2=$$POP^PXRMSTAC(.NUMSTACK)
 +20               SET OP2=$$STRCLEAN(OP2)
 +21               SET OP2C=$SELECT(OP2="{NULL}":"",1:OP2)
 +22               SET OP2P=$SELECT(OP2="":"{NULL}",1:OP2)
 +23               IF UNARY
                       SET TEMP="S RES="_OPER_"OP2C"
                       SET TEXT=OPER_OP2P
 +24               IF 'UNARY
                       Begin DoDot:2
 +25                       SET OP1=$$POP^PXRMSTAC(.NUMSTACK)
 +26                       SET OP1=$$STRCLEAN(OP1)
 +27      ;Flag division by 0 with ~
 +28                       IF DIVOP[OPER
                               IF +OP2=0
                                   SET TEMP="S RES=""~"""
                                   SET TEXT="0/0"
 +29                      IF '$TEST
                               Begin DoDot:3
 +30                               SET OP1C=$SELECT(OP1="{NULL}":"",1:OP1)
 +31                               SET OP1P=$SELECT(OP1="":"{NULL}",1:OP1)
 +32                               SET TEMP="S RES=OP1C"_OPER_"OP2C"
                                   SET TEXT=OP1P_OPER_OP2P
                               End DoDot:3
                       End DoDot:2
 +33      ;Do the math and put the result on the stack. The result of division
 +34      ;by 0 with any operator is 0.
 +35               IF ($GET(OP1)="~")!(OP2="~")
                       SET RES=0
 +36              IF '$TEST
                       XECUTE TEMP
 +37               SET NSTEPS=NSTEPS+1
 +38               SET ^TMP("PXRMFFSS",$JOB,FFN,NSTEPS)=TEXT_"="_RES
 +39               DO PUSH^PXRMSTAC(.NUMSTACK,RES)
               End DoDot:1
 +40       SET RES=$$POP^PXRMSTAC(.NUMSTACK)
 +41       IF PFSTACK(0)=1
               Begin DoDot:1
 +42               SET RES=$SELECT(NLOGIC:1,1:0)
 +43               SET ^TMP("PXRMFFSS",$JOB,FFN,1)=PFSTACK(1)_"="_RES
               End DoDot:1
 +44       QUIT 
 +45      ;
 +46      ;===========================================
STRCLEAN(STRING) ;Remove extra quotes from strings.
 +1        IF +STRING=STRING
               QUIT STRING
 +2        NEW LEN,QUOTE
 +3        SET QUOTE=$CHAR(34)
 +4        SET LEN=$LENGTH(STRING)
 +5        IF ($EXTRACT(STRING,1)=QUOTE)
               IF ($EXTRACT(STRING,LEN)=QUOTE)
                   QUIT $EXTRACT(STRING,2,LEN-1)
 +6        QUIT STRING
 +7       ;