***********************************************************************************************;
**  Program Name    :  adce-s010-lr-p3-saf.sas                                               **;
**  Date Created    :  11Mar2021                                                             **;
**  Programmer Name :  FENGY46                                                               **;
**  Purpose         :  Create adce-s010-lr-p3-saf                                            **;
**  Input data      :  adfacevd adsl                                                         **;
**  Output file     :  adce-s010-lr-p3-saf.html                                              **;
***********************************************************************************************;
options mprint mlogic symbolgen mprint symbolgen mlogic nocenter missing=" ";
ods escapechar="~";
proc datasets library=WORK kill nolist nodetails;
quit;

**Setup the environment**;
%let prot=/Volumes/app/cdars/prod/sites/cdars4/prjC459/nda2_unblinded_esub/bla_esub_adam/saseng/cdisc3_0; 
libname datvprot "&prot./data_vai" access=readonly;

%let codename=adce-s010-lr-p3-saf;
%let outlog=&prot./analysis/esub/logs/&codename..log;
%let outtable=&prot./analysis/esub/output/&codename..html;

proc printto log="&outlog" new;
run;

******************************************************************************************;
* Specification 1                                                                        *;
* Create foramts                                                                         *;
******************************************************************************************;

Proc format;
	value SEV 
	0="Any"           
	1="Mild"          
	2="Moderate"      
	3="Severe"
	4="Grade 4" 
	;
	value VAC 
	1="1"           
	2="2"          
	3="3"      
	99="ANY"
	;  
	value BY1FMT 
	2="16-55 Years"          
	5=">55 Years"      
	;  
run;

******************************************************************************************;
* Specification 2                                                                        *;
* Input source data adfacevd and adsl                                                    *;
******************************************************************************************;

data g_adsl_dsin;
	set DATVPROT.ADSL;
	where SAFFL eq 'Y' and phasen ne 1 and agegr1n ne 1 and MULENRFL ne "Y" and HIVFL ne 'Y';
run;

data g_a_dsin;
	set DATVPROT.adfacevd;
	where SAFFL eq 'Y' and CUTUNBFL ne "Y" and knowvfl="Y" and phasen ne 1 and agegr1n ne 1 and MULENRFL ne "Y" and HIVFL ne 'Y';
	
	if TRTAN in (8) then
		do;
			newtrtn=1;
			newtrt=coalescec("BNT162b2 (30 (*ESC*){unicode 03BC}g)", TRTA);
			output;
		end;

	if TRTAN in (9) then
		do;
			newtrtn=2;
			newtrt=coalescec("Placebo", TRTA);
			output;
		end;
run;

data g_a_dsin;
	set g_a_dsin;
	atptrefn=input(compress(atptref , '', 'A'), ??best.);
	atptref=compress(atptref , '', 'A');
	output;

	if atptref ne "";
	atptref="Any dose";
	atptrefn=99;
	output;
run;


******************************************************************************************;
**Regarding medication errors, subset for Reactogenicity analysis                       **;
**1.Count subjects in what they received at Dose 1 for post Dose 1 summary.             **;
**2.Remove subjects from post Dose 2 summary.                                           **; 
**3.Count subjects in active for after any dose summary.                                **;
******************************************************************************************;
data g_a_dsin;
   set g_a_dsin;
   where trta ne '';
   if VAX101 ne VAX102 and cmiss(VAX101,VAX102)=0 then do;
      if atptrefn=2 then delete;
      if atptrefn=99 then do;
         TRTAN=TRT01AN;TRTA=TRT01A;
         if TRTAN=8 then do; newtrtn =1; newtrt = "BNT162b2 (30 (*ESC*){unicode 03BC}g)"; end;
         if TRTAN=9 then do; newtrtn =2; newtrt = "Placebo"; end;
     end;
   end;
run;

********************************************************************************;
* Specification 3                                                              *;
* 1) Select all necessary parameters                                           *;
* 2) Create flags for Any Local Reaction and Any Dose rows                     *;
* 3) Create order variables for next statistic analyses                        *;
* 4) Merge adsl and analysis dataset                                           *;
********************************************************************************;

proc sort data=g_a_dsin;
	by usubjid;
run;

proc sql;
	create table a1 as select distinct newtrt, usubjid, faobj , atptref from g_a_dsin where upcase(FATESTCD)='OCCUR';
quit;

proc sql;
	create table a2 as select distinct newtrt, usubjid, faobj , atptref from a1 
		except select distinct newtrt, usubjid , faobj , atptref from g_a_dsin where FATESTCD='MAXSEV';
quit;

proc sort data=a2;
	by newtrt usubjid faobj atptref;
quit;

proc sort data=g_a_dsin out=facevd;
	by newtrt usubjid faobj atptref;
quit;

data a3;
	merge facevd(in=a) a2(in=b);
	by newtrt usubjid faobj atptref;
	if fatestcd='OCCUR';
	if a and b then output;
run;

proc sort data=a3;
	by faobj newtrt usubjid atptref ady newtrtn;
quit;

data a4(drop=paramcd);
	set a3;
	by faobj newtrt usubjid atptref ady newtrtn;

	if first.atptref;
	aval=0;
	avalc='NONE';
	knowvfl='Y';
	fatestcd='MAXSEV';
run;

data _param;
	set g_a_dsin;
	if fatestcd='MAXSEV';
	keep faobj paramcd;
run;

proc sort nodupkey data=_param;
	by faobj paramcd;
run;

data a4;
	merge a4(in=a) _param;
	by faobj;
	if a;
run;

data g_a_dsin;
	set g_a_dsin a4;
run;

data _a_dsin;
	set g_a_dsin;
	length _faobj_ord 8;

	if missing(aval) then aval=0;

	if missing(avalc) then avalc='NONE';

	if upcase(faobj)="PAIN AT INJECTION SITE" then faobj="Pain at the injection site";
	FAOBJ=upcase(substr(FAOBJ, 1, 1))||lowcase(substr(FAOBJ, 2));

	if upcase(paramcd)="MSERE" then
		do;
			_faobj_ord=1;

			if upcase(paramcd) in ('MSERE', 'MSESW') then
				do;
					_faobj_label=trim(FAOBJ)||"(*ESC*){super d}";
				end;
			else if upcase(paramcd) in ('MSPIS') then
				do;
					_faobj_label=trim(FAOBJ)||"(*ESC*){super e}";
				end;
			else if upcase(paramcd) in ('MSLARM') then
				do;
					_faobj_label=trim(FAOBJ)||"(*ESC*){super f}";
				end;
			else
				do;
					_faobj_label=trim(FAOBJ);
				end;
			output;
		end;

	if upcase(paramcd)="MSESW" then
		do;
			_faobj_ord=2;

			if upcase(paramcd) in ('MSERE', 'MSESW') then
				do;
					_faobj_label=trim(FAOBJ)||"(*ESC*){super d}";
				end;
			else if upcase(paramcd) in ('MSPIS') then
				do;
					_faobj_label=trim(FAOBJ)||"(*ESC*){super e}";
				end;
			else if upcase(paramcd) in ('MSLARM') then
				do;
					_faobj_label=trim(FAOBJ)||"(*ESC*){super f}";
				end;
			else
				do;
					_faobj_label=trim(FAOBJ);
				end;
			output;
		end;

	if upcase(paramcd)="MSPIS" then
		do;
			_faobj_ord=3;

			if upcase(paramcd) in ('MSERE', 'MSESW') then
				do;
					_faobj_label=trim(FAOBJ)||"(*ESC*){super d}";
				end;
			else if upcase(paramcd) in ('MSPIS') then
				do;
					_faobj_label=trim(FAOBJ)||"(*ESC*){super e}";
				end;
			else if upcase(paramcd) in ('MSLARM') then
				do;
					_faobj_label=trim(FAOBJ)||"(*ESC*){super f}";
				end;
			else
				do;
					_faobj_label=trim(FAOBJ);
				end;
			output;
		end;

	if upcase(paramcd)="ANY" then
		do;
			_faobj_ord=4;

			if upcase(paramcd) in ('MSERE', 'MSESW') then
				do;
					_faobj_label=trim(FAOBJ)||"(*ESC*){super d}";
				end;
			else if upcase(paramcd) in ('MSPIS') then
				do;
					_faobj_label=trim(FAOBJ)||"(*ESC*){super e}";
				end;
			else if upcase(paramcd) in ('MSLARM') then
				do;
					_faobj_label=trim(FAOBJ)||"(*ESC*){super f}";
				end;
			else
				do;
					_faobj_label=trim(FAOBJ);
				end;
			output;
		end;
run;

proc sort data=_a_dsin;
	by newtrt faobj usubjid atptref descending aval;
run;

data _a_dsin;
	set _a_dsin;
	by newtrt faobj usubjid atptref descending aval;
	if first.atptref;
run;

data _a_any;
	set _a_dsin;
	FAOBJ='Any local reaction';
	PARAMCD='ANY';
	_faobj_ord=999;
	_faobj_label=trim(FAOBJ)||"(*ESC*){super f}";
run;

proc sort data=_a_any;
	by newtrt usubjid atptref newtrtn descending aval;
run;

data _a_any;
	set _a_any;
	by newtrt usubjid atptref newtrtn descending aval;
	if first.atptref;
run;

data _a_dsin;
	set _a_dsin _a_any;
run;

data anysev;
	set _a_dsin;

	if aval=0 then
		do;
			ex_none_flg=1;
		end;
	else
		do;
			ex_none_flg=0;
		end;
	AVALC='ANY';
	AVAL=0;
	output;
run;

data _a_dsin;
	set _a_dsin anysev;
run;

proc sql;
	create table _bigN as select distinct newtrt, usubjid, paramcd, knowvfl, atptref 
	  from _a_dsin where fatestcd='MAXSEV';
quit;

data _bigN;
	set _bigN;
	DENOMFL=0;
	output;
	DENOMFL=1;
	output;
	DENOMFL=2;
	output;
	DENOMFL=3;
	output;
	DENOMFL=4;
	output;
run;

proc sort data=_a_dsin;
	by newtrt usubjid paramcd knowvfl atptref;
quit;

proc sort data=_bigN;
	by newtrt usubjid paramcd knowvfl atptref;
quit;

data _a_dsin;
	merge _a_dsin _bigN;
	by newtrt usubjid paramcd knowvfl atptref;

	if paramcd in ('ANY') and ^missing(aval) then
		do;
			denomfl=1;
			if aval > 0 then aval=1;
		end;
run;

data _dsin_terms(keep=paramcd _faobj_ord _faobj_label);
	set _a_dsin;
run;

proc sort data=_dsin_terms out=grp(keep=paramcd _faobj_label) nodupkey;
	by _faobj_ord;
quit;

proc sort data=g_adsl_dsin out=_ds1;
	by usubjid;
run;

proc sort data=_a_dsin out=_ds2;
	by usubjid;
run;

data final;
	merge _ds1(in=d1) _ds2(in=d2);
	by usubjid;
	if d2;
run;
proc sort data=final;
	by newtrt usubjid;
run;

data final;
	set final;
	if knowvfl='Y' then _knowvfl=1;
	if avalc not in ('ANY', 'NONE') then ex_none_flg=0;
run;


******************************************************************************************;
* Specification 4                                                                        *;
* Create a template dataset                                                              *;
******************************************************************************************;

*----------------------------------------------------------------------;
* Initialize structure for _BASETEMPLATE dataset. ;
*----------------------------------------------------------------------;
data _basetemplate(compress=no);
	length _varname $8 _cvalue $30 _direct $20 _vrlabel $200 _rwlabel 
		_colabel $800 _datatyp $5 _module $8 _pr_lbl $ 200;
	array _c _character_;
	delete;
run;

data _data1;
	set final;
	where (NEWTRTN is not missing);
run;

proc sort data=_data1;
	by NEWTRTN USUBJID;
run;

data _data1;
	retain _trt 0;
	length _str $200;
	_datasrt=1;
	set _data1 end=eof;
	by NEWTRTN USUBJID;
	drop _str;
	_str=' ';
	_lastby=1;
	_dummyby=0;

	if first.NEWTRTN then
		do;

			if not missing(NEWTRTN) then
				do;
					_trt=_trt + 1;
				end;
			*----------------------------------------------------------------------;
			* Generate _STR as the treatment label ;
			*----------------------------------------------------------------------;
			_str=NEWTRT;
			*----------------------------------------------------------------------;
			* Update _TRTLB&n with generated treatment label ;
			*----------------------------------------------------------------------;

			if _trt > 0 then
				call symput('_trtlb'||compress(put(_trt, 4.)), trim(left(_str)));
		end;
run;

*----------------------------------------------------------------------;
* Generate a dataset containing all by-variables ;
*----------------------------------------------------------------------;
proc sort data=_data1 out=_bydat1(keep=_datasrt AGEGR1N ATPTREFN ATPTREF 
		_dummyby) nodupkey;
	by _datasrt AGEGR1N ATPTREFN;
run;

data _bydat1;
	set _bydat1 end=eof;
	by _datasrt AGEGR1N ATPTREFN;
	retain _preby 0;
	drop _preby ATPTREF;
	length _bylab1-_bylab2 $100;
	retain _byvar1-_byvar2 0 _bylen1-_bylen2 0 _bylab1-_bylab2;

	if first.AGEGR1N then
		do;
			_byvar2=0;
		end;

	if first.AGEGR1N then
		do;
			_byvar1 + 1;
			_bylab1=put(AGEGR1N, BY1FMT.);
			_bylen1=max(_bylen1, length(_bylab1));
		end;

	if first.ATPTREFN then
		do;
			_byvar2 + 1;
			_bylab2=ATPTREF;
			_bylen2=max(_bylen2, length(_bylab2));
		end;
	output;

	if last.ATPTREFN then
		do;

			if _byvar2 > _preby then
				_preby=_byvar2;
			call symput("_prebyl", compress(put(_preby, 4.)));
		end;

	if eof then
		do;
			call symput("_preby1", compress(put(_byvar1, 4.)));

			if 2=0 then
				output;
		end;
run;

data _bydat1;
	set _bydat1;
	by _datasrt;
	length _bycol _byindnt $50 _bylast $10;
	_bycol="1 2 ";
	_byindnt="0 0 ";
	_bylast=" ";
run;

proc sort data=_bydat1 out=_Byfrm2(keep=_datasrt ATPTREFN) nodupkey;
	by _datasrt ATPTREFN;
run;

data _Byfrm2;
	set _byfrm2;
	by _datasrt ATPTREFN;
	retain _nwbyvar2 0;

	if first.ATPTREFN then
		do;
			_nwbyvar2 + 1;
		end;
run;

proc sort data=_bydat1;
	by _datasrt ATPTREFN;
run;

data _bydat1(drop=_nwbyvar2);
	merge _bydat1 _byfrm2;
	by _datasrt ATPTREFN;
	_byvar2=_nwbyvar2;
run;

proc sort data=_bydat1;
	by _datasrt AGEGR1N ATPTREFN;
run;

proc sort data=_data1 out=_data1;
	by _datasrt AGEGR1N ATPTREFN;
run;

*----------------------------------------------------------------------;
* Merge calculated by variables back into _DATAn dataset. ;
*----------------------------------------------------------------------;

data _data1;
	merge _bydat1(keep=_datasrt _byvar1 _byvar2 AGEGR1N ATPTREFN) _data1(in=_b);
	by _datasrt AGEGR1N ATPTREFN;

	if _b;
run;

proc sort data=_data1;
	by _datasrt _byvar1 _byvar2;
run;

data _tmpdata1;
	set _data1;
	output;
run;

data _trtsubgrpframe;
	_cat=1;
	_trt=1;
	output;
	_trt=2;
	output;
run;

proc sql noprint;
	create table _fullbyvar as select * from (select distinct _trt, _cat from 
		_trtsubgrpframe), (select distinct _byvar1, _byvar2 from _bydat1) order by 
		_trt, _byvar1, _byvar2;
quit;

proc sql;
	create table _bydatn1 as select distinct _trt, _byvar1, _byvar2, count(distinct 
		USUBJID) as byvar1n from _tmpdata1 group by _trt, _byvar1, _byvar2;
quit;

data _fullbyvar;
	merge _fullbyvar(in=a) _bydatn1;
	by _trt _byvar1;

	if a;

	if missing(byvar1n) then
		byvar1n=0;
run;

proc sql;
	create table _bydatn12 as select distinct _trt, _byvar1, _byvar2, 
		count(distinct USUBJID) as byvar12n from _tmpdata1 group by _trt, _byvar1, 
		_byvar2;
quit;

data _fullbyvar;
	merge _fullbyvar(in=a) _bydatn12;
	by _trt _byvar1 _byvar2;

	if a;

	if missing(byvar12n) then
		byvar12n=0;
run;

data _byvardata1;
	set _fullbyvar;

	if _trt=9999 then
		_trt=3;
run;

***************************************************************************************************;
* Specification 5                                                                                 *;
* 1) Count N: number of subjects with any e-diary data reported after Vaccination 1               *;
* 2) Count n and %: number of subjects with the specified characteristic and proportion           *;
* 3) Calculate 95% CI for %: exact 2-sided CI based on the Clopper and Pearson method             *;
***************************************************************************************************;

********************************************************************************;
* Specification 5.1: Statistics for Redness category                           *;
********************************************************************************;
* Specification 5.1.1: Count denominator (N)                                   *;
********************************************************************************;

data _anal1;
	length DENOMFL 8;
	set _data1;
	where same and DENOMFL is not missing;
	_blcksrt=1;
	_cnt=1;
	_cat=1;

	if _trt <=0 then
		delete;
	output;
run;

proc sort data=_anal1;
	by _datasrt _byvar1 _byvar2 _blcksrt DENOMFL _trt _cat;
run;

proc sort data=_anal1 out=_catby1(keep=_byvar1 _byvar2) nodupkey;
	by _byvar1 _byvar2;
	where paramcd eq upcase("Msere");
run;

data _temp1;
	set _anal1;
	output;
run;

proc sort data=_temp1 out=_temp91 nodupkey;
	by _datasrt _byvar1 _byvar2 _blcksrt _cat DENOMFL _trt usubjid;
	where paramcd eq upcase("Msere");
run;

proc freq data=_temp91 noprint;
	format DENOMFL;
	tables _datasrt*_byvar1*_byvar2*_blcksrt*_cat * DENOMFL * _trt / sparse norow nocol 
		nopercent out=_pct1(drop=percent);
run;

proc freq data=_pct1 noprint;
	where DENOMFL ne 9999;
	weight count;
	tables _datasrt*_byvar1*_byvar2*_cat * _trt / sparse noprint out=_denom1(drop=percent);
run;

data _denomf1;
	_datasrt=1;
	set _catby1(keep=_byvar1 _byvar2);
	* All treatment groups ;
	_trt1=0;
	_trt2=0;
	* _CAT is the subgroup variable ;
	_cat=1;
	output;
run;


proc transpose data=_denom1 out=_denomin1(drop=_name_ _label_) prefix=_trt;
	by _datasrt _byvar1 _byvar2 _cat;
	var count;
	id _trt;
run;

data _frame1;
	_datasrt=1;
	set _catby1(keep=_byvar1 _byvar2);
	_blcksrt=1;
	length DENOMFL 8;
	_catLabl=" ";
	_trt=1;
	DENOMFL=0;
	_catord=1;
	_cat=1;
	output;
	_trt=2;
	DENOMFL=0;
	_catord=1;
	_cat=1;
	output;
	_catLabl=" ";
	_trt=1;
	DENOMFL=1;
	_catord=2;
	_cat=1;
	output;
	_trt=2;
	DENOMFL=1;
	_catord=2;
	_cat=1;
	output;
	_catLabl=" ";
	_trt=1;
	DENOMFL=2;
	_catord=3;
	_cat=1;
	output;
	_trt=2;
	DENOMFL=2;
	_catord=3;
	_cat=1;
	output;
	_catLabl=" ";
	_trt=1;
	DENOMFL=3;
	_catord=4;
	_cat=1;
	output;
	_trt=2;
	DENOMFL=3;
	_catord=4;
	_cat=1;
	output;
	_catLabl=" ";
	_trt=1;
	DENOMFL=4;
	_catord=5;
	_cat=1;
	output;
	_trt=2;
	DENOMFL=4;
	_catord=5;
	_cat=1;
	output;
run;

proc sort data=_frame1;
	by _datasrt _byvar1 _byvar2 _blcksrt _cat DENOMFL _trt;
run;

proc sort data=_pct1;
	by _datasrt _byvar1 _byvar2 _blcksrt _cat DENOMFL _trt;
run;

data _pct1;
	merge _frame1(in=_inframe) _pct1;
	by _datasrt _byvar1 _byvar2 _blcksrt _cat DENOMFL _trt;
	if _inframe;
	if count=. then count=0;
run;

proc sort data=_pct1;
	by _datasrt _byvar1 _byvar2 _blcksrt DENOMFL;
run;

data _miss1(keep=_datasrt _byvar1 _byvar2 _blcksrt DENOMFL totcount);
	set _pct1;
	where DENOMFL=9998;
	retain totcount;
	by _datasrt _byvar1 _byvar2 _blcksrt DENOMFL;

	if first.DENOMFL then totcount=0;
	totcount=totcount+count;

	if last.DENOMFL;
run;

data _pct1(drop=totcount);
	merge _pct1 _miss1;
	by _datasrt _byvar1 _byvar2 _blcksrt DENOMFL;

	if totcount=0 then delete;
run;

proc sort data=_denomf1;
	by _datasrt _byvar1 _byvar2 _cat;
run;

proc sort data=_denomin1;
	by _datasrt _byvar1 _byvar2 _cat;
run;

data _denomin1;
	merge _denomf1(in=_inframe) _denomin1;
	by _datasrt _byvar1 _byvar2 _cat;

	if _inframe;
	_blcksrt=1;
run;

proc sort data=_pct1;
	by _datasrt _byvar1 _byvar2 _cat;
run;

data _pct1;
	if 0 then
		set _basetemplate;
	merge _denomin1(in=_a) _pct1;
	by _datasrt _byvar1 _byvar2 _cat;

	if _a;
	_varname="DENOMFL ";
	_vrlabel="Redness(*ESC*){super d} ";
	_rwlabel=put(DENOMFL, sev.);

	if DENOMFL=9998 then
		do;
			_rwlabel="Missing ";
			_catord=9998;
		end;
	else if DENOMFL=9999 then
		do;
			_rwlabel="Total ";
			_catord=9999;
		end;

	if _catord=. then
		_catord=9997;
run;

proc sort data=_pct1;
	by _datasrt _byvar1 _byvar2 _blcksrt _catord DENOMFL _trt _cat;
run;

data _base1;
	length _catlabl $200;
	set _pct1 end=eof;
	by _datasrt _byvar1 _byvar2 _blcksrt _catord DENOMFL _trt _cat;
	retain _rowsrt 0 _rowmax 0;
	array _trtcnt(*) _trt1-_trt3;
	drop _rowmax _cpct;
	length _cpct $100;
	_cpct=' ';
	_module='mcatstat';

	if count > . then
		_cvalue=put(count, 5.);
	else
		_cvalue=put(0, 5.);

	if length(_cvalue) < 5 then
		do;
			*----------------------------------------------------------------------;
			* Put character A0x at right most character to pad text;
			*----------------------------------------------------------------------;
			substr(_cvalue, 5, 1)='A0'x;
		end;

	if first._byvar2 then
		_rowsrt=0;

	if first.DENOMFL then
		do;
			_rowsrt=_rowsrt + 1;
			_rowmax=max(_rowsrt, _rowmax);
		end;
	_datatyp='data';
	_indent=0;
	_dptindt=0;
	_vorder=1;
	_rowjump=1;

	if upcase(_rwlabel)='_NONE_' then
		_rwlabel=' ';
	_indent=8;
	_dptindt=0;

	if _trt=2 +1 then
		_trt=9999;

	if eof then
		call symput('_rowsrt', compress(put(_rowmax, 4.)));
	_direct="TOP ";
	_p=0;
run;

********************************************************************************;
* Specification 5.1.2: Count n and percentage (%) for individual severity      *;
********************************************************************************;

data _anal2;
	length AVAL 8;
	set _data1;
	where same and AVAL is not missing;
	_blcksrt=1;
	_cnt=1;
	_cat=1;

	if _trt <=0 then
		delete;
	output;
run;

proc sort data=_anal2;
	by _datasrt _byvar1 _byvar2 _blcksrt AVAL _trt _cat;
run;

proc sort data=_anal2 out=_catby2(keep=_byvar1 _byvar2) nodupkey;
	by _byvar1 _byvar2;
	where paramcd eq upcase("Msere") and ex_none_flg=0 and knowvfl eq 'Y';
run;

data _temp2;
	set _anal2;
	output;
run;

proc sort data=_temp2 out=_temp92 nodupkey;
	by _datasrt _byvar1 _byvar2 _blcksrt _cat AVAL _trt usubjid;
	where paramcd eq upcase("Msere") and ex_none_flg=0 and knowvfl eq 'Y';
run;

proc freq data=_temp92 noprint;
	format AVAL;
	tables _datasrt*_byvar1*_byvar2*_blcksrt*_cat * AVAL * _trt / sparse norow nocol 
		nopercent out=_pct2(drop=percent);
run;

proc sort data=_temp2 out=_analcnt2 nodupkey;
	by _datasrt _byvar1 _byvar2 _cat _trt USUBJID;
	where paramcd eq upcase("Msere") and knowvfl eq 'Y';
run;

proc freq data=_analcnt2 noprint;
	tables _datasrt*_byvar1*_byvar2*_cat * _trt / sparse noprint out=_denom2(drop=percent);
run;

data _denomf2;
	_datasrt=1;
	set _catby2(keep=_byvar1 _byvar2);
	* All treatment groups ;
	_trt1=0;
	_trt2=0;
	* _CAT is the subgroup variable ;
	_cat=1;
	output;
run;

proc transpose data=_denom2 out=_denomin2(drop=_name_ _label_) prefix=_trt;
	by _datasrt _byvar1 _byvar2 _cat;
	var count;
	id _trt;
run;


data _frame2;
	_datasrt=1;
	set _catby2(keep=_byvar1 _byvar2);
	_blcksrt=1;
	length AVAL 8;
	_catLabl=" ";
	_trt=1;
	AVAL=0;
	_catord=1;
	_cat=1;
	output;
	_trt=2;
	AVAL=0;
	_catord=1;
	_cat=1;
	output;
	_catLabl=" ";
	_trt=1;
	AVAL=1;
	_catord=2;
	_cat=1;
	output;
	_trt=2;
	AVAL=1;
	_catord=2;
	_cat=1;
	output;
	_catLabl=" ";
	_trt=1;
	AVAL=2;
	_catord=3;
	_cat=1;
	output;
	_trt=2;
	AVAL=2;
	_catord=3;
	_cat=1;
	output;
	_catLabl=" ";
	_trt=1;
	AVAL=3;
	_catord=4;
	_cat=1;
	output;
	_trt=2;
	AVAL=3;
	_catord=4;
	_cat=1;
	output;
	_catLabl=" ";
	_trt=1;
	AVAL=4;
	_catord=5;
	_cat=1;
	output;
	_trt=2;
	AVAL=4;
	_catord=5;
	_cat=1;
	output;
run;

proc sort data=_frame2;
	by _datasrt _byvar1 _byvar2 _blcksrt _cat AVAL _trt;
run;

proc sort data=_pct2;
	by _datasrt _byvar1 _byvar2 _blcksrt _cat AVAL _trt;
run;

data _pct2;
	merge _frame2(in=_inframe) _pct2;
	by _datasrt _byvar1 _byvar2 _blcksrt _cat AVAL _trt;

	if _inframe;

	if count=. then
		count=0;
run;

proc sort data=_pct2;
	by _datasrt _byvar1 _byvar2 _blcksrt AVAL;
run;

data _miss2(keep=_datasrt _byvar1 _byvar2 _blcksrt AVAL totcount);
	set _pct2;
	where AVAL=9998;
	retain totcount;
	by _datasrt _byvar1 _byvar2 _blcksrt AVAL;

	if first.AVAL then
		totcount=0;
	totcount=totcount+count;

	if last.AVAL;
run;

data _pct2(drop=totcount);
	merge _pct2 _miss2;
	by _datasrt _byvar1 _byvar2 _blcksrt AVAL;

	if totcount=0 then
		delete;
run;


proc sort data=_denomf2;
	by _datasrt _byvar1 _byvar2 _cat;
run;

proc sort data=_denomin2;
	by _datasrt _byvar1 _byvar2 _cat;
run;

data _denomin2;
	merge _denomf2(in=_inframe) _denomin2;
	by _datasrt _byvar1 _byvar2 _cat;

	if _inframe;
	_blcksrt=1;
run;

proc sort data=_pct2;
	by _datasrt _byvar1 _byvar2 _cat;
run;

data _pct2;
	if 0 then
		set _basetemplate;
	merge _denomin2(in=_a) _pct2;
	by _datasrt _byvar1 _byvar2 _cat;

	if _a;
	_varname="AVAL ";
	_vrlabel=" ";
	_rwlabel=put(AVAL, sev.);

	if AVAL=9998 then
		do;
			_rwlabel="Missing ";
			_catord=9998;
		end;
	else if AVAL=9999 then
		do;
			_rwlabel="Total ";
			_catord=9999;
		end;

	if _catord=. then
		_catord=9997;
run;

proc sort data=_pct2;
	by _datasrt _byvar1 _byvar2 _blcksrt _catord AVAL _trt _cat;
run;

data _base2;
	length _catlabl $200;
	set _pct2 end=eof;
	by _datasrt _byvar1 _byvar2 _blcksrt _catord AVAL _trt _cat;
	retain _rowsrt 5 _rowmax 0;
	array _trtcnt(*) _trt1-_trt3;
	drop _rowmax _cpct;
	length _cpct $100;
	_cpct=' ';
	_module='mcatstat';

	if count > . then
		_cvalue=put(count, 5.);
	else
		_cvalue=put(0, 5.);

	if _trt ne . then
		do;

			if _trtcnt(_trt) > 0 then
				do;
					percent=count / _trtcnt(_trt) * 100;

					if percent > 0 then
						do;

							if round(percent, 0.1) GE 0.1 then
								_cpct="(*ESC*){nbspace 1}("||strip(put(percent, 5.1))||")";
							else
								_cpct="(*ESC*){nbspace 1}(0.0)";
							_cvalue=trim(_cvalue)||_cpct;
						end;
				end;
		end;

	if length(_cvalue) < 13 then
		do;
			*----------------------------------------------------------------------;
			* Put character A0x at right most character to pad text;
			*----------------------------------------------------------------------;
			substr(_cvalue, 13, 1)='A0'x;
		end;

	if first._byvar2 then
		_rowsrt=5;

	if first.AVAL then
		do;
			_rowsrt=_rowsrt + 1;
			_rowmax=max(_rowsrt, _rowmax);
		end;
	_datatyp='data';
	_indent=0;
	_dptindt=0;
	_vorder=1;
	_rowjump=1;

	if upcase(_rwlabel)='_NONE_' then
		_rwlabel=' ';
	_indent=8;
	_dptindt=0;

	if _trt=2 +1 then
		_trt=9999;

	if eof then
		call symput('_rowsrt', compress(put(_rowmax, 4.)));
	_direct="TOP ";
	_p=2;
run;

data _base2;
	set _base2;
	length _cvalue2 $30.;
	_cvalue2=strip(tranwrd(_cvalue, 'A0'x, ""));
	_cvalue21=strip(scan(_cvalue, 1, '('));
	_cvalue22=compress(scan(_cvalue, 2, '('), ')');
run;

data _base1;
	set _base1;
	drop _trt1 _trt2 count;
run;

proc sort data=_base1;
	by _datasrt _byvar1 _byvar2 _cat _trt;
run;

data _base1;
	set _base1;

	if _trt=1 then
		do;
			_trt1=input(_cvalue, ??best.);
		end;

	if _trt=2 then
		do;
			_trt2=input(_cvalue, ??best.);
		end;
run;

proc sort data=_base2(keep=_datasrt _trt _cvalue2 _cvalue21 _cvalue22 _cat 
		_byvar1 _byvar2 count);
	by _datasrt _byvar1 _byvar2 _cat _trt;
run;

data _base2;
	merge _base1(in=a) _base2(in=b);
	by _datasrt _byvar1 _byvar2 _cat _trt;

	if a;

	if a and not b then
		do;
			_cvalue2="0";
			_cvalue21="0";
		end;

	if compress(_cvalue2)="0" then
		_cvalue22=put(0, 5.1);

	if compress(_cvalue)="0" then
		do;
			_cvalue2="NA";
			_cvalue21="NA";
			_cvalue22="NA";
		end;

	if upcase(_rwlabel)="GRADE 4" then
		_rwlabel="Grade 4";
run;

data _base1;
	set _base1;
	delete;
run;

********************************************************************************;
* Specification 5.1.3: Calculate 95% CI for observed proportion                *;
********************************************************************************;

data _cnp _tmp_cnp;
	set _base2;

	if count=. then
		count=0;
	indc=1;
	output _cnp;
	indc=2;

	if _trt=1 then
		do;
			count=_trt1 - count;
		end;

	if _trt=2 then
		do;
			count=_trt2 - count;
		end;
	output _cnp;

	if indc=2 and count=0 then
		output _tmp_cnp;
run;

proc sort data=_cnp;
	by _byvar1 _byvar2 _cat _rowsrt _rwlabel _trt;
run;

proc sort nodupkey data=_tmp_cnp(keep=_byvar1 _byvar2 _cat _rowsrt _rwlabel _trt);
	by _byvar1 _byvar2 _cat _rowsrt _rwlabel _trt;
run;

********************************************************************************;
*  Call proc freq procedure to calculate CI for observed proportion             *;
********************************************************************************;

proc freq data=_cnp noprint;
	by _byvar1 _byvar2 _cat _rowsrt _rwlabel _trt;
	table indc/binomial alpha=0.05;
	output out=obsprop binomial;
	weight count;
run;

data obsprop;
	merge obsprop _tmp_cnp(in=a);
	by _byvar1 _byvar2 _cat _rowsrt _rwlabel _trt;

	if _bin_=1 and not a then
		do;
			xl_bin_=1 - xu_bin;
			xu_bin_=1 - xl_bin;
		end;
	else
		do;
			xl_bin_=xl_bin;
			xu_bin_=xu_bin;
		end;
run;

data cnpobsprop1(keep=_byvar1 _byvar2 _cat _rowsrt _rwlabel _trt cnp_ci);
	set obsprop;
	by _byvar1 _byvar2 _cat _rowsrt _rwlabel _trt;
	cnp_ci='(' || compress(put(xl_bin_ * 100, 5.1)) 
		|| ',(*ESC*){nbspace 1}' || compress(put(xu_bin_ * 100, 5.1)) || ')';
	label cnp_ci='95% CI';
run;

proc datasets lib=work nolist gennum=all;
	delete _cnp obsprop;
	run;

proc sort data=_base2;
	by _byvar1 _byvar2 _cat _rowsrt _rwlabel _trt;
run;

proc sort data=cnpobsprop1;
	by _byvar1 _byvar2 _cat _rowsrt _rwlabel _trt;
run;

data _base2;
	merge _base2(in=a) cnpobsprop1;
	by _byvar1 _byvar2 _cat _rowsrt _rwlabel _trt;

	if a;

	if compress(_cvalue)="0" then
		do;
			cnp_ci="NE";
		end;
run;

********************************************************************************;
* Specification 5.2: Statistics for Swelling category                          *;
********************************************************************************;
* Specification 5.2.1: Count denominator (N)                                   *;
********************************************************************************;

data _anal3;
	length DENOMFL 8;
	set _data1;
	where same and DENOMFL is not missing;
	_blcksrt=2;
	_cnt=1;
	_cat=1;

	if _trt <=0 then
		delete;
	output;
run;

proc sort data=_anal3;
	by _datasrt _byvar1 _byvar2 _blcksrt DENOMFL _trt _cat;
run;

proc sort data=_anal3 out=_catby3(keep=_byvar1 _byvar2) nodupkey;
	by _byvar1 _byvar2;
	where paramcd eq upcase("Msesw");
run;


data _temp3;
	set _anal3;
	output;
run;

proc sort data=_temp3 out=_temp93 nodupkey;
	by _datasrt _byvar1 _byvar2 _blcksrt _cat DENOMFL _trt usubjid;
	where paramcd eq upcase("Msesw");
run;

proc freq data=_temp93 noprint;
	format DENOMFL;
	tables _datasrt*_byvar1*_byvar2*_blcksrt*_cat * DENOMFL * _trt / sparse norow nocol 
		nopercent out=_pct3(drop=percent);
run;

proc freq data=_pct3 noprint;
	where DENOMFL ne 9999;
	weight count;
	tables _datasrt*_byvar1*_byvar2*_cat * _trt / sparse noprint out=_denom3(drop=percent);
run;

data _denomf3;
	_datasrt=1;
	set _catby3(keep=_byvar1 _byvar2);
	* All treatment groups ;
	_trt1=0;
	_trt2=0;
	* _CAT is the subgroup variable ;
	_cat=1;
	output;
run;

proc transpose data=_denom3 out=_denomin3(drop=_name_ _label_) prefix=_trt;
	by _datasrt _byvar1 _byvar2 _cat;
	var count;
	id _trt;
run;

data _frame3;
  set _frame1;
  _blcksrt=2;
run;
  
proc sort data=_frame3;
	by _datasrt _byvar1 _byvar2 _blcksrt _cat DENOMFL _trt;
run;

proc sort data=_pct3;
	by _datasrt _byvar1 _byvar2 _blcksrt _cat DENOMFL _trt;
run;

data _pct3;
	merge _frame3(in=_inframe) _pct3;
	by _datasrt _byvar1 _byvar2 _blcksrt _cat DENOMFL _trt;

	if _inframe;

	if count=. then
		count=0;
run;

proc sort data=_pct3;
	by _datasrt _byvar1 _byvar2 _blcksrt DENOMFL;
run;

data _miss3(keep=_datasrt _byvar1 _byvar2 _blcksrt DENOMFL totcount);
	set _pct3;
	where DENOMFL=9998;
	retain totcount;
	by _datasrt _byvar1 _byvar2 _blcksrt DENOMFL;

	if first.DENOMFL then
		totcount=0;
	totcount=totcount+count;

	if last.DENOMFL;
run;

data _pct3(drop=totcount);
	merge _pct3 _miss3;
	by _datasrt _byvar1 _byvar2 _blcksrt DENOMFL;

	if totcount=0 then
		delete;
run;

proc sort data=_denomf3;
	by _datasrt _byvar1 _byvar2 _cat;
run;

proc sort data=_denomin3;
	by _datasrt _byvar1 _byvar2 _cat;
run;

data _denomin3;
	merge _denomf3(in=_inframe) _denomin3;
	by _datasrt _byvar1 _byvar2 _cat;

	if _inframe;
	_blcksrt=2;
run;

proc sort data=_pct3;
	by _datasrt _byvar1 _byvar2 _cat;
run;

data _pct3;
	if 0 then
		set _basetemplate;
	merge _denomin3(in=_a) _pct3;
	by _datasrt _byvar1 _byvar2 _cat;

	if _a;
	_varname="DENOMFL ";
	_vrlabel="Swelling(*ESC*){super d} ";
	_rwlabel=put(DENOMFL, sev.);

	if DENOMFL=9998 then
		do;
			_rwlabel="Missing ";
			_catord=9998;
		end;
	else if DENOMFL=9999 then
		do;
			_rwlabel="Total ";
			_catord=9999;
		end;

	if _catord=. then
		_catord=9997;
run;

proc sort data=_pct3;
	by _datasrt _byvar1 _byvar2 _blcksrt _catord DENOMFL _trt _cat;
run;

data _base3;
	length _catlabl $200;
	set _pct3 end=eof;
	by _datasrt _byvar1 _byvar2 _blcksrt _catord DENOMFL _trt _cat;
	retain _rowsrt 0 _rowmax 0;
	array _trtcnt(*) _trt1-_trt3;
	drop _rowmax _cpct;
	length _cpct $100;
	_cpct=' ';
	_module='mcatstat';

	if count > . then
		_cvalue=put(count, 5.);
	else
		_cvalue=put(0, 5.);

	if length(_cvalue) < 5 then
		do;
			*----------------------------------------------------------------------;
			* Put character A0x at right most character to pad text;
			*----------------------------------------------------------------------;
			substr(_cvalue, 5, 1)='A0'x;
		end;

	if first._byvar2 then
		_rowsrt=0;

	if first.DENOMFL then
		do;
			_rowsrt=_rowsrt + 1;
			_rowmax=max(_rowsrt, _rowmax);
		end;
	_datatyp='data';
	_indent=0;
	_dptindt=0;
	_vorder=1;
	_rowjump=1;

	if upcase(_rwlabel)='_NONE_' then
		_rwlabel=' ';
	_indent=8;
	_dptindt=0;

	if _trt=2 +1 then
		_trt=9999;

	if eof then
		call symput('_rowsrt', compress(put(_rowmax, 4.)));
	_direct="TOP ";
	_p=0;
run;

********************************************************************************;
* Specification 5.2.2: Count n and percentage (%) for individual severity      *;
********************************************************************************;

data _anal4;
	length AVAL 8;
	set _data1;
	where same and AVAL is not missing;
	_blcksrt=2;
	_cnt=1;
	_cat=1;

	if _trt <=0 then
		delete;
	output;
run;

proc sort data=_anal4;
	by _datasrt _byvar1 _byvar2 _blcksrt AVAL _trt _cat;
run;

proc sort data=_anal4 out=_catby4(keep=_byvar1 _byvar2) nodupkey;
	by _byvar1 _byvar2;
	where paramcd eq upcase("Msesw") and ex_none_flg=0 and knowvfl eq 'Y';
run;

data _temp4;
	set _anal4;
	output;
run;

proc sort data=_temp4 out=_temp94 nodupkey;
	by _datasrt _byvar1 _byvar2 _blcksrt _cat AVAL _trt usubjid;
	where paramcd eq upcase("Msesw") and ex_none_flg=0 and knowvfl eq 'Y';
	;
run;

proc freq data=_temp94 noprint;
	format AVAL;
	tables _datasrt*_byvar1*_byvar2*_blcksrt*_cat * AVAL * _trt / sparse norow nocol 
		nopercent out=_pct4(drop=percent);
run;

proc sort data=_temp4 out=_analcnt4 nodupkey;
	by _datasrt _byvar1 _byvar2 _cat _trt USUBJID;
	where paramcd eq upcase("Msesw") and knowvfl eq 'Y';
run;

proc freq data=_analcnt4 noprint;
	tables _datasrt*_byvar1*_byvar2*_cat * _trt / sparse noprint out=_denom4(drop=percent);
run;

data _denomf4;
	_datasrt=1;
	set _catby4(keep=_byvar1 _byvar2);
	* All treatment groups ;
	_trt1=0;
	_trt2=0;
	* _CAT is the subgroup variable ;
	_cat=1;
	output;
run;

proc transpose data=_denom4 out=_denomin4(drop=_name_ _label_) prefix=_trt;
	by _datasrt _byvar1 _byvar2 _cat;
	var count;
	id _trt;
run;

data _frame4;
    set _frame2;
    _blcksrt=2;
run;

proc sort data=_frame4;
	by _datasrt _byvar1 _byvar2 _blcksrt _cat AVAL _trt;
run;

proc sort data=_pct4;
	by _datasrt _byvar1 _byvar2 _blcksrt _cat AVAL _trt;
run;

data _pct4;
	merge _frame4(in=_inframe) _pct4;
	by _datasrt _byvar1 _byvar2 _blcksrt _cat AVAL _trt;

	if _inframe;

	if count=. then count=0;
run;

proc sort data=_pct4;
	by _datasrt _byvar1 _byvar2 _blcksrt AVAL;
run;

data _miss4(keep=_datasrt _byvar1 _byvar2 _blcksrt AVAL totcount);
	set _pct4;
	where AVAL=9998;
	retain totcount;
	by _datasrt _byvar1 _byvar2 _blcksrt AVAL;

	if first.AVAL then
		totcount=0;
	totcount=totcount+count;

	if last.AVAL;
run;

data _pct4(drop=totcount);
	merge _pct4 _miss4;
	by _datasrt _byvar1 _byvar2 _blcksrt AVAL;

	if totcount=0 then
		delete;
run;

proc sort data=_denomf4;
	by _datasrt _byvar1 _byvar2 _cat;
run;

proc sort data=_denomin4;
	by _datasrt _byvar1 _byvar2 _cat;
run;

data _denomin4;
	merge _denomf4(in=_inframe) _denomin4;
	by _datasrt _byvar1 _byvar2 _cat;

	if _inframe;
	_blcksrt=2;
run;

proc sort data=_pct4;
	by _datasrt _byvar1 _byvar2 _cat;
run;

data _pct4;
	if 0 then
		set _basetemplate;
	merge _denomin4(in=_a) _pct4;
	by _datasrt _byvar1 _byvar2 _cat;

	if _a;
	_varname="AVAL ";
	_vrlabel=" ";
	_rwlabel=put(AVAL, sev.);

	if AVAL=9998 then
		do;
			_rwlabel="Missing ";
			_catord=9998;
		end;
	else if AVAL=9999 then
		do;
			_rwlabel="Total ";
			_catord=9999;
		end;

	if _catord=. then
		_catord=9997;
run;

proc sort data=_pct4;
	by _datasrt _byvar1 _byvar2 _blcksrt _catord AVAL _trt _cat;
run;

data _base4;
	length _catlabl $200;
	set _pct4 end=eof;
	by _datasrt _byvar1 _byvar2 _blcksrt _catord AVAL _trt _cat;
	retain _rowsrt 5 _rowmax 0;
	array _trtcnt(*) _trt1-_trt3;
	drop _rowmax _cpct;
	length _cpct $100;
	_cpct=' ';
	_module='mcatstat';

	if count > . then
		_cvalue=put(count, 5.);
	else
		_cvalue=put(0, 5.);

	if _trt ne . then
		do;

			if _trtcnt(_trt) > 0 then
				do;
					percent=count / _trtcnt(_trt) * 100;

					if percent > 0 then
						do;

							if round(percent, 0.1) GE 0.1 then
								_cpct="(*ESC*){nbspace 1}("||strip(put(percent, 5.1))||")";
							else
								_cpct="(*ESC*){nbspace 1}(0.0)";
							_cvalue=trim(_cvalue)||_cpct;
						end;
				end;
		end;

	if length(_cvalue) < 13 then
		do;
			*----------------------------------------------------------------------;
			* Put character A0x at right most character to pad text;
			*----------------------------------------------------------------------;
			substr(_cvalue, 13, 1)='A0'x;
		end;

	if first._byvar2 then
		_rowsrt=5;

	if first.AVAL then
		do;
			_rowsrt=_rowsrt + 1;
			_rowmax=max(_rowsrt, _rowmax);
		end;
	_datatyp='data';
	_indent=0;
	_dptindt=0;
	_vorder=1;
	_rowjump=1;

	if upcase(_rwlabel)='_NONE_' then
		_rwlabel=' ';
	_indent=8;
	_dptindt=0;

	if _trt=2 +1 then
		_trt=9999;

	if eof then
		call symput('_rowsrt', compress(put(_rowmax, 4.)));
	_direct="TOP ";
	_p=2;
run;

data _base4;
	set _base4;
	length _cvalue2 $30.;
	_cvalue2=strip(tranwrd(_cvalue, 'A0'x, ""));
	_cvalue21=strip(scan(_cvalue, 1, '('));
	_cvalue22=compress(scan(_cvalue, 2, '('), ')');
run;

data _base3;
	set _base3;
	drop _trt1 _trt2 count;
run;

proc sort data=_base3;
	by _datasrt _byvar1 _byvar2 _cat _trt;
run;

data _base3;
	set _base3;

	if _trt=1 then
		do;
			_trt1=input(_cvalue, ??best.);
		end;

	if _trt=2 then
		do;
			_trt2=input(_cvalue, ??best.);
		end;
run;

proc sort data=_base4(keep=_datasrt _trt _cvalue2 _cvalue21 _cvalue22 _cat 
		_byvar1 _byvar2 count);
	by _datasrt _byvar1 _byvar2 _cat _trt;
run;

data _base4;
	merge _base3(in=a) _base4(in=b);
	by _datasrt _byvar1 _byvar2 _cat _trt;

	if a;

	if a and not b then
		do;
			_cvalue2="0";
			_cvalue21="0";
		end;

	if compress(_cvalue2)="0" then
		_cvalue22=put(0, 5.1);

	if compress(_cvalue)="0" then
		do;
			_cvalue2="NA";
			_cvalue21="NA";
			_cvalue22="NA";
		end;

	if upcase(_rwlabel)="GRADE 4" then
		_rwlabel="Grade 4";
run;

data _base3;
	set _base3;
	delete;
run;

********************************************************************************;
* Specification 5.2.3: Calculate 95% CI for observed proportion                *;
********************************************************************************;

data _cnp _tmp_cnp;
	set _base4;

	if count=. then
		count=0;
	indc=1;
	output _cnp;
	indc=2;

	if _trt=1 then
		do;
			count=_trt1 - count;
		end;

	if _trt=2 then
		do;
			count=_trt2 - count;
		end;
	output _cnp;

	if indc=2 and count=0 then
		output _tmp_cnp;
run;

proc sort data=_cnp;
	by _byvar1 _byvar2 _cat _rowsrt _rwlabel _trt;
run;

proc sort nodupkey data=_tmp_cnp(keep=_byvar1 _byvar2 _cat _rowsrt _rwlabel _trt);
	by _byvar1 _byvar2 _cat _rowsrt _rwlabel _trt;
run;

********************************************************************************;
*  Call proc freq procedure to calculate CI for observed proportion            *;
********************************************************************************;
proc freq data=_cnp noprint;
	by _byvar1 _byvar2 _cat _rowsrt _rwlabel _trt;
	table indc/binomial alpha=0.05;
	output out=obsprop binomial;
	weight count;
run;

data obsprop;
	merge obsprop _tmp_cnp(in=a);
	by _byvar1 _byvar2 _cat _rowsrt _rwlabel _trt;

	if _bin_=1 and not a then
		do;
			xl_bin_=1 - xu_bin;
			xu_bin_=1 - xl_bin;
		end;
	else
		do;
			xl_bin_=xl_bin;
			xu_bin_=xu_bin;
		end;
run;


data cnpobsprop1(keep=_byvar1 _byvar2 _cat _rowsrt _rwlabel _trt cnp_ci);
	set obsprop;
	by _byvar1 _byvar2 _cat _rowsrt _rwlabel _trt;
	cnp_ci='(' || compress(put(xl_bin_ * 100, 5.1)) 
		|| ',(*ESC*){nbspace 1}' || compress(put(xu_bin_ * 100, 5.1)) || ')';
	label cnp_ci='95% CI';
run;

proc datasets lib=work nolist gennum=all;
	delete _cnp obsprop;
	run;

proc sort data=_base4;
	by _byvar1 _byvar2 _cat _rowsrt _rwlabel _trt;
run;

proc sort data=cnpobsprop1;
	by _byvar1 _byvar2 _cat _rowsrt _rwlabel _trt;
run;

data _base4;
	merge _base4(in=a) cnpobsprop1;
	by _byvar1 _byvar2 _cat _rowsrt _rwlabel _trt;

	if a;

	if compress(_cvalue)="0" then
		do;
			cnp_ci="NE";
		end;
run;

********************************************************************************;
* Specification 5.3: Statistics for Pain at injection site category            *;
********************************************************************************;
* Specification 5.3.1: Count denominator (N)                                   *;
********************************************************************************;

data _anal5;
	length DENOMFL 8;
	set _data1;
	where same and DENOMFL is not missing;
	_blcksrt=3;
	_cnt=1;
	_cat=1;

	if _trt <=0 then
		delete;
	output;
run;

proc sort data=_anal5;
	by _datasrt _byvar1 _byvar2 _blcksrt DENOMFL _trt _cat;
run;

proc sort data=_anal5 out=_catby5(keep=_byvar1 _byvar2) nodupkey;
	by _byvar1 _byvar2;
	where paramcd eq upcase("Mspis");
run;


data _temp5;
	set _anal5;
	output;
run;

proc sort data=_temp5 out=_temp95 nodupkey;
	by _datasrt _byvar1 _byvar2 _blcksrt _cat DENOMFL _trt usubjid;
	where paramcd eq upcase("Mspis");
run;

proc freq data=_temp95 noprint;
	format DENOMFL;
	tables _datasrt*_byvar1*_byvar2*_blcksrt*_cat * DENOMFL * _trt / sparse norow nocol 
		nopercent out=_pct5(drop=percent);
run;

proc freq data=_pct5 noprint;
	where DENOMFL ne 9999;
	weight count;
	tables _datasrt*_byvar1*_byvar2*_cat * _trt / sparse noprint out=_denom5(drop=percent);
run;

data _denomf5;
	_datasrt=1;
	set _catby5(keep=_byvar1 _byvar2);
	* All treatment groups ;
	_trt1=0;
	_trt2=0;
	* _CAT is the subgroup variable ;
	_cat=1;
	output;
run;

proc transpose data=_denom5 out=_denomin5(drop=_name_ _label_) prefix=_trt;
	by _datasrt _byvar1 _byvar2 _cat;
	var count;
	id _trt;
run;

data _frame5;
    set _frame1;
    _blcksrt=3;
run;

proc sort data=_frame5;
	by _datasrt _byvar1 _byvar2 _blcksrt _cat DENOMFL _trt;
run;

proc sort data=_pct5;
	by _datasrt _byvar1 _byvar2 _blcksrt _cat DENOMFL _trt;
run;

data _pct5;
	merge _frame5(in=_inframe) _pct5;
	by _datasrt _byvar1 _byvar2 _blcksrt _cat DENOMFL _trt;

	if _inframe;

	if count=. then
		count=0;
run;

proc sort data=_pct5;
	by _datasrt _byvar1 _byvar2 _blcksrt DENOMFL;
run;

data _miss5(keep=_datasrt _byvar1 _byvar2 _blcksrt DENOMFL totcount);
	set _pct5;
	where DENOMFL=9998;
	retain totcount;
	by _datasrt _byvar1 _byvar2 _blcksrt DENOMFL;

	if first.DENOMFL then
		totcount=0;
	totcount=totcount+count;

	if last.DENOMFL;
run;

data _pct5(drop=totcount);
	merge _pct5 _miss5;
	by _datasrt _byvar1 _byvar2 _blcksrt DENOMFL;

	if totcount=0 then
		delete;
run;

proc sort data=_denomf5;
	by _datasrt _byvar1 _byvar2 _cat;
run;

proc sort data=_denomin5;
	by _datasrt _byvar1 _byvar2 _cat;
run;

data _denomin5;
	merge _denomf5(in=_inframe) _denomin5;
	by _datasrt _byvar1 _byvar2 _cat;

	if _inframe;
	_blcksrt=3;
run;

proc sort data=_pct5;
	by _datasrt _byvar1 _byvar2 _cat;
run;

data _pct5;
	if 0 then
		set _basetemplate;
	merge _denomin5(in=_a) _pct5;
	by _datasrt _byvar1 _byvar2 _cat;

	if _a;
	_varname="DENOMFL ";
	_vrlabel="Pain at the injection site(*ESC*){super e} ";
	_rwlabel=put(DENOMFL, sev.);

	if DENOMFL=9998 then
		do;
			_rwlabel="Missing ";
			_catord=9998;
		end;
	else if DENOMFL=9999 then
		do;
			_rwlabel="Total ";
			_catord=9999;
		end;

	if _catord=. then
		_catord=9997;
run;

proc sort data=_pct5;
	by _datasrt _byvar1 _byvar2 _blcksrt _catord DENOMFL _trt _cat;
run;

data _base5;
	length _catlabl $200;
	set _pct5 end=eof;
	by _datasrt _byvar1 _byvar2 _blcksrt _catord DENOMFL _trt _cat;
	retain _rowsrt 0 _rowmax 0;
	array _trtcnt(*) _trt1-_trt3;
	drop _rowmax _cpct;
	length _cpct $100;
	_cpct=' ';
	_module='mcatstat';

	if count > . then
		_cvalue=put(count, 5.);
	else
		_cvalue=put(0, 5.);

	if length(_cvalue) < 5 then
		do;
			*----------------------------------------------------------------------;
			* Put character A0x at right most character to pad text;
			*----------------------------------------------------------------------;
			substr(_cvalue, 5, 1)='A0'x;
		end;

	if first._byvar2 then
		_rowsrt=0;

	if first.DENOMFL then
		do;
			_rowsrt=_rowsrt + 1;
			_rowmax=max(_rowsrt, _rowmax);
		end;
	_datatyp='data';
	_indent=0;
	_dptindt=0;
	_vorder=1;
	_rowjump=1;

	if upcase(_rwlabel)='_NONE_' then
		_rwlabel=' ';
	_indent=8;
	_dptindt=0;

	if _trt=2 +1 then
		_trt=9999;

	if eof then
		call symput('_rowsrt', compress(put(_rowmax, 4.)));
	_direct="TOP ";
	_p=0;
run;

********************************************************************************;
* Specification 5.3.2: Count n and percentage (%) for individual severity      *;
********************************************************************************;

data _anal6;
	length AVAL 8;
	set _data1;
	where same and AVAL is not missing;
	_blcksrt=3;
	_cnt=1;
	_cat=1;

	if _trt <=0 then
		delete;
	output;
run;

proc sort data=_anal6;
	by _datasrt _byvar1 _byvar2 _blcksrt AVAL _trt _cat;
run;

proc sort data=_anal6 out=_catby6(keep=_byvar1 _byvar2) nodupkey;
	by _byvar1 _byvar2;
	where paramcd eq upcase("Mspis") and ex_none_flg=0 and knowvfl eq 'Y';
run;

data _temp6;
	set _anal6;
	output;
run;

proc sort data=_temp6 out=_temp96 nodupkey;
	by _datasrt _byvar1 _byvar2 _blcksrt _cat AVAL _trt usubjid;
	where paramcd eq upcase("Mspis") and ex_none_flg=0 and knowvfl eq 'Y';
	;
run;

proc freq data=_temp96 noprint;
	format AVAL;
	tables _datasrt*_byvar1*_byvar2*_blcksrt*_cat * AVAL * _trt / sparse norow nocol 
		nopercent out=_pct6(drop=percent);
run;

proc sort data=_temp6 out=_analcnt6 nodupkey;
	by _datasrt _byvar1 _byvar2 _cat _trt USUBJID;
	where paramcd eq upcase("Mspis") and knowvfl eq 'Y';
run;

proc freq data=_analcnt6 noprint;
	tables _datasrt*_byvar1*_byvar2*_cat * _trt / sparse noprint out=_denom6(drop=percent);
run;

data _denomf6;
	_datasrt=1;
	set _catby6(keep=_byvar1 _byvar2);
	* All treatment groups ;
	_trt1=0;
	_trt2=0;
	* _CAT is the subgroup variable ;
	_cat=1;
	output;
run;

proc transpose data=_denom6 out=_denomin6(drop=_name_ _label_) prefix=_trt;
	by _datasrt _byvar1 _byvar2 _cat;
	var count;
	id _trt;
run;

data _frame6;
    set _frame2;
    _blcksrt=3;
run;

proc sort data=_frame6;
	by _datasrt _byvar1 _byvar2 _blcksrt _cat AVAL _trt;
run;

proc sort data=_pct6;
	by _datasrt _byvar1 _byvar2 _blcksrt _cat AVAL _trt;
run;

data _pct6;
	merge _frame6(in=_inframe) _pct6;
	by _datasrt _byvar1 _byvar2 _blcksrt _cat AVAL _trt;

	if _inframe;

	if count=. then
		count=0;
run;

proc sort data=_pct6;
	by _datasrt _byvar1 _byvar2 _blcksrt AVAL;
run;

data _miss6(keep=_datasrt _byvar1 _byvar2 _blcksrt AVAL totcount);
	set _pct6;
	where AVAL=9998;
	retain totcount;
	by _datasrt _byvar1 _byvar2 _blcksrt AVAL;

	if first.AVAL then
		totcount=0;
	totcount=totcount+count;

	if last.AVAL;
run;

data _pct6(drop=totcount);
	merge _pct6 _miss6;
	by _datasrt _byvar1 _byvar2 _blcksrt AVAL;

	if totcount=0 then
		delete;
run;

proc sort data=_denomf6;
	by _datasrt _byvar1 _byvar2 _cat;
run;

proc sort data=_denomin6;
	by _datasrt _byvar1 _byvar2 _cat;
run;

data _denomin6;
	merge _denomf6(in=_inframe) _denomin6;
	by _datasrt _byvar1 _byvar2 _cat;

	if _inframe;
	_blcksrt=3;
run;

proc sort data=_pct6;
	by _datasrt _byvar1 _byvar2 _cat;
run;

data _pct6;
	if 0 then
		set _basetemplate;
	merge _denomin6(in=_a) _pct6;
	by _datasrt _byvar1 _byvar2 _cat;

	if _a;
	_varname="AVAL ";
	_vrlabel=" ";
	_rwlabel=put(AVAL, sev.);

	if AVAL=9998 then
		do;
			_rwlabel="Missing ";
			_catord=9998;
		end;
	else if AVAL=9999 then
		do;
			_rwlabel="Total ";
			_catord=9999;
		end;

	if _catord=. then
		_catord=9997;
run;

proc sort data=_pct6;
	by _datasrt _byvar1 _byvar2 _blcksrt _catord AVAL _trt _cat;
run;

data _base6;
	length _catlabl $200;
	set _pct6 end=eof;
	by _datasrt _byvar1 _byvar2 _blcksrt _catord AVAL _trt _cat;
	retain _rowsrt 5 _rowmax 0;
	array _trtcnt(*) _trt1-_trt3;
	drop _rowmax _cpct;
	length _cpct $100;
	_cpct=' ';
	_module='mcatstat';

	if count > . then
		_cvalue=put(count, 5.);
	else
		_cvalue=put(0, 5.);
	*----------------------------------------------------------------------;
	* Format percent to append to display value in _CVALUE ;
	*----------------------------------------------------------------------;

	if _trt ne . then
		do;

			if _trtcnt(_trt) > 0 then
				do;
					percent=count / _trtcnt(_trt) * 100;

					if percent > 0 then
						do;

							if round(percent, 0.1) GE 0.1 then
								_cpct="(*ESC*){nbspace 1}("||strip(put(percent, 5.1))||")";
							else
								_cpct="(*ESC*){nbspace 1}(0.0)";
							_cvalue=trim(_cvalue)||_cpct;
						end;
				end;
		end;

	if length(_cvalue) < 13 then
		do;
			*----------------------------------------------------------------------;
			* Put character A0x at right most character to pad text;
			*----------------------------------------------------------------------;
			substr(_cvalue, 13, 1)='A0'x;
		end;

	if first._byvar2 then
		_rowsrt=5;

	if first.AVAL then
		do;
			_rowsrt=_rowsrt + 1;
			_rowmax=max(_rowsrt, _rowmax);
		end;
	_datatyp='data';
	_indent=0;
	_dptindt=0;
	_vorder=1;
	_rowjump=1;

	if upcase(_rwlabel)='_NONE_' then
		_rwlabel=' ';
	_indent=8;
	_dptindt=0;

	if _trt=2 +1 then
		_trt=9999;

	if eof then
		call symput('_rowsrt', compress(put(_rowmax, 4.)));
	_direct="TOP ";
	_p=2;
run;

data _base6;
	set _base6;
	length _cvalue2 $30.;
	_cvalue2=strip(tranwrd(_cvalue, 'A0'x, ""));
	_cvalue21=strip(scan(_cvalue, 1, '('));
	_cvalue22=compress(scan(_cvalue, 2, '('), ')');
run;

data _base5;
	set _base5;
	drop _trt1 _trt2 count;
run;

proc sort data=_base5;
	by _datasrt _byvar1 _byvar2 _cat _trt;
run;

data _base5;
	set _base5;

	if _trt=1 then
		do;
			_trt1=input(_cvalue, ??best.);
		end;

	if _trt=2 then
		do;
			_trt2=input(_cvalue, ??best.);
		end;
run;

proc sort data=_base6(keep=_datasrt _trt _cvalue2 _cvalue21 _cvalue22 _cat 
		_byvar1 _byvar2 count);
	by _datasrt _byvar1 _byvar2 _cat _trt;
run;

data _base6;
	merge _base5(in=a) _base6(in=b);
	by _datasrt _byvar1 _byvar2 _cat _trt;

	if a;

	if a and not b then
		do;
			_cvalue2="0";
			_cvalue21="0";
		end;

	if compress(_cvalue2)="0" then
		_cvalue22=put(0, 5.1);

	if compress(_cvalue)="0" then
		do;
			_cvalue2="NA";
			_cvalue21="NA";
			_cvalue22="NA";
		end;
run;

data _base5;
	set _base5;
	delete;
run;

********************************************************************************;
* Specification 5.3.3: Calculate 95% CI for observed proportion                *;
********************************************************************************;

data _cnp _tmp_cnp;
	set _base6;

	if count=. then
		count=0;
	indc=1;
	output _cnp;
	indc=2;

	if _trt=1 then
		do;
			count=_trt1 - count;
		end;

	if _trt=2 then
		do;
			count=_trt2 - count;
		end;
	output _cnp;

	if indc=2 and count=0 then
		output _tmp_cnp;
run;

proc sort data=_cnp;
	by _byvar1 _byvar2 _cat _rowsrt _rwlabel _trt;
run;

proc sort nodupkey data=_tmp_cnp(keep=_byvar1 _byvar2 _cat _rowsrt _rwlabel _trt);
	by _byvar1 _byvar2 _cat _rowsrt _rwlabel _trt;
run;

********************************************************************************;
*  Call proc freq procedure to calculate CI for observed proportion            *;
********************************************************************************;
proc freq data=_cnp noprint;
	by _byvar1 _byvar2 _cat _rowsrt _rwlabel _trt;
	table indc/binomial alpha=0.05;
	output out=obsprop binomial;
	weight count;
run;

data obsprop;
	merge obsprop _tmp_cnp(in=a);
	by _byvar1 _byvar2 _cat _rowsrt _rwlabel _trt;

	if _bin_=1 and not a then
		do;
			xl_bin_=1 - xu_bin;
			xu_bin_=1 - xl_bin;
		end;
	else
		do;
			xl_bin_=xl_bin;
			xu_bin_=xu_bin;
		end;
run;

data cnpobsprop1(keep=_byvar1 _byvar2 _cat _rowsrt _rwlabel _trt cnp_ci);
	set obsprop;
	by _byvar1 _byvar2 _cat _rowsrt _rwlabel _trt;
	cnp_ci='(' || compress(put(xl_bin_ * 100, 5.1)) 
		|| ',(*ESC*){nbspace 1}' || compress(put(xu_bin_ * 100, 5.1)) || ')';
	label cnp_ci='95% CI';
run;

proc datasets lib=work nolist gennum=all;
	delete _cnp obsprop;
	run;

proc sort data=_base6;
	by _byvar1 _byvar2 _cat _rowsrt _rwlabel _trt;
run;

proc sort data=cnpobsprop1;
	by _byvar1 _byvar2 _cat _rowsrt _rwlabel _trt;
run;

data _base6;
	merge _base6(in=a) cnpobsprop1;
	by _byvar1 _byvar2 _cat _rowsrt _rwlabel _trt;

	if a;

	if compress(_cvalue)="0" then
		do;
			cnp_ci="NE";
		end;
run;

********************************************************************************;
* Specification 5.4: Statistics for Any local reaction category                *;
********************************************************************************;
* Specification 5.4.1: Count denominator (N)                                   *;
********************************************************************************;

data _anal7;
	length _KNOWVFL 8;
	set _data1;
	where same and _KNOWVFL is not missing;
	_blcksrt=4;
	_cnt=1;
	_cat=1;

	if _trt <=0 then
		delete;
	output;
run;

proc sort data=_anal7;
	by _datasrt _byvar1 _byvar2 _blcksrt _KNOWVFL _trt _cat;
run;

proc sort data=_anal7 out=_catby7(keep=_byvar1 _byvar2) nodupkey;
	by _byvar1 _byvar2;
	where paramcd eq upcase("Any");
	;
run;

data _temp7;
	set _anal7;
	output;
run;

proc sort data=_temp7 out=_temp97 nodupkey;
	by _datasrt _byvar1 _byvar2 _blcksrt _cat _KNOWVFL _trt usubjid;
	where paramcd eq upcase("Any");
	;
run;

proc freq data=_temp97 noprint;
	format _KNOWVFL;
	tables _datasrt*_byvar1*_byvar2*_blcksrt*_cat * _KNOWVFL * _trt / sparse norow nocol 
		nopercent out=_pct7(drop=percent);
run;

proc freq data=_pct7 noprint;
	where _KNOWVFL ne 9999;
	weight count;
	tables _datasrt*_byvar1*_byvar2*_cat * _trt / sparse noprint out=_denom7(drop=percent);
run;

data _denomf7;
	_datasrt=1;
	set _catby7(keep=_byvar1 _byvar2);
	* All treatment groups ;
	_trt1=0;
	_trt2=0;
	* _CAT is the subgroup variable ;
	_cat=1;
	output;
run;

proc transpose data=_denom7 out=_denomin7(drop=_name_ _label_) prefix=_trt;
	by _datasrt _byvar1 _byvar2 _cat;
	var count;
	id _trt;
run;


data _frame7;
	_datasrt=1;
	set _catby7(keep=_byvar1 _byvar2);
	_blcksrt=4;
	length _KNOWVFL 8;
	_catLabl=" ";
	_trt=1;
	_KNOWVFL=1;
	_catord=1;
	_cat=1;
	output;
	_trt=2;
	_KNOWVFL=1;
	_catord=1;
	_cat=1;
	output;
run;


proc sort data=_frame7;
	by _datasrt _byvar1 _byvar2 _blcksrt _cat _KNOWVFL _trt;
run;

proc sort data=_pct7;
	by _datasrt _byvar1 _byvar2 _blcksrt _cat _KNOWVFL _trt;
run;

data _pct7;
	merge _frame7(in=_inframe) _pct7;
	by _datasrt _byvar1 _byvar2 _blcksrt _cat _KNOWVFL _trt;

	if _inframe;

	if count=. then
		count=0;
run;

proc sort data=_pct7;
	by _datasrt _byvar1 _byvar2 _blcksrt _KNOWVFL;
run;

data _miss7(keep=_datasrt _byvar1 _byvar2 _blcksrt _KNOWVFL totcount);
	set _pct7;
	where _KNOWVFL=9998;
	retain totcount;
	by _datasrt _byvar1 _byvar2 _blcksrt _KNOWVFL;

	if first._KNOWVFL then
		totcount=0;
	totcount=totcount+count;

	if last._KNOWVFL;
run;

data _pct7(drop=totcount);
	merge _pct7 _miss7;
	by _datasrt _byvar1 _byvar2 _blcksrt _KNOWVFL;

	if totcount=0 then
		delete;
run;

proc sort data=_denomf7;
	by _datasrt _byvar1 _byvar2 _cat;
run;

proc sort data=_denomin7;
	by _datasrt _byvar1 _byvar2 _cat;
run;

data _denomin7;
	merge _denomf7(in=_inframe) _denomin7;
	by _datasrt _byvar1 _byvar2 _cat;

	if _inframe;
	_blcksrt=4;
run;

proc sort data=_pct7;
	by _datasrt _byvar1 _byvar2 _cat;
run;

data _pct7;
	if 0 then
		set _basetemplate;
	merge _denomin7(in=_a) _pct7;
	by _datasrt _byvar1 _byvar2 _cat;

	if _a;
	_varname="_KNOWVFL ";
	_vrlabel=" ";
	_rwlabel="Any local reaction(*ESC*){super f} ";

	if _KNOWVFL=9998 then
		do;
			_rwlabel="Missing ";
			_catord=9998;
		end;
	else if _KNOWVFL=9999 then
		do;
			_rwlabel="Total ";
			_catord=9999;
		end;

	if _catord=. then
		_catord=9997;
run;

proc sort data=_pct7;
	by _datasrt _byvar1 _byvar2 _blcksrt _catord _KNOWVFL _trt _cat;
run;

data _base7;
	length _catlabl $200;
	set _pct7 end=eof;
	by _datasrt _byvar1 _byvar2 _blcksrt _catord _KNOWVFL _trt _cat;
	retain _rowsrt 0 _rowmax 0;
	array _trtcnt(*) _trt1-_trt3;
	drop _rowmax _cpct;
	length _cpct $100;
	_cpct=' ';
	_module='mcatstat';

	if count > . then
		_cvalue=put(count, 5.);
	else
		_cvalue=put(0, 5.);

	if length(_cvalue) < 5 then
		do;
			*----------------------------------------------------------------------;
			* Put character A0x at right most character to pad text;
			*----------------------------------------------------------------------;
			substr(_cvalue, 5, 1)='A0'x;
		end;

	if first._byvar2 then
		_rowsrt=0;

	if first._KNOWVFL then
		do;
			_rowsrt=_rowsrt + 1;
			_rowmax=max(_rowsrt, _rowmax);
		end;
	_datatyp='data';
	_indent=0;
	_dptindt=0;
	_vorder=1;
	_rowjump=1;

	if upcase(_rwlabel)='_NONE_' then
		_rwlabel=' ';
	_indent=0;
	_dptindt=0;

	if _trt=2 +1 then
		_trt=9999;

	if eof then
		call symput('_rowsrt', compress(put(_rowmax, 4.)));
	_direct="TOP ";
	_p=0;
run;

********************************************************************************;
* Specification 5.4.2: Count n and percentage (%) for individual severity      *;
********************************************************************************;

data _anal8;
	length AVAL 8;
	set _data1;
	where same and AVAL is not missing;
	_blcksrt=4;
	_cnt=1;
	_cat=1;

	if _trt <=0 then
		delete;
	output;
run;

proc sort data=_anal8;
	by _datasrt _byvar1 _byvar2 _blcksrt AVAL _trt _cat;
run;

proc sort data=_anal8 out=_catby8(keep=_byvar1 _byvar2) nodupkey;
	by _byvar1 _byvar2;
	where paramcd eq upcase("Any") and ex_none_flg=0 and knowvfl eq 'Y';
run;

data _temp8;
	set _anal8;
	output;
run;

proc sort data=_temp8 out=_temp98 nodupkey;
	by _datasrt _byvar1 _byvar2 _blcksrt _cat AVAL _trt usubjid;
	where paramcd eq upcase("Any") and ex_none_flg=0 and knowvfl eq 'Y';
run;

proc freq data=_temp98 noprint;
	format AVAL;
	tables _datasrt*_byvar1*_byvar2*_blcksrt*_cat * AVAL * _trt / sparse norow nocol 
		nopercent out=_pct8(drop=percent);
run;

proc sort data=_temp8 out=_analcnt8 nodupkey;
	by _datasrt _byvar1 _byvar2 _cat _trt USUBJID;
	where paramcd eq upcase("Any") and knowvfl eq 'Y';
run;

proc freq data=_analcnt8 noprint;
	tables _datasrt*_byvar1*_byvar2*_cat * _trt / sparse noprint out=_denom8(drop=percent);
run;

data _denomf8;
	_datasrt=1;
	set _catby8(keep=_byvar1 _byvar2);
	* All treatment groups ;
	_trt1=0;
	_trt2=0;
	* _CAT is the subgroup variable ;
	_cat=1;
	output;
run;


proc transpose data=_denom8 out=_denomin8(drop=_name_ _label_) prefix=_trt;
	by _datasrt _byvar1 _byvar2 _cat;
	var count;
	id _trt;
run;

data _frame8;
	_datasrt=1;
	set _catby8(keep=_byvar1 _byvar2);
	_blcksrt=4;
	length AVAL 8;
	_catLabl=" ";
	_trt=1;
	AVAL=1;
	_catord=1;
	_cat=1;
	output;
	_trt=2;
	AVAL=1;
	_catord=1;
	_cat=1;
	output;
run;

proc sort data=_frame8;
	by _datasrt _byvar1 _byvar2 _blcksrt _cat AVAL _trt;
run;

proc sort data=_pct8;
	by _datasrt _byvar1 _byvar2 _blcksrt _cat AVAL _trt;
run;

data _pct8;
	merge _frame8(in=_inframe) _pct8;
	by _datasrt _byvar1 _byvar2 _blcksrt _cat AVAL _trt;

	if _inframe;

	if count=. then
		count=0;
run;

proc sort data=_pct8;
	by _datasrt _byvar1 _byvar2 _blcksrt AVAL;
run;

data _miss8(keep=_datasrt _byvar1 _byvar2 _blcksrt AVAL totcount);
	set _pct8;
	where AVAL=9998;
	retain totcount;
	by _datasrt _byvar1 _byvar2 _blcksrt AVAL;

	if first.AVAL then
		totcount=0;
	totcount=totcount+count;

	if last.AVAL;
run;

data _pct8(drop=totcount);
	merge _pct8 _miss8;
	by _datasrt _byvar1 _byvar2 _blcksrt AVAL;

	if totcount=0 then
		delete;
run;

proc sort data=_denomf8;
	by _datasrt _byvar1 _byvar2 _cat;
run;

proc sort data=_denomin8;
	by _datasrt _byvar1 _byvar2 _cat;
run;

data _denomin8;
	merge _denomf8(in=_inframe) _denomin8;
	by _datasrt _byvar1 _byvar2 _cat;

	if _inframe;
	_blcksrt=4;
run;

proc sort data=_pct8;
	by _datasrt _byvar1 _byvar2 _cat;
run;

data _pct8;
	if 0 then
		set _basetemplate;
	merge _denomin8(in=_a) _pct8;
	by _datasrt _byvar1 _byvar2 _cat;

	if _a;
	_varname="AVAL ";
	_vrlabel=" ";
	_rwlabel="Any local reaction(*ESC*){super f} ";

	if AVAL=9998 then
		do;
			_rwlabel="Missing ";
			_catord=9998;
		end;
	else if AVAL=9999 then
		do;
			_rwlabel="Total ";
			_catord=9999;
		end;

	if _catord=. then
		_catord=9997;
run;

proc sort data=_pct8;
	by _datasrt _byvar1 _byvar2 _blcksrt _catord AVAL _trt _cat;
run;

data _base8;
	length _catlabl $200;
	set _pct8 end=eof;
	by _datasrt _byvar1 _byvar2 _blcksrt _catord AVAL _trt _cat;
	retain _rowsrt 1 _rowmax 0;
	array _trtcnt(*) _trt1-_trt3;
	drop _rowmax _cpct;
	length _cpct $100;
	_cpct=' ';
	_module='mcatstat';

	if count > . then
		_cvalue=put(count, 5.);
	else
		_cvalue=put(0, 5.);
	*----------------------------------------------------------------------;
	* Format percent to append to display value in _CVALUE ;
	*----------------------------------------------------------------------;

	if _trt ne . then
		do;

			if _trtcnt(_trt) > 0 then
				do;
					percent=count / _trtcnt(_trt) * 100;

					if percent > 0 then
						do;

							if round(percent, 0.1) GE 0.1 then
								_cpct="(*ESC*){nbspace 1}("||strip(put(percent, 5.1))||")";
							else
								_cpct="(*ESC*){nbspace 1}(0.0)";
							_cvalue=trim(_cvalue)||_cpct;
						end;
				end;
		end;

	if length(_cvalue) < 13 then
		do;
			*----------------------------------------------------------------------;
			* Put character A0x at right most character to pad text;
			*----------------------------------------------------------------------;
			substr(_cvalue, 13, 1)='A0'x;
		end;

	if first._byvar2 then
		_rowsrt=1;

	if first.AVAL then
		do;
			_rowsrt=_rowsrt + 1;
			_rowmax=max(_rowsrt, _rowmax);
		end;
	_datatyp='data';
	_indent=0;
	_dptindt=0;
	_vorder=1;
	_rowjump=1;

	if upcase(_rwlabel)='_NONE_' then
		_rwlabel=' ';
	_indent=0;
	_dptindt=0;

	if _trt=2 +1 then
		_trt=9999;

	if eof then
		call symput('_rowsrt', compress(put(_rowmax, 4.)));
	_direct="TOP ";
	_p=2;
run;

data _base8;
	set _base8;
	length _cvalue2 $30.;
	_cvalue2=strip(tranwrd(_cvalue, 'A0'x, ""));
	_cvalue21=strip(scan(_cvalue, 1, '('));
	_cvalue22=compress(scan(_cvalue, 2, '('), ')');
run;

data _base7;
	set _base7;
	drop _trt1 _trt2 count;
run;

proc sort data=_base7;
	by _datasrt _byvar1 _byvar2 _cat _trt;
run;

data _base7;
	set _base7;

	if _trt=1 then
		do;
			_trt1=input(_cvalue, ??best.);
		end;

	if _trt=2 then
		do;
			_trt2=input(_cvalue, ??best.);
		end;
run;

proc sort data=_base8(keep=_datasrt _trt _cvalue2 _cvalue21 _cvalue22 _cat 
		_byvar1 _byvar2 count);
	by _datasrt _byvar1 _byvar2 _cat _trt;
run;

data _base8;
	merge _base7(in=a) _base8(in=b);
	by _datasrt _byvar1 _byvar2 _cat _trt;

	if a;

	if a and not b then
		do;
			_cvalue2="0";
			_cvalue21="0";
		end;

	if compress(_cvalue2)="0" then
		_cvalue22=put(0, 5.1);

	if compress(_cvalue)="0" then
		do;
			_cvalue2="NA";
			_cvalue21="NA";
			_cvalue22="NA";
		end;
run;

data _base7;
	set _base7;
	delete;
run;

********************************************************************************;
* Specification 5.4.3: Calculate 95% CI for observed proportion                *;
********************************************************************************;

data _cnp _tmp_cnp;
	set _base8;

	if count=. then
		count=0;
	indc=1;
	output _cnp;
	indc=2;

	if _trt=1 then
		do;
			count=_trt1 - count;
		end;

	if _trt=2 then
		do;
			count=_trt2 - count;
		end;
	output _cnp;

	if indc=2 and count=0 then
		output _tmp_cnp;
run;

proc sort data=_cnp;
	by _byvar1 _byvar2 _cat _rowsrt _rwlabel _trt;
run;

proc sort nodupkey data=_tmp_cnp(keep=_byvar1 _byvar2 _cat _rowsrt _rwlabel _trt);
	by _byvar1 _byvar2 _cat _rowsrt _rwlabel _trt;
run;

********************************************************************************;
*  Call proc freq procedure to calculate CI for observed proportion            *;
********************************************************************************;

proc freq data=_cnp noprint;
	by _byvar1 _byvar2 _cat _rowsrt _rwlabel _trt;
	table indc/binomial alpha=0.05;
	output out=obsprop binomial;
	weight count;
run;

data obsprop;
	merge obsprop _tmp_cnp(in=a);
	by _byvar1 _byvar2 _cat _rowsrt _rwlabel _trt;

	if _bin_=1 and not a then
		do;
			xl_bin_=1 - xu_bin;
			xu_bin_=1 - xl_bin;
		end;
	else
		do;
			xl_bin_=xl_bin;
			xu_bin_=xu_bin;
		end;
run;

********************************************************************************;
* SPECIFICATION 5                                                              *;
* - Store the CI value and output the dataset with CI value.                   *;
********************************************************************************;

data cnpobsprop1(keep=_byvar1 _byvar2 _cat _rowsrt _rwlabel _trt cnp_ci);
	set obsprop;
	by _byvar1 _byvar2 _cat _rowsrt _rwlabel _trt;
	cnp_ci='(' || compress(put(xl_bin_ * 100, 5.1)) 
		|| ',(*ESC*){nbspace 1}' || compress(put(xu_bin_ * 100, 5.1)) || ')';
	label cnp_ci='95% CI';
run;

proc datasets lib=work nolist gennum=all;
	delete _cnp obsprop;
	run;

proc sort data=_base8;
	by _byvar1 _byvar2 _cat _rowsrt _rwlabel _trt;
run;

proc sort data=cnpobsprop1;
	by _byvar1 _byvar2 _cat _rowsrt _rwlabel _trt;
run;

data _base8;
	merge _base8(in=a) cnpobsprop1;
	by _byvar1 _byvar2 _cat _rowsrt _rwlabel _trt;

	if a;

	if compress(_cvalue)="0" then
		do;
			cnp_ci="NE";
		end;
run;

******************************************************************************************;
* Specification 6                                                                        *;
* 1) Generate final report dataset                                                       *;
* 2) Titles and footnotes                                                                *;
* 3) Display: output html file                                                           *;
******************************************************************************************;

data _final;
	set _base1 _base2 _base3 _base4 _base5 _base6 _base7 _base8;
run;

proc sort data=_final;
	by _datasrt _byvar1 _byvar2 _blcksrt _rowsrt;
run;

data _bydata;
	set _bydat1;

	if _byvar1=0 then
		delete;
run;

proc sort data=_bydata;
	by _datasrt _byvar1 _byvar2;
run;

data _final;
	merge _bydata _final(in=_b);
	by _datasrt _byvar1 _byvar2;

	if _b;
run;

*----------------------------------------------------------------------;
* Generate treatment header labels and make further modifications  ;
*----------------------------------------------------------------------;

data _final;
	set _final;
	drop __trt;

	if _trt=9999 then
		__trt=2 + 1;
	else
		__trt=_trt;

	if __trt=. then
		__trt=1;
	_column=_trt;

	if _column=9999 then
		_column=2 + 1;
run;

proc sort data=_final out=_final;
	by _datasrt _byvar1 _byvar2 _blcksrt _rowsrt _column;
run;

proc sql noprint;
	create table rspon as select distinct _trt, _column , _byvar1, _bylab1 , _byvar2, _bylab2 , 
		_vrlabel as _rwlabel , _datasrt, _blcksrt, (min(_rowsrt)-0.5) as _rowsrt , 
		_dptindt as _indent , 0 as _dptindt from _final(where=(_vrlabel^=' ')) group 
		by _trt, _column , _byvar1 ,_byvar2 , _datasrt, _blcksrt, _vrlabel;
quit;

data ADCE_S010_LR_AGE_P3_SAF;
	length _rvalue $100;
	set _final rspon end=eof;
	_rwindt=sum(_indent, _dptindt);

	if _rwindt <=0 then
		_rvalue=_rwlabel;
	else
		_rvalue=repeat(byte(160), _rwindt-1)||_rwlabel;
	_dummy=1;

	if _trt=. then
		_trt=1;
run;

proc sort data=ADCE_S010_LR_AGE_P3_SAF;
	by _datasrt _byvar1 _bylab1 _byvar2 _bylab2 _trt _blcksrt _rowsrt;
run;

data ADCE_S010_LR_AGE_P3_SAF;
	set ADCE_S010_LR_AGE_P3_SAF;
	_cvalue=left(compress(_cvalue, 'A0'x));
run;

data treat;
	length FMTNAME $8 start 8 label $200;
	fmtname='TREAT';

	do start=1 to 2 + ("N"="Y");
		label=symget('_TRTLB'|| compress(put(start, 4.)));
		label=trim(label);
		output;
	end;
run;

proc sql noprint;
	select distinct start, label, count(distinct start) into :start1, 
		:_trlbl1 - :_trlbl99, :maxtrt from treat where start ne 9999 order by start;
quit;

*---------------------------------------------------------------------;
* titles and footnotes ;
*---------------------------------------------------------------------;

options orientation=LANDSCAPE papersize="LETTER";
ods escapechar="~";

title1 "Local Reactions, by Maximum Severity, Within 7 Days After Each Dose, by Age Group (Reactogenicity Subset) (*ESC*){Unicode 2013}";
title2 "Phase 2/3 Subjects (*ESC*){unicode 2265}16 Years of Age (*ESC*){Unicode 2013} Safety Population";
footnote1 "Note: Reactions were collected in the electronic diary (e-diary) from Day 1 through Day 7 after each dose.";
footnote2 "Note: Grade 4 reactions were classified by the investigator or medically qualified person.";
footnote3 "a.(*ESC*){nbspace 5}N = number of subjects reporting at least 1 yes or no response for the specified reaction after the specified dose. ";
footnote4 "b.(*ESC*){nbspace 5}n = Number of subjects with the specified characteristic.";
footnote5 "c.(*ESC*){nbspace 5}Exact 2-sided CI based on the Clopper and Pearson method. ";
footnote6 "d.(*ESC*){nbspace 5}Mild: >2.0 to 5.0 cm; moderate: >5.0 to 10.0 cm; severe: >10.0 cm; Grade 4: necrosis (redness and swelling categories) or exfoliative dermatitis (redness category only). ";
footnote7 "e.(*ESC*){nbspace 5}Mild: does not interfere with activity; moderate: interferes with activity; severe: prevents daily activity; Grade 4: emergency room visit or hospitalization for severe pain at the injection site. ";
footnote8 "f.(*ESC*){nbspace 5}Any local reaction: any redness >2.0 cm, any swelling >2.0 cm, or any pain at the injection site. ";

*---------------------------------------------------------------------;
* Output html file;
*---------------------------------------------------------------------;

ods html file="&outtable.";

data report;
	set ADCE_S010_LR_AGE_P3_SAF;

	if _trt=9999 then
		_trt=2 +1;
	_bylab1=tranwrd(_bylab1, "|", '036e'x);
	_bylab2=tranwrd(_bylab2, "|", '036e'x);
	_rvalue=tranwrd(_rvalue, "|", '036e'x);
run;

proc sort data=report;
	by _datasrt _byvar1 _bylab1 _byvar2 _bylab2 _blcksrt _rowsrt _rvalue _trt;
run;

data data_1 (keep=_datasrt _byvar1 _bylab1 _byvar2 _bylab2 _blcksrt _rowsrt _rvalue COL:);
	set report;
	where _trt=1;
	rename _cvalue=COL11 _cvalue2=COL12 cnp_ci=COL13;
run;

data data_2 (keep=_datasrt _byvar1 _bylab1 _byvar2 _bylab2 _blcksrt _rowsrt _rvalue COL:);
	set report;
	where _trt=2;
	rename _cvalue=COL21 _cvalue2=COL22 cnp_ci=COL23;
run;

proc sort data=report out=extradata (keep=_datasrt _byvar1 _bylab1 _byvar2 _bylab2 _blcksrt 
		_rowsrt _rvalue) nodupkey;
	by _datasrt _byvar1 _bylab1 _byvar2 _bylab2 _blcksrt _rowsrt _rvalue;
run;

data report;
	merge data_1 data_2 extradata;
	by _datasrt _byvar1 _bylab1 _byvar2 _bylab2 _blcksrt _rowsrt _rvalue;
run;


data report;
	set report;
	_fixvar=1;
	_fix2var=1;
	_dummy=1;
run;

proc sort data=report out=outdata1;
	by _datasrt _byvar1 _bylab1 _byvar2 _bylab2 _blcksrt _rowsrt _rvalue;
run;

*---------------------------------------------------------------------;
* proc report statements ;
*---------------------------------------------------------------------;

proc report data=outdata1 nowd list missing contents="" split="|" style(report)={} style(header)={} style(column)={};
	column _fixvar _fix2var _datasrt _byvar1 _bylab1 _byvar2 _bylab2 _blcksrt _rowsrt ("" _rvalue) (("Vaccine Group (as Administered)~{line}" 
	("&_trlbl1." (COL11 COL12 COL13)) ("&_trlbl2." (COL21 COL22 COL23))) ) _dummy;
	define _fixvar / group noprint;
	define _fix2var / group noprint;
	define _byvar1 / group order=internal noprint;
	define _bylab1 / group "Age Group" style(column)={just=left} style(header)={just=left} left;
	define _byvar2 / group order=internal noprint;
	define _bylab2 / group "Dose" style(column)={just=left} style(header)={just=left} left;
	define _datasrt / group order=internal noprint;
	define _blcksrt / group order=internal noprint;
	define _rowsrt / group order=internal noprint;
	define _rvalue / group "Local Reaction" order=data style(column)={just=left} style(header)={just=left} left;
	define COL11 / group nozero "N(*ESC*){super a}" style(column)={leftmargin=12px} style(header)={just=center} center;
	define COL12 / group nozero "n(*ESC*){super b}(*ESC*){nbspace 1}(%)" style(column)={leftmargin=12px} style(header)={just=center} center;
	define COL13 / group nozero "(95%(*ESC*){nbspace 1}CI(*ESC*){super c})" style(column)={leftmargin=12px} style(header)={just=center} center;
	define COL21 / group nozero "N(*ESC*){super a}" style(column)={leftmargin=12px} style(header)={just=center} center;
	define COL22 / group nozero "n(*ESC*){super b}(*ESC*){nbspace 1}(%)" style(column)={leftmargin=12px} style(header)={just=center} center;
	define COL23 / group nozero "(95%(*ESC*){nbspace 1}CI(*ESC*){super c})" style(column)={leftmargin=12px} style(header)={just=center} center;
	define _dummy / sum noprint;
	
	break before _fixvar / contents="" page;
	compute before _fix2var;
		line @1 " ~n ";
	endcomp;
	compute after _blcksrt;
		line " ~n ";
	endcomp;
run;

ods html close;
proc printto;
run;
