Compare commits

...

2 Commits

Author SHA1 Message Date
Ryan Rix ebcebf329b some bollocks i forgot to tangle 2024-02-12 11:21:28 -08:00
Ryan Rix 48af3bdf9a integrate django-prometheus 2024-02-12 11:21:11 -08:00
19 changed files with 88 additions and 61 deletions

View File

@ -15,6 +15,8 @@ from __future__ import annotations
from typing import Optional, List
from django.db import models
from django.conf import settings
from django_prometheus.models import ExportModelOperationsMixin as EMOM
import arrow
import functools
@ -41,7 +43,7 @@ Sites are created in the [[id:20231217T154835.232283][Arcology Seed Command]].
#+begin_src python :tangle arcology/models.py
# Sites and SiteDomains are created in django-admin or a seed rather than from arroyo parser, no create_from_arroyo..!
class Site(models.Model):
class Site(EMOM('site'), models.Model):
key = models.CharField(max_length=512, primary_key=True)
title = models.CharField(max_length=512)
@ -73,7 +75,7 @@ class Site(models.Model):
return site
class SiteDomain(models.Model):
class SiteDomain(EMOM('site_domain'), models.Model):
site = models.ForeignKey(
Site,
on_delete=models.CASCADE,
@ -133,7 +135,7 @@ A site has many pages. Pages have a routing key defined by the =ARCOLOGY_KEY= ke
These are created using the [[roam:create_from_arroyo][=create_from_arroyo=]] pattern which makes it easy for the [[id:20231217T154857.983742][Arcology ingest_files Command]] to include new functionality in to the system.
#+begin_src python :tangle arcology/models.py
class Page(models.Model):
class Page(EMOM('page'), models.Model):
file = models.ForeignKey(
roam.models.File,
on_delete=models.CASCADE,
@ -264,7 +266,7 @@ Pages can define an Atom feed + [[id:20230125T143144.011175][Feediverse]] feeds
These are also created using the [[roam:create_from_arroyo][=create_from_arroyo=]] pattern which makes it easy for the [[id:20231217T154857.983742][Arcology ingest_files Command]] to include new functionality in to the system.
#+begin_src python :tangle arcology/models.py
class Feed(models.Model):
class Feed(EMOM('feed'), models.Model):
POST_VISIBILITY = [
("unlisted", "Unlisted"),
("private", "Private"),
@ -356,7 +358,7 @@ migrations.CreateModel(
A FeedEntry is a Heading with a PUBDATE property that exists on a page w/ ARCOLOGY_FEED Keyword. These are used to construct =Feeds=
#+begin_src python :tangle arcology/models.py
class FeedEntry(models.Model):
class FeedEntry(EMOM('feed_entry'), models.Model):
POST_VISIBILITY = [
("unlisted", "Unlisted"),
("private", "Private"),
@ -495,7 +497,7 @@ class FeedEntryAdmin(admin.ModelAdmin):
list_display = ["heading", "route_key", "pubdate", "title"]
#+end_src
* NEXT the web server
* The Web Server
"""arcology URL Configuration
@ -515,7 +517,7 @@ Including another URLconf
#+begin_src python :tangle arcology/urls.py
from django.contrib import admin
from django.urls import path, re_path
from django.urls import path, re_path, include
from arcology import views
@ -524,6 +526,7 @@ urlpatterns = [
path("", views.index),
path("sitemap", views.sitemap, name="sitemap"),
path("sites.css", views.site_css, name="site-css"),
path('', include('django_prometheus.urls')),
# ensure these ones are last because they're greedy!
re_path("(?P<key>[0-9a-zA-Z/_\-]+\.xml)", views.feed, name="feed"),
re_path("(?P<key>[0-9a-zA-Z/_\-]+)", views.org_page, name="org-page"),

View File

@ -3,6 +3,8 @@ from __future__ import annotations
from typing import Optional, List
from django.db import models
from django.conf import settings
from django_prometheus.models import ExportModelOperationsMixin as EMOM
import arrow
import functools
@ -23,7 +25,7 @@ class hashabledict(dict):
# [[file:../arcology.org::*Site][Site:1]]
# Sites and SiteDomains are created in django-admin or a seed rather than from arroyo parser, no create_from_arroyo..!
class Site(models.Model):
class Site(EMOM('site'), models.Model):
key = models.CharField(max_length=512, primary_key=True)
title = models.CharField(max_length=512)
@ -55,7 +57,7 @@ class Site(models.Model):
return site
class SiteDomain(models.Model):
class SiteDomain(EMOM('site_domain'), models.Model):
site = models.ForeignKey(
Site,
on_delete=models.CASCADE,
@ -64,7 +66,7 @@ class SiteDomain(models.Model):
# Site:1 ends here
# [[file:../arcology.org::*Page][Page:1]]
class Page(models.Model):
class Page(EMOM('page'), models.Model):
file = models.ForeignKey(
roam.models.File,
on_delete=models.CASCADE,
@ -154,7 +156,7 @@ class Page(models.Model):
# Page:1 ends here
# [[file:../arcology.org::*Feed][Feed:1]]
class Feed(models.Model):
class Feed(EMOM('feed'), models.Model):
POST_VISIBILITY = [
("unlisted", "Unlisted"),
("private", "Private"),
@ -203,7 +205,7 @@ class Feed(models.Model):
# Feed:1 ends here
# [[file:../arcology.org::*FeedEntry][FeedEntry:1]]
class FeedEntry(models.Model):
class FeedEntry(EMOM('feed_entry'), models.Model):
POST_VISIBILITY = [
("unlisted", "Unlisted"),
("private", "Private"),

View File

@ -35,6 +35,7 @@ INSTALLED_APPS = [
"generators", # [[id:arroyo/django/generators][The Arroyo Generators]]
"syncthonk", # [[id:20231218T183551.765340][Arcology watchsync Command]]
"django_prometheus",
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
@ -85,6 +86,7 @@ LOGGING = {
# [[file:../../configuration.org::*Look don't worry about the rest of these][Look don't worry about the rest of these:1]]
MIDDLEWARE = [
"django_prometheus.middleware.PrometheusBeforeMiddleware",
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
@ -92,6 +94,7 @@ MIDDLEWARE = [
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"django_prometheus.middleware.PrometheusAfterMiddleware",
]
ROOT_URLCONF = "arcology.urls"
@ -120,7 +123,7 @@ WSGI_APPLICATION = "arcology.wsgi.application"
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"ENGINE": "django_prometheus.db.backends.sqlite3",
"NAME": DATABASE_PATH,
}
}

View File

@ -1,6 +1,6 @@
# [[file:../arcology.org::*the web server][the web server:1]]
# [[file:../arcology.org::*The Web Server][The Web Server:1]]
from django.contrib import admin
from django.urls import path, re_path
from django.urls import path, re_path, include
from arcology import views
@ -9,8 +9,9 @@ urlpatterns = [
path("", views.index),
path("sitemap", views.sitemap, name="sitemap"),
path("sites.css", views.site_css, name="site-css"),
path('', include('django_prometheus.urls')),
# ensure these ones are last because they're greedy!
re_path("(?P<key>[0-9a-zA-Z/_\-]+\.xml)", views.feed, name="feed"),
re_path("(?P<key>[0-9a-zA-Z/_\-]+)", views.org_page, name="org-page"),
]
# the web server:1 ends here
# The Web Server:1 ends here

View File

@ -1,4 +1,4 @@
# [[file:../arcology.org::*the web server][the web server:2]]
# [[file:../arcology.org::*The Web Server][The Web Server:2]]
import logging
from django.http import HttpResponse, HttpResponseNotFound
from django.shortcuts import render, get_object_or_404
@ -7,7 +7,7 @@ from arcology.models import Page, Feed, Site
from roam.models import Link
logger = logging.getLogger(__name__)
# the web server:2 ends here
# The Web Server:2 ends here
# [[file:../arcology.org::*=GET /= site index][=GET /= site index:1]]
def index(request):

View File

@ -202,6 +202,7 @@ basically, each org file in this repository, and maybe one or two of your own, a
# Application definition
INSTALLED_APPS = [
<<gen-config-list(arcology_apps)>>
"django_prometheus",
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
@ -398,6 +399,7 @@ IGNORED_ROAM_TAGS = [
#+BEGIN_SRC python :tangle arcology/settings/__init__.py :noweb yes
MIDDLEWARE = [
"django_prometheus.middleware.PrometheusBeforeMiddleware",
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
@ -405,8 +407,16 @@ MIDDLEWARE = [
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"django_prometheus.middleware.PrometheusAfterMiddleware",
]
CACHES = {
'default': {
'BACKEND': 'django_prometheus.cache.backends.filebased.FileBasedCache',
'LOCATION': '/var/tmp/django_cache',
}
}
ROOT_URLCONF = "arcology.urls"
TEMPLATES = [
@ -433,7 +443,7 @@ WSGI_APPLICATION = "arcology.wsgi.application"
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"ENGINE": "django_prometheus.db.backends.sqlite3",
"NAME": DATABASE_PATH,
}
}

View File

@ -22,6 +22,7 @@ python3.pkgs.buildPythonPackage rec {
setuptools
django
polling
django-prometheus
arrow
]);

View File

@ -19,6 +19,7 @@ from __future__ import annotations
from typing import List
from django.db import models
from django.conf import settings
from django_prometheus.models import ExportModelOperationsMixin as EMOM
import arroyo.arroyo_rs as native
@ -31,7 +32,7 @@ import logging
logger = logging.getLogger(__name__)
class GeneratorRole(models.Model):
class GeneratorRole(EMOM('generatorRole'), models.Model):
name = models.CharField(max_length=512, primary_key=True)
@classmethod
@ -44,7 +45,7 @@ class GeneratorRole(models.Model):
]
class Generator(models.Model):
class Generator(EMOM('generator'), models.Model):
class Meta:
abstract = True
@ -130,7 +131,7 @@ role list and exclusions in =create_from_arroyo=
Emacs configuration is not declarative but imperative so dependency order needs to be established which the Nix modules do not nee to perform. =#+ARROYO_MODULE_WANTS= and =#+ARROYO_MODULE_WANTED= Keywords allow documents to describe dependency relationships. The python built-in [[https://docs.python.org/3/library/graphlib.html][=graphlib=]] is used to order the =EmacsSnippets=, with the =DependencyRelationship= class caching edges between the snippets in the database.
#+begin_src python :tangle generators/models.py
class DependencyRelationship(models.Model):
class DependencyRelationship(EMOM('dependencyRelationship'), models.Model):
# extract enough information to run https://docs.python.org/3/library/graphlib.html on the emacs snippets...
dependency = models.ForeignKey(
"EmacsSnippet",
@ -184,7 +185,7 @@ class DependencyRelationship(models.Model):
return list(map(lambda it: mapping[it], ts.static_order()))
class EmacsSnippet(Generator):
class EmacsSnippet(EMOM('emacs_snippet'), Generator):
ARROYO_KEYWORD_NAME = "ARROYO_EMACS_MODULE"
roles = models.ManyToManyField(
@ -257,7 +258,7 @@ test the depdendencyrelationship stuff, the graphlib sort.
It's possible for pages to stash Nix code snippets in to tangled files to make custom Emacs packages available to Arroyo Emacs using helpers like nixpkgs's =melpaBuild= and =trivialBuild= commands.
#+begin_src python :tangle generators/models.py
class EmacsEpkg(Generator):
class EmacsEpkg(EMOM('emacs_epkg'), Generator):
ARROYO_KEYWORD_NAME = "ARROYO_HOME_EPKGS"
roles = models.ManyToManyField(
@ -283,7 +284,7 @@ this one is pretty straightforward implementation of the ABC.
It's possible for pages to signal all or certain deployment roles to include a new NixOS module. This allows a user to download an org-mode file in to their org-roam directory and it will and new functionality to their computer.
#+begin_src python :tangle generators/models.py
class NixosModule(Generator):
class NixosModule(EMOM('nixos_module'), Generator):
ARROYO_KEYWORD_NAME = "ARROYO_NIXOS_MODULE"
roles = models.ManyToManyField(
@ -310,7 +311,7 @@ this one is pretty straightforward implementation of the ABC.
It's possible to add home-manager modules to the user's profile in much the same way.
#+begin_src python :tangle generators/models.py
class HomeManagerModule(Generator):
class HomeManagerModule(EMOM('home_manager_module'), Generator):
ARROYO_KEYWORD_NAME = "ARROYO_HOME_MODULE"
roles = models.ManyToManyField(

View File

@ -1,8 +1,9 @@
# [[file:../generators.org::*Arroyo Generator Data Models][Arroyo Generator Data Models:1]]
# [[file:../generators.org::*document the Generator pattern described by the Abstract Base Class.][document the Generator pattern described by the Abstract Base Class.:1]]
from __future__ import annotations
from typing import List
from django.db import models
from django.conf import settings
from django_prometheus.models import ExportModelOperationsMixin as EMOM
import arroyo.arroyo_rs as native
@ -15,7 +16,7 @@ import logging
logger = logging.getLogger(__name__)
class GeneratorRole(models.Model):
class GeneratorRole(EMOM('generatorRole'), models.Model):
name = models.CharField(max_length=512, primary_key=True)
@classmethod
@ -28,7 +29,7 @@ class GeneratorRole(models.Model):
]
class Generator(models.Model):
class Generator(EMOM('generator'), models.Model):
class Meta:
abstract = True
@ -101,10 +102,10 @@ class Generator(models.Model):
obj.excluded_roles.set(excluded_roles)
ret.append(obj)
return ret
# Arroyo Generator Data Models:1 ends here
# document the Generator pattern described by the Abstract Base Class.:1 ends here
# [[file:../generators.org::*Generate an Emacs configuration][Generate an Emacs configuration:1]]
class DependencyRelationship(models.Model):
class DependencyRelationship(EMOM('dependencyRelationship'), models.Model):
# extract enough information to run https://docs.python.org/3/library/graphlib.html on the emacs snippets...
dependency = models.ForeignKey(
"EmacsSnippet",
@ -158,7 +159,7 @@ class DependencyRelationship(models.Model):
return list(map(lambda it: mapping[it], ts.static_order()))
class EmacsSnippet(Generator):
class EmacsSnippet(EMOM('emacs_snippet'), Generator):
ARROYO_KEYWORD_NAME = "ARROYO_EMACS_MODULE"
roles = models.ManyToManyField(
@ -221,7 +222,7 @@ class EmacsSnippet(Generator):
# Generate an Emacs configuration:1 ends here
# [[file:../generators.org::*Emacs custom package overrides][Emacs custom package overrides:1]]
class EmacsEpkg(Generator):
class EmacsEpkg(EMOM('emacs_epkg'), Generator):
ARROYO_KEYWORD_NAME = "ARROYO_HOME_EPKGS"
roles = models.ManyToManyField(
@ -239,7 +240,7 @@ class EmacsEpkg(Generator):
# Emacs custom package overrides:1 ends here
# [[file:../generators.org::*Declarative NixOS module imports][Declarative NixOS module imports:1]]
class NixosModule(Generator):
class NixosModule(EMOM('nixos_module'), Generator):
ARROYO_KEYWORD_NAME = "ARROYO_NIXOS_MODULE"
roles = models.ManyToManyField(
@ -258,7 +259,7 @@ class NixosModule(Generator):
# Declarative NixOS module imports:1 ends here
# [[file:../generators.org::*Declarative =home-manager= module imports][Declarative =home-manager= module imports:1]]
class HomeManagerModule(Generator):
class HomeManagerModule(EMOM('home_manager_module'), Generator):
ARROYO_KEYWORD_NAME = "ARROYO_HOME_MODULE"
roles = models.ManyToManyField(

View File

@ -5,7 +5,7 @@ version = "0.0.1"
description = "org-mode metadata query engine, publishing platform, and computer metaprogrammer"
# license = "Hey Smell This"
readme = "README.md"
dependencies = ["click ~=8.1", "django ~= 4.2", "django-stub", "polling", "arroyo", "arrow"]
dependencies = ["click ~=8.1", "django ~= 4.2", "django-stub", "polling", "django-prometheus", "arroyo", "arrow ~= 1.3.0"]
requires-python = ">=3.10"
authors = [
{ name = "Ryan Rix", email = "code@whatthefuck.computer" }

View File

@ -25,6 +25,7 @@ from typing import List
from django.db import models
from django.conf import settings
from django.utils.module_loading import import_string
from django_prometheus.models import ExportModelOperationsMixin as EMOM
import arroyo.arroyo_rs as native
@ -43,7 +44,7 @@ def calculate_hash(path: str) -> str:
return digest.hexdigest()
class File(models.Model):
class File(EMOM('file'), models.Model):
path = models.CharField(max_length=512, primary_key=True)
digest = models.CharField(max_length=512)
@ -125,7 +126,7 @@ test the =hash_updated= function, synthesize a File object and check the behavio
** Keyword
#+BEGIN_SRC python :tangle roam/models.py
class Keyword(models.Model):
class Keyword(EMOM('keyword'), models.Model):
class Meta:
# XXX: how do i get out of this? i think i just have to assume
# that there will be duplicate, and these cannot be unique, have
@ -231,7 +232,7 @@ class RoamKeywordTest(TestCase):
** Heading
#+BEGIN_SRC python :tangle roam/models.py
class Heading(models.Model):
class Heading(EMOM('heading'), models.Model):
node_id = models.CharField(max_length=256, primary_key=True)
level = models.IntegerField()
title = models.TextField()
@ -331,7 +332,7 @@ I need to create a Page and a Site to test this ... weird concern-separation hap
** Properties
#+begin_src python :tangle roam/models.py
class HeadingProperty(models.Model):
class HeadingProperty(EMOM('heading_property'), models.Model):
heading = models.ForeignKey(
Heading,
on_delete=models.CASCADE,
@ -406,7 +407,7 @@ Level 1 headings will be properly persisted, let's see if the ID for [[id:202402
** Tag
#+BEGIN_SRC python :tangle roam/models.py
class Tag(models.Model):
class Tag(EMOM('tag'), models.Model):
class Meta:
unique_together = (("heading_id", "tag"),)
@ -439,7 +440,7 @@ class Tag(models.Model):
** Reference
#+BEGIN_SRC python :tangle roam/models.py
class Reference(models.Model):
class Reference(EMOM('reference'), models.Model):
heading = models.ForeignKey(
Heading,
on_delete=models.CASCADE,
@ -469,7 +470,7 @@ class Reference(models.Model):
** Link
#+BEGIN_SRC python :tangle roam/models.py
class Link(models.Model):
class Link(EMOM('link'), models.Model):
title = models.TextField()
source_file = models.ForeignKey(
File,

View File

@ -6,6 +6,7 @@ from typing import List
from django.db import models
from django.conf import settings
from django.utils.module_loading import import_string
from django_prometheus.models import ExportModelOperationsMixin as EMOM
import arroyo.arroyo_rs as native
@ -22,7 +23,7 @@ def calculate_hash(path: str) -> str:
return digest.hexdigest()
class File(models.Model):
class File(EMOM('file'), models.Model):
path = models.CharField(max_length=512, primary_key=True)
digest = models.CharField(max_length=512)
@ -47,7 +48,7 @@ class File(models.Model):
# File:1 ends here
# [[file:../roam.org::*Keyword][Keyword:1]]
class Keyword(models.Model):
class Keyword(EMOM('keyword'), models.Model):
class Meta:
# XXX: how do i get out of this? i think i just have to assume
# that there will be duplicate, and these cannot be unique, have
@ -79,7 +80,7 @@ class Keyword(models.Model):
# Keyword:1 ends here
# [[file:../roam.org::*Heading][Heading:1]]
class Heading(models.Model):
class Heading(EMOM('heading'), models.Model):
node_id = models.CharField(max_length=256, primary_key=True)
level = models.IntegerField()
title = models.TextField()
@ -122,7 +123,7 @@ class Heading(models.Model):
# Heading:1 ends here
# [[file:../roam.org::*Properties][Properties:1]]
class HeadingProperty(models.Model):
class HeadingProperty(EMOM('heading_property'), models.Model):
heading = models.ForeignKey(
Heading,
on_delete=models.CASCADE,
@ -145,7 +146,7 @@ class HeadingProperty(models.Model):
# Properties:1 ends here
# [[file:../roam.org::*Tag][Tag:1]]
class Tag(models.Model):
class Tag(EMOM('tag'), models.Model):
class Meta:
unique_together = (("heading_id", "tag"),)
@ -169,7 +170,7 @@ class Tag(models.Model):
# Tag:1 ends here
# [[file:../roam.org::*Reference][Reference:1]]
class Reference(models.Model):
class Reference(EMOM('reference'), models.Model):
heading = models.ForeignKey(
Heading,
on_delete=models.CASCADE,
@ -190,7 +191,7 @@ class Reference(models.Model):
# Reference:1 ends here
# [[file:../roam.org::*Link][Link:1]]
class Link(models.Model):
class Link(EMOM('link'), models.Model):
title = models.TextField()
source_file = models.ForeignKey(
File,

View File

@ -17,7 +17,7 @@ version = "0.0.1"
description = "org-mode metadata query engine, publishing platform, and computer metaprogrammer"
# license = "Hey Smell This"
readme = "README.md"
dependencies = ["click ~=8.1", "django ~= 4.2", "django-stub", "polling", "arroyo", "arrow ~= 1.3.0"]
dependencies = ["click ~=8.1", "django ~= 4.2", "django-stub", "polling", "django-prometheus", "arroyo", "arrow ~= 1.3.0"]
requires-python = ">=3.10"
authors = [
{ name = "Ryan Rix", email = "code@whatthefuck.computer" }
@ -65,6 +65,7 @@ python3.pkgs.buildPythonPackage rec {
setuptools
django
polling
django-prometheus
arrow
]);
@ -147,6 +148,7 @@ let
django-stubs.override { django = django_4; }
django-stubs-ext.override { django = django_4; }
polling
django-prometheus
arrow
]);
in pkgs.mkShell {

View File

@ -15,6 +15,7 @@ let
django-stubs.override { django = django_4; }
django-stubs-ext.override { django = django_4; }
polling
django-prometheus
arrow
]);
in pkgs.mkShell {

View File

@ -1,4 +1,4 @@
/* [[file:../../../configuration.org::*Per-site CSS][Per-site CSS:6]] */
/* [[file:../../../configuration.org::*The Code][The Code:6]] */
:root {
--alert: #cc6960;
--primary: #707231;
@ -11,4 +11,4 @@
--dark-gray: #82796c;
--black: #211f1c;
}
/* Per-site CSS:6 ends here */
/* The Code:6 ends here */

View File

@ -1,4 +1,4 @@
/* [[file:../../../configuration.org::*Per-site CSS][Per-site CSS:3]] */
/* [[file:../../../configuration.org::*The Code][The Code:3]] */
:root {
--alert: #cc6960;
--primary: #707231;
@ -11,4 +11,4 @@
--dark-gray: #808090;
--black: #211f1c;
}
/* Per-site CSS:3 ends here */
/* The Code:3 ends here */

View File

@ -1,4 +1,4 @@
/* [[file:../../../configuration.org::*Per-site CSS][Per-site CSS:2]] */
/* [[file:../../../configuration.org::*The Code][The Code:2]] */
:root {
--alert: #cc6960;
--primary: #707231;
@ -11,4 +11,4 @@
--dark-gray: #82796c;
--black: #211f1c;
}
/* Per-site CSS:2 ends here */
/* The Code:2 ends here */

View File

@ -1,4 +1,4 @@
/* [[file:../../../configuration.org::*Per-site CSS][Per-site CSS:5]] */
/* [[file:../../../configuration.org::*The Code][The Code:5]] */
:root {
--alert: #cc6960;
--primary: #707231;
@ -11,4 +11,4 @@
--dark-gray: #82796c;
--black: #211f1c;
}
/* Per-site CSS:5 ends here */
/* The Code:5 ends here */

View File

@ -1,4 +1,4 @@
/* [[file:../../../configuration.org::*Per-site CSS][Per-site CSS:4]] */
/* [[file:../../../configuration.org::*The Code][The Code:4]] */
:root {
--alert: #cc6960;
--primary: #707231;
@ -11,4 +11,4 @@
--dark-gray: #82796c;
--black: #211f1c;
}
/* Per-site CSS:4 ends here */
/* The Code:4 ends here */