audit-labs/audit-tools

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

Commit a206aa0bc4

a206aa0bc41d61676f9972e3c56df62bba9a82e9

parent: 8619d8f0c7

Unsigned

cmc <hello@cleberg.net> · 2025-01-16 20:21 UTC

add HTML version of sampling tool

Layout: unified · split

sampling/README.org added +32
@@ -0,0 +1,32 @@
1#+title: Sampling Tools
2
3* =sample.py=
4
5#+begin_src sh
6python ./sample.py
7#+end_src
8
9#+begin_src text
10Dataframe size (rows, columns): (100, 9)
11Sample size: 5
12Sample:
13 Index Organization Id ... Industry Number of employees
1479 80 cBa7EFe5D05Adaf ... Online Publishing 7805
1597 98 E7df80C60Abd7f9 ... Broadcast Media 236
163 4 2bFC1Be8a4ce42f ... Automotive 921
1742 43 A2D89Ab9bCcAd4e ... Capital Markets / Hedge Fund / Private Equity 3816
1870 71 32BB9Ff4d939788 ... Wireless 6146
19
20[5 rows x 9 columns]
21#+end_src
22
23* =sample.html=
24
25This is an interactive web page that allows users to submit their population
26size, sample size(s), and generate a psuedo-random sample list of numbers to use
27when sampling against their population.
28
29Samples can be re-generated and validated using the seed numbers provided during
30the original generation.
31
32[[sample-html.png]]
sampling/sample-html.png added

Binary file not shown.

sampling/sample.html added +167
@@ -0,0 +1,167 @@
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 const seed = customSeedInput ? parseInt(customSeedInput) : Math.floor(Math.random() * 1000000); // Use custom seed if provided
81 generateSamples(seed); // Call the function with the seed
82}
83
84function generateSamples(seed) {
85 const populationSize = parseInt(document.getElementById('populationSize').value);
86 const sampleSize = parseInt(document.getElementById('sampleSize').value);
87 const replacementSize = parseInt(document.getElementById('replacementSize').value || 0);
88 const resultsDiv = document.getElementById('results');
89
90 // Clear previous results
91 resultsDiv.innerHTML = '';
92
93 // Validate inputs
94 if (isNaN(populationSize) || isNaN(sampleSize) || populationSize <= 0 || sampleSize <= 0) {
95 alert("Please enter valid numbers for required fields.");
96 return;
97 }
98 if (sampleSize + replacementSize > populationSize) {
99 alert("Not enough unique samples available. Reduce the sample size or replacement size.");
100 return;
101 }
102
103 // Create seeded random function
104 const random = seededRandom(seed);
105
106 // Generate an array of population numbers
107 const population = Array.from({ length: populationSize }, (_, i) => i + 1);
108
109 // Shuffle the population array using the seeded random function
110 const shuffledPopulation = population
111 .map(value => ({ value, sort: random() }))
112 .sort((a, b) => a.sort - b.sort)
113 .map(({ value }) => value);
114
115 // Select original samples
116 const originalSamples = shuffledPopulation.slice(0, sampleSize);
117
118 // Select replacement samples
119 const replacementSamples = shuffledPopulation.slice(sampleSize, sampleSize + replacementSize);
120
121 // Display the seed
122 const seedInfo = document.createElement('p');
123 seedInfo.textContent = `Seed: ${seed}`;
124 resultsDiv.appendChild(seedInfo);
125
126 // Generate tables
127 const originalTable = createTable(originalSamples, "Original Samples");
128 const replacementTable = createTable(replacementSamples, "Replacement Samples");
129
130 // Append tables to the results div
131 resultsDiv.appendChild(originalTable);
132 if (replacementSamples.length > 0) {
133 resultsDiv.appendChild(replacementTable);
134 }
135}
136
137function createTable(dataArray, tableTitle) {
138 const table = document.createElement('table');
139 const caption = document.createElement('caption');
140 caption.textContent = tableTitle;
141 table.appendChild(caption);
142
143 const headerRow = document.createElement('tr');
144 const indexHeader = document.createElement('th');
145 indexHeader.textContent = 'Index';
146 const sampleHeader = document.createElement('th');
147 sampleHeader.textContent = 'Sample';
148 headerRow.appendChild(indexHeader);
149 headerRow.appendChild(sampleHeader);
150 table.appendChild(headerRow);
151
152 dataArray.forEach((sample, index) => {
153 const row = document.createElement('tr');
154 const indexCell = document.createElement('td');
155 const sampleCell = document.createElement('td');
156 indexCell.textContent = index + 1;
157 sampleCell.textContent = sample;
158 row.appendChild(indexCell);
159 row.appendChild(sampleCell);
160 table.appendChild(row);
161 });
162
163 return table;
164}
165</script>
166</body>
167</html>