Friday, October 31, 2014

Why Doesn't this App Exist?

Surely this app exists, but for the life of me I can't find it on Google Play:

I'm after a simple messaging app that allows one phone to trigger an arbitrary set of vibrations on another phone. The setup would work like so:
  • Phone A: the receiver opens up the app, where it displays the device's unique ID
  • Phone B: the sender, plugs in this ID into his app
  • Phone B: the sender, identifies a series of buttons he'd like to see on the app. Each button has a label as well as a vibration pattern (see also: here) associated with it
Now, anytime a button is pressed on Phone B, Phone A would vibrate to said pattern.

Why do I need such an app? So many reasons. But essentially it allows for quick, silent and long distance communication where the receiver doesn't even need to look at their phone.

Thinking about it, it's basically a digital telegraph, though using vibration instead of sound.

Approximating this app is quite simple in Tasker AutoRemote, so I may just end up doing that as a prototype. Though, that does mean buying Tasker and AutoRemote for the client phone, which all things considered isn't too expensive.

Still, how can this app not exist?

I'll give this a few days, if I'm still craving the app, maybe I'll just write it.

The Time an Accordion Saved a Girl's Life

I'm doing some research on one of the member's of our shul and I came across this breathtaking story:

In 1941, German armed forces overran Bosnia, and stormtroopers quickly started rounding up Jews. The seriousness of the situation became dramatically apparent when Jagoda's father rushed into the family's home and said they had to flee for their lives.

"My father came home all pale and scared to death," Jagoda recalled. "He said the Germans were gathering all the Jews and we had to run away.

"He said it would be too dangerous for all three of us to go together, and that I should go first. He took me to the train station, but he wasn't able to buy me a ticket to a town where his friend would meet me.

"He told me to get on the train, sit down in the compartment and play my accordion. So, for hours, I played all the songs I have ever played."

Passengers were attracted to the music, and soon the compartment was filled with people. When the conductor came in, instead of checking tickets, he sat down to listen.

"The conductor loved music and the accordion and never did ask me for my ticket," Jagoda said. "The accordion was my survival; otherwise, I would have gone in a very bad way.

"My memory of that train trip is fear, fear, fear. Just fear. The music saved my life, because this was a time when they were picking up Jews and sending them to concentration camps.

"Imagine — an accordion, of all things, saving one's life."

Such quick thinking. Such courage. Absolutely amazing. I shudder to think of what my fate would have been if I had been in the same situation.

Recently, I was reminded of the power of music but this takes it to a whole new level.

I'll never listen the accordion the same way again.

Perhaps Aurthur Ashe said it best:

Start where you are. Use what you have. Do what you can.

Here's a short video that captures this story and includes photos of the actual accordion.

Thursday, October 30, 2014

Need a quick mobile prototype? Tasker to the Rescue!

A couple of weeks ago I was browsing the Tasker ChangeLog when I noticed this entry:

event: Steps Taken (Android API 19+)

Interesting. I checked, and sure enough the pedometer on my Galaxy S5 is now wired into Tasker. Specifically, you can have Tasker perform some action when you hit a particular step count (at which point, the step count resets, and you start approaching it again).

I found this functionality terrifically cool, but for the life of me I couldn't think of a practical use for it. After much brainstorming, a half baked project came to mind. What if I plotted my location every 1000 steps. Would results be of interest? (Either as useful personal metrics or maybe just as art).

The more I thought it about it, the more I became curious: would the trail of digital breadcrumbs I left over the weeks and months be of value?

Now that I had my idea I had a new problem: when the heck was I going to find time to implement this bad boy? Probably never.

So I've decided to punt. Yesterday, I setup this new Tasker task:

Profile: Step Loc (41)
Event: Steps Taken [ Number:1000 ]
Enter: Anon (42)
  A1: Get Location [
    Source:GPS Timeout (Seconds):100
    Continue Task Immediately:Off
    Keep Tracking:Off
  ]

  A2: Write File [
   File:Documents/steploc.txt
   Text:%TIMES,%LOC
   Append:On
   Add Newline:On
  ]

Now, every 1,000 steps a two line task is triggered. First the GPS location is calculated, and secondly, this value (%LOC) and the current Unix time (%TIMES) is appended to a data file.

This allows me to start collecting the location and time data now, and if I choose, I can play with it at a later date. If there's a trend there, I can make a more formalized app.

While it's not a slick, real-time visual based solution, it did have the benefit of taking me all of two minutes to write.

Will this little project, if you excuse the pun, lead me down a useful path? I don't know. But I know that I love Tasker for it's ability to quickly prototype concepts just like this one.

Wednesday, October 29, 2014

Praise for Siri and a quick (and surprisingly satisfying) mobile version of Eliza

My friend (and famous author!) Christian Cantrell posted a touching story on Google Plus: To Siri, With Love: How One Boy With Autism Became BFF With Apple’s Siri. It's more than worth your time to read. However, a quick take on it is it that Siri has a number of attributes that make it an excellent companion for the author's Autistic Son(for example: Siri doesn't mind talking minutia for hours, and her gentle corrections help teach important social skills).

Besides this being another see, technology can be a force for good in people's lives! article, it got me thinking about chat bots in general. And no discussion of chat bots is complete without a mention of Eliza, Siri's great-great-great-great-great grandmother. Eliza was a "doctor" who could psychoanalyze you using little more than a set of text matching rules. Still, it managed to give the impression of true intelligence.

With Eliza on the brain, I started wondering how tricky it would be to implement an Eliza clone for my phone. Turns out, not tricky at all. Here's what I did.

First, I cheated and grabbed this implementation of Eliza in Scheme. Yes, I should have written my own. Heck one day, I probably will.

Next, I wrote some wrapper functions around that code to make it accept arbitrary string input:

(define random random-integer)

(define (eliza-scrub text)
 (define (valid-char? c)
  (let ((v (char->integer c)))
   (or (equal? c #\space)
       (and (>= v 97) (<= v 122)))))
 (let* ((chars (string->list text))
        (lower (map char-downcase chars))
        (valid (filter valid-char? lower)))
  (apply string valid)))
  
  
(define (eliza-it text)
 (let ((input (map string->symbol (explode " " (eliza-scrub text)))))
  (implode " "
           (apply-rule ELIZA-RULES input))))

I then busted out my web-apply framework, and attached this function to the local URL: http://localhost:9000/doc:

 (tcp-service-register!
   (list server-address: "*"
    port-number: 9000
    eol-encoding: 'cr-lf)
  (web-fn-dispatcher `(("/doc" . (,eliza-it #t)))))

At this point, I could visit the URL in my browser and have a crude discussion with Eliza. But it's hardly the feel I was after. Next up, I turned to Tasker and created this quick Task:

Eliza (40)
A1: Get Voice [ Title:Talk to the Doctor Language ]
A2: If [ %VOICE eq bye ]
  A3: Say [ Text:Good bye ]
A4: Else
  A5: HTTP Get [ Server:Port:http://localhost:9000
                 Path:/doc
                 Attributes:p0=%VOICE output=display ]
  A6: Say [ Text:%HTTPD ]
  A7: Goto [ Type:Action Number Number:1 ]

The magic is in the Tasker action Get Voice. This prompts a user to say something which is then turned into text and stored in %VOICE. The action Say does the reverse, taking arbitrary text and speaking it aloud. Finally, there's the web invocation of http://localhost:9000/doc which actually executes the above Eliza code.

While the above code is more fragile than I'd like (you need to explicitly bind the the eliza-it function to a port and path), it's also surprisingly effective. The whole experience is voice driven and feels remarkably powerful. It definitely brings back the magic of Eliza that had secretaries and staff confiding in it so long ago.

Tuesday, October 28, 2014

web-apply - Turn your Android Phone into an itty bitty Scheme app server

Checkout screenshots of my latest "web app" :

Pretty lame, right? Perhaps not, allow to me to explain.

What you're looking at are some interactions with web-apply, a crude framework for binding arbitrary Scheme functions to a web page. Here's how it works. First, you start with any old functions. Here's three toy ones:

(define (string-reverse x)
 (apply string
        (reverse (string->list x)))) 

(define (tip-calc amt)
 (map (lambda (percent)
       (cons percent (exact->inexact (+ amt (* (/ percent 100) amt)))))
      '(10 15 20)))

(define (random-within x y)
 (+ x (random-integer (- y x)))) 

Then you bind these functions to a particular port and path:

 (tcp-service-register!
   (list server-address: "*"
    port-number: 9000
    eol-encoding: 'cr-lf)
  (web-fn-dispatcher `(("/rev" . (,string-reverse #t))
                       ("/tip" . (,tip-calc number))
                       ("/rand" . (,random-within number number)))))

tcp-service-register! is built into Gambit Scheme and takes care of accepting TCP connections. web-fn-dispatcher implements trivial HTTP handling and allows for interaction with a browser. The framework has one more trick up it's sleeve: you can pass an output parameter to declare how you want the output rendered. By default, a basic HTML page is generated, though you can pass in display or write to output the content using the aptly named Scheme function.

And here's the cool part: this framework was built in, and explicitly runs on Gambit Scheme on Android. So the above bindings effectively turn my cell phone into a resource an arbitrary user can browse to and interact with.

So why bother writing web-apply? I'm glad you asked. Here are three reasons:

  1. web-apply demonstrates just how powerful Gambit Scheme is on Android. Threads and sockets Just Work, including the ability to debug at the REPL. Combined with Droid Edit, you can really get creative and program dang near anything.
  2. If I try hard enough, I can imagine a circumstance where a team of individuals would want quick and dirty access to interact with some code, and web-apply gives you exactly this.
  3. web-apply should play nice with Tasker, as Tasker allows for easy execution of HTTP requests. This should allow you to code a task mainly using Tasker's standard environment, but jump into the Scheme world when it's convenient.

Of course, this should be considered alpha level code. But it's fun alpha level code, so feel free to play around with it.

Monday, October 27, 2014

Got a little time, Make a little art

While waiting for Disney on Ice: Frozen to being, I captured these pictures of our friend's 3 year old playing with her new light-nunchuks. Surprisingly, they are among my most successful attempts to paint with light. I guess that's what I get for not over-thinking the process.

Disney on Ice: Frozen - So that's what the fuss is all about

This past weekend we took our friend's 3 year old to Disney on Ice: Frozen. Before I talk about the show, let's talk about Frozen itself. Shira wisely suggested we watch the movie before the show, so that's what we did on Friday night (the show being on Sunday). I'm fairly comfortable with sharing spoilers below because we have to be the last people on the planet to have watched the movie.

My first thought, upon finishing the movie, was nu? this is what's taking our culture by storm? But, after thinking about it a bit more, I did appreciate that it was a story of family love and dedication, and not just the usual prince/princess theme. To that end, I was totally fooled by Prince Hans and assumed that Disney was going to give us a happily ever after there. I was less than impressed with story resolution.I appreciate the whole Wizard of Oz you've got the magic within you already. But really, she just realizes "Oh Love?!" and then all her problems are solved? And don't even get me started on the parent's behavior or the troll's bad advice. OK, I suppose I'm being a little too hard on a kid's movie. But still.

After watching the ice version of the story (which more or less follows the movie) I was struck by another important twist: Princess Anna is a self rescuing princess. Well played Disney, well played.

Shira pointed out that it's ridiculous that both princess characters in the movie are beyond-waif thin. If you're going to make characters you're counting on little girls to emulate, it's practically criminal to have this extreme of a body image. Surely some of the billion plus dollars made on the film could have been used to figure out a way to make both attractive and more realistic looking characters.

I suppose it all comes down to the power of music. The story is good enough, the characters lovable (oh Olaf, you're my favorite!) and sure there's some positive lessons in there. But add in catchy songs, and people can't help but love the movie.

If we had daughters in our home, would I want them dressing up like Anna and Elsa? Well, I'd prefer they dress up like, say, Jane Goodall, you could do far worse then a set of sister's who love and support each like the movie suggests.

As for the ice show, it was solid. The costuming, choreography and ice dance were good enough to keep an adult (mostly) entertained. But it was the kid's reactions that made it all worth it. Every child I saw seemed to be loving the experience. From the older ones who were pointing out plot mismatches with the movie and questioning how'd they do that? to the little ones who just loved singing along; everyone was happy. The three year old we brought to the show, watched it with rapt attention. When appropriate, she delicately clapped for the performers. But most of the show was spent spellbound. It was so precious to see.

Sure, the souvenirs and food were overpriced, but there was magic in the air, and for a couple of hours there were many, many happy kids and parents. Who could ask for more?

Gotcha of the Day: Adding an audio stream to a video which Handbrake refuses to process

I'm using handbrake to convert flv videos to various formats on the fly. It's been working exceedingly well, that is until I tried to process a video and hit this error:

$ /usr/local/bin/HandBrakeCLI -i special.flv  -o blank.m4v --preset 'iPhone & iPod Touch'
[11:12:31] hb_init: starting libhb thread
HandBrake svn4582 (2012040901) - Linux i686 - http://handbrake.fr
2 CPUs detected
Opening blank.flv...
[11:12:31] hb_scan: path=blank.flv, title_index=1
libbluray/bdnav/index_parse.c:157: indx_parse(): error opening blank.flv/BDMV/index.bdmv
libbluray/bluray.c:1471: nav_get_title_list(blank.flv) failed (0xb6300490)
[11:12:31] bd: not a bd - trying as a stream/file instead
libdvdnav: Using dvdnav version 4.1.3
libdvdread: Encrypted DVD support unavailable.
libdvdnav:DVDOpenFileUDF:UDFFindFile /VIDEO_TS/VIDEO_TS.IFO failed
libdvdnav:DVDOpenFileUDF:UDFFindFile /VIDEO_TS/VIDEO_TS.BUP failed
libdvdread: Can't open file VIDEO_TS.IFO.
libdvdnav: vm: failed to read VIDEO_TS.IFO
[11:12:31] dvd: not a dvd - trying as a stream/file instead
Input #0, flv, from 'blank.flv':
  Metadata:
    canSeekToEnd    : true
    creationdate    : Thu Oct 23 11:12:12 2014
    Encoded_By      : Sorenson Squeeze
    Encoded_With    : Sorenson Squeeze
  Duration: 00:00:04.03, start: 0.000000, bitrate: 839 kb/s
    Stream #0.0: Video: vp6f, yuv420p, 480x360, 839 kb/s, 29 tbr, 1k tbn, 1k tbc
[11:12:31] scan: decoding previews for title 1
[11:12:31] scan: 10 previews, 480x360, 29.000 fps, autocrop = 0/0/0/0, aspect 1.33:1, PAR 1:1
[11:12:31] scan: title (0) job->width:480, job->height:352
[11:12:31] libhb: scan thread found 1 valid title(s)
+ title 1:
  + stream: blank.flv
  + duration: 00:00:04
  + size: 480x360, pixel aspect: 1/1, display aspect: 1.33, 29.000 fps
  + autocrop: 0/0/0/0
  + chapters:
    + 1: cells 0->0, 0 blocks, duration 00:00:04
  + audio tracks:
  + subtitle tracks:
+ Using preset: iPhone & iPod Touch
<b>ERROR: Invalid audio input track '1', exiting.</b>

The error message is pretty clear - something is up with the audio track of the video. Running flvcheck -v showed that special.flv contained only video frames. Apparently that throws handbrake for a loop (Sorry, Charlie).

The solution turned out to be pretty straight forward. I just needed to turn to my friends stackoverflow and ffmpeg for the answer.

In the end, I used this recipe:

ffmpeg -ar 48000 -ac 2 -f s16le -i /dev/zero \
       -i special.flv -shortest -c:v copy    \
       -c:a aac -strict experimental \
       special_with_audio.flv

This ffmpeg command copies the video stream (without losing any quality) and injects an audio stream built from /dev/zero - which is a stream of null bytes.

This gives you in a glimpse into the power of ffmpeg. One can easily imagine dropping the video stream and keeping the audio; or merging the video of one file with the audio of another. Yeah, if you're going to touch video you need to learn ffmpeg.

Sunday, October 26, 2014

It's a Drive and It's Worth It -- Morven Park

Last night we attended our friends' son's wedding at Morven Park out in Leesburg. The wedding, food and festivities were exquisite (note to self: the idea of having 20+ varieties of cookies for dessert is an absolute winner! Yum!). And the venue, wow, what a place.

Morven Park is definitely worth the schlep (which, without traffic was about 45 minutes away; though the scenery and ambiance is a world away). The changing foliage made the place look like it was out of a storybook. Add to it the three museums on the grounds (where else can you see General Tom Thumb's personal coach or the Museum of Hounds and Hunting) and gardens, it's an absolute winner.

When we arrived fairly close to sunset, the place was crawling with photographers, snapping family pics.

Finally, the park hosts various experimental agriculture projects and is the home of the Presidentially Pardoned Turkeys! Though, there's no mention on the website of whether you can actually run into said turkeys.

Here's one picture of us from the evening. I'd love to go back and shoot many, many more.

Special thanks to our friend Leah for snapping the above photo - nice composition!

Thursday, October 23, 2014

Art Between a Rock and a Hard Place

Next time you're visiting Bluemont Park in Arlington (perhaps to take in a round of Disc Golf, or maybe you're in search of a healthy vending machine snack), take some time to track down J.W. Mahoney's Named Stones art project. When you find it, you'll see a sign with this description:

Arlington artist J.W. Mahoney was one of four sculptors to participate in Onsite: '89: Bluemont Park Sculpture Project, a temporary outdoor sculpture exhibition. Although intended to be temporary, Mahoney’s work, Named Stones, which consists of eight rocks into which words are engraved, endures.

For a temporary art project, choosing to carve in stone was certainly an intriguing choice. Fortunately, most of the rocks are still there and in quite good condition. I ran by Amor and Psyche yesterday and grabbed a few pictures.

I love the relatively camouflaged nature of the project and how it leads to a sense of discovery when you realize what you thought were random rocks are in fact anything but.

Go, track them down. Here's Amor to whet your whistle.

Brain Candy v2.0 - Looking for a Creepiness Check

Two years ago I had a Halloween idea: why not hand out Play-Doh along with candy. The hope would be that this brain candy would foster creativity, versus just fostering cavities. To round out the idea, I thought I'd setup a photo upload site so folks could anonymously share their creations. Like most of my half baked ideas, it went nowhere.

And then, a few weeks ago I was walking through Wegmans and came across this offering from Play-Doh:

They just dropped this idea back in my lap.

So, I took up the cause again. Rather than an obscure tumblr address I went all out and registered sharemycreation.com. I'm still using the Tumblr platform though, as it makes it trivial to take in anonymous picture submissions. Finally, I printed off some labels with the hope of inspiring and explaining the project. Here's what I've ended up with:

I think the odds of anyone actually sharing any pictures of their creations are miniscule, but I just have to put it out there.

I still have a few days to reconsider this little project. What do you think? Have I crossed the line into creepiness? Or will parents see this as a harmless / fun diversion?

By the way, I intentionally kept the site and labels pretty vague, figuring I could hand them out in other contexts besides Halloween. Heck, maybe I could drop some off in the various improvised libraries around town, or just setup my own little Creativity Library. Yeah, how could that fail?

Finally, I've got to send some praise to Avery.com, the company that makes the labels I used. They have an online app that allowed me to create and print off the labels all without me leaving my web browser (and most importantly, without me having to fire up MS-Word).

Caption Me, Rucksack Edition

I managed to grab a snapshot of this group (troop? platoon? patrol? congregation? coalition? quiver? bevy?) of soldiers humping it down Columbia Pike at around 6:45am. This is crying out for a caption, no?

Wednesday, October 22, 2014

All Dressed Up For A Worthy Cause

This past weekend we attended the Arlington Free Clinic Gala, a cause we like to champion. It was held at the National Building Museum, which is quite the venue (as I always say: if it was good enough for Grover Cleveland's Inaugural Ball, it's good enough for me!). But the true star of the evening was my stunning wife.

Tuesday, October 21, 2014

Ancient Laptops and being a Heroic Boyfriend - Text Formatting inspired Stories

You might think a topic like text formatting would be pretty bland. Not so! I have not one, but two stories inspired by the topic. Allow me to share.

I can remember it vividly: I'm 13 years old and working away on my very own laptop. Specifically, a NEC PC-8500, with a whopping 64K (yes kilobytes!) of RAM. I'm typing up an essay for school in the WordStar word processor and having a heck of a time. Specifically, the paragraphs are all askew, with some lines being shorter than others. In the end, I'm left fighting with the computer trying to get the different lines to have somewhat equal length. What a pain.

Looking back, I was running into a fairly classic text formatting problem. Either WordStar had automatic word wrap and I was defeating it by hitting enter at the end of some lines, or it had a manual function to refill paragraphs that I didn't know how to operate. All I know is, this is one of my earliest memories of software appearing to be buggy, but actually performing as designed. Little did I know that I'd pretty much make this fight my life's work by becoming a programmer. Now, on a nearly daily basis I look at software and think "hmmm, it can't possibly be behaving that way...." And yet, it almost always is. And usually it's my fault!

Fast forward from middle school to college for the second story. I'm on Unix Talk with my long-distance girlfriend, and she starts telling me about the arduous task in front of her. She's manually re-formating a massive final lab report. It's taking her forever to adjust each line to the right length. I finally convince her to send me a copy. A minute or two later she receives it back, perfectly formatted. How'd I work this bit magic? Why thanks to the Unix fmt command.

You may be thinking, big deal, you formatted some text. Turns out, it was a big deal. That girlfriend is now my wife of almost 16 17 years. And when I started describing the story a few days ago, she immediately started mentioning details I'd forgotten. That little bit of unix-manship, is probably in the top 10 list of amazing things I've done for my wife. Never underestimate the power of the command line.

In honor of both those stories, I give you a Scheme implementation of fmt. Incidentally, this answers the first part of the Programming-Praxis Challenge, I've still got the second part to complete.

; http://programmingpraxis.com/2014/10/07/text-formatting/

(define (empty? str)
  (= (string-length str) 0))

(define (++ . args)
  (apply string-append
         (map 
           (lambda (any)
             (cond ((string? any) any)
                   ((number? any) (number->string any))
                   ((char? any) (string any))))
         args)))

(define (g options key . default)
  (cond ((assoc key options) => cdr)
        (else (if (null? default)
                  (error "Missing default: " key options)
                  (car default)))))
            
(define (read-token port)
  (let loop ((buffer ""))
    (let ((c (peek-char port)))
      (cond ((eof-object? c)
             (if (empty? buffer)
                 (cons 'eof (read-char port))
                 (cons 'word buffer)))
            ((equal? c #\newline)
             (if (empty? buffer)
                 (cons 'newline (read-char port))
                 (cons 'word buffer)))
            ((equal? c #\space)
             (if (empty? buffer)
                 (begin (read-char port) (loop buffer))
                 (begin (read-char port) (cons 'word buffer))))
            (else
              (loop (++ buffer (read-char port))))))))

(define (output line port opts)
  (let* ((width (g opts 'width 60))
         (align (g opts 'align 'left))
         (delta (- width (string-length line))))
    (case align
      ((left) (display line port))
      ((right)
       (display (make-string delta #\space) port)
       (display line port))
      ((center)
       (display (make-string (floor (/ delta 2)) #\space) port)
       (display line port)))
    (newline port)))
    
(define (handle-word word buffer out width loop opts)
 (let ((line (if (empty? buffer) "" (++ buffer " "))))
   (if (> (string-length (++ line word)) width)
       (begin
         (output buffer out opts)
         (loop word))
       (begin
         (loop (++ line word))))))


(define (fmt in out opts)
  (call-with-input-file in
    (lambda (pin)
      (call-with-output-file out
        (lambda (pout)
          (format pin pout opts))))))

(define (format in out opts)
  (let ((width (g opts 'width 60)))
    (let loop ((buffer ""))
      (let ((next (read-token in)))
        (case (car next)
          ((eof) (output buffer out opts))
          ((word)
           (handle-word (cdr next) buffer out width loop opts))
          ((newline)
           (let ((peek (read-token in)))
             (case (car peek)
               ((newline)
                (output  buffer out opts)
                (newline out)
                (loop ""))
               ((eof) (output buffer out opts))
               ((word)
                (handle-word (cdr peek) buffer out width loop opts))
               (else (error "Unknown peek token:" peek)))))
          (else (error "Unknown token:" next)))))))

(define in "/sdcard/Documents/input.txt")
(define out  "/sdcard/Documents/output.txt")
(define opts '((width . 30)))

(define (range low high)
  (let loop ((i low) (result '()))
    (if (> i high) (reverse result)
        (loop (+ 1 i) (cons i result)))))

(define-macro (repeat qty . body)
  `(for-each 
    (lambda (i) ,@body) (range 1 ,qty)))

Monday, October 20, 2014

What I Learned on The Trail

This marker wasn't intended to report the distance to the nearest bathroom, as I assumed. But was used to report the distance to Washington City. Or as most of us know it, Washington, D.C.

This graffiti wasn't authored by a fan of poetry, as I assumed to be the case. Instead, it was authored by a fan of Dave Mathews.

I can't find any evidence on the web (so it must not be true, right?), but didn't doors stamped with the word 'Globe' appear on the back of school buses? (As say, built by the Sheller-Globe Corp). If so, why would a door end up in the woods, off of 4 Mile Run?

And here are a few more photos I've snapped within the last week or so. Some are from the C & O Canal, and some are from 4 Mile Run.

Why Macros Matter

Imagine you're a Senior Developer at Big Co and while reviewing Junior Programmer Jimmy's latest set of check-ins you see the following code repeated a handful of times:

  return '$' + 
         new BigDecimal(value).
          setScale(2, BigDecimal.ROUND_HALF_UP).
          toPlainString();

You pull Jimmy aside and explain that the above should really be packed into a function (or method) rather than being written out long hand. In other words, it should read:

  return Format.money(value);

You explain that by doing this Jimmy and the team will gain at least three benefits:

  1. Fewer Bugs. Not only is the function call above shorter, but there's no chance to accidentally forget part of it, or put an erroneous value in place (for example, pass 3 to setScale). And if there was a typo, such as Format.mony, you'd get a clear error message rather than just an oddly formatted value.
  2. Clearer Code. In the original version of the code, the reader has to think in terms of numeric and string operations. If the programmer wasn't familiar with BigDecimal, they might have to open up the docs to see how it's used. In the more compact form, the intention is clear: a value is being prepared for display to a human.
  3. Easier Maintenance. From a maintenance perspective, having the code wrapped up in a single location means that it can be fixed or improved upon with ease. Let's say negative values should be rendered with parenthesis around the value. Making this change to Format.money is trivial, do a find a replace throughout a massive code base, no so much.

Finally, you explain to Jimmy that if he ever finds himself copying and pasting code around alarm bells should sound in his head and he should make the appropriate abstraction.

As an aside, the above can be considered a procedural abstraction. Naturally, programmers love them (and for their sanity, need them!). So much so, in fact, that even if a language doesn't provide an official mechanism for creating procedural abstractions (assembly language perhaps? Old school BASIC?), a clever programmer will find a way to simulate them. Sure, this facility may depend on GOTO and global variables, and it may be fragile and error prone, but it will get the job done.

A few weeks later, Jimmy comes bursting into your office. He eagerly explains that he paid attention to what you suggested and has come across a abstraction that the team should adopt. If they do so, thousands of lines of code will be cleaned up. He goes to the whiteboard to explain. Rather than coding like so:

  private int foo;
  public int getFoo() {
    return foo;
  }
  public void setFoo(int _foo) {
    this.foo = _foo;
  }

The team should write:

  property(int, foo);

After all, he explains, you'll get the same 3 benefits as above, though on a larger scale because we use this pattern all over the place.

You're then left with the unfortunate task of explaining to Jimmy that while he's right, it's not so simple. Yes, they should create such an abstraction, but their language of choice (in this case, Java, Circa 2000) doesn't allow for this. That's because what's called for here is a syntatic abstraction rather than a procedural one. In fact, very few languages give you this capability.

Still, programmers are a clever bunch. Just like our Geek Forefathers and Foremothers who made do before reliable procedural abstraction, those lacking syntactic abstraction will find a way. In Java, for example, the above problem may be solved by using the Eclipse to generate the code. In PHP, you could simulate the above using property overloading. And when all else fails, you could run your source code through GNU m4. However, at the end of the day, these methods are all relatively fragile when compared to true syntactic abstractions.

And what language provides such a capability? Why, Scheme does, and the facility goes by the innocuous sounding name macros.

Learn Scheme. Learn Macros. Learn what you've been missing out on.

Thanks to Grant for helping motivate me to write this post.

Wednesday, October 15, 2014

Gotcha of the Day: Creating macros from within Gambit Scheme on Android

One of the most powerful features of Scheme is the ability to create macros. That is, along with the procedural abstractions most languages allow you to create, you can also create syntactical ones (I've got at least one blog post worth of stuff to say about this, so I dare you to ask me more!). While working on a Scheme Challenge on my cell phone, I wanted a quick way to repeat some code. Specifically, something along the lines of:

 (repeat 10
   (display (read-token in)))

(That is, I wanted to read and print the next 10 tokens from the input port in)

This is an easy enough macro to write in syntax-rules so I got to work. I quickly ran into an issue: define-syntax wasn't defined in the Gambit instance I was using. I tried a few other guesses and finally gave up, figuring I'd poke around the manual when I had a chance.

Sure enough, the manual had an explanation: define-macro is available by default, whereas define-syntax requires an add on module. While I'm no fan of define-macro, for my purposes it would work fine. I went ahead and put the following in ex1.scm, the file containing my answer to the exercise I was working on:

(define (range low high)
  (let loop ((i low) (result '()))
    (if (> i high)
        (reverse result)
        (loop (+ 1 i) (cons i result)))))
        
(define-macro (repeat qty . body)
  `(for-each (lambda (i) ,@body) (range 1 ,qty)))

I then ran my (lex) procedure from the REPL. To my surprise, the file loaded.

I then went to test my code:

(repeat 10 (display i) (newline))

To which the interpreter rudely responded:

*** ERROR IN (stdin)@2.2 -- Unbound variable: repeat

What the heck?

After a couple of more attempts I realized that I could use repeat within ex1.scm, but any attempt to use it from the REPL resulted in an unbound variable. When in doubt, read (or in my case, re-re-read) the manual. Which explains:

The scope of a local macro definition extends from the definition to the end of the body of the surrounding binding construct. Macros defined at the top level of a Scheme module are only visible in that module. To have access to the macro definitions contained in a file, that file must be included using the include special form. Macros which are visible from the REPL are also visible during the compilation of Scheme source files.

(Emphasis added by me)

I updated my (lex) procedure to be defined as:

 (define (lex)
  (include "/sdcard/Documents/ex1.scm"))

And what do you know, it worked! The REPL can now see and use the repeat macro.

In the future, I may mess around with loading the syntax-case facility into Gambit. This actually doesn't look like a particularly hard thing to do, I just know that when I attempted to load this file my phone churned on it for quite a while before returning an error. That makes me think this may be asking for a bit much from my Android. Regardless, define-macro gives me plenty of power, and I'm using it on a small enough scale that its unhygienic nature shouldn't do too much damage (famous last words, right?).

Finally, two other useful bits of info if you're playing around with the Gambit REPL on Android:

1) If you hit run next to the "Start REPL Server" example you can use a program like netcat to connect to the REPL for your laptop. This let me fiddle around with Gambit on my phone while using my laptop's keyboard and display. This is a classic trick, but one that never ceases to amaze me when I use it.

2) If you type ,? at the REPL prompt you'll gain access to a number of debugging commands. I haven't quite figured out the various "REPL levels" yet (that is, what's meant when you have an error and Gambit changes the prompt to 2>). But I now know I can jump to the top level by typing ,t.

Tuesday, October 14, 2014

The Running Shoes I Want vs. The Running Shoes I Need

My dream pair of running shoes are minimalist, ultralight, highly breathable and as long as I'm making demands, affordable. Thing is, I own these shoes and to be perfectly blunt, they're awful. Problem is, they deliver on the promise they make: running with them is like running barefoot. Running barefoot is great. That is until you land on a tiny sharp stone. You know, the kind that your buddy in Nikes doesn't even notice. Depending on the size and shape of the rock, the result is somewhere between painful and dangerous.

So while I still keep an eye out for times when I can run in my ultralights, I knew I needed a sturdier shoe for both road and trail running. Enter the Merrell Men's Ascend Glove running shoe. It promised to be a minimal running shoe that was also trail friendly.

The Merrell's arrived and didn't strike me as being particular 'minimal.' Sure, they seemed relatively lightweight, and they have the 0mm drop between the heal and toe going for them. But still, I was skeptical.

I've now taken them out on multiple runs, walks and even used them to climb Old Rag. Any concerns I have, have since evaporated. I'm officially impressed.

The Merrell's are comfortable to run in and the mesh top provides noticeable breathability. I suppose they aren't ultralight, but they're certainly far lighter than Shira's trail runners. Most importantly, the soles are protective enough to let me tackle any terrain I want. From a rocky path to the construction zone at the end of our street, I no longer have to feel like I'm running through a mine field while out for a jog. They Just Work.

In the end, the 'Ascend Glove' appears to be the right balance of lightweight and minimal construction that I want, and the protection and functionality that I need.

Monday, October 13, 2014

Taking a Bite Out of Rochester

This past weekend Shira and I visited family in Rochester. Sunday arrived and we weren't quite sure what activity would work for everyone. After a bit of research, Shira suggested the Annual Apple Tasting Tour, an event nobody in the family had ever heard of. The goal is to visit a bunch of apple farms in the area (specifically in Wayne County) and, well, taste the apples. We figured the scenery alone would be worth the trip. So, we all crammed in the car and off we went.

We ended up making it to two farms and a distillery (more on that in a minute). For once, Rochester weather cooperated, and we were treated to a perfect fall day. Slightly crisp but with lots of sunshine. The apples were quite tasty, and the foliage along the way was downright stunning. While the notion of heading off to Wayne County evoked images of trekking out in the wilderness, it was actually all of about a 25 minute drive. It continues to amaze me how little of the Rochester area I've seen, even though I grew up there (or perhaps, because I grew up there).

An unexpected find in the area was Apple County Spirits, a distillery that specializes in fruit based spirits. They offered tastings of various hard ciders as well as an Apple Vodka and a couple of other hard alcohol choices; one from apples and one from pears. My Mom, whose favorite drink is hard cider, was in heaven. And then there's this thought: when Passover rolls around, most hard alcohol is off the menu because it contains grain. But these varieties come from fruit! With the right certification, they could be the perfect Passover option. Not to mention, without grain, they are gluten free. Regardless, my parents and I quite enjoyed the distillery.

We made one other stop along the way, though this one wasn't on the Tasting Tour. We stopped by our childhood Buddy, Aaron's house, which happens to be just a couple of miles from the farms we were visiting. It was a huge treat getting to catch up with him, and I'm still trying to fully process the fact that not only does he have a 2 story former barn as a garage and a riding lawnmower, but he's got chickens in the backyard! He even gave us a dozen fresh eggs to drive home the point. I'm impressed!

All in all, everyone had a great time. Apples were tasted, alcohol was drunk and I got to take lots of photos. It was a perfect day!

View Photos

Wednesday, October 08, 2014

3 Trail Running Hacks: Duct-Tape, Doggies and Daylight

As long as I've got trail running on the brain, here's a few tips I've come across of late:

A Mini Blister Control Kit -

[A] couple weeks ago while enjoying some epic trail time with a good friend Matt. I rarely have blister issues but five miles into a 17 mile run I had created a whispering hot spot on the outer edge of my right heel. By mile seven, it was rather annoying. I tried various lacing adjustments, readjusted my socks, looked for a boulder positioned at the back of the shoe…nothing provided the continuous relief I was looking for.

After a brief regrouping at our vehicles, I dug through my run bag looking for some Body Glide or tape…nada. Fortunately, Matt dug though his center console and found an old tube of a lip therapy product. I gave it a try and rubbed a bit of the lubricant on the tender hot spot and my foot enjoyed the final 10 miles without any discomfort. Niiiiicccee!

From this experience, the author suggests a handy blister kit:

That would be a tube of lip therapy wrapped in a length of duct tape. Very clever. I carry athletic tape in my trail running kit, so I've got half the tip already implemented.

Read the whole article here: Trail Running Hack: Blister Control Kit

A Doggy Drinking Idea - I can't say that I've ever gone for a run with a pup before. But, I thought this tip was worth knowing and a mention regardless:

One trick I use is to take a clean doggie poop bag (weighs nothing to carry), make it into a dish-shape, and pour water into it, holding the bag in place while she drinks. I have also dug a small hole or indent in the ground, and placed the bag over that. The water pools in the hole, held in place by the bag, and she drinks from there. I can then cover the hole back up and move on.

Maybe this one is obvious to dog owners, but I was impressed. Read the whole article here: 12 Reasons Handheld Bottles Are Better Than Hydration Packs.

Use your GPS to tell you how much daylight you have remaining - I originally downloaded the Android App GPS Test, to well, test Shira's GPS. It turns out, however, that the app is useful for more than just getting diagnostic info about your device's GPS. Using nothing but the GPS on the phone, it can report heading, speed and altitude. And to my surprise, it also reports the sunrise and sunset:

Now, getting your cell phone to cough up sunrise and sunset time is pretty trivial. Just Google for it and you'll get an instant answer. But, GPS Test works its magic without requiring a network. And because I've got T-mobile, pretty much anytime I'm out in the woods, I expect to be without signal.

As long as I've got my phone, I've now got a good sense of how much daylight I've got left. Whether that will help me to actually turn around or not is another story altogether.

Tuesday, October 07, 2014

Miva Merchant for Code Geeks; Or how I fought against the default Miva dev model and sort of won

Miva Merchant? Let's Do it!

I've got a relatively new client who's current platform is MivaMerchant. While he's open to switching to a new platform, I'm hesitant to do so without a firm grasp of his business and what the pros/cons of Miva are. So for now, I need to become best buds with Miva.

Doing a few Google searches turned up MivaScript.com, which implies that Miva is, well, scriptable. And while the syntax appears to be on the clunky side (it's XML based, so that is to be expected), it does look relatively complete.

As I dove into my first few projects, I started to come up to speed on Miva. The video tutorials are well done, the admin tool quite complete, and template language (audaciously named Store Morph Technology aka SMT) looked promising.

But wait...

As I started to truly build out my projects I kept running into two questions: (1) where's the flat file interface for the templates, and (2) when do I get to start using MivaScript?

While the admin UI is nice and all (there's a basic version control system built in), it's hardly the ideal environment to work on large template files (which are a mix of HTML and special tags). Or put more bluntly, I want to use emacs to edit content, not a text area in Firefox. Surely I was missing something. Finally I broke down and filed a ticket on the topic. The tech rep said she'd call me to discuss; and sure enough she did. She explained to me that you *have* to use the admin UI, there is no file interface. Apparently, the Miva techs work by copying and pasting content into a text editor, making changes, and copying and pasting it back.

While the tech was very nice (and again, promptly called me), surely she must have just been misinformed. Miva can't expect professional programmers to build sophisticated stores by copying and pasting code. Can they? Even if I'm OK with all this copying and pasting, how am I supposed to use a real version control system or do an automated deployment, if all the source code needs to live in an HTML admin tool?

I took my quandary further up the Miva chain. (Which again, I give them credit for having as an option.) I finally spoke to a senior developer and he told me that the tech's understanding is correct. They are aware of the limitations of the admin UI, but it's the only way they currently support using Miva. I got the impression that future versions of the product may help address this issue.

OK, I'll learn to love the admin UI. My work around for now is to keep a version of the templates found in Miva in a local source repository. The content of the PROD page for example, is stored in: admin/Pages/PROD/Page.smt.

And it gets worse

Issue number (2), however, points to a potentially larger concern. After a bunch of research I learned that Miva Merchent itself is written in MivaScript< and while the templates themselves understand SMT tags, they don't process MivaScript. In other words, your typical MivaMerchant developer never writes or even encounters MivaScript. Fair enough. But how do they modularize code? That is, how do I void duplicating code in templates, and how do I keep my templates from growing out of control? Looking at the template language of choice, there didn't seem to be a way to include code. Without a basic include statement, how can I achieve any sort of modularity?

I ran these questions by the nice tech that called me. The short answer was, there is no way to do this. At the senior tech level, he mentioned something about setting up custom items that would appear in the UI as their own editable regions, and then I could include those items at will. This is somewhat promising, but that means embracing the the admin UI even more.

All this left me pretty disappointed with Miva. There simply had to be a way to make it more developer friendly.

A first attempt at a fix

If the standard set of tools weren't going to give me what I wanted, what about building out a custom extension or two? I make custom plugins in WordPress all the time, how hard could it be to do in Miva? This seemed promising, as extensions are written in MivaScript, so I'd get power of a full programming language instead of making do with an admin UI and the basic SMT language. Alas, after a few days of analyzing extensions (you can see lots of examples in the source for MivaMerchant provided here (and you'll need the compiler here), I finally had to throw in the towel. Between the fact that MivaScript is a language unto itself, and my lack of understanding of how MivaMerchant operates, I'm just not ready to create extensions for it. I had to surrender.

And the real fix

But still, I wasn't ready to give up on my dream of a move developer friendly Miva experience. And then I found the missing piece of the puzzle: the External File Pro v5+ module. This bad boy allows you to invoke a MivaScript function in an arbitrary file, and it places the result in an SMT file of your choice.

Let's take a specific example to see how this module can save the day. Suppose you want to customize your title tag depending your product name. You could head over to the PROD page and put in some code like this:

<mvt:if expr="l.all_settings:product:name EQ 'Iguana'>
  <title>Love Lizards! Buy an Iguana Today!</title>
</mvt:if>
<mvt:if expr="l.all_settings:product:name EQ 'Turtle'>
  <title>Totally Turtles! Buy an Turtle Today!</title>
</mvt:if>
...

But, that code is messy and hard to maintain. Ideally, it would live in its own function, in its own file. That's where External File Pro comes.

The first order of business is to buy and install the External File Pro v5+. Once you've enabled the module and associated it with the PROD page you're ready to get to work.

I created a MivaScript source file: /mm5/snippets/seo/title.mv. The path is totally arbitrary. I plan to organize all these includes as snippets, and this particular one is related to SEO. Hence the naming. Note, the source file is .mv. The actual MivaScript file looks something like this:

<MvComment>
  Generate our Page Title in a smart way. If we can make a better title than the default one, then
  go for it.
</MvComment>

<MvFUNCTION NAME = "ADS_External_File" PARAMETERS = "module var, item, all_settings var, settings var, ignored" STANDARDOUTPUTLEVEL = "text, html, compresswhitespace">
  <MvIF EXPR = "{ l.all_settings:product:name EQ 'Iguana' }">
    <MvEVAL EXPR = "{ '<title>' $ 'Love Lizards! Buy a ' $ l.all_settings:product:name . ' Today!' $ '</title>' }"/>
    <MvFUNCTIONRETURN />
  </MvIF>

  <MvIF EXPR = "{ l.all_settings:product:name EQ 'Turtle' }">
    <MvEVAL EXPR = "{ '<title>' $ 'Totally Turtles! Buy a ' $ l.all_settings:product:name . ' Today!' $ '</title>' }"/>
    <MvFUNCTIONRETURN />
  </MvIF>

  <MvEVAL EXPR = "{ '<title>' $  $ l.all_settings:product:name $ '! Buy one Today!' $ '</title>' }"/>
  <MvFUNCTIONRETURN />
</MvFUNCTION>

Notice that the function is named ADS_External_File. That's a requirement of the External File Pro plugin, and serves as the entry point to our snippet.

This file needs to be compiled to a .mvc file. I'm using a simple Makefile to accomplish this:

## Makefile for building our MivaScript function files

export PATH := /c/tools/miva/msc/BIN:$(PATH)
RM  = rm
MVC = mvc.exe  -B 'c:\tools\miva\msc\BUILTINS'
SNIPPETS = seo/title
SRCS     = $(addsuffix .mv, $(SNIPPETS)))
COMPILED = $(addsuffix .mvc, $(SNIPPETS))

all : $(COMPILED)

%.mvc : %.mv
 $(MVC) $<

clean :
 $(RM) -f $(COMPILED)

With the command:

  make ;  sitecopy -u dev.mysite.com

The snippet is compiled and pushed to the server.

Finally, in the PROD Page template I put in a call to the snippet:

  <mvt:item name="ads-extfile" param="function|/mm5/snippets/seo/title.mvc"/>

And I'm done.

Whoo!

I've now got the ability to create arbitrary functions in MivaScript and pull their contents into an a template. This gives me the modularity and maintainability I was after, and opens the door to streamlining development of complex functionality. Looks like Miva and I may indeed be best buds after all.

Monday, October 06, 2014

Challenge Finally Accepted - Climbing Old Rag

For years I'd considered dragging Shira out to one of Virginia's most challenging and beloved hikes: Old Rag Mountain, but my fear of heights always kept me from suggesting it. Shira solved this problem earlier in the week by saying she'd like to tackle it. Between that and my brother's assurance that I'd have no problems, the deal was sealed. We'd do Old Rag.

And we did!

Old Rag is essentially a 9 mile hike split into three parts. There's a slog up hill through switchbacks, and there's a long downhill that starts on steep trail and finishes with a couple miles on a gentle downhill road. And in between there's the Rock Scramble; it's this mile plus section that kept me away from the hike for so long.

How to describe the rock scramble? It's essentially a collection of obstacles that require you to shmoosh between, over and/or under various rock formations. For example, the first challenge you encounter is described as a "12 foot deep crack" that you have to slither into. You can see why I was wary of this hike. While some of the sections are ridiculously steep, they thankfully never triggered my heights fear. I think that's because the rocks were fairly sheltered, and one never quite feels like falling off a cliff is an option. One of the early rock scrambles does potentially have you going close to a ledge, but I opted to scoot on my tush under an overhanging rock, rather than stand up and face the drop off. Pride, for me anyway, was the first thing to go on this hike. There's definitely an instant sense of community on this hike. We helped random strangers, and random strangers helped us. There was no ego on the mountain, just a sense that we're all going to get this done.

Now that I've gotten through the rock scramble I can look back and say it was actually fun. There were a handful of times when I thought, "there's simply no way," and yet, we always found a path that worked. Having Shira and Dawn as cheerleaders made all the difference.

This truly is a unique hike, and the fact that it's less than 2 hours from DC makes it even more amazing.

If you're in good physical shape, then Just Do It! I promise you won't be disappointed. Just be prepared to spend 5+ hours on this project (the hike took us 5 and a half hours). That plus the drive time means this is a full day adventure. But, what an adventure it is!

View All Our Pics

Trail and Road Running Kits, v2.0

There's a thread over at edcforums.com that I wanted to contribute to: Your EDC in the woods. I was thinking I'd post my Trail Running Kit (v1.0) as it's the minimum amount of gear I take into the woods (add a water bottle and some snacks, and I'm good for nearly all the hiking I do). However, it occurred to me that the photo there was a bit out of date. So here it is, an update to my running gear.

First off, I'm now using two belt packs for running. No, you'll be happy to know, they don't get worn at the same time. One is for road running and one is for trail running. The trail kit inspired me to carry a few essentials while road running, and to date both kits have come in handy on a number of occasions.

First, here's the trail kit:

This includes:

  • Keychain which includes: compass, Derma-safe razor blade, Photon X-Light, House Key, Pill container with a Bendryl and Migraine medication, Nitecore NWS10 whistle, safety-pin, USB thumb drive / Micro SD Card Holder / Micro SD Card, P-51 Can-opener with paper clip to keep it closed
  • Heatsheet mylar blanket
  • Athletic tape
  • KT Tape
  • Handkerchief
  • Bic Lighter
  • Galaxy S5 Android Phone

Note, the keychain is the standard one I carry around. I just drop it into the pack, and it gives me most of the outdoorsy stuff I could need. The tape has been useful on a number of occasions as has the hanky. The Bic Lighter is strictly a Boy Scout item; there's something about going into the woods that makes me think I should have a way to start a fire. The setup fits nicely in the Amphipod AirFlow Microstretch Belt pack, which stretches to fit everything. There's even room to squeeze in extra goodies, if need be.

The road running kit is similar but exchanges the emergency blanket and Bic Lighter with more city-friendly items:

  • Keychain (the same one as above)
  • Athletic tape
  • KT Tape
  • Handkerchief
  • $20 bill
  • Credit Card
  • Galaxy S5 Android Phone

I actually called up my credit card company and ordered a second card which lives permanently in this kit. They were glad to send me one, and I don't have to worry about forgetting to replace the one in my wallet. This kit is smaller and fits well in a waterproof SPIbelt.

When going on a run, I grab the appropriate kit for the terrain, and I've got all my bases covered.

Friday, October 03, 2014

Ouch! Playing with the VIPERTEK VTS-881 Stun Gun

A few weeks back I'm browsing Amazon and notice a stun-gun is mentioned in the Customers Who Viewed This Item Also Viewed section. Being the ever curious, as well as self appointed Safety and Preparedness Officer of the home, I had to take a peek. I found myself staring at the VIPERTEK VTS-881. I read the reviews, and almost on a lark decided to add the item to my cart. At $13.98, I figured I'd get a smile out of Shira when I presented it to her.

Now, there's at least two obvious problems with stun guns. One, they have no range. From the picture on Amazon I can see two contacts that need to be pressed up against the bad guy (or gal)'s skin. That means that to use this sucker you need to already be in a heap of trouble. Nobody wants that. Pepper spray, on the other hand, at least gives you some stand off distance. (Of course I've bought pepper spray for the wife; my favorite being this guy; perfect to keep under the bed for bumps in the night).

The other problem with a stun gun is that it needs to be applied to the skin (or perhaps thin clothing). That means that not only does the bad guy need to be on top of you, but you need to be targeted as to how you use it. That's going to be tricky, if not impossible to do in a high stress situation.

But, like I said, for $14 bucks, I figured I couldn't go wrong.

A few days later the Vipertek shows up. I'm impressed right away with the build quality. For $14.00, I didn't expect much, and this feels like a sound device. Check out this size comparison:

As you can tell, it's a little narrower than a deck of cards and about the same size as compact LED flashlight. It's got a non-threatening shape as well.

The device itself couldn't be simpler to use. There's a slider switch that goes between off, flash-light and armed and a small button you can press to discharge it.

The flash light is a really nice touch, as it's quite bright and makes the device useful even if you don't find yourself in a dangerous situation.

The device has a slider switch that reveals two prongs that let you plug it into an outlet. It's ideal that you don't need to fiddle with cords or worry about losing a charger. It's all self contained.

I've yet to actually try to stun anyone with this. However, I've discharged it a number of times. Good golly, this sucker is powerful! Just the snap of the arcing electricity is enough to convince me that I don't want to mess with anyone carrying one of these.

Given all the above, I've had to re-think my attitude towards stun guns. While I'm the farthest thing from an expert on this topic, and I've got experience with exactly one device, I can tell that this guy has some key advantages:

  • Given the shape, size and flashlight functionality, you can openly carry this in nearly any context. Walking down a dark alleyway, you could bust it out and never given any indication you're carrying a weapon.
  • While it lacks the stand off distance of pepper spray, you're not going to run into issues with the wind blowing your weapon back in your face.
  • Unlike pepper spray, it's much easier to train with. You can practice with it anywhere, and without worrying that your test conditions won't match the real thing.
  • The aggressive arcing of the spark may in fact provide a deterrent, though that would be situation dependent
  • Chances are the assailant isn't going to be expecting you to have a stun gun, so you may be able to use the element of surprise.

So, should you go to Amazon, buy one of these and walk around like you're bullet proof? Uh, no. I see a weapon like this as being a solid addition to training. For example, in Krav Maga we're always talking about making space to take further action. While I doubt getting 7,000,000 volts to your arm is going to knock a bad guy out, I bet it would work wonders for making that space to take further action.

And besides, for $14.00, it's hard to argue with this guy's value.

If you're looking for another self defense option, check out the Kubotan.