TIL about CSS Grid and actually used it in a project to lay out blog posts. I put in a fall back to flexbox for older browsers.



I listened to most of “A Mind at Play: How Claude Shannon Invented the Information Age” on a road trip today. I learned that all forms of communication share the same basic elements, no matter the sender or medium.
Claude Shannon, the father of information theory, published “A Mathematical Theory of Communication” in 1948, which laid out these basic elements:
Here is a diagram I drew of these elements:

All forms of communication share these same basic elements, including:

We emphasize the importance of working out loud throughout our curriculum. Each of our participants make portfolio sections on their websites where they collect projects theyâve built. How you package and present your projects matter as much as the projects themselves! Here are some general guidelines for what makes a good project write up. https://discoverpraxis.com/guidelines-putting-projects-display/Archived Link

git pull.Here is my testing and deploying workflow:

git push staging master – Sends the code up to the staging server on WPengine. If I have database changes to migrate, I do so immediately afterward. For pages/posts I use the general WordPress exporter. For theme settings, both main theme frameworks I use (Genesis and Total) both have theme settings import/export features. For widgets, I use the Widget Settings Importer/Exporter plugin.git push production master. This pushes my already tested code to the production environment. No code touches production without having been tested on staging first. If database changes need to be moved over, I’ll either use WPEngine’s Deploy Site tool for big changes, or export them from Staging and import them on Production for smaller changes or times when the database on Production is significantly out of sync with staging.At the end of my work day, I back up my work:

This is a two-part process:
git push github master pushes my day’s commits up to Github.gulp dumpDatabase dumps my database from Homestead and saves it to my hard drive, which gets replicated within 30 minutes to Backblaze.
Yesterday I worked on building the new Praxis website for 12 hours straight, from 12-12, after spending the morning on coaching calls with Praxis participants. I was getting a lot of good work done, then I hit a wall with coding out this timeline:

I tried a bunch of different solutions for about three hours. Nothing worked. I got frustrated and almost convinced myself that this just couldn’t be done. It was about midnight at this point. I knew how to make the month boxes offset from each other on the left and right and make the whole thing responsive OR make the month boxes overlapping like this and the whole thing static/non-responsive. But not both.
Then, thankfully, I took a step back for a brief moment. The designer we contracted to design this is well-known and a great web developer in his own right. I was pretty sure that he wouldn’t design something that he couldn’t actually build himself. So I emailed him and asked for guidance.
Within a few hours he got back to me with a rough solution. He immediately pointed out two things that alluded me:
With an hour and a half, I took the rough solution he outlined and turned it into a fully functioning polished version of the design.
This was a great reminder for me:

How do you address being fired when asked in an interview? Turn it into a growth story. https://discoverpraxis.com/turn-defeat-growth-story/Archived Link

Up until last week, Sass breakpoints were a bit of a mystery to me. I finally figured out how they work.
First, they are programmatically generated. Define the breakpoints as a map. I use the list here.
$breakpoints: ( xs: 512px, sm: 768px, md: 896px, lg: 1152px, xl: 1280px );
Next, use a mixin and expressions to build the media queries. I use min-width. I leave it as an exercise for the reader if you wish to reverse this to use max-width instead.
@mixin breakpoint( $breakpoint ) { @if map-has-key( $breakpoints, $breakpoint ) { @media ( min-width: #{ map-get( $breakpoints, $breakpoint ) } ) { @content; } } @else if type_of( $breakpoint ) == number and unit( $breakpoint ) == px or unit( $breakpoint ) == em or unit( $breakpoint ) == rem { @media (min-width: $breakpoint ) { @content; } } @else { @warn "No value could be retrieved from `#{$breakpoint}`. " + "It is either not defined in the `$breakpoints` map, or it is an invalid number of px, em, or rem."; } }
To use, define your breakpoint styles using @import. Here is an example defining H1 font sizes at three different breakpoints:
h1 { text-transform: capitalize; @include breakpoint(xs) { font-size: 2.2em; } @include breakpoint(sm) { font-size: 2.7em; } @include breakpoint(xl) { font-size: 3em; } }

I saw this question on Reddit: I recently graduated with a degree in business management, but Iâm having a hard time finding a management job. Iâm not getting any interviews because I have no experience. What can I do? Here is my answer: https://discoverpraxis.com/10-steps-becoming-manager/Archived Link

Yesterday I threw down a challenge to the Praxis community: 12 Days of Christmas Blogging. Blog every day from the 13th until Christmas. Flex that shipping muscle in the face of holiday obligations and time constraints. Stay on that grind when it is easy to let it slip.
Iâm playing with fire here because I have to ship, too. Like all good challenges, the blade has to cut both ways in order for it to be any fun.
Here is yesterdayâs post: How can I come up with more ideas?Archived Link
This reminds me of my favorite Christmas story: Sir Gawain and the Green Knight.

The story opens with at King Arthurâs court where he and his men are exchanging gifts and getting ready to feast. A gigantic green figure atop a green horse rides into the court with an axe and a piece of holly. He challenges the court to âa Crystemas Gomanâ – someone can strike him with his axe and he will return the stroke in a year and a day. Sir Gawain rises to the challenge and promptly lops off the knightâs head with his own axe. Not missing a beat, the knight picks his head up off of the floor, reminds Sir Gawain that they have date at the Green Chapel in a year and a day, then rides off as abruptly as he arrived.
I wonât ruin the rest for you. Give it a read this Christmas! The story teems with vivid, meaningful descriptions, double meanings, alliteration, imagery, and symmetry. It is a wonderful read.
To mark the occasion of my own Crystemas Goman, here is a translation I did of my favorite passage. I used Casey Finchâs Complete Works of the Pearl Poet for the text and the Oxford English Dictionary for reference of word meanings.
'Nay, frayst I no fyÈt, in fayth I þe telle; 279 Hit arn aboute on þis bench bot berdlez chylder. If I were hasped in armes on a heÈe stede, Here is no mon me to mach, for myÈtez so wayke. Forþy I craue in þis court a Crystemas gomen, For hit is Èol and Nwe Èer, and here ar Èep mony: If any so hardy in þis hous holdez hymseluen, Be so bolde in his blod, brayn in hys hede, Ãat dar stifly strike a strok for an oþer, I schal gif hym of my gyft þys giserne ryche, Ãis ax, þat is heué innogh, to hondele as hym lykes, And I schal bide þe fyrst bur as bare as I sitte. 290
âNay, on my word, I seek no fight; 279 There are about these benches but beardless children. If I were fastened in armor on a noble steed, There is no man here to match me, for their strength is weak. And so I ask in this court for a Christmas game, For it is Yule and the New Year, and here are many agile fellows. If any in this hall holds himself hardy enough, Be so bold in his blood, mad in his mind, That dare swiftly strike one stroke for another, And I shall give him as my gift this well-wrought guisarme, This axe, that is plenty heavy, to handle as he likes, And I shall endure the first blow as bare as I sit. 290

The old saying, âYou are what you eatâ, applies to the creative process. If you want to be creative and come up with ideas, the best thing you can do is engage the creative ideas that are already out there. Not because you want to copy or emulate them, but because creative ideas catalyze other creative ideas. https://discoverpraxis.com/more-ideas/Archived Link

The past few days have been quite a ride in the crypto world! This rollercoaster is reminiscent of late 2013, except now there is much more skin in the game. My latest piece on Yours.org covers my history with BTC, BCH, and Ripple, and my investment and use strategies for the currencies. Read this piece over at https://www.yours.org/content/my-btc–bch–and-ripple-strategies-cb2b3d401e30.

I’m not sure that we have a bitcoin-caused environmental energy crisis on our hands. This piece on Yours.org points out some of the issues with the articles going arount about bitcoin and the environment. Read this piece over at https://www.yours.org/content/does-the-environmental-case-against-bitcoin-have-merit–656fd7d75c0f.

This afternoon I decided to try Yours.org, a site where you can write articles, decide what to charge for them, and get paid in bitcoin cash. I had an idea: If you pay and then a section is revealed to you, that doesn’t have to be just for articles. It can be used for anything digital!
A few ideas:
So, I decided to test it out. I packaged up four sets of national parks photos, put a thumbnail grid in the preview, and put a download link in the paid section:
I’m testing three different price points: $15, $10, and $5.
I also wrote a piece on how to use Yours.org for selling digital products. I priced it at $2.
In just a few hours I made over $40 in bitcoin cash! It is super exciting seeing the notifications come in while you are reading other articles. I think that the notifications are tied to transaction verifications because they come in waves. That must be when blocks get processed and transactions verified.


At Praxis we use Restrict Content Pro as the membership system for our curriculum portal. We decided that all grads get access for life, not just during the program. So, I needed a way to clear over 200 member expiration dates. The only bulk method available through the WordPress interface is to set the expiration dates to another date in the future, which would just kick my problem further down the road. So I needed to dust off my SQL knowledge and directly edit the database.
Don’t be a fool. Back up your database and test the queries on a local development version first. Never run queries for the first time on production. The backup is also a failsafe that you can restore if something goes wrong despite your testing.
I saw that all data related to Restrict Content Pro usually had rcp somewhere in the table, column, or key. So I started with the rcp tables. They had nothing to do with expiration dates, so I checked the wp_usermeta table since RCP extends the WordPress users with more functionality. Bingo. There was a column called meta_key with rcp_expiration in it with corresponding date values.
Sure, you could run your UPDATE statement first, but I like to make sure I am editing the correct data by running a SELECT statement first and then using the same WHERE clause for my UPDATE statement.
After a few stupid syntax errors, here is the SELECT statement that got exactly what I wanted. This shows the user ID so I can spot check, restricts searching to the rcp_expiration meta key, and looks for values that are not none.
SELECT user_id, meta_key, meta_value FROM wp_usermeta WHERE meta_key = 'rcp_expiration' AND meta_value != 'none';
This returned 176 results. When I changed it to show only meta values that were none, I got 31 values. 31+176=207, which is the total number of users. Looking good.
Now that we know we selected the correct data with our previous statement, it is time to craft our UPDATE statement.
Here I’m updating the wp_usermeta table and setting the meta_value to none where the meta_key is rcp_expiration and the corresponding meta_value is not none.
UPDATE wp_usermeta SET meta_value = 'none' WHERE meta_key = 'rcp_expiration' AND meta_value != 'none';
I tested this on my local machine and it updated 176 rows. Just like we wanted.
Now that we’ve tested the query in our development environment and verified that we got the results we wanted, we can run the query on the production database. If you use phpmyadmin and want to triple check that you aren’t messing anything up, you can click the “Simulate Query” button first. (I did.)
Log in to WordPress and check the RCP membership area. Verify that all expiration dates are now set to none. Also verify that your users can still log in. You should have a few user test logins specifically for this purpose. You can also check your site logs throughout the day to make sure people are still logging in. You can’t count on them always letting you know when something doesn’t work. More often than not they will just stop using it. It is up to you to verify everything works as it should!

Adding dates is tricky. Months have different numbers of days, so you can’t rely on just adding 30 days to get an extra month. You also can’t just add a certain number of months because formulas in Salesforce don’t auto increment the year. The solution is modular arithmetic and conditionals.
The goal here was to make a set of fields to send out emails on the first day of each month for 6 months, given a specific month to start with.
What I’m doing here is:
DATE( YEAR( date ) + FLOOR( ( MONTH ( date ) + number_of_months - 1 ) / 12 ), IF( MONTH ( date ) + number_of_months = 12, 12, MOD( MONTH ( date ) + number_of_months, 12 )), 01 )
How to use this: the date variable should be the date field you are starting with. You should replace number_of_months with the number of months you want to add to the original date. If the date is 07/01/2017 I want this to go out on 08/01/2017, I’d set number_of_months to 1. If 09/01/2017, I’d set it to 2, etc.
Note: This only works for the first of each month. If you need it to work on any day of the month, use this more complicated solution to account for months having different lengths.

As I mentioned a few days ago, I’m using Gulp on a new WordPress project. I like to back up my work every night, and since a lot of WordPress config and customization happens in the WordPress editor and widgets, that means backing up the mysql database as well as the code.
Why not use this newfound tool? Let’s do it.
I did some searching and found Gulp WordPress Backup, but it was overkill for what I wanted. But I saw that it used an npm package named mysqldump, for the export, so I grabbed that and started setting up a new task in gulpfile.js:
// add mysqldump as a dependency var mysqlDump = require('mysqldump'); // dumpDatabase gulp.task('dumpDatabase', () => { return new Promise((resolve, reject) => { mysqlDump({ host: 'localhost', user: 'user', password: 'pass', database: 'wp_database', dest: 'backup.sql' }, (err) => { if (err !== null) return reject(err); }); }) .catch((err) => { console.log(err); }); });
Next step: Defining the filename. I just wanted to use today’s date because I intend on running this at the end of each work day. Since gulp is all javascript, this is easy:
var today = new Date(), dd = today.getDate(), mm = today.getMonth()+1 //January is 0! yyyy = today.getFullYear(); if(dd<10) { dd = '0'+dd } if(mm<10) { mm = '0'+mm } today = mm + '-' + dd + '-' + yyyy;
Add this to the gulp task and you are good to go!
gulp.task('dumpDatabase', () => { var today = new Date(), dd = today.getDate(), mm = today.getMonth()+1 //January is 0! yyyy = today.getFullYear(); if(dd<10) { dd = '0'+dd } if(mm<10) { mm = '0'+mm } today = mm + '-' + dd + '-' + yyyy; return new Promise((resolve, reject) => { mysqlDump({ host: 'localhost', user: 'user', password: 'pass', database: 'wp_database', dest: 'SQLBackups/' + today + '.sql' // Outputs to the folder named SQLBackups and uses today's date as the filename. }, (err) => { if (err !== null) return reject(err); }); }) .catch((err) => { console.log(err); }); });
Make sure you add mysqldump to your project’s package.json, or at least run npm install mysqldump before using!

When I updated to macOS High Sierra, a bunch of necessary stuff broke: Jekyll, Homebrew, Node.js, and a bunch of gems. s3_website, the tool I use to deploy my Jekyll site to S3, was one of the gems that just completely disappeared. When I went to reinstall it, I got an error that I didn’t have Java installed. Against my better judgment, I went to the URL listed and installed it. Then I ran s3_website push.
After about 30 seconds, I got an error saying that s3_website doesn’t work with Java 9, which was the most recent version at the link. And also the version you get with brew cask install java. Well, shit.
Exception in thread "main" java.lang.ExceptionInInitializerError at org.jruby.Ruby.newInstance(Ruby.java:266) at s3.website.Ruby$.rubyRuntime$lzycompute(Ruby.scala:4) at s3.website.Ruby$.rubyRuntime(Ruby.scala:4) at s3.website.model.Config$$anonfun$15.apply(Config.scala:229) at s3.website.model.Config$$anonfun$15.apply(Config.scala:227) at scala.util.Try$.apply(Try.scala:192) at s3.website.model.Config$.erbEval(Config.scala:227) at s3.website.model.Site$$anonfun$2.apply(Site.scala:28) at s3.website.model.Site$$anonfun$2.apply(Site.scala:27) at scala.util.Success.flatMap(Try.scala:231) at s3.website.model.Site$.parseConfig(Site.scala:27) at s3.website.model.Site$.loadSite(Site.scala:100) at s3.website.Push$.push(Push.scala:62) at s3.website.Push$.main(Push.scala:40) at s3.website.Push.main(Push.scala) Caused by: java.lang.RuntimeException: unsupported Java version: 9 at org.jruby.RubyInstanceConfig.initGlobalJavaVersion(RubyInstanceConfig.java:1878) at org.jruby.RubyInstanceConfig.(RubyInstanceConfig.java:1585) ... 15 more
After lots of searching, I came across a kind soul on Github suggesting that we use jEnv to define which java environment to use in the directory.
When I first installed jenv, I couldn’t add versions to the tool. I kept getting this error:
ln: /usr/local/opt/jenv/versions/oracle64-9.0.1: No such file or directory
The fix is described here: https://github.com/gcuisinier/jenv/wiki/Trouble-Shooting. Once I added version 8 as well, I switched to version 8 locally with this:
jenv local oracle64-1.8.0.151
Then I opened a fresh Terminal window and ran s3_website again and everything pushed up to s3 without an issue.

The line-height attribute doesn’t work on span by default. If you need to use line-height on a span, you’ll need to set display:block; on the span element to make it display as a block element (like
).

While working on the 51 Line Charts for my Opioid Crisis data visualization, I ran into an issue with generating all 51 charts at the same time: The data was either in 51 rows stacked and I couldn’t access the dates effectively, or 306 rows unstacked and I had 6x as many objects as I needed when I did a join.
The solution was to use D3.nest. Nesting allows elements in an array to be grouped into a hierarchical tree structure; think of it like the GROUP BY operator in SQL, except you can have multiple levels of grouping, and the resulting output is a tree rather than a flat table. The levels in the tree are specified by key functions.
When I used the state as a key, it grouped each state’s data together in a tree.
Input:
state,code,year,deaths,adjrate Alabama,1,2010,547,11.8 Alabama,1,2011,552,11.8 Alabama,1,2012,562,12.1 Alabama,1,2013,598,12.7 Alabama,1,2014,723,15.2 Alabama,1,2015,736,15.7 Alaska,2,2010,83,11.6 Alaska,2,2011,107,14.2 Alaska,2,2012,129,17.4 Alaska,2,2013,105,14.4 Alaska,2,2014,124,16.8 Alaska,2,2015,122,16 Arizona,4,2010,1098,17.5 Arizona,4,2011,1071,16.9 Arizona,4,2012,1134,17.7 Arizona,4,2013,1222,18.7 Arizona,4,2014,1211,18.2 Arizona,4,2015,1274,19 Arkansas,5,2010,350,12.5 Arkansas,5,2011,355,12.6 Arkansas,5,2012,373,13.1 Arkansas,5,2013,319,11.1 Arkansas,5,2014,356,12.6 Arkansas,5,2015,392,13.8
D3 code:
d3.nest() .key(function(d) { return d.state; }) .entries(data);
Output:
[ { "key": "Alabama", "values": [ { "state": "Alabama", "code": "1", "year": "2010", "deaths": "547", "adjrate": "11.8" }, { "state": "Alabama", "code": "1", "year": "2011", "deaths": "552", "adjrate": "11.8" }, { "state": "Alabama", "code": "1", "year": "2012", "deaths": "562", "adjrate": "12.1" }, { "state": "Alabama", "code": "1", "year": "2013", "deaths": "598", "adjrate": "12.7" }, { "state": "Alabama", "code": "1", "year": "2014", "deaths": "723", "adjrate": "15.2" }, { "state": "Alabama", "code": "1", "year": "2015", "deaths": "736", "adjrate": "15.7" } ] }, { "key": "Alaska", "values": [ { "state": "Alaska", "code": "2", "year": "2010", "deaths": "83", "adjrate": "11.6" }, { "state": "Alaska", "code": "2", "year": "2011", "deaths": "107", "adjrate": "14.2" }, { "state": "Alaska", "code": "2", "year": "2012", "deaths": "129", "adjrate": "17.4" }, { "state": "Alaska", "code": "2", "year": "2013", "deaths": "105", "adjrate": "14.4" }, { "state": "Alaska", "code": "2", "year": "2014", "deaths": "124", "adjrate": "16.8" }, { "state": "Alaska", "code": "2", "year": "2015", "deaths": "122", "adjrate": "16" } ] }, { "key": "Arizona", "values": [ { "state": "Arizona", "code": "4", "year": "2010", "deaths": "1098", "adjrate": "17.5" }, { "state": "Arizona", "code": "4", "year": "2011", "deaths": "1071", "adjrate": "16.9" }, { "state": "Arizona", "code": "4", "year": "2012", "deaths": "1134", "adjrate": "17.7" }, { "state": "Arizona", "code": "4", "year": "2013", "deaths": "1222", "adjrate": "18.7" }, { "state": "Arizona", "code": "4", "year": "2014", "deaths": "1211", "adjrate": "18.2" }, { "state": "Arizona", "code": "4", "year": "2015", "deaths": "1274", "adjrate": "19" } ] } ]
A few useful tools and resources for understanding d3.nest:

I’ve used Coda by Panic as my IDE of choice for 10 years now, but I think it is starting to fall behind other tools. It isn’t updated often and there aren’t nearly as many community-built packages as other tools have. So I’m giving both Atom and Sublime a try. I’m trying Atom first.
In my first few days of use, here are some things I love:

I’m working on a new WordPress theme development project and using Gulp and Sketch for the first time. Here are my first use notes:
gulpfile.js
Here are the tasks I’m using:
gulp styles — Compile, autoprefix and minify Sass files.gulp scripts — Minify javascript files.gulp images — Compress and optimize images.gulp watch — Compile assets when file changes are made, start BrowserSyncgulp — Default task – runs all of the above tasks.gulp zip — Package theme into zip file for distribution, ignoring node_modules.TLDR pages – Simplified man pages with practical examples. Probably covers 80% of your daily use cases. Looks super cool.
Great email from Paul Jarvis’s Sunday Dispatches this week. The relationship doesn’t end once you make the sale. That is just the beginning. Don’t be the hot tub guy.
I got this error today when trying to partition a Western Digital My Passport 4TB:
Volume erase failed: Media kit reports not enough space on device
Nothing I could do inside Disk Utility worked. Thanks to some kind soul on Reddit, here is how I solved the issue from the command line:
$ diskutil list
$ diskutil unmountDisk force disk2 #replace disk2 with your disk number
and then write zeros to the boot sector:
$ sudo dd if=/dev/zero of=/dev/disk2 bs=1024 count=1024
Attempt to partition it again:
$ diskutil partitionDisk disk2 GPT JHFS+ "My External HD" 0g
Sometimes I get off track. This is what I need to do to get back on track: