An Ashley Furniture comedy of errors

I had the occasion to the write the following letter to the CEO of Ashley Furniture and a couple of the principals at the local Ashley Furniture. Given the challenging nature of communicating with Ashley, I’m not sure my letter will ever be read (the fax number published for the local store doesn’t work–in fact the local store doesn’t even have a fax machine! Stop trying to fax in those furniture orders for quick pickup!). I’m publishing it here as on open letter to those at Ashley and to help others think critically about furniture purchases. There were several folks at Ashley who did a great job for us and for their efforts we are deeply grateful. The names of the principals have been changed (to the real names of rock and roll stars). 

My wife and I experienced a comedy of Ashley Furniture errors yesterday and last night. On Friday, March 27, we ordered nearly $n worth of furniture from Antoine Domino at a San Antonio store. He was courteous and helpful. The furniture we purchased would need to be delivered in three stages. The important thing to us was getting the bed ASAP and Antoine promised us that our bed frame, box springs, mattress, and mattress pad would be delivered March 31 (yesterday) between 8:30 am and 11:30 am. Antoine confirmed this delivery for us again before we left the store.

About 10:15 on March 31 only the bed frame was delivered. The driver said we should have received a call telling us the mattress and box springs wouldn’t be shipped. He made a call to customer care, in front of my wife, to find out what the problem was and when we’d get the mattress. At one point, he asked the person, Priscilla, on the other end of the line if she wanted to talk to my wife. You should tell Priscilla that she shouldn’t be afraid to talk to customers—she wanted no part of speaking to my wife. Given the comments made, it seems as though your delivery crews are often the bearer of bad news and their support team is good at letting them sweat out the painful face-to-face parts of a broken promise.

Confusion reigned and my wife called the store. Antoine Domino was out of the office so my wife asked to speak to the manager. The lady on the phone with her (we didn’t get her name) wasn’t too quick to jump to that request until my wife mentioned that otherwise we’d like to cancel our nearly $n order. At that, she was patched through to Eugene Dixon. He was going to call her back with more information—but it was starting to appear like we needed face-to-face contact to find out if we were going to get our mattress and box springs as promised.

I drove 30 minutes to the store and talked to Eugene in person—whom had not yet returned my wife’s call. After about 40 minutes of waiting as phone calls were being made, I left the store with Eugene being “cautiously optimistic” that we’d receive our mattress and box springs by 9pm. The last thing I said when I left the store was, “Let’s be clear, mattress and box springs, right?” Eugene and Pauline (the person having done most of the phone research while I was there) confirmed that was correct. Pauline, by the way, never cracked a smile and regarded me only with dead shark eyes the whole time. At no time did I speak in anger, raise my voice, and otherwise exhibit ugly behavior.

At 7:30 so our cautious optimism was rewarded when an Ashley truck arrived and three young men unloaded the two box springs and the mattress pad. Our happiness quickly disappeared when the young men told us there was no mattress on the truck. The mistake wasn’t their fault and I wanted my anger correctly placed. I tipped the three kids $20 and told them to buy a cold drink on me.

I called the store and talked, briefly, to Gloria. I wanted to ensure that yet another truck was on the road somewhere with our mattress in it for delivery that night. My call with Gloria produced nothing like results (you really need to get her some telephone courtesy and manners training) and I called Ashley Customer Care directly and listened to the recorded, hollow claims about how invested Ashley Furniture is in its customers’ happiness for about 15 minutes. Finally, Jan answered my call. For pretty much the first time all day long, an Ashley employee was able to convey a sense of responsibility and empathy for the situation. Jan checked into things professionally and asked me to hang on while she dug for more details. Alas, our call was disconnected.

I called Customer Care back and again listened to the recorded, hollow claims about how invested Ashley Furniture is in its customers’ happiness—for about 10 minutes. This time I spoke to Eleanora. Jan was apparently busy with something else so I started over with Eleanora. Like Jan, she was professional, attentive, and sympathetic to our problem. It was very clear that our order was in utter confusion. At first, Eleanora’s paperwork indicated we got the mattress but didn’t get the box springs. Then she found something to indicate someone had marked out shipping the mattress last night because we had already received it. Eleanora ended the call by, very apologetically, telling me that there wasn’t another truck coming and we wouldn’t be receiving our mattress anytime that night.

Having been fighting this since 8:30am, we were pretty much over Ashley Furniture. Then, about 9pm a mysterious thing happened—Harry Casey, apparently working out of the New Braunfels warehouse, called my wife and said he was going to do his best to try to find a team to deliver our mattress yet that evening.

With a measure of optimism and the kids asleep, we poured ourselves a glass of wine, watched Better Call Saul and put out our of heads the notion that if Harry didn’t deliver we didn’t have any place to sleep.

Sometime around 10pm or a little later, we got the call that George was 20 minutes out with our mattress. Sure enough, George and another man brought us our mattress and capably muscled it up the stairs and onto the bed and box springs. My wife and I were very grateful. I tipped them each 20 bucks for their efforts. We were pretty sure they were going above and beyond for us and we greatly appreciated it.

Nearly 12 hours after the promised delivery time, and tons of confusion and frustration we had a place to sleep.

I would like Eugene Dixon (you know who you are, “Eugene Dixon”!) to email me at roger.pence@gmail.com with absolute, firm delivery dates and times for the two lamps and red sectional couch (currently promised for Tuesday, April 7th) and the gray recliner, red chaise and red ottoman (currently promised for Tuesday April 28th) remaining on the order. We don’t want to wait 12 hours each time we expect an Ashley delivery and we’d like no unpleasant surprises on the rest of our order.

I am out $60 for late night delivery tips. I’d like to have that $60 back. And, if you have any empathy for our frustrations at all, I’d like to have my entire delivery fee back—for the bed and table delivered on Tuesday and for the upcoming two deliveries scheduled. I know you aren’t obligated to return any deliver money to us. It’s up to you. Weigh the value of our future business against that delivery charge. We do intend to buy more furniture soon. Somewhere.

At the end of this fiasco, there were heroes. I am nearly certain that it was either Jan or Eleanora’s efforts that got the message to Harry that something was woefully incorrect with our order. And Harry was able to find two young men willing to go above and beyond to finally fulfill our delivery. Our deepest thanks to Jan, Eleanora, Harry, George and, I apologize for not getting his name, the man helping George deliver the mattress. You should do something nice for them, too.

Given the size and resources of Ashley Furniture, you surely have better consultants and counselors than I could ever be. But, for what it’s worth:

  • Make it easier to contact someone by voice when something is wrong with an order. Your Twitter account seemed concerned but produced no results.
  • Teach your employees that what hangs in the balance isn’t just another delivery; it’s probably the most important thing to the customer that day.
  • Train telephone staff to be courteous and responsive.
  • Give your truck drivers a break and ensure that the customer gets bad news (because it will happen from time to time) well before the truck driver arrives.
  • Have management be proactive with ensuring things are going, or went, well (I hoped for a call from Ashely Furniture this morning to see how things went last night—alas no such call was received).
  • And finally, because I strongly suspect that others have said similar things to you, insist that top management start listening!

Very sincerely,

Roger Pence

Installing PostgreSQL 9.4 on Ubuntu 14.04

postgresql-logo

Postgres 9.4 is a powerful (albeit silly-named) open source database. With 9.4 some powerful features have been added to enhance Postgres’s support for Json. The claim is that Postgres 9.4 offers the power of a relational database coupled with flexible document database features offered by databases such as Casandra, CouchDB, and Mongo DB. This post documents how to install and initially configured Postgres on Ubuntu 14.04.

My first attempt to install Postgres 9.4 on Ubuntu 14.04 failed. After issuing:

apt-get install postgresql-9.4

this message is displayed:

Couldn't find any package by regex postgres-9.4

Having been down similar Ubuntu roads a time or two in the past, the first thing I was did was:

apt-get update
apt-get upgrade 
apt-get install postgresql-9.4

Which resulted in the same package-not-found message being displayed.

Avoid the Postgres graphical installer!

In a desperate attempt to install Postgres 9.4, I used the Postgres graphical installer. While this installer is convenient, it installs components to odd directories and it doesn’t integrate with apt-get. I also had path trouble and psql command line issues. Even though the graphical installer did seem to install a working Postgres 9.4 when used through pgAdmin III (which is also installed with the graphical installer), there were enough off-by-one oddities with the graphical installer that I gave up on it. In its last effort to annoy me, I was also unable to uninstall Postgres when installed with the graphical installer. When installed that way it can’t be uninstalled with with apt-get and its uninstaller binary wouldn’t run for me. The Postgres graphical installer confirmed for me that with Linux the command line is your friend and point-and-click installations should generally be avoided.

Third time’s the charm

My third attempt was my successful attempt to install Postgres 9.4. Had I had the patience to read the Postgres site a little more closely, I would have probably avoided the debacle of the graphical installer.

Update the apt-get repository using the instructions on this Postgres page (see the section PostgreSQL Apt Repository). There is a nifty dropdown on the page that, after you select your Ubuntu version, provides the correct command lines for you. The four steps from that page to install Postgres 9.4 on Ubuntu 14.04 are:

  1. Update (or create it if it isn’t there) the file named /etc/apt/sources.list.d/pgdg.list and add this line to it:
    deb http://apt.postgresql.org/pub/repos/apt/ trusty-pgdg main
  2. Update the apt-get repostitor with the following two lines (note the first threes lines are a single continued command line)
    wget --quiet -O - \ 
    https://www.postgresql.org/media/keys/ACCC4CF8.asc | \
    sudo apt-key add - 
    sudo apt-get update
  3. Install Postgres 9.4:
    sudo apt-get install postgresql-9.4
  4. Install pgAdmin III:
    sudo apt-get install pgadmin3

There isn’t yet an apt-get package for pgAdmin 1.20.0. Step four above installs pgAdmin 1.18.0 which works with Postgres 9.4 but doesn’t provide 9.4-specific features. If you want to install pgAdmin 1.20.0 you currently need to install it from source. (Update: on 6 January, Ubuntu’s automatic software updates upgraded pgAdmin to 1.20.0.)

To confirm Postgres’s installation, use this command to display the version installed:

$ psql --version

Configuring Postgres

After installing Postgres, you need to do a little user configuration before you can use it. I struggled with this task until I found this answer on StackOverflow. It very clearly provides the steps necessary to perform first-time Postgres configuration. The steps below are StackOverflow user manur‘s work; I’m repeating them here for convenience.

  1. Connect to the default database with user postgres:

    sudo -u postgres psql template1
  2. Set the password for user postgres, then exit psql (Ctrl-D or \q):

    ALTER USER postgres with encrypted password 'xxxxxxx';

    Don’t forget the trailing semicolon for the SQL statement above.

  3. Edit the pg_hba.conf file

    sudo vim /etc/postgresql/9.4/main/pg_hba.conf

    And change peer to md5 on the line referencing postgres:

    local    all    postgres    peer md5
  4. Restart the database:

    sudo /etc/init.d/postgresql restart

    Here you can check it worked with psql -U postgres.

  5. Create a user having the same name as you (to find it, you can type whoami):

    createuser -U postgres -d -e -E -l -P -r -s <my_name>

    The options tell Postgres to create a user that can login, create databases, create new roles, is a superuser, and will have an encrypted password. The really important ones are -P -E, so that you’re asked to type the password that will be encrypted, and -d so that you can do a createdb.

    Take care entering the new user password. You’ll be prompted for a password three times. You’ll first be asked twice for the new password for the new user, and then once for the postgres password (the one specified on step 2).

  6. Again, edit the pg_hba.conf file (see step 3 above), and change peer to md5 on the line concerning all other users:

    local    all    all    peer md5
  7. Restart Postgres (like in step 4) and check that you can login without -U postgres:

    psql template1

    Note that if you do a mere psql, it will fail since it will try to connect you to a default database having the same name as you (ie. whoami). template1 is the admin database that is here from the start.

  8. Now you should be able to create a database.

    createdb <dbname>

Configuring the Linux environment

Postgres can use environment variables to provide several default values. At the very least, to execute SQL statements through psql, set the PGPASSWORD environment variable with the new user’s password:

export PGPASSWORD=roger

Assuming you had created a database named geocode and a file named createtable.sql with an SQL Create Table statement in it, you could perform that SQL with this psql command line:

psql -d geocode -a -f createtable.sql

A poor man’s alternative to 4K

I use a MacBook Pro running VirtualBox to provide Linux development environment VMs. I recently explored the possibility of getting a 4K monitor to provide a much-needed increase in display capabilities. I learned that while a 4K monitor is currently beyond my humble hardware’s capabilities, Samsung has an affordable option that exceeds the resolution of my current external monitor by 33% and works with my old Mac.

8 million pixels

4K monitors are called that because their horizontal resolution is (nearly) 4K pixels. With 3,840 by 2,160 resolution, these monitors provide more than 8 million pixels of viewing pleasure. That means a 4K monitor can display four discrete 1920 by 1080 displays—at one time. That’s like getting four monitors in one!

fourKMonitor

 

 

 

 

 

 

 

Alas, there are a couple of catches:

  • 4K monitors are expensive. While prices did drop dramatically during 2014, entry-level 4K monitors currently hover at about $500 and go up substantially from there. 4K monitors aren’t quite a commodity yet.
  • Hardware compatibility is iffy, at best, right now. Driving a 4K monitor is beyond the reach of many of today’s PCs and video cards. Carefully check your existing hardware before buying a 4K monitor. Also, beware your cabling needs (more on this in a moment).
  • Read the fine print. It’s important to read all specs very carefully. It might be possible for your current hardware to support 4K, but only at a 30MHz refresh rate. For simple work with a text editor, that might be fine but for tasks that tax video output like video editing or Photoshop, you’ll probably want to ensure your hardware supports a 4K monitor at a 60MHz refresh rate.

It’s not 4K, but…

My personal laptop is a hand-me-down, late 2008, MacBook Pro. The memory’s been bumped to its 8GB max and it sports a 512GB SSD primary drive and its original 750GB SATA drive resides in what was the superdrive slot. Otherwise, it’s box stock, currently running Mavericks. The MacBook’s internal display provides 1440 x 90 but for external monitors it supports a maximum resolution of 2560 x 1080.

Given my old Mac’s constraints I’ve given up on the hunt for a 4K monitor for now. But while Christmas shopping at CostCo the other day, I saw the LG 25UM65 25″ monitor on sale for $199. Generally, anything wider than 23″ or so doesn’t get my attention. At a 1920 x 1080 resolution bigger isn’t always better. At that resolution, the sweet spot seems to be about 23 or 24 inches. After that, you’re not really gaining useful real estate you’re just getting bigger pixels. TheLG 25UM65 got my attention because its maximum resolution is 2560 x 1080. This resolution would provide two side-by-side 1280 x 1920 displays on the LG. Not quite four 1920 x 1080 displays, but better than a single 1920 x 1080 display by 33%.

I rolled the dice on the LG 25UM65; it seemed like a good partner for my old Mac and one of these days when I do get a more capable Mac that supports 4K, I’m hoping the LG will make a good second monitor for that setup. The purchase was a bit of a gamble because not only did I hope for the monitor to provide 2560 x 1080 on my Mac, but I also hoped that VirtualBox would work with the monitor so that I could exploit its screen real estate with Linux VMs.

Get the right cable

Attaching the LG monitor to the Mac required a $10 mini display port to display port cable. Be careful to note that a display port isn’t an HDMI port nor is it a Thunderbolt port. A Best Buy blue-shirt assured me otherwise–don’t believe anything the BB blue shirts say. To get 60MHx refresh rate 2560 x 1080 resolution with the LG monitor on the MacBook Pro, this mini display port to display port cable is an absolute requirement. With that cable, installation was a snap and the monitor did exactly what it claimed it would do. I didn’t need the software included with the monitor and I didn’t need to read any special directions. I just plugged the monitor in, ensured the Mac’s display settings were set to 2560 x 1080 for the external monitor, and got happy.

Linux VMs through VirtualBox play along with the LG monitor nicely, but often, on session start up I need to fiddle with the monitor settings (I’m pretty sure that with a little more effort fixing that can be done scripting xrandr but I haven’t cracked that nut yet). But that’s something I’ve often needed to do when using multiple display sessions with VirtualBox on my old 1920 x 1080 monitor. The result on the LG monitor is a very wide display that is great for having a browser, Sublime Text, a terminal session, and a file manager (and whatever else I need). An example screen shot is of the LG in action is shown below.

wide-screen

 

 

 

 

 

 

I also have the Mac’s internal 1440 x 900 display running another VirtualBox display just in case.

Highly recommended

The LG 25UM65’s colors are bright, its display is crisp, and with nearly the same physical footprint as my old 1920 x 1080 monitor, it provides 33% more viewing area. The LG monitor claims to have speakers but they don’t work through the display port cable on my Mac (having said that, I spent about three seconds trying to make them work).

Overall, the LG 25UM65 is a great value, especially at $200. That’s a little more than a similar-sized 1920 x 1080 monitor but you are getting 33% more pixels. The stand is not height adjustable, but it does adjust for angle. It does work with VESA wall mounts. If you get one of these extended resolution monitors, be sure to confirm your current PC’s video capabilities and carefully research your cabling needs. You’ll not fully exploit the power of this monitor otherwise.

LG 25UM64 monitor at Amazon  mini display port to display port cable

How to install and configure PHPUnit on Linux

PHPUnit is the canonical unit testing framework for PHP. Even for simple projects and learning exercises, unit testing pays big dividends. This article provides a way to install and configure PHPUnit on Linux. This article assumes you’ve installed Composer, the popular PHP dependency manager. I used the following two lines to install Composer:

$ curl -sS https://getcomposer.org/installer | php
$ sudo mv composer.phar /usr/local/bin/composer

Step 1. Add src and tests directories to your project’s root. These aren’t absolute directory names required, but you’ll see these directory names referenced in following steps. If you change these names be sure to change the corresponding names in subsequent steps.

Step 2. Add the following Composer file, named composer.json in your project’s root.

{
    "name": "rp/puppet02",
    "description": "PHP test template",
    "license": "MIT",
    "require": {
    },
    "require-dev": {
        "phpunit/phpunit": "4.1.*"
    }, 
    "autoload": {
        "psr-0": {
            "": "src"
        }
    }
 }  

Set the name, description, and license keys with your project’s info. The autoload key uses the psr-0 standard to autoload PHP class files located in the specified directory.

Then run composer from your project’s root to install PHPUnit and its dependencies. To ensure PHPUnit installed correctly, run this command from the command line:

phpunit --version    

(Note: If you’d rather not use Composer to install PHPUnit, there are alternative installation instructions on the PHPUnit site.)

If the PHPUnit version is correctly reported you’re ready for Step 3.

Step 3. Add a phpunit.xml file to your project’s root. This XML file provides configuration info to PHPUnit. There are many other configuration settings than what’s shown below available–this step keeps the configuration simple. Check PHPUnit’s documentation for the other configuration options available.

<phpunit
  bootstrap="vendor/autoload.php"
  colors="true">
  <testsuites>
    <testsuite name="Initial tests">
      <directory>tests/</directory>
    </testsuite>
  </testsuites>   
</phpunit>

The bootstrap key identifies the autload file that causes your classes (the ones that you are testing) to be loaded. The colors key tells PHPUnit to show command line test results in color (ie, green for pass, red for fail).

The testsuites key identifies groups of tests (“test suites”) and the directory where the PHP tests files are located. When you run phpunit on the command line without any arguments all of the test suites identified here are performed. You can use PHPUnit’s --testsuite flag to run a single test suite. For example, if you had a test suite named Controller tests the following command line would run that test suite only:

phpunit --testsuite "Controller tests"

The name you provide for test suites is case-sensitive. When a test suite is performed, the tests in its top-level directory, as well as any in any child directory are performed.

Learning how to use PHPUnit is central to learning PHP well, and, as you can see, getting it up and running is easy.

Core Git command line reference

Inspired by John Nickell and Jeffrey Way I am making a renewed commitment to use Git primarily from the command line. While the command line may seem like many steps backwards from using a rich graphical interface, I am finding that it makes me much more aware of exactly what each step of Git is doing and it provides infinitely more quick repeatability of Git tasks.

This is list of Git commands I find myself using over and over. Be sure to familiarize yourself with Git aliases; they go a long way towards making the command concise and effective.

The easy way to put Git on a Windows box is to install Github for Windows and then use its Git shell. The added bonus here is you have good GUI available for basic Git operations as well.

Initialize a local repository

git init 

Stage all file changes to the index

git add .

Stage all file changes, including deletes, to the index

git add -A

Commit changes

git commit -m ‘commit message here’
or
git commit -a -m ‘commit message here’
which automatically stages modified and deleted files before the commit. However, new files you have not explicitly added to Git with ‘git add’ are not affected.

Discard changes

To remove unstaged changes from a specific file:

git checkout path/to/file/to/revert

To delete all unstaged changes:
git checkout — .

Remove a file from the repository

git rm <file name>

Discard all changes since last commit

git reset –hard HEAD
See this link for more info.

Show the repository’s current status

git status

Show all commits in an abbreviated form

git log –pretty=oneline –abbrev-commit

Show the SHA1 for the current commit

git rev-parse HEAD

Change to another commit and then make it a branch

git checkout nnnnnn
where nnnnnn is the first six characters of the desired commit’s SHA1. This puts the repo in a detached HEAD state. Now make a branch out of the commit you just checked out:
git checkout -b new_branch_name
That new branch is made the current branch. You can now switch among branches.

Show all branches

git branch -v

Create a branch

git branch new_branch_name

Create a branch and immediately switch to it

git checkout -b new_branch_name

Switch to a different branch

git checkout new_branch_name

Delete a branch

git branch -d branch_name

Rename current branch

git branch -m

Rename a branch that isn’t the current branch

git branch -m

Show all modified files

git ls-files -m

Show all files

git ls-files

Use Sublime Text as Git’s editor on Windows

git config –global core.editor “‘c:/program files/sublime text 2/sublime_text.exe’ -w”

Use Sublime Text as Git’s editor on a Mac

git config –global core.editor ‘sublime -n -w’
Where ‘sublime’ is a symlink in the $PATH. This Stack Overflow entry was helpful for this.

Show all aliases

git config –get-regex alias

Add a Git command alias

git config –global alias.nn ‘xxxx’
where nn is the name of the alias and ‘xxxx’ is the Git command and its arguments. For example:
git config –global alias.rplog ‘log –pretty=oneline –abbrev-commit’
Call this alias with this command line:
git rplog

Delete a Git command alias

git config –global –unset alias.nn

Clone a repo

git clone <uri>
From a command line, go to the parent folder where you want the repo located. Cloning the repo will create a child folder under the parent folder you selected.

List remote repos

git remote -v

Show a remote repo

git remote show origin

Remove remote repo location

git remote rm origin

Set remote repo location

git remote add origin <uri>

Update remote repo location

git remote set-url origin <uri>

Update a remote repo

git push -u origin –all or git push -u origin master

Update a remote repo with current tags

git push -u origin –tags

A sad Thunderbird hiding in the Texas hill country

For as brown and boring as much of southern Texas can be, there are many great motorcycle rides to be had down here. There isn’t anything that rivals the beauty and challenge of the Blue Ridge Parkway (for me, at least), but there is definitely motorcycle fun to be had down here. I took Glodean (my white 2012 Victory Cross Country Tour) out last Sunday to see what I could find. I live near the northern intersection of 281 and 1604 in San Antonio. This was the starting point of my latest Sunday ride (shown in the map below).

tbird

I headed west on 1604 to SH 16. I much prefer two lanes to four so I was anxious to get on 16 (16 does start out from 1604 as having four lanes, but it pretty quickly turns into two lanes). 16 is a nice ride, with minimal traffic most of the time. I rode it into Bandera (near point #2 on the map above), which considers itself the “cowboy capital of Texas.” And, indeed, it doesn’t take much imagination to see this little town the way the cowboys used to. Basically a single intersection town, on any given Sunday its Main Street is lined with motorcycles, sports cars, and the occasional street rod. I didn’t stop very long in Bandera today, but if you are so inclined there are several biker-friendly saloons that offer a variety of cool refreshments.

willysbandera-bikes

ratbob

On today’s trip through Bandera, I saw a sweet Willys Jeep Wagon and a Goldwing bobber rat. I’ve got a 93 Goldwing taking up space in my garage that I think I oughta bob one of these days. I’m thinking rat bobber bagger. We’ll see. Daydreaming about making that bobber I headed north out of Bandera on US 16. About five miles out of Bandera I took FM 470 west through Tarpley and continued heading west to SH 87 (point #3 three on the map). I left my house at about 9:30 AM and it wasn’t too hot yet. With the XM radio broadcasting a Kasey Kasem American Top 40 rebroadcast from 1974 and the comfortable morning air, choogling down 470 on Glodean felt pretty good.

One of the reasons I really like riding is that you can ride for miles and then realize that for the last 20 minutes you haven’t thought about a goddamned thing! Your head empties and you can’t be emailed, texted, called, meeting invited, conferenced in, cajoled for input, or asked to “do” lunch. Kasey’s long distance dedication (“Dear Kasey, I’ve been in Germany in the Army for the last two years and I really miss my girlfriend. Would you please play Redbone’s Come and Get Your Love for her…”) might drift in one ear and out the other, but otherwise you are untouchable. As a card-carrying introvert, I nearly always feel that the quality of the company I am in is inversely proportionate to the number of people around me. Heading west on FM 470, with no one in front of me and no one behind me, the quality of my company on this morning was as good as it gets!

470West

Morehill

Before heading out on FM 470, don’t leave Bandera with a low tank of gas. There is gas to be had in the hill country, but those chances don’t happen very often. Like many of the hill country highways in Texas, FM 470 is refreshingly devoid of any signs of commerce (except for the occasional real estate “for sale” sign). Fast food places, malls, and other civilization lard are no where to be found. You do see the occasional high-dollar gated entrance to what is surely a beautiful home tucked away in the hills, but mostly FM 470 is you, your bike, and the countryside. For what it lacks in challenging twisties and ups and downs, FM 470 makes up for with gently rolling hills and beautiful hill country vistas.

Texas two-lane secondary highways are designated RM or FM, for Ranch-to-Market and Farm-to-Market. Generally RM highways are west of SH (State Highway) 281 and FM highways are east of SH 281. “Generally” is key here because I’ve been on several FM roads west of 281 (FM 470, for example). I’m a corn fed Hoosier and a Texas RM/FM road is what we’d call a good county road in Indiana. The amazing thing about Texan RM/FM roads is that in Indiana, and may other states, this type of highway almost universally has a 55 MPH or so maximum speed limit. Not in Texas. RM/FM roads can have 70+MPH speed limits. I’ve learned, the hard way, that there are two things to watch out for on RM/FM roads: 1) if you see, in the distance, a newer model Ford pickup parked on the opposing side of the road facing you, usually under the shade of a big tree, slow the hell down. It’s a constable and he’ll getcha if you’re speeding (On RM 337, between Medina and Leakey, give Constable Phillip Tobin a wave as  you go by. He’s a nice motorcycle guy); 2) when you are on a 70 MPH RM/FM road, cruising along nicely, as you approach the occasional little town, you also need to watch your speed. The otherwise crazy-ass fast speed limit can change quickly to 40 MPH and invariably there will be a constable lurking.

HIll

As you approach SH 87 heading west on FM 470, the landscape gets a little more hilly and the road gets a few more turns. There isn’t anything breathtaking or technically challenging here, but the fun factor does twist up a notch or two. Once on SH 87, I went north heading towards RM 337–which is also a very good road to ride. I was really torn when I got to RM 337. Going west on it for about 20 minutes would drop me right into Leakey, the anchor town of the Three Twisted Sisters–a legendary Texas hill country ride. I’ve done the Sisters many times and I would have really liked riding them today, but today I just didn’t have that much time. I stopped at the rustic Lost Maples Store (about halfway between points #3 and #4 on the map) for a bottle of water. I also had a quick chat with the grizzly old Texan running the store (who was trying to watching Ice Road Truckers on TV between customers. I continued north heading up to US 39 damned glad I wasn’t in a truck and on ice.

Three miles or so north of the FM 337 intersection on US 187 is the Lone Star Motorcycle Museum. I have been there many times so I motored on past today, but if you’ve never been there you need to go! The owner, Allan Johncock is a little old Australian expatriate and a motorcycle nut of the highest order. Allan’s got more cool old bikes (some exquisitely restored, others proudly wearing the patina of age and use) in his museum than you’re otherwise ever likely to see in one place. The museum also has a little cafe with a pretty average cheeseburger (no beer, though). I have read on a few forums that the cafe may close this fall–check before you count on eating at the museum. (I love Allan’s museum but if you get this close to Leakey and are hungry, get your ass on over to the Bent Rim Grill in Leakey.)

I rode on up SH 187 to SH 39, taking it east towards Kerrville. SH 39 is a pretty average ride until you get about 15 miles east of Kerrville. There 39 hooks up with the Guadalupe River and a few turns and a few hills. That last 15 miles into Kerrville on 39 is a great ride. It was also, for me this morning, the part of the ride with the most traffic. I don’t ride like a crotchrocket hot dog, but I also don’t dawdle along like a nun in a Model T. More than once I got stuck behind three or four really slow-moving Sunday drivers.

I stopped in Kerrville for a couple of bean and cheese chalupas in a nondescript mom and pop restaurant. It wasn’t anything to brag about but it was also only $4.50 for everything. After lunch, I took Highway 27 south out of  Kerrville and took it east back to I10 to Comfort, Texas. At Comfort, I jumped on RM 473 for a nice little ride on over to US 281.

tbird in sisterdale

I really like old cars and am always on the lookout for vintage tin as I ride through the Texas countryside. On this ride, east of I10 on RM 473, I came across this sad, old 58 or 59 Thunderbird. Its license plate was dated 1975, so I’m assuming this poor old Bird has been sitting in the weeds for nearly 40 years. Despite that, its condition made it more likely a project car than a parts car. A determined builder with some mad skillz and enough time on his hands could turn this old weed steed into something very interesting.

For about 30 minutes I had RM 473 and its occasional twists and turns all to myself before being dumped back into civilization on SH 281 with all the Oldsmobiles and Ford F-250 pickups. By now it was mid-afternoon and the comfortable morning had transitioned into a very hot afternoon. It was hovering at about 100 degrees by 2pm. I was still glad that I wasn’t in a truck but a little of that ice would have been welcome about right now. My ride lasted about five and a half hours and took me just under 230 miles. Once again, Glodean took very good care of me. I got a little sun and was hot and thirsty when I got home, but damn, I can’t wait to do it again!

Hot and Sour Beef Noodle Soup

hot-sour-beef-noodle-soupI’m a big fan of Chinese hot and sour soup and make it every once and while. Learning to make hot and sour soup taught me that the two key ingredients that contribute the most to its flavor profile are finely crushed white pepper (the hot) and Chinese black vinegar (the sour). You can get the Chinese black vinegar in any Asian grocery store, a well-stocked big-box grocer, or at Amazon. It is expensive on Amazon–I pay less than $4 for a bottle locally. Any mom and pop Asian grocer will have it. Beware there isn’t a rational substitute. Search this ingredient out, it is important!

This quick, one-serving recipe isn’t hot and sour soup in the most conventional sense, but if you are hungry for hot and sour soup and want something quick and delicious, this soup is great. I frequently cook with Asian ingredients, so I always have sambalwoodear mushrooms, and Chinese egg noodles on hand (in a pinch the noodles from a package of ramen noodles works fine-but don’t use the seasoning package). The mushrooms and noodles keep nearly forever in the freezer. If you don’t have an ingredient recommended here (except for the black vinegar) use something else! Part of the point of this soup is that it should be quick and easy to make. Oh, and very tasty.

In this variant, I use beef and beef broth (but another possibility is chicken broth and pork or chicken). For a recipe such as this I use “Better Than Bouillon” beef base. This isn’t a product I would normally have ever considered using for anything. However, an article in Cook’s magazine recommended it and I’m glad it did. For basic recipes, the beef and chicken versions of this product provide my go-to quick broth. It seems a little expensive, but it really isn’t compared to canned or boxed broths. The recommended usage is one tablespoon for a cup of water (but as the Cook’s article pointed out) one tablespoon for two cups of water works just fine (and is less salty and makes the base go farther).

For the beef in this recipe I generally rely on leftovers. Flank steak, NY strip, or rib eye works fine–but pretty much anything works. I use about 12-15 thin strips of beef (about four ounces) per two cups of broth. If the meat isn’t cooked, give it a quick flash in the pot before starting the soup. Don’t overdo cooking it. It will finish cooking in the hot soup.

Start the mushrooms soaking first thing and you can be eating this delicious soup in less than 15 minutes!

Hot and Sour Beef Noodle Soup
Author: 
Recipe type: soup
Cuisine: Chinese-inspired white guy
Prep time: 
Cook time: 
Total time: 
Serves: 1
 
A quick ramen-like soup with the flavor profile and full body of hot and sour soup.
Ingredients
  • 2 cups of beef broth (see text)
  • I portion of Asian egg noodles
  • 12 thin strips of beef
  • ½ cup of woodear mushrooms (or shitakes in a pinch)
  • ½ finely-diced carrot (it's not going to cook very long so no big chunks here!)
  • 1 tablespoon of Chinese black vinegar
  • ½ teaspoon of finely crushed white pepper
  • 1 tablespoon of soy sauce
  • 1 tablespoon of sambal chili paste
  • a couple of sprinkles of red chili flakes
  • several scallions for garnish
  • a couple of sprigs of cilantro for garnish
Instructions
  1. If you are using dried mushrooms, put them in a bowl and pour boiling water over them and let them sit until rehydrated (about 15 minutes)
  2. Slice beef into thin strips. If the meat isn't cooked, give it a quick flash in the pot before you start the soup.
  3. Bring broth to a boil in a small pot
  4. Add noodles, diced carrots, sambal, soy sauce and chili flakes
  5. Add the mushrooms, cut into thin strips, when fully rehydrated
  6. When the broth comes to a boil, add the noodles and cook until the noodles are al dente
  7. Remove the pot from heat and add the meat
  8. Serve garnished with thinly sliced scallions and a couple of sprigs of cilantro

 

Laravel’s Eloquent ORM versus Query Builder

Laravel offers two ways to work with your database:

  • Eloquent ORM. Eloquent provides an active record-based ORM. It provides a fluent interface with built-in relational capabilities.
  • Query Builder. The Query Builder provides a flexible, and also fluent, way to create SQL queries. It provides an intuitive way to create SQL queries with nearly all of the flexibility of using SQL direct.

Making my way through learning Laravel, most of the videos and articles I read focused on using Eloquent for database access. However, I found that using Eloquent for generating JSON, at least for some tasks, limited the control I had over how result set JSON was generated. This article shows how I turned to the Query Builder for generating the result sets to be expressed as JSON.

As I make my way further into Laravel, I am sure there will tasks for which Eloquent is superbly suited. However, I learned this weekend that there are also tasks for which the Query Builder is superbly suited.

Using Eloquent ORM

This Eloquent code (assuming the corresponding Laravel relations have been established)

$tasks = Task::with( ['category', 'state', 'type'] )-&gt;
           where('status_id', '&lt;&gt;', 3)-&gt;
           orderBy('description')-&gt;
           orderBy('id', 'desc')-&gt;get(['tasks.id',
                                       'tasks.type_id',
                                       'tasks.status_id',
                                       'tasks.category_id',
                                       'tasks.description',
                                       'tasks.start_time']);
return $tasks;

produces this JSON:

[
    {
        id: "2",
        type_id: "2",
        status_id: "1",
        category_id: "1",
        description: "Dr Schnieder",
        start_time: "2013-08-04 16:00:00",
        category: {
            id: "1",
            text: "Personal",
            created_at: "2013-07-17 04:47:37",
            updated_at: "2013-07-17 04:47:37"
        },
        state: {
            id: "1",
            text: "Open",
            created_at: "2013-07-17 04:47:37",
            updated_at: "2013-07-17 04:47:37"
        },
        type: {
            id: "2",
            text: "Appointment",
            created_at: "2013-07-17 04:47:37",
            updated_at: "2013-07-17 04:47:37"
        }
    },
    ...
]

Notice how the data from the related tables is placed into seperate JSON nodes (ie, the category, state, and type nodes). Unless you use the $hidden array in a model definition, there isn’t a way to limit the columns returned from related tables. The $hidden array can’t be changed at runtime so it must be specified in the model. Thus you either need special-cased models or learn to live with all of the columns being returned for related tables.

Laravel’s Query Builder to the rescue

Using Laravel’s Query Builder, you can get much less verbose JSON. The following query

$tasks = DB::table('tasks')
         ->join('task_categories', 'tasks.category_id', '=', 'task_categories.id')
         ->join('task_states'    , 'tasks.status_id'  , '=', 'task_states.id')
         ->join('task_types'     , 'tasks.type_id'    , '=', 'task_types.id')
         ->orderBy('tasks.description')
         ->orderBy('tasks.id', 'desc')
         ->where('status_id', '<>', 13)
         ->select('tasks.id',
                  'tasks.status_id',
                  'tasks.notes',
                  'tasks.start_time',
                  'tasks.end_time',
                  'tasks.labels',
                  'tasks.description', 
                  'task_categories.text as category',
                  'task_states.text as status',
                  'task_types.text as type')
         ->get();

return $tasks;

produces this JSON. The Query Builder provides a greater level of control over what is included in the query. For example, note how you can use the ‘as’ clause in the select() method to alias result columns.

[
    {
        id: "2",
        status_id: "1",
        notes: "check-up",
        start_time: "2013-08-04 16:00:00",
        end_time: "2013-08-04 17:00:00",
        labels: "",
        description: "Dr Schnieder",
        category: "Personal",
        status: "Open",
        type: "Appointment"
     },
    ...
]

 

Kung Pao sauce

I really like to make Kung Pao dishes. But I have never found a bottled Kung Pao sauce that suits me. When you get a Kung Pao dish from a great Chinese restaurant (and “great Chinese restaurant” can be a pretty grim looking, from the outside, mom and pop shop) it has the perfect combination of zing, flavor, and body. None of the bottled sauces I’ve ever tried provide that–in fact, most are just plain bad. So I spent a couple of months zeroing in on a Kung Pao sauce recipe that suits me. This one isn’t quite there yet, but it’s very close. I want to try grating a little fresh ginger into it. I think that might help round it out a bit.

I don’t like to add garlic to this sauce–and I put garlic in everything! I prefer to add the garlic to the primary contents of the meal. That way, when I am making a meal that uses this sauce, I can add as much garlic as I want knowing that this sauce won’t push the garlic needle too far into the red zone!

I make this sauce in advance and keep it in the freezer. It never fully freezes but lasts for a long time in its “nearly frozen” state. Having it readily available makes it much quicker to whip a Kung Pao-based meal together.

Kung Pao sauce
Author: 
Recipe type: Sauce
Cuisine: Asian
Cook time: 
Total time: 
 
This Kung Pao sauce is easy to make and vastly better than any bottled variety.
Ingredients
  • 2 cups chicken broth
  • ⅔ cup soy sauce (or maybe a little more--but watch the saltiness)
  • ⅓ cup rice wine vinegar
  • ⅓ cup light brown sugar
  • 1 tablespoon hoisin sauce
  • 1 tablespoon chili paste
  • 1 teaspoon red pepper flakes
  • 1 tablespoon cornstarch
  • 3 tablespoons of water
Instructions
  1. Add all ingredients except cornstarch and water to a sauce pan over medium-high heat.
  2. Bring to a boil, stirring frequently with a whisk. When the sauce starts to boil, reduce heat to bring to a simmer. Let simmer for 15 or 20 minutes.
  3. Mix the cornstarch and water in a small bowl. After 20 minutes or so, bring the sauce back to a boil. After the sauce starts boiling, and add the cornstarch/water mix.
  4. Stir vigorously with a whisk until the sauce thickens. When the sauce covers the back of a spoon (the sauce will continue to thicken a bit as it cools), remove from heat and use immediately or freeze for use later. No matter how hard I try, I almost get a few few pasty clumps from the cornstarch, so I usually strain the sauce as I poor it from the pan.
Notes
This recipe makes enough for two or three dishes. It freezes well.

 

Filtering XML with LINQ to XML

Filtering an XML document with LINQ to XML is very easy.

<TRUCKS>
    <TRUCKCOUNT>3</TRUCKCOUNT>
    <TRUCK>
        <CARRIER>MERKIN TRANSPORTATION INC</CARRIER>
        <CARRIERPHONE>(919)258-0939</CARRIERPHONE>
        <UNITNO>509</UNITNO>
        <UNITTYPE>TRACTOR</UNITTYPE>
        <DIMS>
            <BOXLENGTH>0</BOXLENGTH>
            <BOXWIDTH>0</BOXWIDTH>
            <BOXHEIGHT>0</BOXHEIGHT>
        </DIMS>
        <SATELLITE>N</SATELLITE>
        <AVAILABLE>05/24/2012 07:30</AVAILABLE>
        <STATUS>In Service</STATUS>
        <ISCONFIRMED>Y</ISCONFIRMED>
        <TEAM>N</TEAM>
        <LOCATION>GAS CITY, IN</LOCATION>
    </TRUCK>
    <TRUCK>
        <CARRIER>NICKELL FLIGHT SCHOOLS</CARRIER>
        <CARRIERPHONE>(805)767-6700</CARRIERPHONE>
        <UNITNO>958</UNITNO>
        <UNITTYPE>VAN</UNITTYPE>
        <DIMS>
            <BOXLENGTH>144</BOXLENGTH>
            <BOXWIDTH>50</BOXWIDTH>
            <BOXHEIGHT>69</BOXHEIGHT>
        </DIMS>
        <SATELLITE>N</SATELLITE>
        <AVAILABLE>05/26/2012 07:00</AVAILABLE>
        <STATUS>On A Load</STATUS>
        <ISCONFIRMED>Y</ISCONFIRMED>
        <TEAM>N</TEAM>
        <LOCATION>GAS CITY, IN</LOCATION>
    </TRUCK>
    <TRUCK>
        <CARRIER>BEST BRAINS, INC</CARRIER>
        <CARRIERPHONE>(888)345-5655</CARRIERPHONE>
        <UNITNO>427</UNITNO>
        <UNITTYPE>MEDIUM STRAIGHT</UNITTYPE>
        <DIMS>
            <BOXLENGTH>276</BOXLENGTH>
            <BOXWIDTH>92</BOXWIDTH>
            <BOXHEIGHT>88</BOXHEIGHT>
        </DIMS>
        <SATELLITE>N</SATELLITE>
        <AVAILABLE>05/24/2012 09:00</AVAILABLE>
        <STATUS>In Service</STATUS>
        <ISCONFIRMED>Y</ISCONFIRMED>
        <TEAM>N</TEAM>
        <LOCATION>GAS CITY, IN</LOCATION>
    </TRUCK>
</TRUCKS>

Here is the C# to use LINQ to XML.

public void Main()
{   
    string fileName = @"C:\Contents\\Web\MyApp\App_Data\trucks.xml"; 
    string buffer = File.ReadAllText( fileName );
    XDocument xDoc = GetSortedTrucksXml( buffer );
    xDoc.Dump();
}

public XDocument GetSortedTrucksXml( string xmlBuffer )
{
    XDocument xdoc = XDocument.Parse( xmlBuffer );
    int Counter = 0;    
    var trucks = from s in xdoc.Element( "TRUCKS" ).Elements( "TRUCK" )
                 orderby (string)s.Element( "CARRIER" ), 
                         (string)s.Element( "UNITNO" ) 
                 select getNewTruckElement( s, Counter++ );

    var newDoc = new XDocument();
    newDoc.Add( new XElement( "TRUCKS", trucks ) );
    return newDoc;
}

private XElement getNewTruckElement( XElement s, int Counter ) {
    // Add as many elements from the TRUCK as needed 
    // here. 
    XElement result = new XElement( "TRUCK" ,
                          s.Element( "CARRIER" ), 
                          s.Element( "UNITNO" ),
                          s.Element( "UNITTYPE" ),
                          s.Element( "LOCATION" ),
                          s.Element( "DIMS" ) );

    result.SetAttributeValue( "Counter", Counter.ToString() );                  
    return result;
}