Nono.MA

SEPTEMBER 21, 2022

Let's create two files with incremental content.

echo "Hello," > a
echo "Hello, Nono\!" > b

Then show their diff in Visual Studio Code.

code --diff a b

A VSCode window comparing the two files we created will open.

SEPTEMBER 10, 2022

List existing keys added to the SSH agent.

ssh-add -l
# The agent has no identities.

Create a new EdDSA key1.

ssh-keygen -t ed25519 -C "your@email.com"
# Generating public/private ed25519 key pair.
# Enter file in which to save the key (/Users/john/.ssh/id_ed25519):               
# Enter passphrase (empty for no passphrase): 
# Enter same passphrase again: 
# Your identification has been saved in /Users/john/.ssh/id_ed25519
# Your public key has been saved in /Users/john/.ssh/id_ed25519.pub
# 
# The key fingerprint is:
# SHA256:CPtr5U4xCPT1Ypssz0L/bIn7+l2gNMVe1Bkh2H8tB6w your@email.com
# 
# The key's randomart image is:
# +--[ED25519 256]--+
# |        .o*B= oo.|
# |         *o++= ..|
# |        =.B .+o  |
# |       o B Eo.o  |
# |        S o  +.  |
# |       . .  + .. |
# |        .   .+.o.|
# |           . ++++|
# |            .+*.*|
# +----[SHA256]-----+

Here's how to copy the public key to the clipboard on macOS Terminal.

cat /Users/john/.ssh/id_ed25519 | pbcopy
# ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMe/yQPuB7k4MO6pL9c+03YHXKc3q/LLvaUED24Vu6P your@email.com

Your public key can be added to services like GitHub or Bitbucket for remote Git pull/push access or Linux machines via SSH.

For instance, you'd add that output as a New SSH Key to GitHub at github.com/settings/keys.


  1. According to Goteleport, "the [key type] choice is between RSA 2048/4096 and Ed25519 and the trade-off is between performance and compatibility. RSA is universally supported among SSH clients while EdDSA performs much faster and provides the same level of security with significantly smaller keys." 

SEPTEMBER 8, 2022

I spent some time looking for a solution to change the location of Visual Studio Code’s settings.json file without any luck.

But I found a solution.

Visual Studio Code’s settings JSON file is always located at the same path.

~/Library/Application\\ Support/Code/User/settings.json

The way I worked around this limitation is by creating a symbolic link from this path to another file. In my case, I place settings.json on a Dropbox folder that is synchronized across my computers.

ln -s \
~/Dropbox/settings/vscode/settings.json \
~/Library/Application\\ Support/Code/User/settings.json

SEPTEMBER 5, 2022

Here's how to round a decimal float number to two decimals in TypeScript.

parseFloat("123.456").toFixed(2);
// Returns 123.46

Of course, you could change toFixed(2) to any number to keep as many decimals as you wanted.

SEPTEMBER 3, 2022

Here's how to convert a string from CamelCase to snake_case in Python with regular expressions.

import re

# Option 1
regex = r'(?<!^)(?=[A-Z])'
re.sub(regex, '_', 'GettingSimple', 0).lower()
# returns 'getting_simple'

# Option 2
pattern = re.compile(r'(?<!^)(?=[A-Z])')
pattern.sub('_', 'nonoMartinezAlonso').lower()
# returns 'nono_martinez_alonso'

See how to Convert from snake_case to camelCase.

SEPTEMBER 2, 2022

Here's how to remove a remote Git branch without using an app or a website user interface, say, GitHub or GitLab.

# Delete a remote Git Branch (assuming your remote is called origin)
git push origin --delete your-branch-name
# To bitbucket.org:nonoesp/some-repo.git
#  - [deleted]         your-branch-name

Remember that you will also have to delete the Git branch from your local repository as follows.

# Delete a local branch
# -d is a shorthand for --delete
git branch -d your-branch-name
# Deleted branch your-branch-name (was f9b622c).

# Force delete a local branch (regardless of the branch merge status)
# -D is a shorthand for --delete --force
git branch -D your-branch-name
# Deleted branch your-branch-name (was f9b622c).

SEPTEMBER 1, 2022

Here's how to remove a local Git branch.

# Delete a local branch
# -d is a shorthand for --delete
git branch -d your-branch-name
# Deleted branch your-branch-name (was f9b622c).

# Force delete a local branch (regardless of the branch merge status)
# -D is a shorthand for --delete --force
git branch -D your-branch-name
# Deleted branch your-branch-name (was f9b622c).

Remember that you will also have to delete the Git branch from your remote repository as a separate step.

Here's how to remove a remote Git branch without using an app or a website user interface, say, GitHub or GitLab.

# Delete a remote Git Branch (assuming your remote is called origin)
git push origin --delete your-branch-name
# To bitbucket.org:nonoesp/some-repo.git
#  - [deleted]         your-branch-name

AUGUST 31, 2022

I run the following command to clean up unneeded old Homebrew kegs on macOS.

brew cleanup --prune=all

But often get this error.

Error: Could not cleanup old kegs! Fix your permissions on:

Here's the tail of what the command returns when there are permissions issues.

==> This operation has freed approximately 395MB of disk space.
Error: Could not cleanup old kegs! Fix your permissions on:
  /opt/homebrew/Cellar/dnsmasq/2.85
  /opt/homebrew/Cellar/php/8.1.1
  /opt/homebrew/Cellar/php/8.1.1.reinstall
  /opt/homebrew/Cellar/php/8.1.3_1
  /opt/homebrew/Cellar/php/8.1.4.reinstall
  /opt/homebrew/Cellar/php@7.4/7.4.21_1
  /opt/homebrew/Cellar/php@7.4/7.4.27.reinstall
  /opt/homebrew/Cellar/php@7.4/7.4.28_1.reinstall
  /opt/homebrew/Cellar/php@8.0/8.0.14

The fix

brew won't use root permissions for any operations.

This is what you'll see if you try to cleanup with root.

sudo brew cleanup --prune=all                                                   
# Error: Running Homebrew as root is extremely dangerous and no longer supported.
# As Homebrew does not drop privileges on installation you would be giving all
# build scripts full access to your system.

What you have to do is to change the ownership of the problematic directories to your username instead of root.

You can do that with sudo chown -R "$USER":admin /conflicting/dir.

To solve the issues shown in my error above, I ran the following commands.

sudo chown -R "$USER":admin /opt/homebrew/Cellar/dnsmasq/2.85
sudo chown -R "$USER":admin /opt/homebrew/Cellar/php/8.1.1
sudo chown -R "$USER":admin /opt/homebrew/Cellar/php/8.1.1.reinstall
sudo chown -R "$USER":admin /opt/homebrew/Cellar/php/8.1.3_1
sudo chown -R "$USER":admin /opt/homebrew/Cellar/php/8.1.4.reinstall
sudo chown -R "$USER":admin /opt/homebrew/Cellar/php@7.4/7.4.21_1
sudo chown -R "$USER":admin /opt/homebrew/Cellar/php@7.4/7.4.27.reinstall
sudo chown -R "$USER":admin /opt/homebrew/Cellar/php@7.4/7.4.28_1.reinstall
sudo chown -R "$USER":admin /opt/homebrew/Cellar/php@8.0/8.0.14

Then run brew cleanup --prune=all again and everything should work.

AUGUST 29, 2022

You can use the parse_url built-in PHP method to break down a URL into its components.

here's the method itself.

parse_url(string $url, int $component = -1): int|string|array|null|false

And here's how to use it.

parse_url("https://gettingsimple.com/podcast");
// [
//     "scheme" => "https",
//     "host" => "gettingsimple.com",
//     "path" => "/podcast",
// ]

You can then obtain the scheme, host, or path of a URL.

$components = parse_url("https://gettingsimple.com/podcast");

$scheme = $components["scheme"];
// "https"

$host = $components["host"];
// "gettingsimple.com"

$path = $components["path"];
// "/podcast"

AUGUST 28, 2022

Here's how to upgrade to a new version of PHP's Mongo extension if you previously installed it but you've upgraded to the latest PHP version. (If you haven't, see how to install it.)

Uninstall the existing mongodb extension.

sudo pecl uninstall MongoDB
# Extension mongodb disabled in php.ini
# uninstall ok: channel://pecl.php.net/mongodb-1.13.0

Then follow this guide to install it again for the latest PHP version.

AUGUST 27, 2022

Here's how to print the current date and time with bash.

date +%y%m%d_%H%M%S
# 220715_124140

You can store the timestamp on a variable.

DATE_NOW=$(date '+%y%m%d_%H%M%S')

And make use of it later on your command for clarity.

echo "Today is $DATE_NOW."
# Today is 220715_124805.

Note that you can customize the format of your date or timestamp by adjusting the formatting template.

Here's how the command works.

date +{formatting_code}

And here's a full list of options.1

# Gives name of the weekday as Mon, Sun, Fri
date +%a

# Gives name of the weekday as Monday, Sunday, Friday
date +%A

# Gives name of the month as Jan, Feb, Mar
date +%b

# Gives name of the month as January, February, March
date +%B

# Displays day of the month as 05
date +%d

# Displays current date MM/DD/YY format as 11-01-21
date +%D

# Shows date in YYYY-MM-DD format as 2021-11-01
date +%F

# Shows hour in 24-hour format as 22
date +%H

# Shows hour in 12-hour format as 11
date +%I

# Displays the day of the year as 001–366
date +%j

# Displays the number of the month as 01–12
date +%m

# Displays minutes as 00-59
date +%M

# Displays seconds as 00-59
date +%S

# Displays in Nanoseconds
date +%N

# Displays time as HH:MM:SS in 24-hour format
date +%T

# Day of the week as 1-7; 1 is Monday, 6 is Saturday
date +%u

# Shows week number of the year as 00-53
date +%U

# Displays year YYYY as 2021
date +%Y

# Displays time zone
date +%Z

To learn more about what you can do with the date command, run man date to print the manual.

AUGUST 26, 2022

I had installed an old version of Laravel Valet (2.18.10) on my system, and even when running composer global update, Valet wasn't being updated to the latest available version (3.1.9 at the time of this writing).

In theory, here's how you install and update laravel/valet.

# Install
composer global require laravel/valet

# Update
composer global update

But, as I mentioned above, my Valet installation was stuck at 2.18.10.

I forced composer to upgrade laravel/valet to the latest available version by specifying the ^3.0.0 constrain. (Note that this may lock your Valet version and not update in the future when ^4.0.0 is released.)

composer global require laravel/valet:^3.0.0
# Changed current directory to /Users/nono/.composer
# ./composer.json has been updated
# Running composer update laravel/valet
# Loading composer repositories with package information
# Updating dependencies
# Lock file operations: 0 installs, 1 update, 0 removals
#  - Upgrading laravel/valet (v2.18.10 => v3.1.9)
# Writing lock file
# Installing dependencies from lock file (including require-dev)
# Package operations: 0 installs, 1 update, 0 removals
#  - Upgrading laravel/valet (v2.18.10 => v3.1.9): Extracting archive
# Generating autoload files
# 15 packages you are using are looking for funding.
# Use the `composer fund` command to find out more!

Verify the installed version.

valet --version
# Laravel Valet 3.1.9

Inspecting Composer's global composer.json

You can get the path where your global composer.json is located, which defines your installed dependencies.

composer config data-dir
# /Users/nono/.composer

In that directory, you'll find composer.json.

cat $(composer config data-dir)/composer.json
# {
#     "require": {
#         "laravel/valet": "^3.0.0",
#         "laravel/installer": "^4.1"
#     }
# }

AUGUST 25, 2022

Here's how to locate the path of Composer's global composer.json, which defines the system packages installed and managed by Composer.

# Retrieve composer's data directory
composer config data-dir
# /Users/nono/.composer

# Print composer.json's contents
cat $(composer config data-dir)/composer.json
# {
#     "require": {
#         "laravel/valet": "^3.0.0",
#         "laravel/installer": "^4.1"
#     }
# }

AUGUST 24, 2022

Since Laravel Valet version 3, you can choose the specific PHP version a site should run on without the need to change Valet's global PHP version as in previous releases.

You can, for instance, run all your sites in PHP 8.1 but set specific legacy sites to run in PHP 7.4.

You'd set your global Valet PHP version.

valet use php@8.1

Then set the PHP version for a specific linked site.

# When the current folder matches the name of a linked site
valet isolate php@7.4

# Explicitly specifying a site name
valet isolate php@7.4 --site="my-app"

How to find a site's name

valet links
# +------+------------------+-------------------------+-------------+
# | Site | URL              | Path                    | PHP Version |
# +------+------------------+-------------------------+-------------+
# | gs   | http://gs.test   | /Users/.../gs-folio     | php@8.1     |
# | nono | http://nono.test | /Users/.../nonoma-folio | php@8.1     |
# +------+------------------+-------------------------+-------------+

The name of your site is listed in the Site column.

AUGUST 8, 2022


How to build a client for real-time communication with WebSockets in TypeScript using the ws NPM package.


See transcript ›

AUGUST 5, 2022

The osascript Terminal application allows the execution of AppleScript code from the command-line interface.

osascript -e 'tell application "System Events" to set picture of first desktop to "/path/to/your/background-image"'

AUGUST 1, 2022


How to build a server for real-time communication with WebSockets in TypeScript using the ws NPM package.


See transcript ›

JULY 31, 2022

Here's an easy way to retrieve the PHP version your Laravel app is running.

>>> PHP_VERSION
=> "8.1.8"

JULY 30, 2022

Here's an easy way to retrieve the Laravel version your app is running.

>>> Illuminate\Foundation\Application::VERSION
=> "9.22.1"

JULY 25, 2022


WebSocket server and client in TypeScript & Node.js with the ws NPM package.


See transcript ›

JULY 23, 2022

Two months ago, HuggingFace open-source "state-of-the-art diffusion models for image and audio generation in PyTorch" at github.com/huggingface/diffusers.

"Diffusers provides pretrained diffusion models across multiple modalities, such as vision and audio, and serves as a modular toolbox for inference and training of diffusion models."

Here's a text-to-image example from the repository's README.

# !pip install diffusers transformers
from diffusers import DiffusionPipeline

model_id = "CompVis/ldm-text2im-large-256"

# load model and scheduler
ldm = DiffusionPipeline.from_pretrained(model_id)

# run pipeline in inference (sample random noise and denoise)
prompt = "A painting of a squirrel eating a burger"
images = ldm([prompt], num_inference_steps=50, eta=0.3, guidance_scale=6)["sample"]

# save images
for idx, image in enumerate(images):
    image.save(f"squirrel-{idx}.png")

Latent diffusion is the type of model architecture used in Google's Imagen or OpenAI's DALL·E to generate images from text and increase the resolution of output images.

JULY 22, 2022

First, you must install the sass NPM package as a development dependency.

npm install --save-dev sass

Then add your scss file to the vite.config.js file.

// vite.config.js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';

export default defineConfig({
    plugins: [
        laravel({
            input: [
                'resources/sass/app.scss',
                'resources/js/app.js',
            ],
            refresh: true,
        }),
    ],
});

You can then load the built css file in your Blade views.

// my-view.blade.php
@vite(['resources/sass/app.scss'])
// <link rel="stylesheet" href="http://nono.test/build/assets/app.0b1a4b87.css" />

JULY 21, 2022

Laravel recently switched from building assets with Laravel Mix to Vite.js. According to its website, "Vite is a build tool that aims to provide a faster and leaner development experience for modern web projects."

It provides a dev server and a build command that bundles code using Rollup.

"Vite is opinionated and comes with sensible defaults out of the box, but is also highly extensible via its Plugin API and JavaScript API with full typing support."

Here are its main features.

  • 💡 Instant Server Start. On demand file serving over native ESM, no bundling required!
  • ⚡️ Lightning Fast HMR. Hot Module Replacement (HMR) that stays fast regardless of app size.
  • 🛠️ Rich Features. Out-of-the-box support for TypeScript, JSX, CSS and more.
  • 📦 Optimized Build. Pre-configured Rollup build with multi-page and library mode support.
  • 🔩 Universal Plugins. Rollup-superset plugin interface shared between dev and build.
  • 🔑 Fully Typed APIs. Flexible programmatic APIs with full TypeScript typing.

You can create a clean Laravel install that comes with Vite pre-configured.

# Create a Laravel app with the Laravel CLI tool
laravel new app

# Create a Laravel app with Composer
composer create-project laravel/laravel app

# Enter the directory
cd app

# Install NPM dependencies
npm install

# Run Vite's development server
npm run dev
#  VITE v3.0.2  ready in 249 ms
#
#  ➜  Local:   http://localhost:5173/
#  ➜  Network: use --host to expose
#
#  LARAVEL v9.21.3  plugin v0.5.0
#
#  ➜  APP_URL: http://app-laravel.test

# Build for production
npm run build
# > build
# > vite build
# 
# vite v3.0.2 building for production...
# ✓ 58 modules transformed.
# public/build/manifest.json            0.25 KiB
# public/build/assets/app.7c3c19f8.js   0.00 KiB / gzip: 0.02 KiB
# public/build/assets/app.334e7359.js   90.63 KiB / gzip: 33.07 KiB

JULY 18, 2022


How to download Elgato Stream Deck's software, assign actions to keys & the Store.


See transcript ›

JULY 17, 2022

Here's an example on how to use the "in" and "not in" Python operators.

› python
Python 3.9.13 (main, May 24 2022, 21:28:31) 
[Clang 13.1.6 (clang-1316.0.21.2)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> names = ['James', 'Paul', 'Lily', 'Glory']
>>> names
['James', 'Paul', 'Lily', 'Glory']
>>> print('YES' if 'Lily' in names else 'NO')
YES
>>> print('YES' if 'John' in names else 'NO')
NO
>>> print('NO' if 'Lily' not in names else 'YES')
YES
>>> print('NO' if 'John' not in names else 'YES')
NO

You could use this as a conditional in your code.

names = ['James', 'Paul', 'Lily', 'Glory']
new_person = 'Nono'

if new_person not in names:
  names.append(new_person)
  print(f'Added {new_person} to names.')
  # Added Nono to names.

if new_person in names:
  print(f'{new_person} was correctly added to names.')
  # Nono was correctly added to names.

JULY 16, 2022

You have mail, Terminal says from time to time.

There's an internal mail delivery system that certain system services make use of to deliver messages to the user, maybe errors or warnings, that would otherwise be lost. One example is the output of cron jobs; as they run in the background, there's no way to notify the user.

These "mails" are stored at /var/mail/$USER. (You can run echo $USER in Terminal to see what username is being used for the current user.)

Reading your email

The brute force way is to browse the original content of the emails.

cat /var/mail/$USER

A better way is to use the mail command.

mail
# Mail version 8.1 6/6/93.  Type ? for help.
# "/var/mail/nono": 3 messages 3 new
# >N  1 nono@abawrihf  Fri Jul 15 12:26  19/856   "Cron <nono@abawrihf> cd ~/Desktop/some-dir && zip -qr9 ...
#  N  2 nono@abawrihf  Fri Jul 15 12:27  19/856   "Cron <nono@abawrihf> cd ~/Desktop/some-dir && zip -qr9 ...
#  N  3 nono@abawrihf  Fri Jul 15 12:28  19/906   "Cron <nono@abawrihf> cd ~/Desktop/some-dir && zip -qr9 ...
  • Input 2 to show that message, for instance.
  • Input exit to terminate the mail command

Delete existing messages

sudo rm /var/mail/$USER

Then your inbox will be empty.

mail
# No mail for nono

JULY 8, 2022

PHP's ucwords() function converts a phrase to title case.

// PHP
ucwords('a big snake') 
// Returns "A Big Snake"

You can obtain the same result in Python with the .title() string method.

# Python
"a big snake".title()
# Returns "A Big Snake"

Here's how to test this function in the command-line interface.

python -c "print('nono martinez alonso'.title())"

JULY 7, 2022

  • In Visual Studio Code's menu bar, go to Code › Preferences › Settings or press + ,.
  • Search for Render Whitespace (in the Search settings search bar).
  • Set the value to none.

You can also set this value to all to show hidden characters throughout Visual Studio Code, or set it to be displayed for boundary, selection, or trailing.

JULY 6, 2022

  • In Visual Studio Code's menu bar, go to Code › Preferences › Settings or press + ,.
  • Search for Render Whitespace (in the Search settings search bar).
  • Set the value to all.

You can also set this value to none to hide hidden characters throughout Visual Studio Code, or set it to be displayed for boundary, selection, or trailing.

JULY 2, 2022

Here is the fastest way to create a Next.js React app with TypeScript. For the step-by-step version, take a look at the longer version.

Create a Next.js App with TypeScript

Let's use npx and create-next-app.

npx \
create-next-app nextjs-app \
--use-npm \
--example \
"https://github.com/nonoesp/next-learn/tree/master/basics/typescript-final"

Run the app in development mode

# Enter the app's directory
cd nextjs-app
# Run the app in development
npm run dev
# ready - started server on 0.0.0.0:3000, url: http://localhost:3000

You should be able to access the site at http://localhost:3000.

Build & Run for Production

npm run build
npm start
# ready - started server on 0.0.0.0:3000, url: http://localhost:3000

Hands-on tutorial

You can watch my step-by-step video on How to build a Next.js app with React & TypeScript.

Want to see older publications? Visit the archive.

Listen to Getting Simple .