Fundamentals of Mobile Web Development – Chrome Dev Summit 2014 (Matt Gaunt)


[APPLAUSE] Oddly enough, that is
still a vast improvement over my introduction last
year from Jake, where it was, you’re going to vomit
information onto the audience. So you’re doing good, Jake. You’re learning. So my name’s Matt Gaunt. I’m sort of an advocate
on the Google team, yeah? And I’m from London. Hence the accent. I’m not Rob Dodson. And I’m going to talk about
fundamentals of mobile web development. So the way I want
to frame this talk is just really briefly
looking at what we’ve been hearing about today. So we’ve looked at performance
from the SILK team– hitting 60 FPS all the time,
ServiceWorker, and the ability to actually offline
your web page. Some of the things
that are going to be coming off the back
of that– background sync, push notifications, the fact
that all of this needs TLS, and Polymer– a timely new
way of building your web apps. And this is actually
a really exciting time to build for the web, right? Like, all these new
APIs are awesome. And then when you add all
of that on what we already have with WebRTC, Web
Audio, WebGL, like, this is really exciting. But if you’re actually
new to web development, or let’s say you’ve been doing
web development for a while, but the idea of
responsive web design or developing for mobile is
actually a bit scary to you, then all these new
APIs is probably going to be pretty daunting. I mean, I think it
was Paul Kennan, he did some research over the
top 1,000 websites on Alexis. And the thing of
it was, over 30% didn’t have a mobile viewport. And when you talk to some of
these agencies, and companies, and developers, the thought
of responsive web design is still really new to them. They don’t quite understand it. And for them, if you take
all of these new features, building for the web probably
feels a bit like this. And you can kind
of understand why. Like, you’re new to it. You kind of feel like you might
have your feet on the ground, but you completely don’t. You’re completely fresh. But this is overwhelming. And nobody wants this
to happen to them, ever. And it’s kind of interesting
because we’re still building on top of this
core set of technologies. It’s still HTML,
CSS, and JavaScript. We’re just using it in different
ways or different scenarios. And I mean, even if you take
a step back from all of this, and you think about how you’re
going to process new APIs, everyone’s going to
do the same thing. You’re going to
learn about them. You’re probably going to start
building something using it. And then you’re going to
iterate on that thing, probably changing it to fit your use
case or whatever it might be. And we started thinking, well,
if someone actually came to us and said, well, how do I build
a responsive mobile site? And they said, where do I go? What do I do? What do I learn? How do I do this? What’s the approach? We kind of thought
about it and we realized we didn’t
have a good answer. Like, realistically,
you’ve got specs. There’s blog posts. Some of them might be up to
date, some of the might not. And we figured,
actually, there’s something we can
do here to help. So back at the very
start of this year, we came up with the notion
of Web Fundamentals. And this is basically
a set of documentation which is built around use cases. So for example, how do you
build a responsive mobile site? And the idea with this
is that we basically get someone who wanted to
learn a particular thing, jump in, learn the best
practices as fast as possible, and just get running with it. So start this year, we
started working on it. And we started iterating
really, really fast. And we kind of got a
couple of months in, and we realized
we were at a point where we could
release something. And we really wanted to
do it as soon as possible to figure out
whether we were kind of answering a question
no one was answering. So we got to a stage
where, yeah, we’re going to release it. And what we did was we
just published the website. We made no noise because we
didn’t want the attention because, if it was a point
where no one actually wanted this stuff and
they didn’t like it, then it could be like, OK. It was an experiment. We tried it and it
didn’t quite pan out. And we were doing some work
with our GA, who were basically designing the site for us
and building it for us, so we could focus
on the content. And I think Phil Hawksworth
kind of summed up how the launch went
in this respect, “discovering that not all ‘soft
launches’ are equally soft, and embracing the resulting
crowd-sourced QA.” And basically, what happened
with this was the fact that we launched the site. It very quickly got picked up
by Twitter, blogs, Hacker News. We got a ton of traffic
that we weren’t expecting. You’ll also notice that
it’s largely me, Kennan, and Paul Lewis taunting
him with, what do you mean? And it was really
great because what we found is that we had a
GitHub link at the top to just basically encourage
people to raise issues. And what we got was
people complaining about typos, where we’ve
done stupid things, also a lot of people
complaining about the fact that we’d written it
in British English. But then we also
had a ton of issues around people who are actually
experts in their field. So one of the scenarios is
I’d written some documentation around Touch. And I was writing
guidance around, if you’re supporting
mouse and touch, you should probably be using
active Hover and Focus. Good practices. You should do it. And PPK read through
this documentation and she sat there
and said, you’ve said people should
be using Hover. That’s fine. But you don’t mention the fact
that if you touch something, when you actually let go,
the hover state sticks. Now my first thought was WTF? Why is that sticking? But the other part,
I hadn’t noticed it because I’d always
used Focus, as well. So this is really
handy for two reasons. One, he was an
expert in the field. He just jumped in
said, actually, you need to add this in. It’s best practices, and you
have to tell people about this. Update the docs,
it’s in, good to go. The other part is, then
I can go and complain to Chrome engineering and
go, why are we doing this? Is there any way we cannot
do it because I can’t hover on my mobile phone, and
do something with it. So the whole point of Web
Fundamentals is best practices. And we’re still adding
documentation on to it. But one of the
important distinctions to make with all
this documentation is its fundamental practices. So if you take something
like ServiceWorker, that’s not going to land on
Web Fundamentals anytime soon– purely for the fact that it’s
brand spanking new, which means that there
aren’t best practices. I think every one
that’s actually played with ServiceWorker has
done something a little bit different, something
that works of them. So, to be honest, the
idea of best practices, and defining them right
now, they don’t exist. People are still
figuring them out. But it’s also important to point
out that they’re use case lead. So you would never really
land on Web Fundamentals and say, ah. There’s a doc on how to
implement ServiceWorker. What it would be is, how to
implement offline web apps. So the main reason
I say this is, if someone wrote an article
like Jake did for App Cash, and there’s a new API that
we can actually swap out, and then– as time
changes– APIs come and go. We can have the same
document structure, and change the best
practices over time. And one of the main reasons
we wanted this really quick feedback loop is because we were
opinionated in all the docs. If you read something
like the tooling section, and you take a typical
kind of heated discussion, shall we say, within the
web development community like Gulp versus Grunt,
we just pick one. We make an informed decision out
of all of the available tools and we pick the
one that we think is going to fit most use cases. Now, the main reason for this
is, if you’re a new developer and you don’t know
what Gulp or Grunt is, you’ve never had a build
process of your own. Chances are you
don’t want the choice because you’ll quickly
land in this choice paralysis of everyone telling
you one thing versus the other. And the flip side of this is,
well, if you land on the docs and you go, I disagree with
you right here, chances are you know enough
about this to make an informed decision anyway. So you should run with that. But there’s one
massive issue with what we’ve done with Web Fundamentals
and that was the fact that we didn’t help
with building stuff. It’s a set of documentation. You can still get really
overwhelmed by all of this. And this is where we came
up with Web Starter Kit. And the idea behind this was
that all the best practices that we can actually just hand
over to a developer go in here. And it’s kind of interesting
talking to people because they get a bit–
it’s difficult to define what Web Starter Kit is because
we didn’t necessarily do a great job of explaining
it because we basically wanted to get the feedback to figure
out what people wanted us to do with it. And the way I kind
of think of it is, if you create
a new web project, there’s probably a couple
of things you do by default. For me, it’s always I
end up building something with Grunt and Gulp. I just start adding
that in because it just takes care of a ton
of tasks for me. And it’s good to use. I also just end up copying
and pasting something from an old website, in terms
of the header and the footer, just because I can’t be
bothered to remember it. It’s true. But the other side
of it is then I probably either
define a set of styles just to make things look OK,
or I just go and grab something like Bootstrap or Foundation
because, ultimately, I just want something that kick
starts the look and feel. And then I’ll change it
afterwards if I want to. So this was the aim
of Web Starter Kit. So out of the box,
we come with Gulp. And we do a set of
tasks with this. So with your styles, we
have CSS and Sass support. And we concatenate, which means
just two files, smash them together, which means when the
browser has to go and fetch a CSS, it’s fetching one
file rather than five. It’s just easier
and more efficient, in terms of getting
everything to the browser. And we minify it so the files
are actually smaller, faster, to actually get to the device. And it’s been really
interesting because, while I use Sass every day, most
people actually get to a point, when they’re new to this,
they don’t want install Ruby. They don’t want to install
Sass on top of that. So in the next version
of Web Starter Kit, we’re going to drop the
requirement for Sass altogether. We’re going to make
it an optional thing. So by default, no Sass. But if you add it in,
we’ll be using node Sass. So basically, it’s
an NPM module. There’s no additional
dependency. JavaScript minify
and concatenate again because it’s efficient. We also use JSON out of the box. So if you’re a
brand new developer, I think this is probably
a little bit scary because you suddenly get this
thing that goes, actually, in JavaScript you need to fix
these set of issues. But it’s incredibly useful. It catches really simple errors. And plus, it encourages the
education of best practices in JavaScript. Images is an interesting
one because, how many of you guys have heard of
PageSpeed Insights? OK.A fair few. So PageSpeed Insights
looks at your site and basically
analyzes, essentially, the load time
performance of your page. And one of the things it looks
for is image compression. And at Google I/O,
we had a device lab like we had, and
we got to a point where people kind
of said, I want to see my website
across all the things. And we kind of,
me and Pete LePage were manning the station. We got to the point
where we said, OK. We’ll put it on
all these devices if you let us analyze every
single part of your site and kind of point out where
you could be doing better. And images, it was
horrifying the number of people that just
didn’t minify images. And these aren’t even,
like, just pet projects. These are like proper
companies spending lots of time on their mobile sites. And this thing could
save you 50%, 60%, 70% on just a single image. So yeah. We just put that in there. It’s best practice. And then, we’ve also
got a style guide. And the initial intention
with this was, out of the box, if you just wanted
to get going, you’d have a good set of styles. And then, over time, we’d hope
the you’d jump in Style Guide, customize it, do
whatever you want, rip bits out, put stuff
in, and it would be yours. And developers actually
really like this. They like the notion of
splitting content from style. I don’t know whether it’s a
[INAUDIBLE] style guide driven development, but
that’s generally how people come to refer to it. But the problem with the
current version of this is it’s horrible
to actually change. Like, it’s great. A lot of people would
just jump in and use it. But tweaking it is
a pain because we’ve got all these
dependencies on Sass. And it’s not all that good. I’m going to talk
about what we’re going to change with
that in a minute. But first, there’s
two other tools that we added in to
the Web Starter Kit. And basically, the minute you
start a development server with Gulp Serv, it
adds in LiveReload. Now, if you’ve seen any
of my talks in the past, I frigging love LiveReload. I still occasionally see
professional web developers make a change, go into
the browser, hit Refresh, occasionally hit Control
+ Shift + Refresh because the cache
is taking effect. Yeah. It drives me insane. But basically, what it does is
you make a change in HTML, CSS, or JavaScript, and
then it’ll instantly reload the page for you. You get this really nice
development workflow because you can just
stay in your edit to make the changes
that you want. And you immediately
see them take effect. But one of the other tools that
we’ve added in is BrowserSync. Now, BrowserSync is
this weird little thing. If you have a set of
devices and browsers pointing to your local
development server, any interaction that you
do on one of those pages gets synced across
all the other devices. So this is like
tapping, scrolling. You can input text. And all of them get
matched across the devices. Now this is really
handy if you’ve got like different platforms,
different browsers, different screen sizes just
sat next to you at your desk. Maybe like a tablet and a
couple of different versions of different OSes. This is really
useful because you can just stay at your computer,
doing whatever you need to do, and then checking all the part
of your page, just from your, like, development machine. So you don’t have to muck
around with each one. So that’s what we have
in Web Starter Kit today. And I kind of
mentioned that we’re going to drop Sass support. That seems to be quite a big
one that people want to change. The other one was
the style guide. And the biggest issue with this,
the IC, is the fact that A, it’s super unfriendly, and
B, we get to this point where it was getting
unmanageable, even for us. So we needed to
properly strip it back. And just figure out, OK. We need to undo all
this dependency. And we’ve got to a point,
we’re like, we should just start again. Because basically,
it’s a style guide that we inherited
from Web Fundamentals. And we got to this point where
we realized that actually, a lot of the people
using Web Starter Kit, they also had a
lot of requirements around browser support. A lot of these developers
were at a point where they need to
support all the browsers. And then we kind
of realized, well, that’s normally a gating
factor in Polymer. And we figured, well, if we’re
going to do a style guide, we could use the
material design spec and bring it to some
of the older browsers. So this is like a super early
cut of what we currently have. And essentially, it’s
just a material design inspired style guide. It’s got the usual
things that you’d expect– typography,
lists, of course. I really like this bit
because it’s like a rainbow. Obviously, because you’ve
got material design spec, you have to have all the
buttons with all the ripples. My personal favorite
is the text field. And I just love the animations
with the underlines. And then when you get to the
next one, the label goes up. And we just basically have
a set of default boilerplate components. But the really nice thing
with this is behind the hood, it’s so much easier
than what we had before. You can literally jump
into this and understand, if you wanted to change
something with the buttons, you can actually
just find it really clearly in this new structure
because it’s literally like, button folder– button.sass. Easy. But it’s really
interesting, in the process of this, what we realized,
the material spec isn’t necessarily geared
towards standard web design. Like, if you think of a
stereotypical website– header, set of links. That’s pretty much
Web Design 101. I guarantee all of you have
implemented a website exactly like that at some
point in your life. And yet, there wasn’t
anything in the material spec that just did this. So we’ve been working
the Material Design team, just kind of like,
what does this pattern look like in material design? And they’ve been great because,
something as simple as this, we’ve just got a
couple of variations– so just standard kind
of bar with the links on the right, Centered
Horizontal Navigation where we’ve got kind of like the
content embedded within it. If you look at the
material design spec, you also have, like,
static navigation, which is where you have the left
nav bar hidden away on mobile. But then it’s constantly pulled
out when you’re on desktop. And the idea with
all of this is then, you obviously get back
into the standard hamburger menu with the side nav. But it’s been interesting,
the fact that we actually hit this problem where it wasn’t
built for content sites. So it’s been an
interesting kind of process getting to that point. And I wouldn’t be surprised if
we hit another couple of points like this where actually we
need to work the Material Design team to actually bring in these
new kind of design patterns. And we’ve been really
fortunate because we have a couple of Chrome
UX designers in London. And they happen to
unfortunately sit near us. So we can basically
tempt them in to come and help us with things. And they, Hannah and
Ed have been great because they took one
look at our style guide and they kind of, they probably
died a little bit inside, like, what are you doing? But Hannah’s put together
this amazing mock which is basically
how she thinks the style guide will be used. So rather than have, like,
check boxes and buttons, that should really be
grouped into a form. That’s how it’s
going to be used. And I very roughly started
putting this together, hence the bacon ipsum. But it’s an interesting
point, the fact that Style Guide should be kind
of getting to this point where it helps you and encourages you
to use it in a particular way. So we’re going to be including
things like just copy to clipboard, so you don’t
have to worry about finding a particular snippet
hidden away somewhere else. And that brings us
onto this iterate step. Because Web Fundamentals
should help you with learning, Web Starter Kit should help
you with building and starting a brand new project. And the minute you
get to iterating, this is where DevTools
basically comes into its own. And I guarantee
all of you probably have opened up DevTools. So the DevTools team
have been making a ton of changes that basically
help you with mobile web development, as well figure
out what the browser’s doing. So the first one is
this Device mode, which is basically this blue
mobile icon on the top left. Now, the first thing to
call out are these bars just above where the website is. These are basically
an indication of just where you media
queries are on the page. Now, the really useful
thing with this, if you get to a
point where you’ve got a ton of media
queries in your page– perhaps you’re doing
it by component– you can actually
realize where you might have conflicting media
queries, and things might get a bit messy. And there’s a good
chance that there might be something wrong
within those patches because you’ve got so
many things overlapping. The other part of this that
you’ve probably all seen before, just put in a nicer
way, is this Device selection, where basically select
a particular device. And it will set the
width and height of that particular device,
including the screen density, which is really nice because
you get to this point where, if you’re using
responsive images, you’ll actually see all of it. But one of my
particular favorites is this new network throttling. Now what this is,
is you can basically select a particular
network type that you want to emulate
within your browser. And then it will just
apply it for you. So here, if I select 2G,
do a refresh of the page. And this is a pretty
solid indication that I need to do something
with that image at the top because that’s kind of
painful for a 2G user. But the nice thing with this is
actually embedded in DevTools. So this is the point
where you’re already trying different things out. Before, you’d have to pull
out a different, like, application, depending
on which one you use, sometimes they’re actually
a bit fiddly to work. I actually once managed
nearly to lock myself out of my machine because I’d
applied it to my entire machine to actually have
the slowest network connection I could think of. At that point, my
machine decided to lock, and then also decided
it needed to phone home to make sure that I was actually
still legitimately working here. I can’t remember
how I got out of it, but it was not a pleasant
experience, I can tell you. But at least with this,
it’s just built straight in. And it’s really easy to change. So the other area of a ton
of changes in timeline, in DevTools, is timeline. So, if I just refresh the
page, what I’ve got is just, essentially, a timeline of
what the current page rendering is doing. And we always get
this typical waterfall of what the browser’s done. But one of the first new
additions is Paint Profiler. So here I’ve just selected
the paint on the page and it looks fairly hefty. But down below, what you’ve got
is this new Paint Profiler tab. Now what this is
is, along the left, we have a set of draw commands. This is basically
what the browser’s doing to paint these particular
things to the screen. So as I scroll down, we
should get to a point where you can actually start
to see where these paint commands are actually
painting stuff on the page. Along the top here, we
also have representation of how each one of those
commands have happened, and how long they took
to actually occur. And then right in the center,
we have this big bad boy, which is basically what the
browser’s actually painted. Now, the really
nice thing with this is, if I select a small
chunk of the instructions from the Paint, as I
start to scrub along, you can actually see what
the browser’s painting and how it’s painting it. So if you ever get
to a point where you’ve got this huge, long
paint and actually, it’s really causing you issues,
this is the first time you can actually really
dig down into what the browser’s doing
under the hood. But admittedly, you have
to have an issue that warrants that huge paint. But what happens if the
browser could tell you where this paint has happened,
and then also give you an idea of why the hell
it’s actually done it? So if I go to our trusty
Chrome developer website, I should hopefully
find a paint that looks a little
something like that. Now, I genuinely find timeline
confusing at the best of times. And I also find it
even more confusing to figure out what the browser’s
doing when it decides to do it. So when I see a paint like
this, where there’s just a blue block,
there’s a bit of me that questions why it’s painting
a blue block when it’s probably always been there. So, in the Paint Profiler,
this is all you’d get. But if you move to Details,
right down at the bottom, we have this Style
and Validations. And basically, what
this is telling you now is the fact that
it’s this particular element on the page that
has been painted. And the reason why it’s
been painted is animation. Now this is really nice because
before, you’d run a timeline. You’d have to be a
master of the dark art– like Mr. Paul Lewis– understand
what the hell is going on because you know what the
browser’s doing under the hood. This is the first time
DevTools is actually going, I’ve painted. Here’s the reason
why I’ve done it. And it’s kind of
nice with this demo because I can
actually click on this and you see Styles being added. So you can actually see
the style and validation when the paint’s happened. But still thinking
along those lines, if we go back to another
part of this timeline, you can see we’ve got this
recalculate and this layout. Now, again, not being a master
of the dark art of timeline, I genuinely still don’t
know why that would happen. So if I scroll down to
the bottom of this layout, we’ve also got Layout
and Validations. And this is another scenario
where DevTools is actually saying, this particular
thing has happened. Here’s why. So here we can actually get a
stack trace that’s basically saying,
CDS.card.coolproperties is resulting in this
particular layout happening. And it also has a list of the
components that’s basically being laid out as
a result of this. Now this is really useful
because before, you were kind of left high
and dry to figure out what was going on. Now, you can actually
get a bit more of an indication of where
your code is resulting in the browser’s doing
some kind of action. Now, I don’t know about
you, but there comes a point where, if I’m looking at a
waterfall, it kind of just becomes a lot of
pretty colored bricks. And the thing that
really kind of confuses me is, if I take
something like this, I kind of see the layout and
the recalc style have happened. And this yellow block
kind of tells me that it’s my JavaScript
that’s done something. But this isn’t a really
good, clear picture of what’s happening,
why it’s happening, and how long each
piece is taking. It’s just a colored brick. And this is where the new
Flame Chart Viewer comes in. And basically, as
you zoom in, you get a bit of a better
picture as to Animation Frame took this amount of time. Within that, your
JavaScript was actually the majority of the
time spent in it. And something
inside this resulted in recalculate style and layout. Now, it’s exactly
the same information, but it’s just displayed
in a different way. But the nice thing with
this is you can actually start seeing a bit more
of a cause and effect. But admittedly, this
still doesn’t actually help me figure out what
is it in CDS.min that caused calculate Style,
followed by a layout. So wouldn’t it be kind of
handy if you could actually figure out a bit more
about what’s going on? And this is where JS
Profiler comes in. So if I go back and
repeat this same thing. So here, I’ve now enabled the
JS Profiler along the top. If I go and find this Animation
Frame again, some of you may have noticed that
the thing looks suddenly a lot, lot longer
and scarier now. But here, we’ve got the
Animation Frame fired, followed by that exact same function call
of something in our JavaScript. But you notice a
couple of bars in, and suddenly, we’ve got this
CDS.card.expand, followed by CDS.cardcollectproperties. And it’s that method
that’s actually resulted in the recalc
style and the layout. So this is really useful because
now, you’re actually at a point where you don’t have this
magical black box of, you did something, and
now I did something, too. It actually goes, well,
you did some stuff. This was all fine. The minute you hit this
method, this is what happened. So it’s actually starting to
serve us up a ton of stuff. [APPLAUSE] Yeah, there we go. And this is really nice
because, normally, you’d get to this point where
actually, you’d realize, maybe you measured
offset top or something. But unless you know
that’s a problem, it’s pretty hard to diagnose
that, whereas this goes, this method. Something here did
something fishy. And that, at least, reduces
your entire search down to a much, much smaller surface
area to try and figure it out. So one of the other
new cool things, again, still in the vein of
DevTools servicing information, is you notice in the Flame
Viewer, we get to this point where we have these
kind of weird bubbly things along the top, with
some kind of time in it. Now what these
represent are frames. Admittedly, my website is
awful because by the looks of those frames, it’s
definitely not hitting 60 FPS. But we’ll look past
that, just for a minute. But when you actually click
on one of these frames, you get this Layers
panel down the bottom. Now, how many of you guys
are happy when I say, the notion of composite layers? Oh, wow. So Jake actually
gave amazing analogy of this of– if you
had a wall and you had to paint a stick man
moving from left to right, you could draw with a marker
on the wall a stick man, paint over it, draw the stick
man again, paint over it, and repeat until you get
to your final destination. What you could do is have
transparent plastic on wheels, draw the stick man once,
and then just move it across the wall. And the idea of
a composite layer is you basically draw everything
on a transparent layer to move across. And it’s more efficient. It just loads it in the
GPU and you’re good to go. So what this Layers
panel does is it actually tells you everything that’s
been promoted to a layer, whereas before, it
was kind of, you’d have some orange borders
that might tell you. Now it’s really explicit. Now the other side
of this, as well, as you can see, on the right
hand side, Composite Reasons. Now this is great because
sometimes you get to a point where something
would be promoted to a layer you
didn’t mean it to. Other times, you want it
to be promoted to a layer. This tells you it’s not. But if you have something
and you don’t know quite why it’s being promoted to
a layer– like this thing– Composite Reasons will tell you
why it’s made that decision. So in this case, “overlaps with
other composite content cannot be squashed, since this
layer scrolls with respect to the squashing layer.” I didn’t intend
for this to happen. Ironically, this causes a
bug on Android for Chrome where, when you scroll
it off the screen, it doesn’t become
a layer anymore, and things go a bit funky. But this is actually
the first time I’ve debugged it because you
can actually see all the layers. And the nice thing
with this is, if you start clicking through
each of the frames, you should start
seeing the layers move. But because I’m so
janktastic, of course you don’t see the frames. But if it was good demo,
it would’ve worked. But again, the nice thing
with the Composite Reasons is, again, DevTools is actually
explaining what it’s done and why it’s done it. Now, as good speaker, I
have backups to all of these because, when you have
Polaris telling you, don’t update Canary,
it’ll break your demos, you have videos of backups. So, yeah. That’s what we’re doing
on the Chrome team. Web Fundamentals to help you
with learning, Web Starter Kit to help you build new
projects, and DevTools is adding a ton of new features
to help your mobile web development, as well
as understanding what the browser’s doing. So that, that way, when
you hit this problem of not hitting 60 FPS, it’s
actually easier for you to diagnose the problem. So, thank you very
much for listening. Hope it’s something useful. Cheers. [APPLAUSE]

One Comment

Add a Comment

Your email address will not be published. Required fields are marked *