Hello and welcome to Flutter and Agile DeepDive. My name is Joel Venarska and I work for Toyota Connected North America. Quick introduction. Spent a fair amount of time at Qualcomm and the Windows BSP org. Did a lot of interesting and important things there. After that I started at InRex just right after OpenCard had been acquired and I was brought in to do back-end native code and optimizations and commercialization focus. A lot of interesting things happened there. Spent a lot of time on Chromium and just the general design of the browser and what needed to be adjusted. And that's when I started looking at embedded Flutter as a viable solution to replace JavaScript-based UI UX. Not just for automotive but just in general. Pure watercraft. Spent some time bare metal, electric drivetrain, CAN bus. That was a lot of fun. Multibattery packs, etc. And then moving back to Microsoft Surface. I was present for the launch of the Surface Pro X which runs at Qualcomm 8CX. And I'm the author creator of Metaflutter. And the author and owner of IVI Home Screen. Also known as Flutter Auto to the AGL community at Toyota. Embedded Flutter. The components. There's a development environment, a build environment, and a target environment. The Flutter Engine is the core component of the Flutter technology. It's written on C++17. There's a common source tree for all platforms that are supported. Desktop, Mac, Windows, Linux, mobile, Android, iOS, Web, Fuchsia, and Custom Embedder. The build environment is based on Google GN. It's a combination of Dart and Skiya. Impeler is coming into the scene. It will be replacing most of Skiya short of some text layout. And the Custom Embedder back-end supports OpenGL, Software-Based Rendering, Metal, and Vulkan. Some of the benefits. You get a premium user experience. A developer experience that's consistent amongst most targets. You have access to a commodity talent pool. You reduce your NRE, non-recoverable expense, and improve your time to market. The development environment. So, while evolving the development environment for AGL, the goal is to have the shortest path to run the Flutter app on AGL. Something easy to change between Flutter SDK versions, support unique configurations, archive-friendly, also known as LTS, and Ubuntu 20 support. A solution I came up with is Flutter Workspace Automation. Show a quick demo of that. So, I'm running a Python script that's present in the Metaflutter layer. And what this does is it goes out and grabs all the components needed to develop with Flutter in an embedded Linux environment. And it installs all the packages, runtime dependencies. Depending on what the configuration is set for, it'll pull a variety of repositories and locate them into the workspace container. So, once the container is present, then we can start using it. It takes approximately two minutes on a reasonable Internet connection. And so, it'll pull down a debug Flutter engine and better build. That'll pull down the Flutter SDK. And as I mentioned, the application repositories, if defined. And then it'll pull down AGL QMU image, depending on your architecture. And then it will set up all the custom devices that we have defined in the configuration file. The configuration file is the JSON file. And that JSON file can be tailored and customized to an organization's needs and uses. So, if I have a team that focuses on a, you know, coffee maker project, and it's a particular target and I only have certain repositories, well then you can create a standalone configuration file. So, when a new team member joins, they can just run the script and they have the exact same environment as you do, et cetera. Or internally at a large corporation, you may have different groups focusing on different areas of embedded Flutter so they each would want their own environment. So, that's what Flutter Workspace Automation here is about. So, as soon as this is done, we will, there we go, it's installing Flutter Auto desktop build. I'm running this demonstration on Ubuntu 22. This is supported on 20, 22, et cetera, Fedora and Mac M1. We recently merged support for that and that's based on QMU opposed to the virtualization support that was recently introduced in Ventura, which was just recently came out. So, right now it's pulling down the QMU image. So, so far I've opened a terminal and effectively cloned a repository and executed a script so far. Now, once you've set up your environment, or once you've created the workspace, there's no need to rerun the script unless you want to put your environment into a known state. So, there we are. We're complete. Now, if we need to source our setup environment file, as we can see, it prints out a list of custom devices that are available. The ID parameter here is the name that we will use to run an application. So, if we go in and look at this, we can do flutter run dash desktop auto. What will happen is it's going to build and deploy and we will see a Vulkan back-end enabled flutter auto run on the desktop and it's getting the elements for the gallery. There are a fair amount of elements and what it'll do is it'll install those into the pubcache, which is located within the flutter workspace. So, that's downloaded and it's built a bundle. And now it's launching the flutter auto and primary screen. So, let's see. That's that. So, you can also change the default size of it, et cetera. And then from here, I can launch the debugger if I so desire. It asks me every time I do this. So now, here's the debugger. So, we're looking at the flutter hierarchy, performance, et cetera. This is all functioning on the host. This is running Ubuntu native and all the features that you have that you get on the target, you get on the host and vice versa. So, let's close that out. Queue to quit. Okay, that's the quick demo of what that looks like. And now back to this guy. So, what does it do? It creates a flutter workspace, clones the flutter SDK, sets up a local flutter SDK config, sets up a local pubcache, fetches defined artifacts and installs runtime dependencies, clones defined repositories and creates a setup environment. What's in a workspace? Flutter SDK, a sandbox flutter SDK config, sandbox pubcache, platform setup, runtime binary, required dependencies custom, excuse me, device config, and then development repositories and OBS code launch.json. So, one install method from the AGL source tree. So, there's a configuration on meta flutter that's specific to the targets that I build on meta flutter and the configuration is specific to meta AGL flutter when working with targets there. So, it's locked to the flutter SDK version that AGL is locked to. So, meta flutter is typically going to be locked to a newer version than AGL is. This is an install method to get the tip of tree. The script options are listed as follows. So, using this script, you can effectively just pass in the flutter version and it will update your flutter version for you and pull down the debug flutter engine required to run and allows you to quickly swap versions. So, if you have a question like say your team is fixed at 331 and you're not sure about compatibility, someone can run the script, bump it up to 337 and see if everything still runs and works. That's pretty handy. There are some setup caveats with this script. So, Flutter IDE tooling does some things like file watching and they do automatic triggering and it can't interact with if you're updating a repository to a different commit or something like that then all of a sudden the IDE which has potentially a different flutter in its path will then attempt to do some things with it on the wrong version of flutter while you're trying to install one. So, the approach is you basically create your environment externals here tooling. It's handy to create a terminal window and visual code but I suggest not doing that. Multiple flutter's entry in a system path. So, the script will remove the first occurring instance from the path that resolves. It's possible to fake it out and have like I've seen a scenario where someone had three flutter instances in their path. They weren't, you know, and so that was a problem and so we had to go through and clean out all the instances and then that fixes the problem. So, your host machine is expected to have hardware hypervisor support. This is old actually. We check in about a week or so ago, hit dynamically checks for the SVM CPU support and sets that automatically for x86 versions for ARM64 on M1. It's enabled by default. So, debugging on flutter auto desktop. The demo I provided a little bit ago showed that working. So, I'm in a, so GDM stands for known display manager and by default you can, it'll run in X11. If you have Fedora by default it'll run a Wayland session. So, you have to manually select Wayland depending on which version or Ubuntu you are. In the login screen there's a little gear symbol.  Thinkpads with Nvidia hard discreet hardware are a lot of fun, but it works. You just have to do some searching on the internet. So, you log in to your Wayland session. That's sort of expected for people who are working on Wayland to understand how to set that up. So, login via GDM Wayland session. Open a terminal and type source flutter workspace. It's implied that set if it's not, you would now, you know, select the directory and then set up your environment. Then navigate to your favorite app, flutter run, and then device name desktop auto. So, the demo I did is gallery. And then debugging on the AGL QMU image is a little different because you do have a SSH connection on a given port. So, you open a terminal, you source your environment, you type QMU run, you wait until QMU image reaches the login prompt, and then you make sure you have connectivity to the target at local host and make sure that your known hosts are happy. So, if we look at that scenario here, all right, go into an application I want to run on my AGL QMU. And so, if I want to find out which devices are present, I can do flutter doctor-v and it will list out at the end the connected devices. So, using that second column there is the device ID. So, if I say flutter run device AGL QMU, it will then say we're still working on this part. Looking at debugging, you've seen Visual Studio Code. So, looking at a command window that has it set, the environment, we can simply open that up directly and take a look at that. So, on this one, it's created a VS Code launch file and notice the different entries here. Pretty much it takes everything in the config file and makes a target for each given repository. So, if each whichever repo listing has pubspec path set, which means it gives it a valid path to the pubspec YAML, then it will generate a target. So, if we go into this workspace, now notice I have all these options. So, say I want to look at flutter animated background on desktop auto and debug anyway. It's building, launching, and there we go. We see that, and then I have it popped up on the other monitor. So, let's move that over to clickering. It's my dual monitor. There we go. Now, let's maximize it. And then there's controls here. Specified and men speed, max radius, fill, count. You're really good crazy with it. And that's a, there's a variety of different options on this. So, I talked about the VS Code launch. How custom devices work. This question has come up a couple times. So, in, I go to console, and if I type flutter doctor, there's verbose and very verbose. When I type dash v, I got a list of all the devices. If I type dash vv, I got a whole lot of more stuff. It becomes very verbose. Notice there's some commands intermittent in there. So, it, what that is is some of the output of the ping. So, inherently in the tool chain when you have, so if I say flutter config at the bottom, there are a series of settings. Notice that custom devices, enable custom devices is true as is Linux desktop. So, those are the only ones enabled. And by default, when you run this flutter workspace, it's going to persist, right? Because there's a sandbox.config folder, and then I update the xdg home path unique to this environment. And so, these are independent of what happens in the user config. So, in the home folder.config, it gives it a sandbox home, and that's where these exist. So, if I go and open a new terminal, and then I, let's just say we look at lsconfig. Let's do tree config. There's a lot of things that are stored here by the flutter tooling, right? And everything is to do this. So, there's some of that. And the other thing is, the pubcache is also sandboxed, right? Meaning, it's within the container of our workspace. So, the config that has to do with what I type flutter config, it's interacting. See, I'm in the, I haven't set my environment. So, we'll go back to where the environment is set and look at our config. So, I have multiple items enabled. So, as long as custom devices is enabled, it'll attempt to query and ping them. So, the best place to take a look at the interaction with custom devices is with visual studio code. So, let's take a look at that. So, here we have a view of the flutter workspace, the root. I've opened the root up, and this flutter workspace config is what I use to create my workspace. And we notice, for instance, in the top one, desktop auto, this is a custom device that I interact with. There's a section on here called, with the key of custom device, right here. And it's ID desktop auto. So, what happens is, the script will insert these into the flutter configuration of the custom devices. So, let's take a look at that under .config, flutter, we have a file, custom devices.json. And this file is managed and maintained by the flutter tooling. So, when I run the script here, it interacts directly and modifies and updates custom devices external to the tooling. And it leaves it in a state which is usable. So, if, for instance, you have, this is the configuration, this overwrite existing key value, if that's set to false, that means if it queries the custom device file and doesn't find, and finds the same entry, it won't overwrite it. So, that's just to provide some flexibility. But normally, it will just overwrite what was there already. So, if there's a change in this setup and you re-run the script, it would overwrite the existing one in your flutter workspace config. So, in here, this expands out exact, there's some name value, some value substitutions that happen in the script. So, custom device, as is, it won't show up as is. For instance, this one has flutter workspace variable. This one up here has bundle folder. These all get string substituted prior to writing to the configuration file. And then this represents the post-expanded strings, right? So, it's, this is the literal version that config just provides some shortcuts from having to type things in all the time. So, what happens, the interaction with custom devices, when flutter doctor-v is run, or flutter doctor-vv, when we see the verbose output, we see the tooling execute the ping command. And then implicitly, it's waiting for the success-rejects value. And if it matches, then it will list the custom devices being available in the flutter doctor output. And also, if you don't specify a device and there's more than one, it'll prompt with a list of all the custom devices that are available. And so, the availability is determined by this ping and success-rejects response. So, if I was running, in this case, if I were running a X11 session, and I issued this command that I'm expecting type equals Wayland, then it would, it would fail, right? So, it wouldn't list it as being available. So, for instance, on M1 Mac, when you run this, it'll execute the ping, and then, you know, it'll obviously fail on the M1, and so it never shows up as being available, even though the device is defined in the config. So, it's fine to have a config if it doesn't respond and it just isn't listed. So, in the case of AGL QMU, this one will check and see if port 2222 is open. Just, that's the gating check, right? If port 2222 is not open, that would indicate that your QMU session is not running. Okay, and in another scenario, we have this where it'll issue a ping with the hostname, right? This is, so, the Vahi daemon is configured on the image, this device sitting on the network, and so it will broadcast, you know, its name, and it will give resolve to an IP address via that, multicast DNS, and then, that way, you don't have to put an IP address. And, you know, yes, it does a query, but it also makes it portable. So, in that case, ping, this response here is what determines if it's there. And then, the same thing is going to be for this device, Pi 02W Weston. It just pings with a different hostname, right? Same pattern. This one here is saying it gives a different response. So, that's how the ping sort of establishes the configuration when you type flutter doctor dash B, or when you type flutter run and say you have more than one of these custom devices available. So, that will prompt you to enter that value. So, once the ping and response is present, then what happens when you say you type flutter run dash D, and in this case, if you specify desktop dot dash auto, then there would be the series of callbacks that would happen. You have post build, install, uninstall, and run debug. And so, in what I do in install is I effectively create the bundle folder, uninstallable, and I basically cache it and then I push it over to the temp folder. And this is in a host scenario, right? So, it's all happening in the temp folder. Another approach that I may expand that to is use some sim links that point to the flutter assets folder, which would be a better scenario than your hot reload would work on host scenario. In the case of uninstall, it just removes the folder. And for run debug, I'm invoking flutter auto with two flags. One is a JSON flag configuration, which you'll notice. We take a look at that scrolling over in the workspace. Notice that's in the workspace and dot flutter auto default config. So, let's take a look at that default config and it's passing in parameters of the cursor theme and the view size. Now, the other thing it's doing is passing in the bundle folder, right? So, that's easy. In the case of AGL QMU, it's a little more tricky. There's a couple of things going on. So, one is it's expected that you have an SSH connection available to the target to begin with. So, there's no input handling, bash input handling available with the flutter tooling. So, you need to externally pre-connect to the device and ensure that it's connecting. So, in this case, I created a copy of the bundle folder off into a location. And then I talk to the QMU instance and tell it to delete the password for AGL driver. So, this allows me to, because AGL driver is the user in the case of the OS where you log in, you have root and then you have AGL driver. And if you want to invoke applications and have it show up with the compositor, you need to be as user AGL driver because there's, you know, the XDG runtime directory and the Wayland display are set up. And the AGL compositor is running under AGL driver most importantly. So, and then the uninstall that just is running a batch command as user driver. And it just removes from the temp folder where it gets installed. And of course, when you're debugging on a device like this, hot reload isn't necessarily an option, right? Because you have a cache file system unless that gets updated. So, in the case of install, again, using the same pattern, talking to port 2222 as AGL driver, makes the folder and then copies it over using SCP and then good to go. And in the case of run, so this dash t dash t, double entry, what it does is when the session is lost, the TCPIP connection slash SSH connection is lost, it'll actually terminate the process, the SSH process. So without that entry, if you have a connection and then for some reason something you shut down one side of the connection, you have an instance running on the target and then if you try to reconnect, you have a failure because something already connected. So this dash t dash t is there to ensure that it cleans up nicely. And then when you reconnect, you don't have that problem. So in this case, we invoke two things. We have, again, a JSON config and then the app name. And then we have to set the observatory host to any IP address that allows us to talk to it remotely. And then it sets the observatory to a fixed port of 123. And then in this case in AGL, we have a default config and that one's a little different than the other. So it's context specific. We got the background pane and then it's setting it to the default size, you know, the standard AGL size, which is 1920 by 1080, and it sets it to full screen. So that will do a full screen for us. And then back to the Flutter config. What else can we show here on this pattern on the remote ones is the same effectively. We're just not specifying a predetermined port, right? So in the case of QMU, which is right on the host, you know, the QMU session, you have to set up the firewall such that this will talk to it. So in the case of Flutter workspace config, the other element is on the QMU session. We have it broken down between ARM64, Darwin, Ubuntu, and Fedora. And effectively the primary ARG. And so we have ARGs, X86, ARGs, ARM64, QMU image, so image name, a kernel name, in case of ARM64. So on the suffix determines the variant, right? So they're treated independently. And the commands that show up in setup underscore ENV.sh are derived out of these key values here, right? So the combination would be, you know, we have the base QMU command and then the ARGs that are specific to X8664 and then, you know, QMU image. So between those and then you also have, depending on what it's running on, then get some different flavored flags too. So if you're running on the M1, you get the base command, the ARGs, and the kernel name, and then the QMU image, and then you get the additional Darwin flag set. So the resultant output in the case of M1 looks very different than on the X86, etc. So that's how I'm handling the variations on that because each platform has unique requirements around QMU. So in the case of the base arguments here, this is the firewall setup, right? So we specify we open up port 2222 and we also open up port 1234, which is set up for the observatory. So between these two ports allows from, you know, on local host to talk to the QMU image. And those values are effectively the same in the case of the M1 setup right here, right? 22221234. So the axis pattern is the same when you're running on the local host QMU session between targets. So I think that covers the, you know, how custom devices somewhat work. Right presently, the debug scenario is only supported, so profile and release are not supported. That's on the author of the feature and myself have discussed this a bit and we're going to do some work on this in the upcoming quarter around supporting additional modes here. So right now, you know, when we run and debug and talk to a device, whether it's on host or remotely, it's to talk to it for debugging scenarios and the setup for profiling is largely interacting between the Dart VM and the web browser, right? So those, that activity really doesn't necessarily require the debugging. You're not going to single step and, you know, profile. The profiling is about running it full bore and looking at trace data, so sort of different use cases. And in the release case, you know, there's no debugging information, so you don't need to transport.  So, and that, so we, yeah, custom device is used to update and set the config flutter custom devices. And then there's that interaction between the QMU and that's about it. Like the string substitution shows up in there just to make it smaller and easier to read and prevent having to type things over and over again. And yeah, so that covers that. Kirkstone tools is the authoritative repository for this script. Everything that, and ultimately what you would want to do is keep up to date with this script here, not your config. The config may evolve depending on what features get added. So if like, Artifactory support and some other things get pulled in there, then it might, you might want to update it against one of the reference configs. And here's the Garrett for Automotive Linux. The metagl develop. This is where you would find information on how to use Flutter workspace automation with Agl images. That's instructions specific to Agl. And then this last one is the Flutter like generic knowledge of using custom and betters. So the labs side of a Flutter workspace create Agl Flutter application debug it using CLN and debug it using Visual Studio. I didn't run through that a bit. I think I'll leave this up to the to the viewers. This is could be homework. Best way to learn something is by going through the motions and doing it. So it's well documented. Okay. And this is where I talk about the Linux GTK and better. I get a lot of questions about this. Well, I think there's a lot of confusion because there's so many sort of variants of the Flutter and betters. So the Linux GTK and betters. Yes, it's a what Google, the Google Flutter team considers it a first party platform. So canonical is the primary development partner for the GTK and better. The Flutter SDK only supports host only builds. So there's no cross compilation support in the Flutter tooling with the Linux GTK and better. Now, I met a Flutter I do cross compile the Linux GTK shared module. So in theory, one would be able to pass in the right parameters in the Flutter SDK. With a CMake tool chain file, you would be able to cross compile comments on the Linux GTK. I'm better is that the runtime library dependency list is very big. I would consider it applicable to desktop class processors. So there's a lot of extra stuff in it that is a bit overkill for an embedded application. While you could make it work, sure, it's quick and easy and you can do cross platform development and it all works great and you can use some plugins, but your performance on an embedded device is going to be less than stellar because it requires X11 and among other things. So it's not an optimized experience for embedded Linux. Flutter SDK support is missing to consume artifacts. So meaning when I generate, when I cross compile the Linux GTK components, desktop components and then Flutter, it generates an SO and gen snapshot and a couple other tools required to create an AOT. But the Flutter SDK tooling does not support that in any way yet. So I had some dialogues with the area owner on the Flutter team about this and basically the pushback was generate a design document so we can talk about this platform views. So platform views is sort of a quick and easy way to get you some sort of external surface interleaved with your Flutter hierarchy. Now there's been a longstanding issue that Chin made open a while back that discusses around the horrible performance of platform views. And effectively what happens is the, using a platform view can decrease your frame rate dramatically. So what happens is if you look at your widget hierarchy, depending on where the platform view is, one or two of them halfway down, it may have to stop that render pass, go out and fetch it and then continue the rendering. And depending on how it's done, you can typically see half of your frame rate drop. So if you were targeting 60 FPS, you can easily see 30 FPS with platform views and your CPU time would go up. My general recommendation is you want to avoid the usage of it and Flutter Auto does not support it for this reason. Flutter Auto is about being an integrator toolbox best in class sort of giving you an optimal path forward without compromises and we're not trying to please everybody with it right now as a solution. We're looking for creating experiences that will please and delight the consumer and sluggishness and other things like that are not on that list. Platform lit channels. So that's a dark and native code bridge and approximately adds around 10 milliseconds latency per message. So some things are, you know, if you think about your architecture of how you implement something having this everything serialized through this bridge and then having this overhead and it's not a really good combination of things. It's suitable for life cycle calls. So if you want to set up and tear down objects and things like that that don't happen in a high frequency or to support pre-existing platform constructs like tying into some platform channel things that, you know, are low frequency and maybe like platform info or, you know, a handful of things or trigger a launching the browser, things like that. Foreign function interface, FFI. This enables calling native C APIs from dark code and encourage zero latency. There's no message passing. In terms of platform channels, there's no async, await on dark, no garbage collection. This is the preferred model, right? So what you can do is you can use platform channels for the life cycle of your FFI or you can directly just FFI load it up depending on the actual use case. First party Linux plugins. So first party Linux plugins are only intended for Linux. GT came better. The use of the term Linux plugins was poorly chosen, in my opinion. In no way does it mean that first party Linux plugins work with any Flutter embedder that runs on Linux. That's where probably the number one confusion happens in the community. Like if there's a matrix support matrix on this plugin and it says Linux, what do you mean you don't support it? Well, what it should say is GTK better, you know, instead of Linux. So it's sort of a poor choice for how I'm branding that support. It should really be first party Linux GTK plugins. The fact that first party Linux plugin dark code runs and Flutter debug builds as a Flutter bug in its track here. Some solutions involve forking the Flutter SDK to support a custom plugin type, not a Linux. In my view, this is not a long-term solution. RIN drops the frequency of how that Flutter SDK changes. This is really not a good choice because it incurs such high maintenance overhead that it's not terribly practical. Huge amount of busy work. So it's basically cost to ownership goes really high. I look at solutions where you decrease your cost to ownership and you decrease your NRE and etc. So this is one here that I don't think is a good near-term. Well, it's a near-term solution, but it's also not a long-term solution. Bill environment. So the Flutter embedded build environment comprises of Yachto layers and some source code. So Yachto layers, Meta-AGL demo, Meta-AGL develop, Meta-AGL Flutter, Meta Flutter, and then Flutter Auto. So Toyota IVI Home Screen, AGL branch is what's currently used. Meta-AGL demo, a Flutter image, AGL IVI demo platform Flutter image has runtime equals release and a series of Flutter apps, Dashboard or HVAC. That's a typo. Navigation, media player, Meta-AGL develop. This holds a handful of images. AGL image, Flutter runtime, debug, runtime, profile, runtime release. So for these, you really like, if you're doing a debug workflow, you don't necessarily want any applications installed. So your debug build would have no apps installed, and they would all originate from the host via a custom device connection. If you have a runtime release, then either build the AOT externally on the host and then SCP it over to the target to run it. But what you, the general approach is you want to avoid mixing up when you're running a debug versus a release build. So release build, an AOT actually compiles the dark code down to machine code, whereas in a debug it's interpreted. So it's far less performant.  I'm not going to show them a debug build. Like, that would be not a good thing. You would only want to show them a release build. BBaPens and MetaAgeal Flutter. So it disables the GStreamer build flag for Flutter Auto due to the commercial licensing requirement. Enables network access for an archiver and adds a user service for Flutter Gallery. And then MetaFlutter, the other last yachto there. This is considered the upstream. Flutter have bundle structure. So what this is is a folder structure that all the embedders that are present on MetaFlutter support and it's modeled after the GTK runtime folder structure. So when you build a bundle, like Flutter build bundle on the command line, you end up with a build Flutter assets folder. And that is not the exact same structure that you need for running the device. So you can create this with some sembling. So there's a right of ways to do it. But this structure enables a number of things for each embedder. It allows you to do overriding system libraries and things like that. Easy swapping of versions, which I do take advantage of in the Flutter workspace automation. And the recipe is DevTools and MetaFlutter. We have DevTools, Flutter REST bridge example, membrane example, and then REST Proc2 support. This REST support item is the workaround to enable. Well, it's sort of seen as the official solution right now. Actually, there's been a long going issue on MetaREST on this. The approach is you do a BBA pen and you reassign the source to be the test standard lib, which has Proc2. So that is there. And the above two items are REST based projects and they require them. That's why that's there. In the graphics recipes, there's a handful of apps. Trying to pull in things that are relevant. So AGL Flutter apps are somewhat of a sandbox on things that might be changing rapidly. But that's where I tend to lock things. These are all locked. None of these are auto-revved. Flutter apps. Yeah, if one pops up, I will add it. If someone has a recommendation that they think is useful for a functional test, like the animated background one, it's great for just sort of showing a bit of how the efficient GPU is on the target and looking at your CPU load versus the performance, et cetera, on your frame rate. So the Flutter REST bridge, the membrane example, those showcase the model of using FFI with zero copy scenarios. So those are highly, membrane is highly performant. And that's what Toyota, we use as the baseline for our FFI work. The Flutter test video player is the first-party plug-in. And another example where I have some implementation in Flutter Auto that talks the language of the first-party plug-in. So secure storage video player are two of those. The other recipes are Flutter Engine, Flutter Pi, Flutter SDK, Sonia Batters, Toyota. So for the Toyota recipes, there's two. There's Flutter Auto, which correlates to the AGL branch. And IBI Homescreen, which correlates to the quarterly release. So IBI Homescreen on Toyota Connected's GitHub is moved. The main branch is moved to quarterly releases. And the AGL branch has no restriction. So there might be some cherry picking from the AGL branch to main. And vice versa, but it's just the cadence of that update. So major features will be coming in on IBI Homescreen, which then would get pulled into Flutter Auto, the AGL branch. So the tooling, Flutter Workspace Automation. And again, it's the authoritative repo on this script. The Kirkstone CI jobs, Dunfell CI jobs. Try to get a representative sort of swath of devices. There is some, there is no issue around IMX6. And I believe it's the Dart VM has a problem with the tuning that a particular DSP passes in. And so that, you know, IMX6. So there's always a trade-off. If you go as low-end as you can, you're going to have some NRE to deal with problems. And the general recommendation is, well, you can. And if someone forges that trail for you and sorts out the problem, then it's available. But yeah, the cheapest one on this list, I think, is the Raspberry Pi Zero 2W. And that can run a 2K display easy with no latency concerns or any problems. It's a very high value. And then the most expensive on this, I'll let you think about that. Honestor, this was the point where I was focusing on making Vulcan work on RPI 3 and 4. There's a driver that exists for 3 pre-4s. It's not 100% compliant, but it does most things. Like it'll play Quake and whatnot. All right, the flutter auto. Last component of the build area is ABA Home Screen. This is Wayland-based. So it supports the ADL shell. Up to V2, V3 is coming. Before the end of the quarter, XDG shell, stable. So the model here is the same code runs on desktop and on a target device. So there's no pound defines about either or the only difference then really is the graphics stack, right?  And there's plenty of variance between implementations there. MultiView is a feature that allows single process, multiple engines per surface. So, well, an engine per surface. So you can have multiple surfaces all with its own engine instance all running within a single process. Similar to how fusion is it. Back-end support at compile time, not runtime detectable. The point is to shrink down the executable. EGL and Vulkan has a very flexible configuration front-end that involves JSON and bundle override logic. And recently, I've added a feature called Compositor Surface Plugin, which I'll have a demo of that. Here's an example of the Compositor Surface Unit Test Case in action. There's three surfaces, Wayland surfaces here. One is the gray, one is the flutter that's running a Vulkan back-end. The one on the left is EGL. It's a map box instance and the Vulkan PBR on the right. So two Vulkan surfaces, one EGL. In this scenario, I'm exercising the constructor and destructor of the map instance. And that's two EGL surfaces simultaneously in a single process. So, single process for everything. And more. So, some of the command line options for Flutter Auto. So, this is all pretty well documented in README for the source tree. And you can either do manual overrides on the command line or you can specify them in a JSON config file. And then any parameter you pass that is not consumed by the argument handlers, they get directly passed to the Dart VM. So, it's easy to pass things to the Dart VM directly. So, the parameter loading order for JSON. So, there's Vue global and then CLI. So, Vue is defining a window effectively. And within the window, you know, it's on context. And then you have the global umbrella over that and then CLI above that. So, first it'll look at Vue specific parameters. And then those get overwritten by global parameters in the JSON. And then all of that gets overwritten by CLI arguments. So, if you had a multi-view scenario with four windows and you wanted to change one parameter on that, you could do that via CLI. Just append the command to a command line argument list and it would override whatever was in your JSON. So, the bundle override logic will... So, you can basically create a structure where you kind of multiple versions of the same app or bundles. So, you can have one bundle that ran, you know, 3 through 7 and you have one bundle that you could run 3 through 1. So, each of those versions require a specific ICU DTLDAT and each one requires a little Flutter Engine version. So, those have to match what it's built with. Right? So, this allows you to sandbox each app independent of one another. It doesn't have to always use the Flutter Engine version in the system folder. If you built a fresh image with OS and you owned all the apps and nothing changed or moved, then it would make sense to just use a system-based Live Flutter Engine data. So, which is the default install. So, the default build flags for Flutter Auto. There's a few of them. So, it's componentized in a way that you can effectively just turn off all the code that you don't want or you don't need. And by generally, it's better to do that. Although, if, you know, you have an app now and then you want to introduce some functionality later that depends on one of these, then, you know, obviously we want to enable that as needed. So, the CI jobs on this are located here. And when building the source, the best reference for figuring out how to build it is looking at the CI job. And in labs here, running Flutter Apps, Auto Run Flutter App using a system service, MultiView and Run Flutter App and Runtime Profile Image. So, we have these laid out nicely. So, here's the case of MultiView. So, in the JSON, you specify, so each one of these views, it's an array of views, right? Each one here is specifying the bundle path, the window type. This is in the case of the AGL compositor. So, you can specify different panes in the AGL compositor which you wanted to pin to. So, in this one, this is a single process Flutter Auto instance with this configuration. So, they'll put an app on the background pane, the panel top and the panel left. And they're all independent apps and they all have different sizes. Accessibility features is just, that's saying, enable all the bits for accessibility. So, like, there's flags in there where you can turn off motion, like fast motion and things like that that are applicable to automotive. So, you can have a, and then you can dynamically change that as well. Here's an example here where the lab walks you through it. This is running the QMU at AGL image. So, you can see in the background, it has the pump fuel app. On the top, we have the animated background example right here. And on the left, we have the EGL texture test case, right? That's just rendering this with GL. So, and then this shows you how to do, set up a profiling instance on AGL. So, this is what you end up with. You can effectively profile it, right? So, under the CPU profile, you can enable it. And then it will enable, so what happens in the profile images, you have trace markers that are interspersed throughout the code which are enabled as part of the build flag. And so, that allows it to work with a CPU profiler.  It's a listing, similar to like Windows ETL tracing or something like that. And then, it allows you to look at latencies and interactions at a much lower level. So, very useful troubleshooting tool when you're working on the finer nuances of a, you know, UI design. And here we are to the resources. I highly recommend docs.flutter.dev. That's a great Flutter development info. The Flutter Wiki also contains quite a bit of information about the Flutter engine that could be useful. And in general, Yachto, Metaflutter, heavy-eye home screen, et cetera. The AGL compositor information is really great. Documentation on automotivelinux.org, I recommend that. And that concludes the presentation. So, thank you for your time. I appreciate your attendance. And any questions, please feel to reach out to me at joel.vanarska at gmail.com. Thank you.


This, we can look at the starting line up for both these teams and we're gonna settle with Happy Grove here. Shadeh and McLeod is between the six. We believe that they are going in with a back five here. Javor Lawrence, Renako Rameke, Naran Murray and Dante Burke and Mario Barclay in the middle of the park. Son Williams, Jabari Ellis and O'Shayn Chambers and two up front, 24 goals between them. Chevron Miller with 20 monetism with four goals as well as six assists. Yeah, looking to unleash his wingbacks here, Happy Grove and yeah, Chevron Miller, a player he almost didn't have for the season but he's here with him and 20 goals to the good. Almost been taken away by Mon Pleasant but he's here. Let's take a look at from technical starting line up. Oral Davis is between the sticks. They have a back three of Jamil Gale, Jamar Grant and Uriel Lempad in the middle of the park. Javani Williams, Wayne Monnings, Kenmore Brown and Chris Mark Clayton and three up top, O'Brien Reed and Dwayne Watt with four goals and ten assists. Beside his name, Stevon Spence has 22 goals so far this season. They're number 11. Yeah, very exciting players. He knows where the goal is and don't have to say much. That's 22. As we take a look at the full-time highlights here and Happy Grove, they had their chances, especially through Chevron Miller but the captain wasn't on their A game today and here's the ball that came inside and Nemhard did well enough to just bundle that one over the line. Keeper just wasn't strong enough. It was the start of a long afternoon for Shadeen McLeod in goal from one nil up. Then the ball over the top. Some good work on the left. Came across to Watt. Spence was making his way in the middle and guided that header well to the right of Shadeen McLeod. What a ball from Watt. It was his 11th assist of the season and Spence was ecstatic with that. Spence is the first goal of three and then this one over the top. Devon Williams had a really good game and a blasting that one. Well, the defender was in the way. Some really good work by Dante Berk, who had a good game as well. And this attempt, a missteer defensive header over the top and then here's another chance and the keeper making a meal of it. You reckon that he could have held on to that one Omar Davis. Oral Davis rather. And now the long ball tried to beat him skillfully. McLeod was off his line and then there was the lob that was just wide out of the markets. Happy group tried to get back into the contest here. Actually missed pretty comfortably in the end. Devon Miller again wasn't sharp at all. Then Williams firing that one right into the corner and McLeod had to move smartly to his right to dig that one out. And another effort from distance. It really was a grass cut to that one. Just missing. And then Spence probably the easiest goal he scored all season. Deliver coming in from Wayne Mullings and he was right, right at the doorstep. And just touching that one home, getting a second of the game. And then another chance and cleared off the line pretty much Miller again with the opportunity on another day. The early score would have had a hat trick here. And this goal pretty fortunate, but it would complete his hat trick here. And he was in an offside position when the ball came from off the boot of the midfielder there. Yep. Didn't get back in time, but Spence didn't care one who did he. That was his hat trick. 25 goals on the season for the sharpshooter. And then Williams' effort again from long range. He was having fun. But no smiles on the faces of the happy growth players as from technical with 19 shots, 10 on target happy growth with 16 shots. Just three of them were on target. And you can see happy growth with the advantage in terms of the corner kicks 8-6 at their custodian having to make some six saves. Shadeed McLeod and from technical with the majority of the possession at 60%. It's not time for a water man of the match. And it goes to none other than the hat trick hero himself, Stephon Spence. Here with the water man of the match, Stephon Spence. Congratulations. I think I can call you a hat trick hero for today. Tell me how you felt after scoring the third goal, because I saw you dancing on the field, so you looked a little happy to me. Well, I felt great going into the final this season since my first year, my second year of the Ducasta Cup. Well, you were walking over here a while ago, limping a bit. You have an ice pack on your hamstring. What's going on? Well, it was a slight injury, as you can see in the game, you know, hamstring. And that's why a coach had taken you off? Yes, miss. Well, will you be ready for the finals? You have a little over a week to get ready, so... Yes, miss. I don't know. I have to put in the work, miss. I'll come again. Well, let's see what work you do and see you in the finals. All right, miss. And now we welcome the coach of happy growth, Mr. Vin...


She is a WordPress engineer at XWP and she also works for the WordPress project as a documentation lead. She's also been documentation lead for WordPress 5.8 release and she's also working on documentation for the next releases. And today she will use and show you how to use and not talk about WPCLI which is a common tool, line common tool for WordPress. So please give a welcome to Milana. Thank you for coming and thank you to everyone who's going to watch this later. I was going to, come in, come in please. I was going to wow you with my bad Italian but we don't have time for that. I'm usually, I need more than 30 minutes so we're going to squeeze in. So WPCLI is command line interface for WordPress and today when we have so many command line tools like Git and NPM and Docker and Composer, do we really need another one? Of course we do, yeah, because it's, yeah we need, because it's fun. And WPCLI is not only the most powerful tool you can use to do things to WordPress. It's also very fun and not scary. I'm going to show you. So the great thing about WPCLI and all CLI tools is you don't have to use it. Come, come. You don't have to use it right away like a pro. You can start low. You can start with few commands.  So the way I see using WPCLI is like first level. When you install WordPress fresh without any plugins, just default. Anything you can do in dashboard. You can do in WPCLI as well. So everything the same you can do. And this first level I like to call gilfoil level. But then you want to do more. You want to list Chrome jobs. Everybody does. You want to import, export database. In dashboard you need plugin to do that. You can't do it just out of box. But with WPCLI you don't need any plugin. You can do it just out of box. So now you see it's the same. It's not competition. Okay. So this level I like to call, see, Piper level. But then you want to do more. You maybe want to export just parts of database. I needed that. I need to export only posts and only published in past six months. And nothing else. No options. No users. Nothing. There is no plugin to do that. But with WPCLI you can do that. And there's another thing you can do with WPCLI. You can use a command scaffold with which you can create plugins. You can scaffold plugins. You can scaffold themes and taxonomies and post types and many other things. We will see that later. So there is no plugin for that. There is no way to do that in dashboard at all. And with WPCLI you can do that with just one line. So you see it's still the same, right? Yeah. Okay. And this level is your level. And now you think, okay, so we came to the level where you can't do anything in dashboard and you can do it with WPCLI and you think that's all? No. With WPCLI you can scaffold your own custom WPCLI command.  So imagine you get a new project.  But then you look further and you see, oh, there is WPCLI available. Now you're flirting. Stop it. But then you search even further and you find that this hosting company has their own custom WPCLI commands to do stuff in their servers fast and just in seconds. Now that new level of awesomeness is Mr. Robot level. Now I convinced you you want to use it. Okay. I'm totally with you. And I don't have computer or server without it. So I cannot show you how to install it. But there is a very good documentation about it. Okay. Let me just write. So what you need is three and a half commands. But really what you need is one command, this one. With this one, you download WPCLI and it's working. With this half of command, you check if it's working. But you don't want to type PHPWPCLI par every time you want to run commands. So what you do, you make it executable and then after that you move it to a place from where you can execute it. And that's somewhere in your path and you can call it like this. This determines how you call it, sorry, WP. The end of that is WP. That determines how you call it and you can call it whatever you want. Just keep in mind that once you install it, you will do a lot of copy pasting from Stack Overflow and documentation and it's going to start with WP.  And now we can start using it. So if you type WPINFO, you get all the info. Can you see it? You get all the info about your system. So I have Linux, I have PHP 8.2 and you get the part of all the things and my WPCLI version is 2.7. There will be 2.8 in May. So, I usually get a lot of things like well, you have to memorize the command. No, you don't. There is help. And with every CLI tool, you don't have to memorize anything. There is help. There is also tab completion. So if you start typing, I say WP and tab and I have all the commands that I can use. Okay, so that argument is off. Also, there is argument like well, you have to type it correctly. Well, you have to type PHP command correctly. So let's stop there as well. Okay, so how to memorize things easier? With WPCLI, you have WP or whatever you call it, I recommend WP. Then you have none. And this is the entity that you want to work with. There are a lot of entities. After that, you have verb. Now, you will find that a lot of entities have the same verb like add, create, remove, generate, and you will learn at least, the list is very useful as well. So you will learn this by using it. And if this is not enough for you, if this is too generic, then we have flags which are actually parameters or arguments and you don't really have to use, to memorize any of that because every time with every command, with every sub-command you have help at any moment available. So you can see all the parameters and you can see the whole documentation in your terminal. You don't have to go, you don't have to be online. You see all of that and you see also some covered examples there, how to actually command examples, how to use it. So everything is here. And now we can start. I will show you also the most favorite global parameter in the world. It's the best. You're going to love it. And it makes you not memorize anything. Now, you get a pattern that I don't memorize anything. So, let's start. I want to talk about today about doing some administration, making it faster and fun, also security and also some development. So we're going to start with administration. So, imagine this scenario, you had a client, they didn't call, didn't write for a long time. But then they said, they send you email and they said they can't access their WordPress install. They tried to, they can't login. So they tried WP admin, they tried login, they tried everything, and they can't access it. It just keeps sending them to 404 page. And this is because you're smart and you changed the login URL, right?  But you said to your client when you, like, quitting your, when you were finishing the project, you said, okay, change it again so that even I don't know it. Let's pretend they did it. Okay. So they changed it and nobody in the world knows what is login URL. And now, after so many months, you have to find that login URL. So you have two options. You can go and search through database if you have access, which is pouring, or you can run one WPC-like command because we live in a perfect world where every server has WPC-LI available and you have SSH access to it, right? Okay. So you can use alias for that. And how can I know if I have this alias? Well, I can type WPC-LI alias list. Now, you see list, that's a verb. Now, alias is not a command connected to any WordPress install you have in your local WordPress. It is your CLI configuration. So what you configure on your computer, that alias you have on this computer. So if I list it, I have here my client. And I can show you right away like going SSH and Milana at Milana.dev and minus p. So you could do this, like 5, 5, 6, 5, 6. And I go there, yes, this is my imaginary client and if I... Let me put this up. If I go here, info, right, I have... It's a bit old version, but it's going to work. Now, that's possible as well, but the problem is I don't memorize things. I don't know that port number. I don't know even where is the file of that port number, right? I don't know if I have that file. And you can't really log time and, you know, put on your invoice like I've been searching for password for two hours. You can't do that. So you can use alias and I show you how to list alias. So you saw that I used the same thing to log in to my server. So connection here is what is important and what I'm not going to show you, which is like basic administration. I have created a pair of SSH keys, I've written public on my computer. I connected it to the server, which is my imaginary client. So there's public key and we did the first shake and that's it. So now I have connection and now I can create alias with WPCLI. So how do you use alias? Let me show you again that list of alias. So here's at client. And you see this one? It's created right away when you create first custom alias. So if you want to run commands in bulk, but please don't overdo it, you know, you don't want to do. But you can actually create alias for a group of websites. So if you have like local production and staging and you might want to update core at the same time. So you can do that or, you know, whatever, Roxy or both. So I have client. I have these, the connection that is created. So what I'm going to do is WPCLiant. So you have WPC alias name and then type command as you would without alias. So let's check the core version while we are there. Oh, it's outdated, right? So we have to update it now. I'm going to say WPCLiantCoreUpdate. Now, if I wanted a different, a specific version, I would say dash dash version and then equals which version. And if I was going backward from the, what is currently the latest version, I would have to say force. But I don't have to. And I can show you that later. So let's just update this one. Look ma, no hands. You don't even have to go there. But I would suggest you go. Right. So this is updated. Let me show you how you would do with the different version. So let's say version equals maybe I want 5.9. I don't want to break it too much. And because I'm going backwards, I say force. Look ma, I broke it. Right. So it's successfully updated to the lower version. Here it is. Okay. But we are not here to do this. We are here to find that login URL. You forgot already. Okay. So what I'm going to use is a command. I use too many times to admit I love it. It's evil. And it's not evil. And what it does, it executes arbitrary PHP wherever you type it. So I'm going to say echo. And I happen to know what is the function for getting the WordPress login URL. It's called WP login URL. And this is enough. What I'm going to add here is just a new line so that you can see this nicely. You should have asked Milana. So this is my imaginary client. And this is how 5.9 looks like. Okay. So this task could take a lot of time. It could take, you know, you replying to email, oh, I don't have the login. And then clients say, I don't have either. And then you start looking.  And then you log in. But then you see you have to open ticket with support. It's frustrating. It's useless. You are wasting time that you cannot take money for. But if you start adding aliases now, for every website, you work on, you don't need to memorize anything. You see the pattern? Don't memorize anything. Your config file is where every, all credentials are there. Every website is there. And you will love yourself in two years. Trust me. Okay. So that's a little bit of administration. Let's talk about security. Hmm. I have some local here. Okay. And this is freshly installed WordPress like two days ago. Okay. It's 6.2. And let's see what users we have here. User list. So you see WP non-verb user list. I have admin, admin. I went with the stereotype. And it's administrator. I'm going to show you now what this administrator see. Not because I think you don't know this because it's obvious. I know that you know this, but I want to make a point. So now I'm going to use command WP admin. This command doesn't come with WP CLI right away. You have to download it. It's just one command to download it. And what it does, it opens your login URL. So why didn't we use it before? Well, it doesn't behave as expected with remote servers. So you can use it in local and I do it. And I don't know any of my local URLs anymore. So let me log in here. And this admin, this is all the things you know. So this admin has posts and categories and tags and media pages. And a team and editor, site editor, they removed better. So it's kind of safe now, right? I hope there are plugins, users, tools and team file editor, plugin file editor in 2023 from dashboard. You can edit PHP files on your servers. No, thank you. And settings and everything. Okay. And then when we go to the front end. So this is by default when you install WordPress. There is Hello World published. And default teams always show your administrator username. The same administrator that has the access to edit PHP files from dashboard. So all we need now is password, right? And WordPress website gets hacked a lot. It's not a secret. I like to think that's because we are popular. But you don't want to measure your popularity with clients' website, right? Yeah. And if we were talking about this in 2009, we could say, well, yeah, WordPress is a security home server. That's not the time anymore. Now it's code is much more secure. It's tied up and we still get hacked. It's human. Oh my God. I have 10 minutes. Okay. It's human error, right? We have easy passwords. We have clients who saw some shiny new plugin that is doing sharing to all social networks. And the plugin was like Xbox here, but they found it for free. And we know what that means and they installed it. So it's usually the human thing. And the solution is obvious here. Just remove the human, right? No, we can't remove human. We are making websites for the users. And what we can do, we can go around them. So I'm going to go around this user right now. I'm going to demote this user. So let me show you what we can do with users. Help. We can add capability, add role. And here comes the same verbs, like create, delete, generate, list, meta, remove, capability, spam, term, update. With update, you can change the password of the user. So if you want to have some fun, you know, I'm not judging. So what I'm going to do is WP user. Remove role. And now I have to tell to WP CLI which user. I can use username, email address or ID. And I have only one user, so it's ID one. And now we have no role. What that means. Let me watch this. So here we have this admin bar. And now if I want to go to dashboard, there's no dashboard because WordPress doesn't know what to do with you when you have no role. And I would suggest just keeping this password very strong because you want to keep your hackers amused. You don't want to disappoint there. And now this website is secured. Yay. But nothing can happen inside, right? And your client, well, you need someone who can write posts. So let's create user who can write posts. Create. And now there are a number of parameters that I don't know. I know I practiced this, but I don't want to know. I don't want to memorize. And I can use the most beautiful global parameter in the world. It's prompt. And it will prompt you with every parameter there is. You don't have to type anything. You don't have to think about typos. You don't have to memorize what you need. You just type what you need. So I'm going to say author. This is the user name. Then this is not important because it's local. Role default is subscriber. But I'm going to say author because I want author. And user password. Now this should be very strong password. But I have to log in with this user in a minute. So bear with me. It's going to be author. Now I'm going to install it. I'm going to install it on Windows. Next, next, next. Okay. Yeah, we have user. So let's see what this user can do. Oh. They can write posts. But they cannot edit other people's posts. They had never heard about categories or tags. No pages. No editing files in dashboard. Nothing. So I'm going to install. And the other user has no access at all. And look what I can do from WPC li. I can say WPC plug-in. Install. Activate. And I'm going to say simple history. Hmm. So this little plug-in will show you everything that happened in your WordPress install. And you can see this list in dashboard. Well, not in this dashboard. I have no user who can see that. But you see this plug-in author was smart. And they said WPC simple history list, you see. Verb list, yeah, none. Okay. I see everything from SSH. You can do things that are dangerous. You can do things that will change anything that clients shouldn't change. Right? And you can do this in dashboard. Nobody can install plug-in. But this author, if it was your client, they would want more access, right? Yeah. They should have more access. So let's give them access. I can say WPC user add capability. And now I need another parameter, user ID or email or user name. And I can say manage categories. And what this does is it will give them access to categories and tags. I think everybody who writes posts should be able to create tags, right? Then I'm going to say switch teams and the same thing for plug-ins. It's important activate plug-ins. It's important to notice that this doesn't mean they can install any new plug-in or team. They can only switch between existing teams and they can activate and deactivate plug-ins. Now, when something goes wrong with a website first thing you will get from support, first thing you will get is from anyone is switch off all plug-ins and switch to default team, right? Everybody should be able to do this. But there will be no code in this install that is not checked by developer, right? You cannot install plug-in without developer seeing it. Now, there's another thing I want to add here. Many plug-ins and almost all teams and even core now is hiding some settings behind edit team options and you will find it here. So with appearance you get this not better anymore editor and many other things. There are a lot of these capabilities. This is what's important but actually gives access in WordPress. It's not roles, it's capabilities. Roles are just group of capabilities. Role means nothing, capability means access and permission. You can see that here. If you go to documentation WordPress.org documentation, article, roles and capabilities you will find all the capabilities and all the roles and everything so you can play with this. You can set the specific access because I think that's our task to find the exact right access for clients so they can really own the website but not break it. I will break it, it's my job and I will then fix it. Okay, I'm out of time. So we didn't see, this was security so we have two options. Do you want to continue or we stop here? Continue, okay, okay, okay. Do you want to see magic or do you want to see scaffold? I would like both, magic. Magic, let's see the magic. I have my magic folder here which is empty completely. And I'm going to say WP install. The database name is magic because everything is magic. Next, next, next. Windows. Site title is magic. Site URL. I hope you see it. Admin user. Admin password, you can't see that. Almost there, it's cooking. I said it's magic. But it's not done yet. Okay, so do we want to release Kraken? We came here to release the Kraken, yes. And this is our Kraken. And yay, it's another WordPress website. Yay, it's not magic, it's just a website. So, obviously this was the Bash script that you can use to make things more fun and more faster and easier for you and you noticed I didn't type anything. I just typed my own command. Okay, he's pushy. Okay, so let me show you what's in this. I'm going to use Sublime. What's in this Bash script? Here. This is important. So you start with Shebang and then you tell which shell will be used. So I'm using Bash. Then we have only five WP CLI commands in this script. It's very simple, but you can make it as complicated as you want. So we download core, then we have to create config. So you see I'm using prompt here. You can use prompt for partial prompt. So I know that WP user, WP database user will always be root because it's my local. Then I also know what's my root password, but I don't want to leave it in my Bash history. You never want to leave your passwords in your Bash history. So what you can do here see I'm for password I'm using this really simple Bash script to just hide the input and just take it from the user. Then we have database name because that's going to change from side to side. So I'm taking it here, right? And then I say thank you because I like to talk to myself. Especially through terminal. Then we have WP core install. Again, I don't want to think about this. Is it URL title, admin user, whatever I don't want to think about it. Again, for password we are using hidden input and then I'm using CDIS to just combine database name with admin user name. So I have admin email because I never want to type local admin user. That's just annoying. And then we have rewrite structure. So why is this important? If we go back to this previous site that we were looking at. So here you see URL WPCLI.Lock index PHP. That's what you get when you install WPCLI. But here I'm rewriting structure to make it what we are used to and sorry and here you see this I don't have index.php. Now this is not enough to have ability to use a rewrite command in your local. So what you need is enabled Apache module and then you can use every rewrite command and after that I have some Linux found like steam locomotive and letters and whatever and then I ask myself do I want to release the Kraken and if I want the little cow say hi and open the dashboard if I don't want I have a wonderful day. So this is very very simple and you can add here if you have like installing a lot of websites in Italian you can add it here. If you want a dummy text you can generate with WPCLI posts and users and comments and what not you try it you play with it you can also add some plugins or you know the theme that you are using so you can put all of that and laugh out loud because you are not doing this manually ever again. Now this is we didn't see all and I hope you just saw what you can use in your own projects this is just a little tiny piece of what you can do with WPCLI it's fun it's fast it's making tedious tasks that take days in minutes literally my name is Milana Tzap I'm WordPress engineer at XWP and the loudest member of WordPress documentation team if you want to talk about I'm also classical musician and I was in opera so I speak a little bit Italian so if you want to talk about any of these you can find me there if you have any questions you can find me here or you know just tweet me and thank you very much for your time. I guess we have not much time for questions because we are running out of time and we don't have so much time for the questions because in theory we could release you as a cracker to go outside to do a tour so if you have any questions and you don't feel like doing it in English I can translate it otherwise you are free. No questions? It will be around so you can ask Thank you


So thank you, Olivier. My name is Caleb Thompson. I work at Thoughtbot with Mason here, this guy, and co-organize Keep Ruby Weird. We are here to find the answers to the question, what is this PGP thing and how can I use it? You can find me on the internet here just about anywhere. So a lot of you got USB keys. Those have the software that we're going to be using today. So if you can copy that onto your disk and then pass that key along to somebody else, it also has my public key on there. So if you just copy both of those things onto your disk, we'll get to them later. This is a link to the slides because this font doesn't make it very clear, that's a zero. So I'm not going to be pausing too much in this presentation. I don't want to have to go back and forth to show some of the commands that we're going to run. All of the commands are in these slides, so I'll give you a minute to go ahead and grab those. If you are interested in, if you're already like a PGP pro, or if you are more interested in the command line, or if after this you're interested in learning more about PGP in general, I wrote an extensive blog post about a year ago now that details just about everything I know about all of this stuff. It uses the command line tools rather than the GUI tool that we're using today. But all of the same concepts apply, and it does a really good job of explaining why you're doing any of these things as well as how to do them. So we're going to be using a program called GPGTools. It's actually a suite of programs. You can download those from the internet at GPGTools.org or they're on the USB that I've given you. So this is how you would download them. That's the button. So because this is security software, we actually have to verify that the package is the correct package. Mason made the joke that let this be the last package that you don't verify, but we are going to verify it. So if you have a trusted PGP version, then what you can do is download the GPG signature from GPGTools right here. Download the key from here. Import it into GPGTools or into your favorite GPG program, PGP implementation. And then you can verify the fingerprint of the public key here and run this command on the command line to actually make sure that you have the software that you expect to have. Probably though, you didn't already have a GPG implementation on your computer. So we are instead going to verify the SHA of the package. So I've given you something. It could very well be malicious. It could, I could have given you the wrong piece of software accidentally. I didn't install from that binary myself. And so what we're going to do is check it against the SHA that GPGtools.org says is the correct one. So a SHA sum is just the simplest way to verify that the file that you're looking at is the file that somebody wanted you to have.  And maybe that person lying to you is actually a developer. So this is the command that you were gonna run to make the, to verify the package. And it's gonna output a number. You want to make sure that the number matches up to this one. So once you are satisfied that you have the right piece of software, we're gonna install it just like you would normally. There's nothing special here to installing the package. Can somebody make sure that she gets the USB? I'm gonna move on. I have helpers who are gonna make sure that you are being dealt with. Okay, so the next step is going to be building key pairs and uploading public keys.  To get anywhere with PGP, you're gonna need one of these things and it's composed of two parts. That's why it's called a pair. It has a public key which you're gonna publish and it's used to encrypt messages to the owner of that key and to verify messages from you, messages, yeah, from you to that person, to other people. So people will use your public key to verify messages that you send them. And a private key, which you keep secret and safe and it never goes on to the internet and it allows you to decrypt messages that people encrypt to you using your public key and to sign messages so that others can be sure that you made them. Algorithms that use, that separate public and private keys are more secure for several reasons. But the primary one is that the private key just never goes out onto the internet. In the case of PGP, it's also passphrase encrypted and even then, this is still not something that you'd ever put onto Dropbox or Facebook or whatever you kids are using these days to share files. If you must move it around, USB is the easiest and best way to do that. But then you wanna make sure that that USB stick is destroyed and everything else. Kill it with fire. This is how we're actually going to do this. So we're going to generate a new key, click the top left corner to do that. It's gonna fill in a lot of your information automatically. We're gonna make sure that we've picked the longest length. 4096 should be that number, but if there's a bigger one on your machine, use it instead. And then we're going to check expires, I unchecked it, but we're actually going to check it. Change the date to about a year out from now. And the reason that we do this is so that if you ever completely lose access to a key, it'll invalidate itself automatically after some amount of time. And you can change the expiration date, you can just right click on the key, your secret key, and change the expiration date at any time, you just need to unlock the key. But this means that it's sort of a dead man switch. It means that you're not accidentally leaving your key out so that people still think that it's a valid way of contacting you basically. So what can we do with this key? I'm going to pause here and make sure that everybody's got a key. All right, so now we have keys, what can we do with them? The piece of software that I gave you, automatically, if you use mail.app to send email, it's now got a couple of encryption tools in there. So one of them is to sign, one of them is to encrypt. You can now sign every outgoing email and it won't hurt anybody. And if you know that you're communicating with somebody who also has a key and you have that key handy, then you can encrypt to them and that's a good practice as well, just so that we've got more noise when the NSA is trying to crack encryption things. But the simplest thing that we can do that's not already configured for you is to sign git commits. So there's a little bit of configuration in here to do. The first is we need to tell git that we want it to sign all of the commits that we make. So from the terminal, this is how you make that happen. Then we need to tell git which key to sign with. But GPG is pretty smart. By default, it'll use the only private key that you've got, but it's still a good practice to have this in there. So I have my whole name and email address in here. GPG will find this just fine, but it makes a little bit more sense sometimes if you're having issues to just go ahead and use your key ID, which is the last eight characters in your fingerprint, which you can get by right clicking on your key to view details.  How do we do that? So verifying with git is not super difficult, especially if you use aliases. So git log show signatures is the simplest way to do this. So it's gonna print out in addition to the normal commit message and the commit shot and maybe the diff stat or the diff. It's gonna also include the GPG output for verifying when it verifies that the commit is correct. Git show will do the same thing, but just for a specific commit-ish. And then you can do git tag hyphen hyphen verify with a tag name to verify that a specific tag was done. So you'll see tags a little bit more often in the wild because it's easier to convince people that they should be signing tags than it is commits. Why would we do any of this stuff? Well, a signed commit says, I wrote this thing, here's proof. I wrote it and I thought it was good enough to include in this repository. And I've proven that somebody else didn't do this and said it was me. A signed tag says, I released this, here's proof. So it's almost the same thing, but I didn't necessarily write everything. All I did was probably run the tests and said this was ready to go, released a gem version or whatever. What this does for us is it gets your signature in as many places as possible. GPG can be configured to automatically download keys to verify signatures. And that means that you've got more ways to establish trust. So for example, if Aaron Patterson is signing all of his commits into Rails, you can be pretty sure that this person who's doing a lot of cool work is who you think tender love is. So you can say, well, I trust that this person is right, so I'm gonna go ahead and sign their keys, and then you know that anybody that key has signed, which would include me, is probably who they say they are by sort of a transit of trust. And frankly, it's super easy to do, so why wouldn't you do it? Signing and verifying gems. This is where we get into our RailsConf specific bit. First of all, there's no good way at all to do this. There is a way to sign gems, and it comes in this module, which is included in every Ruby installation over the last couple of years. It's not great. It uses some other algorithm that is, in my opinion, not as powerful. And it defaults to not verifying when you sign, or when you create gems, release gems, or install gems. So it's useless. What it does is it uses open SSL keys. So these are the same sort of keys that we use for SSL on the internet. Unfortunately, they're the same sort of keys that we use for SSL on the internet, which means that there's no centralized, there's no way to distribute them. You just get them along with the gem that's installed, or the website that you visit. And there's a centralized authority, a certificate authority. So you, so this isn't taking advantage of the web of trust that PGP provides, which is like, well, you trust Aaron, he trusts me, we're all good to go. It requires you to trust a certificate authority manually. In the case of SSL on the internet, HTTPS stuff, you've actually implicitly trusted all of the certificate authorities that matter to you by having a Mac computer, or having a Windows computer, or installing Chrome. They just do that for you. It's not a decision that you make, which is different in PGP, where you do make that decision explicitly. Private keys are not encrypted. This is not a limitation of open SSL. This is a limitation of gem security. I don't know why, but that's a thing. Keys are self-signed. So most of the time when you get a gem that is signed, it's going to be the signature file or the public key is actually just gonna sign itself. And so the only way that you can trust it is if you explicitly trust that one key. And even the root of the certificate authority has to self-sign to be valid in this silly, silly thing. Open SSL, don't use it. You need a trust path. So verifying a signature or a SHA is dearly meaningless if you can't trust that it's come from a person that you believe in. Just checking that they've signed something doesn't mean anything. It means that they know how to use open SSL or GPG. This is actually what we did at the beginning. We blindly trusted that the website that we downloaded software from was controlled by the people that we thought it was. But they were providing the SHA, the GPG signature, the key, and the software that was signed. So none of it is actually very useful. But it's the closest that we can get unless you actually know one of those maintainers. Or they're on the web of trust, which they are. So a package and a signature all come from the same source that can be faked by everyone. This is true of Gems. This is not really something that you can get around unless there's another way to also get this key. So in the case of Gems, there's really no other way to get the keys that you're verifying. In the case of GPG, we've got key servers. We've got people who upload their own keys. We've got people who give you a USB stick with their keys on them. There are no key servers for open SSL. And key servers are this basically distributed system of sort of like DNS where you upload your key and it propagates out to a bunch of different servers and then anybody can use their own server of choice to pull down a key. In the case of Gems, the keys and the cert chains are included in the gem tarball. You can't specify a system-wide trust. With GPG you can say, I will trust anybody who has any sort of signature or you can say, I only trust people who I've signed myself or you can say, if Derek says they're cool people, I believe it. Signatures are included in the gem. This is what gems look like when you untar them. So you've got each of these .gzip files and if they happen to be signed, which most gems aren't because this is difficult to do. And as I sort of made it clear, not super useful, then they include a signature file for each file as well. Required reading, if any of this is interesting to you, this gem stuff, this slide has a bunch of links on it. This is where I've distilled all of this information that I've just given you from. So sort of my citations as well. So backing up a bit, how do other people take care of these problems? Well, the most common and simplest way to do this is manually, just like we did when we installed GPG tools. It was an archive, so it's a single file that we could have gotten the shot from. And this is what most of the packages are doing for us automatically. Aptitude, homebrew, et cetera, automate this. So aptitude uses GPG to verify. Homebrew has a shot, so as long as you trust the homebrew package itself, then you can trust that the person who authored the recipe for installing a piece of software has downloaded the right piece of software, that the one that they expected to download. And RVM actually distributes Michael Pappas' personal key and automatically verifies that during installation. So to fix these problems for ourselves, we need some sort of automatic verification before installation. We should be verifying signatures, no matter what. Every time we install something, we should verify that it was correctly signed. That means that the person who signed it, the package hasn't been tampered with since the person who signed it signed it. It should be configurable to verify trust. So if I have a large web of trust myself, then I should say you should be verifying that the person who wrote this software somewhere in my web of trust. And if either of those checks fail, if you've configured trust or if the signature fails, the gem shouldn't install at all because it's not what we expect. It's not what we think it is, which means that it may be malicious. So we need stronger web of trust connections throughout the community. If we can verify one maintainer, we can probably trace paths to others. Conferences are a great way to build these cross-organization, interstate, or even transcontinental connections in the web of trust. Open-source companies could have centralized keys. So Thoughtbot actually has one of these. This is not how we use it. This is how I think we should use it and I have begun pushing for this. They should sign each maintainer's employees and contributors, so an external contributor who's doing a lot of work for us, keys. So at things like this, when we're in person, we should be verifying that we should be using this company key to verify other people, individuals' keys. And then also at these events, we can have Thoughtbot's key sign test double's key or AT&T's key, which means that if you have met me and Thoughtbot has signed my key and Test Double has signed Thoughtbot's key and Test Double has also signed Justin Searle's key and Justin Searle's release is a piece of software, you can verify with only four hops the maintainer is who they say they are and then you've got a web of trust connection. It's pretty cool. We need better tools support for all of this. So tools that we use, the big one is RubyGems. RubyGems solution is simple on paper, difficult to implement. We could use OpenPGP instead of OpenSSL. I plan to put my money where my mouth is and actually work on a gem plugin to do this to allow you to sign keys with PGP and verify them on installation. There is already a tool that does this but in my opinion it is too difficult to use so it won't see adoption. GitHub, Git already supports showing signatures. So GitHub could also do that without much more work. This is what Git by the way will output when you actually verify somebody's signature with show signature or with show log or show signatures on log or show. Having a standard way to claim social accounts. So this is a little bit difficult to see but you can see that there's a couple of highlighted user IDs on here. Both of them say at Caleb Thompson and then link to Twitter status or a GitHub repository where I make an assertion that I am the person who controls this account and this key. So by doing that you can be sure that somebody who controls GitHub and somebody who controls the key with this fingerprint are the same person. You can't be sure that they are Caleb Thompson because you haven't looked at my ID. You haven't met me but you do know that the key and the social account is connected. So connecting these two ideas we can say we could have GitHub show a badge like the Twitter verified icon that says yes this commit was signed and is correct because Caleb Thompson has uploaded his key and that key has signed this commit. It's great. People do things for badges, it's crazy but this is just a small thing that GitHub could be doing that would mean that five more people maybe start signing commits and that'd be pretty great. Signing keys. So this is, we've talked about signing keys. This is actually how we do it. So Mason is there. We're gonna need to help again. So signing a key is like signing a message. It uses the same mechanics internally but you're writing onto a signature file. It has a different semantic meaning. What you're doing is asserting that you've verified owner identity. So you've looked at somebody's driver's license or passport and the name on that document matches up to the name on the user IDs on the key. You're asserting that you've verified that you have the right key. So I gave you my key. I will later give you my keys fingerprint and with those two things you can be sure that you have the thing that I wanted you to have and you're asserting that that person has verified ownership of the key which means that they can unlock the private key and use it. This is uncommon to actually see done because it's sort of difficult but it boils down to once you sign a key you export it to a file, encrypt it and email it to the person by using the email on the user ID and then they can decrypt it, import it into their own key chain and upload it to a key server. Because that's a little bit complicated it doesn't happen super often but if we had tooling that made that easier then it could and it would mean that the web of trust is a little bit stronger. So signing a key establishes transitive trust. It announces to the world that if they trust you to verify these things they can trust the keys of the people you have signed because they are more likely to represent the people that they actually say.  You've been introduced. All of this is fundamental to the web of trust. A word that I've said a lot, I have a picture. This is a web of trust. At the center because it's mine, you see me but all of these lines are connections are signatures that I've made with other people. And the more closely we're related in the web of trust the closer people are. This one's a little bit older. My new one is taller. It's pretty cool. But it's just fun to like see graphs. I like graphs of myself and so I sign a lot of keys. But one thing that you can see here is I apologize for dotting but this is Michael's key. Michael has signed George's key. We're all co-workers. I haven't verified George's key in person because he lives in Stockholm, New York now. But because Mike has signed it and I trust Mike to verify George's identity then I can be reasonably sure that when I communicate with George's private key or public key, he is who he says he is. It's great. So signing a key with the GPG key chain. This is gonna work now. So the first thing that we need to do is get the key. I've already given you mine. It was included on the USB stick. But usually people will upload these to the internet somewhere, probably on their own server. Include them in a header on emails or upload them to key servers. And if they've uploaded them to the key server then you can find them by searching like this. So if you do command F or look up key right there, this box will pop up. You can search just about, you can basically just search for a name or an email address. It'll pop up a list of addresses. If you've got this person next to you then they can verify who they are. Otherwise you can probably guess correctly. Once you have that key, you can right click and view details and that'll pop out this side window. And what you need to do is confirm that that long string of text which you actually have to expand the window to see because software matches this. This is my fingerprint. And as I mentioned earlier, the last four digits are the key ID. So if you're searching for me you could search just on this or you could search for my name and that would get you the right key. So we're doing this now. Okay, next we're gonna right click again and we're going to sign key. It's gonna pop up a window like this. You are going to select your secret key. It's probably already pre-selected. And you're going to say that you've done careful checking from the other drop down.  And there's not really much more careful checking that you could do than to check somebody's ID. You could do a background search, I guess, but it doesn't help.  You're saying that name is the name on your screen. So the other options are, I haven't verified, or I won't say. And that means that you may, you've done some amount of verification but you don't want to explicitly state how much you've done. The level above that is I have done no verification. If you have done no verification you should not be signing a key. The level above that is I've done casual verification or some verification. That means you're not playing, are you? That means that maybe somebody handed you an ID or maybe somebody has been your friend and you are pretty sure you know who they are. You've never actually looked at their ID, but whatever, you're willing to sign. That's the level that means that. And then careful checking means that you've looked at a piece of state-issued identification. Does anybody still need this? And you're ready to sign. So signing a key is sort of like going to court and saying yeah, that person is Caleb. Don't check that, I have no idea. Also don't check the signature expires. That's more for certificate authority style things that temporarily state that you're probably the right person, so that's not useful. So all we're doing is filling out these two things and then unchecking those boxes. And we can generate signature. All right, so after we have verified or we have signed we can go ahead and upload the key to the key server. So you can right click again and send public key to the key server. So do this now for both yourself and for me. Okay, we're done. This is the end of the talk.