audit-labs/audit-tools

A collection of scripts, queries, and other goodies you can use in an audit.

clone: git clone https://gitbay.org/audit-labs/audit-tools.git

main: sampling/sample.html · raw

  1<!doctype html>
  2<html lang="en">
  3<head>
  4	<meta charset="utf-8">
  5	<meta name="viewport" content="width=device-width, initial-scale=1">
  6	<title>Sampling Tool</title>
  7	<style>
  8        form {
  9            display: table;
 10        }
 11        form div {
 12            display: table-row;
 13        }
 14        label, input {
 15            display: table-cell;
 16            margin-bottom: 10px;
 17        }
 18        label {
 19            padding-right: 10px;
 20        }
 21        table {
 22            width: 100%;
 23            border-collapse: collapse;
 24            margin-top: 10px;
 25        }
 26        table, th, td {
 27            border: 1px solid black;
 28        }
 29        th, td {
 30            padding: 5px;
 31            text-align: center;
 32        }
 33    </style>
 34</head>
 35<body>
 36<h1>Sampling Tool</h1>
 37<p>This sampling tool provides a quick and easy way to generate
 38psuedo-random samples within a defined range. Simply enter the size of your
 39population, enter your desired number of samples, and generate!</p>
 40<p>To reproduce and validate a previously-generated sample, please ensure
 41you have entered the seed value correctly when submitting the form. All
 42inputs must match the previously-generated sample's inputs to generate the
 43same output.</p>
 44<form id="sampleForm" onsubmit="return handleFormSubmit(event)">
 45	<div>
 46		<label for="populationSize">Population Size*:</label>
 47		<input type="number" id="populationSize" name="populationSize" min="1" autofocus required>
 48	</div>
 49	<div>
 50		<label for="sampleSize">Sample Size*:</label>
 51		<input type="number" id="sampleSize" name="sampleSize" min="1" required>
 52	</div>
 53	<div>
 54		<label for="replacementSize">Replacement Sample Size:</label>
 55		<input type="number" id="replacementSize" name="replacementSize" min="0">
 56	</div>
 57	<div>
 58		<label for="customSeed">Custom Seed (optional):</label>
 59		<input type="number" id="customSeed" name="customSeed" min="0">
 60	</div>
 61	<div>
 62		<input type="submit" value="Calculate">
 63	</div>
 64	<p><i>* Indicates a required field</i></p>
 65</form>
 66<hr>
 67<div id="results"></div>
 68<script>
 69function seededRandom(seed) {
 70    let s = seed % 2147483647;
 71    return function() {
 72        s = (s * 16807) % 2147483647;
 73        return (s - 1) / 2147483646;
 74    };
 75}
 76
 77function handleFormSubmit(event) {
 78    event.preventDefault(); // Prevent the default form submission behavior
 79    const customSeedInput = document.getElementById('customSeed').value;
 80    // Use the custom seed if provided; otherwise draw a strong random seed and
 81    // write it back so the (reproducible) sample can always be tied to a seed.
 82    const seed = customSeedInput
 83        ? Number.parseInt(customSeedInput)
 84        : crypto.getRandomValues(new Uint32Array(1))[0] % 1000000;
 85    if (!customSeedInput) {
 86        document.getElementById('customSeed').value = seed;
 87    }
 88    generateSamples(seed); // Call the function with the seed
 89}
 90
 91function generateSamples(seed) {
 92    const populationSize = Number.parseInt(document.getElementById('populationSize').value);
 93    const sampleSize = Number.parseInt(document.getElementById('sampleSize').value);
 94    const replacementSize = Number.parseInt(document.getElementById('replacementSize').value || 0);
 95    const resultsDiv = document.getElementById('results');
 96
 97    // Clear previous results
 98    resultsDiv.innerHTML = '';
 99
100    // Validate inputs
101    if (Number.isNaN(populationSize) || Number.isNaN(sampleSize) || populationSize <= 0 || sampleSize <= 0) {
102        alert("Please enter valid numbers for required fields.");
103        return;
104    }
105    if (sampleSize + replacementSize > populationSize) {
106        alert("Not enough unique samples available. Reduce the sample size or replacement size.");
107        return;
108    }
109
110    // Create seeded random function
111    const random = seededRandom(seed);
112
113    // Generate an array of population numbers
114    const population = Array.from({ length: populationSize }, (_, i) => i + 1);
115
116    // Shuffle the population array using the seeded random function
117    const shuffledPopulation = population
118        .map(value => ({ value, sort: random() }))
119        .sort((a, b) => a.sort - b.sort)
120        .map(({ value }) => value);
121
122    // Select original samples
123    const originalSamples = shuffledPopulation.slice(0, sampleSize);
124
125    // Select replacement samples
126    const replacementSamples = shuffledPopulation.slice(sampleSize, sampleSize + replacementSize);
127
128    // Display the seed
129    const seedInfo = document.createElement('p');
130    seedInfo.textContent = `Seed: ${seed}`;
131    resultsDiv.appendChild(seedInfo);
132
133    // Generate tables
134    const originalTable = createTable(originalSamples, "Original Samples");
135    const replacementTable = createTable(replacementSamples, "Replacement Samples");
136
137    // Append tables to the results div
138    resultsDiv.appendChild(originalTable);
139    if (replacementSamples.length > 0) {
140        resultsDiv.appendChild(replacementTable);
141    }
142}
143
144function createTable(dataArray, tableTitle) {
145    const table = document.createElement('table');
146    const caption = document.createElement('caption');
147    caption.textContent = tableTitle;
148    table.appendChild(caption);
149
150    const headerRow = document.createElement('tr');
151    const indexHeader = document.createElement('th');
152    indexHeader.textContent = 'Index';
153    const sampleHeader = document.createElement('th');
154    sampleHeader.textContent = 'Sample';
155    headerRow.appendChild(indexHeader);
156    headerRow.appendChild(sampleHeader);
157    table.appendChild(headerRow);
158
159    dataArray.forEach((sample, index) => {
160        const row = document.createElement('tr');
161        const indexCell = document.createElement('td');
162        const sampleCell = document.createElement('td');
163        indexCell.textContent = index + 1;
164        sampleCell.textContent = sample;
165        row.appendChild(indexCell);
166        row.appendChild(sampleCell);
167        table.appendChild(row);
168    });
169
170    return table;
171}
172</script>
173</body>
174</html>