Recovering front-end developer, now I just write JavaScript

Starting With A Personal Trainer

I've started training with a personal trainer. But why?

Starting With A Personal Trainer
Photo by Victor Freitas / Unsplash

In April 2023, the Ghost team was on a retreat in Wales. Several members of the team are runners, and looking at the team Strava group, average distances range from 3km to 25km.

Through a little bit of peer pressure and a lot of potential FOMO, I decided to join them for a run. I had not done anything close to physical exercise since school in 2006, so I didn't know how it would go, but waking up and starting the run at 7:15 am would be an achievement in itself.

The planned loop was 3km, I made it 600 meters before my legs were jelly and my lungs were on fire.

I tapped out and retreated to a convenient bench and sat for 10 minutes. Whatever level of fitness I have is clearly not enough and I need to do something.


Rationale

Researching how to get fitter when you're skinny (190cm and 60kg) is hard. Almost all advice & marketing is about how to lose weight. There's lots of anecdotal information about how to get fitter and not lose weight, but if I'm doing this, I want to do it safely—I need someone who can see me in person to give me the right advice and instruction. I need a personal trainer.

I've toyed with the idea of hiring a PT for a while and have done a lot of Googling, but never had the kick I needed to act on it. I contacted a PT who's local, has their own gym, knows nutrition, and was reasonably priced.

I emailed, he replied, and after a few messages about my current nutrition, what I'm looking for, and availability, I was booked in for the first session on May 9th at 10:30 am.


I currently own zero gym equipment. All the clothing I have that's even remotely close to being suitable is cotton and more fashion-focused. No shoes that properly support my feet, no t-shirts that are light & breath nicely, and no shorts that allow proper movement. I have now acquired one complete outfit with the help of some nice people at a sports shop.

I don't know what to expect, so I don't know how much to prepare, so I'll leave it there until I'm told otherwise.


Post-visit

I arrived a few minutes early, saw the previous people leave, and then walked in. We exchanged pleasantries, went up to the mezzanine, filled out a form, and had a chat about nutrition, my current fitness activities, and how flexible I can be. Thankfully I work with an amazing team so flexibility isn't a big deal. Speaking of the team, I also mentioned my short-term goal of being able to complete a run with everyone on the next retreat.

We then moved on to some light cardio, which was a few minutes in a cycling machine, then a rowing machine. I was later told that I'm not the worst he's had, but there's definitely work to do. Win?

We then went back downstairs where we did some squats, press-ups, curls with some light weights, and a few other small bits.

It was only a half-hour session (starting slowly) but by the end of it, I could definitely feel my heart rate was up and my muscles had worked more than they are used to.

I think this was the perfect intro. He didn't work me too hard and it's shown both of us that's definitely work to be done and lots of ways to improve general fitness.

My homework is to drink at least 2 liters of water a day, keep a food diary, and incorporate more fruits & protein into my diet. The water part is easy (there's an app for that) but the extra nutrition part requires a bit of research to find the best way to fit it into my life.

Unshorten URLs

How to convert a list of short URLs into a list of unshortened URLs

Say you have a text file called old-urls.txt that looks like this:

https://example.com/?p=1234
https://example.com/?p=5678

We know those redirect to a fuller URL, but don't yet know what.

Run this in your terminal:

cat old-urls.txt | while read f; do echo "${f}"; curl -Ls -o /dev/null -w %{url_effective} "${f}" -O; echo "\n"; done;

And get a readout in the terminal like:

https://example.com/?p=1234
https://example.com/2022/02/03/my-post

https://example.com/?p=5678
https://example.com/2022/02/04/another-post

You can then turn that into some JSON or whatever format you need to work with.

Multiple Folders to Multiple Zips

How to create multiple zips from multiple folders

Multiple Folders to Multiple Zips
Photo by Garmin B / Unsplash

If you have a bunch of folders and want to individually zip them up, the simplest method is to right click and compress the folder. But, if you have many folders it can get tiresome.

I searched around and found a way to to run a small bash script that will loop through the top-level folders in a directory and create a zip from it.

For example, say you have:

Main folder:
  - MyFolder
  - Another Folder
  - Yet more folder

cd into the main folder, cd Main\ folder and then run one of the below:

# Loud mode
for i in */; do zip -r "${i%/}.zip" "$i"; done

# Quiet mode
for i in */; do zip -q -r "${i%/}.zip" "$i"; done

The result of the above is:

Main folder:
  - MyFolder
  - MyFolder.zip
  - Another Folder
  - Another Folder.zip
  - Yet more folder
  - Yet more folder.zip

I was using this to backup a load of working files and it worked a charm.

Happy archiving!

Download Images From a Text File

How to download images from a text file, and maybe retain the folder structure

Let's say you have a list of images that another tool has created. Let's say you need to download each of those images and then do something with them. Instead of manually pasting each URL into a browser and saving the image, this trick will do them all in one go.


Create a text file like, such as images.txt. Enter all the URLs into it like so:

https://mysite.com/image1.jpg
http://anothersite.com/lorem/ipsum/image1_1234.jpg
http://anothersite.com/profile.png?1234

Assuming you have wget installed, cd into the folder with the text file in, and run this:

wget -i images.txt

It'll download the image in the same folder, and you'll end up with a folder structure like this:

image1.jpg
image1_1234.jpg
profile.png?1234

And that's it! You now have all the images listed in the text file, saved locally.


Update: Jan 17th 2022

If you add -x after the file name, it will replicate the remote file structure. Taking our earlier example of:

https://mysite.com/image1.jpg
http://anothersite.com/lorem/ipsum/image1_1234.jpg
http://anothersite.com/profile.png?1234

With the updated command:

wget -i images.txt -x

Will yield the following:

mysite.com/image1.jpg
anothersite.com/lorem/ipsum/image1_1234.jpg
anothersite.com/profile.png?1234

Update: Nov 21st 2023

Sometimes, you might need to set a header. Here's how to do that.

header='--header=User-Agent: Mozilla/5.0 (Windows NT 6.0) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.97 Safari/537.11'
wget "$header" -i images.txt -x

Staging & Production Shopify Themes with Theme Kit

How I manage Shopify theme development

Staging & Production Shopify Themes with Theme Kit
Photo by Mohammad Rahmani / Unsplash

Shopify has a library called Theme Kit, which lets you use your local environment to build theme that then deploy to Shopify and lat yo preview on their infrastructure. Most tutorials will guide you in setting this up akin to mid 2000's development where you FTP every change to the server and view the changes on the live site.

The trouble with this comes when you want to work on something that will take more than 2 minutes, and don't want to interrupt the live site and potentially cause issues with people trying to purchase stuff. You wouldn't change the wheel on a moving car.

Thankfully, Theme Kit is configurable and there's a few ways to drastically improve this process.

There's a little bit of legwork to get started, but once done, it's simple.

On Shopify

  • Navigate to the Themes section and create a duplicate of the current live theme
  • Rename the live theme to Your Theme - Production
  • Rename the new duplicate to Your Theme - Development (To help differentiate)
  • Hit [Customise] on the Production theme, and copy the numbers in the URL. This is the theme ID.
  • And do the same for the Development theme.

At this point you should have 2 copies of the same theme, and an ID for each version of that theme.

  • Your Theme - Production123456789123
  • Your Theme - Development123456789456

Local development changes

In config.yml, set development and production environments.

development:
  password: a1b2c3d4
  theme_id: "1234"
  store: mystore.myshopify.com
  ignores:
  - themekit_ignores # Ignores files in ./.themeignore
production:
  password: a1b2c3d4
  theme_id: "1234"
  store: mystore.myshopify.com
  ignores:
  - themekit_ignores # Ignores files in ./.themeignore

Of the Commands section below, one deploys all files whether they have changed or not, so we need to make sure that any files we don't want synced are ignored. For example, config/settings_data.json caused me some headaches (it wiped all custom settings fields), so that's definitely important to ignore.

Your .themeignore file should look something like this, depending how your theme's built:

.DS_Store
node_modules
package-lock.json
package.json
gulpfile.js
config/settings_data.json

Commands

The day-to-day work involves running gulp and the below command in another shell tab.

# Upload changes to the development theme
theme watch --env=development

When I'm ready to deploy all changes, I run gulp build, and the below:

# Deploy changes to production theme
theme deploy --allow-live --env=production

Previewing things

All fo this is great, but if there's no way to preview the changes, what's the point?

Shopify lets you preview any theme installed on your site. By knowing the theme ID, you san skip the step of needing to go into Shopify and opening the preview every time you need it.

https://yourshopifystore.com/?preview_theme_id=123456789456

Now you have a staging version of your Shopify theme, and a single command to deploy that to production.

Happy theming!

Hi! I'm Paul 👋 I write code for a living. Specifically, I work at Ghost where I build & maintain the tooling that enables migrations from other platforms to Ghost.

On this blog, I mostly share random things I find interesting or useful. There is no pattern, there is no plan.