02 Feb 2023
Drupal is an open-source content management system written in PHP. Here's how to install it using Docker on a Ubuntu 22.04 server.
The post How to Install Drupal With Docker on Ubuntu 22.04 appeared first on Linux Today.
02 Feb 2023 9:00pm GMT
Linux is a popular open-source operating system that runs on a variety of hardware platforms, including desktops, servers, and smartphones. One of the key features of Linux is the command-line interface (CLI), which allows users to perform a wide range of tasks using text-based commands.
02 Feb 2023 8:21pm GMT
{{unknown}}
The post appeared first on Linux Today.
02 Feb 2023 7:38pm GMT
Want to organize your windows and use all the screen space you have? These window managers for Linux should come in handy!
The post 8 Best Window Managers for Linux appeared first on Linux Today.
02 Feb 2023 7:00pm GMT
The 2023 LPC PC is pleased to announce that we've begun exclusive negotiations with the Omni Hotel in Richmond, VA to host Plumbers 2023 from 13-15 November. Note: These dates are not yet final (nor is the location; we have had one failure at this stage of negotiations from all the Plumbers venues we've chosen). We will let you know when this preliminary location gets finalized (please don't book irrevocable travel until then).
The November dates were the only ones that currently work for the venue, but Richmond is on the same latitude as Seville in Spain, so it should still be nice and warm.
02 Feb 2023 4:18pm GMT
Ray, the popular open-source machine learning (ML) framework, has released its 2.2 version with improved performance and observability capabilities, as well as features that can help to enable reproducibility.
02 Feb 2023 3:03pm GMT
Part One: SOAP-Based APIs
Simple Object Access Protocol (SOAP) is a messaging protocol based on requests and responses using an XML format. Although some legacy systems still use SOAP over SMTP, the transport method typically used for SOAP requests is HTTP. As an API protocol, SOAP is platform-and language-agnostic, allowing for two applications running on completely different systems to communicate with one another.
This post is part of a two-part series covering how to create custom API endpoints in Salesforce with APEX. In Part One, we'll walk through how to create a SOAP-based API endpoint for other applications to use when communicating with your Salesforce org.
02 Feb 2023 1:18pm GMT
With the new release, Red Hat is integrating new capabilities to help improve security and compliance for OpenShift, as well as new deployment options on ARM-based architectures. The OpenShift 4.12 release comes as Red Hat continues to expand its footprint, announcing partnerships with Oracle and SAP this week.
02 Feb 2023 12:40pm GMT
In one week from now, Twitter will block free API access. This prevents anyone who has written interesting bot accounts, integrations, or tooling from accessing Twitter without paying for it. A whole number of fascinating accounts will cease functioning, people will no longer be able to use tools that interact with Twitter, and anyone using a free service to do things like find Twitter mutuals who have moved to Mastodon or to cross-post between Twitter and other services will be blocked.
There's a cynical interpretation to this, which is that despite firing 75% of the workforce Twitter is still not profitable and Elon is desperate to not have Twitter go bust and also not to have to tank even more of his Tesla stock to achieve that. But let's go with the less cynical interpretation, which is that API access to Twitter is something that enables bot accounts that make things worse for everyone. Except, well, why would a hostile bot account do that?
To interact with an API you generally need to present some sort of authentication token to the API to prove that you're allowed to access it. It's easy enough to restrict issuance of those tokens to people who pay for the service. But, uh, how do the apps work? They need to be able to communicate with the service to tell it to post tweets, retrieve them, and so on. And the simple answer to that is that they use some hardcoded authentication tokens. And while registering for an API token yourself identifies that you're not using an official client, using the tokens embedded in the clients makes it look like you are. If you want to make it look like you're a human, you're already using tokens ripped out of the official clients.
The Twitter client API keys are widely known. Anyone who's pretending to be a human is using those already and will be unaffected by the shutdown of the free API tier. Services like movetodon.org do get blocked. This isn't an anti-abuse choice. It's one that makes it harder to move to other services. It's one that blocks a bunch of the integrations and accounts that bring value to the platform. It's one that hurts people who follow the rules, without hurting the ones who don't. This isn't an anti-abuse choice, it's about trying to consolidate control of the platform.
comments
02 Feb 2023 10:36am GMT

If you work with a federal government-related website in Canada, you invariably have to contend with two challenges. First, everything has to be bilingual in English and French. Second, everything has to meet AA-level conformance with WCAG 2.0 accessibility requirements.
This applies to any website under the umbrella of Canada.ca and a wide array of federally funded organizations, as well as many provincial and municipal organizations.
To address this need, Drupal contributors within the government sector in Canada created the Web Experience Toolkit distribution (Drupal WxT). This is a version of Drupal designed for the Canadian government and other organizations with these particular bilingual and accessibility requirements. It includes a theme that provides accessibility and responsive support, has built-in support for English and French and provides the look and feel of the Government of Canada.
For developers tasked with Drupal-based Government of Canada websites or other sites with similar requirements, WxT is an invaluable tool.
How To Install Drupal WxT 4
There are several different ways to install this distribution. For the purposes of this post, we have done an installation in a Docker-based environment, but it can also be done with Docksal, Lando, DDEV, local Apache or composer.
1. Install in your environment composer and PHP dependencies for Drupal. It's important that you review the dependencies, as you will need PHP 8.1 for this process. See the latest PHP requirements here.
2. Execute the following command to create a project folder with the Drupal installation, using the WxT profile.
composer create-project drupalwxt/site-wxt:9.4.x-dev --no-interaction
3. Once you have the Drupal folder with the code, you can set up the environment as you want. If you are using Docksal, see the following project setup documentation.
4. When you access the site for the first time, the following installation UI will appear in the browser.
5. Choose a language and click on continue. You can then set up the database connection credentials, and the installation will start.
6. Enter the site information details.
7. Translations are then automatically imported.
8. Select the WxT extensions that you plan to use for this particular site. These extensions can be modified as needed.
9. When the WxT extension installation is complete, you'll be redirected to the site homepage as an admin user.
Features
Once you have completed the installation, you can begin to explore the many features of Drupal WxT. Here's an overview of the built-in functionality that the latest version, WxT 4, has to offer.
- WxT themes - Includes a GoC Public and Intranet WxT 3, 3.1 and the newer Bootstrap WxT 4 branch, as well as a plain (non-GoC) WxT theme.
- Multilingualism - Contains a French Canadian language pack, with many contributions from various government departments for common string elements, and has the ability to extend to more than 200 other languages.
- Migration - Can instantly pull content from static sites, TeamSite, OpenText, IBM/Domino and many other sources, thanks to fully automated bulk harvesting of CLF2 and WET3 templates.
- Content staging - You can run a full "staging > deploy" with no code to a live production environment by way of an administrative interface with a bulk scheduled rules engine or on-demand page by page.
- Workflow and moderation - Includes a sophisticated workflow for both simple and complex processes. This enables you to track "who did what when" with versioning and to compare differences in side-by-side revisions, based on your roles and permissions.
- Forms - Has a front-end capable of building and managing everything from simple user author-able feedback forms to comprehensive multifunction apps suitable for integration into legacy systems, with no code necessary.
- Layouts and editors - Enables content teams to manage their layouts and page components with intuitive drag-and-drop panels UI. Also includes a rich text editor with extensive features and user profile-based restrictions, including media file handling and markup blacklists and whitelists, which works with most rich text editors.
- Search - Extends easily with SearchAPI and is proven to work with Google Search and Solr for rich search application-like facets and filters. Enables you to ingest external indexes from other systems and securely present metadata for a unified search results, including full-text files.
- Responsiveness - Uses a mobile-first approach based on the Omega theme, adapting to different screen sizes and device capabilities. Also has touchscreen support, is optimized for performance and is building support for device-based mobile applications.
- Cross-browser compatibility - Has both front-end and back-end compatibility, supporting Google Chrome, Mozilla Firefox, Safari, and IE8+.
- Extensive default typography - Provides you with a wide range of typography options to customize your site.
- And of course … community-based add-ons - This is a big one. Because it's an open-source platform, you can choose from thousands of community-based addons available for free. You often even have options for common requirements.
Need Help?
Want to brush up on your Drupal skills? We have training packages that can help your team take your site to the next level. Learn more about our training tracks.
You can also watch our free on-demand webinar on Drupal WxT, where we cover how to build and maintain accessible, multilingual, easy-to-use, and mobile-friendly websites.
+ more awesome articles by Evolving Web
02 Feb 2023 9:50am GMT
roadmap to learn functional programming
02 Feb 2023 8:58am GMT
While installing Python and Virtualenv on MacOS Ventura and Monterey can be done several ways, this tutorial will guide you through the process of configuring a stock Mac system into a solid Python development environment.
First steps
This guide assumes that you have already installed Homebrew. For details, please follow the steps in the MacOS Configuration Guide.
Python
We are going to install the latest version of Python via asdf and its Python plugin. Why bother, you ask, when Apple includes Python along with MacOS? Here are some reasons:
- When using the bundled Python, MacOS updates can remove your Python packages, forcing you to re-install them.
- As new versions of Python are released, the Python bundled with MacOS will become out-of-date. Building Python via asdf means you always have access to the most recent Python version.
- Apple has made significant changes to its bundled Python, potentially resulting in hidden bugs.
- Building Python via asdf includes the latest versions of Pip and Setuptools (Python package management tools)
Use the following command to install asdf and Python build dependencies via Homebrew:
brew install asdf openssl readline sqlite3 xz zlib
Next we ensure asdf is loaded for both current and future shell sessions. If you are using Fish shell:
# Load asdf for this session
source (brew --prefix)/opt/asdf/asdf.fish
# Ensure asdf loads for all subsequent sessions
echo source (brew --prefix)/opt/asdf/asdf.fish >> ~/.config/fish/config.fish
# Ensure asdf doesn't disrupt activated virtual environments
echo 'if set -q VIRTUAL_ENV; source "$VIRTUAL_ENV/bin/activate.fish"; end' >> ~/.config/fish/config.fish
For Zsh (the default shell on MacOS):
. $(brew --prefix asdf)/asdf.sh
echo -e "\n. $(brew --prefix asdf)/asdf.sh" >> ~/.zshrc
Install the asdf Python plugin and the latest version of Python:
asdf plugin add python
asdf install python latest
Note the Python version number that was just installed. For the purpose of this guide, we will assume version 3.11.1, so replace that number below with the version number you actually just installed.
Set the default global Python version:
asdf global python 3.11.1
Confirm the Python version matches the latest version we just installed:
Pip
Let's say you want to install a Python package, such as the Virtualenv environment isolation tool. While many Python-related articles for MacOS tell the reader to install Virtualenv via sudo pip install virtualenv
, the downsides of this method include:
- installs with root permissions
- installs into the system /Library
- yields a less reliable environment when using Python built with asdf
As you might have guessed by now, we are going to use the asdf Python plugin to install the Python packages that we want to be globally available. When installing via python -m pip […]
, packages will be installed to: ~/.asdf/installs/python/{version}/lib/python{version}/site-packages/
First, let's ensure we are using the latest version of Pip and Setuptools:
python -m pip install --upgrade pip setuptools
In the next section, we'll use Pip to install our first globally-available Python package.
Virtualenv
Python packages installed via Pip are global in the sense that they are available across all of your projects. That can be convenient at times, but it can also create problems. For example, sometimes one project needs the latest version of Django, while another project needs an older Django version to retain compatibility with a critical third-party extension. This is one of many use cases that Virtualenv was designed to solve. On my systems, only a handful of general-purpose Python packages (including Virtualenv) are globally available - every other package is confined to virtual environments.
With that explanation behind us, let's install Virtualenv:
python -m pip install virtualenv
asdf reshim python
Create some directories to store our projects, virtual environments, and Pip configuration file, respectively:
mkdir -p ~/Projects ~/Virtualenvs ~/.config/pip
We'll then open Pip's configuration file (which may be created if it doesn't exist yet)…
vim ~/.config/pip/pip.conf
… and add some lines to it:
[install]
require-virtualenv = true
[uninstall]
require-virtualenv = true
Now we have Virtualenv installed and ready to create new virtual environments, which we will store in ~/Virtualenvs
. New virtual environments can be created via:
cd ~/Virtualenvs
virtualenv project-a
If you have both Python 3.10.x and 3.11.x installed and want to create a Python 3.10.9 virtual environment:
virtualenv -p ~/.asdf/installs/python/3.10.9/bin/python project-b
Restricting Pip to virtual environments
What happens if we think we are working in an active virtual environment, but there actually is no virtual environment active, and we install something via python -m pip install foobar
? Well, in that case the foobar
package gets installed into our global site-packages, defeating the purpose of our virtual environment isolation.
Thankfully, Pip has an undocumented setting (source) that tells it to bail out if there is no active virtual environment, which is exactly what we want. In fact, we've already set that above, via the require-virtualenv = true
directive in Pip's configuration file. For example, let's see what happens when we try to install a package in the absence of an activated virtual environment:
python -m pip install markdown
Could not find an activated virtualenv (required).
Perfect! But once that option is set, how do we install or upgrade a global package? We can temporarily turn off this restriction by defining a new function in ~/.zshrc
:
gpip(){
PIP_REQUIRE_VIRTUALENV="0" python -m pip "$@"
}
(As usual, after adding the above you must run source ~/.zshrc
for the change to take effect.)
If in the future we want to upgrade our global packages, the above function enables us to do so via:
gpip install --upgrade pip setuptools virtualenv
You could achieve the same effect via PIP_REQUIRE_VIRTUALENV="0" python -m pip install --upgrade […]
, but that's much more cumbersome to type every time.
Creating virtual environments
Let's create a virtual environment for Pelican, a Python-based static site generator:
cd ~/Virtualenvs
virtualenv pelican
Change to the new environment and activate it via:
cd pelican
source bin/activate
To install Pelican into the virtual environment, we'll use Pip:
python -m pip install pelican markdown
For more information about virtual environments, read the Virtualenv docs.
Dotfiles
These are obviously just the basic steps to getting a Python development environment configured. Feel free to also check out my dotfiles.
If you found this article to be useful, feel free to find me on Twitter.
02 Feb 2023 7:00am GMT
read previous post before jumping to this program
02 Feb 2023 5:32am GMT
This is the last part of the debugging series. To learn the rest, you'll need to get the book "Practical Debugging at Scale: Cloud Native Debugging in Kubernetes and Production" or the course. One of the most frequently asked questions I receive is: can we do these things in VS Code?
The answer is, unfortunately, no. But I elaborate on the debugging capabilities of VS Code in this video: "16 Missing Features in the VS Code Debugger" on YouTube. I'll do a blog post that covers that next week.
02 Feb 2023 1:37am GMT
Support the Show
This podcast does not have any ads or sponsors. To support the show, please consider purchasing a book, signing up for Button, or reading the Django News newsletter.
02 Feb 2023 12:00am GMT
01 Feb 2023
DevOps is not new. Every business in the IT world knows it is the right software development methodology. Indeed, DevOps has enticed the world with its promise of high-quality product delivery at a faster pace. Despite the clear promise of DevOps, many businesses are failing to realize its complete potential. While cultural inertia and skillset sparsity are some of the reasons, the inability to completely automate the DevOps lifecycle remains the greatest impediment for businesses to drive full value from their DevOps investments. Integration of DevOps and automation is what leads to a more efficient software development lifecycle (SDLC). So, let's understand what it is all about automating DevOps and how you can start automating your DevOps processes.
What Is DevOps Automation?
Automation is the fundamental principle of DevOps. In fact, "automating everything" is the ultimate objective of the DevOps methodology. So, DevOps automation is the process of automating nearly every repetitive and manual task across the DevOps SDLC, from design and development to deployment and release management.
01 Feb 2023 11:20pm GMT
Static files like CSS, JavaScript, and fonts are a core piece of any modern web application. They are also typically confusing for Django newcomers since Django provides tremendous flexibility around …
01 Feb 2023 9:42pm GMT
The release of Drupal 10 has been highly anticipated by the Drupal community, and it was finally launched in December 2022. This latest version of the content management system brings several new features and functional improvements that will make content creation and management easier while also improving SEO, and driving conversions.
In this blog, we'll highlight the key benefits of Drupal 10 for marketers and website managers.

01 Feb 2023 3:29pm GMT
Direct .mp3 file download.
We talk with Ryan Price about how to start a new Drupal project the right way, including development environment setup, code base setup, initial modules, Git setup, and common newbie mistakes.
URLs mentioned
DrupalEasy News
We're using the machine-driven Amazon Transcribe service to provide an audio transcript of this episode.
Subscribe
Subscribe to our podcast on iTunes, Google Play or Miro. Listen to our podcast on Stitcher.
If you'd like to leave us a voicemail, call 321-396-2340. Please keep in mind that we might play your voicemail during one of our future podcasts. Feel free to call in with suggestions, rants, questions, or corrections. If you'd rather just send us an email, please use our contact page.
01 Feb 2023 3:21pm GMT
This tutorial shows how to secure a FastAPI application with JWT Token-based Authentication.
01 Feb 2023 4:28am GMT
27 Jan 2023
After my previous efforts, I wrote up a PKCS#11 module of my own that had no odd restrictions about using non-RSA keys and I tested it. And things looked much better - ssh successfully obtained the key, negotiated with the server to determine that it was present in authorized_keys, and then went to actually do the key verification step. At which point things went wrong - the Sign() method in my PKCS#11 module was never called, and a strange
debug1: identity_sign: sshkey_sign: error in libcrypto
sign_and_send_pubkey: signing failed for ECDSA "testkey": error in libcrypto"
error appeared in the ssh output. Odd. libcrypto was originally part of OpenSSL, but Apple ship the LibreSSL fork. Apple don't include the LibreSSL source in their public source repo, but do include OpenSSH. I grabbed the OpenSSH source and jumped through a whole bunch of hoops to make it build (it uses the macosx.internal SDK, which isn't publicly available, so I had to cobble together a bunch of headers from various places), and also installed upstream LibreSSL with a version number matching what Apple shipped. And everything worked - I logged into the server using a hardware-backed key.
Was the difference in OpenSSH or in LibreSSL? Telling my OpenSSH to use the system libcrypto resulted in the same failure, so it seemed pretty clear this was an issue with the Apple version of the library. The way all this works is that when OpenSSH has a challenge to sign, it calls ECDSA_do_sign(). This then calls ECDSA_do_sign_ex(), which in turn follows a function pointer to the actual signature method. By default this is a software implementation that expects to have the private key available, but you can also register your own callback that will be used instead. The OpenSSH PKCS#11 code does this by calling EC_KEY_set_method(), and as a result calling ECDSA_do_sign() ends up calling back into the PKCS#11 code that then calls into the module that communicates with the hardware and everything works.
Except it doesn't under macOS. Running under a debugger and setting a breakpoint on EC_do_sign(), I saw that we went down a code path with a function called ECDSA_do_sign_new(). This doesn't appear in any of the public source code, so seems to be an Apple-specific patch. I pushed Apple's libcrypto into Ghidra and looked at ECDSA_do_sign() and found something that approximates this:
nid = EC_GROUP_get_curve_name(curve);
if (nid == NID_X9_62_prime256v1) {
return ECDSA_do_sign_new(dgst,dgst_len,eckey);
}
return ECDSA_do_sign_ex(dgst,dgst_len,NULL,NULL,eckey);
What this means is that if you ask ECDSA_do_sign() to sign something on a Mac, and if the key in question corresponds to the NIST P256 elliptic curve type, it goes down the ECDSA_do_sign_new() path and never calls the registered callback. This is the only key type supported by the Apple Secure Enclave, so I assume it's special-cased to do something with that. Unfortunately the consequence is that it's impossible to use a PKCS#11 module that uses Secure Enclave keys with the shipped version of OpenSSH under macOS. For now I'm working around this with an SSH agent built using Go's agent module, forwarding most requests through to the default session agent but appending hardware-backed keys and implementing signing with them, which is probably what I should have done in the first place.
comments
27 Jan 2023 11:39pm GMT
24 Jan 2023
Mastobot: For your Fediverse PHP posting needs
Like much of the world I've been working to migrate off of Twitter to Mastodon and the rest of the Fediverse. Along with a new network is the need for new automation tools, and I've taken this opportunity to scratch my own itch and finally build an auto-posting bot for my own needs. And it is, of course, available as Free Software.
Announcing Mastobot! Your PHP-based Mastodon auto-poster.
Continue reading this post on PeakD.
Larry 23 January 2023 - 10:13pm
24 Jan 2023 4:13am GMT
23 Jan 2023
While SLIME is most of the time able to indent Common Lisp correctly, it will sometimes trip on custom forms. Let us see how we can customize indentation.
In the process of writing my PostgreSQL client in Common Lisp, I wrote a READ-MESSAGE-CASE
macro which reads a message from a stream and execute code depending on the type of the message:
(defmacro read-message-case ((message stream) &rest forms)
`(let ((,message (read-message ,stream)))
(case (car ,message)
(:error-response
(backend-error (cdr ,message)))
(:notice-response
nil)
,@forms
(t
(error 'unexpected-message :message ,message)))))
This macro is quite useful: all message loops can use it to automatically handle error responses, notices, and signal unexpected messages.
But SLIME does not know how to indent READ-MESSAGE-CASE
, so by default it will align all message forms on the first argument:
(read-message-case (message stream)
(:authentication-ok
(return))
(:authentication-cleartext-password
(unless password
(error 'missing-password))
(write-password-message password stream)))
While we want it aligned the same way as HANDLER-CASE
:
(read-message-case (message stream)
(:authentication-ok
(return))
(:authentication-cleartext-password
(unless password
(error 'missing-password))
(write-password-message password stream)))
Good news, SLIME indentation is defined as a list of rules. Each rule associates an indentation specification (a S-expression describing how to indent the form) to a symbol and store it as the common-lisp-indent-function
property of the symbol.
You can obtain the indentation rule of a Common Lisp symbol easily. For example, executing (get 'defun 'common-lisp-indent-function)
(e.g. in IELM or with eval-expression
) yields (4 &lambda &body)
. This indicates that DEFUN
forms are to be indented as follows:
- The first argument of
DEFUN
(the function name) is indented by four spaces.
- The second argument (the list of function arguments) is indented as a lambda list.
- The rest of the arguments are indented based on the
lisp-body-indent
custom variable, which controls the indentation of the body of a lambda form (two spaces by default).
You can refer to the documentation of the common-lisp-indent-function
Emacs function (defined in SLIME of course) for a complete description of the format.
We want READ-MESSAGE-CASE
to be indented the same way as HANDLER-CASE
, whose indentation specification is (4 &rest (&whole 2 &lambda &body))
(in short, an argument and a list of lambda lists). Fortunately there is a way to specify that a form must be indented the same way as another form, using (as <symbol>)
.
Let us first define a function to set the indentation specification of a symbol:
(defun g-common-lisp-indent (symbol indent)
"Set the indentation of SYMBOL to INDENT."
(put symbol 'common-lisp-indent-function indent))
Then use it for READ-MESSAGE-CASE
:
(g-common-lisp-indent 'read-message-case '(as handler-case))
While it is in general best to avoid custom indentation, exceptions are sometimes necessary for readability. And SLIME makes it easy.
23 Jan 2023 6:00pm GMT
One of the persistently lesser-known symptoms of ADHD is hyperfocus. It is sometimes quasi-accurately described as a "superpower" , which it can be. In the right conditions, hyperfocus is the ability to effortlessly maintain a singular locus of attention for far longer than a neurotypical person would be able to.
However, as a general rule, it would be more accurate to characterize hyperfocus not as an "ability to focus on X" but rather as "an inability to focus on anything other than X". Sometimes hyperfocus comes on and it just digs its claws into you and won't let go until you can achieve some kind of closure.
Recently, the X I could absolutely not stop focusing on - for days at a time - was this extremely annoying picture:

Which lead to me writing the silliest computer program I have written in quite some time.
You see, for some reason, macOS seems to prefer YUV422 chroma subsampling on external displays, even when the bitrate of the connection and selected refresh rate support RGB. Lots of people have been trying to address this for a literal decade , and the problem has gotten worse with Apple Silicon, where the operating system no longer even supports the EDID-override functionality available on every other PC operating system that supports plugging in a monitor.
In brief, this means that every time I unplug my MacBook from its dock and plug it back in more than 5 minutes later, its color accuracy is destroyed and red or blue text on certain backgrounds looks like that mangled mess in the picture above. Worse, while the color distinction is definitely noticeable, it's so subtle that it's like my display is constantly gaslighting me. I can almost hear it taunting me:
Magenta? Yeah, magenta always looked like this. Maybe it's the ambient lighting in this room. You don't even have a monitor hood. Remember how you had to use one of those for print design validation? Why would you expect it to always look the same without one?
Still, I'm one of the luckier people with this problem, because I can seem to force RGB / 444 color format on my display just by leaving the display at 120Hz rather than 144, then toggling HDR on and then off again. At least I don't need to plug in the display via multiple HDMI and displayport cables and go into the OSD every time. However, there is no API to adjust, or even discover the chroma format of your connected display's link, and even the accessibility features that supposedly let you drive GUIs are broken in the system settings "Displays" panel, so you have to do it by sending synthetic keystrokes and hoping you can tab-focus your way to the right place.
Anyway, this is a program which will be useless to anyone else as-is, but if someone else is struggling with the absolute inability to stop fiddling with the OS to try and get colors to look correct on a particular external display, by default, all the time, maybe you could do something to hack on this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
import os
from Quartz import CGDisplayRegisterReconfigurationCallback, kCGDisplaySetMainFlag, kCGDisplayBeginConfigurationFlag
from ColorSync import CGDisplayCreateUUIDFromDisplayID
from CoreFoundation import CFUUIDCreateString
from AppKit import NSApplicationMain, NSApplicationActivationPolicyAccessory, NSApplication
NSApplication.sharedApplication().setActivationPolicy_(NSApplicationActivationPolicyAccessory)
CGDirectDisplayID = int
CGDisplayChangeSummaryFlags = int
MY_EXTERNAL_ULTRAWIDE = '48CEABD9-3824-4674-9269-60D1696F0916'
MY_INTERNAL_DISPLAY = '37D8832A-2D66-02CA-B9F7-8F30A301B230'
def cb(display: CGDirectDisplayID, flags: CGDisplayChangeSummaryFlags, userInfo: object) -> None:
if flags & kCGDisplayBeginConfigurationFlag:
return
if flags & kCGDisplaySetMainFlag:
displayUuid = CGDisplayCreateUUIDFromDisplayID(display)
uuidString = CFUUIDCreateString(None, displayUuid)
print(uuidString, "became the main display")
if uuidString == MY_EXTERNAL_ULTRAWIDE:
print("toggling HDR to attempt to clean up subsampling")
os.system("/Users/glyph/.local/bin/desubsample")
print("HDR toggled.")
print("registered", CGDisplayRegisterReconfigurationCallback(cb, None))
NSApplicationMain([])
|
and the linked desubsample
is this atrocity, which I substantially cribbed from this helpful example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
#!/usr/bin/osascript
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use scripting additions
tell application "System Settings"
quit
delay 1
activate
current application's NSWorkspace's sharedWorkspace()'s openURL:(current application's NSURL's URLWithString:"x-apple.systempreferences:com.apple.Displays-Settings.extension")
delay 0.5
tell application "System Events"
tell process "System Settings"
key code 48
key code 48
key code 48
delay 0.5
key code 49
delay 0.5
-- activate hdr on left monitor
set hdr to checkbox 1 of group 3 of scroll area 2 of ¬
group 1 of group 2 of splitter group 1 of group 1 of ¬
window "Displays"
tell hdr
click it
delay 1.0
if value is 1
click it
end if
end tell
end tell
end tell
quit
end tell
|
This ridiculous little pair of programs does it automatically, so whenever I reconnect my MacBook to my desktop dock at home, it faffs around with clicking the HDR button for me every time. I am leaving it running in a background tmux
session so - hopefully - I can finally stop thinking about this.
23 Jan 2023 3:06am GMT
18 Jan 2023
Ever since I got involved with open-source Python projects, tox has been vital for testing packages across Python versions (and other factors). However, lately, I've been increasingly using Nox for my projects instead. Since I've been asked why repeatedly, I'll sum up my thoughts.
18 Jan 2023 12:00pm GMT
Table of Contents
- Introduction
- Defining method combinations - the short form
- Defining method combinations - the long form
- The Hooker
- The Memoizer
- Conclusions
Update [2023-01-23]
Christophe Rhodes pointed out that "The Hooker" method combination is not conforming because there are multiple methods with the same "role" that can't be ordered and that have different qualifiers:
Note that two methods with identical specializers, but with different qualifiers, are not ordered by the algorithm described in Step 2 of the method selection and combination process described in Section 7.6.6 (Method Selection and Combination). Normally the two methods play different roles in the effective method because they have different qualifiers, and no matter how they are ordered in the result of Step 2, the effective method is the same. If the two methods play the same role and their order matters, an error is signaled. This happens as part of the qualifier pattern matching in define-method-combination.
http://www.lispworks.com/documentation/HyperSpec/Body/m_defi_4.htm
So instead of using qualifier patterns we should use qualifier predicates. They are not a subject of the above paragraph because of its last sentence (there is also an example in the spec that has multiple methods with a predicate). So instead of
(define-method-combination hooker ()
(... (hook-before (:before*)) ...) ...)
the method combination should use:
(defun hook-before-p (method-qualifier)
(typep method-qualifier '(cons (eql :before) (cons t null))))
(define-method-combination hooker ()
(... (hook-before hook-before-p) ...) ...)
and other "hook" groups should also use predicates.
Another thing worth mentioning is that both ECL and SBCL addressed issues with the qualifier pattern matching and :arguments since the publication of this blog post.
Introduction
Method combinations are used to compute the effective method for a generic function. An effective method is a body of the generic function that combines a set of applicable methods computed based on the invocation arguments.
For example we may have a function responsible for reporting the object status and each method focuses on a different aspect of the object. In that case we may want to append all results into a list:
(defgeneric status (object)
(:method-combination append))
(defclass base-car ()
((engine-status :initarg :engine :accessor engine-status)
(wheels-status :initarg :wheels :accessor wheels-status)
(fuel-level :initarg :fuel :accessor fuel-level))
(:default-initargs :engine 'ok :wheels 'ok :fuel 'full))
(defmethod status append ((object base-car))
(list :engine (engine-status object)
:wheels (wheels-status object)
:fuel (fuel-level object)))
(defclass premium-car (base-car)
((gps-status :initarg :gps :accessor gps-status)
(nitro-level :initarg :nitro :accessor nitro-level))
(:default-initargs :gps 'no-signal :nitro 'low))
(defmethod status append ((object premium-car))
(list :gps (gps-status object)
:nitro (nitro-level object)))
CL-USER> (status (make-instance 'premium-car))
(:GPS NO-SIGNAL :NITRO LOW :ENGINE OK :WHEELS OK :FUEL FULL)
CL-USER> (status (make-instance 'base-car))
(:ENGINE OK :WHEELS OK :FUEL FULL)
The effective method may look like this:
(append (call-method #<method status-for-premium-car>)
(call-method #<method status-for-base-car> ))
Note that append
is a function so all methods are called. It is possible to use other operators (for example a macro and
) and then the invocation of particular methods may be conditional:
(and (call-method #<method can-repair-p-for-premium-car>)
(call-method #<method can-repair-p-for-base-car> ))
Defining method combinations - the short form
The short form allows us to define a method combination in the spirit of the previous example:
(OPERATOR (call-method #<m1>)
(call-method #<m2>)
...)
For example we may want to return as the second value the count of odd numbers:
(defun sum-and-count-odd (&rest args)
(values (reduce #'+ args)
(count-if #'oddp args)))
(define-method-combination sum-and-count-odd)
(defclass a () ())
(defclass b (a) ())
(defclass c (b) ())
(defgeneric num (o)
(:method-combination sum-and-count-odd)
(:method sum-and-count-odd ((o a)) 1)
(:method sum-and-count-odd ((o b)) 2)
(:method sum-and-count-odd ((o c)) 3)
(:method :around ((o c))
(print "haa!")
(call-next-method)))
(num (make-instance 'b)) ;; (values 3 1)
(num (make-instance 'c)) ;; (values 6 2)
Note that the short form supports also around methods. It is also important to note that effective methods are cached, that is unless the generic function or the method combination changes, the computation of the effective method may be called only once per the set of effective methods.
Admittedly these examples are not very useful. Usually we operate on data stored in instances and this is not a good abstraction to achieve that. Method combinations are useful to control method invocations and their results. Here is another example:
(defmacro majority-vote (&rest method-calls)
(let* ((num-methods (length method-calls))
(tie-methods (/ num-methods 2)))
`(prog ((yes 0) (no 0))
,@(loop for invocation in method-calls
append `((if ,invocation
(incf yes)
(incf no))
(cond
((> yes ,tie-methods)
(return (values t yes no)))
((> no ,tie-methods)
(return (values nil yes no))))))
(error "we have a tie! ~d ~d" yes no))))
(define-method-combination majority-vote)
(defclass a () ())
(defclass b (a) ())
(defclass c (b) ())
(defclass d (c) ())
(defgeneric foo (object param)
(:method-combination majority-vote)
(:method majority-vote ((o a) param) nil)
(:method majority-vote ((o b) param) t)
(:method majority-vote ((o c) param) t)
(:method majority-vote ((o d) param) nil))
(foo (make-instance 'a) :whatever) ; (values nil 0 1)
(foo (make-instance 'b) :whatever) ; #<error tie 1 1>
(foo (make-instance 'c) :whatever) ; (values t 2 0)
(foo (make-instance 'd) :whatever) ; #<error tie 2 2>
Defining method combinations - the long form
The long form is much more interesting. It allows us to specify numerous qualifiers and handle methods without any qualifiers at all.
The Hooker
Here we will define a method combination that allows us to define named hooks that are invoked before or after the method. It is possible to have any number of hooks for the same set of arguments (something we can't achieve with the standard :before
and :after
auxiliary methods):
(defun combine-auxiliary-methods (primary around before after)
(labels ((call-primary ()
`(call-method ,(first primary) ,(rest primary)))
(call-methods (methods)
(mapcar (lambda (method)
`(call-method ,method))
methods))
(wrap-after (the-form)
(if after
`(multiple-value-prog1 ,the-form
,@(call-methods after))
the-form))
(wrap-before (the-form)
(if before
`(progn
,@(call-methods before)
,the-form)
the-form))
(wrap-around (the-form)
(if around
`(call-method ,(first around)
(,@(rest around)
(make-method ,the-form)))
the-form)))
(wrap-around (wrap-after (wrap-before (call-primary))))))
(define-method-combination hooker ()
((normal-before (:before))
(normal-after (:after)
:order :most-specific-last)
(normal-around (:around))
(hook-before (:before *))
(hook-after (:after *)
:order :most-specific-last)
(hook-around (:around *))
(primary () :required t))
(let ((around (append hook-around normal-around))
(before (append hook-before normal-before))
(after (append normal-after hook-after)))
(combine-auxiliary-methods primary around before after)))
With this we may define a generic function and associated methods similar to other functions with an extra feature - we may provide named :before
, :after
and :around
methods. Named auxiliary methods take a precedence over unnamed ones. Only after that the specialization is considered. There is one caveat - PCL
-derived CLOS
implementations (clasp
, cmucl
, ecl
, sbcl
) currently ([2023-01-18 śro]) have a bug preventing wildcard qualifier pattern symbol *
from working. So better download ccl
or wait for fixes. Here's an example for using it:
;;; The protocol.
(defgeneric note-buffer-dimensions-changed (buffer w h)
(:method (b w h)
(declare (ignore b w h))
nil))
(defgeneric change-dimensions (buffer w h)
(:method-combination hooker))
;;; The implementation of unspecialized methods.
(defmethod change-dimensions :after (buffer w h)
(note-buffer-dimensions-changed buffer w h))
;;; The stanard class.
(defclass buffer ()
((w :initform 0 :accessor w)
(h :initform 0 :accessor h)))
;;; The implementation for the standard class.
(defmethod change-dimensions ((buffer buffer) w h)
(print "... Changing the buffer size ...")
(setf (values (w buffer) (h buffer))
(values w h)))
(defmethod note-buffer-dimensions-changed ((buffer buffer) w h)
(declare (ignore buffer w h))
(print "... Resizing the viewport ..."))
;;; Some dubious-quality third-party code that doesn't want to interfere with
;;; methods defined by the implementation.
(defmethod change-dimensions :after system (buffer w h)
(print `(log :something-changed ,buffer ,w ,h)))
(defmethod change-dimensions :after my-hook ((buffer buffer) w h)
(print `(send-email! :me ,buffer ,w ,h)))
CL-USER> (defvar *buffer* (make-instance 'buffer))
*BUFFER*
CL-USER> (change-dimensions *buffer* 10 30)
"... Changing the buffer size ..."
"... Resizing the viewport ..."
(LOG :SOMETHING-CHANGED #<BUFFER #x30200088220D> 10 30)
(SEND-EMAIL! :ME #<BUFFER #x30200088220D> 10 30)
10
30
The Memoizer
Another example (this time it will work on all implementations) is optional memoization of the function invocation. If we define a method with the qualifier :memoize
then the result will be cached depending on arguments. The method combination allows also "normal" auxiliary functions by reusing the function combine-auxiliary-methods
from the previous section.
The function ensure-memoized-result
accepts the following arguments:
test
: compare generations
memo
: a form that returns the current generation
cache-key
: a list composed of a generic function and its arguments
form
: a form implementing the method to be called
When the current generation is nil
that means that caching is disabled and we remove the result from the cache. Otherwise we use the test
to compare the generation of a cached value and the current one - if they are the same, then the cached value is returned. Otherwise it is returned.
(defparameter *memo* (make-hash-table :test #'equal))
(defun ensure-memoized-result (test memo cache-key form)
`(let ((new-generation ,memo))
(if (null new-generation)
(progn
(remhash ,cache-key *memo*)
,form)
(destructuring-bind (old-generation . cached-result)
(gethash ,cache-key *memo* '(nil))
(apply #'values
(if (,test old-generation new-generation)
cached-result
(rest
(setf (gethash ,cache-key *memo*)
(list* new-generation (multiple-value-list ,form))))))))))
The method with the qualifier :memoize
is used to compute the current generation key. When there is no such method then the function behaves as if the standard method combination is used. The method combination accepts a single argument test, so it is possible to define different predicates for deciding whether the cache is up-to-date or not.
(define-method-combination memoizer (test)
((before (:before))
(after (:after) :order :most-specific-last)
(around (:around))
(memoize (:memoize))
(primary () :required t))
(:arguments &whole args)
(:generic-function function)
(let ((form (combine-auxiliary-methods primary around before after))
(memo `(call-method ,(first memoize) ,(rest memoize)))
(ckey `(list* ,function ,args)))
(if memoize
(ensure-memoized-result test memo ckey form)
form)))
Now let's define a function with "our" method combination. We will use a counter to verify that values are indeed cached.
(defparameter *counter* 0)
(defgeneric test-function (arg &optional opt)
(:method-combination memoizer eql))
(defmethod test-function ((arg integer) &optional opt)
(list* `(:counter ,(incf *counter*)) arg opt))
CL-USER> (test-function 42)
((:COUNTER 1) 42)
CL-USER> (test-function 42)
((:COUNTER 2) 42)
CL-USER> (defmethod test-function :memoize ((arg integer) &optional (cache t))
(and cache :gen-z))
#<STANDARD-METHOD TEST-FUNCTION :MEMOIZE (INTEGER)>
CL-USER> (test-function 42)
((:COUNTER 3) 42)
CL-USER> (test-function 42)
((:COUNTER 3) 42)
CL-USER> (test-function 42 nil)
((:COUNTER 4) 42)
CL-USER> (test-function 42)
((:COUNTER 3) 42)
CL-USER> (test-function 43)
((:COUNTER 5) 43)
CL-USER> (test-function 43)
((:COUNTER 5) 43)
CL-USER> (defmethod test-function :memoize ((arg (eql 43)) &optional (cache t))
(and cache :gen-x))
#<STANDARD-METHOD TEST-FUNCTION :MEMOIZE ((EQL 43))>
CL-USER> (test-function 43)
((:COUNTER 6) 43)
CL-USER> (test-function 43)
((:COUNTER 6) 43)
CL-USER> (test-function 42)
((:COUNTER 3) 42)
Conclusions
Method combinations are a feature that is often overlooked but give a great deal of control over the generic function invocation. The fact that ccl
is the only implementation from a few that I've tried which got method combinations "right" doesn't surprise me - I've always had an impression that it shines in many unexpected places.
18 Jan 2023 12:00am GMT
16 Jan 2023
I was working on the terminal output for a Common Lisp logger, and I realized that SLIME does not interpret ANSI escape sequences.
This is not the end of the world, but having at least colors would be nice. Fortunately there is a library to do just that.
First let us install the package, here using use-package
and straight.el
.
(use-package slime-repl-ansi-color
:straight t)
While in theory we are supposed to just add slime-repl-ansi-color
to slime-contribs
, it did not work for me, and I add to enable the minor mode manually.
If you already have a SLIME REPL hook, simply add (slime-repl-ansi-color-mode 1)
. If not, write an initialization function, and add it to the SLIME REPL initialization hook:
(defun g-init-slime-repl-mode ()
(slime-repl-ansi-color-mode 1))
(add-hook 'slime-repl-mode-hook 'g-init-slime-repl-mode)
To test that it works as intended, fire up SLIME and print a simple message using ANSI escape sequences:
(let ((escape (code-char 27)))
(format t "~C[1;33mHello world!~C[0m~%" escape escape))
While it is tempting to use the #\Esc
character, it is part of the Common Lisp standard; therefore we use CODE-CHAR
to obtain it from its ASCII numeric value. We use two escape sequences, the first one to set the bold flag and foreground color, and the second one to reset display status.
If everything works well, should you see a nice bold yellow message:

16 Jan 2023 6:00pm GMT
12 Jan 2023
Knex recently released a new version this week (2.4.0). Before this version, Knex had a pretty scary SQL injection. Knex currently has 1.3 million weekly downloads and is quite popular.
The security bug is probably one of the worst SQL injections I've seen in recent memory, especially considering the scope and popularity.
If you want to get straight to the details:
My understanding of this bug
If I understand the vulnerability correctly, I feel this can impact a very large number of sites using Knex. Even more so if you use Express.
I'll try to explain through a simple example. Say, you have MySQL table structured like this:
CREATE TABLE `users` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
)
And you have a query that does a SELECT
using Knex:
const lookupId = 2;
const result = await knex('users')
.select(['id', 'name'])
.where({
id: lookupId
});
You'd expect the query to end up roughly like this
SELECT `id`, `name` FROM `users` WHERE `id` = 2
The issue is when the user controls the value of lookupId
. If somehow they can turn this into an object like this:
const lookupId = {
name: 'foo'
}
You might expect an error from Knex, but instead it generates the following query:
SELECT `id`, `name` FROM `users` WHERE `id` = `name` = 'foo'
This query is not invalid. I don't fully understand fully understand MySQL's behavior, but it causes the WHERE clause to be ignored and the result is equivalent to:
Truncated by Planet PHP, read more at the original (another 8765 bytes)
12 Jan 2023 9:31pm GMT
10 Jan 2023
Xdebug Update: December 2022
London, UK
Tuesday, January 10th 2023, 09:06 GMT
In this monthly update I explain what happened with Xdebug development in this past month. These are normally published on the first Tuesday on or after the 5th of each month.
Patreon and GitHub supporters will get it earlier, around the first of each month.
You can become a patron or support me through GitHub Sponsors. I am currently 45% towards my $2,500 per month goal. If you are leading a team or company, then it is also possible to support Xdebug through a subscription.
In the last month, I spend 25 hours on Xdebug, with 21 hours funded. Sponsorships are continuing to decline, which makes it harder for me to dedicate time for maintenance and development.
Xdebug 3.2
Xdebug 3.2.0 got released at the start of December, to coincide with the release of PHP 8.2 which it supports, after fixing a last crash with code coverage. Since then a few bugs were reported, which I have started to triage. A particularly complicated one seems to revolve on Windows with PHP loaded in Apache, where suddenly all modes are turned on without them having been activated through the xdebug.mode setting. This is a complicated issue that I hope to figure out and fix during January, resulting in the first patch release later this month.
Plans for the Year
Beyond that, I have spend some time away from the computer in the Dutch country side to recharge my battery. I hope to focus on redoing the profiler this year, as well as getting the "recorder" feature to a releasable state.
Smaller feature wise, I hope to implement file/path mappings on the Xdebug side to aide the debugging of generated files containing PHP code.
Xdebug Cloud
Xdebug Cloud is the Proxy As A Service platform to allow for debugging in more scenarios, where it is hard, or impossible, to have Xdebug make a connection to the IDE. It is continuing to operate as Beta release.
Packages start at £49/month, and I have recently introduced a package for larger companies. This has a larger initial set of tokens, and discounted extra tokens.
If you want to be kept up to date with Xdebug Cloud, please sign up to the mailinglist, which I will use to send out an update not more than once a month.
Xdebug Videos
I have published two new videos:
I have continued writing scripts for videos about Xdebug 3.2's features, and am also intending to make a video about "Running Xdebug in Production", as well as one on using the updated "xdebug.client_discovery_header" feature (from Xdebug 3.1).
You can find all previous videos on my YouTube channel.
Business Supporter Scheme and Funding
In December, no new business supporters signed up.
If you, or your company, would also like to support Xdebug, head over to the support page!
Besides business support, I also maintain a Patreon page, a profile on GitHub sponsors, as well as an OpenCollective organisation.
10 Jan 2023 9:06am GMT
09 Jan 2023
Or: Why does DYLD_LIBRARY_PATH
keep disappearing!?
09 Jan 2023 8:00am GMT
06 Dec 2022

Good news: the second and last release candidate of Plone 6 has arrived! The release manager for this version is Maurits van Rees (https://github.com/mauritsvanrees).
Thank you to everyone involved!
Read more about the upcoming Plone 6 and Plone 6 FAQ.
Highlights
Major changes since 6.0.0rc1:
- None really. Lots of packages have gotten a final release, losing their alpha, beta or release candidate markers.
We are in a bugfix-only mode. An upgrade from rc1 to rc2 should be painless and is recommended for everyone.
The default frontend for Plone 6 is Volto. Latest release is 16.3.0 2. See the changelog 1.
Note that this is a JavaScript frontend that you need to run in a separate process with NodeJS.
The ClassicUI is still available when you only run the Python process.
This release supports Python 3.8, 3.9, 3.10, and 3.11.
For installation instructions, see the documentation.
This documentation is under development, but this should get you up and running. No worries.
We expect to switch https://docs.plone.org to show the Plone 6 documentation sometime this week.
Unless blocking issues are found that require more work, we expect to release Plone 6.0.0 final on December 12, 2022.
If you find any issues, blocking or not, please report them in the main issue tracker.
Try Plone 6!
For installation instructions, see the documentation.
See Plone 6 in action at https://6.demo.plone.org/
Read more at the community forum:
https://community.plone.org/t/plone-6-0-0rc2-released/15945
06 Dec 2022 3:45pm GMT
27 Nov 2022

The Plone community is happy to announce that Volto 16 is ready and shipped! This is the final release for the upcoming Plone 6 and a major achievement from the community. Thank you everyone involved!
Volto is Plone's snappy, modern React front end powered by the RestAPI, and the default for Plone 6.
Volto 16
Volto 16 contains tons of new features, bugfixes and tweaks. Here is a sneak peak to some of them, and you can find the full release notes in GitHub: https://github.com/plone/volto/releases/tag/16.0.0
And to get the latest version go to https://github.com/plone/volto/releases/tag/16.2.0
Top features in Volto 16
- The new Slate editor - improved inline editing and more possibilities
- Content rules - a whole engine for automating processes based on events on the site
- Undo - site admins can see and undo transactions
- Bugfixes and tweaks - it is shiny and polished
- New technology -
More feature highlights

- Added default placeholder for videos to embed them more lightly @giuliaghisini
- Added new Block Style Wrapper. This implementation is marked as experimental during Volto 16 alpha period. The components, API and the styling are subject to change without issuing a breaking change. You can start using it in your projects and add-ons, but taking this into account. See documentation for more information. @sneridagh
- Add default widget views for all type of fields and improve the DefaultView @ionlizarazu
- added configurable identifier field for password reset in config.js. @giuliaghisini
- Add
expandToBackendURL
helper @sneridagh
- added 'show total results' option in Search block configuration. @giuliaghisini
- Added viewableInBrowserObjects setting to use in alternative to downloadableObjects, if you want to view file in browser intstead downloading. @giuliaghisini
- Disable already chosen criteria in querystring widget @kreafox
- Added X-Forwarded-* headers to superagent requests. @mamico
- Updated Brazilian Portuguese translation @ericof
- Forward
HTTP Range
headers to the backend. @mamico
- Add default value to color picker, if
default
is present in the widget schema. @sneridagh
- Inject the classnames of the StyleWrapper into the main edit wrapper (it was wrapping directly the Edit component before). This way, the flexibility is bigger and you can act upon the whole edit container and artifacts (handlers, etc) @sneridagh
- Refactor image block: make it schema extensible @nileshgulia1 @sneridagh
- Add control panel via config.settings @ksuess #3426
- Add noindex metadata tag @steffenri
- Adding Schema for Maps Block in Sidebar @iRohitSingh
- Add a Pluggable to the sharing page @JeffersonBledsoe #3372
- Add listing variation schemaEnhancer to the search block schema @ionlizarazu
- And much much more at https://github.com/plone/volto/releases/tag/16.0.0
Breaking changes 
- Deprecate NodeJS 12 since it's out of LTS since April 30, 2022 @sneridagh
- Move all cypress actions to the main
Makefile
, providing better meaningful names. Remove them from package.json
script section. @sneridagh
- Remove
div
as default if as
prop from RenderBlocks
. Now the default is a React.Fragment
instead. This could lead to CSS inconsistencies if taken this div into account, specially if used in custom add-ons without. In order to avoid them, set the as
property always in your add-ons. @sneridagh
- Removed
date-fns
from dependencies, this was in the build because Cypress
depended on it. After the Cypress
upgrade it no longer depends on it. If your project still depends on it, add it as a dependency of your project. @sneridagh
- Removed all usage of
date-fns
from core. @sneridagh
- Rename
src/components/manage/Widgets/ColorPicker.jsx
component to src/components/manage/Widgets/ColorPickerWidget.jsx
@sneridagh
- Remove the style wrapper around the
<Block />
component in Edit mode, moved to the main edit wrapper @sneridagh
- New
cloneDeepSchema
helper @sneridagh
- Action
listUsers
to be called with Object. Distinguish between search for id or search for fullname, email, username @ksuess
- Integrate volto-state add-on. @tiberiuichim @razvanMiu @eea
- Staticize Poppins font to be compliant with EU privacy. Import from GoogleFont is disabled in site.variables. @giuliaghisini
- Remove the
callout
button (the one with the megaphone icon) from the slate toolbar since it has the same styling as blockquote
. If you need it anyway, you can bring it back in your addon. @sneridagh
- Using volto-slate Headline / Subheadline buttons strips all elements in the selection @tiberiuichim
- Use
Cypress
10.3.0 (migrate from 9.x.x). Cypress 10 has some interesting goodies, being the native support of Apple Silicon Computers the main of it. See https://docs.voltocms.com/upgrade-guide/ for more information. @sneridagh
- The complete configuration registry is passed to the add-ons and the project configuration pipeline @sneridagh
- And much much more at https://github.com/plone/volto/releases/tag/16.0.0
Bugfix
- Fix Search page visit crashes /contents view @dobri1408
- Fix sidebar full size bottom opacity on edit page when sidebar is collapsed @ichim-david
- Fix toolbar bottom opacity on edit page when toolbar is collapsed @ichim-david
- Fix content view regression, height issue @danielamormocea
- Fixed secure cookie option. @giuliaghisini
- Changed addon order in addon controlpanel to mimic Classic UI @erral
- Fixed error when loading content in a language for which a Volto translation is not available. @davisagli
- Fix for clipped dropdown menus when the table has few or no records in Contents view @mihaislobozeanu
- fixed view video list from youtube in Video block. @giuliaghisini
- Fixed ICS URL in event view in seamless mode @sneridagh
- Fix
withStylingSchemaEnhancer
enhancer mechanism @sneridagh
- Add correct query parameters to the redirect @robgietema
- Fix RenderBlocks: path @ksuess
- Fix field id creation in dexterity control panel to have slugified id @erral
- Changed to get intl.locale always from state @ionlizarazu
- Fix regression, compound lang names (eg.
pt-BR
) no longer working @sneridagh
- fix TokenWidget choices when editing a recently created content. @giuliaghisini
- Fix color picker defaults implementation #2 @sneridagh
- Enable default color in
backgroundColor
default StyleWrapper field which wasn't sync with the default value setting @sneridagh
- Fix Block style wrapper: Cannot read properties of undefined (reading 'toString') @avoinea #3410
- fix schema when content contains lock informations. @giuliaghisini
- Don't render junk when no facets are added to the search block @tiberiuichim
- Fix visibility of toolbar workflow dropdown for more states as fitting in .toolbar-content. @ksuess
- Fix the video block for anonymous user @iFlameing
- And much much more at https://github.com/plone/volto/releases/tag/16.0.0
Internal
- Improve Cypress integration, using Cypress official Github Action. Improve some flaky tests that showed up, and were known as problematic. Refactor and rename all the Github actions giving them meaningful names, and group them by type. Enable Cypress Dashboard for Volto. @sneridagh
- Stop using
xmlrpc
library for issuing the setup/teardown in core, use a cy.request
instead. @sneridagh
- Added Cypress environment variables for adjusting the backend URL of commands @JeffersonBledsoe #3271
- Reintroduce Plone 6 acceptance tests using the latests
plone.app.robotframework
2.0.0a6 specific Volto fixture. @datakurre @ericof @sneridagh
- Upgrade all tests to use
plone.app.robotframework
2.0.0a6 @sneridagh
- Upgrade Sentry to latest version because of #3346 @sneridagh
- Update
Cypress
to version 9.6.1 @sneridagh
- Missing change from the last breaking change (Remove the style wrapper around the
<Block />
component in Edit mode, moved to the main edit wrapper). Now, really move it to the main edit wrapper @sneridagh
- Fix warning because missing key in
VersionOverview
component @sneridagh
- Mock all loadable libraries. @mamico
- And much much more at https://github.com/plone/volto/releases/tag/16.0.0
Documentation
- Move Cypress documentation from
README.md
to the docs. Improve the docs with the new Makefile
commands.
- Improve English grammar and syntax in backend docs. @stevepiercy
- Fix JSX syntax highlighting. Remove duplicate heading. @stevepiercy
- fix make task
docs-linkcheckbroken
if grep has exit code 1 (no lines found)
- Updated simple.md @MdSahil-oss
- Fix indentation in nginx configuration in simple.md @stevepiercy
- Remove sphinx_sitemap configuration because Volto's docs are now imported into the main docs, making this setting unnecessary. @stevepiercy
- Set the ogp_site_url to main docs, instead of training. @stevepiercy
aria-*
attributes are now parsed correctly by jsx-lexer 2.0. @stevepiercy
- volto-slate documentation @nileshgulia1
- And much much more at https://github.com/plone/volto/releases/tag/16.0.0
Thank you!
We would like to thank all the people involved in creating Volto 16. Over 40 people have committed code, documentation and other effort for this. It is amazing how much we were able to accomplish as a community, during the last months.
What's Next - Plone 6 final release
Where do we go from here? Plone 6! Right now, the only major feature missing were content rules and the new Slate editor, and both were included in Volto 16.
So the work is not over yet. We still need helping hands and contributors to continue the effort to make Plone 6 a reality. Everybody is welcome!
Try Plone 6 today
Feel free to try out Plone 6 with Volto 16:
27 Nov 2022 5:40pm GMT

Good news: the first release candidate of Plone 6 has arrived! The release manager for this version is Maurits van Rees (https://github.com/mauritsvanrees).
Thank you to everyone involved!
Read more about the upcoming Plone 6 and Plone 6 FAQ.
Installation
Highlights
Major changes since 6.0.0b3:
-
Various packages: updates to support Python 3.11. See below.
-
Zope 5.7: This feature release adds full support for Python 3.11 and a ZPublisher encoder for inputting JSON data.
See the Zope changelog for details.
-
zc.buildout
: After long development this has a final release. We use version 3.0.1, which now works nicely with latest pip (using 22.3.1).
Note that it is usually fine if you use different versions of zc.buildout
, pip
, setuptools
, and wheel
. We just pin versions that we know work at the moment.
-
plone.restapi
:
-
Added @upgrade
endpoint to preview or run an upgrade of a Plone instance.
-
Added @rules
endpoint with GET/POST/DELETE/PATCH.
-
Added link integrity support for slate blocks.
-
plone.scale
: Add support for animated GIFs.
Volto 16 released
The default frontend for Plone 6 is Volto. Latest release is 16.2 and Volto 16 is the final release needed for Plone 6.
https://plone.org/news/2022/volto-16-released
Python compatibility
This release supports Python 3.8, 3.9, 3.10, and 3.11.
Python 3.11.0 was released in October and we are proud to already be able to say Plone supports it! All tests pass.
This is expected to be faster than other Python versions.
Note that not all add-ons may work yet on 3.11, but in most cases the needed changes should be small.
A big thank you for this goes to the Zope part of the Plone community, especially Jens Vagelpohl and Michael Howitz.
Read more on https://plone.org/download/releases/6.0.0rc1
Installation
For installation instructions, see the documentation.
This documentation is under development, but this should get you up and running. No worries.
Help wanted
Plone 6 final needs just the final push! Wondering how you can help?
Plone 6
Plone 6 editing experience combines the robust usability of Plone with a blazingly fast JavaScript frontend

Try Plone 6 Beta!
For installation instructions, see the documentation.
See Plone 6 in action at https://6.demo.plone.org/
Read more at the community forum:
https://community.plone.org/t/plone-6-0-0rc1-released/15885
27 Nov 2022 2:55pm GMT
24 Nov 2022
This is a rather long post as it captures the 13 days of lessons learnt and tips I've been sharing on LinkedIn. Definitely interested to hear other's experiences and thoughts, so do drop me a comment below, if you feel like it.
The content here is predominantly aimed at new managers and leaders as well as new managers of managers, but hopefully others can benefit too.
1. Feedback loops become slower and it takes longer to see the impact of your decisions and actions, which can create self-doubt and insecurity creep
- Ensure you have measurable definition of success in place for yourself and that you refer to it.
- Set clear goal and expectations for what you are focusing on and make sure that you have either reliable qualitative or quantitative way to measure progress and success
- Rock your own feedback and actively seek feedback and don't wait until your performance review time. Be aware that due to the position of authority (depending on environmental/cultural factor as well), the quality and quantity of constructive feedback may decrease.
- Grow your introspective and reflective skills to self-troubleshoot and expand your mindset and perspectives.
- Ensure you have a supporting structure in place, such as a mentor and coach.
2. Context switching increases by factor of N in terms of volume, frequency and types, which can be disorienting and overwhelming
- Learn to identify what brain power and energy types you are using in different contexts and optimize your schedule around that. You may need to grow your self-awareness skills through mindfulness practice (e.g. meditation). Keep experimenting. You may find that meetings work best for you in the morning or maybe that focus time works best for you in the morning and so on.
- Allocate regular focus time for yourself - your brain has limits. Block it off in your diary and guard it like it's a precious stone. Accept that you won't always be able to hold on to all of it as things may crop up, but do your best. You may find that having a bit of quiet time at the start and end of each day will help you prep and digest.
- Do reset your calendar every now and then to defragment as things creep in.
- Companies tend to have a heartbeat and a level of predictability associated with - learn to identify that and use it to your advantage as to how you plan your day and weeks. In a start-up that would be adrenaline pumped heart with low predictability, but as the company gets larger there will be times where certain things happen and activity escalates (e.g. performance reviews, quarterly planning).
- Look for delegation, and thus sponsorship, opportunities at all times.
- Give your brain time to adapt - it's awesome like this.
3. You may feel less part of a team, which will affect your sense of belonging and can leave you feeling lonelier than before
- Accept that the moment you step into a position of authority it changes the relationship dynamics. This is something a new manager will start facing, especially if they are doing the transition in the team where they have been an individual contributor before.
- A bigger step-change for this is becoming manager of managers, so be mindful as you do make that transition.
- Avoid isolating yourself - it will leave you feeling alone with your challenges and increase your stress levels. Instead look to connect with other peers in the company doing the same job and outside (e.g. join meetups and so on).
- Make sure you have someone to talk to with whom you feel safe to share with (mentor, coach)
- Deliberately invest in building better relationships at work
- Take care of yourself outside of work socially and community-wise. It can be easy for work to become the sole source of sense of belonging, which is not a healthy dynamic.
4. The volume of information that you have exposure to may increases dramatically in both depth and breadth, which will feel overwhelming at times
- Your brain will adjust over time and will learn how to filter it and what to capture. Perhaps you will experiment and pick up some tools/techniques in the process.
- Make conscious deliberate decisions about what information you need vs want and why. The temptation to over-consume information to 'stay on top of things' (sense of control) is dangerous, so be strategic about it as a means to be tactical about your limited time, energy and brain capacity.
- Every time you make a step change in leadership reset your expectations and re-review regularly your information needs. Give yourself time and space to figure it out over time.
- Avoid being overly reactive to new information and apply self-control over the urge to explore/act on it unless needed.
- Learn to let go and live in an imperfect world where you can only focus on what's on N things at a time.
- Accept that you will start getting exposed to information that you may not understand fully, so sometimes focus less on the information itself, but the thought processes and approaches behind it. Use coaching and curious questioning. Build trust.
- Develop your people's communication skills, so that information is presented at the right level of detail given the context its needed. Give peers feedback on such.
- Make sure to allocate time and space to give yourself a chance to process and reflect.
- Build a support structure for your self - peer community, coach, mentor. Learn how others are doing things.
5. The general level of uncertainty and ambiguity will rapidly increase which may leave your feeling anxious, scared and out of control
- For new engineering managers it can be a big challenge emotionally, because there is no replacement for the predictability and early validation possible in the software development cycle (write code -> validate it works -> ship it to production). There are also no quick fixes after something goes "live".
- Accept that with every leadership step-change it will feel like uncertainty will increase - in part because it's an entirely new role, but also because there will be more moving pieces and more people involved in the execution.
- Avoid succumbing to the need for control, which is a natural tendency of the anxiety that comes and accept that you will simply not ever be in control. Adding more process, diving deeper into details to assure yourself is common action, but is a good recipe for burnout and dissatisfaction on the other side of it.
- Avoid over-thinking and looking for perfection in decisions.
- Accept that thing will go wrong - it's simply a matter of fact. The best learnings come from failure (do we even learn anything when we succeed?)
- Focus on iterating on your ability to set clear expectations, communicate constrains.
- Learn to build trust, to let go and to build the right framework for you to have a "good enough" confidence and comfort with things, without over-indexing on reactivity due to the emotional impact of uncertainty.
- When you feel out of control, take a deep breath and re-focus on what you are in control of and deliberately let go of what you can't. Don't bottle that tension and stress up.
- Try some mindfulness practice to build emotional resiliency in what may seem like high pressure situations.
- Get someone to talk to - a coach, a mentor, peers. The worst thing you can do for yourself is be overwhelmed alone.
6. The mistakes that you make will have more impact than before, which can increase the level of fear, anxiety and internal pressure to get things "right"
- Watch out for the fear of failure causing anxiety, vulnerability, and behaviour such as perfectionism, overthinking, etc. Improve your mindfulness skills to pick it up.
- Accept that you will make mistakes. It's not a question of if, but more of a question of when. At the end of the day, we are all human and as such we are flawed in many ways, so mistakes are part of our nature.
- Accept that you will fail. It's a question of when, not if. Failure is hard emotionally, but is the best source of learning. Do we even learn from success?
- Identify your tolerance for acceptable risk and play around with stretching it.
- Do accept and acknowledge all the uncomfortable feelings that come with this - it will help build your tolerance, thus emotional resilience to them.
- Sanity check your emotions with some introspective questions, such as "What is the worst that will happen?"
- Swich from "What if " type of thinking to "How will I handle", but try to avoid getting into overthinking spirals. As you will learn, with time, there is no "right decision" - you can simply optimize for what you know at the time, hope for the best and believe that you will be able to deal with the consequences.
- Avoid working in toxic company culture, where failure and mistake is a dirty word.
- Use data to evaluate options and decisions.
- Don't let your ego (bruised or not) to get in the way of recognising mistakes and failure. Have you seen mistakes being swept under the carpet by leaders before? It's important to be honest, transparent and exercise humility and vulnerability when it happens and focus on the learnings and moving forward. Be real.
- Build yourself a support structure around you (manager, mentor, peers)
7. Your sense of achievement and impact may take a hit, which can create dissatisfaction creep and can affect your confidence.
- This is very relevant for new engineering managers who are transitioning from doing to enabling/supporting/empowering/facilitating/etc. This is because up until this point the sense of achievement is likely based (and measured) on direct impact made through output (e.g. code), whereas now the impact be less indirect and there will be a sense of lack of be output "to show for it".
- This can be an even harder transition, when a manager becomes a manager of managers and thus steps out of the team that is delivering the impact.
- It's normal - it's an adjustment of how you measure you worth and value-add as part of the role transition you are going through. It can take time as it's a mindset shift and your brain will need time to rewire.
- Re-think and redefine what you see as "win" and "impact" for yourself. Train your brain to start notice even the smallest of wins. Be your own cheerleader.
- Avoid self-lowering thinking such as "I am not being useful or not adding value". There might be times where indeed you are not adding value to your teams as they are self-sufficient, so be mindful and aware when to refocus your time between types of focus.
- Accept that feedback loops are longer and thus it may take time to see the impact of your actions, so aim to set yourself measurable goals and get regular feedback.
- Watch out for your need for creativity and keeping your creative self fulfilled too. This will affect different people at different intensity. Find something 'yours' and focus on it, when you have time. Alternatively look to rebalance outside of work.
8. Your sense of expertise will erode and morph over time, which can challenge your sense of competency and result imposter syndrome
- It's important to acknowledge that - the sooner the better. Every time you make a step change in leadership you are going into a new role. And surprise, surprise the goal is not to be an expert in your past role any more, so watch out not to act like one.
- As you make step changes up the leadership ladder, some of your powers (e.g. 'knowledge') will diminish, but some others will grow (e.g. influencing). However, there may be a temporary period where you feel the disbalance and it may be frustrating until you hit the rebalancing sweet spot.
- Managing someone in a role that you were very recently (e..g managing a manager when you were a manager recently) can trigger all sorts of insecurities if you don't focus on nurturing your growth mindset. For example you may feel inadequate because you suddenly realize the way you did something before was not very good when you compare yourself/your approach to someone you manage. But, actually that's awesome - you have just learnt something new, but also identified someone that's very good at something that you can lean on. It's all about perspectives. Also in general comparing yourself with others is no good anyway, so avoid in general.
- Watch out for assuming that you should have a right answer and even an answer to questions that hit you by direct reports. You can't possibly have all the answers and assuming this so will erode your confidence and competency perception, which in turn will fill you with guilt and voila - imposter syndrome. Build some coaching skills and find mentors for your direct reports for areas they need, where you can't support them directly.
- Be humble and learn. Ego is the enemy here.
- If you care about this, a wonderful way to maintain some level of expertise is to learn from others and the output of others in the company and outside (e.g. system designs/RFC that are being produced by teams). Asking lots of questions in a curious way and being upfront what you want to get out of it (e.g. not interrogating/challenging) can be helpful too. Going to conferences and meetups is another way.
9. Having an increased scope of accountability can put more internal and external pressure, increasing your stress levels
- Your emotional resilience will build up over time, but it's absolutely critical to take good care of yourself at all times and find ways to cope with stress, anxiety, etc.
- Focus on growing people internally and hiring so that you can delegate and grow other leaders, whilst sharing the load to create sustainability
- Focus on improving your expectation management, communication, time management, prioritization, delegation skills.
- There are various tools out there that can help you evaluate your accountabilities and responsibilities and evaluate where the priority of your energy-spent should be. Ask your peers, your manager for opinions as well, where is your time and energy best spent as you may end up making the wrong assumptions.
- Learn to say no constructively, when needed - it's a skill.
- Find a mentor and a coach to support you
10. Supporting (and working with) an increased number of people (direct reports, skip-level reports, etc) will have a toll on you emotionally
- Your emotional resilience will build up over time naturally as you get exposed to more scenarios and situations, but it's super duper mega important to take care of yourself meanwhile. Whilst it's easy to say "take care of yourself", it can be harder to achieve as leadership can put you in a new place in life and how to do that may be non-obvious.
- Coaching and mentoring skills can help you turn what would be situations ending up with emotional baggage to situations, which end up with no baggage and positive forward momentum.
- Build self-awareness (e.g. through mindfulness practice and skill building) skills to help you improve your Emotional Intelligence and help you regulate and manage your emotional state better.
- Build self-troubleshooting skills, such as introspection, reflective writing to help you train your brain and build a mindset of seeing things the same experience from different perspectives and angles.
- Be clear with yourself what your values are as this will help you identify and acknowledge internal (in yourself) and external (with others) emotional conflict and thus work with it.
- Get a coach and a mentor. Don't shy away from working on a deeper level, if needed, with a psychologist/psychotherapy professional as well - working with other people can be a great way to retrigger any relational or other traumas, or simply old unresolved experiences from your past whether you are aware of it or not.
11. It can be hard to say no and/or disappoint people
- Hard truth of leadership is that you will not liked by everyone and your job is not to please everyone, so the sooner you get comfortable with that - the better.
- Avoid taking ownership ownership or responsibility for the emotional responses of people (e.g. disappointment, frustration, dissatisfaction) as this will lead to unnecessary sticky guilt and feeling bad about stuff (and associated fear of letting them down due to ownership taken). Do maintain a curious mindset and perhaps help them reframe and evaluate things for themselves from different perspectives.
- Try to reframe personalization thinking ("I am disappointing them") to de-personalized (the situation, circumstance, decisions and outcomes thereof. And no - I am not suggesting you do that when you need to own up to a mistake you've made, which is often people that don't own their mistakes do, which in turn leads to double the erosion of trust.
- Never leave space for assumptions (for both yourself and them) - be honest and direct, even if very uncomfortable. Learn to be uncomfortable, accept it and cherish it - it means you are growing emotionally.
- Don't internalize organizational limitations (aka circumstantial/situational limitations), which are negatively impacting people, as a personal failure (e.g. redundancies, teams becoming anaemic due to attrition, etc). Identify what's within your control and influence and what isn't as you don't want to get sticky feelings of powerlessness/disempowerment, which will unnecessarily affect your confidence.
- Consider that what on the surface may seem negative, can actually be very positive when looked from different angles. E.g. delivering uncomfortable constructive feedback that may affect the other person emotionally may be tough, but it will be helpful for their growth. Letting go someone from a team may be helpful for the team and for them to find a better fit place, etc. Not having someone promoted might save them from difficult times if they weren't ready yet.
- Practice and even do some role play with someone if that helps. Saying no and delivering hard messages is a skill.
12. When people you manage leave, it can create self-doubt and insecurity
- Don't overthink it and make assumptions and focus on the facts and what you know and what your data points are telling you (e.g. feedback).
- Remember that people are empowered to make a choice for what's right for them and that's a good thing.
- Focus on the positives - often people will leave, because they have had a chance to learn and grow and have decided to move on to the next thing and use what they have learnt. Or it could be because they have found a place that they will earn more money, get more challenge, and so on and that's good for them. Most of the time someone leaving can be quite positive, even if it creates practical pains
- Focus on having a solid succession plan in place to reduce the practical pain of people leaving.
13. You will be swimming in new and unfamiliar territory a lot of the time and this can make you feel vulnerable
- Vulnerability, when acknowledged, can be very uncomfortable. Even acknowledging it can be hard as it may go against the brain's self-preservation instincts. It may take building some mindfulness skills and reducing your emotional reactivity and increasing your tolerance to the feeling get there.
- Embrace the feelings that come with vulnerability and don't try to run way as that will only result compensatory/defensive behaviours, which are probably the wrong thing to do (e.g. micromanaging, too much process, etc)
- Don't jump too quickly into conclusions and actions - check-in on your motivations.
- Ego is the enemy as it aims to protect our vulnerable self and thus deny us the humble growth mindset.
- Vulnerability is powerful and not a weakness, as when your emotional tolerance to it is built up it can empower you in many different ways.
24 Nov 2022 12:00am GMT