Video hosted by Apple at devstreaming-cdn.apple.com

Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2011-515
$eventId
ID of event: wwdc2011
$eventContentId
ID of session without event part: 515
$eventShortId
Shortened ID of event: wwdc11
$year
Year of session: 2011
$extension
Extension of original filename: m4v
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: [2011] [Session 515] Using HTML5...

WWDC11 • Session 515

Using HTML5 Offline Storage

Internet & Web • iOS, OS X • 49:59

HTML5 Offline Storage refers to a collection of technologies that can be used in a variety of ways to improve your web content. See how to use Offline Storage to reduce web page load time, or how to make a web application that can be used even when users don't have a connection to the Internet. Go beyond the basics and discover best practices for handling cache size limits, responding to a cleared cache, debugging offline storage capabilities, and more.

Speakers: Andy Estes, Alexey Proskuryakov

Unlisted on Apple Developer site

Downloads from Apple

HD Video (335.2 MB)

Transcript

This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.

Hello, everyone. My name is Alexey Proskuryakov. I am an engineer on Safari and WebKit team at Apple. Welcome to session 515, Using HTML5 Offline Storage. There are more and more mobile devices on the web these days, and I'm talking about notebooks, tablets, and, of course, mobile phones. These devices are commonly connected to the Internet over wireless networks, and wireless networks are not as fast as wired ones.

Even worse than that, they're sometimes offline. And these are not new problems. You get offline when you're on an airplane or when you're in a garage in a basement. But now user expectations are changing. Your users are likely to get frustrated when there is no signal and they cannot use their apps. They have grown very dependent on their mobile devices.

So if they see something like this, they won't be happy. And what does that mean to you as a developer? Well, obviously you want your site to load and work as fast as possible on mobile devices. And that means that users will be more likely to come back to your site, more likely to use your web application often.

If at all possible, you also want to work offline so that users could be more dependent on your web application, and again, they would use it more often. And finally, you don't want to spend too much time on that. You have a lot of other work to do. You don't want to rewrite your whole site. to embrace the new technologies. And you want your site to work in all modern browsers on both desktop and mobile platforms.

So these are the technologies that I'm going to talk about today. First, I'm going to give an overview of the technologies that are available for offline use. I'm going to talk about development tools and debugging, since this is key to bringing your app to the market in time and in great shape.

And of course, I'm going to talk about what's new in Safari. And there are quite a few very nice new features in this area. So I'll start with talking about storing resources. And what do I mean by it when I say resources? Let's have a look at how a web application looks, what it has inside. Well, the web application consists of a number of files, like HTML files, CSS style sheets, JavaScript files, images, like Bing images and JPEG images.

It also needs to store some data on a user's computer. It can be as little data as credentials to connect to the server, or it can store preferences. If it's a game, it can store high scores or users' progress. If it's a word processing application, it can store a whole document offline.

And being a web application, it obviously needs the connection to the cloud, a connection to the Internet, so that users could share their documents, share their high scores and achievements. That's what a web application is. These files is what I call application resources, files from the top part of that chart.

When working offline, you want all of these resources to be available on the user's computer. So kind of like the regular HTTP cache, but with the regular HTTP cache, there's no guarantee that the browser won't evict some of the resources, no guarantee that it will download all of them.

You want more control over caching. So how do you do that? Let's have a look at the main HTML file of your web application. Say index HTML. And here's what you need to change to start using offline cache. It's basically just one line. And of course, if it's one line to start using a new technology, And this line is a reference to a different file. And obviously, all the magic is inside that file. Let's have a look at that file.

The application manifest file can live anywhere on your server. In this example, it lives alongside, in the same directory as index.html, but you can provide...

[Transcript missing]

All these resources will be downloaded and stored on a user's computer for offline use or just for use as in a cache.

There's one thing missing here. I talked about HTML files, scripts, images. But you have told us very clearly that a modern web application actually needs media files. When you're writing a game, It needs sounds. And I'm very happy to say it, that Safari now supports media files in offline application cache.

Let's have another look at the diagram of a web application. Besides resources, there is offline data, and there is connection to the Internet. What are the technologies that enable each of these boxes? I have already talked about HTML5 application cache a little. For offline data, it's local storage and SQL database. I will be talking about these in more detail later in this session. And for network connection, it's XML HTTP request, a technology that you're all very familiar with. And it works, just like always, with one exception. It doesn't work.

All network access is blocked in web applications that use offline application cache by default. And this is actually a good thing. It makes development easier. When you are creating your offline application manifest, you don't want to disconnect from the network just to test if everything is there, how it works.

I've been talking about how frustrating it is to users to disconnect from the Net. And obviously it's just as frustrating to you as a developer. You don't want to lose your email, your instant messaging connections. This is why application cache blocks all network access by default, making development easier. And of course, there are ways to work around that, and I'm going to be talking about these right now. So this is the same application cache manifest file that lives somewhere on your web server. But now there is one more section, a network section.

In this example, we have a web application that wants to use Flickr API, the Flickr Web API that's exposed via URLs on the web. And adding Flickr URL to network section achieves that. But there's a number of URLs used by Flickr API. And it would be difficult or even impossible to list them all. This is why the network section is checked by prefix. All resources that match Let's start with the same string that you have in the network section. Can be retrieved from the network. So just adding this single line enables access to the whole Flickr API.

And that's just perfect for an application that is designed to work offline. You list all of your resources. In the first section, you list a few prefix strings for network connection, and you're done. It's not as easy for applications that use offline application cache just for caching that are not intended to work offline. They have a lot of resources that need to be retrieved from the network, and listing them all would be time-consuming and error-prone.

We think that you have better things to do with your time. And happily, the HTML5 Working Group agrees. So now there is a way to specify that all resources can be accessed from the network by default. Just put an asterisk in the network section, and now the technology is perfect for caching. So this is basically all. You need to do about offline application cache to start using it. And there's just one more technology that I'm going to talk about a little. And that's the fallback section.

So, say you have some images or some other resources that you would like to access from the network when working online, but that are not essential for the operation of your application. For example, some preview images. So if you create an image tag with a link to that, And the user is offline, they will get a broken image icon. That's not a great user experience.

To avoid that, you obviously use this fallback section. Lines in this section have two parts. The first part is a URL that might be accessed online, but if it's not available, a URL from the right part for a resource that is cached inside the application cache is used. So in my example, you could use a black image as a fallback or an image that says "Preview not available," something like this. Anything is better than a broken image icon.

So these technologies are all standard, supported in most modern browsers, and the browsers are deployed on computers of a lot of users. But you can do more if you target iOS. There is a number of Apple-specific tags that you can put in your HTML file to customize the behavior of your application on iOS. For example, you can say that you would like Safari to hide its user interface elements. Or you can specify an icon to use when the user puts a link to your application onto their home screen.

I won't be talking about these a lot. They are very well documented on Apple developer's site. And there was a great session earlier this week called Hidden Web App Gems. And if you haven't had a chance to attend that, I highly recommend watching a video. So here's how having an application cache affects the behavior of your application, what you can achieve by having an application cache.

And that's a static picture. The dynamic picture is that you want to deploy new versions of your application. You want to redesign, do any changes you like, like you did before. And the main design principle here is that the process of application cache updating Never leaves you with a mix of old and new resources.

You obviously don't want to have a mix of those after a redesign. And that has... Always been a problem. You have to rename the resources to avoid taking no resource from a cache. You need to specify cache headers and so on. The application cache solves that in an easier way.

So how does it achieve that? When a browser starts loading a page and it sees that there is an offline cache manifest linked from that page, it downloads it and checks if the content of the application cache manifest has changed. If it hasn't changed, the browser decides that the application is the same, and it just uses resources that are stored locally.

What does that mean to you as a developer? That means that if you change some resource, like change a CSS style sheet or edit an image, You won't see it right after loading. That's because the browser sees that application cache manifest hasn't changed. It doesn't even check for your new resources. And to avoid that, you will want to edit the manifest file a little. What I like is adding a comment with a version number.

That way, the browser will check all the resources and download those that are new. So the user has opened the page. The browser has downloaded all the new resources for an updated application cache. What happens next? And perhaps surprisingly, nothing happens. The browser keeps both old and new versions of your web application and continues using the old one on the pages that are already open.

And this is a case of the same design principle. The user has already opened the page. They already have some of their sources on the page. You don't want for a button that's loaded right after the application cache update has been finished to look differently. So the next time the user opens the application, it's then when they will use the new application cache. And I think that's what most web applications want. But just in case you really need to update to the new look or new behavior as soon as possible, there's a JavaScript call for that.

Just swap cache. And I don't really know what's the use case for that, so I'm not giving an example. But there are ways to do that. So what does this mean for users? Application cache update is completely transparent in Safari. And that's exactly what the users want If the web application is using application cache just for that, for caching, users don't need to know that the cache is being updated, that it has been updated. Why would they be interested in that? An application that's designed to work offline, You might have reasons to tell the user what's going on, to show downloading progress, or to tell that now it's okay to disconnect from the network since the application cache has been fully downloaded.

And there are ways to do that. There are DOM events that are dispatched that you can use them for custom UI, for progress. And with this, I would like to invite my colleague Andy Este for a demo of using application cache and using DOM events for custom UI with application cache. Welcome, Andy. Thank you.

Thanks, Alexey. So some of my favorite web apps are games, like I said. I have a game here called The Legend of Sadness. It's written in the style of these great 8-bit Nintendo games, and it's written using Canvas, all modern HTML5 technologies. It's especially great on the iPad. In iOS 5, we have these great Canvas speed improvements, and it works really well. But, you know, I use my iPad a lot of places where I don't have a data connection, where I'm offline.

And it would be great to, you know, still be able to play a game like this in those cases. So let's see how we can use the techniques that Alexey taught us to make this web application available offline. So let me switch to the machine that hosts this application.

I've gone ahead and prepared a cache manifest file. My first line, as Alexey mentioned, is the signature. It's cache manifest. I went ahead and included a version comment. Then I simply listed all the sub-resources of the game. There's about 42 of them. It's a mixture of JavaScript and images and style sheets, etc.

All we need to do once we have the cache manifest created is add one line to our HTML tag, one attribute called manifest, and point it to the URL of the cache manifest file. So I'll save that. And I'm going to switch back to the iPad, and we'll reload the site, and we'll see what happens now that the main resource has a manifest attribute. I've added some logging to the game so that we can see what events fire.

So let me reload. And so here's the logging. The first event that fires is an event called checking. And every time there's a cache manifest, there's a manifest attribute, the checking event will fire. And that indicates that the process of updating the cache manifest has begun. And what it does is it downloads the manifest file and sees if it has changed since the last time we saw it. In this case, this is the first time we saw it. So we're going to download all the resources that are listed in that cache manifest file and cache them in the application cache. So the event we get when that downloading begins is an event called downloading.

And I say we download them, but we do it in a very smart way. If that file is in the HTTP cache and is still fresh, we'll just pull it from there. If it's not fresh, we'll make a conditional request. So we're not necessarily doubling the network traffic just because we're using the application cache. As we go and download resources, the event that fires for each resource is a progress event.

And something that's new in iOS 5 is this progress event has two helpful properties on it. The first property says the number of the resource that is currently downloading. And the second property says the total number of resources that will download. So that's how I can display this 0, 1, 2 of 43 indication. And that would be really useful if you wanted to implement a progress bar, for instance, or some other kind of UI.

So I'm just going to scroll through all these progress events that fired. Finally, we've successfully downloaded and cached all these resources. So the event that fires is the cached event. And that says this resource is now in the cache. And the next time you go to the site, it'll be served from the application cache instead of from the web.

So I'm going to close this dialogue. I still have the start screen of this game up. And as Alexei mentioned, it's cached, but it's not being used yet. It's not being used until the next time that I load the page. So let me go ahead and refresh so I can use the cached version. Now, events fire again. A checking event again fires. And Safari looked at the manifest file and said it hasn't changed. So there's no need for an update. So the event that fires in that case is no update.

I'm going to close this. And the game implements a progress bar as it's loading, and it looks like it's stuck. It's kind of stuck halfway through. Perhaps some resource has failed to load. Another thing Alexey mentioned is that network access is blocked by default. So even though my iPad is online, it can't access any resources that aren't explicitly listed in that cache manifest file. So maybe I missed a resource. Let's go back to the machine hosting this and take a look.

So a helpful debug technique to use in this case is to use Safari. And if I load this in Safari, So if I load it in Safari, I see the same state that I saw on the iPad. What I can do is look at the Activity window, and the Activity window will list all the subresources that are loaded. And sure enough, it's indicating that there's this one resource that was canceled. It was not allowed to load from the network.

That's probably the one that my game needs but is missing from the cache manifest. So I'm going to go ahead and add that. I'm going to add it right here. Resources, tllbundle.js. OK, that looks good. So let me switch back to the iPad, and let's see what happens now.

So I'm going to reload again. So another checking event fires, as I expect. And this time, the cache manifest file has changed. I added that line. So because the cache manifest file changed, every single resource gets revalidated and potentially redownloaded, which is why you see, again, another downloading event and more progress events for each sub-resource.

And at the end, once this is all done, the cached event was fired the first time, but every subsequent time, an event fires called update ready. And update ready means that the update is now cached and will be served the next time you load the page. I'll close out of this. Of course, I'm still in the state where my application has this error.

But here's what I'm going to do now. I'm going to reload it. But before I reload it, I want to disconnect from the network. I really want to be sure that this is actually working even without a data connection. What I'm going to do before that to make this even a little nicer is I'm going to add this app to the home screen.

And I'll, yeah, sure, call it that. I included the right link tag that can give an icon. So now, instead of launching it through Mobile Safari, I can click it from the home screen, just like any other app. So let me go into settings. I'm going to go to Wi-Fi, and I'm going to disconnect from Wi-Fi.

So I don't have a 3G connection. I don't have a Wi-Fi connection. I'm decidedly offline. I'm going to go and launch my demo app. And something interesting happens here. I'm offline, but there is still a manifest attribute on the main resource. So I'm going to still try to update my application cache. So a checking event will fire. Of course, I'm offline, so Safari can't download the cache manifest file and compare it to the one that has cache.

So the event that fires in that case is called error, but this error is totally expected when you're offline. And Safari will continue to serve the most recent version of the application out of the cache manifest. I'm sorry, out of the application cache. So I'll close that, and there we go. There's the game. I'm totally offline, and it's working great, being served from the application cache. Okay, well, back to Alexey.

Thanks, Andy. So you can see that these DOM events really provide a lot of insight into what's going inside the browser, what's going on with the application cache. So I have said it earlier that users don't care what's going on with application cache if it's used just for caching. And that wasn't true. Actually, users care about everything that's stored inside their browser on their computers, and that's because of privacy.

Anything that's stored permanently inside the browser can be used for user tracking. And the most famous example of that is, of course, cookies. But everything else is really just the same. And this is why people demand to have ways to see what's stored inside their browser. And they want to have ways to remove all the traces that a certain site has left inside their browser.

So let's have a look at what UI Safari has for that. Why does that matter to you as a developer? I think there are two reasons. First of all, You're going to use all the same UI when developing your web application. You will want So start with a clean state to remove everything to the original situation.

And secondly, you will want to provide guidance to your users so that you could tell what they should expect, help them if something goes wrong. So here is a new pane in Safari settings on iOS. It's new in iOS 5. It lists all sites that have stored data on the computer, on the iPad or iPhone or Apple touch, and how much data the site has stored.

And this is actually an interesting example. You can see that YouTube, the mobile YouTube site, has stored about half a megabyte of data. And you can bet that it's not all cookies. And yes, I have checked, and the mobile YouTube site uses application cache and local storage, which is cool. And if the user wants to delete all that, they just tap this button. The desktop version of Safari has a new privacy pane in Preferences.

And the part that's interesting to us here, it's basically the same. It lists all the sites that have stored data on the computer. You can see that there are a lot more sites than in iOS, since all sites that have regular cache data are also listed. This can actually also be used for tracking.

And there are ways to remove the data for some or all of the sites. Besides the privacy controls, there are some general maintenance controls that are interesting to us here. The user can reset Safari to a clean state. This is the Safari application menu, the main menu of the browser. Or the user can empty cache.

And this command empties both HTTP cache and application caches for all sites. Which is interesting because the user can delete your application cache, your resources, Without deleting your other locally stored data. So your application needs to be prepared for that situation. So I have talked about application cache.

for storing resources. I have talked about connecting to the cloud. And the last part is storing and synchronizing data. As you have seen in the keynote and throughout WWDC, Mac OS X Lion now supports autosave, meaning that the user doesn't need to save documents if they don't want to. They can just close the application, reboot the computer, start the application again, and their documents will come back. The same has been the situation with the best web apps for quite a while now.

Users of web apps expect That they don't want to save the application, their data, and that their data will not disappear if something bad happens and they need to restart the browser. Obviously, you cannot save to the server when working offline. But even when working online, constantly saving after each keystroke would be prohibitively expensive. It would kill the performance. So we have a trade-off to make.

We want to store all users' data. We want to store it on the remote server because users can start working on their MacBook and then switch to iPad and they expect the data to be there. But you also cannot save all the time because that's just not going to work. We think that the question to ask yourself here for your specific web application is how much data, how much work your users would be prepared to lose without getting too unhappy.

For example, with a game, it might be just fine to be returned to the beginning of a level. If something wrong happens, then you need to restart the browser. With the word processing application, it's more likely that people won't stand losing more than a few seconds of work, maybe half a minute. I don't know. So the answer It depends completely on what users of your web application expect. And when you need to save very often, you can try saving locally first.

And then uploading the data in larger chunks to the server. Then the user won't lose their work. And also, they will be able to switch between machines, between computers. So you save locally when offline, or to improve performance. What to do when the user is about to close a window to close your web application. In that case, there are some DOM events dispatched.

If you get one of those, you know that the user is going to leave your web application, to close the window, to navigate to another site. And that's the time to fully synchronize the data immediately. So what are the technologies that you use to store data? Traditionally, you've been using cookies, but those have a number of limitations. First of all, cookies are severely limited in size.

And even if you can store a cookie, that doesn't mean that it will stay there. The size limit is per domain, and if the limit is exceeded, the browser can evict old cookies. This is not a way to write reliable applications. Besides, all cookies are sent to the server with each HTTP request. And we have seen that for many web applications, the size of cookies dominates the size of the request. Meaning that cookies materially affect the performance of accessing resources from the network.

And besides, cookies are a really old technology, and they don't quite match the modern model of web security. They have a different notion of domain that makes them difficult to program with securely. So we're not saying that cookies are deprecated in any way, no. You're still going to use cookies, for example, for authentication, sure. But we don't think that storing data in cookies makes sense anymore.

So what are the replacement technologies? First of all, it's local storage. It's a very simple API. You can use it pretty much as a drop-in replacement for cookies. It just stores key value pairs, It has the same security model as the rest of the web, origin-based security. And let's have a look at the code, how it's done.

You can see it's really simple. There is a local storage object defined in global object. It's just provided to you by the browser. And you set a property on that, just like you do with the property of any JavaScript object. There's nothing different here. The difference is that when the browser is restarted, the property is still here.

It's stored persistently. And the values are all strings. But you can store... Any objects by serializing them to JSON. However, if you find yourself saving objects into JSON, it might be a moment to consider using a more powerful and flexible mechanism, which is SQL Database. A full SQL database, a full SQL engine inside your browser with everything, with tables for structured data storage, with triggers for maintaining data integrity, with indexes for high performance.

And the API is designed for performance too, even when dealing with huge amounts of data. The reason is that the API is all asynchronous. You tell the browser what you want to do with the database. You provide a function to call when it's done. And while it's working, the browser doesn't freeze, your web application doesn't freeze. It's very good for performance.

And of course, the API has the same security model as the rest of the web. Only sites with the same origin can access the database. Let's have a look at the code. You can see that it's much more code, but it's quite manageable. What are the interesting parts here? Here's the SQL statement. I'm asking the browser to select names and company affiliations of all WWC attendees. And when it's done, a callback function is called. And in this function, I have access to all the rows of the result.

The data is already structured. I don't need to deserialize it. And if something goes wrong, for example, if there's no WWDC attendees table inside your browser, then an error function is called. It's quite simple, in fact. And with this, I would like to invite Andy back with a demo of using HTML5 Data Storage. Thanks, Alexey.

So here I am on Twitter.com. I like to use Twitter a lot. I follow a lot of people on Twitter, and I have this problem where I often have too much data to consume in sort of one sitting. So it would be great if we could use some of the techniques that Alexey has been talking about to maybe cache this information so that I can read it later, possibly even when I'm offline.

So in the first demo, we talked about using the application cache to cache resources, but that's not really appropriate here. The resources of this page are things like its icon and the scripts and style sheets and other images that it uses, things that either don't change or change infrequently, maybe when a new version of the site is rolled out.

But that doesn't really describe the data in the timeline. The data in the timeline is constantly changing. Every second, every minute, there's new data. So the application cache is not an appropriate technique to use there. The appropriate techniques are the two data storage mechanisms that Alexey mentioned, local storage and SQL storage. So what I've done here is I've written a Safari extension to try to cache this information, and I'm not going to go into a lot of detail of the extension itself.

I hope you all saw the extensions session that was right before this, and if you didn't, please watch the video online. It goes into great detail. But what I'll do is just... focus on the part of the extension that deals with offline storage. So let me show you what I've done. I've written an extension that injects a script into Twitter.com.

And it basically extracts the timeline from the DOM and sends to my global page an object that is a JavaScript array of dictionaries. And the array is there's one entry per tweet, and each tweet is a dictionary that has properties for things like the username, the content of the tweet, the message, etc. So once I have that, it's really simple to store this information offline. Now, I could use SQL storage. I could write a schema, and I could write SQL queries to insert this data into SQL, and that would work really well, and it would be really performant.

You know, I'm kind of lazy in this case. I didn't want to go through all that work. I wanted to do something that was really simple. So I decided to use local storage, and local storage is not a bad choice here. We're dealing with, you know, tweets contain small amounts of information. So we're dealing with something that could easily be cacheable in local storage.

So what I've done was I set one property called num_tweets. It simply stores the length of the Twitter array, the timeline array. And then I iterate that array, and I store a value for the name, the username, and the contents of the message. And I just use a convention for the key values of sort of the property I'm interested in, followed by an index into the array so that I can pull it back later. I could also, another way I could do this is I could serialize the entire array of dictionaries into JSON. And then store that in a property as well.

So once we've done that, we can really do a lot of things with that data now that it's in local storage. What I did was I created an extension popover that simply lists this information in a list. And I'm clearly not a designer. Maybe I should go to the CSS talk to make this look good. But, you know, it conveys the right information. It's a list of tweets, and it's not just available on Twitter.com. It's available, you know, anywhere when I'm in Safari, even when I'm offline.

And this isn't bad, but I think we can make it a little better. There's some more information that's in my timeline that I'd be interested in including in this popover. The most interesting piece of information, I think, is the user's profile picture. It adds some visual richness to the popover. It also gives my eyes a way to instantly kind of identify tweets from certain users that I like to follow. So let's see how I can do that.

It seems like it might not be possible with a simple key value store. But there's some tricks we can do by incorporating other technologies in HTML5 to achieve that effect. So I'm going to open another file here. What I have here is a helper function, and it's called encode and store image.

And it takes two parameters. It takes two arguments. It takes a URL to one of those images and then a key, which is the key into local storage where I want to store the result. Now, I could just store the URL directly and just load it in my extension popover later. But that's not going to happen. But that wouldn't work if I was offline. And I'm certainly interested in making all this work seamlessly both online and offline. So I'm going to use another trick.

I'm going to create an image object and give that image object an onload handler. And what that onload handler is going to do is get a reference to a Canvas element that I've created in the global page so it's not visible. I'm going to get the context of that image, and I'm going to draw the image into it.

And once I've done that, I can extract back out of Canvas a data URL. And a data URL is like any other URL. You can use it in place. You can use it in place of any other URL. But the contents of the URL is the image base64 encoded. So the URL is the image itself.

So once I do that, I store it in local storage using the key that I've passed in. And now that I have that onload handler set up, all I need to do is set the image's source property to the URL I'm just loading. The network will load that image, and sometime later, my onload handler will get called and do all this work. So let's add this into my global page. And then let's call it.

So I'm just going to-- the images URL is passed along in this dictionary. So whoops. Nice. There we go. Okay. So now let's take a look at, so first let me, I need to reload my extension. So I'm going to reload my extension. I'm going to go to, you know, apple.com. And sure enough, I can click this, and now I have images, and this is all available offline using a very simple key value approach. So, okay, back to you, Alexey.

Thanks, Andy. It's pretty cool technology, and it also shows the difference between data and resources. You shouldn't think of all images as resources necessarily. And you don't need to update your application cache, basically your application, just to add some data, like in this example. So we have talked about a number of technologies. Those were HTML5 Replication Cache, two technologies for data storage, And how HTML5 application cache interacts with network requests, with XMLHCP requests. And this is quite a bit to swallow.

And a lot of developers have told us, and we have experienced that ourselves, that when you start using all this, suddenly nothing works. And it used to be pretty difficult to debug. It's getting better. Let's talk about debugging offline applications, how you actually bring all these technologies to market.

What do you do if nothing works? Well, now you do just what you do with any other technology. You go to Web Inspector and check Web Inspector console first. We have added a number of error messages for application cache update, and if something goes wrong here, if nothing works, it's almost certain that there will be a message in Web Inspector explaining why.

For a deeper look, you go to Web Inspector Resources pane, and we'll have a look at those very soon. And I have said it before, but I will repeat it. Progressive events that are dispatched And you can handle them from your JavaScript to provide a lot of insight into what is going on there. You can use those to provide UI or to debug. They are really helpful. So what does Web Inspector look like? The resources pane has been redesigned. All the data that's stored locally has been gathered into this single pane.

And the first part of it is SQL database. You can see all the databases that your site have created and stored. There is a nice visual representation. But there's also this little known secret. You can type in any SQL statement, and it will be executed, and the results will be presented graphically. In this example, I select... All entries from WWDC web track sessions that have "offline" in the name. There's only one, so I'm glad you're all here to learn about offline technologies. It's a really powerful tool.

Of course, we display local storage. Just the same nice graphical representation. And you can edit values in local storage as well. In this case, I'm editing a preference. But if your game stores a high score in local storage, you should be prepared to the more advanced of your users gaining incredibly high scores.

Of course, we do display cookies. And again, it's all laid out quite nicely. You can see it here because all the columns are so small, but all the information is readily available. And what's really new here is the application cache pane. Now that we support the asterisk in the network section, It has become even more important to see what exactly is inside your application cache.

You can see it just by testing your application, seeing if it works. So here's the list of all the resources. They have the explanation why they're there in the type column. It's not always obvious, since you don't normally add a manifest file to your cache or the resource from fallback section. And at the first glance, it might be surprising that they're here, they're there. The type column explains why.

So we think that this set of debugging tools

[Transcript missing]

So to recap, I've been talking about a number of offline web technologies. And we think that these are becoming Very important. If you have previously optimized your site for mobile platforms, this is great. But it might not be enough anymore.

People want the applications to work even faster. They want them to be dependable. They want to play a web-based game in airplane. Why not? and all the technologists are there. If you have previously tried using them and found them lacking, We think that you should try again. The platform has become more powerful. The specifications have been expanded. The implementations have improved a lot. And developer tools have become much better, making it more practical to work on these technologies. And speaking of that, Safari has great development tools. We think that this is exactly what's needed to work on these applications.

For more information, please contact Vicky Merlin, who is a Safari and Web Technologies Evangelist at Apple. All these technologies are open standards. And if you want maximum detail, you can go to the standards themselves on WattWG and W3C sites. There's also great documentation on Safari Development Center on developer.apple.com. I personally like this documentation a lot.

To discuss the technologies and to ask questions, please go to Apple Developer Forums. And also you can go to WebKit Open Source Project. WebKit is the basis. under Safari, the open source rendering engine. And their project has a mailing list and an IRC channel if you prefer these methods of communication. I recommend, I have already mentioned that, a session that was earlier in the week. Session about hidden gems for web apps. And thank you.