[This episode is sponsored by Frontend Masters. They have a terrific lineup of live courses you can attend either online or in person. They also have a terrific backlog of courses you can watch including JavaScript the Good Parts, Build Web Applications with Node.js, AngularJS In-Depth, and Advanced JavaScript. You can go check them out at FrontEndMasters.com.]
[This episode is sponsored by Hired.com. Every week on Hired, they run an auction where over a thousand tech companies in San Francisco, New York, and L.A. bid on JavaScript developers, providing them with salary and equity upfront. The average JavaScript developer gets an average of 5 to 15 introductory offers and an average salary of $130,000 a year. Users can either accept an offer and go right into interviewing with the company or deny them without any continuing obligations. It’s totally free for users. And when you’re hired, they give you a $2,000 bonus as a thank you for using them. But if you use the JavaScript Jabber link, you’ll get a $4,000 bonus instead. Finally, if you’re not looking for a job but know someone who is, you can refer them to Hired and get a $1,337 bonus if they accept the job. Go sign up at Hired.com/JavaScriptJabber.]
[This episode is sponsored by DigitalOcean. DigitalOcean is the provider I use to host all of my creations. All the shows are hosted there along with any other projects I come up with. Their user interface is simple and easy to use. Their support is excellent and their VPS’s are backed on Solid State Drives and are fast and responsive. Check them out at DigitalOcean.com. If you use the code JavaScriptJabber, you’ll get a $10 credit.]
[This episode is brought to you by Braintree. If you're a developer or a manager of a mobile app and searching for the right payments API, check out Braintree. Braintree's new v.zero SDK makes it easy to support multiple payment types with one simple integration. To learn more and to try out their sandbox, go to BraintreePayments.com/JavaScriptJabber.]
CHUCK:
Hey everybody and welcome to episode 191 of the JavaScript Jabber Show. This week on our panel we have Aimee Knight.
AIMEE:
Hello.
CHUCK:
AJ O'Neal.
AJ:
Yo, yo, yo, coming at you live from Portland.
CHUCK:
Joe Eames.
JOE:
Hey, everybody.
CHUCK:
I'm Charles Max Wood from DevChat.TV. Quick shout out to JSRemoteConf.com. Go check it out. We're going to do an online conference in January. And some of these people are talking. We have a special guest this week and that is Craig McKeachie.
CRAIG:
Hi, everyone.
CHUCK:
Do you want to introduce yourself? You haven't been on the show for a while.
CRAIG:
Yeah. I have been on the show one time before. But you know, so I feel honored to be a repeat guest here. But my name's Craig McKeachie, developer mostly focusing on training recently. And I was on the show before because I wrote the JavaScript Framework Guide book. So, people might know me for that. I blog at FunnyAnt.com. And that's about all.
CHUCK:
Alright. Well, we brought you on today to talk about Stripe. What makes you a Stripe genius?
CRAIG:
[Laughs] Some years ago, if you want to know the truth on this, I was getting into entrepreneurship. I'm sure Chuck, you can relate since you're on Entreprogrammers podcast. And I needed to hook up payments for a site that I have that, long story short, I'm not even going to say the URL unless you want me to...
CHUCK:
Go ahead.
CRAIG:
That does scavenger hunts for parents. So, it creates an online printable scavenger hunt out of riddles for people. So, I need to accept payments. So, I kind of got into it back then. And ever since then, just been using it for different projects and sites and so forth. And most recently I worked on a course for Pluralsight on the topic. So, spent quite a bit of time digging into some of the parts like recurring payments and so forth that I hadn't looked at before.
CHUCK:
Very cool. I was actually up at Pluralsight's headquarters, I guess you would call it, a few months ago. Kind of a fun office.
JOE:
Yeah.
CHUCK:
So, what's the story with Stripe then? I use Stripe for my stuff. I guess where do we start with Stripe?
CRAIG:
Yeah, that's a good question. So, in your case Chuck, maybe tell us about your use. I would be curious to know what brought you using it.
CHUCK:
Well, there are a couple of things. First off, I started taking donations for the podcasts way back when. I also wound up pulling together some online forums for the different shows. And so, I started taking subscription payments. I have a subscription video series that I have kind of neglected on Ruby on Rails called RailsClips. And that also works through Stripe. And then the online conferences are also paid for through Stripe.
CRAIG:
So, you've got quite a few things going on.
CHUCK:
Yeah, I'm a fan. I like getting paid.
CRAIG:
Yeah. [Laughs] Who doesn't? Who doesn't? I think for me...
JOE:
I don't.
CRAIG:
For me, it was the ease of use about the whole thing.
CHUCK:
Yeah.
CRAIG:
[Chuckles] It really felt like... it's very developer-friendly, I think, particularly if you're in the JavaScript community, as us being on the show, we are, right? It's a very friendly to the JavaScript developer payment solution, I think.
AJ:
And I agree with that. I have used Stripe for payments on my little DJ business. And I think... no, I always take PayPal or check first for programming stuff. But yeah, it's been a pleasure to set up and easy to work with and really, I've enjoyed. It's very customizable, whether you want to use the Stripe frontend or your own frontend. I've really enjoyed it.
CHUCK:
One thing with Stripe that I found speaking of how easy it is, is that it is really simple depending on what you're doing with it. So, setting up the recurring billing and stuff, that was pretty easy. Taking one-time payments was really easy. But if you're taking one-time payments and you're accepting coupons, you have to actually build that yourself even though they accept coupons on the subscriptions. I thought that was interesting.
CRAIG:
Right. That is. And I remember running across that. Why would you need to build a custom form is what you mean, right?
CHUCK:
Yes.
CRAIG:
So, maybe we should take a few steps back. But yeah, if you have to build a... you can use their embedded form which is like the MailChimp experience where you just drop a snippet of code into a page and all of a sudden you've got a sign up form or whatever. Sort of embed solution. But then, and you can customize that to a certain extent but as soon as you need coupons, there's some other use cases that come up pretty quickly like A/B testing and stuff like that. That's when you need to roll your own form. But you get a lot of granular control when you do that. You get a lot nicer chance to do some validations and so forth with custom messages, that sort of stuff, when you roll your own form.
CHUCK:
Yeah, the other thing is that if you want to just get started, you can actually embed the Stripe JavaScript in to your page. And if you're just taking straight up payments and you're not doing anything fancy, you can just use their Stripe, I forget what it is, Stripe Checkout I think it's called? And it just pops up a little payment form and they enter their stuff and it just works. And you don't actually have to build out a custom form at all.
CRAIG:
Right, and then...
AJ:
Yeah, [if you're a pansy]. Just kidding. [Laughter]
CHUCK:
Well, sometimes especially in business as an entrepreneur, that's one less thing I have to do. Now in my case, I actually...
AJ:
And it's consistent.
CHUCK:
Yes.
AJ:
People trust consistency.
CHUCK:
You know, so in my case when I was accepting coupons, yeah I couldn't do that. But in some of the other ones, it's like they click the button, they enter their credit card, done.
CRAIG:
Right. You just include a little bit of code and it's hooked up for you. Just to go in a little bit more detail about that because we're kind of... it sounds like a lot of us have had a direct experience with it but I think we're skipping through some of the, “What's going on?” Yeah, there's a checkout.js script which basically gives you an embedded form and you put a little bit of HTML snippet in there plus that checkout.js script. And it'll give you a button and when you click the button it gives you a modal checkout screen with validation and everything built in from scratch. The other possibility is to use Stripe.js. In that case you need to build the form up by yourself. But then you get that finegrained control of the form. And you have to do a little bit more JavaScript code. It's very, even if you're just familiar with jQuery it'll feel very comfortable to you, I think. And then you can use it.
CHUCK:
Yeah.
AIMEE:
Can you actually talk about how the Stripe API works behind the scenes with that?
CRAIG:
Yeah. I think having a high-level picture of how Stripe works helps a lot. So, there's... if you don't understand this then sometimes when you're looking at Stripe in terms of, “Is it a JavaScript library? Is it a server-side API? Is it this thing? How do I actually charge the card securely?” it's kind of funny unless you have this big picture. So, let me try to take a shot at that. So, you've really got three computers or three groups of computers communicating in Stripe's architecture, like a client desktop computer running a web browser, your application's web server and a server that hosts Stripe's RESTful API, or servers in that case. Because obviously it's going to be, you know, I'm sure their API isn't on one server. But let's just think about it as sort of three boxes for right now.
So, working with Stripe involves using either of its two client-side libraries like we talked about, checkout.js or Stripe.js, to post credit card information like a credit card number, expiration, and CVC code, directly to Stripe's API without it ever hitting your servers. And that's the key, their innovation I think in this space. So, there are some other services that are copying this now and doing the same thing because it's... I think it was a very clever use of web standards. But they basically never send the credit card information to your web server. They just send it to their API server. And then they give back a single-use token that represents the card. Then your browser posts the single use token but not the credit card information to your web server. And then your web server once you're up running code in say Ruby or C# or Python, whatever your preferred language is...
AJ:
Or JavaScript.
CRAIG:
This is JavaScript Jabber. I should probably say Node, right? It could be in Node up there.
[Chuckles] You caught me there. I was like saying it then I was like, “Oh, did I just say that on JavaScript Jabber?”
CHUCK:
[Laughs]
CRAIG:
So, you're up on the web server. And you're obviously writing in Node, right? And you can communicate from your web server to Stripe's API and you send it that token that you have. And it's sort of your ticket to get into the concert. You can say, “Hey, I've got a token. I can get in now and I can charge this card.” And the token basically represents the credit card. And so, then you could actually make a charge but you're up in your server on a secure place where all your secrets are safe, hopefully. And then Stripe responds back and then you send a response back from your web server back to the client. So, it's like two computers end up communicating. Both the clientside browser gets you the token then it goes up to your... the token gets posted up to your server then you communicate with Stripe's API, and then it comes back.
The nice thing about the Stripe API, it's all JSON, RESTful, exactly what you'd expect. They do a great job versioning the API as they've evolved it over time and have just a really nice interface. I believe it's written in Backbone, I've heard before, their dashboard interface that people are familiar with as well. So, they were way ahead of the curve in terms of knowing that JavaScript is going to be the way and so forth.
CHUCK:
Yeah. I just want to reiterate the one thing besides that it just works and it's simple that is the most important thing to me, that you talked about. And that is that the credit card information never actually goes on my server. I recognize we have an international audience. But what that essentially means is that yes, I am mindful of security on my servers but I am not then liable for the credit card information because it never hits my server. And in the US, there are specific regulations that have been put in place that make you liable or you have to meet certain standards in order to collect that credit card information. And so, the fact that I don't have to go hire an expert to help me do that, the fact that I can just collect payments and not worry about that kind of thing on my server and that kind of thing in my business, is a major thing for me.
CRAIG:
Yeah, and you just made the argument for me. I'm glad you said that. But it's basically the laws are PCI Compliance...
CHUCK:
Yes.
CRAIG:
If people have heard of them before. They're the payment card industry data security standard, right? And I found... you know, I was digging around trying to find more information when I was doing the course. And some of the most interesting things I found was that there was some numbers [that were] about cost per [inaudible] on the low end for a PCI Compliance audit. So, in order for you to be compliant with PCI, these are the costs for you to hire a consultant to help you through the PCI compliance process. And at the low end it was 20 to 30 thousand dollars a year. Average was $225,000 a year. And then the top 10%, I'm assuming larger business, it was over a half a million dollars to maintain PCI compliance. So, a lot of people talk about Stripe's fees. It's pretty normal, like PayPal or whatever, 2.9%. But compared to some of those numbers, it seems like quite a bargain for not having to deal with that to me.
AJ:
Yeah. We just did an episode on HIPPA and touched on PCI Compliance on Web Security
Warriors. So, if anybody is interested in that, I'll link to that. But I, as part of Daplie, we are trying to... we kind of want the idea of secure by default, not kind of... we absolutely want the idea of secure by default. And so, we've been looking into that. And there are a lot of subtle things that you have to do. A lot of it's pretty simple, like have HTTPS, duh. But there are some stuff that's more subtle like how you handle logs, how you make sure that when an exception is thrown, the errors don't leak information, like a form POST data could not be exposed during an error exception, like auditing what users have done, which actions. There's a lot stuff that goes into that. And it definitely is really valuable to have something so simple as Stripe where I just don't feel the pain.
CRAIG:
Yeah. And there's a... I'll include it for you guys in the show notes, you may have even seen this when you were researching yourself, but there's a really great resource. It's kind of like a dark art, this whole PCI Compliance thing and what you have to do. But there's one guy that had a business CashStar online. His name's Ken Cochrane. And he posted on his blog. He basically didn't have the funds to hire the consultants to come in and do PCI Compliance. So, he had to read through all the papers and figure out “What does this really mean? What do I actually need to do?” And he documented it pretty well on his blog. So, I've thrown the link out there. It'd definitely worth reading. It goes over some of the details of “What do I actually need to do? I need to do penetration testing. I need to make sure to take care of these logs,” like you said. That kind of stuff. So, I found it very enlightening.
AIMEE:
So, one thing we talked about before the call is what happens when things go wrong. So, I know I've played with Stripe a little bit on my own. But I have more experience with another provider. And one pain point we've had with this other provider is when something goes wrong, because they don't always have visibility into the issue, they will return a 200 with a 'success false'. [Chuckles]
AIMEE:
Which seems a little bit unintuitive. I know AJ has some additional thoughts on this. So, we can get AJ's thoughts. But then also, when he's done, how does Stripe handle things when it doesn't work as expected? When a lot of times, like users will have restrictions on their card because they're making an online purchase or something like that.
AJ:
So, and I'm interested to hear that, too. My experience was browsers don't handle error messages the same way. And when the Firefox phone came out, I was working on an auction site. And we were returning 400 and 500 level errors. And we didn't need it to work on the Firefox phone specifically. But I was testing it in different environments because I wanted to make sure that things worked and I was really excited about the Firefox phone at the time. And what I found was that I would not get error messages on the phone. And it really weirded me out and I spent hours trying to figure out what was going on. You know, that thing where, I don't know. It came down to actually just deleting a whole bunch of code and starting from scratch adding one line, adding one line, adding one line.
And it turned out that the Firefox phone at the time didn't handle 500 error messages. Like, it didn't allow a user to get them. And we've seen that in Chrome and in Firefox and Internet Explorer at varying degrees. But depending on whether it's a 400 or a 500 or if it's a 404, when you're using a web request, you don't always get back the information unless it's a 200. If it's a 200, it's going to work everywhere. And then you can check inside the message to see what the error is. Obviously you want something more descriptive than 'success false'. But that was the use case I saw for doing 200 OK as an error message. And I actually had some debate with other developers on the team about that. And because I was like, “Well, do we want to support just some clients that we're aware of or do we want to support all clients?”
CRAIG:
Right. To address the first question a little more directly, that's a good point. I think when things go wrong, the major thing I see with Stripe is just that it's a lot easier to set up a test environment and actually debug and test your code. So, you don't have to set up an entire infrastructure yourself in order to get a test environment going, right? Because a lot of these, what happens when things go wrong, it happens because you're afraid to fake charge a card or they don't have good support for that.
So for example, when you go into the Stripe dashboard there's a toggle switch which you could switch from test environment, like the whole entire interface, over to a test environment from a live environment. And then you're able to... and there's things in the interface like a common part of Stripe that we haven't really gotten to yet, is web hooks which are essentially user... I think we're all familiar with it but it's an event, a user-defined HTTP callback basically, events between websites. Well, these could be very tricky to figure out when you write an endpoint for that, whether that endpoint, whether all the paths in the code have been covered because you're kind of relying on the message being in a certain format to see whether errors happen.
I think besides having the test environment, once you're in the test environment in Stripe's dashboard you can do really useful things like send test responses for... basically trigger events manually that you want to happen. So, let's say there's a refund, a charge refunded, or a trial end that you want to test and see what a message would look like from Stripe, you could just click a button and say, “Yeah, send me a charge refunded or trial end event.” And you can send... and you could set it to a test endpoint including your localhost.
And I go over, in the course, it's a little bit too deep for this, but maybe you guys have probably run into this if you've worked with any sort of webhook API where you need some sort of... I used something called ngrok which is, it creates a tunnel, a public tunnel to your private localhost so that you can actually temporarily basically get the webhook event sent to you right to localhost code and then still debug through it. I don't know if that makes sense. But it's basically hard to debug something that doesn't have an interface and is not predictable. But if you use one of these tunnelers like ngrok, you can test your webhooks locally and step through the code and see what's going to happen when they send me this message asynchronously.
CHUCK:
Yeah, I've used Runscope to monitor my APIs. And it's pretty handy. It actually records it and then can play it back, kind of like what you were saying there.
CRAIG:
Yeah.
CHUCK:
Except it actually sits between Stripe and my production webhook. And that way if there's a bug in the production system, I could just play it back later.
CRAIG:
Yeah. And I use... they have a... Runscope has a free request bin. I'm sure a lot of people have used requestb.in, I think it is. So, I use that to show that the webhook was working in the first place in the course. And then when I needed to actually debug things and take it to that next level, that's when I brought in one of these tunneling solutions like ngrok. So, that's part of the answer. I kind of focused on webhooks there. But I think it's really just about being able to emulate a production environment safely so that you feel like you can test all the edge cases.
CHUCK:
Yeah. So, I have to say the webhooks were the hardest part for me in implementing Stripe. Hooking up the payment form, fine. But doing the rest of that work, just figuring out, because they have a couple dozen events that they can send to you. And most of the time you really only care about one or two of them. You know, the payment was declined or the payment was accepted. Even with subscriptions it's the same kind of thing, right? You're just looking for that payment and then you make requests to the Stripe API to get the rest of the information so that you can renew somebody's subscription. But setting that up so that it would capture that information and do the right thing with it... and I'm actually using queuing on the backend so it sets up a job and then runs it all asynchronously. Not in JavaScript, incidentally. I'm running it in Rails. But it's really handy that way. The problem was just figuring out what all of that looked like and being able to parse the information they send over.
CRAIG:
You know, I have some resources prepared that I was going to recommend for people who want to learn more about Stripe. But one of them is pretty relevant to what you were just talking about and that's the Pete Keen who wrote 'Mastering Modern Payments' which is a book basically just about using Stripe with Ruby, with Rails in particular. My course is more focused on, for .NET developers, ASP.NET. But he has an excellent free cheatsheet out on the web called 'The Stripe Event Cheatsheet'. If you just google 'Stripe event cheatsheet' you'll hit it as well. And it's just really good for saying, “Hey, if you're in this scenario, here's the five events that Stripe is going to fire to you when these things happen.” It's one of those pieces that kind of, Stripe's documentation is very good but it's just kind of missing this, this scenario-based look at what happens, when you're going to get certain events. So, I thought that was a great resource.
CHUCK:
That's really funny that you bring up Pete Keen, because I just got done talking to him an hour and a half ago for the Freelancers' Show.
CRAIG:
That is funny. [Chuckles] Yeah, he's moved onto doing a more how to run your business type stuff, right?
CHUCK:
Yeah, yeah. That's what we talked to him about over there.
CRAIG:
That's funny.
CHUCK:
So, let's just say that I want to take payments. I put the JavaScript on the page. I've set up the form and I get everything set up. And I have my webhooks set up so that when stuff happens I get notified and the right thing happens. What else do I have to know about in order to effectively use Stripe to run an online business?
CRAIG:
Well, I think one piece that we sort of lightly touched on was we need, you need probably some sort of, or you'll want some sort of server-side library to work with to actually make the charge when it hits your web server. So, you get your token back from Stripe's web API. It comes back to the browser in JavaScript. Then you POST that token up to the web server, to your web server. And it seems like Stripe is big in supporting Ruby. They also have Python, Java, and Node, Go, and iOS APIs. And basically what these are, are wrappers that let you actually call their charge API. But it takes care of some of the serialization and deserialization that goes on between you and their web APIs so that you're not just making raw HTTP requests and dealing with the input and output and so forth. So, they maintain a lot of these libraries. In the .NET space there's an open source one, stripe.net by Jayme Davis that I really like to use. But there is no official .NET library, but they do have Ruby ones, Python, Java, and so forth, as I mentioned before.
CHUCK:
So, if you bring up their documentation, not like the Getting Started Guide but the actual documentation for their API, you can select the language at the top and it'll actually show you how to make calls with their libraries for Ruby, Python, et cetera. So, I don't know if it defaults to Ruby or just remembers that that's usually where I'm living. But yeah, so all my code examples are in Ruby and if I wanted to switch to Node.js, all I'd have to do is click on JavaScript and it switches right over and gives me the code examples in there, in that language.
CRAIG:
Right. And then I also like the fact that they even show them with CURL. So, you could just curl their API, which is pretty common, but that's pretty... So, that's one piece...
AJ:
I love curl. [Inaudible]
CRAIG:
[Laughs] Makes me feel like there's no hidden sauce there, right? It's just, I can use this. The other thing, you mentioned what else are we missing, I think another piece is... so, if you're building that form custom, if you're not using say an embedded form, if you're building a custom version of it, the other thing I ran across that was really useful was the jQuery.payment plugin. And this is actually written by Stripe but it's an open source project. So, you could use it, whatever [payment] system you're using, I would take a look at this library.
You could tell that... basically what happened I think is they open sourced in their embedded form the form they just do for you. And they have all the validation built in and the credit card detection and all that logic that seems easy at first but the more you get into the edge cases with it and supporting lots of different credit cards and so forth, it's pretty complicated. They open sourced that part of checkout.js and made it into a jQuery plugin called jQuery.payment. And so, you could use it whatever payment solution. So, the kind of things it does is like input masks. So, you've entered a credit card on a site before and it gives you the spaces between the different parts of the credit card.
The part I really like is it does card detection of types. So, you can do neat things. Like if you've ever been on a site and you enter a credit card, that you can detect what type of card it is based on the first couple of digits. And then you can say, “Highlight that card on the page,” so that the user gets a good feeling that you recognize their card and what type of card it is, instead of having them pick the type. It does input masks for month and year. So you can, if you've ever used a checkout which I'm sure you probably have, where you have to choose from two drop-downs for the month and the year, this allows you to do one input box that's like, you type in 10/2015 or whatever. And it puts the slash in and just lets you tab through the interface and makes a great user experience. It's not security stuff but this is making a better user experience.
AJ:
So, there's also one called card.js. It's pretty slick, too. I want to see a link to the one that you just talked about so I can take a look at it.
CRAIG:
Yeah.
AJ:
But they're both pretty slick, sounds like.
CRAIG:
I feel like... I did look at card.js. I have no... it seems like it's been around a little bit longer. I do feel like... I'm guessing that the Stripe library has probably had more use cases hit it, if you know what I mean. [Laughs] Because it's out there as part of Stripe and it's a [inaudible] company.
AJ:
Sure.
CRAIG:
A lot people use it and so forth. So, that's what makes me, whether rational or not, feel good about that library in particular.
AJ:
Does there happen to be a demo page for it? I'm not seeing one here in the link.
CRAIG:
It's on the blog. So, if you just google jQuery.payment it will probably... so it's not part of their official documentation because, an open source project right? Just by Stripe. It was written by Alex MacCaw that you guys might be familiar with from... he wrote I think 'JavaScript Web Applications', the O'Reilly book. And he's done a few other very public things, I think.
AJ:
Okay. This makes it really clear the components, if you want to build your own Stripe-like interface. I think that both checkout.js and card.js have sweet user interfaces. And it looks like this jQuery.payment would help you build an interface that has all that functionality built in and let you style it as pretty as you want.
CRAIG:
Yeah. I'm looking here. I just took a look at card.js again. Yeah, but essentially they just extract it out of what checkout.js is, the user interface stuff, the validation logic, and just pulled it into a plugin basically.
AJ:
So, something just came to mind and I'd like to hear your thoughts on this. I noticed when I was working with Stripe, there's like a dozen different things that could go wrong. And we're not talking about bad, like something's wrong with Stripe or something's wrong with the programmer. We're talking about like a card's not valid or the authorization fails even though the card is valid and the address is valid. Like, there are lots of different parts in the process where something could go wrong. If you're doing an authorization and then it captured “blah, blah, blah.” There's just, there's a lot of different places.
And what I found was I was using promises and it just made everything dead simple, because I would have a bunch of success cases and then a reject handler. And the reject handler would just go back to an earlier state that was known good for that waterfall of potential successes. And then if all of the potential successes went through, then it would go through to the next part. And there's what Stripe's doing, what my server's doing, there's what my UI is doing. And until I started using promises on it, I was like, “Ah, how am I ever going to handle these cases?” And then it just [poof], simplified. Do you have a strategy you recommend for handling the way that user flow can go with all those different pieces and servers that you're interacting with?
CRAIG:
Yeah, I mean I think that's a great use of promises. I'm thinking back to myself about the sample code I wrote for the thing. I honestly don't think I use promises but I was thinking about why. And I
think it comes down to, I kind of trusted Stripe as a server to send me back a decent message for it. And I didn't need to do too many different things depending on what message it sent back. I just showed, displayed that message the way my interface worked. Now, if you had an interface that worked differently, you might have some more edge cases. But I used the validation plugin to catch all the upfront stuff. And then if it was more like the card's rejected or the card's expired or funds aren't sufficient, all those different messages really just came back looking the same to me from Stripe. So, I didn't have to deal with that, which it sounds like in your case you had a bunch of different paths there.
The other thing I'll say is just related to that but not directly, is there is a bunch of test credit card numbers that Stripe gives you. I think they're more industry standard test numbers. So, when you're in a test environment you can plug in one of these numbers and get... and follow all the different use cases. So, you know, all the ones that... some of the ones I just mentioned. So, it makes it really easy to make sure you're covering... it's not this, “I don't know what this API could possibly send me back.” It's pretty well-defined that if you type in this number you're going to get this kind of an error case back from it.
AJ:
Yeah. And I remember spending a lot of time on playing around with that, like entering in the 4444444 number and then like, “What if I type in a wrong zip code? What if I type in wrong validation date? What if I type in a...?” and just exploring that way. And that was so useful.
CRAIG:
Yeah. It was very helpful. And most of the server-side libraries, obviously they're written in a lot of languages that make it easy to unit test, like Ruby, and so forth, and Node, JavaScript in particular. So, you just use the same approaches you'd use writing any code for those languages to write some unit tests for these things. But a lot of times it really comes down to, well I want to see that message that comes back from the server. It needs to be more of an integration test. I want to see the response that's going to come back from Stripe so I know that I'm handling it correctly.
AJ:
Another question that I had, different topic, but [inaudible] applications. So, I want to take in payments on behalf of multiple partners and then disperse payments back through multiple partners. Up to this point, the only thing I've used Stripe for is just single business and that's what we've been talking about. That's what Chuck was saying and everybody else I think so far. But what about the case where you're handling payments on behalf of your customers?
CRAIG:
Yeah. I think the pillar client for Stripe for this is Kickstarter. They're obviously handling payments on behalf of lots of people. And they have, there's a part of the API called Stripe Connect that's pretty... it's a newer part of Stripe. And it covers those use cases that you're talking about where you've got... basically you're creating a marketplace or a platform where people need to get paid. I'll be honest. I haven't worked with that. It's not really covered in my course. It's kind of... it ended up being a three-hour course just covering... it gets pretty complicated handling recurring payments and so forth, and an application and signing a user in when you're looking like a Software as a Service application. But I do think that's an interesting part of it. And when I was talking to the Stripe.net author, I know he was updating his library to include the Connect, the parts of Stripe Connect. So, it's like its own, whole part of the API, a new part that has just come into existence recently.
CHUCK:
Yeah, I've been looking at that for the remote conferences website that I'm building. I've got a handful of people who want to do remote conferences. And so, yeah essentially what you do is you make the charge the same way except you have their identifier for their account. And you tell it how big the fee is. And so, it's relatively simple. And the just authenticate their Stripe account and tell which sub-account to connect to via OAuth, I believe.
CRAIG:
That sounds cool.
JOE:
So, one of the things that I really like about Stripe is just the fact that it's very pervasive, right? And it has a lot of partners that it integrates with, which I think is really awesome. For example, I've done some stuff with conferences and Tito has a very natural, nice integration with Stripe. Are you aware of other services out there that have an integration with Stripe?
CRAIG:
Yeah. Off my head, that's a tough one. I do know that there's a new... I've heard a lot about the lift company that does an app. You're thinking more about services though, I think is your question.
JOE:
Yeah. Well, that was...
CRAIG:
So, Shopify. Shopify is the big one I know about. They're a big player in that space. But yeah. [Inaudible]
JOE:
Well, it just seems like they've got such a solid service that a lot of, especially the newer third-party services that are coming out saying, “Hey, you need to take some kind of payment of some kind for whatever.” Like Tito was customized around doing tickets, ticketing, right? But this is getting to be pretty popular, which I think is very cool. It speaks a lot to how great of a service Stripe has.
CRAIG:
Yeah, I see what you mean. I do know of someone who's created a WordPress plugin and basically has made a living off of just the WordPress plugin that uses Stripe, plugs Stripe into WordPress. That's another example of kind of what I think you're talking about, is if you build sort of a platform and a nice API then people can make products that sit on top of it and make it easier to plug payments into specific use cases.
JOE:
Right.
CHUCK:
One other one that's interesting to me is my email provider, Drip. They provide Stripe integration where essentially they connect through the API and over the webhook. And what happens with them is that then when somebody pays for whatever, then you can set up rules so that when it gets notified through the webhook, it adds them to campaigns or tags them in certain ways, or things like that, which is also really, really interesting.
CRAIG:
Yes. I've definitely seen that one. I'm a Drip user myself. And that is very cool. Just looking at the number of companies that use it in general, not necessarily as an integration, it's just a great platform. I think another use case, I know there's a whole entire business built on Stripe Analytics, like building a dashboard out of the Stripe data that comes from the Stripe API. Baremetrics I believe is the name of the company.
CHUCK:
Yes. I was trying to remember what it was. That's it, yup.
CRAIG:
And I think since they've done so well and they're pretty public about things, there have been at least a few people who've copied that idea. So yeah, I don't know why they didn't think of that right away. But they're a really... what's interesting about how they grew their business, marketing online even though it's kind of a tangent, is they made their data about their business available through their own product. So, you could watch their business grow by looking at the Stripe dashboard for their actual business.
CHUCK:
Yeah. They had somebody at MicroConf that talked about that and it was really fascinating. One other thing that I really like about Stripe is the dashboard itself. So, you have this really nice dashboard that shows you how many payments have come in, what days they were on. You can search for customers. So, you can actually go back through and really get a good feel for what's going on with the payments coming in by signing into your Stripe account on Stripe.com.
CRAIG:
Yeah, I really love the dashboard. One thing I didn't realize until I did the course was if you click sign up on their home page if you're just curious and listening to this show, you can actually not create an account. You can create the account later. There's a little link that says “Skip this step” and you can get a look at the dashboard with just some fake data it, without ever signing up, which I think is just super slick basically.
CHUCK:
Yeah.
CRAIG:
So, anybody can get a look at this dashboard we're talking about, even if you don't intend to use it right now. If you just want to see. Because [inaudible] it's a great user interface, particularly when it first came about. It was kind of ahead of its time. [Inaudible] a lot more innovative interfaces on the web but at the time it was one of the first single-page apps that I saw.
AJ:
So, I'll bring up a weird story. When I first got Google Fiber I went into my options, because I want to get the max out of this Google Fiber so I want to be using IPv6 and jumbo packets. Like I wanted to screen. And I turned on jumbo packets and could I notice the difference? No. It's like the difference between 320 mp3 and FLAC. Like, nobody can tell the difference, right? But everything seemed to be fine until I did a Stripe payment and then it kept on failing. And it turned out that one of the routers or proxies or something in between me and the Stripe payment server couldn't handle gigabit jumbo packets. And it caused an internal application error, like a network error like connection reset, like a 500 internal application error. Weird, right? [Laughter]
CRAIG:
That is really weird. It's a great Stripe-related story, for sure.
AJ:
And then I contacted support about it and nobody knew what the heck was going on. And then I
realized that it was actually, because they were like, “We can't reproduce that,” and eventually found out it was the jumbo packets. So, I turned that off. I don't use jumbo packets anymore.
CHUCK:
[Chuckles]
JOE:
You broke the internet Stripe.
CHUCK:
It doesn't sound like it's a Stripe problem. It sounds like it's an AJ problem.
AJ:
No, it was a Stripe problem. It was their server that couldn't receive a jumbo packet. That's definitely an internet thing.
CRAIG:
It's probably worth mentioning that PayPal bought a company called Braintree which most people have probably heard of. And I think it has a similar look and feel and purpose to Stripe. It's a competitor. So, I think that's the other 10,000-pound gorilla in the space if you will.
CHUCK:
I wonder how they feel about us doing this show considering that they're a sponsor. Anyway.
AJ:
So, slick plug. Doesn't Braintree have lower payments or lower percentages and [now] they're a big thing?
CHUCK:
I don't know. I really haven't compared them.
AJ:
My understanding, I need to go look. But my understanding is that they offer some lower-level features that are more like bare metal-ish and that their payment cost structure is a little bit more favorable.
CHUCK:
Yeah. By the time they were sponsoring, I was pretty heavily invested in Stripe. And I wasn't willing to do the work to move. But it does look like a pretty solid product. And it does a lot of stuff.
JOE:
Yeah, I don't know what the other ones I like, but one thing I do like about Stripe as well for my online ticketing needs for example is the fact that they don't charge a different percentage if it's an American Express card.
CHUCK:
Yeah.
JOE:
So, that's really nice.
CHUCK:
Well, the reason that a lot of the other ones charge that is because American Express charges them more to process the card.
JOE:
Right. Right, I know American Express charges more. So, it's nice to have a service that actually doesn't charge more for that.
CRAIG:
And you'll see a lot of information about, for a long time Stripe was behind in supporting international payments. It's really pretty dead even from what I can see now. Like Stripe actually has more countries but a lot of them are still in beta and so forth. So, I'm sure... I think it's kind of a wash at this point between the two for sure.
AJ:
Well...
JOE:
The countries... That made it sound like you said the countries were in beta. [Laughter]
JOE:
Mexico, we've got Mexico in beta. This is beta version of Mexico.
CHUCK:
It's like Google's products, right? They've been in beta forever.
JOE:
Yeah, They've been in beta forever.
CRAIG:
Exactly.
AJ:
Oh, oh, oh Braintree has Bitcoin.
CHUCK:
Yes, they do.
CRAIG:
And so does Stripe though, I have to say.
CHUCK:
Oh, they do?
AJ:
Oh, Stripe has Bitcoin now?
CRAIG:
Yes.
AJ:
Just looking...
JOE:
Is anybody excited by that except for you, AJ?
AJ:
Hey, dude...
CRAIG:
[Laughs]
AJ:
I don't know what the future of Bitcoin is. No one does. But it's something that's interesting in the idea that a person can take charge of their finances rather than having it be institutionalized. And we know that there are a lot of problems in the institutions. There are a lot of benefits there, too. But there are a lot of institutionalized problems.
Like for example, anybody... this actually happened to me two months ago. I was getting charged for somebody else's Comcast account, okay? And what happened was they had just mistyped their account number. And the digit by which they had mistyped their own account number happened to be mind. And there were no protections in place. There is nothing protecting you in a bank. A bank is the most insecure place to keep your money. You're better off keeping it in a safe box in your house. A bank's kind of convenient because you get the debit card and you can make an online transfer to you credit card to pay it off. But it's incredibly insecure. It's just not a good place for it. And I like the idea of what Bitcoin presents with being able to take charge of that. And there's something nice [inaudible] distributed. It's more like...
JOE:
AJ, I have many stories of home burglary that would counter that point of it's safer to [keep your money at home]. [Laughter]
AJ:
Okay, okay. I'll grant you that. It's just I feel weird because I've had experiences with banks where my money was lost and they couldn't tell me how it was lost and they wouldn't recover it for me. They just said, “Oh, it's gone,” and I'm like, “Well, where did it go?” And they were like, “Well, there was an intermediary bank and there's this and there's that.” And I'm like, “Well, you're a bank. You've got one job, right? Keep track of the money. Like, where'd the money go?” And they're like, “Well, it was faxed and then written down by hand,” and then I'm like, “What?”
CHUCK:
Yup. It's a bank. That's the way they work.
AJ:
So, I think that there's some future in this concept of what Bitcoin represents. And I take what people pay me in Bitcoin for programming sometimes. I don't require it. But I feel safer transferring Bitcoin than I do transferring with my account number, because I know from my personal experience how vulnerable those account numbers are.
JOE:
Mm, very interesting.
CHUCK:
Yeah.
AJ:
But what I wanted to say before I got on that rant was Braintree looks a little bit more developer-y. It looks a little less consumer-y and a little bit more developer-y. And that seems every intentional. Their fonts on their website are monospaced. Braintree strikes me are more geeky just looking at their documentation right now.
CHUCK:
Well, that's a criteria I use.
JOE:
Monospace font. It speaks to me. [Laughter]
AJ:
Hey, the font matter, right? [Laughter]
AJ:
[Inaudible] I love you versus... “I love you, I will always find you” when it's in a creepy font and then a cursive font. You see what I mean?
AIMEE:
[Chuckles]
CHUCK:
No. [Laughter]
AIMEE:
I just [inaudible].
JOE:
Did you have your birth certificate reprinted in monospace?
AJ:
No, it came that way. And Utah doesn't accept it. [Laughter]
AJ:
North Carolina birth certificates. Utah doesn't like them.
JOE:
AJ doesn't actually have a birth certificate. He has like a...
CHUCK:
He was hatched. He has a hatch certificate. [Laughs]
JOE:
Yeah. [Chuckles] I was going to say a date of launch.
CHUCK:
A date of launch. [Laughter]
JOE:
Oh yeah. A launch certificate.
CHUCK:
That's better.
JOE:
[Laughs]
AJ:
That's what my business partner Bryson would tell you. Sometimes he's like, “I can't believe you did X, Y, Z.” And I'm like, “Yeah, well I am a human.” And he's like, “No, you're not. You're a machine and machines don't do that.” [Laughter]
JOE:
Aren't you due back at the factory to have your bolts tightened?
AJ:
What?
[Laughter]
JOE:
Have you never heard that before? That's from like, 'Liar Liar' I think.
CHUCK:
Oh. Alright, let's go ahead and do some picks.
JOE:
We're way off track.
CHUCK:
I think we've pretty much killed this one. [Laughter]
CHUCK:
Alright then, before we get to the picks I just want to acknowledge our silver sponsors.
[Once again this episode is sponsored by Braintree. So go check them out at
BraintreePayments.com/JavaScriptJabber. If you need any kind of credit card processing or payment processing in general, they are a great way to go and we appreciate them sponsoring the show.]
[This episode is sponsored by Thinkful.com. Thinkful.com is the largest community of students and mentors. They offer one-on-one mentoring, live workshops, and expert career advice. If you're looking to build a career in frontend, backend, or full-stack development, then go check them out at Thinkful.com.]
[This episode is sponsored by TrackJS. Let's face it, errors cost you money. You lose customers or resources and time to them. Wouldn't it be nice if someone told you when and how they happen so you could fix them before they cost you big-time? You may have this on your backend application code, but what about your frontend JavaScript? It's time to check out TrackJS. It tracks errors and usage and helps you find bugs before your customers even report them. Go check them out at TrackJS.com/JSJabber.]
CHUCK:
Joe, why don't you start us off with picks?
JOE:
Oh, I have to start us off. Alright. I will start off the picks because my picks are always the best. And Aimee, I'm looking at you. You've got to step it up this week.
AIMEE:
[Laughs]
JOE:
There better be some cat-related picks, Aimee. Or else I'm going to be highly disappointed.
AIMEE:
Oh god, I need to think of something quick, then.
CHUCK:
Cat, cat...
JOE:
Christmas cat-related.
CHUCK:
Cat picks or cat picks?
JOE:
[Laughs] Alright. So, my main pick this week is going to be the Star Wars movie because by the time this comes out, it will just barely come out. So, I don't care how crappy it is. Go see it.
CHUCK:
[Laughs]
JOE:
And I highly identify with the guy on Simpsons when the comic book guy came out of the Star Wars movie and he said, “Worst Star Wars movie ever. I will only see it two more times today.” [Laughter]
JOE:
I highly identify with that.
CRAIG:
And you bought your tickets already, I assume.
JOE:
Oh yeah. Tickets have long been bought. I'm actually really disappointed in myself because I won't go in to see at once, opening weekend. But that's because I'm traveling.
CHUCK:
No.
JOE:
And I couldn't make other arrangements. But...
CHUCK:
Get your priorities in line, Joe.
JOE:
I do have poor priorities. I should have rescheduled our travel.
CHUCK:
Are you indoctrinating your kids?
JOE:
Oh, yes
CHUCK:
Okay.
JOE:
Definitely.
CHUCK:
Then it's semi-forgiven.
JOE:
[Inaudible]. We've been indoctrinating her. We've been showing her the movies so that she's ready. So, kids are well indoctrinated. Have been since birth.
My other pick is going to be a new RPG that just Kickstarted. It's got some PDFs of the manuals out. A role-playing game for anybody who happens to like role-playing games. And it's called Masks and it's based on the apocalypse world system which is like the very, very, very best system for role-playing games out there because it makes it a lot more about what is fun and a lot less about dice rolling. And Masks is a superhero-based role-playing game. So, I'm sure they'll be selling the books here soon. The Kickstarter's over but I'm sure the books are... you can probably go on and still back it or something, or just pre-purchase a copy. But if not, keep your eye out for it, because what I've seen so far, the stuff they sent the backers, has been really good. So, that's it.
Those are my picks.
CHUCK:
When you said you backed an RPG I was hoping you had backed a rocket-propelled grenade.
JOE:
[Laughs]
CHUCK:
AJ, what are your picks?
JOE:
I'll do that next time.
CHUCK:
Next week, huh? You're coming over to my house?
JOE:
You've got it. Exactly.
CHUCK:
Alright. AJ, what are your picks?
AJ:
Alright. So, I'm trying to find a particular article I wanted to link to. But one of my picks is 'In Defense of Comic Sans'. I'm going to link to the video because I can't find the specific article. But you can find a number of these. And they talk about, like we all hate Comic Sans. But there are some particular reasons that we hate Comic Sans as designers versus, well it just... yeah, there are some merits to Comic Sans in the same way that there are some merits to WordPress, you know?
CHUCK:
Blasphemy.
AJ:
And also, I want to pick the Runscope t-shirt. The 'everything's going to be 200 OK'. I urge everyone on the planet to test out Runscope just for the sake of getting the t-shirt, because it is the best t-shirt ever. And if I ever run into a woman who is single and wearing it, I will propose on the spot. Done deal. [Laughter]
CHUCK:
You heard it here, folks. Alright Aimee, what are your picks?
AIMEE:
So, the first one I was going to pick, I stumbled upon this, this weekend, somehow. But it is, it's on GitHub. I'll put a link to it. But it's Minko Gechev and he has a repo right now, [inaudible] Angular 1. I think he's working on Angular 2 as well. But it runs through a bunch of different design patterns and how they're implemented in Angular. So, I got a lot out of this because I've just been trying to focus on some of these fundamental concepts. And it gave me, instead of just reading something dry it gave me an actual use case so that... I feel like when you're learning, an actual use case like that will stick in your head a little bit better. So, that was pretty awesome.
And I've been frantically googling for the past couple of minutes to try to appease Joe. And the only pick I could come up with, I don't have a place where you can actually go do this other than if you're near Mall of America, would be Santa photos with your pets. [Chuckles]
CHUCK:
Nice.
AIMEE:
I know PetSmart used to do this. But I don't know if they do it anymore. As I'm googling I think I've read some horror stories about people suing people and whatnot. So, that could have something to do with them not doing it all the time anymore. But I was able to find the link where they're doing it in Mall of America. So, I'll put that in the show notes. If you want to get a picture of Santa with your pets. [Chuckles]
JOE:
Aimee, I'm going to jump in here and say that you missed out on probably the best possible pick you could have had.
AIMEE:
Oh no.
JOE:
And that is ChristmasCats.tv.
AIMEE:
Okay.
JOE:
That's all I'm going to say about it. ChristmasCats.tv. Link is in the show notes in case you can't figure out...
AIMEE:
Oh, shoot.
JOE: www.ChristmasCats.tv.
AIMEE:
Shoot. Actually, I did have a pick. My husband sent me this video of cats with cucumbers. I don't know if anyone has seen them.
JOE:
[Laughs] Did you read all the comments about how it's like animal cruelty?
AIMEE:
[Laughs]
JOE:
And people are watching this. This is like [inaudible].
AIMEE:
Well, of course over thanksgiving I cooked a bunch of squash and zucchini and my husband tried to do this with our cat. But it didn't work.
JOE:
It didn't work?
AIMEE:
He claims it was because it was a zucchini instead of a cucumber. But it was a fail. The cat just kind of batted at it and was like, “What the heck are you doing?” [Laughter]
AIMEE:
Anyway...
JOE:
So, everybody is saying it's like animal cruelty but I can't help but laugh when I watch the video. I'm sorry.
AIMEE:
Yeah, it's good stuff.
JOE:
So hilarious.
AIMEE:
Anyway, carry on. [Chuckles]
CHUCK:
Well, I've got a pick. I got myself a birthday present. I actually got myself a couple of new drills. And just to give you some context, my wife has picked or has bought the last three drills that we got.
JOE:
These are dental drills, right?
CHUCK:
[Laughs] No. So, one of them was a Kawasaki. I think they make motorcycles and drills I guess.
AJ:
And [drills] [inaudible].
JOE:
So, obviously they would make drills if they make motorcycles.
CHUCK:
Right, right. Yeah. The other one was a Drill Master. And yeah, it was crappy too. And the other one was Black & Decker. They make kitchen appliances. So, I got a kitchen appliance that turns screws. They just were crappy drills. So, I was talking to my father-in-law who's a general contractor. And he turned me onto these drills. The brand is RIDGID. That's R-I-D-G-I-D.
AJ:
That's right, bro. Welcome to the club.
CHUCK:
So, I got it on a Black Friday deal at Home Depot. And the cool thing about them is not just that they're twice as powerful as those other drills that I had – and I got the box that has the drill and the impactor, which the difference is basically in how they turn the bit – but the other thing that's nice about them is that they have a lifetime warranty on all of their parts. So, you have to go online and register it. And you have to hang onto the receipt and stuff until you get the confirmation that it's registered. But then my father-in-law left his drill out in the rain and he took it back to Home Depot and they replaced it. There have been a few other things that I've been able to do now that I couldn't quite get to drill or screw before. So anyway, I really like them. So, I'm going to pick those.
And then the other thing that I'm going to pick is JS Remote Conf. Just a quick reminder, go check that out. JSRemoteConf.com. At this point you've missed the early bird when this comes out. It'll just be too late. But you can still get tickets. Several people on this call are going to be speaking. And I'm also releasing the Angular Remote Conf videos right now. If you're subscribed to the list where you get the episodes then you'll get an email about it letting you know that those videos are out and where to get them. So yeah, so that's what I've got going on and what I'm picking.
Craig, what are your picks?
CRAIG:
I wanted to start. I think it's going to unfortunately be a little late. Everybody probably might know about this. But in case people don't, go check out HourOfCode.com. It's basically a movement to expose through education the younger generation to an hour of code. You can volunteer on there. I just did. I think I might have done it too late this year as well. But I'm hoping next year I'll be able to get involved. But it looks like a great cause. And I just have noticed my kids are in elementary school, both of them, and there's just not a lot of education around that. So, I think it's good that there are things like this.
The other thing I wanted to let people know about was I just finished my first egghead.io series of courses. It's basically around when to use service, factory, or provider, which everybody's always confused about, in Angular 1. It comes from a lot of in-person training and people being confused around this concept. And I think I've finally found a good way to explain it so I recorded it and put the videos out there. I'll put a link out there. They're actually all free right now. They kind of... things on egghead go from being free to not free. So, if you... when you hear this, maybe go check it out and hopefully they'll still be all free out there so you can watch them.
The last pick is an iPhone, iTunes game called A Dark Room, I believe.
CHUCK:
Ooh, good pick.
CRAIG:
Yeah. I had heard about it on... I think you guys interviewed on Entreprogrammers the creator of that game. And I just heard about it two or three different places. I finally bought it for my son's 10th birthday when he got a new iPod. And he is just so hooked on it. He actually was playing another game for a while and not interested in it and I was worried that it wasn't going to take off. And then I sat down one day and played with him for two minutes and he's like, “Oh my gosh. This game is awesome. I don't know how I missed this the first time. This is the best game ever.” So, I highly recommend checking that game out. Hard to explain why it's good but you just have to try it.
CHUCK:
Yeah. I'll put a link to that in the show notes from Entreprogrammers.
CRAIG:
I guess there's one more thing I should mention. I don't have any link right now, but I'm finishing up a course. It probably should be done in January on Pluralsight on Babel, which I know you guys just had a great show on that. I recommend [listening] to that if people haven't heard the Babel.js show. So, just telling people so that maybe they'll check that out.
CHUCK:
Alright. Anything else that we should know about? If people want to follow you or get your books or anything like that?
CRAIG:
No, I think most people who have needed have picked up a copy of the 'JavaScript Framework Guide' so I'm pretty good. But if you come by my blog at FunnyAnt.com, I usually only send emails out to people to let them know about stuff when I've got new things like the free course on egghead or something like that. Feel free to sign up there.
CHUCK:
Alright. Well, thanks for coming, Craig. We'll go and wrap up the show and we'll catch you all next week.
[Hosting and bandwidth provided by the Blue Box Group. Check them out at BlueBox.net.]
[Bandwidth for this segment is provided by CacheFly, the world’s fastest CDN. Deliver your content fast with CacheFly. Visit CacheFly.com to learn more.]
[Do you wish you could be part of the discussion on JavaScript Jabber? Do you have a burning question for one of our guests? Now you can join the action at our membership forum. You can sign up at
JavaScriptJabber.com/Jabber and there you can join discussions with the regular panelists and our guests.]