Nono.MA

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.

JULY 1, 2022

Here's how to obtain the numerical value of the chmod permissions of a directory on macOS. (Note that this method also works for files.)

stat -f %A directory/
# 755

Set chmod value and read its string and numerical value

Let's give it a try.

First, create a new directory and set its permissions.

mkdir directory/
chmod 777 directory/

Then we can retrieve its chmod number.

stat -f %A directory/
# 777

And here's how to retrieve it's chmod string value.

ls -n
# drwxr-xr-x 2 501 20 64 Jun 21 13:57 directory/

This method also works for files.

JUNE 30, 2022

Here's how to read text from a file in Python; maybe a file that already exists or a file to which you wrote text with Python.

file = open('/your/file.txt', 'r')

# Read all file contents
contents = file.read()

# Read the lines of the file
lines = file.readlines()

# Iterate through the lines
for line in lines:
  print(line)

JUNE 26, 2022

Here's how to obtain the numerical value of the chmod permissions of a file on macOS. (Note that this method also works for directories.)

stat -f %A file.md
# 755

Set chmod value and read its string and numerical value

Let's give it a try.

First, create a new file and set its permissions.

touch text.md
chmod 777 text.md

Then we can retrieve its chmod number.

stat -f %A text.md
# 777

And here's how to retrieve it's chmod string value.

ls -n text.md
# -rwxrwxrwx 1 501 20 0 Jun 21 13:53 text.md*

This method also works for directories.

JUNE 19, 2022

Here's a simple command to get human-readable sizes of files and folders inside of the current directory. (I've tested it on macOS' Terminal and Linux.)

du -sh -- *
# 124M	backups
# 523M	downloads
# 1.8G	recordings-hijack
# 673M	recordings-obs
# 392K	recordings-zoom
# 403M	settings

Note that you may have to sudo if you're trying to get sizes for files that require sudo permissions.

JUNE 18, 2022

Here are the simplified steps to create a Next.js React app and add TypeScript to the mix. This tutorial combines my Create a Next.js app and Add TypeScript to Next.js posts.

Create a Next.js App

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

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

Add TypeScript

# Enter your app's directory
cd nextjs-app
# Create an empty TypeScript configuration file
touch tsconfig.json
# Install TypeScript, React Types, and Node Types
npm install --save-dev typescript @types/react @types/node

You can customize your TypeScript in tsconfig.json.

Run the app in development mode

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

From index.js into index.tsx

Your application is now ready to be written in TypeScript. The example we've used only has one file named index.js. Rename it to index.tsx and re-write the JavaScript code (and any new code you add to the app) in TypeScript.

Hands-on tutorial

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

JUNE 16, 2022

Today I tried to do this on my 13-inch MacBook Pro (M1, 2020).

conda create -n py2 python=2.7 -y

And I continue getting this error.

Collecting package metadata (current_repodata.json): done
Solving environment: failed with repodata from current_repodata.json,
will retry with next repodata source.
Collecting package metadata (repodata.json): done
Solving environment: failed

PackagesNotFoundError: The following packages are not available
from current channels:

  - python=2.7

Current channels:

  - https://conda.anaconda.org/conda-forge/osx-arm64
  - https://conda.anaconda.org/conda-forge/noarch

To search for alternate channels that may provide the conda
package you're looking for, navigate to

    https://anaconda.org

and use the search bar at the top of the page.

I can create environments with Python 3 versions without a problem though; say, Python 3.7, 3.8, or 3.9.

conda create -n py2 python=3.9 -y

JUNE 15, 2022

When trying to send an email using Amazon SES (Simple Email Service) using Laravel's Mail class.

\Mail::send('email', [], function ($message) {
    $message
    ->from('from@gmail.com', 'John Appleseed')
    ->to('to@gmail.com', 'Nono Martínez Alonso')
    ->subject('A sample email')
    ->html('<p>Hello, this is a test email.</p>');
});

I got the following error.

Expected response code "250" but got code "530",
with message "530 5.7.1 Authentication required".

Set up Amazon SES

You need to configure the following environment variables in .env.

AWS_ACCESS_KEY_ID=XXXXXXXXXXXXXX
AWS_SECRET_ACCESS_KEY=XXXXXXXXXX
AWS_DEFAULT_REGION=us-east-1

And then in config/services.php.

<?php

return [
    // ...
    'ses' => [
        'key' => env('AWS_ACCESS_KEY_ID'),
        'secret' => env('AWS_SECRET_ACCESS_KEY'),
        'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
    ],
];

Set up Laravel Mail

Lastly, set Amazon SES as Laravel's default mailer in .env.

MAIL_MAILER=ses

Note that you could also set the default in your config/mail.php in case there's no MAIL_MAILER key in your .env file.

<?php

return [
    // ...
    'default' => env('MAIL_MAILER', 'ses'),

Request to AWS SES API failed

This is the last error I got before everything worked.

Request to AWS SES API failed.
Email address is not verified.
The following identities failed the check in region US-EAST-1.

I was sending from an unverified email address. Changing it to one of my verified accounts fixed the issue.

JUNE 12, 2022

Here's how to find an item with a matching property value. We're querying an array of items in search of an entry, in this case, looking for a person by name and then retrieving their age.

// Define the Person type
type Person = {
    name: string;
    age: number;
}

// Define an array of persons
const people: Person[] = [
    {
      name: 'James',
      age: 24,
    },
    {
      name: 'Claire',
      age: 13,
    },
    {
      name: 'John',
      age: 42,
    }
  ];
  
  const person = people.find(p => p.name == 'John') as Person;
  // {
  //   name: 'John',
  //   age: 42,
  // }
  
  console.log(`${person.name} is ${person.age}.`);
  // John is 42.

Before you go

If you found this useful, you might want to join my newsletter; or take a look at other posts on TypeScript.

JUNE 11, 2022

Here are the steps to add TypeScript to your Next.js React application.

I assume you have a Next.js React application that can run in development mode. If that's not the case, Create a Next.js app first.

# Enter the directory of your app
cd nextjs-app
# Run Next.js in development
npm run dev
# ready - started server on 0.0.0.0:3000, url: http://localhost:3000

If you can access your site at http://localhost:3000, you're good to go.

Create a tsconfig.json file

# Create an empty TypeScript configuration file
touch tsconfig.json

Simply by creating a tsconfig.json file and restarting the application, Next.js will warn us that we're trying to work with TypeScript and have to install a set of required dependencies.

# Stop the running app with `CMD + C` (or `CTRL + C` on Windows)
# Run Next.js in development once again
npm run dev

You should receive the following warning when restarting the app.

ready - started server on 0.0.0.0:3000, url: http://localhost:3000
It looks like you're trying to use TypeScript but do not have
the required package(s) installed.

Please install typescript, @types/react, and @types/node by running:

  npm install --save-dev typescript @types/react @types/node

If you are not trying to use TypeScript, please remove the
tsconfig.json file from your package root (and any TypeScript
files in your pages directory).

Install TypeScript, React Types, and Node Types

npm install --save-dev typescript @types/react @types/node

Run your app

npm run dev
# ready - started server on 0.0.0.0:3000, url: http://localhost:3000
# We detected TypeScript in your project and created a tsconfig.json
# file for you.

Note that Next.js detected the tsconfig.json file, verified our dependencies were installed, and then populated our empty TypeScript configuration file with a boilerplate JSON object.

// tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": false,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "incremental": true,
    "esModuleInterop": true,
    "module": "esnext",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve"
  },
  "include": [
    "next-env.d.ts",
    "**/*.ts",
    "**/*.tsx"
  ],
  "exclude": [
    "node_modules"
  ]
}

From index.js into index.tsx

Your application is now ready to be written in TypeScript. The example we've used only has one file named index.js. Rename it to index.tsx and re-write the JavaScript code (and any new code you add to the app) in TypeScript.

Learning More

If you want to learn more, you can watch my video on How to build a Next.js app with React & TypeScript and take a look at Next.js's official TypeScript tutorial.

JUNE 10, 2022

For a Docker container started with the docker run command to be removed when it exits, you need to use the --rm flag.

docker run -it --rm ubuntu /bin/bash

JUNE 6, 2022


My video on how to use the YouTube Data API v3 to upload videos to your channel from Python scripts and the command line is now on YouTube.

The video walks through how to create a project in the Google API Console, register an application, generate credentials, and use them in a Python script that can be called from the command-line interface to upload videos to your YouTube account with a web browser.

Types of authorization credentials

  • OAuth 2.0. The application first sends a client ID and client secret to obtain a token. (This is the method used in the video.)
  • API keys. The key identifies your project and provides API access, quota, and reports.
  • Service account. Server-to-server, app-level authentication using robot accounts.

Google Account, Project, and Application

  • You need a Google Account to access the Google API Console, request an API key, and register your application.
  • Create a project in the Google Developers Console and obtain authorization credentials so your application can submit API requests.
    • Go to the API Console and select the project that you just registered.
    • Visit the Enabled APIs page. In the list of APIs, make sure the status is ON for the YouTube Data API v3.
  • Go to the Credentials page and create one.
    • Project name
    • Organization (optional)
    • Click Create
  • Your project should now be showing in the dropdown next to Google Cloud Platform.

Create OAuth 2 credentials

Set up a Python environment with the Google API Client Library with Anaconda

conda create -n yt python=3.8 -y && conda activate yt
pip install google-api-python-client
pip install google_auth_oauthlib
python -c "from apiclient.discovery import build;print(build)"

Upgrading the Python upload video script to Python 3

As the upload_video.py sample is written in Python 2, there are minor edits that need to be done to upgrade to Python 3.

  • Add from http import client
  • Replace appearances of httplib. with client.
  • Update the syntax of except and print statements from Python 2 to 3.

Dispose the created conda environment

You can delete the previously created Python environment when you're done as follows.

conda remove -n yt --all -y

Watch Upload Videos to YouTube with the Data API in Python

JUNE 4, 2022

As the official Create a Next.js App tutorial says, "there are many important details you need to consider to build a complete web application with React from scratch," but here I'm trying to get started as fast as possible.

Create a Next.js App

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

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

Your fresh Next.js app is now in the nextjs-app directory.

Run the App in Development

Now enter the directory and run the app in development mode.

cd nextjs-app
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

Add TypeScript to Next.js

If you want to use TypeScript instead of JavaScript on your Next.js React app, read how to Add TypeScript to Next.js. I also have a step-by-step video on How to build a Next.js app with React & TypeScript.

JUNE 3, 2022

Here's how to determine the location of the active Python binary.

import sys

# Get Python binary's location.
print(sys.executable)
# /Users/nono/miniforge3/bin/python

See how to get Python's version information.

JUNE 2, 2022

Here's how to get the version of your Python executable with Python code and determine the location of the active Python binary.

import sys

# Get Python's version.
print(sys.version)
# 3.9.7 | packaged by conda-forge | (default, Sep 29 2021, 19:24:02) \n[Clang 11.1.0 ]

# Get Python's version information.
print(sys.version_info)
# sys.version_info(major=3, minor=9, micro=7, releaselevel='final', serial=0)

# Get Python binary's location.
print(sys.executable)
# /Users/nono/miniforge3/bin/python

MAY 28, 2022

You can ask ImageMagick for details of image files with the identify. Say, their dimensions (width and height), their resolution (pixels-per-inch), or many other details.

You can run the identify by itself to get a series of default details.

The Identify command

identify image.jpg
# image.jpg JPEG 1600x1659 1600x1659+0+0 8-bit sRGB 475062B 0.010u 0:00.002

The -verbose flag

Or even to obtain greater details with the -verbose flag. (Note that this command returns more than 300 lines of information per image, so I'm omitting most of what was returned.)

identify -verbose image.jpg
# Image:
#  Filename: image.jpg
#  Format: JPEG (Joint Photographic Experts Group JFIF format)
#  Mime type: image/jpeg
#  Class: DirectClass
#  Geometry: 1600x1659+0+0
#  Resolution: 200x200
#  ...

Width and Height of a single image

identify -format "%wx%h" image.jpg
# 1600x1659

Width and Height of multiple images in a directory

identify -format "%wx%h\n" *.jpg
# 1983x1969
# 1912x1803
# 2173x2126
# 1807x1669
# ...

Dimensions and names

identify -format "%wx%h - %f\n" *.jpg
# 1983x1969 - image-01.jpg
# 1912x1803 - image-02.jpg
# 2173x2126 - image-03.jpg
# 1807x1669 - image-04.jpg
# ...

For reference, here are ImageMagick's identify docs.

MAY 27, 2022

I'm writing a series of posts on how to create a Next.js React app with and without TypeScript, trying to summarize the required steps.

# Create a Next.js React JavaScript app with npx
npx \
create-next-app nextjs-app \
--use-npm \
--example \
"https://github.com/nonoesp/next-learn/tree/master/basics/learn-starter"
# Enter the app's directory
cd nextjs-app
# Start the app in development mode
npm run dev
# > dev
# > next dev
#
# ready - started server on 0.0.0.0:3000, url: http://localhost:3000
# wait  - compiling...
# event - compiled client and server successfully in 944 ms (113 modules)

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

MAY 12, 2022

I recently used this regular expression to convert a string from snake to camel case.

import re

def camel(match):
    return match.group(1) + match.group(2).upper()

regex = r"(.*?)_([a-zA-Z])"
snake_case = "my_camel_case_variable_here"
camel_case = re.sub(regex, camel, snake_case, 0)
# returns myCamelCaseVariableHere

MAY 8, 2022

Consistency is key, reads the subtitle of Spatie's Guidelines page. "Most projects are not built or maintained by a single person. Instead, there is a collection of people involved, who all have their own personal preferences." When the Spatie team reaches a consensus about different programming preferences, they write it down.

I'm saving a link to each of their categories to review them in detail in the future.

APRIL 27, 2022

If we try to convert a literal string with decimal points—say, '123.456'—to an integer, we'll get this error.

>>> int('123.456') # Returns 123
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '123.456'

The solution is to convert the string literal into a float first and then convert it into an integer.

int(float('123.456')) # Returns 123

APRIL 18, 2022

Here's how to prompt for user input from a Makefile.

USERNAME ?= $(shell bash -c 'read -p "Username: " username; echo $$username')
PASSWORD ?= $(shell bash -c 'read -s -p "Password: " pwd; echo $$pwd')

talk:
	@clear
	@echo Username › $(USERNAME)
	@echo Password › $(PASSWORD)

You can then execute make talk.

You'll be prompted for a username and password. The variables will get stored as USERNAME and PASSWORD, respectively, and the talk command will print them out to the console.

Note that the password read prompt specifies the -p flag, which hides the characters as you type and stores its value in the PASSWORD variable.

APRIL 14, 2022

Here's an easy way to check your Python variable types.

We first define our variables.

name = "Nono"
names = ["Nono", "Bea"]
person = {"name": "Nono", "location": "Spain"}
pair = ("Getting", "Simple")

Use the isinstance() method to check their types.

# Is name a string?
isinstance(name, str) # True

# Is names a list?
isinstance(names, list) # True

# Is person a dictionary?
isinstance(person, dict) # True

# Is pair a tuple?
isinstance(pair, tuple) # True

# Is name a list?
isinstance(name, list) # False

# Is person a string?
isinstance(person, str) # False

Then we can build conditional statements based on a variable's type.

if isinstance(name, str):
  print(f'Hello, {name}!')

APRIL 9, 2022

After Rendering a scatter plot with Matplotlib, I had to add interactivity (or animation in this case) to the static Matplotlib plot.

Here's how to generate linear-looking data1, visualize it with p5.js, and save it as a high-resolution PNG image. You can see this p5 sketch in action.

// https://editor.p5js.org/nonoesp/sketches/O1_9yJYqK

let amount = 500
let xPaddingPercent = .15
let yPaddingPercent = .15
let X, y, xSize, ySize, xScale, yScale, xPadding, yPadding, lambda

function generateData() {
  xSize = width - 2*xPadding
  ySize = height - 2*yPadding
  
  X = Array.from({length: amount}, () => Math.random() * xSize)
  y = Array.from({length: amount}, () => Math.random() * ySize)
  for (let i = 0; i < X.length; i++) {
    y[i] = 3 + lambda*lambda*X[i] + y[i]
  }

  xScale = xSize / Math.max(...X)
  yScale = ySize / Math.max(...y)
}

function setup() {
  canvas = createCanvas(500, 500);
  xPadding = xPaddingPercent * width
  yPadding = yPaddingPercent * height
  setAttributes('antialias', true);
  noStroke();
  fill(50);
}

function draw() {
  background(255);
  lambda = Math.cos(0.08*frameCount+2*Math.PI) * 4 + 4
  generateData()
  for(let i = 0;i <= X.length; i++) {
    circle(xScale*X[i]+xPadding, height - yScale*y[i] - yPadding, 2)
  }  
}
Scatter plot with animated linear data in p5.js.

APRIL 6, 2022

My site parses Markdown posts into HTML and code blocks are syntax-highlighted with the highlight.js JavaScript library.

How does highlight.js work?

In a nutshell, Markdown code blocks—the content between a pair of three backticks—are parsed into <pre><code> HTML blocks.

If we take this Markdown input.

```
console.log(`Hello, highlight.js!`);
console.log(`Formatting Markdown code blocks!`);
const add = (a: number, b: number) => a + b
add(2, 3) // Returns 5
```

The Markdown parser converts it into a <pre><code> HTML block.

<pre><code>console.log(`Hello, highlight.js!`);
console.log(`Formatting Markdown code blocks!`);
const add = (a: number, b: number) => a + b
add(2, 3) // Returns 5
</code></pre>

Which is then highlighted by highlight.js.

console.log(`Hello, highlight.js!`);
console.log(`Formatting Markdown code blocks!`);
const add = (a: number, b: number) => a + b
add(2, 3) // Returns 5

How can you use highlight.js on your site?

This is all the HTML code you really need.

  • The HTML code block
  • Loading highlight.js
  • Optionally loading a highlight.js CSS style
  • Initialize highlight.js
<!-- Code block -->
<pre><code>console.log(`Hello, highlight.js!`);
console.log(`Formatting Markdown code blocks!`);
const add = (a: number, b: number) => a + b
add(2, 3) // Returns 5
</code></pre>

<!-- Load highlight.js from a CDN -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.0/highlight.min.js"></script>

<!-- Optionally load a template from a CDN -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.0/styles/atom-one-light.min.css" integrity="sha512-o5v54Kh5PH0dgnf9ei0L+vMRsbm5fvIvnR/XkrZZjN4mqdaeH7PW66tumBoQVIaKNVrLCZiBEfHzRY4JJSMK/Q==" crossorigin="anonymous" referrerpolicy="no-referrer" />

<!-- Initialize highlight.js -->
<script>hljs.initHighlightingOnLoad();</script>

How can you add dark mode support to highlight.js?

In my case, I create custom templates or use the ones provided by highlight.js. The only tweak to support the system's appearance—light and dark mode—is to use CSS's prefers-color-scheme to target whether the user has the system's dark mode enabled.

/* highligh-styles.js */

/* Light mode highlight.js theme goes here */

@media screen and (prefers-color-scheme: dark) {
  /* Dark mode highlight.js theme goes here */
}

Thanks to Nino. This post is a reply to his question on Twitter.

APRIL 2, 2022

I was getting this error when trying to git add and git commit code changes in my repository.

fatal: Unable to create '.git/index.lock': File exists.

Another git process seems to be running in this repository, e.g.
an editor opened by 'git commit'. Please make sure all processes
are terminated then try again. If it still fails, a git process
may have crashed in this repository earlier:
remove the file manually to continue.

Simply removing the .git/index.lock file made everything go back to normal.

rm .git/index.lock

Nothing broke and I could immediately add and commit new files.

MARCH 7, 2022

Here's a straightforward way to copy a file with Python to a different path or directory, also useful to duplicate or version a file with a different name.

import shutil

from = '/path/to/origin/file.md'
to = '/path/to/destination/new-name.md'

shutil.copy(from, to)

Source

JANUARY 24, 2022

Here’s a summary guide I followed to install MongoDB PHP extension on a MacBook (M1, 2020).

# First, check whether the extension already exists
› php --ri mongodb
# Extension 'mongodb' not present.

# Let's install the extension
sudo pecl install mongodb

# Wait a few minutes..
# Failed!
# /opt/homebrew/Cellar/php/8.1.1/include/php/ext/pcre/php_pcre.h:23:10: fatal error: 'pcre2.h' file not found
# Let's copy a missing file

cp /opt/homebrew/Cellar/pcre2/10.39/include/pcre2.h /opt/homebrew/Cellar/php/8.1.1/include/php/ext/pcre/pcre2.h

# Let's try installing again
sudo pecl install mongodb
# Build process completed successfully
# Installing '/opt/homebrew/Cellar/php/8.1.1/pecl/20210902/mongodb.so'
# install ok: channel://pecl.php.net/mongodb-1.12.0
# Extension mongodb enabled in php.ini

# Success!
# Let's look for MongoDB now

› pecl list | grep mongo
# mongodb 1.12.0  stable

# Let's check whether the extension exists again
› php --ri mongodb
# mongodb
#
# MongoDB support => enabled
# MongoDB extension version => 1.12.0
# MongoDB extension stability => stable
# libbson bundled version => 1.20.0
# libmongoc bundled version => 1.20.0
# libmongoc SSL => enabled
# libmongoc SSL library => Secure Transport
# libmongoc crypto => enabled
# libmongoc crypto library => Common Crypto
# libmongoc crypto system profile => disabled
# libmongoc SASL => enabled
# libmongoc ICU => disabled
# libmongoc compression => enabled
# libmongoc compression snappy => disabled
# libmongoc compression zlib => enabled
# libmongoc compression zstd => enabled
# libmongocrypt bundled version => 1.3.0
# libmongocrypt crypto => enabled
# libmongocrypt crypto library => Common Crypto
#
# Directive => Local Value => Master Value
# mongodb.debug => no value => no value
# mongodb.mock_service_id => Off => Off

# Get your installed mongodb.so path
› pecl list-files mongodb | grep mongodb.so
# src  /opt/homebrew/Cellar/php/8.1.1/pecl/20210902/mongodb.so

# Find your php.ini path
› php --ini
# Configuration File (php.ini) Path: /opt/homebrew/etc/php/8.1
# Loaded Configuration File:         /opt/homebrew/etc/php/8.1/php.ini
# Scan for additional .ini files in: /opt/homebrew/etc/php/8.1/conf.d
# Additional .ini files parsed:      /opt/homebrew/etc/php/8.1/conf.d/ext-opcache.ini

# Open with your favorite editor
› code /opt/homebrew/etc/php/8.1/php.ini

# Comment out the line that says
# extension="mongodb.so"

# Add the path to mongodb.so
extension="/opt/homebrew/Cellar/php/8.1.1/pecl/20210902/mongodb.so"

# Optionally, you could create a separate extension configuration file
› touch /opt/homebrew/etc/php/8.1/conf.d/ext-mongodb.ini
› code touch /opt/homebrew/etc/php/8.1/conf.d/ext-mongodb.ini

# Then add the path to mongodb.so in that file
extension="/opt/homebrew/Cellar/php/8.1.1/pecl/20210902/mongodb.so"

# Verify your configuration
› php -i | grep mongodb
# Additional .ini files parsed => /opt/homebrew/etc/php/8.1/conf.d/ext-mongodb.ini,
# mongodb
# mongodb.debug => no value => no value
# mongodb.mock_service_id => Off => Off

Here’s a summary guide I followed to install MongoDB PHP extension on a MacBook (M1, 2020).

# First, check whether the extension already exists
› php --ri mongodb
# Extension 'mongodb' not present.

# Let's install the extension
sudo pecl install mongodb

# Wait a few minutes..
# Failed!
# /opt/homebrew/Cellar/php/8.1.1/include/php/ext/pcre/php_pcre.h:23:10: fatal error: 'pcre2.h' file not found
# Let's copy a missing file

cp /opt/homebrew/Cellar/pcre2/10.39/include/pcre2.h /opt/homebrew/Cellar/php/8.1.1/include/php/ext/pcre/pcre2.h

# Let's try installing again
sudo pecl install mongodb
# Build process completed successfully
# Installing '/opt/homebrew/Cellar/php/8.1.1/pecl/20210902/mongodb.so'
# install ok: channel://pecl.php.net/mongodb-1.12.0
# Extension mongodb enabled in php.ini

# Success!
# Let's look for MongoDB now

› pecl list | grep mongo
# mongodb 1.12.0  stable

# Let's check whether the extension exists again
› php --ri mongodb
# mongodb
#
# MongoDB support => enabled
# MongoDB extension version => 1.12.0
# MongoDB extension stability => stable
# libbson bundled version => 1.20.0
# libmongoc bundled version => 1.20.0
# libmongoc SSL => enabled
# libmongoc SSL library => Secure Transport
# libmongoc crypto => enabled
# libmongoc crypto library => Common Crypto
# libmongoc crypto system profile => disabled
# libmongoc SASL => enabled
# libmongoc ICU => disabled
# libmongoc compression => enabled
# libmongoc compression snappy => disabled
# libmongoc compression zlib => enabled
# libmongoc compression zstd => enabled
# libmongocrypt bundled version => 1.3.0
# libmongocrypt crypto => enabled
# libmongocrypt crypto library => Common Crypto
#
# Directive => Local Value => Master Value
# mongodb.debug => no value => no value
# mongodb.mock_service_id => Off => Off

# Get your installed mongodb.so path
› pecl list-files mongodb | grep mongodb.so
# src  /opt/homebrew/Cellar/php/8.1.1/pecl/20210902/mongodb.so

# Find your php.ini path
› php --ini
# Configuration File (php.ini) Path: /opt/homebrew/etc/php/8.1
# Loaded Configuration File:         /opt/homebrew/etc/php/8.1/php.ini
# Scan for additional .ini files in: /opt/homebrew/etc/php/8.1/conf.d
# Additional .ini files parsed:      /opt/homebrew/etc/php/8.1/conf.d/ext-opcache.ini

# Open with your favorite editor
› code /opt/homebrew/etc/php/8.1/php.ini

# Comment out the line that says
# extension="mongodb.so"

# Add the path to mongodb.so
extension="/opt/homebrew/Cellar/php/8.1.1/pecl/20210902/mongodb.so"

# Optionally, you could create a separate extension configuration file
› touch /opt/homebrew/etc/php/8.1/conf.d/ext-mongodb.ini
› code touch /opt/homebrew/etc/php/8.1/conf.d/ext-mongodb.ini

# Then add the path to mongodb.so in that file
extension="/opt/homebrew/Cellar/php/8.1.1/pecl/20210902/mongodb.so"

# Verify your configuration
› php -i | grep mongodb
# Additional .ini files parsed => /opt/homebrew/etc/php/8.1/conf.d/ext-mongodb.ini,
# mongodb
# mongodb.debug => no value => no value
# mongodb.mock_service_id => Off => Off

JANUARY 18, 2022

Here's a simple way to check the MD5 checksum of a file in order to verify the origin of a file.

Open the Terminal app.

Type the following and hit Enter.

md5 /path/to/file
# MD5 (/path/to/file) = 64e7749cc4a60ec3d80707d0d69f5c1c

Note that you can also type md5 and then drag a file to the Terminal windows. Then hit Enter to run the command.

DECEMBER 21, 2021

Say you have a long list of numbers and you want to add them together, or maybe you wish to multiply them or do some other series of operations, to all of them. You can use a reducer, and here's a sample of how to define a reducer as a simply add-two function to add an entire list of numbers.

const numbers = [20, 30, 50];
const reducer = (previousValue, currentValue) => {
  return previousValue + currentValue;
}
const result = numbers.reduce(reducer); // 100

You could easily parse a plain-text list as well.

const text = '1.75 Milk\n0.70 Bread\n2.56 Yogurt';
const numbers = text.split('\n').map(s => parseFloat(s.split(' ')[0]));
const reducer = (previousValue, currentValue) => {
  return previousValue + currentValue;
}
const result = numbers.reduce(reducer); // 5.01

Want to see older publications? Visit the archive.

Listen to Getting Simple .