02 Feb 2023

feedLinux Today

How to Install Drupal With Docker on Ubuntu 22.04

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

feedLXer Linux News

useradd Vs. adduser

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

feedLinux Today


The post appeared first on Linux Today.

02 Feb 2023 7:38pm GMT

8 Best Window Managers for Linux

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

feedKernel Planet

Linux Plumbers Conference: Preliminary Dates and Location for LPC2023

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

feedLXer Linux News

Open source Ray 2.2 boosts machine learning observability to help scale services like OpenAI's ChatGPT

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

feedDZone Java Zone

Part I: Creating Custom API Endpoints in Salesforce With Apex

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

feedLXer Linux News

Red Hat gives an ARM up to OpenShift Kubernetes operations

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

feedKernel Planet

Matthew Garrett: Blocking free API access to Twitter doesn't stop abuse

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.

comment count unavailable comments

02 Feb 2023 10:36am GMT

feedDrupal.org aggregator

Evolving Web: How To Install Drupal WxT 4 for Canadian Government Websites

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.

A web page with a “choose language” dropdown menu.

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.

A web page with a module being installed.

6. Enter the site information details.

A web page with empty fields for site registration and site maintenance information.

7. Translations are then automatically imported.

A web page with translation files in the process of being updated.

8. Select the WxT extensions that you plan to use for this particular site. These extensions can be modified as needed.

A web page with a list of selectable extensions with empty clickable boxes.

9. When the WxT extension installation is complete, you'll be redirected to the site homepage as an admin user.


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.

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

feedPlanet Python

Codementor: Roadmap to Functional Programming

roadmap to learn functional programming

02 Feb 2023 8:58am GMT

Justin Mayer: Python Development Environment on MacOS Ventura and Monterey

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.


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:

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:

python --version


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:

  1. installs with root permissions
  2. installs into the system /Library
  3. 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.


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:

require-virtualenv = true

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:

   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.


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

Codementor: Hello World program in C [In series]

read previous post before jumping to this program

02 Feb 2023 5:32am GMT

feedDZone Java Zone

Remote Debugging Dangers and Pitfalls

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

feedDjango community aggregator: Community blog posts

MongoDB - Mark Smith

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

feedDZone Java Zone

How and Why You Should Start Automating DevOps

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

feedDjango community aggregator: Community blog posts

Django Static Files and Templates

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

feedDrupal.org aggregator

CTI Digital: Drupal 10 - What You Need To Know

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

DrupalEasy: DrupalEasy Podcast S14E6 - Ryan Price - How to start a Drupal project the right way

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

Audio transcript

We're using the machine-driven Amazon Transcribe service to provide an audio transcript of this episode.


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

feedDjango community aggregator: Community blog posts

Securing FastAPI with JWT Token-based Authentication

This tutorial shows how to secure a FastAPI application with JWT Token-based Authentication.

01 Feb 2023 4:28am GMT

27 Jan 2023

feedKernel Planet

Matthew Garrett: Further adventures in Apple PKCS#11 land

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.

comment count unavailable comments

27 Jan 2023 11:39pm GMT

24 Jan 2023

feedPlanet PHP

Mastobot: For your Fediverse PHP posting needs

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

feedPlanet Lisp

Nicolas Martyanoff: Custom Common Lisp indentation in Emacs

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)
        (backend-error (cdr ,message)))
        (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)
                     (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)
    (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:

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

feedPlanet Twisted

Glyph Lefkowitz: A Very Silly Program

One of the persistently lesser-known symptoms of ADHD is hyperfocus. It is sometimes quasi-accurately described as a "superpower"1 2, 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:

chroma subsampling carnage

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 subsampling3 on external displays, even when the bitrate of the connection and selected refresh rate support RGB.4 Lots of people have been trying to address this for a literal decade5 6 7 8 9 10 11, 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" panel12, 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:

import os
from Quartz import CGDisplayRegisterReconfigurationCallback, kCGDisplaySetMainFlag, kCGDisplayBeginConfigurationFlag
from ColorSync import CGDisplayCreateUUIDFromDisplayID
from CoreFoundation import CFUUIDCreateString
from AppKit import NSApplicationMain, NSApplicationActivationPolicyAccessory, NSApplication


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:
    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")
            print("HDR toggled.")

print("registered", CGDisplayRegisterReconfigurationCallback(cb, None))


and the linked desubsample is this atrocity, which I substantially cribbed from this helpful example:


use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use scripting additions

tell application "System Settings"
    delay 1
    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
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

feedPlanet Twisted

Hynek Schlawack: Why I Like Nox

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

feedPlanet Lisp

TurtleWare: Method Combinations

Table of Contents

  1. Introduction
  2. Defining method combinations - the short form
  3. Defining method combinations - the long form
    1. The Hooker
    2. The Memoizer
  4. 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.


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.


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))

CL-USER> (status (make-instance 'base-car))

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!")

(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))
                           ((> 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))
           (wrap-after (the-form)
             (if after
                 `(multiple-value-prog1 ,the-form
                    ,@(call-methods after))
           (wrap-before (the-form)
             (if before
                    ,@(call-methods before)
           (wrap-around (the-form)
             (if around
                 `(call-method ,(first around)
                               (,@(rest around)
                                (make-method ,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))

(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))
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) 

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:

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)
           (remhash ,cache-key *memo*)
         (destructuring-bind (old-generation . cached-result)
             (gethash ,cache-key *memo* '(nil))
           (apply #'values
                  (if (,test old-generation new-generation)
                       (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)

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))
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))
CL-USER> (test-function 43)
((:COUNTER 6) 43)
CL-USER> (test-function 43)
((:COUNTER 6) 43)
CL-USER> (test-function 42)
((:COUNTER 3) 42)


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

feedPlanet Lisp

Nicolas Martyanoff: ANSI color rendering in SLIME

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:

ANSI escape sequence rendering

16 Jan 2023 6:00pm GMT

12 Jan 2023

feedPlanet PHP

Knex (with MySQL) had a very scary SQL injection

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` (
  `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'])
    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

feedPlanet PHP

Xdebug Update: December 2022

Xdebug Update: December 2022

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.

Become a Patron!

10 Jan 2023 9:06am GMT

09 Jan 2023

feedPlanet Twisted

Hynek Schlawack: Surprising Consequences of macOS’s Environment Variable Sanitization

Or: Why does DYLD_LIBRARY_PATH keep disappearing!?

09 Jan 2023 8:00am GMT

06 Dec 2022

feedPlanet Plone - Where Developers And Integrators Write

PLONE.ORG: Plone 6 RC 2 Released

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.


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.

Volto frontend

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.

Python compatibility

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.

Final release date: December 12, 2022

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:

06 Dec 2022 3:45pm GMT

27 Nov 2022

feedPlanet Plone - Where Developers And Integrators Write

PLONE.ORG: Volto 16 Released - Ready for Plone 6

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

Volto grid block

  • 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 Content rules demo

  • 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 listUsersto 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
See https://6.dev-docs.plone.org/volto/upgrade-guide/index.html for more information about all the breaking changes.


  • 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


  • 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


  • 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.

See https://6.dev-docs.plone.org/volto/upgrade-guide/index.html for more information.

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

PLONE.ORG: Plone 6 RC 1 Released

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.



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.

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


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

Plone 6 editor

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:

27 Nov 2022 2:55pm GMT

24 Nov 2022


Ivan Zlatev: 13 Emotional Resilience Challenges in Engineering Leadership and Management + Tips

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

2. Context switching increases by factor of N in terms of volume, frequency and types, which can be disorienting and overwhelming

3. You may feel less part of a team, which will affect your sense of belonging and can leave you feeling lonelier than before

4. The volume of information that you have exposure to may increases dramatically in both depth and breadth, which will feel overwhelming at times

5. The general level of uncertainty and ambiguity will rapidly increase which may leave your feeling anxious, scared and out of control

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"

7. Your sense of achievement and impact may take a hit, which can create dissatisfaction creep and can affect your confidence.

8. Your sense of expertise will erode and morph over time, which can challenge your sense of competency and result imposter syndrome

9. Having an increased scope of accountability can put more internal and external pressure, increasing your stress levels

10. Supporting (and working with) an increased number of people (direct reports, skip-level reports, etc) will have a toll on you emotionally

11. It can be hard to say no and/or disappoint people

12. When people you manage leave, it can create self-doubt and insecurity

13. You will be swimming in new and unfamiliar territory a lot of the time and this can make you feel vulnerable

24 Nov 2022 12:00am GMT