Category: Flex

  • What Rhymes with AIR? I Don’t Care

    I am not interested in developing for AIR, Adobe Integrated Runtime. While the features sound compelling, they do not offer me anything I need in my day to day development for clients. I do not believe the market, currently, has a supporting model for those types of applications in a compelling way. AIR additionally does not offer anything new beyond it being a Flash projector wrapper with Adobe’s name behind it. All of the features I’ve seen can be done, and have been capable of being done for over 5 years now. I believe the only reason there is a perceived vested interest by the community currently has to do in part with Adobe’s immense marketing initiatives, and part because all the new Flex blood has no idea of the history Flash already had doing this stuff.

    I consider Flash and Flex really fun tools to make a living. I used to love doing desktop multimedia using Director, embedded Flash into Visual Basic & C, and even all of the 3rd party projectors (mProjector, Zinc, Screenweaver, etc.). The market, however, has been paying me since 2002 to build for the web. I know of 1 guy up in Detroit, Michigan who does nothing but desktop development doing Flash & Zinc. That’s pretty crazy when you look at all the wonderful things Flash can do being embedded into these various environments. They never got mainstream, even with all the cool things they can do. AIR is not fated to repeat this same history. Regardless, I fail to see how a big brand name with more cheddah’ than Macromedia, and newly christened Java-turned-Flex Developers can do what Director MX, Zinc, and mProjector couldn’t; get enterprise customers paying for Flash on the desktop.

    All the main features of knowing when you are online or off, saving local data into either text files or mini-database engines, and running cross platform was capable of being done for years in Director, mProjector, and Zinc. Clients still didn’t pay for it. Yes, AIR DOES have transparency on an embedded browser, but that is not going to score me more work.

    While I think Google Gears has potential because it actually positively affects my daily life as a consumer, I don’t yet see how AIR will. For example, if I could read my GMail and Google Docs while I’m on a plane with snakes travelling to client sites, that’d be wonderful! Until Delta gets wireless like other airlines, I’m offline when I’m at 30,000 ft. I’m no longer capable of using all the web apps I use up there. There is a real need to satisfy the occasional connectivity problem by having the ability for all of these web apps to work when offline. It’s hard to really gauge interest from the wider web development community when reading the echo chamber. Furthermore, Google Gears clearly shows Google is solving it themselves. Yeah, I know, Kevin Lynch being there might not be coincidence, but if you were Google, what would you do?

    Bottom line, there are 2 sources of revenue that clients who hire me have. Either it comes from advertising, or they have an existing business model, and want me to build software to help them make more in that market. The former will use my content amidst other web content, aka adverts of some sort. The latter loves the deployment model of the web, and uses my applications on their intranets or internal websites to deploy to their customers.

    So, the money fueling my Flash & Flex work right now is web based advertising models, and in using web based software applications to reduce overhead / increase customer retention & draw. People use web browsers to do both of the above, and so do consumers. They all have Flash Player 9 installed, or don’t mind installing it in the 12 seconds it takes on slow DSL . To this day, server admins still perceive Flash Player as a harmless animation toy and this works in my favor in getting them to install it corporation wide.

    The only monkey wrench in the above is an un-substantiated (aka un-cited source because I don’t believe the info yet) report about click through rates. I’ve heard that click-through rates (meaning the percentage of people who see an ad AND click it) are EXTREMELY higher for widgets. While I don’t believe that strictly on the fact I’ve not been shown any official data, there is certainly evidence of it. For example, I’ve gotten 2 contract gig offers to do widget work, 1 from an agency, and 1 from a smaller software shop. The trend the past few years has been moving to bigger apps, not smaller ones, so this is odd… and using Flex, not Flash, to do them to boot. Third, the explosion of widget engines in the past 4 years. Kapsules, Konfabulator & Mac OSX’ built in stuff, Windows Vista’s sidebar, SpringWidgets, and Yourminis … and the 10 billion I’m not documenting here. It’s taking me 6 months to really try the ones that came with my Mac. Could I live without them? Sure, but do I want to? No, I’d prefer to keep them, and have access to them. Finally, the weird MySpace drama where they blocked a widget embedded on MySpaces user pages because it had it’s own ads, thus “stealing” MySpace’s ad revenue… and then subsequently buying them a week later since the company obviously knew how to make more money from MySpace’s users than they did. They wouldn’t do that if they weren’t concerned about losing money, enough to inconvenience users.

    Either way, the only thing that could top the AIRBus travelling the country is if they did what Microsoft did and pay someone to build your existing, and proven to already work but let’s risk breaking it, in an unproven and new technology. Aka Yahoo building their Yahoo Messenger in WPF. On the flip-side, it seems that the Cerulean Studios peeps on their own accord checked AIR out when it was still Apollo, aka alpha, so I’m sure that saved some dough and garnered great feedback from viable developers. I use Adium on my Mac, and Trillian on my PC so does that mean I’d install AIR so I could use Astra on both? At least Yahoo knows that Vista has WPF pre-installed whereas, whereas the rest would have to install AIR even though WPF would be only Windows (they said WPF, not Silverlight, so…).

    Don’t get me wrong, Meebo is cool and all, and I’ve used it from time to time, but there is a reason some of this stuff is out the browser. Those reasons are usually to use powerful code not included in enough browsers to depend on it. Waiting on AIR to implement said useful code means waiting years for it to come to fruition assuming AIR survives to version 2. I don’t know about you, but I like building stuff today, and in the next 6 months, and I fail to see incentives to do so. Yes, I’m aware of the various initiatives to allow talking to the OS via installed local socket programs to allow AIR apps more functionality, and while neat, it’s a hack, building something into AIR that is notnatively there.

    Don’t get me started on how easy it is to write destructive viruses using AIR and how Adobe’s brand will be held accountable.

    Same thing with ubiquity. Flash Player 9 is reported to be at 80% now. In a few months, we’ll have AIR v1 at 0%. What incentives do consumers have to download a large runtime to install your app? What does this to do to adoption rates which in turn affect development initiatives?

    What about multiple computers? GMail works on any box with an internet connection. For AIR apps, however, the runtime has to be installed as does the app yet again on the target machine you wish to use. Furthermore, this assumes you have admin privaledges on the box. In all fairness, so does Flash Player. Finally, your data is probably saved locally unless the developer(s) of the AIR app made a way for it to be saved on a server. If not, your data is on that other machine as well.

    People have spent a lot of money putting their brand online. Those people hire me to help that brand continue making money… online… and in a web browser. An unnamed company was quoted as saying, “…applications connected online that have the benefit of the desktop”. I can do that right now, and last year, and the year before that. It’s just that now, we have a bad ass runtime, and even more awesome tools that are still young, and have yet to be fully integrated. Combine that with a new breed of experienced programmers coming to the party. Just imagine a few years more when Adobe starts getting some competition (yes, I’ll keep praying for this dream, and just act delusional till then). Maybe that’s the tipping point?

    It’s not so much that I wouldn’t enjoy doing development using AIR, but rather, I see it as an extreme niche, and one that there isn’t a lot of opportunity for people like me in. Can AIR do more than a browser? Sure. Will some consumers use AIR in tandem with their browser? Sure. Even so, I highly doubt the mid-size to Enterprise sphere will invest heavily in it. Getting “Flash Player 9” deployed on internal company networks is one thing, getting an app deployed, and then later updated potentially multiple times is another thing. While I love getting experience through hardship, after hearing the horror stories (DLL hell, etc.) I don’t really regret missing the desktop revolution.

    As a Flex and Flash developer who drank the Central kool-aid to an Evangelist degree, I can clearly say I am not interested in developing for AIR.

  • Flex Controlling Flash

    Preface

    This article focuses on controlling applications written Flash Player 8 and below that are loaded into Flex at runtime. If you want to read up on the various ways of doing this, I’ve written in the past how to control Flash Player 8SWF’s in Flash Player 9’s new AVM. This article specifically will talk about using Flash Player 8 content in a Flex 2 environment.

    Before you read further, I strongly suggest you beg those in charge to allow you to re-write the AS2 content in AS3 (Flex 2 or Flash CS3). If that fails, keep reading.

    Use Cases

    Here are some common use cases where one would want to load Flash content into Flex content:

    1. You have some existing Flash content that was previously written for a Flash Player before 9 (8, 7, or 6). This content could be a fully functioning application that has already proven itself by working successfully for awhile. Therefore, you’d like load it in atruntime and let it do it’s thing. There is no time, budget, and/or resources to re-write the content in AS3. An example would be a video player written for Flash Player 8/7/6 customers (those who don’t have 9).

    2. You have some content that was created by another company or 3rd party tool that you want to integrate and possibly control. This could be SWF’s generated by Captivate, Connect, Swish, or perhaps even older versions of Flash. There technically are no “source files” so you couldn’t necessarily re-write the content, or said content just couldn’t be created in Flex in the first place.

    3. You’re a Flex Developer and have no intentions of learning Flash. You’ve been ordered to load SWF’s that are not AS3 and control them.

    4. Like #3, except you can’t find any Flash Developer contractors that are available. Imagine that.

    For the record, all 3 are valiant efforts fraught with peril. Knowing this, you can re-attempt my advice to plead with management to abandon the course in folly, or grit yer teeth and git-r-done. I won’t re-iterate the problems here, you can read that in the above link. I will, however, give a quick refresher on what you can and can’t do.

    First, none of the above scenarios allow embedding. If you do not have the source FLA created in Flash, with a valid copy of the Flash authoring tool (MX, MX 2004, 8, or CS3), you have no choice but to load this stuff at runtime. If you DID have a copy, you could embed it. Embedding AS2 SWF’s, however, removes all of your code. Thus, embedding AS2 applications won’t work. You don’t have these problems with AS3.

    Second, loading AS2 / AS1 content at runtime creates a separate, special security sandbox for the SWF that’s being loaded. The DisplayObject is called AVM1Movie, and he’s an iron-clad, impenetrable black box. There is physically no way to breech it via ActionScript 3 to talk to it. You can, however, useliasons over / under the wall via ExternalInterface or LocalConnection. ExternalInterface sucks because it uses JavaScript. Every project I’ve ever done that incorporated JavaScript as a necessity added 1 more level of complexity, extended the debugging time in the project, and overall made it more challenging to make progress. Thus, while theAVM’s may be different versions, at least we’re coding in a semblance of the same language and runtime… well, more than JavaScript anyway. AS1 and he may be similar , but at least AS1 works the same in all browsers. You already have enough challenging things to worry about now that you are down this dangerous path; you don’t need another headache.

    Third, your AS3 content cannot immediately “get rid of” AS2 / AS1 content in this AVM1Movie thing. Garbage Collection will get it when it feels like it. In the AS2 / AS1 AVM, removeMovieClip for the win! It works immediately, and while the actual RAM of the used variables may not go away, all media stops (sounds, video, animation) as opposed to AS3 where you have to be explicit to do so, not just remove it from theDisplayList.

    Solution: A proxy SWF, aka proxy.swf, aka, a Flex liaison to AVM1 content.

    Why a Proxy SWF

    Since Flex 2 content (Flash Player 9, AS3 AVM+ SWF’s) cannot tell AVM1 SWF’s what to do, they use a guy on the inside, a proxy.swf, to act as agents for them in that world. The proxy.swf executes the orders that Flex issues, and these orders are communicated via LocalConnection.

    That downside is, you still need to code this proxy.swf in AS2 or AS1 and compile it for at least the Flash Player 8 or below. You don’t necessarily need Flash to do this. You could use MTASC, PHP’s Ming, or JGenerator (I think what Lazslo uses?). I haven’t gotten this to work myself, but you could also possibly use the Flex 2 SDK’s mxmlc with the “as3” compiler option set to false, and the “es” option set to true. This should generate a Flash Player 9 SWF that uses the old AVM (so… technically AS2 like code that’s compiled to AS1 bytecode using a Flash Player 9 compiler).

    …or, you could use my generic compiled example, and hope for the best.

    If you want to do it right (keeping in mind “right” here means not-so-right since we shouldn’t be using older SWF content anyway), you typically tailor a proxy.swf for the particular content you are loading. For example, if you are loading Captivate SWF’s, you build a proxy SWF that can:

    1. load in Captivate content
    2. control Captivate content by their *hidden API
    3. unload Captivate content

    * For more info on hidden API, go here, scroll to the bottom and download the big ole PDF, search for “rdinfoFrameCount” which should take you to the “Controlling Adobe Captivate projects with variables” section.

    This, as opposed to just my generic proxy that just accepts methods as strings and runs them much like JavaScript’s eval. That way, you can expose a loose API. You can’t share AS3 and AS2 interfaces, but we’re already past the point of IDE help here, so you’re really doing faith based coding at this point. Anyone whose ever used a dynamic language (as opposed to strict typing) shouldn’t have a problem with this. If you don’t code the proxySWF specifically for the content you are loading, it’s harder to debug, and basically really hard to identify which remote method invocations are failing.

    I’ve provided 2 examples at the bottom of this article. One is my generic “I’ll run what you send me” one and the other is one built specifically to control the Flash 8 Video Player. While the generic can be something you can build upon to support your content, I highly recommend you follow how the video player one is built and build the proxy.swf specifically control a specific SWF.

    How It Works

    They both work the same way.

    1. Flex SWFLoader loads an AVM1 proxy.swf
    2. proxy.swf loads the content it’s supposed to use via loadMovie / MovieClipLoader
    3. once the proxy.swf has loaded it’s content, it let’s Flex know
    4. at this point, Flex can now tell the proxy.swf to do things with the content it’s loaded

    These can sometimes breakdown. LocalConnections are by their very nature asynchronous. While you can create an instance immediately, that doesn’t mean it’s immediately available for use. For example, the AVM1 version of LocalConnection gives you a Boolean so you know if the send actually worked. If you get a true, it doesn’t mean it actually sent, just that the send operation itself “worked”. Amazingly f’ing useless. Send again? Hell… WHY NOT!?!

    The AS3 version is different. You can get a few different types of exceptions from sending messages, such as ArgumentErrors and AsyncErrors. While the docs claim that your syntax can be correct, and it could be your request is just bigger than 40k, this is a crock. Even simple strings can just fail, and then magically work later. In short, LocalConnection is flaky; you’re code should compensate. If you need ensured communication, use ExternalInterface. That, however, has it’s own can of worms.

    You do not have to use a SWFLoader. You could just a Loader, but since Flex is UIComponent based, SWFLoader is UIComponent based, so there you go.

    The proxy examples I have both use MovieClipLoader. While you could simply use loadMovie, MovieClipLoader gives you more events to understand what’s happening with your loaded content. You don’t have to write polling code yourself; instead, you have dependable events that fire. The only one you really care about is onLoadInit. When that fires, whatever SWF you are loading can now be accessed by code in an ensured fashion. This is why you wait for that to fire as opposed to onLoadComplete.

    LocalConnections

    All of this communication between Flash & Flex is done via 4 LocalConnections; 2 in Flex, 2 in Flash. LocalConnections are only 1 way. Meaning, you can only send messages or receive messages; not both. I typically use the “in_lc” and “out_lc” naming convention; feel free to make up your own. The Flex out_lc talks to the Flash in_lc. Vice versa, the Flash out_lc talks the Flex in_lc. The only thing uber confusing is that in Flex, the names are reversed. Since LocalConnections connect on a “connection name”, these 2 names need to be the same in Flash & Flex. So, in Flash I have:

    LC_IN_NAME = “_JXLFlashProxy_IN”;
    LC_OUT_NAME = “_JXLFlashProxy_OUT”;

    And in Flex, I’ll have the same thing for values, but different things for the names; just to help easy the insanity.

    public static const FLASH_LC_IN_NAME:String = “_JXLFlashProxy_IN”;
    public static const FLASH_LC_OUT_NAME:String = “_JXLFlashProxy_OUT”;

    The only difference is in Flex, you use the OUT name for your Flex “in” connection. Since Flash is sending messages out on the OUT connection, Flex needs its IN connection listening to the “Flash OUT” connection name. The reverse holds true for Flex sending messages. He’ll send them on Flash’s IN connection name.

    To reiterate, these messages are asynchronous. They don’t arrive immediately, and you cannot return values. You can treat it like events, where the LocalConnection in Flash can send a message back to Flex with data, but unlike events, you can’t depend on this; some messages just don’t make it.

    Dynamic Flash

    If you are not familiar with Flash, you’ll notice that both AVM1 examples just dig right into the SWF they are loading. This is because there is no runtime strong-typing in pre-Flash Player 9. For example, if you look at the video_player2.fla, you’ll notice some methods on the main timeline. Flex asks the proxy.swf to call those methods since he can’t. Like a kingpin asking a thug to get his hands dirty. I can access those methods as if they were public class methods… even dynamically by concatenating strings together in Flash Player 8 and below. This is where a proxy.swf shines in that since it’s made in dynamic Flash land, it can play by dynamic Flash rules. This is important because sometimes you’ll be loading SWF’s that you don’t have code control over, and need to jury rig them to do things they weren’t originally intended to do.

    Keep in mind a proxy.swf can do more than just dynamically call methods and set properties on a load SWF application. It can also affect the nature of that application. Since you are still in a prototype based language, an object’s prototype property is writable. Thus, even if you don’t have the source, and don’t feel like using aSWF decompiler to get some form of source, you can overwrite prototype objects that you introspect to force the SWF to do things you need.

    …you know, in writing all of that, I’d much rather use a proxy.swf with ExternalInterface. As much as I hate JavaScript, it was pretty easy to break LocalConnection. Maybe next weekend…

    Source Code

    Video Player Flex Example – Example | View Source | ZIP

    Generic Flex Example – Example | View Source | ZIP

  • E4X XML Binding & CDATA

    The benefit with using international standards when creating software is that you can blame to stupid design decisions on “an international team of brilliant computer scientists”. That way, if someone tries to body-check you on the pathetic implementation, you can defer to aforementioned governing body. That way, you’re calling an international standards body a bunch of crackheads, thus making you look like a crackhead. Who in their right mind would attempt to insult a group of talented individuals from around the globe brought together for the specific purpose to collaborate on creating a new programming API?

    Me. I call it like I see it and it’s crap; specifically, CDATA handling in E4X.

    For background, CDATA is a way to put “character data” which is basically text that could have funky characters in it like HTML. Since XML is made up of HTML like syntax, you want to make sure that you can put HTML into XML, and not have itscrew up when parsed. Enter the CDATA tag, a special tag that tells the parser (whoever is converting the XML text into something useful, like Flash or Flex for example), to ignore parsing anything inside of it. Kind of like the “pre” and “code” tags in HTML.

    Putting these special tags into E4X XML is impossible when combined with binding. Binding is an extremely useful way of creating dynamic XML from variables without having to construct it manually. Since XML is a first class citizen in AS3, you can basically copy and paste real XML into your ActionScript, and set it to a variable.

    Even cooler, though, is the binding; sort of like Flex’ databinding, except it works inside of the XML nodes. So, if you are building Factory classes for example that create XML request packets to send to somewebservice, you can make a function that takes some parameters to customize the request, and return the XML, like so:

    function getLoginRequest ( username : String, password : String ) : XML
    {
        var request:XML = <request>
                                <login>
                                    <username>{username}</username>
                                    <password>{password}</password>
                                </login>
                            </request>;
        return request;
    }
    var request:XML = getLoginRequest("Jesse", "moogoo123");

    Working with a talented PHP dev at work named Nick, and he requires me to send a URL in my request to one of the services. We don’t make heavy use of attributes, which you can actually get away with a lot of HTML character data without XML getting mad, even in the old DOM way.

    The URL, however, kept getting URL encoded. The URL was ALREADY URL encoded because it had some parameters on it that the server would use later. However, it seems E4X does automatic URL encoding (akaencodeURIComponent or it’s ilk) on the text you throw into nodes.

    So, I tried Just putting a CDATA tag instead:

    var theURL:String = "http://some.com?var=someval&foo=bar";
    <the_url><![CDATA[{theURL}]]></the_url>

    …however, bindings don’t work in CDATA tags like that. Since the CDATA is doing what it’s told, and telling the XML parser in ActionScript to ignore the inner contents, this includes the binding. Shoot!

    So, I tried creating it as a String:

    var s:String = "<![CDATA[" + theURL + "]]>";
    <the_url>{s}</the_url>

    …but then it URL encodes the URL again!!!

    <the_url><![CDATA[http://some.com?var=someval&amp;foo=bar]]></the_url>

    Son of a…

    I then tried various other ways of doing the same thing, all to no avail. In DOM, we had XML.ignoreWhite, which basically told the parser to ignore whitespace. There doesn’t seem to be the same sort of setting for E4X to turn of automatic encoding. Furthermore, you can treat the CDATA node as just a normal String, unlike the old DOM which was a tad more explicit like node.firstChild vs. node.firstChild.firstChild (or was it nodeValue… forget).

    Anyway, DAMMIT!

    Michael Schmalle had a fix. You CAN bind to functions as well. It’ll do an automatic invoke (just like a getter for example), and you can return whatever you want. So, doing this:

    function cdata(theURL:String):XML
    {
        var x:XML = new XML("<![CDATA[" + theURL "]]>");
        return x;
    }
    <the_url>{cdata("http://some.com?var=someval&foo=bar")}</the_url>

    Flexcoders for the win.

    I’ve gotten used to namespaces. They make sense; while verbose code, at least verbose pays off in AS3 with speed at runtime.

    CDATA handling, however, is an f’ing joke. If it DOES handle it well, then the docs are an f’ing joke. Neither of which is funny. No one cares, though, because I gotta fix and Nick could remove his Base64 decoding hack he put in for me as a temporary band-aid.

  • Flex with REST Same Name Parameters, and SSL

    Have a plane to catch, so figured if I blog when I have no time, I’d be brief for once in my life. Ready? Go.

    Currently in Cali, awaiting for my flight to board back hom to ATL. Cali is 20 degrees colder than ATL; lame. 72 F (22 C) back to 91 F (32 C) will be a welcome change. I was here on-site with a client doing some consulting for my current contracting client. Confused yet? Don’t be, it’s fun. Figured I’d document the Flex lessons I learned while in the trenches the past 2 weeks.

    First up, what do you do when a server-side developer gives you a REST API that has support for multiple parameters with each one have the same name? HTTPService won’t work as you think. HTTPService in a nutshell does a POST to some URL that supports parameters being sent to it in URL encoded variables. So, this:

    var o = {};
    o.name = “value”;
    o.cheese = “muffin”;
    o.skillz = “mad”;

    becomes:

    http://www.cow.com/some.php?name=value&cheese=muffin&skillz=mad

    HTTPService has 2 ways to give it stuff; either set it’s request property before sending or pass it in the send function. However, if a WebSevice accepts this:

    param=val1&param=foo&param=bar

    Well… you’re kind of screwed. There is only 1 param…

    var o = {};
    o.param = “uno”;
    o.param = “dos”; // overwrites uno
    o.param = “tres”; // overwrites dos… all are same param variable

    I tried my best to hack the IMessage object that’s associated with an HTTPService AsyncToken (mx.messaging.messages.HTTPServiceMessage I think), but no go. What to do? Uber l33t h@x of course!

    1. At beginning of Cairngorm Delegate, store service URL property in member variable.
    2. append your parameters manually the the server.url
    3. var token = service.send();
    4. in result / fault handles, set the service.url back to what it was

    Works. Potential problem? If someone ELSE attempts to use that service, it’ll have that URL stored with it, with the URL encoded variables included. If your HTTPService is only ever used once, you’re good to go.

    Second, SSL. SSL is not hard. I remember keeping that Ted Patrick SSL Flash / Flex entry bookmarked for the day a client would require Flash / Flex & SSL. I remember reading horror stories.

    Those didn’t happen to me, though. I think in hindsight, every one’s problem was SWF security sandbox problems and NOT SSL problems. I remember reading about IE caching things, but either way, the ONLY thing that didn’t work was IE 7 on Vista because our security cert didn’t match up 100% with the real URL (we’re testing,hehe). Mac with Safari & Firefox, and PC XP with IE 6, IE 7, and Firefox all worked.

    We’re not just talking about using HTTPS here for secure longins, we’re talking about:
    – EVERY single request is HTTPS
    – this includes file uploads
    – the SWF is on the client’s website, but loaded from our webserver

    That last part is the kicker. I learned that crossdomain.xml files have to explicitly allow ports, in this case 443. Dope!

    Anyway, really rad to learn that if I ever develop widgets professionally, I can get SSL to work on said widget no matter where it is. I think the rule of embedding it with JavaScript with a relative path applies (like UFO or SWFObject); the SWF’ll think it’s loaded via HTTP, and go “Oh noes!!!”. Hardcode that mofo to https://blahblahblah.

    Speaking of which, anyone know of any site like Akamai that supports SSL? Interested to hear how they handle it.

    Finally, some cool links. talks about what I already know. Disagree about his points with regards to “if you don’t blog, you won’t get a good gig compared to someone who does” but the rest I do. If Expose and you raced, and you had this table as your computer screen, who wins? Finally, a video of Steve Jobs and Bill Gates getting interviewed together. Haven’t watched it myself but how can it not be cool?