Transcript
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
[ Silence ]
>> Well, hello again.
For those who have been here
in the previous session,
this is the second session
of our two-part Web
Inspectors extravaganza today.
My name is Antoine, I'm
an engineer on the Safari
and WebKit teams and I work
specifically on Web Inspector.
And so, for those who have been
here in the previous session,
this is a more advanced session
but we will cover some ground
that you may have seen
from the previous session.
We'll try to reduce to overlap
so don't worry, but make sure
that even if some of the content
seems familiar, we always going
to go in much greater
detail than what we've seen
on the previous session.
So Web Inspector is the
Safari developer tool.
It's the one stop shop for you
to inspect, tweak, analyze,
and debug any problem you
may have with your web page.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And it's a tool that runs
on the Mac as part of Safari
and surely enough, you can
use it to inspect pages
and Safari on your Mac.
But we've set it up so that
with remote web inspection,
you can always inspect content
running on your iOS device
and iOS Safari, or even
your own app that you wrote
for iOS that uses UIWebView.
And the first thing I'd like
to do is to go through some
of the changes we've made
into the user interface
across last year.
And to get a sense of our
progress, let's turn back
to a year ago when on this
stage my colleague team Hatcher
introduced Web Inspector
for Safari 6.
And remember that at the time,
the banner feature Web Inspector
was that for the first time,
we added support for
remote web inspection.
And what that meant is that
you could finally inspect your
content loading-- loaded,
sorry, on iOS devices.
That was really a
massive breakthrough.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And we thought that while doing
this would probably gather a
whole set of new users that will
be a lot more used to Xcode,
you know, people that develop
app on iOS are using Xcode.
So we took the cue of the
design lead of Xcode 4
to change the complete
appearance
of web inspector in Safari 6.
So, that is Web Inspector looked
up until Safari 7 is coming out,
and we heard a lot of feedback
about this user interface.
More specifically, we heard that
the organization of icons to--
on the left sidebars and on the
right sidebars was a little bit
confusing and that they
were also a little bit small
and lacked a little
bit of color.
It wasn't just super easy
to learn about the interface
if you weren't already familiar
with Xcode or Web Inspector.
So we took that comments--
those comments to heart
and we worked hard to
improve the user interface
of Web Inspector in Safari 7.
And so, I'd like to walk
you through one major change
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that we've made and
those changes were made
to the tool bar.
And the tool bar is
completely new in Safari 7.
And the first thing
you'll notice is
that to control the display
of your navigation sidebars
to the left with those
three icons, resources,
timelines, and debugger.
Console is a different panel
that we'll go back to later.
And these are icons
that you can control,
you can fully customize
them, they're nice and big
and have a label by default.
We can turn the labels
up, put them to the side,
make the icon smaller, and you
can fully customize the tool bar
to your hearts content.
And you can just do that like
you would in any other Mac app
by just come and click on the
tool bar and customize it.
It's really simple.
OK. Let's move on
to the activity
to your another brand new
thing as part of the tool bar.
I've already talked about
this in the previous session
but let me refresh you memory
or introduce it to people
who may not have been here.
To the left, you have
the first two items,
we'll give you information about
your resources on your page,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
the number of resources
and the aggregate size
for all those resources
put together.
And these are not
just informational.
You can just click on
those and jump straight
to the resources sidebar
and start digging into them
to find out more details.
Likewise, you can track
the low time of your page,
the time up to the load
events in a rolling counter
from the page below to the time
the load even fired and click
on that to jump to the
timeline and find out more
about your network load time.
And finally, to the right,
we have three icons
devoted to the console.
You can try plugs,
errors, and warnings,
and this obviously would take
you to the console by clicking
on them, and what's
even cooler is
that since we added filtering
support to the console
in Safari 7 and Web
Inspector, clicking on either
of those items will
take you to the console
and filter the content to match
where you just clicked on.
So for example if you
click on a warning,
you'll see only warnings
in the console.
If you click an error,
you'll see only errors.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And of course you can
filter back to all messages
from the console very easily.
And the last item to
the right is something
that is actually specific to
when you're inspecting Safari
on the Mac because it's
controlling the docking mode
of Web Inspector.
Web Inspector can run in a
stand-alone window like this
or it can be docked to
the bottom of your page.
We've always supported this.
But something we heard
a lot of feature request
for is the addition of a mode
where the inspector is docked
to the side of the page.
So this is something
new in Safari 7.
You ask for it and
you've got it.
So, now let's move on to or the
real meat of our presentation.
And I wanted to show you
a lot of new features.
And to do that, I'll ask two
colleagues of mine to come up--
come up on stage and show
you some great demos,
really compelling.
They will put a lot of our new
features at work in three tasks.
And if you've been here before,
you'll be familiar
with those tasks.
The first one would be
inspection tweaking then we'll
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
go and take a look
at the performance
of our page and analyze it.
In this case, it will be
layout and rendering specific
and we'll finish with
some JavaScript debugging.
And again, this sounds like the
outline of the previous session
because we think these are core
tasks for you as developers
but the content in this
session is completely different
and we'll be looking
at different features.
So let's start by taking a
look at inspection tweaking.
And to me, inspection
tweaking is about experimenting
with the content of my page.
It's about experimenting with
the DOM structure, the HTML,
but I think most importantly,
it's about interacting
with the styles.
And the style is
really, to me, the bread
and butter of Web Inspector.
It's usually the first
thing I want to do
with Web Inspector is tweak
the appearance of my page
and make sure it's
pixel perfect,
matches the design I want to
achieve, and it's really kind
of the stable feature
of Web Inspector.
But that didn't let us rest
on our laurels and we want
to make sure that we had
the best experience possible
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
for styles editing and we have
a completely refreshed styles
sidebar in Web Inspector
in Safari 7.
So, we still support things
that we've always supporting.
We still has syntax
highlighting,
we still have great
auto completion
where we know exactly what
counts the CSS properties
supported by WebKit since
Web Inspector talks directly
to WebKit.
We got some awesome
great new features.
The first thing, and you'll
see that in great details
in the demos, is that you can
just start clicking anywhere
where you see CSS code
and just start typing.
And as you type, you have auto
completion, syntax highlighting,
and it just behaves just
like you would expect
a great text editor
to behave except now
you're in Web Inspector.
It's just a series of many
text editors one for each rule.
It's just so awesome.
And another thing that we
found was commonly used but not
as accessible as it should
be from the user interface
of our previous version is
the ability to add a new rule.
So we've made that a lot easier.
There's a big button
in the style sidebar,
you can't miss it, and what it--
and we've also made it better
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
such that when you press
that button, it will look
at the currently selected
element and it will try
to generate a CSS selector
for the new rule that is
as specific as it can.
So for example, if your
element as an idea on it,
we'll generate a rule
for that specific idea.
It's really, really useful.
And finally, at the top of the
styles sidebar, we added a way
for you to force
some pseudo-classes
to be applied to our element.
And one that I think is
tremendously useful is being
able to turn on the hover
pseudo-class which is something
that if you wanted to tweak the
hover style of your element,
you'd probably have to
go back through the page,
roll over the element
in question,
and then see what it
does and then go back
into the inspector changes,
roll over back and so forth.
It's just not very convenient.
We've made that a lot better.
And again, we'll see
that in demo right away.
Another thing that I think is
really cool about styles in CSS
and Web Inspector is that
we've made it so that style
that may look great in Web
Inspector was actually something
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that came through
looking horrible before.
And the way we make
it look good is
that we support pretty
printing and this littler button
at the right and it's a button
you may not even have to use
in practice because we
automatically identify
when we download minified
CSS content like this
so that we can display it in
a much nicer way like that.
And so, to walk you through some
of those great new features,
I'd like to invite on
stage my colleague Brian
who will give you a great
demo of advanced styling
and experimentation
in a web page.
[ Applause ]
>> Thank you Antoine.
Check, check.
Good. So I'm actually
really excited
to show you these demos today
because Antoine spends
the entire day working
at web content, allow
these features go along
with my job a lot easier.
So to show you, let's
pop up in demos
that we've been working on.
As you can see, it's a
very simple photo gallery.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
I have pictures of
me and my very close,
very great looking friends.
And as I look at this
side, there's a few things
that I think I can improve
on that I didn't think
about when I was
actually building
and it in my text editor.
Friends and I think of that.
This header sits up to top
as I scroll through the page.
And also this feels very static.
I mean that there is a
cool little hover effect
as I now search of
these thumbnails.
So, let's focus first
on the header.
So to get started let's
open up the Web Inspector
and it causes the event session.
We're going to use the keyboard
command, Command-Option-I.
So this should look
familiar to you.
Now the first thing
I'm going to do
as I reminded you was I
want to fix the header.
So let's zoom in here
into the DOM sheet mode
and let's use the
arrow keys to drill
down into the document
and get our header.
But go over to the
right, you'll notice
that we have some
preexisting styles associated
with the header.
But I want to add a new one.
So let's zoom in closer and
see how we can use the styles
detail bar.
Now because it says a
free-form CSS editor,
I can click anywhere, press
Enter and start typing.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So because you want to
just stick to the top,
we're going to adjust
the position property.
So let's start.
You'll notice the
autocomplete format.
Now, instead of guessing
what the value is
because this has WebKit under
a hood, I can press Escape
and so bring up all the
options available to me.
So, I can go through
it when I want.
And in this case, you
want to use WebKit sticky.
But there's something
you might have missed.
So I'm going to press
command Z to undo this
and I'm going to zoom out.
I want to scroll down to
the middle of the page
so that the header is invisible.
And now, watch what happens
when I click Escape again.
[ Pause ]
There you go.
So as soon I press Escape, it's
going to immediately apply the--
immediately apply the
change of value to the DOM.
So I can move through all these
options and quickly see how each
of this property is
going to fit the layout.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So this is the a lot
better than going back
and forth reaching your editor.
So I can nearly get in-- I
can get immediate feedback
on what the changes
going to look like.
So in this case, I want
to use WebKit sticky,
press Enter to create the
change and we're done.
Something else, I want to
fix is I also have a footer
at the bottom of the page.
Now, I want the footer to have
the same style as the header,
so let's go back into
our style detail bar.
And you notice that I
have shared style which is
in my header and footer below.
So I'm going to go ahead and
cut this because I can do this
since it's free-form, click
anywhere, paste it in,
and let's zoom out
and take a look.
So now we had the footer stick
into the bottom of the page
and the headers stick
on to the top.
So it's looking much
better already.
The second thing I
want to do is I want
to have a nice hover effect when
I roll over one of the images.
So to do that, let's
flat one of the images.
And I want to inspect the image
element that's on the page.
So to do that, I can right
click on the image element
and choose the inspect
element option.
You'll see this fit in directly
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
into that note in
the content view.
Now, if we go over to the right,
we'll see we have some
associate styles to this image.
Now, when tweaking styles,
I like using detail bar.
But I like writing new styles
directly in the CSS file.
And I can get that easily
in Web Inspector by clicking
on this link to the right.
And this is going to be directly
to the area in the style sheet
that I actually find that style.
So now I can go ahead and then
I can start adding to this.
So just like one of text
editor, I can start typing,
just add a hover
effect for the image,
and notice as I type is
going to autocomplete
and also syntax highlight
for me.
So for this, let's add
a little zoom animation.
So, I added WebKit transform,
we're going to do scale,
and let's make it
three for 300 percent.
So as you roll over the images
to the left we can see that.
Let's go over there.
We can see that it's
starting to work.
But this is a little,
a little jumpy.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So let's go back to our style
sheet and add a transition.
And notice the autocomplete
as well
and let's do it for
WebKit transform.
Let's take it 1.5 seconds
and let's make it nice
and smooth ease in our curve.
So you notice that
as I roll over this,
I get immediate feedback on the
changes that I made directly
in the style sheet resources.
But I think this could
be tweaked a little more
and it's really hard for
me to go back and forth
between the style sheet
and then rolling over.
I want a better way
to build with a subtly
and finest this animation.
So, let's go back to the
viewer where before we're able
to see the style details.
To do that, I'm going to
use the navigation bar
on the top here to go back.
And as you can see it brought us
to area where I work previously.
So now what I can do is I could
use a new hover pseudo-class
on the top.
And you notice that when I click
on this, the animation is going
to be applied to the
image that I select.
So I can click on and
off to see the effect
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
but even better I can now see
the hover styles that I added
in my resource directly
in the detail sidebar.
So now I can go ahead and tweak
this through where I want it.
So let's make it a little
faster, maybe a quarter
of a second, and
also, just the scale.
So let's go back,
that's a little too big,
a little too small to, more
point to, that looks just right.
Let's click off and take a look.
So it's looking a
lot better already.
Now, one thing I want to point
out to you is that the changes
that I made to the CSS
in the sidebar are going
to be reflected in
the source code.
So let's click through back
to our CSS file and notice
that these new properties,
the quarter of a second
and the scale, all
reflected in the CSS file.
So, this is looking pretty
good, but what do we do now?
How do we save this?
Typically, we have to go back
to our editor, copy the changes
that we made, and
then start over.
But now in Safari 7, I can
simply press Command S,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
save the file up to my disk.
And to show you that it works,
I'm going to refresh the page.
You can see that all things
I made have now been saved
and I'm ready to continue.
And viola, there you go.
And speaking of viola,
back to Antoine.
[ Applause ]
>> Thanks Brian.
So let's recap what Brian
just showed us on the stage.
Using the new styles
sidebar easier than ever
to make any changes
you want to your page.
We have the great new
free-form CSS editing,
syntax highlighting,
all of this instant,
any change you made just
gets reflected on you page,
and that's just really
amazing I think.
And adding the neurals
just easier than ever
with this big Neural button.
And what I think is extremely
compelling especially in a kind
of demo like this when we
want to tune the transition
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and the transformer applied to
an element when it's hovered,
we can just control that so much
easier in a much easier manner
by just using the hover
checkbox in the pseudo-class bar
at the top of the
styles sidebar.
I think of a future that
might seem just so natural now
that you see it but if you
didn't have it, it would just be
so much more painful is your
ability to just save files
that you've been editing
locally so that it get taken
into account when you
reload, and more importantly,
they just apply directly
and you can just, you know,
those change are done, you
do it all in Web Inspector.
And so, by just pressing Command
S, you can save your file
and it's just save
right where it was
or it can even save a copy
somewhere else if you prefer.
So I think that really
is a good summary
of what Web Inspector
lets you do in terms
of CSS experimentation,
inspection and tweaking.
So now let's move on to the next
section, performance analysis.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And we're going to focus
on layout and rendering.
And I think the greatest leap
forward ever made in a browser
for performance in
terms of layout
and rendering was something
that WebKit pioneered as soon
as early as iOS 2 in the
former hardware compositing
and the ability to
have composited layers
in your document.
So, let me take a step
back for a minute.
Let's get out of the
floor representation
and let's discuss briefly
what composited layers are.
You may not be familiar
with them.
Composite layers is a way
for your document instead
of being a flat surface in terms
of rendering to be a collection
of smaller layers stacked on top
of one another and composited
in a very efficient
way both in performance
and power consumption
by the GPU.
And so, let's take for
example a simple video player.
Imagine that a backdrop
image here is a live video
and we have controls
that we want
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to customize on top
of our video.
So, to make sure that
video playback is a smooth
and power-efficient as possible
in Safari, both on the Mac
and on iOS, we're
making video elements
in WebKit always be hardware
accelerated and hosted
in a composited layer.
So our video is playing and
it's kind of on its own space
above the rest of the web page.
Now, let's imagine that
you hover over the video
and you want the
controls to appear.
So you're probably state a great
little WebKit transition on them
and make sure they start
appearing on top of the video.
So, as soon as something
is animated with opacity
or transform, WebKit will
automatically create a
composited layer for you so
that we have the best possible
performance as the
animation is performed.
But in the end results of that
video control hovering the--
being laid out over the
video, it means that we have
to create a layer for
that control as well.
Obviously, if you have
something displayed in a layer,
in this case are video, and
something else drawn on top
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
of it, that piece
of content laid
out over the video will
itself need a layer.
And what's kind of cool
about layer is not just--
it's not just about
animations and transforms.
It's also that when we have a
smaller logical piece of content
to render in this layer for
example or controls up here,
if we have to make a change
that requires a redraw,
for example pressing the button,
it might turns to button green
or something, then we
can make those changes
in a much small region and make
a much more efficient redraw
cycle in WebKit.
And so, I'm telling you
a lot of information here
and it might seem a little
bit more little abstract.
But there was a great session
on this topic last year.
It's called Optimizing
Web Content in UIWebViews
and Websites on iOS,
I really urge you
to look at that session.
It has so much detail
information about how layout
and rendering happens in WebKit.
Section 601, WWDC 2012, you can
just watch it from the iOS app
as soon as you exit this room.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
OK, so let's go back
to our presentation.
Composited layers, like
I said, they're created
and managed automatically
by WebKit.
It's a great optimization
made by WebKit
and it was such a breakthrough.
I don't even think of other
browsers are quite caught
up with this.
And they pose their
own kinds of challenges
as for you as a web developer.
Who think things in
layers are not for free?
In fact, almost anytime
you gain something
in performance is always an
associated cost often times
in memory.
And layers will be the same.
Something it gets drawn
into a layer requires memory
to match the content
of that layer.
So how do you find out when--
having things in layers
might be a problem?
Well, this is almost
impossible up to now.
We have a brand new sidebar
in Safari 7 called
the layer sidebar
and it provides you all the
detail information you need
about layers in your document.
So let's take a look at what
information is contained here.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
At the top, we have
any information
for a layer associated
to the currently selected
element in the DOM.
So, of course, you may not have
a layer for this element and in
that case that panel will be
empty at the top, that's fine.
And your elements might have
a lot of layers associated
to descendants-- descendant
nodes of that element.
So, we can just list all the
layers associated to any element
in that selected element
subtree right there
in the style sidebar panel.
And that gives you
a great overview
of what actually ends
up being in layers.
And for each of those things
you can track the number
of time those layers are painted
and the associated
memory for that layer.
And what's really cool is
that since we display this
information in the table,
you can sort by memory use
or by paints and keep track
of the things that
might be painting
or using too much
memory in real-time
as this list gets updated as
you interact with the web page.
And we summarize the layer
count as well as the memory
at the bottom of the panel.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So you can just take
a look at that number
and see exactly how much
memory is consumed by layers
on your web page or in
that specific subtree
you're selecting.
OK, so, layers are--
can be associated to all
kinds of different content.
The most obvious one
may be an HTML element,
to which maybe a CSS
transform is applied.
But there are other kinds
of content in your web page
that you can't even
see in the DOM
that might still create a layer.
And one of those things
are pseudo-classes.
And you might have used
before ::after or ::before
or first letter first line,
those types of things.
And what this lets you do purely
in CSS is actually something
that we call generated content.
And for example, I love
to use an after rule
such that I can add and
overlay over an image
that might be semi-transparent
when the mouse is not
on the element and removes
itself when the mouse is over.
So I can create interesting
effect without having
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to change the DOM structure.
But imagine that
this content and that
after selector is
actually composited itself.
Well, that creates a layer.
And you can identify it very
easily by looking for any layer
that has a P icon next to it.
P stands for pseudo-class.
And what about reflections?
Well, reflections themselves
do not require a layer
to be generated.
But imagine you're implying
a reflection to a video.
A video is always
hosting a layer.
So, in order to provide a
reflection for that video,
we need to create a layer
for that reflection.
And again, those things live
completely outside the DOM.
And if it weren't for
the layer sidebar panel,
there would be no way for you
to find out about those layers
and diagnose any
issue laid to them.
So what about jumping from a
layer to the actual element
that this layer is
associated with?
Well, we did something
that's just very intuitive.
You can just hover over
the layer in the sidebar
and a little Go To arrow will
pop up, you'll see them all
over the place in
Web Inspector to jump
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to the associated content and
clicking on it will take you
to that element and
regulate in the DOM.
And then you can maybe change
the stuff for the element
or do whatever you want that
may change this behavior,
use less memory,
or what have you.
And the final thing that I think
is just incredible is that,
like I said,, WebKit has
its own set of reasons
and it does the best it
can to generate layers
when they're needed is not
something you have control
over directly is just a great
optimization by WebKit .
But the reason why something
might be composited can be
very obscure.
But what's great about
this sidebar panel is
that if you select
one of those layers,
it will show you right
away why we composited
that layer in WebKit.
So for example, here are
fairly obscure reason
that have probably would not
have worked out by myself.
The layer associated
to that element, well,
the element overlaps another
element that's being composited
in a layer.
And so, just like I explained in
the overview, because it's laid
out over another element
that's in a layer,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
it needs to be in its own layer.
How could I found that out if--
without that sidebar panel?
Well, this is exactly what
the layer sidebar is for.
And so to find out more about
the layer sidebar and more
about diagnosing and fixing
issues related to performance
of layout and rendering, I'd
like to invite on stage Andreas
to give us a great demo.
[ Applause ]
>> Thank you Antoine.
I'm going to ahead and
reopen the photo gallery
that Brian was just showing us.
And here we go.
So thanks to the latest
enhancements Brian has made.
This is really starting
to come together.
But we got to remember
this is a website.
So not only it's going to be
viewed on different screen sizes
like an iPhone or an iPad
but in case of the desktop,
a user might even choose
to resize the window.
So for that and in order to
have a great user experience,
we want to had and build
this photo gallery using a
responsive layout.
So let's take a look at that.
As you'll notice, as I resized
the window, the layout does
in fact adjust to
the new screen size.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
But in terms of performance,
things are not looking
really good.
Things are laggy and in fact,
I wouldn't say this is
a responsive layout.
So let's go ahead
and try to fix that.
But instead of me trying to
get what's wrong with that,
I'm going to go ahead
and open the inspector.
I'm going to go and jump
right into the timelines view.
For those of you who are
not familiar with timelines,
they allow you to record
any activity that's going
on while you're interacting
or loading your website.
These include stuff like network
requests, layout and rendering,
and JavaScript events.
So let's go ahead and start
recording a new timeline
by clicking on this
button right here.
Now that we're recording, let's
switch back to our photo gallery
and resize the window.
So notice, immediately
as I start interacting
with my website,
the time is updated
with any activity
that was recorded.
Let's go ahead.
I can continue interacting
with this page
but I think I got
enough data for now.
So let's go ahead
and stop recording.
Again, using the same
button I use to start,
I'm going to go ahead and
hide the timeline side panel
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
so we get a little
bit more room here.
And you immediately notice
on the top part of this view,
we get a graphical
timeline and really easy
to quickly visualize
everything that was going on.
In the bottom part, we get
additional details of all
of the events that were
recorded for-- while we are--
of all the events
that are recorded.
These include stuff like
start time, duration,
and in case your
event was triggered
by your JavaScript code, you
even get the function name,
the line number, and if
I hover over one of this,
we even get the entire
call stack that led
to this event being trigger.
Isn't this really cool?
[ Applause ]
So, let's go ahead and take
a look at the different types
of events was going on.
And something that
immediately pops out to me is
that the single function,
this called layout photos,
that seems to be trigging
most of these events.
When I see some stuff like
layout here, some style going
on against some layout, but
let's go ahead and focus
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
on what's going on with styles.
And to do this, I'm going
to go ahead and at the top
of this table, we got
these awesome controls here
that allow us to filter
the data in this table.
So I'm going to ahead and
select invalidate styles.
While holding the command
key, I'm also going to click
on Recalculate Styles.
So as you can see, the
table immediately updated
to just show me those
two types of events.
So again, let's browse
through data
and we can immediately
detect a pattern here.
And it seems that the
layout photos is constantly
invalidating styles and
recalculating styles.
And this seems to be
happening over and over again.
And as I mention before, we can
even see the exact line number
that this is happening on.
In this case, it seems that
line 58 is triggering the
recalculation, and line 64 is
triggering the invalidation.
So let's go ahead and click
on the layout photo right here
to jump right into the code.
And here we go, let me zoom in.
So you'll notice, line 58,
let's go ahead, and it seems
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that I'm inquiring
an offsetWidth.
So this is clearly what's
triggering the recalculation.
And if we jump back to line
64, if you remember correctly,
in here we're setting a style.
So when we set a style,
the browser has to go ahead
and invalidate any cache styles.
So if you look closely,
all of this is happening
inside of for loop.
So the next time I
go into this for loop
and hit this offsetWidth, the
browser is going to have to,
again, recalculate the side.
So clearly, this is what
we were seeing in that--
in the timelines where over and
over we're calculating styles
and invalidation styles.
But before I go ahead
and make any changes,
wouldn't it be great if we
had a concrete measurement
that could tell me how long this
function is taking to execute?
That way, when we
do make changes,
we can have an actual metric
to validate whether those
changes improve things
or made things worse.
So let's go ahead.
And I'm going to use a really
handy Console API I use all
the time.
And what I'm going to do is
I'm going to type console time
at the beginning
of the function.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
I'm going to put
a console timeEnd
at the end of the function.
As you might have guess,
what these APIs do is
they measure the time
between the two calls and
print that out to a console.
But something you might
have notice is I didn't have
to go back to my text editor,
find the corresponding file,
find this layout photo
function and edit my code there.
I did all of this directly
from the web inspector.
And just like with
CSS files when working
up the local file system,
not only can I edit the files
in line but I can go
ahead and Command S
and save the file back
to my file system.
I think this is a
really awesome feature.
So let's go ahead
and save our file.
And I know I'm going to
print some to the console
so let's go ahead and switch
to the console using the keyword
Shortcut Option Command C,
that's the way in here, and
let's go ahead and reload
that page using Command R.
As you'll notice, we immediately
get that timing function
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
so we can see that the
layouts photos is taking
around 210 milliseconds
to execute.
This might not seem like a
lot to some people but we got
to remember we should always try
to minimize our JavaScript
execution time.
And in fact, I'm pretty
confident we can bring this
number down.
And let's go back
and jump to our code,
and to do this I'm going to use
the navigation bars up here.
[ Inaudible ]
Let me use a console.
So here we're back to our
code and let's go ahead
and analyze what's going on.
If you remember, we're
querying the offsetWidth
and if you look closely,
we're using the offsetWidth
to determine how many
photos we can put fair well.
And base on that, we go ahead
and determine the photo
width and the height.
But if you look closely, we're
not relying on any photo's data
to do these calculations.
In fact, these are
pretty static calculations
that can just go ahead and
move out of the for loop.
So I'm going to just do that.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And by doing this,
we're no longer going
to recalculate style
on every loop.
So let's go ahead
and save this, again,
Command S, reload our page.
But before I do that, switch
back to the console again,
zoom in, and let's
reload our page.
And there you have it.
That minor change actually
made a huge improvement,
not only that we make
that optimization
but we have a concrete data
that can help us validate this.
So we went from 200 milliseconds
to just under 10 milliseconds.
So that's good.
But let's go back
to the resizing,
but that's what we're
trying to solve here.
I'm going to zoom
out a little bit,
let's go to the Inspector
for now.
And I'm going to resize the
window and see what happens.
As you'll notice, things
might be a little bit better
but they're still
not [inaudible].
So let's go ahead and see what
other optimizations we can make.
And as you know, we're working
with a lot of images here,
when we're doing
some CSS transforms.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And in fact, to do all
the layouts of the photos,
we're using CSS transforms
as well.
So I'm a little bit concern
about in terms of memory
and in case the browser might
be creating in the layers.
So I'm going to go ahead and
make use of a brand new feature
in Safari 7 that allows me
to quickly visualize all
of the layers in my page.
To do this, let me bring
up the Inspector again.
And let's switch over
to the Resources tab.
And in the DOM tree,
there's a brand new button
in the upper right corner.
But instead of me
explaining what it does,
let me zoom out and
show you exactly.
So I'm going to toggle it and
I know it's a little bit hard
to see so let me zoom in.
What this does, it actually
drag borders around all
of the layers within your page.
So this is a really cool way
that you can quickly
visualize all
of the layers within
your document.
In this case, if
you look closely,
it seems that we're generating,
there are being layers
composited for each photos.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
This is sort of unexpected.
At least it wasn't
my intention, sorry.
So, before I go ahead
and make any changes,
I think it would be
great if we can go
and analyze how many
layers we have
and why the things
are being composited.
So for that, I'm going
to go ahead and open
up the layer side panel,
this brand new layer
side panel over here.
And we can immediately
see the list of all
of the layers for this document.
And as expected, we can see
all the photo wrappers are
being composited.
We go all the way to the bottom.
We can even see then the
exact layer kind of layers.
In this case we have Nighty
and they're consuming a
total of 11 megabytes.
This might not seem like a
lot but we got to remember
that in mobile devices,
memory is restricted.
So we should always
try to memorize--
minimize our memory footprint.
So, now that we've seen how many
layers we have, let's go ahead
and see exactly why layers are
being composited for each photo.
So to do that, I'm going
to go ahead and select one
of the photo wrappers here.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
You immediately see that the
reason this is being composited
is because the element
has a 3D transform.
So now that I know why this is,
let's go back to
our photo gallery.
And as I mentioned before,
we think 3D transforms
or transforms to position
all of these photos
because we have a feature
of the photo gallery
that we haven't shown you yet.
So you might have noticed that
in the upper right corner,
we have a shuffle button.
And instead of me explaining
what it does, let's go ahead
and click it and see,
see them in action.
As you'll notice, as
I click this button,
the layout of the photos is
rearranged and they are animated
to their new position.
So this is why we're
using CSS transforms.
But you'll notice we're
not doing anything fancy.
I don't know what's going
on with the performance here
but we're not doing anything
pretty of anything fancy.
So I think it's safe
to go ahead and remove
that 3D transformation
and convert them
to just use 2D transforms.
So I wrote this code and I
know exactly what file need
to change.
So I'm going to go
ahead in the Resources,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Open photo.js, and here we go.
This is the line of code that's
setting up that 3D transform,
so I'm going to go
ahead and convert this
to a regular translate.
And again, I'm editing right in
the Web Inspector so Command S
to save, save this file,
and let's reload the page.
And you'll notice something
you can immediately see is
that there are no longer borders
being drawn around each photo.
So this means we did something.
And layers are no longer being
composited for each photo.
But just to be absolutely sure,
let's reopen this layer
side panel once again.
And sure enough as
expected, we went down from,
I think it was 90 layers to just
two layers and let's see how
that deal with memory.
And we went down from, I
think, it was 13 megabytes
to just 300 kilobytes.
So this is great.
But before I go and see how
that affected the resizing,
let's make sure we didn't
break any system functionality.
Let's go ahead and
try to shuffle again
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and make sure that's still
running as smooth as before.
So I'm going to click
on it, and you'll notice
that things are still
looking pretty good.
And I know it's a
little bit fast here,
but if you notice closely,
as an animation is happening,
WebKit is smart enough to
composite layers for all
of these elements so
that animation still runs
as smooth as before.
So this is good.
So, let's go ahead
and resize the page
and hopefully this would
fix our performance stages.
So I'm going to go ahead
and resize the page.
Notice, things are
immediately better.
In fact, I would
say that this is now
in fact a responsive layout.
So with that, I'm going to
hand it back to Antoine.
Thank you.
[ Applause ]
>> Thanks Andreas.
I think this is the coolest
demo we've made today
because it puts together so many
of the new features we've had
in Web Inspector and
let's us do things
that would be virtually
impossible
to make with any other tool.
Web Inspector is the only tool
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that let's you check
performance-related issues
that might be originated
due to the use of layers.
So let's recap what we just saw.
The great new layer
sidebar something completely
in Safari 7 let's us inspect at
a glance list of layers we have
and we can even use the new
composited borders button
in the navigation bar
to turn on borders
on any composited
element in the page.
And only to drill into more
information, the layer sidebar
which lets us find out
about the number of panes
or the memory used and even find
out why specific layer was
composited in the first place,
such that if it were
in unexpected behavior,
we could go about fixing
it using the style sidebar.
And in this demo, Andreas
managed to bring the tool number
of layers from 90 to just
two layers just suing those
great techniques.
And Andreas also showcased some
great improvements we've made
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to the timelines panel.
Recording all this information
about layout and rendering,
it might be a lot, so the first
thing you can do is filter
down to just the types of
layout and rendering operations
that are of concern to you.
And then as you select a
specific row in that DataGrid,
you immediately can figure out
what kind of JavaScript code led
to the execution of that layout.
So for example here, we know
that it came from the AppInit
and we can just start drilling
down through those functions
to figure out why we eventually
call it layout photos.
Such a great feature.
You can just jump straight
to where the performance
issue might be.
I think since we're in the
advance session and I'm talking
to a group of developers,
I think everybody are going
to be interested in ways you can
boost your productivity while
using Web Inspector.
And a great way to do that is to
learn more about a Console API.
Andreas used a console time
and console.timeEnd methods
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to time a code segment.
This is really cool.
There are other methods
you can call on console
that could make your
life easier when dealing
with performance analysis.
For example, console
that mark timeline.
What it lets you do is add
a green vertical dash line
to the timeline recording
so that you can visually see
when your piece of
code is being run.
Another great thing we
could have done in this demo
but we didn't is that instead
of calling time and timeEnd,
we're going to call it
profile and profileEnd.
And what this would have done is
start an instrumentation process
where it keep track of all the
JavaScript calls made during
that specific interaction and
present it in a great DataGrid
within the timeline sidebar.
We didn't have time to
feature profiling too much
in this session this year,
but if you come to the lab,
we'll be able to
show you a lot more
about profiling if
you're interested.
OK. So I think that
we did a good job
of showing how we can deal
with performance analysis
and fix those kinds of
performance-related issues
in Web Inspector
in this section.
Now let's wrap this
up by taking a look
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
at debugging in Web Inspector.
I'm going to invite on
the stage, again, Brian,
to show you the final demo.
[ Pause ]
>> Thank you, Antoine.
So, Andreas did a really awesome
job showing you how you can use
a timeline to help profile
of [inaudible] in performance
and layout associated with
their JavaScript code.
But sometime, their JavaScript
code just doesn't work,
at least mine quite often.
So, let's take a look
at the previous example
we're working at.
This is looking pretty good
so far but one feature I want
to add is that when you click
on a photo, it just zoom
in full screen like a
nice photo gallery should.
And I went ahead and
I added some code
to do this but it doesn't work.
And you'll notice
that when I click
on the photos, nothing happens.
So usually when something
goes wrong,
the first thing I do
is I blame Antoine.
The second thing I do is I open
up Web Inspector and take a look
and see if there's any
information to tell me
that something has gone wrong.
So let's do just that.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Now you'll notice
in the top right,
in the top of the activity there
is a pretty obvious glaring
red error.
And this tells me that indeed
something is going-- gone wrong.
And as I click on a photo,
it'll increment that count.
[ Inaudible ]
So as I click on a photo, it's
going to increment that number.
So that tells me that
there's obviously a problem
with the Java that's
being called as a result
of clicking on a photo.
So let's zoom out and let's--
and we already have
console open.
I can also get to that by
clicking on the red icon.
And if I zoom in here, you'll
notice that we have an error
and it's telling me
that we're trying
to call an undefined function.
So let's go straight
into the code
and take a look at
what's going on.
I do that by clicking a
link on the bottom right.
I'm going to zoom out a
little bit and take a look.
So, let's take a look
at code here and see
if we can get an
idea of just looking
at the code what's
trying to happen here.
So clearly we add eventless near
to the element before you click
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
on it, and in the function
handler, we're trying
to call a method that notifies
that a photo was selected.
But this doesn't give me a lot
of information so let's set turn
out the debugger
which you can get too
by toggling on the top here.
And let's set term
breakpoints on and let's do it
for all uncaught exceptions.
Now, if you had exceptions
that were
at in a try/catch statements,
you would also be able
to use the all-exceptions.
So without reloading the
page, I'm first going
to press command K to
clear this error count.
I'm going to click
on another image.
And as you can see, the
debugger braked right
at the area where we expected.
So now that the debugger
stopped at the point
where the error is being thrown,
we have the opportunity to look
at the context and see
what's happening here.
So when you look at the top
right, we have a scope chain
which provides information
about the variables
and arguments in the method.
But nothing looks
obviously wrong here.
There's no neular undefined.
So, I can't really get a sense
about what the problem is.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So let's close this.
Safari 7 is a much better
way to go about doing this.
I can simply roll over--
I can simply roll
over any element here.
And I'm going to
get information,
let me zoom out of it.
I can get information about
any variable here live.
This is a really great way to
visualize the code and walk
through it and see what kind
of information we're getting
and see where the error happens.
So as you can see,
this is the event
that triggered the function.
I can roll over the idea
and see that we're going
to get the correct
idea of the photo.
This is the information
about the photo.
But as we expect, the
notify method is undefined.
So let's keep it going
through the left here
and roll over this.
And we zoom out and we see
that this keyword
represents the element.
So, this is a very subtle
JavaScript [inaudible]
that I ran into all the time.
And we know that a
function is called--
an event list in our function
is called in a context
of the object that
triggered the event.
So in this case, this
keyword refers to the element
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that we clicked on, not the
object that contains the method.
So let's go ahead and continue
the-- let's play through.
And we can have-- let's
do a simple fix for this.
So I'm going to use bind which
is going to bind this scope
of the method to the object
that contains the notify
what's selected method.
I'm going to save
it, use a command S.
And let's refresh the page.
So now when I click on the
photo, boom, it zooms in.
So it's looking pretty
good so far.
But you'll notice that some
of these photos have
comment icons on a corner.
So when I click on it, we
shall load in some comments.
But you'll notice we're
not quite safe yet.
We have another problem
run into.
So clearly, what's
happening here?
So we have four comments
but they're all showing
up with undefined data.
So my hypothesis here is
that we're either not
getting the right data
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
or not running it correctly.
So let's look at
how we can inspect--
how we can debug this problem.
Now, what I want to do is I
want to see the associated data
that this-- that's being used
to render these comments.
So to do that, I'm going
to right click on one
of these elements and
click on inspect elements.
That's going to bring up these
comments in the-- in a DOM tree.
And let me scale
this a little bit
so you can see what
I'm going to do.
Now, I'm going to bring
up the quick console
and show you shorthand.
Let's clear this out.
Now I can use dollar sign 0 and
what this does, this is going
to reference the currently
selected element in the DOM.
So if I press Enter, you'll see
that this comment is the same
as the comment that I selected.
Now, as a debugging
technique, I actually associated
in JavaScript the info, the data
model that this comment used
to surrender itself
on the element itself.
So as I start autocompleting,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
you'll see there's info
object associated with it.
So inspect this object,
we'll see that we are actually
getting valid data here.
So we have the avatar URL,
we have a comment text,
and we also have a date.
But for some reasons, it's
not showing up in the code.
So, let's take a look
at our JavaScript file.
I'm going to use the search
here in the top and I want
to search for comment code.
So let's see.
I think it's called Comment,
and you see the search bar,
such a nice list of
wherever the word Comment was
in our entire working directory.
So in this case, I want
to go to this method,
Comment, Prototype, Set Info.
And this [inaudible] is really
great because we can see--
we can compare to a
data that we're getting
and a data that we're expecting.
So seeing the top, we're
sending the image here
and we're sending the
text from the data,
and we're sending the timestamp.
But in reality, these
are the wrong variables.
Here is this avatar.
Up there is its image and so on.
So, this is a common scenario
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
where sometimes data might
change in the backend
and you're not trying to
update it on the front end.
So let's quickly go in
and make these changes
and see if it works.
This should be comment
and this should be date.
Again, I'm going to
press Command S to save.
I want to zoom back
out and take a look.
Refresh the page.
Let's click on the same image.
And there we go, the
color is showing up.
OK, so I think we're
almost done.
And let's take a look at
some more photos here.
Let's take a look at
our trip to Thailand.
How about this guy?
So again, the color
is looking good.
Let's scroll down.
So we'll notice that
something else is wrong.
So, just when we
thought we were done,
obviously another bug pops up,
that happens once in a while.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So the previous problem
was specific--
was happen to all the comments,
but this problem is specific
to an individual comments.
Now, we can use a [inaudible]
technique that we used
in the last demo, but let me
show something that much cooler.
So I'm going to go to
the search my resources
for a method called
render comments.
Now this is a method
that I wrote,
so I know what it's called.
So let's search for it.
So let's click the
right using the search.
I'm going to escape
out the quick console.
And let's take a
look at this method.
So this method is called when
the full screen view shows up
and it loops through
all the comment data,
it creates a new comment which
renders the HTML content.
And I will set the info on it
which the data we're
getting from server.
So what I want to do is I
want to click on the debugger
and I want to set a
breakpoints right at the point
when the data is being set.
This way I can inspect the
data right before it get sent
to the comments and rendered.
But the problem here is
that I don't want to have
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to run this debugger for
every single comment.
So I have to go to the first
comment, the second comment
and so on until I
got to this one here.
So this is a great usage
of something called
conditional breakpoints.
And let me show you
how that works.
Let me turn on breakpoints here.
Zoom out a little bit.
So you see that, the breakpoint
that I click, that I use,
that I add by clicking
on the gutter here is
on the debug panel on the left.
So if I right click on this,
I can go to edit breakpoint.
Now, this allows me to add
a conditional expression
that will be evaluated right
before this method is reached
and-- the debugger
will only break on it
if this condition is
evaluated to be true.
So a conditional expression
could be anything that you put
and stuff in If statements.
So in this case, let's try
to find an identifiable
characteristic
about these comments that we
can use to add a condition.
So in this case we have
text "Too Much Fun".
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So let's select that.
We'll just type in instead.
So let's use a regular
expression match
to see how this works.
So, toomuchfun.test, and we want
to test it against this line,
so let's try this again.
So we want to test it against
the data and the comment.
So let's do
commentinfo.comments,
remember the correct variable
name from the last mistake,
press Enter, then we're good.
So let's see how this works.
Let's click off this again.
And let's click on
the same photo here.
Now you notice that it correctly
stopped at the breakpoint,
but we zoom out you see that
it actually rendered all the
comments beforehand.
So this stop only at the
comment that was in question
which is really a great way.
If there was a thousand comments
here, that'll be a real pain
to go through each one of them.
So using conditional
breakpoints, you can easily get
to only the problem that
specific that you want to find.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So, using the popovers, we can
now easily go over the code
and see what's going on.
So here I have our
comments arrived.
I don't know about you but
this is the coolest thing ever.
Could I get some
applause for this?
This is great.
[ Applause ]
Thank you.
[ Applause ]
I mean, I can visually
go through the code
and just-- it's just so natural.
Let me get back to the info,
and as you can see, you know,
James wrote these comment, added
some rogue HTML into the comment
which is why it's getting
rendered in correctly.
Now, this is a really
serious issue.
This-- the sites won't allow
me to cross scription--
scripting attacks and this
is something that we'd have
to taught to our server about
to try to sanitize the content.
So, this is a serious issue
that using conditional
breakpoints helped us out.
And with that, back to Antoine.
[ Applause ]
>> Hey, thanks Brian.
So, the debugger sidebar is
the way you can always track
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
where your breakpoints are,
what this data's recall stack is
when you're breaking
into the debugger,
and using the scope
chain, you can always find
out these different values
of the local variables
and their occurring call.
And with conditional
breakpoints,
you can pinpoint specific
instance within a loop
or any kind of other condition
to just break what it matters.
And what I think is really
cool about this feature is
that imagine you're actually
debugging content that's not
even local.
It's content from the server,
there's no way you can edit,
edit the file to tweak the
breakpoint and just break
under certain conditions,
this is really
where the edit breakpoint,
conditional breakpoint setting
is just really vital 'cause
there would be no other
way to do it otherwise.
And the popovers, they just work
whether you're hovering a simple
property or even a
chain of properties,
it's just really fantastic
for real-time debugging.
And again, taking a
look at productivity,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
there are some Command Line APIs
that would be really
useful to you.
So, for example, there are
0 currently selected node,
there are 124 last,
second to last,
and et cetera selected
node, comma and underscore,
dollar underscore, the
value of the last expression
in the debugger in the
console and even short hands
for often used methods
such as querySelector
and querySelectorAll
which you can go
with dollar or dollar-dollar.
And we have a whole list of
those in the documentation
which you should
really go and check out.
So this was it, the new style
sidebar panel made inspection
tweaking a breeze, performance
analysis with the new layouts,
layer sidebar as well
as the great timelines
view just made it so easy
to identify what went
wrong, get to the initiator,
look at the call stack,
and find exactly what piece
of JavaScript calls the
performance issue, and finally,
popovers, conditional
breakpoints, all new features
in Safari 7 that makes debugging
JavaScript code so much easier.
So you can keep up-to-date
with our development
with Web Inspector by
going to nightly.webkit.org
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and you can download the
WebKit nightly and build
with the snapshot
of WebKit everyday.
And race bug as you
encounter them,
go to
bugs.webkit.org/new-inspector-
bug will always track
in them and trying
to fix them as soon as possible.
And if you have any issue you
want to discuss in person--
not exactly in person but live,
you can just connect to IRC
and freenode.net and go
to the #webkit-inspector
channel and find us there.
And finally, because we have
open source Web Inspector today,
you can contribute directly
to the features and the code
of Web Inspector to make it
just a little bit better.
And so, for more information,
you can type [inaudible]
or documentation again, you
will have to check it out,
developer.apple.com/mac,
look for the Safari Web
Inspector Guide, webkit.org,
[inaudible], great places
to find more information
and get answers to
your question.
These are some related sessions
about performance, CSS features,
and introductory talk to Web
Inspector if you miss that.
Thanks very much.
[ Applause ]