Cyrus “Glitch” Spencer dancing to a dubstep mix of “Feel so Close” at the Speck booth.

This was pretty awesome.

This was one of the most impressive tech demos I saw at CES, for several reasons:

  • the side by side comparison clearly showed the benefits compared to other image stabilization systems
  • there’s no trickery here — the video cameras are actually being shaken and filming us, showing the results live
  • there’s a tangible benefit on display that anyone who’s done video will understand and appreciate

I know nothing about this this thing, except what it says in the name. But hey, it’s a robot. Robots are cool. Especially when they do something useful.

I went to CES for the first time this year with the Stremor crew, so we could show off our handiwork at ShowStoppers. I got a chance to get out to the show floor and shoot a few videos.

Here’s the first one: a brief tour of Sennheiser’s booth where I show the general layout and their featured headphones.

Enjoy, and watch this space for more.

I’ve been selling used stuff on Amazon.com off and on for well over three years now — mostly used video games, movies, accessories and such. Despite fairly hefty seller fees, it’s been a lot better than the other alternatives for me. Compared to eBay, the listing process is dramatically faster and simpler, sales prices are often higher, and items stay listed (at fixed prices) until sold. Compared to craigslist, Amazon.com gets you a much wider market (helpful for obscure games & accessories), and a simpler sales process. (coordinating a meeting time just to sell a $15 game? No thanks.)

So over the weekend I was cleaning out my office and listing some old games and controllers. Then I thought about this Lenovo ThinkPad X220 I’ve been trying to sell for months. There was a listing on Amazon.com for the X220 with a couple of other used listings, so I thought it wouldn’t hurt to give it a shot. I listed it Sunday night for $725.

That ThinkPad listing must have triggered an automated account check (due to the dollar amount, no doubt) that the last 3+ years of listings did not. Hours later, close to midnight, I got this cordial email from Amazon.com (emphasis mine):

Hello from Amazon.

We are writing to let you know that we have removed your selling privileges, canceled your listings, and placed a temporary hold on any funds in your seller account.

We took this action because our records indicate that this account is related to another selling account that was closed by Amazon. Once selling privileges have been removed, sellers are not allowed to establish new accounts.

Due to the proprietary nature of our business, we do not provide detailed information on how we determine that accounts are related.

We encourage you to take appropriate steps to resolve any pending orders. Note that any amounts paid as a result of A-to-z Guarantee claims and chargebacks may be deducted from your seller account.

After 90 days, any remaining funds will be available per your settlement schedule. Once the hold has been removed, balance and settlement information will be available in the “Payments” section of your seller account. If you have questions about these funds, please write to payments-funds@amazon.com.

While we appreciate your interest in selling on Amazon.com, the closure of this account is a permanent action.

Regards,

Seller Performance Team
Amazon.com

http://www.amazon.com

The tone of the email didn’t give me a lot of hope. It’s clear that Amazon is not willing to provide details on how they made this determination, or leave an opportunity for appeal. And to be clear, I’m certain that I’ve tripped a false positive of some sort. I have never used another seller account on Amazon.com.

I logged into the seller account to see what it looked like. There was a glimmer of hope: an Appeal button. I dutifully filled out an appeal as follows:

I have never had another seller account with Amazon.com. I’ve been using this account to sell stuff off and on for over three years now, without any issues. I can only assume that this was due to an automated false positive. Please review and reinstate my account.

Amazon replied less than twelve hours later with this:

Hello from Amazon.

Thank you for writing.  After a review of your account by an account specialist, we have decided not to reinstate your selling privileges.

We regret we are unable to provide further information on this situation. Further correspondence regarding the closure of your selling account may not be answered.

The closure of this account is a permanent action. Any subsequent accounts that are opened will be closed as well.

Regards,

Seller Performance Team
Amazon.com
http://www.amazon.com

So that’s that, it seems. It’s clear from the tone of these emails they are not especially sympathetic to the concerns of sellers whose accounts have been mistakenly flagged.

eBay & Paypal have received a lot of well-deserved flak over the years, but compared to this, they come out looking good. They have email addresses and online chat systems and phone numbers answered by actual humans who provide actual details about your case. In many of the Paypal horror stories that circulate, the worst material comes from bad customer service reps. But when you deal with Amazon.com, at least as a seller, there’s no customer service rep to talk to. Cold emails like this are all you get.

I hope this will be helpful to two groups of people:

1. Sellers — look for other alternatives. If you sell on Amazon.com, don’t put all of your eggs in that basket. For me, this just meant a harder time clearing out the closet. But for someone doing a lot of sales on Amazon.com, this could cause a serious loss of business.

2. Amazon.com staff — seriously, just look at this from the customer’s point of view, and try to tell me this is a customer friendly process. More transparency is in order. Your secret fraud detection system is fallible, and it should be treated as such.

If nothing else, this has left me seriously second-guessing my loyalty to Amazon.com. They’ve been far and away my favorite Internet retailer for years, but I’m not going to be quite as eager to shop there any more, especially in categories with strong competition.

Update

Amazon just reactivated my account at 12:15 pm today (AZ time). I did not make any further attempts to contact Amazon after the above account, so I imagine that this was only done as a result of my post hitting the front page of Hacker News. The email regarding the reactivation was as follows:

Hello from Amazon.com.

Thank you for writing regarding your Amazon.com selling account. We have reviewed this situation and have reactivated your account.

We apologize for any inconvenience this has caused. In our efforts to protect our community, we sometimes err on the side of caution.

We appreciate your interest and wish you the best of luck selling on Amazon.com.

Victory? Well, partially. I’m not totally satisfied until and unless Amazon admits to problems with their fraud detection system, and puts in place a better process for recourse. Failing that, others who don’t get this level of publicity will continue to get shafted.

Update 2

Here’s my blog’s visitor count by service provider, per Google Analytics. Looks like a few people at Amazon have taken notice.

I’ve spent the better part of the last six months doing front-end development on a Java project developed with the Spring framework. We’re currently going through the process of internationalizing the application. This necessitated spending a fair amount of time combing through all the raw English strings in templates and replacing them with Spring directives, to be filled in by the .properties file for the user’s locale.

While there is a lot more to internationalization than replacing static text strings, it’s the first (and perhaps largest) task to tackle. Here’s what that process looks like.

Let’s start with a simple template like this:

<ul>
    <li><a href="${welcomeurl}">Welcome</a></li>
    <li><a href="${registerurl}">Register</a></li>
    <li><a href="${contacturl}">Contact Us</a></li>
    <li><a href="${abouturl}">About</a></li>
</ul>

To internationalize it, you replace all of your raw text with spring:message directives as follows:

<ul>
    <li><a href="${welcomeurl}"><spring:message code="common_site_welcome"/></a></li>
    <li><a href="${registerurl}"><spring:message code="common_site_register"/></a></li>
    <li><a href="${contacturl}"><spring:message code="common_site_contact"/></a></li>
    <li><a href="${abouturl}"><spring:message code="common_site_about"/></a></li>
</ul>

Ugh, all of my readable text replaced by XML. OK then.

We’re not done yet; as mentioned, some .properties files need to be created to fill in the proper text strings. So for US English, you would create i18n/messages_en_US.properties as follows:

common_site_welcome=Welcome
common_site_register=Register
common_site_contactUs=Contact Us
common_site_about=About

and for Spanish, i18n/messages_es.properties as follows:

common_site_welcome=Bienvenido
common_site_register=Registro
common_site_contactUs=Contáctenos
common_site_about=Sobre

and if everything is configured correctly, you now have Spanish localization for those strings. Congratulations.

Enter Flask

That’s not where the story ends. This is a public-facing application, and that means there’s a marketing site to go with it. It’s currently just static html, so I thought it would be best to use a simple web framework for proper i18n support (among other things). I turned to my go-to micro-framework, Flask, and set up a small sample app to test out the i18n support.

Flask (along with Django and many other web frameworks) uses the standard GNU gettext API for i18n. Here’s how it works. We start out much the same as in the Spring example, except with Jinja2 templates and Flask’s url_for() function:

<ul>
    <li><a href="{{ url_for('welcome') }}">Welcome</a></li>
    <li><a href="{{ url_for('register') }}">Register</a></li>
    <li><a href="{{ url_for('contact') }}">Contact Us</a></li>
    <li><a href="{{ url_for('about') }}">About</a></li>
</ul>

now to internationalize that template, we just do this:

<ul>
	<li><a href="{{ url_for('welcome') }}">{{ _('Welcome') }}</a></li>
	<li><a href="{{ url_for('register') }}">{{ _('Register') }}</a></li>
	<li><a href="{{ url_for('contact') }}">{{ _('Contact Us') }}</a></li>
	<li><a href="{{ url_for('about') }}">{{ _('About') }}</a></li>
</ul>

Very cool. I just wrap all strings with a short function (_() is the common alias for gettext()) and they’re ready for localization.

Now what about messages? For that, we’ll turn to the Flask-Babel extension. After a short config file, we can do this to extract all i18n strings:

$ pybabel extract -F babel.cfg -o messages.pot .

That will give us a file with all the extracted strings from our Jinja2 template, along with some header info. What’s interesting here is the extra metadata you get with each string:

#: templates/index.html:8
msgid "Welcome"
msgstr ""

#: templates/index.html:9
msgid "Register"
msgstr ""

To generate a message file from messages.pot for a given language (Spanish again in this example), follow with this:

$ pybabel init -i messages.pot -d translations -l es

The resulting file looks much the same as messages.pot. This is the file to send off to the translator.

Taking stock of the two approaches

I see a number of benefits to the approach employed by Flask (and by extension, other frameworks that use gettext tools):

  1. Templates preserve the original English — that makes them easier to convert, more readable, and more searchable.
  2. The Flask approach adds 11 total characters to internationalize a string; Spring adds 25 (and that assumes the variable is the same length as the original English. In a larger project the tendency will be to make it longer for pseudo-namespacing as in the example.)
  3. Spring requires the programmer to define variables for every piece of static text, and manually add them to a properties file. Flask extracts strings with a single command.
  4. Flask’s messages.po files include the file & line number the string came from, as well as the original (English) string. The .properties files in Spring just have a variable name.
  5. In Flask, added and changed strings can be extracted by running a pybabel update command. This will add the new strings to all translations, and mark changed text as “fuzzy”. In Spring, you have to manage additions and changes across all files by hand.

I’m not able to come up with much in favor of the Spring approach honestly. The gettext method seems a lot easier and more maintainable, especially as the size of the project and number of supported languages increases.

Google drops H.264 support in Chrome

Plenty of tech pundits have given their two cents on Google’s turn toward WebM exclusivity, and the vibe is decidedly negative. On the other hand, the move has garnered strong support from Mozilla and Opera, and not surprisingly, the Free Software Foundation.

My take on this is somewhat conflicted. Gruber has a point that content providers will continue to use H.264, and just use Flash for clients that don’t serve it directly. At least, in the short term. On the desktop, however, WebM is now poised to take a decided market share lead. Firefox (in 4.0 beta), Chrome and Opera are all shipping with WebM (and that exclusively); while only Safari and IE remain in the H.264 camp. IE alone could tip the scales in favor of H.264, but support is only coming in version 9 (still in beta). Considering the glacial pace of user adoption for new versions of IE, I’m betting that’s at least two years out.

There will be plenty of time for WebM to gain traction, and with Adobe soon adding WebM support to Flash, the tables could turn one day — clients not supporting WebM may default to Flash on many sites. Firefox (and likely now Google) have taken a stand against ever supporting H.264, but the opposite is not true for Apple and Microsoft — if WebM gains enough momentum, it’s likely that they (especially Apple) will add WebM support .

The mobile picture is murkier. H.264 has more of a stronghold there, due to Apple’s strong position, and the importance of hardware decoder support. Even there, word is that WebM hardware support is coming on many chipsets this year. Within the next year or two, it may be commonplace for chipsets to support both formats out of the box.

On the other hand: critics have a valid point that Google’s ideological justification for this move (“hooray for open”) rings hollow, considering Google’s recent embrace of Flash. It would be one thing if Google merely tolerated Flash due to its ubiquitous use on the web, but there’s more to it than that. Does no one remember Google I/O? Google was practically gloating about Flash support on Android, and Flash support on mobile certainly isn’t the sort of obligation that it’s become on the desktop. In fact, many people (myself included) would prefer that mobile platforms remain Flash-free. Not only that, they also announced support for Adobe AIR on Android, trumpeting both with big shiny icons (Flash more than once). And for good measure, they invited Adobe CEO Shantanu Narayen (among others) on stage. This is far more than toleration–Google has embraced Flash as a competitive advantage against Apple. Open, schmopen; we’ve got it and they don’t. That was Google, circa Google I/O 2010. It’s doubtful that this move means they’ll treat Flash with any less deference.

HTML5 now just “HTML”

HTML5 is now a misnomer — the WHATWG, the standards body charged with defining this stuff, has decided to turn HTML into a rolling standard. There will be no HTML5.1, HTML6, or what have you. Just continuous revisions of HTML. Oddly this comes just a day after the W3C unveiled their shiny new HTML5 logo too.

This is a nice development, if only because HTML5 has become an extremely overloaded buzzword. When people say that, they could mean any number of things. Often it just means “dynamic, JavaScript-driven site.” It usually doesn’t mean new semantic markup elements, Web Workers, or Web Storage — all genuine constituents of the standard formerly known as HTML5. Assuming people get the message, this hopefully compel them to use more accurate terminology.

I’m not so optimistic about recruiters and their ilk, though. Expect to see job ads erroneously demanding HTML5 skills for some time — probably until another buzzword is found to take its place.

Living the dream

After a few short months of doing freelance web development, I have decided to make this a full-time gig. I am quitting my day job as a Desktop Support technician.

I have a few established clients already, some good leads, and some avenues in mind for self-promotion and more work. My ability to pursue leads for more work is severely constrained when this is an after-hours pursuit, not to mention my ability to devote full effort to projects for established clients. The pay is better, and the work more fulfilling. The time is right.

I want to thank my first few clients who have put tremendous faith in me, despite an established track record. I want to especially thank Jared at Pristine Auction, who gave me the confidence to brush off my inhibitions and pursue freelancing. It’s worked out better than I could have imagined.

Let’s say you’re hashing out a Python model class (Django, TurboGears, anything — doesn’t matter). Following the Skinny Controller, Fat Model approach, you want to add some logic and convenience methods to the model, rather than stuffing them into the one or more controllers.

Here’s a basic example using the SQLAlchemy ORM:

class Product(Base):
    __tablename__ = TABLE
    id = Column(Integer, primary_key=True)
    title = Column(TITLE_FIELD, String)
    description = Column(DESC_FIELD, String)

    def get_link(self, link=ITEM_LINK):
        return link % self.id

The get_link() method calls a predefined string, and uses string formatting to insert the class variable id. You might think you could directly define this with a variable, rather than a method. Go ahead, give it a try. But because it calls another (not yet defined) class variable, that simply won’t work. That’s just a fundamental reality of object-oriented code, at least in the Python world.

So we end up with an object that works as follows, assuming item is an instance of Product:

item.title
item.description
item.get_link()

That last line just doesn’t feel right, does it? It ought to be accessible through an attribute, rather than a method — as with the title and description. After all, we are talking about a noun here, not a verb. This works, but it’s inconsistent and inelegant.

Thanks to some perusal of Django models, I found the perfect solution in Python’s built-in property() method.

We can modify the class slightly as follows:

class Product(Base):
    __tablename__ = TABLE
    id = Column(Integer, primary_key=True)
    title = Column(TITLE_FIELD, String)
    description = Column(DESC_FIELD, String)

    def _get_link(self, link=ITEM_LINK):
        return link % self.id
    link = property(_get_link)

And with that simple modification, our item instance works as follows:

item.title
item.description
item.link

There, doesn’t that feel better?

For much more on property(), including how to use for getter and setter methods, and lots of other useful info, see this excellent post courtesy of Adam Gomaa.

Hacker News has become my go-to source for interesting tech news. It surfaces a much wider variety of interesting content than Techmeme, with a focus on programming-related content. The community is intelligent too, and comment threads are remarkably free of trolling.

I noticed a couple of good blog posts that hit the front page by one Eric Harrison. Perusing his blog, I was struck by how open he was to helping and corresponding with fellow programmers. Exhibit A: his mentorship program, whereby he’s offering to take a new programmer or two under his wing and show them the ropes. I’m probably not in the best position to submit myself for that, but another link caught my eye: Ask Me Anything, right in the sidebar. I was under the (mistaken) impression from his PHP post that he was a freelancer, so I submitted an anonymous post asking how to get started.

The form directed to a virtual black hole. Did it get through? Would I get an answer, and if so, where? I was very happy to see a response… and a very thorough one, at that!

A lot of the tips he offers are going to be really tough to execute well, especially given my current time constraints. But I like this one in particular:

Bonus tip: Make friends with small design shops. I’m good friends with Jake Stutzman over at Elevate. He’s primary a designer, but often has clients who need to have designs and development. Being friends with him (and making sure that all the work I produce makes HIM look good) has the potential to land me as much freelance work as I could ever hope for. This sort of interaction between you (the developer) and other shops (designers, etc) is crucial to building a successful freelance business. If you have clients that want design work to go with your development, pass that business along to your designers. This way, everyone wins.

Read the rest here.

There’s a whole cluster of good tech & design firms in the area, the most visible of which are the folks associated with Gangplank. The only reason I haven’t made inroads already is my own introversion and lack of initiative.

But now is as good a time to start as any. Any designers that need coding work? I’m a coder that needs design work. I’m affordable. Let’s talk.

« Older entries