Update ModelUpdate.do

Update ModelUpdate.do

///////////////
// Update Keefer (2007) with data from Laeven and Valencia (2012)
// Christopher Gandrud
// 28 January 2015
// Using Stata 12.1
///////////////

// Set up
// Change as needed.
cd "/git_repositories/Keefer2007Replication/tables"
use "/git_repositories/Keefer2007Replication/data/KeeferExtended_RandP.dta", clear

///// Linear Models ////////////////////////////////////////////////////////////
// Keefer Table 4, Model 2
regress Keefer2007_Fiscal ChecksResiduals33 DiEiec33 stabnsLag3, vce(cluster country)
	regsave using "A1.dta", detail(all) replace table(KeeferOriginal, order(regvars r2) format(%5.2f) paren(stderr) asterisk())

// Remove the Philippines
regress Keefer2007_Fiscal ChecksResiduals33 DiEiec33 stabnsLag3, vce(cluster country)

// Using Honohan original
regress Honohan2003_Fiscal ChecksResiduals33 DiEiec33 stabnsLag3, vce(cluster country)
	regsave using "C1.dta", detail(all) replace table(Honohan, order(regvars r2) format(%5.2f) paren(stderr) asterisk())

// Using updated LV data for crises before 2001 only when Keefer also has data
regress LV2012_Fiscal ChecksResiduals33 DiEiec33 stabnsLag3 if Keefer2007_Fiscal != ., vce(cluster country)
	regsave using "A3.dta", detail(all) replace table(LVPre2001Keef, order(regvars r2) format(%5.2f) paren(stderr) asterisk())

// Using updated LV data for crises before 2001
regress LV2012_Fiscal ChecksResiduals33 DiEiec33 stabnsLag3 if year < 2001, vce(cluster country)
	regsave using "A4.dta", detail(all) replace table(LVPre2001, order(regvars r2) format(%5.2f) paren(stderr) asterisk())

// Using full Laeven and Valencia 2012 data
regress LV2012_Fiscal ChecksResiduals33 DiEiec33 stabnsLag3, vce(cluster country)
	regsave using "A5.dta", detail(all) replace table(LVFull, order(regvars r2) format(%5.2f) paren(stderr) asterisk())

// Using Laeven and Valencia 2012 data, full sample, except for eurozone
regress LV2012_Fiscal ChecksResiduals33 DiEiec33 stabnsLag3 if eurozone == 0, vce(cluster country)
	regsave using "A6.dta", detail(all) replace table(LVFull, order(regvars r2) format(%5.2f) paren(stderr) asterisk())

////// Beta and Zero Inflated Beta Models /////////////////////////////////////
// Convert to proportions
gen keefer_prop = Keefer2007_Fiscal / 100
gen lv_prop = (LV2012_Fiscal / 100)

// Keefer Table 4, Model 2 beta regression
betafit keefer_prop, mu(ChecksResiduals33 DiEiec33 stabnsLag3) vce(cluster country)
	regsave using "B1.dta", detail(all) replace table(KeeferBeta, order(regvars r2) format(%5.2f) paren(stderr) asterisk())

// Beta regresion Using Laeven and Valencia 2012 pre-2001 with adjusted DV
betafit lv_prop if year < 2001, mu(ChecksResiduals33 DiEiec33 stabnsLag3) vce(cluster country)
	regsave using "B2.dta", detail(all) replace table(LVpre2001, order(regvars r2) format(%5.2f) paren(stderr) asterisk())

// Beta regresion Using Laeven and Valencia 2012 full sample with adjusted DV
betafit lv_prop, mu(ChecksResiduals33 DiEiec33 stabnsLag3) vce(cluster country)
	regsave using "B3.dta", detail(all) replace table(LVFull, order(regvars r2) format(%5.2f) paren(stderr) asterisk())

////// Zero-inflated Beta Regression, results not included in output
// Zero-inflated Beta regression Using Laeven and Valencia 2012 for crises before 2001
zoib lv_prop ChecksResiduals33 DiEiec33 stabnsLag3 if year < 2001, zeroinflat(ChecksResiduals33 DiEiec33 stabnsLag3) vce(cluster country)

// Zero-inflated Beta regression Using Laeven and Valencia 2012 for all crises
zoib lv_prop ChecksResiduals33 DiEiec33 stabnsLag3 if year, zeroinflat(ChecksResiduals33 DiEiec33 stabnsLag3) vce(cluster country)

///////////////
// Update Keefer (2007) with data from Laeven and Valencia (2012)
// Christopher Gandrud
// 3 December 2014
// Using Stata 12.1
///////////////

// Set up
// Change as needed.
cd "/git_repositories/Keefer2007Replication/tables"
use "/git_repositories/Keefer2007Replication/data/KeeferExtended_RandP.dta", clear

///// Linear Models ////////////////////////////////////////////////////////////
// Keefer Table 4, Model 2
regress Keefer2007_Fiscal ChecksResiduals33 DiEiec33 stabnsLag3, vce(cluster country)
	regsave using "A1.dta", detail(all) replace table(KeeferOriginal, order(regvars r2) format(%5.2f) paren(stderr) asterisk())

// Remove the Philippines
regress Keefer2007_Fiscal ChecksResiduals33 DiEiec33 stabnsLag3, vce(cluster country)

// Using Honohan original
regress Honohan2003_Fiscal ChecksResiduals33 DiEiec33 stabnsLag3, vce(cluster country)
	regsave using "C1.dta", detail(all) replace table(Honohan, order(regvars r2) format(%5.2f) paren(stderr) asterisk())

// Using updated LV data for crises before 2001 only when Keefer also has data
regress LV2012_Fiscal ChecksResiduals33 DiEiec33 stabnsLag3 if Keefer2007_Fiscal != ., vce(cluster country)
	regsave using "A3.dta", detail(all) replace table(LVPre2001Keef, order(regvars r2) format(%5.2f) paren(stderr) asterisk())

// Using updated LV data for crises before 2001
regress LV2012_Fiscal ChecksResiduals33 DiEiec33 stabnsLag3 if year < 2001, vce(cluster country)
	regsave using "A4.dta", detail(all) replace table(LVPre2001, order(regvars r2) format(%5.2f) paren(stderr) asterisk())

// Using full Laeven and Valencia 2012 data
regress LV2012_Fiscal ChecksResiduals33 DiEiec33 stabnsLag3, vce(cluster country)
	regsave using "A5.dta", detail(all) replace table(LVFull, order(regvars r2) format(%5.2f) paren(stderr) asterisk())

// Using Laeven and Valencia 2012 data, full sample, except for eurozone
regress LV2012_Fiscal ChecksResiduals33 DiEiec33 stabnsLag3 if eurozone == 0, vce(cluster country)
	regsave using "A6.dta", detail(all) replace table(LVFull, order(regvars r2) format(%5.2f) paren(stderr) asterisk())

////// Beta and Zero Inflated Beta Models /////////////////////////////////////
// Convert to proportions
gen keefer_prop = Keefer2007_Fiscal / 100
gen lv_prop = (LV2012_Fiscal / 100)

// Keefer Table 4, Model 2 beta regression
betafit keefer_prop, mu(ChecksResiduals33 DiEiec33 stabnsLag3) vce(cluster country)
	regsave using "B1.dta", detail(all) replace table(KeeferBeta, order(regvars r2) format(%5.2f) paren(stderr) asterisk())

// Beta regresion Using Laeven and Valencia 2012 pre-2001 with adjusted DV
betafit lv_prop if year < 2001, mu(ChecksResiduals33 DiEiec33 stabnsLag3) vce(cluster country)
	regsave using "B2.dta", detail(all) replace table(LVpre2001, order(regvars r2) format(%5.2f) paren(stderr) asterisk())

// Beta regresion Using Laeven and Valencia 2012 full sample with adjusted DV
betafit lv_prop, mu(ChecksResiduals33 DiEiec33 stabnsLag3) vce(cluster country)
	regsave using "B3.dta", detail(all) replace table(LVFull, order(regvars r2) format(%5.2f) paren(stderr) asterisk())

////// Zero-inflated Beta Regression, results not included in output
// Zero-inflated Beta regression Using Laeven and Valencia 2012 for crises before 2001
zoib lv_prop ChecksResiduals33 DiEiec33 stabnsLag3 if year < 2001, zeroinflat(ChecksResiduals33 DiEiec33 stabnsLag3) vce(cluster country)

// Zero-inflated Beta regression Using Laeven and Valencia 2012 for all crises
zoib lv_prop ChecksResiduals33 DiEiec33 stabnsLag3 if year, zeroinflat(ChecksResiduals33 DiEiec33 stabnsLag3) vce(cluster country)


ieddtable : add some comments

ieddtable : add some comments

cap program drop 	ieddtable
	program define	ieddtable

	syntax varlist , 										///
															///
		t(varname numeric) tmt(varname numeric) 			///
		[ 													///
		COVARiates(varlist numeric)							///
		STARLevels(numlist descending min=3 max=3 >0 <1)	///
		STARSNOadd											///
		firstdiff											///
		ROWLabels(string) 									///
		]

	/***************************************
	****************************************

		Input testing

	****************************************
	***************************************/

	/*************

		Call subcommands that prepares labels in the table

	*************/

	prepRowLabels `varlist', rowlabels("`rowlabels'")

	/***************************************
	****************************************

		Calculate results and prepare
		result matrix

	****************************************
	***************************************/

	/*************

		Initiate the result matrix

	*************/

	*Creates the template for the result matrix in a subfunction
	templateResultMatrix
	mat startRow = r(startRow)

	*Remove this when ready for production
	noi di "Start row to see headers, remove for production"
	matlist startRow // See the default row with its column names

	*Initiate the result matrix with a place holder row that will not be used for anything. Matrices cannot be initiated empty
	mat resultMat = startRow
	mat rownames resultMat = placeholder

	/*************

		Loop over all variables and prepare the data

	*************/

	foreach var of local varlist {

		*Each variable is a row in the result matrix
		mat `var' = startRow
		mat rownames `var' = `var'
		mat colnames `var' = `colnames'

		*Local that keeps track of which column to fill
		local colindex 0

		tempvar regsample

		/*************

			Calculating 2nd difference and restict the sample
			for this output var

		*************/

		*Run the regression to get the double difference
		qui reg `var' `tmt'#`t' `covariates'
		mat resTable = r(table)

		**This is why this is done first. All other calculations
		* for this outcome var should be restricted to this sample.
		gen `regsample' = e(sample)
		local N `e(N)'

		**Test that the dummy vars creates for valid groups for each
		* combination of time and treat in the sample used for this outcome var
		testDDdums `t' `tmt' `regsample' `var'  //comment in when this is made into a command

		//Get the second differnce
		local ++colindex
		mat `var'[1,`colindex'] =  el(resTable,1,4)

		*Get the standard error of second difference
		local ++colindex
		mat `var'[1,`colindex'] =  el(resTable,2,4)

		//matlist resTable

		*Get the number of stars using sub-command countStars
		local ++colindex
		local pvalue = el(resTable,4,4)
		countStars `pvalue' `starlevels'
		mat `var'[1,`colindex'] = `r(stars)'

		*Get the N of second difference regression
		local ++colindex
		mat `var'[1,`colindex'] = `N'

		/*************

			Calculating 1st differences

		*************/
		forvalues tmt01 = 0/1 {

			*Regress time against the outcome var one tmt group at the time
			qui reg `var' `t' `covariates' if `tmt' == `tmt01' & `regsample' == 1
			mat resTable = r(table)

			//Get the 1st diff
			local ++colindex
			mat `var'[1,`colindex'] =  el(resTable,1,1)

			*Get the standard error of 1st diff
			local ++colindex
			mat `var'[1,`colindex'] =  el(resTable,2,1)

			*Get the number of stars using sub-command countStars
			local ++colindex
			local pvalue = el(resTable,4,4)
			countStars `pvalue' `starlevels'
			mat `var'[1,`colindex'] = `r(stars)'

			*Get the N of first difference regression
			local ++colindex
			mat `var'[1,`colindex'] =  `e(N)'

		}

		/*************

			Calculating standard means for all groups

		*************/
		forvalues tmt01 = 0/1 {
			forvalues t01 = 0/1 {

				*Summary stats on this group
				qui mean `var' if `tmt' == `t01' & `t' == `tmt01' & `regsample' == 1

				mat resTable = r(table)

				//Get the mean
				local ++colindex
				mat `var'[1,`colindex'] =  el(resTable,1,1)

				*Get the standard error of the mean
				local ++colindex
				mat `var'[1,`colindex'] =  el(resTable,2,1)

				*Get the N of the ordinary means regressions
				local ++colindex
				mat `var'[1,`colindex'] =  `e(N)'
			}
		}

		*Append this row to the result table
		mat 	resultMat = (resultMat \ `var')

	}

	*Remove placeholder row
	matrix resultMat = resultMat[2..., 1...]

	*Show the final matrix will all data needed to start building the output
	noi di "Matlist with results"
	matlist resultMat

end

/***************************************
****************************************

	Write sub-commands for outputs

****************************************
***************************************/

	******
	*Then the result matrix can be passed into subcommands that output in either Excel, LaTeX or in the main window.

	*The results can be accessed like this, which makes the sub-commands less sensitive to changing column order in the section above.
	//mat A = resultMat[3, "C0_Mean"] // returns a 1x1 matrix with the baseline mean for the countrol grop for the thrid outcome var
	//local a = el(A,1,1)				// returns the value

	//matlist A
	//di `a'

/***************************************
****************************************

	Write sub-commands for input handling

****************************************
***************************************/

**Program to prepare row labels for each outcome var, using variable name,
* variable label or manually entered labels depedning on user input. Variable
* names are used if no input.
cap program drop 	prepRowLabels
	program define	prepRowLabels, rclass

	syntax varlist, [rowlabels(string)]

	*Run subcommand that parse the sub-options in rowlabels
	local rowlabels = subinstr(`"`rowlabels'"', ",", "", 1)
	testRowlabelsinput ,`rowlabels'
	local rowlabeltype 	`s(rowlabeltype)'
	local rowlabeltext	`s(rowlabeltext)'

	/*************
		Parse through the manually entered labels
	*************/

	*Create a local with the rowlabel input to be tokenized
	local row_labels_to_tokenize `rowlabeltext'

	while "`row_labels_to_tokenize'" != "" {

		*Parsing name and label pair
		gettoken nameAndLabel row_labels_to_tokenize : row_labels_to_tokenize, parse("@@")

		*Splitting name and label
		gettoken name label : nameAndLabel

		/*
			We store two locals, one with varnames and one with label. They are
			stored in the same order, so if we find varname we know we will find
			the corresponding label in the same order in the other local.
		*/

		*** Tests

		*Checking that the variables used in rowlabels() are included in the table
		local name_correct : list name in varlist
		if `name_correct' == 0 {
			noi display as error "{phang}Variable [`name'] listed in rowlabels(`rowlabtext') is not found among the outcome variables. See option {help ieddtable:rowlabels} for more details{p_end}"
			error 111
		}

		*Testing that no label is missing
		if "`label'" == "" {
			noi display as error "{phang}For variable [`name'] listed in rowlabels(`rowlabels') you have not specified any label. Labels are requried for all variables listed in rowlabels(,text(`rowlabeltext')). See option {help ieddtable:rowlabels} for more details and for explination on what happens to variables not listed in rowlabels(,text()){p_end}"
			error 198
		}

		*Storing the name in local to be used to get index of corresponding label in the second local
		local rowLabelNames `"`rowLabelNames' "`name'" "'

		*Removing leading or trailing spaces and store label with the same index as in the name local above
		local label = trim("`label'")
		local rowLabelLabels `"`rowLabelLabels' "`label'" "'

		*Parse char is not removed by gettoken, so remove it and start over
		local row_labels_to_tokenize = subinstr("`row_labels_to_tokenize'" ,"@@","",1)
	}

	**Set up locals to be returned. One with row labels without varname but in
	* final order, and one local with length of longest label
	local preppedRowLabels
	local maxLen 0

	*Loop over all varaibles and prepare the labels
	foreach var of local varlist {

		**Get the index of this variable in manually entered labels. Index is
		* zero if no manually entered label for this variable
		local rowLabPos : list posof "`var'" in rowLabelNames

		if `rowLabPos' == 0 {
			di ":: `rowlabeltype'"
			*No label was manually entered for this variable, use the other rules
			if "`rowlabeltype'" == "label" {
				local this_label : variable label `var'		//Use variable label
			}
			else if "`rowlabeltype'" == "name" {
				local this_label `var'						//Default, use varname
			}
			else {
				*Since name is the default it should always be name if it is not label, but in case there is some corner case bug
				noi display as error `"{phang}This error is never supposed to happen, please report this on {browse "https://www.github.com/worldbank/ietoolkit/issues"} or contact kbjarkefur@worldbank.org.{p_end}"'
				error 198
			}
		}
		else {
			*Getting the manually defined label corresponding to this variable
			local this_label : word `rowLabPos' of `rowLabelLabels'
		}

		*Update the two locals that will be returned
		local preppedRowLabels "`preppedRowLabels' @@`this_label'"	//Prepare the final list
		local maxLen = max(strlen("`this_label'"),`maxLen')	//Store the length on the longest label, used on some outputs
	}

	*Return the locals
	return local rowlabels `preppedRowLabels'
	return local rowlabel_maxlen `maxLen'

end

*Parses and test the sub-options inside the option rowlabels
cap program drop 	testRowlabelsinput
	program define	testRowlabelsinput, sclass

		syntax  , [name label text(string)]

		*Test that both name and label are not used at the same time
		if "`name'" != "" & "`label'" != "" {

			noi display as error "{phang}You may not use both label and name in the option rowlabel(`rowlabel'). See option {help ieddtable:rowlabels} for details."
			error 198
		}

		*If neither is used, use name as default
		if "`name'`label'" == "" {
			local name "name"
		}

		sreturn local rowlabeltype "`name'`label'"
		sreturn local rowlabeltext "`text'"

	end

cap program drop 	testDDdums
	program define	testDDdums

		args time treat samplevar outputvar

		*Test taht the dummies are dummies
		foreach dummy in `time' `treat' {

			cap assert inlist(`dummy',1,0) | missing(`dummy') | `samplevar' == 0
			if _rc {
				noi di as error "{phang}In the difference in differnce regression for outputvar [`outputvar'], the dummy [`dummy'] is not a real dummy as it has values differnt from 1 and 0. See tab below. The tab is restricted to the observations that are not excluded due to missing values etc. in the difference in differnce regression.{p_end}""
				noi tab `dummy' if `samplevar' == 1, missing
				error 480
			}
		}

		**Test that for only two of three dummies there are observations
		* that has only that dummy. I.e. the two that is not the
		* interaction. If the interaction is 1, all three shluld be 1.

		*Test that there is some observations in each group
		forvalues tmt01 = 0/1 {
			forvalues t01 = 0/1 {

				*Summary stats on this group
				count if `treat' == `t01' & `time' == `tmt01' & `samplevar' == 1

				//There got to be more than 1 observation in each group for the regression to make sense
				if `r(N)' < 2 {
					noi di as error "{phang}In the difference in differnce regression for outputvar [`outputvar'] there were not enough observations in each combination of treatment [`treat'] and time [`time']. The tab below is restricted to the observations that are not excluded due to missing values etc. in the difference in differnce regression.{p_end}""
					noi tab `treat' `time' if `samplevar' == 1, missing
					error 480

				}
			}
		}

	end

/***************************************
****************************************

	Write sub-commands for stats

****************************************
***************************************/

cap program drop 	templateResultMatrix
	program define	templateResultMatrix, rclass

	local 2ndDiff_cols 			2D 2D_err 2D_Stars 2D_N

	local 1stDiff_C_cols		1DC 1DC_err 1DC_stars 1DC_N
	local 1stDiff_T_cols		1DT 1DT_err 1DT_stars 1DT_N

	local basicMean_C0_cols		C0_mean C0_err C0_N
	local basicMean_T0_cols		T0_mean T0_err T0_N
	local basicMean_C1_cols		C1_mean C1_err C1_N
	local basicMean_T1_cols		T1_mean T1_err T1_N

	local colnames `2ndDiff_cols' `1stDiff_C_cols' `1stDiff_T_cols' `basicMean_C0_cols' `basicMean_T0_cols' `basicMean_C1_cols' `basicMean_T0_cols'

	*Define default row here. The results for each var will be one row that starts with all missing vlaues
	mat startRow = (.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.)
	mat colnames startRow = `colnames'

	return matrix startRow startRow

end

cap program drop 	countStars
	program define	countStars, rclass

	args pvalue star1 star2 star3

	*Test if custom star levels are used
	if "`star1'" == "" {

		*Set default levels for 1, 2 and 3 stars
		local star1 .1
		local star2 .05
		local star3 .01
	}

	local stars 0
	foreach star_p_level in `star1' `star2' `star3' {

		if `pvalue' < `star_p_level' local ++stars
	}

	return local stars `stars'

end

cap program drop 	ieddtable
	program define	ieddtable

	syntax varlist , 										///
															///
		t(varname numeric) tmt(varname numeric) 			///
		[ 													///
		COVARiates(varlist numeric)							///
		STARLevels(numlist descending min=3 max=3 >0 <1)	///
		STARSNOadd											///
		firstdiff											///
		ROWLabels(string) 									///
		]

	/***************************************
	****************************************

		Input testing

	****************************************
	***************************************/

	/*************

		Call subcommands that prepares labels in the table

	*************/

	prepRowLabels `varlist', rowlabels("`rowlabels'")

	/***************************************
	****************************************

		Calculate results and prepare
		result matrix

	****************************************
	***************************************/

	/*************

		Initiate the result matrix

	*************/

	*Creates the template for the result matrix in a subfunction
	templateResultMatrix
	mat startRow = r(startRow)

	*Remove this when ready for production
	noi di "Start row to see headers, remove for production"
	matlist startRow // See the default row with its column names

	*Initiate the result matrix with a place holder row that will not be used for anything. Matrices cannot be initiated empty
	mat resultMat = startRow
	mat rownames resultMat = placeholder

	/*************

		Loop over all variables and prepare the data

	*************/

	foreach var of local varlist {

		*Each variable is a row in the result matrix
		mat `var' = startRow
		mat rownames `var' = `var'
		mat colnames `var' = `colnames'

		*Local that keeps track of which column to fill
		local colindex 0

		tempvar regsample

		/*************

			Calculating 2nd difference and restict the sample
			for this output var

		*************/

		*Run the regression to get the double difference
		qui reg `var' `tmt'#`t' `covariates'
		mat resTable = r(table)

		**This is why this is done first. All other calculations
		* for this outcome var should be restricted to this sample.
		gen `regsample' = e(sample)
		local N `e(N)'

		**Test that the dummy vars creates for valid groups for each
		* combination of time and treat in the sample used for this outcome var
		testDDdums `t' `tmt' `regsample' `var'  //comment in when this is made into a command

		//Get the second differnce
		local ++colindex
		mat `var'[1,`colindex'] =  el(resTable,1,4)

		*Get the standard error of second difference
		local ++colindex
		mat `var'[1,`colindex'] =  el(resTable,2,4)

		//matlist resTable

		*Get the number of stars using sub-command countStars
		local ++colindex
		local pvalue = el(resTable,4,4)
		countStars `pvalue' `starlevels'
		mat `var'[1,`colindex'] = `r(stars)'

		*Get the N of second difference regression
		local ++colindex
		mat `var'[1,`colindex'] = `N'

		/*************

			Calculating 1st differences

		*************/
		forvalues tmt01 = 0/1 {

			*Regress time against the outcome var one tmt group at the time
			qui reg `var' `t' `covariates' if `tmt' == `tmt01' & `regsample' == 1
			mat resTable = r(table)

			//Get the 1st diff
			local ++colindex
			mat `var'[1,`colindex'] =  el(resTable,1,1)

			*Get the standard error of 1st diff
			local ++colindex
			mat `var'[1,`colindex'] =  el(resTable,2,1)

			*Get the number of stars using sub-command countStars
			local ++colindex
			local pvalue = el(resTable,4,4)
			countStars `pvalue' `starlevels'
			mat `var'[1,`colindex'] = `r(stars)'

			*Get the N of first difference regression
			local ++colindex
			mat `var'[1,`colindex'] =  `e(N)'

		}

		/*************

			Calculating standard means for all groups

		*************/
		forvalues tmt01 = 0/1 {
			forvalues t01 = 0/1 {

				*Summary stats on this group
				qui mean `var' if `tmt' == `t01' & `t' == `tmt01' & `regsample' == 1

				mat resTable = r(table)

				//Get the mean
				local ++colindex
				mat `var'[1,`colindex'] =  el(resTable,1,1)

				*Get the standard error of the mean
				local ++colindex
				mat `var'[1,`colindex'] =  el(resTable,2,1)

				*Get the N of the ordinary means regressions
				local ++colindex
				mat `var'[1,`colindex'] =  `e(N)'
			}
		}

		*Append this row to the result table
		mat 	resultMat = (resultMat \ `var')

	}

	*Remove placeholder row
	matrix resultMat = resultMat[2..., 1...]

	*Show the final matrix will all data needed to start building the output
	noi di "Matlist with results"
	matlist resultMat

end

/***************************************
****************************************

	Write sub-commands for outputs

****************************************
***************************************/

	******
	*Then the result matrix can be passed into subcommands that output in either Excel, LaTeX or in the main window.

	*The results can be accessed like this, which makes the sub-commands less sensitive to changing column order in the section above.
	//mat A = resultMat[3, "C0_Mean"] // returns a 1x1 matrix with the baseline mean for the countrol grop for the thrid outcome var
	//local a = el(A,1,1)				// returns the value

	//matlist A
	//di `a'

/***************************************
****************************************

	Write sub-commands for input handling

****************************************
***************************************/

cap program drop 	prepRowLabels
	program define	prepRowLabels, rclass

	syntax varlist, [rowlabels(string)]

	*Run subcommand that parse the sub-options in rowlabels
	local rowlabels = subinstr(`"`rowlabels'"', ",", "", 1)
	testRowlabelsinput ,`rowlabels'
	local rowlabeltype 	`s(rowlabeltype)'
	local rowlabeltext	`s(rowlabeltext)'

	/*************
		Parse through the manually entered labels
	*************/

	*Create a local with the rowlabel input to be tokenized
	local row_labels_to_tokenize `rowlabeltext'

	while "`row_labels_to_tokenize'" != "" {

		*Parsing name and label pair
		gettoken nameAndLabel row_labels_to_tokenize : row_labels_to_tokenize, parse("@@")

		*Splitting name and label
		gettoken name label : nameAndLabel

		/*
			We store two locals, one with varnames and one with label. They are
			stored in the same order, so if we find varname we know we will find
			the corresponding label in the same order in the other local.
		*/

		*** Tests

		*Checking that the variables used in rowlabels() are included in the table
		local name_correct : list name in varlist
		if `name_correct' == 0 {
			noi display as error "{phang}Variable [`name'] listed in rowlabels(`rowlabtext') is not found among the outcome variables. See option {help ieddtable:rowlabels} for more details{p_end}"
			error 111
		}

		*Testing that no label is missing
		if "`label'" == "" {
			noi display as error "{phang}For variable [`name'] listed in rowlabels(`rowlabels') you have not specified any label. Labels are requried for all variables listed in rowlabels(,text(`rowlabeltext')). See option {help ieddtable:rowlabels} for more details and for explination on what happens to variables not listed in rowlabels(,text()){p_end}"
			error 198
		}

		*Storing the name in local to be used to get index of corresponding label in the second local
		local rowLabelNames `"`rowLabelNames' "`name'" "'

		*Removing leading or trailing spaces and store label with the same index as in the name local above
		local label = trim("`label'")
		local rowLabelLabels `"`rowLabelLabels' "`label'" "'

		*Parse char is not removed by gettoken, so remove it and start over
		local row_labels_to_tokenize = subinstr("`row_labels_to_tokenize'" ,"@@","",1)
	}

	**Set up locals to be returned. One with row labels without varname but in
	* final order, and one local with length of longest label
	local preppedRowLabels
	local maxLen 0

	*Loop over all varaibles and prepare the labels
	foreach var of local varlist {

		**Get the index of this variable in manually entered labels. Index is
		* zero if no manually entered label for this variable
		local rowLabPos : list posof "`var'" in rowLabelNames

		if `rowLabPos' == 0 {
			di ":: `rowlabeltype'"
			*No label was manually entered for this variable, use the other rules
			if "`rowlabeltype'" == "label" {
				local this_label : variable label `var'		//Use variable label
			}
			else if "`rowlabeltype'" == "name" {
				local this_label `var'						//Default, use varname
			}
			else {
				noi display as error `"{phang}This error is never supposed to happen, please report this on {browse "https://www.github.com/worldbank/ietoolkit/issues"} or contact kbjarkefur@worldbank.org.{p_end}"'
				error 198
			}
		}
		else {
			*Getting the manually defined label corresponding to this variable
			local this_label : word `rowLabPos' of `rowLabelLabels'
		}

		*Update the two locals that will be returned
		local preppedRowLabels "`preppedRowLabels' @@`this_label'"	//Prepare the final list
		local maxLen = max(strlen("`this_label'"),`maxLen')	//Store the length on the longest label, used on some outputs
	}

	*Return the locals
	return local rowlabels `preppedRowLabels'
	return local rowlabel_maxlen `maxLen'

end

*Parses and test the sub-options inside the option rowlabels
cap program drop 	testRowlabelsinput
	program define	testRowlabelsinput, sclass

		syntax  , [name label text(string)]

		*Test that both name and label are not used at the same time
		if "`name'" != "" & "`label'" != "" {

			noi display as error "{phang}You may not use both label and name in the option rowlabel(`rowlabel'). See option {help ieddtable:rowlabels} for details."
			error 198
		}

		*If neither is used, use name as default
		if "`name'`label'" == "" {
			local name "name"
		}

		sreturn local rowlabeltype "`name'`label'"
		sreturn local rowlabeltext "`text'"

	end

cap program drop 	testDDdums
	program define	testDDdums

		args time treat samplevar outputvar

		*Test taht the dummies are dummies
		foreach dummy in `time' `treat' {

			cap assert inlist(`dummy',1,0) | missing(`dummy') | `samplevar' == 0
			if _rc {
				noi di as error "{phang}In the difference in differnce regression for outputvar [`outputvar'], the dummy [`dummy'] is not a real dummy as it has values differnt from 1 and 0. See tab below. The tab is restricted to the observations that are not excluded due to missing values etc. in the difference in differnce regression.{p_end}""
				noi tab `dummy' if `samplevar' == 1, missing
				error 480
			}
		}

		**Test that for only two of three dummies there are observations
		* that has only that dummy. I.e. the two that is not the
		* interaction. If the interaction is 1, all three shluld be 1.

		*Test that there is some observations in each group
		forvalues tmt01 = 0/1 {
			forvalues t01 = 0/1 {

				*Summary stats on this group
				count if `treat' == `t01' & `time' == `tmt01' & `samplevar' == 1

				//There got to be more than 1 observation in each group for the regression to make sense
				if `r(N)' < 2 {
					noi di as error "{phang}In the difference in differnce regression for outputvar [`outputvar'] there were not enough observations in each combination of treatment [`treat'] and time [`time']. The tab below is restricted to the observations that are not excluded due to missing values etc. in the difference in differnce regression.{p_end}""
					noi tab `treat' `time' if `samplevar' == 1, missing
					error 480

				}
			}
		}

	end

/***************************************
****************************************

	Write sub-commands for stats

****************************************
***************************************/

cap program drop 	templateResultMatrix
	program define	templateResultMatrix, rclass

	local 2ndDiff_cols 			2D 2D_err 2D_Stars 2D_N

	local 1stDiff_C_cols		1DC 1DC_err 1DC_stars 1DC_N
	local 1stDiff_T_cols		1DT 1DT_err 1DT_stars 1DT_N

	local basicMean_C0_cols		C0_mean C0_err C0_N
	local basicMean_T0_cols		T0_mean T0_err T0_N
	local basicMean_C1_cols		C1_mean C1_err C1_N
	local basicMean_T1_cols		T1_mean T1_err T1_N

	local colnames `2ndDiff_cols' `1stDiff_C_cols' `1stDiff_T_cols' `basicMean_C0_cols' `basicMean_T0_cols' `basicMean_C1_cols' `basicMean_T0_cols'

	*Define default row here. The results for each var will be one row that starts with all missing vlaues
	mat startRow = (.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.)
	mat colnames startRow = `colnames'

	return matrix startRow startRow

end

cap program drop 	countStars
	program define	countStars, rclass

	args pvalue star1 star2 star3

	*Test if custom star levels are used
	if "`star1'" == "" {

		*Set default levels for 1, 2 and 3 stars
		local star1 .1
		local star2 .05
		local star3 .01
	}

	local stars 0
	foreach star_p_level in `star1' `star2' `star3' {

		if `pvalue' < `star_p_level' local ++stars
	}

	return local stars `stars'

end


Removed -cscript_git-.

Removed -cscript_git-.

*! version 3.6.0  04mar2013
program define cscript_git, rclass
	version 9
	set linesize 79
	while !("`1'" == "adofile" | "`1'"=="adofiles" | "`1'"=="") {
		local stuff `stuff' `1'
		mac shift
	}
	local dup = 79-6-length("`stuff'")
	di in smcl in gr "{hline `dup'}" `"BEGIN `stuff'"'

	mac shift			/* adofile[s] */
	while "`1'" != "" {
		di
		di "-> which `1'"
		which `1'
		mac shift
	}

	drop _all
	label drop _all

	mata: st_local("globals",  invtokens(st_dir("global", "macro", "*")'))
	mata: st_local("sglobals", invtokens(st_dir("global", "macro", "S_*")'))
	local exclude `sglobals' F2 F4 F5 F6 F7 F8 F9 FASTCDPATH
	local globals : list globals - exclude
	if `:list sizeof globals' ///
		macro drop `globals'
	macro drop S_*

	program drop _all
	scalar drop _all
	matrix drop _all
	constraint drop _all
	discard
	mata: mata clear
	set type float
	set maxiter 100
	set scheme s2color8
	set emptycells keep
	set showbaselevels
	set showemptycells
	set showomitted
	set lstretch
	set cformat
	set pformat
	set sformat
	set fvwrap 1
	set fvwrapon word
	set fvlabel on

	if "$S_FLAVOR"!="Small" {
		qui set matsize 400
	}

end


Oops: forgot to silence "clone" when I switched to it

Previously, generate_clone had wrapped itself in quietly { }
but this is the proper way; it mirrors what you do with 'generate'.

/* load the C extension */
ensurelib_aberrance svm // check for libsvm
program _svm, plugin    // load _svm.plugin, the wrapper for libsvm

program define svm_predict, eclass
  version 13
  syntax newvarname [if] [in], [PROBability]
  local target = "`varlist'"
  local _in = "`in'" //these need to be stashed because the hack below will smash them
  local _if = "`if'"

  // C plugins can only speak to variables mentioned in the varlist they are called with
  // that is, if we are going predict on some vectors, we need to know what X variables we're
  // predicting on in their entirety before we call down to C--and they should match what

  // I haven't discovered how regress and friends manage to know which variables to predict on
  // the only place I see them record what they did is in e(cmdline)
  // but that has cruft in it
  // the easiest way I can think to extract the predictor list is to *reparse* the command line
  // TODO: consider if it's saner to simply pre-store e(indepvars) or e(predictors) or something
  local 0 = "`e(cmdline)'"
  gettoken cmd 0 : 0 /*remove the command which was artificially tacked on by svm_train*/
  syntax varlist [if] [in], * //* puts the remainder in `options' and allows this code to be isolated from svm_train (it's not like we actually could tweak anything, since the svm_model is stored on the plugin's C heap)
  gettoken y varlist : varlist // remove the first column to check
  assert "`y'" == "`e(depvar)'" // consistency with the svm_train

  // make the target column
  // it is safe to assume that `target' is a valid variable name: "syntax" above enforces that
  //  and it should be safe to assume the same about `e(depvar)': unless the user is messing with us (in which case, more power to them), it should have been created by svm_train and validated at that point
  quietly clone `target' `e(depvar)' if 0 //'if 0' leaves the values as missing, which is important: we don't want a bug in the plugin to translate to source values sitting in the variable (and thus inflating the observed prediction rate)

  // allocate space (we use new variables) to put probability estimates for each class for each prediction
  // this only makes sense in a classification problem, but we do not check for that
  if("`probability'"!="") {
    // ensure model is a classification
    // this duplicates code over in svm_train, but I think this is safest:
    //  svm_import allows you to pull in svm_models created by other libsvm
    //  interfaces, and they mostly don't have this protection.
    if("`e(svm_type)'" != "C_SVC" & "`e(svm_type)'" != "NU_SVC") {
      // in svm-predict.c, the equivalent section is:
      /*
       *        if (predict_probability && (svm_type==C_SVC || svm_type==NU_SVC))
       *                predict_label = svm_predict_probability(model,x,prob_estimates);
       *        else
       *                predict_label = svm_predict(model,x);
       */
      // it is cleaner to error out, rather than silently change the parameters, which is what the command line tools do
      di as error "Error: trained model is a `e(svm_type)'. You can only use the probability option with classification models (C_SVC, NU_SVC)."
      exit 2
    }

    // ensure type is categorical
    local T : type `e(depvar)'
    if("`T'"=="float" | "`T'"=="double") {
      di as error "Warning: `e(depvar)' is a `T', which is usually used for continuous variables."
      di as error "         It makes no sense to ask for category probabilities of continuous variables."
      di as error ""
      di as error "         If your variable is actually categorical, consider storing it as one:"
      di as error "         . tempvar B"
      di as error "         . generate byte \`B' = `e(depvar)'"   //CAREFUL: B is meant to be quoted and depvar is meant to be unquoted.
      di as error "         . drop `e(depvar)'"
      di as error "         . rename \`B' `e(depvar)'"
      di as error " "
      di as error "         SVM prediction is now being performed, but if your results are absurd, check that you have fit the right variable."
    }

    // save the top level description to splay across the stemmed variables
    local D : variable label `target'

    // loop over the possible (integer) values
    // this is the construction given at http://www.stata.com/support/faqs/data-management/try-all-values-with-foreach/
    // trying to loop over r(levels) directly fails with a syntax error because Stata
    quietly levelsof `e(depvar)', local(levels)
    // XXX the order of iteration here is critical:
    //     it MUST match the order in svm_model->labels or results will silently be permuted
    //     (and with several classes this becomes a big problem)
    foreach c of local levels {
      // this command is obscure; what it does is look up the
      // value label for variable `target' for value `c'
      // *or* give back `c' unchanged if `target' has no labels
      // which is precisely what we want it to do here
      local L : label (`target') `c'
      // compute the full variable name for level `c'
      local stemmed = "`target'_`L'"
      local stemmed = strtoname("`stemmed'") //sanitize the new name; this summarily avoids problems like one of your classes being "1.5"

      // finally, allocate it
      // unlike `target' which clones its source, we use doubles
      // because these are meant to hold probabilities

      // TODO: what happens if there's a name collision partially through this loop?
      //       what I want to happen is for any name collision or other bug to abort (i.e. rollback) the entire operation
      //       This can be achieved with "snapshot": snapshot; capture {}; if(fail) { rollback to snapshot }"
      quietly generate double `stemmed' = .
      label variable `stemmed' "Probability of `D' being category `L'"

      // attach the newcomers to the varlist so the plugin is allowed to edit them
      local varlist = "`varlist' `stemmed'"
    }
  }

  // call down into C
  // we indicate "probability" mode by passing a non-empty list of levels
  //  this list implicitly *removes* from the set range of variables to predict from: the trailing variables are instead write locations
  //  (this feels like programming a hardware driver)
  // Subtlety: we don't quote levels, on the assumption that it is always a list of integers;
  //           that way, the levels are pre-tokenized and the count easily available as argc

  //di as txt "svm_predict: plugin call _svm `target' `varlist' `_if' `_in', predict `probability'" /*DEBUG*/
  plugin call _svm `target' `varlist' `_if' `_in', predict `probability'
end

/* load the C extension */
ensurelib_aberrance svm // check for libsvm
program _svm, plugin    // load _svm.plugin, the wrapper for libsvm

program define svm_predict, eclass
  version 13
  syntax newvarname [if] [in], [PROBability]
  local target = "`varlist'"
  local _in = "`in'" //these need to be stashed because the hack below will smash them
  local _if = "`if'"

  // C plugins can only speak to variables mentioned in the varlist they are called with
  // that is, if we are going predict on some vectors, we need to know what X variables we're
  // predicting on in their entirety before we call down to C--and they should match what

  // I haven't discovered how regress and friends manage to know which variables to predict on
  // the only place I see them record what they did is in e(cmdline)
  // but that has cruft in it
  // the easiest way I can think to extract the predictor list is to *reparse* the command line
  // TODO: consider if it's saner to simply pre-store e(indepvars) or e(predictors) or something
  local 0 = "`e(cmdline)'"
  gettoken cmd 0 : 0 /*remove the command which was artificially tacked on by svm_train*/
  syntax varlist [if] [in], * //* puts the remainder in `options' and allows this code to be isolated from svm_train (it's not like we actually could tweak anything, since the svm_model is stored on the plugin's C heap)
  gettoken y varlist : varlist // remove the first column to check
  assert "`y'" == "`e(depvar)'" // consistency with the svm_train

  // make the target column
  // it is safe to assume that `target' is a valid variable name: "syntax" above enforces that
  //  and it should be safe to assume the same about `e(depvar)': unless the user is messing with us (in which case, more power to them), it should have been created by svm_train and validated at that point
  clone `target' `e(depvar)' if 0 //'if 0' leaves the values as missing, which is important: we don't want a bug in the plugin to translate to source values sitting in the variable (and thus inflating the observed prediction rate)

  // allocate space (we use new variables) to put probability estimates for each class for each prediction
  // this only makes sense in a classification problem, but we do not check for that
  if("`probability'"!="") {
    // ensure model is a classification
    // this duplicates code over in svm_train, but I think this is safest:
    //  svm_import allows you to pull in svm_models created by other libsvm
    //  interfaces, and they mostly don't have this protection.
    if("`e(svm_type)'" != "C_SVC" & "`e(svm_type)'" != "NU_SVC") {
      // in svm-predict.c, the equivalent section is:
      /*
       *        if (predict_probability && (svm_type==C_SVC || svm_type==NU_SVC))
       *                predict_label = svm_predict_probability(model,x,prob_estimates);
       *        else
       *                predict_label = svm_predict(model,x);
       */
      // it is cleaner to error out, rather than silently change the parameters, which is what the command line tools do
      di as error "Error: trained model is a `e(svm_type)'. You can only use the probability option with classification models (C_SVC, NU_SVC)."
      exit 2
    }

    // ensure type is categorical
    local T : type `e(depvar)'
    if("`T'"=="float" | "`T'"=="double") {
      di as error "Warning: `e(depvar)' is a `T', which is usually used for continuous variables."
      di as error "         It makes no sense to ask for category probabilities of continuous variables."
      di as error ""
      di as error "         If your variable is actually categorical, consider storing it as one:"
      di as error "         . tempvar B"
      di as error "         . generate byte \`B' = `e(depvar)'"   //CAREFUL: B is meant to be quoted and depvar is meant to be unquoted.
      di as error "         . drop `e(depvar)'"
      di as error "         . rename \`B' `e(depvar)'"
      di as error " "
      di as error "         SVM prediction is now being performed, but if your results are absurd, check that you have fit the right variable."
    }

    // save the top level description to splay across the stemmed variables
    local D : variable label `target'

    // loop over the possible (integer) values
    // this is the construction given at http://www.stata.com/support/faqs/data-management/try-all-values-with-foreach/
    // trying to loop over r(levels) directly fails with a syntax error because Stata
    quietly levelsof `e(depvar)', local(levels)
    // XXX the order of iteration here is critical:
    //     it MUST match the order in svm_model->labels or results will silently be permuted
    //     (and with several classes this becomes a big problem)
    foreach c of local levels {
      // this command is obscure; what it does is look up the
      // value label for variable `target' for value `c'
      // *or* give back `c' unchanged if `target' has no labels
      // which is precisely what we want it to do here
      local L : label (`target') `c'
      // compute the full variable name for level `c'
      local stemmed = "`target'_`L'"
      local stemmed = strtoname("`stemmed'") //sanitize the new name; this summarily avoids problems like one of your classes being "1.5"

      // finally, allocate it
      // unlike `target' which clones its source, we use doubles
      // because these are meant to hold probabilities

      // TODO: what happens if there's a name collision partially through this loop?
      //       what I want to happen is for any name collision or other bug to abort (i.e. rollback) the entire operation
      //       This can be achieved with "snapshot": snapshot; capture {}; if(fail) { rollback to snapshot }"
      quietly generate double `stemmed' = .
      label variable `stemmed' "Probability of `D' being category `L'"

      // attach the newcomers to the varlist so the plugin is allowed to edit them
      local varlist = "`varlist' `stemmed'"
    }
  }

  // call down into C
  // we indicate "probability" mode by passing a non-empty list of levels
  //  this list implicitly *removes* from the set range of variables to predict from: the trailing variables are instead write locations
  //  (this feels like programming a hardware driver)
  // Subtlety: we don't quote levels, on the assumption that it is always a list of integers;
  //           that way, the levels are pre-tokenized and the count easily available as argc

  //di as txt "svm_predict: plugin call _svm `target' `varlist' `_if' `_in', predict `probability'" /*DEBUG*/
  plugin call _svm `target' `varlist' `_if' `_in', predict `probability'
end


misc optimization

misc optimization

*! version 4.0.3 dev - 12feb2017

program reghdfe, eclass

	* Intercept old+version
	cap syntax, version old
	if !c(rc) {
		reghdfe_old, version
		exit
	}

	* Intercept old
	cap syntax anything(everything) [fw aw pw/], [*] old
	if !c(rc) {
		di as error "(running historical version of reghdfe)"
		if ("`weight'"!="") local weightexp [`weight'=`exp']
		reghdfe_old `anything' `weightexp', `options'
		exit
	}

	* Aux. subcommands
	cap syntax, [*]
	if inlist("`options'", "check", "compile", "requirements", "setup", "update", "version") {
		if ("`options'"=="compile") loc args force
		if ("`options'"=="check") loc options compile
		loc subcmd = proper("`options'")
		`subcmd' `args'
	}
	else if replay() {
		Replay `0'
	}
	else {
		Cleanup 0
		Compile // takes 0.01s to run this useful check (ensures .mlib exists)
		cap noi Estimate `0'
		Cleanup `c(rc)'
	}
end

// --------------------------------------------------------------------------

program Compile
	args force
	ftools, check // in case lftools.mlib does not exist or is outdated
	ms_get_version reghdfe // from moresyntax package; save local package_version

	loc list_objects "FixedEffects() fixed_effects() FE_Options() FE_Output() BipartiteGraph()"
	loc list_functions "reghdfe_*() transform_*() accelerate_*() panelmean() panelsolve_*()"
	loc list_misc "weighted_quadcolsum() safe_divide() check_convergence()"
	// TODO: prefix everything with reghdfe_*

	ms_compile_mata, ///
		package(reghdfe) ///
		version(`package_version') ///
		fun("`list_objects' `list_functions' `list_misc'") ///
		verbose ///
		`force'
end

program Requirements
	di as text _n "{bf:[reghdfe]} - updating required packages"
	di as text "{dup 64:=}"
	* -moresyntax- https://github.com/sergiocorreia/moresyntax/
	cap ado uninstall moresyntax
	//net install moresyntax, from(https://github.com/sergiocorreia/moresyntax/raw/master/source/)
	net install moresyntax, from(c:\git\moresyntax\src)
	di as text "{dup 64:-}"

	* -ftools- https://github.com/sergiocorreia/ftools/
	cap ado uninstall ftools
	//net install ftools, from(https://github.com/sergiocorreia/ftools/raw/master/source/)
	net install ftools, from(c:\git\ftools\src)
	di as text "{dup 64:-}"
	ftools, compile // requires moresyntax
	di as text "{dup 64:-}"
end

program Setup
	* Update requirements/dependencies
	Requirements

	* Compile -reghdfe-
	loc source "c:\git\reghdfe\src"
	di as text _n  _n "{bf:[reghdfe]} - compiling Mata code for {res}reghdfe"
	di as text "{dup 64:=}"
	reghdfe, compile
	di as text "{dup 64:-}"
end

program Update
	* Update requirements/dependencies
	Requirements

	* Update -reghdfe-
	loc source "c:\git\reghdfe\src"
	di as text _n  _n "{bf:[reghdfe]} - updating self from {res}`source'"
	di as text "{dup 64:=}"
	qui ado uninstall reghdfe
	net install reghdfe, from("`source'") // TODO: Change this
	qui which reghdfe
	di as text "{dup 64:-}"
	reghdfe, compile
	di as text "{dup 64:-}"
	di as text "{bf:Note:} You need to run {stata program drop _all} now."
end

program Version
	which reghdfe

	di as text _n "Dependencies installed?"
	local dependencies moresyntax ftools ivreg2 avar tuples
	foreach dependency of local dependencies {
		cap findfile `dependency'.ado
		if (_rc) {
			di as text "{lalign 20:- `dependency'}" as error "not"
		}
		else {
			di as text "{lalign 20:- `dependency'}" as result "yes"
		}
	}

end

// --------------------------------------------------------------------------

program Cleanup
	args rc
	cap mata: mata drop HDFE
	cap mata: mata drop hdfe_*
	cap matrix drop reghdfe_statsmatrix
	if (`rc') exit `rc'
end

program Estimate, eclass
	ereturn clear

* Parse and fill out HDFE object
	mata: HDFE = FixedEffects()
	reghdfe_parse `0' // store results on HDFE, HDFE.options, and HDFE.output
	loc OPT HDFE.options
	loc OUT HDFE.output

* Select sample
	marksample touse, strok // based on locals for varlist+cluster+absvars+if+in+weight (injected by -reghdfe_parse-)
	// -strok- because clustervars can be string

* Construct HDFE object
	// SYNTAX: fixed_effects(absvars | , touse, weighttype, weightvar, dropsing, verbose, object)
	mata: HDFE = fixed_effects(`OPT'.absorb, "`touse'", `OPT'.weight_type, `OPT'.weight_var, `OPT'.drop_singletons, HDFE.verbose, HDFE)
	mata: st_local("N", strofreal(HDFE.N))
	if (`N' == 0) error 2000

* Compute degrees-of-freedom
	mata: HDFE.estimate_dof()

* Save updated e(sample) (singletons reduce sample);
* required to parse factor variables to partial out
	mata: HDFE.save_touse("`touse'", 1)

* Expand varlists
	foreach cat in varlist depvar indepvars endogvars instruments {
		mata: st_local("vars", `OPT'.original_`cat')
		if ("`vars'" == "") continue
		// HACK: addbn replaces 0.foreign with 0bn.foreign , to prevent st_data() from loading a bunch of zeros
		ms_fvstrip `vars' if `touse', expand dropomit addbn onebyone
		// If we don't use onebyone, then 1.x 2.x ends up as 2.x
		loc vars "`r(varlist)'"
		mata: `OPT'.`cat' = "`vars'"
	}

* Stats
	mata: st_local("stats", `OPT'.summarize_stats)
	if ("`stats'" != "") Stats

* Partial out; and save TSS of depvar
	mata: hdfe_variables = HDFE.partial_out(`OPT'.varlist, 1) // 1=Save TSS of first var if HDFE.output.tss is missing

* Regress
	Regress `touse'
	mata: st_local("diopts", `OPT'.diopts)
	Replay, `diopts'

// ~~ Preserve relevant dataset ~~
	//
	// if (`compact') {
	// 	preserve
	// 	keep `varlist' `absorb'
	// 	loc N = c(N)
	// }
	// else {
	// 	qui cou if `touse'
	// 	loc N = r(N)
	// }
end

// -------------------------------------------------------------
// Run OLS regressions with partialled-out variables
// -------------------------------------------------------------
program Regress, eclass
	args touse

	tempname b V N rank df_r
	// Carefully split y from X, without duplicating the memory used
	mata: hdfe_y = hdfe_variables[., 1]
	mata: hdfe_variables = cols(hdfe_variables)==1 ? J(rows(hdfe_variables), 0, .) : hdfe_variables[., 2..cols(hdfe_variables)]
	mata: reghdfe_post_ols(HDFE, hdfe_y, hdfe_variables, "`b'", "`V'", "`N'", "`rank'", "`df_r'")
	mata: st_local("indepvars", HDFE.options.indepvars)
	mata: hdfe_y = hdfe_variables = .

	if ("`indepvars'" != "") {
		matrix colnames `b' = `indepvars'
		matrix colnames `V' = `indepvars'
		matrix rownames `V' = `indepvars'
		ereturn post `b' `V', esample(`touse') buildfvinfo depname(`depvar')
	}
	else {
		ereturn post, esample(`touse') buildfvinfo depname(`depvar')
	}

	ereturn scalar N       = `N'
	ereturn scalar rank    = `rank'
	ereturn scalar df_r    = `df_r'
	ereturn local  cmd     "reghdfe"
	mata: HDFE.output.post(HDFE.options)

	* Post stats
	cap conf matrix reghdfe_statsmatrix
	if (!c(rc)) {
		ereturn matrix summarize = reghdfe_statsmatrix
		mata: st_local("summarize_quietly", strofreal(HDFE.options.summarize_quietly))
		ereturn scalar summarize_quietly = `summarize_quietly'
	}
end

program Replay
	syntax [, *]
	_get_diopts options, `options'
	reghdfe_header // _coef_table_header
	di ""
	_coef_table, `options' // ereturn display, `options'
	reghdfe_footnote

	* Replay stats
	if (e(summarize_quietly)==0) {
		di as text _n "{sf:Regression Summary Statistics:}" _c
		matlist e(summarize)', border(top bottom) rowtitle(Variable) // twidth(18)
	}
end

// -----------------------------------------------------------------------------
// Matrix of summary statistics
// -----------------------------------------------------------------------------
cap pr drop Stats
pr Stats
	* Optional weights
	mata: st_local("weight", sprintf("[%s=%s]", HDFE.weighttype, HDFE.weightvar))
	assert "`weight'" != ""
	if ("`weight'" == "[=]") loc weight
	loc weight : subinstr local weight "[pweight" "[aweight"

	mata: st_local("stats", HDFE.options.summarize_stats)
	mata: st_local("varlist", HDFE.options.varlist)
	mata: st_local("cvars", invtokens(HDFE.cvars))
	loc full_varlist `varlist' `cvars'

	qui tabstat `full_varlist' `weight' , stat(`stats') col(stat) save
	matrix reghdfe_statsmatrix = r(StatTotal)
end

*! version 4.0.3 dev - 12feb2017

program reghdfe, eclass

	* Intercept old+version
	cap syntax, version old
	if !c(rc) {
		reghdfe_old, version
		exit
	}

	* Intercept old
	cap syntax anything(everything) [fw aw pw/], [*] old
	if !c(rc) {
		di as error "(running historical version of reghdfe)"
		if ("`weight'"!="") local weightexp [`weight'=`exp']
		reghdfe_old `anything' `weightexp', `options'
		exit
	}

	* Aux. subcommands
	cap syntax, [*]
	if inlist("`options'", "check", "compile", "requirements", "setup", "update", "version") {
		if ("`options'"=="compile") loc args force
		if ("`options'"=="check") loc options compile
		loc subcmd = proper("`options'")
		`subcmd' `args'
	}
	else if replay() {
		Replay `0'
	}
	else {
		Cleanup 0
		Compile // takes 0.01s to run this useful check (ensures .mlib exists)
		cap noi Estimate `0'
		Cleanup `c(rc)'
	}
end

// --------------------------------------------------------------------------

program Compile
	args force
	ftools, check // in case lftools.mlib does not exist or is outdated
	ms_get_version reghdfe // from moresyntax package; save local package_version

	loc list_objects "FixedEffects() fixed_effects() FE_Options() FE_Output() BipartiteGraph()"
	loc list_functions "reghdfe_*() transform_*() accelerate_*() panelmean() panelsolve_*()"
	loc list_misc "weighted_quadcolsum() safe_divide() check_convergence()"
	// TODO: prefix everything with reghdfe_*

	ms_compile_mata, ///
		package(reghdfe) ///
		version(`package_version') ///
		fun("`list_objects' `list_functions' `list_misc'") ///
		verbose ///
		`force'
end

program Requirements
	di as text _n "{bf:[reghdfe]} - updating required packages"
	di as text "{dup 64:=}"
	* -moresyntax- https://github.com/sergiocorreia/moresyntax/
	cap ado uninstall moresyntax
	//net install moresyntax, from(https://github.com/sergiocorreia/moresyntax/raw/master/source/)
	net install moresyntax, from(c:\git\moresyntax\src)
	di as text "{dup 64:-}"

	* -ftools- https://github.com/sergiocorreia/ftools/
	cap ado uninstall ftools
	//net install ftools, from(https://github.com/sergiocorreia/ftools/raw/master/source/)
	net install ftools, from(c:\git\ftools\src)
	di as text "{dup 64:-}"
	ftools, compile // requires moresyntax
	di as text "{dup 64:-}"
end

program Setup
	* Update requirements/dependencies
	Requirements

	* Compile -reghdfe-
	loc source "c:\git\reghdfe\src"
	di as text _n  _n "{bf:[reghdfe]} - compiling Mata code for {res}reghdfe"
	di as text "{dup 64:=}"
	reghdfe, compile
	di as text "{dup 64:-}"
end

program Update
	* Update requirements/dependencies
	Requirements

	* Update -reghdfe-
	loc source "c:\git\reghdfe\src"
	di as text _n  _n "{bf:[reghdfe]} - updating self from {res}`source'"
	di as text "{dup 64:=}"
	qui ado uninstall reghdfe
	net install reghdfe, from("`source'") // TODO: Change this
	qui which reghdfe
	di as text "{dup 64:-}"
	reghdfe, compile
	di as text "{dup 64:-}"
	di as text "{bf:Note:} You need to run {stata program drop _all} now."
end

program Version
	which reghdfe

	di as text _n "Dependencies installed?"
	local dependencies moresyntax ftools ivreg2 avar tuples
	foreach dependency of local dependencies {
		cap findfile `dependency'.ado
		if (_rc) {
			di as text "{lalign 20:- `dependency'}" as error "not"
		}
		else {
			di as text "{lalign 20:- `dependency'}" as result "yes"
		}
	}

end

// --------------------------------------------------------------------------

program Cleanup
	args rc
	cap mata: mata drop HDFE
	cap mata: mata drop hdfe_*
	cap matrix drop reghdfe_statsmatrix
	if (`rc') exit `rc'
end

program Estimate, eclass
	ereturn clear

* Parse and fill out HDFE object
	mata: HDFE = FixedEffects()
	reghdfe_parse `0' // store results on HDFE, HDFE.options, and HDFE.output
	loc OPT HDFE.options
	loc OUT HDFE.output

* Select sample
	marksample touse, strok // based on locals for varlist+cluster+absvars+if+in+weight (injected by -reghdfe_parse-)
	// -strok- because clustervars can be string

* Construct HDFE object
	// SYNTAX: fixed_effects(absvars | , touse, weighttype, weightvar, dropsing, verbose, object)
	mata: HDFE = fixed_effects(`OPT'.absorb, "`touse'", `OPT'.weight_type, `OPT'.weight_var, `OPT'.drop_singletons, HDFE.verbose, HDFE)
	mata: st_local("N", strofreal(HDFE.N))
	if (`N' == 0) error 2000
	drop `touse' // save memory

* Compute degrees-of-freedom
	mata: HDFE.estimate_dof()

* Save updated e(sample) (singletons reduce sample);
* required to parse factor variables to partial out
	mata: HDFE.save_touse("`touse'")

* Expand varlists
	foreach cat in varlist depvar indepvars endogvars instruments {
		mata: st_local("vars", `OPT'.original_`cat')
		if ("`vars'" == "") continue
		// HACK: addbn replaces 0.foreign with 0bn.foreign , to prevent st_data() from loading a bunch of zeros
		ms_fvstrip `vars' if `touse', expand dropomit addbn onebyone
		// If we don't use onebyone, then 1.x 2.x ends up as 2.x
		loc vars "`r(varlist)'"
		mata: `OPT'.`cat' = "`vars'"
	}

* Stats
	mata: st_local("stats", `OPT'.summarize_stats)
	if ("`stats'" != "") Stats

* Partial out; and save TSS of depvar
	mata: hdfe_variables = HDFE.partial_out(`OPT'.varlist, 1) // 1=Save TSS of first var if HDFE.output.tss is missing

* Regress
	Regress `touse'
	mata: st_local("diopts", `OPT'.diopts)
	Replay, `diopts'

// ~~ Preserve relevant dataset ~~
	//
	// if (`compact') {
	// 	preserve
	// 	keep `varlist' `absorb'
	// 	loc N = c(N)
	// }
	// else {
	// 	qui cou if `touse'
	// 	loc N = r(N)
	// }
end

// -------------------------------------------------------------
// Run OLS regressions with partialled-out variables
// -------------------------------------------------------------
program Regress, eclass
	args touse

	tempname b V N rank df_r
	// Carefully split y from X, without duplicating the memory used
	mata: hdfe_y = hdfe_variables[., 1]
	mata: hdfe_variables = cols(hdfe_variables)==1 ? J(rows(hdfe_variables), 0, .) : hdfe_variables[., 2..cols(hdfe_variables)]
	mata: reghdfe_post_ols(HDFE, hdfe_y, hdfe_variables, "`b'", "`V'", "`N'", "`rank'", "`df_r'")
	mata: st_local("indepvars", HDFE.options.indepvars)
	mata: hdfe_y = hdfe_variables = .

	if ("`indepvars'" != "") {
		matrix colnames `b' = `indepvars'
		matrix colnames `V' = `indepvars'
		matrix rownames `V' = `indepvars'
		ereturn post `b' `V', esample(`touse') buildfvinfo depname(`depvar')
	}
	else {
		ereturn post, esample(`touse') buildfvinfo depname(`depvar')
	}

	ereturn scalar N       = `N'
	ereturn scalar rank    = `rank'
	ereturn scalar df_r    = `df_r'
	ereturn local  cmd     "reghdfe"
	mata: HDFE.output.post(HDFE.options)

	* Post stats
	cap conf matrix reghdfe_statsmatrix
	if (!c(rc)) {
		ereturn matrix summarize = reghdfe_statsmatrix
		mata: st_local("summarize_quietly", strofreal(HDFE.options.summarize_quietly))
		ereturn scalar summarize_quietly = `summarize_quietly'
	}
end

program Replay
	syntax [, *]
	_get_diopts options, `options'
	reghdfe_header // _coef_table_header
	di ""
	_coef_table, `options' // ereturn display, `options'
	reghdfe_footnote

	* Replay stats
	if (e(summarize_quietly)==0) {
		di as text _n "{sf:Regression Summary Statistics:}" _c
		matlist e(summarize)', border(top bottom) rowtitle(Variable) // twidth(18)
	}
end

// -----------------------------------------------------------------------------
// Matrix of summary statistics
// -----------------------------------------------------------------------------
cap pr drop Stats
pr Stats
	* Optional weights
	mata: st_local("weight", sprintf("[%s=%s]", HDFE.weighttype, HDFE.weightvar))
	assert "`weight'" != ""
	if ("`weight'" == "[=]") loc weight
	loc weight : subinstr local weight "[pweight" "[aweight"

	mata: st_local("stats", HDFE.options.summarize_stats)
	mata: st_local("varlist", HDFE.options.varlist)
	mata: st_local("cvars", invtokens(HDFE.cvars))
	loc full_varlist `varlist' `cvars'

	qui tabstat `full_varlist' `weight' , stat(`stats') col(stat) save
	matrix reghdfe_statsmatrix = r(StatTotal)
end


adding col numbers

adding col numbers

program ivest

use $stash/master, clear
keep if isbaseball == 1

gen instrument = post*treat
gen inducted_i = (everinducted == 1)

gen careerlength = finalyear - debutyear
gen ageatdebut = debutyear - birthyear
tabulate year, gen(ytmp)

local controls "inducted_i ageatdebut careerlength"
label variable traf "Traffic"
label variable img "Images"
label variable treat "Out-of-Copy"
label variable instrument "Out-Of-Copy. X Post"

est clear
eststo: reg traf img ytmp5-ytmp13 `controls', clust(id)
estadd local covar "Yes"
estadd local yearfe "Yes"

eststo: xtreg traf img ytmp5-ytmp13, fe clust(id)
estadd local covar "Player FE"
estadd local yearfe "Yes"

eststo: ivreg2 traf (img=instrument) ytmp5-ytmp13, small savefirst savefprefix(first) clust(id)
mat first=e(first)
local FStat = round(first[3,1],0.01)
estadd local FStat `FStat'  : firstimg
estadd local covar "Yes" : firstimg
estadd local covar "Yes"
estadd local yearfe "Yes" : firstimg
estadd local yearfe "Yes"

 eststo: xtivreg2 traf (img=instrument) ytmp5-ytmp13, fe small savefirst savefprefix(firstcontrol) clust(id) ffirst
mat first=e(first)
local FStat = round(first[3,1],0.01)
estadd local FStat `FStat'  : firstcontrolimg
estadd local covar "Player FE" : firstcontrolimg
estadd local covar "Player FE"
estadd local yearfe "Yes" : firstcontrolimg
estadd local yearfe "Yes"

local note1 "Standard errors clustered at player level are reported"
local note2 "* p $<$ 0.10, ** p $<$ 0.05, *** p $<$ 0.01"

esttab est1 est2 firstimg firstc* est3 est4 using ${tables}mechanism.tex, drop(_cons `controls' *ytmp*) se stats(covar yearfe N r2 FStat,labels("Controls" "Year FE" "N" "adj. \$R^2\$" "F-Stat")) label replace mgroups("OLS" "First Stage" "IV Estimates", pattern(1 0 1 0 1 0) prefix(\multicolumn{@span}{c}{) suffix(}) span erepeat(\cmidrule(lr){@span})) booktabs  addnote("`note1'" "`note2'") nonotes

end

program ivest

use $stash/master, clear
keep if isbaseball == 1

gen instrument = post*treat
gen inducted_i = (everinducted == 1)

gen careerlength = finalyear - debutyear
gen ageatdebut = debutyear - birthyear
tabulate year, gen(ytmp)

local controls "inducted_i ageatdebut careerlength"
label variable traf "Traffic"
label variable img "Images"
label variable treat "Out-of-Copy"
label variable instrument "Out-Of-Copy. X Post"

est clear
eststo: reg traf img ytmp5-ytmp13 `controls', clust(id)
estadd local covar "Yes"
estadd local yearfe "Yes"

eststo: xtreg traf img ytmp5-ytmp13, fe clust(id)
estadd local covar "Player FE"
estadd local yearfe "Yes"

eststo: ivreg2 traf (img=instrument) ytmp5-ytmp13, small savefirst savefprefix(first) clust(id)
mat first=e(first)
local FStat = round(first[3,1],0.01)
estadd local FStat `FStat'  : firstimg
estadd local covar "Yes" : firstimg
estadd local covar "Yes"
estadd local yearfe "Yes" : firstimg
estadd local yearfe "Yes"

 eststo: xtivreg2 traf (img=instrument) ytmp5-ytmp13, fe small savefirst savefprefix(firstcontrol) clust(id) ffirst
mat first=e(first)
local FStat = round(first[3,1],0.01)
estadd local FStat `FStat'  : firstcontrolimg
estadd local covar "Player FE" : firstcontrolimg
estadd local covar "Player FE"
estadd local yearfe "Yes" : firstcontrolimg
estadd local yearfe "Yes"

local note1 "Standard errors clustered at player level are reported"
local note2 "* p $<$ 0.10, ** p $<$ 0.05, *** p $<$ 0.01"

esttab est1 est2 firstimg firstc* est3 est4 using ${tables}mechanism.tex, drop(_cons `controls' *ytmp*) se stats(covar yearfe N r2 FStat,labels("Controls" "Year FE" "N" "adj. \$R^2\$" "F-Stat")) label replace mgroups("OLS" "First Stage" "IV Estimates", pattern(1 0 1 0 1 0) prefix(\multicolumn{@span}{c}{) suffix(}) span erepeat(\cmidrule(lr){@span})) booktabs nonumber  addnote("`note1'" "`note2'") nonotes

end