program xstat;{$P+} {$c-,m-,f-} label 1; const defaultpad =' '; type id = array[1..6] of char; calendar = array [1..2] of char; date_of_test = record month:calendar; day:calendar; year:calendar end; lab_data = record name: array [1..30] of char; chart_number:id; date: date_of_test; sex:boolean; weight: real; height: real; surface_area: real; chronological_age: real; bone_age: real; height_age:real; percent_overweight_for_height:real; total_body_water: real; values:array[1..18,1..14] of real; pad:array[1..59] of char; end; xstatistical = array[1..20,1..14,1..18] of real; byte = 0..255; $string0 = string 0; $string255 = string 255; $string80 = string 80; $string14 = string 14; $string4 = string 4; f = file of lab_data; axis_label = array[1..4] of char; var filename:$string14; norms,data:lab_data; num_values, peak_time,time,results,x,y,i:byte; fin:f; average,max,min,sum:real; hardcopy,normal_value_flag, error, terminate, continue,escape:boolean; rec:integer; strvalue:$string80; x_axis_label,y_axis_label: array[1..14] of axis_label; statistics:xstatistical; output:text; {************************* init labels for axis *************************} procedure initialize; var i:byte; begin x_axis_label[1]:= '-30 '; x_axis_label[2]:= '-1 '; x_axis_label[3]:= '15 '; x_axis_label[4]:= '30 '; x_axis_label[5]:= '45 '; x_axis_label[6]:= '60 '; x_axis_label[7]:= '90 '; x_axis_label[8]:= '120 '; x_axis_label[9]:= '150 '; x_axis_label[10]:= '180 '; x_axis_label[11]:= '210 '; x_axis_label[12]:= '240 '; x_axis_label[13]:= '300 '; x_axis_label[14]:= '360 '; y_axis_label[1]:= 'BS '; y_axis_label[2]:= 'IRI '; y_axis_label[3]:= 'GH '; y_axis_label[4]:= 'LH '; y_axis_label[5]:= 'FSH '; y_axis_label[6]:= 'F '; y_axis_label[7]:= 'PRL '; y_axis_label[8]:= 'TSH '; y_axis_label[9]:= 'T '; y_axis_label[10]:= 'DS '; y_axis_label[11]:= 'ACTH'; y_axis_label[12]:= 'T4 '; y_axis_label[13]:= 'TBG '; y_axis_label[14]:= 'TT3 '; end; procedure setlength (var x:$string0; y:integer);external; function length (x:$string255):integer; external; procedure keyin(var cix:char);external; procedure clear_screen; begin write (chr(27),'*',chr(0),chr(0),chr(0),chr(0)); end; procedure erase_lines(starting_line,number_of_lines:byte); const blanks = ' '; var i:byte; begin for i:= 1 to number_of_lines do begin write(chr(27),'=',chr(starting_line + 31),chr(32),blanks,blanks); starting_line:= starting_line + 1; end; end; procedure move_cursor(x,y:byte); begin write(chr(27),'=',chr(y+31),chr(x+31)); end; procedure prompt (x,y,length:byte; p:$string80; protected_field_desired:boolean); var underline:string 80; i:byte; begin setlength(underline,0); for i:= 1 to length do append (underline,'_'); if protected_field_desired = false then write(chr(27),'=',chr(y+31),chr(x+31),p,underline) else write(chr(27),'=',chr(y+31),chr(x+31),chr(27),')',p, underline,chr(27),'('); end; function query(x,y:byte; message:$string80):boolean; {ask y/n question} var answer:char; begin repeat move_cursor(x,y); write(message); keyin(answer); until answer in ['y','n','Y','N']; query:= ((answer = 'y') or (answer = 'Y')); erase_lines(y,1); end; function number_records(filenam:$string14):integer; label 1; var num:integer; i:byte; begin num:= 0; reset (filename,fin); if eof(fin) then begin num:= 1; goto 1; end; with data do begin read(fin:1,data); for i:= 1 to 6 do num:= num*10 + ord(chart_number[i])-48; end; 1: number_records:= num; end; procedure init_statistical_array; begin clear_screen; writeln; writeln('Initializing and loading values into matrix. One moment, please.'); for rec:= 1 to 20 do for results:= 1 to 14 do for time:= 1 to 18 do statistics[rec,results,time]:= -999.0; end; procedure axis; var i:byte; begin writeln; {DEBUG delay...terminal does not seem to respond fast enough} for i:= 6 to 19 do begin move_cursor(1,i-1); write(x_axis_label[i-5]:4); end; move_cursor(9,4); for i:= 1 to 14 do write(y_axis_label[i]:4,' '); end; procedure display_values; var x,y,i:byte; continue:char; begin clear_screen; escape:=false; with data do begin writeln(' '); {DEBUG for terminal delay} axis; move_cursor(1,1); write('name: ',name:30,'chart #: ':10,data.chart_number:6, 'date: ':8,date.month:2,'/',date.day:2,'/',date.year:2); if sex then writeln('sex: male') else writeln('sex: female'); write('ht: ',height:5:1,'wt: ':6,weight:5:1, 'S.A.:':5,surface_area:5:1); writeln('% OWt: ':8,percent_overweight_for_height:5:1, 'T.B.W.: ':10,total_body_water:5:1); writeln('age:':5,chronological_age:5:1,'B.A.: ':8,bone_age:5:1, 'H.A.: ':8,height_age:5:1); x:= 7; y:= 5; for time:= 1 to 14 do begin for results:= 1 to 14 do begin move_cursor(x,y); if abs(values[time,results]) <> 999.0 then write(values[time,results]:4:1) else write(' '); {4 spaces} x:= x + 5; end; y:= y + 1; x:= 7; end; end; {of with data} end; procedure values_calculation; var num:byte; begin with data do begin for results:= 1 to 14 do begin max:= values[1,results]; peak_time:= 1; if values[1,results] = -999.0 then begin sum:= 0.0; num_values:= 0; min:=999.0; end; if values[1,results] > -999.0 then begin sum:= values[1,results] ; num_values:= 1; min:= values[1,results]; end; for time := 2 to 14 do begin if max < values[time,results] then begin max:= values[time,results]; peak_time:= time; end; if (values[time,results] > -999.0) and (min > values[time,results]) then min:= values[time,results]; if values[time,results] > -999.0 then begin sum:= sum + values[time,results] ; num_values:= num_values + 1; end; end; average:= sum/num_values; values[15,results]:= max; values[16,results]:= min; if average = 0.0 then values[17,results]:= -999.0 else values[17,results]:= average; case peak_time of 1: values[18,results]:= -30.0; 2: values[18,results]:= -1.0; 3: values[18,results]:= 15.0; 4: values[18,results]:= 30.0; 5: values[18,results]:= 45.0; 6: values[18,results]:= 60.0; 7: values[18,results]:= 90.0; 8: values[18,results]:= 120.0; 9: values[18,results]:= 150.0; 10: values[18,results]:= 180.0; 11: values[18,results]:= 210.0; 12: values[18,results]:= 240.0; 13: values[18,results]:= 300.0; 14: values[18,results]:= 360.0; end; if average = 0.0 then values[18,results]:= -999.0; end; end; end; procedure mistake; label 1,2; var strtime,strtest:$string80; xtime,xtest: axis_label; matrix,i,ii,j,time,test:byte; found,finished:boolean; begin finished:= false; repeat 1: erase_lines(1,1); move_cursor(1,1); write('Enter test and time of incorrect data, e.g. BS 30 '); move_cursor(65,1); i:=0; repeat i:= i + 1; keyin(xtest[i]); write(xtest[i]); until (xtest[i] = chr(13)) or (i = 4); if xtest[i] = chr(13) then for ii:= i to 4 do xtest[ii]:= ' '; if xtest[1] = chr(27) then begin finished:= true; goto 2; end; move_cursor(75,1); i:= 0; repeat i:= i + 1; keyin(xtime[i]); write(xtime[i]); until (xtime[i] = chr(13)) or (i = 4); if xtime[i] = chr(13) then for ii:= i to 4 do xtime[ii]:= ' '; erase_lines(1,1); time:= 255; test:= 255; matrix:= 1; found:= false; repeat if xtime = x_axis_label[matrix] then begin found:= true; time:= matrix; end; matrix:= matrix + 1; until (found) or (matrix > 14); matrix:= 1; found:= false; repeat if xtest = y_axis_label[matrix] then begin found:= true; test:= matrix; end; matrix:= matrix + 1; until (found) or (matrix > 14); if time = 255 then begin erase_lines(1,1); move_cursor(1,1); write('You have entered an invalid time, please reenter test & time: '); goto 1; end; if test = 255 then begin erase_lines(1,1); move_cursor(1,1); write('You have entered an invalid test, please reenter test & time: '); goto 1; end; prompt(test*5+4,time+2,0,'omit',false); data.values[time,test]:= -999.0; 2: until finished; erase_lines(1,1); values_calculation; end; procedure choose_and_exclude_test; var test:char; begin clear_screen; writeln; writeln('A- BLOOD SUGAR'); writeln('B- INSULIN'); writeln('C- GROWTH HORMONE'); writeln('D- LH'); writeln('E- FSH'); writeln('F- CORTISOL'); writeln('G- PROLACTIN'); writeln('H- TSH'); writeln('I- TESTOSTERONE'); writeln('J- DS'); writeln('K- ACTH'); writeln('L- T4'); writeln('M- TBGI'); writeln('N- TT3'); writeln('O- finished excluding tests'); writeln; write('Please enter the letter corresponding to the test: '); repeat repeat move_cursor(61,19); keyin(test); if (ord(test) > 96) and (ord(test) < 123) then test:= chr(ord(test)-32); write(test); until test in ['A'..'O']; results:= ord(test)-64; if results < 15 then begin writeln; write('Values for ',y_axis_label[results],' will be ignored during analysis.'); for time:= 1 to 18 do data.values[time,results]:= -999.0 end; until results = 15; end; procedure offer_hardcopy; var ch:char; begin clear_screen; repeat move_cursor(1,5); write('Do you want a hardcopy of the data? y/n '); keyin(ch); until ch in ['y','n','Y','N']; if ch in ['y','Y'] then hardcopy:= true else hardcopy:= false; clear_screen; if hardcopy = false then rewrite('con:',output) else begin rewrite('lst:',output); writeln('Prepare printer, then enter any character to initiate printing.'); keyin(ch); end; end; procedure load_statistical_array; label 1; var continue:char; last_record:integer; exclude:boolean; procedure select_data; label 1; var exclusion:char; begin display_values; move_cursor(1,19); writeln('Considering this patient''s lab results, choose one: '); writeln('1- Accept all data as displayed for statistical analysis.'); writeln('2- Exclude all values for 1 or more test(s) from analysis.'); writeln('3- Exclude only one or more value(s) from statistical analysis.'); writeln('4- Exclude patient''s entire lab values from analysis.'); repeat move_cursor(55,19); keyin(exclusion); until exclusion in ['0'..'4']; erase_lines(19,5); exclude:=false; case exclusion of '1': goto 1; '2': choose_and_exclude_test; '3': mistake; '4': exclude:= true; end; 1: end; {of procedure} procedure print_raw_data; var stop,start:integer; i:byte; ch:char; begin for results:= 1 to 14 do begin start:= 2; repeat if (start + 7) > last_record then stop:= last_record else stop:= start + 7; if hardcopy then write(output,chr(12)) else begin erase_lines(1,1); move_cursor(1,1); write('Enter any character to continue. '); keyin(ch); clear_screen; end; for i:= 1 to 3 do writeln(output); writeln(output,'RAW DATA FOR TEST :',y_axis_label[results]:4); writeln(output); write(output,' '); for i:= start to stop do write(output,'#':5,i:2); writeln(output); for time:= 1 to 18 do begin if time < 15 then write(output,x_axis_label[time]:4) else case time of 15: write(output,'max '); 16: write(output,'min '); 17: write(output,'ave '); 18: write(output,'peak'); end; for rec:= start to stop do if abs(statistics[rec,results,time]) <> 999.0 then write(output,statistics[rec,results,time]:7:1) else write(output,' ':7); writeln(output); end; start:= start + 8; until start > last_record; end; end; begin reset(filename,fin); if eof(fin) then begin clear_screen; writeln('FILE NOT FOUND!'); writeln; writeln('Enter any character to continue. '); keyin(continue); goto 1; end; last_record:= number_records(filename); with data do begin for rec:= 2 to last_record do begin read(fin:rec,data); select_data; for results:= 1 to 14 do for time:= 1 to 18 do if exclude = true then statistics[rec,results,time]:=-999.0 else statistics[rec,results,time]:= values[time,results]; end; offer_hardcopy; print_raw_data; end; 1: end; {of procedure} procedure stat_average; var standard_deviation,max,min,average,sum:real; last_record,counter:integer; i:byte; ch:char; procedure calc_variance; var i:byte; variance,xvariance:real; begin xvariance:=0.0; for i:= 2 to last_record do if abs(statistics[i,results,time]) <> 999.0 then xvariance:=xvariance + sqr(statistics[i,results,time]-average); variance:=xvariance/(counter-1); standard_deviation:= sqrt(variance); end; begin clear_screen; offer_hardcopy; last_record:= number_records(filename); writeln; if hardcopy then writeln('Now printing.'); for results:= 1 to 14 do begin if hardcopy then write(output,chr(12)) else begin erase_lines(1,1); move_cursor(1,1); write('Enter any character to continue. '); keyin(ch); clear_screen; end; for i:= 1 to 3 do writeln(output); writeln(output,'STATISTICAL ANALYSIS FOR TEST : ',y_axis_label[results]); writeln(output); writeln(output,'ave':9,'n':5,'s.d.':7,'max':6,'min':7); writeln(output); for time:= 1 to 18 do begin sum:= 0.0; counter:= 0; max:= statistics[1,results,1]; if statistics[1,results,1] = -999.0 then min:= 999.0 else min:= statistics[1,results,1]; if time < 15 then write(output,x_axis_label[time]:4) else case time of 15: write(output,'max '); 16: write(output,'min '); 17: write(output,'ave '); 18: write(output,'peak'); end; for rec:= 2 to last_record do begin if abs(statistics[rec,results,time]) <> 999.0 then begin sum:= sum + statistics[rec,results,time]; counter:= counter + 1; if statistics[rec,results,time] > max then max:= statistics[rec,results,time]; if statistics[rec,results,time] < min then min:= statistics[rec,results,time]; end; end; average:= sum/counter; if (average = 0.0) or (abs(average) = 999.0) then write(output,' ':18) else begin calc_variance; write(output,average:7:1); write(output,counter:4,standard_deviation:7:1); end; if abs(max) <> 999.0 then write(output,max:7:1) else write(output,' ':7); if abs(min) <> 999.0 then write(output,min:7:1) else write(output,' ':7); writeln(output); if hardcopy then writeln(output); end; end; end; procedure get_filename; var newfile:boolean; begin clear_screen; writeln; writeln('Enter name of patient data file as: drive:name.extension '); writeln; writeln('Drive is either ''A'' or ''B'' .'); writeln('Name may be up to 14 letters. '); writeln('Extention may be up to 3 letters.'); move_cursor(10,10); write('----> '); read(filename); reset(filename,fin); if eof(fin) then begin prompt(10,15,0,'A file by that name is NOT FOUND. ',false); newfile:= query(10,16,'Is this a new file? y/n'); if newfile then rewrite(filename,fin) else get_filename; end; end; {*************************** main program *******************************} begin get_filename; initialize; init_statistical_array; load_statistical_array; stat_average; end. .