Free Programs


All you need to do is copy & paste the code its in html to a text Editor and save it . open right click mouse on file and open it in your Browser.

PLEASE READ:

How to Operate and get the Information
save file to open Right click on mouse Open with your Browser

 ** Equibase program
go to Equibase click on Entries pick track then to the far right
you will see SmartPick click go past Graph then copy all horses
go to prgram and paste info in box then click Analyze Horses.Done
To do new race click on Refresh

** 1stBet program just make a mix of 1 factor then click on Handicap
that will get us to the next window then to the Top right corner
click on Top-4 Horses Win we want that % where the winner is in
the top-4 the program will get the top-25 factors.done
To do new race click on Refresh

1stBet

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>1stBet: Top 25 Factors</title>
<style>
body { font-family: Arial, sans-serif; padding: 20px; max-width: 960px; margin: auto; }
textarea { width: 100%; height: 220px; font-family: monospace; }
button { margin-top: 10px; padding: 10px 18px; font-size: 16px; cursor: pointer; }
.results { margin-top: 25px; }
table { border-collapse: collapse; margin-top: 12px; width: 100%; }
th, td { border: 1px solid #888; padding: 5px 10px; text-align: center; }
th { background: #f0f0f0; }
</style>
</head>
<body>
<h2>1stBet: Top 25 Factors</h2>
<textarea id="rawData" placeholder="Paste your handicapping factor data here..."></textarea><br>
<button onclick="processTop25()">Find Top 25 Factors / Top-4 Horses</button>
<div class="results" id="results"></div>

<script>
function escapeHtml(text) {
const div = document.createElement("div");
div.textContent = text;
return div.innerHTML;
}

function processTop25() {
const raw = document.getElementById('rawData').value.trim();
const resultDiv = document.getElementById('results');
if (!raw) {
resultDiv.innerHTML = '<b>Please paste your data before running.</b>';
return;
}

const lines = raw.split('\n').map(l => l.trim()).filter(Boolean);
const factorList = [];
const seenFactors = new Set();
let i = 0;

while (i < lines.length) {
if (/^\d{1,3}%$/.test(lines[i])) {
const winPct = parseInt(lines[i]);
const category = lines[i + 1] || '';
const type = lines[i + 2] || '';
const name = lines[i + 3] || '';

const combined = `${category} ${type} ${name}`.toLowerCase();
if (combined.includes('turf')) {
i += 4;
while (i < lines.length && /^\d+$/.test(lines[i])) i++;
continue;
}

const key = `${winPct}|${category}|${type}|${name}`;
if (seenFactors.has(key)) {
i += 4;
while (i < lines.length && /^\d+$/.test(lines[i])) i++;
continue;
}
seenFactors.add(key);

const horses = [];
let j = i + 4;
while (j < lines.length && /^\d+$/.test(lines[j])) {
horses.push(lines[j]);
j++;
}

factorList.push({
winPct,
fullName: `${lines[i]} | ${type} | ${name}`,
horses
});

i = j;
} else {
i++;
}
}

if (factorList.length === 0) {
resultDiv.innerHTML = '<b>No valid factors found in your data.</b>';
return;
}

const selectedFactors = factorList
.filter(f => f.winPct >= 55 && f.winPct <= 100)
.sort((a, b) => b.winPct - a.winPct)
.slice(0, 25);

if (selectedFactors.length === 0) {
resultDiv.innerHTML = '<b>No factors found with win percentage between 100% and 55%.</b>';
return;
}

const horseCounts = {};
selectedFactors.forEach(factor => {
factor.horses.slice(0, 4).forEach(horse => {
horseCounts[horse] = (horseCounts[horse] || 0) + 1;
});
});

const sortedHorses = Object.entries(horseCounts).sort((a, b) => b[1] - a[1]);

let html = "<h3>Top 25 Factors (100–55% Win, Excluding TURF)</h3><ol>";
selectedFactors.forEach(f =>
html += `<li><b>${escapeHtml(f.fullName)}</b></li>`
);
html += "</ol>";

html += `<h3>Top Horses (# of Top-4 placings in these 25 factors)</h3>`;
html += `<table><tr><th>Horse #</th><th>Top-4 Placings</th></tr>`;
sortedHorses.forEach(([horse, count]) => {
html += `<tr><td>${escapeHtml(horse)}</td><td>${count}</td></tr>`;
});
html += "</table>";

resultDiv.innerHTML = html;
}

// Clear data on page load
window.onload = () => {
document.getElementById('rawData').value = '';
document.getElementById('results').innerHTML = '';
};
</script>
</body>
</html>

Equibase

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Equibase Handicapping</title>
<style>
:root {
--primary-color: #2563eb;
--secondary-color: #f8fafc;
--border-color: #e2e8f0;
--text-color: #1e293b;
--success-color: #10b981;
--warning-color: #f59e0b;
--error-color: #ef4444;
}

* {
box-sizing: border-box;
}

body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
background-color: var(--secondary-color);
color: var(--text-color);
line-height: 1.6;
}

.header {
text-align: center;
margin-bottom: 30px;
padding: 20px;
background: white;
border-radius: 12px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}

.header h1 {
color: var(--primary-color);
margin: 0 0 10px 0;
}

.input-section {
background: white;
padding: 25px;
border-radius: 12px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
margin-bottom: 25px;
}

.input-group {
margin-bottom: 20px;
}

label {
display: block;
margin-bottom: 8px;
font-weight: 600;
color: var(--text-color);
}

textarea {
width: 100%;
min-height: 200px;
font-family: 'Courier New', monospace;
font-size: 13px;
padding: 15px;
border: 2px solid var(--border-color);
border-radius: 8px;
resize: vertical;
transition: border-color 0.3s ease;
background-color: #fafafa;
}

textarea:focus {
outline: none;
border-color: var(--primary-color);
background-color: white;
}

.controls {
display: flex;
gap: 15px;
flex-wrap: wrap;
align-items: center;
}

button {
padding: 12px 24px;
font-size: 14px;
font-weight: 600;
border: none;
border-radius: 8px;
cursor: pointer;
transition: all 0.3s ease;
display: inline-flex;
align-items: center;
gap: 8px;
}

.btn-primary {
background-color: var(--primary-color);
color: white;
}

.btn-primary:hover:not(:disabled) {
background-color: #1d4ed8;
transform: translateY(-1px);
}

.btn-secondary {
background-color: var(--success-color);
color: white;
}

.btn-secondary:hover:not(:disabled) {
background-color: #059669;
}

.btn-warning {
background-color: var(--warning-color);
color: white;
}

.btn-warning:hover:not(:disabled) {
background-color: #d97706;
}

button:disabled {
opacity: 0.6;
cursor: not-allowed;
}

.loading {
opacity: 0.7;
}

.results-section {
background: white;
border-radius: 12px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
overflow: hidden;
margin-top: 25px;
}

.results-header {
background: var(--primary-color);
color: white;
padding: 20px;
display: flex;
justify-content: space-between;
align-items: center;
}

.results-stats {
display: flex;
gap: 20px;
font-size: 14px;
}

.table-container {
overflow-x: auto;
}

table {
width: 100%;
border-collapse: collapse;
font-family: 'Courier New', monospace;
}

th, td {
padding: 12px 16px;
text-align: center;
border-bottom: 1px solid var(--border-color);
}

th {
background: #f8fafc;
font-weight: 600;
color: var(--text-color);
position: sticky;
top: 0;
z-index: 10;
}

tr:hover {
background-color: #f1f5f9;
}

.rank-1 { background-color: #fef3c7; }
.rank-2 { background-color: #f3f4f6; }
.rank-3 { background-color: #fde8d7; }

.high-value { color: var(--success-color); font-weight: 600; }
.medium-value { color: var(--warning-color); font-weight: 600; }
.low-value { color: var(--error-color); font-weight: 600; }

.alert {
padding: 15px;
border-radius: 8px;
margin: 15px 0;
font-weight: 500;
}

.alert-success {
background-color: #d1fae5;
color: #065f46;
border: 1px solid #a7f3d0;
}

.alert-error {
background-color: #fee2e2;
color: #991b1b;
border: 1px solid #fca5a5;
}

.alert-warning {
background-color: #fef3c7;
color: #92400e;
border: 1px solid #fcd34d;
}

.hidden {
display: none;
}

.example-format {
background: #f8fafc;
border: 1px solid var(--border-color);
border-radius: 6px;
padding: 12px;
font-family: 'Courier New', monospace;
font-size: 12px;
margin-top: 10px;
white-space: pre-line;
}

.sort-controls {
display: flex;
gap: 10px;
align-items: center;
margin: 15px 0;
}

.sort-btn {
padding: 6px 12px;
font-size: 12px;
background: #e2e8f0;
color: var(--text-color);
border: none;
border-radius: 4px;
cursor: pointer;
}

.sort-btn.active {
background: var(--primary-color);
color: white;
}

@media (max-width: 768px) {
body {
padding: 10px;
}

.controls {
flex-direction: column;
align-items: stretch;
}

button {
justify-content: center;
}
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js"></script>
</head>
<body>
<div class="header">
<h1>🏇 Equibase Handicapping</h1>
<p>Advanced horse racing analysis with improved parsing and visualization</p>
</div>

<div class="input-section">
<div class="input-group">
<label for="input">Horse Racing Data:</label>
<textarea
id="input"
placeholder="Paste your multiline horse data here... Each horse should start with a number, followed by name and race information."
aria-describedby="format-help"
></textarea>

<details style="margin-top: 10px;">
<summary style="cursor: pointer; color: var(--primary-color); font-weight: 600;">📋 Expected Format Example</summary>
<div class="example-format">1
Horse Name Here
45% Jockey / Trainer Win per Start - Finish Last Start - 3rd - 89.5 Best E Speed Figure
Race Date Track Race Course Dist. Type E Finish
01/15/24 GP 7 D 6F CLM 87 4th/8
01/02/24 GP 5 D 6F CLM 82 6th/10
12/20/23 GP 3 D 6F CLM 85 2nd/7</div>
</details>
</div>

<div class="controls">
<button class="btn-primary" onclick="processInput(this)">
🔍 Analyze Horses
</button>
<button class="btn-warning" onclick="clearData()">
🗑️ Clear All
</button>
</div>
</div>

<div id="alertContainer"></div>

<div id="resultsSection" class="results-section hidden">
<div class="results-header">
<h2>📊 Handicapping Results</h2>
<div class="results-stats">
<span id="horseCount">0 horses analyzed</span>
<span id="avgSpeed">Avg Speed: 0</span>
</div>
</div>

<div class="sort-controls">
<span>Sort by:</span>
<button class="sort-btn active" onclick="sortTable('avgSpeed', this)">AVG</button>
<button class="sort-btn" onclick="sortTable('number', this)">Horse #</button>
</div>

<div class="table-container">
<table id="handicapTable">
<thead>
<tr>
<th>Horse #</th>
<th>Last 3</th>
<th>AVG</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>

<script>
let currentHorses = [];
let currentSort = 'avgSpeed';

window.onload = () => {
document.getElementById('input').value = '';
};

function showAlert(message, type = 'error') {
const container = document.getElementById('alertContainer');
const alert = document.createElement('div');
alert.className = `alert alert-${type}`;
alert.textContent = message;

container.innerHTML = '';
container.appendChild(alert);

setTimeout(() => {
alert.remove();
}, 5000);
}

function parseHorses(src) {
try {
// More robust splitting - handle various line endings and spacing
const normalizedSrc = src.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
const horseEntries = normalizedSrc.split(/\n(?=\d+\s*\n)/g)
.map(s => s.trim())
.filter(Boolean);

const horses = [];
const errors = [];

horseEntries.forEach((block, index) => {
try {
const lines = block.split('\n').map(l => l.trim()).filter(Boolean);
if (lines.length < 2) {
errors.push(`Horse ${index + 1}: Insufficient data`);
return;
}

const number = lines[0];
if (!number.match(/^\d+$/)) {
errors.push(`Horse ${index + 1}: Invalid number format`);
return;
}

let jtPerc = null;
let lastFinish = null;
let bestESpeed = 0;

// More flexible pattern matching for combined info line
const combinedInfoLine = lines.find(line =>
line.includes('per Start') || line.includes('Best E Speed') || line.includes('Jockey')
);

if (combinedInfoLine) {
// Enhanced J/T % extraction
const jtPercMatch = combinedInfoLine.match(/(\d+(?:\.\d+)?)%.*?(?:Jockey|J\/T|Win)/i);
if (jtPercMatch) jtPerc = Math.round(Number(jtPercMatch[1]));

// Enhanced finish extraction
const lastFinishMatch = combinedInfoLine.match(/Finish.*?(\d+)(?:st|nd|rd|th)/i);
if (lastFinishMatch) lastFinish = Number(lastFinishMatch[1]);

// Enhanced speed extraction
const bestESpeedMatch = combinedInfoLine.match(/(\d+(?:\.\d+)?)\s*Best E Speed/i);
if (bestESpeedMatch) bestESpeed = Number(bestESpeedMatch[1]);
}

// Find race data with more flexible header matching
const raceHeaderIndex = lines.findIndex(line =>
line.toLowerCase().includes('race') &&
line.toLowerCase().includes('date') &&
(line.toLowerCase().includes('finish') || line.toLowerCase().includes('type'))
);

let last3EList = [];
if (raceHeaderIndex !== -1) {
// More robust race data extraction
for (let i = 1; i <= 5; i++) { // Check more lines for race data
const raceLineIndex = raceHeaderIndex + i;
if (raceLineIndex < lines.length) {
const raceLine = lines[raceLineIndex];

// Multiple patterns for E speed extraction
let eSpeed = null;

// Pattern 1: Speed followed by finish position (e.g., "87 4th/8")
const pattern1 = raceLine.match(/(\d+)\s+(\d+)(?:st|nd|rd|th)\/\d+/);
if (pattern1) {
eSpeed = Number(pattern1[1]);
} else {
// Pattern 2: Look for numbers in typical speed ranges (60-120)
const numbers = raceLine.match(/\d+/g);
if (numbers) {
for (const num of numbers) {
const n = Number(num);
if (n >= 60 && n <= 120) {
eSpeed = n;
break;
}
}
}
}

// Only add valid E speeds (not 999 which means no race)
if (eSpeed !== null && !isNaN(eSpeed) && eSpeed !== 999 && last3EList.length < 3) {
last3EList.push(eSpeed);
}
}
}
}

// Calculate average with improved logic - exclude 999 (no race) and 0 values
const validSpeeds = [bestESpeed, ...last3EList].filter(s => s > 0 && s !== 999);
const avgAllFour = validSpeeds.length > 0
? Math.round(validSpeeds.reduce((a, b) => a + b, 0) / validSpeeds.length)
: 0;

// Calculate rating based on multiple factors
let rating = 'C';
const score = (avgAllFour * 0.6) + ((jtPerc || 0) * 0.3) + ((lastFinish ? (10 - Math.min(lastFinish, 10)) : 0) * 0.1);

if (score >= 80) rating = 'A+';
else if (score >= 70) rating = 'A';
else if (score >= 60) rating = 'B+';
else if (score >= 50) rating = 'B';
else if (score >= 40) rating = 'C+';

horses.push({
number,
jtPerc,
lastFinish,
bestESpeed,
last3EList,
avgAllFour,
rating,
score
});

} catch (error) {
errors.push(`Horse ${index + 1}: ${error.message}`);
}
});

if (errors.length > 0 && horses.length === 0) {
throw new Error(`Parsing failed:\n${errors.join('\n')}`);
} else if (errors.length > 0) {
showAlert(`Parsed ${horses.length} horses with ${errors.length} warnings`, 'warning');
}

return horses;
} catch (error) {
throw new Error(`Failed to parse horse data: ${error.message}`);
}
}

function sortTable(column, buttonElement = null) {
// Update active sort button
document.querySelectorAll('.sort-btn').forEach(btn => btn.classList.remove('active'));
if (buttonElement) {
buttonElement.classList.add('active');
} else {
// Find the button for this column if not provided
const buttons = document.querySelectorAll('.sort-btn');
buttons.forEach(btn => {
if (btn.textContent.toLowerCase().includes(column.toLowerCase()) ||
(column === 'avgSpeed' && btn.textContent.includes('AVG Speed'))) {
btn.classList.add('active');
}
});
}

currentSort = column;

// Sort horses
currentHorses.sort((a, b) => {
switch (column) {
case 'avgSpeed':
return b.avgAllFour - a.avgAllFour;
case 'number':
return Number(a.number) - Number(b.number);
default:
return 0;
}
});

renderTable();
}

function renderTable() {
const tbody = document.querySelector('#handicapTable tbody');
tbody.innerHTML = '';

currentHorses.forEach((horse, index) => {
const tr = document.createElement('tr');

// Add ranking classes for top 3
if (currentSort === 'avgSpeed' && index < 3) {
tr.classList.add(`rank-${index + 1}`);
}

// Color code AVG Speed
let speedClass = '';
if (horse.avgAllFour >= 85) speedClass = 'high-value';
else if (horse.avgAllFour >= 75) speedClass = 'medium-value';
else if (horse.avgAllFour > 0) speedClass = 'low-value';

const finishText = horse.lastFinish !== null ?
(horse.lastFinish === 1 ? '1st' :
horse.lastFinish === 2 ? '2nd' :
horse.lastFinish === 3 ? '3rd' :
`${horse.lastFinish}th`) : '—';

tr.innerHTML = `
<td><strong>#${horse.number}</strong></td>
<td>${horse.last3EList.length > 0 ? horse.last3EList.join(', ') : 'No races'}</td>
<td class="${speedClass}"><strong>${horse.avgAllFour}</strong></td>
`;
tbody.appendChild(tr);
});
}

function updateStats() {
const horseCount = currentHorses.length;
const avgSpeed = horseCount > 0 ?
Math.round(currentHorses.reduce((sum, h) => sum + h.avgAllFour, 0) / horseCount) : 0;

document.getElementById('horseCount').textContent = `${horseCount} horses analyzed`;
document.getElementById('avgSpeed').textContent = `Avg Speed: ${avgSpeed}`;
}

function processInput(buttonElement = null) {
const text = document.getElementById('input').value.trim();
if (!text) {
showAlert('Please paste horse data into the input field.');
return;
}

try {
const button = buttonElement || document.querySelector('.btn-primary');
button.disabled = true;
button.classList.add('loading');
button.textContent = '🔄 Processing...';

setTimeout(() => {
try {
currentHorses = parseHorses(text);

if (currentHorses.length === 0) {
showAlert('No valid horses found. Please check your input format.');
return;
}

// Sort by default (AVG Speed)
sortTable('avgSpeed');
updateStats();

document.getElementById('resultsSection').classList.remove('hidden');

showAlert(`Successfully processed ${currentHorses.length} horses!`, 'success');

} catch (error) {
showAlert(error.message);
currentHorses = [];
document.getElementById('resultsSection').classList.add('hidden');
} finally {
button.disabled = false;
button.classList.remove('loading');
button.textContent = '🔍 Analyze Horses';
}
}, 100);

} catch (error) {
showAlert('An unexpected error occurred while processing the data.');
}
}

function clearData() {
if (confirm('Are you sure you want to clear all data?')) {
document.getElementById('input').value = '';
document.getElementById('resultsSection').classList.add('hidden');
document.getElementById('alertContainer').innerHTML = '';
currentHorses = [];
showAlert('Data cleared successfully.', 'success');
}
}

function downloadPDF(buttonElement = null) {
const resultsSection = document.getElementById('resultsSection');
if (resultsSection.classList.contains('hidden') || currentHorses.length === 0) {
showAlert('No data available to export. Please process some horse data first.');
return;
}

try {
const button = buttonElement || document.getElementById('pdfBtn');
button.disabled = true;
button.textContent = '📄 Generating PDF...';

const options = {
margin: 0.5,
filename: `handicapping_results_${new Date().toISOString().split('T')[0]}.pdf`,
image: { type: 'jpeg', quality: 0.98 },
html2canvas: {
scale: 2,
useCORS: true,
allowTaint: true,
logging: false
},
jsPDF: {
unit: 'in',
format: 'letter',
orientation: 'landscape'
}
};

html2pdf().set(options).from(resultsSection).save().then(() => {
showAlert('PDF exported successfully!', 'success');
}).catch(error => {
showAlert('Failed to generate PDF. Please try again.');
}).finally(() => {
button.disabled = false;
button.textContent = '📄 Export PDF';
});

} catch (error) {
showAlert('PDF generation failed. Please try again.');
document.getElementById('pdfBtn').disabled = false;
document.getElementById('pdfBtn').textContent = '📄 Export PDF';
}
}

// Add keyboard shortcuts
document.addEventListener('keydown', function(e) {
if (e.ctrlKey || e.metaKey) {
switch(e.key) {
case 'Enter':
e.preventDefault();
processInput();
break;
}
}
});
</script>
</body>
</html>