diff --git a/SERVER_SETUP.md b/SERVER_SETUP.md deleted file mode 100644 index 67f49da..0000000 --- a/SERVER_SETUP.md +++ /dev/null @@ -1,190 +0,0 @@ -# Server Setup: PostgreSQL + PHP Auth for freedoms4 - -## Overview - -``` -/var/www/freedoms4/ ← Hugo's published docs/ folder (static files) -/var/www/freedoms4/api/ ← PHP backend (auth.php lives here) -``` - -Nginx serves the static Hugo site and passes `/api/` requests to PHP-FPM. - ---- - -## 1 · Install PostgreSQL - -```bash -sudo apt update -sudo apt install -y postgresql postgresql-contrib -sudo systemctl enable --now postgresql -``` - ---- - -## 2 · Create the database and user - -```bash -sudo -u postgres psql -``` - -Inside the psql shell: - -```sql -CREATE USER freedoms4_user WITH PASSWORD 'CHANGE_THIS_PASSWORD'; -CREATE DATABASE freedoms4 OWNER freedoms4_user; -\c freedoms4 - -CREATE TABLE users ( - id BIGSERIAL PRIMARY KEY, - username VARCHAR(32) NOT NULL UNIQUE, - email VARCHAR(254) NOT NULL UNIQUE, - password_hash VARCHAR(255) NOT NULL, - created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() -); - -CREATE INDEX idx_users_username ON users (username); -CREATE INDEX idx_users_email ON users (email); - --- Optional: allow only this user to access the table -REVOKE ALL ON TABLE users FROM PUBLIC; -GRANT SELECT, INSERT ON TABLE users TO freedoms4_user; -GRANT USAGE, SELECT ON SEQUENCE users_id_seq TO freedoms4_user; - -\q -``` - -> **Important:** use the same password you set in `DB_PASS` inside `auth.php`. - ---- - -## 3 · Install the PHP PostgreSQL extension - -```bash -# Find your PHP version first: -php -v - -# Install the pgsql extension (replace 8.x with your version, e.g. 8.3): -sudo apt install -y php8.3-pgsql - -# Restart PHP-FPM (replace 8.3 with your version): -sudo systemctl restart php8.3-fpm -``` - -Verify it loaded: - -```bash -php -m | grep pgsql # should print: pgsql -``` - ---- - -## 4 · Deploy the PHP file - -```bash -sudo mkdir -p /var/www/freedoms4/api -sudo cp /path/to/auth.php /var/www/freedoms4/api/auth.php -sudo chown -R www-data:www-data /var/www/freedoms4/api -sudo chmod 640 /var/www/freedoms4/api/auth.php -``` - -Edit the config constants at the top of `auth.php`: - -```php -define('DB_PASS', 'CHANGE_THIS_PASSWORD'); // ← your actual password -``` - ---- - -## 5 · Configure Nginx - -Open your site config (e.g. `/etc/nginx/sites-available/freedoms4`): - -```nginx -server { - listen 443 ssl http2; - server_name freedoms4.org www.freedoms4.org; - - root /var/www/freedoms4; - index index.html; - - # ── Static Hugo files ─────────────────────────────────────────────── - location / { - try_files $uri $uri/ $uri/index.html =404; - } - - # ── PHP API ───────────────────────────────────────────────────────── - location /api/ { - # Only allow POST (OPTIONS for CORS preflight) - limit_except POST OPTIONS { - deny all; - } - - # Pass to PHP-FPM (adjust socket path to match your PHP version) - fastcgi_pass unix:/run/php/php8.3-fpm.sock; - fastcgi_index index.php; - include fastcgi_params; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - fastcgi_param PATH_INFO $fastcgi_path_info; - } - - # ── Block direct access to .php files outside /api/ ───────────────── - location ~* \.php$ { - deny all; - } - - # SSL certs (already configured, adjust paths if needed) - ssl_certificate /etc/letsencrypt/live/freedoms4.org/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/freedoms4.org/privkey.pem; -} -``` - -Test and reload: - -```bash -sudo nginx -t -sudo systemctl reload nginx -``` - ---- - -## 6 · Deploy the Hugo frontend changes - -In your local Hugo project, apply the three file changes from the delivery package, then rebuild and sync: - -```bash -# From inside the freedoms4 project directory: -hugo --minify - -# Sync to server (adjust user/host): -rsync -avz --delete docs/ user@your-vps:/var/www/freedoms4/ -``` - -Or if you use git+CI, commit and push; your pipeline handles the rest. - ---- - -## 7 · Test - -```bash -# Sign up -curl -s -X POST https://freedoms4.org/api/auth.php \ - -H 'Content-Type: application/json' \ - -d '{"action":"signup","username":"testuser","email":"test@example.com","password":"hunter2hunter2"}' | jq . - -# Log in -curl -s -X POST https://freedoms4.org/api/auth.php \ - -H 'Content-Type: application/json' \ - -d '{"action":"login","username":"testuser","password":"hunter2hunter2"}' | jq . -``` - -Both should return `{"success":true, ...}`. - ---- - -## Security notes - -- All passwords are stored as bcrypt hashes (cost 12). Plain-text passwords are never written to disk or logs. -- Session cookies are `HttpOnly`, `Secure`, and `SameSite=Strict`. -- A simple per-IP rate limit (20 requests per 15 min) is enforced server-side via PHP sessions. -- For production, consider adding `fail2ban` rules on your Nginx access log to block repeated 429s at the firewall level. -- Keep `SESSION_SECURE = true` (requires HTTPS, which you already have). diff --git a/api/auth.php b/api/auth.php deleted file mode 100644 index 3605652..0000000 --- a/api/auth.php +++ /dev/null @@ -1,195 +0,0 @@ - false, 'message' => 'Forbidden.']); - exit; -} - -if ($origin) { - header('Access-Control-Allow-Origin: ' . $origin); - header('Access-Control-Allow-Methods: POST, OPTIONS'); - header('Access-Control-Allow-Headers: Content-Type'); - header('Access-Control-Allow-Credentials: true'); -} - -if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { - http_response_code(204); - exit; -} - -// ── Helpers ────────────────────────────────────────────────────────────────── -function json_out(array $data, int $status = 200): never { - http_response_code($status); - header('Content-Type: application/json; charset=utf-8'); - echo json_encode($data); - exit; -} - -function start_session(): void { - if (session_status() === PHP_SESSION_NONE) { - session_name(SESSION_NAME); - session_set_cookie_params([ - 'lifetime' => 0, - 'path' => '/', - 'secure' => SESSION_SECURE, - 'httponly' => true, - 'samesite' => SESSION_SAMESITE, - ]); - session_start(); - } -} - -function db_connect(): PDO { - static $pdo = null; - if ($pdo !== null) return $pdo; - - $dsn = sprintf('pgsql:host=%s;port=%s;dbname=%s', DB_HOST, DB_PORT, DB_NAME); - - try { - $pdo = new PDO($dsn, DB_USER, DB_PASS, [ - PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, - PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, - PDO::ATTR_EMULATE_PREPARES => false, - ]); - } catch (PDOException $e) { - error_log('DB connection failed: ' . $e->getMessage()); - json_out(['success' => false, 'message' => 'Database unavailable. Please try again later.'], 503); - } - - return $pdo; -} - -// ── Only accept POST ────────────────────────────────────────────────────────── -if ($_SERVER['REQUEST_METHOD'] !== 'POST') { - json_out(['success' => false, 'message' => 'Method not allowed.'], 405); -} - -// ── Parse JSON body ─────────────────────────────────────────────────────────── -$body = json_decode(file_get_contents('php://input'), true); - -if (!is_array($body)) { - json_out(['success' => false, 'message' => 'Invalid request body.'], 400); -} - -$action = $body['action'] ?? ''; - -// ── Rate limiting (per-IP via session) ──────────────────────────────────────── -start_session(); -$now = time(); -$rl_key = 'rl_' . hash('sha256', $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0'); -$rl = $_SESSION[$rl_key] ?? ['count' => 0, 'window_start' => $now]; - -if ($now - $rl['window_start'] > 900) { - $rl = ['count' => 0, 'window_start' => $now]; -} - -$rl['count']++; -$_SESSION[$rl_key] = $rl; - -if ($rl['count'] > 20) { - json_out(['success' => false, 'message' => 'Too many requests. Please wait a few minutes.'], 429); -} - -// ════════════════════════════════════════════════════════════════════════════ -// ACTION: login -// ════════════════════════════════════════════════════════════════════════════ -if ($action === 'login') { - $username = trim($body['username'] ?? ''); - $password = $body['password'] ?? ''; - - if ($username === '' || $password === '') { - json_out(['success' => false, 'message' => 'Username and password are required.']); - } - - $pdo = db_connect(); - $stmt = $pdo->prepare('SELECT id, username, password_hash FROM users WHERE username = :u LIMIT 1'); - $stmt->execute([':u' => $username]); - $user = $stmt->fetch(); - - $hash = $user['password_hash'] ?? '$2y$12$invalidhashpadding000000000000000000000000000000000000000'; - if (!$user || !password_verify($password, $hash)) { - json_out(['success' => false, 'message' => 'Invalid username or password.']); - } - - session_regenerate_id(true); - $_SESSION['user_id'] = $user['id']; - $_SESSION['username'] = $user['username']; - - json_out(['success' => true, 'redirect' => '/']); -} - -// ════════════════════════════════════════════════════════════════════════════ -// ACTION: signup -// ════════════════════════════════════════════════════════════════════════════ -if ($action === 'signup') { - $username = trim($body['username'] ?? ''); - $email = trim($body['email'] ?? ''); - $password = $body['password'] ?? ''; - - if ($username === '') { - json_out(['success' => false, 'message' => 'Username is required.']); - } - if (!preg_match('/^[a-zA-Z0-9_\-]{3,32}$/', $username)) { - json_out(['success' => false, 'message' => 'Username must be 3–32 characters: letters, numbers, _ or -.']); - } - if ($email === '' || !filter_var($email, FILTER_VALIDATE_EMAIL)) { - json_out(['success' => false, 'message' => 'A valid email address is required.']); - } - if (strlen($password) < 8) { - json_out(['success' => false, 'message' => 'Password must be at least 8 characters.']); - } - - $pdo = db_connect(); - $stmt = $pdo->prepare('SELECT 1 FROM users WHERE username = :u OR email = :e LIMIT 1'); - $stmt->execute([':u' => $username, ':e' => $email]); - - if ($stmt->fetch()) { - json_out(['success' => false, 'message' => 'Username or email is already taken.']); - } - - $hash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]); - $stmt = $pdo->prepare( - 'INSERT INTO users (username, email, password_hash, created_at) VALUES (:u, :e, :h, NOW())' - ); - $stmt->execute([':u' => $username, ':e' => $email, ':h' => $hash]); - - json_out(['success' => true]); -} - -// ════════════════════════════════════════════════════════════════════════════ -// ACTION: logout -// ════════════════════════════════════════════════════════════════════════════ -if ($action === 'logout') { - $_SESSION = []; - if (ini_get('session.use_cookies')) { - $p = session_get_cookie_params(); - setcookie(session_name(), '', time() - 42000, - $p['path'], $p['domain'], $p['secure'], $p['httponly']); - } - session_destroy(); - json_out(['success' => true, 'redirect' => '/']); -} - -json_out(['success' => false, 'message' => 'Unknown action.'], 400); diff --git a/docs/404.html b/docs/404.html index 1468b90..a5bfc87 100644 --- a/docs/404.html +++ b/docs/404.html @@ -7,4 +7,4 @@

404

The page you visited was not found.

Return to the home page

\ No newline at end of file +Subscribe

404

The page you visited was not found.

Return to the home page

\ No newline at end of file diff --git a/docs/blog/index.html b/docs/blog/index.html index 526c44d..f806126 100644 --- a/docs/blog/index.html +++ b/docs/blog/index.html @@ -8,4 +8,4 @@ Sign Up Subscribe

All Posts | Categories

What is Education?

What is Education? # Education simply means “learning”. It’s a natural process. -Ratio of components in Education: # 50% Knowledge/Understanding, 30% …

\ No newline at end of file +Ratio of components in Education: # 50% Knowledge/Understanding, 30% …

\ No newline at end of file diff --git a/docs/blog/what-is-education/index.html b/docs/blog/what-is-education/index.html index 879909f..e0a797b 100644 --- a/docs/blog/what-is-education/index.html +++ b/docs/blog/what-is-education/index.html @@ -17,4 +17,4 @@ Academics system has evolved with time and got worst. Let’s see what the syste Sign Up Subscribe

What is Education?


What is Education? #

Education simply means “learning”. It’s a natural process.

Ratio of components in Education: #

50% Knowledge/Understanding, 30% Skills, 20% Experience.

Education vs Academics: #

Education and Academics are not the same thing. Academics is Education based of a curriculum and an institution. Plato discovered the word while describing his school of philosophy.

Academics system has evolved with time and got worst. Let’s see what the system has become nowadays: #

Extra bad: #

Education as a concept/implementation/system is good. -Academics is good only as a concept. It’s implementation and system is always the worst and corrupted.

Activities in Education: #

Read vs Study vs Research: #

  1. Read: Reading is about watching or interpreting something/someone to gain knowledge.

  2. Study: Studying is about interpreting a topic, going deeper and gaining some conscious understanding out of it.

  3. Research: Research is about studying a topic and then contributing to it with changes from your end.

Knowledge vs Entertainment: #

Example:

  1. The first book was to provide Knowledge/Understanding, but later books became a source of Entertainment (fiction).
  2. Videos can be used for both Knowledge/Understanding and Entertainment purposes. For example, for Knowledge/Understanding, there are documentaries, tutorial videos etc. For Entertainment, there are movies, funny videos etc.
Tags:
Categories:
\ No newline at end of file +Academics is good only as a concept. It’s implementation and system is always the worst and corrupted.

Activities in Education: #

Read vs Study vs Research: #

  1. Read: Reading is about watching or interpreting something/someone to gain knowledge.

  2. Study: Studying is about interpreting a topic, going deeper and gaining some conscious understanding out of it.

  3. Research: Research is about studying a topic and then contributing to it with changes from your end.

Knowledge vs Entertainment: #

Example:

  1. The first book was to provide Knowledge/Understanding, but later books became a source of Entertainment (fiction).
  2. Videos can be used for both Knowledge/Understanding and Entertainment purposes. For example, for Knowledge/Understanding, there are documentaries, tutorial videos etc. For Entertainment, there are movies, funny videos etc.
Tags:
Categories:
\ No newline at end of file diff --git a/docs/categories/index.html b/docs/categories/index.html index 476dbdd..c62c94e 100644 --- a/docs/categories/index.html +++ b/docs/categories/index.html @@ -8,4 +8,4 @@ Sign Up Subscribe

All Posts | Categories

Philosophy (1)

\ No newline at end of file +› Categories

All Posts | Categories

Philosophy (1)

\ No newline at end of file diff --git a/docs/categories/philosophy/index.html b/docs/categories/philosophy/index.html index 2b7a15a..c31b535 100644 --- a/docs/categories/philosophy/index.html +++ b/docs/categories/philosophy/index.html @@ -10,4 +10,4 @@ Subscribe

All Posts | -Categories

Philosophy

What is Education?

\ No newline at end of file +Categories

Philosophy

What is Education?

\ No newline at end of file diff --git a/docs/changelog/index.html b/docs/changelog/index.html index 3cdec54..5957db5 100644 --- a/docs/changelog/index.html +++ b/docs/changelog/index.html @@ -34,4 +34,4 @@ Changelog page. Remove year from footer copyright. “Contents” style UniNotes

Changelog

[25-05-2026]

[17-05-2026]

[08-05-2026]

[02-05-2026]

[01-05-2026]

[20-04-2026]

[15-04-2026]

[15-04-2026]

[14-04-2026]

\ No newline at end of file +Subscribe

Changelog

[25-05-2026]

[17-05-2026]

[08-05-2026]

[02-05-2026]

[01-05-2026]

[20-04-2026]

[15-04-2026]

[15-04-2026]

[14-04-2026]

\ No newline at end of file diff --git a/docs/coming-soon/index.html b/docs/coming-soon/index.html index 283ceb8..d87ccea 100644 --- a/docs/coming-soon/index.html +++ b/docs/coming-soon/index.html @@ -7,4 +7,4 @@

Coming Soon

This feature is not yet available. Check back later!

\ No newline at end of file +Subscribe

Coming Soon

This feature is not yet available. Check back later!

\ No newline at end of file diff --git a/docs/contact/index.html b/docs/contact/index.html index dcb5418..6a6f6b7 100644 --- a/docs/contact/index.html +++ b/docs/contact/index.html @@ -19,4 +19,4 @@ Lemmy: hyzen@lemmy.today">

Admin: hyzen

Contacts #

Email and XMPP: hyzen@freedoms4.org

IRC/Liberachat: hyzen, #freedoms4

Follow on #

Mastodon: hyzen@mastodon.social

Lemmy: hyzen@lemmy.today

\ No newline at end of file +Subscribe

Admin: hyzen

Contacts #

Email and XMPP: hyzen@freedoms4.org

IRC/Liberachat: hyzen, #freedoms4

Follow on #

Mastodon: hyzen@mastodon.social

Lemmy: hyzen@lemmy.today

\ No newline at end of file diff --git a/docs/css/custom.css b/docs/css/custom.css index 98fbac2..555430a 100644 --- a/docs/css/custom.css +++ b/docs/css/custom.css @@ -233,10 +233,12 @@ display: none; } -.brand__auth-toggle { +.brand__auth-toggle, +.brand__auth-user-btn { display: inline-flex; align-items: center; justify-content: center; + box-sizing: border-box; padding: 0.355rem 0.5rem; border-radius: 3px; border: 1px solid #f26522; @@ -245,6 +247,7 @@ cursor: pointer; font-size: 0.7rem; font-weight: 340; + font-family: inherit; line-height: 1.4; user-select: none; outline: none; @@ -254,21 +257,25 @@ color 0.2s ease; } -.brand__auth-toggle:hover { +.brand__auth-toggle:hover, +.brand__auth-user-btn:hover { background-color: transparent; border-color: #f26522; color: #f26522; } @media (prefers-color-scheme: dark) { - .brand__auth-toggle { + .brand__auth-toggle, + .brand__auth-user-btn { background-color: transparent; border-color: currentColor; color: var(--foreground-color); } .brand__auth-toggle:hover, - .brand__auth:focus-within .brand__auth-toggle { + .brand__auth:focus-within .brand__auth-toggle, + .brand__auth-user-btn:hover, + .brand__auth-user.is-open .brand__auth-user-btn { background-color: var(--foreground-color) !important; border-color: var(--foreground-color) !important; color: var(--background-color) !important; @@ -477,13 +484,15 @@ /* Default (system light): orange filled */ @media (max-width: 600px) { - .brand__auth-toggle { + .brand__auth-toggle, + .brand__auth-user-btn { background-color: #f26522 !important; border-color: #f26522 !important; color: #fff !important; } - .brand__auth:focus-within .brand__auth-toggle { + .brand__auth:focus-within .brand__auth-toggle, + .brand__auth-user.is-open .brand__auth-user-btn { background-color: transparent !important; border-color: #f26522 !important; color: #f26522 !important; @@ -492,13 +501,15 @@ /* System dark: outline */ @media (max-width: 600px) and (prefers-color-scheme: dark) { - .brand__auth-toggle { + .brand__auth-toggle, + .brand__auth-user-btn { background-color: transparent !important; border-color: currentColor !important; color: var(--foreground-color) !important; } - .brand__auth:focus-within .brand__auth-toggle { + .brand__auth:focus-within .brand__auth-toggle, + .brand__auth-user.is-open .brand__auth-user-btn { background-color: var(--foreground-color) !important; border-color: var(--foreground-color) !important; color: var(--background-color) !important; @@ -507,26 +518,30 @@ /* Manual light override */ @media (max-width: 600px) { - [data-theme='light'] .brand__auth-toggle { + [data-theme='light'] .brand__auth-toggle, + [data-theme='light'] .brand__auth-user-btn { background-color: #f26522 !important; border-color: #f26522 !important; color: #fff !important; } - [data-theme='light'] .brand__auth:focus-within .brand__auth-toggle { + [data-theme='light'] .brand__auth:focus-within .brand__auth-toggle, + [data-theme='light'] .brand__auth-user.is-open .brand__auth-user-btn { background-color: transparent !important; border-color: #f26522 !important; color: #f26522 !important; } /* Manual dark override */ - [data-theme='dark'] .brand__auth-toggle { + [data-theme='dark'] .brand__auth-toggle, + [data-theme='dark'] .brand__auth-user-btn { background-color: transparent !important; border-color: currentColor !important; color: var(--foreground-color) !important; } - [data-theme='dark'] .brand__auth:focus-within .brand__auth-toggle { + [data-theme='dark'] .brand__auth:focus-within .brand__auth-toggle, + [data-theme='dark'] .brand__auth-user.is-open .brand__auth-user-btn { background-color: var(--foreground-color) !important; border-color: var(--foreground-color) !important; color: var(--background-color) !important; @@ -878,3 +893,90 @@ color: var(--foreground-color3, #888); transform: none; } + +/* ── Logged-in user button in header ───────────────────────────────────────── */ + +/* Hide the old checkbox toggle + login/signup links when logged in */ +.brand__auth--loggedin .brand__auth-check, +.brand__auth--loggedin .brand__auth-toggle, +.brand__auth--loggedin .brand__auth-links { + display: none !important; +} + +.brand__auth-user { + position: relative; + display: inline-flex; + align-items: center; +} + +/* Extra properties needed only because the user-btn contains text */ +.brand__auth-user-btn { + white-space: nowrap; + max-width: 140px; + overflow: hidden; + text-overflow: ellipsis; +} + +.brand__auth-user-dropdown { + display: none; + position: absolute; + top: calc(100% + 0.4rem); + right: 0; + background: var(--background-color); + border: 1px solid var(--background-color1); + border-radius: 6px; + box-shadow: 0 4px 16px rgba(0,0,0,0.18); + min-width: 110px; + z-index: 100; + overflow: hidden; +} + +.brand__auth-user.is-open .brand__auth-user-dropdown { + display: block; +} + +.brand__auth-user-logout { + display: block; + width: 100%; + padding: 0.55rem 1rem; + background: none; + border: none; + cursor: pointer; + text-align: center; + font-size: 0.78rem; + font-family: inherit; + color: var(--foreground-color); + transition: background 0.12s; +} + +.brand__auth-user-logout:hover { + background: var(--background-color1); + color: var(--foreground-color); +} + +/* Mobile logged-in state */ +.brand__mobile-links .mobile-link--logout { + color: var(--foreground-color); +} + + +/* Reset native button styles + force subscribe-button dimensions on logged-in user button */ +.brand__auth-user-btn { + -webkit-appearance: none !important; + appearance: none !important; + margin: 0 !important; + min-height: 0 !important; + height: auto !important; + vertical-align: middle; + padding: 0.2rem 0.65rem !important; + border-radius: 3px !important; + font-size: 0.7rem !important; + line-height: 1.4 !important; + display: inline-flex !important; + align-items: center !important; + gap: 0.25rem !important; +} + +.brand__auth-user-btn svg { + flex: 0 0 auto; +} diff --git a/docs/index.html b/docs/index.html index f7099fa..60e67ea 100644 --- a/docs/index.html +++ b/docs/index.html @@ -7,4 +7,4 @@

Namaste 🙏 #

My name is hyzen, I'm the founder of this site. This site is my space to write about my views on various subjects and explore ideas that matter to me. I also provide free services to the public that may matter to them.

On the blog I’m writing about: #

Beyond theoretical discussions, I may also write about my day-to-day experiences, thoughts, and feelings - the personal reflections that shape my worldview and understanding of the world around me.

Motive: #

My goal is for everyone who visits this site to leave with something valuable.

Site’s Code: #

This site is also built with open source tools like Hugo and served freely. If you're interested in the code , you can find it here↗.

\ No newline at end of file +Subscribe

Namaste 🙏 #

My name is hyzen, I'm the founder of this site. This site is my space to write about my views on various subjects and explore ideas that matter to me. I also provide free services to the public that may matter to them.

On the blog I’m writing about: #

Beyond theoretical discussions, I may also write about my day-to-day experiences, thoughts, and feelings - the personal reflections that shape my worldview and understanding of the world around me.

Motive: #

My goal is for everyone who visits this site to leave with something valuable.

Site’s Code: #

This site is also built with open source tools like Hugo and served freely. If you're interested in the code , you can find it here↗.

\ No newline at end of file diff --git a/docs/login/index.html b/docs/login/index.html index 1af1e53..98d47f3 100644 --- a/docs/login/index.html +++ b/docs/login/index.html @@ -13,4 +13,4 @@ Subscribe

All Posts | Categories

S1 (16)

\ No newline at end of file diff --git a/docs/services/file-share/index.html b/docs/services/file-share/index.html index f61bf74..26c8d69 100644 --- a/docs/services/file-share/index.html +++ b/docs/services/file-share/index.html @@ -9,4 +9,4 @@ Subscribe

File share

Visit share.freedoms4.org↗ -to quickly upload files and get sharable links.

\ No newline at end of file +to quickly upload files and get sharable links.

\ No newline at end of file diff --git a/docs/services/index.html b/docs/services/index.html index b4e5a07..d8442b6 100644 --- a/docs/services/index.html +++ b/docs/services/index.html @@ -7,4 +7,4 @@

Services

  1. File share
  2. XMPP Account
\ No newline at end of file +Subscribe

Services

  1. File share
  2. XMPP Account
\ No newline at end of file diff --git a/docs/services/xmpp-account/index.html b/docs/services/xmpp-account/index.html index bf176b6..1e01644 100644 --- a/docs/services/xmpp-account/index.html +++ b/docs/services/xmpp-account/index.html @@ -8,4 +8,4 @@ Sign Up Subscribe

XMPP Account

Send your desired username to hyzen@freedoms4.org via Email (or via XMPP if already have an XMPP account). Account creation can take upto 24 hours.

\ No newline at end of file +› XMPP Account

XMPP Account

Send your desired username to hyzen@freedoms4.org via Email (or via XMPP if already have an XMPP account). Account creation can take upto 24 hours.

\ No newline at end of file diff --git a/docs/signup/index.html b/docs/signup/index.html index bc74a85..32995db 100644 --- a/docs/signup/index.html +++ b/docs/signup/index.html @@ -15,4 +15,4 @@ Subscribe

All Posts | Categories

BO DCM1109 (4)

ET DCM1107 (6)

GE DCM1106 (1)

PBM DCM1110 (5)

\ No newline at end of file diff --git a/docs/tags/academics/index.html b/docs/tags/academics/index.html index 288d749..fdb2d00 100644 --- a/docs/tags/academics/index.html +++ b/docs/tags/academics/index.html @@ -10,4 +10,4 @@ Subscribe

All Posts | -Categories

Academics

What is Education?

\ No newline at end of file +Categories

Academics

What is Education?

\ No newline at end of file diff --git a/docs/tags/education/index.html b/docs/tags/education/index.html index 628a32e..2a6fd6f 100644 --- a/docs/tags/education/index.html +++ b/docs/tags/education/index.html @@ -10,4 +10,4 @@ Subscribe

All Posts | -Categories

Education

What is Education?

\ No newline at end of file +Categories

Education

What is Education?

\ No newline at end of file diff --git a/docs/tags/index.html b/docs/tags/index.html index 5cb52d1..85e435f 100644 --- a/docs/tags/index.html +++ b/docs/tags/index.html @@ -8,4 +8,4 @@ Sign Up Subscribe

All Posts | Categories

Academics (1)

Education (1)

System (1)

\ No newline at end of file +› Categories

All Posts | Categories

Academics (1)

Education (1)

System (1)

\ No newline at end of file diff --git a/docs/tags/system/index.html b/docs/tags/system/index.html index e5d1205..3c1d31b 100644 --- a/docs/tags/system/index.html +++ b/docs/tags/system/index.html @@ -10,4 +10,4 @@ Subscribe

All Posts | -Categories

System

What is Education?

\ No newline at end of file +Categories

System

What is Education?

\ No newline at end of file diff --git a/docs/uninotes/index.html b/docs/uninotes/index.html index d4274e4..6b7fc0e 100644 --- a/docs/uninotes/index.html +++ b/docs/uninotes/index.html @@ -37,4 +37,4 @@ Subscribe \ No newline at end of file diff --git a/docs/uninotes/s1/bo-dcm1109/unit1/index.html b/docs/uninotes/s1/bo-dcm1109/unit1/index.html index 4c40b3f..fb19481 100644 --- a/docs/uninotes/s1/bo-dcm1109/unit1/index.html +++ b/docs/uninotes/s1/bo-dcm1109/unit1/index.html @@ -11,4 +11,4 @@ Subscribe