cdn loaded latex math
This commit is contained in:
@@ -7,7 +7,6 @@ from pathlib import Path
|
|||||||
from jinja2 import Environment, FileSystemLoader
|
from jinja2 import Environment, FileSystemLoader
|
||||||
import base64
|
import base64
|
||||||
import random
|
import random
|
||||||
import time
|
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
import marko
|
import marko
|
||||||
@@ -19,6 +18,9 @@ from hashes.hashes import hash_list
|
|||||||
from htmlhandler import htmlhandler as Handler
|
from htmlhandler import htmlhandler as Handler
|
||||||
from lua import plugin_manager
|
from lua import plugin_manager
|
||||||
|
|
||||||
|
# Import your LaTeX extension
|
||||||
|
from hashes.util.LaTeXRenderer import LaTeXExtension
|
||||||
|
|
||||||
plugin_manager = plugin_manager.PluginManager()
|
plugin_manager = plugin_manager.PluginManager()
|
||||||
plugin_manager.load_all() # load plugins
|
plugin_manager.load_all() # load plugins
|
||||||
|
|
||||||
@@ -35,8 +37,8 @@ RUST_PARSER_PATH = ROOT / "fastmd" / "target" / "release" / f"fastmd{exe_ext}"
|
|||||||
if not RUST_PARSER_PATH.exists():
|
if not RUST_PARSER_PATH.exists():
|
||||||
RUST_PARSER_PATH = ROOT / "fastmd" / "target" / "debug" / f"fastmd{exe_ext}"
|
RUST_PARSER_PATH = ROOT / "fastmd" / "target" / "debug" / f"fastmd{exe_ext}"
|
||||||
|
|
||||||
# Python Markdown parser with table support
|
# Python Markdown parser with table support AND LaTeX extension
|
||||||
markdown_parser = marko.Markdown(extensions=[GFM])
|
markdown_parser = marko.Markdown(extensions=[GFM, LaTeXExtension()])
|
||||||
|
|
||||||
# Threshold for switching to Rust parser (number of lines)
|
# Threshold for switching to Rust parser (number of lines)
|
||||||
RUST_PARSER_THRESHOLD = 1000
|
RUST_PARSER_THRESHOLD = 1000
|
||||||
|
|||||||
42
hashes/util/LaTeXRenderer.py
Normal file
42
hashes/util/LaTeXRenderer.py
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
# latex_extension.py
|
||||||
|
import marko
|
||||||
|
import marko.block
|
||||||
|
import marko.inline
|
||||||
|
from marko.md_renderer import MarkdownRenderer
|
||||||
|
import re
|
||||||
|
from log.Logger import Logger
|
||||||
|
logger = Logger()
|
||||||
|
|
||||||
|
class BlockFormula(marko.block.BlockElement):
|
||||||
|
pattern = re.compile(r"\$\$ *\n([\s\S]+?)^\$\$ *$", re.MULTILINE)
|
||||||
|
def __init__(self, match):
|
||||||
|
logger.log_debug("Did shit at __init__ for blockformula")
|
||||||
|
self.children = [marko.inline.RawText(match.group(1))]
|
||||||
|
@classmethod
|
||||||
|
def match(cls, source):
|
||||||
|
return source.expect_re(cls.pattern)
|
||||||
|
@classmethod
|
||||||
|
def parse(cls, source):
|
||||||
|
logger.log_debug("Did some shit with Latex")
|
||||||
|
match = source.match
|
||||||
|
source.consume()
|
||||||
|
return match
|
||||||
|
|
||||||
|
class Paragraph(marko.block.Paragraph):
|
||||||
|
override = True
|
||||||
|
@classmethod
|
||||||
|
def break_paragraph(cls, source, lazy=False):
|
||||||
|
if BlockFormula.match(source):
|
||||||
|
return True
|
||||||
|
return super().break_paragraph(source, lazy=lazy)
|
||||||
|
|
||||||
|
class Renderer:
|
||||||
|
def render_block_formula(self, element):
|
||||||
|
# Render as HTML with MathJax-compatible format
|
||||||
|
return '\n<div class="math-block">$$\n' + self.render_children(element) + '$$</div>\n'
|
||||||
|
|
||||||
|
class LaTeXExtension:
|
||||||
|
logger.log_debug("Did shit at __init__ for latexextension")
|
||||||
|
elements = [BlockFormula, Paragraph]
|
||||||
|
parser_mixins = []
|
||||||
|
renderer_mixins = [Renderer]
|
||||||
@@ -20,6 +20,8 @@
|
|||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.11.0/jszip.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.11.0/jszip.min.js"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js"></script>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js" id="MathJax-script"></script>
|
||||||
|
|
||||||
<!-- remove if causing issues -->
|
<!-- remove if causing issues -->
|
||||||
<script src="../js/post/lazyimg.js"></script>
|
<script src="../js/post/lazyimg.js"></script>
|
||||||
<script src="../js/shared/theme.js"></script>
|
<script src="../js/shared/theme.js"></script>
|
||||||
|
|||||||
104
lua/luarails.lua
Normal file
104
lua/luarails.lua
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
-- Guardrails and safe patterns for plugin development
|
||||||
|
|
||||||
|
-- Safe string operations
|
||||||
|
function safe_concat(...)
|
||||||
|
local result = {}
|
||||||
|
for i, v in ipairs({...}) do
|
||||||
|
if v ~= nil then
|
||||||
|
table.insert(result, tostring(v))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return table.concat(result)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Safe table operations
|
||||||
|
function table_contains(tbl, value)
|
||||||
|
for _, v in ipairs(tbl) do
|
||||||
|
if v == value then return true end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function table_keys(tbl)
|
||||||
|
local keys = {}
|
||||||
|
for k, _ in pairs(tbl) do
|
||||||
|
table.insert(keys, k)
|
||||||
|
end
|
||||||
|
return keys
|
||||||
|
end
|
||||||
|
|
||||||
|
function table_values(tbl)
|
||||||
|
local values = {}
|
||||||
|
for _, v in pairs(tbl) do
|
||||||
|
table.insert(values, v)
|
||||||
|
end
|
||||||
|
return values
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Safe string escaping
|
||||||
|
function escape_html(str)
|
||||||
|
if str == nil then return "" end
|
||||||
|
local s = tostring(str)
|
||||||
|
s = string.gsub(s, "&", "&")
|
||||||
|
s = string.gsub(s, "<", "<")
|
||||||
|
s = string.gsub(s, ">", ">")
|
||||||
|
s = string.gsub(s, '"', """)
|
||||||
|
s = string.gsub(s, "'", "'")
|
||||||
|
return s
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Pattern validation
|
||||||
|
function is_valid_filename(name)
|
||||||
|
if name == nil or name == "" then return false end
|
||||||
|
-- Block directory traversal
|
||||||
|
if string.match(name, "%.%.") then return false end
|
||||||
|
if string.match(name, "/") or string.match(name, "\\\\") then return false end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Safe error handling wrapper
|
||||||
|
function try_catch(fn, catch_fn)
|
||||||
|
local status, err = pcall(fn)
|
||||||
|
if not status and catch_fn then
|
||||||
|
catch_fn(err)
|
||||||
|
end
|
||||||
|
return status
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Request validation
|
||||||
|
function validate_request(req, required_fields)
|
||||||
|
if type(req) ~= "table" then return false, "Request must be a table" end
|
||||||
|
for _, field in ipairs(required_fields) do
|
||||||
|
if req[field] == nil then
|
||||||
|
return false, "Missing required field: " .. field
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true, nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Rate limiting helper (simple in-memory)
|
||||||
|
_rate_limits = _rate_limits or {}
|
||||||
|
function check_rate_limit(key, max_calls, window_seconds)
|
||||||
|
local now = os.time()
|
||||||
|
if _rate_limits[key] == nil then
|
||||||
|
_rate_limits[key] = {count = 1, window_start = now}
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
local rl = _rate_limits[key]
|
||||||
|
if now - rl.window_start > window_seconds then
|
||||||
|
-- Reset window
|
||||||
|
rl.count = 1
|
||||||
|
rl.window_start = now
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
if rl.count >= max_calls then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
rl.count = rl.count + 1
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
log("Lua guardrails initialized")
|
||||||
128
markdown/Rotation.md
Normal file
128
markdown/Rotation.md
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
---
|
||||||
|
summary: "Würfelrotation mit Matrizen die Multipliziert werden erkläret"
|
||||||
|
---
|
||||||
|
|
||||||
|
# Rotation eines Würfels um die x-Achse
|
||||||
|
|
||||||
|
Wir wollen verstehen, wie man einen Würfel im Raum um die x-Achse dreht.
|
||||||
|
|
||||||
|
## 1. Punkte eines Würfels
|
||||||
|
|
||||||
|
Ein Würfel hat 8 Eckpunkte. Wenn wir den Würfel in der Mitte des Koordinatensystems platzieren, können wir die Punkte als Vektoren schreiben:
|
||||||
|
|
||||||
|
$$
|
||||||
|
\mathbf{A} = (1, 1, 1), \quad
|
||||||
|
\mathbf{B} = (1, 1, -1), \quad
|
||||||
|
\mathbf{C} = (1, -1, 1), \quad
|
||||||
|
\mathbf{D} = (1, -1, -1)
|
||||||
|
$$
|
||||||
|
|
||||||
|
$$
|
||||||
|
\mathbf{E} = (-1, 1, 1), \quad
|
||||||
|
\mathbf{F} = (-1, 1, -1), \quad
|
||||||
|
\mathbf{G} = (-1, -1, 1), \quad
|
||||||
|
\mathbf{H} = (-1, -1, -1)
|
||||||
|
$$
|
||||||
|
|
||||||
|
Jeder Punkt hat drei Koordinaten
|
||||||
|
$$
|
||||||
|
(x', y', z')
|
||||||
|
$$
|
||||||
|
|
||||||
|
## 2. Rotationsmatrix um die x-Achse
|
||||||
|
|
||||||
|
Wenn wir einen Punkt
|
||||||
|
|
||||||
|
$$
|
||||||
|
\mathbf{v} = \begin{pmatrix} x \\ y \\ z \end{pmatrix}
|
||||||
|
$$
|
||||||
|
|
||||||
|
um die x-Achse um einen Winkel $\theta$ drehen wollen, benutzen wir die Rotationsmatrix:
|
||||||
|
|
||||||
|
$$
|
||||||
|
R_x(\theta) =
|
||||||
|
\begin{pmatrix}
|
||||||
|
1 & 0 & 0 \\
|
||||||
|
0 & \cos\theta & -\sin\theta \\
|
||||||
|
0 & \sin\theta & \cos\theta
|
||||||
|
\end{pmatrix}
|
||||||
|
$$
|
||||||
|
|
||||||
|
**Hinweis:**
|
||||||
|
- Die x-Koordinate bleibt gleich, weil wir um die x-Achse drehen.
|
||||||
|
- y und z verändern sich je nach Winkel $\theta$.
|
||||||
|
|
||||||
|
## 3. Berechnung des neuen Punktes
|
||||||
|
|
||||||
|
Der neue Punkt $\mathbf{v}'$ nach der Drehung ist:
|
||||||
|
|
||||||
|
$$
|
||||||
|
\mathbf{v}' = R_x(\theta) \mathbf{v} =
|
||||||
|
\begin{pmatrix}
|
||||||
|
1 & 0 & 0 \\
|
||||||
|
0 & \cos\theta & -\sin\theta \\
|
||||||
|
0 & \sin\theta & \cos\theta
|
||||||
|
\end{pmatrix}
|
||||||
|
\begin{pmatrix} x \\ y \\ z \end{pmatrix} =
|
||||||
|
\begin{pmatrix}
|
||||||
|
x \\
|
||||||
|
y \cos\theta - z \sin\theta \\
|
||||||
|
y \sin\theta + z \cos\theta
|
||||||
|
\end{pmatrix}
|
||||||
|
$$
|
||||||
|
|
||||||
|
## 4. Beispiel
|
||||||
|
|
||||||
|
Drehen wir den Punkt
|
||||||
|
|
||||||
|
$$
|
||||||
|
\mathbf{A} = (1,1,1)
|
||||||
|
$$
|
||||||
|
|
||||||
|
um
|
||||||
|
|
||||||
|
$$
|
||||||
|
\theta = 90^\circ = \frac{\pi}{2}
|
||||||
|
$$
|
||||||
|
|
||||||
|
Dann gilt:
|
||||||
|
|
||||||
|
$$
|
||||||
|
\cos \theta = 0, \quad \sin \theta = 1
|
||||||
|
$$
|
||||||
|
|
||||||
|
$$
|
||||||
|
\mathbf{A}' =
|
||||||
|
\begin{pmatrix}
|
||||||
|
1 \\
|
||||||
|
1 \cdot 0 - 1 \cdot 1 \\
|
||||||
|
1 \cdot 1 + 1 \cdot 0
|
||||||
|
\end{pmatrix} =
|
||||||
|
\begin{pmatrix}
|
||||||
|
1 \\ -1 \\ 1
|
||||||
|
\end{pmatrix}
|
||||||
|
$$
|
||||||
|
|
||||||
|
## 5. Tabelle aller Punkte nach Rotation
|
||||||
|
|
||||||
|
$$
|
||||||
|
\begin{array}{c|c}
|
||||||
|
\text{Originalpunkt} & \text{Punkt nach Rotation} \\
|
||||||
|
\hline
|
||||||
|
A (1,1,1) & (1,-1,1) \\
|
||||||
|
B (1,1,-1) & (1,-1,-1) \\
|
||||||
|
C (1,-1,1) & (1,-1,-1) \\
|
||||||
|
D (1,-1,-1) & (1,1,-1) \\
|
||||||
|
E (-1,1,1) & (-1,-1,1) \\
|
||||||
|
F (-1,1,-1) & (-1,-1,-1) \\
|
||||||
|
G (-1,-1,1) & (-1,1,1) \\
|
||||||
|
H (-1,-1,-1) & (-1,1,-1) \\
|
||||||
|
\end{array}
|
||||||
|
$$
|
||||||
|
|
||||||
|
## Fazit
|
||||||
|
|
||||||
|
- x bleibt unverändert
|
||||||
|
- y und z ändern sich je nach Winkel
|
||||||
|
- Rotationsmatrizen sind ein mächtiges Werkzeug, um Objekte im 3D-Raum zu bewegen
|
||||||
|
|
||||||
Reference in New Issue
Block a user