INDEX TO /elem-stat/ FUNCTIONS   A B C D E F G H I K L M N O P Q R S T U V W X Y     Search Code
FUNCTION GROUPS
Arrays   _general_utilities.php [279]
Beta distributions   _statistics.php [52]
Box plots   _statistics.php [936]
Case-insensitive find & compare   _general_utilities.php [1244]
Data simulation   _statistics.php [128]
Distribution functions   _statistics.php [5]
Error handling   _general_utilities.php [1947]
Files   _general_utilities.php [65]
General properties   _database_utilities.php [399]
Histograms   _statistics.php [984]
Links and redirection   _general_utilities.php [2]
Mail   _general_utilities.php [555]
Numeric   _general_utilities.php [1835]
Request, session, and global   _general_utilities.php [843]
Sql datetime handling   _database_utilities.php [337]
Sql insert/delete   _database_utilities.php [230]
Sql multi-record   _database_utilities.php [181]
Sql scalar   _database_utilities.php [130]
Sql single record   _database_utilities.php [157]
Sql vector   _database_utilities.php [205]
Sql-related   _database_utilities.php [15]
String filters   _general_utilities.php [1476]
String parsing   _general_utilities.php [941]
Table construction   _general_utilities.php [1548]
Time & date conversions   _general_utilities.php [1715]
Two-way tables   _statistics.php [812]

574 FUNCTIONS - Ordered by Name [33 duplicates]
 [289] 

D   [
Top/End]
 [186] 
 [131] 
 [224] 
 [182] 
 [170] 
 [194] 
 [215] 
 [189] 
 [199] 
 [152] 
 [166] 
 [158] 
 [147] 
 [206] 
 [138] 
 [231] 

I   [
Top/End]
 [554] 

A   [
Top/End]
[1872] 
[1884] 
[1891] 
[1857] 
  [67] 
[1311] 
[1333] 
[1319] 
  [13] 
[1498] 
[1497] 
  [85] 
 [123] 
 [296] 
[1344] 
[1353] 
[1369] 
 [464] 
   [5] 
 [320] 
 [421] 
 [331] 
 [280] 
 [448] 
 [573] 
 [487] 
 [480] 
 [428] 
 [306] 
 [471] 
 [288] 
 [305] 
[1943] 
 [521] 
 [117] 

B   [
Top/End]
 [102] 
[1168] 
  [93] 
  [46] 
  [47] 
  [43] 
  [44] 
  [49] 
  [45] 
 [284] 
  [98] 
  [50] 
  [51] 
  [42] 
  [48] 
 [122] 
[1273] 
[1301] 
[1287] 
[1263] 
 [112] 
[1428] 
[1438] 
[1453] 
[1164] 
 [118] 
[1162] 
  [64] 
[1219] 
[1157] 
[1185] 
[1011] 
 [377] 
 [260] 
 [271] 

C   [
Top/End]
 [691] 
[1678] 
 [339] 
[1543] 
 [699] 
 [703] 
 [709] 
 [938] 
 [485] 
 [495] 
 [368] 
 [459] 
 [454] 
 [933] 
 [163] 
[1170] 
 [785] 
 [942] 
[1259] 
[1394] 
 [381] 
[1395] 
[1238] 
 [106] 
 [367] 

D   [
Top/End]
[1041] 
 [657] 
[1251] 
   [5] 
 [217] 
 [226] 
 [233] 
 [208] 
[1716] 
[1528] 
[1529] 
 [994] 
[1494] 
 [458] 
  [68] 
 [257] 
 [844] 
[1687] 
  [90] 
  [88] 
[1407] 
[1400] 
[1515] 
 [646] 
[1523] 
[1108] 
[1804] 

E   [
Top/End]
 [719] 
[1512] 
 [832] 
 [826] 
 [100] 
[1948] 
 [407] 
 [404] 
 [527] 
[1107] 
 [556] 
 [575] 
 [587] 
[1061] 
 [511] 
 [491] 
 [540] 
 [814] 
[1139] 
  [83] 
 [116] 
 [104] 

F   [
Top/End]
[1174] 
 [420] 
[1109] 
  [37] 
 [131] 
 [135] 
 [645] 
  [83] 
  [67] 
 [202] 
  [80] 
  [66] 
[1511] 
 [117] 
  [89] 
 [118] 
 [104] 
  [97] 
 [637] 
 [240] 
 [250] 
 [129] 
 [518] 
[1239] 
 [788] 
 [821] 
[1240] 
  [56] 

G   [
Top/End]
  [15] 
 [146] 
 [147] 
 [147] 
 [150] 
 [148] 
 [149] 
 [156] 
 [152] 
 [153] 
 [153] 
 [151] 
 [147] 
 [148] 
 [148] 
 [125] 
 [125] 
 [126] 
 [126] 
 [400] 
[1749] 
[1339] 
 [158] 
 [252] 
 [344] 
 [299] 
 [685] 
 [437] 
[1303] 
 [347] 
 [909] 
 [910] 

H   [
Top/End]
[1147] 
 [128] 
[1169] 
 [796] 
 [806] 
 [817] 
 [813] 
 [985] 
[1010] 
[1939] 
[1931] 
  [25] 
 [361] 

I   [
Top/End]
 [411] 
 [293] 
[1032] 
 [960] 
[1200] 
 [242] 
 [311] 
 [319] 
 [201] 
[1163] 

K   [
Top/End]
[1421] 
[1414] 
 [400] 
 [388] 

L   [
Top/End]
[1333] 
  [79] 
  [61] 
 [130] 
[1249] 
 [689] 
[1496] 
[1495] 
[1047] 
[1072] 
 [159] 
 [401] 
 [388] 
 [103] 
 [176] 
  [84] 
 [129] 
 [131] 
 [413] 
 [122] 
 [127] 
[1743] 
 [981] 

M   [
Top/End]
 [564] 
 [418] 
   [6] 
 [105] 
 [102] 
  [79] 
  [58] 
 [304] 
 [150] 
  [22] 
 [129] 
 [109] 
 [108] 
[1748] 
 [145] 
 [122] 
 [548] 
 [569] 
[1722] 
[1800] 
 [557] 
 [932] 
[1730] 
 [354] 
[1698] 
 [448] 

N   [
Top/End]
[1503] 
[1500] 
[1502] 
[1499] 
[1501] 
  [20] 
[1153] 
 [195] 
[1122] 
[1132] 
 [366] 
  [16] 
[1156] 
 [187] 
 [653] 
 [115] 
  [54] 
  [13] 
[1155] 
 [101] 
[1111] 
 [365] 
 [943] 
[1684] 
 [691] 
 [969] 
[1744] 
[1742] 
 [951] 
 [947] 
[1115] 

O   [
Top/End]
  [82] 
  [80] 
[1167] 

P   [
Top/End]
[1190] 
 [404] 
  [56] 
  [11] 
  [34] 
  [55] 
[1356] 
[1221] 
[1230] 
[1156] 
 [650] 
[1191] 
 [226] 
 [237] 
 [231] 
[1841] 
[1846] 
 [358] 
 [335] 
 [345] 
[1238] 
[1513] 
[1268] 
 [425] 
  [80] 
 [458] 
 [113] 
 [443] 
  [98] 
[1099] 
[1152] 
  [19] 
[1021] 
[1030] 
[1025] 
[1176] 
 [418] 
[1245] 
 [861] 
 [958] 
 [835] 
  [74] 
[1628] 
 [626] 
 [129] 

Q   [
Top/End]
 [539] 
 [103] 
[1836] 

R   [
Top/End]
  [80] 
  [78] 
 [721] 
 [729] 
 [220] 
 [108] 
 [726] 
 [725] 
[1253] 
  [52] 
 [180] 
 [161] 
 [731] 
 [701] 
 [690] 
 [155] 
 [146] 
 [164] 
   [3] 
  [12] 
 [844] 
[1389] 
 [101] 
 [803] 
 [106] 
[1370] 
  [41] 
  [41] 
[1759] 
  [34] 
[1516] 
 [104] 
 [795] 
[1514] 
 [732] 
 [116] 
  [63] 
 [881] 
 [878] 
 [892] 
 [900] 
 [891] 
 [872] 
 [862] 

S   [
Top/End]
[1253] 
  [33] 
 [479] 
 [363] 
 [755] 
 [742] 
 [770] 
 [603] 
 [403] 
 [921] 
 [721] 
 [922] 
 [356] 
 [374] 
[1741] 
[1177] 
[1077] 
[1041] 
 [622] 
 [680] 
 [383] 
[1400] 
[1165] 
[1154] 
[1166] 
  [84] 
  [82] 
[1478] 
[1084] 
  [16] 
  [59] 
 [318] 
  [26] 
  [25] 
  [74] 
  [65] 
  [50] 
 [338] 
 [313] 
  [98] 
  [92] 
 [284] 
 [299] 
  [45] 
  [86] 
  [33] 
  [39] 
 [309] 
 [326] 
 [396] 
 [266] 
 [239] 
 [385] 
  [24] 
[1002] 
  [17] 
 [378] 
 [528] 
 [101] 
[1907] 
 [737] 
 [770] 
 [373] 
 [427] 
 [457] 
[1183] 
 [459] 
 [277] 
 [905] 
[1184] 
 [911] 
 [913] 
 [912] 
 [132] 
 [446] 
 [101] 
  [43] 
 [938] 
  [49] 
  [31] 
  [61] 
  [53] 
  [30] 
 [183] 
 [129] 
 [251] 
 [255] 
 [290] 
  [57] 
 [356] 
 [383] 
 [161] 
 [154] 
  [37] 
 [190] 
  [18] 
  [64] 
 [320] 
  [75] 
 [142] 
 [628] 

T   [
Top/End]
   [9] 
  [24] 
  [39] 
[1579] 
 [422] 
   [2] 
[1550] 
[1562] 
[1659] 
[1680] 
[1665] 
[1161] 
  [29] 
[1592] 
[1609] 
[1611] 
[1620] 
[1610] 
 [714] 
  [79] 
  [77] 
  [77] 
  [75] 
  [78] 
  [76] 
[1273] 
 [135] 
 [697] 
 [694] 
 [698] 
 [633] 
 [638] 
[1679] 
 [924] 
[1590] 
[1584] 
[1785] 
[1771] 
 [670] 
[1737] 
[1813] 
 [988] 
[1192] 
[1195] 
 [370] 
[1621] 
  [79] 
 [563] 
[1225] 
 [369] 

U   [
Top/End]
 [368] 
  [81] 
  [79] 
 [411] 
  [53] 
[1051] 
 [408] 
[1252] 
 [170] 
 [720] 
 [568] 

V   [
Top/End]
[1059] 

W   [
Top/End]
 [473] 
 [376] 
[1269] 
[1202] 
 [929] 
 [928] 
 [371] 

X   [
Top/End]
 [417] 
[1289] 
  [14] 
  [15] 
 [144] 
 [588] 
 [612] 
 [601] 
 [583] 

Y   [
Top/End]
[1296] 
  [16] 
  [17] 
142 FILES
  _all_sites.php
  _code_calls.php
  _code_search.php
  _code_show.php
  _database_utilities.php
  _general_utilities.php
  _gpl.php
  _ngraph.php
  _page_routines.php
  _site_unzip.php
  _statistics.php
  _svg.php
[Run]   anova_difference_of_means.php
[Run]   beta_distribution_parameterized.php
[Run]   bootstrap_means.php
[Run]   box_plot.php
[Run]   box_plot_compare.php
[Run]   boxplot_parameterized.php
[Run]   category_summary.php
[Run]   central_limit.php
[Run]   change_separators.php
[Run]   classification_mistakes.php
[Run]   classification_mistakes_gaussians.php
[Run]   columnize.php
[Run]   combine_grades.php
[Run]   confidence_intervals.php
[Run]   deviations.php
[Run]   deviations_sorted.php
[Run]   dotplot_construction_example.php
[Run]   dotplot_decimals.php
[Run]   dotplot_linear.php
[Run]   dotplot_values.php
[Run]   estimate_variation.php
[Run]   estimate_variation_training.php
[Run]   extract_values.php
[Run]   globals.php
[Run]   grade_average.php
[Run]   histogram.php
[Run]   histogram_animation.php
[Run]   histogram_bins.php
[Run]   histogram_compare.php
[Run]   histogram_construction_example.php
[Run]   histogram_general.php
[Run]   histogram_parameterized.php
[Run]   histogram_setbinsize.php
[Run]   histogram_user_data.php
[Run]   index-all.php
[Run]   index-statistics.php
[Run]   index.php
[Run]   index_elem-stat.php
[Run]   individual_value_plot.php
[Run]   individual_value_plot_modes.php
[Run]   list_examples.php
[Run]   matched_pairs.php
[Run]   mean_confidence_intervals.php
[Run]   normal_2boundary_graph.php
[Run]   normal_area_graph.php
[Run]   normal_boundaries_graph.php
[Run]   normal_boundary_graph.php
[Run]   permutation_mean_test.php
[Run]   permutation_std_test.php
[Run]   permutation_test.php
[Run]   permutations.php
[Run]   plot_individual_values.php
[Run]   population_test.php
[Run]   probability_convergence.php
[Run]   proportion_confidence_intervals.php
[Run]   proportions.php
[Run]   random_run_length.php
[Run]   regression_intervals.php
[Run]   rounding_basin_illustration.php
[Run]   rounding_problem_diagram.php
[Run]   same_distribution_boxplots.php
[Run]   same_distribution_histograms.php
[Run]   sampling-15-7.php
[Run]   sampling.php
[Run]   save_example.php
[Run]   scatter-1.php
[Run]   scatter-1a.php
[Run]   scatter-1b.php
[Run]   scatter-1c.php
[Run]   scatter-1d.php
[Run]   scatter-1e.php
[Run]   scatter-1f.php
[Run]   scatter-1g.php
[Run]   scatter-1h.php
[Run]   scatter-1i.php
[Run]   scatter-1j.php
[Run]   scatter-1k.php
[Run]   scatter-1l.php
[Run]   scatter-1m.php
[Run]   scatter-1r.php
[Run]   scatter-2.php
[Run]   scatter-2a.php
[Run]   scatter-compute-regcoeff.php
[Run]   scatter-influential.php
[Run]   scatter-plot.php
[Run]   scatter-w-correlation.php
[Run]   scatter-w-groups.php
[Run]   scatter-w-line-residualplot.php
[Run]   scatter-w-line.php
[Run]   scatter-w-scales.php
[Run]   script_configuration_edit.php
[Run]   select_columns.php
[Run]   sort_and_shuffle_rows.php
[Run]   standard_deviation.php
[Run]   standard_error_1_proportion.php
[Run]   standard_error_2_population_proportions.php
[Run]   standard_error_2_sample_proportions.php
[Run]   standard_error_correlation_coefficient.php
[Run]   standard_error_correlation_coefficient_direct.php
[Run]   standard_error_diff_two_sample_means.php
[Run]   standard_error_diff_two_sample_means_sd.php
[Run]   standard_error_diff_two_sample_proportions.php
[Run]   standard_error_diff_two_sample_proportions_sd.php
[Run]   standard_error_difference_of_means.php
[Run]   standard_error_difference_of_population_means.php
[Run]   standard_error_one_proportion.php
[Run]   standard_error_one_proportion_sd.php
[Run]   standard_error_one_sample_proportion.php
[Run]   standard_error_one_sample_proportion_sd.php
[Run]   standard_error_regression_coefficients.php
[Run]   statistic-1.php
[Run]   statistic.php
[Run]   stemplot.php
[Run]   stemplot_animation.php
[Run]   stemplot_new.php
[Run]   t_values.php
[Run]   tc-graphs-one-var.php
[Run]   tc-teacher.php
[Run]   threshold.php
[Run]   threshold_cost.php
[Run]   timeseries.php
[Run]   transpose.php
[Run]   transpose_basic.php
[Run]   two-way-table-files.php
[Run]   two-way.php
[Run]   unstack.php
[Run]   upload_data.php
[Run]   word_extraction.php
[Run]   word_length_average.php
[Run]   word_lengths.php

607 FUNCTIONS - Ordered by Location

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [289] 

FILE:
_database_utilities.php [Top/End]
  _database_utilities.php   [Top/End]
 [186] 
  _database_utilities.php   [Top/End]
 [131] 
  _database_utilities.php   [Top/End]
 [224] 
  _database_utilities.php   [Top/End]
 [182] 
  _database_utilities.php   [Top/End]
 [170] 
  _database_utilities.php   [Top/End]
 [194] 
  _database_utilities.php   [Top/End]
 [215] 
  _database_utilities.php   [Top/End]
 [189] 
 [199] 
  _database_utilities.php   [Top/End]
 [152] 
  _database_utilities.php   [Top/End]
 [166] 
 [158] 
  _database_utilities.php   [Top/End]
 [147] 
  _database_utilities.php   [Top/End]
 [206] 
  _database_utilities.php   [Top/End]
 [138] 
  _database_utilities.php   [Top/End]
 [231] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
 [554] 
  _general_utilities.php   [Top/End]
[1872] 
[1884] 
[1891] 
[1857] 

FILE:
_svg.php [Top/End]
  [67] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1311] 
[1333] 
[1319] 
  _general_utilities.php   [Top/End]
  [13] 
  _general_utilities.php   [Top/End]
[1498] 
[1497] 

FILE:
_svg.php [Top/End]
  [85] 
 [123] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [296] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1344] 
[1353] 
[1369] 

FILE:
_svg.php [Top/End]
 [464] 

FILE:
combine_grades.php [Top/End]
  [5] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
 [320] 
 [421] 
 [331] 
 [280] 
 [448] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [573] 
 [487] 
 [480] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
 [428] 
 [306] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [471] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
 [288] 
 [305] 
  _general_utilities.php   [Top/End]
[1943] 
  _general_utilities.php   [Top/End]
 [521] 

FILE:
rounding_basin_illustration.php [Top/End]
 [117] 

FILE:
_page_routines.php [Top/End]
 [102] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1168] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
  [93] 
  _statistics.php   [Top/End]
  [46] 
  [47] 
  [43] 
  [44] 
  [49] 
  [45] 
  _statistics.php   [Top/End]
 [284] 
  _statistics.php   [Top/End]
  [98] 
  _statistics.php   [Top/End]
  [50] 
  [51] 
  [42] 
  [48] 

FILE:
rounding_basin_illustration.php [Top/End]
 [122] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1273] 
[1301] 
[1287] 
[1263] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [112] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1428] 
[1438] 
[1453] 
  _general_utilities.php   [Top/End]
[1164] 

FILE:
histogram_bins.php [Top/End]
 [118] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1162] 
  _general_utilities.php   [Top/End]
  [64] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
[1219] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1157] 
[1185] 
[1011] 
  _general_utilities.php   [Top/End]
 [377] 
  _general_utilities.php   [Top/End]
 [260] 
 [271] 
  _general_utilities.php   [Top/End]
 [691] 
  _general_utilities.php   [Top/End]
[1678] 
  _general_utilities.php   [Top/End]
 [339] 
  _general_utilities.php   [Top/End]
[1543] 
  _general_utilities.php   [Top/End]
 [699] 
 [703] 
 [709] 
  _general_utilities.php   [Top/End]
 [938] 
  _general_utilities.php   [Top/End]
 [485] 
 [495] 
 [368] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [459] 
 [454] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
 [933] 

FILE:
_code_show.php [Top/End]
 [163] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1170] 
  _general_utilities.php   [Top/End]
 [785] 
  _general_utilities.php   [Top/End]
 [942] 
  _general_utilities.php   [Top/End]
[1259] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
[1394] 
  _statistics.php   [Top/End]
 [381] 
  _statistics.php   [Top/End]
[1395] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1238] 

FILE:
rounding_basin_illustration.php [Top/End]
 [106] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
 [367] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
[1041] 
  _statistics.php   [Top/End]
 [657] 
  _statistics.php   [Top/End]
[1251] 

FILE:
_database_utilities.php [Top/End]
  [5] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
 [217] 
 [226] 
 [233] 
 [208] 
  _general_utilities.php   [Top/End]
[1716] 
  _general_utilities.php   [Top/End]
[1528] 
[1529] 
  _general_utilities.php   [Top/End]
 [994] 
  _general_utilities.php   [Top/End]
[1494] 
  _general_utilities.php   [Top/End]
 [458] 
  _general_utilities.php   [Top/End]
  [68] 
 [257] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [844] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1687] 

FILE:
standard_error_correlation_coefficient.php [Top/End]
  [90] 

FILE:
standard_error_regression_coefficients.php [Top/End]
  [88] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1407] 
[1400] 
  _general_utilities.php   [Top/End]
[1515] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [646] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1523] 
  _general_utilities.php   [Top/End]
[1108] 
  _general_utilities.php   [Top/End]
[1804] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [719] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1512] 
  _general_utilities.php   [Top/End]
 [832] 
 [826] 

FILE:
_page_routines.php [Top/End]
 [100] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1948] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [407] 
 [404] 
 [527] 
  _statistics.php   [Top/End]
[1107] 
  _statistics.php   [Top/End]
 [556] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
 [575] 
 [587] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
[1061] 
  _statistics.php   [Top/End]
 [511] 
 [491] 
 [540] 
  _statistics.php   [Top/End]
 [814] 
  _statistics.php   [Top/End]
[1139] 

FILE:
scatter-2.php [Top/End]
  [83] 

FILE:
scatter-2a.php [Top/End]
 [116] 

FILE:
scatter-w-groups.php [Top/End]
 [104] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
[1174] 

FILE:
_database_utilities.php [Top/End]
  _database_utilities.php   [Top/End]
 [420] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1109] 
  _general_utilities.php   [Top/End]
  [37] 
  _general_utilities.php   [Top/End]
 [131] 
 [135] 
  _general_utilities.php   [Top/End]
 [645] 
  _general_utilities.php   [Top/End]
  [83] 
  [67] 
 [202] 
  [80] 
  [66] 
  _general_utilities.php   [Top/End]
[1511] 
  _general_utilities.php   [Top/End]
 [117] 
  [89] 
 [118] 
 [104] 
  [97] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [637] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
 [240] 
 [250] 
 [129] 
  _general_utilities.php   [Top/End]
 [518] 
  _general_utilities.php   [Top/End]
[1239] 
  _general_utilities.php   [Top/End]
 [788] 
 [821] 
  _general_utilities.php   [Top/End]
[1240] 
  _general_utilities.php   [Top/End]
  [56] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
  [15] 

FILE:
classification_mistakes_gaussians.php [Top/End]
 [146] 

FILE:
threshold.php [Top/End]
 [147] 

FILE:
threshold_cost.php [Top/End]
 [147] 

FILE:
classification_mistakes.php [Top/End]
 [150] 
 [148] 
 [149] 
 [156] 

FILE:
classification_mistakes_gaussians.php [Top/End]
 [152] 

FILE:
threshold.php [Top/End]
 [153] 

FILE:
threshold_cost.php [Top/End]
 [153] 

FILE:
classification_mistakes.php [Top/End]
 [151] 

FILE:
classification_mistakes_gaussians.php [Top/End]
 [147] 

FILE:
threshold.php [Top/End]
 [148] 

FILE:
threshold_cost.php [Top/End]
 [148] 

FILE:
classification_mistakes.php [Top/End]
 [125] 

FILE:
classification_mistakes_gaussians.php [Top/End]
 [125] 

FILE:
threshold.php [Top/End]
 [126] 

FILE:
threshold_cost.php [Top/End]
 [126] 

FILE:
_database_utilities.php [Top/End]
  _database_utilities.php   [Top/End]
 [400] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1749] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
[1339] 

FILE:
_code_show.php [Top/End]
 [158] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [252] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
 [344] 
 [299] 
  _general_utilities.php   [Top/End]
 [685] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [437] 
  _statistics.php   [Top/End]
[1303] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
 [347] 
  _general_utilities.php   [Top/End]
 [909] 
 [910] 
  _general_utilities.php   [Top/End]
[1147] 

FILE:
_page_routines.php [Top/End]
 [128] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1169] 
  _general_utilities.php   [Top/End]
 [796] 
 [806] 
 [817] 
 [813] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [985] 
[1010] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1939] 
[1931] 
  _general_utilities.php   [Top/End]
  [25] 
  _general_utilities.php   [Top/End]
 [361] 

FILE:
_database_utilities.php [Top/End]
  _database_utilities.php   [Top/End]
 [411] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
 [293] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
[1032] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
 [960] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
[1200] 
  _statistics.php   [Top/End]
 [242] 
 [311] 
 [319] 
 [201] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1163] 
  _general_utilities.php   [Top/End]
[1421] 
[1414] 
  _general_utilities.php   [Top/End]
 [400] 
 [388] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
[1333] 

FILE:
scatter-w-line.php [Top/End]
  [79] 

FILE:
scatter-w-scales.php [Top/End]
  [61] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
 [130] 
  _general_utilities.php   [Top/End]
[1249] 
  _general_utilities.php   [Top/End]
 [689] 
  _general_utilities.php   [Top/End]
[1496] 
[1495] 
  _general_utilities.php   [Top/End]
[1047] 
[1072] 

FILE:
_code_show.php [Top/End]
 [159] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [401] 
 [388] 

FILE:
_database_utilities.php [Top/End]
  _database_utilities.php   [Top/End]
 [103] 

FILE:
bootstrap_means.php [Top/End]
 [176] 

FILE:
proportions.php [Top/End]
  [84] 

FILE:
sampling-15-7.php [Top/End]
 [129] 

FILE:
sampling.php [Top/End]
 [131] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [413] 

FILE:
_page_routines.php [Top/End]
 [122] 
 [127] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1743] 
  _general_utilities.php   [Top/End]
 [981] 
  _general_utilities.php   [Top/End]
 [564] 
  _general_utilities.php   [Top/End]
 [418] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
  [6] 
  _statistics.php   [Top/End]
 [105] 
 [102] 
  [79] 
  [58] 
  _statistics.php   [Top/End]
 [304] 
 [150] 
  _statistics.php   [Top/End]
  [22] 
  _statistics.php   [Top/End]
 [129] 
  _statistics.php   [Top/End]
 [109] 
 [108] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1748] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [145] 

FILE:
histogram_bins.php [Top/End]
 [122] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
 [548] 
  _general_utilities.php   [Top/End]
 [569] 
  _general_utilities.php   [Top/End]
[1722] 
[1800] 
  _general_utilities.php   [Top/End]
 [557] 
  _general_utilities.php   [Top/End]
 [932] 
  _general_utilities.php   [Top/End]
[1730] 
  _general_utilities.php   [Top/End]
 [354] 
  _general_utilities.php   [Top/End]
[1698] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [448] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1503] 
[1500] 
[1502] 
[1499] 
[1501] 
  _general_utilities.php   [Top/End]
  [20] 
  _general_utilities.php   [Top/End]
[1153] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [195] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1122] 
[1132] 
  _general_utilities.php   [Top/End]
 [366] 
  _general_utilities.php   [Top/End]
  [16] 
  _general_utilities.php   [Top/End]
[1156] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [187] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
 [653] 

FILE:
_ngraph.php [Top/End]
 [115] 
  [54] 
  [13] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1155] 

FILE:
_page_routines.php [Top/End]
 [101] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1111] 
  _general_utilities.php   [Top/End]
 [365] 
  _general_utilities.php   [Top/End]
 [943] 
  _general_utilities.php   [Top/End]
[1684] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [691] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
 [969] 
  _general_utilities.php   [Top/End]
[1744] 
[1742] 
  _general_utilities.php   [Top/End]
 [951] 
 [947] 
[1115] 

FILE:
standard_error_correlation_coefficient.php [Top/End]
  [82] 

FILE:
standard_error_regression_coefficients.php [Top/End]
  [80] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1167] 
[1190] 
  _general_utilities.php   [Top/End]
 [404] 

FILE:
_page_routines.php [Top/End]
  [56] 
  [11] 
  [34] 
  [55] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
[1356] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1221] 
[1230] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
[1156] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
 [650] 
  _general_utilities.php   [Top/End]
[1191] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [226] 
 [237] 
 [231] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1841] 
[1846] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [358] 
 [335] 
 [345] 
  _statistics.php   [Top/End]
[1238] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1513] 
  _general_utilities.php   [Top/End]
[1268] 

FILE:
_svg.php [Top/End]
 [425] 

FILE:
combine_grades.php [Top/End]
  [80] 

FILE:
_svg.php [Top/End]
 [458] 

FILE:
combine_grades.php [Top/End]
 [113] 

FILE:
_svg.php [Top/End]
 [443] 

FILE:
combine_grades.php [Top/End]
  [98] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1099] 
[1152] 
  _general_utilities.php   [Top/End]
  [19] 
  _general_utilities.php   [Top/End]
[1021] 
[1030] 
[1025] 
[1176] 

FILE:
_svg.php [Top/End]
 [418] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1245] 
  _general_utilities.php   [Top/End]
 [861] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [958] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
 [835] 

FILE:
_page_routines.php [Top/End]
  [74] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1628] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [626] 

FILE:
_page_routines.php [Top/End]
 [129] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
 [539] 

FILE:
_page_routines.php [Top/End]
 [103] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1836] 

FILE:
standard_error_correlation_coefficient.php [Top/End]
  [80] 

FILE:
standard_error_regression_coefficients.php [Top/End]
  [78] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
 [721] 
 [729] 

FILE:
_svg.php [Top/End]
 [220] 

FILE:
central_limit.php [Top/End]
 [108] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [726] 
 [725] 
  _statistics.php   [Top/End]
[1253] 

FILE:
matched_pairs.php [Top/End]
  [52] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [180] 
 [161] 
 [731] 
 [701] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
 [690] 
  _general_utilities.php   [Top/End]
 [155] 
 [146] 
 [164] 
  _general_utilities.php   [Top/End]
  [3] 
  [12] 
  _general_utilities.php   [Top/End]
 [844] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
[1389] 

FILE:
standard_error_correlation_coefficient_direct.php [Top/End]
 [101] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [803] 

FILE:
standard_error_correlation_coefficient_direct.php [Top/End]
 [106] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
[1370] 

FILE:
standard_error_correlation_coefficient_direct.php [Top/End]
  [41] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
  [41] 
  _general_utilities.php   [Top/End]
[1759] 
  _general_utilities.php   [Top/End]
  [34] 
  _general_utilities.php   [Top/End]
[1516] 

FILE:
_page_routines.php [Top/End]
 [104] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
 [795] 
  _general_utilities.php   [Top/End]
[1514] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [732] 

FILE:
rounding_basin_illustration.php [Top/End]
 [116] 

FILE:
rounding_problem_diagram.php [Top/End]
  [63] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
 [881] 
 [878] 
 [892] 
 [900] 
 [891] 
 [872] 
 [862] 
  _general_utilities.php   [Top/End]
[1253] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
  [33] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
 [479] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [363] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
 [755] 
 [742] 
 [770] 
 [603] 

FILE:
_database_utilities.php [Top/End]
  _database_utilities.php   [Top/End]
 [403] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
 [921] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [721] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
 [922] 

FILE:
_database_utilities.php [Top/End]
  _database_utilities.php   [Top/End]
 [356] 
 [374] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1741] 
  _general_utilities.php   [Top/End]
[1177] 
[1077] 
[1041] 
  _general_utilities.php   [Top/End]
 [622] 
 [680] 
  _general_utilities.php   [Top/End]
 [383] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
[1400] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1165] 
[1154] 
[1166] 

FILE:
standard_error_correlation_coefficient.php [Top/End]
  [84] 

FILE:
standard_error_regression_coefficients.php [Top/End]
  [82] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1478] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
[1084] 

FILE:
_database_utilities.php [Top/End]
  _database_utilities.php   [Top/End]
  [16] 
  [59] 
  _database_utilities.php   [Top/End]
 [318] 
  _database_utilities.php   [Top/End]
  [26] 
  [25] 
  [74] 
  [65] 
  [50] 
  _database_utilities.php   [Top/End]
 [338] 
  _database_utilities.php   [Top/End]
 [313] 
  _database_utilities.php   [Top/End]
  [98] 
  [92] 
  _database_utilities.php   [Top/End]
 [284] 
 [299] 
  _database_utilities.php   [Top/End]
  [45] 
  [86] 
  [33] 
  [39] 
  _database_utilities.php   [Top/End]
 [309] 
 [326] 
  _database_utilities.php   [Top/End]
 [396] 
  _database_utilities.php   [Top/End]
 [266] 
 [239] 
  _database_utilities.php   [Top/End]
 [385] 
  _database_utilities.php   [Top/End]
  [24] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1002] 

FILE:
_database_utilities.php [Top/End]
  _database_utilities.php   [Top/End]
  [17] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
 [378] 
 [528] 

FILE:
rounding_basin_illustration.php [Top/End]
 [101] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1907] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [737] 
 [770] 
 [373] 
 [427] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
 [457] 
  _general_utilities.php   [Top/End]
[1183] 
  _general_utilities.php   [Top/End]
 [459] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [277] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
 [905] 
  _general_utilities.php   [Top/End]
[1184] 
  _general_utilities.php   [Top/End]
 [911] 
 [913] 
 [912] 

FILE:
_svg.php [Top/End]
 [132] 
 [446] 

FILE:
combine_grades.php [Top/End]
 [101] 

FILE:
_svg.php [Top/End]
  [43] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [938] 

FILE:
_svg.php [Top/End]
  [49] 
  [31] 
  [61] 
  [53] 
  [30] 
 [183] 
 [129] 
 [251] 
 [255] 
 [290] 
  [57] 
 [356] 
 [383] 
 [161] 
 [154] 
  [37] 
 [190] 
  [18] 
  [64] 
 [320] 
  [75] 
 [142] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
 [628] 

FILE:
t_values.php [Top/End]
  [9] 
  [24] 
  [39] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1579] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [422] 

FILE:
t_values.php [Top/End]
  [2] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1550] 
[1562] 
[1659] 
[1680] 
[1665] 
  _general_utilities.php   [Top/End]
[1161] 
  _general_utilities.php   [Top/End]
  [29] 
  _general_utilities.php   [Top/End]
[1592] 
[1609] 
[1611] 
[1620] 
[1610] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [714] 

FILE:
standard_error_correlation_coefficient.php [Top/End]
  [79] 

FILE:
standard_error_regression_coefficients.php [Top/End]
  [77] 

FILE:
standard_error_correlation_coefficient.php [Top/End]
  [77] 

FILE:
standard_error_regression_coefficients.php [Top/End]
  [75] 

FILE:
standard_error_correlation_coefficient.php [Top/End]
  [78] 

FILE:
standard_error_regression_coefficients.php [Top/End]
  [76] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
[1273] 

FILE:
_ngraph.php [Top/End]
 [135] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
 [697] 
 [694] 
 [698] 
 [633] 
 [638] 
  _general_utilities.php   [Top/End]
[1679] 
  _general_utilities.php   [Top/End]
 [924] 
  _general_utilities.php   [Top/End]
[1590] 
[1584] 
  _general_utilities.php   [Top/End]
[1785] 
[1771] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [670] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1737] 
[1813] 
  _general_utilities.php   [Top/End]
 [988] 
[1192] 
[1195] 
  _general_utilities.php   [Top/End]
 [370] 
  _general_utilities.php   [Top/End]
[1621] 

FILE:
_page_routines.php [Top/End]
  [79] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [563] 
  _statistics.php   [Top/End]
[1225] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
 [369] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [368] 

FILE:
standard_error_correlation_coefficient.php [Top/End]
  [81] 

FILE:
standard_error_regression_coefficients.php [Top/End]
  [79] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
 [411] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
  [53] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
[1051] 

FILE:
_database_utilities.php [Top/End]
  _database_utilities.php   [Top/End]
 [408] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
[1252] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
 [170] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [720] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
 [568] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
[1059] 

FILE:
_general_utilities.php [Top/End]
  _general_utilities.php   [Top/End]
 [473] 
 [376] 
  _general_utilities.php   [Top/End]
[1269] 
  _general_utilities.php   [Top/End]
[1202] 
  _general_utilities.php   [Top/End]
 [929] 
 [928] 
  _general_utilities.php   [Top/End]
 [371] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [417] 
  _statistics.php   [Top/End]
[1289] 

FILE:
_svg.php [Top/End]
  [14] 
  [15] 

FILE:
same_distribution_boxplots.php [Top/End]
 [144] 

FILE:
_statistics.php [Top/End]
  _statistics.php   [Top/End]
 [588] 
 [612] 
 [601] 
 [583] 
  _statistics.php   [Top/End]
[1296] 

FILE:
_svg.php [Top/End]
  [16] 
  [17] 

CODE LISTINGS


FILE: _all_sites.php - 51 lines, 0 functions [
Top/End]
  [1]  <?php // if database is to be used, set $database_name in a local _settings.php file (or define it prior to including this file)
  [2]  session_start();
  [3]  ini_set('session.bug_compat_warn',0);
  [4]  date_default_timezone_set('America/Chicago');
  [5]  $site_domain = $_SERVER['SERVER_NAME'];
  [6]  $localhost = ($site_domain === 'localhost');
  [7]  require_once '_general_utilities.php';
  [8]  include_once '_page_routines.php';
  [9]  $site_css = '_site.css';
  [10]  @include_once '_vocabulary.php'; // ensure that the IDE knows that the variables exist, set them to default values
  [11]  // system parameters
  [12]  $system_email = 'hunter@ellinger.org';
  [13]  browser_detect();
  [14]  // initialize global-setting variables
  [15]  $onChange = $extra_head_text = $extra_body_text = '';
  [16]  // standard page settings, can be overridden in page prior to page_start() call
  [17]  $hide_site_banner = FALSE; // to suppress heading, set to TRUE before page_start() call
  [18]  $page_background_color = $localhost ? 'aqua' : 'white';
  [19]  $sv_globals = array();
  [20]  sv_global('page_background_color','aqua','General page background');
  [21]  $page_background_color = $localhost ? 'aqua' : 'white';
  [22]  // current-page tracking
  [23]  $current_page = $_SERVER['PHP_SELF'];
  [24]  $previous_page = sv('current_page');
  [25]  if ($current_page !== sv('current_page')) sv_set('previous_page',sv('current_page'));
  [26]  sv_set('current_page',$current_page);
  [27]  $current_page_name = filename_only($current_page);
  [28]  $development_site = contains($current_page,'_development');
  [29]  $site_directory = before_last($current_page,'/');
  [30]  $home_url = './'; // set to empty string to suppress home-page link at the bottom of the page, or to non-index page if appropriate
  [31]  // parse standard parameters into globals
  [32]  $all = rq1('all');
  [33]  $command = rq('command');
  [34]  $id = rqn('id');
  [35]  $file = rq('file');
  [36]  $random = rqn('random');
  [37]  if (!$command && !$file && !$random) { // start with sample file if present and nothing else specified
  [38]  $file = files("./examples/$current_page_name" . '_example_*');
  [39]  if ($file) {
  [40]  $_SESSION['last_data_filename'] = $file = $file[rand(0,count($file)-1)];
  [41]  $_SESSION['last_data'] = file_read_contents($file);
  [42]  } else $file = '';
  [43]  }
  [44]  $from = rq('from');
  [45]  $sort = rq('sort');
  [46]  if ($sort) { // support alternating-direction sorts, set SQL sort phrase
  [47]  $sort_flip = substr(str_replace('^^','',str_replace(',','^,',"$sort,")),0,-1); // reverse direction of sorts
  [48]  $sql_sort = str_replace('^',' desc',$sort);
  [49]  } else $sql_sort = '';
  [50]  if (rq1('clear')) $file = $_SESSION['last_data'] = $_SESSION['last_data_filename'] = '';
  [51]  ?>
FILE: _code_calls.php - 112 lines, 0 functions [
Top/End]
  [1]  <?php // display specified source code, with function-name indexes into a bookmarked listing
  [2]  include_once '_all_sites.php';
  [3]  $directory = after(substr($_SERVER['PHP_SELF'],0,strrpos($_SERVER['PHP_SELF'],'/')),'/');
  [4]  $suppress_banner = TRUE;
  [5]  $keywords = array('for','foreach','array','while','list','do','if','elseif','isset','case');
  [6]  $locations_labels = array('Local',"/$directory/",'Global','Library');
  [7]  $calls_by_name = $function_calls = $directory_functions = $include_functions =
  [8]  $locations = $call_files = $function_files = $distinct_files = array();
  [9]  // get list of function in general include files
  [10]  foreach (array('_general_utilities','_database_utilities','_page_routines') as $filename) {
  [11]  foreach (nsplit(file_read_contents("../_includes/$filename.php")) as $line) {
  [12]  $line = trim(before($line,'//'));
  [13]  if (begins($line,'function ')) {
  [14]  $include_functions[] = $name = trim(between($line,'function ','('));
  [15]  $locations[$name] = $locations_labels[2];
  [16]  }
  [17]  }
  [18]  }
  [19]  // get list of function in files in this directory (excluding old and hidden ones)
  [20]  $directory_call_count = 0;
  [21]  $search_files = fileset('*.php',array('__*.php','*_old.php','old_*.php'));
  [22]  foreach ($search_files as $filename) {
  [23]  $code_lines = nsplit(trim(file_get_contents($filename)));
  [24]  $line = 0;
  [25]  foreach ($code_lines as $code) {
  [26]  $line++;
  [27]  $code = before($code,'//'); // ignore comments
  [28]  foreach (array_slice(explode('(',$code),0,-1) as $text) {
  [29]  $name = '';
  [30]  $i = strlen($text) - 1;
  [31]  while ($i>=0 && ($text[$i]==='_' || ctype_alnum($text[$i]))) $name = $text[$i--] . $name;
  [32]  if (!$name || is_numeric($name) || in_array($name,$keywords)) continue; // parenthesis used for something other than function call
  [33]  if (begins($text,'function ')) {
  [34]  $directory_functions[] = $name;
  [35]  $function_files[$name][] = $filename;
  [36]  $locations[$name] = $locations_labels[1];
  [37]  } else {
  [38]  $calls_by_name[$name][$filename][] = $line;
  [39]  $calls_by_file[$filename][$name][] = $line;
  [40]  $distinct_files[$name][$filename] = TRUE;
  [41]  $directory_call_count++;
  [42]  }
  [43]  }
  [44]  }
  [45]  }
  [46]  page_start();
  [47]  $uncalled_functions = $multiple_declarations = array();
  [48]  foreach ($function_files as $name=>$fileset) {if (!isset($calls_by_name[$name])) $uncalled_functions[] = titled($name,$fileset[0]);}
  [49]  foreach ($function_files as $name=>$fileset) {
  [50]  if (count($fileset) > 1) {$multiple_declarations[$name] = "<br><b>$name</b> (" . count($fileset) . "): " . implode(' | ',$fileset);}
  [51]  }
  [52]  if ($multiple_declarations || $uncalled_functions) {
  [53]  print "<table border=1 width='94%'><tr><td>";
  [54]  if ($uncalled_functions) print br(italic('Uncalled functions: ') . implode(' | ',$uncalled_functions));
  [55]  if ($multiple_declarations) print "<i>Multiple declarations:</i>\n" . njoin($multiple_declarations);
  [56]  print "</td></tr></table><br>\n";
  [57]  }
  [58]  //
  [59]  $function_count = count($directory_functions);
  [60]  $call_count = count($calls_by_name,1) - $function_count;
  [61]  $file_count = count($calls_by_file);
  [62]  $links = spaces(10) . alink('code listings','_code_show.php') . spaces(5) . alink('code search','_code_search.php');
  [63]  print br(bold(italic(nf($call_count) . " CALLS TO $function_count FUNCTIONS IN $file_count /$directory/ FILES $links")));
  [64]  $links = spaces(5) . $top_link . spaces(5);
  [65]  foreach ($locations_labels as $label) $links .= spaces(5) . alink($label,"?#L_$label") . spaces(5);
  [66]  // make lists of function names ordered by name, call count, and file count
  [67]  foreach ($calls_by_name as $name=>$call_set) {
  [68]  if (!isset($locations[$name])) $locations[$name] = $locations_labels[3];
  [69]  $file_calls[$name] = $title = '';
  [70]  foreach ($call_set as $filename=>$lines) {
  [71]  $file_calls[$name] .= '<br>' . italic("$filename: ") . implode(', ',$lines) . "\n";
  [72]  $title .= " $filename: " . implode(', ',$lines) . "\n";
  [73]  }
  [74]  $call_files[$name] = $file_count = count($call_set);
  [75]  $function_calls[$name] = $call_count = count($call_set,1) - $file_count;
  [76]  $name_text = bold(titled("<a href='#F$name'><b>$name</b></a>",$title));
  [77]  $function_text[$name] = $text = "<br><b>$name_text</b> " . plural($call_count,'call') .
  [78]  ', ' . plural($file_count,'file') . "\n";
  [79] 
  [80]  if (isset($distinct_files[$name]) && count($distinct_files[$name])==1 && isset($function_files[$name][0]) &&
  [81]  isset($distinct_files[$name][$function_files[$name][0]])) $locations[$name] = $locations_labels[0];
  [82]  }
  [83]  ksort($calls_by_name);
  [84]  asort($function_calls);
  [85]  asort($call_files);
  [86]  foreach ($locations_labels as $location) {
  [87]  foreach (array('name'=>$calls_by_name,'# of calls'=>$function_calls,'# of files'=>$call_files) as $tag=>$array) {
  [88]  $location_count[$location][$tag] = 0;
  [89]  foreach ($array as $name=>$text) {if ($locations[$name] === $location) $location_count[$location][$tag]++;}
  [90]  }
  [91]  }
  [92]  foreach ($locations_labels as $location) {
  [93]  print "$links<a name='L_$location'><br><table border=1 width='96%'><tr>\n";
  [94]  foreach (array('name'=>$calls_by_name,'# of calls'=>$function_calls,'# of files'=>$call_files) as $tag=>$array) {
  [95]  print "<td valign=top>" . italic("by $tag for " . plural($location_count[$location][$tag],"$location function"));
  [96]  foreach ($array as $name=>$text) {if ($locations[$name] === $location) print $function_text[$name];}
  [97]  print "</td>\n";
  [98]  }
  [99]  print "</tr></table>\n";
 [100]  }
 [101]  // then print list with details
 [102]  print "<br>$links<br><table width=700><tr><td align=center><table>\n";
 [103]  foreach ($file_calls as $name=>$call_list) print tr(td("<a name='F$name'>" . bold($name) . $call_list));
 [104]  print "</table></td></tr></table>\n";
 [105]  page_end('');
 [106] 
 [112]  ?>
FILE: _code_search.php - 91 lines, 0 functions [
Top/End]
  [1]  <?php // display specified source code, with function-name indexes into a bookmarked listing
  [2]  include_once '_all_sites.php';
  [3]  $suppress_banner = TRUE;
  [4]  $page_width = "'96%'";
  [5]  page_start('Search Site Script Code','   ' . alink('Index to code listings','_code_show.php'));
  [6]  $boxes = 3;
  [7]  $needles = $antineedles = $hneedles = $hantineedles = array();
  [8]  for ($i=0; $i<$boxes; $i++) { // get search input, ignoring blanks or duplicates
  [9]  $needle = rq("needle$i");
  [10]  if ($needle!=='' && !in_array($needle,$needles)) $needles[] = $needle;
  [11]  }
  [12]  for ($i=0; $i<$boxes; $i++) {
  [13]  $antineedle = rq("antineedle$i"); // antineedles must contain, but not equal, some needle
  [14]  if ($antineedle!=='' && !in_array($antineedle,$antineedles) && !in_array($antineedle,$needles)) {
  [15]  foreach ($needles as $needle) {if (strpos($antineedle,$needle)) {$antineedles[] = $antineedle; break;}}
  [16]  }
  [17]  }
  [18]  foreach ($needles as $needle) $hneedles[] = '<b>' . h($needle) . '</b>';
  [19]  foreach ($antineedles as $antineedle) $hantineedles[] = '<b>' . h($antineedle) . '</b>';
  [20]  print "<table border=1 cellpadding=5><tr><td><table border=0>\n";
  [21]  print tr(th('   Contains one of these:   ') . th('   But not as part of these:   '));
  [22]  for ($i=0; $i<$boxes; $i++) {
  [23]  $needle = isset($needles[$i]) ? $needles[$i] : '';
  [24]  $antineedle = isset($antineedles[$i]) ? $antineedles[$i] : '';
  [25]  print tr(tdc(textbox("needle$i",$needle)) . tdc(textbox("antineedle$i",$antineedle)));
  [26]  }
  [27]  print tr(td(commandbutton('Search'),'center 2'));
  [28]  print "</table></td></tr></table><br>\n";
  [29]  if ($_POST) {
  [30]  $files = fileset('*.php');
  [31]  $match_count = 0;
  [32]  foreach ($files as $filename) {
  [33]  $file_text = file_get_contents($filename);
  [34]  $index = 0;
  [35]  foreach (explode("\n",$file_text) as $line) {
  [36]  $index++; // maintain line number
  [37]  $matches = array();
  [38]  $match = FALSE;
  [39]  foreach ($needles as $needle) {
  [40]  $position = strpos($line,$needle);
  [41]  if ($position !== FALSE) { // this needle is a potential match
  [42]  $match = TRUE;
  [43]  foreach ($antineedles as $antineedle) {
  [44]  $offset = strpos($antineedle,$needle);
  [45]  if ($offset === FALSE) continue; // needle not part of this antineedle
  [46]  if (substr($line,$position-$offset,strlen($antineedle)) === $antineedle) {
  [47]  $match = FALSE; // potential needle match voided by this antineedle
  [48]  break;
  [49]  }
  [50]  }
  [51]  }
  [52]  if ($match) $matches[$needle] = $position;
  [53]  }
  [54]  if ($matches) {$match_count++; $found[$filename][$index] = array($line,$matches);}
  [55]  }
  [56]  }
  [57]  if ($found) {
  [58]  print "<b>A total of " . plural($match_count,'matching line was','matching lines were') . " found</b><br>\n";
  [59]  if (count($needles)==1 && !$antineedles) print "Search string: $needles[0]";
  [60]  else {
  [61]  $text = count($hneedles) > 1 ? ' at least one of' : '';
  [62]  print "containing$text { " . implode(' | ',$hneedles) . " }<br>\n";
  [63]  if ($antineedles) print 'but not as part of { ' . implode(' | ',$hantineedles) . " }<br>\n";
  [64]  }
  [65]  print "<table cellpadding=10><tr><td><i>Files containing matches:</i>";
  [66]  foreach ($found as $filename => $line_info) {
  [67]  $name = filename_only($filename);
  [68]  print "<br>   <a href='#$name'>$name</a>";
  [69]  }
  [70]  print "</td></tr></table>\n";
  [71]  print "\n<br>\n<table border=1 cellpadding=3>\n";
  [72]  foreach ($found as $filename => $line_info) {
  [73]  $name = filename_only($filename);
  [74]  $lines = array();
  [75]  foreach ($line_info as $index => $linematches) {
  [76]  list($line,$matches) = $linematches;
  [77]  // TO DO -- use $matches array to make the matches in $line bold for emphasis
  [78]  $lines[] = " <small>[$index]</small> " . h($line);
  [79]  }
  [80]  print tr(td("<a name='$name'><i>$filename</i>   $top_link<br>\n" . implode("<br>\n",$lines)));
  [81]  }
  [82]  print "</table>\n";
  [83]  } else print big("No instances of '$hneedle' were found");
  [84]  }
  [85]  page_end('');
  [91]  ?>
FILE: _code_show.php - 173 lines, 3 functions [
Top/End]
  [1]  <?php // display specified source code, with function-name indexes into a bookmarked listing
  [2]  include_once '_all_sites.php';
  [3]  $page_width="'96%'";
  [4]  $split_length = 50;
  [5]  $suppress_banner = TRUE;
  [6]  page_start();
  [7]  $search_files = fileset('*.php',array('__*.php','*_old.php'));
  [8]  // first pass to extract function references
  [9]  $function_index = $group_index = $file_index = 0; // used to make bookmark tags into code listing
  [10]  $functions = $groups = $function_names = $function_initials = array(); $function_initials[''] = 0;
  [11]  foreach (char_array('ABCDEFGHIJKLMNOPQRSTUVWXYZ') as $initial) $function_initials[$initial] = 0;
  [12]  foreach ($search_files as $filename) {
  [13]  $file_index++;
  [14]  $local = (substr(filename_base($filename),0,1) !== '_'); // general-include filenames start with underscore
  [15]  $code_lines = nsplit(trim(file_get_contents($filename)));
  [16]  $group = '';
  [17]  $line = $group_count = $function_count = $file_function_count = 0;
  [18]  foreach ($code_lines as $code) {
  [19]  $line++;
  [20]  $code = trim($code);
  [21]  if (substr($code,0,5) === '//// ') { // function-group comment
  [22]  $group = get_group_name($code);
  [23]  if ($group) {
  [24]  $group_index++;
  [25]  $group_count++;
  [26]  $title = ($group === $code) ? '' : $code; // suppress hover title if same as group name
  [27]  $groups[$group] = array('name'=>$group,'file'=>$filename,'line'=>$line,'index'=>$group_index,'title'=>h($title));
  [28]  }
  [29]  } else if (substr($code,0,9) === 'function ') { // function definition
  [30]  $name = trim(between($code,'function','('));
  [31]  $name0 = strtoupper(substr($name,0,1));
  [32]  if ($name0 === '_') continue; // ignore helper functions
  [33]  $function_index++;
  [34]  $function_count++;
  [35]  $file_function_count++;
  [36]  $args = trim(between($code,$name,'{'));
  [37]  $title = trim(between($code,'function','{'));
  [38]  if (strlen($title)-strlen(str_replace(',','',$title)) > 4) $title = str_replace(',',",\n ",$title);
  [39]  $functions[$name][$filename] = array('name'=>$name,'file'=>$filename,'line'=>$line,'args'=>$args,'title'=>h($title),
  [40]  'index'=>$function_index,'group'=>$group,'functions'=>$file_function_count,'local'=>$local);
  [41]  $function_names[] = $name;
  [42]  $function_initials[$name0]++;
  [43]  }
  [44]  }
  [45]  $files[$filename] = array('name'=>filename_base($filename),'index'=>$file_index,'lines'=>count($code_lines),
  [46]  'functions'=>$function_count,'groups'=>$group_count,'local'=>$local);
  [47]  }
  [48]  // sort, then write index tables with group/subgroup and alphabetized list on left, then file-order list on right
  [49]  print "<table border=1 cellpadding=5>\n";
  [50]  ksort($function_initials);
  [51]  $initial_links = '';
  [52]  foreach ($function_initials as $initial=>$count) {if ($count) $initial_links .= " <a href='#I_$initial'>$initial</a>";}
  [53]  $directory = after(substr($_SERVER['PHP_SELF'],0,strrpos($_SERVER['PHP_SELF'],'/')),'/');
  [54]  print tr(tdc("<b><i>INDEX TO /$directory/ FUNCTIONS</i>  $initial_links</b>     " . alink('Search Code','_code_search.php'),2));
  [55]  print "<tr>\n";
  [56]  // left index column (groups, then alphabetized function list)
  [57]  print "<td width='48%' valign=top>\n<b>FUNCTION GROUPS</b>\n";
  [58]  ksort($groups);
  [59]  foreach ($groups as $group) {
  [60]  print "<br><a href='#R$group[index]'><b>$group[name]</b></a>   <small>$group[file] [$group[line]]</small>\n";
  [61]  }
  [62]  ksort($functions);
  [63]  $duplicates = '';
  [64]  foreach ($functions as $name=>$functionset) {
  [65]  if (count($functionset) > 1) $duplicates .= " $name: " . implode(' ',array_keys($functionset)) . "\n";
  [66]  }
  [67]  if ($duplicates) $duplicates = titled('<sup>[' . ($function_index-count($functions)) . ' duplicates]</sup>',$duplicates);
  [68]  print br(bold(count($functions) . ' FUNCTIONS - Ordered by Name ') . $duplicates,2,0);
  [69]  $initial = '';
  [70]  foreach ($functions as $name=>$function_set) {
  [71]  $name0 = strtoupper(substr($name,0,1));
  [72]  if ($name0 !== $initial) {
  [73]  $initial = $name0;
  [74]  print "<br><a name='I_$initial'><br><b>$initial</b>   $top_link\n";
  [75]  }
  [76]  foreach ($function_set as $filename=>$function) {
  [77]  $index = $files[$function['file']]['index'];
  [78]  $local = $function['local'] ? small('  ' . titled('[Local]',$function['file'])) : '';
  [79]  $number = titled(spaces(4-strlen($function['line'])) . small("[<a href='#Q$index'>$function[line]</a>]"),"Line $function[line] in $function[file]");
  [80]  $name_length = strlen("$function[name]") + ($function['local'] ? 9 : 0);
  [81]  $args = $function['args'];
  [82]  if ((strlen($args)+$name_length) > $split_length) $args = substr($args,0,max(10,$split_length-3-$name_length)) . '...';
  [83]  print "<br>$number <label title='$function[title]'><a href='#F$function[index]'><b>$function[name]</b>" .
  [84]  h($args) . "</a>$local</label>\n";
  [85]  }
  [86]  }
  [87]  print "</td>\n";
  [88]  // right index column (files, then sequential function list)
  [89]  print "<td width='52%' valign=top>\n<b>" . count($files) . " FILES</b>\n";
  [90]  $alphabetized_files = $files;
  [91]  ksort($alphabetized_files);
  [92]  foreach ($alphabetized_files as $file) {
  [93]  $letter = $file['functions'] ? 'Q' : 'P';
  [94]  $filename = $file['name'];
  [95]  $run_link = $filename[0]==='_' ? '' : small('[' . alink('Run',$filename) . ']');
  [96]  print "<br>$run_link   <a href='#$letter$file[index]'>$file[name]</a>\n";
  [97]  }
  [98]  $groupname = $file = '';
  [99]  print "<br><br><b>$function_index FUNCTIONS - Ordered by Location</b>\n";
 [100]  foreach ($functions as $name=>$functionset) {
 [101]  foreach ($functionset as $filename=>$function) {
 [102]  if ($function['file'] !== $file) {
 [103]  $file = $function['file'];
 [104]  $index = $files[$file]['index'];
 [105]  print "<a name='Q$index'><br><br><i><b>FILE:</b> <a href='#P$index'>$file</a></i> $top_link\n";
 [106]  }
 [107]  if ($function['group'] !== $groupname) {
 [108]  $groupname = $function['group'];
 [109]  $group = $groups[$groupname];
 [110]  $index = $group['index'];
 [111]  if ($groupname) print "<br><label title='$group[title]'><a name='R$index'>" .
 [112]  "<a href='#G$index'><b><i>$groupname</i></b></a></label>   $file   $top_link\n";
 [113]  }
 [114]  $name_length = strlen("$function[name]");
 [115]  $args = $function['args'];
 [116]  $args = strlen($args)+$name_length<$split_length ? $args : substr($args,0,max(10,$split_length-3-$name_length)) . '...';
 [117]  print line_number($function['line']) . "<label title='$function[title]'><a href='#F$function[index]'>" .
 [118]  "<b>$function[name]</b>" . h($args) . "</a></label>\n";
 [119]  }
 [120]  }
 [121]  print "</td>\n";
 [122]  print "</tr>\n";
 [123]  print "</table>\n";
 [124]  // finally, list code for each file, with bookmark anchors at the start of each function
 [125]  print "<br><h3>CODE LISTINGS</h3>\n";
 [126]  print "<table style='font-family:Helvetica'><tr><td>\n";
 [127]  $function_count = $group_count = 0;
 [128]  foreach ($files as $filename=>$file) {
 [129]  print "<a name='P$file[index]'><hr><b>FILE: $filename - $file[lines] lines, " . plural($file['functions'],'function') . "</b> $top_link\n";
 [130]  $code_lines = nsplit(trim(file_get_contents($filename)));
 [131]  $line = 0;
 [132]  $copyright = FALSE;
 [133]  foreach ($code_lines as $code) {
 [134]  $line++;
 [135]  $trimmed_code = trim($code);
 [136]  if ($copyright && strpos($trimmed_code,'*/')===0) {$copyright = FALSE; continue;}
 [137]  if (strpos($trimmed_code,'/* Copyright (C)') === 0) $copyright = TRUE;
 [138]  if ($copyright) continue; // don't include copyright notice in these code listings
 [139]  if (substr($trimmed_code,0,9) === 'function ') { // function definition
 [140]  $declaration = trim(between($trimmed_code,'function ','{'));
 [141]  $remainder = after_with($trimmed_code,'{');
 [142]  $name = trim(before($declaration,'('));
 [143]  $function = $functions[$name][$filename];
 [144]  print " $top_link   <small><a href='#Q$file[index]'>$file[name]</a></small>\n<a name='F$function[index]'>\n" .
 [145]  code_line("function $declaration",$line,'b') . ' ' . h($remainder) . "\n";
 [146]  } else {
 [147]  if (substr($code,0,5) === '//// ') {
 [148]  $group = $groups[get_group_name($code)];
 [149]  if ($group['name']) print "<a name='G$group[index]'>\n";
 [150]  }
 [151]  print code_line($code,$line);
 [152]  }
 [153]  }
 [154]  }
 [155]  print "<hr>\n</td></tr></table>\n";
 [156]  page_end('');
 [157]  [Top/End]   _code_show.php
 [158]  function get_group_name($text) {return ucfirst(trim(str_replace('//',' ',strtolower($text))));} [
Top/End]   _code_show.php
 [159]  function line_number($linenumber) {
 [160]  $linenumber = $linenumber ? '<small>' . nbsp(substr(" [$linenumber]",-6)) . '</small> ' : '';
 [161]  return ("<br>$linenumber\n");
 [162]  } [
Top/End]   _code_show.php
 [163]  function code_line($code,$line='',$tag='') {
 [164]  $code = str_replace("\t",'     ',h($code));
 [165]  if ($tag) $code = "<$tag>$code</$tag>";
 [166]  return (line_number($line) . $code);
 [167]  }
 [173]  ?>

FILE: _database_utilities.php - 430 lines, 51 functions [
Top/End]
  [1]  <?php // SQL-related routines
  [2]  require_once '_general_utilities.php';
  [3]  if (isset($database_name)) $database_connection = database_connect();
  [4]  [Top/End]   _database_utilities.php
  [5]  function database_connect($database='',$context='',$username='',$password='',$host='') {
  [6]  if (!$database) $database = $GLOBALS['database_name'];
  [7]  if (!$database) return FALSE;
  [8]  if (!$username) $username = $GLOBALS['database_user'];
  [9]  if (!$password) $password = $GLOBALS['database_password'];
  [10]  $host = $GLOBALS['database_host'] ? $GLOBALS['database_host'] : 'localhost';
  [11]  $GLOBALS['database_connection'] = mysqli_connect($GLOBALS['database_host'],
  [12]  "$GLOBALS[database_prefix]$username",$password,"$GLOBALS[database_prefix]$database$context") or die;
  [13]  return $GLOBALS['database_connection'];
  [14]  }

  [15]  //// SQL-RELATED [
Top/End]   _database_utilities.php
  [16]  function sq($value) {return ("'" . str_replace("'","''",stripslashes($value)) . "'");} // guard SQL values [
Top/End]   _database_utilities.php
  [17]  function sqv($sql_text,$values) { // replaces ? characters in order with supplied single-quoted values
  [18]  $pieces = explode('?',$sql_text);
  [19]  if (!is_array($values)) $values = array_slice(func_get_args(),1);
  [20]  $count = min(count($pieces)-1,count($values));
  [21]  for ($i=0; $i<$count; $i++) $pieces[$i] .= sq($values[$i]);
  [22]  return implode('',$pieces);
  [23]  } [
Top/End]   _database_utilities.php
  [24]  function sqrq($tag,$default='') {return sq(rq($tag,$default));} [
Top/End]   _database_utilities.php
  [25]  function sql_close() {mysqli_close($GLOBALS['database_connection']);} // close SQL connection at end of page [
Top/End]   _database_utilities.php
  [26]  function sql_clean($value) {
  [27]  $s = "";
  [28]  foreach (split(",",$value) as $c) { // collect non-forbidden characters
  [29]  if (ord($c)>31 && $c!==';' && $c!==':' && $c!=='`') $s .= $c; // drop control, system-call, and statement-separator characters
  [30]  }
  [31]  return $s;
  [32]  } [
Top/End]   _database_utilities.php
  [33]  function sql_query($text) {
  [34]  $GLOBALS['sql_query_text'] = $text;
  [35]  $result = mysqli_query($GLOBALS['database_connection'],$text);
  [36]  if ($result === FALSE) error(br($GLOBALS['sql_query_text'] . ': ' . mysqli_error($GLOBALS['database_connection'])));
  [37]  return $result;
  [38]  } [
Top/End]   _database_utilities.php
  [39]  function sql_query_rows($command) { // returns array of result rows to a general query
  [40]  $result = sql_query($command);
  [41]  $array_of_rows = array(); // empty array is return for no-results case
  [42]  if ($result) while($row = mysqli_fetch_assoc($result)) {$array_of_rows[] = $row;}
  [43]  return $array_of_rows; // this is an unkeyed array of keyed arrays, since rows are arrays keyed by field name
  [44]  } [
Top/End]   _database_utilities.php
  [45]  function sql_open_table ($table,$condition='',$order='') {
  [46]  $result = sql_query("SELECT * FROM $table" . sql_condition_phrase($condition) . sql_order_phrase($order));
  [47]  if ($result === FALSE) error("Failed to open <i>$table</i> table");
  [48]  return $result;
  [49]  } [
Top/End]   _database_utilities.php
  [50]  function sql_create_table($table,$fieldset,$constraints='') { // creates table with auto-increment id field from $name=>$type array
  [51]  if (DBF($table)) sql_query("DROP TABLE $table");
  [52]  $create_fields = array();
  [53]  foreach ($fieldset as $field=>$type) $create_fields[] = "$field $type";
  [54]  $sql_base = "INSERT INTO $table (" . cjoin(array_keys($fieldset)) . ')';
  [55]  if ($constraints) $constraints = ", $constraints";
  [56]  sql_query("CREATE TABLE $table (id INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(id), " . implode(', ',$create_fields) . "$constraints)");
  [57]  return $sql_base;
  [58]  } [
Top/End]   _database_utilities.php
  [59]  function sq_contents($value_array='') { // make parenthesized, comma-separated list, with '' as needed
  [60]  $v = array();
  [61]  if (!is_array($value_array)) $value_array = func_get_args();
  [62]  foreach ($value_array as $value) $v[] = (ctype_digit($value) ? "$value" : sq($value));
  [63]  return ('(' . cjoin($v) . ')'); // can be used either with "id in (1,2,3)" list or for insert-command value list
  [64]  } [
Top/End]   _database_utilities.php
  [65]  function sql_conditions($conditions) {
  [66]  if (!is_array($conditions)) $conditions = func_get_args();
  [67]  $where = '';
  [68]  foreach ($conditions as $condition) {
  [69]  if ($condition) $where .= ' AND (' . sql_condition_phrase($condition) . ')';
  [70]  }
  [71]  if ($where) $where = substr($where,5); // drop leading " AND "
  [72]  return $where;
  [73]  } [
Top/End]   _database_utilities.php
  [74]  function sql_condition_phrase($condition) {
  [75]  if (is_array($condition)) $condition = count($condition) ? 'id in ' . sq_contents($condition) : '';
  [76]  elseif (is_numeric($condition)) {
  [77]  if ($condition > 0) $condition = "id=$condition"; // support lookup by id
  [78]  elseif ($condition < 0) $condition = 0; // negative ids are treated like zero (and thus ignored)
  [79]  } else {
  [80]  if (begins($condition,'()')) $condition = substr($condition,2);
  [81]  if (begins($condition,' and ')) $condition = substr($condition,5);
  [82]  if (begins($condition,' or ')) $condition = substr($condition,4);
  [83]  }
  [84]  return ($condition ? " WHERE $condition" : '');
  [85]  } [
Top/End]   _database_utilities.php
  [86]  function sql_order_phrase($order) {
  [87]  if (!$order) return '';
  [88]  if (is_array($order)) $order = join(',',$order);
  [89]  if (begins($order,'LIMIT ')) return " $order";
  [90]  return (" ORDER BY " . str_replace('^',' desc',$order));
  [91]  } [
Top/End]   _database_utilities.php
  [92]  function sql_group_phrase($group) {
  [93]  if (!$group) return '';
  [94]  if (is_array($group)) $group = join(',',$group);
  [95]  if (contains($group,'GROUP BY ')) $group = after($group,'GROUP BY ');
  [96]  return " GROUP BY $group";
  [97]  } [
Top/End]   _database_utilities.php
  [98]  function sql_fieldnames_from_row($row) {
  [99]  $names = array();
 [100]  foreach ($row as $name=>$value) {if (!is_numeric($name)) $names[] = $name;}
 [101]  return $names;
 [102]  } [
Top/End]   _database_utilities.php
 [103]  function list_table($table,$more='',$variables='*',$characters=200,$view_url='') { // lists contents of any SQL table
 [104]  // $table -- table name (in database that is already connected to)
 [105]  // $more -- SQL qualifying phrases, such as WHERE ..., ORDER BY ... or LIMIT ...
 [106]  // $variables -- optional list of fields (defaults to all fields)
 [107]  if ($characters < 5) $characters = 5;
 [108]  if ($view_url && $variables!=='*' && !contains(",$variables,",',id,')) $variables = "id,$variables";
 [109]  $result = sql_query("SELECT $variables FROM $table $more");
 [110]  $table = "\n<table cellpadding=3 border=1>\n";
 [111]  $headingdone = false;
 [112]  while ($row = mysqli_fetch_assoc($result)) {
 [113]  if (!$headingdone) {
 [114]  $table .= "<tr>\n";
 [115]  foreach ($row as $var => $val) $table .= "<td><i>$var</i></td>";
 [116]  $table .= "</tr>\n";
 [117]  $headingdone = true;
 [118]  }
 [119]  $table .= "<tr>\n";
 [120]  foreach ($row as $var => $val) {
 [121]  if (same($var,'id') && $view_url) $val = small(alink('View',"$view_url?id=$val"));
 [122]  else {$val = h($val); if (strlen($val) > $characters) $val = titled(substr($val,0,$characters-3) . ' ...',$val);}
 [123]  $table .= "<td>$val</td>";
 [124]  }
 [125]  $table .= "</tr>\n";
 [126]  }
 [127]  $table .= "</table>\n";
 [128]  return $table;
 [129]  }

 [130]  //// SQL SCALAR [
Top/End]   _database_utilities.php
 [131]  function DBC($table,$condition='') { // count of rows matching condition
 [132]  $condition = sql_condition_phrase($condition);
 [133]  $result = sql_query("SELECT count(*) FROM $table$condition");
 [134]  if ($result === FALSE) bailout("DBC error -- table=$table condition=$condition");
 [135]  if ($row = mysqli_fetch_row($result)) return $row[0];
 [136]  return 0;
 [137]  } [
Top/End]   _database_utilities.php
 [138]  function DBZ($table,$field,$condition,$order='') { // return scalar value (NULL default)
 [139]  //if (!$condition) return NULL;
 [140]  $condition = sql_condition_phrase($condition);
 [141]  if ($order) sql_order_phrase($order);
 [142]  $result = sql_query("SELECT $field FROM $table$condition$order LIMIT 1");
 [143]  if (!$result) return FALSE;
 [144]  $row = mysqli_fetch_row($result);
 [145]  return ($result===FALSE ? NULL : $row[0]);
 [146]  } [
Top/End]   _database_utilities.php
 [147]  function DBS($table,$field,$condition,$order='') { // return scalar value ('' default)
 [148]  //if (!$condition) return NULL;
 [149]  $result = DBZ($table,$field,$condition,$order);
 [150]  return ($result===NULL ? '' : $result);
 [151]  } [
Top/End]   _database_utilities.php
 [152]  function DBN($table,$field,$condition,$order='') { // return scalar numeric value (zero default)
 [153]  //if (!$condition) return NULL;
 [154]  $n = DBS($table,$field,$condition,$order);
 [155]  return (is_numeric($n) ? $n : 0);
 [156]  }

 [157]  //// SQL SINGLE RECORD [
Top/End]   _database_utilities.php
 [158]  function DBR($table,$condition,$order='') { // returns first row meeting condition (or FALSE if none)
 [159]  if (!$condition) return NULL;
 [160]  $condition = sql_condition_phrase($condition);
 [161]  $order = sql_order_phrase($order);
 [162]  $result = sql_query("SELECT * FROM $table$condition$order LIMIT 1");
 [163]  if (!$result) return FALSE;
 [164]  return mysqli_fetch_assoc($result);
 [165]  } [
Top/End]   _database_utilities.php
 [166]  function DBO($table,$condition='',$order='') { // returns either first row meeting condition, or "empty" row
 [167]  $result = DBR($table,$condition,$order);
 [168]  return ($result ? $result : DBF($table));
 [169]  } [
Top/End]   _database_utilities.php
 [170]  function DBF($table,$fetch_types=FALSE) { // returns an "empty object" row or an array of field types, keyed by field name
 [171]  $where = "WHERE table_schema='$GLOBALS[database_prefix]$GLOBALS[database_name]' AND table_name='$table'";
 [172]  $result = sql_query("SELECT COLUMN_NAME,COLUMN_DEFAULT,DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS $where");
 [173]  if (!$result) return FALSE;
 [174]  $array = array();
 [175]  while ($row = mysqli_fetch_row($result)) {
 [176]  if ($fetch_types) $array[$row[0]] = $row[2]; // set each field to its type
 [177]  else $array[$row[0]] = contains($row[2],'INT') ? num($row[1]) : $row[1]; // set each field to its default
 [178]  }
 [179]  return $array;
 [180]  }

 [181]  //// SQL MULTI-RECORD [
Top/End]   _database_utilities.php
 [182]  function DBE($table,$condition='',$order='') { // returns the array of enabled=1 rows meeting condition
 [183]  $condition = $condition!=='' ? "($condition) AND enabled=1" : "enabled=1";
 [184]  return DBA($table,$condition,$order);
 [185]  } [
Top/End]   _database_utilities.php
 [186]  function DBA($table,$condition='',$order='') { // returns rows meeting condition (all fields)
 [187]  return DBL($table,'*',$condition,$order);
 [188]  } [
Top/End]   _database_utilities.php
 [189]  function DBK($table,$key='id',$condition='',$order='') { // returns rows keyed by specified field
 [190]  $array_of_rows = array();
 [191]  foreach (DBA($table,$condition,$order) as $row) $array_of_rows[$row[$key]] = $row;
 [192]  return $array_of_rows;
 [193]  } [
Top/End]   _database_utilities.php
 [194]  function DBG($table,$grouped_fields,$aggregates='COUNT(*) AS subtotal',$condition='',$order='') { // returns grouped query
 [195]  $groups = array();
 [196]  foreach (csplit($grouped_fields) as $field) $groups[] = before($field,' AS ');
 [197]  return DBL($table,"$aggregates,$grouped_fields",$condition,$order,$groups);
 [198]  } [
Top/End]   _database_utilities.php
 [199]  function DBL($table,$selection='*',$condition='',$order='',$group='') { // returns rows meeting condition (specified fields)
 [200]  $condition = sql_condition_phrase($condition);
 [201]  $order = sql_order_phrase($order);
 [202]  $group = sql_group_phrase($group);
 [203]  return sql_query_rows("SELECT $selection FROM $table$condition$group$order"); // FALSE if error, empty array if no results
 [204]  }

 [205]  //// SQL VECTOR [
Top/End]   _database_utilities.php
 [206]  function DBV($table,$field='id',$condition='',$order='') { // returns array of values of specified field in rows meeting condition
 [207]  $condition = sql_condition_phrase($condition);
 [208]  $order = sql_order_phrase($order);
 [209]  $result = sql_query("SELECT $field FROM $table$condition$order");
 [210]  if ($result === FALSE) return FALSE;
 [211]  $field_value_vector = array();
 [212]  while($row = mysqli_fetch_assoc($result)) {$field_value_vector[] = $row[$field];}
 [213]  return $field_value_vector; // this is a one-dimensional array, with one value from each qualifying row
 [214]  } [
Top/End]   _database_utilities.php
 [215]  function DBI($table,$field,$condition='',$order='') { // returns vector keyed by id number
 [216]  $condition = sql_condition_phrase($condition);
 [217]  $order = sql_order_phrase($order);
 [218]  $result = sql_query("SELECT id,$field FROM $table$condition$order");
 [219]  if ($result === FALSE) return FALSE;
 [220]  $field_value_vector = array();
 [221]  while($row = mysql_fetch_assoc($result)) {$field_value_vector[$row[id]] = $row[$field];}
 [222]  return $field_value_vector; // each key is the id for the corresponding row, each value the field value
 [223]  } [
Top/End]   _database_utilities.php
 [224]  function DBD($table,$id) { // returns comma-separated list of ids of a record and its descendents
 [225]  $descendents = array($id);
 [226]  do {$children = DBV($table,id,"parent_id in ($delete_list)"); $descendents = array_merge($descendents,$children);}
 [227]  while (count($children));
 [228]  return join(',',$descendents);
 [229]  }

 [230]  //// SQL INSERT/DELETE [
Top/End]   _database_utilities.php
 [231]  function DB_delete_with_dependents($table,$id,$subtables='') {
 [232]  $id_list = DBD($table,$id); // get list of ids of this record and its dependents
 [233]  if (!$subtables) {
 [234]  if (!is_array($subtables)) $subtables = array($subtables); // to support scalar subtable name
 [235]  foreach ($subtables as $subtable) sql_query("delete from $subtable where {$table}_id in ($id_list)");
 [236]  }
 [237]  sql_query("delete from $table where id in ($id_list)"); // delete from primary table
 [238]  } [
Top/End]   _database_utilities.php
 [239]  function sql_update_or_insert($table,$contents,$condition='') {
 [240]  $names = $values = '';
 [241]  if ($condition && !is_array($contents)) { // plain update
 [242]  $s = "UPDATE $table SET $contents" . sql_condition_phrase($condition);
 [243]  sql_query($s);
 [244]  return $condition;
 [245]  }
 [246]  // contents are a fieldname=>value record
 [247]  foreach ($contents as $name => $value) { // build SQL text for update or insert
 [248]  if ($name !== 'id') { // ignore id fields, which will be auto-incremented to a new value
 [249]  $names .= ",$name";
 [250]  // if ($name === 'updated_at') $value = sql_timestamp_phrase();
 [251]  $value = sq(str_replace('&', '&', $value));
 [252]  if ($condition) $names .= "=$value"; else $values .= ",$value";
 [253]  }
 [254]  }
 [255]  if ($condition) { // update record if condition specified
 [256]  $s = "UPDATE $table SET " . substr($names,1) . sql_condition_phrase($condition);
 [257]  sql_query($s);
 [258]  return $condition;
 [259]  } else { // insert record if no condition specified
 [260]  $s = "INSERT INTO $table (". substr($names,1) . ") VALUES (" . substr($values,1) . ")";
 [261]  sql_query($s);
 [262]  $id = mysqli_insert_id($GLOBALS['database_connection']);
 [263]  return $id;
 [264]  }
 [265]  } [
Top/End]   _database_utilities.php
 [266]  function sql_update($table,$contents,$condition='') {
 [267]  if (is_array($contents)) { // build set list from array keys and values
 [268]  $set = '';
 [269]  foreach ($contents as $name => $value) {
 [270]  if ($name === 'id') {
 [271]  if (!$condition && is_numeric($value)) $condition = $value;
 [272]  } else {
 [273]  if ($name === 'modified_at') $value = $GLOBALS['sql_now'];
 [274]  else $value = sq(str_replace('&', '&', $value));
 [275]  $set .= ",$name=$value";
 [276]  }
 [277]  }
 [278]  $set = substr($set,1);
 [279]  } else $set = $contents; // plain update, already in name='value' form
 [280]  if (!$condition) {error("No update condition specified for 'UPDATE $table SET $set'"); return 0;}
 [281]  sql_query("UPDATE $table SET $set" . sql_condition_phrase($condition));
 [282]  return mysqli_affected_rows($GLOBALS['database_connection']);
 [283]  } [
Top/End]   _database_utilities.php
 [284]  function sql_insert($table,$fields,$sequence_of_values='') {
 [285]  if (!is_array($sequence_of_values)) {
 [286]  $v = func_get_args();
 [287]  $sequence_of_values = array_slice($v,2);
 [288]  }
 [289]  if (!$sequence_of_values) return sql_insert_record($table,$fields);
 [290]  $values = array();
 [291]  for ($i=0; $i<count($sequence_of_values); $i++) {
 [292]  $value = $sequence_of_values[$i];
 [293]  if (!in_array($value,$GLOBALS['sql_unquoted'])) $value = sq($value);
 [294]  $values[] = $value;
 [295]  }
 [296]  $values = join(',',$values);
 [297]  return sql_raw_insert($table,$fields,$values);
 [298]  } [
Top/End]   _database_utilities.php
 [299]  function sql_insert_record($table,$record) {
 [300]  $values = $names = array();
 [301]  foreach ($record as $name=>$value) {
 [302]  if ($name === 'id') continue;
 [303]  $names[] = $name;
 [304]  if (substr($value,1,1)!=='(' || substr($value,1,-1)!==')') $value = sq($value);
 [305]  $values[] = $value;
 [306]  }
 [307]  return sql_raw_insert($table,join(',',$names),join(',',$values));
 [308]  } [
Top/End]   _database_utilities.php
 [309]  function sql_raw_insert($table,$fields,$values) {
 [310]  sql_query("INSERT INTO $table ($fields) VALUES ($values)");
 [311]  return mysqli_insert_id($GLOBALS['database_connection']);
 [312]  } [
Top/End]   _database_utilities.php
 [313]  function sql_delete($table,$condition) {
 [314]  if (!$condition) bailout("Delete condition for $table not specified");
 [315]  sql_query("DELETE FROM $table" . sql_condition_phrase($condition));
 [316]  return mysqli_affected_rows($GLOBALS['database_connection']);
 [317]  } [
Top/End]   _database_utilities.php
 [318]  function sql_backup_copy($table, $id) { // create disabled copy for possible later reversion
 [319]  $record = DBA($table,$id);
 [320]  if (!$record) return 0;
 [321]  $record[parent_id] = $id;
 [322]  unset($record[created_at]);
 [323]  $record[enabled] = FALSE;
 [324]  return sql_update_or_insert($table,$record,0); // return id of copy
 [325]  } [
Top/End]   _database_utilities.php
 [326]  function sql_revert_from_copy($table, $bid) {
 [327]  $backup_record = DBA($table,$bid);
 [328]  if (!$record || array_key_exists(parent_id,$record)) return FALSE;
 [329]  $parent_id = num($record[parent_id]);
 [330]  $current_record = DBA($table,$parent_id);
 [331]  if (!$current_record || !$parent_id) return FALSE;
 [332]  $backup_record[parent_id] = 0;
 [333]  sql_update_or_insert($table,$backup_record,$parent_id);
 [334]  sql_query("delete from $table where parent_id=$parent_id and id>$parent_id");
 [335]  return TRUE;
 [336]  }

 [337]  //// SQL DATETIME HANDLING [
Top/End]   _database_utilities.php
 [338]  function sql_date($date_text) {
 [339]  $d = split("/",$date_text); // slash is standard separator
 [340]  if (count($d) < 2) { // try alternate separator if no slash
 [341]  $d = split("-",$date_text);
 [342]  if (count($d) < 2) return "";
 [343]  }
 [344]  if (count($d) == 2) { // if year not provided, assume nearest year of specified month
 [345]  $d[2] = idate("Y");
 [346]  if ((idate("m") - intval($d[0])) < 0) $d[2]--;
 [347]  if ((idate("m") - intval($d[0])) > 6) $d[2]++;
 [348]  }
 [349]  $d[0] = intval($d[0]); $d[1] = intval($d[1]); $d[2] = intval($d[2]); // force to integer
 [350]  if ($d[0] > 1900) { // convert into [month,day,year] sequence if in [year,month,day] sequence
 [351]  $d[3] = $d[0]; $d[0] = $d[1]; $d[1] = $d[2]; $d[2] = $d[3];
 [352]  }
 [353]  if ($d[2] < 100) $d[2] += ($d[2] < 50) ? 2000 : 1900; // extend two-digit year to four digits
 [354]  return "'{$d[2]}-{$d[0]}-{$d[1]}'"; // return single-quoted year-month-day form
 [355]  } [
Top/End]   _database_utilities.php
 [356]  function short_datetime($sqldate,$format='n/j/y') { // uses m/d/yy format if more than six months ago
 [357]  $h = $m = 0;
 [358]  $i = strpos($sqldate,":");
 [359]  if ($i>1 && $i<strlen($sqldate)) {
 [360]  $h = intval(substr($sqldate,$i-2,1))*10 + intval(substr($sqldate,$i-1,1));
 [361]  $m = intval(substr($sqldate,$i+1,2));
 [362]  }
 [363]  $d = split("-",$sqldate);
 [364]  if (count($d) < 3) return $sqldate; // return unchanged input if SQL-format date not found
 [365]  $time = mktime($h,$m,0,intval($d[1]),intval($d[2]),intval($d[0]));
 [366]  $ago = time() - $time;
 [367]  if (!$format) $format = 'g:i:s a T, l F j Y';
 [368]  elseif ($ago < 64800) $format = "g:i a"; // show only time if in last 18 hours
 [369]  elseif ($ago < 432000) $format = "D H:i"; // show day of week plus time if in last five days
 [370]  elseif ($ago < 16000000) $format = "n/j"; // drop year if in the last six months
 [371]  elseif ($time < 100000) $format = ""; // return blank if time is uninitialized value
 [372]  return date($format,$time);
 [373]  } [
Top/End]   _database_utilities.php
 [374]  function short_fulldatetime($sqldate) {
 [375]  $h = $m = 0;
 [376]  $i = strpos($sqldate,":");
 [377]  if ($i>1 && $i<strlen($sqldate)) {
 [378]  $h = intval(substr($sqldate,$i-2,1))*10 + intval(substr($sqldate,$i-1,1));
 [379]  $m = intval(substr($sqldate,$i+1,2));
 [380]  }
 [381]  $d = split("-",$sqldate);
 [382]  if (count($d) < 3) return $sqldate; // return unchanged input if SQL-format date not found
 [383]  return date("H:i n/j/y",mktime($h,$m,0,intval($d[1]),intval($d[2]),intval($d[0])));
 [384]  } [
Top/End]   _database_utilities.php
 [385]  function sqldatetime_to_timestamp($sqldate) {
 [386]  $h = $m = 0;
 [387]  $i = strpos($sqldate,":");
 [388]  if ($i>1 && $i<strlen($sqldate)) {
 [389]  $h = intval(substr($sqldate,$i-2,1))*10 + intval(substr($sqldate,$i-1,1));
 [390]  $m = intval(substr($sqldate,$i+1,2));
 [391]  }
 [392]  $d = split("-",$sqldate);
 [393]  if (count($d) < 3) return $sqldate; // return unchanged input if SQL-format date not found
 [394]  return mktime($h,$m,0,intval($d[1]),intval($d[2]),intval($d[0]));
 [395]  } [
Top/End]   _database_utilities.php
 [396]  function sql_timestamp_phrase($time) {
 [397]  return "'0'";
 [398]  }

 [399]  //// GENERAL PROPERTIES [
Top/End]   _database_utilities.php
 [400]  function general_property($name) {
 [401]  return DBS('GeneralProperties','property_text','property_name=' . sq($name));
 [402]  } [
Top/End]   _database_utilities.php
 [403]  function set_general_property($name,$value) {
 [404]  if (DBC('GeneralProperties',$where)) update_general_property($name,$value);
 [405]  else sql_query('INSERT GeneralProperties (property_name,property_text) VALUES (' .
 [406]  sq($name) . ',' . sq($value) . ')');
 [407]  } [
Top/End]   _database_utilities.php
 [408]  function update_general_property($name,$value) {
 [409]  sql_query('UPDATE GeneralProperties SET property_text=' . sq($value),' WHERE property_name=' . sq($name));
 [410]  } [
Top/End]   _database_utilities.php
 [411]  function increment_general_property($name,$amount=1) {
 [412]  $where = 'property_name=' . sq($name);
 [413]  $value = DBS('GeneralProperties','property_text',$where);
 [414]  if (is_numeric($amount)) {
 [415]  $value += $amount;
 [416]  sql_query("UPDATE GeneralProperties SET property_text=$value",$where);
 [417]  }
 [418]  return $value;
 [419]  } [
Top/End]   _database_utilities.php
 [420]  function fetch_general_properties($list='') {
 [421]  if ($list) $list = "property_name in (" . implode(',',array_map(sq,csplit($list))) . ")";
 [422]  foreach (DBA('GeneralProperties',$list) as $property)
 [423]  $GLOBALS[$property[property_name]] = $property[property_text];
 [424]  }
 [430]  ?>

FILE: _general_utilities.php - 1958 lines, 300 functions [
Top/End]
  [1]  <?php // use _code_show.php to quickly find routines in this file
  [2]  //// LINKS AND REDIRECTION [
Top/End]   _general_utilities.php
  [3]  function redirect($target='?',$notice='') { // defaults to same page w/o querystring
  [4]  if ($notice) notice($notice);
  [5]  $url = regularize_url($target);
  [6]  if ($url!==sv('redirection_url') || $_POST) { // guard against infinite loop
  [7]  $_SESSION['redirection_url'] = $url;
  [8]  header("Location: $url");
  [9]  exit;
  [10]  } error('Redirection loop detected');
  [11]  } [
Top/End]   _general_utilities.php
  [12]  function redirect_return($target,$page='') {$_SESSION['return_page'] = coalesce($page,$_SERVER['PHP_SELF']); redirect($target);} [
Top/End]   _general_utilities.php
  [13]  function alink($text,$url='',$prefix='') { // internal hyperlink, into same window
  [14]  return hlink($text,$url,$prefix);
  [15]  } [
Top/End]   _general_utilities.php
  [16]  function nlink($text,$url='') { // no-underline link
  [17]  return str_replace('<a ','<a style="text-decoration:none;"',alink($text,$url));
  [18]  } [
Top/End]   _general_utilities.php
  [19]  function plink($text,$url='?') {print alink($text,$url);} [
Top/End]   _general_utilities.php
  [20]  function nav_link($label,$file='') {
  [21]  if (!$file) $file = strtolower($label) . '.php';
  [22]  if (position($_SERVER[SCRIPT_NAME],"$file")) $label = "<b>$label</b>";
  [23]  return (' ' . alink($label,$file));
  [24]  } [
Top/End]   _general_utilities.php
  [25]  function hlink($text,$url='',$prefix='') { // returns HTML for a hyperlink
  [26]  $url = regularize_url(str_replace('~',$text,$url));
  [27]  return "$prefix<a href=\"$url\">$text</a>";
  [28]  } [
Top/End]   _general_utilities.php
  [29]  function target_link($text,$url,$target='') { // hyperlink into separate window
  [30]  if (!$target) $target = $text;
  [31]  $url = regularize_url($url);
  [32]  return ("<a href='$url' target='$target'>$text</a>");
  [33]  } [
Top/End]   _general_utilities.php
  [34]  function relative_path($file='') { // returns a web-relative path (typically including a '../../../' sequence) to local-disk file outside server directory
  [35]  return str_repeat('../',character_frequency(__DIR__,'/')) . after_with($file,'/');
  [36]  } [
Top/End]   _general_utilities.php
  [37]  function file_link($text,$file,$target='_blank') { // hyperlink to file, adjusted to appropriate relative link
  [38]  $target = $target ? " target='$target'" : '';
  [39]  return ("<a href='" . relative_path($file) . "'$target>$text</a>");
  [40]  } [
Top/End]   _general_utilities.php
  [41]  function regularize_url($url='') { // $url -- current page if filename omitted, php if extension omitted
  [42]  $url = trim($url);
  [43]  $a = substr($url,0,1); // first character will be used to detect initial # or ? or ''
  [44]  if ($a!=='/' && $a!=='.' && $a!=='_' && strtolower($a)===strtoupper($a)) $url = $_SERVER['SCRIPT_NAME'].$url; // use current file if none specified
  [45]  $q = strpos($url,'?');
  [46]  $q_amp = strpos($url,'&'); // treat '&' before '?' as equivalent to '?'
  [47]  if ($q===FALSE || ($q_amp!==FALSE && $q_amp<$q)) $q = $q_amp;
  [48]  if ($q === FALSE) $q = strlen($url);
  [49]  $file = substr($url,0,$q);
  [50]  $last_slash = strrpos($file,'/');
  [51]  $dot = $last_slash===FALSE ? strpos($file,'.') : strpos($file,'.',$last_slash);
  [52]  if (($dot === FALSE) && substr($file,-1)!=='/') $file .= '.php';
  [53]  $query = (strlen($url)-$q > 1) ? ('?' . substr($url,$q+1)) : '';
  [54]  return "$file$query";
  [55]  } [
Top/End]   _general_utilities.php
  [56]  function full_url($text='') {
  [57]  $text = regularize_url($text);
  [58]  if ($text) {
  [59]  if (substr($text,0,1)==='/') $text = "$_SERVER[SERVER_NAME]$text";
  [60]  if (position($text,"http://")===FALSE) $text = "http://$text";
  [61]  }
  [62]  return $text;
  [63]  } [
Top/End]   _general_utilities.php
  [64]  function bookmark($text) {return nameletters_underscore($text);}

  [65]  //// FILES [
Top/End]   _general_utilities.php
  [66]  function filename_only($filename='') {return before(filename_base($filename),'.');} // drops directories, extension, querystring [
Top/End]   _general_utilities.php
  [67]  function filename_extension($file) {return after(filename_base($file),'.');} [
Top/End]   _general_utilities.php
  [68]  function directory_only($path='',$immediate=FALSE) { // returns directory portion of supplied (or current-script) path
  [69]  if (!$path) $path = $_SERVER['PHP_SELF'];
  [70]  $i = strrpos(str_replace("\\",'/',$path),'/'); // tolerates backslash separators (and leaves them unchanged)
  [71]  if ($i !== FALSE) {
  [72]  $directory = substr($path,0,$i);
  [73]  if ($immediate) { // if the immediate directory is asked for, drop any higher ones
  [74]  $j = strrpos(str_replace("\\",'/',$directory),'/');
  [75]  if ($j !== FALSE) $directory = substr($directory,$j+1);
  [76]  }
  [77]  } else $directory = '';
  [78]  return $directory;
  [79]  } [
Top/End]   _general_utilities.php
  [80]  function filename_from_text($text,$directory='',$extension='txt') {
  [81]  return ($directory . nameletters_underscore(replace_chars($text,'./#?&=@ ','________')) . ".$extension");
  [82]  } [
Top/End]   _general_utilities.php
  [83]  function filename_base($filename='') { // drops directories and querystring
  [84]  if (!$filename) $filename = $_SERVER['SCRIPT_NAME'];
  [85]  $i = strrpos(str_replace("\\",'/',before($filename,'?')),'/');
  [86]  if ($i !== FALSE) $filename = substr($filename,$i+1);
  [87]  return before($filename,'?');
  [88]  } [
Top/End]   _general_utilities.php
  [89]  function files_with_extensions($pattern='*',$extensions='') {
  [90]  if (!is_array($extensions)) $extensions = csplit(strtolower($extensions));
  [91]  $files_with_extensions = array();
  [92]  foreach (files("$pattern.*") as $file) {
  [93]  if (in_array(strtolower(filename_extension($file)),$extensions)) $files_with_extensions[] = $file;
  [94]  }
  [95]  return $files_with_extensions;
  [96]  } [
Top/End]   _general_utilities.php
  [97]  function filesize_text($file) {
  [98]  if (!file_exists($file)) return '';
  [99]  $size = filesize($file);
 [100]  if ($size >= 1000000) return nf($size/1000000,1) . 'MB';
 [101]  if ($size >= 10000) return nf($size/1000) . 'KB';
 [102]  else return nf($size) . 'B';
 [103]  } [
Top/End]   _general_utilities.php
 [104]  function filesize_large($file) { // not limited to 2GB
 [105]  $fp = fopen($file,'r');
 [106]  if ($fp === FALSE) return FALSE;
 [107]  $size = 0;
 [108]  $step = 1073741824;
 [109]  while ($step > 1) {
 [110]  fseek($fp, $step, SEEK_CUR);
 [111]  if (fgetc($fp) !== FALSE) {fseek($fp, -1, SEEK_CUR); $size += $step;}
 [112]  else {fseek($fp, -$step, SEEK_CUR); $step = (int)($step / 2);}
 [113]  }
 [114]  while (fgetc($fp) !== FALSE) $size++;
 [115]  return $size;
 [116]  } [
Top/End]   _general_utilities.php
 [117]  function files($pattern='*') {$filenames = glob($pattern); return (is_array($filenames) ? $filenames : array());} [
Top/End]   _general_utilities.php
 [118]  function fileset($include_patterns,$omit_patterns=array()) { // returns non-duplicated list of files from patterns
 [119]  $omit = $files = array();
 [120]  foreach (make_array($omit_patterns) as $pattern) {if ($pattern) $omit = array_merge($omit,files($pattern));}
 [121]  foreach (make_array($include_patterns) as $pattern) {
 [122]  foreach (files($pattern) as $file) {
 [123]  if (!in_array($file,$omit) && !in_array($file,$files) && substr($file,0,2)!=='__') $files[] = $file;
 [124]  }
 [125]  }
 [126]  sort($files,5);
 [127]  return $files;
 [128]  } [
Top/End]   _general_utilities.php
 [129]  function first_file($pattern) {$files = files($pattern); return ($files ? $files[0] : '');} [
Top/End]   _general_utilities.php
 [130]  function last_file($pattern) {$files = array_reverse(files($pattern)); return ($files ? $files[0] : '');} [
Top/End]   _general_utilities.php
 [131]  function file_read_contents($filename) { // no-error read
 [132]  if (strpos($filename,'*') !== FALSE) $filename = first_file($filename); // to support filename conventions that allow distinct names for the same purpose
 [133]  return (($filename && file_exists($filename)) ? file_get_contents($filename) : '');
 [134]  } [
Top/End]   _general_utilities.php
 [135]  function file_write_contents($filename,$content_args) {
 [136]  $lastslash = strrpos(before($filename,'?'),'/');
 [137]  $directory = $lastslash===FALSE ? '' : substr($filename,0,$lastslash);
 [138]  if ($directory && !is_dir($directory)) {if (@mkdir("$directory/",0777,TRUE) === FALSE) {error("Directory creation failure: $directory"); return FALSE;}}
 [139]  $fh = @fopen($filename,'w');
 [140]  if ($fh === FALSE) {error("File open failure: $filename"); return FALSE;}
 [141]  if (!is_array($content_args)) $content_args = array_slice(func_get_args(),1);
 [142]  $length = fwrite($fh,array_content($content_args));
 [143]  fclose($fh);
 [144]  return $length;
 [145]  } [
Top/End]   _general_utilities.php
 [146]  function read_url($url,$errormode=false) { // returns server response to supplied URL
 [147]  // $url -- must start with protocol (e.g., "http://") unless local file
 [148]  // $errormode -- if set, errors emit message and end page
 [149]  $page = '';
 [150]  $fh = fopen($url,'r');
 [151]  if (!$fh) {if ($errormode) die($errormode);}
 [152]  else {while (!feof($fh)) $page .= fread($fh,1000000); fclose($fh);}
 [153]  return $page;
 [154]  } [
Top/End]   _general_utilities.php
 [155]  function read_cached_url($url,$timeout=3600) { // get url contents (or cache if $timeout seconds have not passed)
 [156]  if (!begins($url,'http://')) return file_get_contents($url);
 [157]  $filename = filename_from_text($url,'./cached/'); // make cache filename from url
 [158]  $updated = @filemtime($filename);
 [159]  if (!rq1('refresh') && $updated!==FALSE && $updated+$timeout>time()) return file_get_contents($filename); // use cached copy if still fresh
 [160]  $contents = read_url($url); // otherwise read url, write contents to cache, and return contents
 [161]  if ($contents) {file_write_contents($filename,$contents); return $contents;}
 [162]  else return file_get_contents($filename); // unless url cannot be read
 [163]  } [
Top/End]   _general_utilities.php
 [164]  function read_url_table($url,$field_delimiter="\t",$row_delimiter="\n",$errormode=false) {
 [165]  $lines = explode($row_delimiter,read_url($url,$errormode));
 [166]  $table = array();
 [167]  foreach ($lines as $line) $table[] = explode($field_delimiter,$line);
 [168]  return $table;
 [169]  } [
Top/End]   _general_utilities.php
 [170]  function url_get_contents($url) {
 [171]  $url = str_replace('http://','',$url);
 [172]  if (strpos($url,'/') === FALSE) $url = "$url/";
 [173]  $slash = strpos($url,'/');
 [174]  $host = substr($url,0,$slash);
 [175]  $path = substr($url,$slash);
 [176]  $headers = "GET $path HTTP/1.0\r\nUser-Agent: myHttpTool/1.0\r\n\r\n";
 [177]  $fp = fsockopen($host, 80, $errno, $errmsg, 30);
 [178]  if (!$fp) return "SOCKET OPEN ERROR: $errmsg";
 [179]  fwrite($fp, $headers);
 [180]  while(!feof($fp)) $resp .= fgets($fp, 4096);
 [181]  fclose($fp);
 [182]  $heading = before($resp,"\r\n\r\n") . "\r\n";
 [183]  $cookie = trim(between($heading,'Set-Cookie:',';'));
 [184]  $location = trim(between($heading,"\nLocation:","\n"));
 [185]  if ($location) {
 [186]  if (strpos($location,'/') === FALSE) {
 [187]  $slash = strrpos($path,'/');
 [188]  $location = substr($path,0,$slash+1) . $location;
 [189]  }
 [190]  $headers = "GET $location HTTP/1.0\r\nUser-Agent: myHttpTool/1.0";
 [191]  if ($cookie) $headers .= "\r\nCookie: $cookie";
 [192]  $headers .= "\r\n\r\n";
 [193]  $fp = fsockopen($host, 80, $errno, $errmsg, 30);
 [194]  if (!$fp) return "SOCKET REOPEN ERROR: $errmsg";
 [195]  $resp .= "\r\n----------------------$location-------------------\r\n";
 [196]  fwrite($fp, $headers);
 [197]  while(!feof($fp)) $resp .= fgets($fp, 4096);
 [198]  fclose($fp);
 [199]  }
 [200]  return $resp;
 [201]  } [
Top/End]   _general_utilities.php
 [202]  function filename_from_datetime($datetime,$extension='',$prefix='') { // produces output such as "aaa_2010_12_03_0630.xxx"
 [203]  $filename = date('Y_m_d_Hi',$datetime);
 [204]  if ($prefix) $filename = $prefix . "_$filename";
 [205]  if ($extension) $filename .= ".$extension";
 [206]  return $filename;
 [207]  } [
Top/End]   _general_utilities.php
 [208]  function datetime_from_filename($filename) { // uses underscore-delimited text before the first dot, e.g. "aaa_2010_12_25_0630.xxx"
 [209]  $filenameparts = pathinfo($filename);
 [210]  $name = before($filenameparts['basename'],'.');
 [211]  list($time,$day,$month,$year) = array_reverse(explode('_',$name)); // get last four sections of name
 [212]  if (!is_numeric($year) || $year<1970) list($year,$month,$day,$time) = array($month,$day,$time,'0000'); // time-omitted mode
 [213]  $time = substr($time,0,-2) . ':' . substr($time,-2);
 [214]  if (!is_numeric($year) || $year<1970) return -1; // -1 is also the result from strtotime if datetime-parsing fails
 [215]  return strtotime("$year-$month-$day-$time") + 21600;
 [216]  } [
Top/End]   _general_utilities.php
 [217]  function datenamed_files($pattern) { // fetch array using pattern-matching filenames that imply a datetime
 [218]  $files = array();
 [219]  foreach (files($pattern) as $filename) { // make array to sort by implied datetime
 [220]  $datetime = datetime_from_filename($filename);
 [221]  if ($datetime > 0) $files[$filename] = $datetime; // ignore files whose names do not yield a datetime
 [222]  }
 [223]  asort($files); // sort by date, retaining filenames as keys
 [224]  return array_reverse(array_keys($files)); // return filesnames with most recent first
 [225]  } [
Top/End]   _general_utilities.php
 [226]  function datenamedfile_label($filename) {
 [227]  $datetime = datetime_from_filename($filename);
 [228]  if ($datetime <= 0) return $filename; // return full filename if date-parse failure
 [229]  $label = trim(datenamedfile_prefix($filename));
 [230]  if ($label) $label .= ' - ';
 [231]  return ($label . date('H:i D M j Y',$datetime));
 [232]  } [
Top/End]   _general_utilities.php
 [233]  function datenamedfile_prefix($filename) {
 [234]  $lastslash = strrpos($filename,'/');
 [235]  if ($lastslash !== FALSE) $filename = substr($filename,$lastslash+1); // drop directory from label
 [236]  $filename = before($filename,'.'); // drop extension
 [237]  $parts = array_slice(explode('_',$filename),0,-4);
 [238]  return ($parts ? implode(' ',$parts) : '');
 [239]  } [
Top/End]   _general_utilities.php
 [240]  function find_disk_with_file($disks='FGHIJKLMN',$file_list='*') {
 [241]  $search_files = explode(',',$file_list);
 [242]  foreach (str_split($disks) as $disk) {
 [243]  foreach ($search_files as $search_file) {
 [244]  $files = files("$disk:/$search_file");
 [245]  if ($files) return $files[0]; // return existing filename, not the pattern that found it
 [246]  }
 [247]  }
 [248]  return ''; // disk or file not found
 [249]  } [
Top/End]   _general_utilities.php
 [250]  function find_disks($disks='FGHIJKLMN',$exclude='') {
 [251]  $found = array();
 [252]  foreach (str_split($disks) as $disk) {
 [253]  if (!contains($exclude,$disk) && files("$disk:/*")) $found[] = $disk;
 [254]  }
 [255]  return $found;
 [256]  } [
Top/End]   _general_utilities.php
 [257]  function disk_volume_label($drive) {
 [258]  return (preg_match('#Volume in drive [a-zA-Z]* is (.*)\n#i',shell_exec('dir '.$drive.':'),$m) ? ' ('.$m[1].')' : '');
 [259]  } [
Top/End]   _general_utilities.php
 [260]  function browser_detect() {
 [261]  global $browser;
 [262]  if (contains($_SERVER['HTTP_USER_AGENT'],'Firefox')) $browser = 'Firefox';
 [263]  elseif (contains($_SERVER['HTTP_USER_AGENT'],'Edge')) $browser = 'Internet Explorer';
 [264]  elseif (contains($_SERVER['HTTP_USER_AGENT'],'Chrome')) $browser = 'Chrome';
 [265]  elseif (contains($_SERVER['HTTP_USER_AGENT'],'Safari')) $browser = 'Safari';
 [266]  elseif (contains($_SERVER['HTTP_USER_AGENT'],'Trident')) $browser = 'Internet Explorer';
 [267]  elseif (contains($_SERVER['HTTP_USER_AGENT'],'MSIE')) $browser = 'Internet Explorer';
 [268]  else $browser = '';
 [269]  return $browser;
 [270]  } [
Top/End]   _general_utilities.php
 [271]  function browser_reject($reject,$message='some other browser') {
 [272]  global $browser;
 [273]  if (!contains($reject,$browser) || contains($reject,"~$browser")) return; // acceptable browser
 [274]  page_start('');
 [275]  print br("$browser does not support some of the features required for this page.<br>Try $message.",2);
 [276]  page_end('');
 [277]  exit;
 [278]  }

 [279]  //// ARRAYS [
Top/End]   _general_utilities.php
 [280]  function array_element($array,$key=0,$default=NULL) { // returns individual element from array by either key or position
 [281]  if (array_key_exists($key,$array)) return $array[$key]; // simple key lookup used if key exists
 [282]  if (is_numeric($key)) { // if $key is numeric and not an actual key, use as position
 [283]  $elements = array_slice(array_keys($array),$key,1); // note that negative array_slice positions count backwards from the end
 [284]  if ($elements) return $array[$elements[0]];
 [285]  }
 [286]  return $default; // for not-found non-numeric key or out-of-range numeric key
 [287]  } [
Top/End]   _general_utilities.php
 [288]  function array_vector($matrix,$column_key) {
 [289]  $array = array();
 [290]  foreach ($matrix as $row_key => $row) $array[$row_key] = $row[$column_key];
 [291]  return $array;
 [292]  } [
Top/End]   _general_utilities.php
 [293]  function increment_global($name,$key1='~',$key2='~',$key3='~') { // uses name to increment variables with 0 (i.e., scalar), 1, 2, or 3 dimensions, creating them if they don't exist
 [294]  if ($key1 === '~') {if (!isset($GLOBALS[$name])) $value = 1; else $value = $GLOBALS[$name]+1; $GLOBALS[$name] = $value; return $value;} // scalar global
 [295]  if ($key2 === '~') {if (!isset($GLOBALS[$name][$key1])) $value = 1; else $value = $GLOBALS[$name][$key1]+1; $GLOBALS[$name][$key1] = $value; return $value;}
 [296]  if ($key3 === '~') {if (!isset($GLOBALS[$name][$key1][$key2])) $value = 1; else $value = $GLOBALS[$name][$key1][$key2]+1; $GLOBALS[$name][$key1][$key2] = $value; return $value;}
 [297]  if (!isset($GLOBALS[$name][$key1][$key2][$key3])) $value = 1; else $value = $GLOBALS[$name][$key1][$key2][$key3]+1; $GLOBALS[$name][$key1][$key2][$key3] = $value; return $value;
 [298]  } [
Top/End]   _general_utilities.php
 [299]  function global_array_increment($array_name,$key,$increment=1) {
 [300]  $value = (isset($GLOBALS[$array_name]) && array_key_exists($key,$GLOBALS[$array_name])) ? $GLOBALS[$array_name][$key] : 0;
 [301]  $value += $increment;
 [302]  $GLOBALS[$array_name][$key] = $value;
 [303]  return $value;
 [304]  } [
Top/End]   _general_utilities.php
 [305]  function array_width($array2D) {$w = 0; foreach ($array2D as $row) $w = max($w,count($row)); return $w;} [
Top/End]   _general_utilities.php
 [306]  function array_transpose($array2D,$default=NULL) { // transpose array; keys stripped from both dimensions
 [307]  $array = $transposed = array();
 [308]  $width = array_width($array2D);
 [309]  foreach ($array2D as $i=>$row) {
 [310]  while (count($row) < $width) $row[] = $default; // fill out rectangle with default value, if needed
 [311]  foreach ($row as $j=>$item) $transposed[$j][$i] = $item;
 [312]  }
 [313]  return $transposed;
 [314]  }
 [315]  /*function array_column($array2D,$column,$default='') { // returns a 1-D slice with one item or default for each row
 [316]  $slice = array();
 [317]  foreach ($array2D as $key=>$row) $slice[$key] = isset($row[$column]) ? $row[$column] : $default;
 [318]  return $slice;
 [319]  }*/ [
Top/End]   _general_utilities.php
 [320]  function array_columns($array2D,$column,$columns=0,$default=NULL) { // returns slices of columns of a 2-D array
 [321]  $slices = array();
 [322]  if ($columns) { // if positive column-count given, short slices are filled out with the default value
 [323]  $slice = array_slice($array2D,$column,$columns);
 [324]  while (count($slice) < $columns) $slice[] = $default;
 [325]  $slices[] = $slice;
 [326]  } else { // if no column-count given, all columns from the designated one on are returned
 [327]  foreach ($array2D as $key=>$row) $slices[$key] = array_slice($row,$column);
 [328]  }
 [329]  return $slices;
 [330]  } [
Top/End]   _general_utilities.php
 [331]  function array_content($array,$delimiter='') { // concatenates array elements, including nested ones, into a flat list
 [332]  $result = '';
 [333]  foreach($array as $element) {
 [334]  if (!is_array($element)) $result .= "$element$delimiter";
 [335]  else $result .= array_content($element,$delimiter);
 [336]  }
 [337]  return $result;
 [338]  } [
Top/End]   _general_utilities.php
 [339]  function char_array($text) { // split text into array of single-character strings
 [340]  $array = array();
 [341]  for ($i=0; $i<strlen($text); $i++) $array[] = substr($text,$i,1);
 [342]  return $array;
 [343]  } [
Top/End]   _general_utilities.php
 [344]  function gjoin($delimiter,$array,$prefix='',$suffix='') { // general-case safe join
 [345]  return ($prefix . (is_array($array) ? implode($delimiter,$array) : $array) . $suffix);
 [346]  } [
Top/End]   _general_utilities.php
 [347]  function gsplit($delimiter,$text) { // general-case safe split
 [348]  if (is_array($text)) return $text; // respect existing arrays
 [349]  if ($delimiter === '') return char_array($text);
 [350]  $pieces = array();
 [351]  if ($text!=='' && $text!==NULL) {foreach (explode($delimiter,$text) as $piece) $pieces[] = trim($piece);}
 [352]  return $pieces;
 [353]  } [
Top/End]   _general_utilities.php
 [354]  function msplit($delimiters,$text) { // split text with multiple delimiters
 [355]  if (is_array($text)) return $text; // respect existing arrays
 [356]  if (!is_array($delimiters)) $delimiters = char_array($delimiters);
 [357]  if (!$delimiters) return char_array($text);
 [358]  $text = str_replace($delimiters,$delimiters[0],$text);
 [359]  return gsplit($delimiters[0],$text);
 [360]  } [
Top/End]   _general_utilities.php
 [361]  function hsplit($text) { // splits line at one of a heirarchy of delimiters -- tab,semicolon,comma,space
 [362]  foreach (array("\t",';',',',' ') as $delimiter) {if (contains($text,$delimiter)) return gsplit($delimiter,$text);}
 [363]  return array($text);
 [364]  } [
Top/End]   _general_utilities.php
 [365]  function nsplit($text) {return gsplit("\n",$text);} // split text into one-dimentional item-trimmed array at newlines [
Top/End]   _general_utilities.php
 [366]  function njoin($array,$prefix='',$suffix='') {return gjoin("\n",$array,$prefix,$suffix);} [
Top/End]   _general_utilities.php
 [367]  function csplit($text) {return gsplit(',',$text);} // split text into one-dimentional item-trimmed array at commas [
Top/End]   _general_utilities.php
 [368]  function cjoin($array,$prefix='',$suffix='') {return gjoin(',',$array,$prefix,$suffix);} // undoes csplit (except for trim effects) [
Top/End]   _general_utilities.php
 [369]  function tsplit($text) {return gsplit("\t",$text);} // split text into one-dimentional item-trimmed array at tabs [
Top/End]   _general_utilities.php
 [370]  function tjoin($array,$prefix='',$suffix='') {return gjoin("\t",$array,$prefix,$suffix);} // undoes tsplit (except for trim effects) [
Top/End]   _general_utilities.php
 [371]  function wsplit($text,$prefix='',$suffix='') { // split text into one-dimentional item-trimmed array at whitespace
 [372]  if (is_array($text)) return $text; // respect existing arrays
 [373]  $text = str_replace("\n",' ',str_replace("\t",' ',$text));
 [374]  return gsplit(' ',rtrim(squeeze_spaces($text)),$prefix,$suffix);
 [375]  } [
Top/End]   _general_utilities.php
 [376]  function wjoin($array,$prefix='',$suffix='') {return gjoin(' ',$array,$prefix,$suffix);} // undoes wsplit (except for trim/whitespace-replacement effects) [
Top/End]   _general_utilities.php
 [377]  function brjoin($array,$prefix='',$suffix='') {return gjoin("<br>\n",$array,$prefix,$suffix);} [
Top/End]   _general_utilities.php
 [378]  function ssplit($text) { // split text into two-dimensional array using semicolon & comma delimiters
 [379]  $array = array();
 [380]  if (trim($text)) {foreach (gsplit(';',$text) as $subarray) $array[] = csplit($subarray);}
 [381]  return $array;
 [382]  } [
Top/End]   _general_utilities.php
 [383]  function sjoin($array) { // undoes ssplit
 [384]  $rows = array();
 [385]  foreach (make_array($array) as $subarray) $rows[] = cjoin($subarray);
 [386]  return gjoin(';',$rows);
 [387]  } [
Top/End]   _general_utilities.php
 [388]  function ksplit($text) { // split text into key => value array (comma delimiters, colon key:value separators)
 [389]  if (is_array($text)) return $text; // tolerate pre-split arrays
 [390]  $result = array();
 [391]  if ($text) {
 [392]  foreach (csplit($text) as $element) {
 [393]  $colon = strpos($element,':');
 [394]  if ($colon === FALSE) $result[] = trim($element);
 [395]  else $result[trim(substr($element,0,$colon))] = trim(substr($element,$colon+1));
 [396]  }
 [397]  }
 [398]  return $result;
 [399]  } [
Top/End]   _general_utilities.php
 [400]  function kjoin($array) { // undoes ksplit
 [401]  foreach (make_array($array) as $key => $value) $items[] = is_numeric($key) ? $value : "$key:$value";
 [402]  return $items ? cjoin($items) : '';
 [403]  } [
Top/End]   _general_utilities.php
 [404]  function pack_wrap($array,$glue='|') { // make joined string, with glue also before and after
 [405]  $text = $glue; // empty array will cause return of single delimiter
 [406]  foreach ($array as $element) { // build string, replacing imbedded delimiters with \
 [407]  $text .= str_replace($glue,"\\",$element) . $glue;
 [408]  }
 [409]  return $text;
 [410]  } [
Top/End]   _general_utilities.php
 [411]  function unpack_unwrap($text) { // use first char as delimiter to split input w/o first and last char
 [412]  $n = strlen($text);
 [413]  if ($n < 2) return array(); // leading delimiter alone implies empty array
 [414]  $array = explode($text[0],substr($text,1,$n - ($text[0]===$text[$n-1] ? 2 : 1))); // split inside with delimiter
 [415]  foreach ($array as $key => $element) $array[$key] = str_replace("\\",$text[0],$element); // restore imbedded delimiters
 [416]  return $array; // return unpacked array
 [417]  } [
Top/End]   _general_utilities.php
 [418]  function make_array($var) { // force argument to array
 [419]  return (is_array($var) ? $var : (isset($var) ? array($var) : array()));
 [420]  } [
Top/End]   _general_utilities.php
 [421]  function array_concat() { // concatenates first level of array values, treating scalars as single-element arrays
 [422]  $array = array();
 [423]  foreach (func_get_args() as $arg) {
 [424]  if (is_array($arg)) {foreach ($arg as $key=>$element) $array[$key] = $element;}
 [425]  else $array[] = $arg;}
 [426]  return $array;
 [427]  } [
Top/End]   _general_utilities.php
 [428]  function array_table($array) {
 [429]  $string = print_r($array,TRUE);
 [430]  $text = '';
 [431]  $previous = '';
 [432]  foreach (explode("\n",$string) as $line) {
 [433]  $trimmed = trim($line);
 [434]  if (!$trimmed) continue;
 [435]  elseif ($trimmed==='(' && substr($previous,-5)==='Array') $text .= $trimmed;
 [436]  elseif ($trimmed === ')') $text .= $trimmed;
 [437]  else $text .= "\n$line";
 [438]  $previous = trim($line);
 [439]  }
 [440]  $text = substr($text,1); // drop added initial newline
 [441]  $text = str_replace('] => ','=>',$text);
 [442]  $text = htmlspecialchars($text); // escape array content before adding HTML tags
 [443]  $text = str_replace("\n","<br>\n",$text);
 [444]  $text = str_replace(' ','| ',$text);
 [445]  $text = str_replace(' [',' ',$text);
 [446]  return "<table><tr><td>$text</td></tr></table>\n";
 [447]  } [
Top/End]   _general_utilities.php
 [448]  function array_listing($array,$label='ARRAY') {
 [449]  if (!is_array($array)) return '';
 [450]  $t = "\n*** $label (" . count($array) . ") ***\n";
 [451]  foreach ($array as $key => $value) {
 [452]  if (!is_array($value)) $t .= "[$key]: $value {" . strlen($value) . "}\n";
 [453]  else foreach ($value as $k => $v) $t .= "\t[$k]: $v {" . strlen($v) . "}\n";
 [454]  }
 [455]  return $t;
 [456]  } [
Top/End]   _general_utilities.php
 [457]  function string_r($variable) {return print_r($variable,TRUE);} [
Top/End]   _general_utilities.php
 [458]  function directories_recursive($directory) {return array_merge(array($directory),subdirectories_recursive($directory));} [
Top/End]   _general_utilities.php
 [459]  function subdirectories_recursive($directory) {
 [460]  $directories = array();
 [461]  if (substr($directory,-1) === '/') $directory = substr($directory,0,-1);
 [462]  $files = glob("$directory/*");
 [463]  if (!$files) $files = array();
 [464]  foreach ($files as $file) {
 [465]  if (is_dir($file)) {
 [466]  $directories[] = $file;
 [467]  foreach (subdirectories_recursive($file) as $subdir) $directories[] = $subdir;
 [468]  }
 [469]  }
 [470]  asort($directories);
 [471]  return $directories;
 [472]  } [
Top/End]   _general_utilities.php
 [473]  function webroot() {
 [474]  foreach (array('/htdocs/','/public_html/') as $dir) {
 [475]  if (strpos($_SERVER['SCRIPT_FILENAME'],$dir) !== FALSE) return before_with($_SERVER['SCRIPT_FILENAME'],$dir);
 [476]  }
 [477]  error('Failed to find webroot');
 [478]  } [
Top/End]   _general_utilities.php
 [479]  function scattered_array($array,$columns=2) { // distributes array values sequentially among subarrays (for table columns)
 [480]  for ($i=0; $i<$columns; $i++) $output[$i] = array();
 [481]  $i = 0;
 [482]  foreach ($array as $value) $output[($i++)%$columns][] = $value;
 [483]  return $output;
 [484]  } [
Top/End]   _general_utilities.php
 [485]  function chunked_array($array,$preferred=6,$leeway=TRUE) { // splits array into nearly-equal chunks
 [486]  if (!$array) return array();
 [487]  $count = count($array);
 [488]  if ($preferred < 0) $preferred = (int)(($count-1)/(abs($preferred))) + 1; // negative size means to split into that many pieces
 [489]  if ($preferred < 1) $preferred = 1;
 [490]  $chunks = (int) (($count-1) / $preferred) + 1;
 [491]  $chunk = (int) (($count+$chunks-1) / $chunks);
 [492]  if ($leeway && $count%$chunk>0 && $count%$chunk<$chunks) $chunk++;
 [493]  return array_chunk($array,$chunk,TRUE);
 [494]  } [
Top/End]   _general_utilities.php
 [495]  function chunked_string($string,$preferred=80,$delimiters=" \n\r\t") { // breaks string into nearly-equal pieces at delimiters
 [496]  $length = strlen($string);
 [497]  if ($preferred==0 || $preferred>=$length || !$delimiters) return array($string);
 [498]  if ($preferred < 0) $pieces = abs($preferred); // negative preferred size means to split into that many pieces
 [499]  else $pieces = (int) (($length-1) / $preferred) + 1;
 [500]  $search = replace_chars($string,$delimiters,str_repeat(' ',strlen($delimiters))) . ' '; // append space to simplify search
 [501]  $offset = 0;
 [502]  $output = array();
 [503]  for ($piece=0; $piece<$pieces && $offset<$length; $piece++) {
 [504]  $preferred = (int) (($length - $offset) / ($pieces - $piece) + 1); // split remaining string equally
 [505]  if ($offset+$preferred >= $length) $piece_length = $length - $offset;
 [506]  else {
 [507]  $before = strrpos(substr($search,$offset,$preferred),' '); // find last delimiter before or at preferred length
 [508]  $after = strpos(substr($search,$offset + $preferred),' '); // and first delimiter after preferred length
 [509]  $piece_length = ($before!==FALSE && $after<$preferred-$before-1) ? $preferred+$after+1 : $before+1; // break at closest delimiter
 [510]  if (abs($piece_length-$preferred) > $preferred/2) $piece_length = $preferred; // if no delimiter near preferred length, break at preferred length
 [511]  }
 [512]  $output[] = trim(substr($string,$offset,$piece_length));
 [513]  $offset += $piece_length;
 [514]  }
 [515]  trace('count,length for chunked_string output',count($output). ', ' . strlen(implode('',$output)));
 [516]  return $output;
 [517]  } [
Top/End]   _general_utilities.php
 [518]  function folded_string($string,$preferred=80,$glue="<br>\n",$delimiters=" \n\r\t") {
 [519]  return implode($glue,chunked_string($string,$preferred,$delimiters));
 [520]  } [
Top/End]   _general_utilities.php
 [521]  function average($array,$places='') { // averages values in an array, with optional rounding
 [522]  $count = $value = 0;
 [523]  foreach ($array as $item) {if (is_numeric($item)) {$value += $item; $count++;}} // ignores non-numeric elements
 [524]  if ($count) $value = $value / $count;
 [525]  if ($places !== '') $value = round($value,$places);
 [526]  return $value;
 [527]  } [
Top/End]   _general_utilities.php
 [528]  function standard_deviation($array,$population=FALSE) {
 [529]  $mean = average($array);
 [530]  $variance = $count = 0;
 [531]  foreach ($array as $value) {
 [532]  if (!is_numeric($value)) continue; // ignore non-numeric values
 [533]  $variance += ($value-$mean) * ($value-$mean);
 [534]  $count++;
 [535]  }
 [536]  if (!$population) $count--;
 [537]  return ($count>0 ? sqrt($variance/$count) : 0);
 [538]  } [
Top/End]   _general_utilities.php
 [539]  function quartile($array,$quartile=2) {
 [540]  $count = count($array);
 [541]  if (!$count) return FALSE;
 [542]  if ($count == 1) return $array[0];
 [543]  if ($quartile == 2) return median($array);
 [544]  sort($array,SORT_NUMERIC);
 [545]  $half = floor(count($array)/2);
 [546]  return median(array_slice($array,($quartile==3 ? $count-$half : 0),$half),TRUE);
 [547]  } [
Top/End]   _general_utilities.php
 [548]  function median($array,$sorted=FALSE) {
 [549]  $index = (count($array)-1)/2;
 [550]  if ($index < 0) return FALSE;
 [551]  if (!$sorted) sort($array,SORT_NUMERIC);
 [552]  return ($array[floor($index)]+$array[ceil($index)])/2;
 [553]  } [
Top/End]   _general_utilities.php
 [554]  function IQR($array) {return (quartile($array,3)-quartile($array,1));}

 [555]  //// MAIL
 [556]  set_global_if_missing('system_email','site_email_domain','site_email_reply','site_email_reply_address','no_mail_copy'); [
Top/End]   _general_utilities.php
 [557]  function mlink($text='',$address='',$subject='') {
 [558]  if (!$text) {$text = $address; if (!$address) return '';}
 [559]  if (!$address) $address = extract_emails($text);
 [560]  if (is_array($address)) $address = implode(', ',$address);
 [561]  if ($subject) $subject = '?subject=' . h($subject);
 [562]  return "<a href=\"mailto:$address$subject\">$text</a>";
 [563]  } [
Top/End]   _general_utilities.php
 [564]  function mail_link($text,$subject='',$to='',$cc='',$bcc='') {
 [565]  if (!$text) $text = after($GLOBALS['system_email'],'@');
 [566]  return "<a href=\"mailto:?subject=" & urlencode($subject) . url_join('to',$to) . url_join('cc',$cc) . url_join('bcc',$bcc) . "\">$text</a>";
 [567]  } [
Top/End]   _general_utilities.php
 [568]  function url_join($tag,$addresses) {return ($addresses ? "&$tag=" . urlencode(implode(', ',make_array($addresses))) : '');} [
Top/End]   _general_utilities.php
 [569]  function message_field_lines($record,$field_sequence) { // return a message line for each non-blank field specified
 [570]  $text = '';
 [571]  $args = func_get_args();
 [572]  for ($i=1; $i<count($args); $i++) {if ($args[$i]) $text .= $args[$i] . ": " . $record[strtolower($args[$i])] . "\n";}
 [573]  return $text;
 [574]  } [
Top/End]   _general_utilities.php
 [575]  function extract_email($text) {
 [576]  $email_name_letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.';
 [577]  $i = strpos($text,'@');
 [578]  if ($i === FALSE) return '';
 [579]  $a = $b = '';
 [580]  $j = $k = $i;
 [581]  while (--$j >= 0) {$c = substr($text,$j,1); if (strpos($email_name_letters,$c) === FALSE) break; $a = $c . $a;}
 [582]  while ($k++ < strlen($text)) {$c = substr($text,$k,1); if (strpos($email_name_letters,$c) === FALSE) break; $b .= $c;}
 [583]  $i = strpos($b,'.');
 [584]  if (!$a || !$i || (strlen($b)-$i)<3) return '';
 [585]  return "$a@$b";
 [586]  } [
Top/End]   _general_utilities.php
 [587]  function extract_emails($text) {
 [588]  $email_addresses_found = array();
 [589]  $email_name_letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.';
 [590]  do {
 [591]  $i = strpos($text,'@');
 [592]  if ($i === FALSE) return $email_addresses_found;
 [593]  $a = $b = '';
 [594]  $j = $k = $i;
 [595]  while (--$j >= 0) {$c = substr($text,$j,1); if (strpos($email_name_letters,$c) === FALSE) break; $a = $c . $a;}
 [596]  while ($k++ < strlen($text)) {$c = substr($text,$k,1); if (strpos($email_name_letters,$c) === FALSE) break; $b .= $c;}
 [597]  $i = strpos($b,'.');
 [598]  if ($a && $i && (strlen($b)-$i)>2) $email_addresses_found[] = "$a@$b";
 [599]  $text = substr($text,$k);
 [600]  } while ($text);
 [601]  return $email_addresses_found;
 [602]  } [
Top/End]   _general_utilities.php
 [603]  function send_mail($target,$subject,$message,$reply='') {
 [604]  global $site_email_domain,$site_email_reply_domain,$site_email_reply_address,$system_email,$no_mail_copy;
 [605]  if (!$reply && $site_email_reply_address) $reply = $site_email_reply_address;
 [606]  if (!$reply && $site_email_reply_domain) $reply = "mail@$site_email_reply_domain";
 [607]  if (!$reply && $site_email_domain) $reply = "mail@$site_email_domain";
 [608]  $target = extract_email($target);
 [609]  if (!$target) return '';
 [610]  $mail_headers = "From: website@$site_email_domain\r\n";
 [611]  if ($reply) $mail_headers .= "Reply-To: $reply\r\n";
 [612]  $mail_headers .= "X-Mailer: PHP/" . phpversion();
 [613]  $message = stripslashes($message);
 [614]  if ($target!==$system_email && !$no_mail_copy) {
 [615]  $result = mail($system_email, "COPY: $subject", "SENT TO: $target\n\n$message", $mail_headers);
 [616]  if (!result) error("mail failure for $system_email");
 [617]  }
 [618]  $result = mail($target, $subject, $message, $mail_headers);
 [619]  if (!$result) error("mail failure for $target");
 [620]  return $result;
 [621]  } [
Top/End]   _general_utilities.php
 [622]  function site_mail($subject='',$text='',$target='webmaster') {
 [623]  global $site_email_domain,$site_abbr;
 [624]  if (!contains($target,'@')) $target = "$target@$site_email_domain";
 [625]  if (!$text) $text = $target;
 [626]  return mlink($text,$target,"$site_abbr $subject");
 [627]  } [
Top/End]   _general_utilities.php
 [628]  function system_mail($subject,$message) {
 [629]  global $site_abbr,$system_email;
 [630]  return send_mail($system_email,"$site_abbr SYSTEM: $subject",$message);
 [631]  }
 [632]  // INPUT WIDGETS [
Top/End]   _general_utilities.php
 [633]  function textbox($name,$value='~',$size=30,$maxlength='',$class='textbox') { // returns HTML text input widget
 [634]  $value = plain($value);
 [635]  if ($value === '~') $value = rq($name);
 [636]  return textbox_raw($name,h($value),$size,$maxlength,$class);
 [637]  } [
Top/End]   _general_utilities.php
 [638]  function textbox_raw($name,$value='',$size=30,$maxlength='',$class='') {
 [639]  if ($size < 0) $maxlength = $size = abs($size);
 [640]  if ($size === 0) $size = strlen(detab($value));
 [641]  if ($maxlength) $maxlength = " maxlength=$maxlength";
 [642]  if ($class) $class = " class=\"$class\"";
 [643]  return "<input$class type=text name=$name id=$name value=\"$value\" size=$size$maxlength$GLOBALS[onChange]>";
 [644]  } [
Top/End]   _general_utilities.php
 [645]  function filebox($name,$value='~',$size=20,$mimetypes='') { // returns HTML filename input widget
 [646]  $value = plain($value);
 [647]  if ($value === '~') $value = rq($name);
 [648]  return ("<input type=file name=$name id=$name value=\"" . h($value) . "\" size=$size accept=\"$mimetypes\"$GLOBALS[onChange]");
 [649]  } [
Top/End]   _general_utilities.php
 [650]  function passwordbox($name='password',$value='',$size=20) {
 [651]  return ("<input type=password name=\"$name\" size=$size value=\"". h($value) . "\"$GLOBALS[onChange]>");
 [652]  } [
Top/End]   _general_utilities.php
 [653]  function nonexponential($number,$commas=FALSE,$spaces=FALSE) {
 [654]  $n = strtolower($number);
 [655]  $i = strpos($n,'e');
 [656]  if ($i === FALSE) return $number;
 [657]  $m = substr($n,0,$i);
 [658]  $e = num(substr($n,$i+1));
 [659]  if ($e == 0) return $m;
 [660]  $p = strpos($m,'.');
 [661]  if ($p === FALSE) {$w = $m; $d = '';}
 [662]  else {$w = substr($m,0,$p); $d = substr($m,$p+1);}
 [663]  if ($e > 0) { // positive power of 10
 [664]  if (strlen($d) < $e) $d .= str_repeat('0',$e-strlen($d)); // right-zero-pad decimal if needed
 [665]  $w .= substr($d,0,$e); $d = substr($d,$e); // shift first $e digits from decimal to end of whole number
 [666]  } else { // negative power of 10
 [667]  if (strlen($w) < -$e) $w = str_repeat('0',-$e-strlen($w)) . $w; // left-zero-pad whole number if needed
 [668]  $d = substr($w,$e) . $d; $w = substr($w,0,strlen($w)+$e); // shift last |$e| digits from whole number to beginning of decimal
 [669]  }
 [670]  if ($w === '') $w = '0';
 [671]  if ($commas) $w = nf($w);
 [672]  if ($d && $spaces) {
 [673]  $s = substr($d,0,3);
 [674]  if (strlen($d) > 3) {foreach (str_split(substr($d,3),3) as $group) $s .= " $group";}
 [675]  $d = $s;
 [676]  }
 [677]  if (strlen($d)) $d = ".$d";
 [678]  return "$w$d";
 [679]  } [
Top/End]   _general_utilities.php
 [680]  function sizebox($name,$value,$min_length=1,$max_length=0) { // adjusts textbox size so all of content is shown
 [681]  if ($max_length <= 0) $max_length = max(strlen($value),$min_length);
 [682]  $size = min(max($min_length,strlen($value)),$max_length);
 [683]  return textbox($name,"$value",$size);
 [684]  } [
Top/End]   _general_utilities.php
 [685]  function globalbox($name,$min_length=1,$max_length=0) {
 [686]  $value = isset($GLOBALS[$name]) ? $GLOBALS[$name] : rq($name);
 [687]  return sizebox($name,$value,$min_length,$max_length);
 [688]  } [
Top/End]   _general_utilities.php
 [689]  function lbox($name,$min_length=1,$max_length=0) {$label = before($name,'_'); return cbox($name,$label,$min_length);} [
Top/End]   _general_utilities.php
 [690]  function rbox($name,$min_length=1,$max_length=0) {$label = contains($name,'_') ? after_last($name,'_') : $name; return cbox($name,$label,$min_length,$max_length);} [
Top/End]   _general_utilities.php
 [691]  function cbox($name,$label='',$min_length=1,$max_length=0) {
 [692]  if (!$label) $label = $name; $label = str_replace('_',' ',$label); return (" $label=" . globalbox($name,$min_length,$max_length));
 [693]  } [
Top/End]   _general_utilities.php
 [694]  function textarea_head($name,$rows=5,$columns=80,$wrap=FALSE,$extra='',$class='textbox') {
 [695]  return ("<textarea name='$name' id='$name' rows=$rows cols=$columns class='$class' $extra wrap='" . ($wrap ? 'soft' : 'off')) . "'$GLOBALS[onChange]>";
 [696]  } [
Top/End]   _general_utilities.php
 [697]  function textarea($name,$value='',$rows=5,$columns=80,$wrap=TRUE,$extra='') {return textarea_raw($name,h($value),$rows,$columns,$wrap,$extra);} [
Top/End]   _general_utilities.php
 [698]  function textarea_raw($name,$value='',$rows=5,$columns=80,$wrap=FALSE,$extra='') {return (textarea_head($name,$rows,$columns,$wrap,$extra) . $value . "</textarea>\n");} [
Top/End]   _general_utilities.php
 [699]  function check($label) {
 [700]  $name = str_replace(' ','_',$label);
 [701]  return checkbox($name,rq1($name),$label,$label);
 [702]  } [
Top/End]   _general_utilities.php
 [703]  function checkbox($name,$checked='~',$value='~',$label='~') {
 [704]  if ($checked === '~') $checked = rq1($name);
 [705]  if ($value === '~') $value = $name;
 [706]  $label = str_replace('~',$value,$label);
 [707]  return "<label><input type=checkbox name=\"$name\" value=\"" . h($value) ."\"".($checked? ' checked' : '')."$GLOBALS[onChange]><span>$label</span></label> ";
 [708]  } [
Top/End]   _general_utilities.php
 [709]  function checkbox_set($name,$values=array(),$checked='~',$delimiter='<br>',$label='~',$prefix='') {
 [710]  if ($checked === '~') $checked = rq_array($name);
 [711]  $doubletag = strpos($delimiter,'><');
 [712]  if ($doubletag) {$prefix = substr($delimiter,0,$doubletag+1); $delimiter = substr($delimiter,$doubletag+1);}
 [713]  $text = '';
 [714]  foreach ($values as $key => $value) {
 [715]  $check = isset($checked[$key]) ? ' checked' : '';
 [716]  $labeltext = str_replace('~',$value,$label);
 [717]  $text .= " $prefix <label><input type=checkbox name=\"{$name}[$key]\" value=\"" . h($value) . "\"$check$GLOBALS[onChange]>$labeltext</label> $delimiter \n";
 [718]  }
 [719]  return $text;
 [720]  } [
Top/End]   _general_utilities.php
 [721]  function radio($name,$value,$current='~',$label='',$extra='') { // returns enhanced HTML radiobutton widget
 [722]  $current = $current==='~' ? rq($name) : plain($current);
 [723]  $checked = ("$value" === "$current")? ' checked' : '';
 [724]  if ($label === '') $label = $value;
 [725]  if ($extra) $extra = " $extra";
 [726]  $wid = $name . '_' . nameletters_only("$value");
 [727]  return ("<label><input$checked$extra type=radio name=\"$name\" value=\"" . h($value) . "\" id=\"$wid\"$GLOBALS[onChange]>$label</label>\n");
 [728]  } [
Top/End]   _general_utilities.php
 [729]  function radioset($name,$values,$current='',$separator='   ') { // default to horizontal layout
 [730]  if (!is_array($values)) { // support supply of values list in string form
 [731]  $values = ssplit($values); // try a,aa;b,bb;c,cc literal-list convention
 [732]  if (count($values) == 1) $values = $values[0]; // if no semicolons, use a,b,c convention
 [733]  }
 [734]  $widgets = '';
 [735]  foreach ($values as $value) {
 [736]  if (is_array($value)) {$v = $label = $value[0]; if (count($value) > 1) $v = $value[1];}
 [737]  else {$v = $label = $value;}
 [738]  $widgets .= $separator . radio($name,$v,$current,$label);
 [739]  }
 [740]  return substr($widgets,strlen($separator)); // drop leading separator
 [741]  } [
Top/End]   _general_utilities.php
 [742]  function selectset($name,$list,$current,$extra='') {
 [743]  if (!is_array($list)) { // support supply of values list in string form
 [744]  $list = ssplit($list); // try a,aa;b,bb;c,cc literal-list convention
 [745]  if (count($list) == 1) $list = $list[0]; // if no semicolons, use a,b,c convention
 [746]  }
 [747]  $widget = "<select name=\"$name\"$extra$GLOBALS[onChange]>\n";
 [748]  $sequence = 0;
 [749]  foreach ($list as $key => $text) {
 [750]  $selected = ("$current"==="$key" ? " selected" : "");
 [751]  $widget .= "<option value=\"" . h($key) . "\"$selected>$text</option>\n";
 [752]  }
 [753]  return "$widget</select>\n";
 [754]  } [
Top/End]   _general_utilities.php
 [755]  function selectlist($name,$current,$list,$extra='') {
 [756]  if (!is_array($list)) { // support supply of values list in string form
 [757]  $list = ssplit($list); // try a,aa;b,bb;c,cc literal-list convention
 [758]  if (count($list) == 1) $list = $list[0]; // if no semicolons, use a,b,c convention
 [759]  }
 [760]  $widget = "<select name=\"$name\"$extra$GLOBALS[onChange]>\n";
 [761]  $sequence = 0;
 [762]  foreach ($list as $option) {
 [763]  if (is_array($option)) {$value = $text = $option[0]; if (count($option) > 1) $value = $option[1];}
 [764]  else {$text = $option; $value = $sequence++;}
 [765]  $selected = ("$current"==="$value" ? " selected" : "");
 [766]  $widget .= "<option value=\"" . h($value) . "\"$selected>$text</option>\n";
 [767]  }
 [768]  return "$widget</select>\n";
 [769]  } [
Top/End]   _general_utilities.php
 [770]  function selectvalues($name,$current,$list,$extra='') {
 [771]  if (!is_array($list)) { // support supply of values list in string form
 [772]  $list = ssplit($list); // try a,aa;b,bb;c,cc literal-list convention
 [773]  if (count($list) == 1) $list = $list[0]; // if no semicolons, use a,b,c convention
 [774]  }
 [775]  $widget = "<select name=\"$name\"$extra$GLOBALS[onChange]>\n";
 [776]  $sequence = 0;
 [777]  foreach ($list as $option) {
 [778]  if (is_array($option)) {$value = $text = $option[0]; if (count($option) > 1) $value = $option[1];}
 [779]  else $text = $value = $option;
 [780]  $selected = ("$current"==="$value" ? " selected" : "");
 [781]  $widget .= "<option value=\"" . h($value) . "\"$selected>$text</option>\n";
 [782]  }
 [783]  return "$widget</select>\n";
 [784]  } [
Top/End]   _general_utilities.php
 [785]  function commandbutton($label='Submit',$name='command',$style='background-color:lightgreen;font-weight:bold') { // returns HTML text for form-submission button
 [786]  return form_button($label,$style,$name);
 [787]  } [
Top/End]   _general_utilities.php
 [788]  function form_button($label='Submit',$style='background-color:lightgreen;font-weight:bold',$name='command') { // returns HTML text for form-submission button
 [789]  $display = trim(before($label,'|'));
 [790]  $value = strip_tags($display);
 [791]  $disabled = contains(after($label,'|'),'disabled') ? ' disabled' : '';
 [792]  $GLOBALS[$name . '_number'] = num(after($label,'|'));
 [793]  return "<button type='submit' name='$name' value='$value' style='$style'$disabled>$display</button>\n";
 [794]  } [
Top/End]   _general_utilities.php
 [795]  function reset_button($label='Reset',$style='background-color:yellow;') {return "<input type='reset' value='$label' $style='$style'>";} [
Top/End]   _general_utilities.php
 [796]  function hidden($name,$value='~') { // returns HTML for hidden variable
 [797]  if (!is_array($name)) $name = array($name=>$value);
 [798]  $result = '';
 [799]  foreach ($name as $n=>$v) {
 [800]  if ($v === '~') $v = isset($_REQUEST[$n]) ? $_REQUEST[$n] : '';
 [801]  if (!is_array($v)) $result .= "<input type=hidden name=$n value=\"".addslashes($v)."\">\n";
 [802]  else {foreach ($value as $key => $v) $result .= "<input type=hidden name='{$name}[$key]' value=\"".addslashes($v)."\">\n";}
 [803]  }
 [804]  return $result;
 [805]  } [
Top/End]   _general_utilities.php
 [806]  function hidden_alt($name,$value='~') { // returns HTML for hidden variable
 [807]  if ($value === '~') $value = $_REQUEST[$name];
 [808]  if (!is_array($value)) return "<input type=hidden name=$name value=\"$value\">\n";
 [809]  $result = '';
 [810]  foreach ($value as $key => $v) $result .= "<input type=hidden name='{$name}[$key]' value=\"$v\">\n";
 [811]  return $result;
 [812]  } [
Top/End]   _general_utilities.php
 [813]  function hidden_rq() { // returns hidden-field HTML for all request parameters whose names are supplied as arguments
 [814]  for ($i=0,$result=''; $i<func_num_args(); $i++) {$s = func_get_arg($i); $result .= hidden($s);} // value from rq($s)
 [815]  return $result;
 [816]  } [
Top/End]   _general_utilities.php
 [817]  function hidden_globals() { // returns hidden-field HTML for all global variables whose names are supplied as arguments
 [818]  for ($i=0,$result=''; $i<func_num_args(); $i++) {$s = func_get_arg($i); $result .= hidden($s,$GLOBALS[$s]);}
 [819]  return $result;
 [820]  } [
Top/End]   _general_utilities.php
 [821]  function formheader($action='',$name='form1') {
 [822]  if (!$action) $action = $_SERVER['SCRIPT_NAME'];
 [823]  return "<form enctype='multipart/form-data' name='$name' id='$name' method=POST action='$action'>\n";
 [824]  //<form action="$_SERVER[PHP_SELF]" method=POST>
 [825]  } [
Top/End]   _general_utilities.php
 [826]  function entry_text($label,$size=30,$name='',$extra='') {
 [827]  global $record;
 [828]  if (!$name) $name = str_replace(' ','_',strtolower($label));
 [829]  $value = $record[$name] ? $record[$name] : rq($name);
 [830]  return entry_row($label,textbox($name,$record[$name],$size) . $extra);
 [831]  } [
Top/End]   _general_utilities.php
 [832]  function entry_row($label,$widget) { // returns HTML for two-column row with right-justified label
 [833]  return "<tr><td align=right>$label</td><td>$widget<td></tr>\n";
 [834]  } [
Top/End]   _general_utilities.php
 [835]  function print_entry($label,$content='~') {
 [836]  if ($content === '~') {
 [837]  $name = str_replace(' ','_',strtolower($label));
 [838]  $content = rq($name,$GLOBALS['record'][$name]);
 [839]  }
 [840]  if ($content) print "<tr><td align=right><i>$label</td><td>$content</td></tr>\n";
 [841]  return $content;
 [842]  }

 [843]  //// REQUEST, SESSION, and GLOBAL [
Top/End]   _general_utilities.php
 [844]  function register_request($request_parameter_list,$session_tag='') { // reads REQUEST variable and sets corresponding globals
 [845]  $defaults = array(''=>'','?'=>'FALSE','#'=>0);
 [846]  foreach (csplit($request_parameter_list) as $item) { // comma-separated list of parameters
 [847]  $parts = explode('/',$item,2); // optional default value follows /
 [848]  $name = trim($parts[0]);
 [849]  $type = $name ? substr($name,-1) : ''; // # (numeric) or ? (logical) types may be designated by symbol after name
 [850]  if ($type!=='' && array_key_exists($type,$defaults)) $name = trim(substr($name,0,-1)); else $type = ''; // drop type symbol from name
 [851]  if (!$name) continue;
 [852]  $default = count($parts)>1 ? $parts[1] : $defaults[$type];
 [853]  if ($session_tag && isset($_SESSION["$session_tag$name"])) $default = $_SESSION["$session_tag$name"];
 [854]  if ($type === '#') $value = rqf($name,$default);
 [855]  elseif ($type === '?') $value = rq1($name,$default);
 [856]  else $value = rq($name,$default); // no type designated
 [857]  $GLOBALS[$name] = $value;
 [858]  if ($session_tag) $_SESSION["$session_tag$name"] = $value;
 [859]  }
 [860]  } [
Top/End]   _general_utilities.php
 [861]  function posted($name='') {return ($name? isset($_POST[$name]) : count($_POST));} [
Top/End]   _general_utilities.php
 [862]  function rqn($name='id',$default=0) { // integer value from request; commas are tolerated
 [863]  return num(isset($_REQUEST[$name]) ? str_replace(',','',trim($_REQUEST[$name])) : $default);
 [864]  }
 [865]  //function rqf($name='id',$default=0.0,$percent_basis=1) {
 [866]  // foreach (array(rq($name,$default),$default) as $f) {
 [867]  // if (contains($f,'%')) {$f = trim(before($f,'%')); if (is_numeric($f)) {$f = ($f/100)*$percent_basis;}}
 [868]  // if (is_numeric($f)) return (float)$f; // normal return
 [869]  // }
 [870]  // return 0; // will not be reached except when default is not numeric
 [871]  //} [
Top/End]   _general_utilities.php
 [872]  function rqf($name='id',$default=0.0,$percent_basis=1) {
 [873]  $f = rq($name,$default);
 [874]  if (contains($f,'%')) {$f = trim(before($f,'%')); if (is_numeric($f)) {$f = ($f/100)*$percent_basis;}}
 [875]  return (is_numeric($f) ? (float)$f : $default);
 [876]  }
 [877]  //function rq1($name) {return !!rq($name);} // returns clean logical value from request [
Top/End]   _general_utilities.php
 [878]  function rq1($name,$default=FALSE) { // returns clean logical value from request
 [879]  return !!($_POST ? rq($name) : rq($name,$default)); // on posts, absence implies FALSE
 [880]  } [
Top/End]   _general_utilities.php
 [881]  function rq($name='id', $default='', $maxlength='') { // get trimmed value(s) from request (flatten joined with commas if array)
 [882]  $index = between($name,'[',']');
 [883]  $name = before($name,'[');
 [884]  //$value = array_key_exists($name,$_REQUEST) ? substitute_minus(strip_tags($_REQUEST[$name],'<br><p><b><i><sub><sup>')) : $default;
 [885]  $value = strip_tags(rq_raw($name,$default),'<br><p><b><i><sub><sup>');
 [886]  if (is_array($value)) $value = $index==='' ? implode(',',$value) : $value[$index];
 [887]  //$value = str_replace('\\','',$value);
 [888]  if ($maxlength) $value = substr($value,0,$maxlength);
 [889]  return $value;
 [890]  } [
Top/End]   _general_utilities.php
 [891]  function rq_raw($name,$default='') {return (array_key_exists($name,$_REQUEST) ? substitute_minus($_REQUEST[$name]) : $default);} [
Top/End]   _general_utilities.php
 [892]  function rq_array($name='id',$default=array(),$prefix='',$suffix='') { // get posted array of values
 [893]  $array = array();
 [894]  foreach (make_array(array_key_exists($name,$_REQUEST) ? $_REQUEST[$name] : $default) as $key => $value) {
 [895]  //$array[$key] = $prefix . str_replace('\\','',$value) . $suffix;
 [896]  $array[$key] = "$prefix$value$suffix";
 [897]  }
 [898]  return $array;
 [899]  } [
Top/End]   _general_utilities.php
 [900]  function rq_fields($record) { // returns array with values of corresponding $_REQUEST parameters for keys in input record
 [901]  $result = array();
 [902]  foreach ($record as $field => $value) {if (isset($_POST[$field])) $result[$field] = rq($field);}
 [903]  return $result;
 [904]  } [
Top/End]   _general_utilities.php
 [905]  function substitute_minus($text) { // replaces various non-standard minus characters with standard ascii minus
 [906]  if (strpos($text,'&#') !== FALSE) {foreach (array('#1048576','#8208','#8209','#8211','#8722','#65293') as $c) $text = str_replace("&$c;",'-',$text);}
 [907]  return $text;
 [908]  } [
Top/End]   _general_utilities.php
 [909]  function gv($name, $default='') {$value = $GLOBALS[$name]; return ($value? $value : $default);} [
Top/End]   _general_utilities.php
 [910]  function gv_set($name, $value='', $default='') {$old = gv($name,$default); $GLOBAL[$name] = $value; return $old;} [
Top/End]   _general_utilities.php
 [911]  function sv($name, $default='') {return ((isset($_SESSION[$name]) && $_SESSION[$name]) ? $_SESSION[$name] : $default);} [
Top/End]   _general_utilities.php
 [912]  function sv_set($name, $value='', $default='') {$old = sv($name,$default); $_SESSION[$name] = $value; return $old;} [
Top/End]   _general_utilities.php
 [913]  function sv_global($name,$default='',$description='') {
 [914]  if (isset($_REQUEST[$name])) $GLOBALS[$name] = $_SESSION[$name] = $_REQUEST[$name];
 [915]  elseif (!isset($GLOBALS[$name])) $GLOBALS[$name] = $_SESSION[$name] = $default;
 [916]  elseif (!isset($_SESSION[$name])) $_SESSION[$name] = $GLOBALS[$name];
 [917]  else $GLOBALS[$name] = $_SESSION[$name];
 [918]  $GLOBALS['sv_globals'][$name] = $description;
 [919]  return $GLOBALS[$name];
 [920]  } [
Top/End]   _general_utilities.php
 [921]  function set_global_if_missing() {foreach (func_get_args() as $arg) {if (!isset($GLOBALS[$arg])) $GLOBALS[$arg] = '';}} [
Top/End]   _general_utilities.php
 [922]  function set_session_if_missing() {foreach (func_get_args() as $arg) {if (!isset($_SESSION[$arg])) $_SESSION[$arg] = '';}}
 [923]  // LOGIC-DRIVEN PARSING [
Top/End]   _general_utilities.php
 [924]  function tf($test,$if_true='',$if_false='') {
 [925]  if (func_num_args() === 1) $if_true = $test;
 [926]  return ($test ? $if_true : $if_false);
 [927]  } [
Top/End]   _general_utilities.php
 [928]  function wrap_if($text,$prefix='',$suffix='') {return (strlen($text) ? "$prefix$text$suffix" : '');} [
Top/End]   _general_utilities.php
 [929]  function wrap_array($array,$prefix='',$suffix='',$before='',$after='') {
 [930]  return ($array ? "$before$prefix" . implode("$suffix$prefix") . "$suffix$after" : '');
 [931]  } [
Top/End]   _general_utilities.php
 [932]  function more_if($text,$suffix='') {return (strlen($text) ? "$text$suffix" : '');} [
Top/End]   _general_utilities.php
 [933]  function coalesce() { // return first non-FALSE argument from variable-length list
 [934]  $arg = ''; // default return if no arguments
 [935]  foreach (func_get_args() as $item) {if (isset($item) && $item) return $item; if (isset($item)) $arg = $item;}
 [936]  return $arg; // if no arguments that evaluate as true, return last argument or '' if no set arguments
 [937]  } [
Top/End]   _general_utilities.php
 [938]  function choice($index, $value_sequence) { // return indexed value from sequence
 [939]  return ($index<0 || $index>func_num_args()) ? FALSE : func_get_arg($index);
 [940]  }

 [941]  //// STRING PARSING [
Top/End]   _general_utilities.php
 [942]  function concatenate($args) {$text = ''; foreach (func_get_args() as $arg) $text .= "$arg"; return $text;} [
Top/End]   _general_utilities.php
 [943]  function num($value,$default=0) { // forces to integer; tolerates commas, ignores decimal part
 [944]  $value = str_replace(',','',$value);
 [945]  return (is_numeric($value) ? (int)$value : $default);
 [946]  } [
Top/End]   _general_utilities.php
 [947]  function numf($text,$default=0) { // returns numeric value, recognizing percent sign if supplied; default returned if non-numeric
 [948]  if (contains($text,'%')) {$d = 100; $text = trim(before($text,'%'));} else $d = 1;
 [949]  return (is_numeric($text) ? $text/$d : $default);
 [950]  } [
Top/End]   _general_utilities.php
 [951]  function numbers($values,$default=array()) {
 [952]  $numbers = array();
 [953]  if (!is_array($values)) $values = csplit($values);
 [954]  foreach ($values as $value) {
 [955]  if (is_numeric($value)) $numbers[] = (float)$value;
 [956]  else {foreach (number_range(trim($value)) as $number) $numbers[] = $number;}
 [957]  }
 [958]  return $numbers ? $numbers : $default;
 [959]  } [
Top/End]   _general_utilities.php
 [960]  function integers($values,$minimum='',$maximum='',$default=array()) {
 [961]  $integers = array();
 [962]  foreach (numbers($values) as $value) {
 [963]  if ($minimum!=='' && $value<$minimum) continue;
 [964]  if ($maximum!=='' && $value>$maximum) continue;
 [965]  $integers[] = (int)$value;
 [966]  }
 [967]  return $integers ? $integers : $default;
 [968]  } [
Top/End]   _general_utilities.php
 [969]  function number_range($range_specification) {
 [970]  $numbers = array();
 [971]  list($start,$stop,$step) = array_merge(explode(':',$range_specification),array('',''));
 [972]  if (is_numeric($start)) {
 [973]  if (!is_numeric($stop)) $stop = $start;
 [974]  if (!is_numeric($step) || $step==0) $step = 1;
 [975]  $step = abs($step);
 [976]  if ($start <= $stop) {for ($number=$start; $number<=$stop; $number+=$step) $numbers[] = $number;}
 [977]  else {for ($number=$start; $number>=$stop; $number-=$step) $numbers[] = $number;}
 [978]  }
 [979]  return $numbers;
 [980]  } [
Top/End]   _general_utilities.php
 [981]  function longest($lines,$limit=0) { // return the length of the longest of several lines
 [982]  $length = 0;
 [983]  if (!is_array($lines)) $lines = explode("\n",$lines);
 [984]  foreach ($lines as $line) {if (strlen($line) > $length) $length = strlen($line);}
 [985]  if ($limit && $limit<$length) $length = $limit;
 [986]  return $length;
 [987]  } [
Top/End]   _general_utilities.php
 [988]  function title_case($text) {
 [989]  $words = explode(' ',str_replace('_',' ',strtolower($text)));
 [990]  $text = '';
 [991]  foreach ($words as $word) $text .= ' ' . ucfirst($word);
 [992]  return substr($text,1); // drop leading space
 [993]  } [
Top/End]   _general_utilities.php
 [994]  function detab($text,$spacing=8) {
 [995]  $detabbed = '';
 [996]  for ($i = 0; $i < strlen($text); $i++) {
 [997]  if ($text[$i] === "\t") do {$detabbed .= ' ';} while (strlen($detabbed) % $spacing != 0);
 [998]  else $detabbed .= $text[$i];
 [999]  }
[1000]  return $detabbed;
[1001]  } [
Top/End]   _general_utilities.php
[1002]  function squeeze_spaces($text,$convert_tabs=TRUE) {
[1003]  if ($convert_tabs) $text = str_replace("\t",' ',$text);
[1004]  while (strpos($text,' ') !== FALSE) $text = str_replace(' ',' ',$text);
[1005]  if ($convert_tabs === FALSE) { // absorb spaces into adjacent tabs
[1006]  while (strpos($text,"\t ") !== FALSE) str_replace("\t ","\t",$text);
[1007]  while (strpos($text," \t") !== FALSE) str_replace(" \t","\t",$text);
[1008]  } // calling with $convert_tabs='' will leave tabs unchanged
[1009]  return $text;
[1010]  } [
Top/End]   _general_utilities.php
[1011]  function brace($text,$brace='(',$end_brace='') { // wraps non-empty text with symmetric grouping braces
[1012]  if (!trim($text)) return '';
[1013]  if (!$end_brace) {
[1014]  $end_brace = $brace;
[1015]  foreach (array('('=>')','['=>']','{'=>'}','<'=>'>') as $open=>$close) {
[1016]  if (strpos($brace,$open) !== FALSE) {$end_brace = str_replace($open,$close,strrev($brace)); break;}
[1017]  }
[1018]  }
[1019]  return "$brace$text$end_brace";
[1020]  } [
Top/End]   _general_utilities.php
[1021]  function plural($count,$singular,$plural='') { // returns numeric value followed by text with appropriate plural form
[1022]  if (is_array($count)) $count = count($count);
[1023]  return (number_format($count) . ' ' . pluralize($singular,$count,$plural)); // number_format adds commas if appropriate
[1024]  } [
Top/End]   _general_utilities.php
[1025]  function pluralx($count,$prefix,$singular_suffix='',$plural_suffix='s') { // returns numeric value followed by text with appropriate plural form
[1026]  if (is_array($count)) $count = count($count);
[1027]  return (number_format($count) . " $prefix" . pluralize($singular_suffix,$count,$plural_suffix)); // number_format adds commas if appropriate
[1028]  }
[1029]  $irregular_plurals = array('is'=>'are','was'=>'were','has'=>'have','does'=>'do','person'=>'people'); [
Top/End]   _general_utilities.php
[1030]  function pluralize($word,$count=0,$plural='') { // does not change capitalization, handles y-ended and s-ended words
[1031]  if (is_array($count)) $count = count($count);
[1032]  if ($count == 1) return $word;
[1033]  if ($plural) return str_replace('~',$word,$plural);
[1034]  $lastchar = substr($word,-1);
[1035]  if (same($lastchar,'y')) {$word = substr($word,0,-1); $suffix = 'ies';}
[1036]  elseif (same($lastchar,'s')) $suffix = 'es';
[1037]  else $suffix = 's';
[1038]  if ($lastchar === strtoupper($lastchar)) $suffix = strtoupper($suffix);
[1039]  return ($word . $suffix);
[1040]  } [
Top/End]   _general_utilities.php
[1041]  function singularize($word) { // does not change initial-letter capitalization
[1042]  if (substr($word,-3) === 'ses') return (substr($word,0,strlen($word)-2));
[1043]  if (substr($word,-3) === 'ies') return (substr($word,0,strlen($word)-3) . ($word[-4]==strtolower($word[-4]) ? 'y' : 'Y'));
[1044]  if (substr($word,-1) === 's') return (substr($word,0,strlen($word)-1));
[1045]  return $word;
[1046]  } [
Top/End]   _general_utilities.php
[1047]  function limit_text($text,$limit,$more) {
[1048]  if ($limit>0 && strlen($text)>$limit) $text = h(substr($text,0,$limit)) . $more;
[1049]  return ($limit ? $text : ''); // return empty string for zero limit, full string for negative limit
[1050]  } [
Top/End]   _general_utilities.php
[1051]  function unwiki($text) { // adds spaces before all capital letters except the first letter & grouped capitals
[1052]  if (strtoupper($text)===$text || strtolower($text)===$text) return $text;
[1053]  $string = $previous = $output = ' ';
[1054]  $text = str_replace('_',' ',$text);
[1055]  foreach (str_split($text) as $char) {
[1056]  $alpha = ctype_alpha($char);
[1057]  $upper = ($char!==strtolower($char));
[1058]  if ($previous!==' ' && ($upper || (!$alpha && ctype_alpha($previous)))) $string .= ' ';
[1059]  $string .= $char;
[1060]  $previous = $char;
[1061]  }
[1062]  $allcaps = FALSE;
[1063]  foreach (explode(' ',$string) as $word) {
[1064]  if ($word) {
[1065]  if (strtoupper($word)!==$word || !$allcaps) $output .= ' ';
[1066]  $output .= $word;
[1067]  $allcaps = (strtoupper($word) === $word);
[1068]  }
[1069]  }
[1070]  return trim($output);
[1071]  } [
Top/End]   _general_utilities.php
[1072]  function limited($value,$width=0,$lower_bound=0) { // adjust value if needed to stay within range
[1073]  if ($value<$lower_bound) return $lower_bound; // no lower than zero or specified bound
[1074]  if ($width>0 && $value>=$lower_bound+$width) return $lower_bound+$width-1;
[1075]  return $value; // no change if within specified range
[1076]  } [
Top/End]   _general_utilities.php
[1077]  function significant_digits($value,$digits=3) { // limits text from numeric value to specified number of significant digits
[1078]  if (PHP_VERSION > '5.2.1') $digits++; // because in PHP 5 the # in '%e#' format is decimals rather than significant digits
[1079]  if ($digits <= 0) return ($value ? '1' : '0');
[1080]  if ($digits > 9) $digits = 9;
[1081]  $text = sprintf("%e$digits",$value); // let library handle rounding
[1082]  $parts = split($text,'e',2);
[1083]  $mantissa = digits_only($parts[0]); // get digits; drop sign and decimal
[1084]  $exponent = count($parts)>1 ? num($parts[1]) + 1 : 0; // implied decimal point is now before first digit
[1085]  if ($exponent>-6 && $exponent<9) { // replace e-format text if feasible
[1086]  if ($exponent > 0) { // absolute value is one or larger
[1087]  if ($exponent < $digits) { // embedded decimal needed
[1088]  $text = substr($mantissa,0,$exponent) . '.' . substr($mantissa,$exponent);
[1089]  } else { // zero or more appended zeros needed
[1090]  $text = $mantissa . str_repeat('0',$exponent-$digits);
[1091]  }
[1092]  } else { // absolute value is less than one, so prepend leading zeros
[1093]  $text = '0.' . str_repeat('0',-$exponent) . $mantissa;
[1094]  }
[1095]  if ($value<0) $text = "-$text"; // prepend minus sign if needed
[1096]  } // text is left in e-format if number magnitude too big or small
[1097]  return $text;
[1098]  } [
Top/End]   _general_utilities.php
[1099]  function places($number,$places) { // adds trailing zeros if need to match specified place count
[1100]  $number = round($number,$places);
[1101]  $dot = strpos($number,'.');
[1102]  if ($dot === FALSE) return "$number." . str_repeat('0',$places);
[1103]  $already = strlen($number) - $dot - 1;
[1104]  if ($already < $places) $number .= str_repeat('0',$places-$already);
[1105]  elseif ($already > $places) $number = substr($number,0,$places-$already);
[1106]  return $number;
[1107]  } [
Top/End]   _general_utilities.php
[1108]  function drop_zeros($number) {$i = strlen($number); while (--$i>0 && substr($number,$i)==='0') continue; return substr($number,0,$i+1);} [
Top/End]   _general_utilities.php
[1109]  function fieldname_case($text) {return strtolower(str_replace(' ','_',$text));}
[1110]  // HMTL GENERATION [
Top/End]   _general_utilities.php
[1111]  function np($number,$places=0,$digits=0) { // round to longer of specified places and significant digits
[1112]  if ($digits && $number) $places = max($places,$digits-(1+floor(log10(abs($number)))));
[1113]  return sprintf("%0.0{$places}f",$number);
[1114]  } [
Top/End]   _general_utilities.php
[1115]  function nz($number,$places=0,$digits=0) { // like np(), but with zero in one's place for absolute values less than one
[1116]  $result = np($number,$places,$digits);
[1117]  $char0 = substr($result,0,1);
[1118]  if ($char0 === '-') return str_replace('-.','-0.',$result);
[1119]  if ($char0 === '.') return ('0' . $result);
[1120]  return $result;
[1121]  } [
Top/End]   _general_utilities.php
[1122]  function nf($number,$tag='') {
[1123]  $d = is_numeric($tag) ? abs($tag) : 0;
[1124]  $n = number_format(str_replace(',','',trim($number)),$d);
[1125]  if (is_numeric($tag) && $tag<0 && contains($n,'.')) { // drop trailing zeros in decimal
[1126]  while (substr($n,-1) === '0') $n = substr($n,0,-1);
[1127]  }
[1128]  if (substr($n,-1) === '.') $n = substr($n,0,-1); // drop tailing decimal point
[1129]  if (!is_numeric($tag) && $tag) $n = "<$tag>$n</$tag>";
[1130]  return $n;
[1131]  } [
Top/End]   _general_utilities.php
[1132]  function nfc($number,$tag='') { // rounded number with commas separating thousands
[1133]  $d = is_numeric($tag) ? abs($tag) : 0;
[1134]  $n = round(str_replace(',','',trim($number)),$d);
[1135]  if (is_numeric($tag) && $tag<0 && contains($n,'.')) { // drop trailing zeros in decimal
[1136]  while (substr($n,-1) === '0') $n = substr($n,0,-1);
[1137]  }
[1138]  if (substr($n,-1) === '.') $n = substr($n,0,-1); // drop any tailing decimal point
[1139]  $i = before(abs($n),'.'); // get integer string so that commas can be inserted
[1140]  $n = after_with($n,'.'); // already-rounded decimal part, if any
[1141]  while (strlen($i) > 3) {$n = ',' . substr($i,-3) . $n; $i = substr($i,0,-3);}
[1142]  $n = "$i$n"; // prepend remaining digits
[1143]  if ($number < 0) $n = "-$n"; // prepend minus sign if appropriate
[1144]  if (!is_numeric($tag) && $tag) $n = "<$tag>$n</$tag>";
[1145]  return $n;
[1146]  } [
Top/End]   _general_utilities.php
[1147]  function h($text) {
[1148]  if (is_null($text)) $text = '';
[1149]  return htmlspecialchars($text,ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5,'UTF-8',FALSE);
[1150]  //return htmlentities($text,ENT_QUOTES || ENT_DISALLOWED || ENT_HTML5,'UTF-8',FALSE);
[1151]  } [
Top/End]   _general_utilities.php
[1152]  function plain($text='') {return is_null($text)? '': "$text";} [
Top/End]   _general_utilities.php
[1153]  function nbsp($text) {return str_replace(' ',' ',$text);} [
Top/End]   _general_utilities.php
[1154]  function spaces($spaces) {return ($spaces > 0 ? str_repeat(' ',$spaces) : '');} [
Top/End]   _general_utilities.php
[1155]  function nospace($text) {return str_replace(' ','',$text);} [
Top/End]   _general_utilities.php
[1156]  function no_nbsp($text,$replacement='') {return str_replace(' ',$replacement,$text);} [
Top/End]   _general_utilities.php
[1157]  function br($text='',$before=0,$after=1) {
[1158]  if (!is_numeric($before) || !is_numeric($after)) {error("br($text,$before,$after)"); return "$text<br>\n";}
[1159]  return (str_repeat('<br>',$before) . $text . str_repeat('<br>',$after) . "\n");
[1160]  } [
Top/End]   _general_utilities.php
[1161]  function tag($tag,$text='',$test=TRUE) {return $test ? wrap($text,"<$tag>") : $text;} [
Top/End]   _general_utilities.php
[1162]  function bold($text,$test=TRUE) {return tag('b',$text,$test);} [
Top/End]   _general_utilities.php
[1163]  function italic($text,$test=TRUE) {return tag('i',$text,$test);} [
Top/End]   _general_utilities.php
[1164]  function big($text,$test=TRUE) {return tag('big',$text,$test);} [
Top/End]   _general_utilities.php
[1165]  function small($text,$test=TRUE) {return tag('small',$text,$test);} [
Top/End]   _general_utilities.php
[1166]  function span($text,$class,$test=TRUE) {return tag("span class=$class",$text,$test);} [
Top/End]   _general_utilities.php
[1167]  function overline($text) {return "<span style=\"text-decoration: overline;\">$text</span>";} [
Top/End]   _general_utilities.php
[1168]  function bar($letter,$pixels=5) {return $letter . "<span style='position:relative;left:-{$pixels}px'>̅</span>";} [
Top/End]   _general_utilities.php
[1169]  function hat($letter,$left=-5,$top=2) {return $letter . "<span style='position:relative;left:{$left}px;top:{$top}px'>̂</span>";} [
Top/End]   _general_utilities.php
[1170]  function colored($text,$color='yellow',$test=TRUE) {
[1171]  if (contains($color,'bold') && $test) $text = bold($text);
[1172]  $color = str_replace('bold','',$color);
[1173]  $color = trim(str_replace('bold','',str_replace('italic','',$color)));
[1174]  return ($color ? tag("span style='color:$color'",$text,$test) : $text);
[1175]  } [
Top/End]   _general_utilities.php
[1176]  function plus($value) {return ($value>0 ? "+$value" : $value);} [
Top/End]   _general_utilities.php
[1177]  function signed($value,$plus='+',$minus='–') {
[1178]  $sign = $plus;
[1179]  if (contains($value,'-')) {$sign = $minus; $value = after($value,'-');}
[1180]  elseif (contains($value,'+')) $value = after($value,'+');
[1181]  return ($sign . trim($value));
[1182]  } [
Top/End]   _general_utilities.php
[1183]  function sub($text,$levels=2) {while ($levels-- > 0) {$text = "<sub>$text</sub>";} return $text;} [
Top/End]   _general_utilities.php
[1184]  function sup($text,$levels=1) {while ($levels-- > 0) {$text = "<sup>$text</sup>";} return $text;} [
Top/End]   _general_utilities.php
[1185]  function br_list($heading,$array,$indent=0) {
[1186]  if (!$array) return '';
[1187]  $delim = "\n<br>" . spaces($indent);
[1188]  return ("$heading$delim" . implode($delim,$array));
[1189]  } [
Top/End]   _general_utilities.php
[1190]  function p($text=' ',$padding=3,$margin=0) {return "<p style='padding: {$padding}pt {$margin}pt;'>$text</p>\n";} [
Top/End]   _general_utilities.php
[1191]  function pc($text='',$padding=3) {return "<p align=center style='padding: {$padding}pt;'>$text</p>\n";} [
Top/End]   _general_utilities.php
[1192]  function titled($text,$title,$tag='span') {
[1193]  return ($title ? "<$tag title=\"" . str_replace('"','"',$title) . "\">$text</$tag>" : $text);
[1194]  } [
Top/End]   _general_utilities.php
[1195]  function titled_if_long($text,$truncate_length=20,$nbsp=FALSE) {
[1196]  $title = $text;
[1197]  if (strlen($text) <= abs($truncate_length)) $title = '';
[1198]  else $text = $truncate_length>0 ? (substr($text,0,max(1,$truncate_length-3)) . '...') : ('...' . substr($text,$truncate_length+3));
[1199]  if ($nbsp) $text = nbsp($text);
[1200]  return titled($text,$title);
[1201]  } [
Top/End]   _general_utilities.php
[1202]  function wrap($valuearray,$prefix,$suffix='',$preamble='',$postscript='',$test=TRUE) { // wrap scalar or array with text
[1203]  if (!$suffix) { // wrap in prefix if suffix omitted
[1204]  $suffix = $prefix;
[1205]  // if suffix omitted for tag prefix, use appropriate closing tag as suffix
[1206]  $i = position($prefix,'<');
[1207]  $j = position($prefix,'>');
[1208]  if ($i!==FALSE && $j!==FALSE && $i<$j) {
[1209]  $k = position($prefix,' ');
[1210]  if ($k!==FALSE && $k<$j) $suffix = substr($suffix,0,$k) . substr($suffix,$j); // drop tag parameters
[1211]  $suffix = substr($suffix,0,$i+1) . '/' . substr($suffix,$i+1); // insert slash close character
[1212]  }
[1213]  }
[1214]  $a = '';
[1215]  if ($test) {
[1216]  if (is_array($valuearray)) foreach ($valuearray as $value) $a .= $prefix . $value . $suffix;
[1217]  else $a = $prefix . $valuearray . $suffix; // scalar value is treated as if single-element array
[1218]  }
[1219]  return ($preamble . $a . $postscript);
[1220]  } [
Top/End]   _general_utilities.php
[1221]  function paragraph($text,$class='paragraph',$delimiter="\n") {
[1222]  $p = $class ? "<p class=$class>" : "<p>";
[1223]  if (contains($class,'=')) $p = "<p $class>"; // to support direct style declarations
[1224]  $output = '';
[1225]  foreach (explode($delimiter,str_replace("\r",'',$text)) as $line) {
[1226]  $output .= $p . str_replace(' ','  ',str_replace("\n",' ',str_replace(" \n",' ',trim($line)))) . "</p>\n";
[1227]  }
[1228]  return $output;
[1229]  } [
Top/End]   _general_utilities.php
[1230]  function paragraphed($text) {
[1231]  $output = '';
[1232]  foreach (explode("\n",str_replace("\r",'',$text)) as $line) {
[1233]  $line = str_replace(' ','  ',trim($line));
[1234]  if ($line) $output .= "     $line<br>\n";
[1235]  }
[1236]  return $output;
[1237]  } [
Top/End]   _general_utilities.php
[1238]  function courier($text) {return "<span style='font-family:Courier;'>$text</span>";} [
Top/End]   _general_utilities.php
[1239]  function font($text,$font='Courier') {return "<span style='font-family:$font;'>$text</span>";} [
Top/End]   _general_utilities.php
[1240]  function fraction_table($numerator,$denominator,$font='Courier') { // return a zero-padding table to display a fraction
[1241]  return font(table("cellpadding=0",tr(tdc("<span style='vertical-align:bottom;'>$numerator</span>","style='border-bottom-style:solid;'")),
[1242]  tr(tdc("<span style='vertical-align:top'>$denominator</span>"))),$font);
[1243]  }

[1244]  //// CASE-INSENSITIVE FIND & COMPARE [
Top/End]   _general_utilities.php
[1245]  function position($haystack,$needle,$offset=0) {
[1246]  if ("$needle"==='' || "$haystack"==='') return FALSE;
[1247]  return stripos($haystack,$needle,$offset);
[1248]  } [
Top/End]   _general_utilities.php
[1249]  function last_position($haystack,$needle,$offset=0) {
[1250]  if ("$needle"==='' || "$haystack"==='') return FALSE;
[1251]  return strrpos(strtolower($haystack),strtolower($needle),$offset);
[1252]  } [
Top/End]   _general_utilities.php
[1253]  function same($firststring,$secondstring) { // any additional arguments are also checked, returns TRUE if any match
[1254]  $firststring = strtolower("$firststring");
[1255]  if (!is_array($secondstring)) $secondstring = array_slice(func_get_args(),1);
[1256]  foreach ($secondstring as $string) {if (strtolower("$string") === $firststring) return TRUE;}
[1257]  return FALSE;
[1258]  } [
Top/End]   _general_utilities.php
[1259]  function contains($haystack,$needle,$offset=0) {
[1260]  if ("$needle"==='' || "$haystack"==='') return FALSE;
[1261]  return (position($haystack,$needle,$offset) !== FALSE);
[1262]  } [
Top/End]   _general_utilities.php
[1263]  function begins($full,$start,$offset=0) {
[1264]  if ("$full"==='' || "$start"==='') return FALSE;
[1265]  return (position($full,$start,$offset) === 0);
[1266]  }
[1267]  // SUBSTRING EXTRACTION [
Top/End]   _general_utilities.php
[1268]  function phrase($text,$offset=0,$length=FALSE) {return implode(' ',words($text,$offset,$length));} [
Top/End]   _general_utilities.php
[1269]  function words($text,$offset=0,$length=FALSE) {
[1270]  $words = explode(' ',trim("$text"));
[1271]  return ($length!==FALSE ? array_slice($words,$offset,$length) : array_slice($words,$offset));
[1272]  } [
Top/End]   _general_utilities.php
[1273]  function before($text,$match,$prefix='') { // drops text after match if found
[1274]  // $text -- the string from which the substring is to be extracted
[1275]  // $match -- the search substring
[1276]  if ("$match"==='' || "$text"==='') return '';
[1277]  $j = position($text,$match);
[1278]  if ($j !== FALSE) {
[1279]  $text = substr($text,0,$j);
[1280]  if ($prefix !== '') {
[1281]  $i = last_position($text,$prefix);
[1282]  if ($i !== FALSE) $text = substr($text,$i+1);
[1283]  }
[1284]  }
[1285]  return $text;
[1286]  } [
Top/End]   _general_utilities.php
[1287]  function before_with($text,$match,$prefix='') { // drops text after match if found
[1288]  // $text -- the string from which the substring is to be extracted
[1289]  // $match -- the search substring
[1290]  if ("$match"==='' || "$text"==='') return '';
[1291]  $j = position($text,$match);
[1292]  if ($j !== FALSE) {
[1293]  $text = substr($text,0,$j+strlen($match));
[1294]  if ($prefix !== '') {
[1295]  $i = last_position($text,$prefix);
[1296]  if ($i !== FALSE) $text = substr($text,$i+1);
[1297]  }
[1298]  }
[1299]  return $text;
[1300]  } [
Top/End]   _general_utilities.php
[1301]  function before_last($text,$match,$prefix='') {
[1302]  $j = last_position($text,$match);
[1303]  if ($j === FALSE) return $text;
[1304]  $i = 0;
[1305]  if ($prefix !== '') {
[1306]  $k = last_position(substr($text,0,$i),$prefix);
[1307]  if ($k !== FALSE) $i = $k;
[1308]  }
[1309]  return substr($text,$i,$j-$i);
[1310]  } [
Top/End]   _general_utilities.php
[1311]  function after($text,$match,$suffix='') { // returns the first substring, if any, after the match (but before the optional suffix)
[1312]  // $text -- the string from which the substring is to be extracted
[1313]  // $match -- the search substring; $text after the first instance of $match will be returned
[1314]  // $suffix -- if a match is found, returned text after and including the next instance of $suffix is dropped
[1315]  $text = after_with($text,$match,$suffix);
[1316]  if ($text !== '') $text = substr($text,strlen($match)); // drop match from returned string
[1317]  return $text;
[1318]  } [
Top/End]   _general_utilities.php
[1319]  function after_with($text,$match,$suffix='') { // drops text until match is found
[1320]  // $text -- the string from which the substring is to be extracted
[1321]  // $match -- the search substring
[1322]  // $suffix -- if a match is found, returned text after the next instance of $suffix is dropped
[1323]  if ("$text"==='' || "$match"==='') return '';
[1324]  $i = position($text,$match);
[1325]  if ($i === FALSE) return '';
[1326]  $j = strlen($text);
[1327]  if ($suffix !== '') {
[1328]  $k = position($text,$suffix,$i);
[1329]  if ($k !== FALSE) $j = $k;
[1330]  }
[1331]  return substr($text,$i,$j-$i);
[1332]  } [
Top/End]   _general_utilities.php
[1333]  function after_last($text,$match,$suffix='') {
[1334]  $i = last_position($text,$match);
[1335]  if ($i === FALSE) return '';
[1336]  $i += strlen($match); // space past match
[1337]  $j = strlen($text);
[1338]  if ($suffix !== ''){
[1339]  $k = position($text,$suffix,$i);
[1340]  if ($k !== FALSE) $j = $k;
[1341]  }
[1342]  return substr($text,$i,$j-$i);
[1343]  } [
Top/End]   _general_utilities.php
[1344]  function around($text,$match,$prefix='',$suffix='') { // searches outward from match
[1345]  // $text -- the string from which the substring is to be extracted
[1346]  // $match -- the search substring; $text around the first instance of $match will be returned
[1347]  // $prefix -- limits the returned text before the match to that after the closest previous instance of the prefix
[1348]  // $suffix -- limits the returned text after the match to that before the next instance of the suffix
[1349]  $text = around_with($text,$match,$prefix,$suffix);
[1350]  if ($text !== '') $text = substr($text,strlen($prefix),-strlen($suffix)); // prefix and suffix are not part of returned text
[1351]  return $text;
[1352]  } [
Top/End]   _general_utilities.php
[1353]  function around_with($text,$match,$prefix='',$suffix='') { // searches outward from match
[1354]  // $text -- the string from which the substring is to be extracted
[1355]  // $match -- the search substring; $text around the first instance of $match will be returned
[1356]  // $prefix -- drops text before the closest previous instance of the prefix
[1357]  // $suffix -- drops text after the next instance of the suffix
[1358]  if ("$text"==='' || "$match"==='' || "$prefix"==='' || "$suffix"==='') return '';
[1359]  $i = position($text,$prefix);
[1360]  if ($i === FALSE) return '';
[1361]  $m = position($text,$match,$i);
[1362]  if ($m === FALSE) return '';
[1363]  // matched text is included in search for prefix or suffix
[1364]  $i += last_position(substr($text,$i,$m-$i+strlen($match)),$prefix); // find closer prefix if possible
[1365]  $j = position($text,$suffix,$m);
[1366]  if ($j === FALSE) return '';
[1367]  return substr($text,$i,$j-$i+strlen($suffix)); // prefix and suffix included in returned text
[1368]  } [
Top/End]   _general_utilities.php
[1369]  function arounds($text,$match,$prefix,$suffix,$limit=1000) { // extracts array of substrings around successive matches
[1370]  // $text -- the string from which the substring is to be extracted
[1371]  // $match -- the search substring; text around instances of $match will be returned
[1372]  // $prefix -- drops text before the closest previous instance of the prefix
[1373]  // $suffix -- drops text after the next instance of the suffix
[1374]  // $limit -- maximum number of substrings to return
[1375]  $items = array();
[1376]  if ("$text"!=='' && "$match"!=='' && "$prefix"!=='' && "$suffix"!=='') { // avoid null-string ambiguities
[1377]  $text_lower = strtolower($text);
[1378]  $match = strtolower($match);
[1379]  $prefix = strtolower($prefix);
[1380]  $suffix = strtolower($suffix);
[1381]  $n = strlen($text);
[1382]  $c = strlen($match);
[1383]  $b = strlen($prefix);
[1384]  $a = strlen($suffix);
[1385]  $offset = 0;
[1386]  while ($limit-- && $offset<$n) {
[1387]  $m = strpos($text_lower,$match,$offset);
[1388]  if ($m === FALSE) break;
[1389]  $i = strrpos(substr($text_lower,$offset,$m-$offset),$prefix); // find prefix before match
[1390]  if ($i === FALSE) break;
[1391]  $i += $offset + $b; // adjust index for substring used in strrpos, and for prefix length
[1392]  $j = strpos($text_lower,$suffix,$m+$c); // find suffix after match
[1393]  if ($j === FALSE) break;
[1394]  $items[] = substr($text,$i,$j-$i); // extract contained text segment for list
[1395]  $offset = $j + $a; // move offset to after this suffix
[1396]  }
[1397]  }
[1398]  return $items;
[1399]  } [
Top/End]   _general_utilities.php
[1400]  function drop_before($text,$match) { // drops text until match is found
[1401]  // $text -- the string from which the substring is to be extracted
[1402]  // $match -- the search substring
[1403]  $i = position($text,$match);
[1404]  if ($i === FALSE) return '';
[1405]  return substr($text,$i);
[1406]  } [
Top/End]   _general_utilities.php
[1407]  function drop_after($text,$match) { // drops text after match if found
[1408]  // $text -- the string from which the substring is to be extracted
[1409]  // $match -- the search substring
[1410]  $i = position($text,$match);
[1411]  if ($i === FALSE) return $text;
[1412]  return substr($text,0,$i+strlen($match));
[1413]  } [
Top/End]   _general_utilities.php
[1414]  function keep_before($text,$match) { // keeps text until match is found
[1415]  // $text -- the string from which the substring is to be extracted
[1416]  // $match -- the search substring
[1417]  $i = position($text,$match);
[1418]  if ($i === FALSE) return $text;
[1419]  return substr($text,0,$i);
[1420]  } [
Top/End]   _general_utilities.php
[1421]  function keep_after($text,$match) { // keeps text after match if found
[1422]  // $text -- the string from which the substring is to be extracted
[1423]  // $match -- the search substring
[1424]  $i = position($text,$match);
[1425]  if ($i === FALSE) return '';
[1426]  return substr($text,$i+strlen($match));
[1427]  } [
Top/End]   _general_utilities.php
[1428]  function between($text,$before,$after,$offset=0) {
[1429]  // extracts text between $before and $after strings, exclusive, starting $offset characters deep
[1430]  // $text -- the string from which the substring is to be extracted
[1431]  // $before -- the first search substring
[1432]  // $after -- the second substring
[1433]  // $offset -- where to start in $text
[1434]  $text = between_with($text,$before,$after,$offset);
[1435]  if ($text) $text = substr($text,strlen($before),-strlen($after));
[1436]  return $text;
[1437]  } [
Top/End]   _general_utilities.php
[1438]  function between_with($text,$before,$after,$offset=0) {
[1439]  // extracts text between $before and $after strings, inclusive, starting $offset characters deep
[1440]  // $text -- the string from which the substring is to be extracted
[1441]  // $before -- the first search substring
[1442]  // $after -- the second substring
[1443]  // $offset -- where to start in $text
[1444]  if ("$text"==='' || "$before"==='' || "$after"==='') return '';
[1445]  $text_lower = strtolower($text);
[1446]  $i = strpos($text_lower,strtolower($before),$offset);
[1447]  if ($i === FALSE) return '';
[1448]  $j = strpos($text_lower,strtolower($after),$i+strlen($before));
[1449]  if ($j === FALSE) return '';
[1450]  $i += strrpos(substr($text_lower,$i,$j-$i),strtolower($before)); // in case another 'before' match is closer to 'after' match
[1451]  return substr($text,$i,$j-$i+strlen($after));
[1452]  } [
Top/End]   _general_utilities.php
[1453]  function betweens($text,$before,$after,$limit=1000) { // extracts array of substrings between successive $before/$after pairs
[1454]  // $text -- the string from which the substring is to be extracted
[1455]  // $before -- the first search substring
[1456]  // $after -- the second substring
[1457]  // $limit -- maximum number of substrings to return
[1458]  $items = array();
[1459]  if ("$text"!=='' && "$before"!=='' && "$after"!=='') { // avoid null-string ambiguities
[1460]  $text_lower = strtolower($text);
[1461]  $before = strtolower($before);
[1462]  $after = strtolower($after);
[1463]  $offset = 0;
[1464]  while ($limit-- && $offset<strlen($text)) {
[1465]  $i = strpos($text_lower,$before,$offset);
[1466]  if ($i === FALSE) break;
[1467]  $j = strpos($text_lower,$after,$i+strlen($before)); // find next "after" tag
[1468]  if ($j === FALSE) break;
[1469]  $i += strrpos(substr($text_lower,$i,$j-$i),$before) + strlen($before); // move past last 'before' before 'after'
[1470]  $items[] = substr($text,$i,$j-$i); // extract contained text segment for item list
[1471]  $offset = $j + strlen($after); // move offset to after this "after" tag
[1472]  }
[1473]  }
[1474]  return $items;
[1475]  }

[1476]  //// STRING FILTERS
[1477]  $name_letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_'; [
Top/End]   _general_utilities.php
[1478]  function specific_characters_only($text,$listnames) {
[1479]  $lists = array();
[1480]  foreach (array_slice(func_get_args(),1) as $list) {
[1481]  if (strtoupper($list)!==strtolower($list) && isset($GLOBALS[$list])) $list = $GLOBALS[$list];
[1482]  if ($list !== '') $lists[] = $list;
[1483]  }
[1484]  $output = '';
[1485]  foreach (str_split($text) as $c) {
[1486]  foreach ($lists as $list) {
[1487]  if ($c!=='' && strpos($list,$c)!==FALSE) {
[1488]  $output .= $c; break;
[1489]  }
[1490]  }
[1491]  };
[1492]  return $output;
[1493]  } [
Top/End]   _general_utilities.php
[1494]  function digits_only($text) {$n = ''; foreach (str_split($text) as $c) {if (ctype_digit($c)) $n .= $c;} return $n;} [
Top/End]   _general_utilities.php
[1495]  function letters_only($text) {$a = ''; foreach (str_split($text) as $c) {if (ctype_alpha($c)) $a .= $c;} return $a;} [
Top/End]   _general_utilities.php
[1496]  function letters_and_spaces_only($text) {$a = ''; foreach (str_split($text) as $c) {if (ctype_alpha($c) || $c===' ') $a .= $c;} return $a;} [
Top/End]   _general_utilities.php
[1497]  function alphanumeric_only($text) {$a = ''; foreach (str_split($text) as $c) {if (ctype_alnum($c)) $a .= $c;} return $a;} [
Top/End]   _general_utilities.php
[1498]  function alphanumeric_and_spaces_only($text) {$a = ''; foreach (str_split($text) as $c) {if (ctype_alnum($c) || $c===' ') $a .= $c;} return $a;} [
Top/End]   _general_utilities.php
[1499]  function nameletters_only($text) {$a = ''; foreach (str_split($text) as $c) {if (ctype_alnum($c) || $c==='_') $a .= $c;} return $a;} [
Top/End]   _general_utilities.php
[1500]  function nameletters_dash($text) {$a = ''; foreach (str_split($text) as $c) {if (ctype_alnum($c) || $c==='-' || $c==='_') $a .= $c;} return $a;} [
Top/End]   _general_utilities.php
[1501]  function nameletters_underscore($text) {return nameletters_only(str_replace(' ','_',$text));} [
Top/End]   _general_utilities.php
[1502]  function nameletters_instead($text) {$a = ''; for ($i=0; $i<strlen($text); $i++) {if (!ctype_alnum($text[$i])) $text[$i] = '_';} return $text;} [
Top/End]   _general_utilities.php
[1503]  function namealphanumeric_only($text) { // drops non-alphanumeric except single-quote, comma, hyphen, and first imbedded space
[1504]  for ($a='',$c='',$i=0; $i<strlen($text); $i++) {
[1505]  $b = $text[$i];
[1506]  if (ctype_alnum($b) || $b==="'" || $b===',' || $b==='-' || ($b===' '&&$c!==' ')) {$a .= $b; $c = $b;}
[1507]  else $c = $c ? '' : ' ';
[1508]  }
[1509]  return trim($a);
[1510]  } [
Top/End]   _general_utilities.php
[1511]  function filenameletters_only($text) {return specific_characters_only($text,'name_letters',' -');} [
Top/End]   _general_utilities.php
[1512]  function emailnameletters_only($text) {return specific_characters_only($text,'name_letters','.-');} [
Top/End]   _general_utilities.php
[1513]  function personnameletters_only($text) {return specific_characters_only($text,"'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-',");} [
Top/End]   _general_utilities.php
[1514]  function respace($text) {return str_replace(' ',' ',str_replace('_',' ',$text));} [
Top/End]   _general_utilities.php
[1515]  function drop_chars($text,$chars) {for ($i=0; $i<strlen($chars); $i++) $text = str_replace($chars[$i],'',$text); return $text;} [
Top/End]   _general_utilities.php
[1516]  function replace_chars($text,$chars,$replacement='') {
[1517]  for ($i=0; $i<strlen($chars); $i++) {
[1518]  $c = ($i < strlen($replacement) ? $replacement[$i] : '');
[1519]  $text = str_replace($chars[$i],$c,$text);
[1520]  }
[1521]  return $text;
[1522]  } [
Top/End]   _general_utilities.php
[1523]  function drop_string($text,$string) {
[1524]  $args = array_slice(func_get_args(),1);
[1525]  foreach ($args as $arg) $text = str_replace($arg,'',$text);
[1526]  return $text;
[1527]  } [
Top/End]   _general_utilities.php
[1528]  function dequote($text) {return drop_chars($text,"\"'`\\");} [
Top/End]   _general_utilities.php
[1529]  function deslash($text) { // removes unguarded backslashes
[1530]  if (strpos($text,'\\') !== FALSE) {
[1531]  $pieces = explode('\\',$text); // break string apart at each backslash
[1532]  $$text = ''; // will be rebuilt from pieces
[1533]  $was_bs = FALSE; // be used to include a backslash when a doubled backslash is encountered
[1534]  foreach ($pieces as $piece) {
[1535]  if ($piece === '') { // if successive backslashes in input text, save only 2nd, 4th, etc.
[1536]  if ($was_bs) {$v .= '\\'; $was_bs = FALSE;}
[1537]  else $was_bs = TRUE;
[1538]  } else {$text .= $piece; $was_bs = FALSE;}
[1539]  }
[1540]  }
[1541]  return $text;
[1542]  } [
Top/End]   _general_utilities.php
[1543]  function character_frequency($text,$characters=' ') { // returns the cumulative count of how often each of the characters in $character is in $text
[1544]  $cc = count_chars($text,0);
[1545]  for ($frequency=$i=0; $i<strlen($characters); $i++) $frequency += $cc[ord($characters[$i])];
[1546]  return $frequency;
[1547]  }

[1548]  //// TABLE CONSTRUCTION
[1549]  set_global_if_missing('implicit_td_parameters','table_end'); [
Top/End]   _general_utilities.php
[1550]  function table($parameters=3,$content_args='') {
[1551]  $rows = array();
[1552]  foreach (array_slice(func_get_args(),1) as $contents) { // arguments after the first are row content
[1553]  if (!is_array($contents)) $contents = array($contents); // treat scalars as one-element arrays
[1554]  foreach ($contents as $content) { // an array argument is treated as an array of row content
[1555]  if (!begins($content,'<tr')) $content = tr($content); // ensure proper table-component tags
[1556]  $rows[] = $content;
[1557]  }
[1558]  }
[1559]  $text = table_begin($parameters);
[1560]  return ($text . implode("\n",$rows) . $GLOBALS['table_end']);
[1561]  } [
Top/End]   _general_utilities.php
[1562]  function table_begin($parameters=3) {
[1563]  if (!is_array($parameters)) $parameters = func_get_args(); // multi-set parameters can be either array or sequential
[1564]  $text = $endtext = '';
[1565]  foreach ($parameters as $parameter_set) { // one parameter set for each table when nested
[1566]  if ($text) {$text .= '<tr><td>'; $endtext = "</td></tr>$endtext";} // except for first pass, add html to nest tables
[1567]  $text .= "<table";
[1568]  foreach (explode(' ',"$parameter_set") as $parameter) {
[1569]  if ($parameter !== '') {
[1570]  if (is_numeric($parameter)) $text .= ' cellpadding=' . abs($parameter) . ' border=' . ($parameter>0 ? 1 : 0);
[1571]  else $text .= ' ' . str_replace('"',"'",$parameter);
[1572]  }
[1573]  }
[1574]  $text .= '>'; $endtext = "</table>$endtext";
[1575]  }
[1576]  $GLOBALS['table_end'] = "$endtext\n";
[1577]  return "$text\n";
[1578]  } [
Top/End]   _general_utilities.php
[1579]  function t_extra($extra) { // applies site defaults to table elements
[1580]  if (!$extra && isset($GLOBALS['td_extra_default'])) $extra = $GLOBALS['td_extra_default'];
[1581]  if (isset($GLOBALS['td_extra_always'])) $extra = trim("$GLOBALS[td_extra_always] $extra");
[1582]  return $extra;
[1583]  } [
Top/End]   _general_utilities.php
[1584]  function thr($headings) {
[1585]  if (!is_array($headings)) $headings = func_get_args();
[1586]  $text = "<tr>";
[1587]  foreach ($headings as $heading) $text .= th($heading);
[1588]  return "$text</tr>\n";
[1589]  } [
Top/End]   _general_utilities.php
[1590]  function th($text=' ',$extra='') {return td("<i>$text</i>",t_extra("$extra center"));} // return HTML for a table-header column
[1591]  $implicit_td_parameters = array('left'=>'align','center'=>'align','right'=>'align','top'=>'valign','middle'=>'valign','bottom'=>'valign'); [
Top/End]   _general_utilities.php
[1592]  function td($text=' ',$extra='') { // return HTML for a table-body column
[1593]  $extra = t_extra($extra);
[1594]  if ($text === '') $text = ' ';
[1595]  $pieces = array('td');
[1596]  foreach (explode(' ',trim($extra)) as $piece) {
[1597]  if (strpos($piece,'=') !== FALSE) $pieces[] = $piece; // include any explicit parameters unchanged
[1598]  if (isset($GLOBALS['implicit_td_parameters'][$piece])) {
[1599]  $parameter = $GLOBALS['implicit_td_parameters'][$piece];
[1600]  $pieces[$piece] = $parameter ? "$parameter=$piece" : $piece;
[1601]  } else if ($piece) {
[1602]  if (is_numeric($piece)) $pieces['colspan'] = "colspan=$piece";
[1603]  elseif ($piece==='nowrap') $pieces['nowrap'] = "style='white-space: nowrap'";
[1604]  else $pieces['class'] = "class='$piece'";
[1605]  }
[1606]  }
[1607]  return ("<" . implode(' ',$pieces) . ">$text</td>");
[1608]  } [
Top/End]   _general_utilities.php
[1609]  function tdc($text=' ',$extra='') {return td($text,"$extra center");} [
Top/End]   _general_utilities.php
[1610]  function tdr($text=' ',$extra='') {return td($text,"$extra right");} [
Top/End]   _general_utilities.php
[1611]  function tdn($value='',$places='',$extra='') { // prints datum, right-justified and formatted if numeric
[1612]  if (is_numeric($value)) {
[1613]  // if numeric with unspecified precision, use more precision for smaller numbers
[1614]  if ($places==='' && $value!=round($value)) $places = abs($value)>100 ? 0 : 2;
[1615]  if (!is_numeric($places)) $places = 0;
[1616]  $text = $places>=0 ? number_format($value,$places) : significant_digits($value,-$places);
[1617]  return td($text,"$extra right");
[1618]  } else return td($value,$extra);
[1619]  } [
Top/End]   _general_utilities.php
[1620]  function tdnw($text=' ',$extra='') {return td($text,trim("$extra style='white-space: nowrap'"));} [
Top/End]   _general_utilities.php
[1621]  function tr($text,$extra='') { // return HTML for a table row
[1622]  // $text -- row-body text (one or more td fields)
[1623]  // $extra -- optional row parameters (e.g. bgcolor)
[1624]  if ($extra) $extra = " $extra";
[1625]  if (!begins($text,'<td') && !begins($text,'<th')) $text = td($text);
[1626]  return "<tr$extra>$text</tr>\n";
[1627]  } [
Top/End]   _general_utilities.php
[1628]  function print_table($records,$keys='',$class='',$headings=20) { // print table from record array, based on key list
[1629]  if (!$records || !is_array($records)) return; // print nothing at all for empty arrays
[1630]  $rec = $records[array_rand($records)]; // get a record to use for key extraction
[1631]  if (!is_array($rec)) $rec = array('Contents'); // to tolerate scalar records
[1632]  if (!$keys) $keys = array_keys($rec); // use all record keys if no key-list supplied
[1633]  if (!is_array($keys)) $keys = ksplit($keys); // parse keys from string if not already in array format
[1634]  $fields = array(); // initialize array that will be used to access data from record
[1635]  foreach ($keys as $key => $text) { // build field list from keys that best match record keys
[1636]  if (array_key_exists($key,$rec)) $fields[$key] = $text;
[1637]  elseif (array_key_exists($text,$rec)) $fields[$text] = $text;
[1638]  // if no exact key match, use first field that contains text (case-insensitive)
[1639]  else {foreach ($rec as $field) {if (contains($field,$text) && !in_array($field,$fields)) {$fields[$field] = $text; break;}}}
[1640]  }
[1641]  print "<table>\n";
[1642]  // build header row
[1643]  $header = '';
[1644]  foreach ($fields as $key => $field) {
[1645]  $text = str_replace('_',' ',$field); // make fieldnames print-friendly
[1646]  if ("$key" === "$field") $text = ucfirst($text); // capitalize unless custom header provided
[1647]  $header .= th($text,$class);
[1648]  }
[1649]  $recordcount = 0;
[1650]  foreach ($records as $record) { // print rows, using columns and order implied by keys
[1651]  if ($recordcount++ % $headings == 0) print tr($header);
[1652]  print "<tr>";
[1653]  if (!is_array($record)) {print tdn($record,$class); continue;}
[1654]  foreach (array_keys($fields) as $key) print tdn($record[$key],$class);
[1655]  print "</tr>\n";
[1656]  }
[1657]  print "</table>\n";
[1658]  } [
Top/End]   _general_utilities.php
[1659]  function table_headings($headings) {
[1660]  if (!is_array($headings)) $headings = func_get_args(); // support array or sequential input
[1661]  $text = '';
[1662]  foreach ($headings as $heading) $text .= "<td align=center><i>$heading</i></td>";
[1663]  return "<tr>$text</tr>\n";
[1664]  } [
Top/End]   _general_utilities.php
[1665]  function tablerow($contentarray,$alignment='',$prefix='',$suffix='') { // return table heading row, using variable argument list
[1666]  if (!is_array($contentarray)) {
[1667]  $contentarray = func_get_args(); // use arg list as contentarray if array not supplied
[1668]  $alignment = $prefix = $suffix = ''; // use defaults, since args are actually contents
[1669]  }
[1670]  if (!is_array($alignment)) $alignment = array($alignment);
[1671]  $k = count($alignment) - 1;
[1672]  for ($i=0,$j=0,$text='<tr>'; $i<count($contentarray); $i++) {
[1673]  $text .= td($prefix . $contentarray[$i] . $suffix, $alignment[$j]);
[1674]  if ($j < $k) $j++; // last alignment value supplied used for leftover content
[1675]  }
[1676]  return ($text . "</tr>\n");
[1677]  } [
Top/End]   _general_utilities.php
[1678]  function centered_row($text,$cols=2) {return "<tr><td align=center colspan=$cols>$text</td></tr>\n";} [
Top/End]   _general_utilities.php
[1679]  function textbox_row($label,$name,$size=30,$value='~') {return ("<tr><td align=right>$label</td><td>" . textbox($name,$value,$size) . "</td></tr>\n");} [
Top/End]   _general_utilities.php
[1680]  function tableheading() { // return HTML for the table row with centered, italic values in variable argument list
[1681]  $labels = func_get_args();
[1682]  return tablerow($labels,'center','<i>','</i>');
[1683]  } [
Top/End]   _general_utilities.php
[1684]  function number_cell($count,$word,$padding='  ') {
[1685]  return td(plural($count,$word) . $padding,'right');
[1686]  } [
Top/End]   _general_utilities.php
[1687]  function distribution_table($label,$info,$places=-1,$label_width=150) {
[1688]  if (!$info) return '';
[1689]  ksort($info);
[1690]  $text = "<table border=1 cellpadding=2><tr>" .
[1691]  tdnw("Distribution of <br>$label ","rowspan=2 middle right width=$label_width");
[1692]  foreach ($info as $index => $count) {$text .= tdc(italic($index));     if ($places > -1) $sum += $index * $count;}
[1693]  if ($places > -1) $text .= tdnw("   Average   <br>" . quotient($sum,array_sum($info),$places),"rowspan=2 align=center");
[1694]  $text .= "</tr>\n<tr>";
[1695]  foreach ($info as $index => $count) $text .= tdc(bold($count));
[1696]  return "$text</tr></table>\n";
[1697]  } [
Top/End]   _general_utilities.php
[1698]  function multi_column_text($text,$row_limit=25,$spacing=2) {
[1699]  $rows = nsplit(trim($text));
[1700]  if (count($rows) <= $row_limit) return $text;
[1701]  $lines = array();
[1702]  $max_length = 0;
[1703]  $n = 0;
[1704]  foreach (chunked_array($rows,$row_limit) as $chunk) {
[1705]  for ($i=0; $i<count($chunk); $i++) {
[1706]  $lines[$i] .= $chunk[$n++];
[1707]  if (strlen($lines[$i]) > $max_length) $max_length = strlen($lines[$i]);
[1708]  }
[1709]  for ($i=0; $i<count($chunk); $i++) $lines[$i] .= str_repeat(' ',$max_length+$spacing-strlen($lines[$i]));
[1710]  }
[1711]  $text = '';
[1712]  foreach ($lines as $line) $text .= rtrim($line) . "\n";
[1713]  return $text;
[1714]  }

[1715]  //// TIME & DATE CONVERSIONS [
Top/End]   _general_utilities.php
[1716]  function datetimetoSQL($when, $scale=1) { // returns datetime in format suitable for SQL
[1717]  // $when -- integer time indicator (from time() or microtime()); default
[1718]  // $scale -- the number of $when tics that equal 1 second (e.g., 1000 if $when is in milliseconds)
[1719]  if ($scale) $when = (int)($when/$scale);
[1720]  return date('Y-m-d G:i:s',$when);
[1721]  } [
Top/End]   _general_utilities.php
[1722]  function minsec($seconds) { // returns min:sec text string from number of seconds
[1723]  // $seconds -- time in seconds (may be in float format with decimal-fraction part)
[1724]  $seconds = round($seconds);
[1725]  $minutes = (int)($seconds/60);
[1726]  $seconds = $seconds % 60;
[1727]  if (!$minutes) $minutes = ''; // suppress leading 0 if interval is less than a minute
[1728]  return ("$minutes:" . substr("0$seconds",-2)); // ensure that seconds have tens-place zero if needed
[1729]  } [
Top/End]   _general_utilities.php
[1730]  function msminsec($milliseconds) { // returns compact time-interval description with at least two significant digits
[1731]  // $milliseconds -- time interval in thousanths of a second
[1732]  if ($milliseconds < 995) return number_format($milliseconds/1000, 2); // sub-second intervals to 10-ms precision
[1733]  if ($milliseconds < 9950) return number_format($milliseconds/1000, 1); // intervals less than 10 seconds to 100-ms precision
[1734]  if ($milliseconds < 59500) return round($milliseconds/1000); // intervals less than a minute as integer seconds
[1735]  return minsec($milliseconds/1000); // for intervals of a minute or more, use min:sec notation
[1736]  } [
Top/End]   _general_utilities.php
[1737]  function time_floated() { // return high-precision time value [in PHP 5, this can be done directly in time()]
[1738]  $a = explode(' ',microtime());
[1739]  return (float)$a[1] + (float)$a[0]; // combine second and fraction-of-second values into a 64-bit floating-point number
[1740]  } [
Top/End]   _general_utilities.php
[1741]  function shortdatetime($time='') {return date('G:i n/j',make_time($time));} [
Top/End]   _general_utilities.php
[1742]  function numberdatetime($time='') {return date('G:i n/j/y',make_time($time));} [
Top/End]   _general_utilities.php
[1743]  function longdatetime($time='') {return date('g:i:s a T, F j Y',make_time($time));} [
Top/End]   _general_utilities.php
[1744]  function numberdate($time='') {
[1745]  if ($time==='0000-00-00 00:00:00' || !$time) return '';
[1746]  return date('n/j/y',make_time($time));
[1747]  } [
Top/End]   _general_utilities.php
[1748]  function make_time($time) {if (!$time) $time = time(); if (!is_numeric($time)) $time = strtotime($time); return $time;} [
Top/End]   _general_utilities.php
[1749]  function generaldatetime($time='',$format='n/j/y') { // uses m/d/yy format if more than six months ago
[1750]  if ($time==='0000-00-00 00:00:00' || !$time) return '';
[1751]  $time = make_time($time);
[1752]  $ago = time() - $time;
[1753]  if (!$format) $format = 'g:i:s a T, l F j Y'; // show long & complete version with format of 0 or ''
[1754]  elseif ($ago < 72000) $format = "g:i a"; // show only time if in last 20 hours
[1755]  elseif ($ago < 432000) $format = "D H:i"; // show day of week plus time if in last five days
[1756]  elseif ($ago < 16000000) $format = "n/j"; // drop year if in the last six months
[1757]  return date($format,$time);
[1758]  } [
Top/End]   _general_utilities.php
[1759]  function regularize_year($text='',$firstyear='1900',$lastyear='') { // extracts four-digit year from text
[1760]  $yyyy = date('Y'); // four-digit text for current year
[1761]  $letters = char_array(strrev(trim($text))); // reversed to work from ending digits
[1762]  if ($lastyear === '') $lastyear = plain(num($yyyy)+1); // by default, top limit is next year
[1763]  $y = ''; // extract consecutive trailing digits (including zeros) from $text, dropping preceding oontent
[1764]  foreach ($letters as $letter) {if (ctype_digit($letter)) $y = $letter . $y; else break;} // undo reverse
[1765]  if (strlen($y) == 2) { // extend two-digit year to include appropriate century
[1766]  $y = substr($yyyy,0,2) . $y; // use current century if possible
[1767]  if ($y > $lastyear) $y = plain(num($y)-100); // otherwise, use previous century
[1768]  }
[1769]  return (($y>=$firstyear || $y<=$lastyear) ? $y : ''); // return four-digit year text (or empty string)
[1770]  } [
Top/End]   _general_utilities.php
[1771]  function time24($time='~') { // converts datetime or text (eg: 'h:mmAM', 'hh:mm pm') into 'HH:MM' if not already like that
[1772]  if (!$time) return '';
[1773]  if ($time === '~') $time = time();
[1774]  if (ctype_digit("$time")) return date('H:i',$time);
[1775]  $time = nospace($time);
[1776]  $ampm = substr($time,-2);
[1777]  if (same($ampm,'am','pm')) $time = substr($time,0,-2); else $ampm = '';
[1778]  if (substr($time,-3,1) === ':') {$minutes = substr($time,-2); $hours = substr($time,0,-3);}
[1779]  else {$hours = $time; $minutes = 0;}
[1780]  if (!is_numeric($hours) || !is_numeric($minutes)) return '?'; // return "[$raw_time => $hours:$minutes $ampm]";
[1781]  if ($hours==12 && $ampm) $hours = 0; // so that 12:mm AM and 12:mm PM are correctly handled
[1782]  if ($ampm === 'pm') $hours += 12;
[1783]  return (substr("0$hours",-2) . ':' . substr("0$minutes",-2)); // HH:MM format
[1784]  } [
Top/End]   _general_utilities.php
[1785]  function time12($time='~') { // converts datetime or 24-hour-time text into 12-hour-time text if not already like that
[1786]  if (!$time) return '';
[1787]  if ($time === '~') $time = time();
[1788]  $raw_time = $time;
[1789]  if (ctype_digit("$time")) return date('g:i a',$time);
[1790]  $time = nospace($time);
[1791]  $ampm = substr($time,-2); // leave AM/PM case as is if already 12-hour format
[1792]  if (same($ampm,'am','pm')) $time = substr($time,0,-2); else $ampm = '';
[1793]  if (substr($time,-3,1) === ':') {$minutes = substr($time,-2); $hours = substr($time,0,-3);}
[1794]  else {$hours = $time; $minutes = 0;}
[1795]  if (!is_numeric($hours) || !is_numeric($minutes) || $hours>23 || $hours<0) return "[$raw_time => $hours:$minutes $ampm]";
[1796]  if (!$ampm) $ampm = ($hours < 12) ? 'am' : 'pm';
[1797]  $hours = (($hours - 1) % 12) + 1;
[1798]  return (substr(" $hours",-2) . ':' . substr("0$minutes",-2) . " $ampm");
[1799]  } [
Top/End]   _general_utilities.php
[1800]  function minute_of_day($time) { // returns minutes since midnight
[1801]  $time24 = time24($time); // convert to HH:MM
[1802]  return (60 * num(substr($time24,0,2)) + num(substr($time24,3,2)));
[1803]  } [
Top/End]   _general_utilities.php
[1804]  function duration($seconds) { // return minutes:seconds (or hours:minutes:seconds if longer than an hour)
[1805]  $hours = (int) ($seconds / 3600);
[1806]  $min = (int) (($seconds % 3600) / 60);
[1807]  $sec = (int) ($seconds % 60);
[1808]  $sec = substr("00$sec",-2);
[1809]  if ($hours == 0) return "$min:$sec";
[1810]  $min = substr("00$min",-2);
[1811]  return "$hours:$min:$sec";
[1812]  } [
Top/End]   _general_utilities.php
[1813]  function timer($label='') { // accumulates labeled time-points to be reported at the end of a script
[1814]  global $timer_data;
[1815]  if (!isset($timer_data)) $timer_data = array();
[1816]  $time = $t2 = time(); // $t2 is initially the current time of the report call
[1817]  if ($label) $timer_data[$label] = $time; // called with a label, saves and returns the current time
[1818]  elseif ($timer_data) { // called without a label: prints a timing report, then resets
[1819]  $timer_intervals = array(); // build list of intervals, keyed by label called at start of that interval
[1820]  foreach (array_reverse($timer_data) as $label=>$t1) { // compute intervals from last to first
[1821]  $interval = $t2 - $t1;
[1822]  if ($interval > 1) $timer_intervals[$label] = $interval; // ignore intervals of 1 second or less
[1823]  $t2 = $t1; // the beginning of each interval is the end of the previous interval
[1824]  }
[1825]  $time = $time - $t2; // full time interval recorded for script
[1826]  if (count($timer_data)>1 && $time>2) { // no report for short scripts without explicit timer calls
[1827]  print "<table>\n";
[1828]  foreach (array_reverse($timer_intervals) as $label=>$t) print tr(tdr(duration($t)) . td($label));
[1829]  print "</table>\n";
[1830]  }
[1831]  $timer_data = array(); // re-initialize the timer in case a script wants to generate multiple reports
[1832]  }
[1833]  return $time; // return total time interval covered in report
[1834]  }

[1835]  //// NUMERIC [
Top/End]   _general_utilities.php
[1836]  function quotient($numerator,$denominator=1,$places='') {
[1837]  if (!$denominator || !is_numeric($denominator)) return 0;
[1838]  $quotient = $numerator / $denominator;
[1839]  return (is_numeric($places) ? round($quotient,$places) : $quotient);
[1840]  } [
Top/End]   _general_utilities.php
[1841]  function percent($numerator,$denominator=1,$places=-1) {
[1842]  $percentage = percentage($numerator,$denominator,$places);
[1843]  if ($places>0 && $percentage<100) $percentage = places($percentage,$places);
[1844]  return "$percentage%";
[1845]  } [
Top/End]   _general_utilities.php
[1846]  function percentage($numerator,$denominator=1,$places='') {
[1847]  if (!is_numeric($numerator) || !is_numeric($denominator)) return '';
[1848]  $ratio = quotient($numerator,$denominator);
[1849]  if (!is_numeric($places) || $places<0) {
[1850]  $places = is_numeric($places) ? -$places : 0;
[1851]  if (abs($ratio) < 0.0002) $places += 3;
[1852]  elseif (abs($ratio) < 0.002) $places += 2;
[1853]  elseif (abs($ratio) < 0.02) $places += 1;
[1854]  }
[1855]  return round(100*$ratio,$places);
[1856]  } [
Top/End]   _general_utilities.php
[1857]  function accumulator_reset($variable_names,$prefixes='') { // zeros accumulation variables
[1858]  $names = csplit($variable_names); // multiple global-variable names may be supplied
[1859]  $prefixes = $prefixes ? csplit($prefixes) : array('');
[1860]  foreach ($prefixes as $prefix) { // multiple levels of variable supported
[1861]  foreach ($names as $name) {
[1862]  $GLOBALS["$prefix$name"] = 0;
[1863]  $GLOBALS["count_$prefix$name"] = 0;
[1864]  $GLOBALS["sum_$prefix$name"] = 0;
[1865]  $GLOBALS["square_$prefix$name"] = 0;
[1866]  $GLOBALS["min_$prefix$name"] = 0;
[1867]  $GLOBALS["max_$prefix$name"] = 0;
[1868]  $GLOBALS["histogram_$prefix$name"] = array();
[1869]  }
[1870]  }
[1871]  } [
Top/End]   _general_utilities.php
[1872]  function accumulate($variable_names,$prefix='') {
[1873]  foreach (csplit($variable_names) as $name) { // multiple global variable names may be supplied
[1874]  $value = $GLOBALS["$prefix$name"];
[1875]  $GLOBALS["sum_$prefix$name"] += $value;
[1876]  $GLOBALS["square_$prefix$name"] += $value * $value;
[1877]  if ($GLOBALS["count_$prefix$name"]++) {
[1878]  if ($value<$GLOBALS["min_$prefix$name"]) $GLOBALS["min_$prefix$name"] = $value;
[1879]  elseif ($value>$GLOBALS["max_$prefix$name"]) $GLOBALS["max_$prefix$name"] = $value;
[1880]  } else $GLOBALS["min_$sum_prefix$name"] = $GLOBALS["max_$prefix$name"] = $value; // first accumulated value
[1881]  $GLOBALS["$prefix$name"] = 0; // after accumulation, zero source variable for next round of accumulation
[1882]  }
[1883]  } [
Top/End]   _general_utilities.php
[1884]  function accumulate_histogram($variable_names,$prefix='') { // increments appropriate bin of value-based histograms
[1885]  foreach (csplit($variable_names) as $name) { // multiple global variable names may be supplied
[1886]  $value = $GLOBALS["$prefix$name"];
[1887]  if (isset($GLOBALS["$prefix$name"][$value])) $GLOBALS["histogram_$prefix$name"][$value]++;
[1888]  else $GLOBALS["histogram_$prefix$name"][$value] = 1;
[1889]  }
[1890]  } [
Top/End]   _general_utilities.php
[1891]  function accumulation_statistics($variables_names,$prefixes='') {
[1892]  $names = csplit($variable_names); // multiple global variable names may be supplied
[1893]  $prefixes = $prefixes ? csplit($prefixes) : array('');
[1894]  foreach ($prefixes as $prefix) { // multiple levels of variable supported
[1895]  foreach ($names as $name) {
[1896]  $count = $GLOBALS["count_$prefix$name"];
[1897]  if ($count) {
[1898]  $mean = $GLOBALS["mean_$prefix$name"] = $GLOBALS["sum_$prefix$name"] / $count;
[1899]  $GLOBALS["rms_$prefix$name"] = sqrt($GLOBALS["square_$prefix$name"] / $count);
[1900]  $GLOBALS["std_$prefix$name"] = $count>1 ? sqrt(($GLOBALS["square_$prefix$name"] - $mean * $mean) / ($count-1)) : 0;
[1901]  list($GLOBALS["Q1_$prefix$name"],$GLOBALS["median_$prefix$name"],$GLOBALS["Q3_$prefix$name"]) = statiles($GLOBALS["min_$prefix$name"],4);
[1902]  $GLOBALS["IQR_$prefix$name"] = $GLOBALS["Q3_$prefix$name"] - $GLOBALS["Q1_$prefix$name"];
[1903]  }
[1904]  }
[1905]  }
[1906]  } [
Top/End]   _general_utilities.php
[1907]  function statiles($histogram,$tiles=4,$interpolation=0,$already_sorted=FALSE) { // computes statiles (quartiles by default) from a histogram
[1908]  if (!$already_sorted) ksort($histogram); // statiles based on histograms only make sense if bin order is standardized
[1909]  $total = 0; foreach ($histogram as $counts) $total += $counts;
[1910]  if (!$total) {error('Zero histogram sum'); return array_fill(0,$tiles,0);}
[1911]  $tile_step = $total / $tiles;
[1912]  $cumulative = 0;
[1913]  $tile_values = array();
[1914]  $tile_target = 1;
[1915]  foreach ($histogram as $key=>$counts) {
[1916]  $needed = $tile_target - $cumulative; // amount short of filling current tile, in tile units
[1917]  $bin_step = $counts / $tile_step; // contribution of this bin, in tile units
[1918]  $cumulative += bin_step;
[1919]  while ($bin_step>=$needed && $tile_target<$tiles) { // inner tile boundary crossed, so compute tile value (may repeat within a single bin)
[1920]  if ($interpolation) {$tile_values[$tile_target] = ($key-$interpolation) * (1-$needed) + $key * $needed; // to interpolate, set $interpolation to bin width
[1921] 
[1922]  } else $tile_values[$tile_target] = $key; // set tile value to key of bin that fills it
[1923]  $tile_target++; // start computing next tile
[1924]  $bin_step -= $needed; // deduct amount of bin used for the tile that was just set
[1925]  $needed = 1; // start next tile with a full tile step needed
[1926]  }
[1927]  }
[1928]  if ($tile_target != $tiles-1) error('Histogram tile-computation anomoly');
[1929]  return $tile_values;
[1930]  } [
Top/End]   _general_utilities.php
[1931]  function histogram_modes($array) {
[1932]  if (!is_array($array)) return array();
[1933]  $max = -1;
[1934]  $modes = array();
[1935]  foreach ($array as $index => $count) {if ($count >= $max) {$mode = $index; $max = $count;}}
[1936]  foreach ($array as $index => $count) {if ($count == $max) $modes[] = $index;}
[1937]  return $modes;
[1938]  } [
Top/End]   _general_utilities.php
[1939]  function histogram_mode($array) {
[1940]  $modes = histogram_modes($array);
[1941]  return (count($modes) ? $modes[0] : FALSE);
[1942]  } [
Top/End]   _general_utilities.php
[1943]  function asymptotic_squeeze($value,$center=0,$halfwidth=1) {
[1944]  if ($halfwidth == 0) return $center;
[1945]  return (atan(($value-$center)/$halfwidth*1.5708) / 1.5708 * $halfwidth + $center);
[1946]  }

[1947]  //// ERROR HANDLING [
Top/End]   _general_utilities.php
[1948]  function error_traceback($errno,$errstr,$errfile,$errline) {
[1949]  if (!(error_reporting() & $errno)) return; // This error code is not included in error_reporting
[1950]  debug_print_backtrace();
[1951]  return FALSE;
[1952]  }
[1958]  ?>

FILE: _gpl.php - 1 lines, 0 functions [
Top/End]
  [1]  <?php // show GPL and provide code distribution include_once '_all_sites.php'; $file_separator = "\n~~~~~~~~~~ combined by _gpl.php - "; page_start('General Public License'); $version_link = alink('version 3','_license.txt'); $gnu_link = alink('GNU General Public License','http://www.gnu.org/licenses/'); $show_code_link = alink('Show Code','_code_show.php'); $unzip = '_site_unzip.php'; print <<<HTML <table border=1 width='90%' cellpadding=10><tr><td> <p>     This site is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either $version_link of the License, or (at your option) any later version.  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the $gnu_link for more details.</p> <p>     The site source code is made available both via the $show_code_link dynamic listing/index and as a block of text in the CODE textarea below.  A separate no-dependencies <i>$unzip</i> script that regenerates the site files from that text is displayed in a separate UNZIP textarea.  To replicate the site on a separate server, [1] copy <i>$unzip</i> from the "UNZIP" textarea to the destination directory on new server, [2] make a copy of the contents of the "CODE" textarea below, [3] run the <i>$unzip</i> script on the new server, [4] paste the code into the "CODE" textarea in the new server, and [5] press the "Install" button to unzip the files.</p> </td></tr></table><br> HTML; print br("<b>UNZIP</b> (<i>$unzip</i> script to be copied to the new server, where it can process the code in the next textarea)",1); print br(textarea('unzip',file_get_contents($unzip),10,120,FALSE)); print br("<b>CODE</b> (contents to be copied and pasted into the corresponding textarea on <i>$unzip</i> on the new server)",1); print textarea_head('code',10,120); print "SITE CODE AS OF " . longdatetime(); // preamble to show time and prevent trim of separator $directories = array('.'); foreach (files() as $file) {if (is_dir($file)) $directories[] = './' . filename_only($file);} set_time_limit(300); $time = time(); foreach ($directories as $directory) { foreach (files("$directory/*.*") as $file) { if (contains($file,'.LOG')) continue; $filename = "$directory/" . filename_base($file); print h("$file_separator$filename\n");     print h(file_get_contents($filename)); } } print "</textarea>\n"; if (file_exists('_create_database_tables.sql')) {     print br("<b>DATABASE TABLES</b> (contents to be copied run as SQL script to create needed tables in new database)",2);     print textarea('sql_tables',file_get_contents('_create_database_tables.sql'),120,10); } page_end(); /* Copyright (C) 2010-2015 Hunter Ellinger This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ ?>
FILE: _ngraph.php - 143 lines, 4 functions [
Top/End]
  [1]  <?php
  [2]  include_once '_statistics.php';
  [3]  $session_registration_tag = 'normal_graph_';
  [4]  // declare input-control globals so that development environment acknowledges them, since they will be set via register_requests()
  [5]  global $score,$graph_type,$direction,$fraction,$area_graph_type,$pvalue_mode;
  [6]  global $graph_width,$graph_height,$padding,$curve_thickness,$curve_color,$graph_background,$divider_color,$area_color,$shading_color,
  [7]  $view_background,$page_background_color,$vscale,$hscale,$divider,$percent,$places;
  [8]  global $mean,$std,$area,$sigmas_low,$sigmas_high,$low,$high;
  [9]  // globals for sharing between setup, page-specific, and markup phases
  [10]  global $array,$peak,$xscale,$yscale,$xoffset,$yoffset,$vertical_scale,$horizontal_scale,$view_width,$view_height,$divider_height;
  [11]  global $svg,$curve_points,$filled_curve_points,$extra_controls_link;
  [12]  [Top/End]   _ngraph.php
  [13]  function normal_graph_setup($default_places=4) {
  [14]  global $mean,$std,$area,$sigmas_low,$sigmas_high,$low,$high,$ch,$cw,$extra_settings,$extra_controls_link,$page_background_color,$session_registration_tag;
  [15]  $request_parameters = 'mean#,std#/1,area#/1,sigmas_low#,sigmas_high#,graph_width#/400,graph_height#/150,padding#/' . 2*$ch .
  [16]  ',curve_thickness#/1,curve_color/black,graph_background/lightgray,divider_color/red,area_color/blue,shading_color/gray,view_background/white,' .
  [17]  "page_background_color/$page_background_color,places#/$default_places,extra_settings?/0,vscale?/1,hscale?/1,divider?/1,percent?/1";
  [18]  register_request($request_parameters,$session_registration_tag);
  [19]  $extra_controls_link = small($extra_settings ? alink('Fewer settings','?extra_settings=0') : alink('More settings','?extra_settings=1'));
  [20]  if ($std <= 0) $std = 1;
  [21]  if ($area <= 0) $area = 1;
  [22]  if ($sigmas_high <= $sigmas_low) {$sigmas_low = -4; $sigmas_high = 4;}
  [23]  $low = $mean + $std*$sigmas_low;
  [24]  $high = $mean + $std*$sigmas_high;
  [25]  //
  [26]  global $graph_width,$graph_height,$padding,$curve_thickness,$curve_color,$graph_background,$divider_color,$area_color,$shading_color,
  [27]  $view_background,$page_background_color,$vscale,$hscale,$divider,$percent,$places,
  [28]  $array,$xscale,$yscale,$xoffset,$yoffset,$vertical_scale_thickness,$horizontal_scale_thickness,$divider_height;
  [29]  $array = make_gaussian_array($graph_width,$sigmas_low,$sigmas_high,$area/$std);
  [30]  $peak = $array ? max($array) : 1;
  [31]  $yscale0 = $graph_height / $peak; // ypixels-per-unit-value (before rescaling of $array)
  [32]  foreach ($array as $index=>$value) $array[$index] = $yscale0 * $value; // $array now is pixels above baseline
  [33]  $yscale = 1;
  [34]  $yoffset = $graph_height + $padding;
  [35]  $xscale = $graph_width / ($high-$low); // xpixels-per-unit-value
  [36]  $vertical_scale = $vscale ? svg_vertical_scale($padding,$yoffset,$graph_height,$yoffset,$yscale0,0,$peak) : '';
  [37]  $xoffset = $padding + $vertical_scale_thickness;
  [38]  $view_width = $xoffset + $graph_width + $padding;
  [39]  $horizontal_scale = $hscale ? svg_horizontal_scale($yoffset,$xoffset,$graph_width,$xoffset,$xscale,$low,$high) : '';
  [40]  $view_height = $yoffset + $horizontal_scale_thickness + $ch + $padding;
  [41]  $divider_height = $horizontal_scale_thickness + 0.3*$ch;
  [42]  //
  [43]  global $svg,$curve_points,$filled_curve_points;
  [44]  $svg = svg_start('',$view_width,$view_height,$view_background) . $horizontal_scale . $vertical_scale;
  [45]  $curve_points = svg_points($array,-1,$yoffset,0,0,1,$xoffset);
  [46]  $filled_curve_points = "$xoffset,$yoffset $curve_points " . ($xoffset+$graph_width-1) . ",$yoffset";
  [47]  $attributes = array('fill'=>$graph_background,'stroke'=>'none');
  [48]  if ($graph_background) $svg .= svg_polyline($filled_curve_points,$attributes);
  [49]  $attributes = array('fill'=>'none','stroke'=>$curve_color,'stroke-width'=>$curve_thickness);
  [50]  if ($curve_color) $svg .= svg_polyline($curve_points,$attributes);
  [51]  $xmean = ($mean-$low)*$xscale;
  [52]  if ($xmean>=0 && $xmean<=$graph_width) $svg .= svg_circle($xmean+$xoffset,$yoffset,1,'black');
  [53]  } [
Top/End]   _ngraph.php
  [54]  function normal_graph_markup($dividers,$sections) {
  [55]  global $svg,$low,$high,$divider_color,$area_color,$shading_color,$view_background,$divider_height,$ch,$cw,$graph_height,$graph_width,$area,
  [56]  $array,$xscale,$yscale,$xoffset,$yoffset,$curve_points,$curve_color,$curve_thickness,$sigmas_low,$sigmas_high,$percent,$divider,$padding;
  [57]  foreach ($sections as $parameters) {
  [58]  list ($afraction,$vlow,$vhigh,$places) = $parameters;
  [59]  $area_value = $area==1 ? $afraction : ($afraction*$area);
  [60]  $atext = (is_numeric($places) ? np($area_value,$places) : nonexponential($area_value,TRUE));
  [61]  $length = strlen($atext);
  [62]  $subindex = max(0,round(($vlow-$low)*$xscale));
  [63]  $offset = $xoffset + $subindex;
  [64]  $subcount = max(0,min(count($array)-$subindex,round(($vhigh-$low)*$xscale)-$subindex+1));
  [65]  $subarray = array_slice($array,$subindex,$subcount);
  [66]  if ($vhigh <= $low) {$atext = "← $atext"; $length += 2;}
  [67]  if ($vlow >= $high) {$atext = "$atext →"; $length += 2;}
  [68]  if ($subarray && $shading_color) $svg .= svg_filled_graph($shading_color,$subarray,-1,$yoffset,0,$offset); // draw shaded area
  [69]  if ($percent) {
  [70]  if ($subarray) {
  [71]  $xx = $xtext = mean($subarray);
  [72]  $yy = max(interpolated($subarray,$xx)/2,average($subarray)/2);
  [73]  $ytext = round(max($subarray)) + 3;
  [74]  $svg .= svg_line($offset+$xx,$yoffset-$yy,0,$yy-$ytext,1,$area_color) . svg_circle($offset+$xx,$yoffset-$yy,2,$view_background,1,$area_color);
  [75]  } else {
  [76]  $xtext = $graph_width/2;
  [77]  if (strpos($atext,'larr;') === FALSE) $xtext = $graph_width;
  [78]  if (strpos($atext,'rarr;') === FALSE) $xtext = 0;
  [79]  $ytext = max($array) + 3; // text at top for out-of-range cases
  [80]  }
  [81]  $xtext = text_xadjust($xtext+$subindex,$length,0,$padding/2);
  [82]  $svg .= svg_text($atext,$xoffset+$xtext,$yoffset-$ytext-3,array('font-weight'=>'bold','fill'=>$area_color));
  [83]  $svg .= svg_text('Area',$xoffset+$xtext,$yoffset-$ytext-0.8*$ch,array('font-size'=>10,'fill'=>$area_color));
  [84]  }
  [85]  }
  [86]  foreach ($dividers as $parameters) {
  [87]  list($value,$value_near,$places) = $parameters;
  [88]  if ($value>=$low && $value<=$high && $divider) { // draw boundary value
  [89]  $x = $xoffset + ($value-$low)*$xscale;
  [90]  if (is_numeric($places)) {$value = np($value,$places); $value_near = np($value_near,$places);}
  [91]  $text_offset = 0;
  [92]  $anchor = 'middle';
  [93]  $separation = $value - $value_near;
  [94]  if ($separation) {
  [95]  $overlap = $cw*(strlen($value)+strlen($value_near)+1)/2 - abs($value-$value_near)*$xscale;
  [96]  if ($overlap > 0) {
  [97]  if ($separation < 0) { // left divider
  [98]  $anchor = 'end';
  [99]  $text_offset = -$separation/2+$cw/4;
 [100]  } else { // right divider
 [101]  $anchor = 'start';
 [102]  $text_offset = -$separation/2+$cw/4;
 [103]  }
 [104]  }
 [105]  }
 [106]  $svg .= svg_line($x,$yoffset,0,$divider_height,1,$divider_color);
 [107]  $svg .= svg_text($value,$x+$text_offset,$yoffset+$divider_height+0.6*$ch,array('font-weight'=>'bold','fill'=>$divider_color,'text-anchor'=>$anchor));
 [108]  $svg .= svg_text('Score',$x+$text_offset,$yoffset+$divider_height+1.2*$ch,array('font-size'=>10,'fill'=>$divider_color,'text-anchor'=>$anchor));
 [109]  $svg .= svg_circle($x,$yoffset,2,$view_background,1,$divider_color);
 [110]  }
 [111]  }
 [112]  return p($svg . svg_end()) . br('Show graph portion between ' . sizebox('sigmas_low',plus($sigmas_low)) . ' σ and ' .
 [113]  sizebox('sigmas_high',plus($sigmas_high)) . ' σ, with ' . globalbox('places') . '-decimal-place answers');
 [114]  } [
Top/End]   _ngraph.php
 [115]  function normal_graph_controls($area_option=FALSE) {
 [116]  global $graph_width,$graph_height,$padding,$curve_thickness,$curve_color,$graph_background,$divider_color,$area_color,$shading_color,
 [117]  $view_background,$page_background_color,$vscale,$hscale,$divider,$percent,$extra_settings;
 [118]  $controls = '';
 [119]  $area_option_text = $area_option ? '   Area: ' . globalbox('area') : hidden('area',1);
 [120]  $controls .= p(italic('Distribution:') . '   Mean: ' . globalbox('mean') . '   Standard deviation: ' . globalbox('std') . $area_option_text);
 [121]  $controls .= p(italic('Show: ') . checkbox('hscale',$hscale,1,'Horizontal') . checkbox('vscale',$vscale,1,'Vertical') .
 [122]  checkbox('divider',$divider,1,'Dividers') . checkbox('percent',$percent,1,'Areas'));
 [123]  $controls .= p(commandbutton('Display'));
 [124]  if ($extra_settings) {
 [125]  $controls .= p(italic('Division colors:') . lbox('shading_color') . lbox('divider_color') . lbox('area_color'));
 [126]  $controls .= p(italic('View:') . rbox('graph_width') . rbox('graph_height') . cbox('padding') . lbox('view_background') . lbox('page_background_color'));
 [127]  $controls .= p(italic('Curve:') . rbox('curve_color') . rbox('graph_background') . rbox('curve_thickness'));
 [128]  } else {
 [129]  $names = 'shading_color,divider_color,area_color,graph_width,graph_height,padding,view_background,page_background_color,curve_color,graph_background,curve_thickness';
 [130]  foreach (csplit($names) as $name) $controls .= hidden($name,$GLOBALS[$name]);
 [131]  }
 [132]  $controls .= hidden('extra_settings',$extra_settings);
 [133]  return $controls;
 [134]  } [
Top/End]   _ngraph.php
 [135]  function text_xadjust($xi,$length,$left=0,$right=0) { // find x position for text that remains in view
 [136]  global $ch,$cw,$graph_height,$graph_width,$xscale,$xoffset;
 [137]  $xi0 = $xi;
 [138]  $hpixels = ($length)*$cw/2; // half the width in pixels of the text plus a character
 [139]  if ($xi<$graph_width/2 && $xi<$hpixels-$left) $xi = $hpixels-$left; // crowded to the left, so adjust with allowed overrun
 [140]  elseif ($xi>$graph_width/2 && ($graph_width-$xi)<$hpixels-$right) $xi = $graph_width-$hpixels+$right; // crowded to the right
 [141]  return round($xi);
 [142]  }
 [143]  ?>

FILE: _page_routines.php - 137 lines, 15 functions [
Top/End]
  [1]  <?php // standardized routines and settings for web-page handling
  [2]  require_once '_general_utilities.php';
  [3]  $error = $notice = array(); $home_url = $trace = '';
  [4]  // standard values
  [5]  $top_link = "<small>[<a href='#Top'>Top</a>/<a href='#End'>End</a>]</small>";
  [6]  set_global_if_missing('trace_page','suppress_site_banner','page_width','page_background_color','site_top_navigation','site_bottom_navigation',
  [7]  'extra_head_text','default_titlelink','site_css','user_id','database_connection','gpl','instructions_url');
  [8]  set_session_if_missing('privileges','error','notice','trace');
  [9]  // END OF AUTO-RUN STATEMENTS -- after this, execution chains back to _site_routines.php
  [10]  // page template routines [Top/End]   _page_routines.php
  [11]  function page_start($title='',$posttitle_text='',$pretitle_text='') { // called to start page output
  [12]  foreach (nsplit(file_read_contents('scriptconfiguration.txt')) as $line) {
  [13]  list($name,$url,$custom_title) = array_merge(gsplit(';',$line),array('','',''));
  [14]  if (same($GLOBALS['current_page_name'],before($name,'.'))) {$GLOBALS['instructions_url'] = trim($url); if ($custom_title) $title = $custom_title; break;}
  [15]  }
  [16]  $_SESSION['redirection_url'] = ''; // at this point, no longer any danger of redirection loop
  [17]  if ($GLOBALS['trace_page']) trace_page();
  [18]  timer('Script setup');
  [19]  print page_start_top($title,$GLOBALS['extra_head_text'],"bgcolor='$GLOBALS[page_background_color]' style='margin-top:6pt'");
  [20]  if (function_exists('site_banner') && !$GLOBALS['suppress_site_banner']) print site_banner();
  [21]  $width = ($GLOBALS['page_width'] ? " width=$GLOBALS[page_width]" : '');
  [22]  print "<table$width cellpadding=0><tr><td align=center>\n";
  [23]  $GLOBALS['page_table_depth'] = 1;
  [24]  if (function_exists('site_navigation') && $GLOBALS['site_top_navigation']) print site_navigation();
  [25]  $GLOBALS['site_navigation'] = FALSE; // by default, navigation is only printed at the top of the page
  [26]  if (!$pretitle_text) $pretitle_text = "$GLOBALS[default_titlelink]";
  [27]  $title_text = $title ? "<span class=title>$title</span>" : '';
  [28]  if ($pretitle_text) $title_text = "$pretitle_text   $title_text";
  [29]  if ($posttitle_text) $title_text .= "   $posttitle_text";
  [30]  if ($title_text) print pc($title_text);
  [31]  print_flash('error');
  [32]  print_flash('notice');
  [33]  } [
Top/End]   _page_routines.php
  [34]  function page_start_top($title='',$head_extra='',$body_extra='') { // called to start page output
  [35]  global $user_id,$user,$current_page_name,$site_abbr,$superuser_id,$master_title;
  [36]  $title = strip_tags($title ? $title : $site_abbr);
  [37]  if (isset($master_title)) $title = $master_title;
  [38]  if (!$GLOBALS['site_css']) $GLOBALS['site_css'] = '_site.css';
  [39]  print <<<HTML
  [40]  <!DOCTYPE html>
  [41]  <html>
  [42]  <head>
  [43]  <title>$title</title>
  [44]  <link href="$GLOBALS[site_css]" media="all" rel="stylesheet" type="text/css" />
  [45]  $head_extra</head>
  [46]  <body $body_extra>
  [47]  <div align=center>
  [48]  <a name='Top' />
  [49] 
  [50]  HTML;
  [51] 
  [52]  print formheader();
  [53]  print hidden('submit_link','');
  [54]  } [
Top/End]   _page_routines.php
  [55]  function page_table_close() {while ($GLOBALS['page_table_depth']-- > 0) print "</td></tr></table>\n";} [
Top/End]   _page_routines.php
  [56]  function page_end($footer=' ') {
  [57]  page_table_close();
  [58]  timer();
  [59]  if ($GLOBALS['database_connection']) mysqli_close($GLOBALS['database_connection']);
  [60]  print_flash('notice');
  [61]  print_flash('error');
  [62]  print_flash('trace');
  [63]  if ($footer===' ' && $GLOBALS['gpl']) print br(small(italic("An " . alink('open-source','_gpl.php') .
  [64]  " site  --  " . "Problems/suggestions?  Notify <a href='mailto:hunter@ellinger.org'>hunter@ellinger.org</a>")),1);
  [65]  $navigation = $GLOBALS['home_url'] ? alink('Home',$GLOBALS['home_url']) : '';
  [66]  $instructions = $GLOBALS['instructions_url'] && file_exists($GLOBALS['instructions_url']) ?
  [67]  spaces(5) . alink('Instructions/Discussion for this page',$GLOBALS['instructions_url']) : '';
  [68]  $navigation .= $instructions;
  [69]  if ($navigation) print "$navigation<br>" . small(small('(use ' . ($instructions ? 'one of these links' : 'this link') . ' instead of the Back button)'));
  [70]  print "</font>\n</form>\n</div>\n<a name='End' />\n</body>\n</html>\n";
  [71]  print str_repeat(" \n",50);
  [72]  flush();
  [73]  } [
Top/End]   _page_routines.php
  [74]  function print_flash($tag) {
  [75]  $s = sv_set($tag);
  [76]  if ($s) print table(15,tr(td(substr($s,0,-5),$tag)));
  [77]  return $s;
  [78]  } [
Top/End]   _page_routines.php
  [79]  function trace($tag='',$sequence_of_values='') { // trace variable values; can be called prior to HTML output
  [80]  $args = func_get_args();
  [81]  if (count($args) > 0) {
  [82]  if (count($args) === 1) { // two alternatives for tag-only calls; both use recursion
  [83]  if (!is_array($tag) && substr($tag,0,1)==='$') { // trace globals if named in tag
  [84]  foreach (explode(',',$tag) as $name) {
  [85]  $value = isset($GLOBALS[substr($name,1)]) ? $GLOBALS[substr($name,1)] : 'undefined';
  [86]  trace($name,$value);
  [87]  }
  [88]  } else trace ('',$tag); // otherwise simply trace tag content
  [89]  }
  [90]  foreach (array_slice($args,1) as $value) { // 2 or more arguments
  [91]  if (is_array($value)) $value = string_r($value);
  [92]  if ($tag) $tag .= ': ';
  [93]  $_SESSION['trace'] .= bold(htmlspecialchars($tag)) . htmlspecialchars($value) . "<br>\n";
  [94]  }
  [95]  } else { // no-argument call shows request variables
  [96]  if ($_GET) trace('GET',$_GET);
  [97]  if ($_POST) trace('POST',$_POST);
  [98]  }
  [99]  } [
Top/End]   _page_routines.php
 [100]  function error($text) {if ($text) $_SESSION['error'] .= "$text<br>\n"; $GLOBALS['error'] = $_SESSION['error'];} [
Top/End]   _page_routines.php
 [101]  function notice($text) {if ($text) $_SESSION['notice'] .= "$text<br>\n";} [
Top/End]   _page_routines.php
 [102]  function bailout($text='',$redirect='index.php') {error($text); redirect($redirect);} [
Top/End]   _page_routines.php
 [103]  function quit($text='') {error($text); page_end(); exit;} [
Top/End]   _page_routines.php
 [104]  function require_password($passwords=array(),$site='') {
 [105]  if (!$passwords) $passwords = array($GLOBALS['database_password']);
 [106]  if (rq1('logoff')) session_destroy(); // will force logon page
 [107]  foreach ($passwords as $key=>$password) {if ($password === $_SESSION['password']) return csplit($key);} // already logged on
 [108]  $pwd = rq('password');
 [109]  foreach ($passwords as $password) {
 [110]  if (same($password,$pwd)) {
 [111]  $_SESSION['password'] = $password; // successful log-on attempt
 [112]  redirect(); // return to the same page without POST
 [113]  }
 [114]  }
 [115]  if ($pwd) error('Invalid Password');
 [116]  $GLOBALS['hide_site_banner'] = TRUE;
 [117]  page_start("Enter $site Password");
 [118]  print br(passwordbox() . '   ' . commandbutton('Submit Password'),2,2);
 [119]  page_end('');
 [120]  exit;
 [121]  } [
Top/End]   _page_routines.php
 [122]  function logoff() {
 [123]  $_SESSION = array();
 [124]  if (isset($_COOKIE[session_name()])) setcookie(session_name(),'',time()-42000,'/');
 [125]  session_destroy();
 [126]  } [
Top/End]   _page_routines.php
 [127]  function logon_required($reason='') {if (!$GLOBALS['user_id']) bailout("User lacks privilege to " . coalesce($reason,"view $GLOBALS[current_page]"));} [
Top/End]   _page_routines.php
 [128]  function has_privilege($privilege) {return (contains($_SESSION['privileges'],$privilege) || contains($_SESSION['privileges'],'All'));} [
Top/End]   _page_routines.php
 [129]  function privilege_required($privilege,$reason='') {
 [130]  if (!has_privilege($privilege)) bailout("User lacks privilege to " . coalesce($reason,"view $GLOBALS[current_page]"));
 [131]  }
 [137]  ?>

FILE: _site_unzip.php - 52 lines, 0 functions [
Top/End]
  [1]  <html>
  [2]  <head><title>Site Unzip</title></head>
  [3]  <body bgcolor=aqua>
  [4]  <form method=POST action='_unzip_site.php'>
  [5]  <div align=center>
  [6]  <font face="Verdana">
  [7]  <h3>UNZIP WEBSITE</h3>
  [8]  Copy the contents of the CODE textarea in the _gpl.php page on the source website into this textarea<br>
  [9]  <textarea name='code' id='code' rows=10 cols=120 wrap=off></textarea><br><br>
  [10]  <input name='command' type=submit value='Install Files From Code Copy'>
  [11]        <label><input type=check name='replace' value=1>Replace existing files</label><br>
  [12]  <?php // This is a no-dependencies script for use in copying a website; it will not replace existing files unless specified
  [13]  if ($_POST) {
  [14]  $file_separator = "\n~~~~~~~~~~ combined by _gpl.php - "; // must match that in _gpl.php
  [15]  print "<table><tr><td>\n";
  [16]  $files = $created = $already = $replaced = $errors = 0;
  [17]  $replace = $_POST['replace'];
  [18]  $file_contents = explode($file_separator,$_POST['code']);
  [19]  array_shift($file_contents); // discard first, before-separator content piece
  [20]  foreach ($file_contents as $file_content) {
  [21]  $newline = strpos($file_content,"\n");
  [22]  if (!$newline) continue;
  [23]  $filename = trim(substr($file_content,0,$newline));
  [24]  if (!ctype_alnum($filename[0]) && $filename[0]!=='_' && $filename[0]!=='/' && $filename[0]!=='.') continue;
  [25]  $files++;
  [26]  $exists = file_exists($filename);
  [27]  if (!$replace && $exists) {$already++; print "Already exists in this directory: <b>$filename</b>";}
  [28]  else {
  [29]  $handle = fopen($filename,'w');
  [30]  $size = fwrite($handle,substr($file_content,$newline+1));
  [31]  if ($size !== FALSE) {
  [32]  print ($exists ? 'Replaced' : 'Created') . " <b>$filename</b> (" . number_format($size) . " bytes)";
  [33]  if ($exists) $replaced++; else $created++;
  [34]  } else {$errors++; print "Error when writing: <b>$filename</b>";}
  [35]  fclose($handle);
  [36]  }
  [37]  print "<br>\n";
  [38]  }
  [39]  print "</td></tr></table>\n<br><br>\n";
  [40]  print "INSTALLATION COMPLETE<br>Files: $files, Created: $created, Replaced $replaced, Retained: $already, Errors: $errors<br>\n";
  [41]  }
  [47]  ?>
  [48]  </font>
  [49]  </div>
  [50]  </form>
  [51]  </body>
  [52]  </html>
FILE: _statistics.php - 1405 lines, 130 functions [
Top/End]
  [1]  <?php
  [2]  require_once '_all_sites.php';
  [3]  require_once '_svg.php';
  [4]  $gpl = TRUE;
  [5]  //// DISTRIBUTION FUNCTIONS [
Top/End]   _statistics.php
  [6]  function make_array_into_pdf($array,$area=1) {
  [7]  $sum = 0;
  [8]  foreach ($array as $value) $sum += $value;
  [9]  $normalization = $sum ? $area/$sum : $area;
  [10]  $pdf = array();
  [11]  foreach ($array as $value) $pdf[] = $value * $normalization;
  [12]  return $pdf;
  [13]  }
  [14]  $gaussian_normalization_coefficient = 1/sqrt(2*pi()); [
Top/End]   _statistics.php
  [15]  function gaussian($x,$center=0,$sigma=1,$area=1) {
  [16]  global $gaussian_normalization_coefficient;
  [17]  if ($sigma <= 0) return $center;
  [18]  $v = ($x-$center)/$sigma;
  [19]  return ($area * exp(-0.5*$v*$v)/$sigma * $gaussian_normalization_coefficient);
  [20]  }
  [21]  $gaussian = array('pdf'=>array(),'cdf'=>array(),'size'=>0,'sigmas_low'=>0,'sigmas_high'=>0); [
Top/End]   _statistics.php
  [22]  function make_gaussian_array($size=1000,$sigmas_low=-3,$sigmas_high=3,$area=1) {
  [23]  global $gaussian,$gaussian_normalization_coefficient;
  [24]  $array = array();
  [25]  if ($size>0 && $sigmas_low<$sigmas_high) {
  [26]  $h = $area * $gaussian_normalization_coefficient;
  [27]  $dx = ($sigmas_high-$sigmas_low)/$size;
  [28]  for ($x=$sigmas_low+$dx/2; $x<$sigmas_high; $x+=$dx) $array[] = $h*exp(-0.5*$x*$x);
  [29]  $gaussian = array('pdf'=>$array,'cdf'=>array(),'size'=>$size,'sigmas_low'=>$sigmas_low,'sigmas_high'=>$sigmas_high);
  [30]  }
  [31]  return $array;
  [32]  } [
Top/End]   _statistics.php
  [33]  function scale_array_height($array,$height=1) {
  [34]  $scaled_array = array();
  [35]  if ($array) {
  [36]  $max = max($array);
  [37]  if ($max <= 0) return $array;
  [38]  foreach ($array as $value) $scaled_array[] = $height/$max*$value;
  [39]  }
  [40]  return $scaled_array;
  [41]  } [
Top/End]   _statistics.php
  [42]  function basic_uniform($x) {return (($x>=0 && $x<1) ? 1 : 0);} [
Top/End]   _statistics.php
  [43]  function basic_exponential($x) {return ($x<=0 ? 0 : exp(-$x));} [
Top/End]   _statistics.php
  [44]  function basic_normal($x) {return /*exp(-0.5*$x*$x)*/ gaussian($x);} [
Top/End]   _statistics.php
  [45]  function basic_overlap($x) {return (basic_normal(1.5*$x-1.25)+2.5*basic_normal(2*$x+1.25));} [
Top/End]   _statistics.php
  [46]  function basic_binomial($x) {return (abs($x)<0.05 || abs($x-1)<0.05 ? 1 : 0);} [
Top/End]   _statistics.php
  [47]  function basic_comb($x) {$i = round($x*50); return (($i<0 || $i>=50 || $i%5!=2) ? 0 : 1);} [
Top/End]   _statistics.php
  [48]  function basic_wedge($x) {return (($x>=0 && $x<1) ? 2*$x : 0);} [
Top/End]   _statistics.php
  [49]  function basic_notch($x) {return (($x>=0 && $x<1) ? 4*abs(0.5-$x) : 0);} [
Top/End]   _statistics.php
  [50]  function basic_triangle($x) {return (($x>=0 && $x<1) ? 4*(0.5-abs(0.5-$x)) : 0);} [
Top/End]   _statistics.php
  [51]  function basic_triangles($x) {return (basic_triangle(2*$x+0.25)+basic_triangle(2*$x-0.75));}

  [52]  //// BETA DISTRIBUTIONS [
Top/End]   _statistics.php
  [53]  function unscaled_beta_value($x,$alpha,$beta) {
  [54]  if ($x<=0 || $x>=1) return 0;
  [55]  return (pow($x,($alpha-1)) * pow((1-$x),($beta-1)));
  [56]  }
  [57]  $beta_array_size = 1000; [
Top/End]   _statistics.php
  [58]  function make_beta_distribution($alpha,$beta,$name='beta') {
  [59]  global $beta_distributions,$beta_array_size;
  [60]  if ($alpha<=0 || $beta<=0) return 0;
  [61]  $pdf = $cdf = $icdf = array();
  [62]  $dx=1/$beta_array_size;
  [63]  for ($x=$dx/2,$sum=0; $x<1; $x+=$dx) {
  [64]  $pdf[] = $value = unscaled_beta_value($x,$alpha,$beta);
  [65]  $sum += $value;
  [66]  $cdf[] = $sum;
  [67]  }
  [68]  for ($i=0; $i<$beta_array_size; $i++) {$pdf[$i] /= $sum/$beta_array_size; $cdf[$i] /= $sum;}
  [69]  $x = $yy = $vv = $y = $v = 0;
  [70]  for ($i=0; $i<$beta_array_size; $i++,$x+=$dx,$yy=$y,$vv=$v) {
  [71]  $y = $yy;
  [72]  while (TRUE) {$v = $cdf[$y]; if ($v >= $x) break; if (++$y >= $beta_array_size) {$v = 1; break;}}
  [73]  $f = $v>$vv ? ($v-$x)/($v-$vv) : 0;
  [74]  $icdf[$i] = ($yy*$f + $y*(1-$f)) / $beta_array_size;
  [75]  }
  [76]  $beta_distributions[$name] = array('pdf'=>$pdf,'cdf'=>$cdf,'icdf'=>$icdf,'alpha'=>$alpha,'beta'=>$beta,'normalization'=>1/$sum);
  [77]  return $pdf;
  [78]  } [
Top/End]   _statistics.php
  [79]  function make_beta_data($count,$name='beta',$minimum=0,$maximum=1) {
  [80]  global $beta_distributions,$beta_array_size;
  [81]  $data = array();
  [82]  if (isset($beta_distributions[$name]['icdf'])) {
  [83]  $icdf = $beta_distributions[$name]['icdf'];
  [84]  $width = $maximum - $minimum;
  [85]  for ($i=0; $i<$count; $i++) {
  [86]  $y = interpolated($icdf,random_float(0,$beta_array_size-1),0,1);
  [87]  $data[$i] = ($y * $width + $minimum);
  [88]  }
  [89]  }
  [90]  return $data;
  [91]  }
  [92]  $bellshaped_alpha = $bellshaped_beta = 6; [
Top/End]   _statistics.php
  [93]  function basic_bellshaped($x) {
  [94]  global $bellshape_alpha,$bellshape_beta,$bellshape_scalefactor;
  [95]  return (unscaled_beta_value($x,$bellshape_alpha,$bellshape_beta) * $bellshape_scalefactor);
  [96]  }
  [97]  $skewed_alpha = 1.5; $skewed_beta = 3.7; [
Top/End]   _statistics.php
  [98]  function basic_skewed($x) {
  [99]  global $skewed_alpha,$skewed_beta,$skewed_scalefactor;
 [100]  return (unscaled_beta_value($x,$skewed_alpha,$skewed_beta) * $skewed_scalefactor);
 [101]  } [
Top/End]   _statistics.php
 [102]  function make_bellshaped_distribution() {
 [103]  make_beta_distribution($GLOBALS['bellshaped_alpha'],$GLOBALS['bellshaped_beta']);
 [104]  } [
Top/End]   _statistics.php
 [105]  function make_bellshaped_data($count,$minimum=0,$maximum=1) {
 [106]  return make_beta_data($count,'bellshaped',$minimum,$maximum);
 [107]  } [
Top/End]   _statistics.php
 [108]  function make_skewed_distribution() {make_beta_distribution($GLOBALS['skewed_alpha'],$GLOBALS['skewed_beta']);} [
Top/End]   _statistics.php
 [109]  function make_skewed_data($count,$minimum=0,$maximum=1) {
 [110]  return make_beta_data($count,'skewed',$minimum,$maximum);
 [111]  } [
Top/End]   _statistics.php
 [112]  function beta_distribution($alpha,$beta,$count,$total=1) {
 [113]  if ($count<=0 || $alpha<=0 || $beta<=0) return array();
 [114]  $distribution = array();
 [115]  for ($dx=1/$count,$x=$dx/2,$sum=0; $x<1; $x+=$dx) {
 [116]  $distribution[] = $value = unscaled_beta_value($x,$alpha,$beta);
 [117]  $sum += $value;
 [118]  }
 [119]  $scale = $sum ? $total/$sum : 0;
 [120]  foreach ($distribution as $i=>$value) $distribution[$i] = $value * $scale;
 [121]  return $distribution;
 [122]  } [
Top/End]   _statistics.php
 [123]  function beta_function($alpha,$beta) { // computes normalization factor for a set of beta parameters
 [124]  if ($alpha<=0 || $beta<=0) return 0;
 [125]  for ($dx=0.001,$x=$dx/2,$sum=0; $x<1; $x+=$dx) $sum += unscaled_beta_value($x,$alpha,$beta);
 [126]  return ($sum ? 1/($sum*$dx) : 0);
 [127]  }

 [128]  //// DATA SIMULATION [
Top/End]   _statistics.php
 [129]  function make_gaussian_data($count=100,$center=0,$sigma=1,$width=0) {
 [130]  $data = array();
 [131]  if ($sigma<=0 || $width<0) { // return center value in degenerate cases
 [132]  for ($i=0; $i<$count; $i++) $data[] = $center;
 [133]  } else {
 [134]  $sigmas = $width ? $width/2/$sigma : 100;
 [135]  $outsiders_limit = $count/$sigmas*2 + 100;
 [136]  $i = $outsiders = 0;
 [137]  while ($i < $count) {
 [138]  $v = inverse_ncdf();
 [139]  if (abs($v) < $sigmas) $data[$i++] = $v * $sigma + $center;
 [140]  else {if (++$outsiders>$outsiders_limit) break;}
 [141]  }
 [142]  }
 [143]  return $data;
 [144]  } [
Top/End]   _statistics.php
 [145]  function make_uniform_data($count=100,$min=0,$max=1) {
 [146]  $data = array();
 [147]  for ($i=0; $i<$count; $i++) $data[] = random_float($min,$max);
 [148]  return $data;
 [149]  } [
Top/End]   _statistics.php
 [150]  function make_exponential_data($count=100,$lambda=1,$offset=0,$max=1000000) {
 [151]  $data = array();
 [152]  $i = $outsiders = 0;
 [153]  $outsiders_limit = $count + 100;
 [154]  while ($i < $count) {
 [155]  $v = -log(1-random_fraction());
 [156]  if ($v > $max) {$i--; if (++$outsiders > $outsiders_limit) break;}
 [157]  $data[$i++] = $v / $lambda + $offset;
 [158]  }
 [159]  return $data;
 [160]  } [
Top/End]   _statistics.php
 [161]  function random_scatter_values($count=0,$r='',$scale=100) {
 [162]  if (!$count) $count = rqn('random',25);
 [163]  if ($scale <= 0) $scale = abs($scale) + 1;
 [164]  $slope = random_float(0,2);
 [165]  if ($r === '') $r = random_sign(random_float(0.4,1));
 [166]  $xstart = random_float(-$scale/4,$scale);
 [167]  $ystart = random_float(-$scale/4,$scale);
 [168]  if ($r < 0) {$slope = -$slope; $ystart += $scale;}
 [169]  $xvalues = make_uniform_data($count,$xstart,$xstart+$scale);
 [170]  $ystd = ($r<=-1 || $r>=1) ? 0: $slope*$scale*0.288*sqrt(1-$r*$r);
 [171]  trace('r,ystd',"$r,$ystd");
 [172]  $ynoise = make_gaussian_data($count,0,$ystd,2*$ystd); // will approximately match $r value
 [173]  $xy_pairs = array();
 [174]  foreach ($xvalues as $i=>$x) {
 [175]  $y = $ystart + $x*$slope + $ynoise[$i];
 [176]  $xy_pairs[$i] = array(round($x,2),round($y,2));
 [177]  }
 [178]  return $xy_pairs;
 [179]  } [
Top/End]   _statistics.php
 [180]  function random_scatter_group_data($labels=array('A','B'),$count=0) {
 [181]  if (!$count) $count = rqn('random',25);
 [182]  $lines = array();
 [183]  foreach ($labels as $label) {foreach (random_scatter_values($count) as $pair) $lines[] = "$pair[0] $pair[1] $label";}
 [184]  shuffle($lines);
 [185]  return njoin($lines) . "\n";
 [186]  } [
Top/End]   _statistics.php
 [187]  function noisy_linear_array($count=100,$sigma=1,$start=0,$step=0) {
 [188]  $noise = make_gaussian_data($count,0,$sigma);
 [189]  $data = array();
 [190]  $value = $start;
 [191]  foreach ($noise as $v) {$data[] = $value+$v; $value += $step;}
 [192]  return $data;
 [193]  }
 [194]  //// [
Top/End]   _statistics.php
 [195]  function ncdf($z) { // from http://stackoverflow.com/questions/4304765/how-to-generate-a-cumulative-normal-distribution-in-php
 [196]  $b1 = 0.319381530; $b2 = -0.356563782; $b3 = 1.781477937; $b4 = -1.821255978; $b5 = 1.330274429; $p = 0.2316419; $c = 0.39894228;
 [197]  $t = 1 / (1 + $p * abs($z));
 [198]  $tt = $c * exp(-$z*$z/2) * $t * ($t * ($t * ($t * ($t * $b5 + $b4) + $b3) + $b2) + $b1);
 [199]  return ($z>=0 ? (1 - $tt) : $tt);
 [200]  } [
Top/End]   _statistics.php
 [201]  function inverse_ncdf($p=NULL) { //Input paramater is $p - probability - where 0 < $p < 1.
 [202]  //Inverse ncdf approximation by Peter John Acklam, implementation adapted to PHP by Michael Nickerson, using Dr. Thomas Ziegler's C implementation as a guide. http://home.online.no/~pjacklam/notes/invnorm/index.html
 [203]  //Changes by Hunter Ellinger 2014 (plus non-substantive formatting): default to random input, return -INF or INF for out-of-range $p
 [204]  //Coefficients in rational approximations
 [205]  if (is_null($p)) $p = random_fraction();
 [206]  $a = array(1 => -3.969683028665376e+01, 2 => 2.209460984245205e+02, 3 => -2.759285104469687e+02, 4 => 1.383577518672690e+02, 5 => -3.066479806614716e+01, 6 => 2.506628277459239e+00);
 [207]  $b = array(1 => -5.447609879822406e+01, 2 => 1.615858368580409e+02, 3 => -1.556989798598866e+02, 4 => 6.680131188771972e+01, 5 => -1.328068155288572e+01);
 [208]  $c = array(1 => -7.784894002430293e-03, 2 => -3.223964580411365e-01, 3 => -2.400758277161838e+00, 4 => -2.549732539343734e+00, 5 => 4.374664141464968e+00, 6 => 2.938163982698783e+00);
 [209]  $d = array(1 => 7.784695709041462e-03, 2 => 3.224671290700398e-01, 3 => 2.445134137142996e+00, 4 => 3.754408661907416e+00);
 [210]  $p_low = 0.02425; $p_high = 1 - $p_low; //Define break-points for where to use lower/upper region approximations.
 [211]  if ($p_low <= $p && $p <= $p_high) { //Rational approximation for central region.
 [212]  $q = $p - 0.5;
 [213]  $r = $q * $q;
 [214]  $x = ((((($a[1] * $r + $a[2]) * $r + $a[3]) * $r + $a[4]) * $r + $a[5]) * $r + $a[6]) * $q / ((((($b[1] * $r + $b[2]) * $r + $b[3]) * $r + $b[4]) * $r + $b[5]) * $r + 1);
 [215]  } elseif ($p < $p_low) { //Rational approximation for lower region.
 [216]  if ($p <= 0) return -INF;
 [217]  $q = sqrt(-2 * log($p));
 [218]  $x = ((((($c[1] * $q + $c[2]) * $q + $c[3]) * $q + $c[4]) * $q + $c[5]) * $q + $c[6]) / (((($d[1] * $q + $d[2]) * $q + $d[3]) * $q + $d[4]) * $q + 1);
 [219]  } elseif ($p_high < $p) { //Rational approximation for upper region.
 [220]  if ($p >= 1) return INF;
 [221]  $q = sqrt(-2 * log(1 - $p));
 [222]  $x = -((((($c[1] * $q + $c[2]) * $q + $c[3]) * $q + $c[4]) * $q + $c[5]) * $q + $c[6]) / (((($d[1] * $q + $d[2]) * $q + $d[3]) * $q + $d[4]) * $q + 1);
 [223]  }
 [224]  return $x; //END inverse ncdf implementation.
 [225]  } [
Top/End]   _statistics.php
 [226]  function pdf_mean($array) { // computes weighted-mean index value for a pdf or histogram
 [227]  $sum = $weights = 0;
 [228]  foreach ($array as $i=>$v) {$sum += $i * $v; $weights += $v;}
 [229]  return $weights ? $sum/$weights : 0;
 [230]  } [
Top/End]   _statistics.php
 [231]  function pdf_std($array,$mean='') { // computes standard deviation for a pdf or histogram
 [232]  if ($mean === '') $mean = pdf_mean($array);
 [233]  $sum = $variance = 0;
 [234]  foreach ($array as $i=>$v) {$d = $i-$mean; $variance += $d*$d*$v; $sum += $v;}
 [235]  return $sum ? sqrt($variance)/$sum : 0;
 [236]  } [
Top/End]   _statistics.php
 [237]  function pdf_median($array,$sum=1) { // computes weighted-median index value for a pdf or histogram
 [238]  $sum = array_sum($array);
 [239]  $half_sum = $sum/2;
 [240]  foreach ($array as $i=>$v) {$sum -= $v; if ($sum <= $half_sum) return $i+($half_sum-$sum)/$v;}
 [241]  } [
Top/End]   _statistics.php
 [242]  function interpolated($array,$index_value,$out_of_range_low='',$out_of_range_high='') {
 [243]  $size = count($array);
 [244]  if (!$size) return FALSE;
 [245]  $i = floor($index_value);
 [246]  $j = ceil($index_value);
 [247]  if ($i < 0) return ($out_of_range_low==='' ? $array[0] : $out_of_range_low);
 [248]  if ($j >= $size) return ($out_of_range_high==='' ? $array[$size-1] : $out_of_range_high);
 [249]  if ($i == $j) return $array[$i];
 [250]  return ($array[$i]*($j-$index_value) + $array[$j]*($index_value-$i));
 [251]  } [
Top/End]   _statistics.php
 [252]  function get_sample_distributions($pdf,$samples=array(),$width=0) {
 [253]  $distribution_directory = '/central_limit_distributions';
 [254]  $distribution_directory = './distributions';
 [255]  $pdfs = basic_pdfs();
 [256]  foreach (array_keys($pdfs) as $name) {if (begins($name,$pdf)) {$pdf = $name; break;}}
 [257]  if ($width) {
 [258]  $file = "$distribution_directory/central_limit_$pdf" . substr("0000$width.txt",-8);
 [259]  if (!file_exists($file)) {error("Distribution file $file not found"); return array();}
 [260]  } else {
 [261]  $files = array_reverse(files("$distribution_directory/central_limit_$pdf*.txt"));
 [262]  if (!$files) {error("Distribution file for '$pdf'not found"); return array();}
 [263]  $file = $files[0];
 [264]  $width = num('1' . between($file,$pdf,'.txt')) - 10000;
 [265]  }
 [266]  $f = array();
 [267]  $fh = fopen($file,'r');
 [268]  $f[0] = trim(fgets($fh));
 [269]  $n = 0;
 [270]  $last_n = $samples ? max($samples) : 1000;
 [271]  while ($n++<$last_n && !feof($fh)) {
 [272]  $line = fgets($fh);
 [273]  if (!$samples || in_array($n,$samples)) $f[$n] = csplit(trim($line));
 [274]  }
 [275]  return $f;
 [276]  } [
Top/End]   _statistics.php
 [277]  function subsample($array,$offset=0,$spacing=1,$width=-1) {
 [278]  if ($spacing==0 || !$array) return array();
 [279]  if ($width < 0) $width = round(count($array)/abs($spacing));
 [280]  $sample = array();
 [281]  while ($width-- > 0) {$sample[] = interpolated($array,$offset); $offset += $spacing;}
 [282]  return $sample;
 [283]  } [
Top/End]   _statistics.php
 [284]  function basic_pdfs() {
 [285]  return array('Uniform'=>array(-0.25,1.5),'Normal'=>array(-3,6),'Exponential'=>array(-2,7),
 [286]  'Binomial'=>array(-0.25,1.5),/*'Wedge'=>array(-0.25,1.75),*/'Notch'=>array(-0.25,1.5),'Overlap'=>array(-3,6),
 [287]  'Triangle'=>array(-0.25,1.5),'Triangles'=>array(-0.25,1.5),'Comb'=>array(-0.25,1.5));
 [288]  } [
Top/End]   _statistics.php
 [289]  function sample_user_function($function_name,$count=100,$min=0,$max=1,$middle=FALSE) {
 [290]  $dx = ($max=$min)/$count;
 [291]  $x = $min + ($middle ? $dx/2 : 0);
 [292]  $samples = array();
 [293]  for ($i=0; $i<$count; $i++) {$samples[] = call_user_func($function_name,$x); $x += $dx;}
 [294]  return $samples;
 [295]  } [
Top/End]   _statistics.php
 [296]  function area_partitions($values=array(),$partitions=10) {
 [297]  $areas = make_cumulative_array($values);
 [298]  $n = count($areas);
 [299]  $da = $areas[$n-1] / $partitions;
 [300]  $positions = array(0);
 [301]  for ($i=1; $i<=$n; $i++) $positions[] = inverse_index($areas,$i*$da,$n);
 [302]  return $positions;
 [303]  } [
Top/End]   _statistics.php
 [304]  function make_cumulative_array($array) {
 [305]  $output = array(0);
 [306]  $sum = 0;
 [307]  foreach ($array as $value) {$sum += $value; $output[] = $sum;}
 [308]  return $output;
 [309]  }
 [310]  $last_inverse_index = $previous_inverse_value = 0; [
Top/End]   _statistics.php
 [311]  function inverse_index($cdf=array(),$value,$default=FALSE) { // find interpolated index corresponding to $value's position in a non-decreasing $array
 [312]  $vv = 0;
 [313]  foreach ($cdf as $i=>$v) {
 [314]  if ($v >= $value) {$d = $v - $vv; $r = $d ? ($v-$value)/$d : 0; return ($i-$r);}
 [315]  $vv = $v;
 [316]  }
 [317]  return $default;
 [318]  } [
Top/End]   _statistics.php
 [319]  function inverse_index_iterative($array=array(),$value='',$default=FALSE) { // start search from previously-used index
 [320]  global $last_inverse_index,$previous_inverse_value;
 [321]  $n = count($array); if ($n == 0) return 0;
 [322]  if ($last_inverse_index<0 || $last_inverse_index>=$n) $last_inverse_index = 0;
 [323]  if ($value === '') {$last_inverse_index = 0; $previous_inverse_value = $array[0]; return 0;} // reset
 [324]  while ($last_inverse_index < $n) {
 [325]  $v = $array[$last_inverse_index];
 [326]  if ($v < $value) {$last_inverse_index++; $previous_inverse_value = $v; continue;}
 [327]  $d = $v - $previous_inverse_value;
 [328]  $r = $d ? ($v-$value)/$d : 0;
 [329]  return ($last_inverse_index - $r);
 [330]  }
 [331]  return $default;
 [332]  }
 [333]  $default_percentiles = array(0.01,0.02,0.05,0.10,0.25,0.50,0.75,0.90,0.95,0.98,0.99);
 [334]  $percentile_results = $percentile_indicies = array(); [
Top/End]   _statistics.php
 [335]  function percentile_indicies($histogram,$percentiles='') {
 [336]  if (!$percentiles) $percentiles = $GLOBALS['default_percentiles'];
 [337]  if (!is_array($percentiles)) $percentiles = array_slice(func_get_args(),1);
 [338]  $result = $cdf = $indicies = array();
 [339]  if (!$histogram || min($histogram)<0 || max($histogram)==0) {error('Bad or empty histogram in percentile_indicies'); return FALSE;}
 [340]  $cdf = make_cumulative_array(make_array_into_pdf($histogram));
 [341]  foreach ($percentiles as $p) {if ($p<0 || $p>1) continue; $i = inverse_index($cdf,$p); if ($i !== FALSE) $indicies[] = array($p,$i);}
 [342]  $GLOBALS['percentile_indicies'] = $indicies;
 [343]  return $indicies;
 [344]  } [
Top/End]   _statistics.php
 [345]  function percentile_values($histogram,$percentiles='',$bin_width=1,$min=0,$xscale=1,$xoffset=0) {
 [346]  if (!$percentiles) $percentiles = $GLOBALS['default_percentiles'];
 [347]  $results = array();
 [348]  $indicies = percentile_indicies($histogram,$percentiles);
 [349]  for ($i=0; $i<count($percentiles); $i++) {
 [350]  $width = $indicies[$i][1] * $bin_width;
 [351]  $value = $width + $min;
 [352]  $position = $width * $xscale + $xoffset;
 [353]  $results[] = array('percentile'=>$percentiles[$i],'index'=>$indicies[$i],'value'=>$value,'x'=>$position);
 [354]  }
 [355]  $GLOBALS['percentile_results'] = $results;
 [356]  return $results;
 [357]  } [
Top/End]   _statistics.php
 [358]  function percentile_from_score($score,$histogram,$min=0,$bin_width=1) {
 [359]  $cdf = make_cumulative_array(make_array_into_pdf($histogram));
 [360]  $index = ($score-$min)/$bin_width; // (interpolated) histogram index corresponding to score
 [361]  return interpolated($cdf,$index,0,1); // return corresponding percentile from cdf
 [362]  } [
Top/End]   _statistics.php
 [363]  function score_from_percentile($percentile,$histogram,$min=0,$bin_width=1) {
 [364]  $cdf = make_cumulative_array(make_array_into_pdf($histogram));
 [365]  $index = inverse_index($cdf,$percentile); // (interpolated) index at which cdf equals percentile
 [366]  return ($index===FALSE ? '' : ($min+$index*$bin_width)); // adjust to scale and offset if supplied; return empty string if percentile out of range
 [367]  } [
Top/End]   _statistics.php
 [368]  function uncommented($text) {
 [369]  $data = '';
 [370]  foreach (nsplit($text) as $line) {$s = before($line,'#'); if (trim($s)) $data .= "$s\n";}
 [371]  return $data;
 [372]  } [
Top/End]   _statistics.php
 [373]  function statistics_data_link($data,$label='File containing the data values') {
 [374]  if (is_array($data)) $data = njoin($data);
 [375]  $data_file_header = "# IF YOU WISH TO USE THIS DATA AFTER THIS SESSION, COPY AND SAVE IT NOW.\n" .
 [376]  "# Generated " . numberdatetime() . " in http://$_SERVER[SERVER_NAME]/$_SERVER[PHP_SELF]" ;
 [377]  $filename = './session_data_files/data-' . session_id() . '.txt';
 [378]  file_write_contents($filename,"$data_file_header\n\n$data");
 [379]  return (uncommented($data) ? small("<a href='$filename' target=_blank>$label</a>") : '');
 [380]  } [
Top/End]   _statistics.php
 [381]  function correlation_coefficient($xarray,$yarray) {
 [382]  $count = min(count($xarray),count($yarray));
 [383]  if ($count < 2) {error('Too few points to compute correlation'); return FALSE;}
 [384]  $xmean = average($xarray); $ymean = average($yarray);
 [385]  for ($i=0,$sum=0; $i<$count; $i++) $sum += ($xarray[$i]-$xmean) * ($yarray[$i]-$ymean);
 [386]  return ($sum/($count-1)/standard_deviation($xarray)/standard_deviation($yarray));
 [387]  } [
Top/End]   _statistics.php
 [388]  function linear_slope($xarray,$yarray) {
 [389]  $count = count($xarray);
 [390]  $sumx = $sumy = $sumxy = $sumx2 = $sumy2 = $rsum = 0;
 [391]  for ($i=0; $i<$count; $i++) {
 [392]  $x = $xarray[$i]; $sumx += $x; $sumx2 += $x*$x;
 [393]  $y = $yarray[$i]; $sumy += $y; $sumy2 += $y*$y;
 [394]  $sumxy += $x*$y;
 [395]  }
 [396]  $denominator = $count*$sumx2 - $sumx*$sumx;
 [397]  $numerator = $count*$sumxy - $sumx*$sumy;
 [398]  $slope = $denominator ? $numerator/$denominator : INF;
 [399]  return $slope;
 [400]  } [
Top/End]   _statistics.php
 [401]  function linear_intercept($xarray,$yarray) {
 [402]  return (average($yarray)-average($xarray)*linear_slope($xarray,$yarray));
 [403]  } [
Top/End]   _statistics.php
 [404]  function exponential_rate($xarray,$yarray) { // use linear fit to semi-log
 [405]  return (exp(linear_slope($xarray,logarithms($yarray))) - 1);
 [406]  } [
Top/End]   _statistics.php
 [407]  function exponential_intercept($xarray,$yarray) {
 [408]  $count = count($xarray);
 [409]  $base = 1 + exponential_rate($xarray,$yarray);
 [410]  for ($i=count($xarray)-1,$sum=0; $i>=0; $i--) $sum += $yarray[$i]/pow($base,$xarray[$i]);
 [411]  return ($sum/$count);
 [412]  } [
Top/End]   _statistics.php
 [413]  function logarithms($array) {
 [414]  foreach ($array as $index=>$value) $array[$index] = log($value);
 [415]  return $array;
 [416]  } [
Top/End]   _statistics.php
 [417]  function x_in_pixels($x) {
 [418]  global $xoffset,$xscale,$low;
 [419]  return (($x-$low)*$xscale + $xoffset);
 [420]  }
 [421]  // T statistic [
Top/End]   _statistics.php
 [422]  function t_statistic($array1,$array2) {
 [423]  if (!is_array($array1) || !is_array($array2)) return FALSE;
 [424]  return ((average($array1)-average($array2)) / sqrt(standard_deviation($array1)/count($array1)+standard_deviation($array2)/count($array2)));
 [425]  }
 [426]  // GRANULARITY [
Top/End]   _statistics.php
 [427]  function step_from_value($value,$granularity=0.05) {
 [428]  if (!$value || !is_numeric($value) || !$granularity || !is_numeric($granularity)) return 1; // use step=1 if arguments invalid
 [429]  $abs = abs($value);
 [430]  $grain = $abs*$granularity; // find the preferred step size, before rounding it to integer or few-significant-digit form
 [431]  if ($abs==floor($abs) && $grain<1.5) return 1; // use step=1 if value is a small-enough integer
 [432]  if ($grain > .75) return round($grain); // if implied step is large enough, round to the nearest integer
 [433]  $powerOf10 = pow(10,floor(log10($grain))); // otherwise find the largest power of 10 still less than the grain size
 [434]  $grain = $grain/$powerOf10; // increase to a number in the range 0.1<=n<1.0
 [435]  return round($grain,($grain>.3 ? 1 : 2)) * $powerOf10; // for small values, use decimal-fraction steps with 1 or 2 significant digits
 [436]  } [
Top/End]   _statistics.php
 [437]  function granularity125($approximate_granularity,$split=TRUE) {
 [438]  if ($approximate_granularity <= 0) return 1;
 [439]  $granularity = pow(10,floor(log10($approximate_granularity)));
 [440]  if (!$split) return (3.16*$granularity>$approximate_granularity ? $granularity : 10*$granularity);
 [441]  $difference = $approximate_granularity - $granularity;
 [442]  foreach (array(2*$granularity,5*$granularity,10*$granularity) as $g) {
 [443]  $d = abs($approximate_granularity - $g);
 [444]  if ($d < $difference) {$difference = $d; $granularity = $g;}
 [445]  }
 [446]  return $granularity;
 [447]  } [
Top/End]   _statistics.php
 [448]  function multiple($value,$granularity=1,$rounding_direction=0) {
 [449]  $multiple = $granularity ? $value/$granularity : 0;
 [450]  if ($rounding_direction == 0) return (round($multiple)*$granularity);
 [451]  if ($rounding_direction < 0) return (floor($multiple)*$granularity);
 [452]  if ($rounding_direction > 0) return (ceil($multiple)*$granularity);
 [453]  } [
Top/End]   _statistics.php
 [454]  function close_simple_value($value,$tolerance_ratio=0.05,$rounding_direction=0) {
 [455]  if ($value==round($value) || !$tolerance_ratio) return $value; // leave integers unchanged
 [456]  $granularity = close_simple_granularity($value,$tolerance_ratio);
 [457]  return multiple($value,$granularity,$rounding_direction);
 [458]  } [
Top/End]   _statistics.php
 [459]  function close_simple_granularity($value,$tolerance_ratio=0.05) {
 [460]  if (!$value) return 1;
 [461]  $grain = abs($value) * abs($tolerance_ratio); // infer approximate granularity from value
 [462]  $powerOf10 = pow(10,floor(log10($grain))); // find the largest power of 10 still less than the grain size
 [463]  $grain_fraction = $grain/$powerOf10; // will be a number in the range 0.1<=n<1.0
 [464]  if ($grain_fraction < 0.2) $grain_fraction = multiple($grain_fraction,0.01);
 [465]  elseif ($grain_fraction < 0.5) $grain_fraction = multiple($grain_fraction,0.05);
 [466]  else $grain_fraction = multiple($grain_fraction,0.1);
 [467]  $granularity = $grain_fraction * $powerOf10; // for small values, use decimal-fraction steps with 1 or 2 significant digits
 [468]  return $granularity;
 [469]  }
 [470]  // potential _general_utilities functions [
Top/End]   _statistics.php
 [471]  function array_trim($array,$lower=0,$upper=FALSE,$preserve_keys=FALSE,$use_lower=TRUE,$use_upper=TRUE) { // drops out-of-range values
 [472]  $output = array();
 [473]  foreach ($array as $key=>$value) {
 [474]  if ($lower!==FALSE) {if ($value<$lower || ($value==$lower && $use_lower!==TRUE)) continue;}
 [475]  if ($upper!==FALSE) {if ($value>$upper || ($value==$upper && $use_upper!==TRUE)) continue;}
 [476]  if ($preserve_keys) $output[$key] = $value; else $output[] = $value;
 [477]  }
 [478]  return $output;
 [479]  } [
Top/End]   _statistics.php
 [480]  function array_squeeze($array,$lower,$upper) { // sets out-of-range values to closer range boundary value
 [481]  foreach ($array as $key=>$value) {
 [482]  if ($value < $lower) $array[$key] = $lower;
 [483]  if ($value > $upper) $array[$key] = $upper;
 [484]  }
 [485]  return $array;
 [486]  } [
Top/End]   _statistics.php
 [487]  function array_rescale($array,$scale=1,$zero=0) {
 [488]  foreach ($array as $key=>$value) $array[$key] = ($array[$key]-$zero)*$scale;
 [489]  return $array;
 [490]  } [
Top/End]   _statistics.php
 [491]  function extract_numbers($text,$delimiter='') {
 [492]  global $extracted_number_places,$number_places,$number_places_typical;
 [493]  if (!$delimiter) $delimiter = find_delimiter($text);
 [494]  $text = str_replace("\n",' ',$text);
 [495]  $text = str_replace("\r",' ',$text);
 [496]  $text = str_replace("\t",' ',$text);
 [497]  $numbers = $number_places = array();
 [498]  foreach(wsplit($text) as $item) {
 [499]  $number = extract_number($item);
 [500]  $places = $extracted_number_places;
 [501]  if ($number !== FALSE) {
 [502]  $numbers[] = $number;
 [503]  $number_places[$places] = isset($number_places[$places]) ? $number_places[$places]+1 : 1;
 [504]  }
 [505]  }
 [506]  $n = 0.75 * count($numbers); // 75% of numbers will have no more decimal places than the the number of places to be reported as typical
 [507]  $number_places_typical = 0;
 [508]  foreach ($number_places as $places=>$count) {$number_places_typical = $places; $n -= $count; if ($n <= 0) break;}
 [509]  return $numbers;
 [510]  } [
Top/End]   _statistics.php
 [511]  function extract_number($text,$default=FALSE) {
 [512]  $number = '';
 [513]  $points = $digits = $places = 0;
 [514]  foreach (str_split($text) as $char) {
 [515]  if ($char===',' || !ctype_graph($char)) continue; // ignore commas and whitespace
 [516]  if (ctype_digit($char)) {$number .= $char; $digits++; if ($points) $places++; continue;} // collect digits in order
 [517]  if ($digits+$points == 0) { // notice +/- signs only before any digits or decimal points
 [518]  if ($char === '+') continue;
 [519]  if ($char === '-') {$number = $char; continue;}
 [520]  }
 [521]  if ($char==='.' && $points==0) {$points++; $number .= $char; continue;} // collect only the first decimal point
 [522]  if ($digits > 0) break; // when non-numeric character found: ignore if before digits, stop extraction if after
 [523]  }
 [524]  $GLOBALS['extracted_number_places'] = $places; // track the number of decimal places in the text
 [525]  return ($digits ? $number : $default); // require that at least one digit be found
 [526]  } [
Top/End]   _statistics.php
 [527]  function extract_categorized_numbers($text) {
 [528]  $text = substitute_minus($text);
 [529]  $results = $instances = array();
 [530]  foreach (nsplit(rtrim($text)) as $line) {
 [531]  $items = wsplit($line);
 [532]  if (count($items)>1 && $items[0] && is_numeric($items[1])) {
 [533]  $results[$items[0]][] = $items[1];
 [534]  $instances[$items[0]] = isset($instances[$items[0]]) ? $instances[$items[0]]+1 : 1;
 [535]  }
 [536]  }
 [537]  array_multisort($instances,SORT_DESC,$results); // so most populated categories are first
 [538]  return $results;
 [539]  } [
Top/End]   _statistics.php
 [540]  function extract_numbers2D($text) {
 [541]  global $numbers2D_min_items,$numbers2D_max_items,$numbers2D_rows,$numbers2D_columns,$numbers2D_short,$numbers2D_long;
 [542]  $numbers2D = $numbers2D_columns = array();
 [543]  $numbers2D_mincolumns = strlen($text);
 [544]  $numbers2D_maxcolumns = 0;
 [545]  foreach (nsplit(rtrim($text)) as $line) {
 [546]  $numbers = extract_numbers($line);
 [547]  if (!$numbers) continue;
 [548]  $numbers2D[] = $numbers;
 [549]  $numbers2D_columns[] = count($numbers);
 [550]  }
 [551]  $numbers2D_min_items = $numbers2D_columns ? min(array_keys($numbers2D_columns)) : 0;
 [552]  $numbers2D_max_items = $numbers2D_columns ? max(array_keys($numbers2D_columns)) : 0;
 [553]  $numbers2D_short = $numbers2D_columns ? count($numbers2D)-$numbers2D_columns[$numbers2D_max_items] : 0;
 [554]  return $numbers2D;
 [555]  } [
Top/End]   _statistics.php
 [556]  function extract_columns($line,$columns,$separator="\t") {
 [557]  if (!$columns) return $line;
 [558]  $line_items = gsplit($separator,$line);
 [559]  $items = array();
 [560]  foreach ($columns as $column) {$index = $column-1; $items[] = isset($line_items[$index]) ? $line_items[$index] : '';}
 [561]  return gjoin($separator,$items);
 [562]  } [
Top/End]   _statistics.php
 [563]  function transposed_array($array2D,$default='',$width='',$height='') {
 [564]  if (!is_numeric($width)) $width = count($array2D);
 [565]  if (!is_numeric($height)) {$height = 0; foreach ($array2D as $array) $height = max($height,count($array));}
 [566]  $transposed = array();
 [567]  foreach ($array2D as $i=>$array) {
 [568]  foreach ($array as $j=>$value) $transposed[$j][$i] = $value;
 [569]  for ($j=count($array); $j<$height; $j++) $transposed[$j][$i] = $default;
 [570]  }
 [571]  return $transposed;
 [572]  } [
Top/End]   _statistics.php
 [573]  function array_rectangle($array2D,$default='',$width='',$height='') {
 [574]  $array_rectangle = array();
 [575]  if (!is_numeric($height)) $height = count($array2D);
 [576]  if (!is_numeric($width)) {$width = 0; foreach ($array2D as $array) $width = max($width,count($array));}
 [577]  foreach ($array2D as $array) {
 [578]  for ($j=count($array); $j<$width; $j++) $array[] = $default;
 [579]  $array_rectangle[] = $array;
 [580]  }
 [581]  return $array_rectangle;
 [582]  } [
Top/End]   _statistics.php
 [583]  function xy_arrays($text,$swap_columns=FALSE) {
 [584]  $xarray = $yarray = array();
 [585]  foreach (xy_array($text,$swap_columns) as $pair) {$xarray[] = $pair[0]; $yarray[] = $pair[1];}
 [586]  return array($xarray,$yarray);
 [587]  } [
Top/End]   _statistics.php
 [588]  function xy_array($text,$swap_columns=FALSE) {
 [589]  global $numbers2D_min_items,$numbers2D_max_items,$numbers2D_rows,$numbers2D_columns,$numbers2D_short,$numbers2D_long;
 [590]  $xy_array = array();
 [591]  $numbers2D_short = $numbers2D_long = 0;
 [592]  $array = extract_numbers2D($text);
 [593]  if ($numbers2D_rows < $numbers2D_columns) $array = transposed_array($array,'',2);
 [594]  foreach ($array as $pair) {
 [595]  if (count($pair) == 2) $xy_array[] = $swap_columns ? array($pair[1],$pair[0]) : $pair;
 [596]  elseif (count($pair) < 2) $numbers2D_short++;
 [597]  else $numbers2D_long++;
 [598]  }
 [599]  return $xy_array;
 [600]  } [
Top/End]   _statistics.php
 [601]  function xy_array_basic_old($text,$swap=FALSE) { // returns array of pairs of two numbers from each row
 [602]  global $numbers2D_min_items,$numbers2D_max_items,$numbers2D_rows,$numbers2D_columns,$numbers2D_short,$numbers2D_long;
 [603]  data_legends($text,$swap); // will save column headings if present
 [604]  $xy_array = array();
 [605]  foreach (nsplit($text) as $i=>$line) {
 [606]  if (strtolower($line) !== strtoupper($line)) continue;
 [607]  $nn = extract_numbers($line);
 [608]  if (count($nn) >= 2) $xy_array[] = $swap ? array($nn[1],$nn[0]) : array($nn[0],$nn[1]);
 [609]  }
 [610]  return $xy_array;
 [611]  } [
Top/End]   _statistics.php
 [612]  function xy_array_basic($text,$swap=FALSE) { // returns array of pairs of two numbers from each row
 [613]  global $legends_found;
 [614]  $text = drop_extra_spaces($text);
 [615]  $delimiter = find_delimiter($text,FALSE);
 [616]  data_legends(before($text,"\n"),$swap,FALSE,$delimiter); // will save column headings if present
 [617]  if ($legends_found) $text = after($text,"\n"); // drop first line if column headings found
 [618]  $xy_array = array();
 [619]  foreach (nsplit($text) as $line) {
 [620]  if (strtolower($line) !== strtoupper($line)) continue;
 [621]  $nn = extract_numbers($line);
 [622]  if (count($nn) >= 2) $xy_array[] = $swap ? array($nn[1],$nn[0]) : array($nn[0],$nn[1]);
 [623]  }
 [624]  return $xy_array;
 [625]  } [
Top/End]   _statistics.php
 [626]  function priority_data_split($text) { // splits text lines and columns, with column delimiter inferred -- priority to tabs, then spaces, then commas
 [627]  $text = drop_extra_spaces($text);
 [628]  $delimiter = find_delimiter($text);
 [629]  $splitlines = array();
 [630]  foreach (nsplit($text) as $line) {
 [631]  $items = explode($delimiter,$line);
 [632]  foreach ($items as $i=>$item) $items[$i] = trim($item); // trim whitespace from all items
 [633]  $splitlines[] = $items; // build 2-D output array of rows and column items
 [634]  }
 [635]  return $splitlines;
 [636]  } [
Top/End]   _statistics.php
 [637]  function find_delimiter($text,$extra_spaces_dropped=TRUE) {
 [638]  if (!$extra_spaces_dropped) $text = drop_extra_spaces($text);
 [639]  $counts = count_chars($text); // form character-count array
 [640]  $returns = $counts[ord("\n")];
 [641]  if ($counts[ord("\t")] > $returns/2) $delimiter = "\t"; // tabs are used as delimiters if present in most lines
 [642]  elseif ($counts[ord(',')]>$returns/2 && $counts[ord(',')]>$counts[ord(' ')] && $counts[ord(' ')]<$returns) $delimiter = ',';
 [643]  else $delimiter = ' '; // if not tabs, spaces used as delimiters if present in all lines or if too few commas
 [644]  return $delimiter;
 [645]  } [
Top/End]   _statistics.php
 [646]  function drop_extra_spaces($text) {
 [647]  $text = trim($text);
 [648]  if (strpos($text,' ') !== FALSE) {
 [649]  while (strpos($text,' ') !== FALSE) $text = str_replace(' ',' ',$text); // drop spaces that immediately follow other spaces
 [650]  $text = str_replace(', ',',',$text); // drop spaces that immediately follow commas
 [651]  $text = str_replace(" \n","\n",$text); // drop spaces at the end of lines
 [652]  $text = str_replace(" \t","\t",$text); // drop spaces that immediately precede tabs
 [653]  $text = str_replace("\t ","\t",$text); // drop spaces that immediately follow tabs
 [654]  }
 [655]  return $text;
 [656]  } [
Top/End]   _statistics.php
 [657]  function data_legends($data,$swap=FALSE,$numeric=FALSE,$delimiter='') {
 [658]  global $legends,$legends_found;
 [659]  if (!$delimiter) $delimiter = find_delimiter($data);
 [660]  $line = drop_extra_spaces(before(trim($data),"\n"));
 [661]  $legends = array();
 [662]  $legends[0] = trim(before($line,$delimiter));
 [663]  $legends[1] = trim(before(after($line,$delimiter),$delimiter));
 [664]  $legends[2] = trim(after(after($line,$delimiter),$delimiter)); // rest of first line after the first two column headings (potential graph title)
 [665]  if ($swap) {$legend = $legends[0]; $legends[0] = $legends[1]; $legends[1] = $legend;}
 [666]  $legends_found = ($numeric || (!is_numeric($legends[0]) && !is_numeric($legends[1])));
 [667]  if (!$legends_found) $legends = array('','',''); // number in both first two fields disqualifies line, unless $numeric==TRUE
 [668]  return $legends;
 [669]  } [
Top/End]   _statistics.php
 [670]  function time_data_array($text,$uniform=FALSE) { // returns array with each row a (label,value,time) triplet
 [671]  global $numbers2D_min_items,$numbers2D_max_items,$numbers2D_rows,$numbers2D_columns,$numbers2D_short,$numbers2D_long;
 [672]  $time_data_array = array();
 [673]  $badtimes = $badvalues = 0;
 [674]  $splitlines = priority_data_split($text);
 [675]  foreach ($splitlines as $items) {
 [676]  $label = trim(isset($items[0]) ? $items[0] : '');
 [677]  $value = trim(isset($items[1]) ? $items[1] : '');
 [678]  if (!$time_data_array && !is_numeric($value)) continue; // if value for first line is non-numeric, treat as column-labels line and skip
 [679]  if ($label) {
 [680]  $time = is_numeric($label) ? $label : strtotime($label);
 [681]  if ($time === FALSE) $badtimes++;
 [682]  if (!is_numeric($value) && $value!=='') {$value = ''; $badvalues++;}
 [683]  $time_data_array[] = array($time,$value,$label);
 [684]  }
 [685]  }
 [686]  if ($badtimes && !$uniform) error('The first column of ' . plural($badtimes,'data row') . ' could not be interpreted as a time.');
 [687]  if ($uniform || $badtimes) {foreach ($time_data_array as $i=>$items) $time_data_array[$i] = array($i+1,$items[1],$i+1);}
 [688]  if ($badvalues) error('Ignoring ' . plural($badvalues,'non-numeric value') . ' in the second column.');
 [689]  return $time_data_array;
 [690]  } [
Top/End]   _statistics.php
 [691]  function number_input($name,$value='~',$size=5,$step=1,$min='',$max='') {
 [692]  $focus = $size<0 ? ' autofocus' : '';
 [693]  $width = abs($size) * 2 + 5;
 [694]  if ($value === '~') $value = rqf($name);
 [695]  $value = is_numeric($value) ? " value='$value'" : '';
 [696]  $min = is_numeric($min) ? " min='$min'" : '';
 [697]  $max = is_numeric($max) ? " max='$max'" : '';
 [698]  $step = num($step)>0 ? " step=" . num($step) : '';
 [699]  return "<input type=number name='$name'$value$min$max$step size='$size' style='text-align: right;width:{$width}mm'$focus$GLOBALS[onChange]>";
 [700]  } [
Top/End]   _statistics.php
 [701]  function range_input($name,$value='~',$size=10,$step='',$min='',$max='') {
 [702]  $focus = $size<0 ? ' autofocus' : '';
 [703]  $width = abs($size) * 2 + 5;
 [704]  if ($value === '~') $value = rqn($name);
 [705]  if (is_numeric($value)) {
 [706]  $value = " value='$value'";
 [707]  if (!$step) $step = step_from_value($value);
 [708]  } else $value = '';
 [709]  $min = is_numeric($min) ? " min='$min'" : '';
 [710]  $max = is_numeric($max) ? " max='$max'" : '';
 [711]  $step = num($step)>0 ? " step=" . num($step) : '';
 [712]  return "<input type=range $name='$name'$value$min$max$step$GLOBALS[onChange] style='width:{$width}mm'>";
 [713]  } [
Top/End]   _statistics.php
 [714]  function text_input($name,$value='~',$size=30,$pattern='',$title='Invalid input') {
 [715]  if ($value === '~') $value = rq($name);
 [716]  if ($pattern) return "<input type=text name='$name' size='$size' pattern='$pattern' title=\"$title\"$GLOBALS[onChange]>";
 [717]  else return "<input type=text name='$name' size='$size'$GLOBALS[onClick]>";
 [718]  } [
Top/End]   _statistics.php
 [719]  function email_input($name,$value='~') {if ($value === '~') $value = rq($name); return "<input type=email value='$value'>";} [
Top/End]   _statistics.php
 [720]  function url_input($name,$value='~') {if ($value === '~') $value = rq($name); return "<input type=url value='$value'>";} [
Top/End]   _statistics.php
 [721]  function set_onChange($script='~') {
 [722]  if ($script === '~') $script = 'this.form.submit();';
 [723]  $GLOBALS['onChange'] = trim($script) ? " onchange=\"$script;return 0;\"" : ''; return $GLOBALS['onChange'];
 [724]  } [
Top/End]   _statistics.php
 [725]  function random_fraction() {return ((mt_rand()+1) / (mt_getrandmax()+2));} [
Top/End]   _statistics.php
 [726]  function random_float($low=0,$high=1,$places='') {
 [727]  $value = ($high-$low) * random_fraction() + $low;
 [728]  if ($places !== '') $value = round($value,$places);
 [729]  return $value;
 [730]  } [
Top/End]   _statistics.php
 [731]  function random_sign($value=1) {return (rand(0,1) ? $value : -$value);} [
Top/End]   _statistics.php
 [732]  function round_array($data,$places=0) {
 [733]  for ($i=0; $i<count($data); $i++) $data[$i] = round($data[$i],$places);
 [734]  return $data;
 [735]  }
 [736]  $statistics = array(); [
Top/End]   _statistics.php
 [737]  function statistics($values,$name='') {
 [738]  global $statistics;
 [739]  $statistics = array();
 [740]  if (!$values) return array();
 [741]  $count = count($values);
 [742]  $min = min($values);
 [743]  $max = max($values);
 [744]  $range = $max - $min;
 [745]  $midrange = ($min+$max)/2;
 [746]  $range_recip = $range ? 1/$range : 0;
 [747]  sort($values,TRUE);
 [748]  $q1 = quartile($values,1);
 [749]  $median = median($values,TRUE);
 [750]  $q3 = quartile($values,3);
 [751]  $IQR = $q3 - $q1;
 [752]  $fence_low = $q1 - 1.5*$IQR;
 [753]  $fence_high = $q3 + 1.5*$IQR;
 [754]  $lows = $highs = array();
 [755]  foreach ($values as $value) {
 [756]  if ($value < $fence_low) $lows[] = $value;
 [757]  elseif ($value > $fence_high) $highs[] = $value;
 [758]  }
 [759]  $min_inside = $values[count($lows)];
 [760]  $max_inside = $values[$count-1-count($highs)];
 [761]  $statistics = array('count'=>$count,'min'=>$min,'max'=>$max,'range'=>$range,'midrange'=>$midrange,'range_recip'=>$range_recip,'mean'=>average($values),
 [762]  'std'=>standard_deviation($values),'pop_std'=>standard_deviation($values,TRUE),'median'=>$median,'IQR'=>$IQR,'q1'=>$q1,'q2'=>$median,'q3'=>$q3,
 [763]  'outliers'=>count($lows)+count($highs),'lows'=>$lows,'highs'=>$highs,'min_inside'=>$min_inside,'max_inside'=>$max_inside);
 [764]  if (!$name) return $statistics; // for no-name default, return copy of global array with all computed statistics (which is computed in all cases)
 [765]  if (strpos($name,',') === FALSE) return $statistics[$name]; // for single name, return just that statistic
 [766]  $stats = array(); foreach (csplit($name) as $n) $stats[] = $statistics[$n];
 [767]  return $stats; // otherwise return array based on names, suitable for list($a,$b,$c)=statistics('a,b,c',...) calls
 [768]  }
 [769]  $statistics2D = array(); [
Top/End]   _statistics.php
 [770]  function statistics2D($values2D) { // computes linear fit and correlation computation, as well as statistics on x and y separately
 [771]  global $statistics2D;
 [772]  $statistics2D = array();
 [773]  $statistics2D['x'] = statistics(array_column($values2D,0));
 [774]  $statistics2D['y'] = statistics(array_column($values2D,1));
 [775]  $count = $statistics2D['count'] = count($values2D);
 [776]  $statistics2D['slope'] = $statistics2D['intercept'] = $statistics2D['r'] = $statistics2D['r2'] = 0;
 [777]  if ($count > 1) {
 [778]  $xmean = $statistics2D['x']['mean']; $xstd = $statistics2D['x']['std']; $xstd_recip = $xstd ? 1/$xstd : 0;
 [779]  $ymean = $statistics2D['y']['mean']; $ystd = $statistics2D['y']['std']; $ystd_recip = $ystd ? 1/$ystd : 0;
 [780]  $sumx = $sumy = $sumxy = $sumx2 = $sumy2 = $rsum = 0;
 [781]  foreach ($values2D as $pair) {
 [782]  $x = $pair[0]; $sumx += $x; $sumx2 += $x*$x;
 [783]  $y = $pair[1]; $sumy += $y; $sumy2 += $y*$y;
 [784]  $sumxy += $x*$y; $rsum += ($x-$xmean) * $xstd_recip * ($y-$ymean) * $ystd_recip;
 [785]  }
 [786]  $denominator = $count*$sumx2 - $sumx*$sumx;
 [787]  if ($denominator) {
 [788]  $statistics2D['slope'] = $slope = ($count*$sumxy - $sumx*$sumy) / $denominator;
 [789]  $statistics2D['slope_text'] = ($slope<0 ? '- ' : '+ ') . np(abs($slope),3);
 [790]  $statistics2D['intercept'] = $intercept = $ymean - $slope*$xmean;
 [791]  $statistics2D['intercept_text'] = np($intercept,1,3);
 [792]  } else {
 [793]  $statistics2D['slope'] = 0; // actually infinite, but zero is supplied here to minimize arithmetic exceptions
 [794]  $statistics2D['slope_text'] = 'Infinity';
 [795]  $statistics2D['intercept'] = 0; // actually infinite or indeterminate
 [796]  $statistics2D['intercept_text'] = 'Infinity';
 [797]  }
 [798]  $statistics2D['r'] = $r = $rsum / ($count-1);
 [799]  $statistics2D['r2'] = $r*$r;
 [800]  }
 [801]  return $statistics2D;
 [802]  } [
Top/End]   _statistics.php
 [803]  function regression_report_row($heading='',$statistics2D='') {
 [804]  if (!is_array($statistics2D)) $statistics2D = $GLOBALS['statistics2D'];
 [805]  $text = "<table border=0 cellpadding=3>\n";
 [806]  if ($heading) $text .= tr(tdc($heading));
 [807]  $text .= tr(tdc("<i>correlation coefficient</i><br>" . big(bold(" r = " . np($statistics2D['r'],3))) . small(italic("   [N=$statistics2D[count]]"))));
 [808]  $text .= tr(tdc("<i>regression equation</i><br><b> <i>ŷ</i> = $statistics2D[intercept_text] $statistics2D[slope_text] <i>x</i> </b>"));
 [809]  $text .= "</table>\n";
 [810]  return tr(tdc($text));
 [811]  }

 [812]  //// TWO-WAY TABLES
 [813]  $two_way_table_data_text = ''; [
Top/End]   _statistics.php
 [814]  function extract_two_way_table($text) { // builds table from either primary dataset or from text table
 [815]  global $two_way_table_data_text;
 [816]  $lines = $rkeys = $ckeys = $tbl = $table = array();
 [817]  $input = split_input($text); // will drop # comments, handle commas and tabs, combine adjacent spaces
 [818]  foreach ($input as $items) {if (count($items) > 1) $lines[] = $items;}
 [819]  if (!$lines) return array();
 [820]  if (count($lines,1)/count($lines) < 3.5) { // few-item-per-line text means primary data, not tabular data
 [821]  $two_way_table_data_text = $text;
 [822]  foreach ($lines as $ss) {
 [823]  $r = $ss[0]; $c = $ss[1];
 [824]  $tbl[$r][$c] = isset($tbl[$r][$c]) ? $tbl[$r][$c]+1 : 1;
 [825]  if (!in_array($r,$rkeys)) $rkeys[] = $r;
 [826]  if (!in_array($c,$ckeys)) $ckeys[] = $c;
 [827]  }
 [828]  sort($rkeys); sort($ckeys); // alphabetize keys extracted from primary data
 [829]  foreach ($rkeys as $r) {foreach ($ckeys as $c) $table[$r][$c] = isset($tbl[$r][$c]) ? $tbl[$r][$c] : 0;}
 [830]  } else { // more-items-per-line text means data is already in tabular form
 [831]  $two_way_table_data_text = '';
 [832]  foreach ($lines as $i=>$ss) {
 [833]  if ($i == 0) { // get column labels from first line, retaining their order
 [834]  $ckeys = wsplit(trim(wjoin($ss))); $cn = count($ckeys); // so it doesn't matter if column-label line is indented
 [835]  } else { // all rows after the first one
 [836]  $n = count($ss) - 1; // number of table values since first item in $ss is row label
 [837]  $r = $ss[0]; // row labels from table text retain their order
 [838]  foreach ($ckeys as $j=>$c) $table[$r][$c] = $j<$n ? num($ss[$j+1]) : 0;
 [839]  }
 [840]  }
 [841]  }
 [842]  return $table; // row/column labels/categories can be extracted from $table keys
 [843]  } [
Top/End]   _statistics.php
 [844]  function display_two_way_table($table_text,$query='',$display_data=FALSE,$hover=FALSE) {
 [845]  $rcolor = '#060'; $ccolor = '#006'; $tbg = 'aqua'; $tfbg = 'yellow'; $fbg = 'white'; $fbg_total = '#0EE';
 [846]  $rfocus = $query ? rq('row') : '';
 [847]  $cfocus = $query ? rq('col') : '';
 [848]  $focus = $rfocus || $cfocus;
 [849]  $table = extract_two_way_table($table_text);
 [850]  if (!$table) return array();
 [851]  $rows = $cols = array();
 [852]  foreach ($table as $r=>$row) {
 [853]  $rows[$r] = array_sum($row);
 [854]  if (!$cols) {foreach ($row as $c=>$count) $cols[$c] = $count;}
 [855]  else {foreach ($row as $c=>$count) $cols[$c] += $count;}
 [856]  }
 [857]  $total = array_sum($rows);
 [858]  print "<table cellpadding=10><tr>\n"; // outer table with (optional) data on left, tabulation in center, and details (if specified) on right
 [859]  if ($display_data) print tdc(p(italic('Raw values (read-only)')) .
 [860]  textarea('readonly_data',$GLOBALS['two_way_table_data_text'],max(10,2*count($rows)),20,FALSE,'readonly style="background-color:lightgray"'),'top');
 [861]  print "<td valign=top>\n<table cellpadding=5 border=1>\n<tr><td></td>";
 [862]  foreach ($cols as $c=>$count) print tdc(colored(bold(courier($c),$c===$cfocus),$ccolor),"bgcolor=$tbg");
 [863]  print tdc(small('Row<br>Totals')) . "</tr>\n";
 [864]  foreach ($rows as $r=>$rcount) {
 [865]  print "<tr>" . tdr(colored(bold(courier($r),$r===$rfocus),$rcolor),"bgcolor=$tbg"); // left column with row labels
 [866]  foreach ($cols as $c=>$ccount) {
 [867]  $count = isset($table[$r][$c]) ? $table[$r][$c] : 0;
 [868]  $bg = $tbg;
 [869]  $title = '';
 [870]  if ($count) {
 [871]  $rp = percentage($count,$rows[$r],1) . "% of $r subtotal [conditional probability]";
 [872]  $cp = percentage($count,$cols[$c],1) . "% of $c subtotal [conditional probability]";
 [873]  $tp = percentage($count,$total,1) . "% of overall total [joint probability]";
 [874]  $title = $hover ? plural($count,'instance') . " that are both $r and $c\n $rp\n $cp\n $tp" : '';
 [875]  if ($r===$rfocus && $c===$cfocus) $bg = $tfbg;
 [876]  }
 [877]  print tdr(_cell_link($count,$title,$r,$c,$query),"bgcolor='$bg'"); // inner body of table
 [878]  }
 [879]  $tp = "$r is " . percentage($rcount,$total,1) . "% of overall total [marginal probability]";
 [880]  $title = $hover ? plural($rcount,'total instance') . " of $r\n $tp\n" : '';
 [881]  $bg = $r===$rfocus ? $fbg : $tbg;
 [882]  print tdr(_cell_link(colored(bold($rcount),$rcolor),$title,$r,'',$query),"bgcolor=$bg") . "</tr>\n"; // right row-subtotals column
 [883]  }
 [884]  print "<tr>" . tdr(small('Column<br>Totals'));
 [885]  foreach ($cols as $c=>$ccount) { // bottom column-subtotals row
 [886]  $tp = "$c is " . percentage($ccount,$total,1) . "% of overall total";
 [887]  $title = $hover ? plural($ccount,'total instance') . " of $c\n $tp [marginal probability]\n" : '';
 [888]  $bg = $c===$cfocus ? $fbg : $tbg;
 [889]  print tdr(_cell_link(colored(bold($ccount),$ccolor),$title,'',$c,$query),"bgcolor=$bg");
 [890]  }
 [891]  $bg = $focus ? $fbg_total : $tbg;
 [892]  print tdr(_cell_link(bold($total),'','','',$query),"bgcolor='$bg'") . "</tr></table>\n"; // grand total in lower-right corner of table
 [893]  print "</td>\n"; // end of left-hand cell
 [894]  if ($query) { // this section only invoked when table has dynamic links
 [895]  print "<td align=center valign=top>\n"; // beginning of right-hand cell
 [896]  if ($focus) { // give details on specific cell if requested
 [897]  $rftext = bold(courier($rfocus));
 [898]  $cftext = bold(courier($cfocus));
 [899]  if ($rfocus && $cfocus) {
 [900]  $count = $table[$rfocus][$cfocus];
 [901]  $verb = $count==1 ? 'is' : 'are';
 [902]  $text = tr(tdc(br('The ' . plural($count,'instance') . " that $verb both") . "$rftext & $cftext $verb:"));
 [903]  $text .= _percentage_row($count,$rows[$rfocus],'',$rcolor,"$rftext<br>subtotal",'conditional');
 [904]  $text .= _percentage_row($count,$cols[$cfocus],'',$ccolor,"$cftext<br>subtotal",'conditional');
 [905]  $text .= _percentage_row($count,$total);
 [906]  print table(10,$text);
 [907]  } else {
 [908]  if ($rfocus) {$count = $rows[$rfocus]; $text = $rftext; $color = $rcolor;}
 [909]  else {$count = $cols[$cfocus]; $text = $cftext; $color = $ccolor;}
 [910]  $text = tr('<br>The ' . plural($count,"instance of $text is:","instances of $text are")) .
 [911]  _percentage_row($count,$total,$color,'','','marginal');
 [912]  print table(10,table('border=0',$text));
 [913]  }
 [914]  }
 [915]  if ($query && (!$rfocus||!$cfocus)) print br(italic('For percentages, click the number<br>to be used as the <b>numerator</b>'),2);
 [916]  print "</td>\n";
 [917]  }
 [918]  print "</tr></table>";
 [919]  return $table;
 [920]  } [
Top/End]   _statistics.php
 [921]  function _cell_link($text,$title,$row,$col,$query) {
 [922]  $cell = table('cellpadding=0',courier($text));
 [923]  if (!$query) return $cell;
 [924]  if ($row) $query .= '&row=' . urlencode($row);
 [925]  if ($col) $query .= '&col=' . urlencode($col);
 [926]  return nlink(titled($cell,$title),$query);
 [927]  } [
Top/End]   _statistics.php
 [928]  function _percentage_row($numerator,$denominator,$ncolor='',$dcolor='',$dtype='',$ptype='joint') {
 [929]  if (!$dtype) $dtype = "overall<br>total";
 [930]  $fraction = fraction_table(" " . colored($numerator,$ncolor) . " ",
 [931]  bold(colored($denominator,$dcolor)));
 [932]  $text = tr(td('   ') . tdc($fraction) . td(" = " . percentage($numerator,$denominator,1) . '%  ') .
 [933]  td(" of the $dtype of $denominator")) . tr(td() . td(small("[$ptype probability]"),3));
 [934]  return tr(td(table('border=0 cellpadding=0',$text)));
 [935]  }

 [936]  //// BOX PLOTS
 [937]  $boxplot_lows = $boxplot_highs = array(); [
Top/End]   _statistics.php
 [938]  function svg_boxplot($values,$graph_width,$box_height,$xscale,$xoffset=0,$yoffset=0,$thickness=1,$box_fill='white') {
 [939]  global $text_offset,$boxplot_lows,$boxplot_highs;
 [940]  list($count,$min,$max,$range,$median,$q1,$q3,$IQR,$min_inside,$max_inside,$boxplot_lows,$boxplot_highs) =
 [941]  statistics($values,'count,min,max,range,median,q1,q3,IQR,min_inside,max_inside,lows,highs');
 [942]  $extra = $range/10;
 [943]  $xminimum = $min - $extra;
 [944]  $ycenter = $box_height/2 + $yoffset;
 [945]  $xinside = $xscale*($min_inside-$xminimum) + $xoffset;
 [946]  $xq1 = $xscale*($q1-$xminimum) + $xoffset;
 [947]  $xmedian = $xscale*($median-$xminimum) + $xoffset;
 [948]  $svg = '';
 [949]  $svg .= svg_line($xinside,$ycenter,$xscale*($max_inside-$min_inside),0,$thickness);
 [950]  $svg .= svg_rect($xq1,$ycenter-$box_height/2,$IQR*$xscale,$box_height,$box_fill,$thickness);
 [951]  $svg .= svg_line($xmedian,$ycenter-$box_height/2,0,$box_height,$thickness);
 [952]  foreach (array_merge($boxplot_lows,$boxplot_highs) as $outlier) {
 [953]  $xoutlier = $xscale*($outlier-$xminimum) + $xoffset;
 [954]  $svg .= svg_text('*',$xoutlier,$ycenter+$text_offset,array('font-style'=>'bold'));
 [955]  }
 [956]  return $svg;
 [957]  } [
Top/End]   _statistics.php
 [958]  function print_boxplot($values,$graph_width,$graph_height,$padding=20,$thickness=1,$scale=TRUE,$description=TRUE,$box_fill='white',$bgcolor='white') {
 [959]  global $statistics,$xminimum,$xscale,$xoffset,$text_offset,$horizontal_scale_thickness;
 [960]  $xpadding = $padding;
 [961]  if (!$values) return '';
 [962]  list($count,$min,$max,$range,$median,$q1,$q3,$IQR,$min_inside,$max_inside,$lows,$highs) =
 [963]  statistics($values,'count,min,max,range,median,q1,q3,IQR,min_inside,max_inside,lows,highs');
 [964]  $extra = $range/10;
 [965]  $xscale = $range ? $graph_width/($range+2*$extra) : 0;
 [966]  $xminimum = $min - $extra;
 [967]  $yoffset = $xoffset = $padding;
 [968]  $svg = svg_boxplot($values,$graph_width,$graph_height,$xscale,$xoffset,$yoffset);
 [969]  $view_width = $graph_width + 2*$padding;
 [970]  $view_height = $graph_height + 2*$padding;
 [971]  if ($scale) {
 [972]  $svg .= svg_horizontal_scale($graph_height+2*$padding,$padding,$graph_width,
 [973]  $xoffset,$xscale,$min-$extra,$max+$extra);
 [974]  $view_height += $horizontal_scale_thickness + $padding/2;
 [975]  }
 [976]  print svg_start('boxplot',$view_width,$view_height,$bgcolor) . $svg . svg_end();
 [977]  if ($description) {
 [978]  $text = "<br><i>$count values (";
 [979]  $outliers = count($lows) + count($highs);
 [980]  $text .= ($outliers ? 'including ' . plural($outliers,'outlier') : 'with no outliers') . ')';
 [981]  print br($text);
 [982]  }
 [983]  }

 [984]  //// HISTOGRAMS [
Top/End]   _statistics.php
 [985]  function histogram($values,$bins='',$binsize='',$low='',$high='') {
 [986]  global $histogram_array,$histogram_bins,$histogram_binsize,$histogram_width,$histogram_count,$histogram_max,$histogram_low,$histogram_high,$histogram_lows,$histogram_highs;
 [987]  $histogram_array = $histogram_lows = $histogram_highs = array();
 [988]  $histogram_bins = $histogram_binsize = $histogram_count = $histogram_max = $histogram_low = $histogram_high = 0;
 [989]  if (!$values) return array();
 [990]  list($min,$max) = statistics($values,'min,max');
 [991]  $lowest = $low!=='' ? $low : $min;
 [992]  $highest = $high!=='' ? $high : ($binsize&&$bins ? $lowest+$bins*$binsize : $max);
 [993]  $histogram_width = $binsize&&$bins ? $bins*$binsize : $highest-$lowest;
 [994]  if (!$bins) $bins = $binsize ? max(1,(multiple($highest,$binsize,1)-multiple($lowest,$binsize,-1))/$binsize) : 10;
 [995]  if (!$binsize) $binsize = close_simple_value($histogram_width/$bins,0.05,1);
 [996]  $histogram_low = multiple($lowest,$binsize,-1);
 [997]  $histogram_high = multiple($highest,$binsize,1);
 [998]  for ($index=0; $index<$bins; $index++) $histogram_array[$index] = 0;
 [999]  foreach ($values as $value) {
[1000]  $i = floor(($value-$histogram_low)/$binsize);
[1001]  if ($i < 0) $lows[] = $value;
[1002]  elseif ($i >= $bins) $highs[] = $value;
[1003]  else $histogram_array[$i]++;
[1004]  }
[1005]  $histogram_max = max($histogram_array);
[1006]  $histogram_bins = $bins;
[1007]  $histogram_count = count($values);
[1008]  return $histogram_array;
[1009]  } [
Top/End]   _statistics.php
[1010]  function histogram_graph($values,$bins='',$bin_width='',$low='',$high='',$graph_height,$graph_width,$scales=3,$padding=10,$background='white') {
[1011]  global $statistics,$vertical_scale_thickness,$horizontal_scale_thickness;
[1012]  global $histogram_array,$histogram_bins,$histogram_binsize,$histogram_width,$histogram_count,$histogram_max,$histogram_low,$histogram_high,$histogram_lows,$histogram_highs;
[1013]  $histogram = histogram($values,$bins,$bin_width,$low,$high);
[1014]  if (!$histogram_max || !$histogram_width) return '';
[1015]  if (is_array($padding)) list($left_padding,$right_padding,$top_padding,$bottom_padding) = $padding;
[1016]  else $left_padding = $right_padding = $top_padding = $bottom_padding = $padding;
[1017]  $yscale = $graph_height / $histogram_max;
[1018]  $xscale = $graph_width / $histogram_width;
[1019]  $yoffset = $graph_height + $top_padding;
[1020]  $vertical_scale = $scales&2 ? svg_vertical_scale($left_padding,$yoffset,$graph_height,$yoffset,$yscale,0,$histogram_max) : '';
[1021]  $xoffset = $vertical_scale_thickness + $left_padding;
[1022]  $horizontal_scale = $scales&1 ? svg_horizontal_scale($yoffset,$xoffset,$graph_width,$xoffset,$xscale,$histogram_low,$histogram_high) : '';
[1023]  $view_width = $graph_width + $vertical_scale_thickness + $left_padding + $right_padding;
[1024]  $view_height = $graph_height + $horizontal_scale_thickness + $top_padding + $bottom_padding;
[1025]  $svg = svg_start('histogram',$view_width,$view_height,$background);
[1026]  $xstep = $bin_width * $xscale;
[1027]  foreach ($histogram as $index=>$counts) { // for each bin
[1028]  $svg .= svg_rect($xoffset+$index*$xstep,$yoffset-$counts*$yscale,$xstep,$counts*$yscale,'lightgray','black');
[1029]  }
[1030]  return ($svg . $vertical_scale . $horizontal_scale . svg_end());
[1031]  } [
Top/End]   _statistics.php
[1032]  function individual_value_plot($values,$xmin,$xscale,$xoffset,$y,$width=0,$size=10,$color='black',$thickness=1,$opacity=0.5) {
[1033]  $svg = $width>0 ? svg_line($xoffset,$y,$width,0,1) : '';
[1034]  foreach ($values as $value) {
[1035]  $x = round(($value-$xmin)*$xscale + $xoffset);
[1036]  $svg .= svg_line($x,$y-$size,0,$size,$thickness,$color,"opacity=$opacity");
[1037]  }
[1038]  return $svg;
[1039]  }
[1040]  // [
Top/End]   _statistics.php
[1041]  function data_file_listing($directory,$extensions='txt,csv',$heading='Data files:',$edit='',$run='',$new=FALSE) {
[1042]  $output = "<table cellpadding=3>\n" . ($heading ? br(italic($heading)) : '');
[1043]  $patterns = array();
[1044]  foreach (csplit($extensions) as $ext) $patterns[] = "$directory*.$ext";
[1045]  foreach (fileset($patterns) as $f) {
[1046]  $name = respace(filename_only($f));
[1047]  $contents = file_read_contents($f);
[1048]  if (contains($contents,'#')) {
[1049]  $title = '';
[1050]  foreach (nsplit($contents) as $s) {$t = (after_with($s,'#')); if ($t) $title .= "$t\n";}
[1051]  } else $title = $contents;
[1052]  if ($run) $name = alink($name,"$run$f");
[1053]  $edit_link = $edit ? td(alink(small(italic('Edit')),"$edit$f")) : '';
[1054]  $output .= tr($edit_link . td(titled($name,$title)));
[1055]  }
[1056]  if ($new) $output = alink(italic('Create a new table'),'two-way-table-files.php') . "<br><br>$output";
[1057]  return "$output</table>\n";
[1058]  } [
Top/End]   _statistics.php
[1059]  function vq($input,$name,$default='') {return (isset($input['#vars'][$name]) ? $input['#vars'][$name] : $default);}
[1060]  // [
Top/End]   _statistics.php
[1061]  function extract_input($text,$vars=FALSE,$comments='#') {
[1062]  $text = substitute_minus(rtrim($text));
[1063]  $input['#text'] = $text;
[1064]  $input['#lines'] = $input['#comments'] = $input['#var'] = array();
[1065]  foreach (nsplit($text) as $line) {
[1066]  if (substr(trim($line),0,1) === $comments) { // save whole-line comments
[1067]  $input['#comments'][] = trim(after($line,$comments));
[1068]  } else {
[1069]  $line = rtrim(before($line,$comments));
[1070]  if ($line) { // ignore blank lines and non-whole-line comments
[1071]  if ($vars && contains($line,'=')) { // variable assignments
[1072]  foreach (msplit(";\t",$line) as $phrase) { // multiple assignments may be put on a line
[1073]  $name = trim(before($phrase,'='));
[1074]  if (is_numeric($name)) $name = "#$name";
[1075]  if ($name) $input['#var'][$name] = trim(after($line,'='));
[1076]  }
[1077]  } else $input['#lines'][] = $line; // data lines are any not blank, assignment, or comment
[1078]  }
[1079]  }
[1080]  }
[1081]  return $input;
[1082]  }
[1083]  $linesplit_delimiter = ''; $firstline_items = array(); [
Top/End]   _statistics.php
[1084]  function split_input($text,$ignore_first_line=FALSE,$commas='',$comments='#') {
[1085]  global $linesplit_delimiter,$firstline_items;
[1086]  if ($ignore_first_line) {$firstline = before($text,"\n"); $text = after($text,"\n");}
[1087]  $input = extract_input($text);
[1088]  $text = njoin($input['#lines']); // this drops comments, blank lines, and assignments
[1089]  $c = count_chars($text); // tabs take priority if present, then commas if most frequent, otherwise spaces
[1090]  $tabs = $c[ord("\t")];
[1091]  $lines = $c[ord("\n")];
[1092]  $spaces = $c[ord(' ')];
[1093]  if ($commas==='') { // examine text to see if commas should be used as delimiters
[1094]  $commas = $tabs<$lines/2 && $c[ord(',')]>$tabs+$spaces;
[1095]  }
[1096]  if ($commas) $linesplit_delimiter = ',';
[1097]  else {
[1098]  $convert_tabs = $tabs<$lines/2 && $spaces>$tabs;
[1099]  $text = squeeze_spaces(rtrim($text),$convert_tabs);
[1100]  $linesplit_delimiter = $convert_tabs ? ' ' : "\t";
[1101]  }
[1102]  $firstline_items = $ignore_first_line ? explode($linesplit_delimiter,$firstline) : array(); // global side effect
[1103]  $output = array();
[1104]  foreach (nsplit($text) as $line) $output[] = explode($linesplit_delimiter,$line);
[1105]  return $output;
[1106]  } [
Top/End]   _statistics.php
[1107]  function extract_categorized_values($text,$categories=2,$category_index='') { // parse text into an array of values indexed by category
[1108]  $filtered_items = $instances = $categorized = $valuesets = array();
[1109]  foreach (split_input($text) as $items) {
[1110]  $numerics = array(0,0);
[1111]  foreach ($items as $index=>$item) {
[1112]  $tag = "~$item"; // ensure that indexing treats item value as a string
[1113]  $instances[$index][$tag] = isset($instances[$index][$tag]) ? $instances[$index][$tag]+1 : 1;
[1114]  if (is_numeric($item)) $numerics[$index]++;
[1115]  if ($index == 1) {$filtered_items[] = array($items[0],$item); break;} // after 2nd item, save output and go to next line
[1116]  }
[1117]  }
[1118]  if ($category_index === '') {
[1119]  if ($numerics[0] != $numerics[1]) $category_index = $numerics[0]<$numerics[1] ? 0 : 1;
[1120]  elseif (count($instances[0]) != count($instances[1])) $category_index = count($instances[0])<count($instances[1]) ? 0 : 1;
[1121]  else {notice('Cannot determine category column -- using second column'); $category_index = 1;}
[1122]  }
[1123]  $value_index = 1 - $category_index;
[1124]  $instances = $instances[$category_index]; // extract the appropriate column tabulation
[1125]  asort($instances,SORT_NUMERIC,SORT_DESC); // order categories by membership count, biggest first
[1126]  if ($categories > 0) $instances = array_slice($instances,$categories);
[1127]  $category_tags = array_keys($instances);
[1128]  foreach ($category_tags as $tag) $values[$tag] = array(); // establish biggest-first order for subarrays of output
[1129]  foreach ($filtered_items as $items) {
[1130]  $category = $items[$category_index];
[1131]  $value = $items[$value_index];
[1132]  if (in_array("~$category",$category_tags)) {
[1133]  $categorized[$category][] = $value; // distribute items from valid lines into category subarrays
[1134]  $valuesets[] = array($category,$value); // build list of qualifying category-value pairs
[1135]  }
[1136]  }
[1137]  return array($categorized,$valuesets);
[1138]  } [
Top/End]   _statistics.php
[1139]  function extract_values2D_categories($text,$swap=FALSE,$category_last=TRUE) { // parse text into an array (indexed by category) of 2-column 2D arrays
[1140]  global $values2D,$values2Dcategories;
[1141]  $category_index = $category_last ? 2 : 0;
[1142]  $value_indices = array(0,1,2);
[1143]  unset($value_indices[$category_index]);
[1144]  list($vi0,$vi1) = $swap ? array_reverse($value_indices) : $value_indices;
[1145]  $data = $values2D = $values2Dcategories = array();
[1146]  foreach (split_input($text) as $items) {
[1147]  foreach ($value_indices as $index) {if (!isset($items[$index]) || !is_numeric($items[$index])) continue 2;} // require 2 numeric values
[1148]  $category = isset($items[$category_index]) ? $items[$category_index] : '';
[1149]  if (is_numeric($category)) $category = "#$category"; // prevent numerical interpretation of categories
[1150]  $values2Dcategories[$category] = isset($values2Dcategories[$category]) ? $values2Dcategories[$category]+1 : 1;
[1151]  $values2D[$category][] = array($items[$vi0],$items[$vi1]);
[1152]  }
[1153]  array_multisort($values2Dcategories,SORT_DESC,$values2D); // sort results so that most frequent categories are first
[1154]  return $values2D;
[1155]  } [
Top/End]   _statistics.php
[1156]  function parse_comparison_data($text,$column=0,$ignore_first_line=FALSE) { // splits text data values into an array of text lines indexed by categories
[1157]  global $linesplit_delimiter;
[1158]  $lines = split_input($text,$ignore_first_line); // split text into 2-D array of lines and line-items
[1159]  if (!$lines) return array();
[1160]  $distinct = $output = array();
[1161]  if ($column <= 0) { // if category column from data is not specified, use column with least variety of values
[1162]  foreach ($lines as $line) {for ($i=0; $i<count($line); $i++) $distinct[$i][$line[$i]] = TRUE;} // tabulate distinct values for each column
[1163]  $variety = 1000000;
[1164]  foreach ($distinct as $i=>$values) {if (count($values) < $variety) {$variety = count($values); $column = $i;}}
[1165]  } else $column--; // adjust one-based column numbering to zero-based array indexing
[1166]  foreach ($lines as $line) {
[1167]  $category = $line[$column];
[1168]  unset($line[$column]); // remove category variable prior to reassembling line
[1169]  $output[$category][] = implode($linesplit_delimiter,$line);
[1170]  }
[1171]  return $output;
[1172]  }
[1173]  $data = $values = array(); $columned = FALSE; [
Top/End]   _statistics.php
[1174]  function fetch_1V_data($columnize=0,$places=2) {
[1175]  global $data,$values,$command,$datafilename,$columned;
[1176]  $delimiter = ($columnize>0 || ($columnize==0 && $command)) ? "\n" : ' ';
[1177]  $data = rq('data'); $values = array(); $datafilename = '';
[1178]  if (rq1('clear')) $data = '';
[1179]  else {
[1180]  if (rq('file')) {
[1181]  $filename = rq('file');
[1182]  if (!file_exists($filename) && file_exists("./data/$filename")) $filename = "./data/$filename";
[1183]  $files = files($filename);
[1184]  $datafilename = $files ? $files[rand(0,count($files)-1)] : '';
[1185]  $data = file_read_contents($filename);
[1186]  } elseif (rq('session') && sv(rq('session'))) $data = sv(rq('session')); // data passed from another page
[1187]  else {
[1188]  $random = rqn('random');
[1189]  if ((!$data && !$command && $places>=0) || $random==1) $random = rand(60,90);
[1190]  if ($random) $data = implode($delimiter,round_array(make_gaussian_data($random,rand(70,90),rand(15,25),100),abs($places)));
[1191]  }
[1192]  $data = substitute_minus($data);
[1193]  }
[1194]  $values = extract_numbers($data);
[1195]  $lines = strlen($data) - strlen(str_replace("\n",'',$data));
[1196]  $columned = ($lines<count($values)/2 && $delimiter==="\n"); // TRUE only when data has just been converted from non-column to column form
[1197]  if ($columnize >= 0) $data = implode($delimiter,$values);
[1198]  return statistics($values);
[1199]  } [
Top/End]   _statistics.php
[1200]  function interface_1V_data($label='Paste data values below',$rows=7,$columns=20,$columnize=0,$clear=TRUE,$random=75,$places=2) {
[1201]  global $columned,$data;
[1202]  $statistics = fetch_1V_data($columnize,$places); // returns statistics of data, sets $data and $values arrays as side effects
[1203]  print br($columned ? italic(small('Data values have been ' . alink('rearranged','columnize.php') . ' into a column')) : ' ');
[1204]  if ($label) print br($label);
[1205]  print br(textarea('data',$data,7,20));
[1206]  $text = ($data&&$clear ? alink('Clear values','?clear=1') : spaces(12)) . spaces(10) . ($random ? alink('Random values',"?random=$random") : spaces(13));
[1207]  if ($clear || $random) print br("<sup>$text</sup>");
[1208]  return $statistics;
[1209]  }
[1210]  /*function interface_categorized_1V_data($rows=10,$columns=20,$categories=array('A','B'),$clear=TRUE,$random=75,$places=2) {
[1211]  global $columned,$data;
[1212]  $statistics = fetch_1V_data($columnize,$places); // returns statistics of data, sets $data and $values arrays as side effects
[1213]  print br($columned ? italic(small('Data values have been ' . alink('rearranged','columnize.php') . ' into a column')) : ' ');
[1214]  print br('Paste data values below and ' . commandbutton('Display')) . br(textarea('data',$data,7,20));
[1215]  $text = ($data&&$clear ? alink('Clear values','?clear=1') : spaces(12)) . spaces(10) . ($random ? alink('Random values',"?random=$random") : spaces(13));
[1216]  if ($clear || $random) print br("<sup>$text</sup>");
[1217]  return $statistics;
[1218]  }*/ [
Top/End]   _statistics.php
[1219]  function bootstrap($array) { // returns same-size random sample (with replacement) from input array
[1220]  $i = $n = count($array) - 1;
[1221]  $result = array();
[1222]  while ($i-- >= 0) $result[] = $array[rand(0,$n)];
[1223]  return $result;
[1224]  } [
Top/End]   _statistics.php
[1225]  function trimmed_mean($array,$trim=0.1) {
[1226]  if (!$array) return FALSE;
[1227]  $n = count($array);
[1228]  if ($trim <= 0) return average($array);
[1229]  sort($array,SORT_NUMERIC);
[1230]  if ($trim > 1) $trim = 1;
[1231]  $m = $n * $trim/2; // values to trim from each end before averaging, including fractional part of boundary value
[1232]  $j = floor($m); // index of lower-boundary value
[1233]  $k = $n-$j-1; // index of higher-boundary value
[1234]  $f = 1-($m-$j); // fractional part of boundary value to be included in the mean
[1235]  for ($i=$j+1,$sum=$weight=0; $i<$k; $i++) {$sum += $array[$i]; $weight++;} // sum fully-weighted values
[1236]  return (($sum+$f*($array[$j]+$array[$k])) / ($weight+$f+$f)); // add weighted boundary values, then return weighted average
[1237]  } [
Top/End]   _statistics.php
[1238]  function permutation_test_paragraph($difference,$lower_pct,$higher_pct,$statistic='mean',$view_width='') {
[1239]  $twice_lesser_pct = np(2*min($lower_pct,$higher_pct),0,2);
[1240]  if (!$view_width) $view_width = $GLOBALS['view_width'];
[1241]  $difference_absolute = abs($difference);
[1242]  $text = "The graph is divided into two parts that show the percentage of shuffled cases whose difference of {$statistic}s is on each side of the A-B difference for the original values.";
[1243]  if (rq1('long')) $text .= <<<TEXT
[1244]  Doubling the smaller of these two percentages approximates how likely it is that the observed difference is due to chance. (That is, <i>even if both samples were randomly
[1245]  taken from the same distribution</i>, the {$statistic}s of samples of this size would differ by $difference_absolute or more approximately $twice_lesser_pct% of the time.)
[1246] 
[1247]  TEXT;
[1248]  return table(-3,td(small($text),"width=$view_width"));
[1249]  }
[1250]  // [
Top/End]   _statistics.php
[1251]  function data_requested_link($from) {return ($from ? '<br>Data request from ' . alink(after_last($from,'/'),$from) : '');} [
Top/End]   _statistics.php
[1252]  function upload_link() {return (alink('Upload',"upload_data.php?from=$_SERVER[PHP_SELF]") . ' or ' . alink('Clear','?clear=1') . ' Data');} [
Top/End]   _statistics.php
[1253]  function random_linear_scatter_data($count=25,$group_labels=array('')) {
[1254]  $data_lines = array();
[1255]  foreach ($group_labels as $label) {
[1256]  if ($label) $label = " $label";
[1257]  $m = random_float(-2,2);
[1258]  $xwidth = random_float(1,100);
[1259]  $xstart = random_float(-10,100);
[1260]  $ystd = sqrt(random_float(1,100));
[1261]  $ystart = random_float(-20,50);
[1262]  $xdata = make_uniform_data($count,0,$xwidth);
[1263]  $ynoise = make_gaussian_data($count,0,$ystd,3*$ystd);
[1264]  for ($i=0; $i<$count; $i++) {
[1265]  $x = round($xstart+$xdata[$i],2);
[1266]  $y = round(($xdata[$i]-$xstart)*$m+$ystart+$ynoise[$i],2);
[1267]  $data_lines[] = "$x $y$label";
[1268]  }
[1269]  }
[1270]  shuffle($data_lines);
[1271]  return njoin($data_lines) . "\n";
[1272]  } [
Top/End]   _statistics.php
[1273]  function text_utility_page_links() {
[1274]  $utilities = array(
[1275]  'Select Columns'=>'Extract (and optionally reorder) data columns',
[1276]  'Change Separators'=>'Convert column separators and/or extract/reorder columns',
[1277]  'Columnize'=>'Extract numerical values, forming a single column',
[1278]  'Extract Values'=>'Extract and sort numerical values imbedded anywhere in the input text',
[1279]  'Unstack'=>'Separate stacked data into lists for each category',
[1280]  'Transpose'=>'Exchange rows and columns');
[1281]  $text = '<p><i>This content can be processed further by one of these utility pages</i><br><small>';
[1282]  foreach ($utilities as $label=>$title) {
[1283]  $url = strtolower(str_replace(' ','_',$label) . '.php');
[1284]  if (!contains($_SERVER['PHP_SELF'],$url)) $text .= ' ' . titled(alink($label,"$url?from=$GLOBALS[from]"),$title);
[1285]  }
[1286]  return "$text </small></p>\n";
[1287]  }
[1288]  // [
Top/End]   _statistics.php
[1289]  function xpixel($x,$limit='') {
[1290]  global $xoffset,$xlow,$xscale,$graph_width;
[1291]  $pixels = $p = $xscale*($x-$xlow);
[1292]  if ($limit !== FALSE) $pixels = min(max($pixels,0),$graph_width);
[1293]  if ($limit!=='' || $p==$pixels) return round($xoffset+$pixels,2); // normal return
[1294]  return ''; // out-of-range return when $limit===''
[1295]  } [
Top/End]   _statistics.php
[1296]  function ypixel($y,$limit='') {
[1297]  global $yoffset,$ylow,$yscale,$graph_height;
[1298]  $pixels = $p = $yscale*($y-$ylow);
[1299]  if ($limit !== FALSE) $pixels = min(max($pixels,0),$graph_height);
[1300]  if ($limit!=='' || $p==$pixels) return round($yoffset-$pixels,2); // normal return
[1301]  return ''; // out-of-range return when $limit===''
[1302]  } [
Top/End]   _statistics.php
[1303]  function graph_intersection_line($slope,$intercept) {
[1304]  global $xoffset,$xlow,$xscale,$graph_width,$yoffset,$ylow,$yscale,$graph_height;
[1305]  $xhigh = $xlow + $graph_width/$xscale;
[1306]  $yhigh = $ylow + $graph_height/$yscale;
[1307]  $intersect = FALSE;
[1308]  $x0 = $xlow; // default $x0 is left side of graph
[1309]  $y0 = $intercept + $slope*$x0; // y for intersection of line with left edge of graph (may be out of range)
[1310]  $x1 = $xhigh; // default $x1 is right side of graph
[1311]  $y1 = $intercept + $slope*$x1; // y for intersection of line with right edge of graph (may be out of range)
[1312]  if ($slope == 0) { // horizontal line
[1313]  $intersect = ($y0>$ylow && $y0<$yhigh);
[1314]  } elseif ($y0<$ylow && $y1>$ylow) { // bottom-of-graph first intersection, second may be on side or top
[1315]  $xbottom = ($ylow-$intercept)/$slope;
[1316]  if ($xbottom < $xhigh) {
[1317]  $intersect = TRUE; $x0 = $xbottom; $y0 = $ylow;
[1318]  if ($y1 > $yhigh) {$x1 = ($yhigh-$intercept)/$slope; $y1 = $yhigh;} // second intersection on top side rather than right side
[1319]  }
[1320]  } elseif ($y0>$yhigh && $y1<$yhigh) { // top-of-graph first intersection
[1321]  $xtop = ($yhigh-$intercept)/$slope;
[1322]  if ($xtop < $xhigh) {
[1323]  $intersect = TRUE; $x0 = $xtop; $y0 = $yhigh;
[1324]  if ($y1 < $ylow) {$x1 = ($ylow-$intercept)/$slope; $y1 = $ylow;} // second intersection on bottom side rather than right side
[1325]  }
[1326]  } else { // line first intersects left side of graph
[1327]  $intersect = TRUE;
[1328]  if ($y1 > $yhigh) {$x1 = ($yhigh-$intercept)/$slope; $y1 = $yhigh;} // second intersection is top side
[1329]  elseif ($y1 < $ylow) {$x1 = ($ylow-$intercept)/$slope; $y1 = $ylow;} // second intersection is bottom side
[1330]  }
[1331]  return ($intersect ? array(xpixel($x0),ypixel($y0),($x1-$x0)*$xscale,($y0-$y1)*$yscale) : array());
[1332]  } [
Top/End]   _statistics.php
[1333]  function last_data_type_check($data_type) {
[1334]  $same = same($data_type,sv('last_data_type'));
[1335]  if (!$same) $_SESSION['last_data'] = $_SESSION['last_data_filename'] = '';
[1336]  $_SESSION['data_type'] = $data_type;
[1337]  return $same;
[1338]  } [
Top/End]   _statistics.php
[1339]  function get_data() {
[1340]  global $data_file,$random,$current_page_name;
[1341]  $data_file = rq('file');
[1342]  if ($data_file) {
[1343]  $data = substitute_minus(file_read_contents($data_file));
[1344]  $_SESSION['last_data_filename'] = $data_file;
[1345]  $_SESSION['last_data_page'] = $current_page_name;
[1346]  }
[1347]  elseif ($_POST && !$random) {
[1348]  $data = rq('data');
[1349]  if ($data) $_SESSION['last_data_page'] = $current_page_name;
[1350]  }
[1351]  else $data = sv('last_data');
[1352]  $_SESSION['last_data'] = $data;
[1353]  if ($random && !$data_file) $_SESSION['last_data_filename'] = ''; // appropriate random data will already have been put into $_SESSION['last_data']
[1354]  return $data;
[1355]  } [
Top/End]   _statistics.php
[1356]  function pair_ranges($pairs,$padding=10,$width=0,$height=0) { // returns $xmin,$xmax,$xscale,$ymin,$ymax,$yscale
[1357]  $size[0] = $width ? $width : $GLOBALS['graph_width'];
[1358]  $size[1] = $height ? $height : $GLOBALS['graph_height'];
[1359]  if ($size[0]+$size[1] == 0) return array();
[1360]  if (abs($padding) > 0.5) $padding /= ($size[0]+$size[1])/2; // if padding specified as pixels, convert to ratio to size
[1361]  $results = array();
[1362]  foreach (array(0,1) as $i) {
[1363]  $values = array_column($pairs,$i);
[1364]  $min = min($values); $max = max($values); $edge = ($max-$min) * $padding;
[1365]  $results[] = $min-$edge; $results[] = $max+$edge; // create room on each side of value range
[1366]  $results[] = $max>$min ? $size[$i]/($max-$min+2*$edge) : 0; // compute pixels-per-value scale
[1367]  }
[1368]  return $results;
[1369]  } [
Top/End]   _statistics.php
[1370]  function regression_values($pairs) {
[1371]  $count = count($pairs);
[1372]  if ($count < 2) return array();
[1373]  $pairx = array_column($pairs,0); $pairy = array_column($pairs,1);
[1374]  $xmean = average($pairx); $xstd = standard_deviation($pairx); $xstd_recip = $xstd ? 1/$xstd : 0;
[1375]  $ymean = average($pairy); $ystd = standard_deviation($pairy); $ystd_recip = $ystd ? 1/$ystd : 0;
[1376]  $sumx = $sumy = $sumxy = $sumx2 = $sumy2 = $rsum = 0;
[1377]  foreach ($pairs as $pair) {
[1378]  $x = $pair[0]; $sumx += $x; $sumx2 += $x*$x;
[1379]  $y = $pair[1]; $sumy += $y; $sumy2 += $y*$y;
[1380]  $sumxy += $x*$y; $rsum += ($x-$xmean) * $xstd_recip * ($y-$ymean) * $ystd_recip;
[1381]  }
[1382]  $denominator = $count*$sumx2 - $sumx*$sumx;
[1383]  $numerator = $count*$sumxy - $sumx*$sumy;
[1384]  $slope = $denominator ? $numerator/$denominator : INF;
[1385]  $intercept = $ymean - $slope*$xmean;
[1386]  $r = $rsum / ($count-1);
[1387]  return array($slope,$intercept,$xmean,$ymean,$r);
[1388]  } [
Top/End]   _statistics.php
[1389]  function regression_equation($slope,$intercept) {
[1390]  $slope_text = is_infinite($slope) ? 'Infinity' : (($slope<0 ? '- ' : '+ ') . np(abs($slope),3));
[1391]  $intercept_text = np($intercept,1,3);
[1392]  return "<b> <i>ŷ</i> = $intercept_text $slope_text <i>x</i> </b>";
[1393]  } [
Top/End]   _statistics.php
[1394]  function correlation_box($r) {return table(5,tdc(br(italic('correlation coefficient')) . bold(np($r,3,3))));} [
Top/End]   _statistics.php
[1395]  function correlation_text($r,$count=0,$glyph='') {
[1396]  $text = big(bold(" r = " . np($r,3)));
[1397]  if ($count > 0) $text .= small(italic(" [N=$count] $glyph"));
[1398]  return $text;
[1399]  } [
Top/End]   _statistics.php
[1400]  function sloped_line_graphic($slope,$x,$y,$color='black',$extra='stroke-dasharray="5,5"') {
[1401]  global $xmin,$xscale,$ymin,$yscale,$xoffset,$ybaseline,$graph_width;
[1402]  $xc = $xoffset+($x-$xmin)*$xscale; $yc = $ybaseline-($y-$ymin)*$yscale;
[1403]  return ($xscale ? svg_sloped_line($slope*$yscale/$xscale,$xc,$yc,$color,$extra) : '');
[1404]  }
[1405]  ?>

FILE: _svg.php - 469 lines, 38 functions [
Top/End]
  [1]  <?php
  [2]  sv_global('svg_bgcolor','white','default background for graphics');
  [3]  sv_global('svg_outline','','default width of graphics outline');
  [4]  $svg_move_begin = $svg_move_duration = 0;
  [5]  $svg_width = $graph_width = $view_width = 320; $svg_height = $graph_height = $view_height = $yoffset = $ybaseline = 200; // default dimensions
  [6]  $svg_outline = ''; $svg_thickness = 1; $svg_defaults = array();
  [7]  $cw = 10; $ch = 18; $text_offset = 5; // character width, height, and text-to-graphic alignment spacing
  [8]  $svg_text_defaults = array('font-family'=>'Courier','font-size'=>'10pt','text-anchor'=>'middle','opacity'=>1);
  [9]  $horizontal_scale_thickness = $vertical_scale_thickness = $percentage_scale_thickness = $xoffset = $minimum_xoffset = 0;
  [10]  $xscale = $yscale = 1; $xoffset = $yoffset = $ybaseline = $padding = 0; $tic_size = 5;
  [11]  $point_glyph_colors = array('red','blue','black','green','gray'); $legends = array('','','');
  [12]  $point_glyph_radius = 3; $point_glyph_side = 5; $point_glyph_count = count($point_glyph_colors);
  [13]  // [Top/End]   _svg.php
  [14]  function xvi($xvalue) {return ($xvalue*$GLOBALS['xscale']);} [
Top/End]   _svg.php
  [15]  function xvp($xvalue) {return (xvi($xvalue)+$GLOBALS['xoffset']);} [
Top/End]   _svg.php
  [16]  function yvi($yvalue) {return ($yvalue*$GLOBALS['yscale']);} [
Top/End]   _svg.php
  [17]  function yvp($xvalue) {return ($GLOBALS['yoffset']-yvi($xvalue));} [
Top/End]   _svg.php
  [18]  function svg_start($id='',$width='',$height='',$bgcolor='~',$extra='') {
  [19]  global $svg_width,$svg_height,$svg_bgcolor,$svg_outline,$svg_thickness;
  [20]  $svg_bgcolor = $bgcolor==='~' ? sv('svg_bgcolor') : $bgcolor;
  [21]  $svg = '<svg';
  [22]  if ($id) $svg .= " id='$id'";
  [23]  if ($width) $svg_width = $width;
  [24]  if ($height) $svg_height = $height;
  [25]  $svg .= " viewBox='0 0 $svg_width $svg_height' style='width: {$svg_width}px; height: {$svg_height}px;";
  [26]  if ($bgcolor) $svg_bgcolor = $bgcolor;
  [27]  if ($svg_bgcolor) $svg .= "background-color:$svg_bgcolor;";
  [28]  return "$svg$extra'>\n";
  [29]  } [
Top/End]   _svg.php
  [30]  function svg_end() {return "</svg>\n";} [
Top/End]   _svg.php
  [31]  function svg_container_style($fill,$border,$border_color='black',$extra='') {
  [32]  $border = $border ? " stroke-width:$border;stroke:$border_color;" : '';
  [33]  $fill = $fill ? "fill:$fill;" : '';
  [34]  $style = ($fill||$border||$extra) ? " style='$fill$border$extra'" : '';
  [35]  return $style;
  [36]  } [
Top/End]   _svg.php
  [37]  function svg_rect($x,$y,$w,$h,$fill='',$border=0,$border_color='black',$extra='') {
  [38]  if ($w < 0) {$x += $w; $w = -$w;}
  [39]  if ($h < 0) {$y += $h; $h = -$h;}
  [40]  return "<rect x='$x' y='$y' width='$w' height='$h' fill-opacity='1' stroke-opacity='1'" .
  [41]  svg_container_style($fill,$border,$border_color,$extra) . "></rect>\n";
  [42]  } [
Top/End]   _svg.php
  [43]  function svg_box($x,$y,$w,$h,$border=1,$border_color='black',$extra='') {
  [44]  if ($w < 0) {$x += $w; $w = -$w;}
  [45]  if ($h < 0) {$y += $h; $h = -$h;}
  [46]  return "<rect x='$x' y='$y' width='$w' height='$h' fill-opacity='0' stroke-opacity='1'" .
  [47]  svg_container_style('',$border,$border_color,$extra) . "></rect>\n";
  [48]  } [
Top/End]   _svg.php
  [49]  function svg_circle($x,$y,$r,$fill='',$border=0,$border_color='black',$extra='') {
  [50]  return "<circle cx='$x' cy='$y' r='$r' " .
  [51]  svg_container_style($fill,$border,$border_color,$extra) . "></circle>\n";
  [52]  } [
Top/End]   _svg.php
  [53]  function svg_ellipse($x,$y,$rx,$ry,$fill='',$border=0,$border_color='black',$extra='') {
  [54]  return "<ellipse cx='$x' cy='$y' rx='$rx' ry='$ry'" .
  [55]  svg_container_style($fill,$border,$border_color,$extra) . "></ellipse>\n";
  [56]  } [
Top/End]   _svg.php
  [57]  function svg_line($x,$y,$dx,$dy,$thickness=1,$color='black',$extra='') {
  [58]  $x2 = $x + $dx; $y2 = $y + $dy;
  [59]  return "<line x1='$x' y1='$y' x2='$x2' y2='$y2' style='stroke: $color; stroke-width: $thickness;' stroke-opacity='1' $extra></line>\n";
  [60]  } [
Top/End]   _svg.php
  [61]  function svg_dline($x,$y,$dx,$dy,$thickness=1,$color='black',$separation=2,$fill='white',$extra='') {
  [62]  return svg_line($x,$y,$dx,$dy,2*$thickness+$separation,$color,$extra) . svg_line($x,$y,$dx,$dy,$separation,$fill);
  [63]  } [
Top/End]   _svg.php
  [64]  function svg_text($text,$x,$y,$attributes=array()) {
  [65]  return "<text x='$x' y='$y'" . add_svg_defaults($attributes,'svg_text_defaults') . ">$text</text>\n";
  [66]  } [
Top/End]   _svg.php
  [67]  function add_svg_defaults($attributes,$defaults='svg_defaults') {
  [68]  if (!is_array($defaults)) $defaults = $GLOBALS[$defaults];
  [69]  foreach ($defaults as $name=>$value) {
  [70]  if (!array_key_exists($name,$attributes)) $attributes[$name] = $value;
  [71]  }
  [72]  $parameters = ''; foreach ($attributes as $name=>$value) $parameters .= " $name='$value'";
  [73]  return $parameters;
  [74]  } [
Top/End]   _svg.php
  [75]  function svg_visibility($svg,$begin=0,$duration=1,$opacity=1,$attributes='') {
  [76]  $tag = between($svg,'<',' ');
  [77]  $animation = '';
  [78]  $svg = svg_hide($svg);
  [79]  if (!$attributes) $attributes = array('opacity','stroke-opacity','fill-opacity');
  [80]  foreach (make_array($attributes) as $name) {
  [81]  $animation .= "\n<set attributeName='$name' to='$opacity' begin='$begin' dur='$duration' fill='remove' />";
  [82]  }
  [83]  return (before($svg,"</$tag") . "$animation\n</$tag" . after($svg,"</$tag"));
  [84]  } [
Top/End]   _svg.php
  [85]  function animate($svg,$animations) { // additional arguments are used as more animations
  [86]  global $svg_defaults,$svg_move_begin,$svg_move_duration;
  [87]  $tag = between($svg,'<',' ');
  [88]  $animation = '';
  [89]  foreach (array_slice(func_get_args(),1) as $attributes) {
  [90]  if (!is_array($attributes)) $animation .= $attributes; // insert argument unchanged if not an array
  [91]  else { // one of the two forms of attribute lists
  [92]  $keys = array_keys($attributes);
  [93]  if (!is_numeric($keys[0])) { // argument is $name=>$to array (always uses global begin/duration values)
  [94]  $begin = $svg_move_begin;
  [95]  if ($begin < 0) {$begin = -$begin; $duration = 0;}
  [96]  else $duration = $svg_move_duration;
  [97]  foreach ($attributes as $name=>$to) {
  [98]  $from = between($svg," $name='","'");
  [99]  if ($duration <= 0) $animation .= "\n<animate attributeName='$name' set='$begin' fill='freeze' to='$to' />";
 [100]  else $animation .= "\n<animate attributeName='$name' begin='$begin' dur='$duration' fill='freeze' from='$from' to='$to' />";
 [101]  }
 [102]  } else { // array($name,$to,$begin,$dur) or array($name,$to,$begin,$dur,$from) argument
 [103]  $elements = count($attributes); // array may have 2, 3, 4, or 5 elements
 [104]  $name = $attributes[0];
 [105]  $to = $attributes[1];
 [106]  $begin = $elements>2 ? $attributes[2] : $svg_move_begin; // optional specific begin time
 [107]  if ($begin < 0) {$begin = -$begin; $duration = 0;}
 [108]  else $duration = ($elements>3 && $attributes[3]>0) ? $attributes[3] : $svg_move_duration; // optional specific duration
 [109]  if ($duration) { // transition is interpolated rather than abrupt
 [110]  $from = $elements>4 ? $attributes[4] : trim(between($svg," $name='","'")); // unless supplied, extract initial value from svg element
 [111]  if ($from === '') { // default starting value needed if attribute not named in svg element
 [112]  if (strpos($name,'opacity') !== FALSE) $from = 1;
 [113]  elseif (array_key_exists($name,$svg_defaults)) $from = $svg_defaults[$name];
 [114]  else $from = 0;
 [115]  }
 [116]  $animation .= "\n<animate attributeName='$name' begin='$begin' dur='$duration' fill='freeze' from='$from' to='$to' />";
 [117]  } else $animation .= "\n<animate attributeName='$name' set='$begin' fill='freeze' to='$to' />";
 [118]  }
 [119]  }
 [120]  }
 [121]  return (before($svg,"</$tag") . "$animation\n</$tag" . after($svg,"</$tag"));
 [122]  } [
Top/End]   _svg.php
 [123]  function animation($name,$to=0,$begin=0,$duration='',$from='') {
 [124]  global $svg_move_begin,$svg_move_duration;
 [125]  $duration = $duration==='' ? $svg_move_duration : $duration;
 [126]  if ($from === '') return array($name,$to,$begin,$duration);
 [127]  else return array($name,$to,$begin,$duration,$from);
 [128]  } [
Top/End]   _svg.php
 [129]  function svg_hide($svg,$after=0,$before=1) {
 [130]  return str_replace("opacity:$before","opacity:$after",str_replace("opacity='$before'","opacity='$after'",$svg));
 [131]  } [
Top/End]   _svg.php
 [132]  function svg_animation_timing($begin='',$duration='') {
 [133]  global $svg_move_begin,$svg_move_duration;
 [134]  if (is_numeric($begin)) {
 [135]  if ($begin < 0) $begin = $svg_move_begin - $begin; // negative begin values taken as positive increments
 [136]  $svg_move_begin = $begin;
 [137]  }
 [138]  if (is_numeric($duration)) $svg_move_duration = $duration;
 [139]  return "begin='$svg_move_begin' dur='$svg_move_duration'";
 [140]  }
 [141]  $svg_visibility_opacity=1; $svg_visibility_begin = $svg_visibility_duration = $svg_visibility_before = $svg_visibility_after = 0; [
Top/End]   _svg.php
 [142]  function svg_visibility_timing($begin='',$duration='',$opacity='',$before='',$after='') {
 [143]  global $svg_visibility_begin,$svg_visibility_duration,$svg_visibility_;
 [144]  if (is_numeric($begin)) {
 [145]  if ($begin < 0) $begin = $svg_visibility_begin - $begin; // negative begin values taken as positive increments
 [146]  $svg_visibility_begin = $begin;
 [147]  }
 [148]  if (is_numeric($duration)) $svg_visibility_duration = $duration;
 [149]  if (is_numeric($opacity)) $svg_visibility_opacity = $opacity;
 [150]  if (is_numeric($before)) $svg_visibility_before = $svg_visibility_after = $before;
 [151]  if (is_numeric($after)) $svg_visibility_after = $after;
 [152]  return "begin='$svg_visibility_begin' dur='$svg_visibility_duration'";
 [153]  } [
Top/End]   _svg.php
 [154]  function svg_polyline($points,$attributes=array('stroke-opacity'=>1,'fill-opacity'=>1)) {
 [155]  if (is_array($points)) $points = implode(' ',$points);
 [156]  $style = '';
 [157]  foreach ($attributes as $name=>$value) $style .= ";$name:$value";
 [158]  if ($style) $style = " style='" . substr($style,1) . "' ";
 [159]  return "<polyline $style points='$points'></polyline>\n";
 [160]  } [
Top/End]   _svg.php
 [161]  function svg_points($yy,$yscale=1,$yoffset=0,$yzero=0,$xx=0,$xscale=1,$xoffset=0,$xzero=0,$clip=TRUE) {
 [162]  global $svg_width,$svg_height;
 [163]  $n = count($yy);
 [164]  // x may be supplied either as an array or as a starting value
 [165]  if (!is_array($xx)) {$x = $xx; $xx = array(); for ($i=0; $i<$n; $i++) $xx[] = $x++;}
 [166]  $points = array();
 [167]  $left = $right = -1;
 [168]  for ($i=0; $i<$n; $i++) {
 [169]  $x = round(($xx[$i]-$xzero)*$xscale + $xzero + $xoffset,2);
 [170]  $y = round(($yy[$i]-$yzero)*$yscale + $yzero + $yoffset,2);
 [171]  if ($clip) $y = max(min($y,$svg_height),-1); // clip vertical to just outside window
 [172]  $points[] = "$x,$y";
 [173]  if ($x < 0) $left = $i; // note where points enter and leave the graph's domain
 [174]  if ($x>$svg_width && $right<0) $right = $i;
 [175]  }
 [176]  if ($clip && ($left>=0 || $right>=0)) { // drop out-of-domain points except for first on each side
 [177]  $start = max(0,$left);
 [178]  $points = array_slice($points,$start,min($right-$left+1,$n-$start));
 [179]  }
 [180]  $pp = implode(' ',$points);
 [181]  return $pp;
 [182]  } [
Top/End]   _svg.php
 [183]  function svg_filled_graph($attributes,$yy,$yscale=1,$yoffset=0,$yzero=0,$xx=0,$xscale=1,$xoffset=0,$xzero=0) {
 [184]  if (!is_array($attributes)) $attributes = array('fill'=>$attributes); // support shortcut color designation
 [185]  if (!in_array('fill-opacity',$attributes)) $attributes['fill-opacity'] = 1;
 [186]  $y_anchor = $yoffset + $yzero;
 [187]  $points = "$xx,$y_anchor " . svg_points($yy,$yscale,$yoffset,$yzero,$xx,$xscale,$xoffset,$xzero) . ' ' . ($xx+count($yy)-1) . ",$y_anchor";
 [188]  return svg_polyline($points,$attributes);
 [189]  } [
Top/End]   _svg.php
 [190]  function svg_sloped_line($slope,$xc,$yc,$color='black',$extra='') {
 [191]  global $xoffset,$yoffset,$ybaseline,$graph_width,$graph_height;
 [192]  if ($yoffset == 0) $yoffset = $ybaseline;
 [193]  if (!is_finite($slope)) {$ystart = $yoffset-$graph_height; $dy = $graph_height; $xstart = $xc; $dx = 0;}
 [194]  elseif ($slope == 0) {$xstart = $xoffset; $dx = $graph_width; $ystart = $yc; $dy = 0;}
 [195]  else {
 [196]  $ytop = $yoffset-$graph_height;
 [197]  $xright = $xoffset+$graph_width;
 [198]  $dytop = $yc-$ytop;
 [199]  $dybottom = $yoffset-$yc;
 [200]  $dxright = $xright-$xc;
 [201]  $dxleft = $xc-$xoffset;
 [202]  $dxtop = abs($dytop/$slope);
 [203]  $dxbottom = abs($dybottom/$slope);
 [204]  if ($slope > 0) {
 [205]  $dxup = min($dxtop,$dxright);
 [206]  $dxdown = min($dxbottom,$dxleft);
 [207]  $xstart = $xc - $dxdown;
 [208]  $ystart = $yc + $dxdown*$slope;
 [209]  } else { // negative slope
 [210]  $dxup = min($dxtop,$dxleft);
 [211]  $dxdown = min($dxbottom,$dxright);
 [212]  $xstart = $xc - $dxup;
 [213]  $ystart = $yc + $dxup*$slope;
 [214]  }
 [215]  $dx = $dxup + $dxdown;
 [216]  $dy = - $dx * $slope;
 [217]  }
 [218]  return svg_line(round($xstart,2),round($ystart,2),round($dx,2),round($dy,2),1,$color,$extra);
 [219]  } [
Top/End]   _svg.php
 [220]  function rainbow($bgcolor='#FFF',$digits=array('3','7','B','F')) {
 [221]  $n = count($digits);
 [222]  $colors = $previous = $rainbow = array();
 [223]  for ($rr=0; $rr<$n; $rr++) { // populate possible-colors array, identify background color
 [224]  for ($gg=0; $gg<$n; $gg++) {
 [225]  for ($bb=0; $bb<$n; $bb++) {
 [226]  $r = $rr*7 % $n; // to help mix the sequence of colors
 [227]  $g = $gg*19 % $n;
 [228]  $b = $bb*31 % $n;
 [229]  if (3*$r+3*$g+2*$b<3*($n-1) || (max($r,$g,$b)-min($r,$g,$b))<2) continue; // omit dark and low-saturation colors
 [230]  $color = '#' . $digits[$r] . $digits[$g] . $digits[$b];
 [231]  $a = array($r,$g,$b,$color);
 [232]  if ($bgcolor === $color) $previous = $a; else $colors[] = $a;
 [233]  }
 [234]  }
 [235]  }
 [236]  if (!$previous) $previous = array($n-1,$n-1,$n-1,'#FFF'); // $bgcolor or white will be used as initial previous color
 [237]  while ($colors) {
 [238]  $contrast = $ii = -1;
 [239]  foreach ($colors as $i=>$a) {
 [240]  list($r,$g,$b,$color) = $a;
 [241]  $v = abs($previous[0]-$r) + abs($previous[1]-$g) + abs($previous[2]-$b);
 [242]  if ($v > $contrast) {$ii = $i; $contrast = $v;}
 [243]  }
 [244]  if ($ii < 0) break; // no more candidate colors
 [245]  $previous = $colors[$ii];
 [246]  $rainbow[] = $previous[3];
 [247]  unset($colors[$ii]);
 [248]  }
 [249]  return $rainbow;
 [250]  } [
Top/End]   _svg.php
 [251]  function svg_horizontal_scale($yline,$xline,$xwidth,$xoffset,$xscale,$value_minimum,$value_maximum,$target_label_count=10) {
 [252]  $granularity = granularity125(($value_maximum-$value_minimum)/$target_label_count);
 [253]  return svg_horizontal_scale_exact($yline,$xline,$xwidth,$xoffset,$xscale,$value_minimum,$value_maximum,$granularity);
 [254]  } [
Top/End]   _svg.php
 [255]  function svg_horizontal_scale_exact($yline,$xline,$xwidth,$xoffset,$xscale,$value_minimum,$value_maximum,$granularity,$offset=0) {
 [256]  // $yline = pixel y coordinate of x axis
 [257]  // $xline = pixel x coordinate of the left end of x-axis line
 [258]  // $xwidth = pixel length of x-axis line
 [259]  // $xoffset = pixel x coordinate to which $value_minimum will be mapped
 [260]  // $xscale = pixels per value unit
 [261]  global $horizontal_scale_thickness,$tic_size,$cw,$ch,$legends;
 [262]  $label_padding = -10; $label_offset = -5; $label_rotation = 60;
 [263]  $svg = '';
 [264]  $multiple = multiple(($value_minimum-$offset)/$granularity,0.01); // so that ceil() does not mishandle edge cases
 [265]  $value = ceil($multiple)*$granularity + $offset;
 [266]  $label_count = floor(($value_maximum-$value_minimum)/$granularity+0.01);
 [267]  $y = $yline + $ch + $label_padding + $tic_size;
 [268]  $characters = 0;
 [269]  while ($label_count-- >= 0) {
 [270]  $value_text = round($value/$granularity) * $granularity;
 [271]  $characters = max($characters,strlen($value_text));
 [272]  $x = round($xoffset + $xscale*($value-$value_minimum),1);
 [273]  if ($x <= $xoffset+$xwidth) { // display only label if tic mark still in range of baseline
 [274]  $svg .=     svg_line($x,$yline,0,$tic_size,1);
 [275]  $xx = $x + $label_offset;
 [276]  $svg .= <<<TEXT
 [277]  <text font-family="Courier" font-size="10pt" x="$xx" y="$y" style="color:black" transform="rotate($label_rotation $xx,$y)" text-anchor="start">$value_text</text>
 [278] 
 [279]  TEXT;
 [280]  $value += $granularity;
 [281]  }
 [282]  }
 [283]  $horizontal_scale_thickness = round($tic_size+$characters*$cw*0.87+$ch*0.25);
 [284]  if ($legends[0]) {
 [285]  $horizontal_scale_thickness += $ch;
 [286]  $svg .= svg_text($legends[0],$xoffset+$xwidth/2,$yline+$horizontal_scale_thickness);
 [287]  }
 [288]  return ($svg . svg_line($xline,$yline,$xwidth,0,1,'black'));
 [289]  } [
Top/End]   _svg.php
 [290]  function svg_horizontal_scale_labels($xlabels,$yline,$xline,$xwidth,$xoffset,$xscale,$value_minimum,$value_maximum,$offset=0) {
 [291]  // $xlabels = array of x-positions indexed by corresponding labels
 [292]  // $yline = pixel y coordinate of x axis
 [293]  // $xline = pixel x coordinate of the left end of x-axis line
 [294]  // $xwidth = pixel length of x-axis line
 [295]  // $xoffset = pixel x coordinate to which $value_minimum will be mapped
 [296]  // $xscale = pixels per value unit
 [297]  global $horizontal_scale_thickness,$tic_size,$cw,$ch;
 [298]  $label_padding = -10; $label_offset = -5; $label_rotation = 60;
 [299]  $svg = '';
 [300]  $y = $yline + $ch + $label_padding + $tic_size;
 [301]  $maxcharacters = 0;
 [302]  $xprevious = -$ch*5;
 [303]  foreach ($xlabels as $label=>$xvalue) {
 [304]  if ($label === '') continue;
 [305]  $maxcharacters = max($maxcharacters,strlen($label));
 [306]  $x = round($xoffset + $xscale*($xvalue-$value_minimum),1);
 [307]  if ($x>$xprevious+$ch*2 && $x<=$xoffset+$xwidth) { // display label only if not too close to last label and tic mark still in range of baseline
 [308]  $svg .=     svg_line($x,$yline,0,$tic_size,1);
 [309]  $xx = $x + $label_offset;
 [310]  $svg .= <<<TEXT
 [311]  <text font-family="Courier" font-size="10pt" x="$xx" y="$y" style="color:black" transform="rotate($label_rotation $xx,$y)" text-anchor="start">$label</text>
 [312] 
 [313]  TEXT;
 [314]  $xprevious = $x;
 [315]  }
 [316]  }
 [317]  $horizontal_scale_thickness = round($tic_size+$maxcharacters*$cw*0.87+$ch*0.25);
 [318]  return ($svg . svg_line($xline,$yline,$xwidth,0,1,'black'));
 [319]  } [
Top/End]   _svg.php
 [320]  function svg_vertical_scale($xpadding,$yline,$yheight,$yoffset,$yscale,$value_minimum,$value_maximum,$target_label_count='') {
 [321]  global $vertical_scale_thickness,$cw,$ch,$minimum_xoffset,$legends;
 [322]  $label_offset = 4; $tic_size = 5;
 [323]  $svg = '';
 [324]  if (!$target_label_count) $target_label_count = max(2,floor($yheight/$ch/2));
 [325]  $granularity = granularity125(($value_maximum-$value_minimum)/$target_label_count);
 [326]  $value = ceil($value_minimum/$granularity) * $granularity;
 [327]  for ($v=$value,$characters=0; $v<=$value_maximum; $v+=$granularity) {
 [328]  $characters = max($characters,strlen(round($v/$granularity) * $granularity));
 [329]  }
 [330]  $vertical_scale_thickness = $tic_size+$cw*($characters+1);
 [331]  if ($legends[1]) $vertical_scale_thickness += $ch;
 [332]  $xline = max($xpadding+$vertical_scale_thickness,$minimum_xoffset);
 [333]  if ($legends[1]) {
 [334]  $xx = $xline-$vertical_scale_thickness+$ch;
 [335]  $yy = $yoffset - $yscale*($value_maximum-$value_minimum)/2;
 [336]  $svg .= <<<TEXT
 [337]  <text font-family="Courier" font-size="10pt" x="$xx" y="$yy" style="color:black" transform="rotate(-90 $xx,$yy)" text-anchor="middle">$legends[1]</text>
 [338] 
 [339]  TEXT;
 [340]  }
 [341]  $x = $xline - $tic_size;
 [342]  while ($value <= $value_maximum) {
 [343]  $value_text = round($value/$granularity) * $granularity;
 [344]  $y = round($yoffset - $yscale*($value-$value_minimum),1);
 [345]  $svg .=     svg_line($x,$y,$tic_size,0,1);
 [346]  $yy = $y + $label_offset;
 [347]  $svg .= <<<TEXT
 [348]  <text font-family="Courier" font-size="10pt" x="$x" y="$yy" style="color:black" text-anchor="end">$value_text</text>
 [349] 
 [350]  TEXT;
 [351]  $value += $granularity;
 [352]  }
 [353]  if (is_numeric($yline)) $svg .= svg_line($xline,$yline,0,-$yheight,1);
 [354]  return $svg;
 [355]  } [
Top/End]   _svg.php
 [356]  function svg_percentage_scale($xoffset,$yline,$yheight,$yoffset,$yscale,$value_minimum,$value_maximum,$target_label_count='') {
 [357]  global $percentage_scale_thickness,$cw,$ch;
 [358]  $label_offset = 4; $tic_size = 5;
 [359]  $svg = '';
 [360]  if (!$target_label_count) $target_label_count = max(2,floor($yheight/$ch/2));
 [361]  $granularity = granularity125(($value_maximum-$value_minimum)/$target_label_count);
 [362]  $value = ceil($value_minimum/$granularity) * $granularity;
 [363]  for ($v=$value,$characters=0; $v<$value_maximum; $v+=$granularity) {
 [364]  $characters = max($characters,(1+strlen(round($value/$granularity)*$granularity)));
 [365]  }
 [366]  $percentage_scale_thickness = $tic_size + $cw*($characters+2);
 [367]  $xline = $xoffset;
 [368]  $x = $xline + $tic_size;
 [369]  while ($value <= $value_maximum) {
 [370]  $value_text = (round($value/$granularity)*$granularity) . '%';
 [371]  $y = round($yoffset - $yscale*($value-$value_minimum),1);
 [372]  $svg .=     svg_line($xline,$y,$tic_size,0,1);
 [373]  $yy = $y + $label_offset;
 [374]  $svg .= <<<TEXT
 [375]  <text font-family="Courier" font-size="10pt" x="$x" y="$yy" style="color:black" text-anchor="start">$value_text</text>
 [376] 
 [377]  TEXT;
 [378]  $value += $granularity;
 [379]  }
 [380]  return ($svg . svg_line($xline,$yline,0,-$yheight,1));
 [381]  }
 [382]  $drawable_percentiles = array(); [
Top/End]   _svg.php
 [383]  function svg_percentile_scale($xline,$yline,$line_width,$bin_width,$min,$xscale,$xoffset,$histogram,$tic_length=-5,$percentiles='') {
 [384]  global $drawable_percentiles;
 [385]  // process requested percentiles so that none of the labels overlap and symmetry is maintained
 [386]  if (!$percentiles) $percentiles = $GLOBALS['default_percentiles'];
 [387]  $centeredness = $psets = array();
 [388]  foreach (percentile_values($histogram,$percentiles,$bin_width,$min,$xscale,$xoffset) as $i=>$pv) {
 [389]  $p = $pv['percentile'];
 [390]  $x = $pv['x'];
 [391]  if ($x>$xline && $x<$xline+$line_width) {$centeredness[] = ($p-0.5)*($p-0.5); $psets[] = array('p'=>$p,'x'=>$x,'i'=>$i,'pct'=>100*$p);}
 [392]  }
 [393]  if ($centeredness) array_multisort($centeredness,SORT_NUMERIC,$psets);
 [394]  $closest = 2 * $GLOBALS['cw'];
 [395]  $xlast = $xline + $line_width; // leave plenty of room for the first percentile less than or equal to the median
 [396]  $drawable_percentiles = array();
 [397]  foreach ($psets as $pset) { // keep percentiles that are not too close, going right to left starting from the median position
 [398]  if ($pset['p'] <= 0.5) {if (abs($pset['x']-$xlast) > $closest) {$drawable_percentiles[] = $pset; $xlast = $pset['x'];}}
 [399]  }
 [400]  $drawable_percentiles = array_reverse($drawable_percentiles); // put into left-to-right order so that the final array is all left-to-right
 [401]  $xlast = $drawable_percentiles ? $drawable_percentiles[0]['x'] : $xline; // either the closest left-side position or the left edge of the graph
 [402]  foreach ($psets as $pset) { // keep percentiles that are not too close, going left to right starting from the median position
 [403]  if ($pset['p'] > 0.5) {if (abs($pset['x']-$xlast) > $closest) {$drawable_percentiles[] = $pset; $xlast = $pset['x'];}}
 [404]  }
 [405]  // now draw labels and tic marks for the surviving percentiles
 [406]  $svg = '';
 [407]  $ytext = $GLOBALS['top_padding'] + $tic_length;
 [408]  foreach ($drawable_percentiles as $pset) {
 [409]  $svg .= svg_line($pset['x'],$yline,0,$tic_length);
 [410]  $svg .= <<<TEXT
 [411]  <text font-family="Courier" font-size="10pt" x="$pset[x]" y="$ytext" style="color:black" transform="rotate(-60 $pset[x],$ytext)" text-anchor="start">$pset[pct]%</text>
 [412] 
 [413]  TEXT;
 [414]  }
 [415]  $svg .= svg_line($xline,$yline,$line_width,0);
 [416]  return $svg;
 [417]  } [
Top/End]   _svg.php
 [418]  function point_glyph($x,$y,$index=0) { // return svg code for glyph to mark point position
 [419]  global $point_glyph_colors,$point_glyph_radius,$point_glyph_side,$point_glyph_count;
 [420]  $color = $point_glyph_colors[$index%$point_glyph_count];
 [421]  $fill = $index<$point_glyph_count ? $color : 'white';
 [422]  if ($index%2 == 0) return svg_circle($x,$y,$point_glyph_radius,$fill,1.5,$color); // circle for even, rect for odd
 [423]  return svg_rect($x-$point_glyph_side/2,$y-$point_glyph_side/2,$point_glyph_side,$point_glyph_side,$fill,1.5,$color);
 [424]  } [
Top/End]   _svg.php
 [425]  function pie_chart($parts,$whole=0,$diameter=20,$colors=array()) {
 [426]  $r = $diameter/2; $c = $r+1;
 [427]  $svg = svg_start('',$diameter+3,$diameter+3) . svg_circle($c,$c,$r,'white');
 [428]  if (!is_array($parts)) $parts = csplit($parts);
 [429]  if (!$colors) $colors = $GLOBALS['color_array'];
 [430]  if (!is_array($colors)) $colors = csplit($colors);
 [431]  if ($whole == 0) {foreach ($parts as $part) $whole += $part;}
 [432]  if ($whole) {
 [433]  $arcs = array();
 [434]  $fractions = 0;
 [435]  foreach ($parts as $i=>$part) {
 [436]  $fraction = $part/$whole;
 [437]  $svg .= pie_slice($c,$c,$r,$fraction,array_color($i),$fractions);
 [438]  $fractions += $fraction;
 [439]  }
 [440]  }
 [441]  return sub($svg . svg_end());
 [442]  } [
Top/End]   _svg.php
 [443]  function pie_slice($x,$y,$r,$fraction,$color='red',$fraction_offset=0) {
 [444]  return svg_arc($x,$y,$r,360*$fraction_offset-90,360*$fraction,$color,''); // for pie graph, shift arc so that its zero-degree position is at the top
 [445]  } [
Top/End]   _svg.php
 [446]  function svg_arc($x,$y,$r,$start_degrees,$size_degrees,$fill='',$color='black',$thickness=1) {
 [447]  $path_d = $style = '';
 [448]  $start_degrees;
 [449]  $a0 = deg2rad($start_degrees); $x0 = round($x+cos($a0)*$r,1); $y0 = round($y+sin($a0)*$r,1);
 [450]  $a1 = deg2rad($start_degrees+$size_degrees); $x1 = round($x+cos($a1)*$r,1); $y1 = round($y+sin($a1)*$r,1);
 [451]  $long = $size_degrees>=180 ? 1 : 0;
 [452]  $path_d = "A $r,$r 0 $long,1 $x1,$y1";
 [453]  if ($fill) {$path_d = "M $x,$y L $x0,$y0 $path_d z"; $style .= "fill:$fill;";}
 [454]  else $path_d = "M $x0,$y0 $path_d";
 [455]  if ($color) $style .= "stroke-thickness:$thickness;stroke-color:$color;";
 [456]  return "<path d='$path_d' style='$style' />\n";
 [457]  } [
Top/End]   _svg.php
 [458]  function pie_single_slice($fraction,$start=0,$diameter=20,$color='red',$background='white') {
 [459]  $r = $diameter/2; $c = $r+1;
 [460]  $svg = svg_start('',$diameter+3,$diameter+3) . svg_circle($c,$c,$r,$background) . pie_slice($c,$c,$r,$fraction,$color,$start);
 [461]  return sub($svg . svg_end());
 [462]  }
 [463]  $color_array = array('red','green','blue','yellow','pink','orange','purple','tan'); [
Top/End]   _svg.php
 [464]  function array_color($index,$array=array()) { // picks a color out of supplied or default array, cycling colors if necessary
 [465]  if (!$array) $array = $GLOBALS['color_array'];
 [466]  if (!is_array($array)) $array = csplit($array);
 [467]  return (($array && is_numeric($index) && $index>=0) ? $array[$index%count($array)] : $index);
 [468]  }
 [469]  ?>

FILE: anova_difference_of_means.php - 73 lines, 0 functions [
Top/End]
  [1]  <?php
  [2]  require_once '_statistics.php';
  [3]  //
  [4]  $digits = 6;
  [5]  $file = rq('file');
  [6]  //if ($file) $example = ssplit(str_replace("\n",';',trim(file_read_contents($file))));
  [7]  if ($file) $example = split_input(file_read_contents($file));
  [8]  else $example = ssplit(rq('example'));
  [9]  $k = $example ? count($example) : rq('k');
  [10]  if ($command && (!is_numeric($k) || $k<0 || $k!=round($k))) {error('The number of groups must be an integer greater than 1'); redirect();}
  [11]  //
  [12]  $page = rqn('page') + 1;
  [13]  page_start("ANOVA Test for Difference of Means","<br>(from summarized data)" .
  [14]  (!$k ? ' ' . alink('Example','?example=Group 1,8,30.75,9.25;Group 2,8,34.0,14.63;Group 3,8,49.25,10.79') : ''));
  [15]  print p('<b>Number of groups:</b> k=' . ($k ? "$k " . alink('Reset') . hidden('k',$k) : textbox('k',$k,2)));
  [16]  $ns = $xs = $ss = array();
  [17]  if ($k > 1) {
  [18]  print "<table>" . tr(th('group<br>label') . th('sample<br>size') . th('sample<br>mean') . th('standard<br>deviation'));
  [19]  for ($i=1; $i<=$k; $i++) {
  [20]  $l = isset($example[$i-1]) ? $example[$i-1][0] : rq("label$i","Group $i");
  [21]  $n = isset($example[$i-1]) ? $example[$i-1][1] : rq("n$i");
  [22]  $x = isset($example[$i-1]) ? $example[$i-1][2] : rq("x$i");
  [23]  $s = isset($example[$i-1]) ? $example[$i-1][3] : rq("s$i");
  [24]  print tr(td(textbox("label$i",$l,8)) . tdc(textbox("n$i",$n,5)) . tdc(textbox("x$i",$x,7)) . tdc(textbox("s$i",$s,7)));
  [25]  if ($n !== '') {
  [26]  if (!is_numeric($n) || $n<2 || $n!=round($n) || !is_numeric($x) || !is_numeric($s) || $s<=0) error("Bad entry value for group $i");
  [27]  else {$ns[] = $n; $xs[] = $x; $ss[] = $s;}
  [28]  }
  [29]  }
  [30]  //     $nall = rq("nall");
  [31]  //     $xall = rq("xall");
  [32]  //     $sall = rq("sall");
  [33]  //     print tr(tdr('TOTAL n=') . tdc(textbox("nall",$nall,5)) . tdc(textbox("xall",$xall,7)) . tdc(textbox("sall",$sall,7)));
  [34]  //     if ($page>2 && (!is_numeric($nall) || $nall<2 || $nall!=round($nall) || !is_numeric($xall) || !is_numeric($sall) || $sall<=0)) {error("Bad entry value for Total"); $page = 2;}
  [35]  if ($ns && !$error) {
  [36]  for ($j=0,$nall=0,$xsum=0,$sse=0; $j<$k; $j++) {$nall += $ns[$j]; $xsum += $ns[$j]*$xs[$j]; $sse += ($ns[$j]-1)*pow($ss[$j],2);}
  [37]  $xall = $xsum / $nall;
  [38]  for ($j=0,$ssg=0; $j<$k; $j++) $ssg += $ns[$j] * pow($xs[$j]-$xall,2);
  [39]  $sst = $sse + $ssg;
  [40]  $sall = sqrt($sst/($nall-1));
  [41]  $msg = $ssg / ($k-1);
  [42]  $mse = $sse / ($nall-$k);
  [43]  $f = $msg / $mse;
  [44]  print tr(tdr('Combined') . tdc("n=$nall") . tdc(np($xall,0,$digits)) . tdc(np($sall,0,$digits)));
  [45]  }
  [46] 
  [47] 
  [48]  print "</table>";
  [49]  }
  [50]  print p(commandbutton($k ? 'Compute ANOVA results from these values' : 'Display form to enter group summaries'));
  [51]  print hidden('page',$page);
  [52]  if ($command && $ns && !$error) {
  [53]  print p(bold('From the combined values, compute:'));
  [54]  print "<table border=1 cellpadding=3>" . tr(th('Variability') . th() . th('Value') . th('df'));
  [55]  print tr(tdc('Between groups') . td('SSG') . tdc(np($ssg,0,$digits)) . tdc($k-1));
  [56]  print tr(tdc('Within groups') . td('SSE') . tdc(np($sse,0,$digits)) . tdc($nall-$k));
  [57]  print tr(tdc('Total') . td('SST') . tdc(np($sst,0,$digits)) . tdc($nall-1));
  [58]  print "</table>";
  [59]  print "<table>" . tr(tdc(bold('<br>Then compute the F statistic:'),6));
  [60]  print tr(tdr('MSG = ') . tdc(fraction_table('SSG','k-1','')) . td('=') . tdc(fraction_table(np($ssg,0,$digits),$k-1,'')) . td('=') . td(np($msg,0,$digits)));
  [61]  print tr(tdr('MSE = ') . tdc(fraction_table('SSE','n-k','')) . td('=') . tdc(fraction_table(np($sse,0,$digits),$nall-$k,'')) . td('=') . td(np($mse,0,$digits)));
  [62]  print tr(tdr('F = ') . tdc(fraction_table('MSG','MSE','')) . td('=') . tdc(fraction_table(np($msg,0,$digits),np($mse,0,$digits),'')) . td('=') . td(np($f,0,$digits)));
  [63]  print tr(tdc("with df=$k for the numerator<br>and df=" . ($n-$k) . ' for the denominator',6));
  [64]  print "</table>";
  [65]  }
  [66]  page_end();
  [67] 
  [73]  ?>
FILE: beta_distribution_parameterized.php - 91 lines, 0 functions [
Top/End]
  [1]  <?php
  [2]  require_once '_statistics.php';
  [3]  $graph_width = max(10,rqn('graph_width',500));
  [4]  $graph_height = max(10,rqn('graph_height',375));
  [5]  $shapes = array('Uniform'=>array(1,1),'Bell-shaped'=>array(10,10),'Left-skewed'=>array(7,3),'Right-skewed'=>array(3,7));
  [6]  $padding_names = array('left','right','top','bottom');
  [7]  $left_padding = rqf('left_padding',15,$graph_width);
  [8]  $right_padding = rqf('right_padding',15,$graph_width);
  [9]  $top_padding = rqf('top_padding',15,$graph_height);
  [10]  $bottom_padding = rqf('bottom_padding',15,$graph_height);
  [11]  $color_line = rq('color_line','black');
  [12]  $color_fill = rq('color_fill','lightgray');
  [13]  $color_background = rq('color_background','white');
  [14]  $fill = $color_fill && ($color_fill!==$color_background);
  [15]  $thickness = rqf('thickness',2);
  [16]  $xmin = rqf('xmin',0);
  [17]  $xmax = rqf('xmax',1);
  [18]  $range = $xmax - $xmin;
  [19]  if ($range <= 0) error('<i>x</i>-max must be larger than <i>x</i>-min');
  [20]  $ymax = rqf('ymax',1);
  [21]  if ($ymax <= 0) error('<i>y</i>-max must be positive.');
  [22]  $shift = rqf('shift',0);
  [23]  $stretch = rqf('stretch',1);
  [24]  if ($stretch <= 0) error('stretch ratio must be positive');
  [25]  $mode = rq('mode','area');
  [26]  $scale = rqf('scale',1);
  [27]  $shape = rq('shape','Custom');
  [28]  if ($shape !== 'Custom') {$alpha = $shapes[$shape][0]; $beta = $shapes[$shape][1];}
  [29]  else {$alpha = max(rqf('alpha',6),0.01); $beta = max(rqf('beta',6),0.01);} // custom settings
  [30]  $horizontal = rq1('horizontal') || !$command;
  [31]  $vertical = rq1('vertical') || !$command;
  [32]  //
  [33]  page_start('');
  [34]  print "<table cellpadding=20><tr><td valign=top>\n<table border=1 cellpadding=3>\n"; // controls in left column
  [35]  $radios = radio('shape','Custom',$shape,'Custom') . 'α=' . textbox('alpha',$alpha,3) . ' β=' . textbox('beta',$beta,3);
  [36]  foreach (array_keys($shapes) as $key) $radios .= "<br>\n" . radio('shape',$key,$shape,$key);
  [37]  print tr(tdc(p(commandbutton('Make Graph')) . table('cellpadding=0 border=0',$radios)));
  [38]  print tr(tdc(br(bold('Function Settings')) .
  [39]  br('<i>x</i>-min=' . textbox('xmin',$xmin,5) . '   <i>x</i>-max=' . textbox('xmax',$xmax,5)) .
  [40]  br('stretch=' . textbox('stretch',$stretch,5) . '   shift=' . textbox('shift',$shift,5)) .
  [41]  br('<i>peak:</i> max=' . textbox('ymax',$ymax,3) . ' scale=' . textbox('scale',$scale,3))));
  [42]  $padding = "<i>padding:</i>";
  [43]  foreach ($padding_names as $name) {$name .= '_padding'; $padding .= ' ' . strtoupper(substr($name,0,1)) . textbox($name,$GLOBALS[$name],2);}
  [44]  $colors = "<table cellpadding=0 border=0>";
  [45]  foreach (array('Line color'=>'color_line','Fill color'=>'color_fill','Background'=>'color_background') as $label=>$name) $colors .= tr(tdr($label) . td(textbox($name,$GLOBALS[$name],10)));
  [46]  $colors .= "</table>\n";
  [47]  print tr(tdc(br(bold('Image Settings')) .
  [48]  p('width=' . textbox('graph_width',$graph_width,4) . '   height=' . textbox('graph_height',$graph_height,4)) . p($padding) .
  [49]  p('<i>scales:</i>' . checkbox('horizontal',$horizontal) . checkbox('vertical',$vertical)) . p('<i>line thickness:</i> ' . textbox('thickness',$thickness,2)) . $colors));
  [50]  print "</table></td><td valign=top>\n"; // graph goes in right column
  [51]  // generate data and normalize to specified peak height
  [52]  $f = make_beta_distribution($alpha,$beta);
  [53]  $fmax = $f ? max($f) : 0;
  [54]  foreach ($f as $i=>$p) $f[$i] *= $scale * $ymax/$fmax;
  [55]  //
  [56]  $values = array();
  [57]  if (!$error && $fmax>0) {
  [58]  $xstep = $range/$graph_width/$stretch;
  [59]  $xscale = $graph_width/$range;
  [60]  $yscale = $graph_height/$ymax;
  [61]  $xoffset = $left_padding;
  [62]  $yoffset = $graph_height + $top_padding;
  [63]  $vertical_scale_thickness = $horizontal_scale_thickness = 0;
  [64]  $vertical_scale = $horizontal_scale = '';
  [65]  if ($vertical) $vertical_scale = svg_vertical_scale($left_padding,$yoffset,$graph_height,$yoffset,$yscale,0,$ymax);
  [66]  $xoffset += $vertical_scale_thickness;
  [67]  if ($horizontal) $horizontal_scale = svg_horizontal_scale($yoffset,$xoffset,$graph_width,$xoffset,$xscale,$xmin,$xmax,7);
  [68]  $view_width = $left_padding + $vertical_scale_thickness + $graph_width + $right_padding;
  [69]  $view_height = $top_padding + $graph_height + $horizontal_scale_thickness + $bottom_padding;
  [70]  $interpolation_scale = count($f)/$range;
  [71]  $points = $fill ? "$xoffset,$yoffset " : '';
  [72]  for($i=0,$x=$xoffset; $i<$graph_width; $i++,$x++) {
  [73]  $j = $interpolation_scale * ($i*$xstep-$shift/$stretch);
  [74]  $y = $yoffset - interpolated($f,$j,0,0) * $yscale;
  [75]  $points .= "$x,$y ";
  [76]  }
  [77]  if ($fill) $points .= ($xoffset+$graph_width-1) . ",$yoffset";
  [78]  else $color_fill = $color_background;
  [79]  print svg_start('',$view_width,$view_height,$color_background);
  [80]  print svg_polyline($points,array('fill'=>$color_fill,'stroke'=>$color_line,'stroke-width'=>$thickness));
  [81]  print $vertical_scale . $horizontal_scale . svg_end();
  [82]  }
  [83]  print "</td></tr></table>\n";
  [84]  page_end();
  [85] 
  [91]  ?>
FILE: bootstrap_means.php - 187 lines, 1 function [
Top/End]
  [1]  <?php
  [2]  require_once '_statistics.php';
  [3]  // graph constants
  [4]  $sigmas = 5;
  [5]  $bottom_padding = 1.5*$ch;
  [6]  $top_padding = 2.5*$ch;
  [7]  $side_padding = $cw;
  [8]  $bins = 100;
  [9]  $graph_width = 500;
  [10]  $graph_height = 250;
  [11]  $percentile_colors = array('#DFD',"#DDF");
  [12]  // get-data section
  [13]  $random = rqn('random');
  [14]  $clear = rq1('clear');
  [15]  $data = $clear ? '' : rq('data');
  [16]  if (rq('file')) {
  [17]  $filespec = rq('file');
  [18]  $files = files($filespec);
  [19]  if (!$files && is_dir('data')) $files = files("./data/$filespec");
  [20]  if ($files) {
  [21]  $datafilename = $files ? $files[rand(0,count($files)-1)] : '';
  [22]  $data = file_read_contents($datafilename);
  [23]  }
  [24]  } else $datafilename = '';
  [25]  if ((!$data && !$clear) || $random) $data = implode(' ',round_array(make_uniform_data(($random ? $random : 20),20,180),2));
  [26]  $data = substitute_minus($data);
  [27]  $values = extract_numbers($data);
  [28]  if (count($values) < 2) {$data = ''; $values = array();}
  [29]  $value_count = count($values);
  [30]  // samples section (retrieve previous, decide if more wanted)
  [31]  $samples = nsplit(rq('samples'));
  [32]  $sample_count = count($samples);
  [33]  $stats = nsplit(rq('stats'));
  [34]  $std_sum = rqf('std_sum');
  [35]  if (contains($command,'Reset')) {$samples = $stats = array(); $std_sum = 0;} // discard previous samples
  [36]  $more = rqn('more');
  [37]  if ($clear || $random || $data!==rq('old_data') || contains($command,'Repeat')) { // replace previous samples
  [38]  $more = $more + count($samples);
  [39]  $samples = $stats = array();
  [40]  $std_sum = 0;
  [41]  }
  [42]  // trim section
  [43]  $old_trim = rq('old_trim','No');
  [44]  $trim = rq('trim',$old_trim);
  [45]  $trim_fraction = numf($trim);
  [46]  $statistic = $trim_fraction ? "$trim-trimmed mean" : 'mean';
  [47]  if ($trim != $old_trim) { // recompute statistics from prior samples if trim percentage changed
  [48]  $stats = array();
  [49]  foreach ($samples as $sample) $stats[] = trimmed_mean(csplit($sample),$trim_fraction);
  [50]  }
  [51]  // graph pre-computation section
  [52]  if ($values) {
  [53]  $value_mean = trimmed_mean($values,$trim_fraction);
  [54]  $value_std = standard_deviation($values);
  [55]  while ($more-- > 0) {
  [56]  $sample = bootstrap($values);
  [57]  $stats[] = trimmed_mean($sample,$trim_fraction);
  [58]  $samples[] = cjoin($sample);
  [59]  $std_sum += standard_deviation($sample);
  [60]  }
  [61]  $std = $values ? standard_deviation($values)/sqrt($value_count) : 0;
  [62]  if ($std <= 0) $std = 1; // guard against all-values-equal case
  [63]  $min = $value_mean - $sigmas*$std;
  [64]  $max = $value_mean + $sigmas*$std;
  [65]  $range = $max-$min; // the value width of the horizontal scale for the distribution of bootstrapped means
  [66]  $bin_width = $range / $bins;
  [67]  $xscale = $graph_width / $range;
  [68]  $xstep = $bin_width * $xscale;
  [69]  $histogram = array_fill(0,$bins,0);
  [70]  foreach ($stats as $stat) {
  [71]  $index = floor(($stat-$min)/$bin_width);
  [72]  if ($index>=0 && $index<$bins) $histogram[$index]++;
  [73]  }
  [74]  $histogram_max = max(max($histogram)+1,$graph_height/$xstep);
  [75]  $yscale = $graph_height/$histogram_max;
  [76]  $ystep = -$yscale;
  [77]  $squeezed = ($yscale < 1);
  [78]  $yoffset = $top_padding + $graph_height;
  [79]  $vscale = svg_vertical_scale($side_padding,$yoffset,$graph_height,$yoffset,$yscale,0,$histogram_max);
  [80]  $xoffset = $vertical_scale_thickness + $side_padding;
  [81]  $hlines = svg_line($xoffset,$yoffset,$graph_width,0); // start with black baseline
  [82]  $hline_step = granularity125($histogram_max/12);
  [83]  for ($i=$hline_step; $i<=$histogram_max; $i += $hline_step) $hlines .= svg_line($xoffset,$yoffset+$i*$ystep,$graph_width,0,1,'#BBB',"stroke-dasharray='1,3'"); // add a gray line at each count height
  [84]  $hscale = svg_horizontal_scale($yoffset,$xoffset,$graph_width,$xoffset,$xscale,$min,$max);
  [85]  $view_width = $xoffset + $graph_width +$side_padding;
  [86]  $view_height = $graph_height + $top_padding + $horizontal_scale_thickness + $bottom_padding;
  [87]  $xcenter = $xoffset + $graph_width/2;
  [88]  }
  [89]  //
  [90]  $mode = rq('mode');
  [91]  $score = rq('score');
  [92]  $percentile = rq('percentile');
  [93]  $last_score = rq('last_score');
  [94]  $last_percentile = rq('last_percentile');
  [95]  if (is_numeric($score) && $score!=$last_score) {$mode = 'percentile'; $percentile = '';}
  [96]  elseif ($percentile !== $last_percentile) {$mode = 'score'; $score = '';}
  [97]  if (contains($command,'Percentile')) $mode = 'percentile';
  [98]  elseif (contains($command,'Score')) $mode = 'score';
  [99]  $pfraction = numf($percentile);
 [100]  if ($pfraction < 0) $pfraction = 1 + $pfraction;
 [101]  if ($values) { // infer mode from settings
 [102]  if (($pfraction==0 || $pfraction>=1) && is_numeric($score)) $mode = 'percentile'; // compute percentile if score but not percentile specified
 [103]  if ($pfraction>0 && $pfraction<1 && !is_numeric($score)) $mode = 'score'; // compute score if percentile but not score specified
 [104]  } else $mode = ''; // disable score/percentile computations if no data
 [105]  if ($mode==='percentile') { // compute percentile from score
 [106]  if (is_numeric($score))     {
 [107]  $pfraction = percentile_from_score($score,$histogram,$min,$bin_width);
 [108]  $percentile = contains($percentile,'%') ? nz($pfraction*100,1,4) . '%' : nz($pfraction,3,4);
 [109]  } else {$mode = ''; error(($score==='' ? 'No' : 'Invalid') . ' score specifed for computing percentile');}
 [110]  }
 [111]  if ($mode === 'score') { // compute score from percentile
 [112]  if ($pfraction>0 && $pfraction<1) $score = np(score_from_percentile($pfraction,$histogram,$min,$bin_width),1,4);
 [113]  else {$mode = ''; error(($percentile==='' ? 'No' : 'Invalid') . ' percentile specified for computing score');}
 [114]  }
 [115]  $percentile_cell = br(form_button(bold('Compute Percentile',$mode==='percentile'),'')) . 'for Score=' . textbox('score',$score,5);
 [116]  $score_cell = br(form_button(bold('   Compute Score   ',$mode==='score'),'')) . 'for Percentile=' . textbox('percentile',$percentile,5);
 [117]  $percentile_control = $samples ? p(table(1,table(-5,tr(tdc(br($percentile_cell))),tr(tdc($score_cell))))) : '';
 [118]  //
 [119]  $sample_control = p(bold('Accumulate resamplings'));
 [120]  if ($samples) $sample_control .= form_button('Reset') . '  ';
 [121]  foreach (array(1,10,50,250) as $n) $sample_control .= ' ' . commandbutton($n,'more');
 [122]  $sample_control .= br(plural($stats,'accumulated mean') . ' ' . form_button('Repeat',''),1);
 [123]  //
 [124]  $trim_control = !$samples ? '' : p('Trim means before tabulation?') . br(local_buttons('trim',array('No','5%','10%','20%','50%'),$trim)) .
 [125]  br(small(($trim_fraction ? 'After sorting, use middle ' . round(100-100*$trim_fraction) . "% of the values" : "Use all the values in computing the means")));
 [126]  //
 [127]  page_start('Bootstrap Resampling');
 [128]  $top_text = br(bold('Original Sample') . '   <sup>' . alink('Clear','?clear=1') . '</sup>') . br(textarea('data',$data,5,25));
 [129]  $random_text = br(small('Replace sample with random values ')) . local_buttons('random',array('5','20','100'),$value_count);
 [130]  $data_control = table('border=1 cellpadding=10',tdc(p($top_text) . $random_text));
 [131]  print "<table cellpadding=3><tr>\n" . tdc($data_control . $sample_control . $percentile_control . $trim_control,'top rowspan=2');
 [132]  //
 [133]  print td('','width=20') . "<td valign=top>\n";
 [134]  if ($values) { // graph section
 [135]  print svg_start('histogram',$view_width,$view_height,'white');
 [136]  if ($stats && is_numeric($score)) {
 [137]  $px = max(0,min(($score-$min)*$xscale,$graph_width)) + $xoffset;
 [138]  print svg_rect($xoffset,$top_padding,$px-$xoffset,$graph_height,$percentile_colors[0]);
 [139]  print svg_rect($px,$top_padding,$graph_width+$xoffset-$px,$graph_height,$percentile_colors[1]);
 [140]  if ($mode === 'score') print svg_text("percentile $percentile is at score $score",$xcenter,$ch*1.5);
 [141]  if ($mode === 'percentile') print svg_text("score $score is at percentile $percentile",$xcenter,$ch*1.5);
 [142]  }
 [143]  print $hlines;
 [144]  foreach ($histogram as $index=>$count) {
 [145]  $x = $xoffset + $index*$xstep;
 [146]  $y = $yoffset;
 [147]  if ($squeezed) print svg_rect($x,$y,$xstep,$count*$ystep,'black','black');
 [148]  else {while ($count-- > 0) {print svg_rect($x,$y,$xstep,$ystep,'gray','black'); $y += $ystep;}}
 [149]  }
 [150]  print $hscale . $vscale;
 [151]  $text = "$statistic of the original sample = " . np($value_mean,0,5);
 [152]  $xtext = $xcenter - round(0.8*$cw*strlen($text)/2);
 [153]  $ytext = $yoffset + $horizontal_scale_thickness + $ch;
 [154]  print svg_circle($xtext,$ytext-$text_offset,2,'aqua',1,'black') . svg_text($text,$xtext+$cw,$ytext,array('text-anchor'=>'start'));
 [155]  print svg_circle($xcenter,$yoffset+2,2,'aqua',1,'black');
 [156]  print svg_end();
 [157]  }
 [158]  print "</td></tr>\n";
 [159]  //
 [160]  if ($samples) {
 [161]  $heading = br() . plural($stats,'resample') . ' of ' . plural($values,'item') . small(' (random selections with replacement)');
 [162]  $mean_heading = $trim_fraction ? tdc('<small>' . str_replace('mean','</small><br>mean',"{$statistic}s"),2) : td('','width=10') . tdc("{$statistic}s",'bottom');
 [163]  print tr(td() . td(table(-1,tr(tdc($heading,'bottom') . $mean_heading),
 [164]  tr(td(textarea('samples',njoin($samples),5,55,FALSE,'readonly')) . td() . td(textarea('stats',njoin($stats),5,6,FALSE,'readonly')))),'top'));
 [165]  }
 [166]  print "</table>\n";
 [167]  if ($samples && $value_std>0) { // comparison report
 [168]  $difference_ratio = (average($stats)-$value_mean)/$value_std; // resamples minus original means as fraction of original std
 [169]  $std_ratio = $std_sum/count($samples)/$value_std; // ratio of resampled and original stds
 [170]  print p('<i>comparison of resampled</i>[r]<i> & original</i>[o]<i> value sets:</i>     σ<sub>r</sub>/σ<sub>o</sub> = ' . round($std_ratio,6) .
 [171]  '     (mean<sub>r</sub>-mean<sub>o</sub>)/σ<sub>o</sub> = ' . round($difference_ratio,6));
 [172]  }
 [173]  print hidden('old_data',$data) . hidden('old_trim',$trim) . hidden('mode',$mode) . hidden('std_sum',$std_sum) . hidden('last_score',$score) . hidden('last_percentile',$percentile);
 [174]  page_end();
 [175]  [Top/End]   bootstrap_means.php
 [176]  function local_buttons($name,$value_array,$current,$style='') {
 [177]  $text = '';
 [178]  foreach (make_array($value_array) as $value) $text .= form_button($value,("$current"==="$value" ? 'font-weight:bold;' : '') . $style,$name) . ' ';
 [179]  return $text;
 [180]  }
 [181] 
 [187]  ?>

FILE: box_plot.php - 31 lines, 0 functions [
Top/End]
  [1]  <?php
  [2]  require_once '_statistics.php';
  [3]  $graph_width = 400; $graph_height = 60; $thickness = 1; $box_fill = 'white';
  [4]  $data = rq('data');
  [5]  $random = rqn('random');
  [6]  if (!$data && !rq1('clear') && !$random) $random = 30;
  [7]  if ($random > 0) {
  [8]  $data = '';
  [9]  $power = rqn('power',2);
  [10]  $scale = pow(10,$power);
  [11]  $center = rqf('minimum',0.2*$scale) + 0.5*$scale;
  [12]  foreach (make_gaussian_data($random,$center,0.2*$scale) as $value) $data .= np($value,3-$power) . "\n";
  [13]  }
  [14]  $values = extract_numbers(uncommented($data));
  [15]  $count = count($values);
  [16]  //
  [17]  page_start("Box Plot of Values");
  [18]  print "<table cellpadding=10><tr>\n";
  [19]  print tdc(br(alink('Generate random values','?random=' . rand(8,50))) . pc(italic('Paste values below'),1) .
  [20]  br(textarea('data',uncommented($data),6,10)) . br(commandbutton('Make Box Plot')) . pc(alink('Clear data','?clear=1')));
  [21]  print "<td valign=center align=center>\n";
  [22]  if ($count > 1) print_boxplot($values,$graph_width,$graph_height);
  [23]  print "</td></table>\n";
  [24]  page_end();
  [25] 
  [31]  ?>
FILE: box_plot_compare.php - 45 lines, 0 functions [
Top/End]
  [1]  <?php
  [2]  require_once '_statistics.php';
  [3]  $areas = 3;
  [4]  $padding = 20; $graph_width = 400; $graph_height = 50; $thickness = 1; $box_fill = 'white';
  [5]  page_start("Compare Box Plots");
  [6]  print "<table cellpadding=10><tr><td align=center valign=top>\n";
  [7]  $all_values = array();
  [8]  $dataset_count = 0;
  [9]  for ($n=1; $n<=$areas; $n++) {
  [10]  $values[$n] = extract_numbers(rq("data$n"));
  [11]  if (!$command) $values[$n] = round_array(make_gaussian_data(rand(80+30/rand(1,5),99),30+5*rand(1,5),5));
  [12]  print p("Paste value-set #$n below") . br(textarea("data$n",implode(' ',$values[$n]),6,25));
  [13]  $all_values = array_merge($all_values,$values[$n]);
  [14]  if ($values[$n]) $dataset_count++;
  [15]  }
  [16]  print p(commandbutton('Display'));
  [17]  print "</td>\n<td valign=top align=center>\n";
  [18]  if ($dataset_count) {
  [19]  $all_min = min($all_values);
  [20]  $all_max = max($all_values);
  [21]  $all_range = $all_max - $all_min;
  [22]  $extra = $all_range/10;
  [23]  $xscale = $all_range ? $graph_width/($all_range+2*$extra) : 0;
  [24]  $hscale = svg_horizontal_scale($graph_height+2*$padding,$padding,$graph_width,$padding,$xscale,$all_min-$extra,$all_max+$extra);
  [25]  $view_height = $graph_height + 2.5*$padding + $horizontal_scale_thickness;
  [26]  $view_width = $graph_width + 2*$padding;
  [27]  for ($n=1; $n<=$areas; $n++) {
  [28]  if (!$values[$n]) continue;
  [29]  $xoffset = (min($values[$n])-$all_min)*$xscale + $padding;
  [30]  print "<p>\n" . svg_start('boxplot',$view_width,$view_height,'white');
  [31]  print svg_boxplot($values[$n],$graph_width,$graph_height,$xscale,$xoffset,$padding);
  [32]  print $hscale . svg_end();
  [33]  $outliers = count($boxplot_lows) + count($boxplot_highs);
  [34]  print br() . italic("Set #$n: " . plural($values[$n],'value') . ' (' . ($outliers ? 'including ' . plural($outliers,'outlier') : 'with no outliers') . ')') . "</p>\n";
  [35]  }
  [36]  }
  [37]  print "</td></tr></table>\n";
  [38]  page_end();
  [39] 
  [45]  ?>
FILE: boxplot_parameterized.php - 62 lines, 0 functions [
Top/End]
  [1]  <?php
  [2]  require_once '_statistics.php';
  [3]  $shapes = array('Custom'=>array(0,0),'Uniform'=>array(1,1),'Bell-shaped'=>array(6,6),
  [4]  'Left-skewed'=>array(3.7,1.5),'Right-skewed'=>array(1.5,3.7),'U-shaped'=>array(0.25,0.25));
  [5]  $padding = 20;
  [6]  $count = rqn('count',100);
  [7]  $bins = rqn('bins',15);
  [8]  $low = rqf('low',0);
  [9]  $bin_width = rqf('bin_width',1);
  [10]  $width = $bin_width * $bins;
  [11]  $high = $low + $width;
  [12]  $shape = rq('shape','Custom');
  [13]  if (same($shape,'Custom')) {$alpha = max(rqf('alpha',6),0.01); $beta = max(rqf('beta',6),0.01);}
  [14]  else {$alpha = $shapes[$shape][0]; $beta = $shapes[$shape][1];}
  [15]  $graph_width = rqn('graph_width',250);
  [16]  $graph_height = rqn('graph_height',50);
  [17]  $gbg = rq('gbg','white');
  [18]  $bbg = rq('bbg','lightgray');
  [19]  $pbg = rq('pbg',$page_background_color);
  [20]  if ($pbg) $page_background_color = $pbg;
  [21]  $outline = rq1('outline');
  [22]  $places = rqn('places',2);
  [23]  $stretch = rqf('stretch',1);
  [24]  $shift = rqf('shift',0);
  [25]  $left_padding = rqn('left_padding',5);
  [26]  $right_padding = rqn('right_padding',15);
  [27]  $top_padding = rqn('top_padding',10);
  [28]  $bottom_padding = rqn('bottom_padding',5);
  [29]  //
  [30]  if (contains($command,'Settings')) { // retrieve data from hidden variable
  [31]  $values = csplit(rq('data'));
  [32]  } elseif ($command) { // make new set of values using specified parameters
  [33]  make_beta_distribution($alpha,$beta);
  [34]  $values = round_array(make_beta_data($count,'beta',$low,$high),$places);
  [35]  } else $values = array();
  [36]  //
  [37]  page_start('Box Plot From Parameters');
  [38]  print "<table cellpadding=20><tr><td valign=top>\n<table border=1 cellpadding=3>\n"; // controls in left column
  [39]  $radios = array(); foreach (array_keys($shapes) as $key) $radios[].= radio('shape',$key,$shape,$key);
  [40]  print tr(tdc(br(commandbutton('Generate A New Set Of Values')) .
  [41]  br('α=' . textbox('alpha',$alpha,4) . '   β=' . textbox('beta',$beta,4)) .
  [42]  table("border=0 cellpadding=0",implode("<br>\n",$radios)) .
  [43]  'count=' . textbox('count',$count,3) . '   decimals=' . textbox('places',$places,2)));
  [44]  print tr(tdc(br(bold('Graph Settings')) .
  [45]  br('width=' . textbox('graph_width',$graph_width,3) . '   height=' . textbox('graph_height',$graph_height,3)) .
  [46]  br('<i>Backgrounds</i><br>graph=' . textbox('gbg',$gbg,6) . ' & page=' . textbox('pbg',$pbg,6)) .
  [47]  br('<i>Padding</i><br>left=' . textbox('left_padding',$left_padding,2) . ' right=' . textbox('right_padding',$right_padding,2) .
  [48]  ' top=' . textbox('top_padding',$top_padding,2) . ' bottom=' . textbox('bottom_padding',$bottom_padding,2)) .
  [49]  commandbutton('Same Data With New Settings')));
  [50]  //
  [51]  print "</table></td><td align=center valign=top>\n"; // graph goes in right column
  [52]  if ($count > 1) print_boxplot($values,$graph_width,$graph_height);
  [53]  print "</td></tr></table>\n";
  [54]  print hidden('data',cjoin($values));
  [55]  page_end();
  [56] 
  [62]  ?>
FILE: category_summary.php - 50 lines, 0 functions [
Top/End]
  [1]  <?php
  [2]  require_once '_statistics.php';
  [3]  $note = tr(tdc(small('<br>(Here the categories are in alphabetical order.<br>Other orders are acceptable, and one may even be<br>preferable if the categories have a natural order.)'),'top colspan=2'));
  [4]  $modes = array('count'=>'Counts','percentage'=>'Percentages','fraction'=>'Proportions (fractions)','decimal'=>'Proportions (decimals)');
  [5]  $mode = rq('mode',array_element(array_keys($modes),0));
  [6]  $file = rq('file','one_way_category_data.txt');
  [7]  $variable_name = rq('name','variable name');
  [8]  $data = rq('data');
  [9]  if (!$data) $data = file_read_contents($file);
  [10]  $categories = array();
  [11]  $values = nsplit($data);
  [12]  $data = '';
  [13]  $data_rows = 0;
  [14]  foreach ($values as $line) {
  [15]  if ($line) {
  [16]  if (substr($line,0,1) === '#') $variable_name = substr($line,1);
  [17]  else {
  [18]  if (isset($categories["~$line"])) $categories["~$line"]++; else $categories["~$line"] = 1;
  [19]  $data .= "$line\n";
  [20]  $data_rows++;
  [21]  }
  [22]  }
  [23]  }
  [24]  ksort($categories);
  [25]  page_start('Summary Statistics For Categorical Data');
  [26]  $data_column = tdc(br(italic('Variable Name')) . br(textbox('name',$variable_name,15)) . br('<i>DATA</i>') . textarea('data',$data,min(20,max(10,$data_rows)),10,FALSE),'top');
  [27]  $mode_table = tr(br() . br() . italic("Type of summary:"));
  [28]  foreach ($modes as $name=>$label) $mode_table .= tr(radio('mode',$name,$mode,str_replace(' ','<br>' . spaces(5),$label)));
  [29]  $mode_table = table('',$mode_table . tr(commandbutton('Display Summary')));
  [30]  if ($categories && $mode) {
  [31]  $sum = array_sum($categories);
  [32]  $summary_table = "<table>\n" . tr(td("<br>Summary of <b>$variable_name</b> as <i>{$modes[$mode]}</i>",2)) . "<tr><td width=40></td><td><table cellpadding=5 border=1>\n";
  [33]  foreach ($categories as $category=>$count) {
  [34]  $value = nf($count);
  [35]  if ($mode === 'fraction') $value .= '/' . nf($sum);
  [36]  if ($mode === 'decimal') $value = places($count/$sum,3);
  [37]  if ($mode === 'percentage') $value = percent($count,$sum,1);
  [38]  $summary_table .= tr(tdr("  $value") . td(' ' . substr($category,1)));
  [39]  }
  [40]  $summary_table .= "</table></td></tr></table>\n";
  [41]  } else $summary_table = '';
  [42]  print table('',$data_column . td('','width=15') . td(table('',td($mode_table,'top') . td($summary_table,'top'),$note)));
  [43]  page_end();
  [44] 
  [50]  ?>
FILE: central_limit.php - 132 lines, 1 function [
Top/End]
  [1]  <?php
  [2]  require_once '_statistics.php';
  [3]  $pdfs = basic_pdfs();
  [4]  $gh = max(rqn('gh',300),100); $gw = max(rqn('gw',500),100); // graph height & width
  [5]  $sample_radio = rq('sample_radio');
  [6]  $sample_sizes = rq('sample_sizes');
  [7]  if (!$sample_sizes && !$sample_radio) $sample_radio = '1:15';
  [8]  if ($sample_sizes && $sample_radio && rq('old_sample_sizes')===$sample_sizes) $sample_sizes = '';
  [9]  $ns = array();
  [10]  if ($sample_sizes) $ns = integers(csplit($sample_sizes),1,1000);
  [11]  if ($ns) $sample_radio = ''; else $sample_sizes = '';
  [12]  if (!$ns) $ns = integers(csplit($sample_radio),1,250); // sample sizes to display distributions of (1 added if missing)
  [13]  if (!in_array(1,$ns)) $ns = array_merge(array(1),$ns);
  [14]  $shapes = rq1('shapes');
  [15]  $subtract = rq1('subtract');
  [16]  $legends = rq1('legend');
  [17]  $static = rq1('static');
  [18]  $duration = min(1,10/count($ns));
  [19]  $onset = $fade = $duration/2;
  [20]  $last_n = max($ns);
  [21]  $rainbow = csplit(rq('colors',cjoin(rainbow())));
  [22]  if (!$static) $rainbow = array($rainbow[0]);
  [23]  $pdf = rq('pdf','Uniform');
  [24]  $f = get_sample_distributions($pdf,$ns,500);
  [25]  if (!$f) {page_start(); page_end(); exit;}
  [26]  $fw = count($f[1]);
  [27]  $color_index = $time = 0;
  [28]  foreach ($ns as $n) {
  [29]  $colors[$n] = $rainbow[($color_index++)%count($rainbow)];
  [30]  $maximums[$n] = max($f[$n]);
  [31]  $scaled_maximums[$n] = $maximums[$n] / sqrt($n);
  [32]  $means[$n] = $mean = pdf_mean($f[$n]);
  [33]  $stddevs[$n] = $stddev = pdf_std($f[$n]);
  [34]  $times[$n] = round($time,2);
  [35]  $time += $duration;
  [36]  }
  [37]  // variables used for several sets of graphs
  [38]  $yoffset = $gh-2; // y of zero line
  [39]  $yscale = ($yoffset-$ch-$text_offset) / max($maximums);
  [40]  $opacity = $static ? 1 : 0;
  [41]  // build legend graphic
  [42]  $legend = '';
  [43]  if (!$static) {
  [44]  foreach ($ns as $i=>$n) $legend .= animate(svg_hide(svg_text("N=$n",$means[$n],$yoffset-$text_offset)),
  [45]  array('opacity',1,$times[$n],0.01),($n==$last_n ? '' :array('opacity',0,$times[$n]+$duration,0.01,1)));
  [46]  } elseif ($legends) $legend = rainbow_legend();
  [47]  page_start();
  [48]  // USER CONTROLS
  [49]  print br(radioset('pdf',array_keys($pdfs),$pdf,''));
  [50]  $radios = 'Sample sizes: ';
  [51]  foreach (array(5,10,15,20,25,30,35,40,50,75,100) as $n) $radios .= radio('sample_radio',"1:$n",$sample_radio,$n);
  [52]  print br($radios . spaces(3) . 'or list: ' . textbox('sample_sizes',$sample_sizes,15) . small(' (e.g., 2,5,10 or 1:50)'));
  [53]  print br(commandbutton('Display') . spaces(5) . 'Height:' . textbox('gh',$gh,3) .
  [54]  '   Width:' . textbox('gw',$gw,3) . spaces(10) . checkbox('shapes',$shapes,1,'Compare shapes') .
  [55]  spaces(5) . checkbox('static',$static,1,'Static image'));
  [56]  print "<hr width='80%'>";
  [57]  // COMPARE DISTRIBUTIONS (same scales, showing smaller variance for higher $n)
  [58]  print "<table><tr><td align=center valign=top>\n"; // put this graph in left cell if both cells used
  [59]  print br("<b>$pdf</b> distribution: probability distributions<br>of the sample means for increasing sample sizes");
  [60]  print svg_start('graph',$gw,$gh,'white');
  [61]  $nns = $static ? array_reverse($ns) : $ns;
  [62]  foreach ($nns as $n) {
  [63]  $points[$n] = "0,$yoffset " . svg_points($f[$n],-$yscale,$yoffset) . ' ' . ($gw-1) . ",$yoffset";
  [64]  $svg = svg_polyline($points[$n],array('fill'=>$colors[$n],'stroke'=>'black','stroke-opacity'=>$opacity,'fill-opacity'=>$opacity));
  [65]  if (!$static) $svg = animate($svg,
  [66]  array('stroke-opacity',1,$times[$n],$onset,0),
  [67]  array('fill-opacity',1,$times[$n],$onset,0),
  [68]  ($n==$last_n ? '' : array('stroke-opacity',0,$times[$n]+$duration,$fade,1)),
  [69]  ($n==$last_n ? '' : array('fill-opacity',0,$times[$n]+$duration,$fade,1)));
  [70]  print $svg;
  [71]  }
  [72]  foreach ($ns as $i=>$n) {
  [73]  $svg = svg_polyline($points[$n],array('fill'=>'none','stroke'=>'black','stroke-opacity'=>$opacity,'stroke-dasharray'=>'1,1'));
  [74]  if (!$static) $svg = animate($svg,array('stroke-opacity',round(5/($i+20),2),$times[$n],$onset,0));
  [75]  print $svg;
  [76]  }
  [77]  print svg_line(0,$yoffset,$gw,0,1,'green') . $legend . svg_end();
  [78]  // COMPARE SHAPES (scales adjusted for $n)
  [79]  if ($shapes) {
  [80]  print "</td><td align=center valign=top>\n"; // put this graph in right cell if both cells used
  [81]  $sigma = $stddevs[$last_n] * sqrt($last_n); // scaled stddev in $f units
  [82]  $mean = $means[$last_n];
  [83]  for ($i=0; $i<$gw; $i++) $reference_normal[$i] = gaussian($i,$mean,$sigma); // make reference normal
  [84]  if ($subtract) {
  [85]  foreach ($ns as $n) {for ($i=0; $i<$gw; $i++) $d[$n][$i] = $f[$n][$i]/sqrt($n) - $reference_normal[$i];}
  [86]  $text = "Distribution differences from asymptotic values";
  [87]  trace('min,max difference',min($d[$n]),max($d[$n]));
  [88]  } else $text = 'Distribution shapes, rescaled to correct for sample size';
  [89]  $yscale_1 = ($yoffset-$ch-$text_offset) / max($scaled_maximums); // set vertical scale for shape graph
  [90]  print br("$text<br>(the dotted line is the limiting normal distribution)");
  [91]  print svg_start();
  [92]  foreach ($ns as $n) {
  [93]  $sqrtn = sqrt($n);
  [94]  $yscale_n = $yscale_1 / $sqrtn;
  [95]  if ($subtract) $svg = svg_filled_graph($colors[$n],$d[$n],-$yscale_n,$yoffset/2,0,0,$sqrtn,$gw/2-$fw/2,$means[$n]);
  [96]  else $svg = svg_filled_graph($colors[$n],$f[$n],-$yscale_n,$yoffset,0,0,$sqrtn,0,$means[$n]);
  [97]  if (!$static) $svg = animate(svg_hide($svg),array('fill-opacity',1,$times[$n],$onset,0),
  [98]  ($n==$last_n ? '' : array('fill-opacity',0,$times[$n]+$duration,$fade,1)));
  [99]  print $svg;
 [100]  }
 [101]  print svg_polyline(svg_points($reference_normal,-$yscale_1,$yoffset),array('fill'=>'none','stroke'=>'black','stroke-dasharray'=>'1,1'));
 [102]  print svg_line(0,$yoffset,$gw,0,1,'green') . $legend . svg_end();
 [103]  }
 [104]  print "</td></tr></table>\n";
 [105]  print hidden('old_sample_sizes',$sample_sizes);
 [106]  page_end();
 [107]  [Top/End]   central_limit.php
 [108]  function rainbow_legend() {
 [109]  global $rainbow,$ns,$ch,$cw,$gh,$gw,$colors,$text_offset;
 [110]  $rc = count($rainbow);
 [111]  $cc = min($rc,count($ns));
 [112]  $columns = ceil(($ch*$cc+3)/$gh);
 [113]  $per_column = ceil($cc/$columns);
 [114]  $legend_width = $cw * 5;
 [115]  $x = $gw - ($legend_width+$cw)*($columns+1);
 [116]  $row = 0;
 [117]  foreach ($ns as $i=>$n) {
 [118]  if ($i < $cc) {
 [119]  if ($row++%$per_column == 0) {$y = 5; $x += $legend_width + $cw;}
 [120]  $legend .= svg_rect($x,$y+$text_offset,$legend_width,$ch,$colors[$n]) .
 [121]  svg_text("N=$n",$x+$legend_width/2,$y+$ch);
 [122]  $y += $ch;
 [123]  }
 [124]  }
 [125]  if ($rc < count($ns)) {
 [126]  $x = $gw - ($legend_width+$cw)*$columns/2;
 [127]  $y = 5 + $per_column * $ch + $ch;
 [128]  $legend .= svg_text('(colors repeat)',$x,$y,array('font-size'=>'9pt'));
 [129]  }
 [130]  return $legend;
 [131]  }
 [132]  ?>

FILE: change_separators.php - 79 lines, 0 functions [
Top/End]
  [1]  <?php
  [2]  require_once '_statistics.php';
  [3]  $inputs = array('tabs only','spaces or tabs','commas or tabs','other');
  [4]  $outputs = array('tab','space','comma','other');
  [5]  $comment = rq('comment','');
  [6]  $blank = $command ? rq1('blank') : TRUE;
  [7]  $alpha = rq1('alpha');
  [8]  $noquotes = $command ? rq1('noquotes') : TRUE;
  [9]  $nocommas = $command ? rq1('nocommas') : TRUE;
  [10]  $nospaces = rq1('nospaces');
  [11]  $numberless = rq1('numberless');
  [12]  $nonnumeric = rq1('nonnumeric');
  [13]  $firstline = rq1('firstline');
  [14]  $extract = rq('extract');
  [15]  $extracts = extract_numbers(str_replace(',',' ',$extract)); // support commas as separators
  [16]  $extract = cjoin($extracts);
  [17]  $input = rq('input','spaces or tabs');
  [18]  $input_other = same($input,'other') ? rq('input_other') : '';
  [19]  $output = rq('output','tab');
  [20]  $output_other = contains($output,'other') ? rq('output_other') : '';
  [21]  if (contains($output,'space')) $output_separator = ' ';
  [22]  elseif (contains($output,'comma')) $output_separator = ',';
  [23]  elseif (contains($output,'tab')) $output_separator = "\t";
  [24]  else $output_separator = $output_other ? $output_other : ' ';
  [25]  $data = $text = get_data();
  [26]  $transformed = '';
  [27]  if ($command && $data) { // don't process data until asked, so options can be specified
  [28]  // tabs always act as separators; spaces next to separators ignored unless space is an input separator; adjacent spaces combined
  [29]  while (strpos($text,' ') !== FALSE) $text = str_replace(' ',' ',$text); // always convert multiple adjacent spaces to single space
  [30]  if (contains($input,'commas')) $text = str_replace(',',"\t",$text);
  [31]  if (contains($input,'other') && $input_other) $text = str_replace($input_other,"\t",$text);
  [32]  foreach (array("\t "," \t") as $t) {while (contains($text,$t)) $text = str_replace($t,"\t",$text);}
  [33]  if (contains($input,'spaces')) $text = str_replace(' ',"\t",$text);
  [34]  foreach (nsplit($text) as $line) {
  [35]  if ($transformed || !$firstline) {
  [36]  if ($comment!=='') $line = before($line,$comment);
  [37]  if ($noquotes) $line = drop_chars($line,"'`\"");
  [38]  if ($nocommas) $line = str_replace(',','',$line);
  [39]  $line = rtrim($line);
  [40]  if ($nonnumeric) {
  [41]  $items = array();
  [42]  foreach (tsplit($line) as $item) $items[] = is_numeric($item) ? $item : '';
  [43]  $line = tjoin($items);
  [44]  }
  [45]  $line = extract_columns($line,$extracts);
  [46]  if ($blank && $line==='') continue;
  [47]  if ($alpha && strtolower($line)!==strtoupper($line)) continue;
  [48]  if ($numberless) {if (!extract_number($line)) continue;}
  [49]  } else $line = extract_columns($line,$extracts);
  [50]  $transformed .= implode($output_separator,tsplit($line)) . "\n";
  [51]  }
  [52]  }
  [53]  if ($transformed) $_SESSION['last_data'] = $transformed;
  [54]  if (contains($command,'Send') && $from) redirect($from);
  [55]  //
  [56]  page_start('Change Lines With Columns',data_requested_link($from));
  [57]  print table(-5,tr(tdc(br(italic('Input Lines')) . textarea('data',$data,10,40,FALSE)) .
  [58]  tdc("<h1>→</h1>\n") . tdc(br(italic('Output Lines')) . textarea('transformed',$transformed,10,40,FALSE))));
  [59]  if ($from) print pc(br(commandbutton('Transform & Display') . ' ' . commandbutton('Transform & Send')));
  [60]  else print pc(br(commandbutton('Transform Input')));
  [61]  print pc(br(bold("Input separators: ") . radioset('input',$inputs,$input) . textbox('input_other',$input_other,1)) .
  [62]  bold("Output separator: ") . radioset('output',$outputs,$output) . textbox('output_other',$output_other,1));
  [63]  print "<table border=1 cellpadding=5>\n";
  [64]  print tr(tdc(bold('Extract/reorder specific columns: ') . textbox('extract',$extract,7) . small(' [e.g., "3,2"– by default, all columns are output]')));
  [65]  print tr(tdc(bold('Discard: ') . checkbox('blank',$blank,1,'blank lines') . checkbox('alpha',$alpha,1,'lines with letters') .
  [66]  checkbox('numberless',$numberless,1,'lines with no numbers') . checkbox('nonnumeric',$nonnumeric,1,'non-numeric items') . br() .
  [67]  checkbox('noquotes',$noquotes,1,'quotation marks') . checkbox('nocommas',$nocommas,1,'commas') . checkbox('nospaces',$nospaces,1,'spaces') .
  [68]  spaces(10) . "Discard comment text starting with " . textbox('comment',$comment,1)));
  [69]  print tr(tdc(checkbox('firstline',$firstline,1,'Retain column headings even if they would be discarded in data lines')));
  [70]  print "</table>\n";
  [71]  if ($data) print text_utility_page_links();
  [72]  page_end();
  [73] 
  [79]  ?>
FILE: classification_mistakes.php - 176 lines, 6 functions [
Top/End]
  [1]  <?php
  [2]  require_once '_statistics.php';
  [3]  $graph_width = 500; $graph_height = 150; $padding = 10; $thickness = 2; $band_height = 10;
  [4]  $sigmas = 3;
  [5]  $a_edge_color = 'blue'; $b_edge_color = 'red'; $c_edge_color = 'gray';
  [6]  $a_fill_color = '#55F'; $b_fill_color = '#F55'; $c_fill_color = '#F5F'; $a_fill_color = $b_fill_color = $c_fill_color = 'none';
  [7]  $sigmaa = rqf('sigmaa',1); if ($sigmaa <= 0) {error('σ values must be positive – has been reset to 1'); $sigmaa = 1;}
  [8]  $sigmab = rqf('sigmab',1); if ($sigmab <= 0) {error('σ values must be positive – has been reset to 1'); $sigmab = 1;}
  [9]  $heighta = rqf('heighta',1); if ($heighta <= 0) {error('height values must be positive – has been reset to 1'); $heighta = 1;}
  [10]  $heightb = rqf('heightb',1); if ($heightb <= 0) {error('height values must be positive – has been reset to 1'); $heightb = 1;}
  [11]  $meana = rqf('meana',0);
  [12]  $meanb = rqf('meanb',1);
  [13]  //
  [14]  if (rq('Ataller')) $heighta *= 2;
  [15]  if (rq('Ashorter')) $heighta /= 2;
  [16]  if (rq('Btaller')) $heightb *= 2;
  [17]  if (rq('Bshorter')) $heightb /= 2;
  [18]  if (rq('Awiden')) $sigmaa *= 2;
  [19]  if (rq('Anarrow')) $sigmaa /= 2;
  [20]  if (rq('Bwiden')) $sigmab *= 2;
  [21]  if (rq('Bnarrow')) $sigmab /= 2;
  [22]  $ratio = $heighta*$sigmaa/($heightb*$sigmab);
  [23]  $range = abs($meana-$meanb) + $sigmas*($sigmaa+$sigmab);
  [24]  //$step = close_simple_value($range/10,0.1,1);
  [25]  $step = granularity125($range/10);
  [26]  if (rq('Aleft')) $meana -= $step;
  [27]  if (rq('Bleft')) $meanb -= $step;
  [28]  if (rq('Aright')) $meana += $step;
  [29]  if (rq('Bright')) $meanb += $step;
  [30]  //
  [31]  page_start('Minimizing Classification Mistakes',small('<br>When "Is it A or B?" decisions are made based on overlapping distributions of values, some mistakes are inevitable.<br>However, the number of mistakes can be minimized by this kind of mathematical analysis.'));
  [32]  print "<table cellpadding=20><tr><td align=center valign=top>\n"; // controls in left column
  [33]  print "<table border=1 cellpadding=3><tr>\n";
  [34]  print tdr(small('Distribution <b>A</b>:<br>Center=' . textbox('meana',$meana,5) . '<br>Width=' . textbox('sigmaa',$sigmaa,5) . '<br>Height=' . textbox('heighta',$heighta,5)));
  [35]  print tdr(small('Distribution <b>B</b>:<br>Center=' . textbox('meanb',$meanb,5) . '<br>Width=' . textbox('sigmab',$sigmab,5) . '<br>Height=' . textbox('heightb',$heightb,5)));
  [36]  print "</tr></table>\n";
  [37]  print br(small(commandbutton('Redisplay')));
  [38]  print "<table border=0>" . tr(tdc(italic('<br>Adjust Distributions'),4)) . "<tr>";
  [39]  print tdc('Left<br>' . commandbutton('A','Aleft'). ' ' . commandbutton('B','Bleft'));
  [40]  print td('');
  [41]  print tdc('Right<br>' . commandbutton('A','Aright'). ' ' . commandbutton('B','Bright'));
  [42]  print "</tr><tr>\n";
  [43]  print tdc('Widen<br>' . commandbutton('A','Awiden'). ' ' . commandbutton('B','Bwiden'));
  [44]  print td('');
  [45]  print tdc('Narrow<br>' . commandbutton('A','Anarrow'). ' ' . commandbutton('B','Bnarrow'));
  [46]  print "</tr><tr>\n";
  [47]  print tdc('Taller<br>' . commandbutton('A','Ataller'). ' ' . commandbutton('B','Btaller'));
  [48]  print td('');
  [49]  print tdc('Shorter<br>' . commandbutton('A','Ashorter'). ' ' . commandbutton('B','Bshorter'));
  [50]  print "</tr></table>\n";
  [51]  print pc(small('A/B frequency ratio = ' . close_simple_value($ratio,0.1,1)));
  [52]  print "</td><td align-center valign=top>\n"; // graph goes in right column
  [53]  //
  [54]  $xc = gcrossings($meana,$meanb,$sigmaa,$sigmab,$ratio);
  [55]  $low = min($meana-$sigmas*$sigmaa,$meanb-$sigmas*$sigmab); // lowest displayed x value
  [56]  $high = max($meana+$sigmas*$sigmaa,$meanb+$sigmas*$sigmab); // highest displayed x value
  [57]  if ($xc) { // expand range if needed to fully include crossing points
  [58]  $low = min($low,$xc[0]-(($high-$low)/20));
  [59]  $high = max($high,$xc[count($xc)-1]+(($high-$low)/20));
  [60]  }
  [61]  $dx = ($high-$low)/$graph_width; // xstep per pixel
  [62]  $xscale = $dx ? 1/$dx : 0; // pixels per value
  [63]  $xgranularity = granularity125($dx/5,FALSE);
  [64]  $adist = $bdist = $abdist = $mndist = $mxdist = $wrongdist = $sumdist = $atop = $bands = $mistakes = array();
  [65]  if ($sigmab<$sigmaa || ($sigmaa==$sigmab && $meana<$meanb)) {$labels = array(bold('A'),bold('B')); $colors = array($a_edge_color,$b_edge_color);}
  [66]  else {$labels = array(bold('B'),bold('A')); $colors = array($b_edge_color,$a_edge_color);} // set label and color arrays based on which dominates at -infinity
  [67]  if (!$xc) {
  [68]  $best = "Always guess $labels[0].";
  [69]  $bands = array(array($low,$high,$colors[0]));
  [70]  } elseif (count($xc) == 1) {
  [71]  $best = "Guess $labels[0] for values lower than " . bold(multiple($xc[0],$xgranularity)) . ", guess $labels[1] for higher values.";
  [72]  $bands = array(array($low,$xc[0],$colors[0]),array($xc[0],$high,$colors[1]));
  [73]  } else {
  [74]  $best = "Guess $labels[1] for values between " . bold(multiple($xc[0],$xgranularity)) . ' and ' . bold(multiple($xc[1],$xgranularity)) . ". Otherwise guess $labels[0].";
  [75]  $bands = array(array($low,$xc[0],$colors[0]),array($xc[0],$xc[1],$colors[1]),array($xc[1],$high,$colors[0]));
  [76]  }
  [77]  $h = $ratio/$sigmaa*$sigmab; // compute height of A distribution relative to B from relative frequencies and widths
  [78]  for ($i=0,$x=$low+$dx/2; $i<$graph_width; $i++,$x+=$dx) { // make distribution arrays
  [79]  $ea = ($x-$meana)/$sigmaa;
  [80]  $eb = ($x-$meanb)/$sigmab;
  [81]  $adist[] = $a = $h*exp(-0.5*$ea*$ea);
  [82]  $bdist[] = $b = exp(-0.5*$eb*$eb);
  [83]  $mndist[] = $mn = min($a,$b);
  [84]  $mxdist[] = $mx = max($a,$b);
  [85]  $sumdist[] = $sum = $a + $b;
  [86]  $wrongdist[] = $sum ? $mn/$sum : 0;
  [87]  }
  [88]  $highest = max($sumdist);
  [89]  $yscale = $highest>0 ? $graph_height/$highest : 1; // pixels per y-value
  [90]  $yoffset = $graph_height + $padding;
  [91]  $vertical_scale = svg_vertical_scale($padding,$yoffset,$graph_height,$yoffset,$yscale,0,$highest);
  [92]  $xoffset = $padding + $vertical_scale_thickness;
  [93]  $horizontal_scale = svg_horizontal_scale($yoffset+$band_height+2,$xoffset,$graph_width,$xoffset,$xscale,$low,$high,7);
  [94]  $view_width = $padding + $vertical_scale_thickness + $graph_width + $padding;
  [95]  $view_height = $padding + $graph_height + $band_height + $horizontal_scale_thickness + $padding;
  [96]  $apoints = $bpoints = $cpoints = "$xoffset,$yoffset ";
  [97]  for($i=0,$x=$xoffset; $i<$graph_width; $i++,$x++) {
  [98]  $ay = $yoffset - $adist[$i] * $yscale;
  [99]  $apoints .= "$x,$ay ";
 [100]  $by = $yoffset - $bdist[$i] * $yscale;
 [101]  $bpoints .= "$x,$by ";
 [102]  $cy = $yoffset - min($adist[$i],$bdist[$i]) * $yscale;
 [103]  $cpoints .= "$x,$cy ";
 [104]  }
 [105]  $apoints .= ($xoffset+$graph_width-1) . ",$yoffset";
 [106]  $bpoints .= ($xoffset+$graph_width-1) . ",$yoffset";
 [107]  $cpoints .= ($xoffset+$graph_width-1) . ",$yoffset";
 [108]  print svg_start('',$view_width,$view_height);
 [109]  print svg_polyline($apoints,array('fill'=>$a_fill_color,'stroke'=>$a_edge_color,'stroke-width'=>$thickness));
 [110]  print svg_polyline($bpoints,array('fill'=>$b_fill_color,'stroke'=>$b_edge_color,'stroke-width'=>$thickness));
 [111]  print svg_polyline($cpoints,array('fill'=>$c_fill_color,'stroke'=>$c_edge_color,'stroke-width'=>$thickness));
 [112]  $band_y = $yoffset + $band_height/2 + 2;
 [113]  foreach ($bands as $info) print svg_line($xoffset+($info[0]-$low)*$xscale,$band_y,($info[1]-$info[0])*$xscale,0,$band_height,$info[2]);
 [114]  print svg_text('⇐',$xoffset-3,$band_y+$text_offset) . svg_text('⇒',$xoffset+$graph_width+2,$band_y+$text_offset);
 [115]  print $vertical_scale . $horizontal_scale . svg_end();
 [116]  print pc(bold(italic('Best strategy to use for these two distributions:<br>')) . $best);
 [117]  $mistakes = gcrossing_error($meana,$meanb,$sigmaa,$sigmab,$ratio);
 [118]  $abmistakes = np(100*$mistakes[1],1,2);
 [119]  $bamistakes = np(100*$mistakes[2],1,2);
 [120]  print pc(br(bold(($abmistakes+$bamistakes) . '%') . ' probability of mistakes even when using the best strategy') .
 [121]  small("Misguessing A when really B: $abmistakes% Misguessing B when really A: $bamistakes%"));
 [122]  print "</td></tr></table>\n";
 [123]  page_end();
 [124]  [Top/End]   classification_mistakes.php
 [125]  function gcrossings($ma,$mb,$sa=1,$sb=1,$fa=1,$fb=1,$sort=TRUE) {
 [126]  $va = $sa*$sa; $vb = $sb*$sb;
 [127]  if ($va==0 || $vb==0 || $fa<=0 || $fb<=0) return array();
 [128]  $aa = 1/$vb - 1/$va; // "2a" in quadratic-formula terms (i.e., twice the quadratic-term coefficient)
 [129]  $bb = $ma/$va - $mb/$vb; // "b", the linear-term coefficient
 [130]  $cc = log($fa/$fb) - log($sa/$sb) - 0.5*($ma*$ma/$va-$mb*$mb/$vb); // "c", the constant term
 [131]  if ($aa == 0) { // when variances are equal, reduces to linear equation
 [132]  if ($bb == 0) return array(); // if both means and variances are equal, no crossings (includes congruent-distribution case)
 [133]  return array(-$cc/$bb); // all other equal-variance cases
 [134]  } else { // unequal variances lead to quadratic equation
 [135]  $dd = $bb*$bb - 2*$aa*$cc; // quadratic determinate
 [136]  if ($dd <= 0) return array(); // no crossings because one distribution completely contains the other ($dd=0 would imply a tangency point)
 [137]  $r1 = (-$bb-sqrt($dd))/$aa; // compute the two
 [138]  $r2 = (-$bb+sqrt($dd))/$aa; // quadratic solutions
 [139]  if ($sort) {
 [140]  if ($r1 > $r2) list($r1,$r2) = array($r2,$r1); // if $sort is TRUE, put lower crossing value first in output array
 [141]  } else { // if $sort is FALSE, return crossing x-values in order of closeness to average mean
 [142]  $mm = ($ma*$fa+$mb*$fb) / ($fa+$fb); // average mean
 [143]  if (abs($r1-$mm) > abs($r2-$mm)) list($r1,$r2) = array($r2,$r1); // for some uses, only the near-mean crossing is relevant
 [144]  }
 [145]  return array($r1,$r2);
 [146]  }
 [147]  } [
Top/End]   classification_mistakes.php
 [148]  function gaussian_left_tail($x,$m=0,$s=1,$f=1) {return ($f*ncdf(($x-$m)/$s));} // generalized cumulative gaussian from -infinity to $x [
Top/End]   classification_mistakes.php
 [149]  function gaussian_right_tail($x,$m=0,$s=1,$f=1) {return ($f*(1-ncdf(($x-$m)/$s)));} // generalized cumulative gaussian from $x to +infinity [
Top/End]   classification_mistakes.php
 [150]  function gaussian_interval($x1,$x2,$m=0,$s=1,$f=1) {return (gaussian_left_tail($x2,$m,$s,$f) - gaussian_left_tail($x1,$m,$s,$f));} // gaussian area over an interval [
Top/End]   classification_mistakes.php
 [151]  function gcrossing_p($x,$ma,$mb,$sa=1,$sb=1,$fa=1,$fb=1) { // ratio, at x, of A value to total of A and B values, for gaussians A and B
 [152]  $a = gaussian($x,$ma,$sa,$fa);
 [153]  $b = gaussian($x,$mb,$sb,$fb);
 [154]  return ($a+$b!=0 ? $a/($a+$b) : 0);
 [155]  } [
Top/End]   classification_mistakes.php
 [156]  function gcrossing_error($ma,$mb,$sa=1,$sb=1,$fa=1,$fb=1) { // probability of the wrong choice when using optimal strategy
 [157]  if ($fa<=0 || $fb<=0) return 0; // guard against degenerate cases
 [158]  $xc = gcrossings($ma,$mb,$sa,$sb,$fa,$fb); // the array of crossings (if any) will be in increasing order
 [159]  $errora = $errorb = 0; // these will be set to the numerators of the error ratios; denominator will always be $fa+$fb, which is the total area
 [160]  if ($sb<$sa || ($sa==$sb && $ma<$mb)) { // if A dominates at -infinity
 [161]  if (count($xc) == 0) $errora = $fb; // A always chosen for no-crossing case
 [162]  elseif (count($xc) == 1) {$errora = gaussian_left_tail($xc[0],$mb,$sb,$fb); $errorb = gaussian_right_tail($xc[0],$ma,$sa,$fa);} // one-crossing case
 [163]  else {$errora = gaussian_left_tail($xc[0],$mb,$sb,$fb) + gaussian_right_tail($xc[1],$mb,$sb,$fb); $errorb = gaussian_interval($xc[0],$xc[1],$ma,$sa,$fa);}
 [164]  } else { // if B dominates at -infinity
 [165]  if (count($xc) == 0) $errorb = $fa; // no crossings
 [166]  elseif (count($xc) == 1) {$errorb = gaussian_left_tail($xc[0],$ma,$sa,$fa); $errora = gaussian_right_tail($xc[0],$mb,$sb,$fb);} // one crossing
 [167]  else {$errorb = gaussian_left_tail($xc[0],$ma,$sa,$fa) + gaussian_right_tail($xc[1],$ma,$sa,$fa); $errora = gaussian_interval($xc[0],$xc[1],$mb,$sb,$fb);}
 [168]  }
 [169]  return array(($errora+$errorb)/($fa+$fb),$errora/($fa+$fb),$errorb/($fa+$fb));
 [170]  }
 [176]  ?>

FILE: classification_mistakes_gaussians.php - 162 lines, 4 functions [
Top/End]
  [1]  <?php
  [2]  require_once '_statistics.php';
  [3]  $graph_width = 500; $graph_height = 200; $padding = 15; $thickness = 2; $band_height = 10;
  [4]  $sigmas = 3;
  [5]  $a_edge_color = 'blue'; $b_edge_color = 'red'; $c_edge_color = 'gray';
  [6]  $a_fill_color = '#55F'; $b_fill_color = '#F55'; $c_fill_color = '#F5F'; $a_fill_color = $b_fill_color = $c_fill_color = 'none';
  [7]  $sigmaa = rqf('sigmaa',1); if ($sigmaa <= 0) {error('σ values must be positive – has been reset to 1'); $sigmaa = 1;}
  [8]  $sigmab = rqf('sigmab',1); if ($sigmab <= 0) {error('σ values must be positive – has been reset to 1'); $sigmab = 1;}
  [9]  $meana = rqf('meana',0);
  [10]  $meanb = rqf('meanb',2);
  [11]  //
  [12]  $fraction = rq('fraction','2/1');
  [13]  $ratio = 0;
  [14]  if (is_numeric($fraction) && $fraction>0) $ratio = $fraction;
  [15]  else {
  [16]  $numerator = digits_only(before($fraction,'/'));
  [17]  $denominator = digits_only(after($fraction,'/'));
  [18]  if (is_numeric($numerator) && $numerator>0 && is_numeric($denominator) && $denominator>0) $ratio = $numerator/$denominator;
  [19]  else {$ratio = 2; $fraction = '2/1'; error('Invalid distribution-frequency ratio – changed to 2/1');}
  [20]  }
  [21]  if (rq('Amoreoften') || rq('Blessoften')) $ratio = $fraction = close_simple_value($ratio*1.4,0.1,1);
  [22]  if (rq('Bmoreoften') || rq('Alessoften')) $ratio = $fraction = close_simple_value($ratio/1.4,0.1,1);
  [23]  if (rq('Awiden')) $sigmaa = close_simple_value($sigmaa*1.4,0.1,1);
  [24]  if (rq('Bwiden')) $sigmab = close_simple_value($sigmab*1.4,0.1,1);
  [25]  if (rq('Anarrow')) $sigmaa = close_simple_value($sigmaa/1.4,0.1,1);
  [26]  if (rq('Bnarrow')) $sigmab = close_simple_value($sigmab/1.4,0.1,1);
  [27]  $range = abs($meana-$meanb) + $sigmas*($sigmaa+$sigmab);
  [28]  $step = close_simple_value($range/10,0.1,1);
  [29]  if (rq('Aleft')) $meana -= $step;
  [30]  if (rq('Bleft')) $meanb -= $step;
  [31]  if (rq('Aright')) $meana += $step;
  [32]  if (rq('Bright')) $meanb += $step;
  [33]  //
  [34]  page_start('Minimizing Classification Mistakes',small('<br>When "Is it A or B?" decisions are made from overlapping distributions, some mistakes are inevitable.<br>However, the number of mistakes can be minimized by this kind of graphical/mathematical analysis.'));
  [35]  print "<table cellpadding=20><tr><td align=center valign=top>\n"; // controls in left column
  [36]  print "<table border=0>" . tr(tdc(italic('<br>Adjust Distributions'),4)) . "<tr>";
  [37]  print tdc('Left<br>' . commandbutton('A','Aleft'). ' ' . commandbutton('B','Bleft'));
  [38]  print td('');
  [39]  print tdc('Right<br>' . commandbutton('A','Aright'). ' ' . commandbutton('B','Bright'));
  [40]  print "</tr><tr>\n";
  [41]  print tdc('Widen<br>' . commandbutton('A','Awiden'). ' ' . commandbutton('B','Bwiden'));
  [42]  print td('');
  [43]  print tdc('Narrow<br>' . commandbutton('A','Anarrow'). ' ' . commandbutton('B','Bnarrow'));
  [44]  print "</tr><tr>\n";
  [45]  print tdc('More Often<br>' . commandbutton('A','Amoreoften'). ' ' . commandbutton('B','Bmoreoften'));
  [46]  print td('');
  [47]  print tdc('Less Often<br>' . commandbutton('A','Alessoften'). ' ' . commandbutton('B','Blessoften'));
  [48]  print "</tr></table>\n";
  [49]  print p() . "<table border=0 cellpadding=1>\n";
  [50]  print tr(tdc(small('Distribution A: Mean=' . textbox('meana',$meana,5) . ' σ=' . textbox('sigmaa',$sigmaa,5))));
  [51]  print tr(tdc(small('Distribution B: Mean=' . textbox('meanb',$meanb,5) . ' σ=' . textbox('sigmab',$sigmab,5))));
  [52]  print tr(tdc(small('Ratio of distribution frequencies A/B: ' . textbox('fraction',$fraction,5))));
  [53]  print tr(tdc(small(commandbutton('Redisplay'))));
  [54]  print "</table>\n";
  [55]  print "</td><td valign=top>\n"; // graph goes in right column
  [56]  $gcrossings = gcrossings($meana,$meanb,$sigmaa,$sigmab,$ratio);
  [57]  $low = min($meana-$sigmas*$sigmaa,$meanb-$sigmas*$sigmab); // lowest displayed value
  [58]  $high = max($meana+$sigmas*$sigmaa,$meanb+$sigmas*$sigmab); // highest displayed value
  [59]  if ($gcrossings) { // expand range if needed to fully include crossing points
  [60]  $low = min($low,$gcrossings[0]-(($high-$low)/20));
  [61]  $high = max($high,$gcrossings[count($gcrossings)-1]+(($high-$low)/20));
  [62]  }
  [63]  $dx = ($high-$low)/$graph_width; // xstep per pixel
  [64]  $xscale = 1/$dx; // pixels per value
  [65]  $xgranularity = granularity125($dx/5,FALSE);
  [66]  $adist = $bdist = $abdist = $mndist = $mxdist = $atop = $bands = $crossings = array();
  [67]  $h = $ratio/$sigmaa*$sigmab; // height of A distribution relative to B
  [68]  for ($i=0,$x=$low+$dx/2; $i<$graph_width; $i++,$x+=$dx) { // make distribution arrays
  [69]  $ea = ($x-$meana)/$sigmaa;
  [70]  $adist[] = $a = $h*exp(-0.5*$ea*$ea);
  [71]  $eb = ($x-$meanb)/$sigmab;
  [72]  $bdist[] = $b = exp(-0.5*$eb*$eb);
  [73]  $mndist[] = min($a,$b);
  [74]  $mxdist[] = max($a,$b);
  [75]  }
  [76]  $aa=$adist[0]; // preset comparison values
  [77]  $bb=$bdist[0];
  [78]  for ($i=$istart=0,$x=$low+$dx/2; $i<$graph_width; $i++,$x+=$dx) {
  [79]  $a = $adist[$i];
  [80]  $b = $bdist[$i];
  [81]  $d = $a-$aa-$b+$bb;
  [82]  if ((($a>$b)!=($aa>$bb)) && $d!=0) { // change of which distribution is higher
  [83]  $cx = ($aa-$bb)/$d; // position of crossing point, as a fraction of a pixel
  [84]  $bands[] = array($istart,$i+$dx-$istart,$aa>$bb?1:0); // accumulate selection regions
  [85]  $istart = $i+$cx; // pixel-based selection-region boundary
  [86]  $crossings[] = $x + $dx*($cx-1); // accumulate crossing points
  [87]  }
  [88]  $aa = $a; $bb = $b;
  [89]  }
  [90]  $bands[] = array($istart,$graph_width-$istart,$aa>$bb?1:0); // final selection region
  [91]  $values = array();
  [92]  $yscale = $graph_height / max($h,1); // pixels per y-value
  [93]  $xoffset = $padding;
  [94]  $yoffset = $graph_height + $padding;
  [95]  $horizontal_scale = svg_horizontal_scale($yoffset+$band_height+2,$xoffset,$graph_width,$xoffset,$xscale,$low,$high,7);
  [96]  $view_width = $padding + $graph_width + $padding;
  [97]  $view_height = $padding + $graph_height + $band_height + $horizontal_scale_thickness + $padding;
  [98]  $apoints = $bpoints = $cpoints = "$xoffset,$yoffset ";
  [99]  for($i=0,$x=$xoffset; $i<$graph_width; $i++,$x++) {
 [100]  $ay = $yoffset - $adist[$i] * $yscale;
 [101]  $apoints .= "$x,$ay ";
 [102]  $by = $yoffset - $bdist[$i] * $yscale;
 [103]  $bpoints .= "$x,$by ";
 [104]  $cy = $yoffset - min($adist[$i],$bdist[$i]) * $yscale;
 [105]  $cpoints .= "$x,$cy ";
 [106]  }
 [107]  $apoints .= ($xoffset+$graph_width-1) . ",$yoffset";
 [108]  $bpoints .= ($xoffset+$graph_width-1) . ",$yoffset";
 [109]  $cpoints .= ($xoffset+$graph_width-1) . ",$yoffset";
 [110]  print svg_start('',$view_width,$view_height);
 [111]  print svg_polyline($apoints,array('fill'=>$a_fill_color,'stroke'=>$a_edge_color,'stroke-width'=>$thickness));
 [112]  print svg_polyline($bpoints,array('fill'=>$b_fill_color,'stroke'=>$b_edge_color,'stroke-width'=>$thickness));
 [113]  print svg_polyline($cpoints,array('fill'=>$c_fill_color,'stroke'=>$c_edge_color,'stroke-width'=>$thickness));
 [114]  $band_y = $yoffset + $band_height/2 + 2;
 [115]  foreach ($bands as $info) print svg_line($xoffset+$info[0],$band_y,$info[1],0,$band_height,($info[2] ? $a_edge_color : $b_edge_color));
 [116]  print $horizontal_scale . svg_end();
 [117]  if ($gcrossings) {
 [118]  $text = (count($gcrossings)==1 ? 'Value' : 'Values') . ' at which the mistake-minimizing choice changes: ' . multiple($gcrossings[0],$xgranularity);
 [119]  for ($i=1; $i<count($gcrossings); $i++) $text .= ', ' . multiple($gcrossings[$i],$xgranularity);
 [120]  print pc($text);
 [121]  }
 [122]  print "</td></tr></table>\n";
 [123]  page_end();
 [124]  [Top/End]   classification_mistakes_gaussians.php
 [125]  function gcrossings($ma,$mb,$sa=1,$sb=1,$fa=1,$fb=1,$reorder=TRUE) {
 [126]  $va = $sa*$sa; $vb = $sb*$sb;
 [127]  if ($va==0 || $vb==0 || $fa<=0 || $fb<=0) return array();
 [128]  $aa = 1/$vb - 1/$va; // "2a" in quadratic-formula terms (i.e., twice the quadratic-term coefficient)
 [129]  $bb = $ma/$va - $mb/$vb; // "b", the linear-term coefficient
 [130]  $cc = log($fa/$fb) - log($sa/$sb) - 0.5*($ma*$ma/$va-$mb*$mb/$vb); // "c", the constant term
 [131]  if ($aa == 0) { // when variances are equal, reduces to linear equation
 [132]  if ($bb == 0) return array(); // special congruent-distributions case
 [133]  return array(-$cc/$bb); // all other equal-variance cases
 [134]  } else { // unequal variances lead to quadratic equation
 [135]  $dd = $bb*$bb - 2*$aa*$cc; // quadratic determinate
 [136]  if ($dd <= 0) return array(); // no crossings ($dd=0 would imply tangency)
 [137]  $r1 = (-$bb-sqrt($dd))/$aa; // compute the two quadratic solutions
 [138]  $r2 = (-$bb+sqrt($dd))/$aa; // $r2 is greater than $r1; this order will be returned if $reorder is FALSE
 [139]  if ($reorder) { // if $reorder is TRUE, return crossing x-values in order of closeness to average mean
 [140]  $mm = ($ma*$fa+$mb*$fb) / ($fa+$fb); // average mean
 [141]  if (abs($r1-$mm) > abs($r2-$mm)) list($r1,$r2) = array($r2,$r1); // for some uses, only the near-mean crossing is relevant
 [142]  }
 [143]  return array($r1,$r2);
 [144]  }
 [145]  } [
Top/End]   classification_mistakes_gaussians.php
 [146]  function gaussian_integral($x,$dx=0,$m=0,$s=1,$f=1) {return ($f*inverse_ncdf(($x-$m)/$s));} // generalized cumulative gaussian [
Top/End]   classification_mistakes_gaussians.php
 [147]  function gcrossing_p($x,$ma,$mb,$sa=1,$sb=1,$fa=1,$fb=1) { // ratio, at x, of A value to total of A and B values, for gaussians A and B
 [148]  $a = gaussian($x,$ma,$sa,$fa);
 [149]  $b = gaussian($x,$mb,$sb,$fb);
 [150]  return ($a/($a+$b));
 [151]  } [
Top/End]   classification_mistakes_gaussians.php
 [152]  function gcrossing_error_cost($x,$ma,$mb,$sa=1,$sb=1,$fa=1,$fb=1) { // ???
 [153]  $ab_start = ($sb>$sa || ($sa==$sb && $ma<$mb)) ? 0 : 1; // 0 if A dominates at -infinity, 1 if B dominates
 [154]  $crossings = gcrossings($ma,$mb,$sa,$sb,$fa,$fb,FALSE);
 [155] 
 [156]  }
 [162]  ?>

FILE: columnize.php - 18 lines, 0 functions [
Top/End]
  [1]  <?php
  [2]  require_once '_statistics.php';
  [3]  page_start('Convert input into a column of numbers');
  [4]  $explanation = 'This page extracts any numbers in the input text area (above) and puts them into a single column in the output area (on the right).  ' .
  [5]  'Characters that are not parts of numbers are discarded.  ' . alink('Other data-maniplation pages','explain-data-input-2.html') . ' are also available.';
  [6]  $data = rq('data');
  [7]  $values = extract_numbers($data);
  [8]  $output = implode("\n",$values) . "\n";
  [9]  print table(-5,tr(tdc(br(italic('Input Text')) . br(textarea('data',$data,10,40)) . p(commandbutton('Transform Input')) . p(table('width=350',tr(td($explanation))))) .
  [10]  tdc("<h1>→</h1>\n") . tdc(br(italic($values ? plural($values,'Output Line') : 'Output Lines')) . textarea('output',$output,20,15))));
  [11]  page_end();
  [12] 
  [18]  ?>
FILE: combine_grades.php - 118 lines, 5 functions [
Top/End]
  [1]  <?php
  [2]  require_once '_all_sites.php';
  [3]  require_once '_svg.php';
  [4]  $color_array = array('red','green','blue','yellow','pink','orange','purple','tan'); [Top/End]   combine_grades.php
  [5]  function array_color($index,$array=array()) { // picks a color out of supplied or default array, cycling colors if necessary
  [6]  if (!$array) $array = $GLOBALS['color_array'];
  [7]  if (!is_array($array)) $array = csplit($array);
  [8]  return ($array&&is_numeric($index) ? $array[$index%count($array)] : $index);
  [9]  }