initial commit
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
/public
|
||||
/resources
|
0
.hugo_build.lock
Normal file
4
TODO.md
Normal file
|
@ -0,0 +1,4 @@
|
|||
- Add permalinks to sections
|
||||
- Add summmary to articles
|
||||
- Add open graph metadata
|
||||
- Add json+ld metadata
|
5
archetypes/default.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
+++
|
||||
date = '{{ .Date }}'
|
||||
draft = true
|
||||
title = '{{ replace .File.ContentBaseName "-" " " | title }}'
|
||||
+++
|
0
assets/.gitkeep
Normal file
4
build.sh
Executable file
|
@ -0,0 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
rm -rf public
|
||||
hugo build --minify
|
25
content/_index.md
Normal file
|
@ -0,0 +1,25 @@
|
|||
+++
|
||||
title = 'Home'
|
||||
date = 2025-06-03T23:00:00Z
|
||||
draft = false
|
||||
+++
|
||||
|
||||
With a dual experience in marketing and technical fields, I have contributed to
|
||||
the success of numerous projects by adopting a comprehensive vision of them.
|
||||
|
||||
Graduate from a business school (Skema Business School), I completed a full
|
||||
training in management (accounting, finance, project management, HR, strategy,
|
||||
etc.) and specialized in marketing.
|
||||
|
||||
Passionate about computer science from a young age, I am also a self-taught
|
||||
versatile engineer, performing tasks in system and network architecture and
|
||||
administration, development, support, and training.
|
||||
|
||||
I now have over 18 years of experience in the open-source software world,
|
||||
including 8 years professionally.
|
||||
|
||||
Curious about the continuous innovations offered by all free software, I
|
||||
dedicate part of my time to technological watch, both on productivity tools and
|
||||
system and network tools, which allows me to work on the design and
|
||||
implementation of complex distributed systems as well as on the management and
|
||||
execution of application integration projects within an information system.
|
45
content/blog/001-setup-nginx-for-mediawiki.md
Normal file
|
@ -0,0 +1,45 @@
|
|||
---
|
||||
title: Setup Nginx for Mediawiki
|
||||
date: "2010-09-15T00:00:00+02:00"
|
||||
tags:
|
||||
- Nginx
|
||||
- Mediawiki
|
||||
slug: setup-nginx-for-mediawiki
|
||||
summary: >
|
||||
A simple configuration to serve Mediawiki with Nginx and FastCGI
|
||||
---
|
||||
|
||||
Two weeks ago, I migrated a server from Apache/mod_php to nginx/php-fpm. Only
|
||||
today did i succeed to remove all side effects. The latest one:
|
||||
|
||||
Static files must not go through php-fpm, but a simple test on extensions
|
||||
is ineffective, as url like `http://server/File:name_of_the_file.png`
|
||||
must be processed by PHP.
|
||||
|
||||
Here is my final setup, that corrects all the errors I encountered:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name server_name;
|
||||
index index.php;
|
||||
root /path/to/www/;
|
||||
|
||||
# Serve static files with a far future expiration
|
||||
# date for browser caches
|
||||
location ^~ /images/ {
|
||||
expires 1y;
|
||||
}
|
||||
location ^~ /skins/ {
|
||||
expires 1y;
|
||||
}
|
||||
|
||||
# Pass the request to php-cgi
|
||||
location / {
|
||||
fastcgi_pass 127.0.0.1:9000;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root/index.php;
|
||||
fastcgi_index index.php;
|
||||
include fastcgi_params;
|
||||
}
|
||||
}
|
||||
```
|
32
content/blog/002-build-pgpool-on-debian.md
Normal file
|
@ -0,0 +1,32 @@
|
|||
---
|
||||
title: Build the latest PgPool-II on Debian Etch
|
||||
date: "2010-12-14T00:00:00+01:00"
|
||||
tags: [Debian, PgPool-II]
|
||||
slug: build-pgpool-on-debian
|
||||
summary: >
|
||||
Building PgPool-II on RHEL 5.5 to avoid the "libpq is not installed or
|
||||
libpq is old" error
|
||||
---
|
||||
|
||||
After having build PgPool-II on Red Hat Enterprise Linux 5.5 without any
|
||||
problem, I tried to build it on a fresh Debian Etch. The catch is that I did
|
||||
not want to install PostgreSQL 9.0, but just extract it from the binary
|
||||
packages provided by Entreprisedb (with option `--extract-only 1`).
|
||||
|
||||
Whatever options I passed to `./configure`, it resulted in the same error:
|
||||
|
||||
{{< highlight text >}}
|
||||
checking for PQexecPrepared in -lpq... no
|
||||
configure: error: libpq is not installed or libpq is old
|
||||
{{< /highlight >}}
|
||||
|
||||
Here is the answer: the binary package contains the libpq with the name
|
||||
`libcrypto.so.0.9.8` (the RHEL name) when pgpool is looking `libcrypto.so.6`
|
||||
on Debian. The same applies to `libssl`. So a simple
|
||||
|
||||
{{< highlight bash >}}
|
||||
ln -s libcrypto.so.0.9.8 libcrypto.so.0.9.8
|
||||
ln -s libssl.so.0.9.8 libssl.so.6
|
||||
{{< /highlight >}}
|
||||
|
||||
before your `./configure` will solve it!
|
87
content/blog/003-aptana-eclipse-and-xulrunner.md
Normal file
|
@ -0,0 +1,87 @@
|
|||
---
|
||||
slug: aptana-eclipse-and-xulrunner
|
||||
title: Aptana Studio/Eclipse and Xulrunner
|
||||
tags: [Aptana Studio, Eclipse, Xulrunner, Arch Linux]
|
||||
date: "2011-12-16T00:00:00+01:00"
|
||||
summary: >
|
||||
How to solve the "Unhandled event loop exception" error in Aptana Studio and Eclipse 3.7 with Xulrunner
|
||||
---
|
||||
|
||||
Since a few months, I encountered an annoying error in Aptana Studio and
|
||||
Eclipse 3.7 (the autonomous packages, not the packages from the repositories)
|
||||
whenever I tried to do a git or hg action.
|
||||
|
||||
I could live without until now, but today, it was really bothering me.
|
||||
|
||||
The error is:
|
||||
|
||||
{{< highlight text >}}
|
||||
Unhandled event loop exception
|
||||
No more handles [Unknown Mozilla path (MOZILLA_FIVE_HOME not set)]
|
||||
{{< /highlight >}}
|
||||
|
||||
The log file showed the following backtrace:
|
||||
|
||||
{{< highlight text >}}
|
||||
!ENTRY org.eclipse.ui 4 0 2011-12-16 17:17:30.825
|
||||
!MESSAGE Unhandled event loop exception
|
||||
!STACK 0
|
||||
org.eclipse.swt.SWTError: No more handles [Unknown Mozilla path (MOZILLA_FIVE_HOME not set)]
|
||||
at org.eclipse.swt.SWT.error(SWT.java:4109)
|
||||
at org.eclipse.swt.browser.Mozilla.initMozilla(Mozilla.java:1739)
|
||||
at org.eclipse.swt.browser.Mozilla.create(Mozilla.java:656)
|
||||
at org.eclipse.swt.browser.Browser.<init>(Browser.java:119)
|
||||
at com.aptana.git.ui.internal.actions.CommitDialog.createDiffArea(CommitDialog.java:237)
|
||||
at com.aptana.git.ui.internal.actions.CommitDialog.createDialogArea(CommitDialog.java:158)
|
||||
|
||||
[...]
|
||||
|
||||
at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:620)
|
||||
at org.eclipse.equinox.launcher.Main.basicRun(Main.java:575)
|
||||
at org.eclipse.equinox.launcher.Main.run(Main.java:1408)
|
||||
at org.eclipse.equinox.launcher.Main.main(Main.java:1384)
|
||||
{{< /highlight >}}
|
||||
|
||||
To make it short, after having read [a](https://bugs.archlinux.org/task/5149)
|
||||
[lot](https://bugs.archlinux.org/task/27130)
|
||||
[of](https://github.com/eclipse-color-theme/eclipse-color-theme/issues/50)
|
||||
[posts](https://bbs.archlinux.org/viewtopic.php?id=129982)
|
||||
[about](http://forums.gentoo.org/viewtopic-t-827838-view-previous.html?sid=546c5717e2167c45d9b02f9f20ab36f4)
|
||||
[this](<http://stackoverflow.com/questions/1017945/problem-with-aptana-studio-xulrunner-8-1)
|
||||
[problem](http://www.eclipse.org/swt/faq.php#gtk64), it seemed it was enough
|
||||
to give the path to Xulrunner to Aptana.
|
||||
|
||||
On my Arch Linux, it was
|
||||
|
||||
{{< highlight bash >}}
|
||||
export MOZILLA_FIVE_HOME=/usr/lib/xulrunner-8.0
|
||||
{{< /highlight >}}
|
||||
|
||||
Trying to start Aptana Studio, I had a new error. It simply stated
|
||||
|
||||
{{< highlight text >}}
|
||||
XPCOM error -2147467261
|
||||
{{< /highlight >}}
|
||||
|
||||
The solution is that Aptana Studio cannot work with the version of Xulrunner
|
||||
in Arch Linux repositories because it is too recent.
|
||||
|
||||
To solve this problem, I had to install xulrunner 1.9.2 from AUR:
|
||||
|
||||
{{< highlight bash >}}
|
||||
yaourt -S xulrunner192
|
||||
{{< /highlight >}}
|
||||
|
||||
The PKGBUILD was broken this morning and ended in a 404 Error when fetching
|
||||
sources. If you have the same problem, `here is an updated PKGBUILD
|
||||
<https://gist.github.com/1486851>`__
|
||||
|
||||
Finally, I put
|
||||
|
||||
{{< highlight bash >}}
|
||||
-Dorg.eclipse.swt.browser.XULRunnerPath=/usr/lib/xulrunner-1.9.2
|
||||
{{< /highlight >}}
|
||||
|
||||
at the end of the `AptanaStudio3.ini` file in the Aptana Studio folder. For
|
||||
the package in the Arch Linux repositories, this file is
|
||||
`/usr/share/aptana/AptanaStudio3.ini`.
|
178
content/blog/004-locking-buzhug.md
Normal file
|
@ -0,0 +1,178 @@
|
|||
---
|
||||
tags: [Python, Buzhug, Database, Locks]
|
||||
slug: locking-buzhug
|
||||
title: Locking Buzhug
|
||||
date: "2012-02-07T00:00:00+01:00"
|
||||
summary: >
|
||||
How to implement a cross-process, system-wide lock for Buzhug
|
||||
---
|
||||
|
||||
I have recently decided to work with [Buzhug] on a project. As far as I can tell,
|
||||
it has proven efficient, fast, easy to use and to maintain. However, I ran into
|
||||
a few gotchas.
|
||||
|
||||
[Buzhug]: http://buzhug.sourceforge.net
|
||||
|
||||
Simple solutions are often the best
|
||||
===================================
|
||||
|
||||
I came to use Buzhug for the following requirements:
|
||||
|
||||
- I needed a single table
|
||||
- I did not want to add additional dependencies to the project
|
||||
- The size of the table will average 5K entries (without having more than
|
||||
10k entries in peaks)
|
||||
|
||||
And an additional (personal) one:
|
||||
|
||||
- I did not want to bother with SQL. Really not. no way!
|
||||
|
||||
That left me one option: pure-python embedded database.
|
||||
|
||||
After having considered a few libraries, I have been seduced by the way Buzhug
|
||||
interface is close to manipulating python objects. And the benchmarks seemed
|
||||
to show that it is performant enough for this project.
|
||||
|
||||
After a quick prototyping (1 day), the choice was done.
|
||||
|
||||
Then came a few weeks of development and the first stress tests...
|
||||
|
||||
|
||||
And the real world came back fast
|
||||
=================================
|
||||
|
||||
|
||||
A few times a day, the application backed by this database is intensely used:
|
||||
|
||||
- It can be run up to 50 times simultaneously in separate python process
|
||||
- Each run makes a read and a write/delete operation
|
||||
|
||||
This causes a race condition on the files used to store data, and concurent
|
||||
writes corrupts database.
|
||||
|
||||
Using `buzhug.TS_Base` instead of `buzhug.Base` did not solve anything,
|
||||
as the problem is not thread, but processes. What I need is a system-wide
|
||||
cross-process lock.
|
||||
|
||||
|
||||
Here is the answer
|
||||
==================
|
||||
|
||||
First step was to find how to implement a cross-process, system-wide lock.
|
||||
As it only has to work on Linux, the
|
||||
[Lock class given by Chris from
|
||||
Vmfarms](http://blog.vmfarms.com/2011/03/cross-process-locking-and.html) fits
|
||||
perfectly. Here is a version slightly modified to make it a context manager :
|
||||
|
||||
|
||||
{{< highlight python >}}
|
||||
import fcntl
|
||||
|
||||
class PsLock:
|
||||
"""
|
||||
Taken from:
|
||||
http://blog.vmfarms.com/2011/03/cross-process-locking-and.html
|
||||
"""
|
||||
def __init__(self, filename):
|
||||
self.filename = filename
|
||||
self.handle = open(filename, 'w')
|
||||
|
||||
# Bitwise OR fcntl.LOCK_NB if you need a non-blocking lock
|
||||
def acquire(self):
|
||||
fcntl.flock(self.handle, fcntl.LOCK_EX)
|
||||
|
||||
def release(self):
|
||||
fcntl.flock(self.handle, fcntl.LOCK_UN)
|
||||
|
||||
def __del__(self):
|
||||
self.handle.close()
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
if exc_type is None:
|
||||
pass
|
||||
self.release()
|
||||
|
||||
def __enter__(self):
|
||||
self.acquire()
|
||||
{{< /highlight >}}
|
||||
|
||||
The second step is to define a new class that inheritates from `buzhug.Base`
|
||||
that uses `PsLock` (inspired by `TS_Base`):
|
||||
|
||||
|
||||
{{< highlight python >}}
|
||||
import buzhug
|
||||
|
||||
_lock = PsLock("/tmp/buzhug.lck")
|
||||
|
||||
class PS_Base(buzhug.Base):
|
||||
|
||||
def create(self,*args,**kw):
|
||||
with _lock:
|
||||
res = buzhug.Base.create(self,*args,**kw)
|
||||
return res
|
||||
|
||||
def open(self,*args,**kw):
|
||||
with _lock:
|
||||
res = buzhug.Base.open(self,*args,**kw)
|
||||
return res
|
||||
|
||||
def close(self,*args,**kw):
|
||||
with _lock:
|
||||
res = buzhug.Base.close(self,*args,**kw)
|
||||
return res
|
||||
|
||||
def destroy(self,*args,**kw):
|
||||
with _lock:
|
||||
res = buzhug.Base.destroy(self,*args,**kw)
|
||||
return res
|
||||
|
||||
def set_default(self,*args,**kw):
|
||||
with _lock:
|
||||
res = buzhug.Base.set_default(self,*args,**kw)
|
||||
return res
|
||||
|
||||
def insert(self,*args,**kw):
|
||||
with _lock:
|
||||
res = buzhug.Base.insert(self,*args,**kw)
|
||||
return res
|
||||
|
||||
def update(self,*args,**kw):
|
||||
with _lock:
|
||||
res = buzhug.Base.update(self,*args,**kw)
|
||||
return res
|
||||
|
||||
def delete(self,*args,**kw):
|
||||
with _lock:
|
||||
res = buzhug.Base.delete(self,*args,**kw)
|
||||
return res
|
||||
|
||||
def cleanup(self,*args,**kw):
|
||||
with _lock:
|
||||
res = buzhug.Base.cleanup(self,*args,**kw)
|
||||
return res
|
||||
|
||||
def commit(self,*args,**kw):
|
||||
with _lock:
|
||||
res = buzhug.Base.commit(self,*args,**kw)
|
||||
return res
|
||||
|
||||
def add_field(self,*args,**kw):
|
||||
with _lock:
|
||||
res = buzhug.Base.add_field(self,*args,**kw)
|
||||
return res
|
||||
|
||||
def drop_field(self,*args,**kw):
|
||||
with _lock:
|
||||
res = buzhug.Base.drop_field(self,*args,**kw)
|
||||
return res
|
||||
{{< /highlight >}}
|
||||
|
||||
Now I just use
|
||||
|
||||
{{< highlight python >}}
|
||||
database = PS_Base( ... )
|
||||
{{< /highlight >}}
|
||||
|
||||
|
||||
And all the errors have vanished.
|
|
@ -0,0 +1,35 @@
|
|||
---
|
||||
tags: [Sublime Text 2]
|
||||
slug: automatically-open-sublime-text-projects-in-a-directory
|
||||
title: Automatically open Sublime Text projects in a directory
|
||||
date: "2013-05-15T00:00:00+02:00"
|
||||
summary: >
|
||||
How to automatically open Sublimetext with a file, a project or the current
|
||||
directory according to the context.
|
||||
---
|
||||
|
||||
I usually start Sublime Text 2 from the command line to work, depending
|
||||
on the case, on the content of a directory or on a project (materialized
|
||||
with a `*.sublime-project` file).
|
||||
|
||||
It ends up with one of the following commands :
|
||||
|
||||
- `subl .`
|
||||
- `subl my-project.sublime-project`
|
||||
|
||||
Here is the snippet I added to my .bashrc file to have the `subl`
|
||||
command automatically "guess" what I want. It does the following:
|
||||
|
||||
- If a path is given (subl "my/file.txt"), it opens the file.
|
||||
- If nothing is given and a .sublime-project file exists in the current
|
||||
directory, it opens it
|
||||
- If nothing is given and no .sublime-project file has been found, it
|
||||
opens the folder.
|
||||
|
||||
{{< highlight bash >}}
|
||||
function project_aware_subl {
|
||||
project_file=$(ls *.sublime-project 2>/dev/null | head -n 1)
|
||||
subl ${*:-${project_file:-.}}
|
||||
}
|
||||
alias subl="project_aware_subl"
|
||||
{{< /highlight >}}
|
395
content/blog/006-discourse-without-docker.md
Normal file
|
@ -0,0 +1,395 @@
|
|||
---
|
||||
title: Discourse without Docker
|
||||
slug: discourse-without-docker
|
||||
date: "2016-06-27T00:00:00+02:00"
|
||||
tags: [discourse, docker]
|
||||
summary: Detailed instructions on how to install Discourse and plugins without Docker.
|
||||
---
|
||||
|
||||
{{< warning >}}
|
||||
The only official method is [with docker]. You might not be able
|
||||
to get support from Discourse by following this method.
|
||||
|
||||
[with docker]: http://blog.discourse.org/2014/04/install-discourse-in-under-30-minutes/
|
||||
{{< /warning >}}
|
||||
|
||||
The team behind [Discourse] has chosen to only release Docker images of
|
||||
their software. The rational behind it is: it is easier to only support
|
||||
a single setup. I will not discuss that. It is their choice.
|
||||
|
||||
However, I don't like to use docker to deploy apps in prodution. I even
|
||||
hate it. If you are like me, here are the steps I used to install it
|
||||
and to set it up.
|
||||
|
||||
I use Debian servers in production, so the steps below are all debian
|
||||
oriented.
|
||||
|
||||
{{< note >}}
|
||||
This is not intended as a comprehensive guide. A lot of commands and
|
||||
configuration files might need to be adapted to your environment.
|
||||
|
||||
It does not even tries to talk about important topics in production such as
|
||||
security. This is left as an exercise to the reader.
|
||||
{{< /note >}}
|
||||
|
||||
## Installation
|
||||
|
||||
After all, Discourse is a rails application. It can be installed like
|
||||
any other rails application:
|
||||
|
||||
First things first: Discourse uses Redis and PostgreSQL (or at least,
|
||||
I prefer to use Postgres). I also use Nginx as a proxy to the
|
||||
application. Install the external dependencies:
|
||||
|
||||
```sh
|
||||
# Add the reposirory for Redis
|
||||
echo "deb http://packages.dotdeb.org jessie all" > /etc/apt/sources.list.d/dotdeb.list
|
||||
wget https://www.dotdeb.org/dotdeb.gpg -O - | apt-key add -
|
||||
|
||||
# Add the repository for PostgreSQL:
|
||||
echo "deb http://apt.postgresql.org/pub/repos/apt/ jessie-pgdg main" > /etc/apt/sources.list.d/postgresql.list
|
||||
wget -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
|
||||
|
||||
apt-get update
|
||||
apt-get install postgresql-9.5 redis-server nginx
|
||||
```
|
||||
|
||||
Then, create a database for the application. Enter postgres command
|
||||
line interface:
|
||||
|
||||
```sh
|
||||
su - postgres -c psql
|
||||
```
|
||||
|
||||
and enter the following commands:
|
||||
|
||||
```sql
|
||||
CREATE DATABASE discourse;
|
||||
CREATE USER discourse;
|
||||
ALTER USER discourse WITH ENCRYPTED PASSWORD 'password';
|
||||
ALTER DATABASE discourse OWNER TO discourse;
|
||||
\connect discourse
|
||||
CREATE EXTENSION hstore;
|
||||
CREATE EXTENSION pg_trgm;
|
||||
```
|
||||
|
||||
Then, you can checkout the Discourse code:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/discourse/discourse.git /path/to/discourse
|
||||
|
||||
# Optionally, checkout a specific tag
|
||||
cd /path/to/discourse
|
||||
git checkout v1.5.3
|
||||
```
|
||||
|
||||
Then, go in the application top directory, and set it up as any rails
|
||||
application:
|
||||
|
||||
```bash
|
||||
# Optionally setup rvm with ruby 1.9.3 minimum (I use 2.3.0)
|
||||
rvm install 2.3.0
|
||||
rvm use 2.3.0
|
||||
|
||||
# install dependencies
|
||||
cd /path/to/discourse
|
||||
RAILS_ENV bundle install
|
||||
```
|
||||
|
||||
It's time to configure the application.
|
||||
|
||||
Here, Discourse has a little particularity: The production
|
||||
configuration is located in the file `./config/discourse.conf`.
|
||||
|
||||
Create this file :
|
||||
|
||||
```bash
|
||||
cp config/discourse_defaults.conf config/discourse.conf
|
||||
```
|
||||
|
||||
And edit it with your configuration. The main areas of interest are
|
||||
configuration for the database and for the email server:
|
||||
|
||||
```ini
|
||||
# host address for db server
|
||||
# This is set to blank so it tries to use sockets first
|
||||
db_host = localhost
|
||||
|
||||
# port running db server, no need to set it
|
||||
db_port = 5432
|
||||
|
||||
# database name running discourse
|
||||
db_name = discourse
|
||||
|
||||
# username accessing database
|
||||
db_username = discourse
|
||||
|
||||
# password used to access the db
|
||||
db_password = password
|
||||
```
|
||||
|
||||
and for the SMTP server (in this example, we use Gmail):
|
||||
|
||||
```ini
|
||||
# address of smtp server used to send emails
|
||||
smtp_address = smtp.gmail.com
|
||||
|
||||
# port of smtp server used to send emails
|
||||
smtp_port = 587
|
||||
|
||||
# domain passed to smtp server
|
||||
smtp_domain = gmail.com
|
||||
|
||||
# username for smtp server
|
||||
smtp_user_name = your-address@gmail.com
|
||||
|
||||
# password for smtp server
|
||||
smtp_password = password
|
||||
|
||||
# smtp authentication mechanism
|
||||
smtp_authentication = plain
|
||||
|
||||
# enable TLS encryption for smtp connections
|
||||
smtp_enable_start_tls = true
|
||||
```
|
||||
|
||||
Now, we can prepare discourse for production:
|
||||
|
||||
```bash
|
||||
RAILS_ENV=production bundle exec rake db:migrate
|
||||
RAILS_ENV=production bundle exec rake assets:precompile
|
||||
```
|
||||
|
||||
It is time to start the application. I usually use Puma to deploy
|
||||
Rails app.
|
||||
|
||||
Create the file `config/puma.rb` in discourse directory. Following
|
||||
content should be enough (for more info, see
|
||||
[Puma's documentation]):
|
||||
|
||||
```ruby
|
||||
#!/usr/bin/env puma
|
||||
|
||||
application_path = '/home/discuss.waarp.org/discourse'
|
||||
directory application_path
|
||||
environment 'production'
|
||||
daemonize false
|
||||
pidfile "#{application_path}/tmp/pids/puma.pid"
|
||||
state_path "#{application_path}/tmp/pids/puma.state"
|
||||
bind "unix://#{application_path}/tmp/sockets/puma.socket"
|
||||
```
|
||||
|
||||
From there, the application can be run with the following command :
|
||||
|
||||
```bash
|
||||
bundle exec puma -C config/puma.rb
|
||||
```
|
||||
|
||||
Finally, setup nginx to forward requests to Discourse. Create the file
|
||||
`/etc/nginx/conf.d/discourse.conf` with the following content :
|
||||
|
||||
```nginx
|
||||
upstream discourse {
|
||||
server unix:/path/to/discourse/tmp/sockets/puma.socket;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name example.com;
|
||||
|
||||
location / {
|
||||
try_files $uri @proxy;
|
||||
}
|
||||
|
||||
location @proxy {
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_pass http://discourse;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Your very own forum with Discourse is setup!
|
||||
|
||||
## Service Management
|
||||
|
||||
According to your workflow, you can add systemd units to run discourse.
|
||||
It needs at least two service definition:
|
||||
|
||||
1. Sidekiq, which is used to process asynchronous background tasks
|
||||
2. Rails, for Discource itself.
|
||||
|
||||
With the services setup, services can be started/stopped/enabled with
|
||||
`systemctl` commands.
|
||||
|
||||
But before that, if you use RVM, you must create a wrapper for the
|
||||
environment (local ruby, and optional gemset) used by Discourse:
|
||||
|
||||
```bash
|
||||
rvm wrapper 2.3.0 systemd bundle
|
||||
```
|
||||
|
||||
This creates an executable in `$rvm_bin_path` that you can call
|
||||
in lieu of bundle that will automatically load the right envirnoment.
|
||||
|
||||
### Sidekiq
|
||||
|
||||
First, create a configuration for sidekiq. Create the file
|
||||
`config/sidekiq.yml` in your discoure project with the following
|
||||
content (for more info, see [Sidekiq's documentation]):
|
||||
|
||||
```yaml
|
||||
---
|
||||
:concurrency: 5
|
||||
:pidfile: tmp/pids/sidekiq.pid
|
||||
staging:
|
||||
:concurrency: 10
|
||||
production:
|
||||
:concurrency: 20
|
||||
:queues:
|
||||
- default
|
||||
- critical
|
||||
- low
|
||||
```
|
||||
|
||||
Then, create the service unit for Sidekiq. Create the file
|
||||
`/etc/systemd/system/discourse-sidekiq.service` with the
|
||||
following content:
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=discourse sidekiq service
|
||||
After=multi-user.target
|
||||
|
||||
[Service]
|
||||
WorkingDirectory=/path/to/discourse
|
||||
Environment=RAILS_ENV=production
|
||||
ExecStart=/path/to/rvm/.rvm/bin/systemd_bundle exec sidekiq -C config/sidekiq.yml
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
### Discourse
|
||||
|
||||
For Discourse, just create the service unit for Puma. Create the file
|
||||
`/etc/systemd/system/discourse.service` with the
|
||||
following content:
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=discourse service
|
||||
After=discourse-sidekiq.service
|
||||
Requires=discourse-sidekiq.service
|
||||
|
||||
[Service]
|
||||
WorkingDirectory=/path/to/discourse
|
||||
Environment=RAILS_ENV=production
|
||||
ExecStart=/path/to/rvm/.rvm/bin/systemd_bundle exec puma -C config/puma.rb
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
## Upgrades
|
||||
|
||||
Upgrades are even easier:
|
||||
|
||||
First read the release notes.
|
||||
Then make backups of the code and the database.
|
||||
Now you can checkout the newest version:
|
||||
|
||||
```bash
|
||||
cd /path/to/discourse
|
||||
git checkout vX.X.X
|
||||
```
|
||||
|
||||
Install the new dependencies, run the migrations and rebuild the
|
||||
assets:
|
||||
|
||||
```bash
|
||||
RAILS_ENV=production bundle install
|
||||
RAILS_ENV=production bundle exec rake db:migrate
|
||||
RAILS_ENV=production bundle exec rake assets:precompile
|
||||
```
|
||||
|
||||
Restart Discourse:
|
||||
|
||||
```bash
|
||||
systemctl restart discourse
|
||||
```
|
||||
|
||||
What can go wrong? If if I do not give any solution here, it is always
|
||||
recoverable (hence the backups!).
|
||||
|
||||
- The database migration failed (restore the database with your backup,
|
||||
fix the problem and try again!)
|
||||
- The plugins are not compatible with the latest version (rollback to
|
||||
the previous working solution and wit for them to be compatible)
|
||||
|
||||
## Plugins
|
||||
|
||||
Discourse plugins can be handles the same way.
|
||||
|
||||
### Plugin Installation
|
||||
|
||||
Install the plugin with the url of its repository:
|
||||
|
||||
```bash
|
||||
cd /path/to discourse
|
||||
RAILS_ENV=production bundle exec rake plugin:install[URL]
|
||||
```
|
||||
|
||||
Install the new dependencies, run the migrations and rebuild the
|
||||
assets:
|
||||
|
||||
```bash
|
||||
RAILS_ENV=production bundle install
|
||||
RAILS_ENV=production bundle exec rake db:migrate
|
||||
RAILS_ENV=production bundle exec rake assets:precompile
|
||||
```
|
||||
|
||||
Restart Discourse:
|
||||
|
||||
```bash
|
||||
systemctl restart discourse
|
||||
```
|
||||
|
||||
### Upgrade
|
||||
|
||||
To upgrade a specific plugin, use the following command:
|
||||
|
||||
```bash
|
||||
RAILS_ENV=production bundle exec rake plugin:update[ID]
|
||||
```
|
||||
|
||||
You can also upgrade all plugins at once with the command:
|
||||
|
||||
```bash
|
||||
RAILS_ENV=production bundle exec rake plugin:update_all
|
||||
```
|
||||
|
||||
Then, install the new dependencies, run the migrations and rebuild the
|
||||
assets:
|
||||
|
||||
```bash
|
||||
RAILS_ENV=production bundle install
|
||||
RAILS_ENV=production bundle exec rake db:migrate
|
||||
RAILS_ENV=production bundle exec rake assets:precompile
|
||||
```
|
||||
|
||||
and restart Discourse:
|
||||
|
||||
```bash
|
||||
systemctl restart discourse
|
||||
```
|
||||
|
||||
[Discourse]: http://www.discourse.org/
|
||||
[Sidekiq's documentation]: https://github.com/mperham/sidekiq/wiki/Advanced-Options
|
||||
[Puma's documentation]: https://github.com/puma/puma
|
6
content/blog/_index.md
Normal file
|
@ -0,0 +1,6 @@
|
|||
+++
|
||||
title = 'Blog'
|
||||
date = 2025-06-04T23:00:00Z
|
||||
draft = false
|
||||
+++
|
||||
|
0
data/.gitkeep
Normal file
68
hugo.yaml
Normal file
|
@ -0,0 +1,68 @@
|
|||
baseURL: 'https://bcarlin.net/'
|
||||
languageCode: 'fr-FR'
|
||||
title: 'Bruno Carlin'
|
||||
theme: ['bcarlin']
|
||||
uglyUrls: true
|
||||
copyright: '© 2025 Bruno Carlin'
|
||||
summaryLength: 15
|
||||
params:
|
||||
author:
|
||||
email: mail@bcarlin.net
|
||||
name: Bruno Carlin
|
||||
|
||||
outputs:
|
||||
home:
|
||||
- html
|
||||
section:
|
||||
- html
|
||||
- rss
|
||||
taxonomy:
|
||||
- html
|
||||
term:
|
||||
- html
|
||||
- rss
|
||||
|
||||
outputFormats:
|
||||
rss:
|
||||
noUgly: false
|
||||
|
||||
markup:
|
||||
highlight:
|
||||
noClasses: false
|
||||
|
||||
menus:
|
||||
main:
|
||||
- name: 'Home'
|
||||
pageRef: '/'
|
||||
weight: 10
|
||||
params:
|
||||
class: "u-url"
|
||||
|
||||
- name: 'Blog'
|
||||
pageRef: '/blog'
|
||||
weight: 20
|
||||
|
||||
secondary:
|
||||
- name: '@bcarlin@hachyderm.io'
|
||||
url: 'https://hachyderm.io/@bcarlin'
|
||||
weight: 10
|
||||
params:
|
||||
rel: "me"
|
||||
iconName: "mastodon-fill"
|
||||
iconTitle: "Mastodon"
|
||||
|
||||
- name: 'LinkedIn'
|
||||
url: 'https://www.linkedin.com/in/brunocarlin'
|
||||
weight: 20
|
||||
params:
|
||||
rel: "me"
|
||||
iconName: "linkedin-fill"
|
||||
iconTitle: "LinkedIn"
|
||||
|
||||
- name: 'GPG Key'
|
||||
url: '/bcarlin.gpg'
|
||||
weight: 30
|
||||
params:
|
||||
class: "u-key"
|
||||
iconName: "key-fill"
|
||||
iconTitle: "GPG Public Key"
|
0
i18n/.gitkeep
Normal file
0
layouts/.gitkeep
Normal file
73
static/.well-known/keybase.txt
Normal file
|
@ -0,0 +1,73 @@
|
|||
==================================================================
|
||||
https://keybase.io/bcarlin
|
||||
--------------------------------------------------------------------
|
||||
|
||||
I hereby claim:
|
||||
|
||||
* I am an admin of https://bcarlin.net
|
||||
* I am bcarlin (https://keybase.io/bcarlin) on keybase.
|
||||
* I have a public key with fingerprint 08C4 4FD4 4533 1DEF 6696 FB5D 2298 63E4 199F C2F8
|
||||
|
||||
To do so, I am signing this object:
|
||||
|
||||
{
|
||||
"body": {
|
||||
"key": {
|
||||
"eldest_kid": "01018f3e0c8806ef31d1cb43ec77b9eca048310cde351f76ee10a02cdfc97418eb660a",
|
||||
"fingerprint": "08c44fd445331def6696fb5d229863e4199fc2f8",
|
||||
"host": "keybase.io",
|
||||
"key_id": "229863e4199fc2f8",
|
||||
"kid": "01018f3e0c8806ef31d1cb43ec77b9eca048310cde351f76ee10a02cdfc97418eb660a",
|
||||
"uid": "5b44e763b8950ddd1fb7d76f03513f19",
|
||||
"username": "bcarlin"
|
||||
},
|
||||
"service": {
|
||||
"hostname": "bcarlin.net",
|
||||
"protocol": "https:"
|
||||
},
|
||||
"type": "web_service_binding",
|
||||
"version": 1
|
||||
},
|
||||
"ctime": 1748993287,
|
||||
"expire_in": 157680000,
|
||||
"prev": "14f3ba62d0615cfe0295d5c6924e5175fe57e3e414def1bdd48cfd793cdc78ad",
|
||||
"seqno": 2,
|
||||
"tag": "signature"
|
||||
}
|
||||
|
||||
which yields the signature:
|
||||
|
||||
-----BEGIN PGP MESSAGE-----
|
||||
|
||||
owGtUmtMHFUY3aVgZStKLZWqJaQDjegSOrPz3vDYxFoRQVpoqwiWzOMOO90nOwNI
|
||||
t8hqC1sCC0hbG9jV1gbCaxuLUNTSlECFaEwQxIipMQTE1m2DgKaBpJE6Q+wPE396
|
||||
/9zcc88593zf/ZqjNml02sbdr114cNdv034TYjXmjJqn3RDr4CshoxuygI0NWHkg
|
||||
ycUWkYeMEIzACCWgAOYoCiaAgCI8wrEYCjiSZGnAMTBGoQjM8QDFEYEkAEBgBjZw
|
||||
vMDRJIZQgCUImIGSIUG0lwCX0yXaZdWW4jBM4DEMRxVHIBAETQgszhsMNEWgAENo
|
||||
WuAMAqUIzQ5JVSjhWEYCKaJDwZRD8Ua8/+D/z7nLNuxwFsMASaAsReMwz/OIwJI8
|
||||
SQiwokYFhFaJEnDZGRtQ2CzHuKyiHapKhhSwXOSA2le1kH8TUuxAVpROl0N2cA6r
|
||||
cmGWZadkVIVypVNlVgC2+B+PYla080oXFUU5cEmiww4ZEYXJyaJqipAYRdOogSKT
|
||||
IfC2U3SBYlFl4CRBwcpS3wHliiWCCSjLEAb+MEwgOCcA2EDjPM4RtAEDOELiAsBJ
|
||||
oDYVU34GYXkeoziBJ2mU4zmSYnhILavU7oCMBiUnU6J4SmKJnZHLXACq0tWFoeEa
|
||||
rU4T99Su8NjY1v01+3IShvWTCQ8nLyJMHTuNLjL6IfLmXLQmcD7ksVFNfWtfZFw4
|
||||
7kOuDdZ9dTJq6Yyr1Hs9lri/9Iq1d22s1pK4tSAm1d/wwOiToaNLe+C1QO6ch25M
|
||||
6q4c6/N1ts51hJ80h/oHZ24NZs6vN4Wqj9cHPxma3bL3crCA60idSa36aMtEgceX
|
||||
vGx01xt0loCuZcesdqgp/d5zkeyVvvSUg/mPPxt92lzddeLc1e2YfnlxWZt4o/ax
|
||||
MGmbH7vr3byPyHk0PjI8RiJKGwqvt+Xkgt9au0591n5Tk17kPeEfTDzkBrXl+gKb
|
||||
3c2k9W3tHm3WbloKnlv+YFVz9HzL5JHxmRf/9JR8mXcg4Gs7/bERaYxr/dn0+Y63
|
||||
gDmgy2uQWrJfYAa2TUzV7X59z3f777zcOzT1rSdT/PRdc+jYk4fz3su6uoKmcDWm
|
||||
l+7ELSZAI5HP+2/o/1jN8l5ZS9o+OWrL90DW3vSBgxnVm99of3Uy23FgYZfQKcYU
|
||||
zcdG1K7csvrTz85UyLnV98um/rqY9sw7AVPloZG5az0NP0YVOpHfFwsL9A1dq4v9
|
||||
EeV7vx83Rf4Q2jm+Xt3+yC9ed+ECIHqPBFf4S3U9w7cT7g3M9p+dyOxstsyvHXvC
|
||||
lL1afzs/7/0e4etg/HAwaf1y2s4z08KHXdO+n4riLTfxhV8r4lBppLKIKVw2NWX1
|
||||
XGRaO7pH8elL+gUetelyotrax3x/Aw==
|
||||
=JR35
|
||||
-----END PGP MESSAGE-----
|
||||
|
||||
And finally, I am proving ownership of this host by posting or
|
||||
appending to this document.
|
||||
|
||||
View my publicly-auditable identity here: https://keybase.io/bcarlin
|
||||
|
||||
==================================================================
|
||||
|
148
static/bcarlin.gpg
Normal file
|
@ -0,0 +1,148 @@
|
|||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
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
|
||||
=ebDO
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
5
themes/bcarlin/archetypes/default.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
+++
|
||||
date = '{{ .Date }}'
|
||||
draft = true
|
||||
title = '{{ replace .File.ContentBaseName "-" " " | title }}'
|
||||
+++
|
353
themes/bcarlin/assets/static/css/bcarlin.css
Normal file
|
@ -0,0 +1,353 @@
|
|||
@import url("/static/css/syntax-light.css") only screen and (prefers-color-scheme: light);
|
||||
@import url('/static/css/syntax-dark.css') only screen and (prefers-color-scheme: dark);
|
||||
|
||||
@font-face {
|
||||
font-family: 'Gentium Plus';
|
||||
src: url('/static/fonts/GentiumPlus-Regular.woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Gentium Plus';
|
||||
font-style: italic;
|
||||
src: url('/static/fonts/GentiumPlus-Italic.woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Gentium Plus';
|
||||
font-weight: bold;
|
||||
src: url('/static/fonts/GentiumPlus-Bold.woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Gentium Plus';
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
src: url('/static/fonts/GentiumPlus-BoldItalic.woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Nunito Sans';
|
||||
font-style: italic;
|
||||
font-weight: 200 1000;
|
||||
font-stretch: 100%;
|
||||
src: url('/static/fonts/NunitoSans-Italic.woff2') format('woff2');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Nunito Sans';
|
||||
font-style: normal;
|
||||
font-weight: 200 1000;
|
||||
font-stretch: 100%;
|
||||
src: url('/static/fonts/NunitoSans.woff2') format('woff2');
|
||||
}
|
||||
|
||||
/*
|
||||
* pico.css variables overrides
|
||||
*/
|
||||
|
||||
:root {
|
||||
--pico-font-family: 'Gentium Plus', serif, var(--pico-font-family-emoji);
|
||||
--pico-font-family-sans-serif: 'Nunito Sans', sans-serif, var(--pico-font-family-emoji);
|
||||
--pico-card-sectioning-background-color: transparent;
|
||||
--pico-typography-spacing-vertical: calc(1.5 * var(--pico-spacing));
|
||||
--markup-color: rgb(194 198 207 / 100%);
|
||||
}
|
||||
|
||||
@media only screen and (prefers-color-scheme: light) {
|
||||
:root:not([data-theme=dark]), [data-theme=light] {
|
||||
--pico-background-color: rgb(247 249 252 / 100%);
|
||||
--pico-card-background-color: rgb(255 255 255 / 100%);
|
||||
--pico-card-sectioning-background-color: transparent;
|
||||
}
|
||||
|
||||
.admonition.warning {
|
||||
--admonition-background-color: rgb(255 240 219 / 100%);
|
||||
--admonition-border-color: rgb(255 208 143 / 100%);
|
||||
}
|
||||
|
||||
.admonition.note {
|
||||
--admonition-background-color: rgb(219 238 255 / 100%);
|
||||
--admonition-border-color: rgb(142 202 255 / 100%);
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (prefers-color-scheme: dark) {
|
||||
.admonition.warning {
|
||||
--admonition-background-color: rgb(52 46 38 / 100%);
|
||||
--admonition-border-color: rgb(255 208 143 / 100%);
|
||||
}
|
||||
|
||||
.admonition.note {
|
||||
--admonition-background-color: rgb(48 59 68 / 100%);
|
||||
--admonition-border-color: rgb(142 202 255 / 100%);
|
||||
}
|
||||
}
|
||||
|
||||
article {
|
||||
--pico-card-box-shadow: none;
|
||||
}
|
||||
|
||||
header nav :where(a:not([role="button"])):is([aria-current]:not([aria-current="false"]),:hover,:active,:focus),
|
||||
header nav [role="link"]:is([aria-current]:not([aria-current="false"]),:hover,:active,:focus) {
|
||||
--pico-text-decoration: none;
|
||||
}
|
||||
|
||||
header :where(a:not([role="button"])) {
|
||||
--pico-text-decoration: none;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 40em;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
/*
|
||||
* Layout Styling
|
||||
*/
|
||||
|
||||
.mobile-header {
|
||||
padding: 0 var(--pico-block-spacing-horizontal);
|
||||
position: sticky;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background-color: rgb(from var(--pico-background-color) r g b / 80%);
|
||||
backdrop-filter: blur(3px);
|
||||
font-family: var(--pico-font-family-sans-serif);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.mobile-header img {
|
||||
height: 2em;
|
||||
}
|
||||
|
||||
#menu-close, #menu-close:hover, #menu-toggle {
|
||||
color: inherit;
|
||||
background-color: inherit;
|
||||
border: none;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--pico-background-color);
|
||||
}
|
||||
|
||||
body > header {
|
||||
width: 100vw;
|
||||
text-align: center;
|
||||
height: 100vh;
|
||||
position: fixed;
|
||||
left: -100vw;
|
||||
top: 0;
|
||||
background-color: var(--pico-background-color);
|
||||
z-index: 100;
|
||||
transition: left 0.5s;
|
||||
overflow: hidden auto;
|
||||
}
|
||||
|
||||
body > header.active {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
body > header nav, body > header nav ul {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
body > header .u-logo {
|
||||
width: 5em;
|
||||
}
|
||||
|
||||
|
||||
body > header .title {
|
||||
font-size: 1.5rem;
|
||||
font-weight: bold;
|
||||
font-family: var(--pico-font-family-sans-serif);
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
body > header nav {
|
||||
font-size: 1rem;
|
||||
font-family: var(--pico-font-family-sans-serif);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
body > header nav li {
|
||||
padding: 0;
|
||||
padding: calc( var(--pico-nav-element-spacing-vertical) / 4)
|
||||
calc( var(--pico-nav-element-spacing-horizontal) / 4);
|
||||
}
|
||||
|
||||
body > header a {
|
||||
color: var(--pico-color);
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body > header > a {
|
||||
float: right;
|
||||
padding: 0 1.5em;
|
||||
}
|
||||
|
||||
.menu-primary {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
body > footer p {
|
||||
font-size: 0.7em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media (width >= 1024px) {
|
||||
.mobile-header, #menu-close {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body > header {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 15em;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.container {
|
||||
margin-right: 0;
|
||||
margin-left: 18em;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Content Styling
|
||||
*/
|
||||
|
||||
main > article {
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
main > article > header {
|
||||
margin-bottom: calc(2 * var(--pico-block-spacing-vertical));
|
||||
}
|
||||
|
||||
.metadata {
|
||||
display: flex;
|
||||
gap: 0.5em;
|
||||
}
|
||||
|
||||
ul.tags, ul.tags li {
|
||||
list-style-type: none;
|
||||
display: inline;
|
||||
padding-left: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.tags li:not(:last-child)::after {
|
||||
content: ", ";
|
||||
}
|
||||
|
||||
ul > li {
|
||||
list-style-type: disc;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-family: var(--pico-font-family-sans-serif);
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.7rem;
|
||||
}
|
||||
|
||||
h1::before {
|
||||
content: "# ";
|
||||
color: var(--markup-color);
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
h2::before {
|
||||
content: "## ";
|
||||
color: var(--markup-color);
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
h3::before {
|
||||
content: "### ";
|
||||
color: var(--markup-color);
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
h4::before {
|
||||
content: "#### ";
|
||||
color: var(--markup-color);
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
h5::before {
|
||||
content: "##### ";
|
||||
color: var(--markup-color);
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
h6::before {
|
||||
content: "###### ";
|
||||
color: var(--markup-color);
|
||||
}
|
||||
|
||||
article header h1, article header p {
|
||||
margin-bottom: calc(0.1 * var(--pico-typography-spacing-vertical));
|
||||
}
|
||||
|
||||
|
||||
h1 a, h2 a, h3 a, h4 a, h5 a, h6 a {
|
||||
color: var(--pico-muted-color);
|
||||
text-decoration: none;
|
||||
margin-left: 0.4rem;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
pre {
|
||||
margin-bottom: calc(1.5 * var(--pico-spacing));
|
||||
}
|
||||
|
||||
code, kdb, pre {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
/*
|
||||
* Admonitions
|
||||
*/
|
||||
|
||||
.admonition {
|
||||
font-size: 0.9em;
|
||||
padding: 1em;
|
||||
border-left: solid 4px var(--admonition-border-color);
|
||||
background-color: var(--admonition-background-color);
|
||||
margin-bottom: var(--pico-typography-spacing-vertical);
|
||||
border-radius: var(--pico-border-radius);
|
||||
}
|
||||
|
||||
/*
|
||||
* Post lists
|
||||
*/
|
||||
|
||||
.h-feed article:not(:last-child) {
|
||||
border-bottom: var(--pico-border-width) solid var(--pico-card-border-color);
|
||||
}
|
4
themes/bcarlin/assets/static/css/pico.min.css
vendored
Normal file
3099
themes/bcarlin/assets/static/css/remixicon.css
Normal file
22
themes/bcarlin/assets/static/js/bcarlin.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
'use strict';
|
||||
|
||||
// Listens for clicks on the mobile menu toggle and the main menu close toggle.
|
||||
window.addEventListener('click', function(e) {
|
||||
const menu = document.getElementById('menu'),
|
||||
menuToggle = document.getElementById('menu-toggle'),
|
||||
body = document.body;
|
||||
|
||||
if (e.target.matches('#menu-toggle, #menu-toggle i')) {
|
||||
menu.classList.toggle('active');
|
||||
menu.ariaHidden = false;
|
||||
menuToggle.ariaExpanded = true;
|
||||
body.style.overflow = 'hidden';
|
||||
}
|
||||
|
||||
if (e.target.matches('#menu-close, #menu-close i')) {
|
||||
menu.classList.remove('active');
|
||||
menu.ariaHidden = true;
|
||||
menuToggle.ariaExpanded = false;
|
||||
body.style.overflow = 'auto';
|
||||
}
|
||||
});
|
9
themes/bcarlin/content/_index.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
+++
|
||||
title = 'Home'
|
||||
date = 2023-01-01T08:00:00-07:00
|
||||
draft = false
|
||||
+++
|
||||
|
||||
Laborum voluptate pariatur ex culpa magna nostrud est incididunt fugiat
|
||||
pariatur do dolor ipsum enim. Consequat tempor do dolor eu. Non id id anim anim
|
||||
excepteur excepteur pariatur nostrud qui irure ullamco.
|
24
themes/bcarlin/hugo.toml
Normal file
|
@ -0,0 +1,24 @@
|
|||
baseURL = 'https://example.org/'
|
||||
languageCode = 'en-US'
|
||||
title = 'My New Hugo Site'
|
||||
|
||||
[menus]
|
||||
[[menus.main]]
|
||||
name = 'Home'
|
||||
pageRef = '/'
|
||||
weight = 10
|
||||
|
||||
[[menus.main]]
|
||||
name = 'Posts'
|
||||
pageRef = '/posts'
|
||||
weight = 20
|
||||
|
||||
[[menus.main]]
|
||||
name = 'Tags'
|
||||
pageRef = '/tags'
|
||||
weight = 30
|
||||
|
||||
[module]
|
||||
[module.hugoVersion]
|
||||
extended = false
|
||||
min = '0.146.0'
|
15
themes/bcarlin/layouts/_partials/footer.html
Normal file
|
@ -0,0 +1,15 @@
|
|||
|
||||
<p>
|
||||
© {{ now.Year }} Bruno Carlin
|
||||
<br>
|
||||
The content of this site is licensed under
|
||||
<a href="https://creativecommons.org/licenses/by-nc/4.0/" rel="license">
|
||||
Creative Commons Attribution-NonCommercial 4.0
|
||||
International
|
||||
</a>
|
||||
{{partial "icon.html" (dict "icon" "creative-commons-fill" "label" "Creative Commons Logo")}}
|
||||
{{partial "icon.html" (dict "icon" "creative-commons-by-fill" "label" "Creative Commons Attribution Logo")}}
|
||||
{{partial "icon.html" (dict "icon" "creative-commons-nc-fill" "label" "Creative Commons Non Commercial Logo")}}
|
||||
<br>
|
||||
Generated with <a href="https://gohugo.io">Hugo</a> using a custom theme.
|
||||
</p>
|
24
themes/bcarlin/layouts/_partials/head.html
Normal file
|
@ -0,0 +1,24 @@
|
|||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
|
||||
{{ with .Site.GetPage "/blog" }}
|
||||
{{- with .OutputFormats.Get "rss" }}
|
||||
{{- printf `<link rel=%q type=%q href=%q title=%q>` .Rel .MediaType.Type .Permalink site.Title | safeHTML }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{ if eq .Kind "term" }}
|
||||
{{- with .OutputFormats.Get "rss" }}
|
||||
{{- printf `<link rel=%q type=%q href=%q title='%s | %s'>` .Rel .MediaType.Type .Permalink $.Title site.Title | safeHTML }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
<link rel="icon" type="image/png" href="/favicon-96x96.png" sizes="96x96" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<link rel="shortcut icon" href="/favicon.ico" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
||||
<meta name="apple-mobile-web-app-title" content="bcarlin.net" />
|
||||
<link rel="manifest" href="/site.webmanifest" />
|
||||
|
||||
<title>{{ if .IsHome }}{{ site.Title }}{{ else }}{{ printf "%s | %s" .Title site.Title }}{{ end }}</title>
|
||||
{{ partialCached "head/css.html" . }}
|
||||
{{ partialCached "head/js.html" . }}
|
29
themes/bcarlin/layouts/_partials/head/css.html
Normal file
|
@ -0,0 +1,29 @@
|
|||
{{- with resources.Get "static/css/pico.min.css" }}
|
||||
{{- if hugo.IsDevelopment }}
|
||||
<link rel="stylesheet" href="{{ .RelPermalink }}">
|
||||
{{- else }}
|
||||
{{- with . | minify | fingerprint }}
|
||||
<link rel="stylesheet" href="{{ .RelPermalink }}" integrity="{{ .Data.Integrity }}" crossorigin="anonymous">
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- with resources.Get "static/css/remixicon.css" }}
|
||||
{{- if hugo.IsDevelopment }}
|
||||
<link rel="stylesheet" href="{{ .RelPermalink }}">
|
||||
{{- else }}
|
||||
{{- with . | minify | fingerprint }}
|
||||
<link rel="stylesheet" href="{{ .RelPermalink }}" integrity="{{ .Data.Integrity }}" crossorigin="anonymous">
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- with resources.Get "static/css/bcarlin.css" }}
|
||||
{{- if hugo.IsDevelopment }}
|
||||
<link rel="stylesheet" href="{{ .RelPermalink }}">
|
||||
{{- else }}
|
||||
{{- with . | minify | fingerprint }}
|
||||
<link rel="stylesheet" href="{{ .RelPermalink }}" integrity="{{ .Data.Integrity }}" crossorigin="anonymous">
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
16
themes/bcarlin/layouts/_partials/head/js.html
Normal file
|
@ -0,0 +1,16 @@
|
|||
{{- with resources.Get "static/js/bcarlin.js" }}
|
||||
{{- $opts := dict
|
||||
"minify" (not hugo.IsDevelopment)
|
||||
"sourceMap" (cond hugo.IsDevelopment "external" "")
|
||||
"targetPath" "static/js/bcarlin.js"
|
||||
}}
|
||||
{{- with . | js.Build $opts }}
|
||||
{{- if hugo.IsDevelopment }}
|
||||
<script src="{{ .RelPermalink }}"></script>
|
||||
{{- else }}
|
||||
{{- with . | fingerprint }}
|
||||
<script src="{{ .RelPermalink }}" integrity="{{ .Data.Integrity }}" crossorigin="anonymous"></script>
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
20
themes/bcarlin/layouts/_partials/header.html
Normal file
|
@ -0,0 +1,20 @@
|
|||
<a id="menu-close">
|
||||
{{partial "icon.html" (dict "icon" "close-large-fill" "label" "Close the menu")}}
|
||||
</a>
|
||||
<nav id="main-menu" aria-label="Main menu">
|
||||
<ul>
|
||||
<li>
|
||||
<a href="/" class="contrast">
|
||||
<img class="u-logo" src="/static/logo.svg" alt="Logo"/>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<span class="title p-name"><a href="/" class="contrast">Bruno Carlin</a></span>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
{{ partial "menu.html" (dict "menuID" "main" "class" "menu-primary" "page" .) }}
|
||||
|
||||
{{ partial "menu.html" (dict "menuID" "secondary" "class" "menu-secondary" "page" .) }}
|
||||
</nav>
|
||||
|
1
themes/bcarlin/layouts/_partials/icon.html
Normal file
|
@ -0,0 +1 @@
|
|||
<i class="ri-{{ .icon }}" role="img" title="{{ .label }}"></i>
|
62
themes/bcarlin/layouts/_partials/menu.html
Normal file
|
@ -0,0 +1,62 @@
|
|||
{{- /*
|
||||
Renders a menu for the given menu ID.
|
||||
|
||||
@context {page} page The current page.
|
||||
@context {string} menuID The menu ID.
|
||||
|
||||
@example: {{ partial "menu.html" (dict "menuID" "main" "page" .) }}
|
||||
*/}}
|
||||
|
||||
{{- $page := .page }}
|
||||
{{- $menuID := .menuID }}
|
||||
{{- $menuClass := .class }}
|
||||
|
||||
{{- with index site.Menus $menuID }}
|
||||
<ul class="{{ $menuClass }}">
|
||||
{{- partial "inline/menu/walk.html" (dict "page" $page "menuEntries" .) }}
|
||||
</ul>
|
||||
{{- end }}
|
||||
|
||||
{{- define "_partials/inline/menu/walk.html" }}
|
||||
{{- $page := .page }}
|
||||
{{- range .menuEntries }}
|
||||
{{- $attrs := dict "href" .URL "class" "" }}
|
||||
{{- if $page.IsMenuCurrent .Menu . }}
|
||||
{{- $attrs = merge $attrs (dict "class" "active" "aria-current" "page") }}
|
||||
{{- else if $page.HasMenuCurrent .Menu .}}
|
||||
{{- $attrs = merge $attrs (dict "class" "ancestor" "aria-current" "true") }}
|
||||
{{- end }}
|
||||
{{- $attrs = merge $attrs (dict "class" (print $attrs.class " contrast")) }}
|
||||
{{- if (ne .Params.class nil) }}
|
||||
{{- $attrs = merge $attrs (dict "class" (print $attrs.class " " .Params.class)) }}
|
||||
{{- end }}
|
||||
{{- if (ne .Params.rel nil) }}
|
||||
{{- $attrs = merge $attrs (dict "rel" .Params.rel) }}
|
||||
{{- end }}
|
||||
{{- $name := .Name }}
|
||||
{{- with .Identifier }}
|
||||
{{- with T . }}
|
||||
{{- $name = . }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
<li>
|
||||
<a
|
||||
{{- range $k, $v := $attrs }}
|
||||
{{- with $v }}
|
||||
{{- printf " %s=%q" $k $v | safeHTMLAttr }}
|
||||
{{- end }}
|
||||
{{- end -}}
|
||||
>
|
||||
{{- if (ne .Params.iconName nil) }}
|
||||
{{partial "icon.html" (dict "icon" .Params.iconName "label" .Params.iconTitle)}}
|
||||
{{- end }}
|
||||
{{ $name }}
|
||||
</a>
|
||||
{{- with .Children }}
|
||||
<ul>
|
||||
{{- partial "inline/menu/walk.html" (dict "page" $page "menuEntries" .) }}
|
||||
</ul>
|
||||
{{- end }}
|
||||
</li>
|
||||
{{- end }}
|
||||
{{- end }}
|
10
themes/bcarlin/layouts/_partials/tags.html
Normal file
|
@ -0,0 +1,10 @@
|
|||
{{- with .GetTerms "tags" }}
|
||||
<div>
|
||||
{{ partial "icon.html" (dict "icon" "hashtag" "label" "Tags") }}
|
||||
<ul class="tags">
|
||||
{{- range . }}
|
||||
<li><a href="{{ .RelPermalink }}" rel="tag" class="p-category">{{ .LinkTitle }}</a></li>
|
||||
{{- end }}
|
||||
</ul>
|
||||
</div>
|
||||
{{- end }}
|
38
themes/bcarlin/layouts/baseof.html
Normal file
|
@ -0,0 +1,38 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="{{ site.Language.LanguageCode }}" dir="{{ or site.Language.LanguageDirection `ltr` }}">
|
||||
<head>
|
||||
{{ partial "head.html" . }}
|
||||
</head>
|
||||
<body>
|
||||
<nav class="mobile-header" aria-label="Mobile menu">
|
||||
<ul>
|
||||
<li><a href="/"><img src="/static/logo.svg" alt="Logo"/></a></li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li><a href="/" class="contrast">Bruno Carlin</a></li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>
|
||||
<a
|
||||
id="menu-toggle"
|
||||
role="button"
|
||||
aria-controls="menu"
|
||||
aria-expanded="false"
|
||||
aria-label="Toggle the main menu"
|
||||
>
|
||||
{{partial "icon.html" (dict "icon" "menu-fill" "label" "Open the menu")}}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<header id="menu" class="h-card">
|
||||
{{ partial "header.html" . }}
|
||||
</header>
|
||||
<main class="container">
|
||||
{{ block "main" . }}{{ end }}
|
||||
</main>
|
||||
<footer class="container">
|
||||
{{ partial "footer.html" . }}
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
29
themes/bcarlin/layouts/blog/list.html
Normal file
|
@ -0,0 +1,29 @@
|
|||
{{ define "main" }}
|
||||
<article class="h-feed">
|
||||
<header>
|
||||
<h1 class="p-name">{{ .Title }}</h1>
|
||||
</header>
|
||||
|
||||
{{ .Content }}
|
||||
|
||||
{{ range .Site.RegularPages.GroupByDate "2006" }}
|
||||
<section>
|
||||
<h2>{{ .Key }}</h2>
|
||||
{{- range .Pages }}
|
||||
{{ $dateMachine := .Date | time.Format "2006-01-02T15:04:05-07:00" }}
|
||||
{{ $dateHuman := .Date | time.Format "2006-01-02" }}
|
||||
<article class="h-entry">
|
||||
<p>
|
||||
<a class="u-url p-name" href="{{ .RelPermalink }}">{{ .LinkTitle }}</a>
|
||||
(<time class="dt-published" datetime="{{ $dateMachine }}">{{ $dateHuman }}</time>)
|
||||
</p>
|
||||
<p>
|
||||
{{ .Summary }}
|
||||
</p>
|
||||
</article>
|
||||
{{- end }}
|
||||
</section>
|
||||
{{- end }}
|
||||
</article>
|
||||
{{ end }}
|
||||
|
21
themes/bcarlin/layouts/blog/single.html
Normal file
|
@ -0,0 +1,21 @@
|
|||
{{ define "main" }}
|
||||
{{ $dateMachine := .Date | time.Format "2006-01-02T15:04:05-07:00" }}
|
||||
{{ $dateHuman := .Date | time.Format "2006-01-02" }}
|
||||
<article class="h-entry">
|
||||
<header>
|
||||
<h1 class="p-name">{{ .Title }}</h1>
|
||||
<div class="metadata">
|
||||
<p>
|
||||
Posted on
|
||||
<time class="dt-published" datetime="{{ $dateMachine }}">{{ $dateHuman }}</time>
|
||||
</p>
|
||||
<p> :: </p>
|
||||
{{ partial "tags.html" . }}
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section class="e-content">
|
||||
{{ .Content }}
|
||||
</section>
|
||||
</article>
|
||||
{{ end }}
|
27
themes/bcarlin/layouts/home.html
Normal file
|
@ -0,0 +1,27 @@
|
|||
{{ define "main" }}
|
||||
<article>
|
||||
<header>
|
||||
<h1>{{ .Title }}</h1>
|
||||
</header>
|
||||
|
||||
{{ .Content }}
|
||||
|
||||
<section class="h-feed">
|
||||
<h2 class="p-name">Recent posts</h2>
|
||||
{{- $posts := where .Site.RegularPages "Section" "blog" }}
|
||||
{{- range first 5 $posts }}
|
||||
{{ $dateMachine := .Date | time.Format "2006-01-02T15:04:05-07:00" }}
|
||||
{{ $dateHuman := .Date | time.Format "2006-01-02" }}
|
||||
<article class="h-entry">
|
||||
<p>
|
||||
<a class="u-url p-name" href="{{ .RelPermalink }}">{{ .LinkTitle }}</a>
|
||||
(<time class="dt-published" datetime="{{ $dateMachine }}">{{ $dateHuman }}</time>)
|
||||
</p>
|
||||
<p>
|
||||
{{ .Summary }}
|
||||
</p>
|
||||
</article>
|
||||
{{- end }}
|
||||
</section>
|
||||
</article>
|
||||
{{ end }}
|
18
themes/bcarlin/layouts/page.html
Normal file
|
@ -0,0 +1,18 @@
|
|||
{{ define "main" }}
|
||||
{{ $dateMachine := .Date | time.Format "2006-01-02T15:04:05-07:00" }}
|
||||
{{ $dateHuman := .Date | time.Format "2006-01-02" }}
|
||||
<article class="h-entry">
|
||||
<header>
|
||||
<h1 class="p-name">{{ .Title }}</h1>
|
||||
<p>
|
||||
Posted on
|
||||
<time class="dt-published" datetime="{{ $dateMachine }}">{{ $dateHuman }}</time>
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<section class="e-content">
|
||||
{{ .Content }}
|
||||
</section>
|
||||
{{ partial "terms.html" (dict "taxonomy" "tags" "page" .) }}
|
||||
</article>
|
||||
{{ end }}
|
9
themes/bcarlin/layouts/section.html
Normal file
|
@ -0,0 +1,9 @@
|
|||
{{ define "main" }}
|
||||
<article>
|
||||
<header>
|
||||
<h1>{{ .Title }}</h1>
|
||||
</header>
|
||||
|
||||
{{ .Content }}
|
||||
<article>
|
||||
{{ end }}
|
59
themes/bcarlin/layouts/section.rss.xml
Normal file
|
@ -0,0 +1,59 @@
|
|||
{{- $authorEmail := "" }}
|
||||
{{- with site.Params.author }}
|
||||
{{- if reflect.IsMap . }}
|
||||
{{- with .email }}
|
||||
{{- $authorEmail = . }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- $authorName := "" }}
|
||||
{{- with site.Params.author }}
|
||||
{{- if reflect.IsMap . }}
|
||||
{{- with .name }}
|
||||
{{- $authorName = . }}
|
||||
{{- end }}
|
||||
{{- else }}
|
||||
{{- $authorName = . }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- $pctx := . }}
|
||||
{{- if .IsHome }}{{ $pctx = .Site }}{{ end }}
|
||||
{{- $pages := slice }}
|
||||
{{- if or $.IsHome $.IsSection }}
|
||||
{{- $pages = $pctx.RegularPages }}
|
||||
{{- else }}
|
||||
{{- $pages = $pctx.Pages }}
|
||||
{{- end }}
|
||||
{{- $limit := .Site.Config.Services.RSS.Limit }}
|
||||
{{- if ge $limit 1 }}
|
||||
{{- $pages = $pages | first $limit }}
|
||||
{{- end }}
|
||||
{{- printf "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>" | safeHTML }}
|
||||
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
||||
<channel>
|
||||
<title>{{ if eq .Title .Site.Title }}{{ .Site.Title }}{{ else }}{{ with .Title }}{{ . }} on {{ end }}{{ .Site.Title }}{{ end }}</title>
|
||||
<link>{{ .Permalink }}</link>
|
||||
<description>Recent content {{ if ne .Title .Site.Title }}{{ with .Title }}in {{ . }} {{ end }}{{ end }}on {{ .Site.Title }}</description>
|
||||
<generator>Hugo</generator>
|
||||
<language>{{ site.Language.LanguageCode }}</language>{{ with $authorEmail }}
|
||||
<managingEditor>{{.}}{{ with $authorName }} ({{ . }}){{ end }}</managingEditor>{{ end }}{{ with $authorEmail }}
|
||||
<webMaster>{{ . }}{{ with $authorName }} ({{ . }}){{ end }}</webMaster>{{ end }}{{ with .Site.Copyright }}
|
||||
<copyright>{{ . }}</copyright>{{ end }}{{ if not .Date.IsZero }}
|
||||
<lastBuildDate>{{ (index $pages.ByLastmod.Reverse 0).Lastmod.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</lastBuildDate>{{ end }}
|
||||
{{- with .OutputFormats.Get "RSS" }}
|
||||
{{ printf "<atom:link href=%q rel=\"self\" type=%q />" .Permalink .MediaType | safeHTML }}
|
||||
{{- end }}
|
||||
{{- range $pages }}
|
||||
<item>
|
||||
<title>{{ .Title }}</title>
|
||||
<link>{{ .Permalink }}</link>
|
||||
<pubDate>{{ .PublishDate.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</pubDate>
|
||||
{{- with $authorEmail }}<author>{{ . }}{{ with $authorName }} ({{ . }}){{ end }}</author>{{ end }}
|
||||
<guid>{{ .Permalink }}</guid>
|
||||
<description>{{ .Content | transform.XMLEscape | safeHTML }}</description>
|
||||
</item>
|
||||
{{- end }}
|
||||
</channel>
|
||||
</rss>
|
4
themes/bcarlin/layouts/shortcodes/note.html
Normal file
|
@ -0,0 +1,4 @@
|
|||
<aside class="admonition note">
|
||||
<p class="title">{{partial "icon.html" (dict "icon" "information-fill" "label" "information")}} Note</p>
|
||||
{{ .Inner | .Page.RenderString }}
|
||||
</aside>
|
4
themes/bcarlin/layouts/shortcodes/warning.html
Normal file
|
@ -0,0 +1,4 @@
|
|||
<aside class="admonition warning">
|
||||
<p class="title">{{partial "icon.html" (dict "icon" "error-warning-fill" "label" "warning")}} Warning</p>
|
||||
{{ .Inner | .Page.RenderString }}
|
||||
</aside>
|
16
themes/bcarlin/layouts/taxonomy.html
Normal file
|
@ -0,0 +1,16 @@
|
|||
{{ define "main" }}
|
||||
<article>
|
||||
<header>
|
||||
<h1>{{ .Title }}</h1>
|
||||
</header>
|
||||
|
||||
<ul>
|
||||
{{ range .Data.Terms.Alphabetical }}
|
||||
<li>
|
||||
<a href="{{ .Page.RelPermalink }}">{{ .Page.LinkTitle }}</a>
|
||||
({{ .Count }})
|
||||
</li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
</article>
|
||||
{{ end }}
|
18
themes/bcarlin/layouts/term.html
Normal file
|
@ -0,0 +1,18 @@
|
|||
{{ define "main" }}
|
||||
<article class="h-feed">
|
||||
<header>
|
||||
<h1 class="p-name">{{ .Title }}</h1>
|
||||
</header>
|
||||
|
||||
{{ .Content }}
|
||||
|
||||
{{ range .Pages.ByDate }}
|
||||
{{ $dateMachine := .Date | time.Format "2006-01-02T15:04:05-07:00" }}
|
||||
{{ $dateHuman := .Date | time.Format "2006-01-02" }}
|
||||
<article class="h-entry">
|
||||
<a class="u-url p-name" href="{{ .RelPermalink }}">{{ .LinkTitle }}</a>
|
||||
(<time class="dt-published" datetime="{{ $dateMachine }}">{{ $dateHuman }}</time>)
|
||||
</article>
|
||||
{{ end }}
|
||||
</article>
|
||||
{{ end }}
|
BIN
themes/bcarlin/static/apple-touch-icon.png
Normal file
After Width: | Height: | Size: 5.7 KiB |
BIN
themes/bcarlin/static/favicon-96x96.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
themes/bcarlin/static/favicon.ico
Normal file
After Width: | Height: | Size: 15 KiB |
22
themes/bcarlin/static/favicon.svg
Normal file
|
@ -0,0 +1,22 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="80" height="80"><svg viewBox="0 0 80 80" version="1.1" id="SvgjsSvg1017" sodipodi:docname="logo.svg" inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs id="SvgjsDefs1016"></defs>
|
||||
<sodipodi:namedview id="SvgjsSodipodi:namedview1015" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:showpageshadow="2" inkscape:pageopacity="0.0" inkscape:pagecheckerboard="0" inkscape:deskcolor="#d1d1d1" inkscape:document-units="mm" inkscape:zoom="1.9270133" inkscape:cx="65.645629" inkscape:cy="72.39182" inkscape:window-width="1916" inkscape:window-height="1026" inkscape:window-x="0" inkscape:window-y="0" inkscape:window-maximized="0" inkscape:current-layer="layer1"></sodipodi:namedview>
|
||||
<style id="SvgjsStyle1014">
|
||||
:root { filter: none; }
|
||||
path {
|
||||
fill:none;
|
||||
stroke:#000000;
|
||||
stroke-width:3.5;
|
||||
stroke-linecap:round;
|
||||
stroke-linejoin:miter;
|
||||
stroke-dasharray:none;
|
||||
stroke-opacity:1
|
||||
}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
path { stroke: #f0f0f0 }
|
||||
}
|
||||
</style>
|
||||
<g id="SvgjsG1013">
|
||||
<path d="m 33.93812,57.35608 c -2.09127,-8.3238 -6.421596,-19.16538 -4.113261,-26.0517 1.134461,-3.38437 3.845371,-5.56463 7.977231,-5.73386 3.19716,-0.13095 8.72664,0.36824 9.59761,6.23246 0.76712,5.16491 -4.15506,6.39829 -7.22937,8.1022 6.50598,-1.93981 12.01867,1.47517 13.33694,7.105 1.31827,5.62984 -0.76053,10.88377 -3.67194,14.55887 -2.9114,3.67511 -7.14804,6.27136 -12.7811,6.50685 C 21.415486,68.72968 11.927485,54.67483 11.751441,39.19832 11.575406,23.72181 23.343582,11.494025 40.08723,11.290233 56.83088,11.086441 69.20544,25.91722 68.19167,42.02395 c -0.81502,12.94911 -5.57382,19.26544 -9.73003,22.70007 -1.66423,1.37528 -3.28127,3.98783 -3.28127,3.98783" id="SvgjsPath1012"></path>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2 KiB |
21
themes/bcarlin/static/site.webmanifest
Normal file
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"name": "bcarlin.net",
|
||||
"short_name": "bcarlin.net",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/web-app-manifest-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable"
|
||||
},
|
||||
{
|
||||
"src": "/web-app-manifest-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable"
|
||||
}
|
||||
],
|
||||
"theme_color": "#ffffff",
|
||||
"background_color": "#ffffff",
|
||||
"display": "standalone"
|
||||
}
|
88
themes/bcarlin/static/static/css/syntax-dark.css
Normal file
|
@ -0,0 +1,88 @@
|
|||
/* Generated using: hugo gen chromastyles --style solarized-dark */
|
||||
|
||||
/* Background */ .bg { color:#93a1a1;background-color:#002b36; }
|
||||
/* PreWrapper */ .chroma { color:#93a1a1;background-color:#002b36; }
|
||||
/* Other */ .chroma .x { color:#cb4b16 }
|
||||
/* Error */ .chroma .err { }
|
||||
/* CodeLine */ .chroma .cl { }
|
||||
/* LineLink */ .chroma .lnlinks { outline:none;text-decoration:none;color:inherit }
|
||||
/* LineTableTD */ .chroma .lntd { vertical-align:top;padding:0;margin:0;border:0; }
|
||||
/* LineTable */ .chroma .lntable { border-spacing:0;padding:0;margin:0;border:0; }
|
||||
/* LineHighlight */ .chroma .hl { background-color:#19404a }
|
||||
/* LineNumbersTable */ .chroma .lnt { white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#495050 }
|
||||
/* LineNumbers */ .chroma .ln { white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#495050 }
|
||||
/* Line */ .chroma .line { display:flex; }
|
||||
/* Keyword */ .chroma .k { color:#719e07 }
|
||||
/* KeywordConstant */ .chroma .kc { color:#cb4b16 }
|
||||
/* KeywordDeclaration */ .chroma .kd { color:#268bd2 }
|
||||
/* KeywordNamespace */ .chroma .kn { color:#719e07 }
|
||||
/* KeywordPseudo */ .chroma .kp { color:#719e07 }
|
||||
/* KeywordReserved */ .chroma .kr { color:#268bd2 }
|
||||
/* KeywordType */ .chroma .kt { color:#dc322f }
|
||||
/* Name */ .chroma .n { }
|
||||
/* NameAttribute */ .chroma .na { }
|
||||
/* NameClass */ .chroma .nc { color:#268bd2 }
|
||||
/* NameConstant */ .chroma .no { color:#cb4b16 }
|
||||
/* NameDecorator */ .chroma .nd { color:#268bd2 }
|
||||
/* NameEntity */ .chroma .ni { color:#cb4b16 }
|
||||
/* NameException */ .chroma .ne { color:#cb4b16 }
|
||||
/* NameLabel */ .chroma .nl { }
|
||||
/* NameNamespace */ .chroma .nn { }
|
||||
/* NameOther */ .chroma .nx { }
|
||||
/* NameProperty */ .chroma .py { }
|
||||
/* NameTag */ .chroma .nt { color:#268bd2 }
|
||||
/* NameBuiltin */ .chroma .nb { color:#b58900 }
|
||||
/* NameBuiltinPseudo */ .chroma .bp { color:#268bd2 }
|
||||
/* NameVariable */ .chroma .nv { color:#268bd2 }
|
||||
/* NameVariableClass */ .chroma .vc { color:#268bd2 }
|
||||
/* NameVariableGlobal */ .chroma .vg { color:#268bd2 }
|
||||
/* NameVariableInstance */ .chroma .vi { color:#268bd2 }
|
||||
/* NameVariableMagic */ .chroma .vm { color:#268bd2 }
|
||||
/* NameFunction */ .chroma .nf { color:#268bd2 }
|
||||
/* NameFunctionMagic */ .chroma .fm { color:#268bd2 }
|
||||
/* Literal */ .chroma .l { }
|
||||
/* LiteralDate */ .chroma .ld { }
|
||||
/* LiteralString */ .chroma .s { color:#2aa198 }
|
||||
/* LiteralStringAffix */ .chroma .sa { color:#2aa198 }
|
||||
/* LiteralStringBacktick */ .chroma .sb { color:#586e75 }
|
||||
/* LiteralStringChar */ .chroma .sc { color:#2aa198 }
|
||||
/* LiteralStringDelimiter */ .chroma .dl { color:#2aa198 }
|
||||
/* LiteralStringDoc */ .chroma .sd { }
|
||||
/* LiteralStringDouble */ .chroma .s2 { color:#2aa198 }
|
||||
/* LiteralStringEscape */ .chroma .se { color:#cb4b16 }
|
||||
/* LiteralStringHeredoc */ .chroma .sh { }
|
||||
/* LiteralStringInterpol */ .chroma .si { color:#2aa198 }
|
||||
/* LiteralStringOther */ .chroma .sx { color:#2aa198 }
|
||||
/* LiteralStringRegex */ .chroma .sr { color:#dc322f }
|
||||
/* LiteralStringSingle */ .chroma .s1 { color:#2aa198 }
|
||||
/* LiteralStringSymbol */ .chroma .ss { color:#2aa198 }
|
||||
/* LiteralNumber */ .chroma .m { color:#2aa198 }
|
||||
/* LiteralNumberBin */ .chroma .mb { color:#2aa198 }
|
||||
/* LiteralNumberFloat */ .chroma .mf { color:#2aa198 }
|
||||
/* LiteralNumberHex */ .chroma .mh { color:#2aa198 }
|
||||
/* LiteralNumberInteger */ .chroma .mi { color:#2aa198 }
|
||||
/* LiteralNumberIntegerLong */ .chroma .il { color:#2aa198 }
|
||||
/* LiteralNumberOct */ .chroma .mo { color:#2aa198 }
|
||||
/* Operator */ .chroma .o { color:#719e07 }
|
||||
/* OperatorWord */ .chroma .ow { color:#719e07 }
|
||||
/* Punctuation */ .chroma .p { }
|
||||
/* Comment */ .chroma .c { color:#586e75 }
|
||||
/* CommentHashbang */ .chroma .ch { color:#586e75 }
|
||||
/* CommentMultiline */ .chroma .cm { color:#586e75 }
|
||||
/* CommentSingle */ .chroma .c1 { color:#586e75 }
|
||||
/* CommentSpecial */ .chroma .cs { color:#719e07 }
|
||||
/* CommentPreproc */ .chroma .cp { color:#719e07 }
|
||||
/* CommentPreprocFile */ .chroma .cpf { color:#719e07 }
|
||||
/* Generic */ .chroma .g { }
|
||||
/* GenericDeleted */ .chroma .gd { color:#dc322f }
|
||||
/* GenericEmph */ .chroma .ge { font-style:italic }
|
||||
/* GenericError */ .chroma .gr { color:#dc322f;font-weight:bold }
|
||||
/* GenericHeading */ .chroma .gh { color:#cb4b16 }
|
||||
/* GenericInserted */ .chroma .gi { color:#719e07 }
|
||||
/* GenericOutput */ .chroma .go { }
|
||||
/* GenericPrompt */ .chroma .gp { }
|
||||
/* GenericStrong */ .chroma .gs { font-weight:bold }
|
||||
/* GenericSubheading */ .chroma .gu { color:#268bd2 }
|
||||
/* GenericTraceback */ .chroma .gt { }
|
||||
/* GenericUnderline */ .chroma .gl { }
|
||||
/* TextWhitespace */ .chroma .w { }
|
88
themes/bcarlin/static/static/css/syntax-light.css
Normal file
|
@ -0,0 +1,88 @@
|
|||
/* Generated using: hugo gen chromastyles --style solarized-light */
|
||||
|
||||
/* Background */ .bg { color:#586e75;background-color:#eee8d5; }
|
||||
/* PreWrapper */ .chroma { color:#586e75;background-color:#eee8d5; }
|
||||
/* Other */ .chroma .x { }
|
||||
/* Error */ .chroma .err { }
|
||||
/* CodeLine */ .chroma .cl { }
|
||||
/* LineLink */ .chroma .lnlinks { outline:none;text-decoration:none;color:inherit }
|
||||
/* LineTableTD */ .chroma .lntd { vertical-align:top;padding:0;margin:0;border:0; }
|
||||
/* LineTable */ .chroma .lntable { border-spacing:0;padding:0;margin:0;border:0; }
|
||||
/* LineHighlight */ .chroma .hl { background-color:#d6d0bf }
|
||||
/* LineNumbersTable */ .chroma .lnt { white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f }
|
||||
/* LineNumbers */ .chroma .ln { white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f }
|
||||
/* Line */ .chroma .line { display:flex; }
|
||||
/* Keyword */ .chroma .k { color:#859900 }
|
||||
/* KeywordConstant */ .chroma .kc { color:#859900;font-weight:bold }
|
||||
/* KeywordDeclaration */ .chroma .kd { color:#859900 }
|
||||
/* KeywordNamespace */ .chroma .kn { color:#dc322f;font-weight:bold }
|
||||
/* KeywordPseudo */ .chroma .kp { color:#859900 }
|
||||
/* KeywordReserved */ .chroma .kr { color:#859900 }
|
||||
/* KeywordType */ .chroma .kt { color:#859900;font-weight:bold }
|
||||
/* Name */ .chroma .n { color:#268bd2 }
|
||||
/* NameAttribute */ .chroma .na { color:#268bd2 }
|
||||
/* NameClass */ .chroma .nc { color:#cb4b16 }
|
||||
/* NameConstant */ .chroma .no { color:#268bd2 }
|
||||
/* NameDecorator */ .chroma .nd { color:#268bd2 }
|
||||
/* NameEntity */ .chroma .ni { color:#268bd2 }
|
||||
/* NameException */ .chroma .ne { color:#268bd2 }
|
||||
/* NameLabel */ .chroma .nl { color:#268bd2 }
|
||||
/* NameNamespace */ .chroma .nn { color:#268bd2 }
|
||||
/* NameOther */ .chroma .nx { color:#268bd2 }
|
||||
/* NameProperty */ .chroma .py { color:#268bd2 }
|
||||
/* NameTag */ .chroma .nt { color:#268bd2;font-weight:bold }
|
||||
/* NameBuiltin */ .chroma .nb { color:#cb4b16 }
|
||||
/* NameBuiltinPseudo */ .chroma .bp { color:#cb4b16 }
|
||||
/* NameVariable */ .chroma .nv { color:#268bd2 }
|
||||
/* NameVariableClass */ .chroma .vc { color:#268bd2 }
|
||||
/* NameVariableGlobal */ .chroma .vg { color:#268bd2 }
|
||||
/* NameVariableInstance */ .chroma .vi { color:#268bd2 }
|
||||
/* NameVariableMagic */ .chroma .vm { color:#268bd2 }
|
||||
/* NameFunction */ .chroma .nf { color:#268bd2 }
|
||||
/* NameFunctionMagic */ .chroma .fm { color:#268bd2 }
|
||||
/* Literal */ .chroma .l { color:#2aa198 }
|
||||
/* LiteralDate */ .chroma .ld { color:#2aa198 }
|
||||
/* LiteralString */ .chroma .s { color:#2aa198 }
|
||||
/* LiteralStringAffix */ .chroma .sa { color:#2aa198 }
|
||||
/* LiteralStringBacktick */ .chroma .sb { color:#2aa198 }
|
||||
/* LiteralStringChar */ .chroma .sc { color:#2aa198 }
|
||||
/* LiteralStringDelimiter */ .chroma .dl { color:#2aa198 }
|
||||
/* LiteralStringDoc */ .chroma .sd { color:#2aa198 }
|
||||
/* LiteralStringDouble */ .chroma .s2 { color:#2aa198 }
|
||||
/* LiteralStringEscape */ .chroma .se { color:#2aa198 }
|
||||
/* LiteralStringHeredoc */ .chroma .sh { color:#2aa198 }
|
||||
/* LiteralStringInterpol */ .chroma .si { color:#2aa198 }
|
||||
/* LiteralStringOther */ .chroma .sx { color:#2aa198 }
|
||||
/* LiteralStringRegex */ .chroma .sr { color:#2aa198 }
|
||||
/* LiteralStringSingle */ .chroma .s1 { color:#2aa198 }
|
||||
/* LiteralStringSymbol */ .chroma .ss { color:#2aa198 }
|
||||
/* LiteralNumber */ .chroma .m { color:#2aa198;font-weight:bold }
|
||||
/* LiteralNumberBin */ .chroma .mb { color:#2aa198;font-weight:bold }
|
||||
/* LiteralNumberFloat */ .chroma .mf { color:#2aa198;font-weight:bold }
|
||||
/* LiteralNumberHex */ .chroma .mh { color:#2aa198;font-weight:bold }
|
||||
/* LiteralNumberInteger */ .chroma .mi { color:#2aa198;font-weight:bold }
|
||||
/* LiteralNumberIntegerLong */ .chroma .il { color:#2aa198;font-weight:bold }
|
||||
/* LiteralNumberOct */ .chroma .mo { color:#2aa198;font-weight:bold }
|
||||
/* Operator */ .chroma .o { }
|
||||
/* OperatorWord */ .chroma .ow { color:#859900 }
|
||||
/* Punctuation */ .chroma .p { }
|
||||
/* Comment */ .chroma .c { color:#93a1a1;font-style:italic }
|
||||
/* CommentHashbang */ .chroma .ch { color:#93a1a1;font-style:italic }
|
||||
/* CommentMultiline */ .chroma .cm { color:#93a1a1;font-style:italic }
|
||||
/* CommentSingle */ .chroma .c1 { color:#93a1a1;font-style:italic }
|
||||
/* CommentSpecial */ .chroma .cs { color:#93a1a1;font-style:italic }
|
||||
/* CommentPreproc */ .chroma .cp { color:#93a1a1;font-style:italic }
|
||||
/* CommentPreprocFile */ .chroma .cpf { color:#93a1a1;font-style:italic }
|
||||
/* Generic */ .chroma .g { color:#d33682 }
|
||||
/* GenericDeleted */ .chroma .gd { color:#d33682 }
|
||||
/* GenericEmph */ .chroma .ge { color:#d33682 }
|
||||
/* GenericError */ .chroma .gr { color:#d33682 }
|
||||
/* GenericHeading */ .chroma .gh { color:#d33682 }
|
||||
/* GenericInserted */ .chroma .gi { color:#d33682 }
|
||||
/* GenericOutput */ .chroma .go { color:#d33682 }
|
||||
/* GenericPrompt */ .chroma .gp { color:#d33682 }
|
||||
/* GenericStrong */ .chroma .gs { color:#d33682 }
|
||||
/* GenericSubheading */ .chroma .gu { color:#d33682 }
|
||||
/* GenericTraceback */ .chroma .gt { color:#d33682 }
|
||||
/* GenericUnderline */ .chroma .gl { color:#d33682 }
|
||||
/* TextWhitespace */ .chroma .w { }
|
BIN
themes/bcarlin/static/static/favicon.ico
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
themes/bcarlin/static/static/fonts/GentiumPlus-Bold.woff2
Normal file
BIN
themes/bcarlin/static/static/fonts/GentiumPlus-BoldItalic.woff2
Normal file
BIN
themes/bcarlin/static/static/fonts/GentiumPlus-Italic.woff2
Normal file
BIN
themes/bcarlin/static/static/fonts/GentiumPlus-Regular.woff2
Normal file
BIN
themes/bcarlin/static/static/fonts/NunitoSans-Italic.woff2
Normal file
BIN
themes/bcarlin/static/static/fonts/NunitoSans.woff2
Normal file
BIN
themes/bcarlin/static/static/fonts/remixicon.woff2
Normal file
BIN
themes/bcarlin/static/static/logo.png
Normal file
After Width: | Height: | Size: 14 KiB |
57
themes/bcarlin/static/static/logo.svg
Normal file
|
@ -0,0 +1,57 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
viewBox="0 0 80 80"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
sodipodi:docname="logo.svg"
|
||||
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs1" />
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:zoom="1.9270133"
|
||||
inkscape:cx="65.645629"
|
||||
inkscape:cy="72.39182"
|
||||
inkscape:window-width="1916"
|
||||
inkscape:window-height="1026"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="layer1" />
|
||||
<style
|
||||
id="style1">
|
||||
path {
|
||||
fill:none;
|
||||
stroke:#000000;
|
||||
stroke-width:3.5;
|
||||
stroke-linecap:round;
|
||||
stroke-linejoin:miter;
|
||||
stroke-dasharray:none;
|
||||
stroke-opacity:1
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
path { stroke: #f0f0f0 }
|
||||
}
|
||||
</style>
|
||||
<g
|
||||
id="layer1">
|
||||
<path
|
||||
d="m 33.93812,57.35608 c -2.09127,-8.3238 -6.421596,-19.16538 -4.113261,-26.0517 1.134461,-3.38437 3.845371,-5.56463 7.977231,-5.73386 3.19716,-0.13095 8.72664,0.36824 9.59761,6.23246 0.76712,5.16491 -4.15506,6.39829 -7.22937,8.1022 6.50598,-1.93981 12.01867,1.47517 13.33694,7.105 1.31827,5.62984 -0.76053,10.88377 -3.67194,14.55887 -2.9114,3.67511 -7.14804,6.27136 -12.7811,6.50685 C 21.415486,68.72968 11.927485,54.67483 11.751441,39.19832 11.575406,23.72181 23.343582,11.494025 40.08723,11.290233 56.83088,11.086441 69.20544,25.91722 68.19167,42.02395 c -0.81502,12.94911 -5.57382,19.26544 -9.73003,22.70007 -1.66423,1.37528 -3.28127,3.98783 -3.28127,3.98783"
|
||||
id="path1" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.1 KiB |
BIN
themes/bcarlin/static/web-app-manifest-192x192.png
Normal file
After Width: | Height: | Size: 7.2 KiB |
BIN
themes/bcarlin/static/web-app-manifest-512x512.png
Normal file
After Width: | Height: | Size: 24 KiB |
9
wrangler.toml
Normal file
|
@ -0,0 +1,9 @@
|
|||
name = 'homepage'
|
||||
compatibility_date = "2025-06-26"
|
||||
|
||||
#[build]
|
||||
#command = "./build.sh"
|
||||
|
||||
[assets]
|
||||
directory = "./public"
|
||||
#not_found_handling = "404-page"
|