the mental meanderings of a nerd in the twin cities who has a family and a bike and some other stuff...
11 March, 2018
... thinking in circles
decisionpoints mandated in its execution logic. many loops are terminated
based on a length and they pick through data until some known point, maybe the
length of the data.
in the begininning of my programming days, i was only able to envision fixed
ends. loop `for` and only `for` this long, but that could be inefficient as there
may be a reson to terminate before the end, so `breaks` were used but the syntax
was ugly because the intent of the `for` appears as if it is to run all the way
through. yet, `while` hidden in its logic is a `break` whose condition needs a code
__comment__.
all the `while` a cleaner loop existed with its intent clearly
expressed and the code became more readable with less reliance on
soon-to-be-stale comments. constructs such as `each` took the `for`'s place,
spelling that actions were to happen all along the length of this line of
data.
the loops were all spelled out.
then, came the method that called itself. it didn't look anything like a loop,
just passing along what's left of the data to be handled by the next time this
method was to be called, which was right now because i'm that method and i'm
calling it, which is to say me and... was it to be an endless loop that couldn't
be because of finite resources like a python swallowing its tail?
relax...
although it may not work for everything, the terse--yet powerful--form of
recursion is somewhat poetic. the sleek and postmodern feel to code in which a
method keeps calling itself until some point at which it exits, the depth to
which is not known to the developer. instead, if the data given are still
open to processing, then we let the
(originally a guest post circa 2014 on the now-dark opinionateddeveloper.com)
14 March, 2017
The People
However, today, I talked some, and I listened a lot. I work in a satellite office, but I'm on a visit to HQ. There has been a lot of turnover in leadership through the last year, and I spent time with Directors, VPs, a C-level person, and others. All but one of these people were new since my last visit.
I'm not really a press-the-flesh kind of person. I feel like I can connect, remotely, via technology, but you have to be very deliberate. After today, I realized that being here, in their office, with a limited amount of time, was a different way of being deliberate. Being present, makes you a person, not an appointment. It's easy to skip an appointment.
If I had to come out here to be a human, so be it. I need to accept that certain people need that. Meeting people on their terms, especially for the first time, just reduces friction.
03 December, 2014
Do you currently work in the Dev Ops environment?
"Do you currently work in the Dev Ops environment?"
Here's my answer:
No, the devops is not really a thing. The devops is the intersection of development and operations skills. In reality a devops culture is still built around product. A dev team takes control over its ops concerns to ensure they deliver the best product the can. When someone "specializes" in the devops, they are no longer focused on product and are no longer dev, they are ops. They may be ops for developers--helping build their development environments and playing an extremely important role--but they are no longer devs (for the product team).
Now... ops people who approach things from a software engineering perspective (automate all the things!) are extremely valuable. They probably are the best fit for your search for people to fill the devops role.
30 November, 2014
Empathy and the Product Era
24 May, 2013
tmux clear backscroll...
# clear scrollback
bind-key C-k send-keys -R \; clear-history \; send-keys "Enter"
Which is nice, so I perform a control+b control+k and it clears the screen. However... there's a really nice side effect that I stumbled on completely by accident. If I already have a command queued up and ready to go when I use that keystroke combination, the send-keys "Enter" causes the command to execute.
That way, I get the command to execute and the only output I'll ever be able to scroll to is the entire output of the command! I had added the send-keys "Enter" to this because the rest of the command was leaving me with a blank screen and I had to hit enter to get my prompt back. Now... I have a new workflow I like.
23 February, 2013
tdd-bdd goodness
wow, ok, so here's another huge plus for TDD and BDD. it gives you the confidence to not immediately blame your own code when something goes wrong when you deploy and take part in a large SOA project. when you know that, given the right inputs, you'll produce the right results (because you built the system using TDD based on the other system's messages), you know to look to things outside your system when it's going pear shaped.
turns out, this was a human error thing that was the result of some less-than-stellar design on my part. also, the QA test plan was not using our intended behavior for the software, so... suffice it to say, there were a lot of cognitive leaps to be made to get this validated. buuuuuut... the greatest thing i got out of it was i was an effective troubleshooter because i didn't waste time (or stress) digging in my code for answers.
it turned out to be an education thing. once the dust settled, code was verified.
01 January, 2013
vim commands/functions to run cukes within vim
The other day, I was moaning about cucumber and locations of step files, as it encourages (but doesn't depend upon) a file-naming convention. As such, step files can be hard to find. Anyway, as I'm kicking through a way to script a solution to that problem, I decided I wanted a way to run cukes from within vim.
I came up with two solutions:
- one to run the whole file that's in the currently open buffer
- one to run the scenario that starts on the line the cursor is on
I just added the following command definitions to my .vimrc:
command! Cuke call s:RunShellCommand('bundle exec cucumber ' .expand('%:p')) command! CukeL call s:RunShellCommand('bundle exec cucumber ' .expand('%:p').':'.winline())
I haven't mapped short commands with my <leader> yet as I'm not sure if I'll use this regularly, but it seemed helpful, so I thought I'd share. The drawback is that the execution time of cucumber is long, especially if it's a UI test, so it can take over your UI for a while, which is why I added CukeL, so I cold run just the current line. The cucumber overhead is still pretty high, so I may look into creating a modified RunShellCommand that forks the process, so you can continue working while you fire off the command.
31 December, 2012
cucumber disambiguation, or... survival tip for a noob in an existing rails project
I finally stumbled upon the right incantation of cucumber options to get what i needed:
bundle exec cucumber -o cuke.out --format stepdefs features
If you want to do all features. However, if you just want to discover the feature-step relationships for a specific feature:
bundle exec cucumber -o cuke.out --format stepdefs features/specific_feature_file.feature
Will produce output like this:
5.1738260 /^I am logged in as a valid user$/
# features/step_definitions/authentication_steps.rb:100
2.6341953 /^(?:|I )go to (.+)$/
# features/step_definitions/web_steps.rb:48
2.1448050 /^I should be able to visit the admin area$/
# features/step_definitions/admin/admin_steps.rb:5
1.2116820 /^I am logged in as an admin$/
# features/step_definitions/authentication_steps.rb:106
0.7382180 /^I am logged in as an uber admin$/
# features/step_definitions/authentication_steps.rb:118
0.1408770 /^I should see the Contacts\/New Contacts page$/
# features/step_definitions/marketing/contact_list_steps.rb:1
0.0094120 /^(?:|I )should not see "([^"]*)"$/
# features/step_definitions/web_steps.rb:123
0.0092010 /^(?:|I )should see "([^"]*)"$/
# features/step_definitions/web_steps.rb:105
Now, you can tell where the f-uh-uh-uh-uke, fuke... er... cuke the implementation is. Odds are, a team who's been doing this for a while have shut off step output because they know the project like the back of their hand, but something like this will help a noob like you get up to speed in an existing project. Well, it helped me and it took a while to find the right search terms to give me what I needed. Oh, also, the output file was a huge help because the number of NOT MATCHED BY ANY STEPS lines in the project blew the useful stuff right out of my iTerm's scroll history.
Good luck...
Now, I'm thinking of writing a vim plugin that will use this output to create a ctags like file that will allow you to jump around from feature to step regardless of what your file naming conventions are.
03 November, 2012
agile practitioners, are we waiters or doctors?
I am now in my 8th month at a company who is committed to using Scrum for their development process. I was a certified scrummaster a couple of years back, but my employer at the time didn't practice, so I let certification lapse. Between that employer and my current employer, I took a short stint at a software company that had some big quality issues which they'd asked me to come in and help solve. We didn't have the same view of what might solve the problems, so put a few things in place to help, but ultimately decided to let them get back to handling things without me. I have done a number of agile-flavored things in my career, but had yet to practice a formal agile method before this.
Now, I'm in my 8th month of practicing full-on scrum with a product team. There have been ups and downs, but they're neither as high nor as low as I've experienced at other places. It feels extremely sane, but I have been feeling, lately, like I just react to "priority." Admittedly, until yesterday, I hadn't been able to put a name to it, and, while I had a sense that something was off, I wasn't sure what.
I've wanted to work in an agile process for quite some time, why didn't it feel perfect? Things are working very well, we get our product work done, we meet our deadlines, so what could be wrong? When in an afternoon openspace session about the Doctor-Waiter metaphor, Hussman asks those of us sitting around, "So, are you a Doctor or a Waiter?" It hit me, "oh wow, I'm a waiter." That's what I've been missing.
Anyway, in that openspace session, we kicked the metaphors around and while people were in the process of torturing it, it occurred to me that there are good waiters too. In fact, I had a chance to eat at a great tapas place a few weeks ago in which a waiter guided us through the experience. Could waiter and doctor not be two discrete things, could they, instead exist on a continuum of maturity from waiter to doctor? So, my contribution to the metaphor torture was, "Considering there's a continuum from waiter to doctor, are we working our way through med school by waiting tables?" It got a couple of snickers, but we didn't explore the thought.
Here's what I was trying to get at with the question, just because we're being waiters, doesn't invalidate what it is. It serves a purpose. I am gaining my experience with scrum as a participant, but now that I know there's a higher purpose, I'll be working toward doctor status. Admittedly, my mojo isn't being completely fed or this metaphor wouldn't have resonated so well with me. Some participants (including me for a few moments) in the open space session talked like they were victims of the process, which is why I wanted to kick the metaphor a little longer. Now that we know the names, now that we've identified the healthy state, let's work through it. It's kind of like the start of a 12 step program: admitting the problem.
Except, I won't go so far as saying it's a problem. It may work very well for organizations to feed bite sized chunks of product information through teams working in short iterations. This keeps teams from burning out and it does get things done (still way better than waterfall). What's missing, though, is a feeling of empowerment and engagement for the entire team.
Is being a scrum waiter an organizational thing or is it an individual choice? I will admit, that, as the new guy, I have sat back and observed. I'm working in a new language (yeah, only 8 months with grails too), the lead who hired me has left the company, and I'm experiencing a new development methodology. It didn't take me too long on Agile Day to come to the conclusion that I've chosen to be a waiter. It has served its purpose, giving me exposure to the process, time to absorb a new language and framework, and a breather to embrace the organizational change around me. I have to admit, I've probably even been a little purposefully dysfunctional about my waiter status by pushing all responsibility for prioritizing the backlog on my product manager. Rationalizing it with statements like, "he knows the business."
Now that I am cognizant of that sense of doubt--no... let's call it unease--about where I am in my maturity around scrum, I own the outcome. So, I'm going to start working my way through "med school." I'm not sure of the exact path, but I do know that I have more to contribute to the process than just writing the code. I'm starting to really internalize the product space, so I can begin to help dig into those areas, but I am, for sure, able to be more of an active participant in grooming the backlog and story planning to represent areas in which I do have significant knowledge and the ability to control, e.g., performance and architecture.
As I'm beginning to understand, a healthy scrum process probably expects me to be acting doctorly. So, choosing just to participate with a small pad of paper in my apron and a pencil behind my ear, I'll be the one breaking the rules, not the victim.
14 October, 2012
amping up the watij
I've been working on a grails webapp recently that I need to iterate on pretty quickly. Unfortunately the steps are getting more and more complex that have to be performed in each iteration. This weekend's project was an attempt to get a web-testing automation flow. No, not for deep QA or for extensive regression testing, I just want to be able to fire off some tests so I can iterate. In case you're wondering, this is on a mac.
I've looked around some and, to date, watij had the lowest bar to entry. So long as I had everything on the classpath that came with the watij webspec zip file, it seemed to work just fine. I wrote a shell script watij.sh to handle the dirty work:
export JAVA_OPTS=-d32
export CLASSPATH=$WATIJ_HOME/testlib/engine-gecko.jar:$WATIJ_HOME/
testlib/engine-ie.jar:$WATIJ_HOME/testlib/engine-webkit.jar:$WATIJ_HOME/
testlib/jniwrap-native.jar:$WATIJ_HOME/testlib/junit-4.8.2.jar:$WATIJ_HOME/
testlib/jxbrowser-2.5.jar:$WATIJ_HOME/testlib/log4j-1.2.15.jar:$WATIJ_HOME
/testlib/MozillaGlue.jar:$WATIJ_HOME/testlib/MozillaInterfaces.jar:
$WATIJ_HOME/testlib/mshtml.jar:$WATIJ_HOME/testlib/runtime.jar:
$WATIJ_HOME/testlib/slf4j-api-1.5.8.jar:$WATIJ_HOME/testlib/
slf4j-log4j12-1.5.8.jar:$WATIJ_HOME/testlib/tuxpack-0.2.jar:$WATIJ_HOME/
testlib/watij.jar:$WATIJ_HOME/testlib/webspec.jar:$WATIJ_HOME/testlib/
winpack-3.8.jar:$WATIJ_HOME/testlib/xulrunner-linux.jar:$WATIJ_HOME/
testlib/xulrunner-linux64.jar:$WATIJ_HOME/testlib/xulrunner-mac.jar:$WATIJ_HOME/
testlib/xulrunner-windows.jar:.
USAGE='
usage: watij <watijscript>.groovy [scriptargs ...]
sets watij libs on classpath (based on WATIJ_HOME) and
runs groovy-based watij scripts. All scriptargs passed
on to the groovy call.
'
while [ $# -gt 0 ]
do
case $1 in
-h)
echo >&2 "$USAGE"
exit 1;;
*) break;; # terminate while loop
esac
shift
done
if [[ $1 == *.groovy ]]
then
groovy $@
else
echo >&2 "$USAGE"
fi
Yes, that means you have to set an environment variable, WATIJ_HOME. Then, I also wanted to be able to write and execute my scripts from within vim as that is my primary development tool, so I added the following to my .vimrc:
command! -complete=shellcmd -nargs=* Watij call s:RunShellCommand('watij ' . expand('%:p'). ' ' . <q-args>)
function! s:RunShellCommand(cmdline)
echo a:cmdline
let expanded_cmdline = a:cmdline
for part in split(a:cmdline, ' ')
if part[0] =~ '\v[%#<]'
let expanded_part = fnameescape(expand(part))
let expanded_cmdline = substitute(expanded_cmdline, part, expanded_part, '')
endif
endfor
botright new
setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile nowrap
call setline(1, 'You entered: ' . a:cmdline)
call setline(2, 'Expanded Form: ' .expanded_cmdline)
call setline(3,substitute(getline(2),'.','=','g'))
execute '$read !'. expanded_cmdline
setlocal nomodifiable
1
endfunction
The RunShellCommand function was straight out of the vim tips wiki. It makes it so the output of a command is displayed in an extra window. The Watij command! statement makes it so I can execute watij against the script in the currently active editor window:
Just type :Watij <followed by args>
In this case, my script will launch bing because I added that as an argument
Now... after closing the groovy window with command-q, I see any printed output from the script in the scratch window in vim:
Now, just close the scratch window with :q
In a perfect world, I would like to create a homebrew formula for installing/configuring this and configuring the .vimrc. But... I need to get back to doing some work, so I just decided to blog about it for now.
21 July, 2012
function! s:RunShellCommand(cmdline) echo a:cmdline let expanded_cmdline = a:cmdline for part in split(a:cmdline, ' ') if part[0] =~ '\v[%#<]' let expanded_part = fnameescape(expand(part)) let expanded_cmdline = substitute(expanded_cmdline, part, expanded_part, '') endif endfor botright new setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile nowrap call setline(1, 'You entered: ' . a:cmdline) call setline(2, 'Expanded Form: ' .expanded_cmdline) call setline(3,substitute(getline(2),'.','=','g')) execute '$read !'. expanded_cmdline setlocal nomodifiable 1 endfunctioni found out about this here: http://vim.wikia.com/wiki/Display_output_of_shell_commands_in_new_window
then, i added some commands to my vimrc:
this one searches all my groovy files for the word under the cursor (the
command! Srchwg call s:RunShellCommand( 'find . -name \*.groovy -exec grep -H --regexp="' .expand("<cword>").'" {} \;')this one, takes an argument for a filename extension and will search all files of that type for the word under the cursor:
command! -nargs=+ Srchw call s:RunShellCommand( 'find . -name \*.'' -exec grep -H --regexp="' .expand("<cword>").'" {} \;')
now, i can have my cursor on a line and type :Srchwg which will open a window with a list of files that contain the word. or, if i type :Srchw js, i'll search all js files in my project for the word under the cursor. nice.
i was thinking of writing a function to, then, open files based on the buffer opened by the RunShellCommand method, but i found that vim already has functionality to do that. all i needed to use was the handy-dandy gf functionality!
anyway, one of these days, i'll package up all of my vim tricks into either a vimball or just a vimrc that you can source into your vimrc and open source it on github.
24 March, 2012
Carboy 0.1.2 is out in the wild
Thus, carboy was born. Homebrew is in reference to home brewing of beer and a carboy is an important part of any homebrewer's toolkit. Here's a library that, if included in your rakefile, gives you some valuable build functionality for creating installs for homebrew. I have released preliminary versions of it to github and rubygems.org
https://github.com/bikeonastick/carboy
https://rubygems.org/gems/carboy
For information on how to use it, read the simple steps 1-10 in the README for carboy on github. Step 0 is assumed, but if you need it, you need it. There's also an example included within carboy called my-tools. Look at that for more info.
I'll be speaking at ruby.mn about carboy on Monday 26 March 2012. Well... I was pretty vague when I signed up to speak, which was before I made the jump from telling folks what I learned about developing for homebrew to writing carboy. Oh well...
One last thing for those of you interested in writing your own Homebrew formulae. Here were some good resources:
21 January, 2012
macvim dev env update
as i've been watching grails webcasts like bobby warner's jump into grails 2.0, i've been a little jealous of textmate's ability to "find files." so i started searching for a vim plugin to do the same and found command-t. it's pretty cool. as i've mentioned before, i've been doing a few things with keymappings to make macvim act the way my fingers need it to work. i had to add a little magic to my .gvimrc to make it work for me.
macmenu &File.New\ Tab key=<nop> map <D-t> :CommandT<cr>
now, command + t enables the file finding feature of the command-t plugin.
26 December, 2011
running a simple rails app (like wagn) with ubuntu upstart
I had a hell of a time getting my upstart script to start. It kept launching, reporting that it started and even showing a pid, but it would die. This was a version of the same script I had written in a shell script and it would execute just fine. The addition of the export HOME, suddenly made things come together.
I'd been chasing the various values in the expect stanza, but nothing made sense. Once I had the HOME export in place, I was able to find the right setting for the expect stanza after a couple of tries.
Anyway, I wanted to run a very simple rails app, called wagn, as an internal tool on an internal server. In the event that our box goes down, I want wagn to restart. Furthermore, I don't have a bunch of time to muck about with all of those full-on production ways of deploying ruby, so I went looking for the best way to run this on the platform I had in front of me. I found out the new way of running services on ubuntu is through upstart.
After looking through a bunch of things on upstart:
I found a hint... well, something I hadn't tried yet. Anyway, upstart seems to need a HOME var set when you execute. So, if you've been searching, here's a good example to go on if you want to run a rails server with upstart. You can create something similar to the following in /etc/init/servicename.conf. If you are using it specifically for wagn, edit my path below to match your install location for wagn.
# example script offered with NO WARRANTY. # feel free to use it or just learn from it # wagn-server - wagn-server job file description "wagn server" author "robert tomb" # restart process if crashed try 10 times every 5 seconds respawn respawn limit 10 5 # let upstart know the process will detach expect daemon # When to start the service start on runlevel [234] # When to stop the service stop on runlevel [016] # don't know why but home=root is necessary # found it here: http://kevin.vanzonneveld.net/techblog/article/run_nodejs_as_a_service_on_ubuntu_karmic/ script export HOME="/root" exec /usr/local/wiki/wagn-1.7.0/script/server -b 192.168.1.54 -e production -p 3000 -d > /var/log/wagn.log 2>&1 end script
14 December, 2011
Hate bat scripting? Me too...
Abstract
Hate BAT files? Yeah, so do I. Stuck on windows for reasons beyond your control but need to do some scripting? Sure, you can use perl, ruby, python or jruby, but all of those require the installation of an interpreter.
How do you survive if you have a bare-metal windows box and aren't allowed to dictate prerequisites? You could fall back on bat scripting and risk the integrity of your hairline or you could fall back on your JavaScripting skills and go against the WSH.
I'll show you a couple of minor examples in a JS coding idiom that makes sense to me and share as many of the references as I remember that helped me with my code. Lastly, I'll give a few suggestions as to where this can be used. Hopefully, this will be enough to spur your imagination to use JavaScript solve problems you have on the windows platform.
Windows Scripting Host
Here's your goto microsoft site for this http://msdn.microsoft.com/en-us/library/9bbdkx3k.aspx . This site is going to give you all of the conceptual stuff you need to know about this. I'll talk about some things I had to reconcile and give you a codesample walkthrough.
Executing your scripts
- just execute a js script from the cmd line
jsmn_all.js - execute it from the command line with cscript
cscript /Nologo jsmn_all.js - create a .wsf file to define and execute it with cscript
cscript /Nologo jsmn.wsf - or just execute your wsf file from the command line
jsmn.wsf
Go here for info on wsh files. Basically, they offer the ability to define a script and do imports, similar to what you do in an html file with
I'm not going to get too far ahead of my self decomposing this entire script. Suffice it to say that this allows you to connect to jsmn.js and use things in it, such as the ScriptHelper object. Objects that are part of the windws scripting host, e.g., the WScript object are going to be in your execution scope no matter what, so there's no need to root around for some WSH javascript file to "include."
You can have multiple script references, but I don't know the limitations. You can even have your script entry point in one of the referenced scripts. I can see where it might make better sense (and make your editor of choice happier) if you put all logic in a js file and only used hour WSH file like a project file.
What can you do with this here WSH thingy?
Good question. Well, I have a progressive "hello jsmn" demo for you that might help to enlighten. You'll really have to dig through the Microsoft pages to see all that you can do. You can even use this to wrap windows commandline commands.
I see it as a great way to drop a toolkit onto a bare metal windows box and make yourself productive. Seems like something that could be very powerful for sysadmins or testing engineers especially for windows VMs.
Oh yeah, the demo
Running just this with no Arguments yields a dialog box with:Needs two arguments: one to specifiy the subject and another for desired action. Here's the ScriptHelper class we instantiate and call methods from:
/* * Class for grouping functions that are important to this script. */ function ScriptHelper(word1,word2) { this.desktopiconfolder = ""; this.envname = "jsmn"; this.write_script; this.fullFileName = WScript.ScriptFullName; this.wshShell = WScript.CreateObject("WScript.Shell"); this.objFSO = WScript.CreateObject("Scripting.FileSystemObject"); this.wordOne = word1; this.wordTwo = word2; this.speak = function() { WScript.echo(this.wordOne + " " + this.wordTwo); } }
I'd like to do something slightly more sophisticated than just echo some crap out
So, let's write to a file. I'll add a speakToFile function to my ScriptHelper class
this.speakToFile = function(loc) { this.write_script = loc; var filelocation = loc; if ( this.objFSO.fileExists(filelocation) ) { this.objFSO.moveFile(filelocation,filelocation + ".bak"); } var ForWriting = 2; propFile = this.objFSO.OpenTextFile(filelocation,ForWriting,true); propFile.WriteLine("WScript.echo('from file:" + this.wordOne + " " + this.wordTwo + "');"); propFile.Close(); }
and tell my WSF file to call that instead of speak.
Now, when I run
jsmn.wsf hellooooo jsmn
it writes a file to disk called jsmn_write.js. This file contains one line of javascript and if I execute jsmn_write.js, I'll see
"hellooooo jsmn"
So, I can write a file, what else?
There's all sorts of windowsey stuff you can do like write shortcuts... So, I add a call to a createShortcuts() method
And, this takes a few more methods to support it, but I add the following methods to ScriptHelper
this.createShortcuts = function() { this.createShortcutFolder("Shortcuts for " + this.envname); this.createShortcut("TestShortcutFor-" + this.envname,this.getScriptDir()+"\\"+this.write_script,this.env name); };
this.createShortcutFolder = function(name) { var desktop = this.wshShell.SpecialFolders("Desktop"); this.desktopiconfolder = desktop + "\\" + name; this.objFSO.CreateFolder(this.desktopiconfolder); };
this.getScriptDir = function() { var forShortening = this.fullFileName; var lastSlash = forShortening.lastIndexOf("\\"); var shortened = forShortening.substring(0,lastSlash); return shortened; }; this.createShortcut = function(linkName,tgtPath,args) { var myShort = this.wshShell.CreateShortcut(this.desktopiconfolder + "\\"+linkName+".lnk"); myShort.WindowStyle = 1; myShort.TargetPath = tgtPath; myShort.Arguments = args; myShort.Save(); };
Now when I run
jsmn.wsf hellooooo jsmn
I get a shortcut folder on my desktop with a shortcut in it that has a link to jsmn_write.js. That's it for my demo, I hope it was simple enough to follow but sophisticated enough to give you some ideas for new ways to use your javascripting skillz.
Debugging?
cscript has an option for a debugger, but I have not successfully used it.
//X Execute script in debugger
NOTE: I will research this further and update or write a new entry on this
Soo... What else is possible?
Unit testing is pretty cool and if you're developing some sort of a toolkit with WSH scripts, you might want to be able to build them with TDD or just have some tests to prove that your code doesn't toally suck. I have not tried either of these, but they look very promising:
The next time someone tells you that JS is a toy language and you can't do anything with it, you can tell them to kiss your asterisk.
Acknowledgements
Also, this post uses the awesome syntax highlighter from alex gorbatchev it's some pretty cool javascripting in its own right.