<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: pallade</title>
    <description>The latest articles on DEV Community by pallade (@pallade).</description>
    <link>https://dev.to/pallade</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F398379%2F1c38da2c-d8df-44cd-8080-c3fdba494668.jpeg</url>
      <title>DEV Community: pallade</title>
      <link>https://dev.to/pallade</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pallade"/>
    <language>en</language>
    <item>
      <title>Customizing EurKey on Ubuntu</title>
      <dc:creator>pallade</dc:creator>
      <pubDate>Mon, 23 Feb 2026 14:53:57 +0000</pubDate>
      <link>https://dev.to/pallade/customizing-eurkey-on-ubuntu-19lo</link>
      <guid>https://dev.to/pallade/customizing-eurkey-on-ubuntu-19lo</guid>
      <description>&lt;p&gt;This has been tested in Ubuntu 24.04.&lt;/p&gt;

&lt;p&gt;When you need to type in different languages, you can configure your OS to handle their respective layouts. Often, when switching layout, more than just the letters change: punctuation and shifted keys can change too, and you need to continuously adjust (where is the open parenthesis? Shifted 9 or someplace entirely different? What happens if you hit the key right of L? Etc...).&lt;/p&gt;

&lt;p&gt;I recently switched to a ZSA Voyager programmable keyboard, and I had enough of continuously mistyping special characters and furiously switching keyboard layouts. I needed a single layout that would let me type everything! Eurkey could be the answer but... EurKey, despite its name, does not handle all the language spoken in Europe!&lt;/p&gt;

&lt;p&gt;I needed to support Italian, English and German (which are supported) and Polish (which is not). I also do programming.&lt;/p&gt;

&lt;p&gt;My solution was to create a new OS layout, based on Eurkey. This is not portable, but it makes my life easier most of the time.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Situation&lt;/th&gt;
&lt;th&gt;Portability&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;On my own Ubuntu pc&lt;/td&gt;
&lt;td&gt;Everything works&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;On a PC with EurKEY&lt;/td&gt;
&lt;td&gt;Set layout to EurKey. Italian, German and English work, Polish does not work&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;On a PC without EurKey&lt;/td&gt;
&lt;td&gt;Set language to English. Ita, Ger, Pl do not work.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Here is the resulting layout on Oryx, the ZSA configuration utility from ZSA (it should be easy to reproduce on other programmable keyboards): &lt;a href="https://configure.zsa.io/voyager/layouts/ymMez/latest/0" rel="noopener noreferrer"&gt;https://configure.zsa.io/voyager/layouts/ymMez/latest/0&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;First, get the Eurkey layout (print it is you prefer!) and choose a few keys on the AltGr layer you will never use (for me, the first keys on the Q row are fine): you will override them with other keys that you will use. Decide, for each key, what should it produce when hit with AltGr.&lt;/p&gt;

&lt;p&gt;In my case:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Key&lt;/th&gt;
&lt;th&gt;Key + AltGr will produce&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Q&lt;/td&gt;
&lt;td&gt;ą&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;W&lt;/td&gt;
&lt;td&gt;ę&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;E&lt;/td&gt;
&lt;td&gt;ó&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;R&lt;/td&gt;
&lt;td&gt;ć&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;etc...&lt;/td&gt;
&lt;td&gt;...&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Now follow this tutorial (or the newer version linked there): &lt;a href="https://codeaffen.org/2022/02/07/custom-keyboard-layout/" rel="noopener noreferrer"&gt;https://codeaffen.org/2022/02/07/custom-keyboard-layout/&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In /usr/share/X11/xkb/symbols create a new &lt;strong&gt;euspecial&lt;/strong&gt; file and add the following content:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;default partial alphanumeric_keys modifier_keys
xkb_symbols "basic"  {
    include "eu"

    key &amp;lt;AD01&amp;gt;  {[            q,               Q,              aogonek,              Aogonek  ]};
    key &amp;lt;AD02&amp;gt;  {[            w,               W,              eogonek,              Eogonek  ]};
    key &amp;lt;AD03&amp;gt;  {[            e,               E,               oacute,               Oacute  ]};
    key &amp;lt;AD04&amp;gt;  {[            r,               R,               cacute,               Cacute  ]};
    key &amp;lt;AD05&amp;gt;  {[            t,               T,            zabovedot,            Zabovedot  ]};
    key &amp;lt;AD06&amp;gt;  {[            y,               Y,               zacute,               Zacute  ]};
    key &amp;lt;AD07&amp;gt;  {[            u,               U,               nacute,               Nacute  ]};
    key &amp;lt;AD08&amp;gt;  {[            i,               I,              lstroke,              Lstroke  ]};
    key &amp;lt;AD09&amp;gt;  {[            o,               O,               sacute,               Sacute  ]};

    include "level3(ralt_switch)"
};

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This changes the behavior of keys Q, W, E... through O on the first row.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In /usr/share/X11/xkb/rules/evdev.extras.xml, add a new layout section alongside the others, inside the  section:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    &amp;lt;layout&amp;gt;
      &amp;lt;configItem popularity="exotic"&amp;gt;
        &amp;lt;name&amp;gt;euspecial&amp;lt;/name&amp;gt;
        &amp;lt;!-- Keyboard indicator for European layouts --&amp;gt;
        &amp;lt;shortDescription&amp;gt;eu&amp;lt;/shortDescription&amp;gt;
        &amp;lt;description&amp;gt;EurKEY (Special)&amp;lt;/description&amp;gt;
        &amp;lt;countryList&amp;gt;
          &amp;lt;iso3166Id&amp;gt;US&amp;lt;/iso3166Id&amp;gt;
        &amp;lt;/countryList&amp;gt;
        &amp;lt;languageList&amp;gt;
          &amp;lt;iso639Id&amp;gt;cat&amp;lt;/iso639Id&amp;gt;
          &amp;lt;iso639Id&amp;gt;dan&amp;lt;/iso639Id&amp;gt;
          &amp;lt;iso639Id&amp;gt;eng&amp;lt;/iso639Id&amp;gt;
          &amp;lt;iso639Id&amp;gt;est&amp;lt;/iso639Id&amp;gt;
          &amp;lt;iso639Id&amp;gt;fao&amp;lt;/iso639Id&amp;gt;
          &amp;lt;iso639Id&amp;gt;fin&amp;lt;/iso639Id&amp;gt;
          &amp;lt;iso639Id&amp;gt;deu&amp;lt;/iso639Id&amp;gt;
          &amp;lt;iso639Id&amp;gt;ell&amp;lt;/iso639Id&amp;gt;
          &amp;lt;iso639Id&amp;gt;gsw&amp;lt;/iso639Id&amp;gt;
          &amp;lt;iso639Id&amp;gt;ita&amp;lt;/iso639Id&amp;gt;
          &amp;lt;iso639Id&amp;gt;lav&amp;lt;/iso639Id&amp;gt;
          &amp;lt;iso639Id&amp;gt;lit&amp;lt;/iso639Id&amp;gt;
          &amp;lt;iso639Id&amp;gt;nld&amp;lt;/iso639Id&amp;gt;
          &amp;lt;iso639Id&amp;gt;nor&amp;lt;/iso639Id&amp;gt;
          &amp;lt;iso639Id&amp;gt;por&amp;lt;/iso639Id&amp;gt;
          &amp;lt;iso639Id&amp;gt;spa&amp;lt;/iso639Id&amp;gt;
          &amp;lt;iso639Id&amp;gt;swe&amp;lt;/iso639Id&amp;gt;
        &amp;lt;/languageList&amp;gt;
      &amp;lt;/configItem&amp;gt;
    &amp;lt;/layout&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you should see a new "Eurkey (Special)" entry in your keyboard layout list. If not, restart your computer.&lt;/p&gt;

</description>
      <category>linux</category>
      <category>productivity</category>
      <category>tutorial</category>
      <category>ubuntu</category>
    </item>
    <item>
      <title>From Vue to Alpine.js on a legacy project</title>
      <dc:creator>pallade</dc:creator>
      <pubDate>Sat, 23 Mar 2024 07:31:24 +0000</pubDate>
      <link>https://dev.to/pallade/from-vue-to-alpinejs-on-a-legacy-project-3j6o</link>
      <guid>https://dev.to/pallade/from-vue-to-alpinejs-on-a-legacy-project-3j6o</guid>
      <description>&lt;p&gt;I have been struggling with progressive enhancement on a legacy project. The requirements are simple: there is some PHP-generated HTML that could be nicely enhanced.&lt;/p&gt;

&lt;p&gt;Our approach has been using Vue 2 inline templates. This feature neatly separated HTML code (server generated) from JS and CSS code, that lived on the client.&lt;/p&gt;

&lt;p&gt;No JS? No problem: the HTML works anyway.&lt;/p&gt;

&lt;p&gt;Unfortunately, Vue 3 removed support for inline templates. This left us in a tough spot, since Vue 2 is unsupported and EOL.&lt;/p&gt;

&lt;p&gt;Enter Alpine.js. You know Vue? Alpine is the same sauce. Minus lots of complcations. It is just perfect for this use case!&lt;/p&gt;

&lt;p&gt;Migrating from Vue 2 to Alpine.js is really, really straightforward, and you gain a lot of benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;reactivity is super easy&lt;/li&gt;
&lt;li&gt;reactivity and events bubble outwards, to the outermost Alpine.js enabled element. No need to have props and weird questions about communicating between parents and children!&lt;/li&gt;
&lt;li&gt;data sharing among different components is easy: you can have a global reactive store and bind to that&lt;/li&gt;
&lt;li&gt;all is inline! but you can have some separation of concens and move JS code to a separate file, so that the HTML becomes lighter&lt;/li&gt;
&lt;li&gt;error reporting is stellar: look at your console and you will see a specific and well described error!&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  From file.vue to Alpine.js
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Template (HTML)
&lt;/h3&gt;

&lt;p&gt;If you have a component, it will have its own template, somewhere. &lt;/p&gt;

&lt;p&gt;If it is an inline-template, then replace &lt;code&gt;inline-template&lt;/code&gt; with &lt;code&gt;x-data="customcomponent"&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div is="custom-component" inline-template&amp;gt;...&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;becomes&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div x-data="customcomponent"&amp;gt;...&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Otherwise, you probably have some &lt;code&gt;&amp;lt;custom-component /&amp;gt;&lt;/code&gt; code in your HTML: copy and paste your HTML template that you have in your .vue file, and replace &lt;code&gt;&amp;lt;custom-component /&amp;gt;&lt;/code&gt; with the entire HTML template. Then add  and &lt;code&gt;x-data="customcomponent"&lt;/code&gt; to the outermost tag.&lt;/p&gt;

&lt;p&gt;What is &lt;code&gt;customcomponent&lt;/code&gt;? It is the name of the JS component that we will create in the next step. The &lt;code&gt;customcomponent&lt;/code&gt; will be registered at the last step of this tutorial, and will allow Alpine.js to connect this block of HTML to the correct script that automates it.&lt;/p&gt;

&lt;p&gt;Note that you can (and should) inline x-data too, and have all your logic in one place. But I prefer to separate it as soon as it becomes even slightly complex.&lt;/p&gt;

&lt;p&gt;Now that your HTML is mostly in place, you will need to replace the &lt;code&gt;v-&lt;/code&gt; attributes with... &lt;code&gt;x-&lt;/code&gt; attributes. You can just rename most of them: they are equivalent.&lt;/p&gt;

&lt;p&gt;One exception is &lt;code&gt;x-if&lt;/code&gt; and &lt;code&gt;x-show&lt;/code&gt;: &lt;code&gt;x-if&lt;/code&gt; works on a &lt;code&gt;&amp;lt;template&amp;gt;&lt;/code&gt; tag only, so you should probably start by renaming &lt;code&gt;v-if&lt;/code&gt; to &lt;code&gt;x-show&lt;/code&gt;, unless you have special requirements.&lt;/p&gt;

&lt;h3&gt;
  
  
  CSS
&lt;/h3&gt;

&lt;p&gt;Your CSS code goes to the main CSS. No magic here, sorry.&lt;/p&gt;

&lt;h3&gt;
  
  
  JS
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Create a new &lt;code&gt;custom-component.js&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;Start like this:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default () =&amp;gt; ({
  // Code here
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Paste the insides of your .vue &lt;code&gt;script&lt;/code&gt; tag to where &lt;code&gt;// Code here&lt;/code&gt; is. &lt;/li&gt;
&lt;li&gt;Promote all &lt;code&gt;data&lt;/code&gt; to the outermost scope:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default () =&amp;gt; ({
  reactiveVar1 : 'hi!',
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Promote all &lt;code&gt;computed&lt;/code&gt; to the outermost scope:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default () =&amp;gt; ({
  reactiveVar1 : 'hi!',
  computeMe() : { return this.reactiveVar1; },
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Rename &lt;code&gt;mount()&lt;/code&gt; to &lt;code&gt;init()&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default () =&amp;gt; ({
  reactiveVar1 : 'hi!',
  computeMe() : { return this.reactiveVar1; },
  init() : { reactiveVar1 = 'hello world'; }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Have a &lt;code&gt;watch&lt;/code&gt; block? Promote all the watching function to the main scope, and then connect them manually in your init() function, like this:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;this.$watch('watchedVariable', (newValue) =&amp;gt; this.watchedVariableChanged(newValue))&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Adjust special Vue features, if you have any&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Bring it all together now
&lt;/h2&gt;

&lt;p&gt;You will need to bootstrap Alpine.js somewhere in your JS code, at the top level of your app, the same as you did with Vue.&lt;/p&gt;

&lt;p&gt;You would do something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import Alpine from 'alpinejs/dist/module.cjs';
import collapse from '@alpinejs/collapse'

import customcomponent from './custom-components.js';

window.Alpine = Alpine

document.addEventListener("DOMContentLoaded", function () {
    Alpine.plugin(collapse)

    Alpine.data('customcomponent', customcomponent)

    Alpine.start()
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have imported our JS, we introduced it to Alpine and we  gave it a name: now we can use it.&lt;/p&gt;

&lt;p&gt;Go to your HTML file and replace &lt;code&gt;data='{ someReactiveVar = 1; }'&lt;/code&gt; with &lt;code&gt;data='customcomponent'&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Reload and enjoy!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>New Relic and php-fpm on Ubuntu</title>
      <dc:creator>pallade</dc:creator>
      <pubDate>Fri, 28 Apr 2023 08:53:15 +0000</pubDate>
      <link>https://dev.to/pallade/new-relic-and-php-fpm-on-ubuntu-100a</link>
      <guid>https://dev.to/pallade/new-relic-and-php-fpm-on-ubuntu-100a</guid>
      <description>&lt;p&gt;This is a sad story of a great service with very poor documentation and abysmal customer support.&lt;/p&gt;

&lt;p&gt;When installing New Relic agent, it will not work out of the box.&lt;/p&gt;

&lt;p&gt;How to debug:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;When you install the deb repository, remember do replace &lt;code&gt;http&lt;/code&gt; with &lt;code&gt;https&lt;/code&gt;. Otherwise the repository will not load:&lt;br&gt;
&lt;code&gt;Failed to fetch http://apt.newrelic.com/debian/dists/newrelic/InRelease 301 Moved Permanently&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Check your INI files. Use phpinfo() and find out if the module for newrelic is loaded.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Go to &lt;code&gt;/var/log/newrelic/php_agent.log&lt;/code&gt;. There should be lines there. For example:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;2023-04-28 10:30:39.288 +0200 (2312 2312) info: New Relic 10.9.0.324 ("lilac" - "d563196dce79") [daemon='@newrelic'  php='8.2.5' zts=no sapi='fpm-fcgi'  pid=2312 ppid=1 uid=0 euid=0 gid=0 egid=0 backtrace=yes startup=agent os='Linux' rel='5.15.0-71-generic' mach='x86_64' ver='#78-Ubuntu SMP Tue Apr 18 09' node='XXX']&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You should see things related to your SAPI, in my case php-fpm. If you are using fpm and you see things related to apache2 sapi, then you have some issues. Maybe you are loading modphp and you forgot to disable it?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If you still see nothing on new relic, then check Apparmor. Is it enabled? Is php-fpm in enforce mode? If so, you need to add this line to &lt;code&gt;/etc/apparmor.d/php-fpm&lt;/code&gt;: &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;/proc/*/statm r,&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;then call &lt;code&gt;service apparmor reload&lt;/code&gt; to reload all profiles.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>ppa:ondrej/php on Ubuntu 23.04 (Lunar)</title>
      <dc:creator>pallade</dc:creator>
      <pubDate>Thu, 27 Apr 2023 11:20:15 +0000</pubDate>
      <link>https://dev.to/pallade/ppaondrejphp-on-ubuntu-2304-lunar-ia1</link>
      <guid>https://dev.to/pallade/ppaondrejphp-on-ubuntu-2304-lunar-ia1</guid>
      <description>&lt;p&gt;Ondrej's PPA is &lt;strong&gt;not&lt;/strong&gt; meant to be run on non-LTS versions of Ubuntu. Despite what the docs state (they are unfortunately not up-to-date), &lt;a href="https://github.com/oerdnj/deb.sury.org/issues/1662"&gt;he decided to target LTS versions only&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This said, you may still need to make it work, maybe temporarily. Here is how.&lt;/p&gt;

&lt;p&gt;1:  Add the PPA&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo add-apt-repository ppa:ondrej/php&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;2: Edit &lt;code&gt;/etc/apt/sources.list.d/ondrej-ubuntu-php-lunar.list&lt;/code&gt; and change &lt;code&gt;lunar&lt;/code&gt; to &lt;code&gt;jammy&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;deb https://ppa.launchpadcontent.net/ondrej/php/ubuntu/ jammy main&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;3: If you need the intl extension, download and manually install &lt;code&gt;libicu70_70.1-2_amd64.deb&lt;/code&gt; from the jammy repository. It has no dependencies.&lt;/p&gt;

&lt;p&gt;4: Pin &lt;code&gt;libgd3&lt;/code&gt; to the official Ubuntu version. Otherwise it will make a mess of your system (Ondrej's versio is newer, at the moment, but it has different and unsatisfiable dependencies, resulting in a "broken" package). &lt;/p&gt;

&lt;p&gt;Create a file like this: &lt;code&gt;/etc/apt/preferences.d/ondrejphp&lt;/code&gt; and paste this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Package: libgd3
Pin: release n=lunar
Pin-Priority: 900
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;5: install your PHP packages&lt;/p&gt;

</description>
    </item>
    <item>
      <title>php-fpm says: Failed to open stream: Permission denied</title>
      <dc:creator>pallade</dc:creator>
      <pubDate>Thu, 13 Apr 2023 07:50:59 +0000</pubDate>
      <link>https://dev.to/pallade/php-fpm-says-failed-to-open-stream-permission-denied-3527</link>
      <guid>https://dev.to/pallade/php-fpm-says-failed-to-open-stream-permission-denied-3527</guid>
      <description>&lt;p&gt;This is an error message I recently debugged with PHP-fpm on Apache2 and Ubuntu (other webservers will behave the same way).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Thu Apr 13 09:23:02.625178 2023] [proxy_fcgi:error] [pid 233355] [client XXX.XXX.XXX.XXX:46074] AH01071: Got error 'PHP message: PHP Warning:  PHP Request Startup: Failed to open stream: Permission denied in Unknown on line 0; Unable to open primary script: /ZZZ/XXX/YYY/public_html/index.php (Permission denied)', referer: http://XXXXX.com/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;What does this error say?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Apache connected correctly to the php-fpm backend, so the issue is not to be researched at apache level&lt;/li&gt;
&lt;li&gt;php-fpm correctly identified the file (/ZZZ/XXX/YYY/public_html/index.php) so both the Apache2 instructions and the pool are configured correctly&lt;/li&gt;
&lt;li&gt;php-fpm could not read the file due to permissions denied&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What to check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First, check how does the pool read the file. You can do that simply by calling &lt;code&gt;ps aux | grep php-fpm&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Then, see if the user can effectively read the file: &lt;code&gt;sudo -u PHP_FPM_USER less /ZZZ/XXX/YYY/public_html/index.php&lt;/code&gt;. If this gives a permission denied, then you need to add permissions to the file (and, possibly, add a "x" permission to the path upstream to it).&lt;/li&gt;
&lt;li&gt;If the php-fpm user can read the file, then something else is blocking it, and it is not system file permissions!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In Ubuntu the most probable culprit will be Apparmor. The solution is quite easy however: add your path to the allowed list of directories that php-fpm can read. You can use some magic to make this general.&lt;/p&gt;

&lt;p&gt;Edit &lt;code&gt;/etc/apparmor.d/php-fpm&lt;/code&gt; and add something like:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/ZZZ/*/YYY/site/** rw,&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;this will, for example, allow PHP to read:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;/ZZZ/somesite/YYY/site/index.php&lt;/li&gt;
&lt;li&gt;/ZZZ/somesite/YYY/site/public_html/anything.php&lt;/li&gt;
&lt;li&gt;/ZZZ/othersite/YYY/site/public_html/hello.jpg&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then restart apparmor and it should work.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Css: A rectangle with an oblique bottom border</title>
      <dc:creator>pallade</dc:creator>
      <pubDate>Sat, 22 Aug 2020 11:39:24 +0000</pubDate>
      <link>https://dev.to/pallade/css-a-rectangle-with-an-oblique-bottom-border-11m9</link>
      <guid>https://dev.to/pallade/css-a-rectangle-with-an-oblique-bottom-border-11m9</guid>
      <description>&lt;h2&gt;
  
  
  Update:&lt;a href="https://caniuse.com/mdn-css_types_cos"&gt; trigonometric functions are now available in all major browsers&lt;/a&gt;! No need for such tricks anymore!
&lt;/h2&gt;

&lt;p&gt;My designer came up with a comp that has sections, and some of those sections have an oblique border. Moreover, they also have a drop shadow! And of course, this has to be responsive.&lt;/p&gt;

&lt;p&gt;So I came up with some ideas on how to solve this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Find the codepen at the bottom of this post!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;All of the examples have a div that will host the content ("above-gradient"), and another div that will render the sloping bottom. This is to make things easier, and also most of those solutions require two divs because of the drop shadow.&lt;/p&gt;

&lt;h1&gt;
  
  
  Solution 1: svg triangle without shadow
&lt;/h1&gt;

&lt;p&gt;The first solution is the easiest: just create an SVG triangle and stretch it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"above-gradient"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;'gradient gradient1'&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;svg&lt;/span&gt; &lt;span class="na"&gt;viewBox=&lt;/span&gt;&lt;span class="s"&gt;'0 0 100 100'&lt;/span&gt; &lt;span class="na"&gt;preserveAspectRatio=&lt;/span&gt;&lt;span class="s"&gt;'none'&lt;/span&gt; &lt;span class="na"&gt;overflow=&lt;/span&gt;&lt;span class="s"&gt;"visible"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;polygon&lt;/span&gt; &lt;span class="na"&gt;points=&lt;/span&gt;&lt;span class="s"&gt;"0,100 100,0 0,0"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"main"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="nc"&gt;.above-gradient&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;150px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;yellow&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.gradient&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nt"&gt;svg&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nc"&gt;.main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;yellow&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that the angle is not preserved when the viewport width changes, so the angle will increase when the screen is narrower.&lt;/p&gt;

&lt;p&gt;Advantages: quickest&lt;br&gt;
Disadvantages: angle is not preserved, no shadow&lt;/p&gt;
&lt;h1&gt;
  
  
  Solution 2: svg triangle with shadow
&lt;/h1&gt;

&lt;p&gt;We will be adding a shadow now. Call it gradient2 and apply this CSS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="nc"&gt;.gradient2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;svg&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;drop-shadow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;5px&lt;/span&gt; &lt;span class="nf"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,.&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whoops: we will need to apply some z-indexes, otherwise the shadow will be also on the upper part of the triangle!&lt;/p&gt;

&lt;p&gt;But look carefully: that shadow is inconsistent with the main shape! It is a shadow of a triangle, and not that of a trapezium. This is evident at the far right corner, where the shadow is zero (because near the edge there is nothing that could cast it).&lt;/p&gt;

&lt;p&gt;Advantages: quickest&lt;br&gt;
Disadvantages: angle is not preserved, inconsistent shadow&lt;/p&gt;
&lt;h1&gt;
  
  
  Solution 3: skewed rectangle with JS
&lt;/h1&gt;

&lt;p&gt;So let's come up with something else. How can we fix the shadow problem? We'd need to cast it from a rectangle, that does not have the problem with the edges. And CSS has a filter that is skewY that would skew the entire rectangle to achieve exactly the effect we want.&lt;/p&gt;

&lt;p&gt;Unfortunately there is a problem: the width of the screen is unknown, therefore we cannot both fix an angle and a height. One of the two has to be computed.&lt;/p&gt;

&lt;p&gt;This means: trigonometry.&lt;/p&gt;

&lt;p&gt;Unfortunately, CSS does not have trigonometric functions (yet), so the only possibility is to resort to some JS.&lt;/p&gt;

&lt;p&gt;Since we need to do it the hard way, let's also solve the problem with the angle: let's try to keep the angle constant. We will therefore need to adjust its height.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;updateTan&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;deg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PI&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;180&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;adjacent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;main-wrapper&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;offsetWidth&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;opposite&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;adjacent&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;deg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;documentElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--len-at-3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;opposite&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;updateTan&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;resize&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updateTan&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our JS will get the width of the containing element and compute the appropriate height of our div, given an angle of 3°.&lt;/p&gt;

&lt;p&gt;The first line converts our 3 degrees into radiants, that is the unit expected by Math.tan.&lt;/p&gt;

&lt;p&gt;We are setting a CSS variable here, called --len-at-3, which we will use later in the CSS. We could access the element directly, but it is clearer this way.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;--len-at-3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.gradient3&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;len-at-3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;skewY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;-3deg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;transform-origin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;top&lt;/span&gt; &lt;span class="nb"&gt;left&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If JS is disabled, the element will have a 0 width and no shadow. Since it will also have a z-index of -1 (see previous example) it should not get into our way.&lt;/p&gt;

&lt;p&gt;Advantages: angle preserved&lt;br&gt;
Disadvantages: requires JS&lt;/p&gt;

&lt;h1&gt;
  
  
  Solution 4: cheating with a PNG
&lt;/h1&gt;

&lt;p&gt;There is a solution I used to employ widely which is just to get a triangular PNG file and stretch it edge to edge. &lt;/p&gt;

&lt;p&gt;The shadow is consistent, and there are no problems at the edges. However, this feels a bit as a hack, since stretching an image much beyond its native size feels unnatural.&lt;/p&gt;

&lt;p&gt;Advantages: compatible with ancient browsers, consistent shadow&lt;br&gt;
Disadvantages: angle is not preserved, may lose quality when screen is larger&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Did you come up with a better solution? Please, let me know.&lt;/p&gt;

&lt;p&gt;Below is the codepen with all of them.&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/netpalantir/embed/QWNGoym?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
 &lt;/p&gt;

</description>
      <category>css</category>
    </item>
  </channel>
</rss>
