No Bikes, No Ice Cream, No Bacon, No Ice, No Signal, No Laundry – St George Island Spring Break

2015-04-08 13.26.00
View from the bay side of SGI.

Based on the fact that people seem to love to go to St. George Island, Florida with their dogs, and the $24/night camping available at Dr. Julian G. Bruce St. George Island State Park, trying a new place for Spring Break seemed to be worth the risk. Unfortunately, our risk calculation was poorly researched from the start. Our normal beach destination, Santa Rosa Beach, FL, is only a 9 1/2 hour drive from Louisville, KY vs. over 11 hours to SGI. Fortunately, we broke up the drive both ways with overnight stops, but that seemed to just add to the perceived travel time.

I’d imagine part of the appeal of SGI is its relative remoteness. The state park is on the eastern tip of the island as well, which makes it even more remote. The campsites are 4 miles from the entrance to the park (with official speed limits of 15-25 MPH). It’s another 2-3 miles at 35 MPH from the state park to the first commercial businesses. Camping with limited food supplies meant that eating often required a 30+ minute round trip. The state park didn’t have laundry facilities as our normal Spring Break destination state park does, and the closest laundromat is back across the bridge (probably 20+ minutes away).

Somehow, the squirrels and raccoons on a island that is only connected to the mainland by a 6 mile long bridge are more numerous and aggressive than the animals in the park at Santa Rosa Beach, Florida, just 2-3 hours west on US-98… it only required a few minutes of someone carelessly leaving a campsite unattended for food to be devoured by squirrels in the day and raccoons at night. Of course, it’s not that surprising for experienced campers that animals will target your food, but the efficiency and skill at which they did it *was* surprising. One such casualty was a pound of bacon left in a cooler. The mosquitoes were also out in way more force than other camping trips to the panhandle.

The business owners on SGI expressed surprise that last week was the busiest week they’ve ever experienced. We weren’t able to try to rent bikes until Monday morning, and by then, there were no adult bikes available on the island. We ended up with with 2 20″ bikes and a beat up adult tricycle with a basket for $125. Not really that bad a deal, but one of the bikes went unused most of the week because of its size.

Costs

Restaurants seemed to be a bit pricey relative to our regular stops of Edisto, Santa Rosa, and Outer Banks. Taxes are 7% SGI tax + 2% local option, which further inflates your bills.

Truly Disconnected and the Restaurants

Wireless signal was non-existent for us. Looking at coverage maps, it appears that the magic carrier down on St. George Island is Verizon.

Harry A’s and Subway were staples of the week. Harry A’s is moderately priced, but they have solid wifi, which was necessary because our T-Mobile phones were rarely capable of even texting. Subway actually advertises “We have wifi”. Obviously, it’s a pervasive problem.

The Blue Parrot Paradise Cafe was good and is on the Gulf side which was good for the view, but horrible for cell phone reception and they don’t have wi-fi.

Eddie Teach’s was a pretty miserable experience on a Wednesday night. They ended up being crowded, and then we made the mistake of ordering a pizza for my daughter. The pizza clearly comes from elsewhere–pretty sure it was from the gas station in Eastpoint, 6 miles away. When the pizza came back, the order was wrong, so they reordered. We had a dispute with the owner about whether we should be paying for a pizza that was 30 minutes later than the rest of the order, etc. I won’t be going back there again if I end up on SGI, and I’m definitely not ordering the pizza. My wife got an order of nachos for $10.99 that was pretty mediocre, too.

It seems that the businesses run into supply issues due their remoteness. Subway ran out of bacon. The ice cream shop next to the beach store had a few pathetic looking tubs of partially melted ice cream where there should have been 30 selections or so. The state park ran out of ice for sale on our second to last day (Thursday) with no apparent expectation of it being replenished. Edisto Island in South Carolina seems similarly isolated, but doesn’t seem to have the same supply problem… yet.

Two pleasant surprises of our trip

  • The Apalachicola Bay Aquatic Preserve has several small aquariums showcasing area aquatic life and other exhibits. It’s either brand new or kept in pristine condition.
  • Our trip to Apalachicola, which gave me the opportunity to stop in at the Oyster City Brewing Company (no food, just tap room) and then have incredibly inexpensive dinner at The Hole in the Wall. I would definitely spend more time in Apalachicola next time… it has so much old city charm. Unfortunately, many places seem to close early there.

Trails and Activities

I didn’t bother with my own bike (considering there weren’t any available), but if I had, I would have ridden down the multi-use path that goes down the main road across the island. It goes on for miles (13+ if I recall correctly), but it wasn’t scenic enough for my interests, and it was too far away (4 miles) to run to. Instead, I first explored the limited access park road beyond the last beach access. It’s mostly sand and gravel, and wasn’t suitable for either trail or standard running shoes. More importantly, it had no shade to speak of, so I ran 3 of the 4.2 miles out, and ended up overheating from the sun and walking back.

I next tried the path to the primitive campsite (and Gap Point). 2.5 miles (one way) of about 50% dunes with slightly more shade than the other paths. It was more interesting, but there wasn’t the usual mental stimulation of a trail run, as there’s pretty much only one direction to go in. On my way back, I tried the East Slough trail that goes over wooden bridges. I was pressed for time and baking in the sun so I cut that exploration short.

Final Thoughts

Maybe it was more humid than normal this year. Maybe SGI was more crowded this year.

Experiences with Dropbox as iPhoto Library Backup

Background:

The renewal on my annual Mozy Backup subscription was due, and I decided that I wanted to consolidate backup solutions. Dropbox had (recently?) upped their Pro plan to 1TB, so there was plenty of room to back up a 100GB iPhoto library.

I made the switch on Wednesday of this week, dragging the iPhoto library in Photos over to the Dropbox folder (do this with iPhoto closed and then double-click once moved to let iPhoto figure out the new location.) I did a selective sync to another computer that was lacking in hard drive space so that the Dropbox sync wouldn’t eat up all the space.

Finder claims there are about 98,000 in the library. Dropbox was indexing about 360,000. I haven’t dug into the discrepancy, but I’m guessing hidden files aren’t in the Finder count. 

 Setup:

MacBook Pro mid-2009 model, 8 GB RAM, 1 TB 5400 RPM HD, 50/10 Mbps Cable Internet service through TWC. 

 Tweaks:

Default setting for Dropbox upload is to “Limit automatically” (as shown below) to minimize disruption to other Internet activities. I had to change that to “Don’t Limit”.

Dropbox Network Settings

As of Saturday (3 days later):

I’ve also done a disk clone of the of the 1TB and gotten caught up on Time Machine backups, but three days later, Dropbox has indexed half of the files and uploaded 10GB of data. 

 As of Monday (5 days later):

Dropbox is down to only indexing its last 18,000 files (5.6%) and has uploaded roughly 85 GB of data.

As of Wednesday (7 days later): Dropbox appears to have backed up 160 GB of data, but it also appears to have crashed at some point along the way as well.

devise_security_extension undefined method authenticate for nil:NilClass on Rspec Tests for Controller That Skips Authentication

After installing the Devise Security Extension to add password expiration to my Devise models, I started getting the following error on an RSpec test for a controller that does not perform authentication of the user:

     Failure/Error: get :index
     NoMethodError:
       undefined method `authenticate?' for nil:NilClass

After a bit of digging, I found that the helpers.rb in the gem includes an additional before_filter that needs to be skipped:

module DeviseSecurityExtension
  module Controllers
    module Helpers
      extend ActiveSupport::Concern
 
      included do
        before_filter :handle_password_change
      end

So while I’m skipping authenticate_user! in my controller, I still needed an additional:

  skip_before_filter :handle_password_change

Interestingly enough, the controller itself doesn’t break, just the tests. The downside is that I’m referencing two different Devise filters/actions just to not use them.

How safe is an MD5 hash of a plain password?

First of all, I hope that you’ve moved beyond MD5 hashes and hashing passwords by themselves, adding salts, etc., but I do recall systems in which an MD5 hash of a password by itself was “good enough”.

You can look up some md5 hashes on this md5 cracker page. I found many two word combinations that were crackable.

You can play with generating md5 hashes of questionable passwords (such as your name and p@ssw0rd) with this md5 Hash Generator

Ruby Keyword Argument Implementation Differences Between 2.1 and 2.2

I’m currently reading through Ruby Under a Microscope: An Illustrated Guide to Ruby Internals, and when I tried to test the “hidden hash” in ruby 2.2, I got different results from the book.

In Ruby 2.2, it appears that the default arguments are used as one expects, without regard to the Hash monkey patch:

### CODE ###
class Hash
  def key?(val)
    false
  end
end
 
def blah(a: 2, b: 5)
  puts a + b
end
blah
blah(a:3)
blah(b:3)
blah(a:2000, b:2000)
 
### DISASSEMBLY ###
== disasm: <RubyVM::InstructionSequence:<compiled>@<compiled>>==========
0000 trace            1                                               (   1)
0002 putspecialobject 3
0004 putnil
0005 defineclass      :Hash, <class:Hash>, 0
0009 pop
0010 trace            1                                               (   7)
0012 putspecialobject 1
0014 putspecialobject 2
0016 putobject        :blah
0018 putiseq          blah
0020 opt_send_without_block <callinfo!mid:core#define_method, argc:3, ARGS_SIMPLE>
0022 pop
0023 trace            1                                               (  10)
0025 putself
0026 opt_send_without_block <callinfo!mid:blah, argc:0, FCALL|VCALL|ARGS_SIMPLE>
0028 pop
0029 trace            1                                               (  11)
0031 putself
0032 putobject        3
0034 opt_send_without_block <callinfo!mid:blah, argc:1, kw:1, FCALL>
0036 pop
0037 trace            1                                               (  12)
0039 putself
0040 putobject        3
0042 opt_send_without_block <callinfo!mid:blah, argc:1, kw:1, FCALL>
0044 pop
0045 trace            1                                               (  13)
0047 putself
0048 putobject        2000
0050 putobject        2000
0052 opt_send_without_block <callinfo!mid:blah, argc:2, kw:2, FCALL>
0054 leave
== disasm: <RubyVM::InstructionSequence:<class:Hash>@<compiled>>========
0000 trace            2                                               (   1)
0002 trace            1                                               (   2)
0004 putspecialobject 1
0006 putspecialobject 2
0008 putobject        :key?
0010 putiseq          key?
0012 opt_send_without_block <callinfo!mid:core#define_method, argc:3, ARGS_SIMPLE>
0014 trace            4                                               (   5)
0016 leave                                                            (   2)
== disasm: <RubyVM::InstructionSequence:key?@<compiled>>================
local table (size: 2, argc: 1 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 2] val<Arg>
0000 trace            8                                               (   2)
0002 trace            1                                               (   3)
0004 putobject        false
0006 trace            16                                              (   4)
0008 leave                                                            (   3)
== disasm: <RubyVM::InstructionSequence:blah@<compiled>>================
local table (size: 4, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: 2@0, kwrest: -1])
[ 4] a          [ 3] b          [ 2] ?
0000 trace            8                                               (   7)
0002 trace            1                                               (   8)
0004 putself
0005 getlocal_OP__WC__0 4
0007 getlocal_OP__WC__0 3
0009 opt_plus         <callinfo!mid:+, argc:1, ARGS_SIMPLE>
0011 opt_send_without_block <callinfo!mid:puts, argc:1, FCALL|ARGS_SIMPLE>
0013 trace            16                                              (   9)
0015 leave                                                            (   8)
 
### RESULTS ###
7
8
5
4000

If I reset back to ruby 2.1, I get the unconditional usage of the default arguments:

### CODE ###
class Hash
  def key?(val)
    false
  end
end
 
def blah(a: 2, b: 5)
  puts a + b
end
blah
blah(a:3)
blah(b:3)
blah(a:2000, b:2000)
 
### DISASSEMBLY ###
== disasm: <RubyVM::InstructionSequence:<compiled>@<compiled>>==========
0000 trace            1                                               (   1)
0002 putspecialobject 3
0004 putnil
0005 defineclass      :Hash, <class:Hash>, 0
0009 pop
0010 trace            1                                               (   7)
0012 putspecialobject 1
0014 putspecialobject 2
0016 putobject        :blah
0018 putiseq          blah
0020 opt_send_simple  <callinfo!mid:core#define_method, argc:3, ARGS_SKIP>
0022 pop
0023 trace            1                                               (  10)
0025 putself
0026 opt_send_simple  <callinfo!mid:blah, argc:0, FCALL|VCALL|ARGS_SKIP>
0028 pop
0029 trace            1                                               (  11)
0031 putself
0032 putspecialobject 1
0034 putobject        [:a, 3]
0036 opt_send_simple  <callinfo!mid:core#hash_from_ary, argc:1, ARGS_SKIP>
0038 opt_send_simple  <callinfo!mid:blah, argc:1, FCALL|ARGS_SKIP>
0040 pop
0041 trace            1                                               (  12)
0043 putself
0044 putspecialobject 1
0046 putobject        [:b, 3]
0048 opt_send_simple  <callinfo!mid:core#hash_from_ary, argc:1, ARGS_SKIP>
0050 opt_send_simple  <callinfo!mid:blah, argc:1, FCALL|ARGS_SKIP>
0052 pop
0053 trace            1                                               (  13)
0055 putself
0056 putspecialobject 1
0058 putobject        [:a, 2000, :b, 2000]
0060 opt_send_simple  <callinfo!mid:core#hash_from_ary, argc:1, ARGS_SKIP>
0062 opt_send_simple  <callinfo!mid:blah, argc:1, FCALL|ARGS_SKIP>
0064 leave
== disasm: <RubyVM::InstructionSequence:<class:Hash>@<compiled>>========
0000 trace            2                                               (   1)
0002 trace            1                                               (   2)
0004 putspecialobject 1
0006 putspecialobject 2
0008 putobject        :key?
0010 putiseq          key?
0012 opt_send_simple  <callinfo!mid:core#define_method, argc:3, ARGS_SKIP>
0014 trace            4                                               (   5)
0016 leave                                                            (   2)
== disasm: <RubyVM::InstructionSequence:key?@<compiled>>================
local table (size: 2, argc: 1 [opts: 0, rest: -1, post: 0, block: -1, keyword: 0@3] s1)
[ 2] val<Arg>
0000 trace            8                                               (   2)
0002 trace            1                                               (   3)
0004 putobject        false
0006 trace            16                                              (   4)
0008 leave                                                            (   3)
== disasm: <RubyVM::InstructionSequence:blah@<compiled>>================
local table (size: 4, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, keyword: 2@2] s0)
[ 4] a          [ 3] b          [ 2] ?
0000 getlocal_OP__WC__0 2                                             (   7)
0002 dup
0003 putobject        :a
0005 opt_send_simple  <callinfo!mid:key?, argc:1, ARGS_SKIP>
0007 branchunless     18
0009 dup
0010 putobject        :a
0012 opt_send_simple  <callinfo!mid:delete, argc:1, ARGS_SKIP>
0014 setlocal_OP__WC__0 4
0016 jump             22
0018 putobject        2
0020 setlocal_OP__WC__0 4
0022 dup
0023 putobject        :b
0025 opt_send_simple  <callinfo!mid:key?, argc:1, ARGS_SKIP>
0027 branchunless     38
0029 dup
0030 putobject        :b
0032 opt_send_simple  <callinfo!mid:delete, argc:1, ARGS_SKIP>
0034 setlocal_OP__WC__0 3
0036 jump             42
0038 putobject        5
0040 setlocal_OP__WC__0 3
0042 pop
0043 trace            8
0045 trace            1                                               (   8)
0047 putself
0048 getlocal_OP__WC__0 4
0050 getlocal_OP__WC__0 3
0052 opt_plus         <callinfo!mid:+, argc:1, ARGS_SKIP>
0054 opt_send_simple  <callinfo!mid:puts, argc:1, FCALL|ARGS_SKIP>
0056 trace            16                                              (   9)
0058 leave                                                            (   8)
 
### RESULTS ###
7
7
7
7

Rails AntiPatterns Review/Summary

I’ve had the Rails AntiPatterns: Best Practice Ruby on Rails Refactoring (Addison-Wesley Professional Ruby Series) book on my Safari Books Online bookshelf for almost a year now, and finally started reading through it. It was “updated for Rails 3″, and there doesn’t appear to be a newer version, so I was a bit skeptical about how much I’d get out of the book.

This book has some overlap with Ruby Science, but it is more Rails-centric in its approach. Going through the book I found quite a few topics that I’ve not really read in-depth on in any other book or come across in a couple years of Rails development experience.

  • Use of ActiveSupport::Concern included for specifying validations as part of a module.
  • Discussion of Rails plugins (which later were mentioned as falling out of favor)
  • serialize :value, Hash vs checkbox/boolean model
  • How Rails helps in the building of Semantic HTML
  • Gems Clearance and AuthLogic as simple authentication gems.
  • MVP pattern and ActivePresenter (looks like Rails 3 was the end?)
  • Emphasis on controller as a representation of a resource
  • Rails responders for changing respond_to to respond_with(object)
  • rescue *EXPECTED_EXCEPTIONS (EXPECTED_EXPECTIONS as a constant array) to whitelist exceptions that are anticipated.
  • Mechanize and RestClient as automated interface gems with other sites.
  • render :status => :unprocessable_entity (or :created and other symbols that represent HTTP status codes)
  • Strategies for testing rake tasks, including FileUtils::NoWrite
  • sqlite3 “:memory:” database for gem testing
  • Thoughts on when to add DB indexes
  • AR association methods count vs. length vs. size and their behavior and resource usage.
  • .flatten() as a code smell for ruby code that should be represented as SQL.
  • Run rake db:migrate && rake db:migrate:redo for all migrations created.
  • Don’t go against AR bias against DB constraints except for NULL & default values.
  • Never fail quietly, whether ignoring return values or overzealously catching all exceptions.
  • rescue_from on controller to redirect specific exceptions.

I think the general concepts covered provided valuable background and food for thought even if not all the solutions are still the same. I don’t regret the help examining current practices in my daily Rails development.

Introducing Elixir

I read through Introducing Elixir on Safari Books Online because I had read through a beta edition of Programming Elixir: Functional |> Concurrent |> Pragmatic |> Fun through The Pragmatic Bookshelf and wanted to see about getting a slightly different take on Elixir at the same time I was getting caught up with the current state of Elixir.

The Introducing Elixir book read to me like a quick tour of Elixir, despite being about 80% of the length of Programming Elixir. That’s probably because I took some time to work through the examples in Programming Elixir, back when Elixir was on its 0.12 release. Programming Elixir is set up to be much more of a textbook in its presentation, with programming problems posed, etc. Introducing Elixir hits upon functional programming, the underlying Erlang and OTP libraries, and throws a few ideas of what you can do with it. It’s a decent refresher to shake the cobwebs out, but it doesn’t as much in depth probing into the language as the Programming Elixir book does. I’d recommend the Programming Elixir book from pragprog.com first.

(Amazon affiliate link)

Open Your Github Repo in a Web Browser from the Shell

This assumes that your first remote is a github remote. Put the following in the appropriate bash or zsh initialization script and that you’re on a Mac. You might need to change “open” to whatever will launch a URL in a web browser on a different *nix system.

function gitweb() {
  git remote -v | head -n 1 | awk '{print $2}' | sed 's/.git$//' | sed 's/git@github.com:/https:\/\/github.com\//' | xargs -I {} open {}
}

Programming Style: Language Specific Domains

My Beginner and C Days

The visual presentation of the code has mattered to me, from the first days I wrote C code in Microsoft editor. In those days, it was a Microsoft C 5.0 IDE on either DOS or OS/2.

#include "stdio.h"
main()
{
 
	int rows,columns,ROW, COLUMN;
	scanf("%d %d",&ROW,&COLUMN);
	rows = 0;
	columns = 0;
	while(columns++ < COLUMN)
		printf("\xdb");
	printf("\n");
	rows += 1;
	while(rows++ < (ROW - 2)){
		columns = 0;
		printf("\xdb");
		while(columns++ < (COLUMN - 2)){
			printf(" ");
			}
		printf("\xdb\n");
		}
	columns = 0;
	while(columns++ < COLUMN) {
		printf("\xdb");
		}
 
 
}

Ok, not *that* far back, but I did have strong opinions about C from the early days of my being paid to program in it:

  • TABS, not spaces
  • 3 (in Microsoft land) spaces per tab (eventually switched to 4)
  • always include braces for if clauses
  • generally no parentheses for return values
  • ternary operator GOOD

That made the code look like this (except that tabs are tabs in pre blocks).

 
int compare(const void *a, const void *b)
{
	return(strcmp(*(char **)a, *(char **)b));
}
 
int checkDictionary(char *word)
{
	if(!dictionary)
	{
		loadDictionary("WORD.LST");
	}
	if(bsearch((void *)&word, (void*)dictionary, wordCount, sizeof(char *), compare))
	{
		return 1;
	}
	return 0;
}

But I remember so much variation in coding style preferences, as evidenced by the Indent Style article on Wikipedia. Everyone had their own preferred style, and everyone had their own preference for how much everyone else should adhere to a common style. On one team I worked, they eventually developed code reviews which were nothing more than berating people for not adhering to an arbitrary style guide: an in-house version Hungarian Notation, exactly one return per function, etc.

Java and Perl days

In Java land, my preference for camelCasing was reaffirmed. Working with Perl and Java, I eventually started putting the opening brace on the same line as if statements and function declarations.

if(iAmAChangedProgrammer) {
   hugWithBraces();
}

I think the brace thing was a result of a block that evaluated differently in awk or perl if it didn’t hug the clause. I don’t remember, but from that point on, I was convinced of that way being the only way.

Ruby

Coming into ruby has been interesting. Multiple returns (which never bothered me) are common. Implicit returns are the norm as well. There’s a style guide which, for the most part, experienced rubyists adhere to (even if there are slight variations in practice). I find some disagreement with some of the style recommendations (I think I have found legit use for and over &&, etc…), but I’m happy to fall in line with the style recommendations and help enforce them.

Some of the styles have obvious purpose, but some seem rather arbitrary. Why are guard clauses so accepted in Ruby when C was so scared of them, etc…

Smalltalk

In reading Smalltalk Best Practice Patterns, it all came together.

As part of the style guide near the end of the book, the author talks about using the line-wrapping of the browser window to naturally wrap argument lists instead of taking up vertical space with them. That’s when it dawned on me how much preferences in code styles also come from the languages that influenced the current language.

Ruby’s heritage from Smalltalk means that it carried forward that aversion to deep nesting that performs poorly in small code browser windows (even in Squeak and Pharo, the code windows can get pretty tiny.)

C coders may have come from GOSUB type languages where there truly was only one return (unless an IF clause buried another) and there could be multiple entry points. Multiple entry and exit point aversion came from languages in which you could GOSUB to anywhere before a RETURN statement, and a nested RETURN could be harder to detect than one on the main logic level.

Conclusion

Early language coding styles likely came from specific pain points experienced by a prior guru and then arbitrarily passed along because “We’ve always done it that way.” At some point, tasks and readable code become hindered by following rules that we don’t have a rationale behind.

Community style guides hopefully have the benefit of thousands of years of cumulative experience in challenges and best practices collaborating on equal footing, but that assumes that we’re not just agreeing with our technical elders because that’s the way it’s always been done.

Try to understand the problem domain of coding in a specific language as it relates to coding style. Maybe your coding style thinks its still programming in COBOL or BASIC.

Toy Helicopter Review and Durability Test: Flutterbye Deluxe Fairy

We’ve bought several cheap toy helicopters that have usually met their demise via the breakage of one of the components that rotates at high speed breaking. Air Hogs has been a favorite brand because they are usually cheap and your face on retail shelves. [The charging port on this doll bears the Air Hogs brand, as well.]

[Somewhat related: our big dog doesn’t like any of these flying things and thinks it’s his mission to “kill” them, giving us an extra obstacle to their longevity.]

This fairy doll is the first one we’ve had that doesn’t look like a standard helicopter for us.

When taking off from its base, the doll floats fairly gracefully to the floor. The doll mostly hovers within a foot or two of the surface underneath her. However, you can cup your hands directly below it and it’ll float above your hands briefly instead. I noticed when I did this, the fairy would float steadily to the ceiling and hover and gradually come back down.

The doll will also take off from your hand, but it’s very easy to not be vertical at take-off and/or to present an uneven surface below it, causing to lift off erratically. I recommend letting it take off from the base stand each time.

We’ve had 5-10 crashes with the doll. One thing I noticed with this doll (unlike manually controlled helicopters) is that power is immediately cut to the rotors when a collision happens. This minimizes the high speed damage that the blades and balances endure when you don’t react quickly enough to cut the power on a remote control.

Between the ease of flight, the safety cut-off, and the relatively more durable structure overall, this doll seems like the best value in the under $50 helicopter department for those of us who really don’t know how to successfully fly a toy helicopter, anyway.

Note:
The doll in the video is the Deluxe Light Up Flutterbye Fairy – Rainbow (Amazon affiliate link)