 Okay, quick summary, this talk is about other cool stuff we've built for NN7. We want to be like the hub for alternative paths in India. I'm not going to do any club for NN7, just get started. This is one of the talks which is actually a bit backward from the rest of the talks I've seen all day. The rest of the talks all day seem to talk about here's a new thing which in technology and let's see how we can deploy it and use it. This talk was a bit backwards because we started with NN7.n and we had a bunch of problems to fix and we went from how do you fix this problem with the best technology we can find. So it's a bit backward. So I'll start with what were our key features which we were trying to get right and then we'll get into the code and the kind of features we went about creating. So NN7.n in a nutshell has two key important features, there's content and there's music. Each piece has a set of important things you wanted to build around it. Content for instance we wanted an experience where you could browse content within the site really easily and quickly and we wanted music to be continuously playing on the site. So if you've seen Hype Machine, if you've seen Pandora, if you've seen any big music streaming site one of the things they do really well is when you're navigating through the site the music continues to play. And this is what I call a seamless playback. So this was a really important feature for us and that is what has led to most of the stuff which we're going to show you on how we've got around building it. So key deliverables which we were trying to create, seamless navigation when you're playing music and you click on a link, music doesn't stop. We built the first version where people could pop out of the player and listen to music while they could browse the site, people just absolutely hated it. No one wanted to pop out their browsers. The JavaScript involved in keeping track of your popped out browser. So I built this JavaScript where the browser was at the bottom, like how you see at Nemo and when you click pop out it pops out and then you need to map that this browser is active at all times. So if you close this window it had to appear back in the bottom bar. Like how Facebook chat does it, absolute nightmare to get right across browsers. It worked beautifully on Chrome and Firefox. I just wouldn't work on it. What works sometimes, Opera wouldn't work at all for no good reason because you would create a parent and a child within the new frame and new window and your own window and you would track it. So that didn't work at all for us. Lots of people, it wouldn't work. There was lots of bugs. There was no way to fix it. It was a bug which we didn't know how to fix. So we said check this, we're going to go back to a complete asynchronous JavaScript based approach where every link on the site which is internal is going to be loaded in a JavaScript loop and the music is going to be in the main loop which is always, always on. So whatever you do on the site the music doesn't stop. That is seamless navigation is basically more across various lanes the music doesn't stop. Universal playback always started, I think this, we know the player sometime about a year and a half, two years ago with HTML5 audio was just about there. One of the biggest challenges with HTML5 audio was not getting HTML5 audio right. That is the simplest, easiest thing to do because it's audio, SRC audio and it's the simplest thing to do. The problem is what happens if there is no audio support. And if you have a flash player how do you integrate these two controls? Because I didn't want to show any flash on screen, hell no. I mean like absolutely that would not be any site I ever built. So you have to have like an invisible flash one pixel container and everything else built in JavaScript and then you would write like a JavaScript bridge from flash and expose the same controls in flash as we do for our native audio tag. So this dot play and this dot pause and this dot rewind and this dot forward works irrespective of whether it's a flash container or an audio file. And that is those are the two key things which we created for NH7 and which we will go around explaining how we built it. So couple of, how many of you use Gizmodo? Yeah, so Gizmodo was like about the same time as we launched it. So Gizmodo did this whole attack script thing and he explained how they use a hash bank format. Most of a JAX node works in a hash bank format, but this is a URL and if you need to add a new URL to that to load, you add a hash and a bind and then you add the rest of the path to the URL. This was basically invented by Google because they wanted to index a JAX URL. So just summing up everything. Okay. Hi, I'm Lee and I'll be explaining what we did for the seamless browsing experience on NH7. Okay. So he started something about hash bank URL. I'm pretty sure you guys have seen it. If you don't understand what I'm talking about, I'm talking about we have seen these URL formats. So this was a world of format which was used a while ago to load a JAX content. So the thing is there are several challenges when it comes to loading a JAX content. One thing is the browser location. The URL and the location bar doesn't change. There's a challenge. How do you change the URL over there? The other problem is if there's no JavaScript in the browser, what do you fall back to? What happens then? And the third challenge is how does your search engine index content which is loaded by JavaScript? Because we are essentially a music magazine. It's not a problem for, let's say, Twitter or something or Facebook. We need not index content like it's not content maybe or something. But we had to index content. All our content needed to be indexable by Google and search engines. So that was also another challenge. So I'll explain how we got through all the challenges. The hash bank was the initial system which was started by Google. This was started because basically any hash value appended at the end of the browser can be read using JavaScript. So you can write JavaScript code over this value and load content based on that value. So you can load content and on the page move when you click on a URL with a hash in it. You can write JavaScript to inspect the hash value and fetch the relevant content. So a very popular sign which has this is obviously Twitter. It uses the hash value. So there are several problems in this. One is the URLs are hardly straightforward. They're not like proper URLs. They don't look clean as such. The Google has a specification for indexing this content but we haven't done it yet. So the Google has a specification. I cannot show it to you right now. It has a specification for indexing content in hash bank URLs. But the problem is this is only Google. Other search engines won't be able to index this content. And does it matter? Yeah, does it matter? See the thing is it's not about getting your content across to Google every time. The thing is when your content is fetched, if suppose that there's no JavaScript, or suppose that the JavaScript breaks, the content should still be visible. That's the thing. So there's a bunch of issues with most sites. You would try this any link you get in Twitter. Click on it. It would go to twitter.com. Then twitter.com would redirect you with a hash bank to the URL. Even if you add a relatively straightforward URL. Even if you have twitter.com. And you click on that URL in your browser. It would take you to twitter.com. Then there would be obviously some htx's rule there. You should take that URL out, put a hash bank in, and then redirect you back to the actual URL. Which is how the resource allocation happens. That is really, really broken. Because A, it takes you three, it tries the amount of time it takes you to reach that link. Because there is a redirect in the loop. Two, if JavaScript breaks, and it breaks quite a bit. You actually don't get to the link at all. Right? And this happens a lot. The DAIC is more or less with this approach. They're JavaScript that had an issue, and none of the site pages work. Because everything is so heavily dependent on your JavaScript being loaded. A, and being working 100%. Right? So one of our big tasks was A, to make it work without JavaScript as well. Which, at that part of time, no one had a really clean implementation of. To make sure that the browser back button works. Again, Gmail does this really, really well with hash banks. But now they've moved to history API. But to make sure every time you get back the same thing you expect happened. You go back to the last page. And that needs to happen without your music pausing. So every browser control is actually in JavaScript. So like I was saying, it's not just about getting the search engine to index the content. The thing is if JavaScript breaks, at the very least you should be able to see the content of the page. That's also a problem. The other thing which he again mentioned was, when you're fetching the page, your page request completes. Why should your browser make another request just to fetch the content again? It's like multiple requests just to fetch the content. So that's inefficient. And third is obviously breaking the back button. So there was this while ago. You have these just as an anecdote I'll give you. There is this very popular link sharing site called Reddit. So there was this outcry about people posting Twitter links and sharing Twitter links. Because what happens is if anyone clicks on a Twitter link, and then you try to go back to Reddit, it doesn't work. What happens is it completely breaks your history. It goes over there. Then it redirects some other friends somewhere else. And the back button doesn't work. I think they have fixed this now during some other act. But this was a great big problem with them before. So there are other ways. These are not all disadvantages. These are not all like fixed disadvantages of R&D. Like for example, the back button is fixable in R&D nowadays. They have discovered a way to redirect it and get it to work. But like the indexing thing and the HX loads and all these are still problems with the hash bank developers. So HTML5 introduced a new sort of specification which allowed you to modify your history, your windows history. So there was always an object called a window.history object which allows you to just navigate forward and go back in history. But HTML5 added three new functions to it called push state, replace state, and pop-screen question mark function. Sorry, it's an event. So what push state does is it adds a new event. It adds a new item in the history stack and pushes it to that position in the stack. So what it basically does is it just changes the URL. And it introduces a new history state. So and replace state what it does is instead of pushing a new item it just replaces the current item in the stack. So at the all pop state event it's called every time you press the browser it's forward or backward. So using these three functions you are able to completely like customize your JavaScript role experience. And I have some code with me but I have to show it on my app. So I've written a simple demo. Can you guys see that? So this is just a mix. There's a little bit of plash key code here and then it will help me out over here. So basically I'll explain some of the things I've learned. I'll start off from here. So basically firstly the thing is all the clicks need to be handed using JavaScript. So initially they won't work with the normal this thing. So I have a bunch of exceptions over here. Which is like if the click has class no Ajax then you know don't handle it using JavaScript. And what I do over here is if I check if the click the domain of the click has the same domain as the site you're using. If it's an external link you just open it in a new window. Or if you're handling the click using your control key or your meta key or you're using your middle mouse button just open it in a new window. These are all exceptions. You don't need to use JavaScript load in these instances. Otherwise or if the target is blank I can open it in a new window. Otherwise what you have to do is I call the hand click function over here. So I have written a fallback to the normal hash bank URL also over here. In case HTML5 is not supported. HTML5 is not supported. So the way to check if HTML5 is supported is to check if the push state function exists. That is the simplest and easiest way to check it. You create a state object which stores the current you are in. And you push the object into the stack. That's all you do. Otherwise I'll explain this part later. The other plugin we have over here. And there is a load content function. You're pushing the current URL into the stack. Yeah, the current URL. No, actually it's just in your side. No, I'm pushing the URL to be loaded into the stack. So the new state will have the URL of the present of the state. And the load content function basically what it does is it just fetches the content using Ajax. It finds one dip inside your body and it just inserts the content inside that dip. So there are one or two problems with this. First of all, the URLs are always the same. I mean, it's like if your page has a header or a folder or something, you cannot fetch the entire page and use it inside the page again. So what I do is I just pass a special argument for a JS load to it. And in these pages, I check. In the header itself, I check if the argument is set. If it's set, then I just exclude the header. I don't include the header again. So it's like a simple hack to prevent the content from loading again. And down here, I just have the main container dip which is there to display the content. So I have a simple demo here. So I'm just loading the index page URL and I can show you the network tab in the Chrome Inspector. So now I'm loading out of the page. It's like it's not fetching a new page again. It's just fetching the content for page one using Ajax. And you can see from the response tab that it has only got the internal content, not the entire HTML page. So it just fetches that content and puts it inside this demo. Which is the dip to display the content. It's the same thing with other pages. And if you go back, I didn't explain the on-pop state problems. So on-pop state event is called. Every time you press your browser's forward or back button. So what it does is, it has an argument, the event handler. That will contain the state which you pushed to your push state function. So that will, I have stored the location over there. So I just use that location to load the content again. Based on your forward or back button. It's like you go down the stack or you go up the stack. The new state gets popped out. So you just examine the URL of the new state over there. And you just load that out. And this is another thing I've done. Each page. The app is browser not supported with the history API. Then you would fall back on hash times. I'll explain how it does that after I complete this. So another thing which I've implemented is. It can't handle. The thing is, I have a different htaccess file. This is the demo I've shown you. So I probably have another htaccess file which will specify the cache address. Based on whatever that I have finished. So I'm not talking about the htq address. This is not about the htq address. I'm talking about the html data. Like your tool bar or your sidebar or something like that. That need not be fetched again. And it's paid to the game controller. Still a proper htq data. Yeah. I'm not talking, sorry about that. So another thing all these pages have is. They have their own bootstrap function. To invoke like to execute some JavaScript code. Each time each page is loaded. So what I do is every time I load some content. I just execute. I just check if there is a bootstrap function. I just check if there's a bootstrap function and I execute it. Oh yeah. So the bootstrap one, if I know the content you pull or? In the content I pull. Depending on what each page has. So each page has its own JavaScript. So when you pull a new page you have to execute all the JavaScript of that page. Right. But then the page doesn't have its own JS files as such. No. I mean all the common JS files are abstracted out from the common JS which is included in you. This is per page. Whenever you do a special page and it has specific JS of its own. You basically call the bootstrap function whenever it's loaded in JavaScript. So basically JavaScript pulls the content, puts it in the DOM, calls the bootstrap of their own page so it set up the way it works. So that's why I have a bootstrap function for each page. Otherwise also the URLs remain the same if I just load one of these URLs in a new tab using a normal request. It just works because in this page also I just include the header and it just goes about executing it. Because over here I have just given another check once the page loads if the bootstrap function exists which is executed. And since it's not loaded by Ajax, I just include the header right away. So that works over there. I guess that's about it. You can see. Just one quick question. I am not asking how are you checking if the bootstrap function exists now. Because if you load more pages the previous bootstrap function would have already been there. But it gets overwritten. Oh another thing I do is I nullified the bootstrap before loading content. I mentioned earlier bootstrap equal to zero. I clear out the bootstrap. Otherwise what will happen is if a new page is loaded which doesn't have bootstrap defined and you try to invoke it and it just another previous type of bootstrap. So I clear out the bootstrap over here and I load the content. So other tools are crashing. As you can see this is page one. This is page two. You can see it's out of nowhere. This has been executed by the bootstrap function. So once you navigate it forward and backward it just executes the bootstrap again and again. And would the process be easier? Has it been done? Has it been done? Has it been done? Has it been done? Has it been done? And this is one link which I've given with class no Ajax. In case in your application there are some links which you don't want to be loaded by Ajax for certain reasons. And just an external link which just opens up a new page automatically. And I'll explain about, quickly I'll explain about the fallback to hashback you are using here. There is a plugin called jquery.history.js. What it does is, you just pass a function to it as an argument which gets executed every time the hash value changes. So you just check if the content has been loaded the first time. Otherwise you just load the content. And over here, for the handle click state, you just use doto.history.go. It handles it very well. It just adds an hash before it. You have to specify the exclamation mark yourself in the link. Which I just added manually in the code. And if I have to, I just add manually in the code and I just fetch it. It just handles it very simply. You just have to use doto.history.go of the URL. And over here you just have to initialize it using doto.history.ion id. That's all at this instance. It should be something. I guess yeah, that's about it. Does anyone have any questions? How does it know when the hash point changes? Is there an event or like they keep polling for it? They will keep polling for it every once in a while. I don't think they use it using events. And this whole thing supported on mobile? Like if I support the Safari app, I don't know. Yeah. In the US, they just create the APIs on mobile. And on the Android? Android, it's all supported. But on the phone we actually just have a completely different mobile. Right. But otherwise it's supported. So this works in Chrome. It works in Firefox version 4 onwards. At IE9, it doesn't work. The HTML5 history API. So it falls back to HatchMang URLs. So I'll show you that also. The vision is not big enough. But I think they're valid in IE9. They're valid in the latest version of Oprah too as it turns out. Keep on getting these Oprah updates. I've never seen her do it. So I can't demonstrate the HatchMang because I don't have an older browser only right now. But yeah, so this should work across all modern browsers right now. Anyone has any questions regarding the specific JavaScript role part? I'm curious about why does Twitter still not use something like this? Why does it still have like an explanation of HatchMang? I don't know myself actually. I really don't know why they don't know. Like a lot of things at Twitter, you don't know what they really think. Even Facebook, in fact, until very recently they were using HatchMang URLs. They rectified it very recently. See, one of the good things we realized with this system is when you hit direct links, there's absolutely nothing coming in between the user and his perception that you're on some system where it's an attack. Direct links just work the way you expect a web page to work. It's only when the user interacts with the site, it clicks more links as JavaScript can get in. So there's nothing in HD access which comes in the way of URLs being used. Everything's done on client-side JavaScript. But where does Google come in the future in terms of indexing? Because as far as Google is concerned, it just goes to the page directly and gets the content right? Correct. So, I forgot to mention that part here. In any of the links, we don't have any HatchMang published because that's just the fourth part. So all the links don't have HatchMang. So the links are easily plaudible by Google. Once they reach the page, the content is always there. So that's also easily plaudible by Google. And you always have the seamless page experience so the music always continues to play. Yeah. So I do a quick run through. I have five minutes to go through this. I've done a bunch of this stuff. But I'll tell you what the basic problem is. Any of you are trying to use ht-1.5 video or audio, you have to figure out what each browser supports. On audio, Firefox 3.6 plus supports all in Google. You might see there is not one single codec which is supported across the board. So you can't use one single native codec and say, I'm just going to use this file format and all the audio, your simple audio controls with your source mp3 world across the board. An option to that is you can specify multiple source files. But that means re-encoding every file you have in multiple formats. And the amount of files we have that's not practical at all. And the control which you specify in your audio tag basically comes with four controls which can be accessed through JavaScript. So basically you want an audio tag but you don't want the default control because you want to theme it your way. So they give you in JavaScript access to four functions. The main boss can play type and buffer. So our biggest challenge was how do you take these four functions and integrate it in a seamless way in which even if there's no ht-1.5 audio control available, it will still work with our flash drive. So we have audio ht-1.5 as the default with a fallback to flash. The simple design that we were trying to get across. You can find a classical playlist which basically gives four or five objects to anyone controlling it in the planted. It allows you to play a file. It basically feeds a file. It allows you to pause, forward, rewind and seek. Seek is if you want to skip for beautiful clients. And it figures out whether it's an html5 control or a flash control in its background. So this is your simple audio id file which says the buffer is let the browser like manage its own buffer. But the problem is when there is no support. First we check if audiophile.length if we have some amount of the file cache. And you check the file contents and figure out if this file can be played by the audio tag itself. Which can be played natively. And then once you figure out whether you can play natively or not. You can see that if you can play natively then you bind audio to the audio file which is the id of your audio control. Otherwise you use the flash player control to load it. But the fun part is how do you make the flash player control work exactly like the audio control? Because you don't want multiple... You don't want to say this is not played on flash player. This is not played on boss flash player and so on. So we came up with something, a playlist. Which is probably the nicest EP lights of Koda ever in it. Basically what it allows you is it allows you to bind any existing dim on the browser. To an SWF file. So you'll see this is the SWF object file. Which basically plays the MPP file of audio controls not available. The JavaScript bridge back from flash into this object. So whenever for instance play happens you get this dot boss. Because it's this dot object dot boss which is the SWF object which is created here. So you go around here. There is a playlist of id or dip which we create. Which has the content of the flash file. And then there is a bridge setup where any player or boss comes to playlister. And it figures out whether you need to push this to audio. I mean whether this needs to be transported to flash in the same way as an audio tag. So you can see that these are the controls. So we do when it's ended you get a flash control back saying that this file is ended. And then you trigger and end it on to the main JavaScript file which will then handle it. That's exactly how the audio tag also works. So this one you can see that this approach of the bunch of interesting problems. One we figured out that if you put a flash file inside a dip you couldn't theme it. Because if you theme it any CSS property on to the dip which we had an embedded flash file. So I think there was we had a comment here somewhere saying that don't do that. So we had to like embed the flash of the callback exactly on the body itself. Because the flash file had if you add any CSS properties on it it just wouldn't work. Okay so since we're trying to start with like yeah let's just take questions. The styling thing you know I didn't get it right. So if there's any CSS styling on it they want to say it's the flip file embedded in that. Then they give me no callback from the SRF file back to JavaScript. No the callback from the flash file to the JavaScript which is not working. So the flash file has a bunch of external problems when a file ends or it begins to play. It's then called the dorsal bridge. And the dorsal bridge which was broken in that dip on which you embedded the flash file had some styling. So we had to embed it on the body tag itself because that's the only way to upload it. Embed is the flash file is the face is quite buggy actually.