Why I no longer use Cricket Wireless

Page LogoI tried to add a feature to my wireless services, and things went horribly wrong.

I switched my cell service to a Cricket Wireless prepaid account about a year ago. Other than one missed call, service was good, no complaints. On April 8, 2015 I logged into the website to add international service for my (then) upcoming vacation. On the morning of April 9, 2015 I discovered that my service was turned off and my account was suspended.

Below is the first chat conversation with customer service to find out why. Other than replacing some values with ### to protect my feeble identity, the rest of the conversation remains unchanged.

You have been connected to Gaby.
Gaby: Welcome to Cricket Wireless! What can I do for you today? ☺
Nicholas Fiorello: Hi Gaby. Please explain why my account is suspended. My credit card statement shows that you were paid $35.00 on 3/25. Yesterday I connected to the website and used a different card to pay $10.00 for international roaming. What gives?
Gaby: I’ll be happy to assist you :)
Gaby: May I have your phone number and 4 digits Pin?
Nicholas Fiorello: ########## I believe my pin is either #### or ####
Gaby: Thank you!
Gaby: Please allow me a moment…
Gaby: Thank you for your patience Nicholas
Gaby: in our system the last payment reflected is: Payment deposit date: 2015/03/25. Amount: $ 35.00.
Nicholas Fiorello: Yes,and since it’s prepaid that would be for 3/27 through 4/27
Gaby: no payment for roaming
Nicholas Fiorello: That payment is still showing pending. But that’s kind of beside the point since I’m still in the US, my trip doesn’t start until Saturday
Gaby: if it’s still pending it won’t be processed, it is a failed transaction. You can to dispute the charges with your bank
Nicholas Fiorello: I’m not disputing the charge (yet anyways) I just want my phone re-activated for the time I’ve already paid for.
Gaby: Your account is suspended due to non payment, it is an automatic system, I’m afraid we cannot restore the service without the payment, my apologies
Nicholas Fiorello: non payment of WHAT exactly
Nicholas Fiorello: I paid you on 3/25/####
Gaby: Correct, but you paid for the plan, on 04/08/15 you added the international roaming on the line (###) ###-####
Nicholas Fiorello: And you took my credit card info at that time and there is a pending charge on my card for $1.00 so I know you got the correct info.
Nicholas Fiorello: Please escalate this to a manager
Gaby: would you like to talk to a manager?
Nicholas Fiorello: absolutely
Gaby: Please allow me a brief moment…
Ernesto Chirinos has entered the session.
Nicholas Fiorello: Hello Ernesto.
Ernesto Chirinos: Good Morning Nicholas, How are you today?
Gaby has left the session.
Nicholas Fiorello: As I explained to Gaby, my account was prepaid on 3/25. Yesterday I logged in to your website to add one-time international roaming and entered my credit card info. Today my account is suspended, and I’m having lots of trouble understanding why
Ernesto Chirinos: I understand how frustrating that might feel. But no worries, I’m here to help!
Ernesto Chirinos: Let me go ahead and access your account really quick. Please
Ernesto Chirinos: Reviewing your bill as we speak, Nicholas
Ernesto Chirinos: Are you still with me?
Nicholas Fiorello: Thank you. Yes
Nicholas Fiorello: If it helps, I see the 3/25 payment “Cricket wireless” on my monthly statement. I see the 4/8 “AIO One Time Payment” as pending for $1.00
Ernesto Chirinos: I understand Nicholas. I just checked your account and bill and last payment received was on ” System – Payment received. Payment deposit date: 20150325. Amount: $ 35.00. Method: ##. SUB METHOD: . Source: ####. CONFIRMATION NO: ###################. ”
Ernesto Chirinos: When you add a feature to your rate plan, Nicholas, You need to make an upfront payment first for the feature to be added successfully
Nicholas Fiorello: Which I did when I entered my credit card info to the site yesterday. It must have been the right info because I see the pending charge.
Nicholas Fiorello: Is it somehow possible that charge got added to a different account?
Ernesto Chirinos: If its pending, Nicholas it means payment will not go through and we’ll return those charges back to your card.
Ernesto Chirinos: Do you have another account?
Nicholas Fiorello: No
Ernesto Chirinos: Then I don’t think payment went to another account
Ernesto Chirinos: Since you did not paid the $10 for the feature or payment didn’t went through that caused your service to be suspended
Nicholas Fiorello: Ok, let’s start over. Can you remove the request for international roaming, restore my account and I’ll stop by a cricket store on the way home tonight and get them to add it back?
Ernesto Chirinos: Unfortunately, Nicholas I cannot restore the account, You’ll have to make the payment. Then I will be able to remove the feature
Nicholas Fiorello: And how much exactly do I need to pay go get my account back
Ernesto Chirinos: $26 – $10 $16 due to billing cycle change pro rated charges. Every time you let your account get suspended for non payment your bill cycle date change automatically. I am able to provide as a one time courtesy $10 credit for you to pay the other $16 and get your service restored
Nicholas Fiorello: This is insane. I have already paid for 18 more days of domestic service. Now you want $26 more because I wanted to add a $10.00 feature and YOU F###ED IT UP?
Ernesto Chirinos: I am very sorry Nicholas, Payment did not went through.
Ernesto Chirinos: As I explained to you before, I am able to provide as a one time courtesy $10 credit for you to pay the other $16 and get your service restored.
Ernesto Chirinos: That’s the only option I have for you. I do apologize
Nicholas Fiorello: I will have my credit card company contact you. good by

After I disconnected the chat, I contacted my credit card company and declined the $35.00 charge on 3/25 on the basis that I paid for 30 days of service and only received 12. My account remained suspended until later that night when I logged in and paid $26.00 (the amount listed on the site) to restore service. I didn’t expect the account to be turned on but figured $26.00 roughly covers the amount of usage between 3/25 and 4/9. My phone was enabled for the remainder of the day. However by 4/10 it was once again suspended. By this time I’d already left for vacation.

Immediately upon my return, I checked my credit card account to see that the $26.00 was indeed charged. When I checked my Cricket account, a $5.00 late fee was posted. (A late fee for “pre-paid” service?) So I once again contacted customer service. Below is the transcript from that conversation, again edited for identity purposes.

You have been connected to Angela.
Nicholas J. Fiorello jr.: I want the late fee removed from my account NOW
Angela: Thank you for Contacting the New Cricket Wireless and for being part of the Best Chat Customer Service Experience! My name is Angela and it is a pleasure for me to assist you today, now let me ask you, How is your day going so far?
Nicholas J. Fiorello jr.: Angela, let’s save some time. I want a senior supervisor NOW
Angela: I will definitely help you with the late fee, we know how important is to have everything correctly setup to avoid having inconveniences, so I’m going to do my best to assist you, you’re in great hands! ☺
Angela: I understand you want a supervisor and I can tell you’re frustrated with good reasons, but I can help you as well
Angela: Could you please be so kind and provide me with the phone and pin number on your account?
Nicholas J. Fiorello jr.: On March 25 ####, I paid for 30 days of service. I only received 12 days. Do you understand this?
Nicholas J. Fiorello jr.: ###-###-#### PIN is either #### or #### I forget which
Angela: Off course I understand, let me verify what happened to fix it right away!
Angela: Thank you for the info! Allow me just one minute to access to your account please ☺
Angela: Perfect! I’m already on your account, let me verify what happened with your billing cycle
Angela: Ok, I’m able to see here that the reason of the suspension is because the payment you did for $35.00 on 03/25/2015 was reversed on 04/10/2015
Angela: I’m verifying now why
Nicholas J. Fiorello jr.: IT WAS REVERSED BECAUSE YOU CUT OFF MY PHONE SERVICE ON 4/10/####
Angela: It’s actually the opposite, since the payment got reversed, the services got suspended, the reverse payment happened on 04/10/15 06:10 and the suspension on 04/11/15 03:52
Nicholas J. Fiorello jr.: Look up my account history and you’ll see the chat conversation I had.
Nicholas J. Fiorello jr.: I have a transcript.
Angela: Unfortunatelly, we do not have access to previous conversations and we do not have any notes about it either
Nicholas J. Fiorello jr.: What you do not see, because you haven’t read the whole thing, is that I paid 26.00 to get it re-activated on 4/10
Nicholas J. Fiorello jr.: I’m sorry 4/9. The charge appears on my statement.
Angela: Ok, let me double check that info for you
Angela: Yes, I see here that you made a payment for $26.00 on 04/10/2015 and I also see here that on the same day your billing cycle was changed from 27 to 9
Angela: Did you request that?
Nicholas J. Fiorello jr.: No
Nicholas J. Fiorello jr.: Everything started when I tried to add one-time international service on 4/8. The next day I discovered that the phone was switched off. That’s when I chatted with “Gaby” and “Ernesto Chirinos”
Angela: Oh I see, What I’m able to see here is that it happened because the previous payment got reversed so since technically you paid after the due date, the day you pay its going to be the new billing cycle
Nicholas J. Fiorello jr.: Ernesto refused to reactivate my account (without international service) for the remaining 18 days of my billing cycle. So that’s when I contacted AMEX and reversed the charge.
Angela: OMG! I’m really sorry you had to go through this hard time
Angela: I’m not even able to find notes about the international feature
Angela: Let me help you with this
Angela: I just need to verify some info, allow me two minutes please
Nicholas J. Fiorello jr.: Ok, one thing. I’m back from my trip. Whatever you do, I don’t need the international plan anymore. (Phone was off the whole time)
Nicholas J. Fiorello jr.: service I mean. The camera still worked
Angela: Sure! let me make sure that feature it is not associated to your account, ok?
Angela: You do have it and it wont let remove it unless the account is active, so please allow me 2 minutes to work on that
Angela: Thank you for staying online
Nicholas J. Fiorello jr.: sure
Angela: I’m still working on your account allow me one more minute please
Nicholas J. Fiorello jr.: yes
Angela: Thank you for staying online, I was trying to verify if I could remove the charges on your account, unfortunately, the charges are valid, what I can do is give a credit for $5.00 that is going to remove the late fee
Nicholas J. Fiorello jr.: Unfortunately that’s not enough to keep me as a customer. I had no phone over my vacation because of an error that happened within YOUR billing system. I tried without success to resolve it before I left. The way I see it, the $26 paid on 4/9 covers the 12 days from 3/25 till 4/9 and we’re even.
Nicholas J. Fiorello jr.: so if you can’t help me. please refer me to a supervisor who can
Nicholas J. Fiorello jr.: I will be happy to email you the transcript from the previous conversation if you need to review it.
Angela: I think is not necessary, I can assist you with this matter, what I understood and correct me please if I’m wrong is that you paid your regular bill for $35.
Angela: on 03/25/2015 after that you requested the Roaming Mexico feature, however since there was no payment for the feature the account got suspended, you requested to restore it and remove the RM however previous re could not do it
Angela: So you requested to to have previous payment reversed
Nicholas J. Fiorello jr.: Here’s the timeline…
Nicholas J. Fiorello jr.: 3/25 auto-pay $35.
Nicholas J. Fiorello jr.: 4/8 tried to add roaming
Nicholas J. Fiorello jr.: 4/9 discovered phone was off, chatted with customer service
Nicholas J. Fiorello jr.: 4/9 Reversed 3/25 charge
Nicholas J. Fiorello jr.: 4/9 Paid $26 to restore service
Angela: The phone got off after you added the Roaming Mexico because the payment for the feature $10.00 was not made
Nicholas J. Fiorello jr.: 4/11 discovered phone was off again
Angela: that is why the account got suspended
Angela: Even though you paid for the $26.00 was not enough for the bill with the feature which is still added to the account
Angela: Also because every time you reverse a payment there’s a fee depending on the bank
Nicholas J. Fiorello jr.: I don’t know why the payment did not go though, and to be honest I don’t care. Cricket is a PRE paid service. I never got ANY international roaming because my service was disabled from the time I asked for it. There’s no way in hell i’m going to pay for it.
Nicholas J. Fiorello jr.: NOW here is what it is going to take to keep me from closing the browser and going to another carrier. You remove all fees from my account, clear the slate and let me start clean today… preferably with a month free for my trouble. If you can’t do this, the conversation is over.
Angela: Unfortunately Nicholas that is not possible, because the charges you have are valid and trust me I did everything in my power to assist you, but I’m not allowed to waived valid charges
Nicholas J. Fiorello jr.: well then I guess we are done. Thank you for your time.

So now my number’s been ported to another carrier.

Temporary files in application specific folder.

Sometimes you come across something you wish you knew 5 years ago. I can’t count the number of projects I’ve written or inherited that work with temporary files. Out of the box, .NET provides two functions to help you work with temp files.

  • System.IO.Path.GetTempFileName Creates a uniquely named, zero-byte temporary file on disk and returns the full path of that file.
  • System.IO.Path.GetTempPath Returns the path of the current user’s temporary folder ending with a backslash.

I was working on a service recently that’s going to be creating / deleting lots of temp files, and I thought it would be helpful to move them to their own folder. Some of the projects I’ve worked on have used this technique, so I pulled one up to see how it was implemented. I was surprised to find code like:

Which works, but there’s no guarantee that the file created in the parent folder will still be unique in the child. I’m a pessimist, and I wanted something better. I started thinking there should be a SetTempPath method to changes where GetTempFileName creates it’s files. But SetTempPath doesn’t exist. Oh wait, yes it does! But the secret is hidden in the documentation details of GetTempPath

This method checks for the existence of environment variables in the following order and uses the first path found:

  1. The path specified by the TMP environment variable.
  2. The path specified by the TEMP environment variable.
  3. The path specified by the USERPROFILE environment variable.
  4. The Windows directory.

Reading this, If I change where TMP points to, I change where GetTempFileName creates files. And that’s easy enough:

I added these lines of code to the entry point of my service, and GetTempFileName now puts my temp files exactly where they need to go. Specifying EnvironmentVariableTarget.Process ensures I’m not changing the behavior of any other application.

Detecting errors in a custom ConfigurationSection

The service I am currently writing has some complex configuration settings. I’ve created custom ConfigurationSections to handle validation. My goal is to validate the entire configuration at startup. In the process I’ve observed some interesting behaviors about ConfigurationSection’s.

To illustrate, I begin with the definition of a simple configuration section:

And a program to load/access it:

Running the program with the following configuration:

Produces:

Since the section isn’t defined, the expected outcome is that it is not loaded. But now it starts getting interesting because this configuration:

Produces:

Even though there is no <mySection> tag in the configuration file, a section is created using all the default values. Further, those values are validated as evidenced by the “Checking value ‘chicago'” reported by the CallbackValidator.

Produces:

Here all the default values were again loaded as reported by the CallbackValidator. Then the section was checked for required values. Since none were supplied, the expected exception was raised and then trapped by line 35 of the program. This configuration:

Produces:

With a fully valid configuration, it’s plain that both default values and supplied values are validated as the section gets loaded. Also note that when the bears property is read, the validation method is not called a third time.

Now the really confusing bit. This Configuration:

Produces:

Despite there being an invalid value ‘panda’ in the configuration file, the section loaded successfully. In contrast to the missing required value error above, no exceptions were during the load even though “Raising No Panda’s Allowed” indicates that the throw line did execute. Only later when the property is accessed does the exception get raised, but where did that exception come from if the callback was not executed again? One last configuration to examine. This configuration:

Produces:

This illustrates that this strange behavior isn’t limited to the CallbackValidator. What’s happening here is that failures reported by ConfigurationValidators are trapped by the framework, They get added to a collection found at section.ElementInfo.Errors. Looking at the documentation of ElementInfo another useful property is IsPresent which provides a nice way to tell if the tag existed in the file or if it was created on the fly.

And my updated program to detect error conditions before trying to use attributes:

I can’t explain the quirks in the validation process, but hopefully I’ve provided a reasonable workaround.

iPad AirPrint using Ubuntu server and a network printer

Like a lot of other folks, I recently updated my iPad to iOS 4.2.1 and began looking to see what worked and what didn’t. After getting over the mute switch, I wanted to try AirPrint. I don’t know how much I’ll ever use this feature but it bugs me that support is limited to so few printers. I have an HP OfficeJet Pro L7680 All in One. I loathe this printer, and don’t recommend buying one but it’s the printer I own. Anyway I thought maybe if I could find enough information on the Internet I could configure my Linux VM to serve up my “incompatible” printer.

Most of what follows is based on a blog entry from Ryan Finne with added help from a blog entry by tjfontaine. I won’t repeat their great work here. Instead, I hope to add more of the noob perspective since I didn’t even know what CUPS was until I began this quest.

My Linux VM is a minimal install of Ubuntu 10.04 server with samba, vsftpd, and nfs. I use it primarily to share a big USB drive to the Windows boxes in my home and also to the ESXi server hosting it. My VM is named allspice. However, I do not run a local DNS so everything was done using it’s static IP address of 192.168.8.199. Your mileage may vary.

Step 1 was to get the files necessary to support printing from the VM:

This got me the CUPS files, the PDF filter, and the support files for my HP printer. With no GUI on the server, the next step was to gain access to the CUPS web interface from another box. I had to modify 0/etc/cups/cupsd.conf because the default file only allows localhost access. Below is a summary of my changes:

CUPS Server SettingsAfter restarting CUPS, I could browse https://192.168.8.199:631 and see the web interface. There I changed the basic settings on the configuration tab as noted. Once the server restarted and the page refreshed, I clicked the Find New Printers button. My network printer was located and included in the list of printers to add. In my case my printer model showed up twice in the list. Both entries appeared identical HP HP Officejet Pro L7600 (Officejet Pro L7600 [9CD796]) however viewing the page source revealed that one had a URI of:

while the other had a URI of:

I chose the one ending in _printer._tcp.local. I named it HPL7680, and chose the appropriate driver from the offered list. The last thing I did was to print a test page and verify that the VM was capable of printing.

Next I jumped in head first and followed my source’s instructions only to get nowhere fast. Something was missing. After a half a day of no-progress I slept on it, and woke up with a fresh idea. I have one other Linux box, an Asus EEE netbook which also is running Ubuntu. I pulled that out and sat down to try and print Ubuntu to Ubuntu. Once I fed it (just) the address of the print server, the netbook detected my printer at ipp://192.168.8.199:631/printers/HPL7680 and I was able to print a test page.

Now I knew my print server was serving up my configured printer to my network. But the iPad still wouldn’t display it. The problem had to lie in the advahi configuration. I re-ran tjfontaine’s script and had a look at the file it generated:

Using the default options, the file it created contained adminurl=ipp://localhost:631/printers/HPL7680 which obviously won’t work remotely. I manually changed this to ipp://192.168.8.199:631/printers/HPL7680 and restarted the avahi-daemon.

My netbook could see AirPlay HPL7680 @ allspice but not my iPad. I tried configuring the printer on the netbook using the AirPlay configuration. Still no test page was printed. Browsing the CUPS error_log revealed this line:

After I changed the line <txt-record>rp=/printers/HPL7680</txt-record>
to remove the leading ‘/’. I restarted the avahi-daemon and finally my iPad could see and more importantly print to the printer.

Stoopit Code, Stoopit Space, Stoopit Comment

I was in the middle of updating an 830 line function in my favorite web application when I came across a single line of code that gave me pause:

As much as I am a proponent of commenting, sometimes people just don’t get the purpose behind them. I don’t know who wrote this. But sitting here 5-10 years later I have to wonder exactly what they were thinking when this line was keyed in. The comment, at first glance appears incorrect. A character in c++ is written with single quotes. So _T(‘ ‘) if you include the macro for UNICODE.  This is not a Space character. This is a zero terminated string containing a single space.

Names are important and strSpace is pretty specific. It’s not strTemp or strToBeAnnounced. Seeing strSpace sets the mind to thinking “this thing holds a space and probably won’t change”.  Why bother? What use can there be in declaring strSpace?

For methods taking a constant reference:

_T(“”) can be swapped in in for the tiniest of performance hits.

For methods that take a non-constant reference:

Here passing _T(“”) wrapped inside a variable might be required but calling it strSpace is a lie if it is eventually to be changed to some other value.

So neither is a very valid reason for the declaration.  I thought about it some more.  One other reason for declaring fixed values is to guard against change.  Under what circumstances would strSpace or _T(” “) need to be changed to a different value? What possible change was the original developer guarding against by declaring strSpace?

To answer that I needed to examine the context in which it was used.  Unfortunately there is no context. The only place strSpace is used in that 830 line method is right there in the variable declaration.

Which in a crazy stupid way validates the comment. It is indeed just Space.

(Sort of like this blog)

A Rain of Arrows

Today I spent some time creating new arrow images for a web application I’m maintaining. For a while now I’ve been toying off and on with a freeware vector graphics program called Inkscape. This gave me a chance to do something real.

Not known for my artistic talent, I glued a triangle and a square together pulled on some corners and quickly came up with:

left.png and up.png which isn’t too bad for 10 minutes work.

But I wasn’t all that sure blue was the right color choice. So I created a new gradient and a couple more exports led to:

right.png anddown.png Looking better.

In the process I learned how to export all four images with one button click.

export.png

The important thing is to select and export each object individually to a unique file name. Inkscape will remember this and use it for the bulk export. Yet another gradient / export iteration and

left.png up.png right.png down.png

And then I really went overboard.

Now to decide what ones to use. Next thing I want to learn is how to apply a stroke to a segment of a path so I can outline the tabs