Ugly Date & File Date Organizer

Organize photos, screenshots, audio captures, and other files by date.

Photos, screenshots, audio recordings … there are countless files that are stored (or should be stored) with the event’s date in the name. And, as it becomes easier to create these, they accumulate at an ever-increasing rate… usually in one folder without any type of organization. Of course, we could take the time to organize those folders, move files into proper folders, and delete what we don’t … oh, nevermind. Who am I kidding? Nobody does that.

For me, one simple step to greatly improve the value of these files is to organize them by their event date. This would at least help me find them if I need them. Grouping all files from the same day would help narrow down what may be relevant to that specific time frame. Sadly, there is no magical command, or even a utility, that will do this easily. And, even if one exists, it surely won’t work on all of the machines I use.

Well, now there is! Enter File Date Organizer and Ugly Date!

Of course, I chose to write these two utilities using NodeJS to ensure I can use them on macOS, Windows, and Linux. That’s a no-brainer.

Writing File Date Organizer came to a screeching halt the moment I pulled in the first few files and noticed that every utility I use to create screenshots formats the file names with a completely different convention…

Screen Shot 2016-07-29 at 6.11.png
Screenshot 2014-09-07 13.36.45.png
Snapshot-3208-2016-10-11-08-31-16.JPG

Even worse was the error I received when I tried to use MomentJS (the de facto utility for untangling these odd formats) to untangle those formats…

Deprecation warning: value provided is not in a recognized ISO format. moment construction falls back to js Date(), which is not reliable across all browsers and versions. Non ISO date formats are discouraged and will be removed in an upcoming major release. Please refer to http://momentjs.com/guides/#/warnings/js-date/ for more info.

After doing a bit of research, and seeing what options exist out there for detecting date formats, I understood why MomentJS decided to pull out their detection logic. Virtually every plugin or library out there uses basic RegEx (at best) to find four-digit years, two-digit minutes, or similar and fails miserably. They seem to all want so badly to return a value that they make assumptions along the way. In the end, most of them return bad values instead of no values at all… which, in my opinion, is the worst possible scenario. This is where Ugly Date comes into play.

Ugly Date is a bit of an experiment and takes a slightly different approach to parsing. Instead of simply using a series of RegEx patterns, Ugly Date contains groups of patterns and validators with the intent on locating possible matches, within the value, and then scores and compares those results with each other to return the best pattern versus returning any qualifying pattern. The change feels like a bit of a tradeoff. In the beginning, it will mean more maintenance and adding of patterns. However, over time, it should mean a better result when detecting more diverse patterns. Basically, you supply a string and Ugly Date parses it and returns both the date as well as a slew of potentially helpful information:

{
  "date": "2015-07-09T17:33:25.000Z"
  "hasDate": true,
  "hasDay": false,
  "hasTime": true,
  "pattern": "Screen Shot YYYY-MM-DD at hh.mm.ss a",
  "value": "Screen Shot 2015-07-09 at 1.33.25 PM",
  "values": {
    "YYYY": 2015,
    "MM": 7,
    "DD": 9,
    "h": 1,
    "mm": 33,
    "ss": 25,
    "aa": "PM"
  },
  "locations": [
    {
      "formal": "YYYY-MM-DD",
      "pattern": "YYYY-MM-DD",
      "position": 12,
      "type": "DATE",
      "value": "2015-07-09",
      "values": {
        "YYYY": 2015,
        "MM": 7,
        "DD": 9
      }
    },
    {
      "formal": "hh.mm.ss a",
      "pattern": "h:mm:ss aa",
      "position": 26,
      "type": "TIME",
      "value": "1.33.25 PM",
      "values": {
        "h": 1,
        "mm": 33,
        "ss": 25,
        "aa": "PM"
      }
    }
  ]
}

Unlike its sister, File Date Organizer is far simpler than Ugly Date. There’s really nothing magical happening under the hood. You supply the source & target folders, tell it if you want to move or copy, overwrite or ignore, and let it go. In turn, it uses the logic within Ugly Date to parse each file and move them into a folder structure with a property date hierarchy:

The command itself is fairly logical with many “either / or” type of choices. Other than the source and target folder paths, the rest is somewhat a la carte. The basic command…

file-date-organizer \
  --source "/Users/flackey/Documents/Screenshots" \
  --target "/Volumes/MPHD01/Screenshots" \
  --use-name \
  --move

…can be swapped out with several other options. For example…

--move or --copy
--ignore or --overwrite
--use-created or --use-modified (for filenames not having a date)

It will also build your target folder structure using almost any of the date sections by using various “--add” switches. For example, adding --add-second causes the entire folder structure to be built all the way down to the seconds in the date value (ie, /YYYY/MM/dd/HH/mm/ss). There is a full list of switches on the project page. And, of course, the library can be used programmatically by pulling it into a Node project.

Granted, none of this is a perfect solution. And, Ugly Date is taking a very different approach to parsing dates compared to more traditional libraries. If nothing else, this satisfied the anal-retentive side of my brain.

Can Teachers Think Outside of the Box? - David Cutler - Medium

New Tool: File Line Replacer

There a new command-line tool for searching files, scanning those files for blocks of multi-line content and then replacing those blocks with different lines. Some benefits of this are…

  • works on Windows, Mac, and Linux
  • no nasty RegEx or escape characters to specify multi-line values
  • backs up original files before making changes (if desired)
  • whitespace is either ignored or preserved … your choice
  • supports text files of virtually any size

Yes, I realize there are other utilities out there that will replace text… sed, awk, etc. PowerShell will even do it if you know the switches. However, in my opinion, all of them are heavily opinionated and take the geek-first approach. I wanted something I could give to a junior or mid-level person and know they can get the job done without spending their time researching how to structure some overly complex command.

DbSchema Example Model
DbSchema Example Model

One of the best tool sets for prototyping a relational data service is…

DbSchema : for brainstorming an designing the entities;

ExpressJS : probably the best web framework for hosting the web service; and,

Sequelize ORM : to generate the models and handle the data calls.

My original need came while using Sequelize to generate model files while for a new data service. I’m not sure what caused it (maybe switching between MySQL and PostgreSQL) but the models did not include logic for auto-incrementing primary key fields. So, models ended up having this

id: {
  type: DataTypes.INTEGER.UNSIGNED,
  allowNull: false,
  primaryKey: true
},

… when they should have had this

id: {
  type: DataTypes.INTEGER.UNSIGNED, 
  autoIncrement: true, 
  primaryKey: true 
},

So, why not contribute to the Sequelize project and submit a fix? The short answer is that the need to search & replace multiple lines is not specific to Sequelize. As a developer, all of your work is done with text files… the source code. And, over the years, I’ve had reason to perform this type of task several times. Creating file-line-replacer allowed me to get past the hiccup and be ready for the time when I need it again, outside of Sequelize.

Installing the utility is a snap. Once you have Node on your machine, simply install the command with…

npm install -g file-line-replacer

This installs the project and allows it to be used just like any other command-line utility. Then, correcting the model files was as simple as issuing one lil’ command…

file-line-replacer \
    --search-dir "/Users/flackey/my-project/src/data/models" \
    --backup-dir "/Users/flackey/my-project/_backup" \
    --old-lines "allowNull: false,|primaryKey: true" \
    --new-lines "autoIncrement: true,|primaryKey: true" \
    --overwrite

The switches used here are the key. Here’s what they do…

--search-dir
Starting directory to search for files.

--backup-dir
Each file is stored in this location before it is modified.

--old-lines
Pipe-delimited list of text lines to search for within each file.

--new-lines
Replacement lines for each occurrence of the --old-lines

--overwrite
Ensures we know the files will be overwritten (flags are set to true by simply adding the flag name to the command).

There are tons of other flags and features listed on the project page here. Some of them include…

--source-file
Not everyone wants to search for files. You are able to specify the exact file to tweak. This is great if you want to use file-line-replacer in a BASH script.

--destination-file and --destination-dir
Maybe you don’t want to overwrite your files. Specifying the “destination” allows you to tweak your files and send them to a specific folder. This is great for working with source templates where overwriting or modifying the template is not desired.

--old-lines-file and --new-lines-file
Allows you to store the “old” and “new” lines inside of text files. You would provide a path to the file instead of supplying the actual values. This is handy for complex lines and making your scripts more “human-readable.”

--ignore-patterns and --ignore-patterns-file
The default search pattern is **/*.* (aka “all files, recursively”). Specifying “ignore” patterns allows more granular control on files and directories to skip.

In the grand scheme of things, I could have accomplished all of this with a BASH script. However, then I would have had more of a “uni-tasker” and not really gained anything in my developer toolbox.

Overall, I think this is a great lil’ utility. It performs a task that is quite common with developers and IT people while preventing folks from having to remember the complex syntax for outdated commands. It also allows me to personally overcome a speedbump that has been occasionally bothering me for years.

In the end, I hope whoever finds the utility is helped in some way. After all, that is why I love development so much.

Bixby Killed Samsung (for Me)

I’ve been writing software now for 36 years and have been focused on mobile apps for 12 of them. And, like many geeks, I’ve had every iPhone since the day it was released. However, a couple of years ago, I switched from iPhone to Android because of Samsung Mobile’s S7 Edge. It was the first Android phone that felt completely… natural in my hand. I also switched from my Apple Watch to the S2 and then the S3 (which I feel are infinitely better than the Apple Watch). When the S8 came out, I was confident that I would never switch phones again. And then came Bixby. I Hate BIXBY so much that I switched to an LG G6 just to get rid of the Bixby button. I now have THREE brand new S8 units, my S2 watch, my S3 watch, and two Gear VR headsets sitting in a drawer collecting dust. Have I considered the Samsung Galaxy S9? Of course I have. I loved my Galaxy & Frontier devices. However, until I can completely disable Bixby, I will never go back to Samsung.

I’m curious how many feel the same way.

Cool Utility: Live Server

I just stumbled across one of those “it’s about time” utilities for front-end app development: Live Server. Long story short, you issue the command live-server from your application’s current directory and… well… that’s it. A browser pops open, your web app is loaded, and the lil’ utility watches for changes. Any changes that are made are instantly pushed to the browser.

Installation is ridiculously easy via NPM:

npm install -g live-server

Of course, there’s a slew of command line switches and parameters to make even the geekiest geek happy:

  • --port=NUMBER – select port to use, default: PORT env var or 8080
  • --host=ADDRESS – select host address to bind to, default: IP env var or 0.0.0.0 (“any address”)
  • --no-browser – suppress automatic web browser launching
  • --browser=BROWSER – specify browser to use instead of system default
  • --quiet | -q – suppress logging
  • --verbose | -V – more logging (logs all requests, shows all listening IPv4 interfaces, etc.)
  • --open=PATH – launch browser to PATH instead of server root
  • --watch=PATH – comma-separated string of paths to exclusively watch for changes (default: watch everything)
  • --ignore=PATH – comma-separated string of paths to ignore (anymatch-compatible definition)
  • --ignorePattern=RGXP – Regular expression of files to ignore (ie .*\.jade) (DEPRECATED in favor of --ignore)
  • --middleware=PATH – path to .js file exporting a middleware function to add; can be a name without path nor extension to reference bundled middlewares in middleware folder
  • --entry-file=PATH – serve this file (server root relative) in place of missing files (useful for single page apps)
  • --mount=ROUTE:PATH – serve the paths contents under the defined route (multiple definitions possible)
  • --spa – translate requests from /abc to /#/abc (handy for Single Page Apps)
  • --wait=MILLISECONDS – (default 100ms) wait for all changes, before reloading
  • --htpasswd=PATH – Enables http-auth expecting htpasswd file located at PATH
  • --cors – Enables CORS for any origin (reflects request origin, requests with credentials are supported)
  • --https=PATH – PATH to a HTTPS configuration module
  • --proxy=ROUTE:URL – proxy all requests for ROUTE to URL
  • --help | -h – display terse usage hint and exit
  • --version | -v – display version and exit

If you’re building web-based apps, or even if you’re just starting out in web development, this little gem will save you a tonne of time up front.

Enjoy! =)

Receive SMS Messages Via Email from Flowroute Phone Numbers

In today’s mobile world, people just assume every phone number is a cell phone… even if it’s clearly listed as “office” on your business card. And, in most cases, if the phone number belongs to a corporate phone system, or PBX, any text messages sent to that number are lost forever in the great bitbucket in the sky. Until now, that is! If you happen to be using Flowroute as your backend trunking provider, you can now receive any SMS text message via email.

Here’s how to do it…

1. Setup My Proxy App Using Docker
I’ve whipped up a simple Node app to make life easy for you. In short, it receives all SMS text messages, from Flowroute, and emails them to you at either a single email address or custom “wildcard” domain. Assuming you have Docker installed a public server, install it via the following command:

docker run --name flowroute-proxy -p 3000:3000 \
    -e TO_EMAIL=bruce@batmail.com \
    -e SMTP_PASS=robin4ever \
    -e SMTP_USER=bruce@batcave.com \
    -e SMTP_HOST=smtp.batcave.com 
    fredlackey/flowroute-proxy  

The settings are all done by environment variables. A complete list is in the Docker Hub:

https://hub.docker.com/r/fredlackey/flowroute-proxy/

Of course, it will be up to you to ensure your DNS and server settings are both setup with a FQDN pointing to that docker container. You’ll also need to have an SMTP account for outgoing messages.

2. Activate the API with Flowroute
Once you have a Flowroute account, head over to their Developer Portal and click on the Get API Access button. This will bounce you over to the Flowroute portal where you will enter the URL to the Docker container you setup above:

Generating Mongo / Mongoose Models

Having come from the .NET world, I have always loved the ability to whip up a quick model diagram using the SQL Server Diagram Tool. It’s painless to model your data objects, and capture a good chunk of your business, for LOB applications. And, while in that world, I relied upon the CodeSmith Generator to spit out all sorts of documents from my database.

Alas, having moved to Mac, Linux, and MEAN Stack, all this is in the past.

… until now.

DbSchema is really what started me thinking down this line. It’s written in Java and, therefore, is cross-platform. I have used it successfully on all three platforms, to replace the SQL Server Diagram Tool, and it works flawlessly.

Here’s the cool part: unlike the M$ tool, DbSchema stores its data in good ole’ XML. So, of course, I’ve created a few tools to add some awesome sauce to it…

DbSchema Parser dbschema-parser

Long story short, dbschema-parser allows you to walk the data structures using NodeJS. You may navigate from Database, to Schema, to Table, to Column, and back up again, or in any direction.

DbSchema Parser CLI dbschema-parser-cli

Since I want to use the Parser to generate files, I’m gonna need a CLI. That’s what this project brings to thy table.

DbSchema Mongoose dbschema-mongoose

Under the hood this one is ugly as sin. However, it’s the thang that gives the two projects, above, some coolness. It basically looks at your DbSchema’s data file and spits out the equivalent Mongoose model files.

Side note…

I’m also using Keybaord Maestro, on Mac, and AutoHotkey, on Windows, to help me bang out complex data diagrams with only a few keystrokes. So, that helps a great deal.

Why create this?

In short, there’s nothing stable that provides this. DbSchema is the only tool that comes close to the stability and fluidity of the SQL Server Diagram Tool. And, as for generating models, there’s nothing out there that feeds from an elegant UI. Plus, although there’s a tonne of shtuff with Yarn and Yeoman, nothing feels fully baked.

Anywhoo, I hope this helps someone. It’s ugly. I know. If anyone shows genuine interest in it, I’ll see about extending it.

Force Outlook Data Path

I admit it. I’m really anal when it comes to allowing apps to consume hard drive space whenever and wherever they want. And Outlook is one of the worst at this. The path names make no sense to anyone but their developers and, if you have a ton of mail (like I do), this means a chunk of your system drive is gonna go bye-bye. For this reason, I force Outlook to store my mail files on a completely separate drive.

This trick is also particularly handy for those folks working on a corporate computer. Prevent Outlook from remembering your personal passwords. Then, force your data to be stored on a USB thumb drive that you take with you each day… encrypted, of course.

Okay, so here’s now…

Use the registry editor to created two string keys ForceOSTPath (for IMAP) and ForcePSTPath (for Exchange) in the following path:

HKEY_CURRENT_USER\Software\Microsoft\Office\<version>\Outlook

For example, if you’re using Outlook 2016, the path would be:

HKEY_CURRENT_USER\Software\Microsoft\Office\16\Outlook

Here’s mine…

Regedit ForceOSTPath

That’s really all there is to it.

Enjoy! =)

Filter Out Docker Noise

Sometimes the smallest lil’ gem makes you feel great. For me, Docker’s --format option is one such gem. As much as I love Docker, for me, their commands’ output are far too verbose and noisy. In fact, the net is filled with complaints about this. However, the --format option makes them perfect… or closer to perfect. Even the noisiest command can be transformed…

… from this …

Before Docker Aliases

… to this …

After Docker Aliases

… in just a few extra keystrokes!

It outputs just the right amount of info to be particularly great for “4-up” or “2-up” arrangements…

Docker Aliases with 4 Up Display

Docker’s info for the ps command completely sucks and offers no info on this option. In short, you basically use it to tell Docker what columns to display. For example, with ps you have the following columns to choose from:

  • ID
  • Image
  • Command
  • RunningFor
  • Status
  • Ports
  • Names

So, for the example above, the syntax would be:

docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Image}}\t{{.Ports}}"  

Or, better yet, if you’re on Linux or macOS / OSX, take a few seconds and create aliases for dps and dpsa in your ~/.bash_aliases file by adding these two lines:

alias dps='docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Image}}\t{{.Ports}}"'  
alias dpsa='docker ps -a --format "table {{.ID}}\t{{.Names}}\t{{.Image}}\t{{.Ports}}"'  

Enjoy… finally! =)

(I’ve added these two aliases to my dotfiles project, if you’re following that project.)

Wake Up Gently to the Sound of Nature

I absolutely love the feeling of waking up to birds singing in the cool summer breeze. Sleeping with the windows open, here in the northeastern United States, allows my body to be gently lulled awake as distant birds stretch their wings in search of an early morning snack.

Countless studies have proven the abrupt sound of a typical alarm clock causes you to feel tired, run-down, and may induce headaches. I have avoided these unpleasent feelings for years ensuring I always wake up gently to the sound of nature. When weather does not allow for the windows to remain open, or when I must be awake by a certain time, I rely on special high-quality recordings in lieu of Mother Natuer herself.

The recordings below are each one or two hours in length. Each original recording is accompanied by three others altered to gradually increase their volume (or “fade in”) from 0db (complete silence) to their full volume over time.

How to determine your new alarm time:
1. Pick a awake time using the time you need to wake up: 8:00 AM
2. Your waking duration is the amount of time to lull your body awake: 30 minutes
3. The alarm time is your waking duration subtracked from your awake time7:30 AM

How to use the recordings:
1. Listen to each Sample to find a recording you enjoy;
2. Download the Original version (used to set volumes);
3. Download the version with a fade-in time equal to your waking_ duration;
4. Play the Original version on your alarm clock to find a comfortable full volume level; and,
5. Set your alarm clock to play the version with the fade at your alarm time (above).

Example:
Actual time I must wake up by:     8:00 AM
Duration to lull my body awake:    30 minutes
Alarm's time (start playing MP3):  7:30 AM
Backup alarm's time:               8:15 AM (on critical days)

Note:
On critical days, I generally set a backup alarm, using a separate device, for 10-15 minutes after my awake time. The backup alarm does not use a gradual volume increase. This ensures I’ll be awake even on those days when I’m too tired to hear my alarm clock.

Rememeber to grab the original version!
I recommend also using the original version of the selected track to set the volume of your alarm clock or listening device. This will help prevent selecting a volume that is too quiet to actually wake you.


Available Tracks

Relaxing Bird Songs in Wood Birds Chirping (64 min total)
Original | Sample | 10 min fade-in | 30 min fade-in | 60 min fade-in

Forest Birdsong – Birds Chirping (120 min total)
Original | Sample | 10 min fade-in | 30 min fade-in | 60 min fade-in

Meditation Music Relax Mind Body (64 min total)
Original | Sample | 10 min fade-in | 30 min fade-in | 60 min fade-in


Please let me know if there are any other sounds or tracks that might help you with this technique. My email address is: fred.lackey@gmail.com