EaglePress

EaglePress Download v1.43!

Hot off the Press!
Download link: EaglePress v1.43 d87421f3_eaglepress_v1.43.zip

SHA-512 hash of EaglePress v1.43:

6297aab079a01877d3d2343ee009861d45c598876cc995adc07d46e6e853244ce60cef4803772d670db65b1b302098ac5d80fa45e98e9d170afcceaa71bd0650

Welcome to EaglePress

--- how to configuration of Apache2 / Nginx
--- GitHub EaglePress v1.43

Markdown + HTML
# EaglePress — Summary Project Press

**Platform:** Python 3 CGI + PostgreSQL Web Publishing System
**Current Version:** 1.43
**Date:** May 2026

---

## What Is EaglePress?

A self-hosted, open-source CMS and blog platform built entirely in Python 3 and PostgreSQL. No web framework. No ORM. Runs on any Apache or Nginx server with CGI support.

---

## Core Highlights

- Pure Python 3 CGI router — zero external framework dependency
- PostgreSQL backend — 10 normalized tables, FK constraints, indexed queries
- Zero-config installer — one SQL file + one Python script sets up everything
- Clean URL routing via `PATH_INFO` with `?r=` fallback
- Full theme system — drop-in theme directories, exec-based renderer

---

## Security

- PBKDF2-HMAC-SHA256 passwords — 310,000 iterations (NIST-recommended)
- Session tokens — 64-character hex, stored in DB, 30-day expiry with IP + user-agent logging
- 100% parameterized queries — no SQL injection surface
- XSS protection — all output routed through `html.escape()`
- Upload safety — extension + MIME-type whitelist, server-side enforced
- CGI errors isolated to `tmp_errors/` — never exposed to visitors

---

## CGI Library — `cgi_improved2.py`

A custom drop-in replacement for Python's deprecated `cgi` and `cgitb` standard library modules, written specifically for EaglePress.

**Parsing architecture:**
- Streaming 64 KB-chunk multipart parser — peak memory scales with the largest single part, not the total body
- Replaces the legacy approach of reading the entire POST body into RAM before parsing

**Hard request limits:**
- 10 MB maximum total POST body
- 5 MB maximum per uploaded file
- 200 maximum form fields per request
- 70-byte maximum boundary length (RFC 2046)
- 1024-byte maximum uploaded filename length

**Security measures built into the library:**
- RFC 5987 filename decoding — handles `filename*=UTF-8''encoded` form
- Charset validation for text parts against a safe-charsets allowlist
- Error log redaction — sensitive local variable names (`password`, `password_hash`, `token`, `session`, `USERNAME`, `PASSWORD`, `cc_number`, database cursors, raw request body) are replaced with `<redacted>` in all traceback logs
- HTTP header redaction — `HTTP_COOKIE`, `HTTP_AUTHORIZATION`, `HTTP_PROXY_AUTHORIZATION` stripped from logged environment dumps
- Log file permissions set to `0o600` — readable only by the server process owner
- Traceback output suppressed from HTTP responses by default (`display=0`)
- Variable repr truncation — log entries capped at 200 characters per value, 30 variables per frame

**Drop-in compatible** — same `cgi.FieldStorage()` / `cgitb.enable()` interface as the standard library.

---

## Content Management

- Posts and pages — draft, published, preview states; soft-delete to trash
- Auto-generated slugs — deduplicated with `-2`, `-3` suffixes
- Categories (hierarchical) and tags
- Featured images, view counter, comment toggle per post
- Comment threading with moderation queue
- User profiles with avatar upload and Gravatar fallback

---

## Markdown Parser

Custom server-side Markdown-to-HTML with no third-party packages:

- ATX headings, bold, italic, strikethrough
- Fenced code blocks with syntax highlighting
- Ordered and unordered lists, blockquotes, horizontal rules
- Extended image syntax — size (`=WxH`), alignment, title
- Download buttons for non-image file links
- Shortcodes for embedding post/page links
- External links auto-tagged `rel="noopener"`
- Raw HTML pass-through

---

## Syntax Highlighting

Custom pure-Python engine (`syntax_highlight.py` + `syntax_themes.py`) — no external packages.

**12 languages** + plain text: Python 3, JavaScript, CSS, HTML, PHP, Bash, C, C++, Lua, Perl, SQL, Markdown + HTML

**11 colour themes**: github-dark, atom-one-dark, monokai, dracula, nord, tokyo-night-dark, github, atom-one-light, solarized-light, vs, xcode

**Per-block features:** language label, language selector drop-down, theme selector drop-down, copy button, keyboard navigation

**Score-based auto-detection** — no lang hint needed; fenced block content stripped before scoring to prevent embedded language examples from polluting outer document detection

---

## Frontend Reader Experience

- Image lightbox with keyboard navigation
- Reading progress bar
- Back-to-top button
- Like button (localStorage)
- Social share — Copy link, Twitter, Facebook
- Lazy image loading + fade-in scroll animations

---

## Admin Panel

- Dashboard with live stats
- Post / page editor with live Markdown preview
- Media library — upload, browse, delete
- User management — five roles: admin, editor, author, contributor, subscriber
- Comment moderation queue
- Category management
- Site settings

---

## Theme System

Themes are self-contained directories. The active theme's `theme.py` is exec'd by the router with all page variables pre-populated. Bundled themes: `firstTheme`, `secondTheme`, `americanTheme`, `USAtheme`.

---

## Version History (overview)

| Version | Title |
|---|---|
| v1.0 | Foundation Release |
| v1.01 | Theme Expansion |
| v1.02 | Syntax Highlighting Engine |
| v1.03 | Markdown Parser Overhaul |
| v1.04 | SQL Language Support |
| v1.05 | Per-Block Theme Scoping |
| v1.06 | Reader Theme Persistence |
| v1.07 | Frontend Reader Experience |
| v1.08 | Streaming CGI Parser & Security (`cgi_improved2.py`) |
| v1.09 | Project Documentation & Archive Policy |
| v1.10 | Markdown + HTML Language & SQL Detection Fix |
| v1.11 | Markdown Auto-Detection Fix — fenced block stripping |
| v1.12 | Markdown Detection Hardened — ATX heading rule, tilde fence signal |
| v1.13 | highlight.js Markdown Grammar Fix — underscore in identifiers (`highlight_custom_improved.js`) |
| v1.14 | Markdown Highlighting — server-side Python tokenizer in `syntax_highlight.py`; JS grammar `h.regex.concat()` fixed |
| v1.15 | Markdown Highlighting — JS tokenizer in `highlight_custom_improved.js` replaces Python; patches `hljs.highlightElement()` for consistent single code path; all themes now load custom script |
| v1.16 | USAtheme + "Register" → "Create Account" | New USAtheme (red-dominant americanTheme variant); "Register" label renamed to "Create Account" in nav, login page link, and browser title across all themes and core |
| v1.17 | Code Block Word Wrap Toggle | Checkbox in code block toolbar (left of theme dropdown) to toggle `white-space: pre-wrap`; gold `#D4AF37` outline on checkbox when active; state persisted per-block in localStorage (`ep_ww_{pathname}_{index}`); restored on page load; all 4 themes + admin panel |
| v1.18 | Admin Password Change + Theme Preview | Settings page: Account Security section — current/new/confirm password fields with show/hide eye toggle, live strength meter (Weak→Fair→Good→Strong), confirm-match hint, AJAX endpoint `www_password_change.py`; Appearance section: live theme preview image (`.svg`) below active-theme dropdown, updates dynamically on selection change; SVG preview images for all 4 bundled themes |
| v1.19 | Firefox Android Word Wrap Fix | Added `.ep-code-block.ep-code-wrap pre code` CSS rule in `styles_core.css`; targets the `code` element directly with `white-space: pre-wrap`, `word-break: break-word`, `overflow-wrap: anywhere`, `overflow-x: hidden` — overrides the HLJS CDN stylesheet's `pre code.hljs { overflow-x: auto }` which was creating an independent scroll container in Gecko, preventing inherited wrap properties from taking effect on Firefox for Android |
| v1.20 | Custom Arbitrary Slug Mode | Third slug option in post/page editor — "Custom slug" lets editors type any arbitrary URL slug; `ep_posts.use_title_slug` column changed from `BOOLEAN` to `TEXT` (`'title'`/`'id'`/`'custom'`); migration file `sql/migrations/1.20.sql` provided ⚠️ DB migration |
| v1.21 | Dynamic sys.path in AJAX Scripts | Replaced hardcoded `/var/websites/EaglePress/www` path in all 15 AJAX scripts with `_THIS_DIR`/`_WWW_DIR` derivation via `__file__`; codebase no longer tied to a specific deployment path |
| v1.22 | Database Migration System | `sql/migrate.py` runner; `ep_schema_version` table tracks schema version in the DB; `sql/migrations/` directory holds numbered idempotent SQL upgrade files; `install.py` stamps version on fresh install; `setup.sql` includes version table |
| v1.23 | Image Alignment CSS Fix | Fixed `.ep-img-center` / `.ep-img-left` / `.ep-img-right` not applying on published posts; `.ep-post-content img` (specificity 0,1,1) was overriding alignment classes (0,1,0); scoped all three to `.ep-post-content .ep-img-*` (0,2,0) in all 4 themes |
| v1.24 | Post Delete Count Correction | `www_post_delete.py` now decrements `ep_users.post_count`, `ep_categories.post_count`, and `ep_tags.post_count` when a post is removed |
| v1.25 | Editable Display Name + Profile Author Fix | Admin Users panel: display name is now an editable text input with Save button wired to new `www_user_displayname_save.py` endpoint; fixed profile page post cards showing "Unknown" author by adding `ep_users` JOIN to profile posts query |
| v1.26 | Profile Page Featured Image Fix | Added `LEFT JOIN ep_media` and `featured_image_url` / `featured_image_id` / `show_featured_image` fields to profile posts query in `index.py`; post cards on user profile pages now show featured images matching home page behaviour |
| v1.27 | Light/Dark Mode Toggle + Full Dark Theme | Sun/moon toggle button left of search in all 4 themes and admin topbar; OS `prefers-color-scheme` detection on first visit; unified `ep_theme` localStorage key; anti-FOUC inline script eliminates flash; CSS `::before` emoji pattern (☀️ light / 🌙 dark); per-theme dark palettes preserving accent colors; americanTheme and USAtheme background fix (body/main/single-post hardcoded dark; post content headings readable accent colors; sidebar/widget dark); firstTheme single-post dark background; admin editor dark background |
| v1.28 | Dark Mode Post Title + Category Count Accuracy | americanTheme: single-post title now off-white (`var(--am-text)`) in dark mode instead of dark navy; sidebar category widget query replaced with live `COUNT` of published posts (`JOIN ep_posts WHERE status='published'`) so any category with zero published posts — including the default "Uncategorized" — is hidden across all themes |
| v1.29 | Profile Page Post Count Accuracy | `_handle_profile` user query now computes `post_count` as a live subquery (`COUNT(*) FROM ep_posts WHERE author_id = ... AND status='published' AND post_type='post'`) instead of reading the stale denormalized `ep_users.post_count` column; count on the profile stats bar is now correct across all themes after post edits and deletes |
| v1.30 | Admin Categories Post Count Accuracy | `_render_admin_categories` replaced `SELECT * FROM ep_categories` (stale `post_count` column) with a live `LEFT JOIN ep_post_categories → ep_posts WHERE status != 'trash'` grouped COUNT; admin categories table now shows correct counts after any post is removed or transferred |
| v1.31 | Admin Users Post Count + Posts/Pages/Frontend Comment Count Accuracy | Admin Users panel: `ep_users.post_count` replaced with live subquery (non-trash posts); Admin Posts/Pages list: `ep_posts.comment_count` replaced with live subquery (non-trash comments); `_get_posts_for_list` frontend: `comment_count` replaced with live subquery (approved comments only) — all three now accurate after any delete or moderation action |
| v1.32 | Sidebar Tags Cloud Count Accuracy | `get_sidebar_data()` tags query replaced with live `JOIN ep_post_tags → ep_posts WHERE status='published'` grouped COUNT; tags with zero published posts hidden from the sidebar cloud across all themes, matching the category fix from v1.28 |
| v1.33 | Dashboard Drafts Panel + Configurable Auto-save | Dashboard: new Drafts section lists all unpublished (non-trash) posts and pages with Title, Type (Post/Page), Author, Status, Last Modified — auto-hidden when empty, trash action removes entries inline; Settings: Auto-save Interval dropdown (30 s / 1 / 2 / 3 / 5 / 10 min) stored as `autosave_interval`; editor reads interval from hidden input and sets `setInterval` accordingly; autosave skips save when both title and content are empty |
| v1.34 | Syntax Highlighter — Markdown Detection Fix + Inline Language Hint | Fixed SQL false-positive on Markdown documents containing SQL snippets in prose by applying a `-15` ATX-heading penalty to SQL (matching existing C/C++ rule) and scaling Markdown score by heading/list-item count; added inline `=language` hint — first content line of any fenced block may be `=python3`, `=sql`, `=markdown`, etc. to force the language, accepting all aliases (13 languages, 40+ identifiers) |
| v1.35 | Emoji Picker | Toolbar 😊 button (after Horizontal Rule) opens a floating emoji picker panel: 9 categories (Smileys, People, Animals, Food, Travel, Activities, Objects, Symbols, Flags), 1,257 emojis total, live search across 100+ keyword groups, hover preview footer, category tabs, dark-mode aware; clicking any emoji inserts it at the textarea cursor; all functionality in `app_core.js` + `styles_core.css` (no CDN dependency) — works across all themes |
| v1.36 | Emoji Picker Expansion — Skin Tones, Sports, Education & Tech | Skin tone selector (6 swatches: default + 5 Unicode modifiers) in People & Body category applies to all 50+ compatible hand/person emojis; Activities & Sports expanded to 158 emojis — full sport sets (soccer, football, baseball, hockey, basketball, tennis, martial arts, winter/water/track/gym), gendered athlete variants, exercise emojis (🏋️ 🤸 🧘 🚴 🏊 🧗), and energy/lightning emojis (⚡ 💥 🔥 🌪️); new 🎓 Education & Tech category (123 emojis) — school, STEM, computer/laptop, AI/robotics, mathematics, data analytics; 222 search keywords total (added soccer, baseball, hockey, gym, workout, yoga, yoga, stem, coding, laptop, chemistry, physics, math, lightning, bolt, energy, school, teacher, student, graduation, ai, robot, innovation and more) |
| v1.37 | Markdown Italic/Bold Underscore Fix | Added `(?<!\w)` / `(?!\w)` word-boundary guards to the `_italic_` and `__bold__` regex in `_process_inline()` and `_process_inline_simple()` in `markdown_parser.py`; identifiers like `some_var_name`, `__init__`, `HTTP_COOKIE`, `file_name.py` now render as plain text instead of being partially wrapped in `<em>` tags; intentional `_italic_` and `__bold__` at true word boundaries still work correctly |
| v1.38 | Apostrophe Fix in Code Block Highlighting | `highlight_custom_improved.js`: `hljs.highlightElement` patch for non-markdown languages now replaces apostrophes in English contractions (`don't`, `it's`, `we're`, `they've`, `we'll`, `I'd`, `I'm`, possessives) with U+E000 placeholder before calling hljs, restores `'` in innerHTML after — hljs never activates single-quote string mode on prose content; `syntax_highlight.py`: prose-safety fallback in `detect_language()` — if winning language uses `'` for strings, scores low (<5), and content has 2+ contractions, fall back to `markdown`/`plaintext` |
| v1.39 | Emoji Expansion + Markdown Help + Smart Auto-save + Light Mode Default + User Deletion | **Emoji picker:** widened to 400 px (`max-width: calc(100vw - 16px)` for mobile); Animals category cleaned — all plant emojis moved to new **🌿 Nature & Plants** category (31 emojis: trees, flowers, rose, sky, weather, moon/stars, ocean, earth); search debounced 2 s using `_renderGridOnly()` — input element never recreated so focus is never lost; 15 new search keywords (`nature`, `plant`, `rose`, `ocean`, `sky`, `cloud`, `storm`, `forest`, `beach`, `sunset`, `fog`, `camp`, `grass`, `wind` + expanded `tree`). **Auto-save:** `⚡ Smart (2 s)` debounce mode + 5 s / 10 s / 20 s options added to interval dropdown; Smart mode binds directly on `#ep-post-content` and `#ep-post-title` input events, calls `EP.autoSave.saveDraft()` which POSTs full form data to `www_post_save.py` with `status='draft'` — new posts are created in DB and URL updated to `/admin/edit/<id>`; `autosave_interval` added to `ALLOWED_KEYS` in `www_settings_save.py` (was missing — setting was never persisted). **Markdown Help:** `?` toolbar button (between emoji and 📁 Media) uses direct DOM binding (not delegation) to open a two-option dropdown; **⚡ Quick Reference** — floating positioned panel with 14-row cheat sheet; **📖 Markdown Tutorial** — modal covering EaglePress image syntax (`=300x200 center`), download buttons, shortcodes (`[post id=5]`), inline language hint (`=sql`), toolbar reference; dropdown centered on mobile (≤ 640 px) via `_posMenu()` mobile branch; panel always opens below button with dynamic `maxHeight`. **Light-mode default:** anti-FOUC inline script in all 4 themes + admin changed from `prefers-color-scheme` detection to `||'light'` — site always starts light; dark mode is user-toggled and persisted to `ep_theme` localStorage as before. **User deletion:** new `www_user_delete.py` endpoint (chmod 0755); JS delete button opens `EP.modal` dialog asking **Reassign content** (default — creates/finds `_deleted_` placeholder user, updates `ep_posts.author_id`) or **Delete all content** (explicitly removes posts + post_tags + post_categories + post comments, then deletes account); sessions purged in both cases; `ON DELETE SET NULL` FK handles remaining media/comment references; delete button carries `data-username` / `data-display` attributes; table row fades out on success. |
| v1.40 | Code Block Markdown Rendering + Theme Fixes | `_epShowMarkers` setter reads `code_md_render` setting on each call; `data-mdSrc` cache on `<code>` element fixes re-highlight after syntax theme switch; removed hardcoded `color` from `.hljs-section` / `.hljs-bullet` in all 5 CSS files (was overriding every hljs CDN theme with the same blue/amber); firstTheme dark-mode `.ep-post-content` text color fix; firstTheme + secondTheme light-code-on-dark-page pre background fix; secondTheme full toolbar CSS added (was absent — `styles_core.css` not loaded by frontend); secondTheme markdown rules changed from `.ep-post-content` to `.ep2-article-body` (rules were dead selectors on frontend); CSS `transition` on `.ep-code-block` / `.ep-code-toolbar` eliminates theme-switch flash; `sql/migrations/1.40.sql` |
| v1.41 | NewsTheme | Fifth bundled theme: news magazine layout (NewsBlogger-inspired); red accent top bar + dark header with serif logo + sticky nav + breaking news ticker; hero card (image / text split) + 3-column post grid + right sidebar with widget headers; built-in 🎨 color picker — 8 preset swatches + custom hex input; chosen accent color saved to `localStorage.ep_nt_accent`, restored on load via anti-FOUC script, updates `--nt-accent` CSS variable throughout; full syntax highlighting stack (`.nt-article-body` scoping, all 11 hljs themes, per-block persistence, word-wrap toggle); dark mode; reading progress bar; share bar; threaded comments AJAX; responsive (1024 / 768 / 480 px breakpoints); `EPNews` JS module | **Emoji picker:** widened to 400 px (`max-width: calc(100vw - 16px)` for mobile); Animals category cleaned — all plant emojis moved to new **🌿 Nature & Plants** category (31 emojis: trees, flowers, rose, sky, weather, moon/stars, ocean, earth); search debounced 2 s using `_renderGridOnly()` — input element never recreated so focus is never lost; 15 new search keywords (`nature`, `plant`, `rose`, `ocean`, `sky`, `cloud`, `storm`, `forest`, `beach`, `sunset`, `fog`, `camp`, `grass`, `wind` + expanded `tree`). **Auto-save:** `⚡ Smart (2 s)` debounce mode + 5 s / 10 s / 20 s options added to interval dropdown; Smart mode binds directly on `#ep-post-content` and `#ep-post-title` input events, calls `EP.autoSave.saveDraft()` which POSTs full form data to `www_post_save.py` with `status='draft'` — new posts are created in DB and URL updated to `/admin/edit/<id>`; `autosave_interval` added to `ALLOWED_KEYS` in `www_settings_save.py` (was missing — setting was never persisted). **Markdown Help:** `?` toolbar button (between emoji and 📁 Media) uses direct DOM binding (not delegation) to open a two-option dropdown; **⚡ Quick Reference** — floating positioned panel with 14-row cheat sheet; **📖 Markdown Tutorial** — modal covering EaglePress image syntax (`=300x200 center`), download buttons, shortcodes (`[post id=5]`), inline language hint (`=sql`), toolbar reference; dropdown centered on mobile (≤ 640 px) via `_posMenu()` mobile branch; panel always opens below button with dynamic `maxHeight`. **Light-mode default:** anti-FOUC inline script in all 4 themes + admin changed from `prefers-color-scheme` detection to `||'light'` — site always starts light; dark mode is user-toggled and persisted to `ep_theme` localStorage as before. **User deletion:** new `www_user_delete.py` endpoint (chmod 0755); JS delete button opens `EP.modal` dialog asking **Reassign content** (default — creates/finds `_deleted_` placeholder user, updates `ep_posts.author_id`) or **Delete all content** (explicitly removes posts + post_tags + post_categories + post comments, then deletes account); sessions purged in both cases; `ON DELETE SET NULL` FK handles remaining media/comment references; delete button carries `data-username` / `data-display` attributes; table row fades out on success. |
| v1.42 | NewsTheme URL Fix + Slug-Type Support | All 15 URL constructions in `NewsTheme/html/theme.py` and `NewsTheme/functions/functions.py` migrated from query-param format (`/?r=post/slug`) to clean PATH_INFO format (`/post/slug`, `/page/slug`, `/category/slug`, `/tag/slug`, `/profile/user`, `/login`, `/register`); `get_post_url()` and `get_page_url()` now honour the `slug_type` setting from v1.20 — `'id'` → numeric id, `'title'`/`'custom'` → slug field (falls back to id if empty) |
| v1.43 | NewsTheme Home Page "No Posts" Fix | Home page showed "No posts yet. Create your first post" even when a post existed — the hero card consumed `_posts[0]`, leaving the grid loop over `_posts[1:]` empty, which incorrectly triggered the empty-state message. Fixed by guarding the empty-state in the `else` branch of `if _posts` so it only fires when there are genuinely no posts |


> **On version update:** after replacing the `www/` folder, run `python3 sql/migrate.py` to apply any pending database schema changes while keeping all existing data intact, otherwise, apply the sql version directly to the database to apply the database update.

---




## Technical Stack

| Layer | Technology |
|---|---|
| Language | Python 3.8+ |
| Database | PostgreSQL 12+ |
| Web server | Apache `mod_cgi` / Nginx `fcgiwrap` |
| Frontend JS | jQuery 4.0 (CDN) |
| Syntax highlighting | highlight.js (CDN) + custom JS tokenizer (`highlight_custom_improved.js`) |
| Dependencies | `psycopg2` only |

example of the syntax highlighting:

Python 3

import os

for root, dirs, files in os.walk("."):
    for name in files:
        print(os.path.join(root, name)) # Prints the full path of every file
    for name in dirs:
        print(os.path.join(root, name)) # Prints the full path of every folder
Bash
traverse() {
    for file in "$1"/*; do
        if [ -d "$file" ]; then
            echo "Directory: $file"
            traverse "$file"  # Recursive call
        elif [ -f "$file" ]; then
            echo "File: $file"
        fi
    done
}

# Usage
traverse "/your/start/path"
JavaScript
function listFiles($dir) {
    $files = scandir($dir);
    foreach ($files as $file) {
        if ($file === '.' || $file === '..') continue;
        
        $path = $dir . DIRECTORY_SEPARATOR . $file;
        if (is_dir($path)) {
            listFiles($path); // Recursive call
        } else {
            echo $path . PHP_EOL;
        }
    }
}
C
#include <stdio.h>
#include <dirent.h>

int main() {
    struct dirent *entry;
    DIR *dp = opendir("."); // Open current directory

    if (dp == NULL) {
        perror("opendir");
        return 1;
    }

    while ((entry = readdir(dp))) {
        printf("%s\n", entry->d_name);
    }

    closedir(dp);
    return 0;
}
C++
#include <iostream>
#include <filesystem>

namespace fs = std::filesystem;

int main() {
    std::string path = "./my_directory";

    for (const auto& entry : fs::recursive_directory_iterator(path)) {
        std::cout << entry.path() << std::endl;
    }
    return 0;
}
Lua
local lfs = require("lfs")
local path = "."

for file in lfs.dir(path) do
    if file ~= "." and file ~= ".." then
        local full_path = path .. "/" .. file
        print("Found: " .. full_path)

        -- Check if it's a directory to recurse
        local mode = lfs.attributes(full_path, "mode")
        if mode == "directory" then
            print(full_path .. " is a directory")
        end
    end
end
Perl
use strict;
use warnings;
use File::Find;

# Specify the directory you want to start from
my $dir = '.'; 

# find() takes a code reference and the starting directory
find(\&process_file, $dir);

sub process_file {
    # $_ contains the current filename
    # $File::Find::name contains the full path to the file
    print "Found file: $File::Find::name\n" if -f $_;
}
SQL
CREATE TABLE Inventory (
    ProductID INT PRIMARY KEY,           -- Unique identifier (Integer)
    ProductName VARCHAR(100) NOT NULL,   -- Variable-length text (Name)
    Quantity INT DEFAULT 0,              -- Whole number (Stock count)
    UnitPrice DECIMAL(10, 2),            -- Precise decimal for currency (Price)
    IsActive BIT DEFAULT 1,              -- Boolean flag (1 for true, 0 for false)
    LastUpdated DATETIME DEFAULT CURRENT_TIMESTAMP -- Date and time stamp
);

Image Tag Reference

EaglePress Markdown supports an extended image syntax that lets authors control dimensions and layout alignment directly in content — no raw HTML needed.

Syntax

Markdown + HTML
![alt text](url =WIDTHxHEIGHT ALIGN "title")

All parameters after the URL are optional and can be combined in any order (width/height must come before alignment if both are used).

Parameters

| Parameter | Format | Description |
|---|---|---|
| alt text | ![alt text] | Alt text for accessibility / broken-image fallback |
| url | (url | Absolute or relative URL to the image |
| width × height | =800x600 | Sets width and height HTML attributes in pixels |
| alignment | left / center / right | Applies CSS class for float or centering |
| title | "tooltip text" | Sets the title tooltip attribute |

Alignment Classes

| Value | CSS Class Applied | Visual Effect |
|---|---|---|
| left | ep-img ep-img-left | Float image left, text wraps right |
| center | ep-img ep-img-center | Center image (block, no float) |
| right | ep-img ep-img-right | Float image right, text wraps left |
| (none) | ep-img | Inline, no alignment override |

Examples

| Markdown | Output |
|---|---|
| ![logo](/uploads/logo.png) | Basic inline image, no sizing |
| ![chart](/uploads/chart.png =800x400) | Image with explicit 800×400 px dimensions |
| ![photo](/uploads/photo.jpg center) | Centered image, natural size |
| ![icon](/uploads/icon.png =64x64 left) | 64×64 floated left |
| ![hero](/uploads/hero.jpg =1200x600 center "Homepage banner") | Full-width centered image with tooltip |
| ![report](/uploads/report.pdf) | Non-image file → renders as a styled download button |

The usage of syntax highlighting of a code block and a syntax language

Usually the Syntax Highlighting Language is auto detected, however, it may be manually stated of which syntax language a code block is utilizing.

Identifier example

● In the EaglePress post/page editor, fenced code blocks work like standard
Markdown with an optional language identifier after the opening backticks:

Basic fenced code block:
```python
def greet(name):
print(f"Hello, {name}!")
```

will display as:

Python 3
  def greet(name):
      print(f"Hello, {name}!")

Supported language identifiers:

┌──────────────────────────────┬────────────┐
│ Identifier(s) │ Language │
├──────────────────────────────┼────────────┤
│ python, py, python3 │ Python 3 │
├──────────────────────────────┼────────────┤
│ javascript, js, jsx, ts, tsx │ JavaScript │
├──────────────────────────────┼────────────┤
│ css, scss, sass, less │ CSS │
├──────────────────────────────┼────────────┤
│ html, htm, xml, svg │ HTML │
├───────────────────────────────────────┼────────────┤
│ php │ PHP │
├───────────────────────────────────────┼────────────┤
│ bash, sh, shell, zsh │ Bash │
├───────────────────────────────────────┼────────────┤
│ c, h │ C │
├───────────────────────────────────────┼────────────┤
│ cpp, c++, cxx, cc, hpp │ C++ │
├───────────────────────────────────────┼────────────┤
│ lua │ Lua │
├───────────────────────────────────────┼────────────┤
│ perl, pl, pm │ Perl │
├───────────────────────────────────────┼────────────┤
│ sql, mysql, pgsql, postgresql, sqlite │ SQL │
├───────────────────────────────────────┼────────────┤
│ markdown, md, mdown, mkd │ Markdown │
├───────────────────────────────────────┼────────────┤
│ text, txt, plain, plaintext │ Plain Text │
└───────────────────────────────────────┴────────────┘

Force language with inline hint (when the opening fence can't carry a label):
```
=python3
def hello():
pass
```

will display as:

Python 3
  def hello():                                                                  
      pass    

The first line =python3 is consumed as a language hint and not shown in the
output.

If you omit the identifier, the engine auto-detects the language from the
content using score-based heuristics. For short or ambiguous code areas you can
always force it explicitly with the language selector dropdown that appears in
the code block toolbar after the page renders.

0 Comments

No comments yet. Be the first!

Leave a Comment