*! 1.0.0 06Jun2020  // Ariel Linden, Chuck Huber, Geoffrey T. Wodtke
*! 1.0.1 26Mar2021  // Ariel Linden, Chuck Huber, Geoffrey T. Wodtke
                    // Chuck updated updated the output with SMCL


program define rwrmed, eclass

	version 14

	syntax varlist(min=1 numeric) [if][in] [pweight],		 	///
		avar(varname numeric)									///
		mvar(varname numeric)									///
		a(real) 												///
		astar(real) 											///
		m(real)													///
		[ mreg(string) 											/// default is regress
		cvar(varlist numeric)									///
		CAT(varlist numeric)									/// specify categorical variables
		cxa														/// interaction between cvar and avar
		cxm														/// interaction between cvar and mvar
		lxm														/// interaction between lvar and mvar
		NOIsily													/// display SEM output (not available for bootstrap)
		NOINTERaction											/// no interaction between treatment and mediator
		BOOTstrap BOOTstrap2(string) * ]


		qui {
			marksample touse
			count if `touse'
			if r(N) == 0 error 2000
			local N = r(N)
			replace `touse' = -`touse'
		}

		* parse to get yvar and lvars
		gettoken yvar lvar : varlist

		* parse and assess whether vce() has been specified, and if not, set vce(robust)
        gettoken before after : 0, parse(",") bind match(par) quotes

		if regexm("`after'","vce") == 0 {
			local vcetype "vce(robust)"
		}

		* set default mediator model to regress
		if "`mreg'" == "" local mreg regress

		* verify correct model is chosen
		local mregtypes regress logit poisson
		if !inlist(substr("`mreg'", 1, 3), "reg", "log", "poi") {
				display as error "Error: mreg must be chosen from: `mregtypes'."
				exit 198
		}

		****************
		// if Bootstrap
		****************

		if `"`bootstrap'`bootstrap2'"' != ""  {

			local bootstrap `", `bootstrap2'"'
			parse_bootstrap_options `bootstrap'

			type_text , mreg(`mreg')
			local NDE "e(`r(NDEtype)')"
			local NIE "e(`r(NIEtype)')"
			local ATE "e(`r(ATEtype)')"

			type_text , mreg(`mreg') lvar(`lvar') cvar(`cvar')
			bootstrap CDE=e(CDE) `r(NDEtype)'=`NDE' `r(NIEtype)'=`NIE' `r(ATEtype)'=`ATE',  `s(bsoptions)' : ///
				rwrmed_calc `varlist' if `touse' [`weight' `exp'], avar(`avar') mvar(`mvar') a(`a') astar(`astar') ///
					m(`m') mreg(`mreg') cvar(`cvar') cat(`cat') `cxa' `cxm' `lxm' `nointeraction' `options'

			type_text , mreg(`mreg') lvar(`lvar') cvar(`cvar')
			local CDE_col = strpos("`r(NDEtext)'", ":") + 2
			di as txt "CDE:" _column(`CDE_col') "controlled direct effect at m=`m'"
			di as txt "{p2col 1 `CDE_col' `CDE_col' 0: `r(NDEtext)'}{p_end}"
			di as txt "{p2col 1 `CDE_col' `CDE_col' 0: `r(NIEtext)'}{p_end}"
			di as txt "{p2col 1 `CDE_col' `CDE_col' 0: `r(ATEtext)'}{p_end}"

		}

		********************
		// If not bootstrap
		********************
		if `"`bootstrap'`bootstrap2'"' == ""  {

			rwrmed_margins `varlist' if `touse' [`weight' `exp'], avar(`avar') mvar(`mvar') a(`a') astar(`astar') m(`m') mreg(`mreg') ///
				cvar(`cvar') cat(`cat') `cxa' `cxm' `lxm' `noisily' `nointeraction' `vcetype' `options'

		} // end not bootstrap

		ereturn local cmdline `"rwrmed `0'"'

end


capture program drop rwrmed_margins
program define rwrmed_margins, eclass

	version 14

	syntax varlist(min=1 numeric) [if][in] [pweight],		 	///
		avar(varname numeric)									///
		mvar(varname numeric)									///
		a(real) 												///
		astar(real) 											///
		m(real)													///
		[ mreg(string) 											/// default is regress
		cvar(varlist numeric)									///
		CAT(varlist numeric)									/// specify categorical variables
		cxa														/// interaction between cvar and avar
		cxm														/// interaction between cvar and mvar
		lxm														/// interaction between lvar and mvar
		NOIsily													/// display SEM output (not available for bootstrap)
		NOINTERaction * ]										/// no interaction between treatment and mediator


		qui {
			marksample touse
			count if `touse'
			if r(N) == 0 error 2000
			local N = r(N)
			replace `touse' = -`touse'
		}

		gettoken yvar lvar : varlist

		* set default mediator model to regress
		if "`mreg'" == "" local mreg regress

		* verify model name
		local mregtypes regress logit poisson
		if !inlist(substr("`mreg'", 1, 3), "reg", "log", "poi") {
				display as error "Error: mreg must be chosen from: `mregtypes'."
				exit 198
		}

		// generate treatment X mediator interaction
		if "`nointeraction'" == "" {
			tempvar inter
			qui gen `inter' = `avar'*`mvar' if `touse'
		}
		// residualize pre-treatment covariates
		qui if "`cvar'"!="" {
			foreach c in `cvar' {
				local ctest : list c in cat
				* categorical variables
				if `ctest' == 1 {
					levelsof `c' if `touse', local(levels)
					local levcnt: word count `levels'
					if `levcnt' < 2 {
                        di as err "`c' must have at least 2 levels."
						exit 198
					}
					* binary
					else if `levcnt' == 2 {
						regress `c' [`weight' `exp'] if `touse'
						tempvar `c'_r
						predict ``c'_r' if e(sample), resid
						* residualized cvars
						local cvar_r `cvar_r' ``c'_r'
						* revised cvars
						local cvarlist `cvarlist' `c'
					}
					* else multicategorical
					else if `levcnt' > 2 {
						sum `c' if `touse', meanonly
						local min = `r(min)'
						levelsof `c' if `c' > `min' & `touse', local(levels)
						foreach i of local levels {
							tempvar `c'`i'
							gen ``c'`i'' = (`c'==`i') if `touse'
							regress ``c'`i'' [`weight' `exp'] if `touse'
							tempvar `c'_r`i'
							predict ``c'_r`i'' if e(sample), resid
							* residualized cvars
							local cvar_r `cvar_r' ``c'_r`i''
							* revised cvars
							local cvarlist `cvarlist' ``c'`i''
						} // foreach
					} // end levcnt > 2
				} // end ctest == 1
				* else continuous
				else {
					regress `c' [`weight' `exp'] if `touse'
					tempvar `c'_r
					predict ``c'_r' if e(sample), resid
					* residualized cvars
					local cvar_r `cvar_r' ``c'_r'
					* revised cvars
					local cvarlist `cvarlist' `c'
				} // end ctest == 0
			} // end foreach
		} // end if cvar

		// generate avar X cvar interactions
		if "`cxa'"!="" {
			foreach c in `cvar_r' {
				tempvar `avar'X`c'
				gen ``avar'X`c'' = `avar' * `c' if `touse'
				local cxa_r `cxa_r'  ``avar'X`c''
			}
		}

		// generate mvar X cvar interactions
		if "`cxm'"!="" {
			foreach c in `cvar_r' {
				tempvar `mvar'X`c'
				gen ``mvar'X`c'' = `mvar' * `c' if `touse'
				local cxm_r `cxm_r'  ``mvar'X`c''
			}
		}

		// residualize post-treatment covariates
		qui if "`lvar'"!="" {
			foreach l in `lvar' {
				local ltest : list l in cat
				if `ltest' == 1 {
					levelsof `l' if `touse', local(levels)
					local levcnt: word count `levels'
					if `levcnt' == 2 {
						capture logit `l' `avar' `cvarlist' `cxa_r' [`weight' `exp'] if `touse'
						capture assert e(rank) == e(k)
						if _rc==9 {
							display "`l' has values that lead to perfect prediction, and thus observations were dropped"
						}
						tempvar `l'_r
						predict ``l'_r' if e(sample), pr
						replace ``l'_r' = `l' - ``l'_r' if `touse'
						local lvar_r `lvar_r' ``l'_r'
					}
					else if `levcnt' > 2 {
						sum `l' if `touse', meanonly
						local min = `r(min)'
						levelsof `l' if `l' > `min' & `touse', local(levels)
						foreach i of local levels {
							tempvar `l'`i'
							gen ``l'`i'' = (`l'==`i') if `touse'
							capture logit ``l'`i'' `avar' `cvarlist' `cxa_r' [`weight' `exp'] if `touse'
							if _rc==430 {
								noisily di _n
								di as err "A model could not converge when residualizing level `i' of `l'."
								di as err "Consider either collapsing this variable into fewer categories, or treat it as a continuous variable"
								exit 430
							}
							capture assert e(rank) == e(k)
							if _rc==9 {
								noisily di _n
								di as err "When residualing level `i' of `l', the model had values that lead to perfect prediction, and thus observations were dropped."
								di as err "Consider either collapsing `l' into fewer categories, or treat it as a continuous variable"
							}
							tempvar `l'_r`i'
							predict ``l'_r`i'' if e(sample), pr
							replace ``l'_r`i'' = ``l'`i'' - ``l'_r`i'' if `touse'
							local lvar_r `lvar_r' ``l'_r`i''
						} // foreach
					} // end levcnt > 2
				} // end ltest == 1
				else {
					regress `l' `avar' `cvarlist' `cxa_r' [`weight' `exp'] if `touse'
					tempvar `l'_r
					predict ``l'_r' if e(sample), resid
					local lvar_r `lvar_r' ``l'_r'
				} // end ltest == 0
			} // end foreach
		} // end if lvar

		// generate mvar X lvar interactions
		if "`lxm'"!="" {
			foreach l in `lvar_r' {
				tempvar `mvar'X`l'
				gen ``mvar'X`l'' = `mvar' * `l' if `touse'
				local lxm_r `lxm_r'  ``mvar'X`l''
			}
		}

		// display SEM table (works with nlcom only)
		if "`noisily'" == ""  {
		    local qui "quietly"
		}


		*******************************
		// block 1: mreg=regress //
		*******************************
		if substr("`mreg'", 1, 3) == "reg" {

			// no interaction
			if "`nointeraction'" != "" {

				`qui' gsem (`yvar' <- `avar' `mvar' `cvar_r' `lvar_r' `cxa_r' `cxm_r' `lxm_r' [`weight' `exp'] if `touse', regress) ///
							(`mvar' <- `avar' `cvar_r' `cxa_r' , regress), `options'

				estimates store gsem

				local CDE  "_b[`yvar':`avar'] * (`astar'-`a')"
				local NDE  "_b[`yvar':`avar'] * (`astar'-`a')"
				local NIE  "_b[`mvar':`avar'] * _b[`yvar':`mvar'] *(`astar'-`a')"
				local ATE "(`NDE') + (`NIE')"

				qui {
					*CDE
					margins, expression(`CDE') vce(unconditional) post
					matrix cdeB = e(b)
					matrix cdeV = e(V)
					scalar aS = cdeV[1,1]
					mat colname cdeB = CDE

					* NDE
					estimates restore gsem
					margins, expression(`NDE') vce(unconditional) post
					matrix ndeB = e(b)
					matrix ndeV = e(V)
					scalar bS = ndeV[1,1]
					matrix colname ndeB = NDE

					* NIE
					estimates restore gsem
					margins, expression(`NIE') vce(unconditional) post
					matrix nieB = e(b)
					matrix nieV = e(V)
					scalar cS = nieV[1,1]
					mat colname nieB = NIE

					* ATE
					estimates restore gsem
					margins, expression(`ATE') vce(unconditional) post
					matrix ateB = e(b)
					matrix ateV = e(V)
					scalar dS = ateV[1,1]
					matrix colname ateB = ATE

					matrix b = cdeB, ndeB, nieB, ateB
					matrix V = (aS,0,0,0\0,bS,0,0\0,0,cS,0\0,0,0,dS)

					type_text , mreg(`mreg') lvar(`lvar') cvar(`cvar')
					matrix colname b = CDE "`r(NDEtype)'"  "`r(NIEtype)'"  "`r(ATEtype)'"
					matrix rowname V = CDE "`r(NDEtype)'"  "`r(NIEtype)'"  "`r(ATEtype)'"
					matrix colname V = CDE "`r(NDEtype)'"  "`r(NIEtype)'"  "`r(ATEtype)'"

				} // end quietly
				estimates drop gsem
				ereturn post b V
				ereturn display

				type_text , mreg(`mreg') lvar(`lvar') cvar(`cvar')
				local CDE_col = strpos("`r(NDEtext)'", ":") + 2
				di as txt "CDE:" _column(`CDE_col') "controlled direct effect at m=`m'"
				di as txt "{p2col 1 `CDE_col' `CDE_col' 0: `r(NDEtext)'}{p_end}"
				di as txt "{p2col 1 `CDE_col' `CDE_col' 0: `r(NIEtext)'}{p_end}"
				di as txt "{p2col 1 `CDE_col' `CDE_col' 0: `r(ATEtext)'}{p_end}"

			} // end nointeraction

			else if "`nointeraction'" == "" {

				`qui' gsem  (`yvar' <- `avar' `mvar' `inter' `cvar_r' `lvar_r' `cxa_r' `cxm_r' `lxm_r' [`weight' `exp'] if `touse', regress) ///
							(`mvar' <- `avar' `cvar_r' `cxa_r', regress) , `options'

				estimates store gsem

				local CDE  "(_b[`yvar':`avar'] + _b[`yvar':`inter'] * `m') * (`astar'-`a')"
				local NDE  "(_b[`yvar':`avar'] + _b[`yvar':`inter'] * (_b[`mvar':_cons] + _b[`mvar':`avar'] * `a')) * (`astar'-`a')"
				local NIE  "_b[`mvar':`avar'] * (_b[`yvar':`mvar'] + _b[`yvar':`inter'] * `astar') * (`astar'-`a')"
				local ATE "(`NDE') + (`NIE')"

				qui {
					*CDE
					margins, expression(`CDE') vce(unconditional) post
					matrix cdeB = e(b)
					matrix cdeV = e(V)
					scalar aS = cdeV[1,1]
					mat colname cdeB = CDE

					* NDE
					estimates restore gsem
					margins, expression(`NDE') vce(unconditional) post
					matrix ndeB = e(b)
					matrix ndeV = e(V)
					scalar bS = ndeV[1,1]
					matrix colname ndeB = NDE

					* NIE
					estimates restore gsem
					margins, expression(`NIE') vce(unconditional) post
					matrix nieB = e(b)
					matrix nieV = e(V)
					scalar cS = nieV[1,1]
					mat colname nieB = NIE

					* ATE
					estimates restore gsem
					margins, expression(`ATE') vce(unconditional) post
					matrix ateB = e(b)
					matrix ateV = e(V)
					scalar dS = ateV[1,1]
					matrix colname ateB = ATE

					matrix b = cdeB, ndeB, nieB, ateB
					matrix V = (aS,0,0,0\0,bS,0,0\0,0,cS,0\0,0,0,dS)

					type_text , mreg(`mreg') lvar(`lvar') cvar(`cvar')
					matrix colname b = CDE "`r(NDEtype)'"  "`r(NIEtype)'"  "`r(ATEtype)'"
					matrix rowname V = CDE "`r(NDEtype)'"  "`r(NIEtype)'"  "`r(ATEtype)'"
					matrix colname V = CDE "`r(NDEtype)'"  "`r(NIEtype)'"  "`r(ATEtype)'"

				} // end quietly
				estimates drop gsem
				ereturn post b V
				ereturn display

				type_text , mreg(`mreg') lvar(`lvar') cvar(`cvar')
				local CDE_col = strpos("`r(NDEtext)'", ":") + 2
				di as txt "CDE:" _column(`CDE_col') "controlled direct effect at m=`m'"
				di as txt "{p2col 1 `CDE_col' `CDE_col' 0: `r(NDEtext)'}{p_end}"
				di as txt "{p2col 1 `CDE_col' `CDE_col' 0: `r(NIEtext)'}{p_end}"
				di as txt "{p2col 1 `CDE_col' `CDE_col' 0: `r(ATEtext)'}{p_end}"

			} // end with interaction
		} // end mreg == regress


		**************************
		// block 2: mreg=logit //
		**************************
		if substr("`mreg'", 1, 3) == "log" {

			// no interaction
			if "`nointeraction'" != "" {

				`qui' gsem  (`yvar' <- `avar' `mvar' `cvar_r' `lvar_r' `cxa_r' `cxm_r' `lxm_r' [`weight' `exp'] if `touse', regress) ///
					(`mvar' <- `avar' `cvar_r' `cxa_r', logit) , `options'

				estimates store gsem

				local CDE  "_b[`yvar':`avar'] * (`astar'-`a')"
				local NDE  "_b[`yvar':`avar'] * (`astar'-`a')"
				local NIE `""_b[`yvar':`mvar'] * ((exp(_b[`mvar':_cons] + _b[`mvar':`avar'] * `astar') / (1 + exp(_b[`mvar':_cons] + _b[`mvar':`avar'] * `astar'))) - (exp(_b[`mvar':_cons]""'
				local NIE `"`NIE' " + _b[`mvar':`avar'] *`a') / (1 + exp(_b[`mvar':_cons] + _b[`mvar':`avar'] * `a'))))""'
				local ATE "(`NDE') + `NIE'"

				qui {
					*CDE
					margins, expression(`CDE') vce(unconditional) post
					matrix cdeB = e(b)
					matrix cdeV = e(V)
					scalar aS = cdeV[1,1]
					mat colname cdeB = CDE

					* NDE
					estimates restore gsem
					margins, expression(`NDE') vce(unconditional) post
					matrix ndeB = e(b)
					matrix ndeV = e(V)
					scalar bS = ndeV[1,1]
					matrix colname ndeB = NDE

					* NIE
					estimates restore gsem
					margins, expression(`NIE') vce(unconditional) post
					matrix nieB = e(b)
					matrix nieV = e(V)
					scalar cS = nieV[1,1]
					mat colname nieB = NIE

					* ATE
					estimates restore gsem
					margins, expression(`ATE') vce(unconditional) post
					matrix ateB = e(b)
					matrix ateV = e(V)
					scalar dS = ateV[1,1]
					matrix colname ateB = ATE

					matrix b = cdeB, ndeB, nieB, ateB
					matrix V = (aS,0,0,0\0,bS,0,0\0,0,cS,0\0,0,0,dS)

					type_text , mreg(`mreg') lvar(`lvar') cvar(`cvar')
					matrix colname b = CDE "`r(NDEtype)'"  "`r(NIEtype)'"  "`r(ATEtype)'"
					matrix rowname V = CDE "`r(NDEtype)'"  "`r(NIEtype)'"  "`r(ATEtype)'"
					matrix colname V = CDE "`r(NDEtype)'"  "`r(NIEtype)'"  "`r(ATEtype)'"

				} // end quietly
				estimates drop gsem
				ereturn post b V
				ereturn display

				type_text , mreg(`mreg') lvar(`lvar') cvar(`cvar')
				local CDE_col = strpos("`r(NDEtext)'", ":") + 2
				di as txt "CDE:" _column(`CDE_col') "controlled direct effect at m=`m'"
				di as txt "{p2col 1 `CDE_col' `CDE_col' 0: `r(NDEtext)'}{p_end}"
				di as txt "{p2col 1 `CDE_col' `CDE_col' 0: `r(NIEtext)'}{p_end}"
				di as txt "{p2col 1 `CDE_col' `CDE_col' 0: `r(ATEtext)'}{p_end}"

			} // end nointeraction

			// with interaction
			if "`nointeraction'" == "" {

				`qui' gsem  (`yvar' <- `avar' `mvar' `inter' `cvar_r' `lvar_r' `cxa_r' `cxm_r' `lxm_r' [`weight' `exp'] if `touse', regress) ///
					(`mvar' <- `avar' `cvar_r' `cxa_r', logit) , `options'

				estimates store gsem

				local CDE  "(_b[`yvar':`avar'] + _b[`yvar':`inter'] * `m')  *  (`astar'-`a')"
				local NDE  "(_b[`yvar':`avar'] + _b[`yvar':`inter'] * (exp(_b[`mvar':_cons] + _b[`mvar':`avar'] *`a') / (1 + exp(_b[`mvar':_cons] + _b[`mvar':`avar'] * `a')))) * (`astar'-`a')"
				local NIE  `""(_b[`yvar':`mvar'] + _b[`yvar':`inter'] * `astar') * ((exp(_b[`mvar':_cons] + _b[`mvar':`avar'] * `astar') / (1 + exp(_b[`mvar':_cons] + _b[`mvar':`avar'] * ""'
				local NIE `"`NIE' " `astar'))) - (exp(_b[`mvar':_cons] + _b[`mvar':`avar'] *`a') / (1 + exp(_b[`mvar':_cons] + _b[`mvar':`avar'] * `a'))))""'
				local ATE "(`NDE') + `NIE'"

				qui {
					*CDE
					margins, expression(`CDE') vce(unconditional) post
					matrix cdeB = e(b)
					matrix cdeV = e(V)
					scalar aS = cdeV[1,1]
					mat colname cdeB = CDE

					* NDE
					estimates restore gsem
					margins, expression(`NDE') vce(unconditional) post
					matrix ndeB = e(b)
					matrix ndeV = e(V)
					scalar bS = ndeV[1,1]
					matrix colname ndeB = NDE

					* NIE
					estimates restore gsem
					margins, expression(`NIE') vce(unconditional) post
					matrix nieB = e(b)
					matrix nieV = e(V)
					scalar cS = nieV[1,1]
					mat colname nieB = NIE

					* ATE
					estimates restore gsem
					margins, expression(`ATE') vce(unconditional) post
					matrix ateB = e(b)
					matrix ateV = e(V)
					scalar dS = ateV[1,1]
					matrix colname ateB = ATE

					matrix b = cdeB, ndeB, nieB, ateB
					matrix V = (aS,0,0,0\0,bS,0,0\0,0,cS,0\0,0,0,dS)

					type_text , mreg(`mreg') lvar(`lvar') cvar(`cvar')
					matrix colname b = CDE "`r(NDEtype)'"  "`r(NIEtype)'"  "`r(ATEtype)'"
					matrix rowname V = CDE "`r(NDEtype)'"  "`r(NIEtype)'"  "`r(ATEtype)'"
					matrix colname V = CDE "`r(NDEtype)'"  "`r(NIEtype)'"  "`r(ATEtype)'"

				} // end quietly
				estimates drop gsem
				ereturn post b V
				ereturn display

				type_text , mreg(`mreg') lvar(`lvar') cvar(`cvar')
				local CDE_col = strpos("`r(NDEtext)'", ":") + 2
				di as txt "CDE:" _column(`CDE_col') "controlled direct effect at m=`m'"
				di as txt "{p2col 1 `CDE_col' `CDE_col' 0: `r(NDEtext)'}{p_end}"
				di as txt "{p2col 1 `CDE_col' `CDE_col' 0: `r(NIEtext)'}{p_end}"
				di as txt "{p2col 1 `CDE_col' `CDE_col' 0: `r(ATEtext)'}{p_end}"

			} // end nointeraction
		} // end mreg == logit

		****************************
		// block 3: mreg=poisson //
		****************************
		if substr("`mreg'", 1, 3) == "poi" {

			// no interaction
			if "`nointeraction'" != "" {

				`qui' gsem  (`yvar' <- `avar' `mvar' `cvar_r' `lvar_r' `cxa_r' `cxm_r' `lxm_r' [`weight' `exp'] if `touse', regress) ///
					(`mvar' <- `avar' `cvar_r' `cxa_r', poisson), `options'

				estimates store gsem

				local CDE  "(_b[`yvar':`avar'] * (`astar'-`a'))"
				local NDE  "(_b[`yvar':`avar'] * (`astar'-`a'))"
				local NIE  "(_b[`yvar':`mvar'] * ((exp(_b[`mvar':_cons] + _b[`mvar':`avar'] * `astar')) - (exp(_b[`mvar':_cons] + _b[`mvar':`avar'] * `a'))))"
				local ATE "(`NDE') + (`NIE')"

				qui {
					*CDE
					margins, expression(`CDE') vce(unconditional) post
					matrix cdeB = e(b)
					matrix cdeV = e(V)
					scalar aS = cdeV[1,1]
					mat colname cdeB = CDE

					* NDE
					estimates restore gsem
					margins, expression(`NDE') vce(unconditional) post
					matrix ndeB = e(b)
					matrix ndeV = e(V)
					scalar bS = ndeV[1,1]
					matrix colname ndeB = NDE

					* NIE
					estimates restore gsem
					margins, expression(`NIE') vce(unconditional) post
					matrix nieB = e(b)
					matrix nieV = e(V)
					scalar cS = nieV[1,1]
					mat colname nieB = NIE

					* ATE
					estimates restore gsem
					margins, expression(`ATE') vce(unconditional) post
					matrix ateB = e(b)
					matrix ateV = e(V)
					scalar dS = ateV[1,1]
					matrix colname ateB = ATE

					matrix b = cdeB, ndeB, nieB, ateB
					matrix V = (aS,0,0,0\0,bS,0,0\0,0,cS,0\0,0,0,dS)

					type_text , mreg(`mreg') lvar(`lvar') cvar(`cvar')
					matrix colname b = CDE "`r(NDEtype)'"  "`r(NIEtype)'"  "`r(ATEtype)'"
					matrix rowname V = CDE "`r(NDEtype)'"  "`r(NIEtype)'"  "`r(ATEtype)'"
					matrix colname V = CDE "`r(NDEtype)'"  "`r(NIEtype)'"  "`r(ATEtype)'"

				} // end quietly
				estimates drop gsem
				ereturn post b V
				ereturn display

				type_text , mreg(`mreg') lvar(`lvar') cvar(`cvar')
				local CDE_col = strpos("`r(NDEtext)'", ":") + 2
				di as txt "CDE:" _column(`CDE_col') "controlled direct effect at m=`m'"
				di as txt "{p2col 1 `CDE_col' `CDE_col' 0: `r(NDEtext)'}{p_end}"
				di as txt "{p2col 1 `CDE_col' `CDE_col' 0: `r(NIEtext)'}{p_end}"
				di as txt "{p2col 1 `CDE_col' `CDE_col' 0: `r(ATEtext)'}{p_end}"

			} // end no interaction

			// with interaction
			if "`nointeraction'" == "" {

				`qui' gsem  (`yvar' <- `avar' `mvar' `inter' `cvar_r' `lvar_r' `cxa_r' `cxm_r' `lxm_r' [`weight' `exp'] if `touse', regress) ///
					(`mvar' <- `avar' `cvar_r' `cxa_r', poisson), `options'

				estimates store gsem

				local CDE  "(_b[`yvar':`avar'] + _b[`yvar':`inter'] * `m')  *  (`astar'-`a')"
				local NDE  "(_b[`yvar':`avar'] + _b[`yvar':`inter'] * (exp(_b[`mvar':_cons] + _b[`mvar':`avar'] * `a'))) * (`astar'-`a')"
				local NIE  `""(_b[`yvar':`mvar'] + _b[`yvar':`inter'] * `astar') * ((exp(_b[`mvar':_cons] + _b[`mvar':`avar'] * `astar')) - (exp(_b[`mvar':_cons]""'
				local NIE `"`NIE' " + _b[`mvar':`avar'] * `a')))""'
				local ATE "(`NDE') + `NIE'"


				qui {
					*CDE
					margins, expression(`CDE') vce(unconditional) post
					matrix cdeB = e(b)
					matrix cdeV = e(V)
					scalar aS = cdeV[1,1]
					mat colname cdeB = CDE

					* NDE
					estimates restore gsem
					margins, expression(`NDE') vce(unconditional) post
					matrix ndeB = e(b)
					matrix ndeV = e(V)
					scalar bS = ndeV[1,1]
					matrix colname ndeB = NDE

					* NIE
					estimates restore gsem
					margins, expression(`NIE') vce(unconditional) post
					matrix nieB = e(b)
					matrix nieV = e(V)
					scalar cS = nieV[1,1]
					mat colname nieB = NIE

					* ATE
					estimates restore gsem
					margins, expression(`ATE') vce(unconditional) post
					matrix ateB = e(b)
					matrix ateV = e(V)
					scalar dS = ateV[1,1]
					matrix colname ateB = ATE

					matrix b = cdeB, ndeB, nieB, ateB
					matrix V = (aS,0,0,0\0,bS,0,0\0,0,cS,0\0,0,0,dS)

					type_text , mreg(`mreg') lvar(`lvar') cvar(`cvar')
					matrix colname b = CDE "`r(NDEtype)'"  "`r(NIEtype)'"  "`r(ATEtype)'"
					matrix rowname V = CDE "`r(NDEtype)'"  "`r(NIEtype)'"  "`r(ATEtype)'"
					matrix colname V = CDE "`r(NDEtype)'"  "`r(NIEtype)'"  "`r(ATEtype)'"

				} // end quietly
				estimates drop gsem
				ereturn post b V
				ereturn display

				type_text , mreg(`mreg') lvar(`lvar') cvar(`cvar')
				local CDE_col = strpos("`r(NDEtext)'", ":") + 2
				di as txt "CDE:" _column(`CDE_col') "controlled direct effect at m=`m'"
				di as txt "{p2col 1 `CDE_col' `CDE_col' 0: `r(NDEtext)'}{p_end}"
				di as txt "{p2col 1 `CDE_col' `CDE_col' 0: `r(NIEtext)'}{p_end}"
				di as txt "{p2col 1 `CDE_col' `CDE_col' 0: `r(ATEtext)'}{p_end}"

			} // end with interaction
		} // end mreg == poisson

end


capture program drop parse_bootstrap_options
program parse_bootstrap_options, sclass
    version 14
    syntax [varlist(default=none)]        ///
           [, reps(integer 50) * ]

    local bsoptions "reps(`reps') noheader nowarn `options'"
    sreturn clear
    sreturn local bsoptions `bsoptions'
end


capture program drop type_text
program type_text, rclass
    version 14
    syntax [varlist(default=none)] [, mreg(string) lvar(string) cvar(string) ]

		* regress
		if substr("`mreg'", 1, 3) == "reg" {

			// text to accompany estimates
			if "`lvar'"=="" {
			    local NDEtype "NDE"
				local NDEtext NDE: natural direct effect
				local NIEtype "NIE"
				local NIEtext NIE: natural indirect effect
				local ATEtype "ATE"
				local ATEtext ATE: average total effect
			}
			else {
				local NDEtype "rNDE"
				local NDEtext rNDE: randomized intervention analogue of the natural direct effect
				local NIEtype "rNIE"
				local NIEtext rNIE: randomized intervention analogue of the natural indirect effect
				local ATEtype "rATE"
			    local ATEtext rATE: randomized intervention analogue of the total effect
			}
		} // mregs = regress

		* logit
		if substr("`mreg'", 1, 3) == "log" {

			// text to accompany estimates
			if "`cvar'"=="" & "`lvar'"=="" {
				local NDEtype NDE
				local NDEtext NDE: natural direct effect
				local NIEtype NIE
				local NIEtext NIE: natural indirect effect
				local ATEtype ATE
				local ATEtext ATE: average total effect
			}
			else if "`cvar'"=="" & "`lvar'"!="" {
			    local NDEtype rNDE
				local NDEtext rNDE: randomized intervention analogue of the natural direct effect
				local NIEtype rNIE
				local NIEtext rNIE: randomized intervention analogue of the natural indirect effect
				local ATEtype rATE
			    local ATEtext rATE: randomized intervention analogue of the total effect
			}
			else if "`cvar'"!="" & "`lvar'"=="" {
			    local NDEtype NDEc
				local NDEtext NDEc: natural direct effect at sample means of cvars
				local NIEtype NIEc
				local NIEtext NIEc: natural indirect effect at sample means of cvars
				local ATEtype ATEc
				local ATEtext ATEc: total effect at sample means of cvars
			}
			else {
				local NDEtype rNDEc
				local NDEtext rNDEc: randomized intervention analogue of the natural direct effect at sample means of cvars
				local NIEtype rNIEc
				local NIEtext rNIEc: randomized intervention analogue of the natural indirect effect at sample means of cvars
				local ATEtype rATEc
			    local ATEtext rATEc: randomized intervention analogue of the total effect at sample means of cvars
			}
		} // mregs = logit

		* poisson
		if substr("`mreg'", 1, 3) == "poi" {

			// text to accompany estimates
			if "`cvar'"=="" & "`lvar'"=="" {
				local NDEtype NDE
				local NDEtext NDE: natural direct effect
				local NIEtype NIE
				local NIEtext NIE: natural indirect effect
				local ATEtype ATE
				local ATEtext ATE: average total effect
			}
			else if "`cvar'"=="" & "`lvar'"!="" {
			    local NDEtype rNDE
				local NDEtext rNDE: randomized intervention analogue of the natural direct effect
				local NIEtype rNIE
				local NIEtext rNIE: randomized intervention analogue of the natural indirect effect
				local ATEtype rATE
			    local ATEtext rATE: randomized intervention analogue of the total effect
			}
			else if "`cvar'"!="" & "`lvar'"=="" {
			    local NDEtype NDEc
				local NDEtext NDEc: natural direct effect at sample means of cvars
				local NIEtype NIEc
				local NIEtext NIEc: natural indirect effect at sample means of cvars
				local ATEtype ATEc
			    local ATEtext ATEc: total effect at sample means of cvars
			}
			else {
				local NDEtype rNDEc
				local NDEtext rNDEc: randomized intervention analogue of the natural direct effect at sample means of cvars
				local NIEtype rNIEc
				local NIEtext rNIEc: randomized intervention analogue of the natural indirect effect at sample means of cvars
				local ATEtype rATEc
			    local ATEtext rATEc: randomized intervention analogue of the total effect at sample means of cvars
			}
		} // mregs = poisson

		*return clear
		return local NDEtype `NDEtype'
		return local NDEtext `NDEtext'
		return local NIEtype `NIEtype'
		return local NIEtext `NIEtext'
		return local ATEtype `ATEtype'
		return local ATEtext `ATEtext'
end