Using 'prettier', a Javascript formatter in bbedit

You have to have NodeJS. If you don't have it, google it and make it happen.

Then you need to install prettier. It's NPM page is here.

To install it, type...

npm install prettier -g

This will install it in a command line utility.

In some file (I do a lot of this, so I created a Scripts folder and called the file, ~/Scripts/bin/js/runPrettier.js, you can do what works for you just remember that the bash file below has to point to the file), insert this:

#!/usr/local/bin/node
const prettier=require('prettier');
var inString='';
var writeStuff = function() {
        var outString='';
outString=inString;
        outString=outString.replace(/^[\s]$/gm, "/*linebreak*/"); //I like to retain linebreaks
        outString=prettier.format(outString)
        outString=outString.replace(/\/\*linebreak\*\//gm, ""); //you can remove these if you don't
        process.stdout.write(outString);
    };
//the rest ========================================================
process.stdin.resume();
process.stdin.setEncoding('utf8');
process.stdin.on('data', function(data){
        inString+=data;
    });
process.stdin.on('end', writeStuff);

Then in a file in the bbedit directory (~/Library/Application Support/BBEdit/Text Filters)

Create a file (I called this 'runPrettier') containing this...

#!/bin/bash
~/Scripts/bin/js/runPrettier.js

In the terminal make the bash script executable...

chmod +x ~/Library/Application Support/BBEdit/Text Filters/runPrettier

and, voila!, you have an operating formatter for Javascript.

I assigned mine to a command key so I can always make it pretty.


NGINX server_name is not working, ignoring config and getting the wrong server including SSL

When NGINX is trying to find something to serve it tries to match all the server names BUT ONLY IF THERE IS A DEFAULT SITE.

I don't understand why it fails even when the server name matches something. However, if you have two separate servers with:

server_name xxx.com

server_name yyy.com

You would expect that (assuming that the configs appear in this order) that http://yyy.com would match that server_name. It will not. It will match xxx.com. Why? Because when there is not default, it simply uses the first server. Period.

If you have a default, though...

server_name xxx.com

server_name yyy.com

default_server

It works. yyy.com will match xxx.com.

I come upon this problem because I had a configuration that had the default file that comes in the distribution and it worked.

Then I added SSL. It did not work. Having long forgotten the issue with default, I debugged like a madman. Then I thought about the default issue (I ran into it sometime in the dark past - it is buried in the docs) and saw, There's a default right there!!!

Eventually (I know. This is the least entertaining punchline in history.), I realized that there was no default for port 443. QED


# Default server configuration
#
server {
    listen 80 default_server;
    listen [::]:80 default_server;
    root /var/www/html;
    index index.html index.htm index.nginx-debian.html;
    server_name _;
    location / {
        try_files $uri $uri/ =404;
    }
}
server {
    listen 443 ssl default_server;
    listen [::]:443 ssl default_server;
    ssl on;
    ssl_certificate /etc/ssl/PATH/TO/CERT.cer;
    ssl_certificate_key /etc/ssl/PATH/TO/CERT.key;
    root /var/www/html;
    index index.html index.htm index.nginx-debian.html;
    server_name _;
    location / {
        try_files $uri $uri/ =404;
    }
}






Using iTerm2 for the bbedit 'Go here in terminal' command

Turns out that bbedit uses the standard system terminal. Someday I will figure out how to subvert that because I cannot imagine any reason that I would ever want to use Apple's dumb old terminal program when iTerm2 exists. In the meantime, I asked the lovely people at Bare Bones Software how to change bbedit's behavior.

Turns out it's right there in the Expert Preferences list (about a hundred obscure things that I never thought of as I searched the Preference preferences for some way to control this). To make it easier for future generations, I offer the complete command line:

    defaults write com.barebones.bbedit TerminalBundleID -string "com.googlecode.iterm2"

It works and make bbedit another fraction better.

nodemon does not watch node_modules

I'm no fan of the node_modules structure. I'd have gone for a dichotomy, node_library and node_modules. node_library would be the place that npm and yarn install stuff from npmjs.org. node_modules would be for my modules and other code. I would have node search up the tree in both folders. Complicated, yes. But having no systematic way of determining which code is mine is simply awful.

In one of the goofiest decisions in the node world, the project monitor, nodemon, does not look inside node_modules to figure out whether to restart a project when files are changed. This is certainly because it has to monitor a zillion files if it does and the guy worries about performance.

The problem is that my projects are comprised of node modules and they are put in node_modules. If there is a better place to put them, I beg you, write some comments and save me and the rest of the misery.

So, if you

cannot get nodemon to restart your project or
nodemon won't detect changed files
nodemon will not watch node_modules
(put search phrases in the comments, please)

you can remedy the situation by adding an ignoreRoot key to you nodemon.json file
{
  "ignoreRoot": [".git", ".jpg", ".whatever"]
}


This overrides the default ignore behavior entirely. Choosing to not list node_modules means they can now be watched.

This is, in fact, explained on the github site (here) but, you have to read a lot of stuff to get to it and it doesn't get found by google.

Perhaps this will change that.

Scrolls Bars on Macintosh

Among the worst things that Apple ever did was make it so that scroll bars are only visible when you want to use them. Often it's hard to figure out how to activate them or they go away before I'm done using them.

Of course, Apple is actually awesome and, after all these years, I just realized that they provide make them show all the time. In the two days since I discovered this, I am happy again for the first time.

To accomplish this minor miracle...

System Preferences -> General -> Show Scroll Bars -> Always

It's like being able to breathe again.

rsync error: error in rsync protocol data stream (code 12)

The internet failed to tell me:

This error can result from not having one of the directories present. Yes, I know that rsync creates lots of directories very nicely. Not all of them.

To wit:

rsync someDirectory someUser@1.1.1.1:/home/someUser/system/code

Gave the the data stream error until I created the directory 'system'.

I can't imagine why. The only thing that is distinctive about 'system' is that it is also ~/system, ie, at the top of the user's directory.



Windows is Bad, Example #billion

I often note that whenever Microsoft has a decision to make, they unerringly choose the worst alternative. Most of these are so small that I forget about them but today, I ran into one that is so perfect, I want to remember it forever.

As with my Macintosh, one way to rename a file is to click once directly on the text of the name. It will turn into a text entry and select the name, awaiting the new file name.

Occasionally, I want to append something to the name, eg, BACKUP, HOLD, TMP, DISCARD, etc. So that I can use the real file name for something new without having to lose access to the old file.

On my Macintosh, I open the name for editing and touch the right arrow. This moves the cursor to the end of the selection and lets me keep typing.

On my Windows machine, it moves it past the end of the selection and then past the period so that I am changing the file extension. While it's not impossible that this is what I want (on my Mac, select-all, right-arrow, delete delete delete), it's relatively rare.

Which is to say, Windows forces me to do extra work to accomplish the most common function. Like always. It also increases the likelihood of error.

How much does Windows suck? Just sayin'.

Access Web.config from Classic ASP

I am in pain. The things I do for money. Visual Basic in asp. Kill me now!

I am handed this app with the URL of a JSON endpoint hard coded into it. That might not be horrible except that this is not a one-shot application. This is something we sell to a lot of people and the endpoint needs to point to the customer's domain or that nasty cross browser stuff will bite you.

After sneering about the laziness, I set about looking for the equivalent of getEnv() or process.env.varName or any of the sane ways that other language systems provide access to configuration data.

Nope. This is Microsoft after all. Not only can't I find said simple 'read the config' function, I can't really find a straight answer. (The fact that I didn't know to google "Classic ASP" didn't help. - Hey! Stop laughing. I still am not sure what the language is called. vbscript, visual basic, asp... WTF? I hate Microsoft apps. I'm only doing this because nobody else in my shop could figure out why it was broken.)

Of course, StackOverflow eventually came to the rescue, sort of. A nice person named Connor worked through this problem. It didn't work for me right away but, thanks. It saved my bacon. I present it here so I can find it again if I am ever again unable to escape a Classic ASP task, and so that it has more good google keywords. This is copied directly out of my app. It works.


'****************************** GetConfigValue *******************************
' Purpose:      Utility function to get value from a configuration file.
' Conditions:   CONFIG_FILE_PATH must be refer to a valid XML file
' Input:        sectionName - a section in the file, eg, appSettings
'               attrName - refers to the "key" attribute of an entry
' Output:       A string containing the value of the appropriate entry
'**********************************************************************************

CONFIG_FILE_PATH="Web.config" 'if no qualifier, refers to this directory. can point elsewhere.
Function GetConfigValue(sectionName, attrName)
    Dim oXML, oNode, oChild, oAttr, dsn
    Set oXML=Server.CreateObject("Microsoft.XMLDOM")
    oXML.Async = "false"
    oXML.Load(Server.MapPath(CONFIG_FILE_PATH))
    Set oNode = oXML.GetElementsByTagName(sectionName).Item(0)
    Set oChild = oNode.GetElementsByTagName("add")
    ' Get the first match
    For Each oAttr in oChild
        If  oAttr.getAttribute("key") = attrName then
            dsn = oAttr.getAttribute("value")
            GetConfigValue = dsn
            Exit Function
        End If
    Next
End Function

settingValue = GetConfigValue("appSettings", "someKeyName")
Response.Write(settingValue)


ps, here's Connor's post: http://stackoverflow.com/questions/28960446/having-classic-asp-read-in-a-key-from-appsettings-in-a-web-config-file/34779392#34779392



why use "console.log.bind(console)"

Oddly, I never saw this construct much until recently (late 2015). I suppose that's because the problem it solves wasn't common before promises arrived on the scene and people wanted to pass console.log around for debugging purposes. When it did start showing up, I was perplexed. I am 100% comfortable with the details of the bind() function and why to use it. I could not, for the life of me, understand why it was needed here.

The answer:

It's not needed. I tried to get the behavior discussed below in a few contexts and it appears that console.log has been revised so that this isn't needed. Or, maybe it is. I didn't do a comprehensive check of the entire world.

Well, then, wtf?

Turns out that, in some previous world (perhaps some browsers today that I don't have the patience to experiment with), console.log() contains a reference to it's own this which is lost in a simple function assignment. IE...

If you, for some reason, want to pass the function console.log around, eg,

var xxx=console.log

xxx('message');

It won't work. The console.s log() method refers to this.something that isn't a part of it's new, post assignment 'this' (ie, the global scope, which is 'this' when nothing else is applicable).

That is, if you could magically add console.dir(this) to console.log, you would get something in this spirit...

{

log:function,

somethingElse:godKnowsWhat

}

But, if you were magically able to get that same console.dir(this) after the assignment to xxx, it would produce something like this...

{

//global scope items that do not include anything name somethingElse

}

The construct in question specifies the value of this for the newly assigned xxx

var xxx=console.log.bind(console);

That is, it will be bound to its original 'this', (ie, this===console) and it will be able to find whatever somethingElse it needs.