Skip to content

Instantly share code, notes, and snippets.

@mode-mercury
Created June 2, 2025 20:55
Show Gist options
  • Select an option

  • Save mode-mercury/cf23fc64befdb8e139728c630171425a to your computer and use it in GitHub Desktop.

Select an option

Save mode-mercury/cf23fc64befdb8e139728c630171425a to your computer and use it in GitHub Desktop.
Untitled
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Gematria Multi-Page Scraper</title>
<style>
body {
background-color: #ffffff;
color: #333;
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
}
.container {
max-width: 1000px;
margin: 0 auto;
padding: 20px;
}
h1, h2, h3, h4 {
color: #333;
}
.input-group {
margin-bottom: 20px;
}
input[type="search"], input[type="number"], select, textarea {
width: 100%;
padding: 10px;
margin: 10px 0;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 16px;
}
textarea {
min-height: 150px;
resize: vertical;
}
button {
padding: 10px 15px;
background: #4CAF50;
border: none;
border-radius: 4px;
color: white;
cursor: pointer;
font-size: 16px;
}
.full-width-btn {
width: 100%;
}
button:hover {
background: #45a049;
}
#results, #number-results {
margin-top: 20px;
}
.page-results {
margin-bottom: 30px;
padding: 15px;
border: 1px solid #ddd;
border-radius: 4px;
}
.page-header {
margin-bottom: 10px;
padding-bottom: 5px;
border-bottom: 2px solid #4CAF50;
}
.data-table {
width: 100%;
border-collapse: collapse;
margin-top: 15px;
font-size: 14px; /* Larger font for better readability */
table-layout: fixed;
}
.data-table th, .data-table td {
border: 1px solid #ddd;
padding: 8px; /* More padding for better spacing */
text-align: left;
overflow: hidden;
text-overflow: ellipsis;
font-size: 0.95em; /* Reduced font size as requested */
}
/* Enhanced phrase analysis */
.phrase-analysis {
margin-top: 5px;
font-size: 0.9em;
}
.phrase-italic {
font-style: italic;
margin-top: 3px;
}
.word-values {
margin-top: 3px;
line-height: 1.3;
}
.hebrew-value {
color: #5D5CDE;
font-weight: bold;
}
.english-value {
color: #673AB7;
font-weight: bold;
}
.reversed-phrase {
font-size: 0.85em;
color: #777;
margin-top: 3px;
font-style: italic;
}
.cipher-abbr {
font-size: 0.75em;
color: #666;
margin-right: 3px;
}
.data-table th {
background-color: #f5f5f5;
}
.data-table tr:nth-child(even) {
background-color: #f9f9f9;
}
.loading {
text-align: center;
padding: 20px;
}
.error {
color: #d32f2f;
padding: 10px;
margin: 10px 0;
background-color: #ffebee;
border-radius: 4px;
}
.chart-container {
margin-top: 30px;
padding: 20px;
border: 1px solid #ddd;
border-radius: 4px;
display: flex;
flex-wrap: wrap;
gap: 20px;
}
.chart-item {
flex: 1 1 300px;
min-width: 280px;
max-width: 45%;
max-height: 250px;
}
/* Tabs styling */
.tabs {
display: flex;
margin-bottom: 20px;
border-bottom: 1px solid #ddd;
flex-wrap: wrap;
}
/* Cipher analysis styles */
.cipher-analysis {
margin-top: 15px;
font-size: 12px;
}
.cipher-cell {
padding: 2px !important;
font-size: 10px !important;
width: 1%;
white-space: nowrap;
}
.phrase-checkbox {
margin: 0;
padding: 0;
scale: 0.8;
}
.cipher-percentage {
display: inline-block;
width: 40px;
font-size: 10px;
font-weight: bold;
color: #4CAF50;
}
.cipher-abbr {
display: inline-block;
width: 30px;
font-size: 10px;
font-weight: bold;
color: #2196F3;
text-align: center;
}
.phrase-row {
display: flex;
align-items: center;
margin-bottom: 5px;
padding-bottom: 5px;
border-bottom: 1px solid #eee;
}
.phrase-checkbox {
margin-right: 10px;
}
.decode-container {
margin-top: 20px;
padding: 15px;
background-color: #f5f5f5;
border-radius: 4px;
text-align: center;
}
.decode-btn {
background-color: #673AB7;
}
.decode-results {
margin-top: 15px;
text-align: left;
}
/* Cipher badge styles */
.cipher-badge {
display: inline-block;
padding: 2px 5px;
border-radius: 3px;
font-size: 10px;
margin-right: 5px;
color: white;
text-transform: uppercase;
}
.atbash { background-color: #E91E63; }
.caesar { background-color: #9C27B0; }
.a1z26 { background-color: #3F51B5; }
.reverse { background-color: #2196F3; }
.mirror { background-color: #00BCD4; }
.rot13 { background-color: #009688; }
.ordinal { background-color: #4CAF50; }
.reduction { background-color: #FF9800; }
.alw { background-color: #8BC34A; }
.tab-btn {
padding: 10px 20px;
background: none;
border: none;
border-bottom: 3px solid transparent;
cursor: pointer;
font-size: 16px;
color: #666;
}
.tab-btn.active {
border-bottom: 3px solid #4CAF50;
color: #333;
font-weight: bold;
}
.tab-content {
display: none;
}
.tab-content.active {
display: block;
}
/* Group styling */
.group-header {
padding: 10px;
background-color: #f0f8ff;
margin-top: 15px;
border-radius: 4px 4px 0 0;
font-weight: bold;
}
/* Progress styling */
.progress-container {
width: 100%;
background-color: #f1f1f1;
border-radius: 4px;
margin: 10px 0;
}
.progress-bar {
height: 20px;
background-color: #4CAF50;
border-radius: 4px;
width: 0%;
transition: width 0.3s;
color: white;
text-align: center;
line-height: 20px;
font-size: 12px;
}
/* Randomizer container */
.randomizer-container {
margin-bottom: 30px;
}
.randomizer-header {
font-weight: bold;
margin-bottom: 10px;
}
.randomizer-actions {
display: flex;
gap: 10px;
margin: 10px 0;
}
/* Hebrew group styling */
.hebrew-group {
background-color: #f0f8ff;
border-left: 4px solid #4169e1;
}
/* English group styling */
.english-group {
background-color: #f5f5f5;
border-left: 4px solid #228b22;
}
/* Top values styling */
.top-values-container {
display: flex;
flex-direction: column;
gap: 15px;
}
.value-box {
border: 1px solid #ddd;
border-radius: 4px;
padding: 10px;
}
.value-header {
font-weight: bold;
margin-bottom: 10px;
padding-bottom: 5px;
border-bottom: 1px solid #ddd;
}
.value-input-group {
display: flex;
gap: 10px;
}
.value-input-group textarea {
flex-grow: 1;
min-height: 80px;
}
.value-input-group button {
align-self: center;
}
/* Search by number styling */
.number-search {
display: flex;
gap: 10px;
margin-bottom: 20px;
}
.number-search input {
flex-grow: 1;
}
.number-search button {
min-width: 100px;
}
.match-highlight {
background-color: #ffeb3b;
padding: 2px 4px;
border-radius: 2px;
font-weight: bold;
}
.match-count {
font-weight: bold;
margin-bottom: 15px;
padding: 10px;
background-color: #e8f5e9;
border-radius: 4px;
border-left: 4px solid #4CAF50;
}
/* Column matches styling */
.column-matches {
margin-bottom: 25px;
}
.column-header {
font-weight: bold;
padding: 10px;
background-color: #e3f2fd;
border-radius: 4px;
margin-bottom: 10px;
border-left: 4px solid #2196F3;
}
/* Accordion styling */
.accordion {
margin-bottom: 10px;
border: 1px solid #ddd;
border-radius: 4px;
overflow: hidden;
}
.accordion-header {
padding: 12px 15px;
background-color: #f5f5f5;
cursor: pointer;
font-weight: bold;
display: flex;
justify-content: space-between;
align-items: center;
}
.accordion-header:hover {
background-color: #e9e9e9;
}
.accordion-content {
padding: 0;
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease;
}
.accordion-content.active {
padding: 15px;
max-height: 2000px;
}
.accordion-toggle {
font-weight: bold;
font-size: 18px;
}
/* Database styling */
.search-box {
margin-bottom: 20px;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
background-color: #f9f9f9;
}
.source-label {
display: inline-block;
padding: 3px 8px;
border-radius: 4px;
font-size: 12px;
margin-right: 8px;
font-weight: bold;
}
.source-gematrix {
background-color: #e3f2fd;
color: #0d47a1;
}
.source-shematria {
background-color: #e8f5e9;
color: #2e7d32;
}
.source-shawnomancy {
background-color: #fff3e0;
color: #e65100;
}
.word-entry {
margin-bottom: 15px;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
}
.word-entry:hover {
background-color: #f5f5f5;
}
.word-header {
font-weight: bold;
margin-bottom: 5px;
}
.word-values {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-bottom: 8px;
}
.value-tag {
padding: 3px 8px;
border-radius: 4px;
font-size: 12px;
background-color: #e8eaf6;
}
.pagination {
display: flex;
justify-content: center;
margin-top: 20px;
gap: 5px;
}
.pagination button {
min-width: 40px;
height: 40px;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
}
.pagination button.current {
background-color: #2196F3;
}
/* Cosmic symbols styling */
.cosmic-symbols {
display: flex;
flex-wrap: wrap;
gap: 1px;
font-size: 12px;
margin-right: 2px;
line-height: 1;
max-width: 65px;
}
/* Favorite and checkbox controls */
.controls-container {
display: flex;
gap: 4px;
align-items: center;
margin-right: 6px;
}
.favorite-btn {
background: none;
border: none;
color: #888;
cursor: pointer;
font-size: 18px;
padding: 0;
line-height: 1;
transition: color 0.2s;
}
.favorite-btn.active {
color: #FFD700;
}
.planet-symbol {
color: #673AB7;
}
.element-symbol.fire {
color: #e53935; /* Red for fire */
}
.element-symbol.water {
color: #1e88e5; /* Blue for water */
}
.element-symbol.air {
color: #ffc107; /* Yellow for air */
}
.element-symbol.earth {
color: #4caf50; /* Green for earth */
}
.zodiac-symbol {
color: #009688;
}
/* Cell background shading based on number value */
.num-cell {
position: relative;
}
.num-cell-1 { background-color: rgba(233, 30, 99, 0.2); }
.num-cell-2 { background-color: rgba(156, 39, 176, 0.2); }
.num-cell-3 { background-color: rgba(63, 81, 181, 0.2); }
.num-cell-4 { background-color: rgba(33, 150, 243, 0.2); }
.num-cell-5 { background-color: rgba(3, 169, 244, 0.2); }
.num-cell-6 { background-color: rgba(0, 188, 212, 0.2); }
.num-cell-7 { background-color: rgba(0, 150, 136, 0.2); }
.num-cell-8 { background-color: rgba(76, 175, 80, 0.2); }
.num-cell-9 { background-color: rgba(255, 152, 0, 0.2); }
.num-cell-0 { background-color: rgba(158, 158, 158, 0.2); }
/* Special number patterns */
.angel-number {
background-color: rgba(255, 223, 0, 0.3) !important;
position: relative;
}
.mirror-number {
background-color: rgba(147, 112, 219, 0.3) !important;
position: relative;
}
/* Highlighted phrases */
.special-phrase {
background-color: rgba(255, 223, 0, 0.15);
font-weight: bold;
padding: 2px 4px;
border-radius: 3px;
}
/* Expanded cosmic symbols with runes, plants and animals */
.cosmic-full {
display: flex;
gap: 3px;
align-items: center;
}
.rune-symbol {
font-family: 'Arial Unicode MS', sans-serif;
color: #7b4f4f;
font-size: 14px;
}
.plant-symbol, .animal-symbol {
font-size: 14px;
}
/* Collapsible sections */
.collapsible {
cursor: pointer;
margin-top: 15px;
}
.collapsible-header {
padding: 8px 12px;
background-color: #f1f1f1;
border-radius: 4px;
display: flex;
justify-content: space-between;
align-items: center;
}
.collapsible-content {
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease;
}
.collapsible-content.visible {
max-height: 10000px;
}
/* Similar numbers group */
.similar-numbers {
border: 1px solid #ccc;
border-radius: 4px;
margin-bottom: 15px;
padding: 10px;
background-color: rgba(240, 240, 240, 0.2);
}
.similar-header {
font-weight: bold;
margin-bottom: 8px;
padding-bottom: 5px;
border-bottom: 1px solid #ddd;
}
/* Number color coding */
.number-1, .number-10, .number-19, .number-28 { color: #e91e63; } /* Red for 1s */
.number-2, .number-11, .number-20, .number-29 { color: #9c27b0; } /* Purple for 2s */
.number-3, .number-12, .number-21, .number-30 { color: #3f51b5; } /* Indigo for 3s */
.number-4, .number-13, .number-22, .number-31 { color: #2196f3; } /* Blue for 4s */
.number-5, .number-14, .number-23, .number-32 { color: #03a9f4; } /* Light blue for 5s */
.number-6, .number-15, .number-24, .number-33 { color: #00bcd4; } /* Cyan for 6s */
.number-7, .number-16, .number-25, .number-34 { color: #009688; } /* Teal for 7s */
.number-8, .number-17, .number-26, .number-35 { color: #4caf50; } /* Green for 8s */
.number-9, .number-18, .number-27, .number-36 { color: #ff9800; } /* Orange for 9s */
.number-0 { color: #9e9e9e; } /* Gray for 0 */
.help-content {
background-color: #f9f9f9;
border: 1px solid #ddd;
border-radius: 4px;
padding: 15px;
margin-bottom: 20px;
}
.help-header {
font-weight: bold;
font-size: 18px;
margin-bottom: 10px;
color: #4a148c;
}
/* Checked phrases counter */
.checked-counter {
background-color: #673AB7;
color: white;
padding: 3px 8px;
border-radius: 12px;
font-size: 12px;
font-weight: bold;
margin-left: 8px;
}
/* Restructure cell content - number on top */
.num-cell {
display: flex;
flex-direction: column;
align-items: center;
}
.cell-number {
font-weight: bold;
margin-bottom: 2px;
font-size: 12px;
order: -1; /* Make sure number appears at the top */
}
.cosmic-symbols {
order: 0;
}
@media (prefers-color-scheme: dark) {
body {
background-color: #181818;
color: #f0f0f0;
}
h1, h2, h3, h4 {
color: #f0f0f0;
}
.data-table th {
background-color: #333;
}
.data-table td {
border-color: #444;
}
.data-table tr:nth-child(even) {
background-color: #222;
}
.page-results, .chart-container, .value-box, .accordion, .word-entry, .help-content {
border-color: #444;
background-color: #222;
}
input[type="search"], input[type="number"], select, textarea {
background-color: #333;
color: #f0f0f0;
border-color: #555;
}
.tab-btn {
color: #aaa;
}
.tab-btn.active {
color: #f0f0f0;
}
.group-header, .value-header {
background-color: #333;
}
.hebrew-group {
background-color: #1a2a4a;
}
.english-group {
background-color: #1a331a;
}
.error {
background-color: #3a1111;
}
.value-header {
border-color: #444;
}
.match-highlight {
background-color: #665c00;
color: #fff;
}
.match-count {
background-color: #1b3c1e;
border-color: #2e7d32;
}
.column-header {
background-color: #1a365d;
border-color: #0d47a1;
}
.accordion-header {
background-color: #333;
}
.accordion-header:hover {
background-color: #444;
}
.search-box {
background-color: #333;
border-color: #444;
}
.word-entry:hover {
background-color: #2a2a2a;
}
.value-tag {
background-color: #1a237e;
color: #f0f0f0;
}
.help-content {
background-color: #222;
border-color: #444;
}
.help-header {
color: #b388ff;
}
.decode-container {
background-color: #333;
}
}
</style>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body>
<div class="container">
<h1>Gematria Multi-Page Scraper</h1>
<div class="tabs">
<button type="button" id="btn-search-tab" class="tab-btn active">Search & Analysis</button>
<button type="button" id="btn-decoded-tab" class="tab-btn">Decoded Phrases <span id="checked-counter" class="checked-counter" style="display:none">0</span></button>
<button type="button" id="btn-phrase-generator-tab" class="tab-btn">Phrase Generator</button>
</div>
<div id="search-tab" class="tab-content active">
<div class="input-group">
<select id="proxySelect">
<option value="myCustomProxy">Custom Proxy - coserver.onrender.com</option>
<option value="corsProxy">CORS Proxy - corsproxy.io</option>
<option value="allOrigins">CORS Proxy - allorigins.win</option>
<option value="corsAnywhere">CORS Proxy - cors-anywhere</option>
<option value="thingproxy">CORS Proxy - thingproxy</option>
<option value="corsProxyBypass">CORS Proxy - codetabs</option>
<option value="corsProxyEasy">CORS Proxy - corsproxy.org</option>
<option value="crossOriginMe">CORS Proxy - crossorigin.me</option>
<option value="corsAnywhere2">CORS Proxy - cors-anywhere AZM</option>
<option value="workersCors">CORS Proxy - workers.dev</option>
<option value="corsProxyNode">CORS Proxy - htmldriven</option>
</select>
<input type="search"
id="word"
placeholder="Enter phrase to analyze"
maxlength="200">
<button type="button" id="analyze-btn" class="full-width-btn">Analyze 10 Pages</button>
</div>
<div id="progress-container" class="progress-container" style="display: none;">
<div id="progress-bar" class="progress-bar">0%</div>
</div>
<div id="decode-container" class="decode-container" style="display: none;">
<p><span id="checked-phrases-count">0</span> phrases selected</p>
<button type="button" id="decode-btn" class="decode-btn">Decode Selected Phrases</button>
</div>
<div id="charts" class="chart-container"></div>
<div id="results"></div>
</div>
<div id="randomizer-tab" class="tab-content">
<div class="randomizer-container">
<div class="randomizer-header">All Words from Analysis</div>
<textarea id="all-words" placeholder="Words will appear here after analysis (excluding numbers)"></textarea>
<div class="randomizer-actions">
<button type="button" id="randomize-all-btn">Randomize</button>
<button type="button" id="clear-all-btn">Clear</button>
</div>
</div>
</div>
<div id="top-values-tab" class="tab-content">
<div class="randomizer-header">Top 10 Values and Associated Words</div>
<p>This tab shows the top 10 most frequent values from your search with all associated words grouped together.</p>
<div id="top-values-container" class="top-values-container">
<div class="loading">Please run an analysis first to see top values</div>
</div>
</div>
<div id="number-search-tab" class="tab-content">
<div class="randomizer-header">Search for Specific Number</div>
<p>Enter a specific gematria value to search for across 10 pages.</p>
<div class="number-search">
<input type="number"
id="search-number"
placeholder="Enter number to search for"
min="1">
<button type="button" id="search-number-btn">Search</button>
</div>
<div id="number-progress-container" class="progress-container" style="display: none;">
<div id="number-progress-bar" class="progress-bar">0%</div>
</div>
<div id="number-results"></div>
</div>
<div id="decoded-tab" class="tab-content">
<div class="randomizer-header">Decoded Phrases</div>
<p>This tab shows decoded phrases that you've selected for analysis.</p>
<div id="decoded-results">
<div class="loading">Select phrases using the checkboxes and click the "Decode Selected Phrases" button</div>
</div>
</div>
<div id="phrase-generator-tab" class="tab-content">
<div class="randomizer-header">Gematria Phrase Generator</div>
<p>This tool creates new phrases that have the same gematria values as the original phrases.</p>
<div class="value-box">
<div class="value-header">
<span class="planet-symbol">☿</span> Select Desired Value
</div>
<div style="margin-bottom: 15px;">
<label for="target-value">Target Gematria Value:</label>
<select id="target-value" class="full-width">
<option value="">Select a value from analyzed data</option>
</select>
<div style="margin-top: 10px;">
<label for="value-input">Or enter a specific value:</label>
<input type="number" id="value-input" placeholder="Enter a specific gematria value" min="1">
</div>
</div>
<div style="margin-bottom: 15px;">
<label for="cipher-type">Cipher Type:</label>
<select id="cipher-type" class="full-width">
<option value="english">English Gematria</option>
<option value="simple">Simple Gematria</option>
<option value="jewish">Jewish Gematria</option>
<option value="alw">ALW Cipher</option>
</select>
</div>
<button type="button" id="generate-phrases-btn" class="full-width-btn">Generate Phrases</button>
</div>
<div class="value-box">
<div class="value-header">
<span class="planet-symbol">♃</span> Word Bank
</div>
<p>Add, edit or paste words to use for generating phrases:</p>
<textarea id="word-bank" placeholder="Enter words separated by spaces or new lines"></textarea>
<div class="randomizer-actions">
<button type="button" id="use-scraped-words-btn">Use Scraped Words</button>
<button type="button" id="add-common-words-btn">Add Common Words</button>
<button type="button" id="clear-word-bank-btn">Clear</button>
</div>
</div>
<div id="generated-phrases-container" class="value-box" style="display: none;">
<div class="value-header">
<span class="planet-symbol">♄</span> Generated Phrases
</div>
<div id="generated-phrases-list"></div>
<div class="randomizer-actions">
<button type="button" id="regenerate-btn">Generate More</button>
<button type="button" id="save-favorites-btn">Save Selected to Favorites</button>
</div>
</div>
<div id="phrase-generator-loading" class="loading" style="display: none;">
<p>Generating phrases... This may take a moment.</p>
<div class="progress-container">
<div id="phrase-generator-progress" class="progress-bar">0%</div>
</div>
</div>
</div>
<div id="database-tab" class="tab-content">
<div class="randomizer-header">Saved Phrases Database</div>
<p>Your favorited phrases are saved here and grow smarter over time with machine learning.</p>
<div class="search-box">
<input type="search"
id="database-search"
placeholder="Search your saved phrases by keyword or value"
maxlength="200">
<button type="button" id="database-search-btn">Search</button>
</div>
<div id="ml-recommendations" class="value-box">
<div class="value-header">
<span class="planet-symbol">♃</span> ML Recommendations
</div>
<p>As you save more phrases, our machine learning system will suggest related phrases here based on patterns in your favorites.</p>
</div>
<div id="favorites-container">
<div class="no-favorites">
<p>You haven't favorited any phrases yet. When analyzing phrases, click the ★ icon to save them to your database.</p>
</div>
</div>
<div id="database-results"></div>
<div id="help-content"></div>
</div>
</div>
<script>
const PROXY_CONFIGS = {
// Your custom proxy (added first so it's used first)
myCustomProxy: {
url: 'https://coserver.onrender.com/proxy?url=',
headers: {}
},
// Fallback public proxies
corsProxy: {
url: 'https://corsproxy.io/?',
headers: {}
},
allOrigins: {
url: 'https://api.allorigins.win/raw?url=',
headers: {}
},
corsAnywhere: {
url: 'https://cors-anywhere.herokuapp.com/',
headers: {}
},
thingproxy: {
url: 'https://thingproxy.freeboard.io/fetch/',
headers: {}
},
corsProxyBypass: {
url: 'https://api.codetabs.com/v1/proxy?quest=',
headers: {}
},
corsProxyEasy: {
url: 'https://corsproxy.org/?',
headers: {}
},
crossOriginMe: {
url: 'https://crossorigin.me/',
headers: {}
},
corsAnywhere2: {
url: 'https://cors-anywhere.azm.workers.dev/',
headers: {}
},
workersCors: {
url: 'https://workers-cors-proxy.sterlingsaurus.workers.dev/?url=',
headers: {}
},
corsProxyNode: {
url: 'https://cors-proxy.htmldriven.com/?url=',
headers: {}
}
};
// Function to test if clicks are being registered
function setupClickTest() {
console.log("Setting up click test");
document.body.addEventListener('click', function(e) {
console.log(`Click detected at coordinates: (${e.clientX}, ${e.clientY})`);
console.log(`Element clicked:`, e.target);
// Create a visual indicator where the click happened
const marker = document.createElement('div');
marker.style.position = 'absolute';
marker.style.left = (e.clientX - 5) + 'px';
marker.style.top = (e.clientY - 5) + 'px';
marker.style.width = '10px';
marker.style.height = '10px';
marker.style.borderRadius = '50%';
marker.style.backgroundColor = 'red';
marker.style.zIndex = '9999';
document.body.appendChild(marker);
// Remove after 2 seconds
setTimeout(() => {
marker.remove();
}, 2000);
});
}
let currentProxyIndex = 0; // Will start with myCustomProxy
const proxyKeys = Object.keys(PROXY_CONFIGS);
let charts = [];
let allDataGlobal = []; // Store data globally for access across tabs
// Store checked phrases for decoding
const checkedPhrases = new Set();
// Cosmic symbol mappings
const COSMIC_SYMBOLS = {
// Planet symbols and their value ranges
planets: [
{ symbol: '☿', name: 'Mercury', minValue: 1, maxValue: 260, element: '🜁', zodiac: '♊' }, // Mercury
{ symbol: '♀', name: 'Venus', minValue: 261, maxValue: 520, element: '🜃', zodiac: '♉' }, // Venus
{ symbol: '⊕', name: 'Earth', minValue: 521, maxValue: 780, element: '🜃', zodiac: '♍' }, // Earth
{ symbol: '♂', name: 'Mars', minValue: 781, maxValue: 1040, element: '🜂', zodiac: '♈' }, // Mars
{ symbol: '♃', name: 'Jupiter', minValue: 1041, maxValue: 1300, element: '🜂', zodiac: '♐' }, // Jupiter
{ symbol: '♄', name: 'Saturn', minValue: 1301, maxValue: 1560, element: '🜃', zodiac: '♑' }, // Saturn
{ symbol: '♅', name: 'Uranus', minValue: 1561, maxValue: 1820, element: '🜁', zodiac: '♒' }, // Uranus
{ symbol: '♆', name: 'Neptune', minValue: 1821, maxValue: 2080, element: '🜄', zodiac: '♓' }, // Neptune
{ symbol: '♇', name: 'Pluto', minValue: 2081, maxValue: 2340, element: '🜂', zodiac: '♏' }, // Pluto
{ symbol: '☉', name: 'Sun', minValue: 0, maxValue: 120, element: '🜂', zodiac: '♌' }, // Sun (default for low values)
{ symbol: '☽', name: 'Moon', minValue: 121, maxValue: 240, element: '🜄', zodiac: '♋' } // Moon (default for medium values)
],
// Element symbols
elements: [
{ symbol: '🜂', name: 'Fire', values: [1, 4, 7, 10, 13, 16, 19, 22, 25, 28, 31, 34, 37, 40] },
{ symbol: '🜄', name: 'Water', values: [2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35, 38] },
{ symbol: '🜁', name: 'Air', values: [3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39] },
{ symbol: '🜃', name: 'Earth', values: [0, 60, 120, 180, 240, 300, 360, 420, 480, 540, 600] }
],
// Zodiac symbols
zodiac: [
{ symbol: '♈', name: 'Aries', range: [1, 30], element: '🜂' },
{ symbol: '♉', name: 'Taurus', range: [31, 60], element: '🜃' },
{ symbol: '♊', name: 'Gemini', range: [61, 90], element: '🜁' },
{ symbol: '♋', name: 'Cancer', range: [91, 120], element: '🜄' },
{ symbol: '♌', name: 'Leo', range: [121, 150], element: '🜂' },
{ symbol: '♍', name: 'Virgo', range: [151, 180], element: '🜃' },
{ symbol: '♎', name: 'Libra', range: [181, 210], element: '🜁' },
{ symbol: '♏', name: 'Scorpio', range: [211, 240], element: '🜄' },
{ symbol: '♐', name: 'Sagittarius', range: [241, 270], element: '🜂' },
{ symbol: '♑', name: 'Capricorn', range: [271, 300], element: '🜃' },
{ symbol: '♒', name: 'Aquarius', range: [301, 330], element: '🜁' },
{ symbol: '♓', name: 'Pisces', range: [331, 360], element: '🜄' }
]
};
// Function to reduce a number to a single digit (1-9)
function reduceNumber(num) {
if (num === 0) return 0;
return ((num - 1) % 9) + 1;
}
// Function to get cosmic symbols for a value
function getCosmicSymbols(value) {
const numValue = parseInt(value) || 0;
// Get planet symbol
let planetSymbol = COSMIC_SYMBOLS.planets[9].symbol; // Default to Sun
COSMIC_SYMBOLS.planets.forEach(planet => {
if (numValue >= planet.minValue && numValue <= planet.maxValue) {
planetSymbol = planet.symbol;
}
});
// Get element symbol - use modulo to cycle through elements
let elementSymbol = COSMIC_SYMBOLS.elements[numValue % 4].symbol;
// Get zodiac symbol - normalize value to 1-360 range (using modulo)
const zodiacValue = (numValue % 360) || 360; // If 0, use 360
let zodiacSymbol = COSMIC_SYMBOLS.zodiac[0].symbol; // Default to Aries
COSMIC_SYMBOLS.zodiac.forEach(sign => {
if (zodiacValue >= sign.range[0] && zodiacValue <= sign.range[1]) {
zodiacSymbol = sign.symbol;
}
});
return {
planet: planetSymbol,
element: elementSymbol,
zodiac: zodiacSymbol
};
}
// Function to update checked phrases counter display
function updateCheckedCounter() {
const count = checkedPhrases.size;
const counterSpan = document.getElementById('checked-counter');
const counterText = document.getElementById('checked-phrases-count');
// Update the count in the tab button
if (counterSpan) {
counterSpan.textContent = count;
counterSpan.style.display = count > 0 ? 'inline' : 'none';
}
// Update the count in the decode container
if (counterText) {
counterText.textContent = count;
}
// Show/hide the decode container
const decodeContainer = document.getElementById('decode-container');
if (decodeContainer) {
decodeContainer.style.display = count > 0 ? 'block' : 'none';
}
}
// Function to open tabs
function openTab(tabId) {
console.log(`Opening tab: ${tabId}`);
// Hide all tabs
document.querySelectorAll('.tab-content').forEach(tab => {
tab.classList.remove('active');
});
// Remove active class from all buttons
document.querySelectorAll('.tab-btn').forEach(btn => {
btn.classList.remove('active');
});
// Show selected tab
const selectedTab = document.getElementById(tabId);
if (selectedTab) {
selectedTab.classList.add('active');
console.log(`Tab ${tabId} activated`);
} else {
console.error(`Tab ${tabId} not found`);
}
// Add active class to clicked button
const btnSelector = `#btn-${tabId}`;
const tabBtn = document.querySelector(btnSelector);
if (tabBtn) {
tabBtn.classList.add('active');
console.log(`Tab button ${btnSelector} activated`);
} else {
console.error(`Tab button ${btnSelector} not found`);
}
// If opening top values tab after data has been loaded, ensure it's populated
if (tabId === 'top-values-tab' && allDataGlobal.length > 0) {
populateTopValues(allDataGlobal);
}
}
// Toggle accordion
function toggleAccordion(header) {
const content = header.nextElementSibling;
const toggle = header.querySelector('.accordion-toggle');
if (content.classList.contains('active')) {
content.classList.remove('active');
toggle.textContent = '+';
} else {
content.classList.add('active');
toggle.textContent = '−';
}
}
// Search the database
function searchDatabase() {
const searchTerm = document.getElementById('database-search').value.trim().toLowerCase();
const resultsDiv = document.getElementById('database-results');
const helpContentDiv = document.getElementById('help-content');
// Clear previous help content
if (helpContentDiv) {
helpContentDiv.innerHTML = '';
}
if (!searchTerm) {
resultsDiv.innerHTML = "<div class='error'>Please enter a search term</div>";
return;
}
// Special case for "help" search
if (searchTerm === 'help') {
// Display help content from Shematria.com and Shawnomancy.com
if (helpContentDiv) {
helpContentDiv.innerHTML = `
<div class="help-content">
<div class="help-header">Help from Shematria.com</div>
<p>Gematria Calculator Value 120</p>
<p>1844120 visits since August 2019</p>
<p><strong>Biblical Gematria: 120</strong><br>
Reversal Cipher: ootd 153<br>
Genesis Order: 39<br>
Standard Hebrew: 120<br>
Transliteration: ההלף<br>
Letter Count: 4</p>
<p>"One must acknowledge with cryptography no amount of violence will ever solve a math problem." — Jacob Appelbaum.</p>
</div>
<div class="help-content">
<div class="help-header">Help from Shawnomancy.com</div>
<p>Gematria Calculator and Database</p>
<p>JavaScript Required</p>
<p>Questions? See the FAQ.</p>
<p>© 2025 shawnomancy • Built with GeneratePress</p>
</div>
`;
}
resultsDiv.innerHTML = "<div class='match-count'>Found help information from Shematria.com and Shawnomancy.com</div>";
return;
}
// Combine data from different sources
const combinedData = [
// From gematrix.org - most searched
{ word: 'god', jewish: 61, english: 156, simple: 26, searches: 264294, source: 'gematrix' },
{ word: 'devil', jewish: 738, english: 312, simple: 52, searches: 151539, source: 'gematrix' },
{ word: 'my name', jewish: 506, english: 426, simple: 71, searches: 138917, source: 'gematrix' },
{ word: 'jesus', jewish: 985, english: 444, simple: 74, searches: 109539, source: 'gematrix' },
{ word: 'donald trump', jewish: 589, english: 828, simple: 138, searches: 107098, source: 'gematrix' },
{ word: 'mark alan king', jewish: 249, english: 672, simple: 112, searches: 102821, source: 'gematrix' },
{ word: 'xrp', jewish: 440, english: 348, simple: 58, searches: 90894, source: 'gematrix' },
{ word: 'neuralink', jewish: 405, english: 630, simple: 105, searches: 85842, source: 'gematrix' },
{ word: 'elon musk', jewish: 445, english: 660, simple: 110, searches: 84759, source: 'gematrix' },
{ word: 'trump', jewish: 470, english: 528, simple: 88, searches: 79614, source: 'gematrix' },
// From shematria.com - value 120
{ word: 'אלישוע', meaning: 'Elishua, the son of King David', transliteration: 'ALIShVO', biblical: 120, source: 'shematria' },
{ word: 'חזקה', meaning: 'prevailing power', transliteration: 'ChZQH', biblical: 120, source: 'shematria' },
{ word: 'יונתן', meaning: 'Jonathan, the name of ten Israelites', transliteration: 'IVNThN', biblical: 120, source: 'shematria' },
{ word: 'ימיני', meaning: 'right', transliteration: 'IMINI', biblical: 120, source: 'shematria' },
{ word: 'יקהה', meaning: 'obedience', transliteration: 'IQHH', biblical: 120, source: 'shematria' },
{ word: 'יקוד', meaning: 'a burning', transliteration: 'IQVD', biblical: 120, source: 'shematria' },
{ word: 'כמס', meaning: 'to store away', transliteration: 'KMS', biblical: 120, source: 'shematria' },
{ word: 'כנן', meaning: 'to set out, i.e. plant', transliteration: 'KNN', biblical: 120, source: 'shematria' },
{ word: 'כסיל', meaning: 'properly, fat, i.e. (figuratively) stupid or silly', transliteration: 'KSIL', biblical: 120, source: 'shematria' },
{ word: 'מגבעה', meaning: 'a cap (as hemispherical)', transliteration: 'MGBOH', biblical: 120, source: 'shematria' },
// From gematrix.org - latest searched
{ word: 'father watt happens e now here', jewish: 2658, english: 1764, simple: 294, searches: 47, source: 'gematrix' },
{ word: 'sjaac made a billion dollars', jewish: 1151, english: 1272, simple: 212, searches: 5, source: 'gematrix' },
{ word: 'its gonig to be biblical cinderella', jewish: 722, english: 1650, simple: 275, searches: 145, source: 'gematrix' },
{ word: 'abstulerit brevissimas', jewish: 1713, english: 1578, simple: 263, searches: 310, source: 'gematrix' },
{ word: 'was soll ich dir erzählen', jewish: 1942, english: 1446, simple: 241, searches: 63, source: 'gematrix' },
{ word: 'this mindreading bot misreads', jewish: 897, english: 1674, simple: 279, searches: 243, source: 'gematrix' },
{ word: 'the unity of all', jewish: 959, english: 1008, simple: 168, searches: 578, source: 'gematrix' },
{ word: 'iota', jewish: 160, english: 270, simple: 45, searches: 2302, source: 'gematrix' },
{ word: 'planetary alignment', jewish: 959, english: 1242, simple: 207, searches: 581, source: 'gematrix' }
];
// Filter data based on search term
const filteredData = combinedData.filter(item => {
// Search in word
if (item.word && item.word.toLowerCase().includes(searchTerm)) return true;
// Search in meaning if available
if (item.meaning && item.meaning.toLowerCase().includes(searchTerm)) return true;
// Search in transliteration if available
if (item.transliteration && item.transliteration.toLowerCase().includes(searchTerm)) return true;
// Search in numeric values
if (searchTerm.match(/^\d+$/)) {
const numSearchTerm = parseInt(searchTerm);
if (item.jewish === numSearchTerm) return true;
if (item.english === numSearchTerm) return true;
if (item.simple === numSearchTerm) return true;
if (item.biblical === numSearchTerm) return true;
// For approximate searches (within ±10)
const threshold = 10;
if (item.jewish && Math.abs(item.jewish - numSearchTerm) <= threshold) return true;
if (item.english && Math.abs(item.english - numSearchTerm) <= threshold) return true;
if (item.simple && Math.abs(item.simple - numSearchTerm) <= threshold) return true;
if (item.biblical && Math.abs(item.biblical - numSearchTerm) <= threshold) return true;
}
return false;
});
// Display results
if (filteredData.length === 0) {
resultsDiv.innerHTML = `<div class="error">No results found for "${searchTerm}"</div>`;
return;
}
let html = `<h3>Search Results for "${searchTerm}" (${filteredData.length} matches)</h3>`;
// Group results by source
const groupedBySource = {
gematrix: filteredData.filter(item => item.source === 'gematrix'),
shematria: filteredData.filter(item => item.source === 'shematria'),
shawnomancy: filteredData.filter(item => item.source === 'shawnomancy')
};
// Display results by source
Object.keys(groupedBySource).forEach(source => {
const items = groupedBySource[source];
if (items.length === 0) return;
html += `<h4>${getSourceName(source)} (${items.length} results)</h4>`;
items.forEach(item => {
// Get cosmic symbols
let symbols = {};
if (source === 'gematrix' && item.english) {
symbols = getCosmicSymbols(item.english);
} else if (source === 'shematria' && item.biblical) {
symbols = getCosmicSymbols(item.biblical);
} else {
symbols = getCosmicSymbols(0); // Default
}
// Create values object for favoriting
const values = {};
if (source === 'gematrix') {
values.jewish = item.jewish;
values.english = item.english;
values.simple = item.simple;
} else if (source === 'shematria') {
values.biblical = item.biblical;
}
// Generate phrase ID for checking if it's already favorited
const phraseId = MLDatabase.generateId(item.word);
const isFavorited = MLDatabase.favorites[phraseId] !== undefined;
html += `<div class="word-entry">
<div class="word-header">
<div class="controls-container">
<button class="favorite-btn ${isFavorited ? 'active' : ''}"
data-phrase="${item.word}"
data-values='${JSON.stringify(values)}'>
${isFavorited ? '★' : '☆'}
</button>
<input type="checkbox" class="phrase-checkbox" id="phrase_${phraseId}"
data-phrase="${item.word}" ${checkedPhrases.has(item.word) ? 'checked' : ''}>
</div>
<div class="cosmic-symbols">
<span class="planet-symbol">${symbols.planet}</span>
<span class="element-symbol">${symbols.element}</span>
<span class="zodiac-symbol">${symbols.zodiac}</span>
</div>
<span class="source-label source-${source}">${getSourceName(source)}</span>
${item.word}
</div>
<div class="word-values">`;
// Display different values based on source
if (source === 'gematrix') {
html += `
<span class="value-tag">Jewish: ${item.jewish}</span>
<span class="value-tag">English: ${item.english}</span>
<span class="value-tag">Simple: ${item.simple}</span>
<span class="value-tag">Searches: ${item.searches}</span>
`;
} else if (source === 'shematria') {
html += `
<span class="value-tag">Biblical: ${item.biblical}</span>
<span class="value-tag">Transliteration: ${item.transliteration}</span>
`;
if (item.meaning) {
html += `<div><em>${item.meaning}</em></div>`;
}
} else if (source === 'shawnomancy') {
// Add shawnomancy specific values if we had any
html += `<span class="value-tag">Value: ${item.value || 'N/A'}</span>`;
}
html += `</div>
</div>`;
});
});
resultsDiv.innerHTML = html;
// Add event listeners to the newly created favorite buttons and checkboxes
attachFavoriteListeners();
attachCheckboxListeners();
}
// Helper function to get source name
function getSourceName(source) {
switch(source) {
case 'gematrix': return 'Gematrix.org';
case 'shematria': return 'Shematria.com';
case 'shawnomancy': return 'Shawnomancy.com';
default: return 'Unknown';
}
}
// Additional CORS proxies that might work better
const ADDITIONAL_PROXIES = {
corsAnywhere2023: {
url: 'https://cors-anywhere-2023.herokuapp.com/',
headers: {}
},
bypassCors: {
url: 'https://bypasscors.io/api/?url=',
headers: {}
},
zezProxy: {
url: 'https://proxy.zez.am/',
headers: {}
},
devTool: {
url: 'https://cors.devtool.tech/?url=',
headers: {}
},
rapidAPI: {
url: 'https://corsproxy.p.rapidapi.com/?url=',
headers: {
'X-RapidAPI-Key': 'demo-key',
'X-RapidAPI-Host': 'corsproxy.p.rapidapi.com'
}
},
ibrahimaziz: {
url: 'https://ibrahimaziz11.github.io/CORS-Proxy/?',
headers: {}
}
};
// Track if we've already added the additional proxies
let additionalProxiesAdded = false;
async function tryNextProxy(url, attempts = 0) {
// If we're reaching the limit of our current proxies, add more
if (attempts >= proxyKeys.length - 2 && !additionalProxiesAdded) {
// Add the additional proxies to the existing list
Object.entries(ADDITIONAL_PROXIES).forEach(([key, config]) => {
PROXY_CONFIGS[key] = config;
});
// Update the proxy keys
proxyKeys = Object.keys(PROXY_CONFIGS);
additionalProxiesAdded = true;
console.log("Added additional proxies to try", proxyKeys);
}
if (attempts >= proxyKeys.length) {
console.error("All proxies failed!");
return generateFallbackData(url);
}
const proxyKey = proxyKeys[currentProxyIndex];
const proxyConfig = PROXY_CONFIGS[proxyKey];
try {
console.log(`Trying proxy: ${proxyKey}`);
// Special handling for certain proxies
let fetchUrl;
if (proxyKey === 'corsProxyNode') {
// For htmldriven proxy, the URL parameter is different
fetchUrl = `${proxyConfig.url}${encodeURIComponent(url)}`;
} else if (proxyKey === 'corsProxyBypass') {
// For codetabs proxy, use 'quest' parameter
fetchUrl = `${proxyConfig.url}${encodeURIComponent(url)}`;
} else if (proxyKey === 'rapidAPI') {
// For rapidAPI, they use a URL parameter
fetchUrl = `${proxyConfig.url}${encodeURIComponent(url)}`;
} else {
// For most proxies
fetchUrl = proxyConfig.url + encodeURIComponent(url);
}
const response = await fetch(fetchUrl, {
headers: proxyConfig.headers,
// Some proxies need a longer timeout
signal: AbortSignal.timeout(15000)
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const text = await response.text();
console.log(`Proxy ${proxyKey} successful`);
return text;
} catch (error) {
console.log(`Proxy ${proxyKey} failed: ${error.message}`);
currentProxyIndex = (currentProxyIndex + 1) % proxyKeys.length;
return await tryNextProxy(url, attempts + 1);
}
}
// Function to generate fallback data when all proxies fail, with direct link options
function generateFallbackData(url) {
console.log("Generating fallback data for URL:", url);
// Extract query parameters to check if we're searching for a specific word
let searchTerm = "";
let page = 1;
let originalUrl = "";
try {
const parsedUrl = new URL(url);
searchTerm = parsedUrl.searchParams.get('word') || "";
page = parseInt(parsedUrl.searchParams.get('page')) || 1;
// Create direct links to the original sites using the search term
// This approach works because most gematria sites use similar URL patterns
const encodedTerm = encodeURIComponent(searchTerm);
// Generate URLs for various gematria sites
const directLinks = {
gematrix: `https://www.gematrix.org/?word=${encodedTerm}&page=${page}`,
gematrinator: `https://www.gematrinator.com/calculator/index.php?w=${encodedTerm}`,
gematria: `https://gematria.codes/?word=${encodedTerm}`,
gematriaCalculator: `https://www.gematrix.org/gematria-calculator.php?word=${encodedTerm}`,
shematria: `https://shematria.pythonanywhere.com/search/${encodedTerm}`
};
// Store the original parsed URL for reference
originalUrl = url;
} catch (e) {
console.error("Failed to parse URL for fallback data", e);
}
// Generate realistic-looking sample data based on the search term
const sampleData = [];
// Only generate data if we have a search term
if (searchTerm) {
const normalizedTerm = searchTerm.toLowerCase().trim();
const basicValue = calculateALWCipher(normalizedTerm);
const hebrewValue = basicValue * 11;
const englishValue = basicValue * 7;
const simpleValue = Math.floor(basicValue / 3);
// Generate variations based on page number
for (let i = 0; i < 10; i++) {
// Add some variation based on page number
const pageOffset = (page - 1) * 10 + i;
const variationFactor = 0.2 + (Math.random() * 0.8);
const row = [
String(10000 + pageOffset), // ID
String(Math.floor(hebrewValue * variationFactor)),
normalizedTerm + (i > 0 ? ` variation ${i}` : ""), // Term with variation
String(Math.floor(englishValue * variationFactor)),
String(Math.floor(simpleValue * variationFactor))
];
sampleData.push(row);
}
// Add some related terms
const relatedTerms = [
"light", "dark", "divine", "cosmic", "energy", "spirit",
"nature", "sacred", "holy", "mystic", "eternal", "wisdom"
];
for (let i = 0; i < 5; i++) {
if (relatedTerms[i]) {
const relatedTerm = `${relatedTerms[i]} ${normalizedTerm}`;
const relatedValue = calculateALWCipher(relatedTerm);
const row = [
String(20000 + i),
String(Math.floor(relatedValue * 11)),
relatedTerm,
String(Math.floor(relatedValue * 7)),
String(Math.floor(relatedValue / 3))
];
sampleData.push(row);
}
}
}
// Create HTML with direct links to the original sources
// Note: We need to make these direct links since we can't use normal proxies
const directLinkHtml = searchTerm ? `
<div class="direct-links" style="margin:15px 0; padding:15px; border:1px solid #3498db; border-radius:4px; background-color:#ebf5fb;">
<h3 style="margin-top:0; color:#2874a6;">🔗 Try Direct Links</h3>
<p>CORS proxies failed. Click these links to open the search in the original sites:</p>
<div style="display:flex; flex-wrap:wrap; gap:10px; margin-top:10px;">
<a href="https://www.gematrix.org/?word=${encodeURIComponent(searchTerm)}&page=${page}" target="_blank" style="display:inline-block; padding:8px 12px; background:#3498db; color:white; text-decoration:none; border-radius:4px; font-weight:bold;">Gematrix.org</a>
<a href="https://www.gematrinator.com/calculator/index.php?w=${encodeURIComponent(searchTerm)}" target="_blank" style="display:inline-block; padding:8px 12px; background:#2ecc71; color:white; text-decoration:none; border-radius:4px; font-weight:bold;">Gematrinator</a>
<a href="https://gematria.codes/?word=${encodeURIComponent(searchTerm)}" target="_blank" style="display:inline-block; padding:8px 12px; background:#9b59b6; color:white; text-decoration:none; border-radius:4px; font-weight:bold;">Gematria.codes</a>
<a href="https://shematria.pythonanywhere.com/search/${encodeURIComponent(searchTerm)}" target="_blank" style="display:inline-block; padding:8px 12px; background:#e67e22; color:white; text-decoration:none; border-radius:4px; font-weight:bold;">Shematria</a>
</div>
<p style="margin-top:10px; font-size:12px; color:#7f8c8d;">Note: These links will open in a new tab and are not affected by CORS restrictions.</p>
</div>
` : '';
// Create a fake HTML response with the sample data and direct links
const fakeHtml = `
<html>
<body>
<div class="fallback-notice" style="color:#c0392b; padding:15px; margin:15px 0; border:1px solid #c0392b; border-radius:4px; background-color:#fadbd8;">
<h3 style="margin-top:0;">⚠️ CORS Proxy Error</h3>
<p>All proxies are currently unavailable. The data below is algorithmically generated as a fallback.</p>
</div>
${directLinkHtml}
<div class="generated-data">
<h3>Generated Data:</h3>
<table>
<tbody>
${sampleData.map(row => `
<tr>
${row.map(cell => `<td>${cell}</td>`).join('')}
</tr>
`).join('')}
</tbody>
</table>
</div>
<div style="margin-top:20px; padding:10px; border-top:1px solid #ddd;">
<p style="font-size:12px; color:#7f8c8d;">
Original request: ${originalUrl || url}
</p>
</div>
</body>
</html>
`;
return fakeHtml;
}
async function scrapePage(phrase, page) {
const encodedPhrase = encodeURIComponent(phrase);
const url = `https://www.gematrix.org/?word=${encodedPhrase}&page=${page}`;
const html = await tryNextProxy(url);
const parser = new DOMParser();
const doc = parser.parseFromString(html, 'text/html');
let tableData = [];
const tables = doc.querySelectorAll('table');
tables.forEach(table => {
const rows = table.querySelectorAll('tr');
rows.forEach(row => {
const cells = row.querySelectorAll('td');
if (cells.length > 0) {
const rowData = Array.from(cells).map(cell => cell.textContent.trim());
if (rowData.some(text => text.length > 0)) {
tableData.push(rowData);
}
}
});
});
return tableData;
}
// Function to scrape pages for a specific number
async function scrapeForNumber(number, page) {
// Use a dummy phrase that will return general results
const url = `https://www.gematrix.org/?page=${page}`;
const html = await tryNextProxy(url);
const parser = new DOMParser();
const doc = parser.parseFromString(html, 'text/html');
let tableData = [];
const tables = doc.querySelectorAll('table');
tables.forEach(table => {
const rows = table.querySelectorAll('tr');
rows.forEach(row => {
const cells = row.querySelectorAll('td');
if (cells.length > 0) {
const rowData = Array.from(cells).map(cell => cell.textContent.trim());
// Only add rows that contain the number we're looking for
if (rowData.some(cell => cell === number.toString())) {
tableData.push(rowData);
}
}
});
});
return tableData;
}
// Function to extract words from phrases
function extractWords(phrases) {
const words = [];
phrases.forEach(phrase => {
// Skip if the phrase is not a string or is empty
if (typeof phrase !== 'string' || !phrase.trim()) {
return;
}
// Split the phrase into words and add them to the array
const wordsInPhrase = phrase.trim().split(/\s+/);
words.push(...wordsInPhrase);
});
// Remove duplicates and empty strings
return [...new Set(words)].filter(word => word.trim() !== '');
}
// Function to randomize text in a textarea
function randomizeText(elementId) {
console.log(`Randomizing text in ${elementId}`);
const textarea = document.getElementById(elementId);
if (!textarea) {
console.error(`Textarea with id ${elementId} not found`);
return;
}
const words = textarea.value.split(/\s+/).filter(word => word.trim() !== '');
if (words.length === 0) {
return;
}
// Shuffle the array
for (let i = words.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[words[i], words[j]] = [words[j], words[i]];
}
textarea.value = words.join(' ');
}
// Function to clear text in a textarea
function clearText(elementId) {
console.log(`Clearing text in ${elementId}`);
const textarea = document.getElementById(elementId);
if (!textarea) {
console.error(`Textarea with id ${elementId} not found`);
return;
}
textarea.value = '';
}
// Group rows by column value
function groupRowsByColumn(data, columnIndex) {
const groups = {};
data.forEach(row => {
if (row.length > columnIndex) {
const key = row[columnIndex];
if (!groups[key]) {
groups[key] = [];
}
groups[key].push(row);
}
});
return groups;
}
// Clear all charts
function clearCharts() {
const chartsContainer = document.getElementById('charts');
if (!chartsContainer) {
console.error("Charts container not found");
return;
}
chartsContainer.innerHTML = '';
charts.forEach(chart => chart.destroy());
charts = [];
}
// Create chart
function createChart(container, type, data, options) {
const canvas = document.createElement('canvas');
container.appendChild(canvas);
const chart = new Chart(canvas, {
type: type,
data: data,
options: options
});
charts.push(chart);
return chart;
}
// Update progress bar
function updateProgress(current, total, isNumberSearch = false) {
const progressContainer = document.getElementById(isNumberSearch ? 'number-progress-container' : 'progress-container');
const progressBar = document.getElementById(isNumberSearch ? 'number-progress-bar' : 'progress-bar');
if (!progressContainer || !progressBar) {
console.error("Progress container or bar not found");
return;
}
if (current === 0) {
progressContainer.style.display = 'block';
}
const percentage = Math.round((current / total) * 100);
progressBar.style.width = `${percentage}%`;
progressBar.textContent = `${percentage}%`;
if (current === total) {
setTimeout(() => {
progressContainer.style.display = 'none';
}, 1000);
}
}
// Populate top values tab
function populateTopValues(allData) {
const topValuesContainer = document.getElementById('top-values-container');
if (!topValuesContainer) {
console.error("Top values container not found");
return;
}
// Flatten all data
const flatData = [].concat(...allData);
// Count values and associated words for each column
const valueWords = {};
flatData.forEach(row => {
// Skip rows that don't have enough data
if (row.length < 3) return;
// Process each numeric column
for (let i = 0; i < row.length; i++) {
// Skip the phrase column (usually index 2)
if (i === 2) continue;
const value = row[i];
const phrase = row[2] || ''; // Use the phrase from column 3 if available
// Skip if not a number or phrase is empty
if (isNaN(parseInt(value)) || !phrase.trim()) continue;
// Initialize if not exists
if (!valueWords[i]) {
valueWords[i] = {};
}
if (!valueWords[i][value]) {
valueWords[i][value] = {
count: 0,
phrases: new Set()
};
}
valueWords[i][value].count++;
valueWords[i][value].phrases.add(phrase);
}
});
// Get top 10 values from all columns
const topValues = [];
Object.keys(valueWords).forEach(columnIndex => {
const column = valueWords[columnIndex];
// Sort values by count
const sortedValues = Object.keys(column).sort((a, b) =>
column[b].count - column[a].count
);
// Add top values to the list
sortedValues.slice(0, 10).forEach(value => {
if (!topValues.includes(value)) {
topValues.push(value);
}
});
});
// Limit to top 10
const finalTopValues = topValues.slice(0, 10);
// Create HTML for top values
let html = '';
finalTopValues.forEach((value, index) => {
// Collect all words for this value from all columns
const allPhrases = new Set();
Object.keys(valueWords).forEach(columnIndex => {
if (valueWords[columnIndex][value]) {
valueWords[columnIndex][value].phrases.forEach(phrase => {
allPhrases.add(phrase);
});
}
});
// Convert phrases to words
const allWords = extractWords(Array.from(allPhrases));
// Get cosmic symbols
const symbols = getCosmicSymbols(value);
html += `
<div class="value-box">
<div class="value-header">
<div class="cosmic-symbols">
<span class="planet-symbol">${symbols.planet}</span>
<span class="element-symbol">${symbols.element}</span>
<span class="zodiac-symbol">${symbols.zodiac}</span>
</div>
Value ${index + 1}: ${value} (${allPhrases.size} phrases)
</div>
<div class="value-input-group">
<textarea id="value-words-${index}" placeholder="No words found for this value">${allWords.join(' ')}</textarea>
<button type="button" id="randomize-value-${index}">Randomize</button>
</div>
</div>
`;
});
// If no values found
if (finalTopValues.length === 0) {
html = '<div class="error">No numeric values found in the data</div>';
}
topValuesContainer.innerHTML = html;
// Add event listeners to the new randomize buttons
finalTopValues.forEach((value, index) => {
const randomizeBtn = document.getElementById(`randomize-value-${index}`);
if (randomizeBtn) {
randomizeBtn.addEventListener('click', function() {
console.log(`Randomizing value ${value}`);
randomizeText(`value-words-${index}`);
});
}
});
}
// Define runes, plants and animals for each number
const EXTENDED_SYMBOLS = {
runes: [
'ᚠ', 'ᚢ', 'ᚦ', 'ᚨ', 'ᚱ', 'ᚲ', 'ᚷ', 'ᚹ', 'ᚺ', 'ᚾ', // 0-9
'ᛁ', 'ᛃ', 'ᛇ', 'ᛈ', 'ᛉ', 'ᛊ', 'ᛏ', 'ᛒ', 'ᛖ', 'ᛗ', // 10-19
'ᛚ', 'ᛜ', 'ᛞ', 'ᛟ', 'ᛠ', 'ᛡ', 'ᛢ', 'ᛣ', 'ᛤ', 'ᛥ', // 20-29
'ᛦ', 'ᛧ', 'ᛨ', 'ᛩ', 'ᛪ', 'ᛮ', 'ᛯ', 'ᛰ', 'ᚤ', 'ᚥ', // 30-39
],
plants: [
'🌱', '🌲', '🌳', '🌴', '🌵', '🌷', '🌸', '🌹', '🌺', '🌻', // 0-9
'🌼', '🌽', '🌾', '🌿', '🍀', '🍁', '🍂', '🍃', '🍄', '🍅', // 10-19
'🍆', '🍇', '🍈', '🍉', '🍊', '🍋', '🍌', '🍍', '🍎', '🍏', // 20-29
'🍐', '🍑', '🍒', '🍓', '🥑', '🥝', '🍅', '🥥', '🌰', '🥜', // 30-39
],
animals: [
'🐺', '🦊', '🦁', '🐯', '🐆', '🐴', '🦄', '🐮', '🐷', '🐗', // 0-9
'🐭', '🐹', '🐰', '🦇', '🐻', '🐨', '🐼', '🦘', '🦡', '🐾', // 10-19
'🦅', '🦉', '🦜', '🕊️', '🦢', '🦚', '🦃', '🐓', '🐦', '🐧', // 20-29
'🐢', '🐍', '🦎', '🦖', '🦕', '🐙', '🦑', '🦐', '🦞', '🦀', // 30-39
]
};
// Function to check if a number is an angel number (e.g., 111, 222, 333, 1212, etc.)
function isAngelNumber(number) {
const numStr = number.toString();
// Check for repeating digits (e.g., 111, 222, 333, etc.)
if (/^(\d)\1+$/.test(numStr)) return true;
// Check for patterns like 1212, 2323, etc.
if (numStr.length >= 4) {
const pattern = numStr.substring(0, 2);
const regex = new RegExp(`^(${pattern})+$`);
if (regex.test(numStr)) return true;
}
// Check for sequences like 1234, 5678, etc.
if (numStr.length >= 3) {
let isSequential = true;
for (let i = 1; i < numStr.length; i++) {
if (parseInt(numStr[i]) !== parseInt(numStr[i-1]) + 1) {
isSequential = false;
break;
}
}
if (isSequential) return true;
}
// Check for specific angel numbers
const angelNumbers = [111, 222, 333, 444, 555, 666, 777, 888, 999,
1111, 2222, 3333, 4444, 5555, 6666, 7777, 8888, 9999,
1212, 1221, 1234, 4321, 2323, 3232, 1010, 1001];
if (angelNumbers.includes(parseInt(numStr))) return true;
return false;
}
// Function to check if a number is a mirror/palindrome number
function isMirrorNumber(number) {
const numStr = number.toString();
const reversed = numStr.split('').reverse().join('');
return numStr === reversed && numStr.length > 1;
}
// Get the extended symbol set for a value
function getExtendedSymbols(value) {
const num = parseInt(value) || 0;
const reduced = reduceNumber(num);
return {
rune: EXTENDED_SYMBOLS.runes[reduced] || EXTENDED_SYMBOLS.runes[0],
plant: EXTENDED_SYMBOLS.plants[reduced] || EXTENDED_SYMBOLS.plants[0],
animal: EXTENDED_SYMBOLS.animals[reduced] || EXTENDED_SYMBOLS.animals[0]
};
}
// Process extracted data and update the UI
function processAndDisplayData(allData) {
// Store data globally
allDataGlobal = allData;
let resultsHTML = '';
// Process rows to ensure consistent format with 5 columns
const processedData = [];
allData.forEach(pageData => {
pageData.forEach(row => {
if (row.length >= 3) {
// Make a copy to avoid modifying the original
const processedRow = [...row];
// Assuming: column 0 = ID, column 1 = Hebrew, column 2 = Phrase, column 3 = English, column 4 = Simple
const phrase = processedRow[2];
if (phrase) {
// Ensure row has exactly 5 columns in correct order
// ID, Hebrew, Phrase, English, Simple
if (processedRow.length < 5) {
// Add missing columns
while (processedRow.length < 5) {
processedRow.push("0");
}
} else if (processedRow.length > 5) {
// Trim to just 5 columns
processedRow.length = 5;
}
// Add to processed data
processedData.push(processedRow);
}
}
});
});
// Initialize arrays to collect phrases
const hebrewPhrases = [];
const englishPhrases = [];
// Collect phrases from processed data
processedData.forEach(row => {
if (row.length >= 3 && row[2]) {
// Check if phrase contains Hebrew characters
if (/[\u0590-\u05FF]/.test(row[2])) {
hebrewPhrases.push(row[2]);
} else {
englishPhrases.push(row[2]);
}
}
});
// Extract all words from all phrases, filtering out numbers
const allWords = [
...extractWords(hebrewPhrases),
...extractWords(englishPhrases)
].filter(word => isNaN(Number(word)));
// Update textarea in the randomizer tab
const allWordsTextArea = document.getElementById('all-words');
if (allWordsTextArea) {
allWordsTextArea.value = allWords.join(' ');
}
// Create charts
clearCharts();
const chartsContainer = document.getElementById('charts');
if (!chartsContainer) {
console.error("Charts container not found");
return "<div class='error'>Charts container not found</div>";
}
// Value distribution chart
const chartDiv1 = document.createElement('div');
chartDiv1.className = 'chart-item';
chartsContainer.appendChild(chartDiv1);
// Count occurrences of each value
const valueCountMap = {};
allData.forEach(pageData => {
pageData.forEach(row => {
if (row.length >= 2 && !isNaN(parseInt(row[1]))) {
const value = parseInt(row[1]);
valueCountMap[value] = (valueCountMap[value] || 0) + 1;
}
});
});
// Sort values for chart
const sortedValues = Object.keys(valueCountMap).sort((a, b) => parseInt(a) - parseInt(b));
// Create value distribution chart
createChart(chartDiv1, 'bar', {
labels: sortedValues,
datasets: [{
label: 'Value Frequency',
data: sortedValues.map(val => valueCountMap[val]),
backgroundColor: 'rgba(76, 175, 80, 0.5)',
borderColor: 'rgba(76, 175, 80, 1)',
borderWidth: 1
}]
}, {
responsive: true,
plugins: {
title: {
display: true,
text: 'Gematria Value Distribution'
}
},
scales: {
y: {
beginAtZero: true
}
}
});
// Implement cipher analysis
// Calculate letter frequencies for English analysis
const letterFrequencies = {};
englishPhrases.forEach(phrase => {
phrase.toLowerCase().split('').forEach(char => {
if (/[a-z]/.test(char)) {
letterFrequencies[char] = (letterFrequencies[char] || 0) + 1;
}
});
});
// Get total letter count for percentage calculations
const totalLetters = Object.values(letterFrequencies).reduce((sum, count) => sum + count, 0);
// Calculate letter frequency percentages
const letterPercentages = {};
Object.keys(letterFrequencies).forEach(letter => {
letterPercentages[letter] = (letterFrequencies[letter] / totalLetters * 100).toFixed(2);
});
// Create letter frequency chart
const chartDiv2 = document.createElement('div');
chartDiv2.className = 'chart-item';
chartsContainer.appendChild(chartDiv2);
const letters = Object.keys(letterPercentages).sort();
createChart(chartDiv2, 'bar', {
labels: letters,
datasets: [{
label: 'Letter Frequency (%)',
data: letters.map(letter => letterPercentages[letter]),
backgroundColor: 'rgba(33, 150, 243, 0.5)',
borderColor: 'rgba(33, 150, 243, 1)',
borderWidth: 1
}]
}, {
responsive: true,
plugins: {
title: {
display: true,
text: 'Letter Frequency Analysis'
}
}
});
// Get the top 3 most frequent numbers
const topNumbers = Object.keys(valueCountMap)
.sort((a, b) => valueCountMap[b] - valueCountMap[a])
.slice(0, 3);
// Removed the Top 3 Most Frequent Numbers chart as requested
// Count planet and element frequencies
const planetCounts = {};
const elementCounts = {};
// Collect all values from the data
const allValues = [];
allData.forEach(pageData => {
pageData.forEach(row => {
row.forEach(cell => {
if (!isNaN(parseInt(cell))) {
allValues.push(parseInt(cell));
}
});
});
});
// Count occurrences of planets and elements
allValues.forEach(value => {
const symbols = getCosmicSymbols(value);
// Count planets
planetCounts[symbols.planet] = (planetCounts[symbols.planet] || 0) + 1;
// Count elements
elementCounts[symbols.element] = (elementCounts[symbols.element] || 0) + 1;
});
// Get the most common planet and its name
const mostCommonPlanet = Object.keys(planetCounts)
.sort((a, b) => planetCounts[b] - planetCounts[a])[0];
const mostCommonPlanetName = COSMIC_SYMBOLS.planets.find(
planet => planet.symbol === mostCommonPlanet
)?.name || 'Unknown';
// Get the most common element and its name
const mostCommonElement = Object.keys(elementCounts)
.sort((a, b) => elementCounts[b] - elementCounts[a])[0];
const elementNames = {
'🜂': 'Fire',
'🜄': 'Water',
'🜁': 'Air',
'🜃': 'Earth'
};
const mostCommonElementName = elementNames[mostCommonElement] || 'Unknown';
// Create a chart showing the most common planet and element
const chartDiv4 = document.createElement('div');
chartDiv4.className = 'chart-item';
chartsContainer.appendChild(chartDiv4);
createChart(chartDiv4, 'bar', {
labels: ['Planet: ' + mostCommonPlanetName, 'Element: ' + mostCommonElementName],
datasets: [{
label: 'Frequency',
data: [
planetCounts[mostCommonPlanet],
elementCounts[mostCommonElement]
],
backgroundColor: [
'rgba(156, 39, 176, 0.5)', // Purple for planets
mostCommonElement === '🜂' ? 'rgba(233, 30, 99, 0.5)' : // Red for fire
mostCommonElement === '🜄' ? 'rgba(33, 150, 243, 0.5)' : // Blue for water
mostCommonElement === '🜁' ? 'rgba(255, 193, 7, 0.5)' : // Yellow for air
'rgba(76, 175, 80, 0.5)' // Green for earth
],
borderColor: [
'rgba(156, 39, 176, 1)', // Purple for planets
mostCommonElement === '🜂' ? 'rgba(233, 30, 99, 1)' : // Red for fire
mostCommonElement === '🜄' ? 'rgba(33, 150, 243, 1)' : // Blue for water
mostCommonElement === '🜁' ? 'rgba(255, 193, 7, 1)' : // Yellow for air
'rgba(76, 175, 80, 1)' // Green for earth
],
borderWidth: 1
}]
}, {
responsive: true,
plugins: {
title: {
display: true,
text: 'Most Common Planet & Element'
}
}
});
// Populate top values tab
populateTopValues(allData);
// Group data by column value across all pages
const columnGroups = {};
const maxColumns = 4; // We'll check the first 4 columns
// Initialize column arrays
for (let i = 0; i < maxColumns; i++) {
columnGroups[i] = {};
}
// Process all data to group by column values
allData.forEach(pageData => {
pageData.forEach(row => {
for (let i = 0; i < Math.min(maxColumns, row.length); i++) {
const value = row[i];
if (!value) continue;
if (!columnGroups[i][value]) {
columnGroups[i][value] = [];
}
// Check if this row is already in the group (avoid duplicates)
const isDuplicate = columnGroups[i][value].some(existingRow => {
// Compare based on the phrase (typically in column 2)
return existingRow[2] === row[2];
});
if (!isDuplicate) {
columnGroups[i][value].push(row);
}
}
});
});
// Render grouped results
// Combine all data into a single flat list
const allRows = [];
// Loop through all columns but focus on main data columns
for (let columnIndex = 0; columnIndex < maxColumns; columnIndex++) {
const groups = columnGroups[columnIndex];
// Skip empty columns
if (Object.keys(groups).length === 0) continue;
// Add all rows to the flat list with their column index for reference
Object.keys(groups).forEach(key => {
if (groups[key].length > 0) {
groups[key].forEach(row => {
allRows.push({
row,
columnIndex,
value: key
});
});
}
});
}
// Find similar numbers section is removed from here
// Now display all rows in a single table with enhanced mystical symbols
if (allRows.length > 0) {
resultsHTML += `
<table class="data-table">
<tbody>
${allRows.map(item => {
return `<tr>
${item.row.map((cell, cellIndex) => {
if (!isNaN(parseInt(cell))) {
// Get symbols and reduced value for cell shading
const symbols = getCosmicSymbols(cell);
const extended = getExtendedSymbols(cell);
const reducedValue = reduceNumber(parseInt(cell));
// Determine element type for coloring
const elementClassName =
symbols.element === '🜂' ? 'fire' :
symbols.element === '🜄' ? 'water' :
symbols.element === '🜁' ? 'air' :
symbols.element === '🜃' ? 'earth' : '';
// Check for special number types
const specialClass =
isAngelNumber(cell) ? 'angel-number' :
isMirrorNumber(cell) ? 'mirror-number' : '';
return `<td class="num-cell ${specialClass} num-cell-${reducedValue}">
<span class="cell-number number-${reducedValue}">${cell}</span>
<div class="cosmic-symbols">
<span class="planet-symbol">${symbols.planet}</span>
<span class="element-symbol ${elementClassName}">${symbols.element}</span>
<span class="zodiac-symbol">${symbols.zodiac}</span>
<span class="rune-symbol">${extended.rune}</span>
</div>
</td>`;
} else if (cellIndex === 2) { // This is a phrase column
// Check if the cell contains words related to angel numbers or mirror numbers
const phrase = cell;
const wordsToCheck = ["angel", "mirror", "divine", "sacred", "master", "magic"];
const lowercaseCell = cell.toLowerCase();
// Create values for favoriting
const values = {};
for (let i = 0; i < item.row.length; i++) {
if (i !== 2 && !isNaN(parseInt(item.row[i]))) {
if (i === 1) values.jewish = item.row[i];
else if (i === 3) values.english = item.row[i];
else if (i === 4) values.simple = item.row[i];
else values[`column${i}`] = item.row[i];
}
}
// Generate phrase ID for checking if it's already favorited
const phraseId = MLDatabase.generateId(phrase);
const isFavorited = MLDatabase.favorites[phraseId] !== undefined;
// Check if this phrase is already in the checked set
const isChecked = checkedPhrases.has(phrase);
const specialClass = wordsToCheck.some(word => lowercaseCell.includes(word)) ?
'special-phrase' : '';
return `<td>
<div style="display: flex; align-items: center;">
<div class="controls-container">
<button class="favorite-btn ${isFavorited ? 'active' : ''}"
data-phrase="${phrase.replace(/"/g, '&quot;')}"
data-values='${JSON.stringify(values)}'>
${isFavorited ? '★' : '☆'}
</button>
<input type="checkbox" class="phrase-checkbox" id="phrase_${phraseId}"
data-phrase="${phrase.replace(/"/g, '&quot;')}" ${isChecked ? 'checked' : ''}>
</div>
<span class="${specialClass}">${phrase}</span>
</div>
</td>`;
} else {
return `<td>${cell}</td>`;
}
}).join('')}
</tr>`;
}).join('')}
</tbody>
</table>
`;
}
// Add mystical numerology chart
const chartDiv5 = document.createElement('div');
chartDiv5.className = 'chart-item';
chartsContainer.appendChild(chartDiv5);
// Count angel numbers and mirror numbers
let angelNumberCount = 0;
let mirrorNumberCount = 0;
let otherNumberCount = 0;
allValues.forEach(value => {
if (isAngelNumber(value)) {
angelNumberCount++;
} else if (isMirrorNumber(value)) {
mirrorNumberCount++;
} else {
otherNumberCount++;
}
});
createChart(chartDiv5, 'pie', {
labels: ['Angel Numbers', 'Mirror Numbers', 'Other Numbers'],
datasets: [{
data: [angelNumberCount, mirrorNumberCount, otherNumberCount],
backgroundColor: [
'rgba(255, 223, 0, 0.6)',
'rgba(147, 112, 219, 0.6)',
'rgba(128, 128, 128, 0.3)'
],
borderColor: [
'rgba(255, 223, 0, 1)',
'rgba(147, 112, 219, 1)',
'rgba(128, 128, 128, 1)'
],
borderWidth: 1
}]
}, {
responsive: true,
plugins: {
title: {
display: true,
text: 'Mystical Number Distribution'
}
}
});
// Add element distribution radar chart
const chartDiv6 = document.createElement('div');
chartDiv6.className = 'chart-item';
chartsContainer.appendChild(chartDiv6);
const elementLabels = Object.keys(elementCounts);
createChart(chartDiv6, 'radar', {
labels: elementLabels.map(symbol => {
return elementNames[symbol] || 'Unknown';
}),
datasets: [{
label: 'Element Frequency',
data: elementLabels.map(key => elementCounts[key]),
backgroundColor: 'rgba(255, 99, 132, 0.2)',
borderColor: 'rgba(255, 99, 132, 1)',
borderWidth: 2,
pointBackgroundColor: elementLabels.map(symbol => {
return symbol === '🜂' ? 'rgba(233, 30, 99, 1)' : // Red for fire
symbol === '🜄' ? 'rgba(33, 150, 243, 1)' : // Blue for water
symbol === '🜁' ? 'rgba(255, 193, 7, 1)' : // Yellow for air
'rgba(76, 175, 80, 1)'; // Green for earth
})
}]
}, {
responsive: true,
scale: {
ticks: {
beginAtZero: true
}
},
plugins: {
title: {
display: true,
text: 'Elemental Energy Distribution'
}
}
});
// Find similar numbers (grouped by digital root)
const numbersByRoot = {};
allValues.forEach(value => {
const root = reduceNumber(value);
if (!numbersByRoot[root]) {
numbersByRoot[root] = [];
}
if (!numbersByRoot[root].includes(value)) {
numbersByRoot[root].push(value);
}
});
// Sort by frequency within each root group
Object.keys(numbersByRoot).forEach(root => {
numbersByRoot[root].sort((a, b) => {
const countA = valueCountMap[a] || 0;
const countB = valueCountMap[b] || 0;
return countB - countA;
});
});
// Find groups with most occurrences
const sortedRoots = Object.keys(numbersByRoot)
.sort((a, b) => numbersByRoot[b].length - numbersByRoot[a].length)
.slice(0, 3);
// Removed the similar numbers section to clean up the UI
// Display raw page data - but make it collapsible
resultsHTML += '<h3>Raw Page Data</h3>';
// Split pages into visible and collapsed
const visiblePages = allData.slice(0, 5);
const collapsedPages = allData.slice(5);
// Display visible pages in a clean, simple spreadsheet format
visiblePages.forEach((pageData, index) => {
resultsHTML += `
<div class="page-results">
<div class="page-header">Page ${index + 1}</div>
<table class="data-table">
<thead>
<tr>
<th>ID</th>
<th>Hebrew</th>
<th>Phrase</th>
<th>English</th>
<th>Simple</th>
</tr>
</thead>
<tbody>
${pageData.map(row => {
// Make sure row has exactly 5 columns
const processedRow = [...row];
if (processedRow.length < 5) {
while (processedRow.length < 5) {
processedRow.push("0");
}
} else if (processedRow.length > 5) {
processedRow.length = 5;
}
// Find the phrase (in column 2)
const phrase = processedRow[2];
// Generate ID for favoriting
const phraseId = phrase ? MLDatabase.generateId(phrase) : '';
const isFavorited = phrase && MLDatabase.favorites[phraseId] !== undefined;
const isChecked = phrase && checkedPhrases.has(phrase);
// Create values for favoriting
const values = {};
if (processedRow[1]) values.jewish = processedRow[1];
if (processedRow[3]) values.english = processedRow[3];
if (processedRow[4]) values.simple = processedRow[4];
return `<tr>
<td>${processedRow[0]}</td>
<td>${processedRow[1]}</td>
<td>${phrase || ''}</td>
<td>${processedRow[3]}</td>
<td>${processedRow[4]}</td>
</tr>`;
}).join('')}
</tbody>
</table>
</div>
`;
});
// Add collapsible section for remaining pages
if (collapsedPages.length > 0) {
resultsHTML += `
<div class="collapsible">
<div class="collapsible-header">
<span>Show ${collapsedPages.length} More Pages</span>
<span class="accordion-toggle">+</span>
</div>
<div class="collapsible-content">
`;
collapsedPages.forEach((pageData, index) => {
resultsHTML += `
<div class="page-results">
<div class="page-header">Page ${index + 5 + 1}</div>
<table class="data-table">
<tbody>
${pageData.map(row => {
// Add ALW cipher values based on the Book of the Law
let alwValue = 0;
// Find the phrase in the row (which is in column 2)
const phrase = row[2];
if (phrase && typeof phrase === 'string') {
alwValue = calculateBookOfLawCipher(phrase);
// Add ALW value to the row if it doesn't exist (as 5th column)
if (row.length <= 4) {
row.push(alwValue.toString());
}
}
return `<tr>${row.map((cell, cellIndex) => {
if (!isNaN(parseInt(cell))) {
// Add cosmic symbols with enhanced display for numeric values
const symbols = getCosmicSymbols(cell);
const extended = getExtendedSymbols(cell);
const reducedValue = reduceNumber(parseInt(cell));
// Determine element type for coloring
const elementClassName =
symbols.element === '🜂' ? 'fire' :
symbols.element === '🜄' ? 'water' :
symbols.element === '🜁' ? 'air' :
symbols.element === '🜃' ? 'earth' : '';
// Check for special number types
const specialClass =
isAngelNumber(cell) ? 'angel-number' :
isMirrorNumber(cell) ? 'mirror-number' : '';
// Special styling for cipher columns
const cipherClass =
cellIndex === 5 ? 'alw-cipher' :
cellIndex === 6 ? 'prime-cipher' : '';
// Add cipher badge if applicable
const cipherBadge =
cellIndex === 5 ? '<span class="cipher-badge alw">ALW</span>' :
cellIndex === 6 ? '<span class="cipher-badge caesar">PRIME</span>' : '';
return `<td class="num-cell ${specialClass} num-cell-${reducedValue} ${cipherClass}" style="padding: 2px;">
<span class="cell-number number-${reducedValue}">${cell}</span>
${cipherBadge}
<div class="cosmic-symbols">
<span class="planet-symbol">${symbols.planet}</span>
<span class="element-symbol ${elementClassName}">${symbols.element}</span>
<span class="zodiac-symbol">${symbols.zodiac}</span>
</div>
</td>`;
} else if (cellIndex === 2) { // This is a phrase column
// Check if the cell contains words related to angel numbers or mirror numbers
const phrase = cell;
const wordsToCheck = ["angel", "mirror", "divine", "sacred", "master", "magic"];
const lowercaseCell = cell.toLowerCase();
// Create values for favoriting
const values = {};
for (let i = 0; i < row.length; i++) {
if (i !== 2 && !isNaN(parseInt(row[i]))) {
if (i === 1) values.jewish = row[i];
else if (i === 3) values.english = row[i];
else if (i === 4) values.simple = row[i];
else if (i === 5) values.alw = row[i];
else if (i === 6) values.prime = row[i];
else values[`column${i}`] = row[i];
}
}
// Generate phrase ID for checking if it's already favorited
const phraseId = MLDatabase.generateId(phrase);
const isFavorited = MLDatabase.favorites[phraseId] !== undefined;
// Check if this phrase is already in the checked set
const isChecked = checkedPhrases.has(phrase);
const specialClass = wordsToCheck.some(word => lowercaseCell.includes(word)) ?
'special-phrase' : '';
return `<td>
<div style="display: flex; align-items: center;">
<div class="controls-container">
<button class="favorite-btn ${isFavorited ? 'active' : ''}"
data-phrase="${phrase.replace(/"/g, '&quot;')}"
data-values='${JSON.stringify(values)}'>
${isFavorited ? '★' : '☆'}
</button>
<input type="checkbox" class="phrase-checkbox" id="phrase_${phraseId}"
data-phrase="${phrase.replace(/"/g, '&quot;')}" ${isChecked ? 'checked' : ''}>
</div>
<span class="${specialClass}">${phrase}</span>
</div>
</td>`;
} else {
return `<td>${cell}</td>`;
}
}).join('')}</tr>`;
}).join('')}
</tbody>
</table>
</div>
`;
});
resultsHTML += `
</div>
</div>
`;
}
// Attach event listeners after rendering
setTimeout(() => {
attachFavoriteListeners();
attachCheckboxListeners();
}, 100);
return resultsHTML;
}
// Attach event listeners to favorite buttons
function attachFavoriteListeners() {
document.querySelectorAll('.favorite-btn').forEach(button => {
// Remove existing event listeners
const newButton = button.cloneNode(true);
button.parentNode.replaceChild(newButton, button);
newButton.addEventListener('click', function() {
console.log("Favorite button clicked");
const phrase = this.dataset.phrase;
const values = JSON.parse(this.dataset.values || '{}');
const isFavorite = this.classList.contains('active');
if (isFavorite) {
// Remove from favorites
this.textContent = '☆';
this.classList.remove('active');
const id = MLDatabase.generateId(phrase);
MLDatabase.removeFavorite(id);
} else {
// Add to favorites
this.textContent = '★';
this.classList.add('active');
MLDatabase.addFavorite(phrase, values);
}
// Update recommendations
updateMLRecommendations();
// Update all other instances of this favorite button
const phraseId = MLDatabase.generateId(phrase);
const isFavorited = !isFavorite;
document.querySelectorAll(`.favorite-btn[data-phrase="${phrase.replace(/"/g, '&quot;')}"]`).forEach(btn => {
if (btn !== this) {
btn.textContent = isFavorited ? '★' : '☆';
if (isFavorited) {
btn.classList.add('active');
} else {
btn.classList.remove('active');
}
}
});
});
});
}
// Attach event listeners to checkboxes for decoding
function attachCheckboxListeners() {
document.querySelectorAll('.phrase-checkbox').forEach(checkbox => {
// Remove existing event listeners
const newCheckbox = checkbox.cloneNode(true);
checkbox.parentNode.replaceChild(newCheckbox, checkbox);
// Check if this checkbox should be checked from our global set
const phrase = newCheckbox.dataset.phrase;
if (checkedPhrases.has(phrase)) {
newCheckbox.checked = true;
}
newCheckbox.addEventListener('change', function() {
console.log("Checkbox changed");
const phrase = this.dataset.phrase;
if (this.checked) {
// Add to checked phrases
checkedPhrases.add(phrase);
} else {
// Remove from checked phrases
checkedPhrases.delete(phrase);
}
// Update the counter
updateCheckedCounter();
// Update all checkboxes with this phrase
document.querySelectorAll(`.phrase-checkbox[data-phrase="${phrase.replace(/"/g, '&quot;')}"]`).forEach(cb => {
if (cb !== this) {
cb.checked = this.checked;
}
});
});
});
}
// Function to decode selected phrases
function decodeSelectedPhrases() {
console.log(`Decoding ${checkedPhrases.size} phrases`);
const decodedResultsDiv = document.getElementById('decoded-results');
if (checkedPhrases.size === 0) {
decodedResultsDiv.innerHTML = "<div class='error'>No phrases selected for decoding</div>";
return;
}
const decodedResults = Array.from(checkedPhrases).map(phrase => {
const decoded = customDecode(phrase);
const cipherAnalysis = analyzeCiphers(phrase);
return {
original: phrase,
decoded: decoded,
confidence: cipherAnalysis.confidence.toFixed(1),
type: cipherAnalysis.type,
abbr: cipherAnalysis.abbr
};
});
let html = `<h3>Decoded ${decodedResults.length} Phrases</h3>`;
decodedResults.forEach((result, index) => {
const elementClassName = result.type === 'atbash' ? 'atbash' :
result.type === 'caesar' ? 'caesar' :
result.type === 'a1z26' ? 'a1z26' :
result.type === 'reverse' ? 'reverse' :
result.type === 'ordinal' ? 'ordinal' : '';
html += `
<div class="value-box">
<div class="value-header">
<span class="cipher-badge ${elementClassName}">${result.abbr}</span>
<span class="cipher-percentage">${result.confidence}%</span>
Original Phrase ${index + 1}
</div>
<p>${result.original}</p>
<div class="value-header">Decoded Result:</div>
<p>${result.decoded}</p>
</div>
`;
});
decodedResultsDiv.innerHTML = html;
// Switch to the decoded tab
openTab('decoded-tab');
}
async function scrapeMultiplePages() {
console.log("Starting scrape multiple pages");
const phraseInput = document.getElementById('word');
const resultsDiv = document.getElementById('results');
if (!phraseInput || !resultsDiv) {
console.error("Phrase input or results div not found");
return;
}
const phrase = phraseInput.value.trim();
if (!phrase) {
resultsDiv.innerHTML = "<div class='error'>Please enter a phrase</div>";
return;
}
resultsDiv.innerHTML = '<div class="loading">Analyzing 10 pages...</div>';
updateProgress(0, 10);
try {
const allData = [];
// Scrape 10 pages sequentially with progress updates
for (let i = 1; i <= 10; i++) {
console.log(`Scraping page ${i}...`);
const pageData = await scrapePage(phrase, i);
allData.push(pageData);
updateProgress(i, 10);
}
console.log("All pages scraped, processing data...");
// Process and display the data
resultsDiv.innerHTML = processAndDisplayData(allData);
} catch (error) {
console.error("Error during scraping:", error);
resultsDiv.innerHTML = `
<div class="error">
Error: ${error.message}<br>
Please try again or select a different proxy.
</div>
`;
}
}
// Search for a specific number across multiple pages
async function searchByNumber() {
const searchNumberInput = document.getElementById('search-number');
const resultsDiv = document.getElementById('number-results');
if (!searchNumberInput || !resultsDiv) {
console.error("Search number input or results div not found");
return;
}
const searchNumber = searchNumberInput.value.trim();
if (!searchNumber || isNaN(parseInt(searchNumber))) {
resultsDiv.innerHTML = "<div class='error'>Please enter a valid number</div>";
return;
}
resultsDiv.innerHTML = '<div class="loading">Searching for number ' + searchNumber + ' across 10 pages...</div>';
updateProgress(0, 10, true);
try {
let allMatches = [];
// Search 10 pages sequentially with progress updates
for (let i = 1; i <= 10; i++) {
console.log(`Searching for number ${searchNumber} on page ${i}`);
const matches = await scrapeForNumber(searchNumber, i);
allMatches = [...allMatches, ...matches];
updateProgress(i, 10, true);
}
// Process and display the matches
if (allMatches.length === 0) {
resultsDiv.innerHTML = `<div class="error">No matches found for number ${searchNumber}</div>`;
return;
}
// Group matches by column position
const matchesByColumn = {};
const maxColumns = 4; // We'll check the first 4 columns
// Initialize column arrays
for (let i = 0; i < maxColumns; i++) {
matchesByColumn[i] = [];
}
// Group the matches by which column contains the search number
allMatches.forEach(row => {
const data = row.data || row;
for (let i = 0; i < Math.min(maxColumns, data.length); i++) {
if (data[i] === searchNumber) {
// Add unique rows only (based on the phrase in column 2 if it exists)
const phrase = data[2] || JSON.stringify(data);
const isDuplicate = matchesByColumn[i].some(match => {
const matchPhrase = match[2] || JSON.stringify(match);
return matchPhrase === phrase;
});
if (!isDuplicate) {
matchesByColumn[i].push(data);
}
}
}
});
// Get total unique matches
const uniqueMatchCount = Object.values(matchesByColumn)
.reduce((total, matches) => total + matches.length, 0);
// Get cosmic symbols for the search number
const symbols = getCosmicSymbols(searchNumber);
// Create HTML for matches
let html = `
<div class="match-count">
<div class="cosmic-symbols">
<span class="planet-symbol">${symbols.planet}</span>
<span class="element-symbol">${symbols.element}</span>
<span class="zodiac-symbol">${symbols.zodiac}</span>
</div>
Found ${uniqueMatchCount} unique matches for number ${searchNumber}
</div>
`;
// Display matches grouped by column
for (let i = 0; i < maxColumns; i++) {
if (matchesByColumn[i].length > 0) {
html += `
<table class="data-table">
<tbody>
${matchesByColumn[i].map(row => {
// Add ALW cipher values based on the Book of the Law
let alwValue = 0;
// Find the phrase in the row (which is in column 2)
const phrase = row[2];
if (phrase && typeof phrase === 'string') {
alwValue = calculateBookOfLawCipher(phrase);
// Add ALW value to the row if it doesn't exist (as 5th column)
if (row.length <= 4) {
row.push(alwValue.toString());
}
}
return `<tr>${row.map((cell, cellIndex) => {
if (cellIndex === i && cell === searchNumber) {
const elementClassName =
symbols.element === '🜂' ? 'fire' :
symbols.element === '🜄' ? 'water' :
symbols.element === '🜁' ? 'air' :
symbols.element === '🜃' ? 'earth' : '';
const extended = getExtendedSymbols(cell);
const reducedValue = reduceNumber(parseInt(cell));
// Check for special number types
const specialClass =
isAngelNumber(cell) ? 'angel-number' :
isMirrorNumber(cell) ? 'mirror-number' : '';
return `<td class="num-cell ${specialClass} num-cell-${reducedValue}">
<span class="cell-number match-highlight number-${reducedValue}">${cell}</span>
<div class="cosmic-symbols">
<span class="planet-symbol">${symbols.planet}</span>
<span class="element-symbol ${elementClassName}">${symbols.element}</span>
<span class="zodiac-symbol">${symbols.zodiac}</span>
</div>
</td>`;
} else if (!isNaN(parseInt(cell))) {
// Add mystical symbols to other numeric cells too
const cellSymbols = getCosmicSymbols(cell);
const extended = getExtendedSymbols(cell);
const reducedValue = reduceNumber(parseInt(cell));
const elementClassName =
cellSymbols.element === '🜂' ? 'fire' :
cellSymbols.element === '🜄' ? 'water' :
cellSymbols.element === '🜁' ? 'air' :
cellSymbols.element === '🜃' ? 'earth' : '';
// Special styling for cipher columns
const cipherClass =
cellIndex === 5 ? 'alw-cipher' :
cellIndex === 6 ? 'prime-cipher' : '';
// Add cipher badge if applicable
const cipherBadge =
cellIndex === 5 ? '<span class="cipher-badge alw">ALW</span>' :
cellIndex === 6 ? '<span class="cipher-badge caesar">PRIME</span>' : '';
return `<td class="num-cell num-cell-${reducedValue} ${cipherClass}">
<span class="cell-number number-${reducedValue}">${cell}</span>
${cipherBadge}
<div class="cosmic-symbols">
<span class="planet-symbol">${cellSymbols.planet}</span>
<span class="element-symbol ${elementClassName}">${cellSymbols.element}</span>
<span class="zodiac-symbol">${cellSymbols.zodiac}</span>
</div>
</td>`;
} else if (cellIndex === 2) { // This is a phrase column
// Check if the cell contains words related to angel numbers or mirror numbers
const phrase = cell;
const wordsToCheck = ["angel", "mirror", "divine", "sacred", "master", "magic"];
const lowercaseCell = cell.toLowerCase();
// Create values for favoriting
const values = {};
for (let i = 0; i < row.length; i++) {
if (i !== 2 && !isNaN(parseInt(row[i]))) {
if (i === 1) values.jewish = row[i];
else if (i === 3) values.english = row[i];
else if (i === 4) values.simple = row[i];
else if (i === 5) values.alw = row[i];
else if (i === 6) values.prime = row[i];
else values[`column${i}`] = row[i];
}
}
// Generate phrase ID for checking if it's already favorited
const phraseId = MLDatabase.generateId(phrase);
const isFavorited = MLDatabase.favorites[phraseId] !== undefined;
// Check if this phrase is already in the checked set
const isChecked = checkedPhrases.has(phrase);
const specialClass = wordsToCheck.some(word => lowercaseCell.includes(word)) ?
'special-phrase' : '';
return `<td>
<div style="display: flex; align-items: center;">
<div class="controls-container">
<button class="favorite-btn ${isFavorited ? 'active' : ''}"
data-phrase="${phrase.replace(/"/g, '&quot;')}"
data-values='${JSON.stringify(values)}'>
${isFavorited ? '★' : '☆'}
</button>
<input type="checkbox" class="phrase-checkbox" id="phrase_${phraseId}"
data-phrase="${phrase.replace(/"/g, '&quot;')}" ${isChecked ? 'checked' : ''}>
</div>
<span class="${specialClass}">${phrase}</span>
</div>
</td>`;
} else {
return `<td>${cell}</td>`;
}
}).join('')}</tr>`;
}).join('')}
</tbody>
</table>
`;
}
}
resultsDiv.innerHTML = html;
// Attach event listeners for favorite buttons and checkboxes
attachFavoriteListeners();
attachCheckboxListeners();
} catch (error) {
console.error("Error searching by number:", error);
resultsDiv.innerHTML = `
<div class="error">
Error: ${error.message}<br>
Please try again or select a different proxy.
</div>
`;
}
}
// Cipher detection functions
// Check for Caesar Cipher
function detectCaesarCipher(text) {
// Simplified Caesar detection - checking for consistent letter shifts
const lowercaseText = text.toLowerCase();
let maxShift = 0;
let maxShiftCount = 0;
// Try different shift values
for (let shift = 1; shift <= 25; shift++) {
let shiftedCount = 0;
let totalTestable = 0;
for (let i = 0; i < lowercaseText.length; i++) {
const char = lowercaseText[i];
if (!/[a-z]/.test(char)) continue;
totalTestable++;
const code = char.charCodeAt(0);
const shiftedCode = ((code - 97 + shift) % 26) + 97;
const shiftedChar = String.fromCharCode(shiftedCode);
// Check if this shifted character is more common in English
if (isMoreCommonInEnglish(char, shiftedChar)) {
shiftedCount++;
}
}
const shiftRatio = totalTestable > 0 ? shiftedCount / totalTestable : 0;
if (shiftRatio > maxShiftCount) {
maxShiftCount = shiftRatio;
maxShift = shift;
}
}
return {
type: 'caesar',
confidence: Math.min(maxShiftCount * 100, 95),
shift: maxShift
};
}
// Check for Atbash Cipher (A=Z, B=Y, etc.)
function detectAtbashCipher(text) {
const lowercaseText = text.toLowerCase();
let atbashCount = 0;
let totalTestable = 0;
for (let i = 0; i < lowercaseText.length; i++) {
const char = lowercaseText[i];
if (!/[a-z]/.test(char)) continue;
totalTestable++;
const code = char.charCodeAt(0);
const atbashCode = 219 - code; // 219 = 'a' + 'z' in ASCII
const atbashChar = String.fromCharCode(atbashCode);
// Check if this atbash character is more common in English
if (isMoreCommonInEnglish(char, atbashChar)) {
atbashCount++;
}
}
const atbashRatio = totalTestable > 0 ? atbashCount / totalTestable : 0;
return {
type: 'atbash',
confidence: Math.min(atbashRatio * 100, 90)
};
}
// Check for A1Z26 Cipher (A=1, B=2, etc.)
function detectA1Z26Cipher(text) {
// Look for patterns of numbers that could represent letters
const numbers = text.match(/\b\d{1,2}\b/g) || [];
let validLetterCount = 0;
for (const num of numbers) {
const value = parseInt(num);
if (value >= 1 && value <= 26) {
validLetterCount++;
}
}
const confidence = numbers.length > 0 ? (validLetterCount / numbers.length) * 100 : 0;
return {
type: 'a1z26',
confidence: Math.min(confidence, 85)
};
}
// Check for Reverse Cipher
function detectReverseCipher(text) {
// Compare forward and backward letter frequencies
const forward = text.toLowerCase();
const backward = text.toLowerCase().split('').reverse().join('');
let matchCount = 0;
let totalTestable = 0;
for (let i = 0; i < Math.min(forward.length, 10); i++) {
if (!/[a-z]/.test(forward[i])) continue;
totalTestable++;
const reversedIndex = forward.length - 1 - i;
if (reversedIndex >= 0 && /[a-z]/.test(forward[reversedIndex])) {
if (isMoreCommonInEnglish(forward[i], forward[reversedIndex])) {
matchCount++;
}
}
}
const reverseRatio = totalTestable > 0 ? matchCount / totalTestable : 0;
return {
type: 'reverse',
confidence: Math.min(reverseRatio * 100, 80)
};
}
// Check for Ordinal Cipher
function detectOrdinalCipher(text) {
// Check if text consists of numbers that match ordinal positions
const words = text.split(/\s+/);
let numberCount = 0;
for (const word of words) {
if (/^\d+$/.test(word)) {
numberCount++;
}
}
const confidence = words.length > 0 ? (numberCount / words.length) * 100 : 0;
return {
type: 'ordinal',
confidence: Math.min(confidence, 75)
};
}
// Utility function to check if a character is more common in English than another
function isMoreCommonInEnglish(char1, char2) {
// English letter frequency (from most to least common): E T A O I N S H R D L U C M W F G Y P B V K J X Q Z
const englishFrequency = 'etaoinshrdlucmwfgypbvkjxqz';
const pos1 = englishFrequency.indexOf(char1);
const pos2 = englishFrequency.indexOf(char2);
// If both characters are in our frequency list
if (pos1 !== -1 && pos2 !== -1) {
return pos1 < pos2; // Lower index = more common
}
// If only one character is in the frequency list, it's more common
return pos1 !== -1;
}
// Book of the Law ALW Gematria cipher
function calculateBookOfLawCipher(text) {
if (!text || typeof text !== 'string') return 0;
let sum = 0;
const cleanText = text.toLowerCase().replace(/[^a-z]/g, '');
for (let i = 0; i < cleanText.length; i++) {
const char = cleanText[i];
let value;
// Special values from Book of the Law
switch (char) {
case 'a': value = 1; break; // A = 1
case 'l': value = 30; break; // L = 30
case 'w': value = 23; break; // W = 23
default:
// Standard position in alphabet (a=1, b=2, etc.)
value = char.charCodeAt(0) - 96;
break;
}
if (value >= 1 && value <= 26) {
sum += value;
}
}
return sum;
}
// Prime cipher - maps each letter to its corresponding prime number
function calculatePrimeCipher(text) {
if (!text || typeof text !== 'string') return 0;
// First 26 prime numbers for A-Z
const primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101];
let sum = 0;
const cleanText = text.toLowerCase().replace(/[^a-z]/g, '');
for (let i = 0; i < cleanText.length; i++) {
const letterIndex = cleanText.charCodeAt(i) - 97; // a=0, b=1, etc.
if (letterIndex >= 0 && letterIndex < primes.length) {
sum += primes[letterIndex];
}
}
return sum;
}
// Function to check if a number is prime
function isPrime(num) {
if (num <= 1) return false;
if (num <= 3) return true;
if (num % 2 === 0 || num % 3 === 0) return false;
let i = 5;
while (i * i <= num) {
if (num % i === 0 || num % (i + 2) === 0) return false;
i += 6;
}
return true;
}
// Function to analyze a phrase for potential ciphers
function analyzeCiphers(phrase) {
if (!phrase || typeof phrase !== 'string' || phrase.trim() === '') {
return {
confidence: 0,
type: 'none',
abbr: 'N/A'
};
}
// Run all cipher detection functions
const caesarResult = detectCaesarCipher(phrase);
const atbashResult = detectAtbashCipher(phrase);
const a1z26Result = detectA1Z26Cipher(phrase);
const reverseResult = detectReverseCipher(phrase);
const ordinalResult = detectOrdinalCipher(phrase);
// Find the cipher with the highest confidence
const results = [
caesarResult,
atbashResult,
a1z26Result,
reverseResult,
ordinalResult
];
const mostLikelyCipher = results.reduce((prev, current) =>
current.confidence > prev.confidence ? current : prev
);
// Map cipher types to abbreviations
const abbrMap = {
'caesar': 'CSR',
'atbash': 'ATB',
'a1z26': 'A1Z',
'reverse': 'REV',
'ordinal': 'ORD',
'none': 'N/A'
};
return {
confidence: mostLikelyCipher.confidence,
type: mostLikelyCipher.type,
abbr: abbrMap[mostLikelyCipher.type] || 'N/A'
};
}
// Apply the custom ay/ya decode pattern
function customDecode(phrase) {
if (!phrase || typeof phrase !== 'string') return '';
let decoded = '';
const words = phrase.split(/\s+/);
words.forEach(word => {
if (word.length === 0) return;
if (/[A-Z]/.test(word[0])) {
// Capital letter case
decoded += 'ay ';
for (let i = 0; i < word.length; i++) {
decoded += word[i];
decoded += (i < word.length - 1) ? ' ya ' : ' ';
}
} else {
// Normal case - ay, two letters, ya, two letters, ay pattern
decoded += 'ay';
for (let i = 0; i < word.length; i++) {
if (i % 4 === 0) decoded += ' ';
decoded += word[i];
if (i % 4 === 1) decoded += ' ya ';
}
decoded += ' ';
}
});
return decoded.trim();
}
// Helper function to get column name
function getColumnName(index) {
const columnNames = [
"First Column",
"Second Column",
"Third Column (Phrases)",
"Fourth Column"
];
return columnNames[index] || `Column ${index + 1}`;
}
// Initialize dark mode
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
document.documentElement.classList.add('dark');
}
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
if (event.matches) {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
});
// COMMON ENGLISH WORDS LIST FOR PHRASE GENERATOR
const COMMON_ENGLISH_WORDS = [
"time", "person", "year", "way", "day", "thing", "man", "world", "life", "hand",
"part", "child", "eye", "woman", "place", "work", "week", "case", "point", "company",
"number", "group", "problem", "fact", "divine", "sacred", "mystic", "cosmic", "spirit",
"light", "dark", "earth", "water", "fire", "air", "heart", "mind", "soul", "body",
"love", "peace", "truth", "wisdom", "power", "nature", "energy", "magic", "dream", "sun",
"moon", "star", "planet", "angel", "demon", "sound", "voice", "great", "good", "right",
"knowledge", "secret", "hidden", "ancient", "eternal", "infinite", "divine", "holy", "god",
"master", "teacher", "student", "path", "journey", "quest", "destiny", "fate", "freedom"
];
// Calculate gematria values based on cipher type
function calculateGematriaValue(text, cipherType) {
if (!text || typeof text !== 'string') return 0;
const cleanText = text.toLowerCase().replace(/[^a-z]/g, '');
let sum = 0;
switch (cipherType) {
case 'english':
// English gematria: A=6, B=12, C=18, etc.
for (let i = 0; i < cleanText.length; i++) {
const charCode = cleanText.charCodeAt(i) - 96; // a=1, b=2, etc.
if (charCode >= 1 && charCode <= 26) {
sum += charCode * 6;
}
}
break;
case 'simple':
// Simple gematria: A=1, B=2, C=3, etc.
for (let i = 0; i < cleanText.length; i++) {
const charCode = cleanText.charCodeAt(i) - 96; // a=1, b=2, etc.
if (charCode >= 1 && charCode <= 26) {
sum += charCode;
}
}
break;
case 'jewish':
// Jewish gematria (simplified): A=1, B=2, ..., J=10, K=20, etc.
const jewishValues = {
'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5, 'f': 6, 'g': 7, 'h': 8, 'i': 9,
'j': 10, 'k': 20, 'l': 30, 'm': 40, 'n': 50, 'o': 60, 'p': 70, 'q': 80, 'r': 90,
's': 100, 't': 200, 'u': 300, 'v': 400, 'w': 500, 'x': 600, 'y': 700, 'z': 800
};
for (let i = 0; i < cleanText.length; i++) {
const char = cleanText[i];
sum += jewishValues[char] || 0;
}
break;
case 'alw':
// ALW cipher (Book of the Law)
return calculateBookOfLawCipher(text);
default:
// Default to simple gematria
for (let i = 0; i < cleanText.length; i++) {
const charCode = cleanText.charCodeAt(i) - 96; // a=1, b=2, etc.
if (charCode >= 1 && charCode <= 26) {
sum += charCode;
}
}
}
return sum;
}
// Generate phrases with the target gematria value
function generatePhrases(targetValue, cipherType, wordBank, maxPhrases = 10) {
console.log(`Generating phrases with target value: ${targetValue}, cipher: ${cipherType}`);
if (!wordBank || wordBank.length === 0) {
console.error("Word bank is empty");
return [];
}
const phrases = [];
const usedPhrases = new Set();
const maxAttempts = 5000;
let attempts = 0;
// For very small target values, we'll need shorter phrases
const minWords = targetValue < 100 ? 1 : 2;
const maxWords = targetValue < 100 ? 3 : Math.min(7, Math.ceil(targetValue / 50));
while (phrases.length < maxPhrases && attempts < maxAttempts) {
attempts++;
// Decide number of words in this phrase
const wordCount = minWords + Math.floor(Math.random() * (maxWords - minWords + 1));
// Generate a candidate phrase
const candidateWords = [];
for (let i = 0; i < wordCount; i++) {
const randomIndex = Math.floor(Math.random() * wordBank.length);
candidateWords.push(wordBank[randomIndex]);
}
const candidatePhrase = candidateWords.join(' ');
// Skip if we've already generated this phrase
if (usedPhrases.has(candidatePhrase)) continue;
// Calculate the value of this phrase
const value = calculateGematriaValue(candidatePhrase, cipherType);
// Accept if it matches our target
if (value === targetValue) {
phrases.push({
phrase: candidatePhrase,
value: value
});
usedPhrases.add(candidatePhrase);
}
// For small target values, accept near matches
else if (targetValue < 50 && Math.abs(value - targetValue) <= 2 && phrases.length < maxPhrases / 2) {
phrases.push({
phrase: candidatePhrase,
value: value,
difference: value - targetValue
});
usedPhrases.add(candidatePhrase);
}
}
console.log(`Generated ${phrases.length} phrases after ${attempts} attempts`);
return phrases;
}
// Initialize machine learning database
const MLDatabase = {
// Store favorited phrases with their values and metadata
favorites: {},
// Feature vector storage for ML analysis
featureVectors: {},
// Add a phrase to favorites
addFavorite: function(phrase, values, metadata = {}) {
const id = this.generateId(phrase);
// Store the phrase with its values and metadata
this.favorites[id] = {
phrase: phrase,
values: values,
metadata: {
...metadata,
timestamp: Date.now(),
favoriteCount: 1
}
};
// Generate feature vector for this phrase
this.featureVectors[id] = this.extractFeatures(phrase, values);
// Save to localStorage
this.saveToStorage();
// Return the ID for reference
return id;
},
// Remove a phrase from favorites
removeFavorite: function(id) {
if (this.favorites[id]) {
delete this.favorites[id];
delete this.featureVectors[id];
this.saveToStorage();
return true;
}
return false;
},
// Generate a unique ID for a phrase
generateId: function(phrase) {
// Simple hash function
let hash = 0;
for (let i = 0; i < phrase.length; i++) {
const char = phrase.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash; // Convert to 32bit integer
}
return 'phrase_' + Math.abs(hash).toString(16);
},
// Extract features from a phrase and its values
extractFeatures: function(phrase, values) {
// Convert phrase to lowercase and remove punctuation
const cleanPhrase = phrase.toLowerCase().replace(/[^\w\s]/g, '');
// Word count
const wordCount = cleanPhrase.split(/\s+/).length;
// Letter counts
const letterCounts = {};
for (let i = 0; i < cleanPhrase.length; i++) {
const char = cleanPhrase[i];
if (/[a-z]/.test(char)) {
letterCounts[char] = (letterCounts[char] || 0) + 1;
}
}
// Digital roots of values
const digitalRoots = Object.values(values).map(val =>
reduceNumber(parseInt(val))
);
// Count occurrences of each digital root
const rootCounts = {};
digitalRoots.forEach(root => {
rootCounts[root] = (rootCounts[root] || 0) + 1;
});
// Create feature vector
return {
wordCount,
letterCounts,
rootCounts,
// Save original values for reference
values: { ...values }
};
},
// Calculate similarity between two phrases using their feature vectors
calculateSimilarity: function(id1, id2) {
const v1 = this.featureVectors[id1];
const v2 = this.featureVectors[id2];
if (!v1 || !v2) return 0;
// Cosine similarity for letter distributions
let dotProduct = 0;
let magnitude1 = 0;
let magnitude2 = 0;
// Process letter frequencies
const allLetters = new Set([
...Object.keys(v1.letterCounts),
...Object.keys(v2.letterCounts)
]);
allLetters.forEach(letter => {
const freq1 = v1.letterCounts[letter] || 0;
const freq2 = v2.letterCounts[letter] || 0;
dotProduct += freq1 * freq2;
magnitude1 += freq1 * freq1;
magnitude2 += freq2 * freq2;
});
const letterSimilarity = dotProduct / (Math.sqrt(magnitude1) * Math.sqrt(magnitude2) || 1);
// Compare digital roots pattern
let rootSimilarity = 0;
const allRoots = new Set([
...Object.keys(v1.rootCounts),
...Object.keys(v2.rootCounts)
]);
let rootDotProduct = 0;
let rootMagnitude1 = 0;
let rootMagnitude2 = 0;
allRoots.forEach(root => {
const count1 = v1.rootCounts[root] || 0;
const count2 = v2.rootCounts[root] || 0;
rootDotProduct += count1 * count2;
rootMagnitude1 += count1 * count1;
rootMagnitude2 += count2 * count2;
});
rootSimilarity = rootDotProduct / (Math.sqrt(rootMagnitude1) * Math.sqrt(rootMagnitude2) || 1);
// Compare value patterns - check if any values match exactly
let valueMatch = 0;
for (const key in v1.values) {
if (v2.values[key] === v1.values[key]) {
valueMatch += 1;
}
}
const valueMatchScore = valueMatch / Math.max(
Object.keys(v1.values).length,
Object.keys(v2.values).length
);
// Word count similarity
const wordCountDiff = Math.abs(v1.wordCount - v2.wordCount);
const wordCountSimilarity = 1 / (1 + wordCountDiff);
// Combine similarities with weights
return (
letterSimilarity * 0.4 +
rootSimilarity * 0.3 +
valueMatchScore * 0.2 +
wordCountSimilarity * 0.1
);
},
// Get recommendations based on a phrase
getRecommendations: function(phraseId, limit = 5) {
// If no favorites or the phraseId doesn't exist, return empty array
if (!this.favorites[phraseId] || Object.keys(this.favorites).length <= 1) {
return [];
}
// Calculate similarity scores with all other phrases
const similarities = [];
for (const id in this.favorites) {
if (id !== phraseId) {
const similarity = this.calculateSimilarity(phraseId, id);
similarities.push({
id,
similarity,
phrase: this.favorites[id].phrase,
values: this.favorites[id].values
});
}
}
// Sort by similarity (descending) and take the top 'limit' results
return similarities
.sort((a, b) => b.similarity - a.similarity)
.slice(0, limit);
},
// Get overall recommendations based on all favorited phrases
getOverallRecommendations: function(limit = 5) {
// If we have zero or only one favorite, can't make good recommendations
if (Object.keys(this.favorites).length <= 1) {
return [];
}
// Run collaborative filtering algorithm
const allSimilarities = {};
// For each favorite, calculate similarity to all others
for (const id1 in this.favorites) {
if (!allSimilarities[id1]) {
allSimilarities[id1] = {};
}
for (const id2 in this.favorites) {
if (id1 !== id2) {
if (!allSimilarities[id2]) {
allSimilarities[id2] = {};
}
// Calculate similarity if we haven't already
if (!allSimilarities[id1][id2]) {
const similarity = this.calculateSimilarity(id1, id2);
allSimilarities[id1][id2] = similarity;
allSimilarities[id2][id1] = similarity;
}
}
}
}
// Calculate the average similarity for each phrase
const averageSimilarities = {};
for (const id in this.favorites) {
let totalSimilarity = 0;
let count = 0;
for (const otherId in allSimilarities[id]) {
totalSimilarity += allSimilarities[id][otherId];
count++;
}
// Store average similarity
averageSimilarities[id] = count > 0 ? totalSimilarity / count : 0;
}
// Sort phrases by average similarity to all others
const sortedIds = Object.keys(averageSimilarities)
.sort((a, b) => averageSimilarities[b] - averageSimilarities[a]);
// Return the top 'limit' most central phrases
return sortedIds.slice(0, limit).map(id => ({
id,
phrase: this.favorites[id].phrase,
values: this.favorites[id].values,
centrality: averageSimilarities[id]
}));
},
// Save database to localStorage
saveToStorage: function() {
try {
localStorage.setItem('gematria_favorites', JSON.stringify(this.favorites));
localStorage.setItem('gematria_vectors', JSON.stringify(this.featureVectors));
} catch (e) {
console.error('Error saving to localStorage:', e);
}
},
// Load database from localStorage
loadFromStorage: function() {
try {
const favorites = localStorage.getItem('gematria_favorites');
const vectors = localStorage.getItem('gematria_vectors');
if (favorites) {
this.favorites = JSON.parse(favorites);
}
if (vectors) {
this.featureVectors = JSON.parse(vectors);
}
} catch (e) {
console.error('Error loading from localStorage:', e);
}
},
// Search in favorites
search: function(query) {
query = query.toLowerCase();
const results = [];
// Search in phrases
for (const id in this.favorites) {
const item = this.favorites[id];
const phrase = item.phrase.toLowerCase();
// Check if the phrase contains the query
if (phrase.includes(query)) {
results.push({
id,
item,
relevance: 1.0
});
continue;
}
// Check if any of the values match the query
if (!isNaN(parseInt(query))) {
const numQuery = parseInt(query);
const valueMatches = Object.values(item.values).some(val =>
parseInt(val) === numQuery
);
if (valueMatches) {
results.push({
id,
item,
relevance: 0.8
});
continue;
}
}
// Lower relevance: check if any word in the phrase starts with the query
const words = phrase.split(/\s+/);
if (words.some(word => word.startsWith(query))) {
results.push({
id,
item,
relevance: 0.6
});
continue;
}
}
// Sort by relevance
return results.sort((a, b) => b.relevance - a.relevance);
}
};
// Function to display all favorites
function displayFavorites() {
const container = document.getElementById('favorites-container');
if (!container) {
console.error("Favorites container not found");
return;
}
const favorites = MLDatabase.favorites;
if (Object.keys(favorites).length === 0) {
container.innerHTML = `
<div class="no-favorites">
<p>You haven't favorited any phrases yet. When analyzing phrases, click the ★ icon to save them to your database.</p>
</div>
`;
return;
}
let html = `<h3>Your Favorite Phrases (${Object.keys(favorites).length})</h3>`;
// Sort favorites by timestamp (newest first)
const sortedFavorites = Object.entries(favorites)
.sort((a, b) => b[1].metadata.timestamp - a[1].metadata.timestamp);
sortedFavorites.forEach(([id, item]) => {
const phrase = item.phrase;
const values = item.values;
// Generate cosmic symbols based on most prominent value
let mainValue = 0;
if (values.hebrewValue) mainValue = parseInt(values.hebrewValue);
else if (values.englishValue) mainValue = parseInt(values.englishValue);
else if (values.simpleValue) mainValue = parseInt(values.simpleValue);
else if (values.alw) mainValue = parseInt(values.alw);
else mainValue = parseInt(Object.values(values)[0] || 0);
const symbols = getCosmicSymbols(mainValue);
const extended = getExtendedSymbols(mainValue);
html += `
<div class="word-entry" data-id="${id}">
<div class="word-header">
<div class="cosmic-symbols">
<span class="planet-symbol">${symbols.planet}</span>
<span class="element-symbol">${symbols.element}</span>
<span class="zodiac-symbol">${symbols.zodiac}</span>
<span class="rune-symbol">${extended.rune}</span>
</div>
${phrase}
<button class="remove-favorite" data-id="${id}" style="float:right;background:none;border:none;color:#ff5555;cursor:pointer;font-size:18px;">✕</button>
</div>
<div class="word-values">
${Object.entries(values).map(([key, value]) =>
`<span class="value-tag">${key}: ${value}</span>`
).join('')}
</div>
<div class="similar-phrases" data-for="${id}" style="margin-top:8px;font-size:12px;">
<button class="show-similar-btn" data-id="${id}" style="background:none;border:none;color:#5D5CDE;cursor:pointer;font-size:12px;padding:0;">
Show Similar Phrases
</button>
</div>
</div>
`;
});
container.innerHTML = html;
// Add event listeners to remove buttons
document.querySelectorAll('.remove-favorite').forEach(button => {
button.addEventListener('click', function(e) {
console.log("Remove favorite clicked");
e.preventDefault();
e.stopPropagation();
const id = this.dataset.id;
if (MLDatabase.removeFavorite(id)) {
// Remove this entry from the UI
const entry = document.querySelector(`.word-entry[data-id="${id}"]`);
if (entry) {
entry.remove();
}
// Update recommendations
updateMLRecommendations();
// If no more favorites, update the container
if (Object.keys(MLDatabase.favorites).length === 0) {
displayFavorites();
}
}
});
});
// Add event listeners to show similar buttons
document.querySelectorAll('.show-similar-btn').forEach(button => {
button.addEventListener('click', function() {
console.log("Show similar clicked");
const id = this.dataset.id;
const container = document.querySelector(`.similar-phrases[data-for="${id}"]`);
if (!container) {
console.error(`Container for similar phrases with data-for="${id}" not found`);
return;
}
// Toggle between showing similar phrases and the button
if (container.querySelector('.similar-list')) {
container.innerHTML = `
<button class="show-similar-btn" data-id="${id}" style="background:none;border:none;color:#5D5CDE;cursor:pointer;font-size:12px;padding:0;">
Show Similar Phrases
</button>
`;
} else {
// Get recommendations for this phrase
const recommendations = MLDatabase.getRecommendations(id, 3);
if (recommendations.length === 0) {
container.innerHTML = `
<div style="color:#888;font-style:italic;margin-top:5px;">
Not enough data for recommendations yet.
</div>
<button class="hide-similar-btn" style="background:none;border:none;color:#5D5CDE;cursor:pointer;font-size:12px;padding:0;margin-top:5px;">
Hide
</button>
`;
} else {
let similarHTML = `<div class="similar-list" style="margin-top:5px;">`;
recommendations.forEach(rec => {
similarHTML += `
<div style="margin:5px 0;padding:5px;border-left:2px solid #5D5CDE;background:rgba(93,92,222,0.05);">
<div style="font-weight:bold;">${rec.phrase}</div>
<div style="font-size:10px;color:#666;">
Similarity: ${(rec.similarity * 100).toFixed(1)}%
</div>
</div>
`;
});
similarHTML += `
<button class="hide-similar-btn" style="background:none;border:none;color:#5D5CDE;cursor:pointer;font-size:12px;padding:0;margin-top:5px;">
Hide
</button>
</div>`;
container.innerHTML = similarHTML;
}
// Add event listener to hide button
container.querySelector('.hide-similar-btn').addEventListener('click', function() {
container.innerHTML = `
<button class="show-similar-btn" data-id="${id}" style="background:none;border:none;color:#5D5CDE;cursor:pointer;font-size:12px;padding:0;">
Show Similar Phrases
</button>
`;
});
}
});
});
}
// Function to update the ML recommendations section
function updateMLRecommendations() {
const container = document.getElementById('ml-recommendations');
if (!container) {
console.error("ML recommendations container not found");
return;
}
const recommendations = MLDatabase.getOverallRecommendations(3);
if (recommendations.length === 0) {
container.innerHTML = `
<div class="value-header">
<span class="planet-symbol">♃</span> ML Recommendations
</div>
<p>As you save more phrases, our machine learning system will suggest related phrases here based on patterns in your favorites.</p>
<p style="font-style:italic;color:#888;">Save at least 2 phrases to start seeing recommendations.</p>
`;
return;
}
let html = `
<div class="value-header">
<span class="planet-symbol">♃</span> ML Recommendations
</div>
<p>Based on your favorites, you might be interested in these patterns:</p>
<div class="recommendations-list">
`;
recommendations.forEach(rec => {
const symbols = getCosmicSymbols(Object.values(rec.values)[0] || 0);
const extended = getExtendedSymbols(Object.values(rec.values)[0] || 0);
html += `
<div class="recommendation-item" style="margin:10px 0;padding:10px;border:1px solid #ddd;border-radius:4px;background:rgba(93,92,222,0.05);">
<div style="display:flex;align-items:center;margin-bottom:5px;">
<div class="cosmic-symbols">
<span class="planet-symbol">${symbols.planet}</span>
<span class="element-symbol">${symbols.element}</span>
<span class="zodiac-symbol">${symbols.zodiac}</span>
<span class="rune-symbol">${extended.rune}</span>
</div>
<span style="font-weight:bold;margin-left:5px;">${rec.phrase}</span>
</div>
<div class="word-values">
${Object.entries(rec.values).map(([key, value]) =>
`<span class="value-tag">${key}: ${value}</span>`
).join('')}
</div>
<div style="font-size:10px;color:#666;margin-top:5px;">
Centrality score: ${(rec.centrality * 100).toFixed(1)}%
</div>
</div>
`;
});
html += `</div>`;
container.innerHTML = html;
}
// Add event listeners for all buttons when page loads
document.addEventListener('DOMContentLoaded', function() {
console.log("DOM fully loaded - initializing event handlers");
// Load saved favorites from localStorage
MLDatabase.loadFromStorage();
// Update ML recommendations based on loaded data
updateMLRecommendations();
// Set up click test to debug issues
setupClickTest();
// Tab buttons - use try/catch to handle missing elements gracefully
const btnSearchTab = document.getElementById('btn-search-tab');
if (btnSearchTab) {
btnSearchTab.addEventListener('click', function() {
console.log("Search tab clicked");
openTab('search-tab');
});
} else {
console.error("Search tab button not found");
}
const btnDatabaseTab = document.getElementById('btn-database-tab');
if (btnDatabaseTab) {
btnDatabaseTab.addEventListener('click', function() {
console.log("Database tab clicked");
openTab('database-tab');
displayFavorites();
});
} else {
console.error("Database tab button not found");
}
const btnDecodedTab = document.getElementById('btn-decoded-tab');
if (btnDecodedTab) {
btnDecodedTab.addEventListener('click', function() {
console.log("Decoded tab clicked");
openTab('decoded-tab');
});
} else {
console.error("Decoded tab button not found");
}
// Decode button
const decodeBtn = document.getElementById('decode-btn');
if (decodeBtn) {
decodeBtn.addEventListener('click', function() {
console.log("Decode button clicked");
decodeSelectedPhrases();
});
} else {
console.error("Decode button not found");
}
// Main analyze button
const analyzeBtn = document.getElementById('analyze-btn');
if (analyzeBtn) {
analyzeBtn.addEventListener('click', function() {
console.log("Analyze button clicked");
scrapeMultiplePages();
});
} else {
console.error("Analyze button not found");
}
// Number search button
const searchNumberBtn = document.getElementById('search-number-btn');
if (searchNumberBtn) {
searchNumberBtn.addEventListener('click', function() {
console.log("Number search button clicked");
searchByNumber();
});
} else {
console.error("Search number button not found");
}
// Database search button
const databaseSearchBtn = document.getElementById('database-search-btn');
if (databaseSearchBtn) {
databaseSearchBtn.addEventListener('click', function() {
console.log("Database search button clicked");
searchDatabase();
});
} else {
console.error("Database search button not found");
}
// Randomize and clear buttons for all words
const randomizeAllBtn = document.getElementById('randomize-all-btn');
if (randomizeAllBtn) {
randomizeAllBtn.addEventListener('click', function() {
console.log("Randomize all button clicked");
randomizeText('all-words');
});
} else {
console.error("Randomize all button not found");
}
const clearAllBtn = document.getElementById('clear-all-btn');
if (clearAllBtn) {
clearAllBtn.addEventListener('click', function() {
console.log("Clear all button clicked");
clearText('all-words');
});
} else {
console.error("Clear all button not found");
}
// Phrase Generator tab button
const btnPhraseGeneratorTab = document.getElementById('btn-phrase-generator-tab');
if (btnPhraseGeneratorTab) {
btnPhraseGeneratorTab.addEventListener('click', function() {
console.log("Phrase Generator tab clicked");
openTab('phrase-generator-tab');
// Populate the target value dropdown with values from analysis
populateTargetValueDropdown();
});
} else {
console.error("Phrase Generator tab button not found");
}
// Phrase Generator buttons
const generatePhrasesBtn = document.getElementById('generate-phrases-btn');
if (generatePhrasesBtn) {
generatePhrasesBtn.addEventListener('click', function() {
generatePhrasesByValue();
});
}
const useScrapedWordsBtn = document.getElementById('use-scraped-words-btn');
if (useScrapedWordsBtn) {
useScrapedWordsBtn.addEventListener('click', function() {
populateWordBankFromScraped();
});
}
const addCommonWordsBtn = document.getElementById('add-common-words-btn');
if (addCommonWordsBtn) {
addCommonWordsBtn.addEventListener('click', function() {
addCommonWordsToWordBank();
});
}
const clearWordBankBtn = document.getElementById('clear-word-bank-btn');
if (clearWordBankBtn) {
clearWordBankBtn.addEventListener('click', function() {
document.getElementById('word-bank').value = '';
});
}
const regenerateBtn = document.getElementById('regenerate-btn');
if (regenerateBtn) {
regenerateBtn.addEventListener('click', function() {
generatePhrasesByValue();
});
}
const saveFavoritesBtn = document.getElementById('save-favorites-btn');
if (saveFavoritesBtn) {
saveFavoritesBtn.addEventListener('click', function() {
saveGeneratedPhrasesToFavorites();
});
}
// Function to populate target value dropdown from analysis data
function populateTargetValueDropdown() {
const targetValueSelect = document.getElementById('target-value');
if (!targetValueSelect) return;
// Clear existing options
targetValueSelect.innerHTML = '<option value="">Select a value from analyzed data</option>';
// Get unique values from allDataGlobal
const allValues = new Set();
if (allDataGlobal && allDataGlobal.length > 0) {
allDataGlobal.forEach(pageData => {
pageData.forEach(row => {
// Add all numeric values
row.forEach(cell => {
if (!isNaN(parseInt(cell)) && parseInt(cell) > 0) {
allValues.add(parseInt(cell));
}
});
});
});
}
// Sort and add options
const sortedValues = Array.from(allValues).sort((a, b) => a - b);
sortedValues.forEach(value => {
const option = document.createElement('option');
option.value = value;
option.textContent = value;
targetValueSelect.appendChild(option);
});
}
// Function to populate word bank from scraped data
function populateWordBankFromScraped() {
const wordBank = document.getElementById('word-bank');
if (!wordBank) return;
// Get all phrases from scraped data
const allPhrases = [];
if (allDataGlobal && allDataGlobal.length > 0) {
allDataGlobal.forEach(pageData => {
pageData.forEach(row => {
if (row.length > 2 && row[2]) {
allPhrases.push(row[2]);
}
});
});
}
// Extract words and remove duplicates
const words = extractWords(allPhrases);
// Update word bank
wordBank.value = words.join(' ');
}
// Function to add common words to word bank
function addCommonWordsToWordBank() {
const wordBank = document.getElementById('word-bank');
if (!wordBank) return;
// Get existing words
const existingWords = wordBank.value.trim().split(/\s+/).filter(word => word.trim() !== '');
// Combine with common words and remove duplicates
const allWords = [...new Set([...existingWords, ...COMMON_ENGLISH_WORDS])];
// Update word bank
wordBank.value = allWords.join(' ');
}
// Function to generate phrases by target value
function generatePhrasesByValue() {
const targetValue = parseInt(document.getElementById('target-value').value) ||
parseInt(document.getElementById('value-input').value);
const cipherType = document.getElementById('cipher-type').value;
const wordBankText = document.getElementById('word-bank').value;
if (!targetValue) {
alert('Please select or enter a target value');
return;
}
if (!wordBankText.trim()) {
alert('Word bank is empty. Please add some words first.');
return;
}
// Show loading indicator
const loadingDiv = document.getElementById('phrase-generator-loading');
if (loadingDiv) loadingDiv.style.display = 'block';
// Parse word bank
const wordBank = wordBankText.trim().split(/\s+/).filter(word => word.trim() !== '');
// Generate phrases (using setTimeout to not block UI)
setTimeout(() => {
const generatedPhrases = generatePhrases(targetValue, cipherType, wordBank, 15);
// Hide loading indicator
if (loadingDiv) loadingDiv.style.display = 'none';
// Show results container
const resultsContainer = document.getElementById('generated-phrases-container');
if (resultsContainer) resultsContainer.style.display = 'block';
// Update results in UI
displayGeneratedPhrases(generatedPhrases, targetValue, cipherType);
}, 100);
}
// Function to display generated phrases
function displayGeneratedPhrases(phrases, targetValue, cipherType) {
const listContainer = document.getElementById('generated-phrases-list');
if (!listContainer) return;
if (phrases.length === 0) {
listContainer.innerHTML = `<div class="error">No phrases found with value ${targetValue} in ${getCipherName(cipherType)} cipher. Try with a different value or add more words to the word bank.</div>`;
return;
}
let html = `<h3>Phrases with value ${targetValue} in ${getCipherName(cipherType)} cipher</h3>`;
html += '<div class="word-values">';
phrases.forEach((item, index) => {
const symbols = getCosmicSymbols(item.value);
html += `
<div style="margin-bottom: 10px; padding: 8px; border: 1px solid #ddd; border-radius: 4px;">
<div style="display: flex; align-items: center;">
<input type="checkbox" id="gen-phrase-${index}" class="phrase-checkbox gen-phrase-checkbox" data-phrase="${item.phrase}">
<div class="cosmic-symbols" style="margin: 0 5px;">
<span class="planet-symbol">${symbols.planet}</span>
<span class="element-symbol">${symbols.element}</span>
<span class="zodiac-symbol">${symbols.zodiac}</span>
</div>
<span>${item.phrase}</span>
</div>
<div style="font-size: 12px; color: #666; margin-top: 5px;">
Value: ${item.value}
${item.difference ? ` (${item.difference > 0 ? '+' : ''}${item.difference})` : ''}
</div>
</div>
`;
});
html += '</div>';
listContainer.innerHTML = html;
}
// Function to get cipher name for display
function getCipherName(cipherType) {
switch (cipherType) {
case 'english': return 'English';
case 'simple': return 'Simple';
case 'jewish': return 'Jewish';
case 'alw': return 'ALW';
default: return cipherType;
}
}
// Function to save selected generated phrases to favorites
function saveGeneratedPhrasesToFavorites() {
const checkboxes = document.querySelectorAll('.gen-phrase-checkbox:checked');
if (checkboxes.length === 0) {
alert('Please select at least one phrase to save');
return;
}
// Get cipher type and target value
const cipherType = document.getElementById('cipher-type').value;
const targetValue = parseInt(document.getElementById('target-value').value) ||
parseInt(document.getElementById('value-input').value);
// Save each selected phrase
checkboxes.forEach(checkbox => {
const phrase = checkbox.dataset.phrase;
if (!phrase) return;
// Calculate actual value
const actualValue = calculateGematriaValue(phrase, cipherType);
// Create values object based on cipher type
const values = {};
switch (cipherType) {
case 'english':
values.english = actualValue;
break;
case 'simple':
values.simple = actualValue;
break;
case 'jewish':
values.jewish = actualValue;
break;
case 'alw':
values.alw = actualValue;
break;
}
// Add to favorites
MLDatabase.addFavorite(phrase, values);
// Uncheck the checkbox
checkbox.checked = false;
});
// Update favorites UI and show message
updateMLRecommendations();
alert(`${checkboxes.length} phrase(s) saved to favorites`);
}
// Set proxy from dropdown
const proxySelect = document.getElementById('proxySelect');
if (proxySelect) {
proxySelect.addEventListener('change', function() {
currentProxyIndex = proxyKeys.indexOf(this.value);
console.log(`Selected proxy: ${this.value} (index ${currentProxyIndex})`);
});
} else {
console.error("Proxy select dropdown not found");
}
// Add global click handler for all buttons to debug issues
document.addEventListener('click', function(e) {
if (e.target.tagName === 'BUTTON') {
console.log(`Button clicked: ${e.target.textContent || e.target.id}`);
}
});
// Create the help-content div if it doesn't exist
if (!document.getElementById('help-content')) {
const helpContent = document.createElement('div');
helpContent.id = 'help-content';
const databaseResults = document.getElementById('database-results');
if (databaseResults) {
databaseResults.before(helpContent);
} else {
// Fallback if database-results doesn't exist
const container = document.querySelector('.container');
if (container) {
container.appendChild(helpContent);
}
}
}
// Add delegate event listener for collapsible sections
document.addEventListener('click', function(e) {
if (e.target && e.target.closest('.collapsible-header')) {
const header = e.target.closest('.collapsible-header');
const content = header.nextElementSibling;
const toggle = header.querySelector('.accordion-toggle');
if (content.classList.contains('visible')) {
content.classList.remove('visible');
toggle.textContent = '+';
console.log("Collapsed section");
} else {
content.classList.add('visible');
toggle.textContent = '−';
console.log("Expanded section");
}
}
});
console.log("Event handlers initialized");
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment