Transcript
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
[ Applause ]
>> ANDREW PLATZER:
Good morning, everyone,
and welcome to WatchKit
in Depth Part 1,
the first of two sessions
to explore a bit more
about the changes in WatchKit.
My name is Andrew
Platzer and along
with Forest Hill we will be
covering some topics today
hopefully of interest to you.
I'm going to be covering
three sections, architecture,
the basic layout of how a
watch extension works inside a
watch app.
I will talk about where
resources and data live
because it is a two-part system,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
because it is a two-part system,
and so it may be a bit
confusing to start with.
For those who have already
worked on watchOS 1,
a WatchKit extension, a
watch app, I will talk a bit
about migrating over, what's
changed, what's the same,
and then Forest will carry on
and talk a bit more about some
of the new API and the
new classes in WatchKit.
So your Watch app
has three parts.
It's got an iOS application,
and that is what you would
get installed on the phone,
as well as that, you
provide a WatchKit extension,
this is the code you write,
and then a watch OS application
which contains resources
and interface description.
You have your phone and
you download your app,
and what we have done is
added a new bundle of data,
bundle of files that get along
with, install along with it,
and that's the Watch app,
that contains your
interface description
and maybe some resources, and
then your WatchKit extension
which contains code and
additional resources.
So when you pair it with
your watch, we copy over all
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So when you pair it with
your watch, we copy over all
of that information, and it
appears on the Home screen
as a full application.
Of course, a copy is still
left on the phone for later
in case it needs
to be reinstalled.
So I want to talk
about the two parts
that you are going
to be providing.
One is the interface and
the other is the actual code
and the extension.
When you create a
new WatchKit App,
you can see there are
actually two separate targets,
two separate components, the app
with the interface storyboard
and your code, in this
case in Swift, and you have
up to four different
things you can add code for.
So for the storyboard, this
is the interface part of it,
you can edit in IB just like
you would an iOS application,
and we provide a reasonably
rich set of interface elements,
labels, images, et cetera.
This is all in watchOS 1 and we
have added a couple of new ones
in watchOS 2, the thicker view,
which will give you a
lot more rich interface,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
which will give you a
lot more rich interface,
and the movie view.
So, for example, here are three
standard possible controllers
with all of the controls
you can see,
and these are created
in interface builder.
We also have custom interfaces
for specific functions,
one is Glances, and it's
got a more specific layout
and the other two are
for notifications.
One is for static, one is
for more dynamic information
which you provide at run time.
So as I said, there are four
roles for your extension.
There is an application role,
so when your application is
launched from the Home screen,
we call your extension.
It's also used for the single
page glance that appears
from the clock, notifications
when you receive one,
and now complications.
And for each of these, there
is an associated controller,
for the Glances and the
regular application,
there are WKInterfaceController.
There is the specific sub class
called WK user notification
controller which you should
use for notifications,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
controller which you should
use for notifications,
and there is a new data
source object CLK complication
data source.
I won't talk anymore
about the complications.
There is a session
later today that will go
into great detail about this.
So your WKInterfaceController
is your main connection
to your interface.
The main thing it does is it
provides automatic creation
of interface properties so
you tag an interface element
in your interface design and
say this is like, for example,
my label, and then we
create an associated object
on the controller and we connect
it up automatically for you.
The controller also
supports menu handling.
You can customize menus
or have static ones.
We provide navigation,
push and so on, or paging,
modal presentation
of controllers
and alerts, and action sheets.
One other thing we do provide
is a number of system UI sheets,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
text input, video play
back, audio recording.
So, for example, here is
a very simple interface
controller class.
It has one outlet, app image
and we have loaded up in IB
and when we run the application
we see it pulls the image
and displays it on the screen.
So I want to talk a little bit
about the location of stuff,
where your resources live, where
you can pull your data from.
Because there are two
parts to this watch app,
there is the watch app itself
and the WatchKit extension,
there are two places
where data is stored,
there's the WatchApp bundle and
the WatchKit extension bundle,
and you have got to be sure
you remember where it is.
For example, here I have
created another project,
it has an interface
storyboard as before
and also an application
image.png
and the localized string file
and the extension itself also
has the same kind of thing.
It has another .png file
and a localizable string.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So now if we do the obvious,
which would be create a couple
of outlets, wire them up
using IB outlet to indicate
that these are the properties,
and call set image, well,
we don't get an extension image.
The reason for that is that
when you call set image named
on a WKInterfaceImage,
it doesn't look
up in the applications bundle,
but the extension image doesn't
live in the applications bundle.
So instead, what you need
to do is directly fetch it
in the code that's running
in that particular bundle.
So in the extension code, you
call UI image 'image named,
and it will pull the image
locally since it knows how
to search inside its own bundle.
Then you send that across.
You call set imagine instead of
set image named so it will pass
over the image and both will
appear in your application.
So now you want to
store some data.
You don't want just
pull some static images.
You have a much more
dynamic application,
so there are two folders
that are of interest.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
One is the documents folder,
this is where you would store
more persistent information.
It's not purgeable.
That means it hangs around
between reboots, et cetera,
but one thing to note, it is
not restored, so you may have
to check for that if
the watch was erased
or you go to a new watch.
There is also a caches folder.
This one is purgeable, so if
the system decides it needs more
storage for music or
pictures or other apps,
it will remove those images,
so you should consider those
may go away at any time.
And so here is a quick
example of where to find it.
In this case, the main call here
is the document directory class
file manager for
URLs for directory.
It will ask for the first
one and that's the URL.
So we can create a URL
including our file name
and write some data to it.
Now, media presents
another interesting problem
because the application is in
charge of playing the media,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
because the application is in
charge of playing the media,
and it's also in charge of
recording it audio somewhere.
So when you, your extension
requests to play a movie
or play audio or record audio,
we send that off
to the application.
On the other hand, the extension
is in charge of getting
that media, downloading it from
the internet or generating it
or whatever, and
it's also in charge
of getting the recorded audio
files that you may have set up
and sending them
out to your server.
So what you need to do is set
up what's called a
shared container.
And that basically lets both
processes, the application
and the extension have a
common place to access.
Because for security reasons,
normally you can't access
from one process into
another's storage area.
And you enable this index code.
You use something called 'app
groups' for both the extension
and the application you
give a unique identifier
and that's your application
group.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and that's your application
group.
And so the only real thing
here you need to worry
about is there is a
single function, again,
the file manager, you
can ask container URL
for security application group
identifier and you will pass
in the group identifier
that you created
and that will give you URL
to a shared storage area.
So from there, you can save
files that the app can read
from the extension or pull
files that the app wrote
into the extension
and an example here we have
a present audio recording
controller and that takes the
URL from the shared container,
so it will record the
audio to that file.
So now, I want to talk about
getting the data to the watch.
There are two ways
of doing that,
one is NSURLSession,
whichs in foundation.
And the other is a new framework
called watch connectivity.
So the NSURLSession is the
one you use a lot to get stuff
from the internet, if you have
got a chat app or something
like that, you will want
to talk to your server,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
like that, you will want
to talk to your server,
it gives you direct access
to the internet using HTTP
and HTTPS and there are
several ways of configuring it.
And it allows for
backgrounds and downloads.
The reason for that is your
extension is often not running,
your watch screen is turned
off, your extension is sleeping,
your extension may not
even be running for awhile
that it takes to
download the data.
One thing to note is once we
tell you the data is there,
once the file is
completely downloaded,
you need to grab it right away,
because otherwise it will be
removed from a temporary cache.
So here is some code,
a couple of pages,
a simple downloader class.
The first thing we do is cut an
NSURLSession, we do it lazily
in case we don't
need to ever call it.
And the main call here
is to create the session.
And there's really two lines.
One is you configure
it for the background,
so you want to say here
is a background session,
and we want to pass in an
ID, and I'll talk about that
in a moment, and we
create the URL session
with that configuration
and we make the downloader
class itself the instance
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and we make the downloader
class itself the instance
after a delegate so
we get notification
when the file comes in.
Then to start the URL
download, we ask for a new task
and tell it to go, and it
will send off the request
and start the download.
So as I said, often your
extension is shut down
or not awake while
that's happening.
In the case where it's shut
down, you will want to reconnect
to all of those download
tasks you have set up.
So what you will set
up is, for example,
a function here called
restart that you might call
from your WK extension, and
Forest will talk about that,
at start up to restart
the download
so that you know
they are coming.
Actually they will be
going, but you won't know
that they have finished.
And so here is the
actual delegate method.
This is the one you are
wired up to the NSURLSession,
and it's called when the
file finishes downloading,
and as I said, we need to
copy the file immediately
so it doesn't go away, so
the system doesn't remove it.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
so it doesn't go away, so
the system doesn't remove it.
In this case, we will
get the caches directory
because maybe we will
need it a short while.
We will generate a URL, and
we will call the file manager
to copy that from the
original URL that passed in,
the location URL to the
cache's directory URL.
So we have a copy of it and we
will keep track of it for later
so we can access whatever
the data is you downloaded.
There is also the WatchKit
connectivity framework.
It actually exists
on both sides.
If you share data between them
so, for example, you could set
up a dictionary that could share
between the watch
and the iPhone.
It lets you transfer files
over, again, the background,
and it lets you send direct
requests from the watch
to the phone app your parents,
your parent iPhone,
parent application.
And there is a session
on that tomorrow,
and I suggest you definitely
listen to it because it is new
and does exist on both
the watch and the iPhone.
So just a few slides on
migration, for those of you
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So just a few slides on
migration, for those of you
who have started
a watchOS 1 app,
you have probably run into this.
The WatchKit extension
for watchOS 1 is something
you have created already,
there is a target
in your project,
but it uses the iOS
platform in SDK.
So it lives on the iPhone
rather than on the watch.
Because of that, it lets you
share a framework on the phone,
so you might have some
code that's common
to both the extensions,
for example,
fetching your information from
the network, and you will have
that same code being run by
both the iPhone application
and the watch application.
Because you have no direct
storage access to the watch,
we gave you a way
of caching images
of basically saying here is
an image and here is a name
and later on when I
say 'said image named,
we will have already downloaded
that asset, those resources
to the watch, and it
will be much faster.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to the watch, and it
will be much faster.
So we gave you a way of directly
talking to the application.
Obviously this is from the phone
to the phone process
so it's very fast.
With watchOS 2 we
have added a new SDK.
It's completely separate,
similar to the iPhone
and OS 10 SDKs.
It does give you a subset
of available iOS frameworks,
so you won't get the complete
set of functionality as you do
on the phone, but
you will get a lot.
You can, in your project,
include a framework just
like you did on your iPhone
watchOS 1 app, but, of course,
this framework is downloaded
with the watch application,
watch extension, and so you
don't get to share the code
in one device, but it does
let you still separate
out your network access code
into a separate framework
that the watch can use.
Now, of course, the watch, for
example, for watch framework
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that you provide, for
example, might use NSURLSession
to access information.
So if you have done a
watchOS 1 application,
you have actually already
actually got a lot ready
for watchOS 2.
It's got the same API with
some changes and additions.
But you should be able
to compile a lot of it
without any changes at all
and copy resources over,
so if you have images in your
watchOS 1 extension you could
add them to the target of
the watchOS 2 extension
and have them copied
to the watch.
But you do want to make sure
they are sized appropriately
for the watch.
There are a couple
of new things.
The main thing, of course, is
that your watch app is running
on your watch, and so
the extension is running,
and that means UI
responsiveness is much better.
You tab a button, and
it immediately responds.
Of course, you have also got
independent operation now
and you don't have to worry
about the phone being nearby,
you don't need to worry
about the phone being
connected or on the network.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
about the phone being
connected or on the network.
We added a couple of
UI elements as well
as some new system UI sheets and
those will be talked about later
in the session and
in other sessions.
We have added animation, so now
you can animate the transitions
between changing, for example,
the size of a graph or a graphic
or a size or something
like that or the opacity
of a string, you
can animate that.
There is a session
for that tomorrow.
So I suggest you take a
look at that one as well.
So for controllers, the API
is pretty much the same.
So you have got the same
interface controller
and the same, you
will use the glance,
nothing has changed there and
the same for the notification,
you don't need to make
any changes there.
There are a couple of APIs
which are no longer there,
image caching and open parent,
those have been replaced
with direct images and
watch connectivity.
Two new things are the extension
delegate which Forest will talk
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Two new things are the extension
delegate which Forest will talk
about in a bit, and the
complication data source
which is used to provide
the images and text
for complications
display on the watch face.
For those having
existing Xcode projects,
you can add a new target.
You can have the
watchOS 1 there,
you can say give me a
watchOS 2 and add files in,
mark files as part of
the same target, so on,
add the frameworks
to be compiled
and loaded on the watch.
If you want, you can start from
Xcode with a whole new project,
and it will automatically create
the iOS and the watchOS 2 app
so you can start it
filling in from there.
There was a session yesterday,
I suggest you take a look
at the videos that detail
this procedure much better.
And that's it for me.
So now I will hand it
over to Forest who will go
into more detail
about the new classes
and changes to the existing API.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
[ Applause ]
>> FOREST HILL: My
name is Forest,
I'm an engineer on WatchKit.
I would like to talk to you
about the APIs we have added
in WatchKit for watchOS 2.
First I'd like to talk
about WK extension delegate.
On iOS we have UI
Application Delegate.
Among other things, this serves
to help you track your app's
life cycle, this includes things
like your did launch,
your did become active.
And your will resign active.
We have added WK
extension delegate
to track your application's
lifecycle.
First up, I will start
with application did
finish launching.
This will be called once
when the application
has finishes launching
from when your extension
hasn't been run at all.
This is a great place to
perform initialization steps
that your application
might need,
set up notification
observers and warm
up any services you
might need later.
It's important to note that at
this time your application is
not yet active.
Next we have application
did become active.
This will be called each time
your application is brought
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
This will be called each time
your application is brought
from the background
to the foreground
or after first launch.
This is a great time to
start any code that needs
to be running only while your
application is actually active,
activate any timers
you might need
and especially update any state
that might have changed while
your application was either
in the background or
not running at all.
Application will resign
active is called prior
to your app resigning
being active,
moving to the background.
You want to prepare to
be in an inactive state.
If you have started any timers,
this is a good place
to pause them.
If you choose not to pause them
at this time, they won't run
in the background, you won't
get background running time,
but you will lose control
over the exact cycle
in which they run.
So if you want control
over that, it's a good idea
to pause them when
you become inactive
and restart them specifically
on did become active.
And you want to save your
application state at this time.
Because after this point,
your extension may be killed
if another process on the
system needs that memory.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
if another process on the
system needs that memory.
So in summary, WK extension
delegate will help you
to track your application
life cycle.
It's very important to note that
this does have not have anything
to do with your notification
UI, your glance UI,
or your complication data.
This is only about tracking
the application's lifecycle.
Next up I would like to talk
about handle user activity.
Handle user activity is an
existing call from watchOS 1.
In watchOS 1 it was used
when application was launched
by a tap on your
glance to navigate
to the appropriate
location in your application
that was reflected
from the glance.
We are building on that
in watchOS 2 in two ways.
First is that this
will also be called
if your application is launched
by a tap on your complication.
So similarly any
state you reflected
in your complication you
will want to navigate
to the appropriate place in
your application for that state.
Additionally, we are moving it
to WK extension delegate rather
than calling it on the
root interface controller,
which is what we used to do.
This should give you greater
flexibility with what you want
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
This should give you greater
flexibility with what you want
to do to handle your
state maintenance.
So we have a new call on a new
object called WK extension.
The new call is root interface
controller, which I have
to warn you this is
coming in a future seed.
It's not in the existing seed.
So in order to approximate
this for now,
you'll have to save off
your interface controller
when it's first created.
With that in mind, here is how
you might implement handle user
activity on you are WK
extension delegate for now.
I will get the root
controller with the new call,
pop back to the root and then
I will ask the root controller
to go ahead and do whatever it
is that would be appropriate
to restore your state.
Note there are lots of other
things you could do here.
You might put up a modal
alert or other things
to handle the user activity
you have been handed.
Next up, on IOS we
have UI application
which is a singleton object
that represents the
running application.
So on watchOS 2 we
have added WK extension
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So on watchOS 2 we
have added WK extension
which is roughly
analogous to that.
Among other things this
is the main interface
for opening standard
system URLs.
So you will be able to open the
open system URL API to do things
like start a phone call,
send a text message
or display PassKit UI.
That's open system
URL and WK extension.
Now, I would like to talk a
little bit about notifications.
First, I would like to talk
about remote notifications.
Remote notifications
come from the internet,
and they always go
to your phone first.
At that point, your
phone will decide whether
to display the notification
itself or whether to forward it
on to be displayed on the watch.
Now, the phone uses a set
of rules to determine this,
and the criteria in these
rules include whether
or not your phone screen is
locked and whether your watch is
on your wrist and unlocked.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
on your wrist and unlocked.
So like watchOS 1, your WK
user notification interface
controller is run when a
notification is received
for your app while
it is inactive.
When this happens,
one of these calls,
did receive remote notification
or did receive local
notification, will be called
on your controller,
and it's up to you
to call the completion
handler in a timely manner.
If you take too long, your
default interface will be shown,
which is a little
bit less lively.
So it's up to you to do this
in a reasonable amount of time.
Next up, I would like to talk
about local notifications.
Local notifications must
be fired on the phone
by your iPhone app, but you
can message your iPhone app
from your WatchKit
extension and ask it
to fire the local notification.
The same logic will be applied
as for remote notification,
where the phone will
decide whether
to display the notification
itself or whether
to send it back to the
watch to be displayed there.
So let's walk through an example
of how you would go
about doing that.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
of how you would go
about doing that.
Here, I'm going to use watch
connectivity send message call
to send the message from
the watch to the phone app.
When my iPhone app
receives that message,
it can fire the local
notification
to kick off the normal
logic to determine
where the display the alert.
Relatively simple code.
So now we have the alert
visible on your watch.
I would like to talk about
launching your application
from your notification UI.
The app can be launched
in two ways from here.
Either you can launch from
a notification action button
which in this case I have
set up with the reply button.
The user can also launch the
application for notification
by tapping on the application
iCon in the upper left corner.
When one of these
actions happens
or when the user does
one of these things,
one of these calls will be made
on your WK extension delegate,
either the handle
with identifier call will
be made either for remote
or local notification.
You will receive the identifier
of the action that was tapped.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
You will receive the identifier
of the action that was tapped.
If they tapped
on the application iCon you
will receive a nil for that,
and in the remote case, you
will get a dictionary containing
notification payload.
In the local case, you will
receive the UI notification
object that you created
in the beginning
to fire your notification
to begin with.
So that's launching your
app from a notification.
Next, I would like to talk
about inline notification
text replies.
In iOS 9 and watchOS 2 we
have added third party support
for inline notification
text replies.
In this example, the reply
action has been designated
as having text input behavior.
When the user taps this action,
instead of launching the app
or sending a signal
back to your iPhone app,
the user will be presented
with text input UI.
So you can see in this UI
the user is able to tap
on the microphone in order
to dictate the response,
they are able to tap on the
emoji iCon in order to enter
from the emoji picker, or pick
from a list of suggestions
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
from the emoji picker, or pick
from a list of suggestions
which you as the app developer
will be able to supply.
And the way you will do that
is by implementing suggestions
to response to actions
identifier call
on your WK user /notification
interface controller.
So once the user has selected,
or has provided their text
input either through one
of your selections or
one of the other methods,
your application
will be launched,
and you will receive this handle
action with identifier call
on your WK or your WK
extension delegate.
You will note that this
variant has a new parameter,
the response info, and the
response info will contain the
text that the user entered
in the UI user notification
action response typed text key.
So another new feature
I like to talk about is
on the fly language selection.
Here you can see we have
standard text input.
Any time the user has the
standard text input UI up,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Any time the user has the
standard text input UI up,
they can choose to do
a Force Touch to bring
up a language chooser.
The language chooser
will offer an option
of all languages
that are available.
These are selected based
on the keyboards you have
made available on your iPhone.
So I have made English
and Spanish available.
So I will go ahead
and switch to Spanish
which will switch the text
input UI to Spanish and allow it
to populate with a list
of Spanish suggestions
instead of English ones.
So that's on the fly
language selection.
Next up I would like to
talk about another way
to handle notifications.
In watchOS 1, whether your
app was active or not,
we would always instantiate your
WK user notification interface
controller, and the system
would display that over the top
of whatever was on the screen
including your own app.
In watchOS 2, if
your app is active,
we will no longer be doing that.
Instead the WK extension
delegate will receive a did
receive notification calls.
It will be up to your app to
handle, to display the contents
of the notification
as appropriate.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
of the notification
as appropriate.
So, for example, if you
are writing a chat app,
you might append the contents to
the end of the chat transcript.
Again, the system will no longer
be putting up the alert for you
so if you want the user to
know the notification happened,
you need to present
it in your UI.
Next I would like to
talk about modal alerts.
In WatchOS 1, you could unhide
a hidden group to show an alert.
In watchOS 2 we have allowed
present alert controller
with title which should
make it much easier
to present modal
alerts to users.
There are three variants
on this call.
The first one is alert.
This is a simple call
for telling the user
that something has happened.
Next we have the side
by side buttons alert.
This is presenting
either-or options to the user
and we think the third-party
developers will want to use this
in their application as well.
And finally, we have
the action sheet.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And finally, we have
the action sheet.
The action sheet can have
up to four main actions plus
a customizable cancel action.
You can see the never mind,
the action I have
customized to be never mind.
Actiions can be optionally
marked destructive
which I have done with
the delete button.
Currently that means they
will be displayed in red.
Once the user selects
from the cancel or one
of the four main actions
you will receive a call back
indicating which
one was selected.
So in summary, we have got a
new architecture it watchOS 2,
we've added WK extension
delegate
to help you manage your
application's lifecycle.
We have got a whole
host of new APIs.
And, of course, there
is more to come.
If you -- for further
info on the things Andrew
and I have talked about
here, please check
out the documentation,
the sample code
and if you have specific
inquiries,
please contact Jake
Behrens at this address
and there is a whole host
of related sessions including
the next session in here
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
of related sessions including
the next session in here
which is part 2 of this talk.
So thank you all
very much for coming.
[ Applause ]