tag:tech.genericwhite.com,2013:/posts I Love Javascript! 2017-04-19T18:54:08Z TQ White II tag:tech.genericwhite.com,2013:Post/1132846 2017-04-19T18:54:08Z 2017-04-19T18:54:08Z Macbook Display Port VGA Adapter Doesn't Work

Google as I might, nobody would tell me that the adapter had firmware that could be out of date. Eventually, I found a reference to the idea in the form of an updater that would not work.

The important thing is that I realized that if you cannot use your Macbook for presentations on a VGA projector or display, it might be that you simply need to buy a new one.

I did and now it works.

]]>
TQ White II
tag:tech.genericwhite.com,2013:Post/1147610 2017-04-19T18:53:09Z 2017-04-19T18:53:09Z MacOS/OS X Dock presentation formatting with Spacers!!
I have a lot of stuff in my dock. I have long wished I could have some sort of grouping mechanism so it was easier to find what I want. Today I learned that you can add spaces to your Dock. Life is good.

Enter:

defaults write com.apple.dock persistent-apps -array-add '{"tile-type"="spacer-tile";}’; 
killall Dock;

In your Dock, you will see a space that you can drag as you see fit. You can repeat the above as many times as you want. If you want to remove the space, just drag it out like anything else.

I added some to separate my email and web browser from my development tools and those from the rest of the stuff.

]]>
TQ White II
tag:tech.genericwhite.com,2013:Post/1127342 2017-01-30T20:17:49Z 2017-01-30T20:21:23Z 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.


]]>
TQ White II
tag:tech.genericwhite.com,2013:Post/1123974 2017-01-17T22:06:54Z 2017-01-17T22:06:54Z 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;
    }
}






]]>
TQ White II
tag:tech.genericwhite.com,2013:Post/1118474 2016-12-27T05:39:02Z 2016-12-27T05:39:03Z 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.

]]>
TQ White II
tag:tech.genericwhite.com,2013:Post/1111804 2016-11-29T23:05:24Z 2016-11-29T23:05:24Z 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.

]]>
TQ White II
tag:tech.genericwhite.com,2013:Post/1111707 2016-11-29T15:58:08Z 2016-11-29T15:58:08Z 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.

]]>
TQ White II
tag:tech.genericwhite.com,2013:Post/1093191 2016-09-25T05:46:35Z 2016-11-29T15:58:32Z Semi-colons should be considered mandatory in Javascript

As long as this

var obj={a:'a', b:'b'};
var a = obj
[a].forEach(()=>{})

produces an error, semi-colons are mandatory and any suggestion to the contrary is childish perversity.


]]>
TQ White II
tag:tech.genericwhite.com,2013:Post/1004115 2016-02-29T22:24:21Z 2016-02-29T22:24:32Z 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.



]]>
TQ White II
tag:tech.genericwhite.com,2013:Post/971765 2016-01-15T22:05:44Z 2016-01-15T22:05:44Z 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'.

]]>
TQ White II
tag:tech.genericwhite.com,2013:Post/970442 2016-01-14T00:43:18Z 2016-01-14T00:43:18Z 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



]]>
TQ White II
tag:tech.genericwhite.com,2013:Post/962664 2016-01-03T15:59:51Z 2016-12-21T20:22:24Z 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.

]]>
TQ White II
tag:tech.genericwhite.com,2013:Post/961508 2016-01-01T19:11:26Z 2016-01-01T19:13:47Z Mongo Mongoose Objects Weird Properties Can't Access

Yep. I'm all about search engine titles this week.

In my new Mongo/mongoose world, I've exposed myself ot a ton of information, tutorials, explanations, examples, you name it and there is a HUGE thing that no one mentions.

Perhaps I'm an idiot or maybe the fact that I work entirely alone means that I am not privy to common knowledge so common that no one needs to say it but, I'm saying it now:

Mongoose does not create nice Javascript objects. When you do a find, you get something that will console.dir() and look like something you recognize. It is a false appearance. It is some nasty Mongo thing. Eg,...

I had an object that, viewed with my general purpose display program, looks like this:

Doesn't look like it should be a problem. Addressing it as...

var item=recipient[0][0];

recipient[0] gave me the first array element, an object.

recipient[0][0] attempted to to address the object containing the email address and came back undefined.

Nothing I could do gave me the email address. It was insane.

Turns out that I could google the answer pretty easily once I realized what was going on but only after tearing my hair out because no one mentioned that mongoose produces bizarre data structures.

The answer is (drum roll, please)...

.lean()

as in...

query.lean().exec(wrapCallback(callback)); //this produces a plain, Javascript object

as compared to

query.exec(wrapCallback(callback)); //this produces a mongoose object from hell

Obviously, if you are doing your processing in a model, you might really like the benefits of using the mongoose data type. I bet there are a TON of them but, if you are trying to construct a test, as I was, or send it to a web page, like I plan to do, you are going to want something that acts like a civilized citizen, not some rogue toxic waste factory.

But, I wouldn't have minded at all if somewhere in the mongoose quick start and documentation they had said, "The output of find() must be accessed with mongoose utilities unless you add the lean() function to convert it to plain Javascript."

Maybe you got to this note before you actually ruined yourself. Or, maybe you, like everyone else on earth, already know.


]]>
TQ White II
tag:tech.genericwhite.com,2013:Post/960806 2015-12-31T14:06:03Z 2015-12-31T14:06:04Z Mongo Mongoose Simple Tutorial Quick Start Code Example

How's that for a search engine friendly title? It's a combination of the things I tried as I started my experience with Mongo/mongoose that did not give me what I wanted. What I did get were all sorts of useful explanations and advice. What I did not get is a simple bit of working code to satisfy my Hello World needs.

The code below includes the lesson, 'use createConnection(), not connect()'. The former allows you to access the database from separate model classes without having to pass a connection object around. In the depths of the mongoose forums, the fancy guys admit that they prefer createConnection() so it's ok.

It also has my curried default test callback. I had a problem when I tested the example that required it so I left it in so you can solve whatever screws it up for you more easily.

I had two problems you might want to know about:

You will notice that the boilerplate has a peculiar model name (userTqTest). I built this example inside my real, working project. It turns out that Mongo does not forget old model definition stuff. I haven't quite worked out the details but the bottom line is that when I declared this model as User and saved, I got errors based on the validation in my previous, real model. That is, the mongoose model does not supersede the one inside Mongo itself. I got over it by, first, dropping the collection. Then, since I don't want you to have to drop your User collection, I changed it to a name that is very unlikely to collide with you database.

Second is one that you probably will notice instantly but, because I was focused so much on showing the simple syntax, I didn't think about right away is that these calls to save, get and delete are asynchronous. They are triggered in the right order but they are happening in whatever order Mongo takes care of it.

I didn't want to complicate the example with async or some other method to sequence the calls, so I didn't. This code definitely works if you run the three functions one at a time but give unpredictable results otherwise. My problem was that the delete fired before the save was complete leaving the record to give me a duplicate key error on the second pass.

Enjoy.

========================================

        var mongoConnection = mongoose.createConnection("mongodb://localhost:27017/test");
        mongoConnection.on('error', function(err) {
            throw ("user code says, mongoose failed")
        });

        var userSchema = new Schema({
            userName: {
                type: String,
                unique: true
            } /*obviously you'd have more properties*/
        });

        var userAccessor = mongoConnection.model('UserTqTest', userSchema);

        var saveUser = function(user, callback) {
            /*you'd probably do some validation even though the mongoose will also validate
            you'd also wrap stuff in try/catch but that's not the point of this example.*/

            var newUser = new userAccessor(user);
            newUser.save(callback('saveUser' + '/' + user.userName));
        }

        var getUser = function(user, callback) {
            var query = userAccessor.findOne(user);
            query.exec(callback('getUser'));

        }

        var deleteUser = function(user, callback) {
            userAccessor.remove(user, callback('deleteUser'));
        }

        var callback = function(callingName) {
            return function(err, result) {
                console.log(callingName + '============');
                console.dir(err);
                console.dir(result);
                console.log('=====');
            }
        }

        saveUser({
            userName: 'tqwhite'
        }, callback);


        getUser({
            userName: 'tqwhite'
        }, callback);


        deleteUser({
            userName: 'tqwhite'
        }, callback);




   


]]>
TQ White II
tag:tech.genericwhite.com,2013:Post/955248 2015-12-22T18:57:59Z 2015-12-29T03:28:33Z Running Multiple Versions of NodeJS on One Server

In the modern age, node installation is handled by the 'n', eg,

sudo n stable #the current stable version

or,

sudo n 0.10.40 # to install v0.10.40

Once you have installed a version, it never goes away. You can switch back and forth between versions instantly. That means that you can easily alternate between two (or more) versions if you want.

But, you might (as I did) have an app that must run on an old version but you otherwise want to use a modern version. That is, you want two different versions active at once.

This can be done by referring to the node binary with a fully qualified path. (Remember, when you type "node", your shell is simply giving you /usr/local/bin/node.)

The program 'n' allows you to find the path to the binary (assuming that you have previously installed it), ie,

n bin 0.10.40

->/usr/local/n/versions/node/0.10.40/bin/node

You can then type

/usr/local/n/versions/node/0.10.40/bin/node SOME_OLD_APP.js

into your shell or put it into your initialization script or whatever.

I create separate users for each of the apps I have running on my server. There is only one that requires the old version of node. I want to use the latest stable version for everything else so, I have done "n stable". For the user account where I run the old app, I change my .bash_alias file to include...

alias node="/usr/local/n/versions/node/0.10.40/bin/node"

Then I can type

node SOME_OLD_APP.js

and get good results, or,

node --version

->v0.10.40

But when I log in as the user for a different app, I get the latest stable version.

Obviously, you can do this for as many node versions as you want but, if you need a lot, you might want to think about why (for me, it is Meteor, which only runs on old node).


UPDATE:

I have had occasion since I wrote this to install a new server. I was reminded that the utility 'n' does not come automatically with a NodeJS install. After you install NodeJS (which also installs npm), type

sudo npm install n -g

and the you can verify it by typing

n --help

and you will get all kinds of good info.

]]>
TQ White II
tag:tech.genericwhite.com,2013:Post/952026 2015-12-17T20:47:25Z 2015-12-17T20:53:49Z Color and Other Format for Fargo.io

Dave Winer is the guru of outlining. He is the person who moved outlines from English class onto the computer in the eighties. He's done a lot of other things, too. But, his development tool Frontier was a game changer for me. I eventually had to leave it behind because my brain needs color. I need code coloring when I'm programming and I need color cues to work productively with an outliner (everything else, too; my emails alway have colored sections).

His newest outline, Fargo, is very cool (at http://fargo.io). It runs in a web browser and saves your files into your Dropbox. Awesome. Unfortunately, it's also black and white and serif type face. I don't like that and, honestly, I have a hard time working with black type if there is very much of it. I tried it out. Liked it. I continued to use Omni Outliner. (If I could get Frontier to use Omni's formatting, I would be so happy.)

Lately I've been working on a very outline intensive project and now I want to work on it with other people. But, it really needs to be an active outline with expanding and collapsing sections.

I discovered that I could export the outline from Omni into OPML, the basic data structure Dave uses for Fargo. I copied the OPML into the Dropbox file Fargo uses and, boom!, I had Fargo functionality.

To my eye, it was ugly but it turns out that Dave did a BEAUTIFUL THING. He made it so that you can execute Javascript from the outliner. No kidding. You just type some JS into the outline, hit cmd-/ and it runs.

Here's what I did:

$('body').prepend("<script src='http://static.tqwhite.org/iepProject/formatFargo.js'>");


That's right, I loaded a chunk of JS from my static server. That code changes this:



to look like this..



It took a fair amount of reverse engineering to figure it out but, it works like a charm.


Here's the code:

(I think the colorized picture is easier to read.)


And here it is if you want to do your own colorizing:


var colorize = function() {
    $('.concord .concord-node .concord-wrapper .concord-text').css({'font-family': 'sans-serif'});
    $('.concord-level-1-text').css({'color': 'black'});
    $('.concord-level-2-text').css({'color': '#664F58'});
    $('.concord-level-3-text').css({'color': '#456D72'});
    $('.concord-level-4-text').css({'color': '#AD9470'});
    $('.concord-level-5-text').css({'color': '#D3AF74'});
    $('.concord-level-6-text').css({'color': '#90967E'});

    $('.concord-level-7-text').css({'color': '#778'});
    $('.concord-level-8-text').css({'color': '#788'});

    $('.concord .concord-node > .concord-wrapper').css({'background': 'white'});
    $('.concord .concord-node.selected > .concord-wrapper').css({'background': 'rgb(245,250, 250)'});
    $('.concord .concord-node.selected').find('li .concord-wrapper').css('background', 'rgb(245,250, 250)')
}

$('body').bind('keyup', colorize);
$('body').bind('click', colorize);

colorize();

document.styleSheets[0].insertRule(".selected { background:rgb(245,250, 250); }", 0);
document.styleSheets[0].insertRule(".selected div { background:rgb(245,250, 250); }", 0);
document.styleSheets[0].insertRule(".selected div { color:normal; }", 0);
document.styleSheets[0].insertRule(".selected i { background:rgb(245,250, 250); }", 0);







]]>
TQ White II
tag:tech.genericwhite.com,2013:Post/948542 2015-12-12T17:58:06Z 2015-12-12T17:58:06Z Reinstalling NodeJS and npm

Recently, I upgraded to the latest NodeJS/npm and npm stopped working. It turns out that there was a problem with the OSX installer.

After painful amounts of googling, I found that some had solved it by "tracking down" the node and npm files, removing them and then reinstalling with the node distribution download (dmg) from nodejs.org.

I tracked down the files. Do this:


sudo rm -rf /usr/local/bin/node

sudo rm /usr/local/bin/npm

sudo rm -rf /usr/local/lib/node_modules/npm


And then hit up http://nodejs.org for a new installer. You will have a fresh working installation.


PS, the problem with npm was this:

When I typed

npm init

to start up a node module, I got errors that included

Error: Cannot find module 'github-url-from-git'

Turns out that basically everything I did with npm except --version was broken in this way.

The 'delete before reinstalling' process listed above fixed it.







]]>
TQ White II
tag:tech.genericwhite.com,2013:Post/938701 2015-11-24T17:42:10Z 2015-11-25T15:34:55Z Visual Studio 2015, .NET 5 rc1, dnu restore, asp.net missing (I can't believe it either)

It's been a half dozen years since I started a new project in Visual Studio. I was a little excited at the prospect. I like learning things and I know a lot about almost all the rest of the internet development topics.

I looked up the latest stuff and it turns out that we have a new Visual Studio and a new .NET that have taken a lot of good lessons from the rest of the world of web development. .NET 5 is out of beta and into Release Candidate 1. That's good enough for me. I expect the bugs will be small.

Wait. It's Microsoft and everything they do is stupid.

Problem Zero (which I won't detail)

I actually went through fits trying to get it all installed and looking good, but, having done that, I create a new project: ASP Web Application/ASP.NET 5 Web Application.

Problem One:

I have to do this twice. I keep code on an external drive that the file dialog navigates to as //psf.stuff... . It tells me I that "UNC paths are not supported." The second time, I typed (not navigate) the volume letter, "X:", and it worked.

Problem Two:

I build the solution. I get a bazillion (well, 204) errors. The first one tells me that "The type or namespace name 'Identity' does not exist in the namespace "Microsoft.AspNet'". Another, "The type or namesspace name 'AspNet' does not exist in the namespace 'Microsoft'". Can you imagine?

The project listed in the first error says "TestProject.DNX 4.5.1, TestProject.DNX Core 5.0" (obviously, the 'TestProject' is my project name). For the second one, it's "DNX 4.5.1" only.

I try using Nuget to add "Identity.Core" and it changes things. I screw around with that for awhile as new missing references appear until I start getting messages telling me that I have duplicate definitions. This is truly awful. (Did I mention that Microsoft always does it stupid? The package manager doesn't make sure the references are correct? Really?)

Problem Three:

I start over and this time I decide that I'm working toward .NET 5.0 so to hell with 4.5.1. I edit the project.json file and remove it. Build takes forever and I pretty much expect everything will blow up but instead, I get a message, "Dependencies in project.json were modified. Please run "dnu restore" to generate a new lock file."

This feels like progress. I right-click on the project, choose Open Command Line and type "dnu restore". It works. I return to VS and build again. It instantly repeats the exact same message. I delete the lock file and restore it. Same thing. A complete, stupid dead end.

THE SOLUTION (and a lesson is the complete depth of Microsoft stupidity)

I reverse the order of the references to 4.5.1 and 5.0 so that 5.0 comes first. IE,

I change from this:



to this:



The build succeeds promptly. Clicking the IIS Express button opens a web browser and shows me the scaffold web page.

This has taken me over 2.5 hours. Certainly, my inexperience with this technology made it slower. Someone better might have done it more quickly. However, this is the scaffold. This is the part that supposed to save time. This is an epic fail on Microsoft's part. I mean, they put the dependencies in the scaffold in the wrong order!!

The good news is that, if I got enough Google-friendly text in this page, you might have found it well before 2.5 hours elapsed.

Of course, that just means you need to endure Microsoft's next awful surprise. Good luck. I know I need some.



]]>
TQ White II
tag:tech.genericwhite.com,2013:Post/935679 2015-11-18T17:47:30Z 2015-11-18T17:47:30Z Bash List of Files in Directories with Complete Paths

I don't want to forget this and it took me too much googling to find.

find $PWD -type f | grep xsd

gets:

/..absolute path../Collections.xsd
/..absolute path../Composite/SIFNACompositeObjects.xsd
/..absolute path../Entity/SIFIdentityManagement.xsd
/..absolute path../Report/SIFNAassessmentSummary.xsd
/..absolute path../SIFglobal.xsd

Note that it is looking inside folders.


(Too much googling but, thanks StackOverflow: http://stackoverflow.com/questions/246215/how-can-i-list-files-with-their-absolute-path-in-linux)

]]>
TQ White II
tag:tech.genericwhite.com,2013:Post/933367 2015-11-13T19:55:57Z 2016-11-09T19:45:55Z NodeJS Express Body-Parser Post Data Missing Problem

I am amazed that NodeJS' main network server package, Express, does not handle Post data on its own. I just don't get it. It requires a package called Body-Parser.

I copied in the sample code from the Express website

http://expressjs.com/4x/api.html#req.body

got the required packages and made a little form to test it.

It did not work.

The docs explain that Body-Parser builds a request.body that contains the post data but it was empty. It did exist, but it was empty.

I did one million things to make sure that I was doing what I thought I was doing. Postman? Check. Curl? Check. Inch by inch inspection of my entry page? Check.

I got to looking at the post on the way into the page in Firebug. I noticed that the encoding that Firefox was using was

application/x-www-form-urlencoded

The Body-Parser docs say that any of their decoders will take a type parameter to specify this. I found an example and tried it out:

{type:'application/x-www-form-urlencoded'}

Nope. I tried this in some decoder called raw(), the urlencoded() one, I even put in into json() just in case. Nada.

At my wits end, I'm just trying things in Postman. I tell it to encode it in various ways and, Voila!!, when I choose

multipart/form-data

It works.

WTF? I think. Everything specifically tells me that Body-Parser SPECIFICALLY DOES NOT DO MULTIPART form data.


How much clearer could it be?

Then I realize, the sample code from the Express docs caused me to install (last night when this nightmare began) something called Multer. Experimentation tells me that this is the reason I can do multipart/form-data. Without Multer, I get nothing.

But, without Multer, I get nothing no matter what I do. I did everything I have tried before and could not get Body-Parser to work. With Multer, only multipart/form-data. Without, nothing.

If anyone can enter a comment telling me how I got this wrong, I would be grateful.


UPDATE: It was none of the above!!!


It turns out that, in the course of the above screwing around, I moved the assignment of the router to follow the assignment of the Body_Parser. It executes the router before the parser if you tell it to. I had inserted the new body-parser code after the route. No reason, it just happened .

app.use(bodyParser.urlencoded({ extended: true }))

must precede

app.use('/', router);


]]>
TQ White II
tag:tech.genericwhite.com,2013:Post/928166 2015-11-05T17:11:43Z 2017-01-09T11:14:31Z “This project is incompatible with the current version of Visual Studio”

Nice error message Microsoft. Why not just say, "Screw off. We don't care about your old projects." This is why I avoid them whenever possible.

However, in this case, it wasn't possible. It was some reference code for the protocol of a new thing I'm working on. It was done in Visual Studio 2013. I'm using Visual Studio 2015.

After doing a bunch of stuff that was totally useless (I am not very strong in .NET), I happened up on this simple solution...

Open the .csproj file in a text editor.

Change

12

to

14

Done.

Or, if you need more detail:

Change

<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

to

<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

After that it opened with no problem and I was able to build and use the project.

I have no idea what the ramifications of this could be in the long run. If I find any that are adverse, I will write it down here.




]]>
TQ White II
tag:tech.genericwhite.com,2013:Post/898773 2015-08-28T17:52:26Z 2015-08-28T17:52:26Z mysql: Load Data From and Select ... Into Outfile

Just so I don't forget...

I did a test of this.

select firstName, lastName from users into outfile 'tempTest9999'

Then, after creating an appropriate table...

load data infile 'tempTest9999' into table tempTest

The thing I don't want to forget is that the file was put into the directory...

/var/lib/mysql/DATABASENAME

The owner and group were both 'mysql'.

I know, it's what one would expect, but I forget these things.

]]>
TQ White II
tag:tech.genericwhite.com,2013:Post/897886 2015-08-26T14:35:10Z 2015-08-26T14:35:10Z Responsive Image Maps - Generator and jQuery Plugin

Bottom line, I need to do an image map in a responsive website.

First, I found this lovely image map generator. It is simple and works very well. It's good enough that I actually gave him a few bucks.

http://www.image-maps.com

The resulting <map> worked right away.

Then I started working on the real website. The image loads in a size relative to the browser window's size. The image map was out of alignment. I quickly realized the problem and googled Responsive Image Maps.

I found this:

https://github.com/stowball/jQuery-rwdImageMaps

I groaned. I hate adding dependencies and even more, I hate figuring out how to work new stuff that I'm probably not going to use again (this is the first image map I've used in years and once this project ends, probably the last for a long time). But, I did it.

The learning curve was ZERO.

I added the plugin. Copied his sample initialization and it worked perfectly the first time.

Win!!

]]>
TQ White II
tag:tech.genericwhite.com,2013:Post/891837 2015-08-09T19:51:12Z 2016-05-13T06:06:53Z Tape Suppresses console.log() and Makes Debugging Difficult

I was seduced, eg [1], by the fact that the Tape (the "tap-producing test harness for node and browsers") unit testing tool does less. Not only does it not litter your Javascript universe with globals, it does a lot less magic stuff.

I am in the early stages of a new project and decided to do the right thing and test everything from the first moment. Having been irritated by the amount of arcane stuff in Mocha, I drank the koolaid and rewrote my starter testing for Tape.

Bad move.

Tape is simple to use but, when I started doing real development and a new test didn't run, I needed to debug and couldn't.

Turns out that Tape suppresses console.log(), process.exit(), etc. Of course, there are other ways to debug Javascript, but I am a fan of print-trace, ie, console.log() and you cannot use console.log() with Tape.

Searching the web, I found that this is not something that is not something that is noted very often. I don't know why. If I had known this, I would not use Tape. In fact, I am going to revert to using Mocha. The elimination of testing globals is not sufficiently compelling to make it worth changing my approach to debugging.


[1] Why I use Tape Instead of Mocha & So Should You - http://tqwhite.org?F7A285

]]>
TQ White II
tag:tech.genericwhite.com,2013:Post/891832 2015-08-09T19:38:53Z 2015-08-09T19:38:53Z Remote Volume Sharing with Ubuntu and fstab

I have two applications that run on my Ubuntu server. They both deposit their output onto the different  directories on the same remote volume. To avoid confusing my tiny brain, I like to isolate separate applications into separate users on my server. (It allows me to login and have the environment initialized with appropriate, different, management tools.)

So, I set about making it so that the volume mounted all the time. (That they are Windows volumes has, I believe, no bearing on this subject.) That is, the /ets/fstabs file contains a couple of lines like this:

//00.00.00.00/c$ /home/appUserA/volumeName cifs uid=appUseruserA,rw,user,username=remoteName,password=******* 0 0

//00.00.00.00/c$ /home/appUseruserA/volumeName cifs uid=appUseruserB,rw,user,username=remoteName,password=******* 0 0

The important point is that the IP addresses (here shown with zeroes) are the same and volumes (c$) match. 

The mounting worked. I could see the volume in both user directories. I got the application for appUserA to work. Life is good. But, when I got to the other application for appUserB, I could not write to its destination directory. 

After screwing around a long time, I realized that Ubuntu locks the mounted directory for the user that touches it first. This, before I figured it out, made for confusing results. Sometimes A could write. Other times B. In any case, I could always write with sudo.

I will have to do a different way of making these directories accessible (probably a common mount point with aliases into the appropriate directories).

So will you.


]]>
TQ White II
tag:tech.genericwhite.com,2013:Post/873005 2015-06-23T16:25:23Z 2015-06-23T16:25:23Z AMD for CSS

I am using a lot of Javascript plugins these days and managing them has become a fairly big deal. Recently, I have adopted Asynchronous Module Definition. I am using Require JS (http://requirejs.org) and like it a lot.

The problem is, Require JS does not work with CSS and it turns out that loading CSS is as much of a hassle as loading Javascript.

I think that the basic solution is to put a link to the CSS file into their page. But, I work with a framework and I do not want to pollute it with content-specific code. Some of the pages/sites that use the framework do not need plugin X and should not be having the CSS for it any more than they should have the JS.

Require JS says that they don't support CSS files because there isn't any good way to know when they arrive. It offers a tidbit of code for those, they say, who don't care about the timing of the arrival of the file.

This is nonsense. Following is code that does exactly that. Unfortunately, since it's not built into Require JS, I have to wrap stuff up for callback, but, c'est la vie.


var loadCssFile = function(filePath, callback){

  var link = document.createElement("link");
  link.type = "text/css";
  link.rel = "stylesheet";
  link.href = filePath;
  document.getElementsByTagName("head")[0].appendChild(link);

  var count=0,
  tryAgain=function(){
    for (var i=0, len=document.styleSheets.length; i<len; i++){
      var element=document.styleSheets[i];
      if (element.href && element.href.match(filePath)){
        callback();
        return;
      }
    }
        if (count<10){
          count++;
          setTimeout(tryAgain, 100);
        }
        else{
          throw "loadCssFile() failed on to find "+filePath;
        }
  }

  setTimeout(tryAgain, 100);

}
]]>
TQ White II
tag:tech.genericwhite.com,2013:Post/856642 2015-05-15T19:29:05Z 2015-05-29T15:41:42Z PHP Pretty Print with bbedit PHP is old and ubiquitous. It is completely bizarre that there are almost no options to format your PHP. Javascript has eighteen formatters and evaluaters and lint-ers. PHP is really lame by comparison.

In fact, other than online versions, I only found one. (Your comments will be appreciated!)

http://www.phpformatter.com/ is the only one I could find that I can run on my own computer. It is a pear component. I hate pear. It has all the worst aspects of php - inconsistent calls, structures and everything else.

But, I'm desperate. After a year of primarily NodeJS, I'm returning to PHP having developed a strong reliance on being able to clean up my code at the press of a button. Further, the project I'm returning to did not benefit from that technology so it's got a million lines of code that is only as pretty as I had energy that particular day. Since I'm also trying to read an old project, this is an urgent need.

Since I have hated pear for much longer than I've had my current computer, I had to install it. That was infinitely more hassle than it should have been (I know there are people who dislike NPM but it works infinitely better than anything PHP, including composer). But, done.

After that, installing php_formatter was no big deal. It works, too. Except...

1) Php_formatter actually sets the PHP error_level explictly. The PHP authors, in another example of what's bad about PHP, has changed the meaning of E_ALL. Now it includes E_STRICT. This is really stupid.

2) Php_formatter strips all empty lines from the code. I use empty lines. A lot.

So, here's the thing. I had to edit the php_formatter files to comment out their error specification. Amateurs. It was two files. I don't remember which so do a multi-file search.

I use bbedit by Bare Bones Software (a great program). I want this to operate as a Text Filter. That's not so hard. bbedit passes the contents of the window (or selection) to the program and, bingo!, you are in business. In fact, php_formatter worked correctly once I got it working at all.

The problem is the stripping of blank lines. Turns out that php_formatter supposedly has a filter that preserves them but I could not make that work.

I made a NodeJS program that turns blank lines into comments. Then I beautify. Then I remove the comment characters. Voila! Blank lines are retained.

For the record, here's the Text Filter:

#!/bin/bash

~/Scripts/bin/js/commentUnComment.js -c | php  /Users/tqwhite/Documents/webdev/pear/bin/php_beautifier -t | ~/Scripts/bin/js/commentUnComment.js -u


And here's commentUncomment.js:

[NOTE: This is updated as of 5/29/15. The second regex failed in some circumstances.]

//=========================================================
#!/usr/local/bin/node

var inString='';

var cmdLineParameters={};
for (var i = 0, len = process.argv.length; i < len; i++) {
            var element = process.argv[i];
            if (element=='-c'){
                cmdLineParameters.c=true;
            }
            if (element=='-u'){
                cmdLineParameters.u=true;
            }
        }
       
var writeStuff = function() {
        var outString='';
       
        if (cmdLineParameters.c){
        outString=inString.replace(/\n\s*\n/gm, '\r//\r');
        }
        if (cmdLineParameters.u){
        outString=inString.replace(/^\s*\/\/\s*$/gi, '');
        outString=inString.replace(/^\t*\/\/\s*$/gmi, '');
        }
       
       
        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);

]]>
TQ White II
tag:tech.genericwhite.com,2013:Post/856520 2015-05-15T13:50:27Z 2015-05-15T13:50:28Z Apple OSX Mail Program Changes the Port on Its Own

I use Mandrill for my outbound SMTP. For SSL, it operates through port 587.

I have had many occasions where my connection fails for no apparent reason. I'm just living my life and sending email and then, poof!, an email tells me it can't send with that server. I go through debugging and re-enter the credentials and it would work.

I started thinking "last time it happened, wasn't it the port number that was different then, too?" So, I changed the name of the server to "Mandrill, s/b port 587" so I would know.

It happened again today. I went to look at it the settings and there was a change to port 486. WTF?


I changed it back to 587 and it worked.

I have changed the setting "Automatically detect and maintain account settings" to be off. I'm going to be that stops the problem. If not, I'll update here. If it's been a long time since 5/15/15, you are safe in seeing that as a solution.

]]>
TQ White II
tag:tech.genericwhite.com,2013:Post/838446 2015-04-09T16:07:14Z 2015-04-09T16:10:12Z bbedit as commit message editor for Git

I had this

export EDITOR="bbedit -w"

and, as expected, Git opened bbedit.

But, it also said

Aborting commit due to empty commit message.

Screwy.

I found this:

git config --global core.editor "bbedit --wait --resume"

and put it here so it would be remembered.


]]>
TQ White II
tag:tech.genericwhite.com,2013:Post/827565 2015-03-20T15:16:47Z 2015-03-20T15:20:04Z Dave Winer Strikes a Blow for Freedom

I started my web career with this guy's software. He's an original blogger and podcaster whom I've been reading since the nineties. He's done a lot of interesting things but now he's doing something important.

He has put together a Javscript/Browser blog editing environment that is not tied to any predefined external service. He's making a big point of keeping all open source. One of his major ideas is creating ecosystems. I think this will establish an important niche.

The reason it's important is that it will allow us to establish a web presence without relying on some big company's software. For the most part, anyone who wants to blog or otherwise express him or herself on the web has to use Facebook, Twitter, Blogger, hosted Wordpress, Tumblr, etc. That is, you put yourself at the mercy of their terms and conditions. Worse, your information is stored on their servers where it is probably hard to retrieve for posterity, reuse or backup - if you can get it at all.

Dave's thing is intended to counter that. As I understand it, pre-release, he has defined a protocol for storing data from the browser that can be implemented on any server you want. He also has created a NodeJS component that implements the protocol. All open source.

With his other Javascript things (he calls them "snacks"), he has made configuring and using them an entirely browser-based experience. It sounds like this might require creating a storage location this time. We will see.

However, he has often expressed a philosophical viewpoint with which I agree heartily that being free requires that we be able to communicate on our own terms with technology that is sufficiently decentralized that we cannot be shut down. I'm looking forward to his release of his MyWord Editor Project.

http://tqwhite.org/?89E805

Dave provides additional explanation.

http://tqwhite.org?41A5AE

]]>
TQ White II