Okay, we're live Hi everybody, welcome to the October edition of the Wikimedia TechHack today. We have Roan Kekitao principal software engineer on the product team talking about resource loader tips and tricks You can follow us on the YouTube stream live That's listed here as well. And you can ask questions there as well as on the IRC office channel I'll be collecting answers throughout the talk and we will answer them at the end Talk should go about 45 minutes So we should have plenty of time at the end for questions and answers If there's anything that we don't get to or something that comes up later Feel free to let me know and we can talk with Roan to get that answer for you and Without further ado, here's Roan All right, everybody hear me and stuff. Yes, that's fine. And then Can I get my slides as well? Yeah, feel free to present them now. Oh, it's it thinks it's still There we go, I saw it and then I just I just stopped. Yeah. Yeah Here we go, so I will be talking about Tips and tricks for using resource loader and so I'll start with just like a basic introduction as hopefully most of you know resource loader is our asset management system in media wiki, so it's what lets you load JavaScript and CSS and other front-end assets on on a page and Just as an introduction, I'll first walk through some of the basic things But then we'll get into some of the fun more advanced things that you can do with resource loader and also some of the newer features that we introduced this year and how they work and why we want you to use them So starting with the basics resource loader revolves around modules. So a module is a piece of front-end stuff So here's an example definition of a module This is in the resources of PHP file in core and As you can see this module contains some JavaScript files. It contains the CSS file it contains some internationalization messages And it has a dependency it will Go into those into each of those components But what this is is this is called jQuery.confirmable and it's a library for giving the user a confirmation prompt and other So modules can either be something library-like that other code can use or they can just be functionality that you want to load somewhere so here's a Different Example of a module definition. This is how what it looks like if you have to do an extension an extension of JSON Where of course you're writing this in JSON and on a PHP This in this example is in multimedia viewer where they have a module called tipsy dialogue, which is a pretty clear Dialogue thing that they have. I don't know exactly what it is And you can see this one also has a JavaScript file a less file because that's also supported and a number of other modules that it depends on So then when you've defined a module you've defined a bundle of stuff about most scripts and styles Etc that you want to load in some situations you have to tell resource loader to actually load load it so On the PHP side when you're rendering a page you have an output page objects So you're in like a special page or in a before pages play hook or a place like that you can Call add modules on the output page objects and tell it which module or modules to load and that will get loaded In this example that is the HTML form code for media wiki You can also do lazy loading of modules from within JavaScript. So if you have If you discovered later that you need something or if you have a module that is really big and you only want to load it when the user interacts with your feature for example, if they Open visual editor they click edit and then you realize you need to load all this code because they want to use visual editor now You can use mw loader using for that So you can tell it which module or modules you want to load it gives you a promise and then That promise gets resolved when the module you asked for has loaded that code is available So in this example this lazy loads table sort of code and then when it arrives it Applies a table sorter to a thing another thing that is Maybe not as well known, but that is also pretty fundamental and that I Want more people understand is the notion of render blocking CSS so You saw that a lot of these modules that I showed before had both JavaScript and CSS in them And that's suitable for when the CSS is only needed to style the things that the JavaScript Does or creates But there's also some CSS that you need just to render the initial page like the skin CSS like the CSS that makes the sidebar and that makes the tabs at the top of the page and it makes the The links at the top right and all those kinds of things That is CSS that you need even when there's no JavaScript just to render the HTML it comes out of the out of your php code And that CSS we make render blocking which means it loads very early And it gets loaded before the browser paints anything and that's because it's so important that if you Try to render the HTML without it. It would just be a mess So obviously this should be used sparingly because of the performance implications of loading it so early that everything else is blocked on it, but you should also use it when when it's needed so for Things that do require this CSS very early you should put it you should make it render blocking Otherwise you will get a flash of on cell content the page will first load without a CSS It will look ugly and then it will jump as the CS arrives It will fix itself and that's not an experience that you want So this is definitely something to be judicious about but also Don't be afraid to use it when you do need it just check these Criteria to see whether you do or not dealing with render CSS block we're in relocking CSS is a little bit different in resource loader The way you do it is you put the CSS that you need to be render blocking in a separate module That only contains CSS that has no dependencies. It's it doesn't have scripts. It doesn't have anything else just CSS And you use add module styles instead of add modules to add it So one thing you'll frequently see is that The same component registers two modules one for the essential render blocking styles and one for All the other stuff that can come later. So the the JavaScript and the CSS that goes with that JavaScript So that's what you see in this code snippet Mediaweek action edit is the module that has the JavaScript and the CSS that goes with the JavaScript and the messages and all the stuff that you need for Dynamic things and mediaweek action edit dot styles is the essential styles that need to be render blocking and that is They're they have to be separate modules because they have to be loaded in different ways as you Can see over here and if you if you try to use that module styles with the module that contains anything It's not css. You will get an error message Another pretty fundamental thing that we have in resource loader modules internationalization messages And this is probably pretty familiar concept if you have ever written any php code in media wiki because we make everybody use this but I'll just go over it real quick You can define translatable messages in E n dot json both in both in core and extensions And those modules those messages can be translated into other languages and they can have parameters like this example Uploaded colon and then a parameter Um that message has a symbolic name in this case. That's multimedia viewer dash daytime dash uploaded um, you can then In when you create a module So this is an example module definition and extension of json um The module definition has a list of messages that isn't that are needed by the module. So you put it in that list Uh, that means that module gets shipped over to the client side and your JavaScript can then use it um And you end up writing code like this Where you call it w message give it the name of the message that you want you give it the parameter And then you tell it whether you want text or html from it um, and Now you will have a ground rise translated message in your Uh javascript and this is something that we also have a php library for and the way that you use it in javascript Is mostly the same except that you have to add the message to the module definition otherwise it won't work And so this means that international this and messages are also a core component of a module along with scripts and styles um another Thing that a lot most people know about is that your css can get flipped. So on the left is um A screenshot from english Wikipedia from a couple days ago And on the right is a screenshot of arabic Wikipedia and you see that you can see that it's basically a mirror image And almost everything is mirrored The sidebar is on the right instead of on the left the tabs flow from right to left um the icon Oh, this actually doesn't have a flipped search icon the magnifying glass icon is not flipped, but I think in the past it has been um Some icons are flipped uh the direction of absolutely everything is flipped. Um, and this has implications for how you write your css So we used to write a separate override style sheet for uh, right to left languages that was always out of date and always a pretty crappy experience But with resource loader you can just write css from a left to right perspective And when your page is viewed in the right to left language We will automatically take care of flipping things for you. So when you write float right that becomes float left When you write padding left that becomes padding right when you write these like Four value like margin padding or border rules with different values. We know that the second one is that Right one and the fourth one is a left one. And so we switch those around And if you put things like dash left or dash ltr in your Image names, uh, we will flip that to dash right or dash rtl and pick the other one. So if you have images like that magnifying glass or Or arrows or some other things That need to be reversed in rtl We won't actually go and reverse the image for yourselves But you can make a rtl version of the image Encoded in a file in this way and then we will load the other one when appropriate So that's a that's a pretty cool feature that I hope most people know about But also pretty fundamental for To understand how resource loader works on what kinds of implications it has All right, so that was the basic stuff Let's get into some of the more advanced stuff and stuff that not everybody knows you can do This is not always going to be useful to everybody all the time, but it's good to know that it's there So for example You can have style files. So css or less files in your module You can also have skin specific style files in your module. So in this example This is an example from echo. We have a style file Over here that is always used We also have style files specific to each skin one from minerva one from monobuck and one from vexer Down there. So this definition is pretty intuitive. It's pretty intuitive what this does And you don't always need it, but when you do you'll be glad it's there More obscure is that you can also do this for scripts. You can have JavaScript files that are only loaded in certain skins So this is a bit of a weird example, but here there's one file that gets loaded in The minerva skin and then a different file that gets loaded on every other skin. That's not minerva Is what this definition means You can even do this With languages you can have different scripts that load in different languages This is not used very often Video jest apparently use it because that's where I took this example from And things like moment jest which is a timestamp rendering library Use this it's uh, it's not super common But you might see it around sometimes and You know one in a hundred times you will actually need to use this And then you'll be glad to say um another thing is a little bit more commonly useful is template support so In addition to scripts styles and messages as resources in a module You can also add a template as a resource So in this example, um, I added a html file thumbnail html as a template To a module And when you do that it gets that html file gets loaded along And it means you can write JavaScript like this Where you call mw template that get with the module name and the template file name And you call dot render and now you have a jQuery object that Has the parse html from the template And you can go and fill in a bunch of your placeholders with With stuff and then put it in dot which is what this code does um This is not really normal templating as you might be used to so we also have support for moustache templates, which are more like actual templating Um, so you can write a file called food at moustache that looks like this with which actual template syntax with parameter and stuff And you can I think you can write like if statements and simple loops and stuff um, and you can also put that in Your module didn't show the example here, but the syntax is the same as the previous slide. You just have a moustache extension instead of a dot html extension um And the clients that use is also the same except you have to give the render function um You have to tell what do you want the parameters to be replaced with and so the result of this will be a JavaScript Object that is a link with that URL title unlabel filled in for the parameter values in a template And obviously it's a simple example, but um There are more advanced uses of this out there where people have large html structures with many grammars that they fill in this way um As an aside, it kind of crazy use of this is that um, you can also have templates whose file names end in dot reject And then there are rejects So this is used. I'm only aware of one place where this is used in the media. We could get your eye Module where there's some sort of massive rejects that needs to be used and you can Include that as a template file This pretty obscure you're not going to need very often But it's a nice illustration of the kind of cool stuff that uh people have figured out how to do this is I think this is something that barters came up with like four years ago or something um Another fun thing that you can do is you can have internationalized messages in your less style sheet Which seems kind of crazy that you would want translated messages in your styles But for a column before and column after content rules it can be useful Uh, so this is an example from core. You have to have this Class resource loader less of our file module magic thing Um, and then there is a less messages property And what this means is that you can write um Code like this in your less file where the Uh, the variable over here this msg that show to you see thing ends up being replaced with text like Show table of contents and but translated in whatever language you're viewing this in um, so use usually we try to put um Translated translated and translatable content in the html and not in the cs as much But in some cases This can be useful and so there's a couple of modules here and there to use this Uh, it's pretty cool trick And I think John robson was the one that introduced this like a year or two ago Maybe and then a volunteer named foma fix generalize it to let you use any message In any module this way um, all right, so those are Some pretty cool advanced things that you can do they've also been around for a few years I think the most The newest thing that I showed you was the less messages thing and that's from 2017 Uh, so now I want to talk about some of the stuff that we introduced earlier this year Um to do with package modules, which you may have heard about what I want to go into some more detail on Um, so something that's existed for longer is that you can use required for Uh, like the the node js like common js style require function for modules So for example in media we get a string the js which is a library and core We have this statement statement at the end where module of exports gets like a bunch of stuff put into it that the module wants to export And then in somewhere else in some file that uses module you can write code like this So this is a lot more like the node js style of using things um most of media wiki is most of media wiki's javascript is written around the idea that your Libraries just like put stuff in a global object somewhere and then you use a global object in your in your file where you use the library That's not how modern javascript is written anymore um, so a while ago we started supporting this uh syntax for modules Which is cool, but we can we figured we could do better Uh, what's new is that you can do require for files now, which is also how uh a lot of Modern javascript code is written So this is an example from I don't even remember where I pulled this from where one file has module of exports equals some function in the file and then another file in the same module um Just requires a file and this is a This is a typo. I think I got the file names the wrong way around here um, so excuse me for that, but the idea is that um, you can Export something using module of exports in one file and then Uh, require the file from another file and get the thing that was exported Um, and this is nice because now you don't have to use the global namespace to communicate between separate files in the same module Uh, you do have to do some magic and we're going to dive into this magic uh in a second Uh in your module definition you have to use this new thing called package files instead of scripts and so, uh, we'll um Go into that in a minute But just as an overview a package module is the term for a module that uses this functionality So instead of the scripts Thing in the module definition you use package files to indicate that you're using the new feature in a new style The first file that you list in this list of package files is the entry point So that is the first that is the file is going to be executed when Uh, the module loads the other files after that their order doesn't matter and they're not going to be executed unless Uh, something calls require on them. So that's a big difference because with the scripts The old style of defining modules with scripts Every file is going to be executed in the order that you listed them. So you have to think about Depend like which files depend on which other files and you have to think about the right order to execute them all in And typically the file that does all the work and ties everything together and it's sort of like the Main orchestration file is typically going to be the last one in your list there So with package files that is going to be the first file Um, and it is going to use require To call other files and that causes them to be executed. They are not executed in any given order Except through this on-demand mechanism the other thing to note is that there is a Syntax difference to indicate whether you're requiring a module or a file For a module you just require the module name For a file you have to start with dot slash or dot slash to indicate that you're To disambiguate basically and to indicate that you're trying to require a file This is a little different. This is most this is compatible with how node works It does mean that there's some shorthands that you can use and know that you can't use here So you can't require directories. You can't Amidst file name extensions that kind of stuff. So Everything we let you do on resource loader is compatible with how node works It's not the case of everything. I know let's you do we also like because we are a little bit stricter And there's a link at the bottom of the slide To documentation page that explains more but i'm also going to Walk through some of this stuff so here's a basic example of A module uses package files that was I think this is from code that I reviewed a few weeks ago um, so this very first File notifications.js. That's the entry point. So that file is going to be able to get it first um And that's going to like require a bunch of other files and pull everything together and then do what needs to be done um All these other files. So overlay address for example, but also all the other ones are only going to be executed if and when Uh, someone require calls require dot slash overlay address Hopefully every file is going to be executed because hopefully they were all needed if If not, then you are wasting your time putting them in and you're wasting bandwidth, etc um But if through some circumstance, you don't ever call require in a file it won't ever get run If you require it twice, it will only get run the first time and it will just give you a cash result the second time And the order of the files here is completely meaningless except for the first one Files will just get executed in whatever order they're required uh, another thing, uh, that's important to point out here is that It makes sense when you think about it, but it's going to be a bit of a pitfall sometimes that pads are relative So here's an example of a module that has um files in a bunch of different directories So the init file is in skins of nervous scripts But then that has a sub directory called page issues that some but not all the files are in and there's also this file That is in a completely different components directory um, and that means that in your init file Uh, this is the kind of thing you see before the for the files in a sub directory You have to have the sub directory in the path and for the file that was in the completely different directory You have to do dot slash a bunch of times to get there um, this makes a lot of sense, but it's um It's easy. It can be easy to get wrong sometimes Um, and another thing that makes a lot of sense and they can be easy to get wrong sometimes is that the paths Are relative to the file that you're in So once you've gone into the page issues directory and the init.js file requires the index of just file in that directory um Once you're there the other file in the directory parts of the jess Is you're already in a directory so you're not going to have to do dot slash page issues again The path is relative not to The first file but to whatever file you're in at that moment um, this is also how things work in uh, node gs So it should not be a huge surprise and it does make a lot of sense, but It can be easy to forget sometimes Especially if you're just looking at the module definition a lot and going on with that Or if you're moving files around Um, so because of that and because you end up with these kinds of repetitive definitions here There's a feature to make your life a little bit easier called base base paths. So Very frequently. So in this example two You'll see that almost every file is or actually every file Is in the same directory and they all have this common prefix And you can write The definition differently so that uh, you put the common prefix in the base path You have to do this weird incantation with a remote x path to make research loader happy And that differs a little bit between extensions and core but you can find examples of plenty in In the core research file and in extension files But this allows you to factor out the common prefix and now your practice files definition looks a lot simpler This is hopefully Obvious and it's clear whether it's clear why you would want this for convenience But it's about to become a lot more convenient with the next feature That i'll get to you in a second So first why would you use this why would you migrate existing Modules over to the system or and or why would you write new code using the system? The the main reasons for this are that Your code structure will be nicer if you don't have to Use global objects to sort of transmit classes or functions or whatever it is that you're Exporting and transmitting between different files. You won't have to believe the global namespace a bunch It's easier to actually keep your function the class is complete hidden from other people and not Make them accessible at all even in global namespace and it's easier to see Which file a thing came from or which files your file depends on Because you can just search for use require calls and see which files get required from which file which is Hopefully not too hard if you use like a consistent naming scheme with the old method, but This makes it a lot easier You also don't have to think endlessly about whether your file is listed in the right order And you don't get bugs from listing your files in the wrong order Because you know you might try to use something that's not been defined yet Or worse. You might have a sort of circular dependency and have things breaking and worse with With require you don't have those problems and You also will not have to adjust your module definition because you change which file depends on which file And a lot of people that have used this have said that it made their code a lot Better and more readable I didn't even realize this would happen until after I implemented the feature and I saw one of the patches from one of my team members who converted some of this code to the system and I was like wow this actually Does make things a lot better. All right, so That's That's cool, but now let's just let's take this a step further We decided that we were also going to let you require JSON files So for example, there's this module in media we could core That has special characters that we want you to be able to use in Toolbars and stuff for inserting different types of characters. So there's this big json file that Has like all the different characters in all different categories of characters So there's like here's all the latin extended characters and here's all the greek ones and here's all the Bengali ones, etc, etc Previously we had to write special code just to get that json file embedded in a resource loader module and it was pretty awkward Now that's just a core feature. So you can just list a json file as one of your package files Can't be the first file because you can't actually give a json file, but you can Have it as one of the non first files And then in a JavaScript file you can require an json file and that will do exactly what you expected to do it will Just json parts that file and give you the objects So now instead of writing a bunch of weird code that Like has php that generates a JavaScript dynamically and it was all awkward We can just add this special character to json file to our module as a file and then Just write some JavaScript that says require a special character to json and now you have the object with the dictionary of all the special characters Um, so this is cool, but we don't have this tremendously often the reason why this is Um, uh, so life changing is that we also support virtual json files So this is where things get a little spacey. So this is where I'll Start taking more time per slide to explain what I'm Uh, showing you Uh, so this module definition and I'll pick this apart in a second because it has a lot of elements But the important thing that I'm showcasing here is that it has a virtual json file called Uh names.json So the syntax is a bit weird here But uh, basically what this is is we say there's this file called names of json. It's not a real file Um, but here's some code that lets you generate the contents of this file. So Basically we're instructing researchers to pretend that there is a json file called names of json And to run this code to determine what is in that file. So in our case Uh, excuse me In our case that is the result of that fetch language names function over there. So this is a Uh virtual file that contains some names of all languages in our current language um So in order to make this work, uh, we use a base path Because uh things would get pretty awkward otherwise if we didn't use a base path then You would be seeing resources slash source slash media dot language slash You get a language of names that's yes on the first line and then for the second file We would either have to pretend that our fake file is in that same directory Which would get confusing because then if someone goes looking for a file it's not actually there Or we would not have a prefix and just call names of json, but then The javascript file would have to require dot dot slash dot slash dot slash names of json Which is also not very fun. Uh, so this is what this is the reason why Uh, I highlighted the base path feature so early We use it almost always in modules that have virtual files So that things don't get that awkward Uh, so this uh over here is a function that returns the contents of this file So in this case, it's the language names. It's the language names in the language Um, and so there is a context object that gets passed this parameter so that you can Find out some things that you need like which language are being executed in right now Uh, so with that all uh, this is basically a replacement for The way that you used to have to do this is either write Some code that like four people on earth understood how to write so that you could put dynamic things in this part of your module um, or you had to make this Uh a configuration variable basically and export it through the configuration system so that you could get it with mw.config.get And then language names or something But this is a way that you can put data in a module um, and That is pretty powerful. We're going to see some more applications of that Um, but this syntax can be confusing. So if uh, people have questions about how it all works then that would be very understandable Um, another hiccup there is that when you're in an extension of json final Uh, you can't of course write inline functions in json the way that you can in php the previous example Um, I had an inline function in the module declaration. You're not going to be able to do that in json So the syntax for that instead is that you put a function somewhere typically in your hooks class as a static function and then you just put the name of that function in the extension of json file and Then you write that function that takes a context object and a config object and Returns whatever data. So in this case there is a config.json file in This echo module that i'm using as an example that has uh that contains Json object with two keys and values one is the max notification count that it gets from a static variable somewhere And one is a config setting that it gets from the config So this is also this was previously using nw config yet. So instead of using nw config, this is now bundling this information with that module um That is a nice segue into the shorthand that we put in for config variables A lot of some of the time you want To have data that is generated by like real code Uh to be in your module, but most of the time Really what you want is just actual config variables. Um And that's what's happening here in this, uh meeting with your special block module So this just needs access to a couple of config variables from the php side And so instead of callback and you could write a callback that takes The config object in the second parameter and then returns Uh an object that has those keys and gets the values and config objects But that's work and there's no reason you would do that work if everyone's doing the same thing So we put in the shorthand syntax where you can just Add put in a list of config variables that you want And we will make that happen for you. So now in the block address file Uh, there is code that just requires the config of json file And then gets the config variables out of it Previously this was using nw config that get Um So let's talk about why you want want to use this instead of nw config to get Because the old way that a lot of this stuff was supported, especially with config variables, but also with Things that were data, but not too big and sort of like config variables is that You registered a resource loader get config bars hook Um where you added these config variables and then in your javascript code You could call nw config to get and get your variable Um The way that this works is that it puts your config variable in this in something called the startup module It doesn't really matter what it is What matters is that it gets loaded on every single page view and it gets put in a global nw config namespace Um, so this new way using package files Has advantages because now your config bars are namespace to your module So you can give them names that are not That don't have to be globally unique You don't have to have a long prefix in front of them to make sure they're globally unique Um, and you're not polluting that global uh config object And they also get loaded with your only with your modules So they don't get loaded on every page view. They only get loaded when they're needed and For config variables in core, this can be a bit different but for almost all config variables and extensions They're really only needed For modules from that extension and most the vast majority of them are only needed by one module Uh, so this makes that very suitable for that case in particular It also means that the data in that config variable gets cast for a longer period of time And doesn't cast get cast for only five minutes And it doesn't get reevaluated in a hot code path because we have to update it every five minutes um There are also cases when you can't use this um, you can't use this when you have config variables that depend on Data specific to the request So if there's something that depends on query string parameters or on The page title or just more broadly on Which page you're on? or On which I should have really put that in the slides which user Is logged in right now or whether the user is an administrator or whether the user has a certain right or all those kinds of things If you're the only thing that you can use when you're in One of those callbacks for a virtual json file is the skin in a language and that's it. That's the only thing you get so if you need to look at The page title or the user is that envy or the user's rights in order to decide whether the user gets Whether they get a certain feature or not and you're putting that in a config variable You can't use this feature. You're still going to have to use Uh output paid the ags config bars and output page the good news is that You already would not have been able to use restart or to get config bars because that has the same that hook has the same constraints as this So anything that used that before can Be migrated Can simply be migrated to your system So you can help us by converting your extensions or the code that you maintain to Use these new features, especially if we're exporting config variables or other like simple bits of data that you need Like I said, most config bars are only used in one module. It's often For the simple case. It's a pretty simple grabbing exercise to confirm that it's safe to convert something and then just convert it And another good thing to start with is a look at your extensions reach slower to get config bars hook See what it exports and see if you can Migrate all of those things and eliminate the hook. I've been able to do that in a few extensions Secondly you can use the package files feature and the profile require in a new code because We think it results in better code and less global namespace pollution and all those nice things Uh, and thirdly, you can tell us what your experience is using the system. It works well and what doesn't work I've already heard from some people that debugging is a bit harder when you use the package file feature and so and we're already thinking about some ways to fix that and Make the debugging experience better But there might be other things or there might be other reasons why This doesn't work work as well for you as it should or Maybe it's awesome and we and you love it and we like to hear that too So, uh, so yeah, tell us uh, and then let's see I have some bonus material But sarah, how am I on time and on questions? You have uh, we have 15 minutes left and it looks like we have one question So far so you could probably take a little bit more time for a bonus material And then we could ask the question or we could ask the question And then you could do bonus material Say say that again, let's do the question first Okay, so this is a question on irc It might be as though if you look at it, it would be in the office channel Um, just because it involves a file name, but I'll go ahead and read it out to you Um, it says I note that a lot of virtual file generators are stored in the extension name In paren hooks that php file Is that a good practice given that these aren't really hooks? That's a good question. Um I don't think that we really decided yet yet. Um, it's uh The reason that I am doing that and the reason that I'm sort of propagating that is because it's historically where we've put Other callbacks from extension of json. It aren't really hooks. So extension of json also has a Um like extension in it callback feature Where you can register a callback that gets run when your extension is Loaded and that lets you set up global variables and do some other stuff that wasn't like completely migratable from The old extension php system to the new extension of json system Um, those are also put in hook files. So it has sort of become the dumping ground for Random static functions that need to go somewhere Um, admittedly there's only one there's only zero or one in it extension callbacks for every extension and there's potentially more um Of these config or of these virtual file callbacks Uh, so if people want to start a convention where those go in a different class I would be very uh very open to that Um, it's just what we're doing now because that's sort of following this circle pattern, but we didn't really Give them much thought to be honest. I just went with that Okay, that looks like for now. That's the only question. I don't see anything on the um The youtube stream or anything else on the irc channel. Uh, so if you want to share Um, the rest that you have You have about 14 minutes left. Um, and we can always check for questions. Uh after that as well All right, so I'll go through the bonus material real quick. Um There is I only ended up having time to write two bonus slides. Uh, so there's really only one topic here and I'll We'll make sure to upload the slides somewhere. I'm sure and so this is Going to be useful to refer to for uh for people because the second slide is just going to be huge and have a lot of examples But another cool thing that you can do that none of people know about is that you can have what we call icon modules or image modules um, which uh are basically just Modules that add o UI icons or insert your favorite icon management system here and that embed a bunch of images So uh, this is a simple example where Uh, you use this class resource or image module thing magic thing to say that it's an image module you Indicate the selector pattern for how it should make the class selector for the For the icon with the name placeholder and then you just list a bunch of svg images and That produces that ends up producing a module whose css looks something like the below. It's Simplified a bit because there's actually more going on but that gives you the basic idea So this is compatible with o ui's icon system And so if you have custom icons that you want to be able to use o ui icons This is a very easy and concise way of defining them And that's what it gets used for a lot The more complex example is this one Um, and there's a there's a lot going on here, but it's I found this example in the wild in manorva and it's a Pretty great like omnibus example of using every Every feature that I know exists in this system and some features that I didn't know just to honestly And I didn't even have to contrive this example. I found it So there's a bunch of different things going on here for one thing You can have different octl or left to right and different and right to left versions of the same icon That will get selected automatically um We saw that you could already do this with css flipping if you just wrote icon stuff in css, but you can define it this way as well um You can make give your icons colors And I didn't actually know this feature existed until friday when I made these slides You can set up the fall color for your um For images and this means that all these images will uh, there's only works for svgs, but icons should always be svgs anyways um This means that all of your all things that are normally black will be made This I think grayish color that is defined here um You can also define color as variance So in this example, that's in verse which is set to white. So then you get a white on black version of the icon, but um, you can also use this to make things Red or green or blue, which is something that oi does for progressive and destructive icons um You can set the variance be global which means that every icon gets it or in this case, we didn't do that and we only do it for some Uh images. So now this icon can be used in two different ways You can use the regular clock icon and you just get a clock icon Or you can use clock dash inverts and you get a white on black uh clock icon and Uh in this case, they're using the mw ui icon uh system and naming scheme for dc assess selectors, but If you put in the right naming scheme for dc assess selectors up here Then you can this also ends up being compatible with oi system and it will um automatically invert icons for you if they appear in a place where they need to be Uh where there's a colored background the icon needs to be white um So this is a pretty crazy example, but it gives you an idea of how powerful this stuff all is and And what you can do with it and I don't know how much documentation there is but The if you look up the definition of this module skins from nerve icons images. It does basically everything I can do So it's pretty good. Let's look. Oh, yes, and I'm looking at irc now on my phone I see the andro auto says that uh he and team have recently added a call that pram Uh, which is another cool feature that's That I don't have an example of right now, but it's worth looking at um A Mirror asks is there any way to change the value of the virtual json file on tests? I want to write some key in a test for different values of a config variable that can find an easy way That's a really good question. I don't have an offhand answer to but that's uh, another thing that we should look into improving if it isn't already doable because um You're right that it would be good for especially these more complicated callback functions the ones that aren't just like oh here's a config variable put it in but The ones that actually do work It would be good to be able to test them And I don't think that we have a great way to unit tests. Um those callbacks right now and it's something I'll probably consult with timo on because He knows both more about resource loader and more about unit tests than I do And that's the combination of things that we'll need here awesome ron. I just um I didn't see any other questions and If you don't have any more Bonus stuff. I just wanted to say thank you so much for speaking today. Um, we really appreciate you Sharing all this information. That's really really interesting And um, I also wanted to thank uh, brendan cambell craven and the AV team. I don't think I think them enough on these calls or on these tech talks as well They do so much background work To help make this possible. So Um, is there anything else that you Would like to share ron or any um additional questions that folks have I have nothing else. So unless there are last minute questions, um, I will keep it at this Okay, great. So what I will do is um, again, if anybody does have questions on the youtube stream Maybe you're watching this later. Um, feel free to ask those I can forward those to ron Rone is okay for people to reach out directly and ask you questions too. Okay Great. Um, and then uh, we as always just kind of a little plug for tech talks. We have this talk every month This is open to members of our community As well as staff anyone who wants to share technical topics Definitely feel free to reach out and we'll schedule you in and uh, And have you shared the community? All right Yes see see um I had this slide up earlier and you can look at that. Um, and that has information about how you can How you can sign up for those as well. So again, thank you everyone for attending today. Um, thanks for everyone helping and thanks for everyone who has questions Okay


Some of these, you know, one of the question is that why Newton's law is said to be a law and D'Alembert's principle is a principle. Even what I have learnt, you know, I probably would not be able to give you the fantastic answer, but what I have learnt that law can deviate, but a principle cannot. So what it essentially means that if you look at Newton's law, it depends on what reference frame you are choosing. That means if I say force equals to mass times acceleration and I look at a frame that is moving with the, you know, body, then I do not think Newton's law can be hold there. So that law violates. That means depending on the frame you are analyzing, you have to say resultant force equals to mass times acceleration in that direction, okay. But D'Alembert's principle as we started, it is a principle because it does, it is valid, you know, in any moving frame that you see. That means as long as we say that M A is taken in an opposite manner, the body is at rest. So it does not violate. So it is, you know, in any non-inertial frame, if we choose, then that principle will not be broken down. You have also seen that Newton's law is not valid when the speed of light, let us say, you know, your speed is very high comparable to the light, then there are some violations there also. So principle is something that I learnt that some others, you know, theorem is derived from those principles. There is no violation to the principle. For example, why principle of transmissibility? That was another question. Why do we say transmissibility is a principle? Remember the concept is that as long as equilibrium is concerned, a force can be taken anywhere in its line of action and there is no violation to that. You cannot violate that no matter what you do. So principle cannot be violated, but a law there may be deviations, okay. So that is all I can answer at this moment. But if I do get a better answer from other experts, I will convey that to you, okay. So other issues, I do not think there are many relevant questions that are coming up. If we merge this system in any fluid, which density is D, then what effect of the fluid on this system please explain. I do not know the answer. I can only tell you that, okay, probably you know, when you are dipping it, that means there is a resistance from the fluid. So fluid is entering, you know, in the equation of motion, you only get that in terms of the damping force, viscous force. So fluid friction, fluid friction is going to come into play and that we are going to, you know, look at in the next half, this half as well. So that will be damped vibration. Think of a piston, just think of a piston, okay, and that is let us say on a cylinder that piston, you know, is going into the cylinder and that cylinder is basically filled with fluid. What happens? You will have the, okay, you will have the friction force that is coming as a resistance as the piston is trying to go down. Now from the experiment, we have observed that that force, the resistance force is proportional to the velocity of the piston, okay. Other question, what is the, you know, please specify the reference books for dynamics and vibration. I do not think for engineering mechanics course, our books, you know, set of references are fixed. As we said that very, you know, good book if you want to see, definitely there are two, as we have referred to, B.R. and Johnston and Merriam and Craig. So these are the two books, B.R. and Johnston and Merriam and Craig. In both cases, in fact, we find that dynamics is more than that of statics. So now there are other questions coming up. What is the difference between oscillation and vibration? Vibration is more general, oscillation is very specific, okay. So anything oscillate that means we try to say it is always going from positive to negative. But in vibration it is not necessary that it will always go from a, you know, some positive to some negative, okay. So that is one of the questions. I think how to account inertia forces for the body under motion, I think that is what we are covering, okay. Inertia force is again a resistance to the motion and it has to be taken in an opposite way, okay.  I am looking on to this. But let us try to, you know, as such I do not see everything is crystal clear in terms of the problems look like. There was a question in this problem, I think the problem number was, yes, so this problem I think why this force was taken up here, someone said it should be down, just look at it carefully, okay. So Xa is chosen to be greater than Xd that means there is a net tension in the spring. If there is a tension in the spring then how it should act, okay. So we have, we are analyzing this problem. We have assumed the fact, let us say Xa is greater than Xd. It does not matter, just because of that, you know, we are deriving the equation of motion based on that particular notion that, okay, I have Xa and then Xd is coming into play, Xa is greater than Xd. Therefore, I have a tension in the bottom spring. So how does tension will be from the spring is going to come to the body, it should be upward, okay. Similarly, if you look at the spring, this is also under tension, spring under, you know, tension at B as well. So how the body is going to see the force? Newton's third law. So Newton's third law is a coming into play, okay. So it is going to be downward. So I do not see any problem as such. Is that clear now, okay? So that is more relevant towards what I studied, okay. Now what we will do? We will try to solve few tutorial problems before we go to the damped vibrations and we can do the damped vibration as a separate study and as long as we grasp this concept, I think there is not much issue to deliver these concepts to the students, okay. So all I said or all we have learned is the fact that, you know, we can represent the body in an equivalent static system, okay by using the D'Alembert's principle which states that the inertia forces should be taken in an opposite manner. That means mass times acceleration and I times alpha, they should be taken in an opposite sense on the body and then you can solve that problem at any instant of time t, okay, by using the equilibrium. That means resultant force should be 0 and resultant moment should be 0. That is all we have done, okay. But it is a very systematic and thorough procedure and we have found that students actually, you know, enjoy doing that without getting into lot of nitty-gritty of dynamics as such. So with this I think what we will do? We will try to go to the damped vibration but I would not spend much time on that maybe 15 minutes or so because as such we do not, you know, also in the syllabus of IIT it is not there. As you have seen the main objective is to deliver the concept of drawing the free body diagrams. That is what we have been doing from the beginning. How to draw the free body diagram? How to show the forces? And in this dynamic problem I have simply said, okay, using this principle we are looking at the equivalent static system. So let us now look at the damped free vibrations. The first statement that is being given is all vibration are damped to some degree but by forces due to dry friction, fluid friction or internal friction, okay. It has to be damped because we know that a system cannot oscillate for infinite long time. So amplitude is going to decay and it is going to stop at some point of time. So now here basically we have to represent this, you know, how the damping is coming into play. So again it is a viscous damper or a dashpot. So remember this piston is going into a cylinder which is of, has some fluid which has a viscosity. So if it is water and if it is let us say some honey, the viscosity will be different and all of us know that therefore what is going to happen? That one will, honey will give more resistance than that of water as simple as that. Now experimental evidence shows for small motion the force that the body sees is going to be proportional to the velocity and that proportionality constant is called to be damping coefficient C which is a known, okay. Now you look at the equilibrium of this mass with the dashpot. If we just think of the free body diagram of this entire thing as it is isolated from the spring, again we are measuring the vibration from static equilibrium configuration. The mass is displaced by x or let us say some x0 and released, okay. So it is going to oscillate like this about the equilibrium configuration. So at any instant of time x, sorry at any instant of time t displacement is x. So what is the forces? Now what are the forces acting on that? That is k delta s t plus x that is the spring force. Mass times acceleration that is the inertia force W C x dot, okay. Remember this W is actually equals to k times delta s t. So that is going to go away ultimately. So what we land up getting is m x double dot plus C x dot plus k x, okay. Now I have to solve this equation of motion. So idea is that we substitute for x equals to e to the power lambda t, assume the solution in this form and dividing through the e to the power lambda t. So ultimately this is going back to the mass. So we have, remember x double dot that will be what? Lambda square e to the power lambda t. x dot is simply lambda e to the power lambda t, right and k x. So ultimately this cannot be 0 because then we are not solving any problems. e to the power lambda t cannot be 0. So we can divide this entire thing by that one for non-trivial solution. So for the non-trivial solution we have the characteristic equation that is displaced. So it will have two roots, right. So roots are like this. Now what we have defined here? We have defined a damping in a critical damping coefficient such that this is equals to 0, okay. So that way what will happen? I will have the value of the critical damping coefficient that is 2 m square root of k over m that is 2 m omega n, clear. Now what it will do? Ultimately once I know C c let us say that is the critical damping coefficient. Remember if C c by 2 m, ultimately you have to always look at this if that is greater than omega n or if that is less than omega n that is the whole idea or if that is equals to 0. So ultimately your roots of these equations are changing, okay. So we will write it in a bit different form. So ultimately look how I have written it. I will define rather a damping ratio which is xi. xi is equals to what? C by C c. Now C c is already given 2 m omega n. Therefore now lambda can be expressed in terms of xi that is the damping ratio and the omega n, okay. So negative xi omega n plus minus i omega n square root of 1 minus xi square. So I will write the 2 roots in that form, clear just by defining this damping ratio, okay. Now what is happening therefore I can have 3 different situations. First one is xi less than 1. If xi is less than 1 that means C is less than C c. So that is C is less than the critical damping. We will call that under damped system, okay. So in case of that remember I have a positive i and negative i. 2 roots are given by exactly what is shown and therefore we can say that we have the general solution in this form. Remember this therefore what will happen that omega d is coming into play that is damped circular frequency of vibration. Therefore you are going to get an periodicity of omega d sin omega d t plus cosine omega d t. So this is basically the math and here you are having a decaying term e to the power minus C by 2 m is what xi omega n, do not forget C by 2 m is simply xi omega n that is my damping ratio, okay. So ultimately I am going to get my general solution in this form. Now I have to solve for C 1 and C 2 which can be done depending on the problem. Let us say we are talking about a free damped vibration then this C 1 and C 2 can be obtained based on the information on the initial conditions, okay. So that means whether at t equals to 0 I have x 0 or t equals to 0 I have v 0. So that is under damped system. What is critical damping when xi is equals to 1 that means C is equals to C c. So xi is equals to 1 therefore what happens you can see clearly if you go back to the math therefore you have C 1 plus C 2 t to the power minus omega n t that is the solution, okay, right. And then third one will be xi is greater than 1. Now if xi is greater than 1 you are going to get real roots, okay. So therefore again we are going to get a solution of this form. So this is called over damped system. So what we have now learned that I have xi less than 1, xi equals to 1 or xi greater than 1. Three situations can happen and for each one of these my solution is bound to change just because of the property of the roots. So that is the you know done in the it is assumed that it is already done in the differential equation class. Now let us take the damped vibration as I was saying so we are just trying to understand the physical you know nature how I am going to get my solution rather than going to the math. So what is displayed is a comparison between a damped case and an undamped case. We have already studied, right. Now in the damped case how do I get my solution given that I have x0 and v0 as my initial condition that will be the complete solution. Remember what will happen if I assume x0 equals to sin phi and this quantity as cosine phi then I can express is again sin omega dt plus phi and with a rho here that rho is going to be the amplitude. So there is again an amplitude of vibration, right. Remember that amplitude of vibration if v0 equals to 0 still has the xi. In this case it is undamped situation if v0 0 it becomes x0. So now let us try to plot these two equations. As I said please replace this figure by saying u equals to x so displacement is x velocity at t equals to 0 is x0 sorry displacement at t equals to 0 is x0 and velocity at t equals to 0 is v0 just replace. So I have x displacement this way and time this way and I am comparing an undamped system that is a faint line and damped system that is a bold line. So what is happening ultimately as expected we can see that the damped system is actually decaying in the amplitude and what is that envelope of the decay that envelope of the decay is completely driven by rho multiplied by e to the power xi omega nt. That is the first thing therefore there is a decay in the motion and there is a envelope that controls the decay clear. Second feature what is the second feature you think what essentially xi you do for an you know undamped system what is the effect on the time period. So I have tau d right and tau n do not you think that time period of oscillation a time period of vibration is going to increase when you have presence of xi of course the motion is going to get slow slowed down right. So it is going to take more time to come back to the original configuration or equilibrium configuration than that of the undamped case undamped case when you have no damping. So there is going to be a small increase in the time period of oscillation and you can show that also. We can clearly see that omega d equals to omega n square root of 1 minus xi square. So therefore the time period td is equals to that means damped time period equals to the undamped time period divide by square root of 1 minus xi square. So for xi less than 1 here we are talking about xi less than 1 everywhere. Your time period of vibration is going to increase a little bit depending on the value of xi. Remember xi still has to be greater than sorry less than 1 okay. So depending on the xi time period will definitely increase. Now there is an interesting thing going on how about if I take two successive peaks of the damped system. Let us say I know the amplitude here and let us say I know the amplitude here. Can I get a relationship directly between these two amplitudes? Answer is yes because this envelope is controlled by rho e to the power minus xi omega n t right. Now the difference between these two peaks what is the time difference? Capital td right that is the time period. So therefore if you take the ratio I will have x 1 divide by x 2 should be equals to e to the power xi omega n multiplied by the time period okay. So now what is happening? If we look at from the logarithmic point of view you take the log of this then ultimately I have xi omega n td. So td can be expressed in terms of tn and tn can be expressed in terms of 2 pi by omega n. So ultimately you see I have 2 pi xi square root of 1 minus xi square. So we say it is a logarithmic decrement between the two amplitudes okay. So if we know the successive amplitude then you can measuring the successive amplitudes we can in principle calculate what is the xi that means the damping ratio and therefore what is the damping coefficient c clear. So physically if we look at now we can actually solve problems through this concept but before that I will show one more thing that okay what happens xi equals to 1 and xi equals to 2. So let us say critically damped that means xi equals to 1 and critically over damped that means let us say xi is greater than 1 so we assume xi equals to 2 what it does? Now all of these remember we can simply take an excel file or let us say we take help of MATLAB okay we take help of MATLAB and we can plot this type of graphs what is t versus displacement right time versus displacement graph. Now this graph is given in terms of velocity equals to 0 the initial condition is at time t equals to 0 I have velocity 0 that means slope of this curve should be 0 velocity 0 means at time t equals to 0 the slope of this curve should be equals to 0 no initial velocity only thing I have is an initial displacement that initial displacement is x0 so it is a normalized curve and we can do that ultimately what is the outcome remember this is a vibratory motion so it is a oscillation right and what happens to this? This is non-vibratory motion both for critically damped and over damp as if they are not going to you know as you let us say you think of this door that door has a dashpot right here and you open the door so you are giving it some theta right and you are releasing this door what it does it is designed in such a way the damping is in such a way that xi is either equals to 1 and greater than 1 that means door is not going to go back to its equilibrium okay so it is not going to go back to the other side and then again come back so in absence of this what will happen if you release it is simply going to hit you and again come back okay that is the whole idea so to prevent that okay I am not going to get hit by opening this door so therefore what is going to happen you simply open the door and leave it it is going to come back and stop at its equilibrium configuration so very nice example to look at so how do you solve these equations I am leaving it to math because that is basically mathematics not going into the details but what is most important to coming back to its equilibrium configuration right it is taking more and more time because time period of vibration is naturally elongated is that clear now so I think with that I will just give a very quick example of that of a loaded railroad car let us say that is weighing 3000 or 30000 pounds it has a mass let us say is rolling at a constant velocity and it couples with a spring and dashboard bumper system okay so it is moving at a constant velocity now this let us say has a negligible mass so what is happening basically this momentum is going to come to here so ultimately it is going to get an initial velocity you have already learned the conservation of momentum right so ultimately this is going to be transferred because this mass is going to be attached so this system mass dampers you know a spring damper system is going to get an additional mass with a velocity v0 at time t equals to 0 so your problem starts now so what happens let us assume that there is a recording device that is measuring the displacement and the displacement is measured like this okay determine the damping constant and the spring constant look how nice this problem is I have a recorded data and from that I am trying to determine what is the spring constant and what is the damping constant required okay so again since I know this successive peaks so therefore I can simply use the concept of logarithmic decrement right so in the next slide first of all we know let us say what is the time period of vibration to complete one cycle that is TD that is 0.41 second that is given I can calculate what is omega D okay now look at the logarithmic decrement x1 by x2 should be e to the power xi omega n TD so therefore e to the power c by 2 m TD right so ultimately I know this I know this ratio x1 by x2 right so therefore I can calculate what is the c because m is also known so c can be calculated and therefore we can go to omega D expression that has k and m both k m and c right and from that I can calculate the k okay so ultimate idea is we do not get into lot of mathematics as such now what is happening we can think of forced vibration we solve the differential equation and so on so forth but ultimately you know in this particular modeling session we have delivered the concept of single degree of freedom system we have looked at what is generalized single degree of freedom system we have introduced the concept of D'Alembert's principle to get the equations of motion for this system and therefore we have also looked at can I solve this type of system for free undamped and free damped vibrations and we have looked at some of the you know applications physical applications that are actually possible okay so I think with that what I will do I will conclude this session.


Welcome to Designing in the Browser, the series where we explore user interface design through the lens of modern web technology. In this season, we're doing a deep dive into the APIs that prepare you for the new responsive web of tomorrow. And today is all about theming and dark mode. Dark mode is one of the top requested features from developers and users alike, especially those who like to browse the web at night. When Twitter released their first preview version of the new Twitter PWA, the feedback they got was that users wanted dark mode, an emoji picker, and more dark mode. So a lot of very vocal users have this feature request. But not everyone prefers a dark theme. Luckily, CSS gives us the ability to hook into user interface preferences and provide the optimal experience based on what a user says they prefer. This is called the prefers color scheme media query. It is another aspect of this new responsive web. The new responsive framework is not only about new APIs for component-based responsive design, which we covered in the previous two episodes. But it's also about putting your user first and creating experiences responsive to them and their needs. And preference queries are perfect for this. In this episode, I'll cover how to create a beautiful dark theme, including a few design considerations for dark themes, as well as introduce some auto-darkening capabilities that you can use as a shortcut for browser interfaces. Let's get started with the practical stuff, how to create dark themes. The path I'd recommend is to use custom properties for theming and then dynamically swap your custom property values based on those user preferences. So let's take a look at what this might look like. This is a website called Tooling Report, which assesses various bundlers, their capabilities, and performance. My team at Chrome built this site, and it has a solid dark theme. So I'd like to use this as an example. Here's the site. And as you go through, you can see that there is an overview of capabilities. You can click on these. There are tooltips that provide more. You can reach into the pages for more information and then dive a little bit deeper about some of these capabilities. So what I like about this is how it's set up for theming. You have your spacing here and your roots. You have font sizes.  And these color values are what we're going to focus on because we're talking about theming today. So what I can do is I can go into the Rendering tab inside of DevTools. And I can emulate what a dark theme looks like. I can turn on Preferred Color Scheme Dark. And what this would emulate is if a user has this operating system preference that they prefer a dark color scheme, or if they're using something that automatically converts the color scheme based on time of day or another mechanism. So now we are in a dark theme. And you can see that these colors have shifted. So here is what that dark theme looks like. This is being emulated throughout. And the tooltips, the headers, the text. We have light text here now. And these colors are actually adjusting themselves, still in the root, but using that prefers color scheme media query. So now if I adjust this, the light theme again, you can see that these color values are coming back. We have this background blue color. We have text gray, which is a dark color value. And then we swap to a prefers color scheme dark. They're getting overridden. So now something like that blue background is going to be a darker blue. It's sort of like this navy. We still have this text gray. It's now a lighter text color. So you can make these swaps in just a single line of code. Instead of shadows here, we have some glow as well. And there is a lot of interesting features that we've done to adjust for this dark preference color scheme. You might also want to add the color scheme CSS property at this point. Color scheme tells the user agent to make adjustments to the user interface, including form controls, scroll bars, and the base values of the CSS system color is provided by the user agent. So it will automatically do some inversions for you, such as present light text instead of dark text by default. Color scheme is currently supported in Chromium-based browsers and Safari. So if you are using this as a capability for dark themes, make sure that you are testing cross-browser. You can apply color scheme within a media query, like this, or use color scheme to create automatic browser provided dark themes by setting color scheme light dark on the base root to tell the browser that this site supports both light and dark themes and to automatically do that conversion help for you. Here's what that looks like without any custom color on a web page using native browser styles provided by the user agent in Chrome. I have it set here on the root color scheme light dark. And then when I emulate the dark color scheme, you see that we now have light text on a dark background. OK, so now let's talk about some decisions you might need to make when converting your site into a dark theme. Because you might want a more custom experience than that standard user agent style, right? The first consideration is, what do you do to create depth when you can't rely on shadows? Shadows just won't work the same on a dark background as they do on a light background. So something that Material Design recommends and I love to do is instead of adding shadows to create elevation from the background, add light to create elevation from the foreground. Let me show you something. Take this dino. When I shine a light on it to create depth from the background, it casts a shadow that brings the dino forward from the background. Now, if the background was dark, like this one, that shadow isn't as visible and it has a lower contrast. But the more forward I bring it toward the light, the brighter the light is that shines on its surface. So you can take this physical concept and translate it into the digital world. Let's take a look at a web example. Here we have a card in a light theme and it has this shadow that makes it stand out from the background. But when I turn on the prefers color scheme dark and put it onto a dark background, that shadow pretty much disappears and it actually looks kind of funky. So I don't think we want this. Another live site that my team built is Houdini.how.  So I can also convert this to the prefers color scheme dark as we've designed a dark theme just for this site. This site also uses shadows that kind of disappear when you have a darker background. If we go to the resources page, what I'm doing here on these cards is having a little bit of a translation as they shift up and down. I'm also using a lighter foreground color on the cards so that they stand out from the background. Now, if I wanted to make these stand out even more, say in the hover state, I could adjust that background to be even lighter. So here I have this transform. Let's just, you know, instead of transforming it, change the background color. So we'll do background color. Let's make it maybe a slate gray. And now it's a little bit lighter than something next to it. So when I have the state, it'll stand out from the other cards around it. Now we might also wanna adjust the transition. So we'll set transition to background color and we'll do maybe 0.25 seconds. So now it's a little bit more of a smooth transition. I have this hover and focus state. So that it stands out from the other cards around it when you're interacting with it and it sort of elevates this card forward. So that's exactly what I'm doing in this dark theme. Here's just a blog site that I was creating and I am using these softer pastel colors. So when I set this to prefers color scheme dark, I wanna keep that pastel vibe and that pastel aesthetic but just converted to a dark theme. So I've desaturated a lot of these colors. And then when I hover over these cards here, I have sort of a deeper maroon color that does make the card stand out but stays within the color scheme vibe of this site, making it work on a dark theme. Another consideration for dark theme adjustment is color vibrancy. On a light background, a very bright or saturated color doesn't have as strong a visual contrast and vibration next to a light color than it does next to a dark color. It's sort of like neon versus day and nights. This makes vivid colors a bit harder to focus on with a dark background because there's just more visual vibration that your eyes are seeing. So let's take a look at an example. Here we have this card and this is in this dark color scheme. This very vivid saturated color is a little bit harder to read when you're looking at it against this black background. On a light color scheme, especially at some of the more lighter shades, it's not as obtrusive to our eyes. So what we might wanna do here is instead of having it be very saturated, is decrease the saturation, maybe make it a little bit less vibrant and this tends to work better for nighttime viewing and for dark themes. So this is why you might wanna tone down bright brand colors for dark themes. Dark themes aren't just nice for user experience but they also save significant battery life. In a lab-based Pixel study, we found that on average at 75% brightness, dark themes saved users 11% battery life on the OLED screen of a Pixel 6. That's pretty significant. So if you needed another reason to build a dark theme, it's not just about respecting your user's preferences, but it's also about respecting their battery life. Building dark themes with custom properties is great and there are a lot of systems out there with predefined color values and dark themes like open props, which was recently launched by my colleague Adam Argyle. So here I have an example of open props and it has custom property values in the root. You can see the brand color, text color and surface colors. And when I adjust these values from the slight theme to a dark theme, those brand colors stay the same.  So you can see that there's a more vibrant orange here than we see here in the dark mode. And then the text colors also invert and become light. Adam's also showing us a dim theme here and great. You can go wild with theming and really let your user create custom experiences and view your site the way that works best for them. The color scheme property is one form of auto darkening on the style layer, but Chrome is currently exploring some other techniques for auto darkening to reduce your workload and getting your site dark mode capable. You can try out what this looks like by opening Chrome and turning on auto dark mode emulation in DevTools. So open back up my Houdini site here and if we scroll below where that prefers color scheme media emulation is, there is an emulate auto dark mode feature. So I turned that on and enable it. You can see Chrome trying to automatically create a dark mode for me and I can then see where this works, where it doesn't. So it's not perfect yet. This feature is a work in progress and we definitely need your input if you spot bugs and accessibility issues. You can provide your feedback on auto dark using the link within the show notes. All right, that's all we have time for today but I hope that you've been inspired to create your own dark themes. Do it for your users. And if you haven't tried the dark mode on the design center site yet, I highly recommend you do. It's a fun one and we had a lot of fun putting it together. As always, I'll see you on the internet. Bye for now.


Good afternoon everyone and welcome to the Stockswish Show Play of the Day, Play of the Day. This is MTW. It's been a really good week. It's been a good earnings season and it's not even anywhere near over. The rest of the month is earnings season, all of August is earnings season. I don't know why people don't like to trade in the summer. I love to trade in the summer. Summer is a great time to trade if you trade the strategy that I trade, which is gaps. So here's the MTW. It's really good and I liked it at 100% conviction at this morning.  I mean, I could have literally probably rated 50 things and I wasn't going to do that. So you know, I can tell though because I have a really good eye for what I like and what I know is the top watch and in fact I was talking about this in the room this morning to the people that were there. To learn in the golden gap class how to find the gaps and rate the gaps. The benefit of being in the live trading room though above and beyond after you take the class is that you get me to do the top picks, which I do when I review the stocks and look at the ratings because I have a very good trained eye. It's a trained eye and it's something that you can get if you're with me for a while in the room plus learning the information in the class.  The idea is to train your eye to be like mine to see these things when they work. So I mean, when people say, well, what can you do for me? What can you teach me here in the market? Well, I'm teaching people how to trade gaps, how to find the right direction to play the gaps, how to find the right stock to trade on the day, how to know what direction it's going to go into and also how to take the entries in the setups. And then I'm teaching people how to reprice action like for example in the stock today. And at one point today, the stock actually rallied back almost went over the high and I still had the position and I think a lot of people thought it was done that was in the room, but I knew that it wasn't done. I knew that it wasn't done and this is not even done right now, which is crazy. All right, let's go over it. Wow, look at this thing. It's going to make a new low right now. Wow. This is going to make another new low. This could actually get a $25, $50, $25 today. It's early. It's 12 o'clock noon. This is making a new low right now as we're talking right at the second. This could actually go all the way down to $25 today. That's realistic. It's not even a dream target. Look at this. All right, let's go over it. So again, I like to trade the morning here. So I took an entrance immediately in this, immediately in this and I really gave this a cushion and the reason I gave it the cushion was because of the fact that it did have a moving spread in the morning just to make sure that I didn't get popped out. This happens here. Again, are you buying this? No. It's a golden gap. It's a professional bearish gap. It's a gap that raised more than 20 points per my 26-point rating system. I'm not buying this. I am shorting this. I'm looking to short it to get in to get in to get in. And here you could have taken more in this. You could have even taken more in this here. Dropped, broke. I did not get out of any of this here. It rallied back. I didn't do anything with this at all because I was waiting, waiting, waiting, waiting for it to break down again. Now, when it came down in here because of the time of the day, I did give it out of some, but I didn't get out of the whole thing. And I kept the stock for the original stock, stock rallied all the way up and dropped and broke again. And now it's continuing even more. So, you know, what gives me the ability to be able to stay with the trade or hold the trade through any kind of rally or any kind of number or while the market's doing whatever is my conviction in the gap. It's the basis for everything I do. That's the reason I take the trade. That's what enables me to take the risk and to see the trade through and follow it through. If you're looking for a trend on a one-minute chart in this, this one-minute chart actually did not have a clean-down trend here in the morning. It actually flipped into an uptrend at one point after 10 o'clock, where people might have exited their short or bought it, thinking it was going to fill the gap or something, which I've talked about a million times, filling gaps. It's not a strategy. It's not the right way to trade. You know, it's just, this is absolutely nothing. There's no strategic reason for that. The strategic reason for doing this trade today, which by the way is making a brand new loan here now, a brand new loan by 12 o'clock in the stock. The strategic reason for taking this trade is that the stock got sold off, sold off in the gap, and I look at the price of the stock where it's opening. I look at the price of the stock where it's opening. I look at the price of the gap and I determine using the daily chart if this stock is going to drop more on the day, which it has to drop more. So the only way that's going to happen for a stock to drop more from the gap down is if it would have continued selling or shorting. That's the only way something will follow through in a gap down, just like the only way something would fall through on a gap up is if it had continued buying, okay, new buying. Who was in control of this chart? The bearish. This is a short today. The bar is red. This bar will close, but this bar will close with a red body. The red body in this today could be bigger than it is right now, plus another dollar. So honestly, this is a trade you could take any set up in today. The whole day, this might be the load of the day here, but it looks like it's going to break in any second. Time of the day here is good, and I know this bar will close red today. So I had a great conviction in this today, did the right thing, got some money booked in here. Do you see how if you don't know what to do with this, you might buy this? Like, let's pretend this didn't happen here. Get rid of this. First of all, I knew this was a good short, but can you see how what people do here and here? Some people buy this. Triggered on a buy set up here, and some people bought this, thinking it was done, or it was going to fill the gap, or it was going to rally back, or it was a long, a long above and beyond and over the 200-perman moving average. But that's the wrong way to look at the gap. And so people did buy this. People did buy this, and they got stopped out under the load of the day when the stock went down and broke under the load of the day right in there. And nobody should have bought this, though. But this is what confuses traders. And why if you don't have 100% conviction or know how to read the actual daily chart to read what is happening and the price of the gap, you might short something, then buy it, then short it again, then buy it again, and you'd have no idea what to do and no conviction at all. And you have to have conviction to trade and to know what to do. And I just have a really good eye for these things. I mean, I can look at 50 gaps in the morning, 150 gaps in the morning, and take out the best thing to do. And there it is. So that was this today. Beautiful move in this. Beautiful move, and it may not even be done. So, great job, everyone. It's stuck with the MTW today. Beautiful golden gap. It's been a fantastic week. It's been a fantastic week. We're just gonna stay on track here. What a great way to end this month here, July 31st. What a great way to end this month. So today is actually the last day for the special for August for anyone that wants to sign up. It's the last day today. And the golden gap class for August is August 9th and 10th. If you are interested, email me at Melissa at thestockswish.com if you wanna sign up for that class. And just carry on, people. Continue to do your thing, trade. And for those of you that have been watching me, you gotta decide if you wanna make money in the market.  There's a lot of things out there that teach you good information in different places in different classes. And I teach good information. However, I also teach people how to make money. And if you're following me and taking the calls and taking the trades that I'm calling then they're making money too. Things have been going great this year. It's been a beautiful year. Fantastic year 2014. Gorgeous fabulous summer. Have a fantastic day, everyone. If you're interested in signing up for the golden gap class, it's August 9th and 10th. Again, there is a bonus day for that class. It's gonna be Saturday, Sunday, and Monday. It's gonna be a special bonus day for that class where I'll be doing golden gap reviews. In fact, we can go over this one. We'll go over this one then. We'll actually review this one on the Monday after the class. That's what we'll do, because this was a goodie. Have a great day, everyone. Email me at Melissa at thestopswitch.com. Thanks, everybody. Have a great day.


Hey guys, Thundie here, and welcome to another unscientific, ultimate battery test. In this test, we're including the brand new OnePlus 8 and OnePlus 8 Pro to see how well they do, of course, in fast, wired charging. Both the OnePlus 8 and the OnePlus 8 Pro come with the 30W T-Warp charger. This is the fastest charger from OnePlus. Both devices have different battery sizes. The OnePlus 8 comes with a 4300mAh battery while the OnePlus 8 Pro comes with a 4510mAh battery. So of course, we'll see how well they handle, especially against some of the other devices we have here, which include the brand new Oppo Find X2 Pro, which comes with a 4200mAh battery and a 65W charger. It's massive. Next up is the Huawei P40 Pro with a 4200mAh battery and a 40W charger. Now after that, of course, is the Galaxy S20 Ultra with a 5000mAh battery, and in this test we'll be using the 45W charger. I know some of you are going to talk and complain, but I will show you and give you the results for using this device with the 25W charger that comes in the packaging. So there you have it guys, let's go ahead and start charging. So kicking off our charge test here, devices are on. Now we're going to leave it in this natural state, so if the device actually fully powers on we'll leave it that way, if they are off we'll leave it that way as well. And as you can see, we've got our OnePlus 8 on the far left. This is the Oppo Find X2 Pro, in the middle is the Huawei, next to the Huawei on the right is the OnePlus 8 Pro, and finally, if our left is the S20 Ultra. And as you know, they've got different batteries and different sizes of chargers, but what we're going to do is we're going to check at different times. So we'll go in at 5 minutes first to see where everything stands. So at 5 minutes, OnePlus 8 is at 12%. The Oppo Find X2 Pro is at 22%. And the P40 Pro is at 14%, while the OnePlus 8 Pro is at 12%, and the Galaxy S20 Ultra is at 13%. So as expected, the Oppo is going to take the lead, but interesting numbers all across. Again, they all have different battery sizes as well. So we're going up to our 10 minute mark, which is our next check. The OnePlus 8 is at 24%, while the Oppo is at 39%, the Huawei is at 30%. The OnePlus 8 Pro is at 24%, and the S20 Ultra is at 24%. So Ultra and the 8 Pro are neck and neck, even though the Ultra has the biggest battery here. So looking good there with that, of course, 45W battery will give you the results to 25W later on. So we're coming to our 20 minute mark here. While the OnePlus 8 is at 47%, the Oppo is at 73%, impressive. Huawei is at 55%, the OnePlus 8 Pro is at 46%, and the S20 Ultra is at 47%. So numbers are interesting, clearly looks like Oppo is going to take the swing, and it looks like the OnePlus 8 might come in second, but we'll see how that pans out. The other three phones, it's pretty tight. So 30 minute mark, we have the OnePlus 8 at 67%, the Oppo is at 94%, the Huawei is at 77%, OnePlus 8 Pro is at 65%, and the Galaxy S20 Ultra is at 69%, so the Ultra is taking a little lead there over the OnePlus 8 Pro itself, which is nice. Now we know quite well that Oppo usually ends around 38 minutes, it's getting really close, we can see that here, but is it going to be 38 this time? We shall see, and it's looking like it's going to be past 38 minutes. And as we wind out to quickly check in our next look, the Oppo is going to end at 39 minutes and 29 seconds. So 39 minutes for the Oppo, that is truly impressive. Now who's going to come in second? I think the OnePlus 8 will, because the last numbers we checked, it was much closer than of course what we've seen right here, and as we speed through getting close, you can see the OnePlus 8 is doing much better, and that's 100% at 55 minutes, in about 28 seconds or so. So the OnePlus 8 comes in second here. Now for third place, it's quite interesting because they're all pretty close. You can see those numbers, 97, 95, 96, and it just goes really, really close. Now we had 59 minutes, who's going to take that lead? It looks like Huawei is ahead right there, and the Galaxy is behind now at 97%, it's still 59 minutes, and the Galaxy's numbers are changing there. The Huawei is still, the P40 Pro is still at that 98%, the Galaxy is now at 99%, the OnePlus 8 Pro is still at 99%, there's trickle charging at the very end, and the Galaxy turns 100 at 60 minutes and 5 seconds. So 60 minutes and 5 seconds is where the Galaxy actually turned 100%, so let's see where the others are. It's really close, it's really close, the P40 Pro is still 99, 99, also for the OnePlus 8 Pro, so we'll see where it lands. Again, this is just a matter of seconds here, it's probably going to be pretty close between these guys left to right, and the P40 Pro turned 100 at 60 minutes and 27 seconds. Where's the OnePlus 8 Pro here? So we'll see where it is, it's 100% at 62 minutes. So there we have it guys, 62 minutes for the OnePlus 8 Pro. Alright so those were some impressive numbers, right? The Oppo Find X2 Pro finished first at 39 minutes, truly impressive, 4200mAh battery, while the OnePlus 8 came in second at 55 minutes with its 300mAh battery. So that's actually pretty nice, but again, battery size put that into perspective. Now the number 3 winner, or at least runner up here, is the S20 Ultra which I didn't expect it, it's got the bigger battery, it's 5000mAh, although this is the 45W charger, and our test results came in of course at 60 minutes and 2 seconds though. The first time we ran both the 25 and 45W with the Galaxy S20 Ultra, the 25W finished at 61 minutes and the 45W finished at 58 minutes and about 26 seconds, so again, different test results. Now when you look at of course our number 4 device here, it's the Huawei, coming in right after at of course 60 minutes and 27 seconds, and rounding of the bunch of course is the OnePlus 8 Pro with its of course 4500mAh, 4510mAh battery coming in at 62 minutes. So all in all you can see where everything stands and I think the Galaxy S20 Ultra has the best, at least charge ratio, especially with the bigger, much bigger battery than everybody else. The fastest of course is the Oppo Find X2 Pro and the OnePlus 8 does pretty well especially for its battery size. So if you have any questions or comments or you don't agree, you think all this charging is rubbish, leave your thoughts down below guys, otherwise go check out more videos we're doing of course with the OnePlus 8 Pro and the OnePlus 8 in different scenarios. We have a speaker test video that's out there, we also have of course our camera comparisons and you know it, we have a gaming video for you, so thank you very much guys, don't forget to like, share, subscribe, stay safe and always enjoy your entertainment.