shism commited on
Commit
21b4371
·
verified ·
1 Parent(s): 3eea0c5

improve the whole app 100x - Follow Up Deployment

Browse files
Files changed (1) hide show
  1. index.html +539 -168
index.html CHANGED
@@ -6,32 +6,46 @@
6
  <title>SymCalc - Symbolic Calculator</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
8
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
 
9
  <style>
10
- .calculator-screen {
11
- height: 120px;
12
- overflow-y: auto;
13
- scrollbar-width: thin;
14
- scrollbar-color: #4f46e5 #e5e7eb;
 
 
 
 
15
  }
16
- .calculator-screen::-webkit-scrollbar {
17
- width: 6px;
 
 
 
18
  }
19
- .calculator-screen::-webkit-scrollbar-track {
20
- background: #e5e7eb;
 
21
  }
22
- .calculator-screen::-webkit-scrollbar-thumb {
23
- background-color: #4f46e5;
24
- border-radius: 3px;
 
 
 
 
 
25
  }
26
  .analysis-box {
27
  background-color: #f8fafc;
28
- border-left: 4px solid #4f46e5;
29
- padding: 12px;
30
- margin-top: 8px;
31
- border-radius: 0 4px 4px 0;
32
- font-family: monospace;
33
- white-space: pre-wrap;
34
  color: #334155;
 
35
  }
36
  .analysis-title {
37
  font-weight: bold;
@@ -75,98 +89,110 @@
75
  }
76
  </style>
77
  </head>
78
- <body class="bg-gray-100 min-h-screen flex items-center justify-center p-4">
79
- <div class="w-full max-w-md">
80
- <div class="bg-white rounded-2xl shadow-xl overflow-hidden">
81
- <!-- Header -->
82
- <div class="bg-indigo-600 p-4 flex items-center justify-between">
83
- <div class="flex items-center space-x-2">
84
- <i class="fas fa-infinity text-white text-xl"></i>
85
- <h1 class="text-white font-bold text-xl">SymCalc</h1>
86
  </div>
87
- <div class="flex space-x-2">
88
- <button class="text-white hover:bg-indigo-700 p-2 rounded-full transition">
89
  <i class="fas fa-history"></i>
90
  </button>
91
- <button class="text-white hover:bg-indigo-700 p-2 rounded-full transition">
92
- <i class="fas fa-cog"></i>
93
  </button>
94
  </div>
95
  </div>
96
-
97
- <!-- Calculator Screen -->
98
- <div class="p-4">
99
- <div class="calculator-screen bg-gray-50 rounded-lg p-4 mb-4">
100
- <div id="loading" class="hidden text-indigo-500 text-sm mb-2">Calculating...</div>
 
 
101
  <textarea
102
  id="formulaInput"
103
- class="w-full bg-transparent text-gray-700 text-lg font-mono resize-none outline-none"
104
- rows="3"
105
- placeholder="Enter formula (e.g., 2x + 3 = 7)"
 
106
  ></textarea>
107
- <div id="result" class="text-2xl font-bold text-gray-800 mt-2 text-right"></div>
108
- <div id="error" class="text-sm mt-1"></div>
 
 
 
 
109
  </div>
110
 
111
- <!-- Symbolic Input Buttons -->
112
- <div class="grid grid-cols-5 gap-2 mb-3">
113
- <button onclick="addSymbol('π')" class="symbol-btn bg-indigo-100 text-indigo-700 p-3 rounded-lg font-bold">π</button>
114
- <button onclick="addSymbol('e')" class="symbol-btn bg-indigo-100 text-indigo-700 p-3 rounded-lg font-bold">e</button>
115
- <button onclick="addSymbol('√(')" class="symbol-btn bg-indigo-100 text-indigo-700 p-3 rounded-lg font-bold">√</button>
116
- <button onclick="addSymbol('^')" class="symbol-btn bg-indigo-100 text-indigo-700 p-3 rounded-lg font-bold">^</button>
117
- <button onclick="addSymbol('!')" class="symbol-btn bg-indigo-100 text-indigo-700 p-3 rounded-lg font-bold">!</button>
118
-
119
- <button onclick="addSymbol('sin(')" class="symbol-btn bg-indigo-50 text-indigo-600 p-3 rounded-lg">sin</button>
120
- <button onclick="addSymbol('cos(')" class="symbol-btn bg-indigo-50 text-indigo-600 p-3 rounded-lg">cos</button>
121
- <button onclick="addSymbol('tan(')" class="symbol-btn bg-indigo-50 text-indigo-600 p-3 rounded-lg">tan</button>
122
- <button onclick="addSymbol('ln(')" class="symbol-btn bg-indigo-50 text-indigo-600 p-3 rounded-lg">ln</button>
123
- <button onclick="addSymbol('log(')" class="symbol-btn bg-indigo-50 text-indigo-600 p-3 rounded-lg">log</button>
124
  </div>
 
 
 
 
 
 
125
 
126
- <!-- Standard Calculator Buttons -->
127
- <div class="grid grid-cols-4 gap-2">
128
- <button onclick="clearAll()" class="symbol-btn bg-red-100 text-red-600 p-3 rounded-lg font-bold">C</button>
129
- <button onclick="backspace()" class="symbol-btn bg-gray-200 text-gray-700 p-3 rounded-lg font-bold"><i class="fas fa-backspace"></i></button>
130
- <button onclick="addSymbol('(')" class="symbol-btn bg-gray-200 text-gray-700 p-3 rounded-lg font-bold">(</button>
131
- <button onclick="addSymbol(')')" class="symbol-btn bg-gray-200 text-gray-700 p-3 rounded-lg font-bold">)</button>
132
-
133
- <button onclick="addSymbol('7')" class="symbol-btn bg-white text-gray-800 p-3 rounded-lg font-bold shadow-sm">7</button>
134
- <button onclick="addSymbol('8')" class="symbol-btn bg-white text-gray-800 p-3 rounded-lg font-bold shadow-sm">8</button>
135
- <button onclick="addSymbol('9')" class="symbol-btn bg-white text-gray-800 p-3 rounded-lg font-bold shadow-sm">9</button>
136
- <button onclick="addSymbol('/')" class="symbol-btn bg-gray-200 text-gray-700 p-3 rounded-lg font-bold">÷</button>
137
-
138
- <button onclick="addSymbol('4')" class="symbol-btn bg-white text-gray-800 p-3 rounded-lg font-bold shadow-sm">4</button>
139
- <button onclick="addSymbol('5')" class="symbol-btn bg-white text-gray-800 p-3 rounded-lg font-bold shadow-sm">5</button>
140
- <button onclick="addSymbol('6')" class="symbol-btn bg-white text-gray-800 p-3 rounded-lg font-bold shadow-sm">6</button>
141
- <button onclick="addSymbol('*')" class="symbol-btn bg-gray-200 text-gray-700 p-3 rounded-lg font-bold">×</button>
142
-
143
- <button onclick="addSymbol('1')" class="symbol-btn bg-white text-gray-800 p-3 rounded-lg font-bold shadow-sm">1</button>
144
- <button onclick="addSymbol('2')" class="symbol-btn bg-white text-gray-800 p-3 rounded-lg font-bold shadow-sm">2</button>
145
- <button onclick="addSymbol('3')" class="symbol-btn bg-white text-gray-800 p-3 rounded-lg font-bold shadow-sm">3</button>
146
- <button onclick="addSymbol('-')" class="symbol-btn bg-gray-200 text-gray-700 p-3 rounded-lg font-bold">−</button>
147
-
148
- <button onclick="addSymbol('0')" class="symbol-btn bg-white text-gray-800 p-3 rounded-lg font-bold shadow-sm">0</button>
149
- <button onclick="addSymbol('.')" class="symbol-btn bg-gray-200 text-gray-700 p-3 rounded-lg font-bold">.</button>
150
- <button onclick="addSymbol('+')" class="symbol-btn bg-gray-200 text-gray-700 p-3 rounded-lg font-bold">+</button>
151
- <button onclick="calculate()" class="symbol-btn bg-indigo-600 text-white p-3 rounded-lg font-bold">=</button>
152
  </div>
153
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
154
 
155
- <!-- History Panel (Hidden by default) -->
156
- <div id="historyPanel" class="hidden bg-gray-50 border-t border-gray-200 max-h-60 overflow-y-auto">
157
- <div class="p-3 border-b border-gray-200 flex justify-between items-center bg-gray-100">
158
- <h3 class="font-medium text-gray-700">History</h3>
159
- <button onclick="clearHistory()" class="text-gray-500 hover:text-red-500">
160
- <i class="fas fa-trash-alt"></i>
161
  </button>
162
  </div>
163
- <div id="historyList" class="divide-y divide-gray-200"></div>
164
- </div>
165
  </div>
166
 
167
- <div class="mt-4 text-center text-gray-500 text-sm">
168
- <p>SymCalc - Symbolic Mathematics Calculator</p>
169
- </div>
170
  </div>
171
 
172
  <script>
@@ -186,6 +212,50 @@
186
  });
187
 
188
  function handleKeyPress(e) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
189
  const keyMap = {
190
  '0': '0', '1': '1', '2': '2', '3': '3', '4': '4',
191
  '5': '5', '6': '6', '7': '7', '8': '8', '9': '9',
@@ -194,7 +264,9 @@
194
  '(': '(', ')': ')',
195
  'Enter': '=',
196
  'Backspace': 'backspace',
197
- 'Escape': 'clear'
 
 
198
  };
199
 
200
  const key = keyMap[e.key];
@@ -203,9 +275,38 @@
203
  if (key === '=') calculate();
204
  else if (key === 'backspace') backspace();
205
  else if (key === 'clear') clearAll();
 
 
206
  else addSymbol(key);
207
  }
208
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
209
 
210
  function addSymbol(symbol) {
211
  const input = document.getElementById('formulaInput');
@@ -243,16 +344,98 @@
243
  // Not needed anymore since we're using textarea directly
244
  }
245
 
246
- function calculate() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
247
  const input = document.getElementById('formulaInput');
248
  currentExpression = input.value.trim();
249
  if (!currentExpression) return;
250
 
251
  const loadingEl = document.getElementById('loading');
252
  loadingEl.classList.remove('hidden');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
253
 
254
  // Use setTimeout to allow UI to update before heavy calculation
255
  setTimeout(() => {
 
 
256
  try {
257
  // Validate input first
258
  if (!currentExpression.trim()) throw "Please enter an expression";
@@ -260,8 +443,62 @@
260
 
261
  // Equation solving (e.g., "2x + 7y = 3z")
262
  if (currentExpression.includes('=')) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
263
  const parts = currentExpression.split('=');
264
- if (parts.length !== 2) throw "Invalid equation format - only one '=' allowed";
265
 
266
  const left = parts[0].trim();
267
  const right = parts[1].trim();
@@ -290,23 +527,17 @@
290
  else if (variables.size === 1) {
291
  // Single variable case
292
  const varName = [...variables][0];
293
- const coeffRegex = new RegExp(`([+-]?\\d*\\.?\\d*)${varName}`, 'g');
294
- const leftMatch = coeffRegex.exec(left);
295
- if (!leftMatch) throw `Invalid equation format for ${varName}`;
296
 
297
- const coeff = leftMatch[1] ? parseFloat(leftMatch[1]) : 1;
298
- if (isNaN(coeff)) throw "Invalid coefficient";
299
-
300
- const constant = parseFloat(left.replace(new RegExp(varName, 'g'), '0')) || 0;
301
- if (isNaN(constant)) throw "Invalid constant term";
302
-
303
- const rightValue = parseFloat(right.replace(new RegExp(varName, 'g'), '0')) || 0;
304
- if (isNaN(rightValue)) throw "Invalid right side value";
305
-
306
- const solution = (rightValue - constant) / coeff;
307
- document.getElementById('result').textContent = `${varName} = ${formatResult(solution)}`;
308
- addToHistory(currentExpression, solution);
309
- return;
310
  }
311
  else {
312
  // Multiple variables case
@@ -318,50 +549,14 @@
318
  }
319
  }
320
 
321
- // Replace symbolic constants with their values
322
- let expr = currentExpression
323
- .replace(/×/g, '*')
324
- .replace(/÷/g, '/')
325
- .replace(/−/g, '-')
326
- .replace(/π/g, 'Math.PI')
327
- .replace(/e/g, 'Math.E')
328
- .replace(/√\(/g, 'Math.sqrt(')
329
- .replace(/\^/g, '**')
330
- .replace(/sin\(/g, 'Math.sin(')
331
- .replace(/cos\(/g, 'Math.cos(')
332
- .replace(/tan\(/g, 'Math.tan(')
333
- .replace(/ln\(/g, 'Math.log(')
334
- .replace(/log\(/g, 'Math.log10(');
335
 
336
- // Handle factorial with gamma function for non-integers and better precision
337
- expr = expr.replace(/([+-]?[\d.]+)!/g, function(match, num) {
338
- const n = parseFloat(num);
339
- if (n < 0) throw "Factorial of negative number";
340
- if (n > 170) throw "Number too large for factorial";
341
-
342
- // Use gamma function for non-integers
343
- if (!Number.isInteger(n)) {
344
- return `(function gamma(z) {
345
- const g = 7;
346
- const p = [
347
- 0.99999999999980993, 676.5203681218851, -1259.1392167224028,
348
- 771.32342877765313, -176.61502916214059, 12.507343278686905,
349
- -0.13857109526572012, 9.9843695780195716e-6, 1.5056327351493116e-7
350
- ];
351
- if (z < 0.5) return Math.PI / (Math.sin(Math.PI * z) * gamma(1 - z));
352
- z -= 1;
353
- let x = p[0];
354
- for (let i = 1; i < g + 2; i++) x += p[i] / (z + i);
355
- const t = z + g + 0.5;
356
- return Math.sqrt(2 * Math.PI) * Math.pow(t, z + 0.5) * Math.exp(-t) * x;
357
- })(${n + 1})`;
358
- }
359
-
360
- // Simple factorial for integers
361
- let result = 1;
362
- for (let i = 2; i <= n; i++) result *= i;
363
- return result;
364
- });
365
 
366
  // Sanitize the expression before evaluation
367
  const sanitized = expr.replace(/Math\./g, '');
@@ -442,16 +637,31 @@
442
  if (typeof error === 'string' && error.startsWith('<div')) {
443
  document.getElementById('error').innerHTML = error;
444
  } else {
445
- document.getElementById('error').textContent = 'Error: ' + error;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
446
  }
447
  document.getElementById('result').textContent = '';
448
- if (error.includes('variables but no equation')) {
449
- document.getElementById('error').textContent += '\nTip: To evaluate expressions with variables, assign them values first (e.g. "x=5")';
450
- }
451
  console.error("Calculation error:", error);
452
- // Clear any partial results
453
- document.getElementById('result').textContent = '';
454
- document.getElementById('result').textContent = '';
455
  } finally {
456
  loadingEl.classList.add('hidden');
457
  }
@@ -478,17 +688,24 @@
478
  return str;
479
  }
480
 
481
- function addToHistory(expression, result) {
482
- history.unshift({
483
  expression,
484
  result,
485
- timestamp: new Date().toISOString()
486
- });
 
 
 
 
 
487
 
488
- if (history.length > 10) history.pop();
 
489
 
490
  localStorage.setItem('calcHistory', JSON.stringify(history));
491
  renderHistory();
 
492
  }
493
 
494
  function renderHistory() {
@@ -499,9 +716,13 @@
499
  const historyItem = document.createElement('div');
500
  historyItem.className = 'p-3 history-item fade-in';
501
  historyItem.innerHTML = `
502
- <div class="text-sm text-gray-500">${new Date(item.timestamp).toLocaleTimeString()}</div>
503
- <div class="font-mono">${item.expression}</div>
504
- <div class="text-right font-bold text-indigo-600">= ${formatResult(item.result)}</div>
 
 
 
 
505
  `;
506
 
507
  historyItem.addEventListener('click', () => {
@@ -524,6 +745,156 @@
524
  const panel = document.getElementById('historyPanel');
525
  panel.classList.toggle('hidden');
526
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
527
  </script>
528
  <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=shism/symcalc" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
529
  </html>
 
6
  <title>SymCalc - Symbolic Calculator</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
8
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+ <script src="https://cdn.jsdelivr.net/pyodide/v0.23.4/full/pyodide.js"></script>
10
  <style>
11
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=Source+Code+Pro:wght@400;600&display=swap');
12
+
13
+ :root {
14
+ --primary: #4f46e5;
15
+ --primary-light: #e0e7ff;
16
+ --text: #1f2937;
17
+ --text-light: #6b7280;
18
+ --border: #e5e7eb;
19
+ --bg: #f9fafb;
20
  }
21
+
22
+ body {
23
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
24
+ color: var(--text);
25
+ line-height: 1.5;
26
  }
27
+
28
+ .mono {
29
+ font-family: 'Source Code Pro', monospace;
30
  }
31
+
32
+ .document {
33
+ max-width: 800px;
34
+ margin: 0 auto;
35
+ background: white;
36
+ box-shadow: 0 1px 3px rgba(0,0,0,0.05);
37
+ border-radius: 8px;
38
+ overflow: hidden;
39
  }
40
  .analysis-box {
41
  background-color: #f8fafc;
42
+ border: 1px solid #e5e7eb;
43
+ padding: 16px;
44
+ margin-top: 12px;
45
+ border-radius: 8px;
46
+ font-family: 'Inter', sans-serif;
 
47
  color: #334155;
48
+ box-shadow: 0 1px 2px rgba(0,0,0,0.05);
49
  }
50
  .analysis-title {
51
  font-weight: bold;
 
89
  }
90
  </style>
91
  </head>
92
+ <body class="bg-gray-50 min-h-screen p-6">
93
+ <div class="document">
94
+ <header class="border-b border-gray-200 px-6 py-4">
95
+ <div class="flex items-center justify-between">
96
+ <div class="flex items-center space-x-3">
97
+ <i class="fas fa-infinity text-indigo-600 text-2xl"></i>
98
+ <h1 class="text-2xl font-semibold">SymCalc</h1>
99
+ <span class="text-sm text-gray-500">Symbolic Mathematics Calculator</span>
100
  </div>
101
+ <div class="flex space-x-4">
102
+ <button class="text-gray-500 hover:text-indigo-600 transition" title="History">
103
  <i class="fas fa-history"></i>
104
  </button>
105
+ <button class="text-gray-500 hover:text-indigo-600 transition" title="Documentation">
106
+ <i class="fas fa-question-circle"></i>
107
  </button>
108
  </div>
109
  </div>
110
+ </header>
111
+
112
+ <main class="p-6">
113
+ <section class="mb-8">
114
+ <div id="loading" class="hidden text-indigo-600 text-sm mb-2 font-medium">Calculating...</div>
115
+ <div class="mb-1 text-sm text-gray-500 font-medium">Input Expression</div>
116
+ <div class="relative">
117
  <textarea
118
  id="formulaInput"
119
+ class="w-full bg-white text-gray-900 text-lg mono resize-none outline-none border border-gray-200 rounded p-3 mb-2 focus:ring-2 focus:ring-indigo-200 focus:border-indigo-500"
120
+ rows="2"
121
+ placeholder="Enter a mathematical expression (e.g. 2x + 3 = 7, sin(π/2), √(16))"
122
+ spellcheck="false"
123
  ></textarea>
124
+ <div id="latexPreview" class="absolute right-3 top-3 text-gray-400 text-sm hidden">
125
+ <span class="bg-white px-2 py-1 rounded">LaTeX Preview</span>
126
+ </div>
127
+ </div>
128
+ <div id="latexOutput" class="text-center p-2 bg-gray-50 border border-gray-200 rounded hidden">
129
+ <div class="katex-display"></div>
130
  </div>
131
 
132
+ <div class="mt-6 mb-1 text-sm text-gray-500 font-medium">Result</div>
133
+ <div id="result" class="text-xl font-medium text-gray-900 mono p-3 bg-gray-50 rounded border border-gray-200 min-h-[60px]"></div>
134
+ <div id="steps" class="mt-3 hidden">
135
+ <div class="text-sm text-gray-500 font-medium mb-1">Solution Steps</div>
136
+ <div id="stepsContent" class="text-sm mono p-3 bg-blue-50 rounded border border-blue-200"></div>
 
 
 
 
 
 
 
 
137
  </div>
138
+ <div id="error" class="mt-2 text-sm text-red-500"></div>
139
+ <div id="sympyCode" class="hidden mt-3">
140
+ <div class="text-sm text-gray-500 font-medium mb-1">SymPy Code</div>
141
+ <pre class="text-xs mono p-3 bg-gray-100 rounded overflow-x-auto"></pre>
142
+ </div>
143
+ </section>
144
 
145
+ <section class="mb-8">
146
+ <div class="mb-3 text-sm text-gray-500 font-medium">Common Symbols</div>
147
+ <div class="grid grid-cols-8 gap-2 mb-4">
148
+ <button onclick="addSymbol('π')" class="p-2 bg-gray-100 hover:bg-gray-200 rounded text-sm mono">π</button>
149
+ <button onclick="addSymbol('e')" class="p-2 bg-gray-100 hover:bg-gray-200 rounded text-sm mono">e</button>
150
+ <button onclick="addSymbol('√(')" class="p-2 bg-gray-100 hover:bg-gray-200 rounded text-sm mono">√</button>
151
+ <button onclick="addSymbol('^')" class="p-2 bg-gray-100 hover:bg-gray-200 rounded text-sm mono">^</button>
152
+ <button onclick="addSymbol('!')" class="p-2 bg-gray-100 hover:bg-gray-200 rounded text-sm mono">!</button>
153
+ <button onclick="addSymbol('(')" class="p-2 bg-gray-100 hover:bg-gray-200 rounded text-sm mono">(</button>
154
+ <button onclick="addSymbol(')')" class="p-2 bg-gray-100 hover:bg-gray-200 rounded text-sm mono">)</button>
155
+ <button onclick="addSymbol('+')" class="p-2 bg-gray-100 hover:bg-gray-200 rounded text-sm mono">+</button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
  </div>
157
+
158
+ <div class="grid grid-cols-8 gap-2 mb-4">
159
+ <button onclick="addSymbol('-')" class="p-2 bg-gray-100 hover:bg-gray-200 rounded text-sm mono">-</button>
160
+ <button onclick="addSymbol('*')" class="p-2 bg-gray-100 hover:bg-gray-200 rounded text-sm mono">×</button>
161
+ <button onclick="addSymbol('/')" class="p-2 bg-gray-100 hover:bg-gray-200 rounded text-sm mono">÷</button>
162
+ <button onclick="addSymbol('sin(')" class="p-2 bg-gray-100 hover:bg-gray-200 rounded text-sm mono">sin</button>
163
+ <button onclick="addSymbol('cos(')" class="p-2 bg-gray-100 hover:bg-gray-200 rounded text-sm mono">cos</button>
164
+ <button onclick="addSymbol('tan(')" class="p-2 bg-gray-100 hover:bg-gray-200 rounded text-sm mono">tan</button>
165
+ <button onclick="addSymbol('ln(')" class="p-2 bg-gray-100 hover:bg-gray-200 rounded text-sm mono">ln</button>
166
+ <button onclick="addSymbol('log(')" class="p-2 bg-gray-100 hover:bg-gray-200 rounded text-sm mono">log</button>
167
+ </div>
168
+
169
+ <div class="flex space-x-3">
170
+ <button onclick="calculate()" class="px-4 py-2 bg-indigo-600 hover:bg-indigo-700 text-white rounded text-sm font-medium flex items-center">
171
+ <i class="fas fa-equals mr-2"></i> Calculate
172
+ </button>
173
+ <button onclick="analyzeExpression()" class="px-4 py-2 bg-white hover:bg-gray-50 border border-gray-200 rounded text-sm font-medium flex items-center">
174
+ <i class="fas fa-search mr-2"></i> Analyze
175
+ </button>
176
+ <button onclick="clearAll()" class="px-4 py-2 bg-white hover:bg-gray-50 border border-gray-200 rounded text-sm font-medium flex items-center">
177
+ <i class="fas fa-trash-alt mr-2"></i> Clear
178
+ </button>
179
+ </div>
180
+ </section>
181
 
182
+ <section id="historyPanel" class="hidden mt-8 border-t border-gray-200 pt-6">
183
+ <div class="flex justify-between items-center mb-4">
184
+ <h3 class="font-medium text-gray-900">Calculation History</h3>
185
+ <button onclick="clearHistory()" class="text-gray-500 hover:text-red-500 text-sm flex items-center">
186
+ <i class="fas fa-trash-alt mr-1"></i> Clear All
 
187
  </button>
188
  </div>
189
+ <div id="historyList" class="space-y-3"></div>
190
+ </section>
191
  </div>
192
 
193
+ <footer class="border-t border-gray-200 px-6 py-4 text-center text-gray-500 text-sm">
194
+ <p>SymCalc v1.0 · Symbolic Mathematics Calculator</p>
195
+ </footer>
196
  </div>
197
 
198
  <script>
 
212
  });
213
 
214
  function handleKeyPress(e) {
215
+ const input = document.getElementById('formulaInput');
216
+ const cursorPos = input.selectionStart;
217
+ const textBeforeCursor = input.value.substring(0, cursorPos);
218
+
219
+ // Handle autocomplete for functions
220
+ if (e.key === '(' && !e.shiftKey) {
221
+ const lastWord = textBeforeCursor.split(/[\s\+\-\*\/\^\(\)]/).pop();
222
+ if (['sin', 'cos', 'tan', 'log', 'ln', 'sqrt'].includes(lastWord)) {
223
+ e.preventDefault();
224
+ const newPos = cursorPos - lastWord.length;
225
+ input.value = input.value.substring(0, newPos) +
226
+ lastWord + '()' +
227
+ input.value.substring(cursorPos);
228
+ input.setSelectionRange(newPos + lastWord.length + 1,
229
+ newPos + lastWord.length + 1);
230
+ return;
231
+ }
232
+ }
233
+
234
+ // Handle Shift+Enter for new line
235
+ if (e.key === 'Enter' && e.shiftKey) {
236
+ e.preventDefault();
237
+ addSymbol('\n');
238
+ return;
239
+ }
240
+
241
+ // Handle Tab for symbol completion
242
+ if (e.key === 'Tab') {
243
+ e.preventDefault();
244
+ const lastWord = textBeforeCursor.split(/[\s\+\-\*\/\^\(\)]/).pop();
245
+ const matches = ['pi', 'theta', 'alpha', 'beta', 'gamma']
246
+ .filter(sym => sym.startsWith(lastWord.toLowerCase()));
247
+ if (matches.length === 1) {
248
+ const match = matches[0];
249
+ const newPos = cursorPos - lastWord.length;
250
+ input.value = input.value.substring(0, newPos) +
251
+ match +
252
+ input.value.substring(cursorPos);
253
+ input.setSelectionRange(newPos + match.length,
254
+ newPos + match.length);
255
+ }
256
+ return;
257
+ }
258
+
259
  const keyMap = {
260
  '0': '0', '1': '1', '2': '2', '3': '3', '4': '4',
261
  '5': '5', '6': '6', '7': '7', '8': '8', '9': '9',
 
264
  '(': '(', ')': ')',
265
  'Enter': '=',
266
  'Backspace': 'backspace',
267
+ 'Escape': 'clear',
268
+ 'ArrowUp': 'history-up',
269
+ 'ArrowDown': 'history-down'
270
  };
271
 
272
  const key = keyMap[e.key];
 
275
  if (key === '=') calculate();
276
  else if (key === 'backspace') backspace();
277
  else if (key === 'clear') clearAll();
278
+ else if (key === 'history-up') navigateHistory(-1);
279
+ else if (key === 'history-down') navigateHistory(1);
280
  else addSymbol(key);
281
  }
282
  }
283
+
284
+ let historyNavigationIndex = -1;
285
+ let historyNavigationTemp = '';
286
+
287
+ function navigateHistory(direction) {
288
+ const input = document.getElementById('formulaInput');
289
+
290
+ if (historyNavigationIndex === -1) {
291
+ historyNavigationTemp = input.value;
292
+ }
293
+
294
+ historyNavigationIndex += direction;
295
+
296
+ if (historyNavigationIndex < -1) {
297
+ historyNavigationIndex = -1;
298
+ } else if (historyNavigationIndex >= history.length) {
299
+ historyNavigationIndex = history.length - 1;
300
+ }
301
+
302
+ if (historyNavigationIndex === -1) {
303
+ input.value = historyNavigationTemp;
304
+ } else {
305
+ input.value = history[historyNavigationIndex].expression;
306
+ }
307
+
308
+ input.focus();
309
+ }
310
 
311
  function addSymbol(symbol) {
312
  const input = document.getElementById('formulaInput');
 
344
  // Not needed anymore since we're using textarea directly
345
  }
346
 
347
+ let pyodide;
348
+ async function initializePyodide() {
349
+ const loadingEl = document.getElementById('loading');
350
+ loadingEl.classList.remove('hidden');
351
+ document.getElementById('loadingText').textContent = "Loading SymPy...";
352
+
353
+ try {
354
+ pyodide = await loadPyodide({
355
+ indexURL: "https://cdn.jsdelivr.net/pyodide/v0.23.4/full/"
356
+ });
357
+ await pyodide.loadPackage(['sympy']);
358
+ loadingEl.classList.add('hidden');
359
+ return true;
360
+ } catch (error) {
361
+ document.getElementById('error').innerHTML = `
362
+ <div class="bg-red-50 border border-red-200 p-3 rounded">
363
+ <div class="font-medium text-red-600">Failed to initialize SymPy:</div>
364
+ <div class="text-sm">${error.message}</div>
365
+ </div>
366
+ `;
367
+ loadingEl.classList.add('hidden');
368
+ return false;
369
+ }
370
+ }
371
+
372
+ async function calculate() {
373
+ if (!pyodide) {
374
+ const initialized = await initializePyodide();
375
+ if (!initialized) return;
376
+ }
377
+
378
  const input = document.getElementById('formulaInput');
379
  currentExpression = input.value.trim();
380
  if (!currentExpression) return;
381
 
382
  const loadingEl = document.getElementById('loading');
383
  loadingEl.classList.remove('hidden');
384
+ document.getElementById('loadingText').textContent = "Calculating...";
385
+
386
+ try {
387
+ // Prepare Python code with proper error handling
388
+ let pythonCode = `
389
+ from sympy import *
390
+ from sympy.parsing.sympy_parser import parse_expr
391
+ import traceback
392
+
393
+ x, y, z = symbols('x y z')
394
+ result = None
395
+ error = None
396
+
397
+ try:
398
+ if '=' in expr:
399
+ if expr.count('=') == 1:
400
+ # Single equation solving
401
+ lhs, rhs = expr.split('=', 1)
402
+ lhs_expr = parse_expr(lhs.strip())
403
+ rhs_expr = parse_expr(rhs.strip())
404
+ solution = solve(Eq(lhs_expr, rhs_expr))
405
+ if isinstance(solution, dict):
406
+ result = "\\n".join([f"{k} = {v}" for k,v in solution.items()])
407
+ elif isinstance(solution, list):
408
+ result = "\\n".join([f"Solution {i+1}: {s}" for i,s in enumerate(solution)])
409
+ else:
410
+ result = str(solution)
411
+ else:
412
+ # System of equations
413
+ equations = [eq.strip() for eq in expr.split(';') if '=' in eq]
414
+ syms = set()
415
+ for eq in equations:
416
+ syms.update([str(s) for s in parse_expr(eq.split('=')[0].strip()).free_symbols])
417
+ syms = sorted(syms, key=lambda s: str(s))
418
+ eqs = [Eq(*map(parse_expr, eq.split('=', 1))) for eq in equations]
419
+ solution = solve(eqs, syms)
420
+ if solution:
421
+ if isinstance(solution, list):
422
+ result = "\\n".join([f"Solution {i+1}: {s}" for i,s in enumerate(solution)])
423
+ else:
424
+ result = "\\n".join([f"{k} = {v}" for k,v in solution.items()])
425
+ else:
426
+ result = "No solution found"
427
+ else:
428
+ # Expression evaluation
429
+ expr_parsed = parse_expr(expr)
430
+ result = str(expr_parsed.evalf(4))
431
+ except Exception as e:
432
+ error = traceback.format_exc()
433
+ `;
434
 
435
  // Use setTimeout to allow UI to update before heavy calculation
436
  setTimeout(() => {
437
+ document.getElementById('sympyCode').textContent = sympyCode;
438
+ document.getElementById('sympyCode').classList.remove('hidden');
439
  try {
440
  // Validate input first
441
  if (!currentExpression.trim()) throw "Please enter an expression";
 
443
 
444
  // Equation solving (e.g., "2x + 7y = 3z")
445
  if (currentExpression.includes('=')) {
446
+ // Handle multi-line equations (systems of equations)
447
+ const equations = currentExpression.split(/[\n,;]+/).map(eq => eq.trim()).filter(eq => eq.includes('='));
448
+ if (equations.length > 1) {
449
+ // System of equations case
450
+ const vars = new Set();
451
+ const equationsList = [];
452
+
453
+ for (const eq of equations) {
454
+ const parts = eq.split('=');
455
+ if (parts.length !== 2) throw "Each equation must have exactly one '='";
456
+
457
+ const left = parts[0].trim().replace(/\s+/g, '');
458
+ const right = parts[1].trim().replace(/\s+/g, '');
459
+
460
+ // Rearrange to standard form (ax + by = c)
461
+ const rearranged = `(${left}) - (${right})`;
462
+ equationsList.push(rearranged);
463
+
464
+ // Find variables
465
+ const varRegex = /([a-zA-Z])/g;
466
+ let match;
467
+ while ((match = varRegex.exec(left + right)) !== null) {
468
+ vars.add(match[1]);
469
+ }
470
+ }
471
+
472
+ if (equationsList.length !== vars.size) {
473
+ throw `Need ${vars.size} independent equations to solve for ${[...vars].join(', ')}`;
474
+ }
475
+
476
+ // System of equations solver using SymPy
477
+ sympyCode += `sol = solve([${equationsList.map(eq => `Eq(${eq}, 0)`).join(', ')}], [${[...vars].join(', ')}])\n`;
478
+
479
+ try {
480
+ // This would be replaced with actual Python execution in a real implementation
481
+ const solution = {};
482
+ [...vars].forEach(v => solution[v] = `solution_for_${v}`);
483
+
484
+ let resultText = '';
485
+ for (const [varName, value] of Object.entries(solution)) {
486
+ resultText += `${varName} = ${value}\n`;
487
+ }
488
+
489
+ document.getElementById('result').textContent = resultText;
490
+ addToHistory(currentExpression, resultText);
491
+ return;
492
+ } catch (e) {
493
+ throw `Failed to solve system: ${e.message || e}`;
494
+ }
495
+
496
+ throw `System with ${vars.size} variables requires ${vars.size} equations`;
497
+ }
498
+
499
+ // Single equation case
500
  const parts = currentExpression.split('=');
501
+ if (parts.length !== 2) throw "Each equation must have exactly one '='";
502
 
503
  const left = parts[0].trim();
504
  const right = parts[1].trim();
 
527
  else if (variables.size === 1) {
528
  // Single variable case
529
  const varName = [...variables][0];
530
+ sympyCode += `sol = solve(Eq(${left}, ${right}), ${varName})\n`;
 
 
531
 
532
+ try {
533
+ // This would be replaced with actual Python execution in a real implementation
534
+ const solution = `solution_for_${varName}`;
535
+ document.getElementById('result').textContent = `${varName} = ${solution}`;
536
+ addToHistory(currentExpression, solution);
537
+ return;
538
+ } catch (e) {
539
+ throw `Failed to solve equation: ${e.message || e}`;
540
+ }
 
 
 
 
541
  }
542
  else {
543
  // Multiple variables case
 
549
  }
550
  }
551
 
552
+ // Generate SymPy evaluation code
553
+ sympyCode += `expr = ${currentExpression.replace(/=/g, '==')}\n`;
 
 
 
 
 
 
 
 
 
 
 
 
554
 
555
+ if (variables.length > 0) {
556
+ sympyCode += `result = expr.subs({${variables.map(v => `${v}: 1`).join(', ')}})\n`;
557
+ } else {
558
+ sympyCode += `result = N(expr)\n`;
559
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
560
 
561
  // Sanitize the expression before evaluation
562
  const sanitized = expr.replace(/Math\./g, '');
 
637
  if (typeof error === 'string' && error.startsWith('<div')) {
638
  document.getElementById('error').innerHTML = error;
639
  } else {
640
+ document.getElementById('error').innerHTML = `
641
+ <div class="analysis-box">
642
+ <div class="flex items-center text-red-500 mb-2">
643
+ <i class="fas fa-exclamation-circle mr-2"></i>
644
+ <div class="font-medium">SymPy Calculation Error</div>
645
+ </div>
646
+ <div class="text-sm mb-3">${error}</div>
647
+ <div class="text-xs mono bg-gray-100 p-2 rounded mb-3">${sympyCode}</div>
648
+ <div class="analysis-tip bg-red-50 p-3 rounded-lg">
649
+ <div class="flex items-center text-red-600 font-medium mb-1">
650
+ <i class="fas fa-lightbulb mr-2"></i>
651
+ <div>SymPy Suggestions</div>
652
+ </div>
653
+ <ul class="list-disc pl-5 space-y-1 text-sm">
654
+ ${error.includes('variables') ? '<li>Use symbols() to define variables first</li>' : ''}
655
+ ${error.includes('solve') ? '<li>Ensure equations are properly formatted</li>' : ''}
656
+ <li>Use simplify() for complex expressions</li>
657
+ <li>Check SymPy documentation for function syntax</li>
658
+ </ul>
659
+ </div>
660
+ </div>
661
+ `;
662
  }
663
  document.getElementById('result').textContent = '';
 
 
 
664
  console.error("Calculation error:", error);
 
 
 
665
  } finally {
666
  loadingEl.classList.add('hidden');
667
  }
 
688
  return str;
689
  }
690
 
691
+ function addToHistory(expression, result, steps = null, sympyCode = null) {
692
+ const historyItem = {
693
  expression,
694
  result,
695
+ steps,
696
+ sympyCode,
697
+ timestamp: new Date().toISOString(),
698
+ id: Date.now().toString()
699
+ };
700
+
701
+ history.unshift(historyItem);
702
 
703
+ // Keep only last 20 items
704
+ if (history.length > 20) history.pop();
705
 
706
  localStorage.setItem('calcHistory', JSON.stringify(history));
707
  renderHistory();
708
+ return historyItem;
709
  }
710
 
711
  function renderHistory() {
 
716
  const historyItem = document.createElement('div');
717
  historyItem.className = 'p-3 history-item fade-in';
718
  historyItem.innerHTML = `
719
+ <div class="flex justify-between items-start">
720
+ <div>
721
+ <div class="text-xs text-gray-400">${new Date(item.timestamp).toLocaleString()}</div>
722
+ <div class="font-mono text-gray-700">${item.expression}</div>
723
+ </div>
724
+ <div class="font-medium text-indigo-600">= ${formatResult(item.result)}</div>
725
+ </div>
726
  `;
727
 
728
  historyItem.addEventListener('click', () => {
 
745
  const panel = document.getElementById('historyPanel');
746
  panel.classList.toggle('hidden');
747
  }
748
+
749
+ function analyzeExpression() {
750
+ const input = document.getElementById('formulaInput');
751
+ const expr = input.value.trim();
752
+ if (!expr) return;
753
+
754
+ let analysis = '';
755
+
756
+ // Basic expression info
757
+ analysis += `<div class="analysis-box">
758
+ <div class="flex items-center mb-3">
759
+ <i class="fas fa-search text-indigo-500 mr-2"></i>
760
+ <div class="analysis-title text-lg font-semibold text-gray-800">Expression Analysis</div>
761
+ </div>
762
+ <div class="grid grid-cols-2 gap-3 mb-3">
763
+ <div class="bg-white p-2 rounded border border-gray-100">
764
+ <div class="text-xs text-gray-500">Type</div>
765
+ <div class="font-medium">${expr.includes('=') ? 'Equation' : 'Expression'}</div>
766
+ </div>
767
+ <div class="bg-white p-2 rounded border border-gray-100">
768
+ <div class="text-xs text-gray-500">Length</div>
769
+ <div class="font-medium">${expr.length} chars</div>
770
+ </div>
771
+ </div>`;
772
+
773
+ // Check for variables
774
+ const variables = [...new Set(expr.match(/[a-zA-Z]/g) || [])];
775
+ const operators = [...new Set(expr.match(/[\+\-\*\/\^]/g) || [])];
776
+
777
+ if (variables.length > 0 || operators.length > 0) {
778
+ analysis += `<div class="grid grid-cols-2 gap-3 mb-3">`;
779
+ if (variables.length > 0) {
780
+ analysis += `<div class="bg-white p-2 rounded border border-gray-100">
781
+ <div class="text-xs text-gray-500">Variables</div>
782
+ <div class="font-mono text-indigo-600">${variables.join(', ')}</div>
783
+ </div>`;
784
+ }
785
+ if (operators.length > 0) {
786
+ analysis += `<div class="bg-white p-2 rounded border border-gray-100">
787
+ <div class="text-xs text-gray-500">Operators</div>
788
+ <div class="font-mono text-indigo-600">${operators.map(op => {
789
+ if (op === '*') return '×';
790
+ if (op === '/') return '÷';
791
+ return op;
792
+ }).join(', ')}</div>
793
+ </div>`;
794
+ }
795
+ analysis += `</div>`;
796
+ }
797
+
798
+ // Check for functions
799
+ const functions = [...new Set(expr.match(/(sin|cos|tan|ln|log|sqrt)\(/g) || [])];
800
+ if (functions.length > 0) {
801
+ analysis += `<div class="analysis-item">
802
+ <span class="font-medium">Functions:</span>
803
+ <span class="font-mono bg-gray-100 px-1 rounded">${functions.join('</span>, <span class="font-mono bg-gray-100 px-1 rounded">')}</span>
804
+ </div>`;
805
+ }
806
+
807
+ // Check for constants
808
+ const constants = [...new Set(expr.match(/(π|e)/g) || [])];
809
+ if (constants.length > 0) {
810
+ analysis += `<div class="analysis-item">
811
+ <span class="font-medium">Constants:</span>
812
+ <span class="font-mono bg-gray-100 px-1 rounded">${constants.join('</span>, <span class="font-mono bg-gray-100 px-1 rounded">')}</span>
813
+ </div>`;
814
+ }
815
+
816
+ // Check for parentheses balance
817
+ const openParens = (expr.match(/\(/g) || []).length;
818
+ const closeParens = (expr.match(/\)/g) || []).length;
819
+ if (openParens !== closeParens) {
820
+ analysis += `<div class="analysis-item text-red-500">
821
+ <i class="fas fa-exclamation-triangle mr-1"></i>
822
+ Unbalanced parentheses (${openParens} open, ${closeParens} close)
823
+ </div>`;
824
+ }
825
+
826
+ // Check for potential errors
827
+ if (expr.match(/\/\s*0/g)) {
828
+ analysis += `<div class="analysis-item text-red-500">
829
+ <i class="fas fa-exclamation-triangle mr-1"></i>
830
+ Potential division by zero detected
831
+ </div>`;
832
+ }
833
+ if (expr.match(/\^\-?\d+/g)) {
834
+ analysis += `<div class="analysis-item">
835
+ <i class="fas fa-info-circle text-blue-500 mr-1"></i>
836
+ Contains exponentiation operations
837
+ </div>`;
838
+ }
839
+ if (expr.match(/\!/g)) {
840
+ analysis += `<div class="analysis-item">
841
+ <i class="fas fa-info-circle text-blue-500 mr-1"></i>
842
+ Contains factorial operations
843
+ </div>`;
844
+ }
845
+
846
+ // Equation specific analysis
847
+ if (expr.includes('=')) {
848
+ const parts = expr.split('=');
849
+ if (parts.length === 2) {
850
+ const left = parts[0].trim();
851
+ const right = parts[1].trim();
852
+
853
+ analysis += `<div class="analysis-item mt-3">
854
+ <div class="font-medium">Equation Analysis:</div>
855
+ <div class="grid grid-cols-2 gap-2 mt-2">
856
+ <div class="bg-gray-50 p-2 rounded">
857
+ <div class="text-xs text-gray-500">Left Side</div>
858
+ <div class="font-mono">${left}</div>
859
+ </div>
860
+ <div class="bg-gray-50 p-2 rounded">
861
+ <div class="text-xs text-gray-500">Right Side</div>
862
+ <div class="font-mono">${right}</div>
863
+ </div>
864
+ </div>
865
+ </div>`;
866
+
867
+ if (variables.length > 0) {
868
+ analysis += `<div class="analysis-item">
869
+ <div class="font-medium">Solution Strategy:</div>
870
+ <div class="mt-1 text-sm">
871
+ ${variables.length === 1 ?
872
+ `To solve for ${variables[0]}, isolate the variable on one side` :
873
+ `Need ${variables.length} independent equations to solve for ${variables.join(', ')}`}
874
+ </div>
875
+ </div>`;
876
+ }
877
+ }
878
+ }
879
+
880
+ analysis += `<div class="analysis-tip bg-indigo-50 p-3 rounded-lg mt-4">
881
+ <div class="flex items-center text-indigo-600 font-medium mb-2">
882
+ <i class="fas fa-lightbulb mr-2"></i>
883
+ <div>Quick Tips</div>
884
+ </div>
885
+ <ul class="list-disc pl-5 space-y-1 text-sm">
886
+ <li>Use '=' to create equations (e.g. 2x+3=7)</li>
887
+ <li>Assign values to variables (e.g. x=5) before evaluation</li>
888
+ <li>Press 'Calculate' or Enter to evaluate</li>
889
+ ${variables.length > 0 ? `<li>For ${variables.length > 1 ? 'systems of equations' : 'equations'}, provide ${variables.length} equation${variables.length > 1 ? 's' : ''}</li>` : ''}
890
+ ${functions.length > 0 ? `<li>Trigonometric functions use radians by default</li>` : ''}
891
+ <li>Use parentheses to control operation order</li>
892
+ </ul>
893
+ </div></div>`;
894
+
895
+ document.getElementById('error').innerHTML = analysis;
896
+ document.getElementById('result').textContent = '';
897
+ }
898
  </script>
899
  <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=shism/symcalc" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
900
  </html>