I can’t stand people who recline their seats on airplanes

I haven’t had a good travel rant in a while.  However the recent debate over the Knee Defender and the incident on a flight from Newark to Denver which has been in the news, reminded of a situation I was personally involved in back in February.

For the most part travel is what it is.  A necessary evil.  Maybe I am jaded having flown so much over the years but there isn’t anything glamorous about it.  Full flights, competition for overhead bin space, delays, minimal service – I am not sure why anyone would think flying is glamorous.

There was an opinion piece in today’s Raleigh News and Observer from Froma Harrop that caught my eye.  As I read Ms. Harrop’s opinion piece I sat there and shook my head and concluded Ms. Harrop must not travel much.  If she does, she and I are 180 degrees out of phase.

In my opinion, Ms. Harrop couldn’t be more wrong.  After reading her article I wondered who she is (a syndicated columnist) and found her web site where she had another post about the Knee Defender.  This post contained a link to the story in the NY Times by Josh Barro.  Ms. Harrop had stated in her post that Mr. Barro defended the Knee Defender user but that isn’t how I read his article but that is besides the point.

Maybe Ms. Harrop would have a different opinion of seat recliners had her computer been damaged by an over zealous seat recliner like mine was on a US Air flight back in February.

I’ve read a bunch of articles and comments I am squarely on the side of the Knee Defender user and firmly believe that people who reline their seats to the max and/or without consideration are simply rude.  Particularly those who do it without concern to who or what might be behind them.

My job requires me to travel.  Over the 20+ years of doing what I do for a living, I have flown in excess of 3,000,000  (yes million) air miles.  Most of it is on American Airlines (by far my favorite airline) but for the past 5-6 years I’ve mostly flown on United  (starting with Continental until the merger).  USAir had been part of the Star Alliance (their participation ended at the ended of March due to the AA merger) so I also had quite a few flights on USAir.  USAir via Charlotte is by far the best (and cheapest) way for me to get to Phoenix from Raleigh which I’ve been doing 8-10 times a year for the past few years.

I get a lot of work done on the plane.  I find it very productive time and actually look forward to being disconnected from my phone and the Internet for an extended period to work on something without interruption.  For me time on the plane isn’t down time and it isn’t fun time.  It is work time just like if I were in the office.

About the only time I recline my seat is when flying on the red-eye.  Why?  Because I think it is rude and discourteous to lean my seat back into someone’s face.  I am also fully aware that a lot of people, particularly those who don’t travel much, feel it is their birth right to recline their seat.

Some people are fairly reasonable – if you ask them if if it is really necessary to fully recline their seat, most will accommodate the request and recline partially.  Of course some won’t.  I’ve dealt with obnoxious people over the years.

Yes, it is your right to lean your seat back but if you must do it, and I really don’t think you do, at least be courteous about it.  Look before you lean back.  Lean back slowly.  Ask if it is ok.  I’m fairly tall, 6’2″, so on some flights a reclined seat results in my knees in the back of the seat.  Does that bother you Mr. or Ms. Seat Recliner?  Too bad.  I don’t like it either but you are the one who chose to recline your seat.

So what happened to my computer?  As I was working away on a flight from Charlotte to Phoenix, the woman in front of me reclined her seat very quickly and very forcefully.  I am usually aware of seat recliners because I am worried about my laptop.  However this woman surprised me and I wasn’t ready.  When she leaned her seat back, the corner of her seat where the tray table sites caught the corner of my laptop and stopped the seat from reclining.  I guess I had my laptop at just the right angle because instead of moving the lid one way or other, the force of the seat coming back compressed the screen and hinge to point where it broke.  Because her seat recline was temporarily impeded by my laptop screen, she began really pushing it back almost as if she were bouncing against it.  This caused the screen to bend and an audible crack was heard as part of it broke.

This all happened in a matter of seconds and I immediately yelled “stop it” and put my hand on the back of the seat and pushed it back forward.  This made the woman very upset and resulted in a minor scene.  Needless to say I was upset – the damage to my laptop was obvious and the screen immediately showed a entire area of dead pixels and vertical lines.  The woman kept going on about how she was “entitled” to recline her seat.

She wasn’t the least bit sorry that her recline had damaged my laptop.  She was offended that I was upset.  I was dumbfounded as to how she could be so selfish as I would (a) never had done what she did and (b) if I were involved in a similar incident, I would have apologized for being negligent.

Accidents happen and had this woman shown any remorse what so ever, I would have chalked it up to one of those things which happens if you fly enough.  The only thing she was worried about was her right to recline her seat which she was “entitled” to.  She then said to me “you must not travel much” which left me almost speechless.  Almost.  I told her I travel plenty and I would never do anything as rude and inconsiderate as what she had done.  Ever.

The flight attendant was actually pretty helpful as he told the woman to calm down and be reasonable.  He also gave me some information to take to US Air customer service once I got to Phoenix.  He dodn’t know what they would do but he said it was worth a shot to make a claim.

In Phoenix I visited customer service and even though it took a while, the woman I spoke to said there was a chance US Air would do something.  After several weeks of phone calls, faxes, and emails, I actually got in touch with someone at US Air who seemed to have the authority to do something.  Much to my surprise, US Air paid to have my laptop repaired although it took a lot of my time to chase it down.  The repair costs was about $350.

Personally I’d like to see all seats be fixed so they can’t recline like the seats in front of the emergency exit row.  I think it it would prevent quite a bit of in flight aggravation and eliminate the need for devices like the Knee Defender.

So Ms. Harrop, you’re absolutely entitled to your opinion.  I just think you’re wrong.  I felt that way years ago and I definitely reaffirmed my opinion back in February dealing with the “entitled” seat recliner.  I hope the hour of recline that woman had was worth it – her selfish act probably resulted in 20 hours of legwork and follow up for me with US Air to get my computer fixed.

Buying a SIM Card in Germany was harder than it SHould Be

A while ago I gave up my AT&T unlimited international data plan (you did what?) to move my family to a Mobile Share plan.  We have 8 phones on a 10GB Mobile Share plan and have only exceeded our limit once so objectively it was the right decision for us.  Having a Verizon MiFi from work certainly helps although it does mean that I need to actually think when I travel internationally.

I am in Munich this week for work and even though work will pay for the international add-on I have to turn on now when I travel out of the US, I decided I would buy a prepaid SIM card for data and put it in an unlocked Moto G which I have (having an unlocked phone comes in handy from time to time) and see if it would be a viable alternative to the $50 I paid AT&T for 500M of international data.

When I went to Poland a couple months ago I connected via Heathrow and picking up a SIM card was trivial.  You put your credit card in a vending machine, picked the SIM plan you wanted and and it was dropped out like a candy bar.  Simple.  Two minute transaction, if that.

I expected the same in Germany if not even easier, because if there is one thing Germany is good at, it is automating processes.  My experience was pretty much the opposite.  Not a SIM card vending machine in site at the Munich airport.  No big deal, there are several stores that appear to be selling them so I stopped in one.  The person in front of me wanted two SIM cards for their iPhones.  I waited at least 10 minutes before I gave up to go meet some co-workers and the cashier hadn’t   even gotten one working.  Odd.

I ventured out from my hotel having seen a number of stores in the general vicinity – Vodafone, O2, T-Mobile, and several independent stores.  I thought I was looking for something relatively simple.  I was looking for 1GB of data for about 20 Euros, less would be better.  It seemed that every store I went into had a different story.  From two different T-Mobile stores I got different answers.  At one I was told 10 Euros for 500MB but I couldn’t add to it if I went over.  At another store I was told that I could get 200MB per day for 10Euros up to 1GB during a week and  it would cut off after 200MB until the next day.  Odd.

Other vendors had variations of similar things.  I settled on an O2 card of 1GB which was good for a week.  Great, sound just like what I am looking for.  I’ll take it. Give  the clerk my Visa card – uh-oh, only cash for pre-paid SIM cards.  WTF?  I usually have some Euros with me but not an hour earlier I had dropped about 60 Euros for lunch for myself and three co-workers because the restaurant didn’t take credit cards.  That would have been helpful to know before we ate!

So out I go in quest of Euros from an ATM.  While I was out getting Euros I realized the cashier at the cell phone shop still had my passport!  Major panic.  If there is one thing that I worry about traveling it is losing my passport.  I have copies of it but I really don’t want to have to go through that experience.  Fortunately the cashier realized it as soon as I left the shop and put it in a safe place.  Yikes!  Back to find Euros.  For whatever reason the only credit card I can get Euros with is my PayPal debit card. 

So now I have  Euros to pay for the SIM card and this whole experiment is taking way longer than it should but with this much time invested, I press on.  Besides, I need something to keep me occupied until I meet up with my co-workers later this evening.  I need to stay away from the hotel room where it would be too easy to take a nap and be out of sync time wise all week.

As the cashier, a young guy – maybe 20 years old, is completing my transaction three young women come into the shop asking for unlimited Internet SIM cards in English.  After conversing with them in English for a bit he asks if they are Russian and switches to speaking Russian.  At that point his attention is on them and he fails to give me a critical piece of information with my SIM card packet.  The registration number.

I leave the store ready to try my experiment.  The instructions are in German, which I don’t speak but how hard can it be?  It is a SIM card and it has been paid for.  Put it in the phone and it should work.  Right?

Nope.  I have the SIM installed and the phone asks for a SIM activation pin code which is on the package and I enter.  So far so good.  Can I browse the web?  Nope.  An O2 web site comes up, in German of course, which I am clueless as what to do with.  It wants some sort of registration number.  Great.  After futzing around with it for 10 minutes I head back to the O2 store, which fortunately is next door to the hotel, I go back for the third time.

The woman helping me this time asks if I registered it?  No, how would I know what to do or how?  She pulls a scratch card out of the package which apparently my original clerk should have alerted me to and probably would have had he not been distracted by the Russian girls.  10 minutes later I am online and headed back to my hotel.  Oh yeah, one other little caveat.  Prepaid plans only support 3G.  No LTE and no HSUPA.  Bummer.

So in the end was it worth it?  I don’t know.  It was a good learning experience and it kept me busy for a couple hours.  I know a lot more should I or someone in my family, ever need to do this again.  I’ll play with it some more over the course of the week but in summary, it is waaaaaaay harder than it should be and quite a bit harder than in the UK.

Google Forms, Checkboxes and PHP 5.4 or 5.5

WordPress Google Form v0.63 introduced a change  which allowed the plugin to work on newer versions of PHP, notably 5.4 and 5.5.  Unfortunately that change has broken support for checkboxes.

For those who are new to the plugin or never needed to know how it worked, what the plugin does is retrieve the HTML for the form from Google and render it within the context of WordPress.  When the form is submitted, it is actually submitted within the context of WordPress.   The data is collected by the plugin and then submitted to Google.  The retrieval from and submission to Google is done with the WordPress HTTP API.  In particular, the wp_remote_get() and wp_remote_post() functions are used to retrieve and submit the form.

To complicate the problem further, Google uses Python as the backend for their form processor where as WordPress uses PHP.  For the most part, the fact that they are based on different scripting languages isn’t a big deal.  Until you get to checkboxes.  Checkboxes in Python are handled differently than they are in PHP.

I had solved the compatibility problem a couple years ago (see this thread on the wp-hackers mailing list) using a small jQuery script which fixed the form variables on the WordPress side and manual construction of the body parameter for wp_remote_post() when submitting the data to Google.  This solution worked fine until I received a bug report that nothing was being submitted on a site which was running PHP 5.4.x.

Fortunately the user who encountered the problem provided me with a patch that I was able to fold in which changed the way the body parameter was constructed (array instead of a string) which worked with PHP 5.4.x and also worked with older versions.  However, I didn’t test it thoroughly as I have had several reports that checkbox content was not being submitted correctly.  Uh-oh.  I was able to verify the problem fairly quickly and was able to push out a version which essentially reverts how the body parameter is constructed (string instead of an array).  The problem is, this build doesn’t work with newer versions of PHP.

I have PHP 5.5 running on an Ubuntu virtual machines for testing and so far, I have not found a solution which (a) works with PHP 5.5. and (b) submits checkboxes correctly.

Stay tuned.

Odd behavior with PHP’s method_exists() function

I recently had a report from a user that many of the pages within the wp-SwimTeam plugin were blank.  This is odd and incorrect behavior but I have seen it before.  When I last chased it down I found that the way various versions of PHP 5.2.x and 5.3.x handled Constructors was different and in some versions Constructors in parent classes would be called and in some versions they wouldn’t.

I assumed this new report of blank pages meant that I had missed one of these Constructor issues somewhere.  It turns out that wasn’t the case.  This time I found that PHP’s method_exists() function behaves differently between different versions of PHP on different platforms.

The report came in from a site running PHP 5.3.13 which is the same as what I am running in my development area.  The only difference I can see between the two servers is mine is running on Windows under IIS where as the problematic site is running Apache under Linux.

When a page is rendered for wp-SwimTeam, the objects on the page are traversed and HTML code is generated.  The objects which comprise the page content can either be strings (HTML code) or objects themselves which then traversed recursively until all of the leaf HTML is assembled.  This is core functionality in phpHtmlLib that I have been using for years without any issues until now.

What I found was that if the variable passed to method_exists() was a string instead of an object, PHP goes out in the weeds and never returns which ultimately results in the blank page.  This is the code that has been rendering objects in phpHtmlLib for 10+ years:

if (method_exists($item, "render") ) {

It was fairly simple to fix it.  By checking to see if the item is an object prior to checking for it’s render method, the problem is resolves and the page renders correctly.

if (is_object($item) && method_exists($item, "render") ) {

I will be updating phpHtmlLib with this fix shortly.

phpHtmlLib updated to v2.6.4.3566

I received another report from a user experiencing blank pages on some of the wp-SwimTeam tabs.  I had run into this previously and determined it to be a PHP issue in the early 5.3.x releases (.1 and .2 for sure).  PHP was terminating with a fatal error which resulted in an incomplete HTML page.  If you looked at the page source for these “blank” pages you would see nice HTML simply terminate with no closing tags which obviously resulted in missing content.

It turns out that phpHtmlLib was the culprit (which I suspected) and it was behavior that is inconsistent between releases of PHP including PHP4.

Many of the widgets in phpHtmlLib build upon one another by extending classes.  It is not uncommon to find some classes that are extended 3-4 levels.  No problem, that is one of the beauties of classes.  The problem came from some classes having constructors where some of their descendants did not AND the grand child (or great grand child) class referenced the parent constructor.

Because phpHtmlLib originated in PHP4, all of the syntax remains in PHP4 format including the use of class constructors.  The following example illustrates the problem I had run into:

<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */

class Sample_A {
    /**
     * Constructor
     */
    function Sample_A() {
        printf('<h3>%s::%s - Sample A Constructor</h3>', basename(__FILE__), __LINE__);
    }
}

class Sample_B extends Sample_A {
    /**
     * No Constructor!
     */
}

class Sample_C extends Sample_B {
    /**
     * Constructor
     */
    function Sample_C() {
        printf('<h4>%s::%s - Sample C Constructor</h4>', basename(__FILE__), __LINE__);
        parent::Sample_B() ;
    }
}


ini_set('display_errors','stdout');
error_reporting(E_STRICT | E_ALL) ;

printf('<h2>%s::%s - Instantiating Sample A</h2>', basename(__FILE__), __LINE__);
$A = new Sample_A() ;
printf('<h2>%s::%s - Instantiating Sample B</h2>', basename(__FILE__), __LINE__);
$B = new Sample_B() ;
printf('<h2>%s::%s - Instantiating Sample C</h2>', basename(__FILE__), __LINE__);
$C = new Sample_C() ;

?>

Running the code above results in the following with certain versions of PHP (e.g. 5.3.1).

<h2>sample.php::33 - Instantiating Sample A</h2>
<h3>sample.php::9 - Sample A Constructor</h3>
<h2>sample.php::35 - Instantiating Sample B</h2>
<h3>sample.php::9 - Sample A Constructor</h3>
<h2>sample.php::37 - Instantiating Sample C</h2>
<h4>sample.php::24 - Sample C Constructor</h4>

Fatal error: Call to undefined method Sample_B::Sample_B() in /var/www/clients/client3/web44/web/sample.php on line 25

Why does this happen? It turns out that earlier (and now later) versions of PHP would handle the missing constructor in Sample_B implicitly. Because some constructors are fairly complex and pass multiple arguments, I don’t really want to add all of the intermediate constructors just because some versions of PHP don’t handle the constructor chain properly (or at least consistently). So I came up with the following solution:

class Sample_B extends Sample_A {
    /**
     * Constructor - needed for early PHP 5.3.x compatibility
     *
     * @param Parent Constructor
     * @param array of Constructor Arguments
     */
    function Sample_B() {
	    call_user_func_array('parent::Sample_A', func_get_args()) ;
    }
}

Adding this constructor to the Sample_B class results in the following (which is what I want):

<h2>sample.php::39 - Instantiating Sample A</h2>
<h3>sample.php::9 - Sample A Constructor</h3>
<h2>sample.php::41 - Instantiating Sample B</h2>
<h3>sample.php::9 - Sample A Constructor</h3>
<h2>sample.php::43 - Instantiating Sample C</h2>
<h4>sample.php::30 - Sample C Constructor</h4>
<h3>sample.php::9 - Sample A Constructor</h3>

There is a chance there are more places within phpHtmlLib that could have this problem with some versions of PHP5.3.x. Now that I know how to solve them, fixing them is pretty simple and very quick. If you run into any blank pages within wp-SwimTeam, let me know ASAP and more than likely a solution like the above within phpHtmlLib will address the issue.

The phpHtmlLib plugin has been updated to v2.6.4.3566 and committed to the WordPress plugin repository.

Working on Hy-tek Entries

Over the last few days I have been working the Hy-tek HY3 equivalent of exporting SDIF meet entries.  For the most part the logic is largely the same but the Hy-tek Meet Entries format is different enough that it isn’t a simple port.  In particular, relay entries have me a bit stumped.

In SDIF it is possible to assign any number of swimmers to a relay event as an “Alternate” using the “A” designation in the leg field of the F0 record.  As near as I can tell, the Hy-tek equivalent doesn’t exist.  A relay team can be defined in the HY3 F1 record and the heat and lane assignment can be set in the F2 record.  Swimmers are designated in the F3 record.  So I am somewhat stumped – do I just define the relay teams and then let the assignment of swimmers to the relay teams happen within either Team Manager or Meet Manager or do I keep track of the number of potential swimmers and create the maximum number of relay teams and simply assign swimmers to each team so they can be sorted out later?

The other dilemma I face has to do with the swimmer id field which is not the same as the registration number field.  The swimmer id field is an internal database field which connects D1, E1, and F3 records to the same swimmer.  Within my plugin I have unique swimmer ids in the form of database record identifiers that I know will be unique.  Should I use them or is simply starting at 1 and sequencing the number of swimmers as using that as an id sufficient?

My guess is the answer to both of these questions will be “it depends” and I’ll need to experiment.  Life would be so much easier if Hy-tek would simply support the SDIF format correctly instead of the half assed way they do it now.

wp-SwimTeam v1.26.871 released tonight

I released a second build today, v1.26.871 was pushed out late tonight.  I don’t like to do this as constantly having the Update notice on your Dashboard can be a bit of a nuisance.  We’re gearing up for Swim Team, he have our season opening party in one week so I’ve am trying to get ready and have been working on the plugin a lot over the past few days.

This build addresses a few minor nits but the primary new feature is the ability to display the meet time as part of the wpst_meet_schedule short code.

  1. I’ve added a new option to Miscellaneous tab to control how time is formatted. Usage of the format is not yet pervasive through the plugin.
  2. Enhanced wpst_meet_schedule shortcode with two new attributes: fmt=’time format’ and ‘showtime=yes|no’. Default is not to show the time and use the time setting from the Miscellaneous tab. The fmt attribute expects a string formatted following the conventions outlined in the PHP date function.
  3. Removed redundant code from Swim Meet module.

The build has been pushed to the WordPress plugin repository and also appears on my Download & Installation page.

Why is my web site so sloooooooooow?

I apologize for how slow this web site has been lately.  I don’t visit it myself too often when I am not actively working on wp-SwimTeam so I was somewhat oblivious to it.  My sites are hosted with GoDaddy and I’ve never really had an issue with their shared hosting service.  It is cheap, easy to administer, and for the low volume traffic I tend to get, more than adequate.

I called GoDaddy this morning to see why my sites was loading so slowly – I am seeing page load times of 30-40 seconds which is just plain silly.  It looks like another web site that I happen to be sharing the “shared” server with is consuming all of the resources.  GoDaddy is going to monitor it and see what is up.  I expect it will remain slow for at least a few days.  Hopefully they’ll figure out what it is and do something about it but they did tell me that if the other site isn’t violating their TOS, there isn’t much I can do about it.  They also suggested I look into a WordPress caching plugin.  I don’t have near the volume of data nor traffic to warrant a caching plugin but if the situation persists, I’ll look into it.

Bleh.  Even on a shared server there ought to be some expectation of “reasonable” performance.  I will continue to monitor the performance and see what I can do about it.

Meet Manager SDIF Compatibility

I’ve been doing some research into Meet Manager and its ability to import an SDIF entries file.  Since so many teams use Meet Manager, getting data into it is pretty much of a requirement.

I posted previously on this topic but this year, as I was preparing our entries for the Cary City Meet, I did some experiments.  Hy-tek now makes a demo version of Meet Manager available.  The demo version is limited to six (6) events which makes it useless for doing much real work but it is fine for some simple experiments like I wanted to do.

What did I learn?

Meet Manager is really picky about SDIF.  This really isn’t a surprise.  The first thing I ran into was SDIF files (which are ASCII) that go through e-mail as simple attachments rarely will read into Meet Manager successfully.  There is something about line endings that Meet Manager is unusually sensitive too.  This issue can be avoided by zipping an SDIF file before sending it via e-mail.  You can actually load the zip file into Meet Manager directly, Meet Manager will unzip it for you.

The real compatibility issue comes from D0 and E0 SDIF records which don’t have a seed time.  Meet Manager simply does not like records without a seed time (blank) even though the SDIF specification indicates this is legal.

To get past this issue, the SDIF file must contain either “NT” or “00:00.0” (right justified) in the seed time field AND the course code.  Meet Manager will accept both formats as “no seed time”.

Unfortunately Meet Manager still does not read heat and lane information from the SDIF record.  This is really a nuisance.  As near as I can tell the only way to get heat and lane information into Meet Manager is via a .CL2 file (maybe) or via a .HY3 file (definitely).  Of course both of these file formats, which are similar to SDIF, contain the Hy-tek proprietary checkum for each record.

I would really like to solve this problem as it would make interchanging data so much easier.

Another goofy e-mail from GoDaddy

I had another go-round with GoDaddy yesterday which resulted in another goofy e-mail.  I posted the fsockopen() example they had asked me to which timed out and GoDaddy responded with this:

Dear Mike,

I sincerely apologize for any confusion or frustration. You will need to specify the proxy in your coding. Applications that need to make outbound connections (port 443) will need to be made “proxy aware”. This will require additional coding to varying degrees, depending on the application. You will need to know the ip address and port of the proxy server in order to correctly modify your code. The ip of the proxy server is 64.202.165.130 and connections will be made on port 3128.

You will need to use this when coding with PHP:
curl_setopt ($ch, CURLOPT_HTTPPROXYTUNNEL, TRUE);
curl_setopt ($ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
curl_setopt ($ch, CURLOPT_PROXY, http://64.202.165.130:3128);
curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, FALSE);

I hope this information helps.

Please let us know if we can assist you in any other way.

Sincerely,
Lindsay C.
Online Support Representative

Right back to the cURL requirements which really don’t make any sense for fsockopen().  It really doesn’t matter as I chnaged the code which manages the Google Maps so it no longer needs it.