ces, in terms of providing good feedback when things go wrong, and just reducing complexity, reducing cognitive load. And of course, if you make deep learning easier to use, then you're also making it accessible to more people. So the end goal with Keras is to make deep learning accessible to as many people as possible. Until now, the TensorFlow implementation for the Keras API was available as part of an external open source repository. But now what's happening is that we are bringing the Keras API directly into the TensorFlow project. And we are doing that to make Keras work seamlessly with your existing TensorFlow workflow. Concretely, what's happening is Keras becomes available as a new module inside TensorFlow, the tf.keras module. And it contains the entire Keras API. So if you're a TensorFlow user, what that means for you is that now you get access to this new set of easy to use deep learning building blocks that will work seamlessly with your workflow. And if you're an existing Keras user, what this integration means for you is that suddenly you gain access to high level TensorFlow training features, things like distributed training, things like distributed hyperparameter optimization, training on Cloud ML. So that's really powerful. So to give you a concrete sense of what your workflow will be like when using the Keras API to define your models and when using TensorFlow estimators and TensorFlow experiments to train your models in a distributed setting, I will walk you through a simple yet fairly advanced example. We will look at the video question answering problem. So that's what the problem looks like. We have this data set of a few thousand of videos. Each video is about 10 second long. It shows some people doing some activities. And a deep learning model will be looking at the frames of these videos. And it will try to make sense of it. And then you can ask the model short natural language questions about the contents of the video. So in this example, we have a short video of a man packing some boxes into a car. And you can ask, what is the man doing? And the model will be looking at the video. We'll be looking at the question. And we'll have to select one answer word out of a set of possible answers. So here in this example, you can ask, what's the man doing? He's packing. And that's actually an interesting question, because if you were to just look at a single frame from this video, you couldn't answer the question. The man could be unpacking as well. So the reason you know he's packing is because of the order of the frames. So we expect our model to be able to leverage not just the visual contents of the frames, but the order of the frames as well. So needless to say, this is a tremendously difficult problem. Just three or four years ago, before Keras, before TensorFlow, this would have been only doable for a handful of freely well-funded research labs. This would have been pretty much a six-month project for a team of expert engineers. And what we are doing now is that we are making this really advanced problem accessible to pretty much anyone with basic Python scripting abilities. So we are democratizing deep learning. So that's what our solution looks like. That's our network. It is structured in three parts. So first, you have one branch that takes the video input and turns it into a vector that encodes information about the video. And you have one branch that takes the question and turns it into a vector. So now you can concatenate the question vector and the video vector. And you can add a classifier on top. And the job of the classifier will be to select the correct answer out of a pool of candidate answers. So the first step is to turn the video input answer into a vector. A video is just a sequence of frames. And a frame is an image. So what you do with an image is that you run it through a convnet. That's what you do with an image, natural thing to do, a CNN. And each CNN will extract one vector representation for each frame. So what you get out of that is a sequence of vectors encoding the frames. And when you have a sequence, what you do with it, the natural thing to do is to run it through the sequence processing module called an LSTM. And this LSTM will reduce the sequence to a single vector. And this vector is encoding information about all the frames and their order. So the entire visual contents are the video. The next thing to do is a similar process applied to the question. The question is a sequence of words. And you will use a numbering module to map each word into a vector, a word vector. So you get a sequence of word vectors. And we reduce it using a different LSTM layer. Once you have your vector representation for your video and your vector representation for your question, you can connect them. And you add this classifier on top, whose job is to select the right answer. So that's really the magic of deep learning. UTex is really complex inputs, which could be videos, images, language, sound. And you turn them into vectors. So you turn them into points in some geometric space. You turn meaning into points in a geometric space. That's the essence of deep learning. And what's really powerful about it is that once you've done that, you can use linear algebra to make sense of these geometric spaces. And you can learn interesting mappings between different geometric spaces. So in our case, we are learning a mapping between an initial space of videos and questions and a space of answer words. And we are doing that just through exposure to training data. And the way we are doing this is really by assembling together these specialized blocks for information processing. And it's a very natural thing to do. If you have an image, you process it using an image processing module, which is a CNN. If you have a sequence, you process it using a sequence processing module, which is an LSTM. And if you want to select one element out of a pool of possible candidates, then you use a classifier. It's a natural thing to do. So what you're really doing with deep learning is plugging together these information processing bricks that are pretty similar to LEGO blocks, right? To LEGO bricks. So building deep learning models is conceptually similar to playing with LEGOs. And if the ideas behind deep learning are so simple, then the implementation should be simple as well. So let's take a look at the implementation. This figure is a very straightforward translation, a form model, into a Keras implementation. On the video encoding side, we have this inception v3 convnet. And we use a time distributed layer to essentially apply this convnet to each frame alongside the time axis of an input video tensor. And then we pipe the output through this LSTM layer, which will use it to a single vector. So one interesting thing to note here is that our inception v3 convnet will come loaded with pre-trained weights. And the reason that's important is because with our current video data set, we don't have enough data to learn interesting visual features on our own. So we need to leverage pre-existing visual features that were learned on a larger data set, so ImageNet in this case. And that's a very common pattern in deep learning. And it's a pattern that is made really easy by Keras. And we'll see how in a second. On the question encoding side, it's even simpler. You just run the sequence of words into an embedding layer to produce sequence of vectors. And then you reduce the sequence of vectors to a single vector using an LSTM layer. So once you have this video vector and this question vector, you can coordinate them with a simple concat app. And you add the class file on top, which is just two dense layers, which will select the correct answer. Let's look at the code. So this is the entirety of the code for the video encoding part. It's just a few lines. It's very readable. It's very simple. You start by specifying your inputs. So this is your video input. It's a sequence of a viable number of frames. So the none here is the number of frames. It's undefined, which means it could change from batch to batch. And each frame is a 150 by 150 image, restrict color channels. In the next step, in just one line, we're defining an entire Inception Visual Stream model, which is a fairly complex model defined in just one line. And it comes loaded with pre-trained weights from the ImageNet dataset. And all of this is built-in. It's already into Keras. So you don't have to do anything more. It's literally just one line. And we are not including the top layers because they are not relevant to us. And we are adding some pooling on top, which allows us to extract exactly one vector from each frame. In the next step, we are setting this carbonate to be non-trainable, which means that its representations will not be updated during training. And the reason that's important is because this carbonate already comes with good, interesting representations. And you don't want to alter them. Again, so that's a very common pattern in deep learning to take a pre-trained model and freeze it and make it part of a new pipeline. And it's a pattern that's made really easy in Keras. So once we have this frozen pre-trained carbonate, we use a time-distributed layer to distribute the carbonate across the time axis of the video input. And the result of that will be this tensor of frames, which we run through an LSTM layer to get a single vector for the video. On the question side, things are even simpler. We define our question input as a sequence of integers, a variable number of integers. So why integers? Because every integer will be mapped to a vector in some vocabulary. And we run this sequence of integers into an embedding layer, which will map every integer to one vector. And these embeddings are trained, of course. It's just part of the weights of your model. And then you run this sequence of vectors through an LSTM to reduce it to a single vector. So one interesting thing to note here with the two LSTM layers that you've instantiated so far is that we were not configuring the layers beyond just specifying the number of output units. And that's interesting because usually when you're using LSTM layers, there are lots of things you have to keep in mind. Lots of best practices you should be following to make things work. For instance, you should remember that the recurrent weights should be initialized with an orthogonal initialization. You need to remember that the forget-get bias should be initialized to one and many more. And here we are not doing this because all these best practices are already part of the default configuration of Keras layers. It's a very important principle in Keras that best practices come included as default. And what this means for you is that your models will typically just work out of the box without you having to tune every parameter to make it work. So that reties into our goal with Keras to reduce cognitive load, to reduce complexity. We don't want you to care about these technical details. We just take care of them for you. So once you've done encoding your video and encoding your question, you just use a concat op to turn them into a single vector. And you add these two dense layers on top, which will select one answer word out of a vocabulary of a given size. In the next step, you're using your inputs and your outputs to instantiate the Keras model, which is essentially a container for a graph of layers. And then you are specifying the training configuration. So you are specifying the optimizer that you want to use, the item optimizer. And you are specifying the loss function for which you are optimizing. So that's very simple so far. At this stage, we've defined our model. We've defined our training configuration. And now we want to train this in a distributed setting, maybe on Cloud ML. So let's see how that works. This is that. This is where the magic happens. You can use the TensorFlow estimator and the experiment classes that Martin introduced to train this model, this Keras model, in a distributed setting in just a few lines of code. All you have to do is to write this experiment function in which you define your model. You use your model to instantiate an estimator using this built-in guest estimator method. And once you have this estimator, you use it to create an experiment. And that's where you specify your input data, for instance. So it's just a few lines of code. It's really like magic. In just a few lines are very readable, straight for our pattern code. We've defined a state-of-the-art model. And we are training it in a distributed setting. So to solve this really challenging problem of video question answering, we should have been completely out of reach to almost anyone just a few years ago. So these APIs, these new high-level APIs, are really democratizing deep learning. That's made possible by two things. On one hand, you have the Keras API, which is this very high-level, easy to use, and powerful way to define deep learning models in TensorFlow. And besides being just easy to use, each layer comes with good default configurations, which allows your model to just run out of the box without much tuning. And the other piece of magic is these new high-level TensorFlow training APIs that Martin introduced, estimator and experiment. And together, this allows you to solve any deep learning problem with very little effort. So we think these new APIs are a big step towards democratizing deep learning and making TensorFlow and deep learning available to everyone. And we hope you will find them useful. And we are very much looking forward to seeing all the cool applications that we'll be building with TensorFlow and Keras. Thank you very much for listening. As a lot of developers know, there's more to having an app succeed than just building a great app. You want your app to be dynamic and responsive by delivering fresh content to users and quickly reacting to their changing needs. You want to test out major decisions to make sure you're doing the right thing before you push them to your entire audience. And ideally, you want to provide a tailored experience for each user so your VIPs feel like, well, VIPs. But let's be honest, that can be a lot of work. And if you're a developer without a ton of resources, that's time you'd rather spend on other things, like building your app. That's where Firebase Remote Config comes in. Firebase Remote Config is a simple key value store that lives in the cloud. But don't let that simplicity fool you. Because it lives in the cloud, it means you're able to deploy changes that your app can read within a matter of minutes. For instance, say you've just pushed your app out to the world and you suddenly discover that your Swedish text contains some offensive language. How are you supposed to know? You don't speak Swedish. I don't blame you. But fixing that text the old-fashioned way would mean creating a new build and going through the entire publishing process again. That's something that could take days, which is an awfully long time to have 9.2 million people cursing your name. But if your app uses Firebase Remote Config, you could change that text in the cloud through the Firebase console, kind of like this. The next time your users fire up their app, Remote Config will grab the latest values, update your app's text, and just like that, you've averted a major international crisis. Or let's say you've got a puzzle game and you're hearing complaints from your players that level five is too hard. If you've configured your app using Remote Config, you could tweak those settings to give your players a few more turns and push out that change to the world. But hang on, are you sure that's the right thing to do? What if the silent majority of your users actually enjoy the challenge of a more difficult level?  How could you test whether or not this changes a good one? Sounds like you need an A-B test. That's where Remote Config's Audience Segmentation feature comes in. This allows you to deliver different configurations to different groups of users simultaneously. So you can try out your new level settings with half your users, while keeping the old settings with the other half. But Audience Segmentation isn't just great for A-B testing. Maybe you've got a feature change that could have a major impact on your in-app economy. Or maybe you just wanna double-check that some new networking code isn't going to set your servers on fire. You can use Firebase Remote Config to gradually roll out these changes, trying them first with a small percentage of your users before pushing them out to your entire audience. Remote Config can also deliver different configuration sets to your users based on all sorts of different factors, from device type or locale to any audience segment you've defined in Firebase Analytics. So you can send out one welcome message to your New Zealand customers and another to your Australian ones. Or only show your review this app button to people who use your app every day. Or you can change your home screen experience for your customers who have spent large amounts of money on in-app purchases. So they feel special. Remote Config is backed by a client library on iOS and Android that handles important tasks like caching, dealing with flaky connections, and keeping network requests lightweight, which is always a good thing. To give Remote Config a try, check out our documentation here. We can't wait to see what you built. So you've built an amazing mobile app that your users are gonna love. But you wanna get it into people's hands and let them see just how awesome it is. Well, AdWords helps you do this, putting ads for your app in front of billions of people that use Search, YouTube, Google Play, and more. You can quickly set up an ad campaign to reach the type of users that might be interested in your app. You only pay if the user clicks on that ad and you can set the budget and acquisition costs that you're comfortable with. But how do you know you're reaching the right users? Maybe some will install your app and forget about it while others will make it part of their daily lives. Firebase Analytics helps you do this. You can define events that happen in your app that you consider to be important, such as reaching the first level of your game, purchasing a fancy new pair of sunglasses, or returning every morning to check out new products. You can tell AdWords which of these events are most important to you. Then, AdWords will display ads to people who are more likely to complete these important actions in the future. You can also build audiences, which are specific segments of users and have AdWords display your app to them. For example, imagine that you have a group of users who are very active, have added a product to their cart, but haven't purchased yet. Well, you can use Firebase to create an audience of just these people and then use AdWords to give them specific ads and encourage them to come back to your app and take action. Understanding your users and engaging with them at just the right time and in the right way will help you build loyal users for your app. Firebase and AdWords working together to help you grow your user base. Get started today, your new users are waiting. Okay, so we're now in the Android sandbox area. I'm gonna spend some time in this area because there's a lot going on, but we're gonna start with just features of the OS and David here is gonna tell us about a couple things I've been really curious about. Can we start with Kotlin? Let's talk about Kotlin. Sure, Kotlin is definitely the show stealer, it seems to me, from watching the keynotes. So Android Studio now has Kotlin support. You can create a new project and you'll see that you have the ability to check Kotlin support in from the beginning. We already have a Kotlin app here, but you can also write Java code and convert it to Kotlin very simply. And do you like writing Kotlin? I love writing Kotlin. I actually haven't gotten a chance to write Kotlin recently, but when I was first learning about it a year ago, I spent a lot of time just going through the language and getting very excited about it just because it looked so much more concise and it brings in a lot of modern features that I like from a lot of other languages. And I was really happy to see how fast they moved on it and the great tooling support that IntelliJ brought into it as well. Yeah, I mean, I've been talking to people around the festival today and one of the things they keep saying is how well designed they believe Kotlin is and what a mature language it is because of that. Yeah, no, it's absolutely. I feel that they got a lot of influences from a lot of new languages. I highly recommend trying it out, give it a shot. And Catherine, you've been working on bringing Kotlin into Android for a little while. Can you tell us what the motivation for that was? Yeah, so I think the big reasons we wanted to bring Kotlin to Android were that, like David says, most developers who try it find it to be really concise and expressive and it has a lot of awesome features like type and null safety, which are really useful for writing stable, non-crashy apps. Plus, it's totally compatible with the existing Android environment and also with the Java language, which means that even if you have a large existing Android code base, it's really easy to incrementally adopt it and you can kind of try things where it works. You don't have to go rewriting large swaths of code. That's awesome. Being able to incrementally adopt it, as you were saying, so you don't have to jump in and refactor everything all at once. Yeah, exactly. If you have some chunk of Java you're happy with, you can just leave that, keep modifying it, write some new module in Kotlin, kind of adopt it very organically as you see fit. Awesome. I think the final thing is just, we've been hearing about from more and more developers that they love it, it really makes them happy to write in it. And we try to listen to our developers and give them things they love, so hey. I want to look at something else as well, David, the profiler in Android Studio. Can you show me something there? Sure. We're really excited about the profilers. I feel like this is a long time coming. If you look here, you can actually see that this is displaying bitmaps as a sample Android app. We downloaded it as is, we didn't modify it at all. And if you look over here, you can actually see we've already started the profilers on it. We have the CPU memory and network profiler, so if I start to interact with the app, you'll start to see the different profiler shown. Yeah. So you can deep dive into any of them. You can sample CPU activity here. We can click on some stuff, and then what you'll see is if you drag across here, you could actually look at the content of the request. This is actually an HTTPS request, and you can still see the contents of it, which is something that we're very excited about because that was normally a challenge for a lot of people to try to do. I think some people would debug in kind of HTTP traffic in order to see it. We've sort of enabled some new features here, which we're happy about. Oh yeah, I'm used to inspecting the traffic on the machine that I'm testing on to try and get that debug information, and yet here it is right in studio. That's so convenient. Yeah, I really hope that people have a chance to play with it. We hope that they find the profilers intuitive. I mean, to me what's exciting is as you're messing around with your app, you might, all of these things that we're invisible for, you now have a chance to actually play around with it and see it. And as I said, we don't even think, we're including documentation with it, but we're even hoping that even without it, you should just be able to play around and try things out and see what happens and then learn more about your code. We were once debugging some code and we're like, no, something's wrong here. We're getting this weird memory spike and we were actually, we were surprised to find that all along, this code had our problem with it, but we didn't know about it until we had written our own profilers. That's profiling. There you go. Awesome. David, thanks so much for taking the time. Thank you very much. A few people online have been asking me to get a demo of picture and picture. So I found Rob and he's going to give that to us. Hey, I'm Rob from the Android Window Manager team and I've been working on picture and picture for this release. We're really excited about it because Android, you know, it's always been a good platform for interacting with content, watching YouTube, et cetera, but if you want to start to interact more deeply and multitask, we haven't always provided the tools and I think picture and picture is a great one. So I'll walk you through a way of using it. So here we have this video and it's a go game by Lisa Dole, the player who famously challenged AlphaGo last year. And we can see if we go back to home, we'll get the video and it's still playing here. We can move it around. And for example, I could go into my Go app and I could start to multitask and I could play the game along so that I could, you know, play along with the game and begin to explore my own variations and I can dismiss when I'm done. That's awesome. Enjoy picture and picture. Thanks, Rob. Well, thank you. Everybody's talking about Kotlin so I was able to get some more info out of Andre from JetBrains. Hi, Andre. Hello. So first question, you've been working with the Android team for a while. What are you most excited about with this collaboration? Well, this is very great to be here because basically this means that there are many people will be coming to Kotlin, new users, new, well, new exciting ways of using the language, new learning materials, new libraries, everything. So it's basically Kotlin's growing as we are looking at it and it's all together wonderful. I'm very grateful to the Android team that they had the courage to make the move. But that was, as they say, that was what the public was actually wanting them to do. So we're very happy about it. All right. So let's talk a little bit about the future and what's coming next. First, the language. What's coming next with the Kotlin language? There are actually many things we're working on but so the brand new thing with Kotlin is coroutines. We have shown the experimental design pretty... Yeah, it was like three months ago. So coroutines are a big thing now doing asynchronous programming in an easy way. So we're now looking into improving that and finalizing the design so that the next version of Kotlin will probably have it already stable so everybody can use it and be sure it will work for all the versions. Then the next big thing is multiply from Kotlin. So Kotlin is now big on Android, big on the server side. We are working on JavaScript and we have recently introduced native which is in a technical preview version now. So we're trying to span the language across many platforms and enable multi-platform development where we can say have a couple of modules reused for many platforms and then some platform specific modules implemented some functionality in a specific way that's leveraging the intricacies of the platform. So it's a very big direction for us. And then there are language-only things like value types, for example, for optimal storage or collection controls. So we have very many directions there and the strategic ones are those, you know, platform things and the coroutines. Awesome, what about tooling? What's next there? Yeah, so we're actually, JetBrains is all about tooling. So our first and foremost goal with Kotlin was making the language toolable and now we're in a pretty good shape with many things but there's a long road ahead. We are now tightly integrated with Android Studio and we'll work more on that. So in 3.0 preview, we have new wizards for creating things and we have unified analysis for Java and Kotlin and we'll improve that. We're working on the incrementality of the tool chain. So Google side as well as JetBrains side and for non-Android things, we're doing pretty much the same. We're basically getting on par with Java on the Java platform. We're working on debugability and incrementality for JavaScript. Native is very young for that but we'll get all that there too. Awesome, thank you so much. Thank you very much. The Firebase Notifications Console lets you re-engage your users quickly and easily. With it, you can manage and send notifications to your users easily with no additional coding required. Messages can be addressed to single devices, Firebase Cloud Messaging topics or devices that you select using powerful analytics tools. So for example, you can send a message to all of your users who've made an in-app purchase, giving them a special offer, allowing you to re-engage with them. The Firebase Notifications Console integrates with analytics so you can measure the effectiveness of your messages and explore insights based on your users' activities so you can grow your application by easily engaging your users through the Firebase Notifications Console. All right, so now we're in the Android Wear area and we're gonna take a look at some of the newest watches with the design lead from Android Wear, Brett. Hi, Brett, how you doing? Hey, Timothy, doing great. So I was talking to David Singleton earlier today and he said you have to check out the new Tag Watch. Can you show it to me? Yeah, I can. So here it is. And you can also see that it's available in this diamond-studded edition as well. And one of the things that's really nice about the Tag Connected is that it's modular and that's actually in the name. And so not only can you swap bands, but you can also swap out the tabs on the device in addition to the bands. So you could have a metal bracelet band, a leather band, a sport band, as well as you can change these accents out as well so you can go for same tone or contrasting tone and that all snaps back together. And when it's together, it's like rock solid. So that's one example of how partners are really doing really interesting things on the hardware side. With, of course, Tag, it's got all its iconic watch faces in the software and it's all powered by the Android Wear platform. Yeah, so that's pretty exciting. It was fun to be in Switzerland for the launch event for this too. They know how to host. I bet they do. Tell me one other thing I want to know is for developers, what's the new thing that they get to do that you're most excited about? Really, I'm going to demo a different watch at that point. So the best thing that developers can do now is they can start powering the complication slots or developing watch faces that show off really actionable and great information for end users. So here I've got this watch face that us two developed and it's got four slots in addition to the time. So all I have to do is long press on it. Just, you know, awesomely it's working just like it should. So I long press on it and I can change any of these slots. So I can make my, you know, next meeting. I can go and do like countdown to some important upcoming date. I can show today's date. I can go and for, let's see, let's change the layout you know, over to a different one.  And so developers can do two things. They can either be the watch face itself.  You can just let the users decide. You can add these slots for complications and let data providers either from the system or from other apps power them. And the benefit to users is that they'll really like your watch face. Or if the users are already using something like Robinhood for stocks or Google Fit for fitness tracking, they can get that data right on their watch face. So we're really excited about what developers are doing there and what there's still a lot of possibility left of mind. Awesome. Thanks. Sure thing, Tim. Well, I work as a developer advocate at Google. My primary job is to kind of work with our last partners and work on technical integrations and work with our product teams to improve our products, which are developer facing. I regularly write software. We, I'm part of the engineering ladder. So yes, we are expected to be hands-on with code. Right. So do you love coding? Oh, yes, yes. I'm very much in love with coding. I still do it regularly. Well, I started very early. I was about 12 or 13 when I started coding. And it was always fun for me. I wrote more code than I played games, I guess, at that age. So it was always fun for me. At age of 12? Yeah, I started off pretty early. I had good mentors, so that's the way I would put it. So with which programming language you really start? I started with C. That's the mother of language, right? Yeah, C was where I started off. Well, I went on to do my engineering and after that, I started working in a startup and then moved to IBM. So I guess it was a logical progression for me after engineering to kind of take up a job which paid for it. I wanted the software engineering job itself. And which was particularly in coding where I found, I felt more comfortable. So I just went ahead to do that. If somebody is to design a social app in which areas participant needs to search out those things. So the first step would be to identify a problem that you want to solve in that community which that community would accept as a value add to them and then use an app as a medium through which that solution can be delivered to them. So identify the problem would be the first step for me. But gathering that data will give you insights which will help you define that pain point really, really well. Because you are not that audience. If you're not part of that community, it's very difficult for you to kind of understand the pain point of the community and be in that shoes. So it is best that you interview people who are in that situation and then get the data to decide on the problem. Exactly. So that was Mr. Amarik for you. Thank you Mr. Amarik for your time. We were honored to have you here. That was fun. Yeah, it was fun too. Welcome friends. Today we have with us Preeti Guruswamy to share her journey as a women in tech. Preeti, how did you get started with programming? I don't come from a CS background. I come from a biotechnology background. I wanted to be in medicine, unfortunately, because of financial situation. I couldn't get into medicines. So a lot of people said, why not try IT? Started as a software tester and something caught me. After a year, I wanted to do programming and I remember my mentor. She asked me, have you programmed? I said, no, will you do it? She asked me and I said, yes. Preeti, you've been involved in many communities. What is the one thing that keeps you motivated to contribute back to the society? I feel women need a lot of empowerment and even as a child, right, whenever there used to be a maid and their daughters, I used to always sit with them and teach them so that, okay, do something as an education because education is a very important part of it. And mostly you're educated because you need to have a good husband. Otherwise, if you're less educated, you may not get a very... I think that's why mostly all of us are educated. At least my cousin clan, we're all educated because we get a good husband and I was not very keen about not getting good husband because I never thought education is for an husband, right? Education was for self. What is the message that you would like to give to the women out there who want to start mentoring other women? I think first thing, whether you want to be a mentor or not, you need to believe in yourself and move forward. I think most of the time we don't believe in ourselves, right? And mentoring is one of the beautiful concepts that has been in India. We call Guru, we had Gurus before. They were all mentors. Unfortunately, we have forgotten that fact, right? And being a mentor, you will learn a lot. So be truthful, be sincere and tell your experience in a very sincere way. You know, you don't know who will be inspired by you, who will learn from you. You don't know, they might learn or they may not learn, but at least you'll carve a path for somebody and definitely you will be a good mentor. Thanks a lot, Preeti. And you have a great story to share. Thank you so much. It's a pleasure to be here and thank you very much. Welcome everyone. We have with us Soham Mondal today, who is a Google Developer Expert for user experience. Soham, what is UX according to you? So UX is, as you know, right, user experience. It's about understanding the need, the basic goal that they want to achieve and helping them achieve that goal as simple as that. Recently, your app got featured on the Play Store. So what are your tips for other app developers? So the first thing is, do a lot of user research. Understand their backgrounds and motivations, why they are installing your app in the first place and then build something for that. After that, once you've understood that, you've tested that, done some usability testing, then follow guidelines, right? Guidelines make your life easier. Follow material design guidelines and other guidelines. That's how my app got featured on the Play Store. What are the tips you would like to give for people who are building for rural India? The challenges in rural India are completely different. You have to first of all localize the application, right? There's so many languages in India. It's very important that you localize the app and make it very, very accessible. Apart from that, make sure that the gestures and icons and the overall application is very, very localized. So people are not used to swiping because that's their first computing device. So make sure that you are building something that they understand. And finally, make sure that you're doing usability testing, that they're able to achieve the task, right? In any kind of application. That's very, very important. So with all of this, I'm sure you'll be able to make a great application for the whole of India.  What is it that motivates you to give your skills and expertise back to the community? I've been part of this community for, you know, since 2009.  I used to go to meetups, I used to learn so much. So meet so many interesting people.  I've learned so much from it. It's only fair that I give it back. So that's my motivation. Whether you're just starting out on your journey toward a career in Android development, or you've been working as an Android developer for some time, you might ask yourself, how can I separate myself from the pack and get recognized? Introducing the Associate Android Developer Certification by Google. An achievement available to those who can display the skills of an entry-level Android developer. The first step on your journey is determining if you're ready to take the exam. Start by learning what the exam covers. And review the skills that you'll need to demonstrate when taking the exam. Next, decide whether you need training or are ready to take the exam. Training is available online as well as in person. Also, training is available in some colleges and universities. When you're ready, sign up and take the exam. As part of the sign up, you'll pay an exam fee. If you live in India, you will pay 6,500 rupee. If you live outside of India, you will pay $149 US. After you've signed up and paid the fee, you will download the exam and load it into Android Studio and begin. The exam is a timed performance-based assessment in which you'll implement new features and debug issues in an existing app. When you start the exam, you'll have 48 hours to finish. And once you are done, you will submit the exam for grading. Your submission will be evaluated through a combination of machine and human grading. Based on the outcome of machine grading, you will move on to the exit interview. After you've finished and you've passed your interview, you will then receive a mark from Google and join our community of Google-certified associate Android developers. Once you are certified, you can share your mark on your resume, LinkedIn, G-plus, Twitter, and in your email signature. Every time your mobile app crashes, it's an invitation to your users to rate it poorly and uninstall it. This can spell disaster for the new app that you just launched. If you're an app developer, you need to know exactly where your app is having problems. And you need this information quickly so you can correct the issue before it affects too many of your users. This is where Firebase Crash Reporting can help. Our Crash Reporting tool collects information about crashes that your users are experiencing and sends that data as quickly as possible to be tracked in your dashboard. With the dashboard, you can monitor the overall health of your app. Here, you can see the top crashes and track the recent history of crashes in your app. Crashes are grouped by similarity and ordered by the severity of impact on your users so you always know which issues to address first in order to best increase the quality of your app. Each instance of a crash comes with detailed information surrounding its circumstances, including the stack trace, device type, and other important details about the device at the moment of the crash. To further enhance these details, you can log additional information as the app is running. All recent log messages are captured for every crash to help your diagnosis. In the event that you're able to handle and recover from an error in your code but want to report that event for analysis as well, there's an API to send these non-fatal errors for display in the dashboard. It's easy to get started with Firebase Crash Reporting. On Android, the SDK is enabled simply by integrating the Firebase Gradle plugin into your build with no additional lines of code required. And on iOS, there's a CocoaPod which requires a few lines of code for initialization when the app launches. To learn more and get started with Firebase Crash Reporting today, be sure to start with the documentation available right here. We can't help you write perfect code, but we can help you fight fires with Firebase. Launching a great app requires dedication and vision, but growing one takes revenue. How about a monetization solution tailored specifically to your app? One that has rich and engaging ads? One that works with Firebase to give you the insights you need to grow? And one that uses mediation to connect you with networks all over the world? Well, that solution is AdMob. Trusted by more than 1 million apps, AdMob offers developers everything they need to implement first-class monetization strategies. And when paired with Firebase, it's even better. AdMob is included with the Firebase SDK and its APIs are built to make adding banners, interstitials, and video ads to your app simple. Plus, AdMob automatically selects the ads that pay you the most so you can sit back and watch your revenue grow. And as your business grows, you can benefit from AdMob's advanced features. Say version two of your app has a slick new design and now you need an ad format that fits naturally with your content. With AdMob's native ads, you can create CSS templates designed specifically for your user experience. We'll style the ads to match and display the result in a native ad view that fits your app like they were made for each other. And it doesn't stop there. AdMob helps you earn in-app purchase revenue too. AdMob can determine which of your users is most likely to make a purchase and target those people. They'll see an ad you design and they can make purchases right there. Now, with your app's slick design and in-app products, it's become a worldwide sensation. But how can you make sure you're maximizing the revenue generated by each user? With AdMob, you can connect to ad networks around the world, bringing even more advertisers who'll compete for your impressions. And because you're using Firebase, you get access to free and unlimited analytics. Imagine a big-time blogger in Tokyo posts about your app and overnight your Japanese audience quadruples. With Firebase Analytics, you can easily spot the trend and then switch to your AdMob settings to tweak mediation configurations or start a campaign targeting your new fans. That's AdMob with Firebase. It's as easy as you want and as powerful as you need. Analytics, we all know they're important to building a successful app, which is why there are many different kinds of analytics tools for app developers to use. There are in-app behavioral analytics, which measure who your users are, what they're doing, and so on. And then you've got attribution analytics, which you can use to measure the effectiveness of your advertising and other growth campaigns, not to mention push notification analytics and crash reporting. But quite often, this work is being done by completely different analytics libraries, which means you've got reports living in various tools across the web and trying to understand trends across these different reports, much less get them to talk to each other, isn't always easy. That's why we've created Firebase Analytics. Firebase Analytics is built from the ground up to provide all the data that mobile app developers need in one easy place. And it starts by giving you free and unlimited logging and reporting. That's right, no quotas, no sampling, and no paid tier to worry about. Simply by installing the Firebase SDK, Analytics automatically starts providing insight into your app.  But not all apps are alike, and you can get detailed information about what your users are up to by logging events specific to your app. These can include common events that Firebase Analytics has already defined, like when your users add an item to their cart, and there's also support for custom events you create yourself, like when a user completes a workout in your fitness app, or when they take a selfie in your photo app. Geez. But it's not just about seeing what your users are doing, it's also about discovering who your users are. So in addition to demographic information, you can also discover how your different groups of users behave by setting custom user properties. Have a music app and wanna find out whether your classical music fans are browsing more albums than your jazz fusion fans, that's the kind of data you can easily break out thanks to custom user properties. And Firebase Analytics doesn't just measure what's happening inside your app, it lets you combine your behavioral reporting, what your users are doing with attribution reporting, or what growth campaigns are bringing people to your app in the first place. So if you wanna know which ad campaigns are bringing you the users who spend the most money, or are sharing the app with their friends, or have unlocked the last level in your game and are ready for the sequel, you can do all of that in Firebase Analytics. But don't stop there, once you have all this information, you can take action on it using Firebase Analytics Audiences. Firebase Analytics gives you the power to build up groups of users, or audiences, out of just about anything you can measure in your app. Wanna target users in Brazil who have visited the sports section of your in-app store? It's as easy as a few clicks in a Firebase console. Once your app has built up this audience, you can send them notifications using Firebase Notifications, or you can modify their in-app experience using Firebase Remote Config, or you can target them through AdWords, Google's ad platform. And then, because that impact can be measured using Firebase Analytics, you can confirm you're getting the outcomes you expect. Firebase Analytics already comes with a dashboard that lets you view answers for common questions, but if you need more specialized analysis, you can export all of your data into BigQuery, Google's data warehouse in the cloud, where you can run super-fast SQL queries to slice and dice this data however you'd like. You can even combine it with other analytics data that you might be capturing. And this is just the tip of the iceberg of what Firebase Analytics can do for you. To find out more, check out our documentation here and give Firebase Analytics a try. We are in the era of progressive web apps. Browsers are more performant and capable than ever, and front-end JavaScript frameworks like Angular and Polymer have simplified development of rich app-like websites. You can now build an entire application purely with static files like HTML, CSS, and JavaScript. Firebase Hosting is tailored for front-end web applications. Firebase Hosting is a developer-focused static web hosting provider that is fast, secure, and reliable. No matter where a user is, the content is delivered fast. Files deployed to Firebase Hosting are cached on SSDs at CDN Edge servers around the world. From San Francisco to Stockholm to Seoul, your users get a reliable, low-latency experience. And every site is served over a secure connection. Firebase Hosting automatically provisions and configures an SSL certificate for each site deployed so you can get that green lock of confidence. Deploying your app from a local directory to the web only takes one command. So whether you're building a single-page web app, a mobile app landing page, or a progressive web app, Firebase Hosting has you covered. To get started with Firebase Hosting, check out our quick start to get you up and running in minutes. Happy deploying! So here we are on Main Street. It's pretty much the main thoroughfare at Google I.O. 2017. I figured, just take a stroll and see what's going on. Wanna come with me? Okay. Hi, everybody enjoying the festival? Okay, good. So apparently this is an AR augmented reality for those paying attention. Well, I haven't gotten, oh, figured out how to do it just yet though. Maybe it's over this way. It's just one of the many things that you can do here in between the sessions. I believe this is dancing, right? So let's go over here. So one of the cooler things that I found here on Main Street is the opportunity to send a postcard well to anybody. I'm choosing to send it to Future Timothy. Shall we write me a few notes? Okay. Hi, I'm gonna join you all here and write a postcard. Well, who'd you write? I'm writing back home to Georgia, the country. Quite far. Let's see how long it takes to get there. We'll find out. I'm sending mine to Future Timothy. Oh, wow. Can I do that? But not to Future Timothy, but Future Nino. Can I send it to myself? Let's go do it here. I'm just gonna write mine over here. What was that? I don't know where we'll be leaving at the time. Well, see, if you send the postcard now, Future U is any time after now. So you're good. So the address is Future. Are you still writing the address there? Yeah, I'll get there. Are all the addresses in Georgia long? No, not really, not really.  Yeah. Okay, okay. It's okay, we'll wait. Okay, I hope you're doing well. Take care. I'm so nice to myself. Take care and good luck with your startup. I have a startup. Great, so. I think we gotta mail them. All right. Oh, there was more, more designs, next time. Okay. Bye. See ya. Okay. All right, let's check out what this wall is all about. It's going well, how are you? I'm great, thanks, having a great time here. Hey, it's a developer festival. How could you not have a good time? I have no idea, honestly. It's beautiful out, it's awesome time. So tell me what's going on with this wall. It's more than just a wall, right? It is more than just a wall. So this is actually gonna be an AR mule. So as you can see, there's a lot of little icons and things on the screen. If I actually put up my tablet here, you can see that there's actually gonna be floating overlays, so this AR is being generated because of there's triggers within the actual mule itself. So there's a couple of different icons and different animations here, so here you can be the Google icons in. And so what we've been doing today is just taking little short, five just second GIFs for people and then being able to send them to them so they have something that's kind of a moment of today. Awesome. I love it. I do, but can you send me a GIF, not a GIF? I don't know about that. Yeah, whatever. So there you are, jumping around in the background. What do you think? That's very cool. It's got the heel click and everything. Exactly. Awesome. Thank you so much. You're very welcome, of course. All right, let's go somewhere else. At this time, please find your seat. Our session will begin soon. Hello, welcome. Good afternoon, everybody. I'm Yiit. I'm the technical lead for architecture components and I'm here joining with Krill. It's also part of the team. So today we are going to talk about persistence. Now this is a loading screen. This is one of my favorite screens. Said no one. No one ever said, I like to wait. Especially if there's some content that they have already seen. And if you are making the user wait to see the same content, it's horrible.  I don't mean that. So now how do we fix this? We persist the data. This is what we recommend developers. Whatever information you fetch from your network, different data sources, save it to disk so that if your application is restarted when there is no network conditions, you can show something to the user. You can make that experience seamless. When we say persist on Android, we know this is a very crowded sphere. There's a lot of different options, different companies. And most of these solutions are really, really good solutions. But especially if you come to Android and if you are new to the platform, what you would do? You would check what is inside the framework already. So there's these three things that come with the standard library. And if you read about them, you realize that if you want to put structured data, then you want to go with SQLite. SQLite is something we have been shipping since Android 1. It's a proven technology. It works very well. So you go ahead and say, OK, I know SQL. I want to use SQLite. You go to this page. This is the very first page you see. This is horrible. It's kind of trying to say, you know what? You actually don't want to persist. That's not what we meant, but this is what we have. So we said, you know what? Let's look at this page. We want to make this better, right? Let's look at this page. It's trying to say, I want to select these columns with this constraints, with this order. So if you look at this, this is a very, very simple SQL query, but it takes a lot of stuff to write it. You will need to define all these constants, which are not even visible on this page. So I want to say, OK, there should be some room for improvement when we came up with room, which is an object mapping library for SQLite. Now, OK, we said, OK, let's step back. We said writing the same thing with SQL is a lot shorter, a lot nicer. So let's go back to our roots, which now there's an SQL query that we assign it to a string. It is standard SQLite. Now, of course, if it is like this, we cannot understand it. We love annotations, so we put it inside an annotation. And if it is inside an annotation, now you want to get the response from the query. Want to say, well, put it into a method so we can understand what the query wants to return. Now, we know that this is a query. It wants to fetch these columns from this table and with this constraint. But if you look at the constraint, there's actually a bind parameter. This is SQLite standard bind parameter syntax. We didn't come up with this. So where do we get this bind parameter? How do you get parameters to your functions from the function argument? So we put it there, the most obvious place to get this argument from. And then, last but not least, we want to know what it wants to return. OK, so it's a returning list of weeds. Now, of course, there's that feed class, so it needs to be somewhere. We have that class. And I want to put this query inside a data access object. That's what DAO stands for. Because you don't want to have your application making database queries around the code base, you want to put these into certain classes, which we call data access objects. So it's a DAO. We need to tell the room that this is a DAO. And then we need to tell the room that feed is some class that it would like to persist into the database. Last but not least, we need the database to put these two things together. That needs to extend the room database class. And so the feed DAO we defined there, we just say this database has this DAO. And the feed entity we defined there, we put inside the database. So you can have multiple entities, multiple DAOs. You can actually have multiple database definitions that access the same DAOs. As long as whatever schema you define in that database works with the DAOs and entities, room will figure it out. Once you have all that description, you can get the implementation of that database through this builder. It's very similar to how you use retrofeed dagger. You define the interfaces. We provide the implementation. Now, of course, because we are doing the implementation, select queries are very specific. We really don't know how you will select. But there are other queries, right? You would like to insert something into database. So we said, OK, we can just define another annotation to make it easier for you. Inside these annotations, these are actually very, very flexible. You can pass multiple arguments. Like, if you read this method, it says insert both. You really want to insert both of them to database. And the room understand this. You can send a list of items. You can send variable arguments, multiple parameters. Like, if it is readable, room will make it work. You can even say, when you try to insert this thing, if there's a unique key conflict in the database, do this. So you can also specify these constraints. So since we have the insert annotation, we have similarly delete or update annotations just for the very common tasks. Now, there is, so we said, we just start up on the SQLite. But there are some cases where writing SQLite is harder. For example, I have this query where I want to query these feeds. But I'm trying to return a list of feed, which means I want to get multiple feed items. So that means I want to get them by ID. So I probably want to pass multiple IDs. Now, in SQL, you will do this in these IDs. But you need to know how many IDs you have, so you can put that number of bind parameters. But this is some information we don't know while writing this query. Well, that's OK. Room can understand it. If whatever the parameter you are passing to a function is a collection, Room knows that, OK, they want to have multiple bind parameters. At runtime, we will generate the right query for you, and we will do that. Send them as an array. Send them as a list. Doesn't really matter. If Room can understand it, we will do it for you. Now, the most important part about Room is that once we let you define all these things, let your Room understands these queries. It's not just take this SQL and compile time generate the code. Room understands it, knows what you are trying to do, and this gives us a lot of power. For example, if Room looks at this query, it says, OK, this is a select query with this bind parameter, which is passed in as a string. And it knows it is from the feed table. And it wants to return items as feeds. Then Room goes and says, OK, can I validate this? Yeah, the table has these three columns. The feed item has these three columns. These match. They're fine. You could have another class instead of that feed that has these three fields. Room will still work. Now, after this verification, let's say you made a typo. The reason why we define all those constants or use Java builders is also avoid this typing, like mistyping queries. Room can do this validation for you. Similar to Java code, right? You don't use builders to write Java code. You write your Java code. Compiler tells you if it is wrong. And the ID helps you with this. So the reason why we don't have builders is that we think helping you write a SQL query is the job of Android Studio, which they are working on it. But once you write the query, Room verifies that it is correct. So if you do this mistake, Room will not let you compile the application. Similarly, if you access some columns that doesn't exist in the database, again, it will be a compile time error. By the way, it can be any query. You might be joining five tables. Room will still understand. You might have grouping, like almost anything in SQL. Let's say we made a mistake like that, where we only fetch the subtitle column. But we want to return this as a feed. Now, in this case, the feed object also has a subtitle column. So this might be intentional. Maybe you are going to fill in those fields later on. Or you made a mistake. We don't know. In this case, Room just generates a warning. It says, hey, feed class has these two other fields that you are not returning from the query. It will just give you all the details, well, what the query returns. Maybe you made a typo. And what are the fields in the column, in the entity? Now, there are two ways you can get through of this warning. The first thing you can do is maybe you really want to return them as feed instances. And I can tell Room to ignore it. I know what I'm doing, suppressed this warning. Alternatively, you can just create any class. As I said, you can just say, return me these as a string. You are returning one column as a string. And Room will do it for you. Very similarly, what if we are returning ID and title? In that case, again, Room will say, well, there's two columns, one string that doesn't match. It will give you an error. And when that happens, we can just create a pojo. Again, any class in your application, as long as we can read what's inside it and it matches what the query returns, we will generate the code. And to make the match, you can rename the columns in SQLite. All of those things works here. Now, this Room does everything automatically. But there's sometimes you have classes we don't know about. Now, I want to invite Kirill to talk about them. How do we extend Room, Kirill? Thank you. So let's talk about something a little bit more interesting. Going back to this feed object that has one ID integer field and two strings, these are primitive types that are directly supported by the underlying SQLite database. What happens if we want to add a field of a type that is not directly supported by SQLite, such as Java utility. In this case, at compile time, Room is going to tell us, well, I can't really figure out how to save this. You need to help me out. And the way you help out, in this case, is provide two methods to take your original data, convert it to something that SQLite can store. So that is going into the database. And on the way out, when you're doing the queries, convert back from that representation in the database to your original data type. You implement these two methods. In this particular case, we are converting date to long and back from long to date. We annotate them. As Yitz said, we'll have annotations. We use the type converter annotations on these two methods. And then we take this MyConverters class and use the type converters annotation pointing to these two methods, pointing essentially to this class that has our converter methods. You can put it directly on the field in your entity object. You can put it on the entity object itself. You can put it onto your data access object class or the specific query in it. Or you can put it on your database class, no matter where you put it. At compile time and at runtime, Roon will do the right thing to find those two methods. Now with this, we can write a query that finds the list of all the feeds that were posted between two specific dates, from and to. So here, since we are accessing the from and to fields or columns in the database that are defined as long when the database table is created, you don't really want to use long as the implementation detail. Since you are using the date class for your entity data field, you want to use the date objects in the query itself. And this is what you do here. And when the query runs, these two values from and to are going to be converted to longs. The query will run. And on the way back, when Roon constructs and fills these feed objects, it's going to convert back from long to dates. Now let's talk about even more complicated stuff. What happens if you have a class hierarchy in your kind of data model universe that has object graph that is not flat? In this case, we are adding a location object that has two double fields, latitude, longitude, into our feed. Now what happens at compile time? Once again, at compile time, you need to tell Roon how to store this field. Since especially here, not even it's not a primitive type, but it's a type that has subfields in it. So one option is going back to our type adapters. You can do something like take latitude and longitude and convert them into a single concatenated string with some kind of, let's say, semicolon as a separator on the way in. And on the way back, it's going to be some kind of a split where the string goes back to these two doubles. Or you can go to do something like bit masking and bit shifting to try and convert these two doubles, encode them in one long field. This is going to be hard to query even for this simple case when we only have two doubles that we are trying to encode. We're trying to kind of compact it into one field. And the more complicated the data structure is, the harder it becomes to use type adapters for these cases. Another option is to say that I'm going to flatten everything that you are going to flatten everything for us. So instead of having the location data field in your data entity, you are essentially flattening all the fields from the location class into the main feed class. And then, Room is going to create these two latitude longitude columns, which works. But first of all, you lose the encapsulation. Now you just look at the definition of your data class, of this feed object, or somebody else in your project looks at that. And it's not really clear that these two objects kind of represent one single entity. And another thing is just because you want to persist this object and later on retrieve it, why should you be changing the definition of your data classes? That's not good. Instead, there's another option, which is also not ideal. You can say we have two data classes. Why don't we store these objects, each one in its own separate database table? So we have our feed object with ID title, subtitle, and posted at the date.  Now in order to connect them, not when you save, but when you retrieve them, in order to connect the location back to its feed, you need to have the primary key, the feed ID, so that they are combined together. Once again, it works. First of all, yet another table is not very clean, but also going back to what I mentioned before, why should you be forced to change and tweak the definition of your data model classes just because you want to persist them? So what would be ideal is that you have your clean separation of how you define your data classes, but at runtime, the way the feed object is persisted is in one flattened table. So essentially, the latitude and longitude fields from the location are flattened into the same table. And the way you do it is with this embedded annotation. At compile time and at runtime, room is going to figure out how to flatten your entire hierarchy into this one table. Now you can write a query like this in your data access object. We are going to select all the feeds in the specific geographical rectangular area. As you can see, we are referencing latitude and longitude in the query directly. They are not in a separate table. And you are just using the same names for the database columns as the attributes in your location object. You can write a query like this to select the location for the specific feed based on the feed ID. And room is going to figure out that while it needs to fetch the entire row from the database, it only needs to create and fill the location object, because this is what this method wants to return. Or if you want to be more specific, you can say, I only want you to fetch the latitude and longitude from that table. The last part about embedded objects is what happens when you have more than one field of the same kind of nested class. So in this case, we want to store two locations. So what is going to happen at compile time, room is going to say, as I was flattening these fields into one database table definition, I see that the same latitude field is defined by two objects. And since SQLite doesn't support having two columns with the same name in the same database table, it's going to fail as an error, not as a warning. And what you need to do is, in case you do want to have something like this, to have, in this particular case, two locations, you want to use the prefix attribute on the embedded annotation. At compile time and at runtime, it's going to be used as room is flattening the data graph definition. It's going to use these prefix to create latitude longitude for the original, for the first location, and seen latitude, seen longitude for the second location object. Now let's talk about observability for those of you who have listened to yesterday's introduction session and who have been here earlier in the day to listen to the lifecycle live data view model. We want to talk about observability. So this is a simple query that returns the list of feeds based on a particular query. This is a snapshot, a point in time where you have run this query. And however many feeds it returns, it represents the state of your data universe at that particular moment. What happens if your data is dynamic? It can be manipulated directly by your users in the app, or maybe it's pushed or pulled from the server. So in this case, if one of the feed changes in the database, when you add new feeds, when you delete existing feeds that match this query, every single time to reflect these changes back onto the screen, you would need to refresh this query explicitly, to run this query again and again. Instead of returning list of feeds, you can wrap this return object. It can be a single feed or a list of feeds in a live data object. This instructs room not only to fetch it once, but also update the live data. The callback that you pass to the live data when you call the dot observe will see it in a few slides. Every single time, any one of the objects that were returned by this query was changed, or new objects were added, or existing objects were removed from the result of the query. And this is my favorite part by far of architecture components. And also, we provide support for using flowable from RxJava 2. So let's see. Woo. Like this one. OK, so let's see an example of how room integrates with the rest of lifecycle aware and lifecycle aware parts of architecture components. We're going to start with a simple database interface. It has one method to load the data for a specific user, and one method to save the data. The first time, it's going to be a simple insert. And then as the data changes, it's going to be an update or replace. As you can see here, instead of returning the user object directly in our load method, we're returning a live data that traps the information about this user. Now, we're going to set up the data binding to actually show the information on that user, perhaps in the details page or somewhere in some kind of a profile page. We have our lifecycle activity. It can be a lifecycle fragment. It can be a lifecycle service or your custom lifecycle owner. In this case, we're using a lifecycle activity. And in onCreate, we're going to get access to our database and database access object. We're going to call our load method that returns the live data that traps that user data. And now, we are going to use the observe method on this live data object passing two parameters. The first parameter is the reference to the lifecycle owner. This is our activity. And the second parameter is the callback that is going to be invoked by a room at runtime every time this user information changes in the database on the first load or on the subsequent updates. Now, word of caution, because it's kind of like, you know, we don't want to put too many lines of code here on one slide, you usually don't want to kind of expose database details or details about loading this information from your web service or caching it locally in some form directly to the activity or directly to the fragment. So this code is highly recommended to be put in a view model. And once again, the most powerful part here is this connection between the lifecycle activity, the owner, that says, I'm active or I'm not active, and the live data that room returns as a result for this particular query. This callback, the callback that you provide as the second parameter to the method, once again, is going to be invoked every time room detects that the result of that query that you wrote, select star from the user database table, has changed. Once again, the flow of information is one part of your app. It can be some kind of a service that pulls information from your back end. Or maybe the information is pushed through some kind of network tickles. It gets updates on the data. It's using this save method to insert the information into the database or update the existing information. As the data is updated in the database, room is going to detect at runtime all those active places in your app, activity, fragment service, or your custom lifecycle owners that are active and that are subscribed or are observing a live data object that traps the information that has been updated. And then this callback is going to be invoked, letting you know that most probably you want to update whatever slice of data is right now showing in the application screen. So for example, it can be an app that shows live results for some sports games or live updates for weather wherever you happen to be. All live updates to market stock prices. One part of your app handles the data flow, get that information, and display and insert it into the database or update in the database. And the other part gets notified by room and the live data that the information is now has new data. And you need to update whatever the presentation is once again in your activity, in your fragment, or in your service that posts maybe notification or handles a widget. All right, thank you. So let's focus on another important topic, which is relations. Now, SQLite is a relational database so it can understand the relations between entities. And if you are using any ORM on Android or like in any other platform, they usually try to handle these relations for you. So let's look at it how it works in room. So if you have a feed, we probably also has a user object which has posted this feed item. So you want to have a user field inside that field, inside that entity. If you do this in room, it actually won't compile the application. The moral of the story, we don't allow entities to contain other entities. Now, you're probably asking why everybody else does this. And if we can understand all this SQLite, why can't we just enable this? Now, there's a very particular reason for us not to do this. We have seen a lot of problems with applications caused by these kind of models. So I just want to go through an example. So first, let's look at this query. It strikes to select a feed with some ID. When we select this feed or when you look at this feed item, you cannot know whether it also fetches the user or not. It's very hard to define. And most of the ORMs, the way they solve this problem is you just say, lazy loading, right? Until the user wants to fetch that data, don't load it. Which works very well if you're working on the server side. But on the UI, it is a little bit more tricky. So it's implemented lazy loading, right? We could just generate this code for you. We could say, just keep a user ID. We'll say, keep a user instance. When the get user is called, we could say, if the user is the first time, now fetch it from the database. Otherwise, just return the existing ground. Well, it's very easy. We believe this is actually a mine planted in your code base. Let's see how we exploit it. We are using a recycler view where we show these feed items. And then we'll get the feed, and we'll show the title and the subtitle of the feed item. It all looks fine.  Actually, you know what? Let's show the user name in that feed item as well, right? It makes sense. It's like, OK, it's so easy. Your developer goals just add, well, feed get user, get user name, put it on the text view. You are done. You send the code review. It looks obvious. It passes the code review. You test it. It looks fine as well. But when your users start using it and your application starts receiving these ANRs, which stands for application not responding, this happens because when you are testing the application, you are on device. There is good network. Everything is fast. But when the user is using their application, there is this probably 50 other applications that are also trying to run. And if you want to relate to this, just try to use your application when Play Store is updating your applications. You will see how it feels. These are still mobile devices. The disk on these devices is actually relatively slower. And the UI thread only has 16 milliseconds. So even if your query takes five milliseconds, like ignore all the locks and everything. Even if it's five milliseconds, five milliseconds is a lot of time. You can probably lay out 20 recycler views at that time. So how do we solve this problem with room? Now, previously, we said SQLite is a relational database. We should just take advantage of it. We just keep the user ID. We know the feed as a user ID. Just keep it. And now we can write a query that says, I want subtitle, subtitle, and username, and join me these two tables on this constraint. Like this is already a solved problem on the SQLite LAN. Why don't we just embrace it? When you do this, it's faster. You only fetch the data you need. And when you fetch the data, you know that data is in memory. I'm going to say, wait, what is this item? This is, say, it can be like any Java class. It may even have a constructor with public fields, public final fields. Room will set this without any reflection. We will use that constructor. You can even say return a live data. Because room knows about the query, it knows it's querying these two tables. Like, think about the other example. If you were observing the feed, if the user changes, how do we know should we invalidate the feed or not? But when you wrote this, we actually know we know what you are returning. We know which tables you are querying. So we can be clever about this. So it's what we tell people. If you want to have relations, and you cannot use embedded or type adapters, you probably want to use pojos for your relations, which means you don't have any hidden costs. You only fetch what you need. And it's still observable, and you don't need to do anything for that. But of course, we said SQLite is relational, and it supports foreign keys. Room supports foreign keys as well. So inside your entity, you can say, this entity has a foreign key to this other entity, where I want to match the ID column in that entity with this child column. SQLite foreign keys also support, like you may have multiple fields matching multiple fields in the other tables. It's very complex. You should just go ahead and read. But once you declare this, now SQLite knows about this relationship. And if it knows, you can say things like, you know what? If someone tries to delete that user, don't let them delete, because I have a feed for them. Or you can say, if that user is updated, please update me as well. So we're trying to embrace SQLite rather than trying to hide these details and create a bunch of pitfalls. Index is another great thing. Now, SQLite keeps the data on the disk in a structured way so that you can query it back. As you can write a query like this, where you want to select feed items, which has a certain title. But if you just write this query and don't do anything else, that means SQLite needs to go through every single row in the database to find the ones that are matching. Now, if you are not making this query frequently, that's fine. But if this is the query that you run frequently, you probably want to index it. It's very simple in room. You just inside the annotation, you can say, well, can you please index this column? If your query is like this where you have your query title and subtitle together, you can also create a composite index, which means these two things will be indexed together. So if you are querying together, that will be fast. And you could have multiple indices. It doesn't matter. Either way, just because you're querying something doesn't mean you should index it, because every index you add has a cost on every insertion or data change. So you need to just measure and see what's the best way. And SQLite's documentation on query planner is amazing. If you read that, you will know how to write queries and how to optimize it. Now, testing. We know in the past we haven't been very good in this area. But when we were designing architecture components, testing was a very, very important topic for us. We wanted to have whatever we create for architecture components that can scale and that can be testable. So it's OK how you can test your queries. By the way, you should really test. Just because we are verifying your SQL queries doesn't mean that that's what you really intended. Your Java code compiles, but you still test it. Similarly, if your room SQL compiles, you should still test it. But testing room is actually very easy. Now, we still recommend testing on the device. But there is no activity or UI, so they run faster. You can also test on the JVM by changing the SQLite bindings we use. So you say, I'm just going through a sample case. So before each test is created, I create my database, but I create an in-memory database, which means the database will be created when the test starts, and I can clean it afterwards. You want these tests to run isolated from other tests. So you don't want to save the data into disk. So I say, after, just close the database so the memory can be released fast. And I can write it as the rest. This is just like I create an item. I inserted the room and then make some queries on it and then verify that that's what I expect. But the way room is designed actually helps with the overall application testing. Do you remember we talked about those DAO classes we generate? Because you defined how you access the database as an interface, which has nothing to do with SQL, you can very, very easily mock it. So if you have a V-model that you want to test, first of all, you can test V-models on your computer. You don't need to run them on the device. You can create a mock of that DAO. You can just use Mokito to mock it. And then you can write a test like this, like when load feed with this parameter is called, return these feeds. Because it's just a Java interface, like there is not even any mention of database there. So it's all very well abstracted without you doing anything. Now, migrations is another important topic, right? So as you use the application over time, your entities will change. They say, if you add this user object, now we start to show user photos. So you want to add this new field into that. You see, if you do that, when you run the application, as soon as your first access to the database, the room will say, oops, looks like you changed the schema, but you didn't increase the version. It's going to crash your application. Now you need to handle this. You can simply increase your database version in the annotation, which means you don't want any of the previous data you want to start from scratch, or you can write a migration. Now to write the migrations in our database builder, you can just pass a couple of migration implementations. Like this one says, I know how to migrate from one to two. You can have one from two to three, three to four, and then room will run whatever necessary from the current version on the device to your latest version. It will just chain them. And if anything in the middle is missing, that's going to recreate the database. Another important thing to know in these migrations, don't use any constants. Always use full SQLite, because over time, your application will change. Those constants may change, and you will get bugs. OK, we wrote this, but we said testing is important, right? So room also comes with a testing main one artifact. We have a separate artifact so that you can test your migrations. Now these are a couple of steps. First, when we compile room, we can actually ask room to export the schema, how your database looks, into some JSON files, which you should be committing to your version control system. Past argument. And then we want these schema files to be visible to our test, right, so that we can access them. Last but not least, for our Android test, we add this new dependency from room, which includes some helper classes that will help us with our migration testing. So let's say we are trying to test a migration from version 1 to 3. There is this migration test helper clumps, which comes from that artifact. We create an instance of that helper. This canonical name is how room exports these files by default. Just need to think about it much. And we create an open helper factory. Once we have that, we say, OK, migrate from 1 to 3. We ask helper to create the database at version 1. You may even have entities that doesn't exist anymore. It doesn't matter, because it did export the schema previously. By reading that, it can recreate your database in that version. You can just change it directly to whatever you want. But as you realize, this doesn't return you a DAW. It just returns your database instance, because DAW may not be valid anymore. You can just say, run these migrations and validate the schema. We give it a database name. We give it the version we want. Now, you may have tables that you had before. And maybe you want to still keep them, but don't tell room about it. So you can decide whether we should check for these or not. And then you give a list of migrations. These are the all migrations we have. What the room do is migrate the database from the previous version to the new version, and then check the schema for you. And then you can also have, if you have custom things, have changed the entities in the previous versions to the new versions, then you can manually assert on these things. OK, so that was room. We have a very detailed documentation page on the documentation on the web page. By the way, like we do for room, also for all our architecture components, we have a testing artifact, which includes one rule for JUnit and one rule for your instrumentation test that starts with dealing with the background test we use. So we want to make sure everything we have here is testable, and if it is not, we will fix it. So what's next for you? Room is available today. Please go check it, like play with it, see how it looks. Check out developerandroid.com slash Arch, which is the main page for all of these architecture components. Now we say these can work independently, but these also work very well together, as you've seen in the live data example, Kiril Hatt. So check it out, and also check out the call labs. We have call labs for both room and life cycles, and they're available in the call lab tent. Thank you. Hello, everyone, and welcome to the 2017 TensorFlow Developer Summit, and I'm delighted to see all of you here today. Today, we are excited to announce TensorFlow 1.0. TensorFlow's philosophy has always been to give you the power to do whatever you want, but also make it easy, and this makes it even easier. We really were hoping to build a machine learning platform for everyone in the world that was fast, flexible, and production ready. The point of TensorFlow was to figure out, how can we give this back to the community and be able to use TensorFlow to further weather as the research for the production needs? It's how we express our ideas, and it's the piece of software our engineers and scientists spend most of their time interacting with. So TensorFlow is a really exciting tool. Something that will let you take the confusing world of TensorFlow and start to dive into it. It's just a really amazing time to be an AI researcher. One of the projects that we've been working on is using deep learning for retinal imaging. Can we use deep learning and reinforcement learning to generate compelling media? But this is just the beginning. The TensorFlow community is truly global. We want to see all the amazing things that you guys can do with TensorFlow. Thank you very much. Good morning, Berlin. It is an absolute pleasure to be here with you. Here we go. We're live. We have a lot of experience building some of the world's most popular applications. And we've learned a thing or two about what it takes to build an app. And we've found that it's a pretty difficult process. A lot of your time goes into running infrastructure instead of building the features that make your app your app. There has to be a better way. That better way is using Firebase. We're now up to over 750,000 developers using the product. If you use Firebase, your app's code talks directly to our powerful managed backend services. We take care of security and of scalability so that you can focus on building the features that your users love. Today, we're launching Firebase UI 1.0. It's an open source library. It has customized theming. And it works for web and Android and iOS. So you can go ahead and drop that in. And you'll have all of the UIs that you'll need. Is my app set up correctly? Which events are being captured by the SDK? Are you receiving my events and parameters? We've built something, the ideal tool to answer all of these questions and these pain points. App quality leads to better user retention. Better your app is and the more stable it is, the more likely for users to come back and for your business to be successful and sustainable. And that's where we come in. So we're really looking forward to get the feedback from the community, as always, to help us continue to refine a product and to work together to help you build a better app. And we want you to be able to spend all of your energy on bringing innovation and creativity, something new to the world. That's really what we're trying to achieve here is making all the infrastructure pieces simple for you. And I'm really excited for you to engage with Firebase and see how it can make you more successful. All right, let's get back to the code. Hey, gang, want to see something neat? Check out this awesome hidden feature I found in Firebase Analytics. So I'm over here looking at all my reports in the Firebase Analytics dashboard. Here, for instance, I've got my active users for the last 30 days. And while these graphs sure are pretty, I'm thinking it'd be kind of nice if I could get these numbers into Google Sheets or maybe Excel so I could analyze them a little better, right? Well, watch this. I'm going to select my graph here in the Firebase console. It's kind of hard to tell, but you can see by the highlighted text here that my graph has been selected. And then I'll hit Command C to copy it. And then I'm going to switch to a blank Google spreadsheet and hit Command V to paste. And look at that. All my values are right there in the spreadsheet for me to analyze. So you can see here on the leftmost column, I've got the date. And then all the actual numbers are in the columns next to it. Now, you might notice that I seem to have two columns of what looks like the same data, right? I've got monthly active users here. And then right next to it, I've got this monthly users column. And then the same goes for my weekly actives and same for my daily actives. And so basically, that first column is for the value that corresponds to the date here on the left. The second column is basically for that corresponding day in the previous 30-day time period. Basically, it's the values that belong to this dotted line here in the graph that I copied. Make sense? Okay. And then I can do the same thing for a bunch of these other graphs. Here I can copy and paste my daily engagement numbers. Let's get these into a new sheet here. And again, you can see I've got my engagement numbers from this timeframe and this first column, and then those same numbers for the previous 30 days in this second column. And better yet, I can jump over to an individual event like this completed five levels event and copy all these graphs here at the top. And you can see I'll get event counts, user counts, event per user counts and values for every one of my events that I am recording in Firebase Analytics. And this lets me do some pretty nice calculations right here in Google Sheets. For example, let's say our game designer is curious how often people are failing a level in our game. Well, for starters, I've got my level start graph here to show when people are starting a level in my game. So first I'm gonna copy and paste these numbers into a new sheet. Let's put them in. Okay, great. And then I'm gonna do the same thing for my level fail graph. And that will show when people have failed the level. So we'll copy from here and we'll paste them right in next to my other numbers. And once I've copied and pasted these values into Google Sheets, I can then calculate my average failure rate per game stat by dividing this number here by this other one. I'm gonna copy this formula down for all of my dates. Let's give it a percentage format so it looks nice. Maybe we'll add an average at the bottom here. Let's do average for all these numbers. And there we go. Looks like my game has an average failure rate somewhere in the low 30s, which sounds like it's just challenging enough for our players. So our game designer is happy. Now, a couple of disclaimers here. First, this doesn't work on all the graphs I've tried. Some of them just don't seem to copy and paste as well as others, but it does work on a surprising number of them. You'll just kind of have to try them out and see if they work. And second, this will never be a replacement for some of the awesome and sophisticated data analysis capabilities you get by exporting your raw data to BigQuery. And you should totally go watch this video if you wanna find out more. But if all you wanna do is maybe compare two graphs to each other or calculate some standard deviations or averages on a particular event, this trick can work surprisingly well. So give it a try yourself, have fun with it, and we will see you soon on another episode of Firecasts. We're now in the IoT tent. And first, we're gonna learn all about OpenThread from Jonathan. All right, so OpenThread is an open-source implementation of the Thread Networking Protocol. What it is is a low-power mesh networking technology that allows devices, IoT devices, to talk to each other over a low-power mesh network. So if you're building products that run on battery that's supposed to last for years, not months, Thread's a great solution for that. So what we've done at Nest is taken the protocol and made an open-source implementation, put it in our products and made it available to developers to build into their own ones. Awesome. Yeah, so you want me to walk you through the demo here? Yeah, show me what's going on. So all these devices you see on the wall are actually running OpenThread. They're running our partner hardware and they're connected to a single Thread network, one giant mesh network. And one of the benefits of Thread is actually using IP, so just internet protocol. And each device has an IP address, an IPv6 address to be specific. So that makes it really easy for developers to build apps because it's just IP that they're used to. So if you can ping a web server, you can ping a Thread node. So in this demo, we're actually showing pinging a device over the Thread network. So as you see that light blink, it's actually going over Wi-Fi from this tablet to this Raspberry Pi, which happens to be on Wi-Fi, and then fanning out to the Thread network. And you can imagine sensors or actuators like door locks and windows being replaced by an LED, but we're just simplifying it with this demonstration. It's really cool. That's awesome. Thank you so much. Hey, before we go, actually, if developers want to get started, where do they go? Sure. It's been public available for the last year. We launched it at Google I.O. last year. And you can go on github.com slash OpenThread slash OpenThread. There's code labs available if you're here at Google I.O., but it's also available on the Google Code Lab website for you to try out at home. I see a golden retriever. It's a golden retriever. That's pretty great. So we're in the Android Things room, and I'm here with Ryan and Wayne. Ryan, tell us about some of the stuff that is built on Android Things in this room. Cool. Have you told him? Sure. All right. So over here, we have a simple demo that we are using to show how easy it is to go from prototype to production with Android Things. So at the top, we have a very simple light that's turned on using an Intel Edison kit. Over here, we're using the design, but we used a custom PCB to make the footprint smaller. Therefore, you can fit the overall thing into a smaller form factor at the bottom you can see in the candle. Actually, the really cool part about that demo is that any developer can make a circuit board like that. So in our talk tomorrow, we're going to show how to actually build that circuit board. And you can actually solder this up in your own workshop at home, so it's actually one of the really cool things about the SOM architectures you can do that. Yep. On the right, we have the TensorFlow Camera demo. This is also running on Android Things. We have Raspberry Pi 3 camera. And it's actually fairly easy to build as well. All these parts are off the shelf. So you'll notice that it's running on battery, completely portable. And the best part is it's actually running offline, completely locally on the device. So we're running the TensorFlow model, TensorFlow Inception model you can get online. And then once we download it, install it as an APK here. Now, you don't need online at all. So you don't need data cost associated with it at all. So when I press this button, it will take a picture using the camera module located here. And then it'll be processed on the device. And it'll say what it thinks it is using Android Text to Speech. Tell me about the M&Ms over here. So on this one, this was actually built by one of our external developers in our community, Louis. So the Smile Candy Dispenser. It's powered by Android Things using Raspberry Pi 3. And once you press this button, the camera will take a picture of you, send that image through Cloud Vision API. And if it detects a smile, it'll give you the candy. And we're using our relay module, as you can see here, connected to the motor of the dispenser to activate the dispensing. All right, y'all. Well, I think that's all the Android Things that we're going to check out in this booth. Wayne, before we get going, what are some things that developers can do today to play with Android Things? The really cool thing is all these samples here. We've open sourced all of them. So the TensorFlow image recognition, the LED candle. We've released all the source code on GitHub. The schematics for the candle are also available as actual circuit designs. You can actually make them yourself. So you can try all these things out. And then it's really easy to get started. You use Android Studio to write your code. And it's really easy to get going. So any Android program who's written a phone app now has the ability to make IoT apps as well. So that's one of the really cool things about Android Things is it takes advantage of all of your existing Android knowledge and allows you to apply it here. All right, we're now in the Works with Nest room. And I'm here with Jesse, who's going to tell us a little bit about Works with Nest. Yeah, thanks for stopping by. So Works with Nest is a developer program for Nest.  And there's a lot of ways that you can connect. You can connect to the thermostat, the camera, the smoke alarm, and then also our demand response programs that we set up with utility companies across country. That's awesome. So what are some of your favorite integrations with the Works with Nest program? So some of the really cool ones are over here. Be aware, it's an air quality sensor. And it'll measure the different things in your air. And then how it integrates with Nest is it connects to the thermostat and uses the fan to clean up the air in your house when it detects that levels are high. Oh, that's cool. What else? Another one that's really cool, which is a little different. It's not directly connecting with the they're all over. The product is the Rochio Sprinkler. So I have that in my house. It manages the water automatically. So I don't have to worry about it in my yard. With Nest, it shows up in my home report every month, where Nest tells me how much energy I'm using with my thermostat. But then I also have a list of how much water I've used and compares it to the previous month. Pretty cool. Cool. So that's some of the stuff that's been around for a little bit. What's next? What's like the newest integrations? So some of our new things are with the camera. So the camera is now connected to the thermostat or to the APIs. And we're doing cool new things there. So originally, you could use the APIs and get motion events and then have your products respond to motion in the house. But lately, we've been developing our image vision. And now we can recognize people. So now, works with Nest products can get these people events and do things when they know that there's a person. One example is not necessarily with people, but cool integrations with the camera is Chamberlain and garage doors. So what they do is when the garage door opens, they grab a snapshot from the thermostat and they integrate that in their history UI and their app. That's awesome. Totally. OK, so one last question, because we also checked out OpenThread. Is there anything in here that's using Thread? Absolutely. So super excited about Thread. It's really like the next phase of our development program. So the first one is giving people an easy way to connect to Nest products. And then phase two, we're going to take some of the core technology that we've developed at Nest to build our Nest products and make it available for developers. So we're working with Yale on this lock. Yale's been making locks for 50 years, 100 years. And they're really good at it, but not really a software company. So we've taken some of the software that we use on our Nest products, like Thread, and made it available to them. And it's going to be a really cool lock that's integrated with the ecosystem. And we've actually open sourced Thread. And we have a booth just a couple of booths down where you can see all about it and figure out where to get the code. Awesome. Is there anything else you'd like to tell all the developers out there? Check out the code labs. We have an open Thread code lab. We have one with the camera that integrates with TensorFlow. It's a fun stuff that you can do for the next two days. Awesome. Thanks, Jesse. Thank you. How's everybody doing? You OK? Yeah? That was really bad. How's everybody doing? You OK? That is much better. I'm Paul. I'm Sturma. And what we normally do is we do a show called Super Charged, where we live code things for people.  And we thought, let's do it again. And so that's exactly what we're going to do today. But what we normally do is we normally have one of us code and one of us talk. But today, we thought we'd have both of us code. So not at the same time. I mean, we could.  We probably shouldn't. We shouldn't.  We shouldn't do that. So Sturma's going to code first.  All right. So I had the idea that, or actually, I exported my Twitter archive, because I wanted to have it and look through it. And it turns out that the file that contains all my tweets I've ever done is about 16 megabytes worth of JSON, which is a big file. And I'm not going to open it because VS Code doesn't like big files, apparently. But I have the first four tweets and an extra file. So that's basically what we're looking at. And you can see my first tweet apparently was in 2008, where I say something fundamental as, got an account on Twitter. Yay. That's everybody's first. It's the universal first tweet, I think. It's either that or hello world. Like shouting into the empty echo chamber. Nobody cares. And what we wanted to do is, how would you use this file in a web app? Bring that file back, because there's something I noticed here. This isn't an array of objects. Oh, exactly. It's not an array. It's literally just concatenated JSON objects. So they end here. The next one starts. There is no commas. In fact, yeah, the JSON parser is kind of, if you get rid of the selection, it's got a red wiggly under there because it thinks, well, it's not real JSON, right? It's not a JSON file, because there's more than one JSON object in there. So there's going to be some difficulties. So I guess before we lose more time, we just get started. And the first thing we always have to do is type really fast and suddenly we have copyright errors. We like snippets too. So I'm going to work with some script. So what we're going to do is I'm going to work with my part of the program. And I'm going to use the new stuff, which Serma.js. That's me. Brilliant. OK, fine. Fine. Fine. That's the game you want to play. I should call it desktop, because that's my Twitter handle. OK, like it. Follow me. Wow. Always branding. I love it. So I'm going to use a module, which is a new thing, which, A, allows me to be deferred by default, which is something you should always be doing. But also, we get to use the new fancy import, which we're going to use later. So let's write a new file and look at the tweet and fetch the tweets.json file. So I'm not going to put anything else in here. I'm just going to put this here and call it doesserma.js and go in here, go to the networks tab. And if I load this, you can see I just downloaded 16 megabytes of JSON, which is quite a bit. This was really, really fast, because I have a server running locally. The second you actually are on the internet, this is going to take a while. So you would have to wait seconds, if not minutes, before you could do anything with the data. And that's actually a really important point. The web is a streaming medium, and we actually want to treat it like that, rather than saying, I'm going to hold everything back, and then da-da. So what you would usually do is the official sound. The official, I receive the response sound. What you would usually want to do is you want to take respond and then call.json, which turns the response into JSON. Because as we have established, it's not actually a JSON object, it's a bunch of JSON objects. This would fail with, there's like trailing data, please take care of this, so I can't use it. The next option that most people probably are aware of is, not that, got text, which would give you a 16 megabyte sized JavaScript string. And I'm telling you, on mobile, you're not going to have a good time. So we're now going to go into the new territory and use something that probably is not as well known, namely that response.body is a stream. Ooh. And what kind of stream? Thank you. I was waiting for your line. Sorry. It's a readable stream, meaning that it's a stream that you can read. OK. You came in for the education. You get it. I'm going to explain it more. So a readable stream is a synchronous data structure. Some people are going to scope it. It's a little bit like a promise, but that can be recalled multiple times. So every time you get a new result back. It's a pipe of data, right? Yeah, it's a pipe. It's a pipe. It's a pipe. I'm going to assume data off it, right? And every time you get the next chunk in the network delivered. But because it is from the network or because it's a stream, once you get that chunk, it's gone. It's been consumed. And therefore, there can only be one reader at a time. And so what we need to do is we need to get a lock for this reader, which you get by GetReader, which means you have now a reader object and you're the only person who can read from this stream. And what do you do if you want to get rid of the lock? Is there like a get rid of reader? Release lock. OK. I knew that. That seems really OK. GetReader and release lock. We don't need that though. So we have a reader. And as I said, a reader is an asynchronous data structure. And so I'm going to make use of async functions. Because otherwise, this is going to get weird. Because with async functions, we can write code in a linear imperative way, even though it is asynchronous. So we can do stuff that is very old school and usually very hated upon a geographer. It's well true. Ew. Really? Yes. Oh, this isn't production code, by the way. Yeah, it's not production code. How are we going to say that? It will work. Hopefully. Hopefully. But there's, yeah. So what you get, so when you want to read from a stream, you would call your reader and say, read. And since it's asynchronous, we have to await that. It's basically a promise. But with the wait, it just inlines all the handling. And it makes it much nicer. And what we get from there is a value and a done flag. A little bit of destructuring going on there. All the new features, man. All the new features. So if the stream is done, it's end of stream. Then it's done. So done is true and we can just return. Which is why a while true loop is OK, because that is our cancel condition. This is how we break out of it. I'm still really iffy on it, seriously. Anyway. So what is value? Let's just try out what value actually is. So I now console log the value thing. I'm going back here. Going to open the console.  This is literally the raw data from the HTTP response packaged in nice typed arrays in JavaScript. And you can see that they're all pretty much 32 kilobytes big. But that is more for coincidence than anything else. So for example, the last one is smaller. There's probably some smaller ones somewhere in the middle. I don't know. But it's a number you cannot rely on. This might be an implementation detail of Chrome or my Go server. It doesn't matter. The number not really relevant. OK. So now we are receiving these chunks. And they're 32K big, coincidentally. But the problem is really that we have these whole series of JSON objects in my tweet file. And now a tweet could be, there could be multiple tweets in one chunk. Or there could be one tweet spanning multiple chunks. And that's not really helpful. What we're going to do is we're going to write a so-called transform stream, which is going to transform our stream in a way that the chunks and the JSON objects align. So basically, every chunk after the transform, we can be sure it's exactly one JSON object. Got it. So you could pass that to jason.pars and you would get a JSON object. In the end, we should be able to do that. So instead of just arbitrary splits at 32K, we want it per object. Exactly. So now we're going to use the reference implementation for transform streams. They're going to be in the browser at some point. So a transform stream, to explain, is a readable stream, a stream that you can read, a writable stream, a stream that you can write, put together into one object where you put things in at one end, do some transform, and get it out at the other end. But they have not landed yet, so I'm going to have to rely on the reference implementation. So I'm going to import from transformstream.js. And now we have it and can use it. And let's see how to actually use it. So as I said, response.body is a stream. And if you have a transform stream, you can use pipe through, which means here's a transform stream, pipe that data through the transform, and give me the result. So here we would create a new transform stream, and that transform stream takes a transformer, not to be confused with the cars. So what we have to write is a JSON transformer. You sure you don't want to know the new inside there as well? Let's go three deep. Meet more. I can give you a variable. So this is going to give us the JSON stream. So as a return, we get the transform stream, which is now a stream of individual JSON objects. So afterwards, we're not going to get the lock on our body, but on our JSON stream. And that should work. So let's take a look at the actual juicy bit, which is the JSON transformer. So class, JSON transformer. It has a constructor, which we are going to need, but not right now. And a transformer has to have three methods. It's a start, which is called at the start. We don't need that. There's flush, which is called at the end. And there is attention transform. Oh, that's what we need, right? That's what we need. And the transform, you get two parameters, the chunk that you now have to transform and the controller. And the controller is something it allows you to control your stream. Let me explain with code. I think code is always better than trying to hand wave all the things. It allows you to do stuff like to define what is the output of this chunk. You can have set all kinds of different signals, like back pressure, and your cache is full. And we don't need any of that. We just want to see it. I've got a feeling if you Google for Jake Archibald's streams, you're probably going to get a really good article. I think it's going to appear. It's just, yeah, well, that's the worry if you say streams too many times. I'm going to stop mentioning the word now. So we take the controller. And with NQ, we can put something onto the output queue. So just to show it works, I'm just going to not do any transform. Whatever comes in, I'm going to take it and put it into the output. It's like a null transform. So do nothing. Ideally, everything should work the same. Yes. So it's still doing nothing, just downloading the file. But now we have a point where we can inject our code to do all the transformation-y bits. So how do you do that? And the thing that we have to do now is we have to kind of write our own little JSON parser. Really? It's not as complicated as it sounds. OK. So what we will do is we will collect all the chunks that belong to one JSON object. And once we have those, we'll squash them together, get a string, and put that in the output. And you NQ your iPhone. And then we start over. So in this chunks array, we're going to collect all the chunks that belong to one JSON object. And now we have to figure out how do we know when we've reached the end of a JSON object. And we do that by counting curly braces. So what we're going to do is whenever we get a chunk, byte of chunk, so we're going to loop over all the bytes in our chunk. That could be const. That could be const. Sorry. Sorry. Inadvertent. Ring from. Stop it. Review. Sorry. Carry on. We're going to convert it into a character because we know JSON is always ASCII, so we don't have to worry about UTF-8 unicode shenanigans. Yeah. OK. And then we're going to switch over whatever character it is. And we care about it's either an opening brace. Sure. Or? Closing brace. Closing brace. Well done. Weight off. And we're going to start. And we're going to try to count how deeply nest we are. So whenever we encounter an opening curly brace, we increase it. And whenever we encounter a caps lock, it's in the way. I mean, this does not feel brittle to me. Stop it. I'm cool with this. So when we decrease the depth, we will hopefully, at some point, reach zero, which means we have found the end of a JSON object. So what we're going to do here, we're going to emit. And we're going to talk about this later. If we have reached the end of the chunk without having reached zero, we know that we have to continue into the next chunk. And this current chunk is hard. I like it a little bit. Yes, I do the dancing programming. Do the chunk. OK, fine. It's going to help people understand. Sure, no, I get it. It's great. So when we've reached the end of a chunk but not emitted it, then we need to chunks, push, chunk, push. This is like when I type. I know. Ah, it's not a good thing. I'm the one that does the typos. He's the one that's normally really good at typing. And it's really annoying to me because he's pretty good at it. So we are now in the middle of some chunk. We have reached zero. We know the start of the chunk is part of the JSON object. The rest is part of the next JSON object. So we're going to split that apart. So we have the tail. You intate array. So that's actually an interesting thing because all these typed arrays in JavaScript are basically just a chunk of memory and you can have different views. So we can look at the same memory as a series of floats or a series of ints. But also you can have them in different positions. So we are going to split it apart by just creating new views onto the same memory. So to be clear, rather than, say, copying this array into two separate arrays, you're just creating two views onto the same memory underneath. And that one becomes the end of the object and the next one becomes the start of the next object. Exactly. OK, fine. So what I just realized, though, that for this we need to know the position, the index where we add. So I'm going to rewrite the for loop to do the old. I was feeling really smooth about that. I know it was nice, but, you know, length, i plus plus, done. All right, so the tail goes to i plus 1 because at the i we have the closing brace. So the next one is where we want to cut. And we have the next object where we kind of do the same. And we start after. And if we emit the last parameter, it means all the rest of it. So because i is the curly brace, i plus 1 is the next character. Fine. So and because after this, we want to continue working on the remainder. I'm just going to get a little bit tricky and just say we're just going to overwrite our chunk because that's the next thing we can work on. Well, this kind of stuff really ruins my head. Well, so tail is, as I said, the last bits of our JSON object. So it's part of the chunks array. So now at this point, we know that the chunks array is our next JSON object, but potentially split into multiple chunks. So we need to convert this into a string. So you've got several potentially unit arrays that need flattening down to a string. Yes. Got it. And sadly, to convert a buffer or a typed array to a string, we need to use a text decoder. Sure, we do. Sure. So it's a little bit. Sometimes I wish this would be simpler, but it's just how it is. Now, OK. And what we can do is we can use this.chunks.reduce. We're going to start with an empty string, and we're going to take the string and the chunk. And we're going to concatenate the string with a decoded version of the chunk. And that is going to be our JSON string. Sure. Is this correct? I think it is. And now we have a JSON string, which we can. Is there a German word for the feeling of sadness you get when something is really convoluted? I think you could say something like simplizismus mangelverzweiflung. Pardon? Simplizismus mangelverzweiflung. I love it. That's all my favorite CSS. Tell me what CSS is. Wait. It was kaskadien desilisierungsvorlagen. Yes. More stuff should be done. German always has a word. All right. All right. So we have JSON string, which we can emit. So we now have actually turned it into a string. We can push that out. And now the only thing left to do is to reset our state. So we have to say this chunks is now empty because we're done processing it. That is true. You could also set dot length equals 0. Can you? Yes, you can. Can you say I can do this? Yes, really? Yes, you can. I did not know length of readable. I'm trusting you. Awkward. Awkward. And now this is, and because on the next loop we want to start at 0, but it's a for loop. So I plus plus is going to happen. We have to set it to minus 1. No. Ew, that's gross. All right. You're not chipping that, are you? Yeah, I am. OK. All right, sure. So it's prototype. I'm not going to run this code on my big treat file. I'm going to take it on 4 because otherwise it's going to take too long. It's just no. OK, so if this goes right, we're going to see four tweets. No, we're not. Line 13. People are paying attention. I like it. What is on line 13? Oh, byte is not defined. Yes. So byte is our chunk I. See, it's judging you because you changed my four const to that. And I type out decode. Yay! But it's like it's a bit bigger. So we can now consider we have four individual console logs which contain exactly one JSON object, which means the alignment works. But, and there is always a but. So let's show you why. What if there is an opening brace in a string? See, see, I see. That would not do that. If I do that, we would see nothing because the parser would see, oh, opening curly brace. An object started, but it's in a string and we didn't know that. So what we have to do is it's actually not that hard to fix. We just need to track if we are in a string. Oh, you're kidding me. Oh, come on. So whenever we find a double quote, we're just going to go in string is this. Sure. In string. Yeah. And whenever we are in string, we don't actually care. Now I'm getting that word, that feeling, the German one about the sadness. Does it feel less brittle now? Isn't it nice? No, OK. Yeah, no, it feels perfect, Mary. Great. This should work now. Yay. Cool. But. Backslash double quote. Backslash double quote. Oh, yeah, he's right. Got that. So I guess if I do this, it wouldn't work. Yeah, that's a bad. Let's fix that. Easy, easy. Good shout, though. It's a great shout. So if we find something that is escaped, which we have to escape because it's the escape line. You must. We have to skip the next character. Sure. Aim, skip next. That is fine. Can I revoke your programming license? No. And if we, so if we have to skip the next one, we have to set it to false. Sure, false, yeah, go on then. Yeah. And continue. Sure, yeah. Yeah. All right. And just the ultimate test is going back to the full file and make DevTools grind to a halt. All right? But it's actually a little scroll because we are not blocking the main thread too badly because this is actually kind of OK. Kind of important, actually. You've got a 16 meg file that's being handled on the fly. It's being streamed and transformed on the fly. And you've got, what's the most recent one there? Is that, must be, what, German, in German, yeah, OK. I mean, I was wondering how fast it's actually, I mean, yeah, there is processing going on, but it works pretty well. I mean, yeah. All right, and now. Mike, go on, go on, move it. Right, because normal people, I don't think, would sit there going, oh yes, I am enjoying your JSON coming down and watching it arrive in the console there. Well, I certainly do.  So we thought the better thing to do might be to actually create some kind of progress style. And that's my job today. So as always, you do the visual stuff. That's how I roll. So I'm going to make an SC dial because it's the car. I think I might just call it arrow twist style, so my branding is OK. I can't believe you did that. That is not. I wonder if you want to call it dial JS or Lewis JS. I want to call it. Or arrow twist JS. I want to call it stick to the script. Arrow twist.js, fine. I approve. I know you do. It's not what I expected from today. OK, so I've got an SC dial. I'm going to make something called arrow twist.js. And you know what? I have a custom elements. I don't like writing these out with all the. I can't type in by heart. I just choose not to. With all those lifecycle callbacks already filled out for the custom elements, 1.0. What's the German for custom or lifecycle callback functions, Sirma? Lebenszyklus-Rückruffunktion. See? Yeah, that would be one. Right, normally we have, I'm actually going to call it SC dial. Normally I go with an unnamed class, but today I'm not going to. That's going to apply to SC dial and SC dial. And I don't need attribute change callback. So just did that just so you have a name for the class because you want to refer to it later. Yeah, I've got a fee. Yeah, we're going to need some constants in here and refer to them as static members of the class. So let me see. What I'm going to do, first of all, is I'm actually going to get rid of this here because I like my log. I know. Well, tough. I'm in control now. I'm the one doing the drawing. Right, now normally you could do something like this with SVG, but today I'm going to use a canvas because I feel like not a lot of people like the canvas. You talk to people and they're like, you know, I did it. But I use the canvas. So you're not going to bend over backwards and try to make it div be around. No, I'm going to use a canvas. Canvas is blazingly fast and I think it's heavily underutilized on the web. And when you use a canvas, you get the context from the canvas like this. WebGL? No. Oh, just 2D. OK, also. So basically, you can think of the context as your pen that you move around on the canvas because you give commands like move to, line to, and you draw on a piece. See, I told you I was going to do some static. Ah, constants. Yeah, size. That makes you a good citizen because you avoid magic numbers. I know, right? I feel really good. This.appenchild, because it's a custom element, I can just call appenchild against it rather than something else, it's an extending HTML element. But, but. What? It's a bug that it works in Chrome, which I always thought was hilarious. You are, per spec, not allowed to manipulate the DOM in the constructor of a custom element. You have to do it in the. Works. It's a bug. Works. Move it to the connected callback because that's where you're supposed to do it. Because technically, you cannot rely on the fact that the DOM is already available in the constructor. It could still float in the ether of custom elements. It works. And then I probably should remove it, but whatever. All right. Sure. So the other thing that we're probably going to do is, so what I want is an API where we can set a percentage value for the dial. As the file is coming down, as we get our 16 megs down, we should set a value. I'm going to say between 0 and 1, I'm for some unknown. We kind of need a way to put that value in from the outside, right? Exactly, right. So I'm going to set percentage. Ah, centers. Percentage. So I guess the reason