Merge branch 'master' of git.fsfe.org:FSFE/fsfe-website

This commit is contained in:
2025-11-20 10:23:43 +01:00
231 changed files with 691 additions and 358 deletions

View File

@@ -4,19 +4,24 @@
"""Lib functions used mainly in checks mainly for testing a file."""
import copy
import logging
import sys
from pathlib import Path
from typing import TYPE_CHECKING
from lxml import etree
if TYPE_CHECKING:
from collections.abc import Iterable
from pathlib import Path
logger = logging.getLogger(__name__)
def compare_files(
file1: Path,
file2: Path,
attr_whitelist: set[str] | None = None,
xpaths_to_ignore: Iterable[str] | None = None,
_path: str = "",
) -> list[str]:
"""Compare two xml files, passes as paths."""
@@ -27,21 +32,50 @@ def compare_files(
logger.critical("XML parse error: %s", e)
sys.exit(1)
return compare_elements(t1.getroot(), t2.getroot(), attr_whitelist)
return compare_elements(t1.getroot(), t2.getroot(), xpaths_to_ignore)
def _delete_by_xpaths(root: etree.Element, xpaths: Iterable[str]) -> None:
"""Remove every element/attribute that matches any of the xpaths."""
for xpath in xpaths:
# Distinguish attribute XPaths (ending with /@attr) from element XPaths
if xpath.endswith(("/@*", "/@x")): # attribute path
parent_xpath = xpath.rsplit("/@", 1)[0] or "." # default to root
for parent in root.xpath(parent_xpath):
if isinstance(parent, etree.Element):
attr = xpath.rsplit("/", 1)[1].lstrip("@")
if attr == "*":
parent.attrib.clear()
else:
parent.attrib.pop(attr, None)
else: # element path
for el in root.xpath(xpath):
if isinstance(el, etree.Element):
parent = el.getparent()
if parent is not None:
parent.remove(el)
def compare_elements(
elem1: etree.Element,
elem2: etree.Element,
attr_whitelist: set[str] | None = None,
elem_input1: etree.Element,
elem_input2: etree.Element,
xpaths_to_ignore: Iterable[str] | None = None,
_path: str = "",
) -> list[str]:
"""Recursively compare two XML elements.
Returns a list of short, informative error strings.
"""
if attr_whitelist is None:
attr_whitelist = set()
if xpaths_to_ignore is None:
xpaths_to_ignore = ()
# make a copy to prevent modifying parent scope
elem1 = copy.deepcopy(elem_input1)
elem2 = copy.deepcopy(elem_input2)
# Prune ignored parts
_delete_by_xpaths(elem1, xpaths_to_ignore)
_delete_by_xpaths(elem2, xpaths_to_ignore)
errors: list[str] = []
tag_path = f"{_path}/{elem1.tag}" if _path else elem1.tag
@@ -65,10 +99,7 @@ def compare_elements(
f" only 1: {only_in_elem1} only 2: {only_in_elem2}"
)
for key in common:
if (
attributes_of_elem1[key] != attributes_of_elem2[key]
and key not in attr_whitelist
):
if attributes_of_elem1[key] != attributes_of_elem2[key]:
error_msg = (
f"Attribute value diff at <{elem1.tag} {key}>:"
f" {attributes_of_elem1[key]!r}{attributes_of_elem2[key]!r}"
@@ -85,7 +116,9 @@ def compare_elements(
# and then recurse into children
for idx, (child1, child2) in enumerate(zip(kids1, kids2, strict=False), start=1):
errors.extend(
compare_elements(child1, child2, attr_whitelist, _path=f"{tag_path}[{idx}]")
compare_elements(
child1, child2, xpaths_to_ignore=(), _path=f"{tag_path}[{idx}]"
)
)
# this should be stable from the sorts above, so no need to sort it here

View File

@@ -6,11 +6,13 @@
import logging
import subprocess
from pathlib import Path
from typing import Any, cast
from typing import TYPE_CHECKING, Any, cast
from lxml import etree
if TYPE_CHECKING:
from pathlib import Path
logger = logging.getLogger(__name__)

View File

@@ -7,13 +7,15 @@
import logging
import re
from datetime import datetime
from pathlib import Path
from typing import Any
from typing import TYPE_CHECKING, Any
from lxml import etree
from fsfe_website_build.lib.misc import get_basename, get_version, lang_from_filename
if TYPE_CHECKING:
from pathlib import Path
logger = logging.getLogger(__name__)

View File

@@ -5,10 +5,13 @@
"""Implementation of the full build logic."""
import logging
from pathlib import Path
from typing import TYPE_CHECKING
from fsfe_website_build.lib.misc import run_command
if TYPE_CHECKING:
from pathlib import Path
logger = logging.getLogger(__name__)

View File

@@ -4,9 +4,12 @@
"""Global directory symlinking logic."""
import logging
import multiprocessing.pool
from itertools import product
from pathlib import Path
from typing import TYPE_CHECKING
if TYPE_CHECKING:
import multiprocessing.pool
from pathlib import Path
logger = logging.getLogger(__name__)

View File

@@ -9,7 +9,10 @@ found in the website to build source tree.
import logging
import sys
from pathlib import Path
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from pathlib import Path
logger = logging.getLogger(__name__)

View File

@@ -10,7 +10,10 @@ found in the website to build source tree.
import logging
import sys
from pathlib import Path
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from pathlib import Path
logger = logging.getLogger(__name__)

View File

@@ -10,8 +10,7 @@ directory tree and does not touch the target directory tree at all.
"""
import logging
import multiprocessing.pool
from pathlib import Path
from typing import TYPE_CHECKING
from .prepare_subdirectories import prepare_subdirectories
from .update_css import update_css
@@ -20,6 +19,10 @@ from .update_localmenus import update_localmenus
from .update_stylesheets import update_stylesheets
from .update_xmllists import update_xmllists
if TYPE_CHECKING:
import multiprocessing.pool
from pathlib import Path
logger = logging.getLogger(__name__)

View File

@@ -9,12 +9,15 @@ distributed to the web server.
"""
import logging
from pathlib import Path
from typing import TYPE_CHECKING
import minify # pyright: ignore [reportMissingTypeStubs]
from fsfe_website_build.lib.misc import run_command, update_if_changed
if TYPE_CHECKING:
from pathlib import Path
logger = logging.getLogger(__name__)

View File

@@ -11,8 +11,11 @@ file.
"""
import logging
import multiprocessing.pool
from pathlib import Path
from typing import TYPE_CHECKING
if TYPE_CHECKING:
import multiprocessing.pool
from pathlib import Path
logger = logging.getLogger(__name__)

View File

@@ -8,14 +8,17 @@ After this step, all .localmenu.??.xml files will be up to date.
"""
import logging
import multiprocessing.pool
from collections import defaultdict
from pathlib import Path
from typing import TYPE_CHECKING
from lxml import etree
from fsfe_website_build.lib.misc import get_basepath, sort_dict, update_if_changed
if TYPE_CHECKING:
import multiprocessing.pool
logger = logging.getLogger(__name__)

View File

@@ -14,14 +14,17 @@ per-year archives.
"""
import logging
import multiprocessing.pool
import re
from pathlib import Path
from typing import TYPE_CHECKING
from lxml import etree
from fsfe_website_build.lib.misc import touch_if_newer_dep
if TYPE_CHECKING:
import multiprocessing.pool
from pathlib import Path
logger = logging.getLogger(__name__)

View File

@@ -15,9 +15,9 @@ After this step, the following files will be up to date:
import datetime
import fnmatch
import logging
import multiprocessing.pool
import re
from pathlib import Path
from typing import TYPE_CHECKING
from lxml import etree
@@ -28,6 +28,9 @@ from fsfe_website_build.lib.misc import (
update_if_changed,
)
if TYPE_CHECKING:
import multiprocessing.pool
logger = logging.getLogger(__name__)

View File

@@ -7,9 +7,12 @@ Uses a multithreaded pathlib copy.
"""
import logging
import multiprocessing.pool
import shutil
from pathlib import Path
from typing import TYPE_CHECKING
if TYPE_CHECKING:
import multiprocessing.pool
from pathlib import Path
logger = logging.getLogger(__name__)

View File

@@ -10,11 +10,14 @@ generate a symlink from about/index.en.html to about.en.html
"""
import logging
import multiprocessing.pool
from pathlib import Path
from typing import TYPE_CHECKING
from fsfe_website_build.lib.misc import get_basename
if TYPE_CHECKING:
import multiprocessing.pool
from pathlib import Path
logger = logging.getLogger(__name__)

View File

@@ -12,8 +12,11 @@ takes the file.html.<lang> format.
"""
import logging
import multiprocessing.pool
from pathlib import Path
from typing import TYPE_CHECKING
if TYPE_CHECKING:
import multiprocessing.pool
from pathlib import Path
logger = logging.getLogger(__name__)

View File

@@ -9,16 +9,19 @@ which is useful to prevent reparsing the XSL multiple times.
"""
import logging
import multiprocessing.pool
from collections import defaultdict
from itertools import product
from pathlib import Path
from typing import TYPE_CHECKING
from lxml import etree
from fsfe_website_build.lib.misc import get_basepath
from fsfe_website_build.lib.process_file import process_file
if TYPE_CHECKING:
import multiprocessing.pool
logger = logging.getLogger(__name__)

View File

@@ -5,14 +5,17 @@
"""Script for FSFE website build, phase 2."""
import logging
import multiprocessing.pool
from pathlib import Path
from typing import TYPE_CHECKING
from .copy_files import copy_files
from .create_index_symlinks import create_index_symlinks
from .create_language_symlinks import create_language_symlinks
from .process_files import process_files
if TYPE_CHECKING:
import multiprocessing.pool
from pathlib import Path
logger = logging.getLogger(__name__)

View File

@@ -4,11 +4,14 @@
"""Use rsync to copy files to the targets."""
import logging
import multiprocessing.pool
from pathlib import Path
from typing import TYPE_CHECKING
from fsfe_website_build.lib.misc import run_command
if TYPE_CHECKING:
import multiprocessing.pool
from pathlib import Path
logger = logging.getLogger(__name__)

View File

@@ -3,9 +3,12 @@
# SPDX-License-Identifier: GPL-3.0-or-later
from argparse import Namespace
from pathlib import Path
from typing import TYPE_CHECKING
from fsfe_website_build.build import build
from pytest_mock import MockFixture
if TYPE_CHECKING:
from pytest_mock import MockFixture
def no_rebuild_twice_test(mocker: MockFixture) -> None:
@@ -13,14 +16,12 @@ def no_rebuild_twice_test(mocker: MockFixture) -> None:
args = Namespace(
full=True,
languages=[
"ar",
"de",
"en",
"es",
"fr",
"it",
"nl",
"de",
],
log_level="DEBUG",
log_level="CRITICAL", # by only logging critical messages
# the build should be faster, as evaluating less trhings to strings
processes=8,
source=Path(),
serve=False,

View File

@@ -2,13 +2,16 @@
#
# SPDX-License-Identifier: GPL-3.0-or-later
import tempfile
from collections.abc import Generator
from pathlib import Path
from typing import TYPE_CHECKING
import pytest
from fsfe_website_build.lib.checks import compare_elements, compare_files
from lxml import etree
if TYPE_CHECKING:
from collections.abc import Generator
class TestCompareFiles:
"""Smoke tests for the high-level entry point."""
@@ -60,9 +63,11 @@ class TestCompareElements:
assert len(diff) == 1
def whitelisted_attribute_ignored_test(self) -> None:
e1 = etree.Element("root", x="1")
e2 = etree.Element("root", x="2")
assert compare_elements(e1, e2, attr_whitelist={"x"}) == []
e1 = etree.Element("root")
etree.SubElement(e1, "test", x="1")
e2 = etree.Element("root")
etree.SubElement(e2, "test", x="2")
assert compare_elements(e1, e2, ["//*[@x]"]) == []
def child_count_mismatch_test(self) -> None:
e1 = etree.Element("root")

2
fsfe.org/.gitignore vendored
View File

@@ -7,7 +7,7 @@ events/????/index.xsl
news/????/index.??.xhtml
news/????/index.sources
news/????/index.xsl
news/*/.*.??.xml
news/**/.*.??.xml
# search index
search/index.js
#tags

View File

@@ -75,6 +75,48 @@ RewriteRule ^translators(.*) /contribute/translators/translators.html [R=301,L]
RewriteRule ^news/podcast/?$ /news/podcast.html [R=301,L]
RewriteRule ^news/podcast.rss$ /news/podcast.en.rss [L,R=301]
RewriteRule ^news/podcast-opus.rss$ /news/podcast-opus.en.rss [L,R=301]
RewriteRule ^news/podcast/episode-1.html$ news/podcast/2019/episode-1.html [L,R=301]
RewriteRule ^news/podcast/episode-10.html$ news/podcast/2021/episode-10.html [L,R=301]
RewriteRule ^news/podcast/episode-11.html$ news/podcast/2021/episode-11.html [L,R=301]
RewriteRule ^news/podcast/episode-12.html$ news/podcast/2021/episode-12.html [L,R=301]
RewriteRule ^news/podcast/episode-13.html$ news/podcast/2022/episode-13.html [L,R=301]
RewriteRule ^news/podcast/episode-14.html$ news/podcast/2022/episode-14.html [L,R=301]
RewriteRule ^news/podcast/episode-15.html$ news/podcast/2022/episode-15.html [L,R=301]
RewriteRule ^news/podcast/episode-16.html$ news/podcast/2022/episode-16.html [L,R=301]
RewriteRule ^news/podcast/episode-17.html$ news/podcast/2022/episode-17.html [L,R=301]
RewriteRule ^news/podcast/episode-18.html$ news/podcast/2022/episode-18.html [L,R=301]
RewriteRule ^news/podcast/episode-19.html$ news/podcast/2023/episode-19.html [L,R=301]
RewriteRule ^news/podcast/episode-2.html$ news/podcast/2019/episode-2.html [L,R=301]
RewriteRule ^news/podcast/episode-20.html$ news/podcast/2023/episode-20.html [L,R=301]
RewriteRule ^news/podcast/episode-21.html$ news/podcast/2023/episode-21.html [L,R=301]
RewriteRule ^news/podcast/episode-22.html$ news/podcast/2023/episode-22.html [L,R=301]
RewriteRule ^news/podcast/episode-23.html$ news/podcast/2023/episode-23.html [L,R=301]
RewriteRule ^news/podcast/episode-24.html$ news/podcast/2024/episode-24.html [L,R=301]
RewriteRule ^news/podcast/episode-25.html$ news/podcast/2024/episode-25.html [L,R=301]
RewriteRule ^news/podcast/episode-26.html$ news/podcast/2024/episode-26.html [L,R=301]
RewriteRule ^news/podcast/episode-27.html$ news/podcast/2024/episode-27.html [L,R=301]
RewriteRule ^news/podcast/episode-28.html$ news/podcast/2025/episode-28.html [L,R=301]
RewriteRule ^news/podcast/episode-29.html$ news/podcast/2025/episode-29.html [L,R=301]
RewriteRule ^news/podcast/episode-3.html$ news/podcast/2019/episode-3.html [L,R=301]
RewriteRule ^news/podcast/episode-30.html$ news/podcast/2025/episode-30.html [L,R=301]
RewriteRule ^news/podcast/episode-31.html$ news/podcast/2025/episode-31.html [L,R=301]
RewriteRule ^news/podcast/episode-32.html$ news/podcast/2025/episode-32.html [L,R=301]
RewriteRule ^news/podcast/episode-33.html$ news/podcast/2025/episode-33.html [L,R=301]
RewriteRule ^news/podcast/episode-34.html$ news/podcast/2025/episode-34.html [L,R=301]
RewriteRule ^news/podcast/episode-35.html$ news/podcast/2025/episode-35.html [L,R=301]
RewriteRule ^news/podcast/episode-36.html$ news/podcast/2025/episode-36.html [L,R=301]
RewriteRule ^news/podcast/episode-37.html$ news/podcast/2025/episode-37.html [L,R=301]
RewriteRule ^news/podcast/episode-38.html$ news/podcast/2025/episode-38.html [L,R=301]
RewriteRule ^news/podcast/episode-39.html$ news/podcast/2025/episode-39.html [L,R=301]
RewriteRule ^news/podcast/episode-4.html$ news/podcast/2020/episode-4.html [L,R=301]
RewriteRule ^news/podcast/episode-40.html$ news/podcast/2025/episode-40.html [L,R=301]
RewriteRule ^news/podcast/episode-41.html$ news/podcast/2025/episode-41.html [L,R=301]
RewriteRule ^news/podcast/episode-5.html$ news/podcast/2020/episode-5.html [L,R=301]
RewriteRule ^news/podcast/episode-6.html$ news/podcast/2020/episode-6.html [L,R=301]
RewriteRule ^news/podcast/episode-7.html$ news/podcast/2020/episode-7.html [L,R=301]
RewriteRule ^news/podcast/episode-8.html$ news/podcast/2020/episode-8.html [L,R=301]
RewriteRule ^news/podcast/episode-9.html$ news/podcast/2021/episode-9.html [L,R=301]
RewriteRule ^news/podcast/episode-special-1.html$ news/podcast/2020/episode-special-1.html [L,R=301]
# ILoveFS
# TODO for new news-item: update links for latest news-item

View File

@@ -25,6 +25,8 @@
annual meetings:</p>
<ul>
<li><a href="/about/legal/minutes/minutes-2025-10-11.en.pdf">Minutes from 2025-10-11</a></li>
<li><a href="/about/legal/minutes/minutes-2024-09-28.en.pdf">Minutes from 2024-09-28</a></li>
<li><a href="/about/legal/minutes/minutes-2023-10-21.en.pdf">Minutes from 2023-10-21</a></li>
<li><a href="/about/legal/minutes/minutes-2022-10-29.en.pdf">Minutes from 2022-10-29</a></li>
<li><a href="/about/legal/minutes/minutes-2021-11-27.en.pdf">Minutes from 2021-11-27</a></li>

Binary file not shown.

Binary file not shown.

View File

@@ -110,6 +110,15 @@ We have an international <a href="/activities/yh4f/jury.html">jury</a>, with lum
celebration. You made it! Your hard work paid off. Now you can enjoy 2
educative and exciting days in Brussels and socialise with fellow winners.
</p>
<h2>2025 Winners</h2>
<figure>
<img src="https://pics.fsfe.org/uploads/medium/fb/c9/286a506abffdf52d384f503af7ff.jpeg" alt="Picture of the winners posing during the Award Ceremony with a FSFE roll up on the background"/>
<figcaption>YH4F 2025 winners: Marius, Jonas, Pingu, Tuxilio, Mario, Vinícius, Corentin and Augustin at the award ceremony in Brussels</figcaption>
</figure>
<p>The six winning projects, created by participants aged 14 to 18 and presented at the 2025 awards ceremony in Brussels, are: a language learning platform, a custom ROM page, a scroll wheel, a smart watering robot, a hyperbolic rendering engine, and a version control system. You can find out more about the six inspiring projects <a href="/news/2025/news-20251025-01.html">here</a>.</p>
<h2>2024 Winners</h2>
@@ -190,8 +199,9 @@ You can find out more about the six inspiring projects <a href="/news/2024/news-
</div>
<div class="center">
<a href="https://www.proxmox.com"> <img src="https://pics.fsfe.org/uploads/original/24/53/32ae8d70d491553a73dd8d917adb.png"/> </a>
<a href="https://openssf.org/"> <img src="https://pics.fsfe.org/uploads/original/15/ce/d78f723ae4105ed27d875c36150f.png"/> </a>
<!-- <a href="https://www.proxmox.com"> <img src="https://pics.fsfe.org/uploads/original/24/53/32ae8d70d491553a73dd8d917adb.png"/> </a>
<a href="https://openssf.org/"> <img src="https://pics.fsfe.org/uploads/original/15/ce/d78f723ae4105ed27d875c36150f.png"/> </a>
-->
</div>
<div class="color-box background" data-color="android-blue">

View File

@@ -37,6 +37,7 @@
<category3>
<!-- 60 per month or 720 in this year -->
<!-- Sorted by name, no image -->
<donor since="2022">Adfinis</donor>
<donor since="2022">Büchel Blech AG</donor>
<donor>dyve</donor>
<donor>Eclipse Foundation</donor>

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<eventset>
<version>1</version>
<event start="2025-11-22T11:00:00Z" end="2025-11-22T15:00:00Z">
<title>FSFE-booth, workshop and presentation at LocHal Open Source Event</title>
<group>
<name>Netherlands</name>
<url></url>
</group>
<body>
<p>On Saturday November 22 we will host a FSFE-booth at the Open Source Event in LocHal public library in Tilburg the Netherlands. We will host a phone flashing workshop Free Your Android and present about Ada &amp; Zangemann book translations. We are looking forward to have a chat with you about Free Software! </p>
</body>
<link>https://www.lochal.nl/open-source-event-2025</link>
<tags>
<tag key="nl">
Netherlands </tag>
<tag key="talk"/>
<tag key="infobooth"/>
<tag key="localgroup"/>
<tag key="workshop"/>
<tag key="front-page"/>
</tags>
</event>
</eventset>

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<eventset>
<version>1</version>
<event start="2025-11-22T11:00:00Z" end="2025-11-22T15:00:00Z">
<title>FSFE-kraam, workshop en presentatie bij LocHal Open Source Event in Tilburg, Netherlands in Tilburg, Netherlands</title>
<group>
<name>Netherlands</name>
<url></url>
</group>
<body>
<p>Op zaterdag 23 november zijn we met een FSFE-kraam aanwezig in de LocHal bibliotheek in Tilburg. We hosten een Free Your Android workshop en presenteren over Ada &amp; Zangemann boekvertalingen. We kijken ernaar uit met u een praatje over Vrije Software te maken!</p>
</body>
<link>https://www.lochal.nl/open-source-event-2025</link>
<tags>
<tag key="nl">
Netherlands </tag>
<tag key="talk"/>
<tag key="infobooth"/>
<tag key="localgroup"/>
<tag key="workshop"/>
<tag key="front-page"/>
</tags>
</event>
</eventset>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<eventset>
<version>1</version>
<event start="2025-11-24T18:00:00Z" end="2025-11-24T21:00:00Z">
<title>FSFE Rhein-Main local group meeting in Frankfurt am Main, Germany</title>
<group>
<name>Rhein/Main</name>
<url></url>
</group>
<body>
<p>FSFE Rhein-Main is a loose gathering of people interested in Free Software. We hold monthly meetings in the Hackspace run by CCC-FFM &lt;https://ccc-ffm.de/hackerspace&gt;, Hohenstaufenstraße 8, 60327 Frankfurt am Main. This month we meet on 24th of November 2025 at 7 PM (local time). There is no need for prior registration and new appearances are always welcome. We tend to speak German, but most of us are also quite fluent in English.</p>
</body>
<tags>
<tag key="de">
Germany </tag>
<tag key="localgroup"/>
<tag key="meeting"/>
<tag key="front-page"/>
</tags>
</event>
</eventset>

View File

@@ -6,11 +6,14 @@
import logging
import multiprocessing
from pathlib import Path
from textwrap import dedent
from typing import TYPE_CHECKING
from fsfe_website_build.lib.misc import update_if_changed
if TYPE_CHECKING:
from pathlib import Path
logger = logging.getLogger(__name__)

View File

@@ -6,8 +6,10 @@ fsfe.org/news/nl/nl-$thisyear*:[front-page]
fsfe.org/news/nl/nl-$lastyear*:[front-page]
fsfe.org/news/nl/.nl-$thisyear*:[front-page]
fsfe.org/news/nl/.nl-$lastyear*:[front-page]
fsfe.org/news/podcast/episode-*:[front-page]
fsfe.org/news/podcast/.episode-*:[front-page]
fsfe.org/news/podcast/$thisyear/episode-*:[front-page]
fsfe.org/news/podcast/$thisyear/.episode-*:[front-page]
fsfe.org/news/podcast/$lastyear/episode-*:[front-page]
fsfe.org/news/podcast/$lastyear/.episode-*:[front-page]
fsfe.org/about/people/data/testimonials/*:[]
fsfe.org/events/$thisyear/event-*:[front-page]
fsfe.org/events/$nextyear/event-*:[front-page]

View File

@@ -8,13 +8,16 @@ import datetime
import logging
import operator
import os
from pathlib import Path
from typing import TYPE_CHECKING
from urllib.parse import urlparse
import requests
from fsfe_website_build.lib.misc import update_if_changed
from lxml import etree
if TYPE_CHECKING:
from pathlib import Path
logger = logging.getLogger(__name__)
@@ -60,7 +63,7 @@ def run(source: Path, languages: list[str], processes: int, working_dir: Path) -
try:
enddate = datetime.datetime.strptime(row[5], "%Y-%m-%d")
except ValueError:
enddate = datetime.datetime.today () + datetime.timedelta (days=7)
enddate = datetime.datetime.today() + datetime.timedelta(days=7)
if datetime.datetime.today() > enddate:
continue

View File

@@ -114,7 +114,7 @@
<p>
A few days later, one of the students, Zehra Irem Kuyucu, even went one step
further. She resorted to drastic measures by <a href="https://gitlab.digilol.net/Siren/vgtu-article/-/blob/master/vgtu.md">hacking
further. She resorted to drastic measures by <a href="https://kernal.eu/posts/hacking-vilnius-tech-ms-authenticator/">hacking
the university's GitLab instance</a>. She explained that she wanted to “teach what
their infrastructure is worth, as another bad habit they have is poor
security, despite authoring articles about it”. Then she sent an email to the IT department with security advice. She has, on other occasions, also reported problems regarding

View File

@@ -58,20 +58,19 @@ fetches Custom ROM devices and versions and displays it on a page. If
you're a developer, a file devices.json is
generated.</li>
<li><strong>Awesome Hacker Award:</strong>
<em>Mario</em> with <a href="https://github.com/Mallo321123/Scroll-Wheel"><strong>Scroll
<li><strong>Awesome Hacker Award</strong>: <em>Mario</em>
with <a href="https://github.com/Mallo321123/Scroll-Wheel"><strong>Scroll
Wheel</strong></a>, a big high resolution
scroll wheel inspired by Engineer Bo.</li>
<li><strong>Green Robot Award</strong>:
Vinicius with <strong><a href="https://codeberg.org/Batsvini/YH4F25_Smart_watering_robot">Smart Plant Watering Robot</a></strong>, a robot that can water your plants at home.</li>
<li><strong>Green Robot Award</strong>: <em>Vinícius</em> with <strong><a href="https://codeberg.org/Batsvini/YH4F25_Smart_watering_robot">Smart Plant Watering Robot</a></strong>, a robot that can water your plants at home.</li>
<li><strong>Beautiful Math Award:</strong> <em>Corentin</em> with <strong><a href=" https://github.com/CoCoSol007/hyper/">Hyper
<li><strong>Beautiful Math Award</strong>: <em>Corentin</em> with <strong><a href=" https://github.com/CoCoSol007/hyper/">Hyper
A Hyperbolic Rendering Engine</a></strong> for visualizing non-Euclidean geometry.
It renders an infinite world, offering an Educational, interactive view
of hyperbolic tilings and maze algorithms.</li>
<li><strong>Thinking Out of the Box Award: </strong><em>Augustin</em>
<li><strong>Thinking Out of the Box Award</strong>: <em>Augustin</em>
with <strong><a href="https://github.com/Gystek/dcg">dcg</a></strong> which aims at being a fast distributed revision control system
analysing files syntactically rather than linearly.</li>
</ul>
@@ -121,8 +120,6 @@ next edition will be shared soon on both, <a href="/">fsfe.org </a>and <a href="
<tag key="yh4f-project">Youth Hacking 4 Freedom - Project</tag>
<tag key="be">Belgium</tag>
<tag key="front-page"/>
<tag key="highlights">highlights</tag>
</tags>
<discussion href="https://mastodon.social/@fsfe/115435870688841134"/>

View File

@@ -6,5 +6,7 @@ fsfe.org/news/nl/nl-$thisyear*:[]
fsfe.org/news/nl/nl-$lastyear*:[]
fsfe.org/news/nl/.nl-$thisyear*:[]
fsfe.org/news/nl/.nl-$lastyear*:[]
fsfe.org/news/podcast/episode-*:[]
fsfe.org/news/podcast/.episode-*:[]
fsfe.org/news/podcast/$thisyear/episode-*:[]
fsfe.org/news/podcast/$thisyear/.episode-*:[]
fsfe.org/news/podcast/$lastyear/episode-*:[]
fsfe.org/news/podcast/$lastyear/.episode-*:[]

View File

@@ -1,2 +1,2 @@
fsfe.org/news/podcast/episode-*:[]
fsfe.org/news/podcast/.episode-*:[]
fsfe.org/news/podcast/*/episode-*:[]
fsfe.org/news/podcast/*/.episode-*:[]

View File

@@ -1,2 +1,2 @@
fsfe.org/news/podcast/episode-*:[]
fsfe.org/news/podcast/.episode-*:[]
fsfe.org/news/podcast/*/episode-*:[]
fsfe.org/news/podcast/*/.episode-*:[]

View File

@@ -69,7 +69,7 @@
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-1.html</url>
<url>/news/podcast/transcript/2019/episode-1.html</url>
</transcript>
<chapters>

View File

@@ -72,7 +72,7 @@
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-1.html</url>
<url>/news/podcast/transcript/2019/episode-1.html</url>
</transcript>
<chapters>

View File

@@ -59,7 +59,7 @@
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-1.html</url>
<url>/news/podcast/transcript/2019/episode-1.html</url>
</transcript>
<chapters>

View File

@@ -57,7 +57,7 @@
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-1.html</url>
<url>/news/podcast/transcript/2019/episode-1.html</url>
</transcript>
<chapters>
<chapter start="0:00">Welcome to the podcast</chapter>

View File

@@ -67,7 +67,7 @@
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-2.html</url>
<url>/news/podcast/transcript/2019/episode-2.html</url>
</transcript>
<chapters>

View File

@@ -56,7 +56,7 @@ Una volta al mese, parliamo con persone che hanno ispirato idee per la libertà
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-2.html</url>
<url>/news/podcast/transcript/2019/episode-2.html</url>
</transcript>
<chapters>
<chapter start="0:00">Benvenuti al podcast</chapter>

View File

@@ -53,7 +53,7 @@ Bij het plannen van deze tweede aflevering van de Software Freedom Podcast wilde
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-2.html</url>
<url>/news/podcast/transcript/2019/episode-2.html</url>
</transcript>
<chapters>
<chapter start="0:00">Welkom bij de podcast</chapter>

View File

@@ -62,7 +62,7 @@ One of the main topics this year was and still is the coming implementation of t
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-3.html</url>
<url>/news/podcast/transcript/2019/episode-3.html</url>
</transcript>
<chapters>
<chapter start="0:00">Welcome to the podcast</chapter>

View File

@@ -60,7 +60,7 @@
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-3.html</url>
<url>/news/podcast/transcript/2019/episode-3.html</url>
</transcript>
<chapters>
<chapter start="0:00">Benvenuti al podcast</chapter>

View File

@@ -57,7 +57,7 @@ Een van de belangrijkste onderwerpen dit jaar was en is de komende implementatie
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-3.html</url>
<url>/news/podcast/transcript/2019/episode-3.html</url>
</transcript>
<chapters>
<chapter start="0:00">Welkom bij de podcast</chapter>

View File

@@ -56,7 +56,7 @@ In the monthly Software Freedom Podcast we talk with people who have inspiring i
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-4.html</url>
<url>/news/podcast/transcript/2020/episode-4.html</url>
</transcript>
<chapters>
<chapter start="0:00">Welcome to the podcast</chapter>

View File

@@ -53,7 +53,7 @@
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-4.html</url>
<url>/news/podcast/transcript/2020/episode-4.html</url>
</transcript>
<chapters>
<chapter start="0:00">Benvenuti al podcast</chapter>

View File

@@ -56,7 +56,7 @@
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-4.html</url>
<url>/news/podcast/transcript/2020/episode-4.html</url>
</transcript>
<chapters>
<chapter start="0:00">Welcome to the podcast</chapter>

View File

@@ -65,7 +65,7 @@ This fifth episode of the Software Freedom Podcast covers the complicated topic
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-5.html</url>
<url>/news/podcast/transcript/2020/episode-5.html</url>
</transcript>
<chapters>
<chapter start="0:00">Welcome to the podcast</chapter>

View File

@@ -80,7 +80,7 @@ Entrevista con el Profesor Lawrence Lessig acerca de la regulación de la socied
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-5.html</url>
<url>/news/podcast/transcript/2020/episode-5.html</url>
</transcript>
<chapters>

View File

@@ -63,7 +63,7 @@
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-5.html</url>
<url>/news/podcast/transcript/2020/episode-5.html</url>
</transcript>
<chapters>
<chapter start="0:00">Benvenuti al podcast</chapter>

View File

@@ -62,7 +62,7 @@
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-5.html</url>
<url>/news/podcast/transcript/2020/episode-5.html</url>
</transcript>
<chapters>
<chapter start="0:00">Welcome to the podcast</chapter>

View File

@@ -55,7 +55,7 @@ repositories</a></li>
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-6.html</url>
<url>/news/podcast/transcript/2020/episode-6.html</url>
</transcript>
<chapters>
<chapter start="0:00">Welcome to the podcast</chapter>

View File

@@ -54,7 +54,7 @@
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-6.html</url>
<url>/news/podcast/transcript/2020/episode-6.html</url>
</transcript>
<chapters>

View File

@@ -55,7 +55,7 @@
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-6.html</url>
<url>/news/podcast/transcript/2020/episode-6.html</url>
</transcript>
<chapters>

View File

@@ -61,7 +61,7 @@ Our guest for the seventh episode of the Software Freedom Podcast is Vincent Leq
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-7.html</url>
<url>/news/podcast/transcript/2020/episode-7.html</url>
</transcript>
<chapters>
<chapter start="00:00">Welcome to the podcast</chapter>

View File

@@ -72,7 +72,7 @@ technologie dans notre vie quotidienne.
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-7.html</url>
<url>/news/podcast/transcript/2020/episode-7.html</url>
</transcript>
<chapters>

View File

@@ -59,7 +59,7 @@
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-7.html</url>
<url>/news/podcast/transcript/2020/episode-7.html</url>
</transcript>
<chapters>
<chapter start="00:00">Benvenuti al podcast</chapter>

View File

@@ -60,7 +60,7 @@
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-7.html</url>
<url>/news/podcast/transcript/2020/episode-7.html</url>
</transcript>
<chapters>
<chapter start="00:00">Welcome to the podcast</chapter>

View File

@@ -56,7 +56,7 @@ For this episode we talk about why Free Software can cost money. Bonnie Mehring
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-8.html</url>
<url>/news/podcast/transcript/2020/episode-8.html</url>
</transcript>
<chapters>
<chapter start="0:00">Intro</chapter>

View File

@@ -53,7 +53,7 @@
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-8.html</url>
<url>/news/podcast/transcript/2020/episode-8.html</url>
</transcript>
<chapters>
<chapter start="0:00">Introduzione</chapter>

View File

@@ -56,7 +56,7 @@
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-8.html</url>
<url>/news/podcast/transcript/2020/episode-8.html</url>
</transcript>
<chapters>
<chapter start="0:00">Intro</chapter>

View File

@@ -69,7 +69,7 @@ In this special episode of the Software Freedom Podcast we talk about some of th
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-special-1.html</url>
<url>/news/podcast/transcript/2020/episode-special-1.html</url>
</transcript>
<chapters>
<chapter start="0:00">Preface</chapter>

View File

@@ -69,7 +69,7 @@ In questa puntata speciale del podcast Software Freedom discutiamo di alcuni van
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-special-1.html</url>
<url>/news/podcast/transcript/2020/episode-special-1.html</url>
</transcript>
<chapters>
<chapter start="0:00">Avvertimenti</chapter>

View File

@@ -68,7 +68,7 @@
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-special-1.html</url>
<url>/news/podcast/transcript/2020/episode-special-1.html</url>
</transcript>
<chapters>
<chapter start="0:00">Preface</chapter>

View File

@@ -62,7 +62,7 @@ For this episode Matthias Kirschner and Bonnie Mehring talk with Elisa Lindinger
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-10.html</url>
<url>/news/podcast/transcript/2021/episode-10.html</url>
</transcript>
<chapters>
<chapter start="00:00">Intro</chapter>

View File

@@ -61,7 +61,7 @@
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-10.html</url>
<url>/news/podcast/transcript/2021/episode-10.html</url>
</transcript>
<chapters>
<chapter start="00:00">Introduzione</chapter>

View File

@@ -50,7 +50,7 @@ Voor deze aflevering praten Matthias Kirschner en Bonnie Mehring met Elisa Lindi
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-10.html</url>
<url>/news/podcast/transcript/2021/episode-10.html</url>
</transcript>
<chapters>
<chapter start="00:00">Intro</chapter>

View File

@@ -58,7 +58,7 @@ Max Mehl and Bonnie Mehring talk about the REUSE initiative and the newly launch
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-11.html</url>
<url>/news/podcast/transcript/2021/episode-11.html</url>
</transcript>
<chapters>
<chapter start="0:00">Welcome to the podcast</chapter>

View File

@@ -58,7 +58,7 @@ Max Mehl e Bonnie Mehring parlano dell'iniziativa REUSE e del nuovo programma RE
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-11.html</url>
<url>/news/podcast/transcript/2021/episode-11.html</url>
</transcript>
<chapters>
<chapter start="0:00">Benvenuti al podcast</chapter>

View File

@@ -58,7 +58,7 @@ Max Mehl en Bonnie Mehring praten over het REUSE-initiatief en het onlangs gelan
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-11.html</url>
<url>/news/podcast/transcript/2021/episode-11.html</url>
</transcript>
<chapters>
<chapter start="0:00">Welcome to the podcast</chapter>

View File

@@ -95,7 +95,7 @@
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-12.html</url>
<url>/news/podcast/transcript/2021/episode-12.html</url>
</transcript>
<chapters>

View File

@@ -84,7 +84,7 @@
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-12.html</url>
<url>/news/podcast/transcript/2021/episode-12.html</url>
</transcript>
<chapters>

View File

@@ -85,7 +85,7 @@
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-12.html</url>
<url>/news/podcast/transcript/2021/episode-12.html</url>
</transcript>
<chapters>

View File

@@ -55,7 +55,7 @@ In this ninth episode, Bonnie Mehring and Matthias Kirschner cover one of the ol
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-9.html</url>
<url>/news/podcast/transcript/2021/episode-9.html</url>
</transcript>
<chapters>
<chapter start="00:00">Intro</chapter>

View File

@@ -53,7 +53,7 @@
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-9.html</url>
<url>/news/podcast/transcript/2021/episode-9.html</url>
</transcript>
<chapters>
<chapter start="00:00">Introduzione</chapter>

View File

@@ -55,7 +55,7 @@ In deze negende aflevering behandelen Bonnie Mehring en Matthias Kirschner een v
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-9.html</url>
<url>/news/podcast/transcript/2021/episode-9.html</url>
</transcript>
<chapters>
<chapter start="00:00">Intro</chapter>

View File

@@ -82,7 +82,7 @@ Diese Podcastepisode nimmt Sie mit auf eine Reise durch die Entwicklung des Spie
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-13.html</url>
<url>/news/podcast/transcript/2022/episode-13.html</url>
</transcript>
<chapters>

View File

@@ -83,7 +83,7 @@ This podcast episode takes you on a journey through the game's development and i
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-13.html</url>
<url>/news/podcast/transcript/2022/episode-13.html</url>
</transcript>
<chapters>

View File

@@ -80,7 +80,7 @@
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-13.html</url>
<url>/news/podcast/transcript/2022/episode-13.html</url>
</transcript>
<chapters>

View File

@@ -44,7 +44,7 @@ Deze podcast-aflevering neemt u mee op een reis door de ontwikkeling van het spe
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-13.html</url>
<url>/news/podcast/transcript/2022/episode-13.html</url>
</transcript>
<chapters>

View File

@@ -67,7 +67,7 @@ With this episode the Software Freedom Podcast opens the door to the fascinating
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-14.html</url>
<url>/news/podcast/transcript/2022/episode-14.html</url>
</transcript>
<chapters>

View File

@@ -47,7 +47,7 @@ Avec cet épisode, le podcast Liberté des Logiciels ouvre la porte au fascinant
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-14.html</url>
<url>/news/podcast/transcript/2022/episode-14.html</url>
</transcript>
<chapters>
<chapter start="00:00">Introduction</chapter>

View File

@@ -65,7 +65,7 @@
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-14.html</url>
<url>/news/podcast/transcript/2022/episode-14.html</url>
</transcript>
<chapters>

View File

@@ -48,7 +48,7 @@ Met deze aflevering opent de Software Freedom Podcast de deur naar de fascineren
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-14.html</url>
<url>/news/podcast/transcript/2022/episode-14.html</url>
</transcript>
<chapters>
<chapter start="00:00">Intro</chapter>

View File

@@ -76,7 +76,7 @@
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-15.html</url>
<url>/news/podcast/transcript/2022/episode-15.html</url>
</transcript>
<chapters>

View File

@@ -97,7 +97,7 @@ lavoro per la libertà del software, aiutaci con una
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-15.html</url>
<url>/news/podcast/transcript/2022/episode-15.html</url>
</transcript>
<chapters>

View File

@@ -41,7 +41,7 @@
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-15.html</url>
<url>/news/podcast/transcript/2022/episode-15.html</url>
</transcript>
<chapters>
<chapter start="00:00">Intro</chapter>

View File

@@ -55,7 +55,7 @@ Hugo has been a volunteer for the FSFE for over 10 years now. Have you ever wond
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-16.html</url>
<url>/news/podcast/transcript/2022/episode-16.html</url>
</transcript>
<chapters>
<chapter start="00:00">Welcome to the podcast</chapter>

View File

@@ -55,7 +55,7 @@
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-16.html</url>
<url>/news/podcast/transcript/2022/episode-16.html</url>
</transcript>
<chapters>
<chapter start="00:00">Benvenuti al podcast</chapter>

View File

@@ -55,7 +55,7 @@
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-16.html</url>
<url>/news/podcast/transcript/2022/episode-16.html</url>
</transcript>
<chapters>
<chapter start="00:00">Welkom bij de podcast</chapter>

View File

@@ -55,7 +55,7 @@ Petter Joelson is the director of <a href="https://digidemlab.org/">Digidem Lab<
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-17.html</url>
<url>/news/podcast/transcript/2022/episode-17.html</url>
</transcript>
<chapters>

View File

@@ -55,7 +55,7 @@ Petter Joelson è il direttore di <a href="https://digidemlab.org/">Digidem Lab<
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-17.html</url>
<url>/news/podcast/transcript/2022/episode-17.html</url>
</transcript>
<chapters>
<chapter start="00:00">Benvenuti al podcast</chapter>

View File

@@ -56,7 +56,7 @@ Petter Joelson is de directeur van <a href="https://digidemlab.org/">Digidem Lab
</mp3>
<!-- Transcript -->
<transcript>
<url>/news/podcast/transcript/episode-17.html</url>
<url>/news/podcast/transcript/2022/episode-17.html</url>
</transcript>
<chapters>
<chapter start="00:00">Welkom bij de podcast</chapter>

Some files were not shown because too many files have changed in this diff Show More