***************************************************************************************************
*                                           PROGRAM OVERVIEW
****************************************************************************************************
*
* PROGRAM: ms_cidanum.sas  
* Created (mm/dd/yyyy): 12/19/2014
*
*--------------------------------------------------------------------------------------------------
* PURPOSE:
*   This macro will compute the numerators for each cohort and call many other macros:
*   - creating the denominators 
*   - creating output tables
*   - performing multiple cohort analyses (PSA/Covariate stratification, Multiple Events, Concomitant Use, Overlap, Tree Extraction) 
*   
*  Program inputs:   
*   -infolder.&MONITORINGFILE.
*   -infolder.&USERSTRATA.
*   -infolder.&COMBOFILE.
*   -infolder.&COHORTFILE.
*   -infolder.&COHORTCODES.
*   -infolder.&INCLUSIONCODES. 
*   -infolder.&STOCKPILINGFILE.
*   -infolder.&ZIPFILE.
*   -infolder.&TYPE1FILE.
*   -infolder.&TYPE2FILE.
*   -infolder.&TYPE3FILE.
*   -infolder.&TYPE4FILE.
*   -infolder.&MODPREGDUR. 
*   -infolder.&TYPE5FILE.
*   -infolder.&TYPE6FILE. 
*   -infolder.&METADATAFILE.
*   -infolder.&COVARIATECODES. 
*   -infolder.&UTILFILE. 
*   -infolder.&COMORBFILE.
*   -infolder.&DRUGCLASSFILE.
*   -infolder.&MFUFILE.
*   -infolder.&MULTEVENTFILE. 
*   -infolder.&MULTEVENTFILE_ADHERE. 
*   -infolder.&CONCFILE. 
*   -infolder.&OVERLAPFILE. 
*   -infolder.&OVERLAPFILE_ADHERE. 
*   -infolder.&ITSFILE. 
*   -infolder.&TREATMENTPATHWAYS. 
*   -infolder.&MICOHORTFILE.
*   -infolder.&TREEFILE.
*   -infolder.&TREELOOKUP.
*   -infolder.&ICD10ICD9MAP.
*   -infolder.&PSESTIMATIONFILE.
*   -infolder.&PSMATCHFILE.
*   -infolder.&STRATIFICATIONFILE.
*   -infolder.&COVSTRATFILE.   
*   -infolder.&IPTWFILE.
*   -infolder.&PSCSSUBGROUPFILE.
*
*                                     
*  Program outputs:       
*   -Numerous dplocal and msoc datasets
*                                                                                                  
*  PARAMETERS:  
*
*   -RUNID                  = Run identifier to denote each execution of the program
*   -PROJID                 = SOC-defined value  
*   -WPTYPE                 = SOC-defined value
*   -WPID                   = SOC-defined value
*   -DPID                   = SOC-defined value
*   -VERID                  = SOC-defined value
*   -PERIODIDSTART          = Starting PERIODID from the MONITORINGFILE
*   -PERIODIDEND            = Ending PERIODID from the MONITORINGFILE
*   -ANALYSIS               = Indicates whether to perform tree extraction
*   -MONITORNGFILE          = Name of the SAS dataset that defines the relevant query periods for execution
*   -USERSTRATA             = Name of the SAS dataset that defines the stratifications to return in the MSOC folder
*   -COMBOFILE              = Name of the SAS dataset that will be used to create combination items. 
*                             When this parameter is specified, "CODES" input files is required, and "STOCK" is optional
*   -COHORTFILE             = Name of the SAS dataset that defines how the cohort should be created (gaps, coverage,...)
*   -COHORTCODES            = Name of the SAS dataset that includes the codes defining the cohort 
*   -INCLUSIONCODES         = Name of the SAS dataset that includes the codes defining inclusions/exclusions
*   -STOCKPILINGFILE        = Name of the SAS dataset that defines how the stockpiling algorithm should be performed
*   -RUN_ENVELOPE           = Indicates if the envelope macro should include Adate or be turned off entirely
*   -FREEZEDATA             = Indicates if SDD patient data should be copied to DPLocal
*   -ZIPFILE                = Name of the SAS dataset that contains list of valid zip to geographical area mappings
*   -LABSCODEMAP            = Name of the SAS dataset that contains laboratory matching information
*   -DISTINDEX              = Indicates if distribution of index defining codes should be output to MSOC folder
*   -TYPE1FILE              = Name of the SAS dataset that defines type 1 cohort parameters (washouts, cohortdef, ...)
*   -TYPE2FILE              = Name of the SAS dataset that defines type 2 cohort parameters (washouts, cohortdef, ...)
*   -TYPE3FILE              = Name of the SAS dataset that defines type 3 cohort parameters (washouts, cohortdef, ...)
*   -TYPE4FILE              = Name of the SAS dataset that defines type 4 cohort parameters (washouts, cohortdef, ...)
*   -MODPREGDUR             = Name of the SAS dataset that contains pregnacy duration delivery codes for type 4 analysis  
*   -TYPE5FILE              = Name of the SAS dataset that defines type 5 cohort parameters (washouts, cohortdef, ...)
*   -TYPE6FILE              = Name of the SAS dataset that defines type 6 cohort parameters (washouts, cohortdef, ...)
*   -METADATAFILE           = Name of the SAS dataset that defines the metadata generated for each time period request for sequential analysis
*   -SURVEILLANCEMODE       = Indicates if the module should be executed in suveilance mode and which type
*   -COVARIATECODES         = Name of the SAS dataset that includes the codes associated with covariate exctraction
*   -UTILFILE               = Name of the SAS dataset that defines how medical and drug utilization metrics should be calculated
*   -COMORBFILE             = Name of the SAS dataset that defines how CCI/Elixhauser Combined Comorbdity Score should be calculated
*   -DRUGCLASSFILE          = Name of the SAS dataset that lists NDCs by generic and class names and allows 
*                             the program to count the number of distinct generic names and class names
*   -PROFILE                = Indicates if a covariate profile file should be produced
*   -MFUFILE                = Name of the SAS dataset that defines how MFU analysis should be performed
*   -MULTEVENTFILE          = Name of the SAS dataset that defines how a multiple events analysis should be performed
*   -MULTEVENTFILE_ADHERE   = Name of the SAS dataset that defines how adherence is calculated for a multiple events analysis
*   -CONCFILE               = Name of the SAS dataset that defines how concomitant episodes should be created and evaluated
*   -OVERLAPFILE            = Name of the SAS dataset that defines how secondary episode overlap of primary episodes should be evaluated 
*   -OVERLAPFILE_ADHERE     = Name of the SAS dataset that defines how adherence is calculated for a overlapping episodes analysis
*   -ITSFILE                = Name of the SAS dataset that defines parameters for an Interupted Time Series (ITS) analysis
*   -TREATMENTPATHWAYS      = Name of the SAS dataset that defines how the switching module should be performed
*   -MICOHORTFILE           = Name of the SAS dataset that defines how Type 4 PSA/Mother-Infant cohorts will be created
*   -TREEFILE               = Name of the SAS dataset that defines parameters for tree extraction 
*   -TREELOOKUP             = Name of the SAS dataset that defines the parent-child nodes for tree extraction
*   -ICD10ICD9MAP           = Name of the SAS dataset that maps ICD 9 to ICD 10 codes
*   -HDVARSEL_INPUT         = For requests calculating a HDPS, lists each data dimension dataset  
*   -PSESTIMATIONFILE       = Name of the SAS dataset describing parameters for estimating a PS model
*   -PSMATCHFILE            = Name of the SAS dataset describing parameters for a PS Matching analysis
*   -STRATIFICATIONFILE     = Name of the SAS dataset describing parameters for a PS stratification analyses
*   -COVSTRATFILE           = Name of the SAS dataset describing parameters for a covariate stratification analyses
*   -IPTWFILE               = Name of the SAS dataset describing parameters for Inverse Probability Treatment Weight(IPTW) analyses
*   -PSCSSUBGROUPFILE       = Name of the SAS dataset describing parameters for subgroups within the PS/CS submodule
*   -INDLEVEL               = Indicates whether to return an individual level file after PS or Covariate Stratification analysis in the MSOC folder
*   -DIAGNOSTICS            = Indicates if proc logistic diagnostic output files should be generated
*
*
*  Programming Notes:                                                                                
*                                                                           
*
*--------------------------------------------------------------------------------------------------
* CONTACT INFO: 
*  Sentinel Coordinating Center
*  info@sentinelsystem.org
*
**********************************************************************************************************************************************;

%macro ms_cidanum(RUNID=,
                  PROJID=,  
                  WPTYPE=,
                  WPID=,
                  DPID=,
                  VERID=,
                  PERIODIDSTART=,
                  PERIODIDEND=,
                  ANALYSIS=,
                  MONITORINGFILE=,
                  USERSTRATA=,
                  COMBOFILE=,
                  COHORTFILE=,
                  COHORTCODES=,
                  INCLUSIONCODES=,
                  STOCKPILINGFILE=,
                  RUN_ENVELOPE=,
                  FREEZEDATA=,
                  ZIPFILE=,
                  LABSCODEMAP=,
                  DISTINDEX=,
                  TYPE1FILE=,
                  TYPE2FILE=,
                  TYPE3FILE=,
                  TYPE4FILE=,
                  MODPREGDUR=, 
                  TYPE5FILE=,
                  TYPE6FILE=,
                  METADATAFILE=,
                  SURVEILLANCEMODE=,
                  COVARIATECODES=,
                  UTILFILE=,
                  COMORBFILE=,
                  DRUGCLASSFILE=,
                  PROFILE=,
                  MFUFILE=,
                  MULTEVENTFILE=,
                  MULTEVENTFILE_ADHERE=,
                  CONCFILE=,
                  OVERLAPFILE=,
                  OVERLAPFILE_ADHERE=,
                  ITSFILE=,
                  TREATMENTPATHWAYS=,
                  MICOHORTFILE=,
                  TREEFILE=,
                  TREELOOKUP=,
                  ICD10ICD9MAP=,
                  HDVARSEL_INPUT=,                          
                  PSESTIMATIONFILE= ,
                  PSMATCHFILE=,
                  STRATIFICATIONFILE=,
                  COVSTRATFILE=,
                  IPTWFILE=,
                  PSCSSUBGROUPFILE=,
                  INDLEVEL=,
                  DIAGNOSTICS=);

    %put =====> MACRO CALLED: ms_cidanum ;

    %ms_starttimer(timestart=qrpruntime);

    /*---------------------------------------------------*/
    /*  01 -- Set up variables needed for the run        */
    /*---------------------------------------------------*/
    %LET PROJID=%LOWCASE(&PROJID.);
    %LET WPTYPE=%LOWCASE(&WPTYPE.);
    %LET WPID=%LOWCASE(&WPID.);
    %LET DPID=%LOWCASE(&DPID.);
    %LET VERID=%LOWCASE(&VERID.);
    %LET PERIODIDSTART=%LOWCASE(&PERIODIDSTART.);
    %LET PERIODIDEND=%LOWCASE(&PERIODIDEND.);
    %LET ANALYSIS=%LOWCASE(&ANALYSIS.);
    %LET SURVEILLANCEMODE=%LOWCASE(&SURVEILLANCEMODE.);
    %let PROFILE=%LOWCASE(&PROFILE.);
    %let DISTINDEX=%LOWCASE(&DISTINDEX.);
    %let FREEZEDATA=%LOWCASE(&FREEZEDATA.);

    %LET MONITORINGFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&MONITORINGFILE.), .sas7bdat, %STR())));
    %LET USERSTRATA=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&USERSTRATA.), .sas7bdat, %STR())));
    %LET COHORTFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&COHORTFILE.), .sas7bdat, %STR())));
    %LET TYPE1FILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&TYPE1FILE.), .sas7bdat, %STR())));
    %LET TYPE2FILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&TYPE2FILE.), .sas7bdat, %STR())));
    %LET TYPE3FILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&TYPE3FILE.), .sas7bdat, %STR())));
    %LET TYPE4FILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&TYPE4FILE.), .sas7bdat, %STR())));
    %LET TYPE5FILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&TYPE5FILE.), .sas7bdat, %STR())));
    %LET TYPE6FILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&TYPE6FILE.), .sas7bdat, %STR())));
    %LET METADATAFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&METADATAFILE.), .sas7bdat, %STR())));
    %LET COHORTCODES=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&COHORTCODES.), .sas7bdat, %STR())));
    %LET INCLUSIONCODES=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&INCLUSIONCODES.), .sas7bdat, %STR())));
    %LET COVARIATECODES=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&COVARIATECODES.), .sas7bdat, %STR())));
    %LET MFUFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&MFUFILE.), .sas7bdat, %STR())));
    %LET STOCKPILINGFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&STOCKPILINGFILE.), .sas7bdat, %STR())));
    %LET UTILFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&UTILFILE.), .sas7bdat, %STR())));
    %LET COMORBFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&COMORBFILE.), .sas7bdat, %STR())));
    %LET DRUGCLASSFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&DRUGCLASSFILE.), .sas7bdat, %STR())));
    %LET COMBOFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&COMBOFILE.), .sas7bdat, %STR())));
    %LET MODPREGDUR=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&MODPREGDUR.), .sas7bdat, %STR())));
    %LET ZIPFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&ZIPFILE.), .sas7bdat, %STR())));
    %LET MULTEVENTFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&MULTEVENTFILE.), .sas7bdat, %STR())));
    %LET MULTEVENTFILE_ADHERE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&MULTEVENTFILE_ADHERE.), .sas7bdat, %STR())));
    %LET CONCFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&CONCFILE.), .sas7bdat, %STR())));
    %LET OVERLAPFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&OVERLAPFILE.), .sas7bdat, %STR())));
    %LET OVERLAPFILE_ADHERE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&OVERLAPFILE_ADHERE.), .sas7bdat, %STR())));
    %LET ITSFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&ITSFILE.), .sas7bdat, %STR())));
    %LET TREATMENTPATHWAYS=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&TREATMENTPATHWAYS.), .sas7bdat, %STR())));
    %LET MICOHORTFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&MICOHORTFILE.), .sas7bdat, %STR())));
    %LET TREEFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&TREEFILE.), .sas7bdat, %STR())));
    %LET TREELOOKUP=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&TREELOOKUP.), .sas7bdat, %STR())));
    %LET ICD10ICD9MAP=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&ICD10ICD9MAP.), .sas7bdat, %STR())));
    %let INDLEVEL=%LOWCASE(&INDLEVEL.);
    %let PSESTIMATIONFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&PSESTIMATIONFILE.), .sas7bdat, %STR())));
    %let PSMATCHFLE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&PSMATCHFILE.), .sas7bdat, %STR())));
    %let STRATIFICATIONFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&STRATIFICATIONFILE.), .sas7bdat, %STR())));
    %let IPTWFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&IPTWFILE.), .sas7bdat, %STR())));
    %let PSCSSUBGROUPFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&PSCSSUBGROUPFILE.), .sas7bdat, %STR())));
    %let COVSTRATFILE=%TRIM(%SYSFUNC(TranWrd(%LOWCASE(&COVSTRATFILE.), .sas7bdat, %STR())));
    %let DIAGNOSTICS=%lowcase(&DIAGNOSTICS.);

    /*---------------------------------------------------*/
    /*  02 -- Import input files in SAS format           */
    /*---------------------------------------------------*/

    %IMPORTFILES(var=&MONITORINGFILE.);
    %IMPORTFILES(var=&USERSTRATA.);
    %IMPORTFILES(var=&COHORTFILE.);
    %IMPORTFILES(var=&TYPE1FILE.);
    %IMPORTFILES(var=&TYPE2FILE.);
    %IMPORTFILES(var=&TYPE3FILE.);
    %IMPORTFILES(var=&TYPE4FILE.);
    %IMPORTFILES(var=&TYPE5FILE.);
    %IMPORTFILES(var=&TYPE6FILE.);
    %IMPORTFILES(var=&METADATAFILE.);
    %IMPORTFILES(var=&COHORTCODES.);
    %IMPORTFILES(var=&INCLUSIONCODES.);
    %IMPORTFILES(var=&COVARIATECODES.);
    %IMPORTFILES(var=&MFUFILE.);
    %IMPORTFILES(var=&STOCKPILINGFILE.);
    %IMPORTFILES(var=&UTILFILE.);
    %IMPORTFILES(var=&COMORBFILE.);
    %IMPORTFILES(var=&DRUGCLASSFILE.);
    %IMPORTFILES(var=&COMBOFILE.);
    %IMPORTFILES(var=&DRUGCLASSFILE.);
    %IMPORTFILES(var=&LABSCODEMAP.);
    %IMPORTFILES(var=&PTSTOEXCLUDE.);
    %IMPORTFILES(var=&MODPREGDUR.);
    %IMPORTFILES(var=&ZIPFILE.);
    %IMPORTFILES(var=&MULTEVENTFILE.);
    %IMPORTFILES(var=&MULTEVENTFILE_ADHERE.);
    %IMPORTFILES(var=&CONCFILE.);
    %IMPORTFILES(var=&OVERLAPFILE.);
    %IMPORTFILES(var=&OVERLAPFILE_ADHERE.);
    %IMPORTFILES(var=&ITSFILE.);
    %IMPORTFILES(var=&TREATMENTPATHWAYS.);
    %IMPORTFILES(var=&MICOHORTFILE.);
    %IMPORTFILES(var=&TREEFILE.);
    %IMPORTFILES(var=&TREELOOKUP.);
    %IMPORTFILES(var=&ICD10ICD9MAP.);
    %IMPORTFILES(var=&PSESTIMATIONFILE.);
    %IMPORTFILES(var=&PSMATCHFILE.);
    %IMPORTFILES(var=&STRATIFICATIONFILE.);
    %IMPORTFILES(var=&IPTWFILE.);
    %IMPORTFILES(var=&PSCSSUBGROUPFILE.);
    %IMPORTFILES(var=&COVSTRATFILE.);

    /*---------------------------------------------------*/
    /*  03 - Jump to checkpoint if restarting QRP        */
    /*---------------------------------------------------*/
    
    %if &restartrun = Y %then %do;
        %goto checkpoint;
    %end;

    /*---------------------------------------------------*/
    /*  04 -- Initialize macro variables and             */
    /*        Process input file parameters              */
    /*---------------------------------------------------*/

    *Initialize macro variables;
    %ms_initmacrovariables();

    *Process input files;
    %ms_processinputfiles();

    /*---------------------------------------------------*/
    /*  05 -- Process Ranges "-" and Wilcards "*"        */
    /*        in lookup codes                            */
    /*---------------------------------------------------*/

    %ISDATA(dataset=_diag);
    %IF %EVAL(&NOBS.>=1) %THEN %DO;
        %ms_processwildcards(InFile=_diag, 
                             CodeVar=code, 
                             OutFile=_diag);
    %END;

    /*---------------------------------------------------*/
    /*  06 -- Extract Raw Data and run envelope or       */
    /*        Create combo records (if applicable)       */
    /*---------------------------------------------------*/
    %if %str(&COMBOFILE.) = %str() or %length(&COMBOFILE.) = 0. %then %do;  

       *Programming note:  We are not using caresettingprincipal in the pre-extraction phase because
        typical sensitivity analysis around caresettingprincipal could lead to massive claim duplication;
        /*Procedure extraction*/
       %ms_extractmeds(datafile=indata.&proctable.,
                       datacode=PX ,
                       datacodetype=PX_codetype ,
                       lookfile=_proc, 
                       mindate = &studystartdate.,
                       outfile=worktemp._procextract(keep=PatID ADate EncType PX PX_CodeType));

        proc sort data=worktemp._procextract nodupkey;
        by _all_;
        run;

       *Delete data from patients in DPs &PTSTOEXCLUDE. files; 
       %ms_delpatients(datafile=worktemp._procextract,
                       ptsfile=&PTSTOEXCLUDE.,
                       Outfile=worktemp._procextract);

        /*Diagnosis extraction*/
       %ms_extractmeds(datafile=indata.&diatable.,
                       datacode=DX,
                       datacodetype=DX_codetype,
                       lookfile=_diag, 
                       mindate = &studystartdate.,
                       outfile=worktemp._diagextract(keep = PatID ADate EncType DX DX_CodeType PDX));

        proc sort data=worktemp._diagextract nodupkey;
        by _all_;
        run;

       *Delete data from patients in DPs &PTSTOEXCLUDE. files; 
       %ms_delpatients(datafile=worktemp._diagextract,
                       ptsfile=&PTSTOEXCLUDE.,
                       Outfile=worktemp._diagextract);

        /*Dispensing extraction*/
        *Codes must be unique to avoid claim duplication.;
        proc sort nodupkey data=_ndc;
        by code;
        run;

        %ms_extractdrugs(datafile=indata.&distable.,
                         lookfile=_ndc, 
                         lookvar=code , 
                         mindate = &studystartdate.,
                         outfile=drugs);

        proc sort data=drugs out=worktemp.drugs(where=(RxSup>0 and RxAMt>0)) nodupkey;
        by _all_;
        run;

        proc datasets nowarn noprint lib=work;
            delete drugs;
        quit;

       *Delete data from patients in DPs &PTSTOEXCLUDE. files; 
       %ms_delpatients(datafile=worktemp.drugs,
                       ptsfile=&PTSTOEXCLUDE.,
                       Outfile=worktemp.drugs);
                       
       /*Lab extraction*/
       %ms_extractlabs(datafile=indata.&labtable.,
                       lookfile=_lab, 
                       mindate = &studystartdate.,
                       outfile=worktemp.labextract);

       proc sort data=worktemp.labextract nodupkey;
       by _all_;
       run;

       *Delete data for patients in DPs &PTSTOEXCLUDE. files; 
       %ms_delpatients(datafile=worktemp.labextract,
                       ptsfile=&PTSTOEXCLUDE.,
                       Outfile=worktemp.labextract);   
    %end;
    %else %do;
       *Combo is called using a macro wrapper to preserve the scoping of 
        macro call combo variables (specifically STOCKPILINGFILE);
        %MACRO RUNCOMBO;        
            %let COMBORUN=1;
             %let DXENVEL = 1;
             %let PXENVEL = 1;
            %if %EVAL(&RUN_ENVELOPE. = 2) %then %do;
                %let DXENVEL = 0;
                %let PXENVEL = 0;
            %end;
            %combo(COMBFILE=&COMBOFILE.,
                   CODESFILE=&COMBOFILE.Codes,
                   DXENVEL=&DXENVEL.,
                   PXENVEL=&PXENVEL.,
                   OUTNAME=&RUNID._Combo,
                   STOCKPILING=1,
                   STOCKPILINGFILE=&COMBOFILE.Stock,
                   ENROLGAP=0,
                   LABSCODEMAP=&LABSCODEMAP.,
                   SAVETODPLOCAL=N,
                   PTSTOEXCLUDE=&PTSTOEXCLUDE.);
        %MEND RUNCOMBO;
        %RUNCOMBO;

    %end;

    *Deaths, MI Linkage are not processed by combo tool. Therefore they must be extracted no matter if combo is run;
    *Encounters can optionally be extracted by ms_cidanum outside of combo tool whether or not combo is run;

    /*MI Linkage table extraction*/
    %ms_extractmilinkage(datafile=indata.&miltable.,
                         lookfile=_mil,
                         mindate = &studystartdate.,
                         outfile=worktemp.milextract);

    *Delete data for patients in DPs &PTSTOEXCLUDE. files; 
    %ms_delpatients(datafile=worktemp.milextract,
                    ptsfile=&PTSTOEXCLUDE.,
                    Outfile=worktemp.milextract);     

    /*Encounter table extraction*/
    %ms_extractencounters(datafile=indata.&enctable.,
                         lookfile=_enc,
                         mindate = &studystartdate.,
                         outfileprefix=worktemp.encextract);

    *Delete data for patients in DPs &PTSTOEXCLUDE. files; 
    %if %str("&enctypeextractlist.") ne %str("") %then %do;
        %macro wrapper();
            %local e enc;
            %do e = 1 %to %sysfunc(countw(&enctypeextractlist.));
                %let enc = %scan(&enctypeextractlist., &e.);
                %ms_delpatients(datafile=worktemp.encextract&enc.,
                                ptsfile=&PTSTOEXCLUDE.,
                                Outfile=worktemp.encextract&enc.);     
            %end;
        %mend;
        %wrapper();
    %end;

    * Deaths are not processed by combo tool. Therefore they must be extracted no matter if combo is run;
    %ms_extractdeaths(deathfile=indata.&DEATHTABLE.,					  
                      encounterfile=indata.&enctable.,					  
					  codfile=indata.&CODTABLE.,
					  codlookupfile=_cod,					  
                      deathoutfile=worktemp.deathextract,
					  codoutfile=worktemp.codextract);

    * Delete data for patients in DPs &PTSTOEXCLUDE. files; 
    %ms_delpatients(datafile=worktemp.deathextract,
                    ptsfile=&PTSTOEXCLUDE.,
                    Outfile=worktemp.deathextract); 

	%ms_delpatients(datafile=worktemp.codextract,
                    ptsfile=&PTSTOEXCLUDE.,
                    Outfile=worktemp.codextract);    

    *Combine _diags and _procs for envelope later;
    data worktemp.meds(keep=Patid Adate Code Pdx EncType /*RxSup RxAmt*/ CodeType CodeCat);
      length adate 4 code $&codelength.;
      set worktemp._procextract (in = procex)
          worktemp._diagextract (in = diagex);
      if procex then do;
      code = compress(PX,' .');
      PDX = " ";
      Codetype = PX_codetype;
      CodeCat = "PX";
      end;
      else if diagex then do;
      code = compress(DX,' .');
      Codetype = DX_codetype;
      CodeCat = "DX";
      end;
      *RxSup = 1;
      *RxAmt = 1;
   run;
    * Delete _procextract and _diagextract from worktemp;
	proc datasets nowarn noprint lib=worktemp;
	  delete _procextract _diagextract;
	quit;

    *If meds records not out of combo, run envelope;
    %ISDATA(dataset=worktemp.meds);
    %if (%str(&COMBOFILE.) = %str() or %length(&COMBOFILE.) = 0.) & %EVAL(&NOBS.>=1) & %EVAL(&RUN_ENVELOPE. ne 2) %then %do;    
        %MS_ENVELOPE(INFILE=worktemp.meds,                       /*Name of SAS dataset with diagnosis and/or procedure claims data*/
                     ENCOUNTERINFILE=indata.&ENCTABLE.,         /*Name of SAS dataset with encounter data*/
                     OUTFILE=worktemp.meds);                     /*Name of output file with reclassified claims*/ 
    %end;

    proc datasets library=work nowarn nolist;
    delete _:;
    quit;

    /*---------------------------------------------------*/
    /*  07 -- Reconcile all enrollment spans             */ 
    /*---------------------------------------------------*/

    %ms_create_enrollment_spans();

    /*---------------------------------------------------*/
    /*  08 -- Create worktemp.meds partition             */ 
    /*---------------------------------------------------*/

    *Partitition worktemp.meds if diagnosis or procedure claims are requested in %scenarioloop;	
    %isdata(dataset=worktemp.meds);
    %if %eval(&nobs.>0) %then %do;
    %let partition=N;
    data _null_;
        set &COHORTCODES.(where=(codecat in ('DX','PX') and group in (&cohortgrplist.)));
        if _n_ =1 then call symputx('partition', 'Y');
    run;

    %if &partition.= Y %then %do;
        %ms_partition_patients(datalib =WORKTEMP, 
                               datafile =MEDS, 
                               split_vars =patid,
                               outfile =medspartition);

        /*Number of partitions*/
        proc sql noprint;
            select max(partition) into: nummeds_partitions
            from medspartition;
        quit;

        /*Split data if nummeds_partitions>1*/
        %if %eval(&nummeds_partitions.)>1 %then %do;
            %ms_partition_splitdata(partitiondata =medspartition, 
                                    datafile =worktemp.meds(keep=patid adate codecat codetype code enctype pdx), 
                                    outfile =medstemp.meds, 
                                    num_partitions=&nummeds_partitions.);

            /*delete worktemp.meds to save disk space*/
            proc datasets nowarn noprint lib=worktemp;
                delete meds;
            quit;
        %end;
    %end;
    %end;

    /*---------------------------------------------------*/
    /*  09 -- Loop through Group(s)                      */ 
    /*---------------------------------------------------*/
    
        /*Output preproccessing runtime*/
        %ms_stoptimer(timestart=qrpruntime);
        %ms_outputruntimes(timevar=qrpruntime, step=%str(Preprocessing/code extraction), group=, monitoringperiod=);

    /*---------------------------------------------------*/
    /*  If restarting QRP, restore prior session         */ 
    /*---------------------------------------------------*/
    %checkpoint:

    %let startgroup = 1;

    %if &restartrun = Y %then %do;

        /*Replace dplocal and msoc folder contents*/
        proc datasets nowarn noprint lib=dplocal kill; quit;
        proc copy in=dptemp out=dplocal memtype=data; run;
        proc datasets nowarn noprint lib=msoc kill; quit;
        proc copy in=msoctemp out=msoc memtype=data; run;
        proc datasets nowarn noprint lib=worktemp kill; quit;
        proc copy in=wrktemp2 out=worktemp memtype=data; run;

        data _null_;
            set dplocal.&runid._checkpoints nobs=nobs;
            if _n_ = nobs then do;
                startgroup = groupnum+1;
                call symput("startgroup", put(startgroup, best.));
            end;
        run;

        %if %eval(&startgroup.>&ngroup.) %then %goto postgrouploop;
    %end;

    %macro ms_scenarioloop;

    %do Group=&startgroup. %to &Ngroup.;

    /*---------------------------------------------------*/
    /*  09.a -- Loop pre-processing                      */ 
    /*---------------------------------------------------*/

        /*loop timing*/
        %ms_starttimer(timestart=loopruntime);
        
        *Set current Group macro parameters;
        %ms_setnumloopmacrovars();

        %PUT INFO: NOW LOOPING ON &ITGROUP.;
        %PUT &ITGROUP. processing began on %sysfunc(date(),date9.) %sysfunc(time(),tod8.);

        *Set query period for data driven queries;
        %if "&datadrivenqueryperiod" = "Y" %then %do;
            %ms_setdatadrivenqueryperiod();
        %end;

        *Get specific codes for this loop, separate diags from others to process wildcards, 
         and set flags to carry through variables needed to compute dose;
        %let computedose = N ;
        %let computepov3cumdose = N;
        %let computepov3afdd = N;
        %let computepov3cfdd = N;

        data _diag 
             _others;
            set &COHORTCODES.(where=(group="&ITGROUP."));
            /*only keep strength if specified in codes file*/
            if missing(strength)=0 and missing(unit)=0 then call symputx('computedose', 'Y');
            %if &excl_incl. = Y %then %do;
            if indexcriteria in ('INC', 'EXC') and mincumdose >0 then call symputx('computepov3cumdose', 'Y');
            if indexcriteria in ('INC', 'EXC') and (minafdd >0 | maxafdd>0) then call symputx('computepov3afdd', 'Y');
            if indexcriteria in ('INC', 'EXC') and (mincfdd >0 | maxcfdd>0) then call symputx('computepov3cfdd', 'Y');
            %end;
            if CodeCat in("DX") then output _diag ;
            else output _others;
        run;

        %ISDATA(dataset=_diag);
        %IF %EVAL(&NOBS.>=1) %THEN %DO;
            %MS_ProcessWildcards(InFile=_diag, 
                                 CodeVar=code, 
                                 OutFile=_diag);
        %END;

        *Create Loop-specific parameter files;
        data _ITGroupParamNDC  (keep = obsnum codecat codetype code dateonly stockgroup codesupply indexcriteria CareSettingprincipal 
                                %if &computedose. = Y %then %do; strength %end;
                                %if %eval(&type. = 2) %then %do; fupcriteria %end;    
                                %else %if %eval(&type. = 3) %then %do; fupcriteria %end;                              
                                %else %if %eval(&type. = 4) %then %do; fupcriteria PriorityGroup1 PriorityGroup2 duration priority %end;    
                                %else %if %eval(&type. = 6) %then %do; productapprovaldate productmarketingdate otherproductdate %end; 
                                %if &excl_incl = Y %then %do; 
                                    &InclExclVars. %if &computepov3cumdose. = Y %then %do; mincumdose %end; %if &computepov3cfdd. = Y %then %do; mincfdd maxcfdd %end; 
                                %end;)
             _ITGroupParamNDCForExtract  (keep = obsnum code codetype codesupply)  /* NDC extract for processing loopmeds*/  
             _ITGroupParamMeds  (keep = obsnum codecat codetype code dateonly codesupply indexcriteria CareSettingprincipal
                                %if %eval(&type. = 2) %then %do; fupcriteria %end;    
                                %else %if %eval(&type. = 3) %then %do; fupcriteria %end;                              
                                %else %if %eval(&type. = 4) %then %do; fupcriteria PriorityGroup1 PriorityGroup2 duration priority %end;      
                                %else %if %eval(&type. = 6) %then %do; productapprovaldate productmarketingdate otherproductdate %end; 
                                %if &excl_incl = Y %then %do; &InclExclVars. %end;)
             _ITGroupParamLabs (keep = codecat codetype code dateonly codesupply indexcriteria CareSettingprincipal
                                       RawLabResult RawLabDateType Group  
                                %if %eval(&type. = 2) %then %do; fupcriteria %end;    
                                %else %if %eval(&type. = 3) %then %do; fupcriteria %end;                              
                                %else %if %eval(&type. = 4) %then %do; fupcriteria PriorityGroup1 PriorityGroup2 duration priority %end;     
                                %else %if %eval(&type. = 6) %then %do; productapprovaldate productmarketingdate otherproductdate %end; 
                                %if &excl_incl = Y %then %do; &InclExclVars. %end;
                                rename=(CareSettingprincipal=RawCaresetting Group=RawGroup))
             _ITGroupParamDate (keep = codecat codetype code dateonly codesupply indexcriteria 
                                %if %eval(&type. = 2) %then %do; fupcriteria %end;    
                                %else %if %eval(&type. = 3) %then %do; fupcriteria %end;                              
                                %else %if %eval(&type. = 4) %then %do; fupcriteria PriorityGroup1 PriorityGroup2 duration priority %end;     
                                %else %if %eval(&type. = 6) %then %do; productapprovaldate productmarketingdate otherproductdate %end; 
                                %if &excl_incl = Y %then %do; &InclExclVars. %end;)
             _ITGroupParamMIL  (keep = codecat codetype code dateonly codesupply indexcriteria  
                                %if %eval(&type. = 2) %then %do; fupcriteria %end;    
                                %else %if %eval(&type. = 3) %then %do; fupcriteria %end;                              
                                %else %if %eval(&type. = 4) %then %do; fupcriteria PriorityGroup1 PriorityGroup2 duration priority %end;      
                                %else %if %eval(&type. = 6) %then %do; productapprovaldate productmarketingdate otherproductdate %end; 
                                %if &excl_incl = Y %then %do;&InclExclVars. %end;)
             _ITGroupParamEnc  (keep = codecat codetype code dateonly codesupply indexcriteria CareSettingprincipal  
                                %if %eval(&type. = 2) %then %do; fupcriteria %end;    
                                %else %if %eval(&type. = 3) %then %do; fupcriteria %end; 
                                %else %if %eval(&type. = 4) %then %do; fupcriteria %end;                               
                                %else %if %eval(&type. = 6) %then %do; productapprovaldate productmarketingdate otherproductdate %end; 
                                %if &excl_incl = Y %then %do; &InclExclVars. %end;)
             _ITGroupParamDth  (keep = codecat codetype code dateonly codesupply indexcriteria CareSettingprincipal  
                                %if %eval(&type. = 2) %then %do; fupcriteria %end;    
                                %else %if %eval(&type. = 3) %then %do; fupcriteria %end; 
                                %else %if %eval(&type. = 4) %then %do; fupcriteria %end;                               
                                %else %if %eval(&type. = 6) %then %do; productapprovaldate productmarketingdate otherproductdate %end; 
                                %if &excl_incl = Y %then %do; &InclExclVars. %end;)
                                ;
            set _diag
                _others;

			obsnum = _N_;
            *Defensive coding;
			*Do not create Incl/Excl variables if they are not required;
			%if &excl_incl = Y %then %do;
	            if Condinclusion=. then Condinclusion=1;
	            if SubCondinclusion=. then SubCondinclusion=1;
	            if Cond=. then Cond=-1;
	            if SubCond=. then SubCond=-1;   
                if codedays = . then codedays = 1;
			%end;
            if missing(dateonly) then dateonly = 'N';
            else dateonly=upcase(dateonly);

            *Output;
            if CodeCat="RX"               then do;
			      output _ITGroupParamNDC;
			      output _ITGroupParamNDCForExtract;
			      end;
            else if CodeCat in("DX","PX") then output _ITGroupParamMeds;
            else if CodeCat in("LB")      then output _ITGroupParamLabs;
            else if CodeCat in("AN","DT") then output _ITGroupParamDate;
            else if CodeCat in("MI")      then output _ITGroupParamMIL;
            else if CodeCat in("EN")      then output _ITGroupParamEnc;
            else if CodeCat in("DH","CD") then output _ITGroupParamDth;
        run;

        *Indicator if group index determined by Age Anniversary or Calendar Date;
        %let agedatecohort = N;
        %isdata(dataset=_ITGroupParamDate);
        %if %eval(&nobs.) > 0 %then %do;
            %let agedatecohort = Y;
        %end;

        *Break out CaresettingPrincipal into Caresetting and Principal;
        %ms_caresettingprincipal(InFile=_ITGroupParamMeds, 
                                 Var=CareSettingPrincipal, 
                                 OutFile=_ITGroupParamMeds);
			
        %ms_caresettingprincipal(InFile=_ITGroupParamEnc, 
                                 Var=CareSettingPrincipal, 
                                 OutFile=_ITGroupParamEnc);

        %ms_caresettingprincipal(InFile=_ITGroupParamDth, 
                                 Var=CareSettingPrincipal, 
                                 OutFile=_ITGroupParamDth);

      * Meds dataset with reduced variables for processing loopmeds;						 
		data _ITGroupParamMedsForExtract;
		  set _ITGroupParamMeds(keep = obsnum code codetype codecat pdx enctype);
		run;

    /*---------------------------------------------------*/
    /*  09.b -- Extract loop-specific records            */ 
    /*---------------------------------------------------*/

        *Partitition worktemp.enr_&enrollmentnum. and execute ms_loopmeds/ms_shaveoutside for each partition;
        %isdata(dataset=_ITGroupParamMeds);
        %if %eval(&nobs.>0) %then %do;
            /*Split data if nummeds_partitions>1*/
            %if %eval(&nummeds_partitions.)>1 %then %do;
                %ms_partition_splitdata(partitiondata =medspartition, 
                                        datafile =worktemp.enr_&enrollmentnum.(keep=patid enr_start enr_end), 
                                        outfile =worktemp.enr_&enrollmentnum., 
                                        num_partitions=&nummeds_partitions.);
        %end;

        /*loop through partitions*/
            %do p = 1 %to %eval(&nummeds_partitions.);
                %if %eval(&nummeds_partitions.) = 1 %then %do;
                %let datafile = worktemp.meds;
                %let pnum = ;
            %end;
            %else %do;
                %let datafile = medstemp.meds_&p.;
                %let pnum = _&p.;
            %end;

            *Extract Records necessary for creating this group only
            (record duplic OK + add loop parameters back to records); 
            %ms_loopmeds(datafile=&datafile.,
                         lookfile=_ITGroupParamMedsForExtract, 
                         multiplecodecat=Y,
                         outfile=_ITMeds&pnum.);
    
            /*----------------------------------------------*/
            /*  Shave claims - Meds only in partition loop  */
            /*----------------------------------------------*/
            *Make sure all claims overlap enrollment span and only 
             keep eligible exposures (overlaping Enr_Start Enr_End);
             %ms_shaveoutside(reffile=worktemp.enr_&enrollmentnum.&pnum.(keep=enr_start enr_end patid),
                             refstart=Enr_Start,
                             refend=Enr_End,
                             KeepPartBf=N,
                             ToShaveFile=_ITMeds&pnum.(keep=patid adate obsnum enctype pdx),
                             ToShaveStart=ADate,
                             ToShaveEnd=ADate,
                             shaverx=N,
                             outfile=_ITMeds&pnum.);

            /* Get meds required parameters using obsnum as the key */
            proc sql noprint undo_policy=none;
                   create table _ITMeds&pnum.(drop=obsnum) as
                   select  a.PatId,
                   		a.ADate,
                        a.enr_start,
                        a.enr_end,
						a.enctype,
						a.pdx,
                   		b.*
                   from _ITMeds&pnum. as a
                inner join _ITGroupParamMeds
                    (keep = obsnum codecat codetype code codesupply dateonly indexcriteria
                            %if %eval(&type. = 2) %then %do; fupcriteria %end;    
                            %else %if %eval(&type. = 3) %then %do; fupcriteria %end;                              
                            %else %if %eval(&type. = 4) %then %do; fupcriteria PriorityGroup1 PriorityGroup2 duration priority %end;  
                            %else %if %eval(&type. = 6) %then %do; productapprovaldate productmarketingdate otherproductdate %end; 
            		        %if &excl_incl = Y %then %do; &InclExclVars. %end;) as b
                on a.obsnum=b.obsnum;
              quit;
        %end;

            %if %eval(&nummeds_partitions.)>1 %then %do;
            /*Stack partitioned data and delete partitions*/
            data _itmeds;
                set _itmeds_:;
            run;

            proc datasets nowarn noprint lib=worktemp;
                delete enr_&enrollmentnum._:;
            quit;
            proc datasets nowarn noprint lib=work;
                delete _itmeds_:;
            quit;
        %end;
        %end;
        %else %do;
            data _ITMeds;
                length codetype $3.;
                set %if %eval(&nummeds_partitions.) > 1 %then %do; medstemp.meds_1(obs=0) %end;
                    %else %do; worktemp.meds(obs=0) %end;
                    _ITGroupParamMeds(obs=0 drop=code);
            run;
        %end;

        /*Encounters*/
        options minoperator;
        %ms_loopenc(datafilesuffix=worktemp.encextract,
                    lookfile=_ITGroupParamEnc,
                    keepvars = codetype codecat codesupply dateonly code %if &excl_incl = Y %then %do; &InclExclVars. %end; 
                               enctype indexcriteria
                         %if &type. in (2 3 4) %then %do; fupcriteria %end;
                         %if %eval(&type.=6) %then %do; productapprovaldate productmarketingdate otherproductdate %end;,
                    outfile=_ITEnc);
        options nominoperator;
		/*Death*/
       	%ms_loopdth(deathdatafile=worktemp.deathextract,
					coddatafile=worktemp.codextract,
                    lookfile=_ITGroupParamDth,
					keepvars = indexcriteria codesupply dateonly CodeType EncType %if %eval(&type=2 | &type=3 | &type=4) %then %do; fupcriteria %end;,
                    outfile=_ITDth);

        %macro mergedrugvars(outfile= , allvarsfile=);   
       	/* Get drugs required parameters using obsnum as the key. Select only variables that will be relevant for the ms_stockpiling 
    	  	macro as the others will be dropped after the macro execution anyway */
          proc sql noprint undopolicy=none;
            create table &outfile. as
         	select a.Patid,
         	       a.RxDate,
         	       a.RxAmt,
    			   a.Codetype,
         	       case when not missing(a.codesupply) then a.CodeSupply
    	 		       else a.RxSup end as RxSup, 
    			       case when not missing(a.codesupply) then (a.Rxdate + a.codesupply-1)
    	 		       else (a.Rxdate + a.RxSup-1) end as RxSupEndDt format date9.,
         		    b.CodeCat,
         		    b.StockGroup,
         	        b.indexcriteria,
                   %if &computedose. = Y %then %do;
                    b.strength,
                   %end;
                   %if %eval(&type. = 2) %then %do; b.fupcriteria, %end;    
                   %else %if %eval(&type. = 3) %then %do; b.fupcriteria, %end; 
                   %else %if %eval(&type. = 4) %then %do; b.fupcriteria, %end;  
         		   %if &excl_incl = Y %then %do;
         			 b.condinclusion,
         			 b.subcondinclusion,
         			 b.cond,	
         			 b.subcond,
         			 b.condfrom,
         			 b.condto,
         		     b.codedays,
                     %if &computepov3cumdose. = Y %then %do; b.mincumdose, %end;
                     %if &computepov3cfdd. = Y %then %do; b.mincfdd, b.maxcfdd, %end;
         		   %end;
         		   %if %eval(&type.=6) %then %do;
                     a.rx,
         			 b.productapprovaldate,
         			 b.productmarketingdate,
         			 b.otherproductdate,
         		   %end;
         		     b.dateonly
             from &outfile. as a
         	 join &allvarsfile. as b
             on a.obsnum=b.obsnum;
          quit;
        %mend mergedrugvars;

        %ms_extractdrugs(datafile=worktemp.drugs,
                         lookfile=_ITGroupParamNDCForExtract, 
                         lookvar=code , 
                         mindate=,
                         outfile=_ITDrugs);
        
        %mergedrugvars(outfile=_ITDrugs,
				       allvarsfile =_ITGroupParamNDC);

        %if &CHKCOMBREC = 1 %then %do;
        %ms_extractdrugs(datafile=worktemp.drugscomb,
                         lookfile=_ITGroupParamNDCForExtract, 
                         lookvar=code , 
                         mindate=,
                         outfile=_ITDrugsComb);

        %mergedrugvars(outfile=_ITDrugsComb,
				       allvarsfile =_ITGroupParamNDC);
        %end;

        %ms_extractlabs(datafile=worktemp.labextract,
                        lookfile=_ITGroupParamLabs, 
                        mindate=,
                        outfile=_ITlabs);   

        %ms_extractmilinkage(datafile=worktemp.milextract,
                             lookfile=_ITGroupParamMIL,
                             mindate=,
                             outfile=_ITMIL);

    /*---------------------------------------*/
    /*  09.c -- Shave enrollment spans       */
    /*---------------------------------------*/    

        *Make sure all claims overlap enrollment span and only 
         keep eligible exposures (overlaping Enr_Start Enr_End);
        %ms_shaveoutside(reffile=worktemp.enr_&enrollmentnum.,
                         refstart=Enr_Start,
                         refend=Enr_End,
                         KeepPartBf=N,
                         ToShaveFile=_ITDrugs,
                         ToShaveStart=RxDate,
                         ToShaveEnd=RxSupEndDt,
                         shaverx=Y,
                         outfile=_ITDrugs);
       
        %ISDATA(dataset=_ITDrugsComb);
        %IF %EVAL(&NOBS.>=1) %THEN %DO;
        %ms_shaveoutside(reffile=worktemp.enr_&enrollmentnum.,
                         refstart=Enr_Start,
                         refend=Enr_End,
                         KeepPartBf=N,
                         ToShaveFile=_ITDrugsComb,
                         ToShaveStart=RxDate,
                         ToShaveEnd=RxSupEndDt,
                         shaverx=Y,
                         outfile=_ITDrugsComb(drop=Enr_Start Enr_end));
        %END;

        %isdata(dataset=_ITLabs);
        %if %eval(&NOBS.>=1) %then %do;
        %ms_shaveoutside(reffile=worktemp.enr_&enrollmentnum.,
                       refstart=Enr_Start,
                       refend=Enr_End,
                       KeepPartBf=N,
                       ToShaveFile=_ITLabs (keep=PatID Adate codecat codetype code CodeSupply dateonly indexcriteria
                                            %if %eval(&type. = 2 | &type. = 3 ) %then %do; fupcriteria %end;                               
                                            %else %if %eval(&type. = 4) %then %do; fupcriteria PriorityGroup1 PriorityGroup2 duration priority %end;     
                                            %else %if %eval(&type. = 6) %then %do; productapprovaldate productmarketingdate otherproductdate %end; 
                                            %if &excl_incl = Y %then %do; &InclExclVars. %end;
                                            ),
                       ToShaveStart=ADate,
                       ToShaveEnd=ADate,
                       shaverx=N,
                       outfile=_ITLabs);   
        %end;

        %isdata(dataset=_ITEnc);
        %if %eval(&NOBS.>=1) %then %do;
        %ms_shaveoutside(reffile=worktemp.enr_&enrollmentnum.,
                         refstart=Enr_Start,
                         refend=Enr_End,
                         KeepPartBf=N,
                         ToShaveFile=_ITEnc,
                         ToShaveStart=adate,
                         ToShaveEnd=expiredt,                 
                         shaverx=Y,
                         outfile=_ITEnc);
        %end;

        %isdata(dataset=_ITDth);
        %if %eval(&NOBS.>=1) %then %do;
        %ms_shaveoutside(reffile=worktemp.enr_&enrollmentnum.,
                         refstart=Enr_Start,
                         refend=Enr_End,
                         KeepPartBf=N,
                         ToShaveFile=_ITDth,
                         ToShaveStart=DeathDt,
                         ToShaveEnd=DeathDt,                 
                         shaverx=N,
                         outfile=_ITDth);
        %end;

        *For MIL analysis, Mother must be enrolled on ADate. Infant claim not shaved;
        %ms_shaveoutside(reffile=worktemp.enr_&enrollmentnum.,
                       refstart=Enr_Start,
                       refend=Enr_End,
                       KeepPartBf=N,
                       ToShaveFile=_ITMil,
                       ToShaveStart=ADate,
                       ToShaveEnd=ADate,
                       shaverx=N,
                       outfile=_ITMIL);  
        
        /*For Type 6 analysis, need to select earliest date for same-day dispensings before getting resolved in %ms_stockpiling.
         if uptakedate = COMPUTEDSTARTMARKETINGDATE, can ignore, because specific COMPUTEDSTARTMARKETINGDATE is GROUP and not NDC specific*/
        %if %eval(&type.=6) & %upcase("&UPTAKEDATE.") ne "COMPUTEDSTARTMARKETINGDATE" %then %do;
            %isdata(dataset=_itdrugs);   
            %if %eval(&nobs.>0) %then %do;
            proc means data=_itdrugs noprint nway;
                var &uptakedate.;
                class patid rxdate indexcriteria;
                output out=_mindates(drop=_:) min=;
            run;

            proc sql noprint undo_policy=none;
                create table _itdrugs as
                select x.*,
                       y.&uptakedate.
                from _itdrugs(drop=&uptakedate.) as x,
                     _mindates as y
                where x.patid = y.patid and x.rxdate = y.rxdate and x.indexcriteria=y.indexcriteria;
            quit;
            %end;
        %end;

        /*Type 3*/
        %if %str(&ExclOnSameDay.)=%str(Y) %then %do;
            *Identify SameDayDispensings for different NDCs but from the same group;
            proc sort nodupkey data=_ITDrugs(keep=Patid rxdate ndc indexcriteria) out=_SameDayNDCs(keep=Patid rxdate ndc);
            by Patid rxdate ndc;
            WHERE indexcriteria="DEF";
            run;

            proc means data=_SameDayNDCs nway noprint;
            class Patid rxdate;
            output out=_SameDayNDCs(where=(_freq_>1));
            run;        
        %end;  


    /*--------------------------------------------------------------*/
    /*  09.d -- Create claims dataset based on age or calendar date */ 
    /*--------------------------------------------------------------*/

        %ms_extractanniversarydate(datafile = worktemp.enr_&enrollmentnum.,
                                    lookfile = _ITGroupParamDate,
                                    lookvar = code,
                                    outfile = _itdates);

    /*---------------------------------------------------*/
    /*  09.e -- Apply StockPiling                        */ 
    /*---------------------------------------------------*/

        %let unique_stock_params=0;

        %ISDATA(dataset=STOCKPILE_NONCOVAR);
        %if %eval(&NOBS>0) %then %do;
        /* store maximum number of combination of stockpiling parameters */
        proc sql noprint;
          select max(stocknumber)
            into :unique_stock_params
            from STOCKPILE_NONCOVAR
            where group="&ITGROUP.";
        quit;
        %end;

        %if &unique_stock_params <= 1 %then %do;

        %if &unique_stock_params <= 0 %then %do;
        /* set defaults */
        %let SAMEDAY=aa;
        %let SUPRANGE=0<-HIGH;
        %let AMTRANGE=0<-HIGH;
        %let PERCENTDAYS=;
        %end;

        %else %do;
        data _null_;
            set STOCKPILE_NONCOVAR;
            where group="&ITGROUP";
            call symputx("SAMEDAY",strip(SameDay));
            call symputx("SUPRANGE",strip(SupRange));
            call symputx("AMTRANGE",strip(AmtRange));
            call symputx("PERCENTDAYS",put(PercentDays,best.));
        run;
        %end; /* =1 */

        %MS_STOCKPILING(INFILE=_ITDrugs,            
                        CLMDATE=RxDate,                                 
                        CLMSUP=RxSup,                                   
                        CLMAMT=RxAmt,                                   
                        PROCFLAG=,                                      
                        PERCENTDAYS=&PERCENTDAYS., 
                       	%if &computedose. = Y %then %do; strength = strength, %end;					
                        GROUPING=StockGroup indexcriteria dateonly 
                                 %if %eval(&type. = 2) %then %do; fupcriteria %end;    
                                 %else %if %eval(&type. = 3) %then %do; fupcriteria %end;                              
                                 %else %if %eval(&type. = 4) %then %do; fupcriteria %end; 
                                 %if &excl_incl = Y %then %do; 
                                 &InclExclVars. %if &computepov3cumdose. = Y %then %do; mincumdose %end; %if &computepov3cfdd. = Y %then %do; mincfdd maxcfdd %end; 
                                 %end;,                        
                        SAMEDAY=&SAMEDAY.,                                  
                        SUPRANGE=&SUPRANGE.,                                    
                        AMTRANGE=&AMTRANGE.,
                        ID=CODECAT &t6vars.,                                            
                        OUTFILE=_ITDrugs,       
                        OUTFILEEXCL=_ITDrugsExcl
                        );
        %end; /* <=1 */

        %if &unique_stock_params > 1 %then %do; 
        %do z = 1 %to &unique_stock_params;

        data STOCKPILE_NONCOVAR_&z;
            set STOCKPILE_NONCOVAR;
            where group="&ITGROUP." and stocknumber=&z;
            call symputx("SAMEDAY",strip(SameDay));
            call symputx("SUPRANGE",strip(SupRange));
            call symputx("AMTRANGE",strip(AmtRange));
            call symputx("PERCENTDAYS",put(PercentDays,best.));
        run;

        /* Only process dataset if there are subsetted observations */
        %ISDATA(dataset=STOCKPILE_NONCOVAR_&z);
        %if %eval(&NOBS>0) %then %do;
        %let stock_list=;
        proc sql noprint;
          select distinct quote(strip(stockgroup))
          into :stock_list separated by ' ' 
          from STOCKPILE_NONCOVAR_&z;
        quit;

          %MS_STOCKPILING(INFILE=_ITDrugs(where=(stockgroup in (&stock_list))),            
                        CLMDATE=RxDate,                                 
                        CLMSUP=RxSup,                                   
                        CLMAMT=RxAmt,                                   
                        PROCFLAG=,                                      
                        PERCENTDAYS=&PERCENTDAYS.,    
                        %if &computedose. = Y %then %do; strength = strength, %end;								
                        GROUPING=StockGroup indexcriteria dateonly 
                                 %if %eval(&type. = 2) %then %do; fupcriteria %end;    
                                 %else %if %eval(&type. = 3) %then %do; fupcriteria %end;                              
                                 %else %if %eval(&type. = 4) %then %do; fupcriteria %end; 
                                 %if &excl_incl = Y %then %do; 
                                 &InclExclVars. %if &computepov3cumdose. = Y %then %do; mincumdose %end; %if &computepov3cfdd. = Y %then %do; mincfdd maxcfdd %end; 
                                 %end;,                        
                        SAMEDAY=&SAMEDAY.,                                  
                        SUPRANGE=&SUPRANGE.,                                    
                        AMTRANGE=&AMTRANGE.,
                        ID=CODECAT &t6vars.,                                            
                        OUTFILE=_ITDrugs_&z,       
                        OUTFILEEXCL=_ITDrugsExcl_&z
                        );

        %end; /* %isdata(&STOCKPILE_NONCOVAR._&z) */

        %end; /* z */

        /* Stack all datasets together */
        data _ITDrugs;
          set _ITDrugs_:;
        run;

        data _ITDrugsExcl;
          set _ITDrugsExcl_:;
        run;

        /* Delete temporary datasets */
        proc datasets nowarn noprint lib=work;
        delete _ITDrugs_: _ITDrugsExcl_: stockpile_noncovar_:;
        quit;

        %end; /* unique_stock_params > 1 */

        %if &CHKCOMBREC = 1 %then %do;
        data _ITDrugs;
        set  _ITDrugs
             _ITDrugsComb(in=a);
        *ExpireDt does not exist in _ITDrugsComb;
        length ExpireDt 4;
        if a then ExpireDt=Rxdate+RxSup-1;  
        run;
        %end;

        *Need to reshave because Stockpiling may have pushed claims outside enrollment period;
        %ISDATA(dataset=_ITDrugs);
        %IF %EVAL(&NOBS.>=1) %THEN %DO;
            %ms_shaveoutside(reffile=worktemp.enr_&enrollmentnum.,
                           refstart=Enr_Start,
                           refend=Enr_End,
                           KeepPartBf=N,
                           ToShaveFile=_ITDrugs,
                           ToShaveStart=RxDate,
                           ToShaveEnd=ExpireDt,
                           shaverx=Y,
                           outfile=_ITDrugs);
        %END;   

        proc datasets library=work nowarn nolist;
        delete _diag _others;
        quit;

    /*---------------------------------------------------*/
    /*  09.f -- Create raw POVs datasets                 */
    /*---------------------------------------------------*/
        data _GroupIndex(keep=PatId Adate ExpireDt RXsup RXAmt NumDispensing Enr_Start Enr_end                          /* POV1: Primary cohort Group Index Date   (GroupIndex) */
                              %if %eval(&type = 6) %then %do; productapprovaldate productmarketingdate otherproductdate %end;
                              codecat codetype code stockgroup enctype pdx 
                              %if %eval(&type = 4) %then %do; csex linkedid cbirth_date cenr_start birth_type matchmethod %end;
                              %if &computedose. = Y & %eval(&type.=2) %then %do; strength cumdose &rxsupvar. &rxamtvar. %end;
                              %if &computedose. = Y & %eval(&type.=5) %then %do; strength %end;)                                                 
            _GroupWashForTrunk(keep=PatId Adate)                                                                        /* POV4: Primary Cohort Truncation         (GroupTrunk)  */
            _InclExcl(keep=PatId ADate ExpireDt %if &excl_incl = Y %then %do; &InclExclVars. %end;
                        %if &computepov3cumdose. = Y %then %do; cumdose rxsup mincumdose stockgroup %end; 
                        %if &computepov3afdd. = Y %then %do; cfdd NumDispensing stockgroup %end; 
                        %if &computepov3cfdd. = Y %then %do; cfdd mincfdd maxcfdd %end; )                               /* POV3: Inclusion/Exclusion               (InclExcl)    */
            _FUPEvent(keep=PatId Adate ExpireDt codecat codetype code dateonly stockgroup enctype pdx)             		/* POV5: Risk Follow-Up Event              (FUPEvent)    */
            _FUPWash(keep=PatId Adate ExpireDt dateonly)                                                           		/* POV6: Risk Follow-Up Washout            (FUPWash)     */

            /*Type 4 files*/
            %if %eval(&type.=4) %then %do;
            %do n=1 %to &NUM_MPN.;
            _GroupIndex&n.(keep=PatId Adate ExpireDt Enr_Start Enr_End NumDispensing RXsup RXAmt CodeSupply)            /* POV1: Primary cohort Group Index Date    (GroupIndex) */
            _GroupWash&n.(keep=PatId Adate ExpireDt dateonly)                                                      		/* POV2: Primary Cohort Group Washout       (GroupWash)  */
            %end;
            _GroupPreg(keep=PatId Adate Code PriorityGroup1 PriorityGroup2                                              /* Pregnancy cohort Group duration def      (GroupPreg)  */
                            Priority Duration rename=code=pregdurcode)           
            %end;

            /*Type 6 files*/
            %if %eval(&type.=6) %then %do;
            _GroupIndex2(keep=PatId Adate ExpireDt RXsup RXAmt NumDispensing Enr_Start Enr_end                          /* POV1: Secondary Cohort Group Index Date  (GroupIndex2) */
                              productapprovaldate productmarketingdate otherproductdate code)
            %end;
            ;
            length code $&codelength. expiredt 4;
            set _ITDrugs(in=a rename=RxDate=ADate %if %eval(&type.=6) %then %do; rename=rx=code %end;)
                _ITMeds(in=b)
                _ITLabs(in=c)
                _itdates(in=d)
                _itmil(in=e)
                _itenc(in=f)
				_itDth(in=g rename=DeathDt=ADate);

            /*Dose*/
            %if (&computedose. = Y & %eval(&type.=2)) | &computepov3cumdose.=Y %then %do;
                cumdose = strength*RxAmt;
            %end;
            %if &computepov3afdd. = Y | &computepov3cfdd. = Y %then %do;
                cfdd = (strength*rxamt)/rxsup;
            %end;
                
            if b or c or d or e or g then do;
                if not missing(codesupply) then RxSup = CodeSupply;
                else RxSup = 1;
                Expiredt=Adate+RxSup-1;
                RXAmt=1;
                NumDispensing = 1;
            end;

            if f then do;
                NumDispensing = 1;
            end;

            %if %eval(&type.=1) %then %do;
                /*POV1*/ if indexcriteria in('DEF')       then output _GroupIndex;                
                /*POV3*/ if indexcriteria in('INC','EXC') then output _InclExcl;            
            %end;

            %if %eval(&type.=2) %then %do;

                /*POV1*/ if indexcriteria in('DEF')       then do;
                  %if &POINT = Y %then %do;
                    %if &mincumdose ne . | (&maxcumdose. ne . and &cumdoseper. ne .) | &mincfdd. ne . | &maxcfdd. ne . %then %do; 
                        origrxsup = rxsup;
                        origrxamt = rxamt;
                    %end;
                  rxsup=0;
                  rxamt=0;
                  %end;
                  output _GroupIndex;
                         end;                
                /*POV4*/ if indexcriteria in('FUT') 	  then output _GroupWashForTrunk;
                /*POV3*/ if indexcriteria in('INC','EXC') then output _InclExcl;
                /*POV5*/ if fupcriteria in('DEF')         then output _FUPEvent;
                /*POV6*/ if fupcriteria in('IOC')         then output _FUPWash;
            %end;

            %if %eval(&type.=3) %then %do;
                /*POV1*/ if indexcriteria in('DEF')       then output _GroupIndex;                
                /*POV3*/ if indexcriteria in('INC','EXC') then output _InclExcl;
                /*POV5*/ if fupcriteria in('DEF')         then output _FUPEvent;
                /*POV6*/ if fupcriteria in('IOC')         then output _FUPWash;
            %end;

            %if %eval(&type.=4) %then %do;
                /*POV1*/ if indexcriteria in('DEF')       then output _GroupIndex;
                    %do n=1 %to &NUM_MPN.;
                /*POV1*/ if indexcriteria in("MP&n.")     then do;							
		                    %if &POINT. = Y %then %do;
		                    rxsup=0;
		                    rxamt=0;
		                    %end;
							output _GroupIndex&n.;
						 end;
                    %end;                
                    %do n=1 %to &NUM_MPN.;
                /*POV2*/ if indexcriteria in("IC&n.")     then output _GroupWash&n.;
                    %end;
                /*POV3*/ if indexcriteria in('INC','EXC') then output _InclExcl;
                /*Preg*/ if indexcriteria in('PCY')       then output _GroupPreg;
                /*POV5*/ if fupcriteria in('DEF')         then output _FUPEvent;
                /*POV6*/ if fupcriteria in('IOC')         then output _FUPWash;                              
            %end;

            %if %eval(&type.=5) %then %do;
                /*POV1*/ if indexcriteria in('DEF')       then output _GroupIndex;                
                /*POV4*/ if indexcriteria in('FUT') 	  then output _GroupWashForTrunk;
                /*POV3*/ if indexcriteria in('INC','EXC') then output _InclExcl;
            %end;

            %if %eval(&type. eq 6) %then %do;
                /*POV1*/ if indexcriteria in('DEF')       then output _GroupIndex _GroupIndex2;                
                /*POV3*/ if indexcriteria in('INC','EXC') then output _InclExcl;
            %end;
        run;

        proc datasets library= work nowarn nolist;
            delete _ITDrugs _ITMeds _ITLabs _ITDates _ITEnc _ITDth;
        quit;

    /*---------------------------------------------------*/
    /*  09.g -- POV1: Find All potential index dates     */
    /*---------------------------------------------------*/

        *Leave CohortId blank for primary cohort;
        %ms_createpov1(CohortId=);

        %IF %EVAL(&type.=4) %THEN %DO;
            %ms_createpov1t4(CohortId=);
            %do n=1 %to &NUM_MPN.;
                %ms_createpov1(CohortId=&n.);
            %end;
        %END;

    /*---------------------------------------------------*/
    /*  09.h -- POV2: identify all Type 4 MOI index      */
    /*          dates that are free of POV2 records 	 */
	/*			in washper. For all other types, this 	 */
	/*			is assesed with POV3					 */
    /*---------------------------------------------------*/
        		
        %IF %EVAL(&type.=4) %THEN %DO;
            %do n=1 %to &NUM_MPN.;
                %ms_createpov2(CohortId=&n.);
            %end;
        %END;

    /*---------------------------------------------------*/
    /*  09.i -- POV3: identify all index dates meeting   */
    /*          inclusion Exclusion                      */
    /*---------------------------------------------------*/

        *POV3 will be evaluated for prevalent Type 6 episodes in %ms_createt6episodes;
        %if %eval(&type. ne 6) %then %do;
        %ms_createpov3(CohortId=);    
        %end;

    /*---------------------------------------------------*/
    /*  09.j -- POV4: Create At-Risk Episodes            */
    /*---------------------------------------------------*/        
        *Leave CohortId blank for primary cohort;
        %IF %EVAL(&type. ne 4) %THEN %DO;       
            %ms_createpov4(CohortId=);
        %END;
        %ELSE %DO;      
            %do n=1 %to &NUM_MPN.;               
                %ms_createpov4(CohortId=&n.);
            %end;                       
        %END;   

    /******************************************/
    /* For Type 6 - select prevalent episodes */
    /******************************************/
        %if %eval(&type=6) %then %do;
            /*POV1*/
            %ms_createpov1(CohortId=2);

            proc datasets nowarn noprint lib=work;
                delete _agegroups;
                change _AgeGroups2 = _AgeGroups;
            quit;
            /*POV3*/
            %ms_createpov3(cohortID=2);    
            /*POV4*/
            %ms_createpov4(CohortId=2);
        %end;

    /*---------------------------------------------------*/
    /*  09.k -- Create Final Record wrt index date       */
    /*---------------------------------------------------*/
        %ms_createptsmasterlist();
        
    /*******************************************************************/
    /* For Type 2 when autoprev = Y - select incident episodes */
    /*******************************************************************/
        %if %eval(&type=2) and %str("&autoprev.") = %str("Y") %then %do;
            %ms_findgap(InFile=_groupindex,
                            OutFile=_pov12, 
                            gap=&Washper2.);
                            
            *Add looking period related variables to POV1 for attrition;
            proc sql noprint undo_policy=none;
              create table _POV12 as
              select dat.*,
                     look.lookstartdt as IndexLookStartDt,
                     look.LookEnddt as IndexLookEndDt,
                     Look.Look as IndexLook
              from _POV12 as dat,
                   looks as look
              where look.LookStartdt<=dat.Adate<=look.LookEnddt
              order by Patid,Adate;
            quit;
            
            data _POV12(drop=AgeGroup);
               merge _POV12(in=a)
                     _agegroups(keep=PatId indexdt AgeGroup rename=indexdt=adate);
               by patid adate;
               if a and strip(AgeGroup) ne "";
            run;
            
            /* Apply previnc variable to ptsmasterlist */
            data _PtsMasterList;
              merge _PtsMasterList (in = mstr)
                    _pov12         (in = pov12 keep = patid adate rename = (adate=indexdt));
              by patid indexdt;
              length previnc $4.;
              if pov12 then previnc = "Inc";
              else previnc = "Prev";
              if mstr then output;
            run;
        %end;
        
    /**********/
    /* EVENTS */
    /**********/

        %ms_createpov56();  
        
    /********************************************************************/
    /* For Type 5 - select index episode and create subsequent episodes */
    /********************************************************************/
        %if %eval(&type=5) %then %do;
            %ms_createt5episodes();
        %end;

    /*---------------------------------------------------*/
    /*  09.l -- Finalize Episode List                    */
    /*---------------------------------------------------*/
        
        %ms_finalizeptsmasterlist();

        %if %eval(&type=4) %then %do;
            * Create the control group (match treated patients);
            %ms_createnopreggroup();

            * Retain MOI episodes/codes during pregnancy/control episode;
            %ms_finalizemoiepisodes();
        %end;


    /*---------------------------------------------------*/
    /*  09.m -- Calculate additional metrics             */
    /*---------------------------------------------------*/

        %if %eval(&type < 3) %then %do; 
            *Compute Denominators;
/*            %ms_cidadenom();*/ /*PLUS: not requested*/
        %end;

        %if %eval(&type = 2) %then %do; 
            *Compute never exposed Cohort;
            %ms_nvrexposed();
        %end;
        %if %eval(&type = 4) %then %do; 
            *Compute MOI stats;
            %ms_moimetrics(cohortfile=_PtsMasterList, outfile=mstr_preg);
            %if "&t4_nopreggroup." = "Y" %then %do;
            %ms_moimetrics(cohortfile=_ControlGroup, outfile=mstr_nopreg);
            %end;
        %end;

        *Run surveillance if required and applicable;
        %if ("&SURVEILLANCEMODE."="f" or "&SURVEILLANCEMODE."="p") and %eval(&type. = 2) %then %do;

            %if ("&SURVEILLANCEMODE."="f") %then %do;
                data _PtsMasterList;
                set _PtsMasterList;
                format EndFollowUpType $20.;
                length LastLookFollowedDt 4;
                if LastLookFollowed=0 then do; *apply only to eligible patients;
                  if min(Feventdt,EpisodeEndDt) < &enddate. then do;
                      LastLookFollowedDt = &enddate.; 
                      LastLookFollowed = &PERIODIDSTART.;
                      EndFollowUpType="EpisodeEndBFEnddate";
                  end;
                  else if Feventdt = &enddate. then do;
                      LastLookFollowedDt = &enddate.; 
                      LastLookFollowed = &PERIODIDSTART.;
                      EndFollowUpType="EventOnEnddate";
                  end;
                end;
                run;
            %end;

            * Prior data existence for Surveillance;
            %ISDATA(dataset=DPLPRIOR.&RUNID._mstr); 
            %IF %EVAL(&NOBS.>0) and %EVAL(&PERIODIDSTART. > 1) %THEN %DO;
                %ms_surveillance();
            %END; 
        %end;

        *Type 6;
        %if %eval(&type=6) %then %do;
            /*Calculate dates for [runid]_T6_ProductDates*/
                /*1. ProductApprovalDate, ProductMarketingDate, Otherproductdate*/
                data _ITGROUPPARAM_Combined;
                    set _itgroupparammeds(keep=productmarketingdate productapprovaldate Otherproductdate)
                        _itgroupparamndc(keep=productmarketingdate productapprovaldate Otherproductdate)
                        _itgroupparamlabs(keep=productmarketingdate productapprovaldate Otherproductdate);
                run;

                proc sql noprint;
                    create table _productdates1 as
                    select  min(productmarketingdate) as productmarketingdate format=date9.
                          , min(productapprovaldate) as productapprovaldate format=date9.
                          , min(Otherproductdate) as Otherproductdate format=date9.,
                          "&ITGROUP." as group format=$40.
                from _ITGROUPPARAM_Combined;
                quit;

                /*2. ComputedStartMarketingDate*/
                %isdata(dataset=_PtsMasterList);
                %if %eval(&NOBS.>=1) %then %do;
                proc sql noprint;
                    create table _productdates2 as
                    select min(indexdt) as computedstartmarketingdate format=date9.,
                            "&ITGROUP." as group format=$40.
                    from _PtsMasterList;
                quit;
                %end;
                %else %do;
                    data _productdates2;
                        format group $40. computedstartmarketingdate date9.;
                        computedstartmarketingdate = .;
                        group = "&ITGROUP.";
                    run;
                %end;

                data _productdates_group;
                    format group $40.;
                    merge _productdates1 _productdates2;
                    by group;
                run;

            /*Store to MSOC*/
            %IF %EVAL(&group.=1) %THEN %DO;
                data MSOC.&RUNID._T6_productsdates;
                    set _productdates_group;
                run;
            %end; 
            %else %do;
                data MSOC.&RUNID._T6_productsdates;
                    set MSOC.&RUNID._T6_productsdates
                        _productdates_group;
                run;
            %end; 

            proc sort data=_PtsMasterList; by group; run;

            /*Add computedstartmarketingdate to _PtsMasterList*/
            data _PtsMasterList;
                merge _PtsMasterList (in=a)
                    _productdates_group (keep=group computedstartmarketingdate);
                by group;
                if a;
            run;

            /*Calculate total time on treatment*/
			proc sort data=_PtsMasterList; 
                by patid;
            run;

            proc means data=_PtsMasterList noprint nway;
                var episodelength;
                class patid;
                output out=_totalepisodelength(drop=_:) sum=CumEpisodeLength;
                where incexl = 1; 
            run;
                
            /*Update [runid]_mstr with total time on treatment*/
            data _PtsMasterList;
                merge _PtsMasterList _totalepisodelength;
                by patid;
            run;
        %end;

        *Codes that define exposure and hoi;
        %if "&DISTINDEX." = "y" %then %do;
            %ms_codedistribution();
        %end;

        /*PLUS: merge in urbanicity and SES variables*/
        proc sql noprint;
            create table _zip as
            select pts.*,
                   lkup.statecode,
                   lkup.cb_region,
                   lkup.med_house_inc,
                   lkup.med_prop_val,
                   lkup.perc_unempl,
                   lkup.house_inc_known,
                   lkup.prop_val_known,
                   lkup.perc_unempl_known,
                   lkup.all_ses_known,
                   lkup.urban_cat
            from _PtsMasterList as pts
            left join infolder.&zipfile. as lkup
            on pts.zip = lkup.zip;
        quit;

        data _PtsMasterList(drop=statecode cb_region);
            length cb_reg $7 urban_cat $30;
            set _zip;
            if missing(zip) then do;
                cb_reg = 'Missing';
                urban_cat = 'Unknown';
                house_inc_known = 0;
                prop_val_known = 0;
                perc_unempl_known = 0;
                all_ses_known = 0;
                med_house_inc = .;
                med_prop_val = .;
                perc_unempl = .;
            end;
            else if missing(statecode) then do;
                cb_reg = 'Invalid';
                urban_cat = 'Unknown';
                house_inc_known = 0;
                prop_val_known = 0;
                perc_unempl_known = 0;
                all_ses_known = 0;
                med_house_inc = .;
                med_prop_val = .;
                perc_unempl = .;
            end;
            else do;
                cb_reg = cb_region;
                if urban_cat not in ('Rural', 'Urban', 'Suburban') then urban_cat = 'Unknown';
                if statecode ne '' and missing(cb_reg) then do;
                    cb_reg = 'Other';
                end;
            end;

            /*PLUS: add known race*/
            if race in ('1','2','3','4','5') then known_race='1'; else known_race = '0';
        run;

        /***************************************************/
        /** ALL Types - Store patient episodes to DPLocal **/
        /***************************************************/
        %IF %EVAL(&group.=1) %THEN %DO;

            %if %eval(&type ne 4) %then %do;
                data DPLocal.&RUNID._mstr;
                set _PtsMasterList;
                run;
            %end;

            %if %eval(&type eq 4) %then %do; 
                data DPLocal.&RUNID._mstr_preg;
                set _PtsMasterList;
                run;

                data DPLocal.&RUNID._sec;
                set _PtsMasterList2;
                run;
                %if "&t4_nopreggroup." = "Y" %then %do;
                    data DPLocal.&RUNID._mstr_nopreg;
                    set _ControlGroup;
                    run;
                %end;
                data DPLocal.&RUNID._prePostCodes;
                set _prePostCodes;
                run;
                data DPLocal.&RUNID._allDeliveries;
                set _Deliveries;
                run;
            %end;

            %if %eval(&type.=5 | &type.=6) %then %do; 
                data DPLocal.&RUNID._dispensings;
                set _dispensings;
                run;
            %end;
        %END;
        %ELSE %DO;
            /*Because of surveillance mode and the carried forward  variables from look <&PERIODIDSTART. that have not been 
             calculated yet for the (&PERIODIDSTART.<=look<=&PERIODIDEND.)) - we will use a set method rather than append*/

            %if %eval(&type ne 4) %then %do;
                data DPLocal.&RUNID._mstr;
                set DPLocal.&RUNID._mstr
                    _PtsMasterList;
                run;   
            %end; 

            %if %eval(&type eq 4) %then %do; 
                proc append base=DPLocal.&RUNID._mstr_preg
                            data=_PtsMasterList force;
                run;
                proc append base=DPLocal.&RUNID._sec 
                            data=_PtsMasterList2 force;
                run;
                %if "&t4_nopreggroup." = "Y" %then %do;
                    proc append base=DPLocal.&RUNID._mstr_nopreg 
                                data=_ControlGroup force;
                %end;
                run;
                proc append base=DPLocal.&RUNID._prePostCodes 
                            data=_prePostCodes force;
                run;
                proc append base=DPLocal.&RUNID._allDeliveries 
                            data=_Deliveries force;
                run;
            %end;

            %if %eval(&type.=5 | &type.=6) %then %do;
                proc append base=DPLocal.&RUNID._dispensings
                        data=_dispensings force;
                run;
            %end;
        %END;

        
        %if &censor_dth.=1 %then %do;
            *If censoring is used, truncate enrollment at death date (for denominators/attrition);
            data worktemp.enr_group&GROUP.;
            set worktemp.enr_&enrollmentnum.;
                if enrend_death in ('B', 'C') and DeathDt <= Enr_End then do;
                    Enr_End=DeathDt;
                end;
                if Enr_end < Enr_Start then delete;
            run;

            data _groupindex;
            set _groupindex;
                if enrend_death in ('B', 'C') and . < DeathDt < adate then delete;
            run;
        %end;

        *Compute Attrition for this group;
        %if %eval(&type=2) and %str("&autoprev.") = %str("Y") %then %do;
           %ms_attrition (ds_suffix =, where_clause =%str((where=(PrevInc = "Inc"))), cohortid=2);
           %ms_attrition (ds_suffix =_prev, where_clause =%str((where=(group in ("&prevgroups.") and previnc_def in ("Both","Prev")))), cohortid=);
        %end;
        %else %do;
           %ms_attrition;
        %end;

        proc datasets nowarn noprint lib=worktemp;
            delete enr_group&group. %if &group. = &ngroup. %then %do; _keep %end;;
        quit;


        * Reset loop macro variables;
        %let EXCL=;
        %let INCL=;
        %let CHARTRES=;

        * Save _GroupIndex for later processing;
        %if %eval(&concomitant.=1) %then %do;
            data gi&itgroup.;
                set _groupindex;
            run;
        %end;

        proc datasets nowarn noprint lib=work;
            delete _pov: _uniquepts: _age: _control: _deliveries _demo: _groupindex: _it: _next: _ptsmasterlist: _groupwash: _t&type.priorlooks
                   _EventsInBlackout _InclExcl _FUPEvent _FUPWash _GroupPreg _fut: _temp _tmp _zip;
        quit;

        /*Output loop runtime*/
        %ms_stoptimer(timestart=loopruntime);
        %ms_outputruntimes(timevar=loopruntime, step=%str(CIDA Loop), group=&itgroup., monitoringperiod=);

        %put LAST GROUP RAN WAS &ITGROUP. &group.;
        %PUT &ITGROUP. processing ended on %sysfunc(date(),date9.) %sysfunc(time(),tod8.);

        /*Checkpoint*/
       %ms_checkpoint(macrocalled=ms_scenarioloop);

    %end; /*group loop*/

    %mend ms_scenarioloop;

    %ms_scenarioloop;

    /*recreate worktemp.meds and clear medstemp folder*/
    %if %eval(&nummeds_partitions.>1) %then %do;
        data wrktemp2.meds;
            set medstemp.meds:;
        run;

        proc copy in=wrktemp2 out=worktemp memtype=data; 
            select meds;
        run;

        proc datasets nowarn noprint lib=medstemp kill;
        quit;
    %end;

    %postgrouploop:

    /* Assign patid length if it does not already exist */
    %if %symexist(patid_len) = 0 %then %do;
        %varlength (var = patid, indata = DPLocal.&RUNID._mstr&preg.);
    %end;

    proc datasets nowarn noprint lib=work;
        delete demogs: MultiDemogs:;
    quit;

    /* Code distribution pts vars - Determine max length of values of distindexexp/distindexhoi 
       and apply as the length of the variable */
    %if "&DISTINDEX." = "y" %then %do;
        %macro codedistlength(data=, hoi=);
            proc sql noprint;
                select max(length(distindexexp))
                %if &hoi.=Y %then %do;
                , max(length(distindexhoi))
                %end;
                into :distexplength
                %if &hoi.=Y %then %do;
                   , :disthoilength
                %end;
                from dplocal.&runid._mstr&data.(keep=distindex:);
            quit;

            data dplocal.&runid._mstr&data.;
                set dplocal.&runid._mstr&data.(rename=(distindexexp=var1 
                        %if &hoi.=Y %then %do; distindexhoi=var2 %end; ));
                length distindexexp $%sysfunc(max(1,&distexplength.))
                %if &hoi.=Y %then %do; distindexhoi $%sysfunc(max(1,&disthoilength.)) %end;
                ;

                distindexexp = var1;
                drop var1;
                %if &hoi.=Y %then %do;
                distindexhoi = var2;
                drop var2;
                %end;
            run;
        %mend;

        %if %eval(&type = 4) %then %do;
            %codedistlength(data=_preg, hoi=N);
        %end;
        %else %if (%eval(&type.=2) | %eval(&type.=3)) & "&analysis" ne "tree" %then %do;
            %codedistlength(data=, hoi=Y);
        %end;
        %else %do;
            %codedistlength(data=, hoi=N);
        %end;
    %end;
   
    *all patients in master list;
	proc sort nodupkey data = DPLocal.&RUNID._mstr&preg. (keep = patid) out = _unique_&runid._mstr&preg.;
	  by patid;
	run;
	
	%if %eval(&milinkage. =1) %then %do;
	   proc sort nodupkey data = DPLocal.&RUNID._mstr&preg. (keep = linkedid) out = _unique_link_&runid._mstr&preg. (rename = (linkedid = patid));
	     by linkedid;
	   run;
    %end;
    %if %eval(&type.=4) & "&t4_nopreggroup." = "Y" %then %do;
       proc sort nodupkey data = DPLocal.&RUNID._mstr_nopreg (keep = patid) out = _unique_&RUNID._mstr_nopreg;
	     by patid;
	   run;
    %end;
	
	data worktemp.ptsmstrall;
	   merge _unique_&runid._mstr&preg.
	     %if %eval(&milinkage. =1) %then %do;
	        _unique_link_&runid._mstr&preg.
		 %end;	
         %if %eval(&type.=4) & "&t4_nopreggroup." = "Y" %then %do;
            _unique_&RUNID._mstr_nopreg
         %end;;
	   by patid;
	run;
	
	proc datasets library=work nowarn nolist;
        delete _unique_&runid._mstr:;
    quit;
	
    %do e = 1 %to &numenrollgroup.;
        *Extracting enrollment data for patients in master list;
        %restrictclms(indata=worktemp.enr_&e., lookupdata=worktemp.ptsmstrall, outdata=worktemp.enr_&e.);
            *Adjust enrollment for death for later processing;
            %if %sysfunc(exist(infolder.&type4file.)) ne 1 %then %do;
                data worktemp.enr_&e.;
                    set worktemp.enr_&e.;
                        if enrend_death in ('B', 'C') and DeathDt <= Enr_End then do;
                                Enr_End=DeathDt;
                            end;
                        if Enr_end < Enr_Start then delete;
                run;
                %end;
    %end;

    *subset medical/Rx claims to only patients in master list if they are used for following analyses;
    %if %eval(&milinkage. =1)| %eval(&switchincl.)=1 | &CovarCodes.=Y | %length(&Comorbfile.) | %length(&CONCFILE.) %then %do;
        %ISDATA(dataset=worktemp.meds);    
        %if %eval(&NOBS.>0) %then %do;
        %restrictclms(indata=worktemp.meds, lookupdata=worktemp.ptsmstrall, outdata=worktemp.meds);
        %end;
        %ISDATA(dataset=worktemp.drugs);    
        %if %eval(&NOBS.>0) %then %do;
        %restrictclms(indata=worktemp.drugs, lookupdata=worktemp.ptsmstrall, outdata=worktemp.drugs);
        %end;
        %ISDATA(dataset=worktemp.drugscomb);    
        %if %eval(&NOBS.>0) %then %do;
        %restrictclms(indata=worktemp.drugscomb, lookupdata=worktemp.ptsmstrall, outdata=worktemp.drugscomb);
        %end;

     *For encounter claims;
        %if %str("&enctypeextractlist.") ne %str("") %then %do;
        %local e enc;
           %do e = 1 %to %sysfunc(countw(&enctypeextractlist.));
               %let enc = %scan(&enctypeextractlist., &e.);
               %restrictclms(indata=worktemp.encextract&enc., lookupdata=worktemp.ptsmstrall, outdata=worktemp.encextract&enc.);
            %end;
        %end;
    %end;
    
    proc datasets library=worktemp nowarn nolist;
        delete PtsMstrall enr_m: enr_d:;
    quit;

    *if data-driven query period, assign calendar based macro variables for reporting;
    %if "&datadrivenqueryperiod" = "Y" %then %do;
        %ms_assigncalmacrovars(date1=&MinExpPeriodStartDt., date2=&MaxExpPeriodEndDt.);
    %end;
    
    /********************/
    /* Switching module */
    /********************/
    %if %eval(&type. eq 6) %then %do;
        %ms_switching();
    %end;   

    /******************************/
    /* Secondary Episode Analysis */
    /*  -Multiple Events          */
    /*  -Overlap                  */
    /*  -Concomitant Use Episodes */
    /******************************/
    %if %eval(&multievent.=1 | &overlap.=1) %then %do;
        %ms_evalsecondaryepi();
        %if %eval(&type.=2) %then %do;
           %ms_evalsecondarytables (ds_suffix =, where_clause = %str(and PrevInc = "Inc"));
           %if %index(&tables.,t2multeventprev) >0 or %index(&tables.,t2overlapprev)> 0 or %index(&tables.,t2epigapprev)> 0 %then %do;
             %ms_evalsecondarytables (ds_suffix =_prev, where_clause =%str(and previnc_def in ("Both","Prev")));
           %end;
        %end;
        %else %do;
           %ms_evalsecondarytables;
        %end;
    %end;

    %if %eval(&concomitant.=1) %then %do;
        %ms_concomitantuse();
    %end;

    /************************/
    /* Mother-Infant module */
    /************************/
    %if %eval(&milinkage. =1) %then %do;
        %ms_createmicohorts();
    %end;   

    /********************************************************************************************************/
    /* Freeze Patients Data - Will save A/Y patients now. Matched patients saved after covariate_adjustment */
    /********************************************************************************************************/
    %macro saveptstofreezedata(data=, wherekeep=);    

        %ms_starttimer(timestart=freezeruntime);

        %if "&t4_nopreggroup." = "N" %then %do; 
            data _ptslist(keep=patid);
                set DPLocal.&RUNID.&data.&preg.(&wherekeep.);
            run;
        %end;
        %else %do;
            data _PtsList;
            set DPLocal.&RUNID._allDeliveries (keep=Patid)
                DPLocal.&RUNID._mstr_nopreg (keep=Patid);
            run;
        %end;
       %isdata(dataset=_PtsList);
        %if %eval(&nobs.>0) %then %do;            
            %IF %STR(&ENRTABLE.) ne %STR() or %LENGTH(&ENRTABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&ENRTABLE, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._enrtable);%END;            
            %IF %STR(&DEMTABLE.) ne %STR() or %LENGTH(&DEMTABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&DEMTABLE, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._demtable);%END;            
            %IF %STR(&DISTABLE.) ne %STR() or %LENGTH(&DISTABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&DISTABLE, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._distable);%END;            
            %IF %STR(&DIATABLE.) ne %STR() or %LENGTH(&DIATABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&DIATABLE, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._diatable);%END;           
            %IF %STR(&PROCTABLE.) ne %STR() or %LENGTH(&PROCTABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&PROCTABLE,PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._proctable);%END;            
            %IF %STR(&ENCTABLE.) ne %STR() or %LENGTH(&ENCTABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&ENCTABLE, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._enctable);%END;           
            %IF %STR(&LABTABLE.) ne %STR() or %LENGTH(&LABTABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&LABTABLE, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._labtable);%END;           
            %IF %STR(&VITTABLE.) ne %STR() or %LENGTH(&VITTABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&VITTABLE, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._vittable);%END;            
            %IF %STR(&DEATHTABLE.) ne %STR() or %LENGTH(&DEATHTABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&DEATHTABLE, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._deathtable);%END;
            %IF %STR(&MILTABLE.) ne %STR() or %LENGTH(&MILTABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&MILTABLE, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._miltable);%END;
            %IF %STR(&pretable.) ne %STR() or %LENGTH(&pretable.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&pretable, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._pretable);%END;

            /*Facility and provider table are lookup tables without patID - will freeze entire table*/
            %IF %STR(&factable.) ne %STR() or %LENGTH(&factable.) > 0. %THEN %DO;
                data freedir.&RUNID._factable;
                    set indata.&factable.;
                run;
            %end;
            %IF %STR(&pvdtable.) ne %STR() or %LENGTH(&pvdtable.) > 0. %THEN %DO;
                data freedir.&RUNID._pvdtable;
                    set indata.&pvdtable.;
                run;
            %end;

            *This datalib will point to the subset of PatId data generated by Freeze data;
            %let datalib_enr=freedir.&runid._enrtable;
            %let datalib_dem=freedir.&runid._demtable;
            %let datalib_dis=freedir.&runid._distable;
            %let datalib_dia=freedir.&runid._diatable;
            %let datalib_proc=freedir.&runid._proctable;
            %let datalib_enc=freedir.&runid._enctable;
            %let datalib_lab=freedir.&runid._labtable;
            %let datalib_vit=freedir.&runid._vittable;
            %let datalib_death=freedir.&runid._deathtable;
            %let datalib_mil=freedir.&runid._miltable;
            %let datalib_pre=freedir.&runid._pretable;
        %end;

        /*Output freezedata runtime*/
        %ms_stoptimer(timestart=freezeruntime);
        %ms_outputruntimes(timevar=freezeruntime, step=%str(Freeze Data), group=, monitoringperiod=);
    %mend saveptstofreezedata;

    %if %str("&FREEZEDATA.")=%str("y") | %str("&FREEZEDATA.")=%str("a") %then %do;
        %if %str("&FREEZEDATA.")=%str("a") %then %do; 
        %saveptstofreezedata(data=_mstr, wherekeep=%str(keep=patid));
        %end;
        /*if y - excluded never-exposed cohorts and any patID not identified in a secondary episode cohort */
        %else %if %str("&FREEZEDATA.")=%str("y") %then %do; 
            %if %eval(&multievent.=1) %then %do;
                %saveptstofreezedata(data=_mstr_multevent, wherekeep=%str(keep=patid));
            %end;
            %else %if %eval(&overlap.=1) %then %do;
                %saveptstofreezedata(data=_mstr_overlap, wherekeep=%str(keep=patid));
            %end;
            %else %if %eval(&concomitant.=1) %then %do;
                %saveptstofreezedata(data=_mstr_concomitance, wherekeep=%str(keep=patid));
            %end;
            %else %do;
                %saveptstofreezedata(data=_mstr, wherekeep=%str(keep=patid group where=(index(lowcase(group), "_nvrexp") = 0)));
            %end;
        %end;
    %end;

    /*** Extract Covariates and Produce Baseline table ***/
        
        *CIDA Groups: Types 1-5;
        %if %eval(&type. ne 6) & %eval(&multievent.=0) & %eval(&overlap.)=0 & %eval(&concomitant.=0) %then %do;
            %ms_CIDAcov(data=mstr&preg., outcohort=&preg., groupvar=group, groupdefdata=cohortfile, groupdefvar=cohortgrp
						%if %eval(&type.=4) %then %do; ,lookdt=EpisodeEndDt %end;);
        %end;

        *CIDA Groups: Type 4 control group;
        %if %eval(&type.=4) & "&t4_nopreggroup" = "Y" %then %do;
            %ms_CIDAcov(data=mstr_nopreg, outcohort=_nopreg, groupvar=group, groupdefdata=cohortfile, groupdefvar=cohortgrp, lookdt=EpisodeEndDt);
        %end;

        *Concomitant episodes;
        %if %eval(&concomitant.=1) %then %do;
            %ms_CIDAcov(data=mstr_concomitance, outcohort=_concomitance, groupvar=analysisgrp, groupdefdata=infolder.&concfile., groupdefvar=analysisgrp, cohortgrpvar=primary);
        %end;

        *Multiple event analysis;
        %if %eval(&multievent.=1) %then %do;
            %ms_CIDAcov(data=mstr_multevent, outcohort=_multevent, groupvar=analysisgrp, groupdefdata=secondaryinputfile, groupdefvar=analysisgrp, cohortgrpvar=primary);
        %end;

        *Overlap event analysis;
        %if %eval(&overlap.=1) %then %do;
            %ms_CIDAcov(data=mstr_overlap, outcohort=_overlap, groupvar=analysisgrp, groupdefdata=secondaryinputfile, groupdefvar=analysisgrp, cohortgrpvar=primary);
        %end;

        *Mother-infant analysis;
        %if %eval(&milinkage. =1) %then %do;
            %ms_CIDAcov(data=mstr_mi, outcohort=_mi, groupvar=group, groupdefdata=migroupnames, groupdefvar=cohortgrp, cohortgrpvar=groupname);
        %end;

		*Switch episode analysis;
		%if %eval(&type.=6) %then %do;

            /* loop through all potential switches */
            %do switchnum = 0 %to 2;
            %ms_CIDAcov(data=t6_switchepisodes, outcohort=_switch_&switchnum, groupvar=analysisgrp, groupdefdata=type6groups_forbaseline, groupdefvar=analysisgrp, cohortgrpvar=primary, suffixvarnum=&switchnum);
            %end;

            /* Stack switch datasets */
            %do i = &PERIODIDSTART. %to &PERIODIDEND.; 

                /* Only stack when at least one table is requested */
                %let checkbaseline=;
                proc sql noprint;
                  select upcase(createbaseline)
                  into :checkbaseline
                  from infolder.&TREATMENTPATHWAYS
                  where upcase(createbaseline) = 'Y';
                quit;

                %if &checkbaseline = Y %then %do;
                    /*Check that switcheval step 0 ADS file exists*/
                    %isdata(dataset=dplocal.&RUNID._ads_t6_switchepisodes_0_&i.);
                    %if %eval(&nobs.>0) %then %do;
                    data dplocal.&RUNID._ads_t6_switchepisodes_&i.;
                      set 
                        %do j = 0 %to 2;
                        %if %sysfunc(exist(dplocal.&RUNID._ads_t6_switchepisodes_&j._&i.)) %then %do;
                        dplocal.&RUNID._ads_t6_switchepisodes_&j._&i.
                        %end;
                        %end;
                        ;
                    run;
                    %end;

                    data msoc.&RUNID._baseline_switch_&i;
                    set 
                        %do j = 0 %to 2;
                        %if %sysfunc(exist(msoc.&RUNID._baseline_switch_&j._&i.)) %then %do;
                        msoc.&RUNID._baseline_switch_&j._&i.
                        %end;
                        %end;
                        ;
                    run;
                %end;

                proc datasets nowarn noprint lib=msoc;
                  delete &RUNID._baseline_switch_0_&i. 
                         &RUNID._baseline_switch_1_&i.
                         &RUNID._baseline_switch_2_&i.;
                quit;

                proc datasets nowarn noprint lib=dplocal;
                  delete &RUNID._ads_t6_switchepisodes_0_&i. 
                         &RUNID._ads_t6_switchepisodes_1_&i.
                         &RUNID._ads_t6_switchepisodes_2_&i.;
                quit;
            %end;
		%end;

        proc datasets library=worktemp nolist nowarn;
          delete encextract: type6groups_forbaseline;
        quit;

        /*****************************************/
        /** Extract Claims Files (for MFU/HDPS) **/
        /*****************************************/

        %if %eval(&type. ne 6) & %eval(&multievent.=0 & &overlap.=0 & &concomitant.=0) %then %do;
        %ms_createclaimsfiles;
        %end;

        /**Conduct MFU analysis*/
        %isdata(dataset=infolder.&mfufile.);
        %if %eval(&nobs.>0) %then %do;

            %ms_starttimer(timestart=mfuruntime);

            %ms_mfu(%if %eval(&type. = 2) %then %do; 
                    where=previnc="Inc" 
                    %end; 
                    %else %do; 
                    where=1 
                    %end;
                    ,t3out=);

            %if %eval(&type.=3) %then %do;
            %ms_mfu(where=analysiscohort=1, t3out=_an);
            %end;

            %ms_stoptimer(timestart=mfuruntime);
            %ms_outputruntimes(timevar=mfuruntime, step=%str(MFU Module), group=, monitoringperiod=);
        %end;

        /*****************************/
        /* Produce Aggregate Outputs */
        /*****************************/
        %if %eval(&type. = 1) %then %do;
           %ms_cidatables;
        %end;
        %if %eval(&type.=2) %then %do;
           %ms_cidatables (ds_suffix =, where_clause = %str(PrevInc = "Inc"), followuptimevar=followuptime);
           %if %index(&tables.,t2cidaprev) >0 %then %do;
             %ms_cidatables (ds_suffix =_prev, where_clause =%str(previnc_def in ("Both","Prev")), followuptimevar=followuptime);
           %end;
        %end;
        %if %eval(&type. eq 3) %then %do; 
            %ms_cidatablest3();     
        %end;
        %if %eval(&type. eq 4) %then %do;
            %ms_cidatablest4();
        %end;   
        %if %eval(&type. eq 5) %then %do;
            %ms_cidatablest5();
        %end;   
        %if %eval(&type. eq 6) %then %do;
            %ms_cidatablest6();
        %end;   
        %if %eval(&concomitant.=1) %then %do;
            %ms_concomitantusetables();
        %end;

        *output censoring table;
        %if "&censor_output." = "Y" %then %do;
           %if %eval(&type.=2) %then %do;
              %if %sysfunc(findw(&tables., t2censor)) >0 %then %do;
			    %ms_createcensortable(table = censor, ds_suffix =, where_clause = %str(PrevInc = "Inc"), 
				                      convar = timetocensor, catvar = censdays_value_cat,
				                      dplocalflaglist = cens_elig cens_dth cens_dpend cens_qryend,
									  msocflaglist = cens_elig cens_dth cens_dpend cens_qryend);
              %end;
              %if %sysfunc(findw(&tables., t2followuptime)) > 0 %then %do;
			    %ms_createcensortable(table = followuptime, ds_suffix =, where_clause = %str(PrevInc = "Inc"), 
				                      convar = followuptime, catvar = fupdays_value_cat,
				                      dplocalflaglist = fup_elig fup_dth fup_dpend fup_qryend fup_episend fup_spec fup_event,
									  msocflaglist = cens_elig cens_dth cens_dpend cens_qryend cens_episend cens_spec cens_event);
              %end;
              %if %sysfunc(findw(&tables., t2censorprev)) >0 %then %do;
			    %ms_createcensortable(table = censor, ds_suffix =_prev, where_clause = %str(previnc_def in ("Both","Prev")), 
				                      convar = timetocensor, catvar = censdays_value_cat,
				                      dplocalflaglist = cens_elig cens_dth cens_dpend cens_qryend,
					    		      msocflaglist = cens_elig cens_dth cens_dpend cens_qryend);
              %end;
              %if %sysfunc(findw(&tables., t2followuptimeprev)) >0 %then %do;
			    %ms_createcensortable(table = followuptime, ds_suffix =_prev, where_clause = %str(previnc_def in ("Both","Prev")), 
				                      convar = followuptime, catvar = fupdays_value_cat,
				                      dplocalflaglist = fup_elig fup_dth fup_dpend fup_qryend fup_episend fup_spec fup_event,
				 				      msocflaglist = cens_elig cens_dth cens_dpend cens_qryend cens_episend cens_spec cens_event);
              %end; 
           %end;
           %else %do;
			    %ms_createcensortable(table = censor, convar = timetocensor, catvar = censdays_value_cat,
				                      dplocalflaglist = cens_elig cens_dth cens_dpend cens_qryend,
									  msocflaglist = cens_elig cens_dth cens_dpend cens_qryend);
           %end;
        %end;

        *ITS analysis;
        %if %eval(&ITSANALYSIS.=1) %then %do;
            %if %eval(&type=2) %then %do;
                %ms_its (ds_suffix =, where_clause = %str(and PrevInc = "Inc")
                      ,data = %if %eval(&overlap.=1) %then %do;_mstr_overlap %end; %else %do; _mstr_multevent %end;);
                %if %index(&tables.,t2itsprev) >0 %then %do;
                   %ms_its (ds_suffix =_prev, where_clause = %str(and previnc_def in ("Both","Prev"))
                      ,data = %if %eval(&overlap.=1) %then %do;_mstr_overlap %end; %else %do; _mstr_multevent %end;);
                %end;
            %end;
        %end;

    *delete undocumented vars from MSTR;
    data dplocal.&RUNID._mstr&preg.(drop=EndFollowUpType blackoutper);
        set dplocal.&RUNID._mstr&preg.;
        if _n_ = 1 then do;
            dsid = open("dplocal.&RUNID._mstr&preg.");
                if varnum(dsid,"EndFollowUpType") = 0 then EndFollowUpType ='';
                if varnum(dsid,"blackoutper") = 0 then blackoutper =.;
            rc= close(dsid);
        end;
        drop rc dsid;

        %if %eval(&type.=5) %then %do;
            drop FEventDt; 
        %end;
    run;
            
    proc datasets library=work nowarn nolist;
        delete &cohortcodes. drugs drugscomb ENR_MD30 LABEXTRACT DeathExtract meds &MONITORINGFILE. &inclusioncodes. Enr_:
            PreMeds ElixMeds covmeds PreDrugs Monitoringfileflm Premeds Ptslist Studynames _: STOCKPILE_NONCOVAR;
    quit;


    /*plus: logistic regressions*/

    %isdata(dataset=infolder.&ormodelfile.);
    %if %eval(&nobs.>0) %then %do;
        %let orcompnumber = &nobs.;

        ods listing close;

        *Initialize output table;
        data msoc.&runid._oddsratios;
            format group $40. modelnum 8. race $1. byvarvalue $30. npts numevents 8. var 8.4 or lowerci upperci oddsr8.3 pvalue pvalue6.4;
            call missing(group, modelnum, race, byvarvalue, npts, numevents, or, var, lowerci, upperci, pvalue);
            stop;
        run;

        /*Create squared race and urban_cat dataset - will square all race values, regardless of reference vaue*/
        data _square_race_urban;
            format variable $9. ClassVal0 $1. urban_cat $30.;
            variable = "race";
            %do v =0 %to 5;
                ClassVal0 = "&v.";
                urban_cat = 'Urban'; output;
                urban_cat = 'Rural'; output;
                urban_cat = 'Suburban'; output;
                urban_cat = 'Unknown'; output;
            %end;
        run;

        /*sort by urban_cat for by statement*/;
        proc sort data=dplocal.&runid._ads_mstr_1 out=&runid._ads_mstr_1;
            by urban_cat;
        run;

        /*Add dummy vars (for diagnostics)*/
        data &runid._ads_mstr_1;
            set &runid._ads_mstr_1;

              length sex_f sex_m race_0 race_1 race_2 race_3 race_4 race_5 3;

              if sex="F" then sex_F=1;else sex_F=0;
              if sex="M" then sex_M=1;else sex_M=0;
              if race="0" then race_0=1; else race_0 = 0;
              if race="1" then race_1=1; else race_1 = 0;
              if race="2" then race_2=1; else race_2 = 0;
              if race="3" then race_3=1; else race_3 = 0;
              if race="4" then race_4=1; else race_4 = 0;
              if race="5" then race_5=1; else race_5 = 0;

              length pat 3;
              pat = 1;
        run;

        /*Number of patients and number of events*/
        proc means data=&runid._ads_mstr_1 noprint;
            var pat event;
            class group race urban_cat all_ses_known;
            output out=totalcounts(drop=_:) sum=npts numevents;
        run;

        *loop through each model;
        %do comp = 1 %to %eval(&orcompnumber.);

            data _null_;
                set infolder.&ormodelfile.;
                if _n_ = &comp. then do;                
                    call symputx('orgroup', lowcase(strip(group))); 
                    call symputx('modelnum', modelnum);
                    call symputx('orclass', lowcase(class));
                    call symputx('ornoclass', lowcase(noclass));
                    call symputx('racelevel', racelevel);
                    call symputx('byvar', lowcase(byvar));
                    call symputx('whereclause', where);
                end;
            run;

            /*check at least 1 event in model*/
            %let eventexists = N;
            data _null_;
                set &runid._ads_mstr_1(where=(group="&orgroup." %if %length(&whereclause.)>0 %then %do; and &whereclause. %end;));
                if event = 1 then do;
                    call symputx('eventexists', 'Y');
                    stop;
                end;
            run;

            %if &eventexists = N %then %do;
                %put WARNING: (Sentinel) Group &orgroup. and model &modelnum. does not have any events. Model will be skipped; 
                %goto skiplogistic;
            %end;

            /*if byvar is specified - remove any categories that do not have events*/
            %let byvarmissinglist =;
            %if %length(&byvar.)>0 %then %do;
                proc means data=&runid._ads_mstr_1(where=(group="&orgroup." %if %length(&whereclause.)>0 %then %do; and &whereclause. %end;)) nway noprint;
                    var event;
                    class &byvar.;
                    output out=_tmpeventcount(drop=_:) sum=sumevent;
                run;

                proc sql noprint;
                   select quote(strip(&byvar.),"'") into: byvarmissinglist separated by ', '
                   from _tmpeventcount
                   where sumevent <=0;
                quit;
            %end;

            /*select dummy vars*/
            %let racevars = %sysfunc(tranwrd(race_0 race_1 race_2 race_3 race_4 race_5, race_&racelevel.,%str() ));
            /*sex only variable needing dummy coding*/
            %let orclass = %sysfunc(tranwrd(&orclass., sex, sex_f ));
         
            %if %length(&byvar.)>0 %then %do;
                %if &byvar. ne urban_cat %then %do;
                    %put WARNING: (Sentinel) BYVAR can only be populated with URBAN_CAT;
                %end;
            %end;

            /*Must have at least 1 patient with race reference level
                /*if no patients with racelevel - skip logistic. if patients exist in certain BY groups, then run logistic
                  using only those BY groups */
            proc means data=&runid._ads_mstr_1(where=(group="&orgroup." %if %length(&whereclause.)>0 %then %do; and &whereclause. %end;
                                                      %if %length(&byvarmissinglist.)>0 %then %do; and &byvar. not in (&byvarmissinglist.) %end; )) nway noprint;
                var pat;
                class race &byvar.;
                output out=_tmpracecount(drop=_:) sum=;
            run;

            %if %length(&byvar.)>0 %then %do;
                %let racelevelmissing = Y;

                proc sql noprint;
                   select quote(strip(&byvar.),"'") into: racelevelmissing separated by ', '
                   from _tmpracecount
                   where race = "&racelevel" and pat >0;
                quit;
                %put &racelevelmissing;
            %end;
            %else %do;
                %let racelevelmissing = Y;
                /*skip model*/
                data _null_;
                    set _tmpracecount;
                    if race = "&racelevel" and pat >0 then call symputx('racelevelmissing', 'N');
                run;
            %end;

            %if &racelevelmissing = Y %then %do;
                %goto skiplogistic;
            %end;

            title modeling group = &orgroup. and model = &modelnum.;

            *Run model;
            ods rtf file="&MSOC.&RUNID._runmodel_&orgroup._&modelnum..rtf";
            ods output Association = fit;
            ods output ConvergenceStatus = converge;
            ods output Nobs = Nobs;
            ods output SimpleStatistics = simple;
            ods output IterHistory = itprint;
            ods output ParameterEstimates = param;
            ods output CLOddsWald = clodds;
            proc logistic data = &runid._ads_mstr_1(where=(group="&orgroup." %if %length(&whereclause.)>0 %then %do; and &whereclause. %end;
                                                            %if %length(&byvarmissinglist.)>0 %then %do; and &byvar. not in (&byvarmissinglist.) %end; 
                                                            %if %length(&racelevelmissing.)>0 and &racelevelmissing. ne N %then %do; and &byvar. in (&racelevelmissing.) %end; )) descending simple;
                 model event = &racevars &orclass &ornoclass / clodds=wald firth itprint;
                 %if %length(&byvar.)>0 %then %do;
                     by &byvar.;
                 %end;
            run;
            ods rtf close;
            title;

            /*diagnostics*/
                *remove sex b/c need to dummy code;
                %if %index(&orclass, sex_f)>0 %then %let orclass = &orclass sex_m;

                /*correlations*/
                ods output PearsonCorr=corrs;
                  proc corr data=&runid._ads_mstr_1(where=(group="&orgroup." %if %length(&whereclause.)>0 %then %do; and &whereclause. %end;));
                  var race_0 race_1 race_2 race_3 race_4 race_5 &orclass. &ornoclass.;
                  run;
                ods output close;

                data corrs;
                    set corrs;
                    keep variable race_0 race_1 race_2 race_3 race_4 race_5 &orclass. &ornoclass.;
                run;
                proc sort data=corrs;
                    by Variable;
                run;
                proc transpose data=corrs out=corrst;
                    by Variable;
                run;

                data finalcorrst;
                  length Variable _NAME_ $32 modelnum 3;
            	  format group $40.;
                    set corrst;
                    rename Variable=Var1
                           _NAME_=Var2
                           col1=Corr;
            		group="&orgroup.";
            		modelnum=1;
                run;

                proc append base=msoc.&RUNID._corr data=finalcorrst force;
                run;

                /*runreg*/
    	        ods rtf file="&MSOC.&RUNID._runreg_&orgroup._&modelnum..rtf";
                    ODS GRAPHICS OFF;
                    TITLE "OLS Regression with Group of Interest=&orgroup. and model &modelnum.";
                      proc reg data=&runid._ads_mstr_1(where=(group="&orgroup." %if %length(&whereclause.)>0 %then %do; and &whereclause. %end;));
                      model event = &racevars. &orclass. &ornoclass. /COLLINOINT VIF;
                        %if %length(&byvar.)>0 %then %do;
                             by &byvar.;
                        %end;
                      quit;
                    TITLE;
                    ODS GRAPHICS ON;
                ods rtf close;

            /*skipped model if no events or no patients with reference race level*/
            %skiplogistic:

            *Defensive incase output datasets are not produced / model skipped
            *Write Sentinel Note if model run and datasets not created;
            %isdata(dataset=param);
            %if %eval(&nobs.<1) %then %do;
                %if &eventexists = Y | &racelevelmissing = Y %then %do;
                    %put NOTE: (Sentinel) ParameterEstimates not produced for group &orgroup. and model &modelnum.;
                %end;
                data param;
                    format variable $9. ClassVal0 $1. StdErr 8.4 ProbChiSq PVALUE6.4 urban_cat $30.;
                    call missing(variable,ClassVal0, StdErr, ProbChiSq, urban_cat);
                    stop;
                run;
            %end;
            %if %sysfunc(exist(clodds))=0 %then %do;
                %if &eventexists = Y %then %do;
                    %put NOTE: (Sentinel) CLOddsWald not produced for group &orgroup. and model &modelnum.;
                %end;
                data clodds;
                    format variable $9. ClassVal0 effect $1. OddsRatioEst lowercl uppercl oddsr8.3 urban_cat $30.;
                    call missing(variable,ClassVal0, effect, OddsRatioEst, lowercl, uppercl, urban_cat);
                    stop;
                run;
            %end;   
            %else %do;
                /*extract effect value*/
                data clodds;
                    set clodds;
                    length ClassVal0 $1;
                    ClassVal0 = substr(effect,6,1);
                    variable = substr(effect,1,4);
                run;
            %end; 

            *Merge to create output dataset; 
            proc sql;
                create table _or as
                select distinct "&orgroup." as group format=$40. length=40,
                       &modelnum. as modelnum,
                       a.ClassVal0 as race,
                       %if %length(&byvar.)>0 %then %do;
                       a.&byvar. as byvarvalue format=$30. length=30,
                       %end;
                       %else %do;
                       '' as byvarvalue format=$30. length=30,
                       %end;
                       x.OddsRatioEst as or,
                       y.StdErr**2 as var format=8.4,
                       x.lowercl as lowerci,
                       x.uppercl as upperci,
                       y.ProbChiSq as pvalue,
                       case when z.npts = . then 0
                       else z.npts end as npts,
                       case when z.numevents = . then 0
                       else z.numevents end as numevents
                from _square_race_urban as a
                left join param(where=(lowcase(substr(variable,1,4)) = 'race')) as y
                    on a.ClassVal0 = substr(y.variable,6,1)
                    %if %length(&byvar.)>0 %then %do;
                        and a.&byvar. = y.&byvar.
                    %end; 
                left join clodds(where=(lowcase(variable) = 'race')) as x
                    on substr(y.variable,6,1) = x.ClassVal0
                    %if %length(&byvar.)>0 %then %do;
                     and x.&byvar. = y.&byvar.
                    %end;
                left join totalcounts(where=(group="&orgroup." 
                                      %if %length(&whereclause)>0 %then %do; and all_ses_known = 1 %end;
                                      %else %do; and missing(all_ses_known)=1 %end;
                                      %if %length(&byvar)=0 %then %do; and missing(urban_cat) = 1 %end;)) as z
                    on a.ClassVal0 = z.race
                    %if %length(&byvar.)>0 %then %do;
                     and a.&byvar. = z.&byvar.
                    %end;
                 ;
            quit;

            proc append base=msoc.&runid._oddsratios data=_or force; run;

            proc datasets nowarn noprint lib=work;
                delete param clodds _or fit converge nobs simple itprint finalcorrst corrs:;
            quit;

        %end;   

        proc datasets nowarn noprint lib=work;
            delete totalcounts &runid._ads_mstr;
        quit;

        ods listing;
    %end;

    /************************************************/
    /* Propensity Score/Covariate adjusted analysis */
    /************************************************/

   %if "&run_ps_cov_analysis." = "Y" %then %do;
        proc printto log="&MSOC.&RUNID._covariateadjustment.log" new;
        run;

        %if %eval(&type.=2) %then %do;
            %ms_covariateadjustment(indata=dplocal.&runid._ads_mstr);
        %end;
        %if %eval(&type.=4) %then %do;
            %ms_covariateadjustment(indata=dplocal.&runid._ads_mstr_mi);
        %end;

        proc printto log="&MSOC.&RUNID._cida.log";
        run;
    %end;

    proc datasets library=worktemp nowarn nolist;
        delete _: drugs lab: mil: death: meds: drug: denom: enr_: enc:;
    quit;

    /****************************/
    /* Freeze Patients Data - M */
    /****************************/
    %macro wrapper();
        %if %str("&FREEZEDATA.")=%str("m") %then %do;

            %ms_starttimer(timestart=freezeruntime);

            data _PtsList(keep=patid);
                set
                %do look=%eval(&periodidstart.) %to %eval(&periodidend.);
                 dplocal.&runid._adjusted_&look.(keep=patid matchid)
                %end;
                ;
                where missing(matchid)=0;
            run;

            %if %eval(&type.=4) %then %do;
                data _PtsList2(rename=linkedid=patid);
                    set
                    %do look=%eval(&periodidstart.) %to %eval(&periodidend.);
                     dplocal.&runid._adjusted_&look.(keep=linkedid matchid);
                    %end;
                    ;
                    where missing(matchid) and missing(linkedid)=0;
                    keep linkedid;
                run;

                data _ptslist;
                    set _PtsList _PtsList2;
                run;
            %end;

            %isdata(dataset=_PtsList);
            %if %eval(&nobs.>0) %then %do;            
                %IF %STR(&ENRTABLE.) ne %STR() or %LENGTH(&ENRTABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&ENRTABLE, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._enrtable);%END;            
                %IF %STR(&DEMTABLE.) ne %STR() or %LENGTH(&DEMTABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&DEMTABLE, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._demtable);%END;            
                %IF %STR(&DISTABLE.) ne %STR() or %LENGTH(&DISTABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&DISTABLE, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._distable);%END;            
                %IF %STR(&DIATABLE.) ne %STR() or %LENGTH(&DIATABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&DIATABLE, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._diatable);%END;           
                %IF %STR(&PROCTABLE.) ne %STR() or %LENGTH(&PROCTABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&PROCTABLE,PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._proctable);%END;            
                %IF %STR(&ENCTABLE.) ne %STR() or %LENGTH(&ENCTABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&ENCTABLE, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._enctable);%END;           
                %IF %STR(&LABTABLE.) ne %STR() or %LENGTH(&LABTABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&LABTABLE, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._labtable);%END;           
                %IF %STR(&VITTABLE.) ne %STR() or %LENGTH(&VITTABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&VITTABLE, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._vittable);%END;            
                %IF %STR(&DEATHTABLE.) ne %STR() or %LENGTH(&DEATHTABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&DEATHTABLE, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._deathtable);%END;
                %IF %STR(&MILTABLE.) ne %STR() or %LENGTH(&MILTABLE.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&MILTABLE, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._miltable);%END;
                %IF %STR(&pretable.) ne %STR() or %LENGTH(&pretable.) > 0. %THEN %DO;%MS_FREEZEDATA(INFILE=indata.&pretable, PATLISTINFILE=_PtsList,OUTFILE=freedir.&RUNID._pretable);%END;

                /*Facility and provider table are lookup tables without patID - will freeze entire table*/
                %IF %STR(&factable.) ne %STR() or %LENGTH(&factable.) > 0. %THEN %DO;
                    data freedir.&RUNID._factable;
                        set indata.&factable.;
                    run;
                %end;
                %IF %STR(&pvdtable.) ne %STR() or %LENGTH(&pvdtable.) > 0. %THEN %DO;
                    data freedir.&RUNID._pvdtable;
                        set indata.&pvdtable.;
                    run;
                %end;

                *This datalib will point to the subset of PatId data generated by Freeze data;
                %let datalib_enr=freedir.&runid._enrtable;
                %let datalib_dem=freedir.&runid._demtable;
                %let datalib_dis=freedir.&runid._distable;
                %let datalib_dia=freedir.&runid._diatable;
                %let datalib_proc=freedir.&runid._proctable;
                %let datalib_enc=freedir.&runid._enctable;
                %let datalib_lab=freedir.&runid._labtable;
                %let datalib_vit=freedir.&runid._vittable;
                %let datalib_death=freedir.&runid._deathtable;
                %let datalib_mil=freedir.&runid._miltable;
                %let datalib_pre=freedir.&runid._pretable;
            %end;

            /*Output freezedata runtime*/
            %ms_stoptimer(timestart=freezeruntime);
            %ms_outputruntimes(timevar=freezeruntime, step=%str(Freeze Data), group=, monitoringperiod=);
        %end;
    %mend wrapper;
    %wrapper();

    /*******************/
    /* Tree extraction */
    /*******************/
    %if "&analysis" = "tree" %then %do;
        %if %eval(&type.=2) | %eval(&type.=4) %then %do;
            %isdata(dataset=dplocal.&runid._adjusted_&periodidstart.);
            %if %eval(&nobs.>0) %then %do;
            %ms_treeextraction(data=dplocal.&runid._adjusted_&periodidstart.(where=(missing(matchid)=0 and missing(subgroup))), grp=analysisgrp);
            %end;
        %end;
        %if %eval(&type.=3) %then %do;
            %isdata(dataset=dplocal.&runid._mstr);
            %if %eval(&nobs.>0) %then %do;
            %ms_treeextraction(data=dplocal.&runid._mstr, grp=group);
            %end;
        %end;
    %end;

    * Reset global macro variables;
    %let COMBORUN=;

    *Create the number of groups to create cohorts (into NOBS);
    %ISDATA(dataset=infolder.&COHORTFILE.);

    /*Output QRP runtime*/
    %ms_stoptimer(timestart=qrpruntime);

    data msoc.&runid._runtimes;
        set msoc.&runid._runtimes;
        if step = 'QRP Runtime' then do;
            format start stop datetime21.2; 
            start=input("&qrpruntime.",best.); 
            stop=input("&STOP.",best.);   
            format Seconds $20.;
            Seconds=put(int(&stop.-&qrpruntime.),best.)||" s";
            enddate = "&qrpruntimeenddate."; 
            endtime = "&qrpruntimeendtime.";
            runtime = strip("&hours. h &minutes. m &seconds. s");
            drop start stop seconds;
        end;
    run;
 
    *Signature file;
    data signature;
    
        /*Request meta data*/
        ReqID="&REQID.";
        ProjID="&PROJID.";  
        WPType="&WPTYPE.";
        WPID="&WPID.";
        DPID="&DPID.";
        VerID="&VERID.";
        RunID="&RUNID.";
        MPVer="&QRPVer.";
        CustomCodeVersion="&CustomCodeVer.";

        format StartTime StopTime datetime21.2; 
        StartTime=input("&qrpruntime.",best.); 
        StopTime=input("&STOP.",best.);   
        format Seconds $20.;
        Seconds=put(int(&stop.-&qrpruntime.),best.)||" s";
        ExecutionTime="&hours. h &minutes. m &seconds. s";    

        /*Data Partner meta data*/
        DP="&DP.";
        format DPMINDATE DPMAXDATE date9.;
        DPMINDATE=&DP_MinDate.;
        DPMAXDATE=&DP_MaxDate.;
        PATIDEXCL="&PATIDEXCL.";
        ETLNUMBER="&ETL.";
        BYPASSCC="&ccbypass.";
        SCDMVERSION="&scdmver.";
        RUNTYPE="&SYSENV.";
        SASVERSION="&SYSVER.";
        SASVERSIONLONG="&SYSVLONG.";
        OSABBR="&SYSSCP.";
        OSNAME="&SYSSCPL.";
        NCPU="&SYSNCPU.";

        /*Run Parameters*/
        ScenarioCnt=strip("&NOBS.");
        PERIODIDSTART="&PERIODIDSTART.";
        PERIODIDEND="&PERIODIDEND.";
        ANALYSIS="&ANALYSIS.";
        MONITORINGFILE="&MONITORINGFILE.";
        USERSTRATA="&USERSTRATA";
        COMBOFILE="&COMBOFILE.";
        COHORTFILE="&COHORTFILE.";
        COHORTCODES="&COHORTCODES.";
        INCLUSIONCODES="&INCLUSIONCODES.";
        STOCKPILINGFILE="&STOCKPILINGFILE.";
        RUN_ENVELOPE = "&RUN_ENVELOPE.";
        FREEZEDATA="&FREEZEDATA.";
        ZIPFILE="&ZIPFILE.";
        LABSCODEMAP="&LABSCODEMAP.";
        DISTINDEX = "&DISTINDEX.";
        TYPE1FILE="&TYPE1FILE.";
        TYPE2FILE="&TYPE2FILE.";
        TYPE3FILE="&TYPE3FILE.";
        TYPE4FILE="&TYPE4FILE.";
        MODPREGDUR="&MODPREGDUR.";    
        TYPE5FILE="&TYPE5FILE.";
        TYPE6FILE="&TYPE6FILE.";
        METADATAFILE="&METADATAFILE.";
        SURVEILLANCEMODE = "&SURVEILLANCEMODE";
        COVARIATECODES="&COVARIATECODES.";
        UTILFILE="&UTILFILE.";
        COMORBFILE="&COMORBFILE.";
        DRUGCLASSFILE="&DRUGCLASSFILE.";
        PROFILE = "&PROFILE.";
        MFUFILE="&MFUFILE.";
        MULTEVENTFILE="&MULTEVENTFILE.";
        MULTEVENTFILE_ADHERE="&MULTEVENTFILE_ADHERE.";
        CONCFILE="&CONCFILE.";
        OVERLAPFILE="&OVERLAPFILE.";
        OVERLAPFILE_ADHERE="&OVERLAPFILE_ADHERE.";
        ITSFILE="&ITSFILE.";
        TREATMENTPATHWAYS="&TREATMENTPATHWAYS.";
        MICOHORTFILE="&MICOHORTFILE.";
        TREEFILE="&TREEFILE.";
        TREELOOKUP="&TREELOOKUP.";
        ICD10ICD9MAP="&ICD10ICD9MAP.";

        /*Matching parameters*/
        PSESTIMATIONFILE="&PSESTIMATIONFILE.";
        PSMATCHFILE = "&PSMATCHFILE.";
        STRATIFICATIONFILE = "&STRATIFICATIONFILE.";
        COVSTRATFILE = "&COVSTRATFILE.";
        IPTWFILE = "&IPTWFILE.";
        PSCSSUBGROUPFILE = "&PSCSSUBGROUPFILE.";
        %if "&runhdps" = "Y" %then %do;
        HDVARSEL_INPUT="&HDVARSEL_INPUT.";
        %end;
        %else %do;
        HDVARSEL_INPUT="";
        %end;   
        INDLEVEL="&INDLEVEL.";
        DIAGNOSTICS="&DIAGNOSTICS.";

        output;
    run;

    proc transpose data=signature out=msoc.&runid._signature(rename=_NAME_=Var rename=COL1=VALUE);
       var _ALL_;
    run;

    data msoc.&RUNID._signature;
        set msoc.&RUNID._signature;
        value = strip(value);
    run;

    /*save SCDM specific meta data to separate signature file in FREEZEDATA directory*/
    %if %str("&FREEZEDATA.")=%str("y") | %str("&FREEZEDATA.")=%str("a") | %str("&FREEZEDATA.")=%str("m") %then %do;
        data freedir.&RUNID._signature_freezedata;
            set msoc.&RUNID._signature;
            where upcase(var) in ('DPMINDATE', 'DPMAXDATE', 'ETLNUMBER', 'BYPASSCC', 'SCDMVERSION');
        run;
    %end;

    %put NOTE: ********END OF MACRO: ms_cidanum ********;

%mend ms_cidanum;