Get path or location of currently executing batch/command file in Windows

I didn’t know it was this simple, and am posting this information on my blog so I find it in the future, but hopefully this will help someone else!

I’ve created a number of batch files over the years which routinely copy files from one location to another, usually as part of a backup strategy. However, I’ve always just hard-coded the paths of the drives, etc. into the batch files. While this works for drives which are permanently attached (or internal), it’s more fragile with external (flash/USB) drives. As I’ve never understood the logic of drive letter selection in Windows (letters usually are the same, but occasionally not), it meant that I was tweaking the drive letter in the batch file before running. Annoying, but it worked.

Thanks to more than a few web sites, I now know there is a much better way!

There are basically two decent options, depending on your scenario and requirements.

Option 1

If you are using drive letters (and not a mapped drive\network share), then you can use the variable %CD%.

It contains the “current directory.” So, that actually may be more than you wanted if the current directory isn’t the root of the drive.

image

Simple, just chop it off:

image

%CD:~0,2%

The colon and tilde character is a flag which indicates that a substring should be returned rather than the entire string. The first value is the zero-based starting index and the second is the number of characters you want to return:

image

The above starts at character 4, and includes 3 characters.

For fun, you can use negative values:

image

With only a single negative parameter, it returns the number of characters requested starting with the rightmost character.  (Check here for a bunch of examples on string manipulation.)

So, you could use knowledge in a batch file:

image

The above line uses robocopy (available in modern versions of Windows without an extra install) to copy from the folder \\server\Backups to the current path appended with \server\backups. So, if the batch file containing the robocopy command was executing on the J: drive, the resulting robocopy command would be:

image

By using the :~0,2 syntax, regardless of the folder the batch file is located in, it always copies to the root of the J drive (as the first two characters are J and : ).

Option 2

The other option is a bit different as it only works in a batch or command file.

image

Parameter zero (%0) in batch file represents the full path of the currently executing file (path and filename). The (dp) modifiers expand the value to be the “drive” and the “path,” excluding the file name.

image

You can manipulate the value as well:

image

I’m immediately going to adopt the first option into all of my “robocopy” batch files.

Nest Thermostat Review, Update #10: Wifi Settings Missing

One more brief update about our Nest thermostats. After a few weeks of limited use of our HVAC system due to a very unusually warm late winter and early spring, I’d set the whole house to AWAY mode last evening. However, a bit later, I heard the furnace running. Odd. I walked to the thermostat that I’d set to away and confirmed it was still “AWAY.”

imageI grabbed the iPad and used the Nest app. The thermostat that I had set AWAY to was reporting the same error that I’d seen back in January: the giant question mark. Tapping the image resulted in the message:

Thermostat Disconnected – The thermostat First Floor last connected to the nest.com more than 3 days ago.

Three days?

image

So, I went to the thermostat and checked it’s settings. Great, no wifi and no account information. It had apparently forgotten it’s wifi connection information completely and also my account information.

Seriously, I’d want to fire myself if I wrote code that was this bad. Why would it EVER dump that information? It’s literally its key to being a smart thermostat.

Thankfully, as we still have 2 other thermostats in the house, it was simple to add the account back to the thermostat after entering the wifi password again, as the thermostat recognized that there were other Nests nearby.

Without the wifi connection, you still have a thermostat (thankfully!). However, you loose all remote scheduling capabilities via their web site or apps.

I still can’t recommend these thermostats. While the “BETA” label has been finally removed from their remote access web application, the device itself still has numerous unresolved issues.

Captcha, gone wrong

On a Google site this morning, Captcha:

image

As I have a US English keyboard – I was unable to type the first word. (Anyone know what language that is? I thought Greek at first, but the “n” didn’t make sense.)

I then proceeded to skip through 8 more captcha’s before I found one I could actually recognize. Sigh.

JavaScript: isScrolledIntoView

image

I needed a simple way to detect when a placeholder DIV (that would contain an image) had scrolled into the current viewport of the browser. I’ve seen a few solutions that worked, and a few that didn’t (hello? test your code!). Here’s my simple solution:

function isScrolledIntoView(elem) {
    elem = $(elem);
    var win = $(window);
    var docViewTop = win.scrollTop();
    var docViewBottom = docViewTop + win.height();
    var elemTop = elem.offset().top;
    var elemBottom = elemTop + elem.height();

    var a = (elemTop > docViewBottom);
    if (a) { return false; }
    var b = (elemBottom > docViewTop);
    if (!b) { return false; }
    return !(a && b);
}

Nothing fancy, except it does require jQuery.

When one of the place holder DIVs scrolled into view, the code would trigger a queued load of the image.

SmugMupBrowser-live

As the SmugMug API is poorly designed in a few places, in particular as it relates to showing a thumbnail for a gallery/album, when an album/gallery is scrolled into view, the app loads a list of ALL of the images from the now visible album and selects one of them to show as the thumbnail. It’s extremely inefficient unfortunately. Instead, if they could have included that extra piece of data in the gallery list (thumbnail image and thumbnail image key), boom!

I’ve also included a delay so that the auto loading only occurs after a 1 second pause (either the window being resized or scrolling occurring):

function delayLoadNewVisible() {
    if (visibilityDelayTimerId == 0) {
        visibilityDelayTimerId = window.setTimeout(function () {
            visibilityDelayTimerId = 0;
            loadNewVisible();
        }, 1000);
    }
}

I’m not going to post the code for the other useful aspect of this functionality, but I’ll tell you about it, and leave coding it as an exercise for the reader. Smile

When the user scrolls new albums into view, after the pause, they’re added to a load queue. However, as it’s just as likely that the user will scroll the album off the screen, my load code also can remove something from the load queue if it hasn’t been loaded already. This way, visible albums are given precedence. By using the queue in this way, there are a manageable number of outstanding requests at any given time, and ideally only those that are relevant to what’s on the user’s screen.

Knockout.JS: Dictionary/Index and ObservableArray, Part 2

Ryan suggested an alternative in a comment (and corresponding jsFiddle) to the technique that I’d used in my previous Knockout.JS post.

Following his suggestion, I made a few tweaks to my original function (and renamed it yet again):

ko.observableArray.fn.withIndex = function (keyName) {        
    var index = ko.computed(function () {
        var list = this() || [];    // the internal array
        var keys = {};              // a place for key/value
        ko.utils.arrayForEach(list, function (v) {
            if (keyName) {          // if there is a key
                keys[v[keyName]] = v;    // use it
            } else {
                keys[v] = v;
            }
        });
        return keys;
    }, this);

    // also add a handy add on function to find
    // by key ... uses a closure to access the 
    // index function created above
    this.findByKey = function (key) {
        return index()[key];
    };

    return this;
};

To use, just tag on the withIndex function call:

var ViewModel = function () {
    this.uniqueNumber = 0;
    this.list = ko.observableArray([]).withIndex('id');
};

In the example above, the objects stored in the “list” observableArray will be indexed by the “id” property.

By adding the withIndex function call to the observableArray creation, an additional function is added to the array object, findByKey.

$("#btnAdd").on("click", function () {
    var id = vm.uniqueNumber++;
    vm.list.push({
            id: id,
            time: new Date().toLocaleTimeString()});
    var data = vm.list.findByKey(id);
});

In the above example, a new “log” object is added to the list, and then retrieved by the key a moment later (dumb, yes, but hopefully instructive).

I intentionally added the findByKey only to array instances that include the indexing functionality added by withIndex. One reason was to not have the function be available for all arrays (as it doesn’t work for non-indexed arrays) and the second was that it makes possible a bit of slick JavaScript closure value hiding. This way, the index is never stored anywhere on the original view model. Instead, it’s kept entirely within the closure.

But there’s more!

What if you want to have multiple keys or don’t like the name of the find function?

Here’s the kicked up a notch version:

ko.observableArray.fn.withIndex = function (keyName, useName) {
    /// keyName == the name of the property used as the index
    ///            value.
    /// useName == when false, a function named findByKey 
    ///            is added to the observableArray.
    ///            when true, the function is named based
    ///            on the name of the index property &
    ///            capitalized (like id becomes findById)
    var index = ko.computed(function () {
        var list = this() || [];    // the internal array
        var keys = {};              // a place for key/value
        ko.utils.arrayForEach(list, function (v) {
            if (keyName) {          // if there is a key
                keys[v[keyName]] = v;    // use it
            } else {
                keys[v] = v;
            }
        });
        return keys;
    }, this);

    var fnName = "";
    if (useName && keyName) {
        var cap = keyName.substr(0, 1).toUpperCase();
        if (keyName.length > 1) {
            fnName = cap + keyName.substring(1);
        } else {
            fnName = cap;
        }
    } else {
        fnName = "Key";
    }

    var fnName = "findBy" + fnName;
    this[fnName] = function (key) {
        return index()[key];
    };

    return this;
};

This optionally uses the name of the key parameter to build a findByXYZ function using the pattern of findBy{KeyName}. It also capitalizes the function name to follow typical JavaScript coding conventions. Here it is in when initialized:

this.list = ko.observableArray([])
                .withIndex('id', true)
                .withIndex('time', true);

(note that they’re chained above) … and in use:

var data = vm.list.findById(id);
data = vm.list.findByTime(time);

You’ll see how the “findBy” functions are named “findById” and “findByTime” as the original call to “withIndex” used the optional second parameter set to true. I suppose this follows a tiny bit of the automatic mix-in style of Ruby on Rails (but is optional).