Archive for the ‘Coding’ Category

Sublime Text 4 Build 4113 is Out

Wednesday, July 14th, 2021

Sublime Text 2

This morning I saw a tweet that a new version of Sublime Text 4 is out - and given the few little issues I've seen, I was quick to upgrade and see what the release notes said. What I read was that there were significant speed improvements, along with improvements in the OpenGL rendering, and several fixes in the specifics of the UI rendering. There was only one Mac-specific issue, and that was related to the Dark/Light scheme, which is fine, but doesn't worry me.

When I started using it, I was pleased to see that I didn't see any of the problems I'd seen before, and the editor seemed zippy - so what's not to like? πŸ™‚ I have a new TypeScript project I'm about to start, so we'll see how it handles that load as well.

Nice Updates to GitHub Codespaces

Friday, June 25th, 2021

GitHub Source Hosting

When last I looked at GitHub Codespaces, it had a few issues that meant I couldn't really do all the development I needed because it couldn't yet forward ports on the web-based UI. I found a way to run Postgres on a Codespace, so I'd have a built-in database, and it was persistent across restarts - which was marvelous. And I could customize the UI to be pretty much exactly what I needed to get work done.

But it was that nagging port forwarding that really meant I couldn't get real work done - not like I could on my laptop. And then I decided to give it another look... and they have not been sitting idly by. πŸ™‚

The latest update to Codespaces has a much improved UI in the browser. It seems nearly native on my iPad Pro, and handles both the touch and trackpad gestures. Very nicely done. It also has a slight difference on the mounting of the work, so I had to update the cleanup() script in my .bashrc file:

  #
  # This is a simple function to cleanup the GitHub Codespace once it's been
  # created. Basically, I need to remove the left-overs of the dotfiles setup
  # and clean up the permissions on all the files.
  #
  function cleanup () {
    pushd $HOME
    echo "cleaning up the dotfiles..."
    rm -rf dotfiles install README.md
    echo "resetting the ownership of the /workspaces..."
    sudo chown -R drbob:drbob /workspaces
    echo "cleaning up the permissions on the /workspaces..."
    sudo chmod -R g-w /workspaces
    sudo chmod -R o-w /workspaces
    sudo setfacl -R -bn /workspaces
    echo "done"
    popd
  }

and with this, all my new Codespaces will have the right permissions, and the terminal will look and act like it should. Not too bad a change. But the real news is in the forwarded ports.

It appears that what GitHub has done is to open the port(s) on the running Docker image so that you can easily open a browser to the jetty port 8080 service that's running. It's really just as good as the port forwarding, and it completes the last needed capability to use Codespaces for real development.

If there was one more thing I'd wish for - it's that this would be included in the GitHub iPad app - so that the files are held locally, and edited locally, and the connection to the Docker instance is remote, but you can work locally.

Maybe soon. πŸ™‚

GitHub Actions are Very Impressive

Wednesday, June 16th, 2021

GitHub Source Hosting

Several weeks ago, The Shop made the decision to implement CI/CD on the code repositories at GitHub using GitHub Actions. And it has been an amazing success. The ability to set up individual responses to GitHub actions like push, and so on. It's also very nice that it's all done in parallel, which is very nice for speed.

One of the things I have really enjoyed about the Actions is that GitHub gives each project quite a lot of free compute minutes for the execution of the Actions. This means that if you have a relatively static project, this is likely something you will be able to use for free. And if it's a business, you could prove out that this will work for you before having to invest in more tooling.

When you do run up against the limits of the free plan, the only thing that will happen is that the Actions will all fail. This is completely understandable, and a very reasonable fall-back position for projects. Add a billing source, and you're back in business. Very nicely done.

Wishing for new Apple Silicon MacBook Pros

Wednesday, March 24th, 2021

Apple Computers

Like many folks that are developers, I'm very interested in what the new 16" MacBook Pros with Apple Silicon will be like. Right now, I'm really focusing on a few key features I've read, and seen, on the 13" MacBook Pros with M1 chips: the Display handling, and the Operating temperatures.

Right now, I've got a couple of LG 5K monitors, and my 16" MacBook Pro can drive them, but the temperature of the laptop starts to rise, and then the kernel_task rises, and the box essentially becomes unusable. I understand all the reasons for the kernel_task, and how it keeps the machine from overheating. And I've blown out my recent-vintage 16" MacBook Pro, so it's not an obvious issue, but I get it... I'm driving big 5K monitors, and that heats up the laptop.

From what I've read, the new Apple Silicon MacBook Pro can drive one 6K monitor, or two 4K monitors - just like the new Mac mini. Which is nice, and I'm just betting that the new 16" MacBook Pros will be able to drive two LG 5Ks - like the current lot can. Which will be nice. And to have no fan noise - that will be the real treat.

Which comes to the point of the thermal environment for the new laptop. I get that they need to be able to cool the components, but I'm to the point that I don't Zoom or run Google Meet on the laptop as it just makes it too hot. I can run Zoom and Meet on my iPad Pro, and it's faster, better, quieter, and I don't have to worry about a long meeting contributing to my machine slowing down.

I know it'll be the end of this year to get the new machines, but at least the new iPad Pros will be out sooner than that - and that too, will be a very nice upgrade. πŸ™‚

Google Cloud has some Nice Tools

Saturday, March 13th, 2021

Google Cloud

Today I've been working on some code for The Shop, and one of the things I've come to learn is that for about every feature, or service, of AWS, Google Cloud has a mirror image. It's not a perfect mirror, but it's pretty complete. Cloud Storage vs S3... Tasks vs. SQS... it's all there, and in fact, today, I really saw the beauty of Google Cloud Tasks over AWS SNS/SQS in getting asynchronous processing going smoothly on this project.

The problem is simple - a service like Stripe has webhooks, or callbacks, and we need to accept them, and return as quickly as possible, but we have significant processing we'd like to do on that event. There's just no time or Stripe will think we're down, and that's no good. So we need to make a note of the event, and start a series of other events that will to the more costly work.

This is now a simple design problem. How to partition the follow-on tasks to amke use of an efficient loadbalancer, and at the same time, make sure that everything is done in as atomic way as possible. For this project, it wasn't too hard, and it turned out to actually be quite fun.

The idea with Cloud Tasks is that you essientially give it a payload and a URL, and it will call that URL with that payload, until it gets a successful response (status of 200). It will back-off a bit each time, so if there is a contention issue, it'll automatically handle that, and it won't flood your service, so it's really doing all the hard work... the user just needs to implement the endpoints that are called.

What turned out to be interesting was that the docs for Cloud Tasks didn't say how to set the content-type of the POST. It assumes that the content-type is applciation/octet-stream, which is a fine default, but given the Node library, it's certainly possible to imagine that they could see that the body being passed in was an Object, and then make the content-type applciation/json. But they don't.

Instead, they leave an undocumented feature on the creation of the task:

  // build up the argument for Cloud Task creation
  const task = {
    httpRequest: {
      httpMethod: method || 'POST',
      url,
    },
  }
  // ...add in the body if we have been given it - based on the type
  if (body) {
    if (Buffer.isBuffer(body)) {
      task.httpRequest.body = body.toString('base64')
    } else if (typeof body === 'string') {
      task.httpRequest.body = Buffer.from(body).toString('base64')
    } else if (typeof body === 'object') {
      task.httpRequest.body = Buffer.from(JSON.stringify(body)).toString('base64')
      task.httpRequest.headers = { 'content-type': 'application/json' }
    } else {
      // we don't know how to handle whatever it is they passed us
      log.error(errorMessages.badTaskBodyType)
      return { success: false, error: errorMessages.badTaskBodyType, body }
    }
  }
  // ...add in the delay, in sec, if we have been given it
  if (delaySec) {
    task.scheduleTime = {
      seconds: Number(delaySec) + Date.now() / 1000,
    }
  }

The ability to set the headers for the call is really very nice, as it opens up a lot of functionality if you wanted to add in a Bearer token, for instance. But you'll have to be careful about the time... the same data will be used for retries, so you would have to give it sufficient time on the token to enable it to be used for any retry.

With this, I was able to put together the sequence of Tasks that would quickly dispatch the processing, and return the original webhook back to Stripe. Quite nice to have it all done by the Cloud Tasks... AWS would have required that I process the events off an SQS queue, and while I've done that, it's not as simple as firing off a Task and fogetting about it.

Nice tools. πŸ™‚

Fun Feature Request for iTerm2

Wednesday, December 30th, 2020

iTerm2

A few days ago, I sent an email to the iTerm2 developer, and asked him the following question:

...and maybe this is a silly request, but I would really enjoy the option to put the Emoji Picker on the TouchBar of my MacBook Pro while in iTerm2… I know it’s not a Big Deal - so dragging it off/on in the customization makes sense, but there are a lot of times in my Git commit messages that I’d like to be able to toss in an emoji

and this morning I got a (surprise) response:

Thanks for pointing this out. There’s no good reason why it shouldn’t be allowed. Commit 1ae34d90f adds it. You can test in the next nightly build, due out in about an hour. In order to avoid breaking existing setups, it’s not in the default setup. You need to choose View > Customize Touch Bar to add it.

which is perfect for what I was hoping to have.

One of the best uses I've found for the TouchBar on the MacBook Pro is the Emoji Picker - as it's perfect for Instant Messaging, and Twitterrific, and at The Shop it's a big thing to have a nice, representative emoji as the first character of a pull request title. This is OK with LaunchBar, but it's not as convenient as the TouchBar Emoji Picker, and that's really what I was hoping to use it for. But until recently, iTerm2 just didn't allow it in the configuration of the TouchBar.

I am as pleased as I can be. Sounds silly, but it's nice to see that your thoughts aren't completely left-field to others. πŸ™‚

UPDATE: the v3.4.4beta2 release has the Emoji Picker. I'm just smiling. πŸ™‚

Advent of Code 2020

Wednesday, December 2nd, 2020

Christmas Tree

Yesterday started Advent of Code 2020, and it looks to be a fun theme - Vacation - and while I'm sure it's been planned well in advance of the current pandemic, I'd like to think that the folks in charge are thinking of all of us, and making it a little more enjoyable this year... because we've been cooped up all year.

The puzzels start easy, and then build through the month, and that's just as it should be - an easy way to introduce folks to coding with fun problems as opposed to so many made-up teaching problems they run into. They always make me smile.

Is that just what we all need now? A smile? πŸ™‚

Setting up Versioned Node Environment

Wednesday, November 25th, 2020

Javascript

Today I spent a little time with a good friend helping me get going on a good, versioned Node environment - a lot like RVM for Ruby - but for Node. I wanted to do this because it looks like I might be doing some work for a Node-based company where the development is all based in Node, and I wanted to make sure I got it all set up right.

I just finished reading a nice book on ES5, ES6, Promises, async and await, and all the new features of JavaScript called Simplifying JavaScript from the Pragmatic Programmers. They are having a Thanksgiving Sale, and it seemed like a great time to pick up a book that I'd probably like on the subject. I did.

It's been a long time since I spent any real time on JavaScript, and if I'm going to be taking a bit out of this project, I wanted to make sure I had come up to speed on JavaScript, and Node as well. The book was laid out well, with all the ideas based on a decent understanding of JavaScript, but not the latest additions. It really read well to me, and I was able to finish it in two days.

So, here's what I needed to do on my 16" MacBook Pro to get things up and running... πŸ™‚

Start off by installing nodenv from Homebrew. This is the equivalent of rvm, and will manage the Node versions nicely for me.

  $ brew install nodenv

I then needed to add in the environmental set-up in my ~/.zlogin file by adding:

  # now do the nodenv stuff
  eval "$(nodenv init -)"

right after I set up my PATH and RVM environment things. It's very similar to the RVM approach, with directory-level controls, as well as system-wide defaults.

At that point, I can source my ~/.zlogin and then I'm ready to go. Next, is to install a good, long-term stable (LTS) version of Node:

  $ nodenv install 14.15.1
  $ nodenv global 14.15.1

where the second command sets that version as the global default for new projects, etc. You can always check the versions with:

  $ nodenv versions
  * 14.15.1 (set by /Users/drbob/.nodenv/version)

Next was to install a few global tools with npm that I'd need:

  $ npm install -g express-generator
  $ npm install -g nodemon
  $ nodenv rehash

where the first is the basic RESTful pattern for a service, and the latter is a way to run a Node app while monitoring the filesystem for changes to the files, and reloading them automatically. This will no-doubt prove to be exceptionally handy. The rehash command is something he's found to be nexessary when installing new global tools, as they don't seem to properly get picked up in the PATH without it. Fair enough.

At this point, we can make a new project, just to play with the new features in the book. Start by making a directory to put all this, and then use the express-generator to make the skeleton we need:

  $ mkdir playground
  $ cd playground
  $ express api --no-view

and now, in the api/ directory we have what we need to get started. Simply have npm pull everything down:

  $ cd api
  $ npm install

and we are ready to go.

There is an index.html file in the public/ directory, and we can use that... and running the Node server is as simple as:

  $ node bin/www
  ... this is the log output... 

or if we want to use the file-watching version, we can say:

  $ nodemon bin/www
  ... this is the log output... 

The port is set in the bin/www script, but I'm guessing the default is port 3000, so if you go to localhost:3000 you'll see the GET calls, and the page. Very slick... very easy. πŸ™‚

Once I get this into a git repo, or start working on a real project/git repo, I'll see if I can get it loaded up on my iPad Pro using play.js - as it appears to be able to run all this, and have a web page to hit it... so that would be very interesting to work with - given the power of the iPad Pro, and the perfect size.

UPDATE: Indeed... once I pused the code to GitHub, and then went into play.js on my iPad Pro, I could Create a new project, from a Git Clone, and putting in the repo location, and the SSH Keys, etc. it all came down. Then it was just resolving the dependencies with the UI, and then setting the "start" command to be the npm command in the package.json, and then it ran.

Open up the play.js web browser, and it's there. On port 3000, just like it's supposed to be. And editing the file, refreshing the page - it's there. No saving, it's just there. Amazing. This is something I could get used to.

Updating Postgres to 13.1 with Homebrew

Monday, November 23rd, 2020

PostgreSQL.jpg

With the update to macOS 11 Big Sur, and the updates I keep doing to my linode box, I thought it would be a nice time to update Postgres to the latest that Homebrew had - I was expecting 12.5, as that's what's latest for Ubuntu 20.04LTS at linode, and it was surprisingly easy - even with the major version update.

The standard upgrade for anything in Homebrew is:

  $ brew upgrade postgres

and it will upgrade the binaries as well as upgrade the database files - if it's a minor release change. But if it's a major release change - like it was for me from 12.x to 13.x, then you also have to run:

  $ brew postgresql-upgrade-database

and that will update the database files and place the old database files in /usr/local/var/postgres.old so after you're sure everything is running OK, you just need to:

  $ rm -rf /usr/local/var/postgres.old

and it's all cleaned up.

The one wrinkle is that I have set up the environment variable not to do automatic cleanups of the old versions of packages - because I wanted to have multiple versions of Leiningen hanging around, so I needed to clean up the old versions of postgres with:

  $ brew cleanup postgres
  Removing: /usr/local/Cellar/postgresql/11.1_1... (3,548 files, 40.3MB)
  Removing: /usr/local/Cellar/postgresql/12.1... (3,217 files, 37.7MB)  

and then the old versions are cleaned up as well.

I was expecting 12.5... but got all the way to 13.1 - nice. πŸ™‚

Getting Apache 2.4.46 + PHP 7.3.22 Going on macOS 11 Bug Sur

Friday, November 13th, 2020

Yosemite

This morning, with the update to macOS 11 Big Sur it was time perform the ritual of getting the old web development tools that I've used in the past going again - this time on macOS 11. Now I haven't used PHP in ages, and this looks to be the last time I'll have to worry about this, as Apple is going to drop PHP from their releases, and they have already dropped their Postgres support in PHP. But let's get done what we can.

Activating UserDir in Apache 2.4.46

As in the previous updates, the UserDir extension is not enabled by default, so we need to get that going right away. This enables the code to be run from the development directories, and that's a big time-saver. First, we need to enable the UserDir module in Apache, and then make a specific config file for the user in question. Start by editing /etc/apache2/httpd.conf and line 184 needs to be uncommented to read:

  LoadModule userdir_module libexec/apache2/mod_userdir.so

and then similarly on line 521 uncomment the line to read:

  Include /private/etc/apache2/extra/httpd-userdir.conf

Next, make sure that the file we just included is set up right for including the user directories. Edit /etc/apache2/extra/httpd-userdir.conf and line 16 needs to be
uncommented to read:

  Include /private/etc/apache2/users/*.conf

At this point, you need to make sure you have at least one file in the /etc/apache2/users/ directory for each user, like: drbob.conf:

  <Directory "/Users/drbob/Sites/">
      Options FollowSymLinks Indexes MultiViews ExecCGI
      Require all granted
  </Directory>

where the last line - Require all granted is new as of Apache 2.4, and without it you will get errors like:

  [Thu Dec 18 10:41:32.385093 2014] [authz_core:error] [pid 55994]
    [client fe80::7a31:c1ff:fed2:ca2c:58108] AH01630: client denied by server
    configuration: /Users/drbob/Sites/info.php

Activating PHP in Apache

The mext thing to do is to activate PHP in the supplied Apache 2 with macOS 11. This is line 187 in the file - /etc/apache2/httpd.conf and you need to uncomment it to read:

  LoadModule php7_module libexec/apache2/libphp7.so

and then verify a file called /etc/apache2/other/php7.conf exists and contains:

  <IfModule php7_module>
    AddType application/x-httpd-php .php
    AddType application/x-httpd-php-source .phps
 
    <IfModule dir_module>
        DirectoryIndex index.html index.php
    </IfModule>
  </IfModule>

which does all the other PHP configuration in a separate file to make upgrades easy.

Finishing Up

At this point, a simple restart of apache:

  $ sudo apachectl restart

and everything should be in order. Hit a URL that's a static file with the contents:

  <?php
    phpinfo();
  ?>

and you should see all the details about the PHP install - it's all there, as in older releases, but it was surprising to me to see that there was no longer any support for Postgres within the PHP version that was delivered with Big Sur. More to the point - the warning is clear - PHP will be dropped in a future macOS release. Until then, we still have:

  • PHP 7.3.22
  • MySQL 5.0.12
  • SQLite3 3.28.0

so things are still there - kinda... MySQL is still supported, for those that want that, and SQLlite3, which is likely my most logical choice, but in truth... this is progress. Folks don't do PHP development like they used to, and so it's going to go away. I'll miss it, but maybe Homebrew will have something - and I remember building it all from source before... so I can do it again - if I need to.