Thanks everyone for joining this evening, this morning, wherever you are from coming. You know, I appreciate you all coming into the Selenium Light Conference. This is kind of the precursor for the main event. Like I like to tell my team that this is kind of a test for the main event. So we kind of test if everything is in place and we can, you know, kind of go from there. So I would love to introduce Simon who's going to be kicking off the light event. I'm sure most of you know Simon. He's been the author of WebDriver, done a whole bunch of things with Selenium. I would say today's Selenium is Selenium for a large degree because of Simon's contributions. So Simon is going to be talking about some of the CI related stuff which is an extremely important part. In fact, I think of it as lifeline for most projects. So Simon's going to be talking about that today and sharing his wisdom of, you know, how this project, the Selenium project itself uses this. So without much delay, I think I want to hand it over to you Simon. Brilliant. Well, thank you very much for that introduction. I'm very kind of you. And it's fantastic to be here back at Selenium Conflite. Let's find out that everything works. As Narek said, if you've been part of the Selenium community for a while, you may know me as the person who led the Selenium project from 2009 until the end of 2021. But if not, it's nice to meet you and have a chance to talk to you. Now, normally in these kinds of talks, I introduce like new features or talk about the direction of the project. But today I thought I'd take a different approach. Hopefully if you're here at Selenium Conflite, you believe in the value of automated testing and you probably have a CI pipeline. So I thought I'd explain a little bit about how we build and test Selenium itself and why I think you might want to look at adopting some of the tools and techniques we use. Now, this here is a screenshot of the current source of GitHub in GitHub. As you can see, the Selenium repo is effectively a monorepo containing bindings with Java, C-Shop, Python, Ruby, and JavaScript in the same tree. The language bindings all share some common code, which is written in JavaScript, which we call the atoms because of the smallest indivisible unit of Bratzel automation. These are compiled using the Google Closure Compiler to create minified lumps of JavaScript that we pull into each of the bindings. The support for Chrome's own debugging protocol, the CDP, is also shared between languages with code generators wrapping the raw JSON descriptions of the CDP to create language specific implementations. Of course, not only do we have language bindings, but we also have the Selenium server in the same tree, and this is written in Java with a React-based web UI. Finally, we try and share as much of our test code as possible, and this includes shared web pages for test cases and a basic web server to set these out. As you can see here, the code is primarily organized at the top level of the project by language, and then within each language we organize by whatever seems right for that language. When we started the project, it was a little unusual to arrange a code like we do now. Nowadays, with the rise of complexity-wise written in JavaScript and protobufs being more widely used, it's increasingly common to find these polyglot code bases, that is, those with a mix of languages all within the same repo. Even if you're not using lots of languages, things like Docker and Kubernetes are changing how we perceive our code can and should be built. So Selenium is a project and code base that's almost ideally suited to being built with a build tool that can handle multiple different languages. I think more projects are starting to head into this world. Before I begin describing what we do now, I think it might be helpful to see how we got to where we are. When I joined the Selenium project in 2009, there was one person left who understood how the whole build worked. The bulk of the code was in Java, so it was natural to use Maven back then. This was great for the server-side pieces, but for the language bindings, there was an obvious problem. People wanted the APIs for all supported languages to match and keep pace with each other. To solve this problem, the API was described in an XML document, and this was transformed using XSLT into the specific language bindings. Maven would then delegate to each language's native build tool to compile and package these language bindings properly. Needless to say, there was a surprising amount of stuff that was needed to get the build working, and it depended quite heavily on the developer having set up the machine just so. Building away from Windows was somewhat tricky for the obvious reason that .NET wasn't really portable at the time. Surprisingly, the complexity of the build wasn't really a problem. After all, because of the way that Selenium RC worked, the language bindings were mostly dependent on the XSLT. Once it was working, the real action happened either in the server, which was written in Java, or in the injected JavaScript, which was shared. Put another way, if the build worked in Java, it probably worked everywhere, and that meant the only people who needed to worry about the complexity of the entire build were the ones doing a release. Now, WebDriver started in 2007 as a small open-source project independent of Selenium. I knew from the start that I wanted to support multiple different languages and that I'd need to compile them all in a single build, so I went hunting for the right tool. The problem is, at the time, there weren't really any great choices for a polyglot build tool. Ant and Maven existed for Java, but they really didn't handle Python or C sharp, well, if at all. MS Build and Nant were great for your .NET projects, but when it came to Ruby or Java, no good. So I looked around for a solution, and the one I settled on was Rake, which is a Ruby build tool. Why? Rake? Well, while Rake is ideally suited to building RubyJones, it has the interesting property that it's a DSL for describing builds, and each rake build is itself a Ruby program. That means that it's entirely possible to extend the DSL with custom types of build artifact, providing you can figure out how to express that compilation in code or as a shell script. Better yet, Ruby makes it easy to execute random shell commands. The original build for WebDriver then consisted of a single build file, which declared some helper functions, and then just ran a fairly simple build. I say fairly simple, but as the project grew and the number of browsers and languages we supported expanded, this rake file became increasingly terrifying. In the end, there was only one person on the project who felt comfortable working on it, and that was me. Clearly, the situation had become completely untenable. We needed to find another way of doing things. By this time, I was working at Google, which had a really impressive build system. The way that builds at Google worked, and I believe still work, is there are build files scattered all over the source tree. While there are a lot of build files, it's easy to see how they link together, and I mean that changes in one part of the tree don't affect changes in another. The other nice thing with the build files was that rather than describing a set of steps to perform, they contained a description of the outputs that would be produced. A Java library error, Python binary there. Each of these outputs listed the inputs it needed. It looked very much like a series of Python calls, and that's because originally they were Python calls. These ideas of scattering build files through the tree and having them describe the outputs to be built were utterly, utterly brilliant, and I loved it. So I asked if I could open source that idea, and the open source people at Google had no problem with it. By now, we'd merge a web driver and Selenium into one project called Selenium. We still use rake for the project's combined builds, and you'll remember that rake builds are essentially a DSL that executes a Ruby program. You can do whatever you want within that structure. So I did. Using a parser generator called Radle, I described the build grammar I wanted, and then I implemented that as a series of Ruby functions. The build started by finding all these build.desk files in the tree, and then used those to generate rake targets using a target syntax that looked remarkably like Bazel's does today. Once that was done, we just let rake do its thing. On this slide, you can see one of the build.desk files. But there was a problem. We'd accidentally written a not entirely awful polyglot build tool at this point, but the Selenium team has never been huge, and we already had our hands full maintaining what was rapidly becoming an extremely popular and large open source project. We didn't really have the time or energy to support a second project. So we used some social engineering to make sure that no one would try and extract and use the build tool we had in Selenium for themselves. We gave it a ridiculous name that described how much I'd enjoyed working on it, and we called it Crazy Fun. Crazy Fun was all well and good, but it had some drawbacks. We never really got parallel builds working properly, so although we could build anything, we could only build that anything very slowly, and that's suboptimal. By this time, I joined Facebook, and there I had met up with Michael Bolin, who'd also worked at Google. Now, an interesting thing with the Zootlid diaspora is that many of us missed the wonderful tooling that Google have. Michael was no exception, and he was missing Blaze, their build tool. Rather than moping, he'd created a new build tool called Buck, which was rapidly gaining usage within Facebook. It shared the concept of build files scattered through the tree, and also had a very familiar syntax for its build files. Best of all, it was optimized for speed on a developer's machine and could automatically parallelize work by analyzing how targets within the build files related to each other. The question I asked was, what if Crazy Fun delegated a buck wherever possible and just handled the bits of the build buck couldn't? It turns out it wasn't hard to wire the two together with Crazy Fun delegating to buck where possible. And suddenly, Selenium builds were a lot faster. This was joyous. Coding was fun again. At this point, it sounds like we had everything sorted out, right? But if that's the case, why is this talk called CI with Bazel? Well, while buck was definitely a step forward, it wasn't ideal, and why not? Well, there are plenty of reasons, but one of the most important technical reasons was that extending buck was extremely difficult. When we'd been working on buck at Facebook, adding an extension mechanism had always been a high priority, but never quite made it to the top of the list. That meant the only way to extend buck was to fork it and to add your own extension to buck's own source before compiling a fork and uploading it somewhere. Being able to extend our build was really important for Selenium. We were building things that people at Facebook just didn't need, like the Zippies of Firefox and .NET code. In addition, the Selenium team had been very patient humoring me with various build systems, but it was clear that people would be happy using something that other people knew. And that leads me to the other reason for moving away from buck, the social ones. The frankly weird build system that Selenium had made it really hard to find help when it went wrong. There was no way to find the answer to your problem on Stack Overflow. There was no one to ask for help other than the Selenium developers themselves. We really wanted a build system that had an active and vibrant community, a build system where we could ask questions and where Stack Overflow might be able to help. Community matters. Sadly, from the outside, it also looks like buck has basically ground to a halt and it never really had a large community built around it for any number of reasons. I'm really looking forward to the rumored buck, too, that's coming out at some point, but for now, the version of buck that Selenium used looks like a dead end. So we decided to look for another build tool entirely, one that was well supported, fast, flexible, and good enough for Selenium. What criteria did we use to assess the build tool? Stepping all the way back, let's answer the question of what a build actually is. Regardless of your language of choice, we can think of it as a process of transforming the original source code that we can ship to our users. Be that like a binary, like the Selenium server, libraries people can depend on, or just a simple script that we can render do something interesting. If you're using a compiled language, such as Java, Go, or Rust, one of these transformations is to invoke the compiler to generate binary outputs. For JavaScript folks, one transformation might be concatenating all the source files based on inputs and another might be tree shaking to reduce the size of the generated JavaScript. Another kind of transformation would be to take generated outputs and package them up into SIPs or JAR files. If we tilt our heads and squint a little, we can even say that running tests is one of these transformations. After all, we take test code and transform it into a series of passes and failures. Now, behind the scenes, build tools typically attempt to reduce work by looking at the inputs of each step of the build, and if those inputs haven't changed, they simply skip the step. What inputs should we be considering? Well, let's take the case of using NPM to compile some TypeScript. The obvious inputs we think about are the actual source files, but we've all run into the problem where the build works on one machine but not another, so that can't be all there is to it, right? One reason is that tooling, such as the TypeScript compiler is present on one machine, not on another. So the TypeScript compiler is an input. But they fix bugs between releases. So I guess the version of the compiler also matters. The version is an input, too. Because these inputs aren't normally stated, we can think of them as implicit inputs. Worse, compilers can be affected by things like the command line flags used, or even environment variables that the OS you're running on. These are more implicit inputs, and very few build tools enumerate them properly. This is one of the reasons we all suffer so much from works on my machine. So in the ideal build system, we'd have a way of listing not only the obvious, but the implicit dependencies. Another thing to bear in mind is that the outputs of one function are inputs to another. We need to properly track what's being produced rather than just dumping it out on the disk and hoping for the best. Not tracking the stuff properly is one of the major reasons we need to run clean builds, and those are incredibly wasteful if we do them, and risky if we don't. I guess we better add that to our list of things for an ideal build system. Track outputs. Another implicit input is when we're running our build. Try and resolve the latest version of some dependency you use right now, like Selenium, and you'll get one version. Try the same thing in six months. You'll likely get another version entirely. How do we handle this? With lock files. These allow one person in one place at one time to figure out which particular set of dependencies play nicely together, and that down somewhere where we can check into the build. This means that subsequent builds don't need to take the time to do the same dependency resolution, meaning a faster build, and we've also removed the importance of the exact time and date where the build is being run. It's such a good idea that almost all modern build systems have some mechanism for creating sharing and using lock files. Clearly, the ideal build system would do this too. Once we've nailed down implicit inputs, our next problem is we need to be able to tell if this has actually changed or not. One common way to do this is to take a look at the time where the input was last modified, the end time. If that's later than the last time a particular output that was generated from it, then clearly it's dirty and we should regenerate the output. That's the way Maven and Gradle all work by looking at the end time. But this isn't a great way to do things. It's all too easy to get the modified timestamps out of line with the derived outputs, causing us to either under or over build. Either way is not great. What else could we do? Well, the thing that really matters is it was in the input files, right? We don't actually care when they were modified just that they've been changed. The way that this problem is commonly solved is by hashing the file and using the hash to figure out if the file has changed. There are plenty of fast hashing algorithms out there and there are ways we can avoid having to read the entire file system each time we do a build. So although this might be a bit slower at the end time, the reduction in read work is enough to make this a really good way of figuring out whether something has changed. Our ideal build system will hash inputs rather than relying on the modification time. There's another thing we'd like from our ideal build system, that for each step, the same inputs lead to the same output. Why is that something we'd like? At the simplest level, it makes caching a lot easier, but meaning that we can do less work in our builds. Now, sometimes some non-determinism in outputs is unavoidable. I'm looking at UC compilers. But most modern tool chains for most languages we care about make this possible. So our ideal build system will do its best to make sure that each step of the build is what's known as a pure function. Given the same inputs, we'll always give you the exact same output. Now, we know the hashes of all our inputs and we also believe we have a build where the same inputs lead to the same outputs. We can start doing some pretty clever things. For a start, it's possible to store each and everything we produce in content addressable storage, using keys derived from hashes of the inputs. If you're not familiar with content addressable storage, just think of it as a giant dictionary or hash. A key points to a specific value and output. We could host that on some central server and then everyone in the team who's trying to build the same thing can take advantage of the work that's already being done. But yet, our listing of the implicit inputs is sufficiently good. There's no reason to be constrained to just running on our local machine. Why not just have a fleet of boxes running in the cloud, each of which can reach into the shared cache, grab the inputs it needs, run the build steps contained in a single pure function before uploading the results into the cache again. That way, you could run hundreds of build steps at the same time and everything would go faster still. It would be nice if our ideal build system supported remote caching and through that, distributed builds. There's something we ran into really quickly with Selenium, but more and more people are running into now. Our builds are seldom just one language. It's not uncommon to have a JavaScript front-end talking to backends written in Java Go or Rust or maybe all three. Maybe using protocol buffers to define the shape of the data in the RPCs that can be used. And then we want to be able to run these things locally but also package them as Docker images. We need almost all these things in the Selenium project. Our repo contains code written in JavaScript, Java, Python, C-Sharp and Ruby. Each of these languages use fragments of JavaScript compiled down to the small arms of reusable code, those atoms. So we all need to consume JavaScript. The Java build reaches a web-based front-end written in React and the language bindings also have code generated from CDP definitions which are stored as JSON. We want to be able to test by deploying the grid in a fully distributed mode to a local Kubernetes cluster. There are so many interdependencies and so much shared code between the languages that separating the repos would be a tragic waste of effort. If we relied on language-specific build tools, the number of tools would be mind-boggling. Weaving them all together to produce a cohesive and sensible whole would be a daunting task and one that most people would quite rightly avoid if at all possible. Crazy fun already offered us the ability to run Java tests for the same ease as JavaScript tests or Python ones. We could already build things like Python, Wills, Ruby, Jams and Java Jars. We quite liked the build files being easy to work with with a common syntax being used no matter which language we were building with. Our ideal build system would retain this polyglot nature and the simple build files. We're asking a lot of this build system, right? It'd be like finding a unicorn, right? There's a slow of new build tools appearing recently but the one we settled on was Bazel. Originally, this was called Blaze and was part of Google's secret source for dealing with their massive monoreaper. It meets many of the criteria we have for our ideal build system. Trax inputs and outputs carefully, so we seldom need to run clean. Each build step in the build called an action attempts to be a pure function and often succeeds in being so. It works with all the languages we support although the .NET supporter is shakier best. It's also sounding someone else is working on. There's a wealth of support options available and plenty of answers on Stack Overplay. There's another reason why making the jump to Bazel was good for us. It made getting started building the project significantly less painful. Using Bazel means there are fewer dependencies that need to be on the developer's machine. We now use pinned versions of Python, Ruby and the JDKs used to compile the project as well as pinned versions of the MPM and all of our third party dependencies. We even have pinned versions of Firefox, Chrome and Edge as well as the drivers for each of these browsers. That means that someone new to the project doesn't need to have all these things already installed before getting something done. Instead, they need to install Bazelisk which is a widely used wrapper for Bazel that allows us to pin the version of Bazel we use, the .NET developer tools, the various runtime libraries for browsers need or they're not the browsers themselves and Python 3 which we transparently call from a script run before every build. It took us a while to fully adopt Bazel and members of the Selenium team had been responsible for improving many of the language specific Bazel rule sets we use. It's not always been fun to get that but we made the leap and now many of the rough edges have been smoothed. All this means that getting started on the Selenium build is a lot easier than it used to be. But there's another reason for picking Bazel and that is it opens up some really interesting possibilities for our CI builds. A lot of this rests in the fact we can query the build graph. The build what now? Graphs are really useful data structures. They represent nodes that are connected to one another with lines. Think of a software map and you've got an idea of what a graph might look like. The kind of graph we're interested in is a directed acyclic graph. Directed means a line connecting each node and that gives them a direction and acyclic means that there's nowhere in the graph where if you followed the lines in the direction they point you'd be able to make a circle. You can imagine your build describes one of these directed acyclic graphs. Now, some build tools use a really coarse build graph but Bazel looks to have a very fine grained one. Why is that? The nice thing is with graphs is there are some really well-known algorithms for figuring out how to parallelize operations on each node of the graph. The finer the build graph the better the chances parallelism can be used the faster our builds. Within the Selenium project we aim for a single build file per Java package. On this slide you can see a simplified build graph generated by Bazel of the dependencies of the core WebDriver APIs. Each node has a label attached to it. These begin with a double slash, have a path and then a colon followed by another string and they tell us exactly where in the source tree each target is. I said it was important for us to be able to easily extend our build tool. Bazel does make this easy by allowing us to write extensions in the form of our own build rules. This is the Selenium project. Bazel rules are written in a Python-like language called Starlark. Notice that if you're comfortable with Python you'll feel pretty comfortable straight away. If you're not then Starlark has taken away much of the complexity to make the programming model even lighter. Don't worry too much about what this rule does but the interesting thing is that each rule is composed of a series of actions. In this we create two actions. The first creates a directory and the second runs a shell script. As the user, the build is composed of a series of rules that are tied together in the build files. But under the covers the build is actually a series of actions each of which can be executed when their inputs are ready for them. This allows Bazel to have an even more finely grained build than it otherwise would and again allows us to code just a little bit faster. So let's assume you've checked out the Selenium project. How does one build for example everything in the Java and Python trees easy like this? Notice that we're building both languages at the same time with the same Bazel build command. The build is also pulling in various bits of JavaScript to make things work the way we expect them to. This is an actual build of Selenium. For me on my machines a clean build can take about two to three minutes but here I've already partially built some stuff notably the React UI so the build is a lot faster only taking about 11 seconds in the end. Now let's run all the smallest tests we have for Python and Java. I could do the other languages but I think this shows the idea. It only takes about a minute to build everything and run and you'll see there's a failing test in there if you've got keen eyes. One thing that Bazel is doing here is it's automatically parallelizing the test for us so we're using my machine as efficiently as possible. If you've keen eyes you'll see that some of the tests haven't been run, they've been cached. That's because I ran a subset of these earlier before recording the video. Bazel knows that I've not changed anything and the test passed before so it's not running them again which is probably what you'd hope a build system would do. I don't need to know anything other than the fact the tests are there to be run. Even though I'm running both Python and Java tests the same command is used to run them. This means that anyone on the team can make a change in the shared JavaScript and rerun all the affected tests without needing to know how to do this on a regular language basis. It's a really powerful thing. So now you know a lot more about Selenium why we chose Bazel and the journey we took to get started using it. Along the way we've made plenty of contributions to the Bazel project and the rules that we use. I'm really proud that the Selenium team has had a positive impact and I hope that some of you get to benefit from the work we did. But this talk isn't about the history of the Selenium project and the why and how we did our migration. We started with Bazel using Selenium as an example we'll talk about. So continuous integration. For the sake of this discussion I'll ignore the CI builds where we were still marrying crazy fun in Bazel and instead focus on just the Bazel bits. Guess we should start at the beginning. The Bazel migration took a long time when we started and we did it in stages starting with Java. When we started our Bazel CI builds the way that many teams do by running Bazel test dot dot dot was used when it was green. This approach has the advantage of staggering simplicity. With it you know the definitely builds and the definitely passes or you know doesn't. The approach worked well but the machines that our GitHub actions run on are pretty underpowered so we decided to make a few changes. Remember the Selenium repo is a polyglot repo with different languages being broken out into different top level directories. Simple enough to create a workflow per language without a fan out. So rather than Bazel test everything it's possible to run Bazel test everything on the Python, Bazel test everything on the Java. If caching had been set up right then if those tests turned out to be a no op then they'd finish pretty quickly since it would just be hitting the cache. The simple heuristic we could have used is to simply check the top level directory of every file within a given PR and just run the per language workflows for those but there's a few problems with that. The first is that occasionally we'd modify a file that wasn't under a particular top level directory which didn't have a matching language specific workflow. I guess it's not much of a problem because then you just do nothing and let the build pass, right? Except then you hit the second problem. Sometimes those top level files actually matter. You do want to run those per language workflows as an example bumping the dot Bazel version file to contain the latest version of Bazel should really force all the tests run. Related to this, sometimes there's code in one tree that affects the others. Most often this happens in the Java tree where the grid server is used by the tests of the other languages and the JavaScript tree where there's a substantial body of shared code so language specific workflows are great but we needed a more sophisticated mechanism for indicating what we should do. It would be nice if we could use Bazel's build graph. We already know that Bazel maintains a build graph. It also provides a query command that allows us to introspect that graph. As an example while I was preparing this talk I noticed that if I change the color class from the support package, it won't test a run. It's not obvious why. Let's ask Bazel and see if it can help. First of all, we want to get a list of the tests that need to be run if the color class changes. Then we'll pick one of those and find out the path between that test and color. I don't know about you but I find text quite hard to read when it's like this. Let's generate an image with the graph so we can actually see the reason. I know we're going quite fast here but the idea I'm trying to get across is that Bazel allows you to easily introspect the graph. This opens up all sorts of interesting possibilities for us. Don't worry if you miss the details as long as you have the idea. Here you can see where the test depend on color. It's because it goes through this driver, this module, which is used by all of our tests. Fantastic. It's good to know that. This idea of querying the build graph to figure out what's changed is often called target determination. A target determinator is a tool that identifies the files that have changed between two revisions of the codebase, then runs a series of queries to identify the targets that have been affected. Each of the language-specific workflows we have is gated by a script which is very heavily based on a similar script used by Bazel itself in its own CI builds. You can see the meat of the script here. For each file in the PR, we identify the matching Bazel targets. We then look up the reverse dependencies of each of those targets in the entire repo before filtering that to a list to identify only tests. Once we have that list of test targets, then we can compute with the per-language prefix. If and only if there's a match there, we can allow the per-language workflow to continue. That's where we are now. For example, if you're building Bazel, you can also adopt some of the tooling we've created around the project. Specifically, the idea of target determination can take a traditional build pipeline of run all the small tests, then run the medium tests, do some panning and packing things up, and turn it into a far more focused process. By running only the specific success of tests you need, your average CI times can drop dramatically. A one project I worked on, build times dropped by an average of about 40%, dropping from two hours to about 20 minutes. But there are some things we can do to go even faster and have our build to be even more precise. The first of these is to improve our target determinator. The one we have is fine, but it misses some pretty important edge cases, such as when we changed the pinned version of Bazel. Fortunately, as part of the Bazel Contrib GitHub organization, there's now a rather nice target determinator that's being actively worked on, by a few projects. It'd be really nice to adopt this, and the demo I'm about to do, this open source project, is the second tool I use. It's the binary called target determinator. Look, here's a demo of it in action on a recent Selenium commit. You can see that when we run the current target determinator it returns an error, and so we don't run any tests. Now the change that we're looking at only changes the IU driver, but we don't build that with Bazel since it's effectively frozen. Because of that, we're not expecting to see any files to be detected that are changed to cause any tests to run. Now you'll notice that the second target determinator appears to be a lot slower than the first one. Part of this is because it's actually working. Bazel didn't even get a chance to do any work previously. But the other reason is the second target determinator is doing a lot more work, as it's comparing both the current and previous versions of the repo to make sure that nothing is falling through the cracks. The tradeoff with completeness is speed. Given that RCI builds can take an hour identifying that no targets need rebuilding has saved us an awful lot of time. Well, just let this finish running. I think it's nearly done now. It appears to be querying the state of the project after the change has been made. It's all very exciting watching a script run, isn't it? And you will see just a few seconds more . There we go. After a minute, it figured out nothing needed to be done. We saved an hour. I mentioned it's possible to run Bazel tests remotely. Now, there are a handful of open source projects that allow you to set up and manage your own distributed build grid, like Selenium's build grid, you know? I've been using Build Barn recently and it's been great for us at work, but for an open source project, I'm not particularly keen on running the infrastructure for a Bazel build grid. Given that we're all Selenium users, I guess most of us are familiar with companies such as Source Labs and Browserstack that offer Selenium as a service. Fortunately, there are so builders of service offerings that are starting to appear. One that I like is called Endflow and I have a fork at the Selenium project that can use it. Just as before, we're going to run our tests, but now, rather than running them locally, I'm going to run them on Endflow's distributed build grid. It's as simple as adding one more flag to the Bazel card, telling it to use the Endflow config. Now, one thing this allows us to do is to run more tests that I can on my regular machine, because there are hundreds of tests and these can scale horizontally. But the other thing is that we can share work easily. In this example of us running the same build, we're using two different machines. I'm using separate dock containers, but there's nothing shared. You can see this plugging away. Now, I started running this test while I was talking about this retry request test. It takes quite a long time to run. Just settle down, make yourselves comfortable. You'll see that we've run 653 tests. Scrolling up. What I'm going to do, I'm going to copy the command that I used to run these commands, these tests. You will also notice the host name begins with 4-8-F. Here, we're on a different host. There's nothing shared between these machines other than the interflow distributed build cache. They can be on different computers, different planets. It doesn't matter. Different planets would be really impressive. When Bazel starts, all it does is it takes a look at its workspace and it figures out what's in those build files and what it has to go and build. Then, for everything, it goes up to the remote end and it goes, have you built this already? Have you done this already? Have you done this already? You'll see that's what it's doing now. These tests are coming through really fast now. You'll see a third of the way through, quarter of the way through, third of the way through. That thing there being built is the ReactUI front end for the grid. You'll see here that zero out of 653 tests needed to be run again because they were all cached. Imagine that and you'll see I built. Now, our local build times using Bazel are already pretty good. With the remote built enabled, I think we can get these wickedly fast build times. That's why if I had to choose between a better target to terminate Bazel to do distributed builds, I'd always plunk for distributed builds. But a time is drawing to the close. Perhaps I should start wrapping up. Selenium is the complicated project with lots of languages. Would Bazel be a good fit for you? Let's look at the downsides first. Most importantly, there's the learning curve. If you have access to someone who's used Bazel successfully before, it's a lot easier to get started. If you've not got access to a local expert, then I'd be cautious for now. The nice thing is the pool of people who are familiar with Bazel is growing all the time. It's already less of a problem than it was when Selenium adopted the tool. And that's a situation that's only going to improve. The next rough edge with Bazel is that writing build files can be hard. Fortunately, that's also changing pretty rapidly. There are build file generators for Praetopuffs, Go, Python and Java. If you're interested in exploring this area, the tool the Bazel community is working with is called Gazel. It's well worth a look. Another problem is that pinning everything comes at a cost. Downloading all those tool chains and third-party dependencies can lead us needing to download hundreds of megabytes of stuff before the very first line of code can be compiled. Waiting all that time is dull and it's worse because we can't really do anything until it finishes. Well, at least we only need to do this once when it's a fresh checkout. Or when someone updates a dependency, that doesn't happen often. It's also possible to reduce this cost by having caches which are stored between Bazel builds. Now, I will note it's not a problem unique to Bazel. Anyone who's using a modern Java or JavaScript build tool will be familiar with long pauses as they download all the required dependencies or do dependency resolution. It's true that Bazel's approach leads to more things being downloaded, but at the end of the day, it typically is a cost we sell them at the pay. Now, some tool chains like Go's are incredibly quick already and adopting Bazel for them isn't such an obvious win. But the moment you start needing something to coordinate steps, perhaps if you want to generate some files, then any build tool starts to look more useful. And if your project is going to grow and develop over time and you're going to use multiple languages, then considering Bazel becomes an option. IDE support for Bazel isn't great. If you're on the happy path of working with Java, C++ or Go, you'll be okay. But once you're off that path it gets less comfortable. Fortunately, the plugins for both IntelliJ and VS Code are improving and support is getting better with each release of these plugins. The other day, JetBrains announced that they were taking on co-maintenorship of the IntelliJ plugin. And finally, Google uses Linux for almost everything and there are very few people there using Windows. Bazel is derived from Google's own Blaze build tool and so it has a strong Unix bias. It works great on macOS, but Windows can be a bit of a struggle. If first-class Windows support is something you need, Bazel isn't for you. Now, lots of the Bazel docs talk about how great it is at massive scale and plenty of the Bazel advocates, myself included, are mono repo fans. But it scales down too. This is largely to do with it doing better rebuilds and being able to selectively run subsets of tests. If there's access to a build grid, then the point where build speed improves comes even sooner. Another massive benefit is the simplicity of the shared command line for building running and testing. Just knowing that to build something I need to use build and to test something is test is conceptually simple and because Bazel does such a good job of caching I typically just choose to test everything. And one of the nice things about Bazel's build files is their language agnostic. That means that if I can read one, I can figure out how the various bits of the build hang together without needing a deep knowledge of how multiple tools work. Again it makes it easier to work in a polyglot repo but it also makes it easier to switch between repos in the same company that all use Bazel. One is if one project is using Java or Kotlin one's in JavaScript and another is in Go no biggie. As engineering organizations get larger, that ability to move smoothly from repo to repo becomes more important. Because Bazel pins dependencies there's far less variance between what one developer is using and another. Couple that with the being able to build remotely and you can dramatically reduce the number of cases where something works on my machine than not someone else's. The number of engineers out as I've seen this say has already been incalculable. As you saw earlier builds are ultimately defined as actions and these have all their inputs and outputs defined. This means that if you have access to a Bazel grid you can use it for anything that Bazel supports. You've seen examples of that today when we did the distributed builds. Such a powerful thing to do and so useful when you have access to it it's hard to go back to building locally. And remember, the nice thing is that Bazel is a lot like Selenium that if you wanted to you could set up and manage your own grid but you want to have someone else manage the updates make sure the latest versions of things available handle the security side of things and ensure the uptime of the system but there are options already available for you that you can turn to. So I hope you found this talk interesting and informative. Thank you very much for your time and attention. I hope there's enough time left over for some questions but if there's something you need to ask just come and find me on the Hangout or on the Selenium or Bazel Slack channels on both of those things publicly and I'll be happy to help you as much as I can. Thank you very much. Awesome. Thanks. Thanks a lot Simon. I see four questions in the Q&A section so if you still have questions folks please use the Q&A section. We'll take about five minutes. We'll go through a few questions and of course like Simon mentioned, he'll be available on the Hangout for more questions. If you're raising your hand it might be helpful to just put in the questions and we take it from there. All right so here we go Simon I'm just going to read out the questions on my screen. What are all the upcoming plans for Selenium Web Driver development in the next two years? So I sit down as Project Lead so it's not up to me anymore but I definitely know that on the list is support for what's known as WebDriver Byday so the original WebDriver model is a request response one where the test sends out a request to the browser, it does something and the response comes back but that doesn't allow you to do bi-directional communication sometimes it's useful to get events from the browser like other error logs being executed by JavaScript like we'd like to get those back, watching the life cycle of the page, doing request interception and stuff like that. So the WebDriver Byday spec is an attempt to allow that bi-directional communication to come through and it's being worked on by Google, Microsoft, Missila, Apple are involved like all the major browser vendors are involved and it'll come soon. If you're using Selenium 4 you can already get a taste of some of the things that we're planning on offering by taking a look at interfaces such as like network interceptor for example in the Java bindings but I think that's like the big feature. Cool, all right and there will be certainly be a lot more talks about what's coming up in the main conference so please do attend that if you're more interested in some of these topics. Moving to the next one how in your view how would you compare UI automation tools like Cypress, WebDriver IO to Selenium like how competent do you think they are? I have opinions. I think the Cypress model Cypress does a really nice developer experience like the UI is nice the IDE has is nice everything is packaged up reduced to the amount of thought you have to put in but fundamentally the technology is based on what we abandoned with Selenium RC attempting to inject things as JavaScript into pages is incredibly painful and they've only just managed to land support for navigating between domains and when we did that with Selenium RC it was a painful man like they're just going to run into more and more problems. Things like puppeteer and playwright they use a bi-directional communication they take some shortcuts so it looks like they start faster than Selenium does but if you put them into the same mode they're about the same speed but the problem with both of those is they're tied to specific versions of specific browsers rather than being a general tool so you can't take the test you wrote today and run it with the current version of Chrome the next version of Chrome the current version of Edge and so on and so forth and Firefox right so you're limited in your testing options I think the capabilities that BiDi offers will mean that the things that you can do with those frameworks rapidly become less of a differentiator like both Selenium will be able to do all those things There's a question from so far the questions were anonymous so I didn't read out the names but the next question is from Mahesh he's asking again about playwright already taking up the API integration so any plans of having API integration in future in Selenium you're asking the wrong person like the technical leadership committee of Selenium is the right people to ask and they would be able to help I think Diego is speaking later today he's on that the TLC one question from Madan after completion of your session I would I think he's asking something more specific about a problem he's facing with Chrome 103 driver and .NET so I guess Madan if you can join the Hangout table you might be able to deep dive with Simon it would be even better if he joined the public Selenium Slack channel and asked for help there like I haven't run into this issue so I don't use .NET so debugging that is going to be quite complicated for me but people who are on the public Slack channel will be able to do it in order to go there go to Selenium.dev and then click on support and then one of the options is like join the public Slack and that's where you'll be able to get like the best help perfect alright we'll take one last question and then we'll move to the Hangout again from anonymous attendee can we have the video recording facility in Selenium WebDriver if you use Selenium Grid you already have it like it's there as an option so use Selenium Grid or use something like BrowserStack or Source Labs which also are for the ability to have videos recorded of your tests perfect alright I think with that we'll wrap up this session thanks again Simon this evening for spending time with us it's always great to hear your insights from the Selenium project so I'll now kind of wrap up the session thanks again everyone for joining as well we will now move to the Hangout Tables meet Simon over there see you later thank you bye bye


SCP-656 appears to be a board game box, labeled Home Edition. Contained inside SCP-656 is a recordable VHS tape, with Home Edition written on the label in black marker. When SCP-656-1 is inserted into a VCR attached to a television, it plays a taped episode of R. which appears to be from the mid-1980s. The recording begins during the theme music, cutting off an unknown amount of time. The show follows a quiz show format, where three contestants answer trivia questions to win money. All of the contestants are confirmed to be living, although none have records suggesting that they competed on a game show.


The horse trembled with strength and power and energy. I sat over on the sideline fence. It was a round pin and I saw that horse snort and just trembling and waiting to explode. There was a young man there. A young man who understands the nature of horses. A young man who loves horses. A young man who has experience in guiding horses. And he clucked to the horse and he led the horse and he worked with that horse around and around and around. I had just stopped in in the spur of the moment. A godly young man in our community a few weeks ago that I know and I wanted to stop and see him and visit him for a little bit and he was leading a horse into the ring and so I just sat on the sideline for about the next hour and I watched. That day discipleship had been on my mind and God had some lessons about discipleship for me as I watched that young man working with that incredibly powerful horse. And Taylor told me he said really brother Joe horse training involves learning to control and direct their energy. It's teaching them the blessing and the opportunity to go fast and to gallop suddenly but then to be able to slow down abruptly when necessary. Learning to respond properly when they encounter obstacles, loud noises, sudden movements, rattlesnakes, things out of the ordinary. Other animals, water crossings and it's learning to develop in that horse a sense of trust. And so I watched as Taylor led that horse all around the ring and then before long he saddled the horse and he climbed on the horse and he worked with the horses that backed up and he taught the horse to go backwards and forwards. He said this horse was brought to me because it was no longer controllable by its owners. And the last time I trained it before the weekend I think it was on Friday and this was Monday. He said I didn't get along well at all but today the horse was learning and it was working well. And God was teaching me some lessons in discipleship and trust because there is in this generation my brothers tremendous energy and potential and power and opportunity.  Now Taylor could not have possibly held back that horse if the horse wasn't willing. That horse had so much more strength and power than he did. He's a strong young man but no match for a mighty horse. But that horse wanted to please and that horse just needed some guidance. I believe God is calling us in this generation also to discipleship. Like that's what we want to talk about for just a few moments while we're here together in this message and that is discipleship in the 21st century. Discipleship in the 21st century. After Jesus lived among humanity he left his wonderful life example and his powerful teachings about the kingdom. You know that's why we're here tonight. You know that he went to the cross and he offered his own blood and gave his life as a ransom payment for my sin and for your sin and for the sin of the whole world. After three days he rose in glorious triumph and he was seen of his disciples for 40 days. Then shortly before his ascension he went out and he gave these words to his followers.  Jesus said all authority has been given to me in heaven and in earth. Go therefore and make disciples of all the nations, baptizing them in the name of the Father and of the Son and of the Holy Spirit teaching them to observe all that I have commanded you and lo I am with you always even unto the end of the age. Discipleship in the 21st century. I want to briefly consider seven areas quickly. What is discipleship? Why is discipleship necessary? What is unique about discipleship in the 21st century? I want to think about a call to personal discipleship. I want to think about a call to discipleship in our homes. I want to think about a call to discipleship in our churches. Last of all I want to think about discipleship, a call to go get it. A call to go get it. Let's think about these thoughts for the next few moments together. Discipleship in the 21st century. What is discipleship? Point number one. What is discipleship? I want to suggest to you this definition. You can ponder it. I welcome your input and response, but I suggest that it is the intentional investment of time, teaching, disciplines, demonstration, and care of a person or people into the life of another to direct them into a definite pattern of understanding and living. I'll say that one more time. I suggest to you that discipleship is the intentional investment of time, teaching, disciplines, demonstration, and care of a person or people into the life of another to direct them in a definite pattern of living, of understanding, and living. A disciple is a learner. A disciple is a follower. It's one who adheres to the teachings of another. People can be disciples tonight of many different people or of things or of movements. There are all kinds of disciples after this or that in American society around us tonight. But Christian discipleship begins with a true conversion and conviction that the gospel of Jesus Christ is powerful enough to produce a transformed life. Christian discipleship begins with true conversion and a conviction that the gospel of Jesus Christ is powerful enough to produce a transformed life. May God be praised. Let's consider the second area tonight. Why is discipleship necessary? Why is discipleship necessary? Well, I'll suggest a few things for your consideration tonight. Why is discipleship necessary? Well, first of all, I would say because Jesus specifically said to do it. He said go and make disciples of all the nations. Jesus told us to do that, to do this. That alone makes it necessary. But further, Jesus modeled discipleship for us. We have recorded in the New Testament, in the gospels, not only the teaching but also the life example of our Savior, the Lord Jesus Christ. Jesus modeled discipleship for us and we are to be like Him. But furthermore, we have examples of discipleship in this book, the Bible, the Word of God from the beginning to the end. My mind goes to men like Moses who had disciples around him. Moses had a Joshua who was his servant, the one who accompanied him, the one who went up on the mountain with him, the one who saw his heartbeat, the one who heard his prayers, the one who witnessed as Moses communed with God. I think about men like Jehoshaphat that the Bible says when he was used by God to help accomplish a revival in the nation of Judah, that Jehoshaphat sent out men to bring the people back to the Lord. And not only that, but a little later on, I love this, the Bible says of Jehoshaphat himself. Even after he'd had some failures, even after he'd had some rebukes, Jehoshaphat himself went out and gathered the people back to the Lord. That is discipleship tonight. That's why it's necessary we have the example in the Word of God and also the teaching of our Lord Jesus. Furthermore, as we move on into the New Testament, we see that the apostles also both instructed and modeled this example of discipleship. One example that is so fascinating to me that particularly comes to my mind tonight is the New Church at Antioch. Now the church at Antioch, as far as I'm able to tell in the New Testament, was the first primarily Gentile church. And it was quite a church in a bustling metropolis of Antioch up north of Jerusalem, perhaps 300 miles. And as that church began to grow, and these were Gentile people, and there was something a little different about this church, the Bible says that tidings of these things came to the ears of the apostles at Jerusalem. And what did they do? I love the response of the apostles. It said when they heard that, they decided to send Barnabas up to Antioch. They didn't raise alarms.  They sent a son of consolation. They sent Barnabas up to Antioch, and Barnabas took a young man by the name of Paul along with him. And the Bible tells us that a whole year they met with those new believers. That, beloved, is an example of discipleship. Well, why is discipleship necessary? Jesus said to do it. Jesus modeled it. We have examples of it from the Old Testament, all the way through the New Testament. And further, discipleship is necessary because, now get this, brothers and sisters, discipleship is necessary because our creation in the image and likeness of God includes the reality that we are relational people. We are relational people. And that means, among other things, that we are influenced and were guided by the lives of others. That's a reality of our image. And since we are influenced and guided by the lives of others, we have to pause and recognize tonight that since sin has entered into the world, most of the influences around us, as well as the influence of our own flesh, as well as the influence of an enemy, the evil one, Satan himself, who is proactively against the work of God because of these things. We need definite, deliberate discipleship in the Word and in the will of God because we're not in neutral territory. We're not in a neutral spot. We're behind the lines in enemy territory. And beloved, we need discipleship. I need it. You need it. We all need it. We need discipleship. That's why it's necessary. Finally, discipleship is necessary because we will pattern after something. We will pattern after something. Discipleship sets forward and promotes a pattern of godliness. Discipleship in the 21st century, we thought about what is it? We thought about why is it necessary? I want to consider a third area and that is this. What is unique about discipleship in the 21st century? It would be interesting to know how you would answer that question. What is unique about discipleship in our day, in the 21st century? You know Jesus asked a question in the 1st century, in his day, to a group of men. I just can hear the cry of Jesus as he somewhat in pathos and yet also an understanding of humanity that he had had a part in creating the image and likeness of God. In fact, the word tells us that all things were made by him and without him was not anything made that was made. But Jesus made a cry to the men of his day and he said, Where unto shall I liken the men of this generation? And to what are they like? That was the text of the first sermon I ever preached a number of years ago. Where unto shall we liken the men of this generation? As a young man I was concerned about that. I wondered about the realities of our generation. That's been perhaps nearly 20 years ago now, 18 or 20 years. I can't even remember exactly right in this moment. How much more so today? Where unto shall we liken the men of this generation? What about our generation, brothers and sisters? What is unique about discipleship now? Well, in 2 Timothy chapter 3, the Apostle Paul said these words. Some of you have memorized the last part of this chapter. And I'll just share with you a little example of discipleship. When I was a young man, I was a teenager before I give you this quote. I don't know why he did it, but I came in the house one evening and my father was sitting in the chair. My father is a man of God. And he gave me this challenge.  Now it's not a long chapter, but somehow he sensed the right moment. Many times it wouldn't have worked. Many times I might not have responded, but somehow in that moment I sensed the work of God. I sensed the call of the Spirit and I took that challenge. I rose as a young man and I went in my bedroom and I poured in my Bible till late that night. And before I went to bed, I went out to dad's chair and I said, dad, I think I've got it. 2 Timothy chapter 3 and was able to share that with him.  I want you to think about a few words of it now. That was discipleship on his part. I'll be forever grateful for my father's discipleship. But the Apostle Paul said in that chapter, this know also that in the last days, perilous times shall come. That word perilous could be translated raging. And isn't that an apt description of America today or even our world today in the 21st century, raging times shall come. Times of turmoil and busyness, what is unique about discipleship in the 21st century? It goes on to say, for men shall be lovers of their own selves, covetous boasters, proud, blasphemers, disobedient to parents, unthankful, unholy, without natural affection, truth breakers, false accusers, incontinent, fierce, despisers of those that are good, traitors, heady, high-minded, lovers of pleasure, more than lovers of God, having a form of godliness but denying the power thereof from such turn away and so on. Isn't that a description of America today in the 21st century? What is unique about discipleship in the 21st century? Well, there's a group of people and I've visited with some of you brothers about this. I did some study on this a number of years ago myself, but it's moving on. There's a group of people in America today known as the millennials. And the millennials are the people today that are, and a number of you are here, your millennials. If you're from 16 to 36, would you please raise your hand? If you're aged 16 to 36, take a look. This is the group that society would call the millennial generation today. And God bless you. But the millennials face a very unique challenge. They follow generation Y and generation X and so forth. And there are social analysts who study the generations and certain things that are typical of each generation. But I just want to say without taking time to go into that, that I think we have a culture that is very proactive in discipleship. And if we're going to, in some way, cultivate the love and the life of Jesus Christ, it will take deliberate discipleship on our part. Otherwise, the culture is going to do it for us. Many people today are being discipled. The millennial generation is being discipled by American culture. You can attempt to order a supply or a part or a book on Amazon. And that's a useful tool. The headquarters is a couple hours from where I live over in Seattle. But that company, you can go on to that site and all kinds of suggestions will pop up at you. Here's a free movie clip that maybe you would like to watch right now to see if you would like to download that. Here is what is popular. Here are best-seller books. Wouldn't you like to see the clothing item that's been the most popular that has sold the discipleship? The culture is discipling very proactively around us. The social networks around us are setting trims. I'm not here ringing my hands tonight. I want you to know that. I just think we need to pause and take a look at reality. The discipleship of our culture. I remember several years ago, I couldn't think of a current example, but most of you know who Sarah Palin was when she ran for president. She wore a certain type of glasses that were kind of noted. And I just remember reading that as she began to appear in the media, the sales of that type of glasses just went off the charts. And she was just one public political figure, let alone the celebrities and the sports figures and the Hollywood figures. They're discipling very proactively. That's one of the things that I believe is unique about discipleship in the 21st century. I want to read to you a couple of verses out of the book of Daniel. The last chapter of Daniel, verse 3 says this. And they that be wise shall shine as the brightness of the firmament and they that turn many to righteousness as the stars forever and ever. But thou, O Daniel, shut up the words and seal the book even to the time of the end many shall run to and fro and knowledge shall be increased. Now I think those are two factors that we see Daniel prophesied would be evident in the time of the end. And I think that's what's unique about the millennial generation about discipleship in the 21st century. It's that many shall run to and fro, first of all. We live in a society of globalization. We live in a society of travel. We can communicate, we can travel. It's a beautiful, it's a tremendous opportunity for discipleship and for spreading the gospel. I'm excited to live in this generation. Brother and sister and friend tonight, you aren't here in 2016 by accident. It's a wonderful time to be alive and serve the Lord Jesus Christ. But it's also a time to be real, to accept the reality that we live in a very proactive, discipling culture. And if we want to be disciples of Jesus Christ, we're going to have to be intentional about it. Many shall run to and fro. The second point that scripture says is that knowledge shall be increased. Technology, industry, instant communication, social networking, instant shopping. A few weeks ago my wife went outside. We live out in the country in the state of Washington. And she heard a buzzing sound. And she looked around, couldn't figure out what that buzzing noise was. And about 10 feet over our roof was a little drone flying. And it turned out it was just a neighbor flying a drone around. And I had to chuckle at the contrast. We lived right across the road from our church. And it's a simple plain white building and there was a man parked in the parking lot, launching his drone and taking high-tech pictures around the valley. You think about that. Discipleship in the 21st century. And those things can be used profitably. I realize that. But it does make a time a unique challenge. Well, I just want to say this. This generation longs for input and accountability and affirmation and engagement. I believe that with all my heart. This is a wonderful generation. I see so much potential. You that raised your hands tonight. There is so much potential in your generation. God bless you. I'm so excited for you. I'm just a little bit out of your, a little bit older than you. But God bless you. What potential? Well, let's consider quickly a call to personal discipleship. A call to personal discipleship. That is your investment in the life of another. It's seizing opportunities in the life of another. This calls for humility. It calls for availability.  And so often, I think we miss the little indicators. Have you ever had someone just kind of casually mentioned, I've been struggling a little bit. Yeah, I'm doing fine. Yeah, fine. How are you? What's the indicator? I think too often we're busy. We're caught up in our lives. And we don't want to take time and we don't want life to get complicated. And we want to be a little bit protective. And sometimes we're hearing the temp of the iceberg and it's a call for personal discipleship. Personal discipleship, be ready. It may be a text, a call, just a little hint. But it's, and sometimes it's a direct request. I've had that too. A call on the phone. Would you meet with me? Would you disciple me? I'm struggling. God bless them. God bless them. This is powerful prayer, accountability, encouragement, calling people back to the truth. Sometimes we let the devil whisper lies in our eyes. Generation, this generation of millennials, the devil is promoting lies in your ears. But you don't have to listen.  Yes, I think there's a great longing for that and it reminds me of a little boy a few weeks ago, just a little boy about this tall. And I'm thinking of the longing for discipleship and this little boy, his father told him, one evening his father had been very busy and his father told him, tomorrow morning son, we're going to get up and go fishing. You know what that little boy did? It touched my heart. That little boy went and got on his bib overalls and he got on his flannel shirt and went to bed. He wanted to be ready. He wanted to be ready when daddy called in the morning that it's time to go fishing. And beloved, so often I think there are people craving and crying out for personal discipleship, for an investment in each other's lives. God bless you.  Sometimes I had a group of young brothers in my home just a few nights ago and the ladies were at a ladies meeting and some of these young men, I asked them about this subject. I said, what would you say if I just said this title, discipleship in the 21st century? And I got a variety of responses and we had a good discussion. But when that discussion was all over, I said, brothers, just remember this. And these were young men of God. I thank God for them. I said, it's your turn. They were talking about how they've appreciated it and they love it and they welcome it. It's your turn. It's now your time. Isn't that what our scripture says? The things which thou has heard of me, the apostle wrote to Timothy, among many witnesses, the same commit thou to faithful men who shall be able to teach others also. This thing keeps going and passes on.  It's your time. It's your time to reach out. Well, let's think a moment about this, the call to discipleship in our homes. A call to discipleship in our homes. I just want to say tonight, this is an incredible opportunity. It's a powerful opportunity for amazing influence, our homes. An open home, a cup of coffee, a glass of iced tea, perhaps a meal, maybe a Bible study, maybe a place to stay.  Is it a place for my space? Or is it a mission station for Jesus Christ? Is it a place of discipleship? And I know we all need times where we have quiet. And I encourage us to arrange our homes where we have a spot that we can get away. But I also encourage us to open the doors. Do you know that a stable, godly, loving home is an extremely rare thing in our world today? And there are people crying out for that. If you have a godly home tonight, do you know that your home shouts without you ever saying a word?  Well, the sixth point I wanted to make, I want to hurry on and conclude is a call to discipleship in our churches. A call to discipleship in our churches, the Ecclesia. That word means the assembly. It literally means the called out and called together. The called together, the assembled ones. This is God's plan. So clear in the book, in the Word of God, so clear in the example in the Acts of the Apostles that the local, functional, healthy, stable churches where there is love and joy and discipleship, this is God's idea. God puts the solitary in families and he does it on purpose. Discipleship in our churches. You know, our churches, stable, healthy, functional churches at least as they develop include bishops and deacons, the Word of God says. And these men are not to be lords, but they're to be helpers. They're to be encouragers. They're to be examples, the Bible says. And brothers, I just want to say to us in our churches here tonight, I really believe that we need to face, if you're struggling, if you're a pastor tonight or if you're an older brother in a church and maybe you struggle with facing future fears of compromise or of wash out or of dilution, I believe we need to face those fears not with more rules, more and more and more rules and adding and trying to desperately keep up with the new trends so I can categorize something else to deal with this, but rather with deliberate discipleship, with reaching out in love and relationship and teaching with our brothers and sisters, daring discipleship. Yes, the local church, our local churches should be greenhouses of growth for disciples. But with all of that, I want you to remember, remember the example of our Lord Jesus, he fulfilled the prophecy literally that was written of him and we need to remember this example in discipleship as well. Yes, we want to inspire, we want to call this generation to high ground, we want to motivate, we want to prompt them to godly living, but remember, the Bible says of Jesus that a bruised reed would he not break and smoking flax would he not quench. He didn't stamp it out if there was just a little spark and we want to follow that example in discipleship in our churches. Well, the last point I want to give as I take my seat is discipleship, a call to go get it, a call to go get it. My observation is that those that seek shall find, to those that knock it shall be opened. My wife and I learned the familiar sound of the gravel crunching in the driveway and we could sometimes tell who it was by the way they drove or the sound of the vehicle or the sound of the bicycle or the knock on the door. But I just want to encourage you, my young brother, sister, friend, man, woman, older brother, whoever you are, go get it. Go after discipleship. James says you have not because you asked not and I've had people say I don't have anyone to talk to. I don't have anyone to speak to about how to go in life and I know God intended that there would be godly homes with good parents and I had that blessing but not everyone does and we need to be there for those who do not. So go get it. Other brothers and sisters can help you in learning to practice spiritual disciplines, Bible reading, prayer, fasting, memorization and meditation, how to fight sin and temptation, seeking discernment in my life, choices and decisions, all of those things. It's serious. Remember Jesus said if any man will come after me, let him deny himself and take up his cross and follow me. In fact he says, whosoever of you will not forsake all that he hath, he cannot be my disciple. It's serious. It's worth making hard choices to have it. Young man and young woman tonight, whoever you are, maybe you don't know many people here or elsewhere but if you are seeking to follow Jesus, I encourage you to surround yourself with godly men and women. It's worth making hard choices. It may mean a job change. It may mean a geographical change. It may mean a personal liberty sacrifice. It's worth staying around for the hard sayings of Christ. Our Lord Jesus one time looked at a group of disciples, a whole group of them and he taught some pretty hard things and quite a few of them walked away and Jesus turned to the few and he said, will you also go away? Tonight I wonder if there's someone here just about to go away. Just about to walk away. Will you also go away? Hundreds have walked away. Thousands have walked away in the past few years from godly, solid discipleship. I'll leave their lives in the hands of God and let's go after them by the way when we have the opportunity but will you go away? Make some hard choices. Make some resolves tonight. I want to be a disciple of Jesus. I want men and women of God to surround my life. May God bless you. Let's seek discipleship in the 21st century.


On Sunday, July 31st, Governor Beshear made a trip to the Knot County Sports Plex to address the media and local officials regarding the flood relief effort. While community members continue to support each other in this time of need, Governor Beshear is also expressing his dedication towards the people of Kentucky. First, we understand and we love them. We care about them. We're going to do everything within our power to get them back up on their feet. And while it's going to take years to rebuild their lives, we were just talking about the location where we want to set up a one-stop health area here. If we had to come in and talk to a FEMA representative face-to-face, get your driver's license. If you have to file for an F1 to talk about your prescription refill, to talk about housing, to hopefully get all those services that so many of us take for granted. But when you've had everything wiped out, you shouldn't have to go to five or six offices. You're already in a difficult spot. It's not going to be easy. But we are tough people. We open our hearts and our homes to one another. We talked to folks in West Liberty, hit by a massive tornado ten and a half years ago. We do get back up on our feet. They will too because we're going to be standing right there next to them every day. Experienced heart specialist and sub-specialist collaborating for the benefit of your care. Top 10% national hospital rankings for patient safety and heart attack and heart failure treatment. The technology is skilled to perform extraordinary complex, minimally invasive cardiac, electrophysiology, interventional and structural heart surgeries. This is a heart and vascular institute at Pikeville Medical Center. When it comes to your heart, place your care in our hands. Governor Bashir acknowledges the damage done to the roads and homes in the surrounding East Kentucky areas, but remains optimistic about the progress being made to rebuild and move on from the crisis. Well, when you look at these roadways, first this water can just totally eat up the road. Wipe it out and make it impassable. Then you get mudslides that are coming down with debris that separately have to be removed. I want to say the transportation cabinet, local officials, people out there with the back hose from their farms are doing an incredible job and a lot of areas are open that many would have thought would have taken a lot longer. We want to make sure that we're not keeping one family from getting what they need. And remember, it's their stories that are important, but it's mainly them that are important. We'll help you replace the stuff. I know that's hard if you just lost everything, but we're glad everybody that's here is here. Thank y'all. Reporting for Mountain Top News, I'm Nick Colum.


The United States Savings Bonds Division presents Guest Star! How do you do, ladies and gentlemen? This is Wayne Elliott, your host for Guest Star, a transcribed feature program brought to you by this station and United States Savings Bonds as a public service. Each week these programs are presented as a pleasant reminder that the sure way to save is the automatic way. So buy Savings Bonds automatically through the Payroll Savings Plan where you work, or the Bond a Month Plan where you bang. Today we have the honor to present Mr. Jose Itorbi, one of the outstanding artists of our time. Before we bring him to our microphone, however, here is an opening selection from the Savings Bonds Orchestra directed by Harry Sosnick. Mr. Sosnick's own arrangement of L. Radicario, who introduced today's guest. Known throughout the world for his work on concert stage in motion pictures on phonograph records and on radio, he is unquestionably one of our finest and most versatile pianists. He will play Reverie by Debussy. And here he is, Mr. Jose Itorbi. Mr. Itorbi, that was absolutely wonderful. Gee, I can't find words to describe. Mr. Elliott, may I suggest that you save your voice for more important work? Well, what can be more important than to tell you how very much we enjoyed your playing? Thank you. Well, one thing that is more important, I think, is to tell your listeners of the reason for this program. You mean tell them about Savings Bonds? Exactly. And I believe that it is vitally important that every American know what a fine investment a saving bond is. And it's even more important that they buy them. That's right, friends. Savings Bonds are a fine investment. They're an investment in your own future and in your own country. Buy them regularly where you work, or if you're your own boss, where you bank. That's right, Mr. Elliott. And I recommend them to all of you who are listening in. Goodbye, and thank you for having me on your program. Goodbye, and thank you, Jose Itorbi, and come again. Now, the Savings Bonds Orchestra with Harry Sosnick's own special arrangement of I Only Have Eyes For You. The Transcribe Feature Program guest star brought you at this same time each week by United States Savings Bonds in this station as a public service. It was our pleasure today to have as today's guest the noted concert pianist and conductor in Mr. Jose Itorbi. There'll be another fine guest on next week's program, so be sure to tune in at this same time. Meanwhile, this is when Elliott's saying so long with a word about Savings Bonds. There's no finer, safer investment in the world today, so buy Savings Bonds regularly. Where you work, where you bank, or at your local post office.


Okay, so my talk is about a particular neuroinformatics system that I developed with Michael Arbeb at my time at USC. He's now just retired, so I'm continuing on with this project. This is called the Brain Operation Database. So just to put it in a bit of context and see how it fits in with the rest of the field of neuroinformatics. There's a few databases currently that are dedicated to storing details about computational models of the brain, such as Model DB, Open Source Brain. And these are focused more on storing the code of the model and details about the model. And then on the other side, there's a lot of empirical databases that are specialized for different types of experimental data, like connectivity data in the monkey, human imaging data, neurophysiology data. But where Bode B comes in is in linking model descriptions with summaries of empirical data. So documenting models in terms of the data that's used to support their design, as well as the data that's used to test them. So for half of my talk, I'll give an overview of Bode B. And then we've also developed one of these specialized databases called Sensory Motor DB. And this is for storing and collating and analyzing neurophysiology data and linking that with behavioral data. So Bode B defines a functional ontology for brain models. And so our core entities are, of course, a model. And we decompose models into hierarchies of interacting submodules. Brain operating principles.  For example, a winner-take-all mechanism or heavy-in-learning. Summaries of empirical data. And so at least at systems-level modeling, modelers may not be so concerned with the very low-level details of the empirical data. And they sort of want an overview of it. Of course, this is dependent on the type of modeling that's being done. But so we summarize empirical data at a level appropriate for different types of models. And then, of course, we store summaries of the key model simulation results. So just a bit about how these entities are related to each other. So models are built using summaries of empirical data. So these embody the assumptions made by the model and inform the design of the model.  They implement brain operating principles. And they generate simulation results. And these simulation results can then be linked to summaries of the empirical data that they either explain or contradict. And where no appropriate empirical data exists, they can make predictions. So as I said, we link models to summaries of empirical data. And these can be entered in a generic sort of free form format, just describing them in text. Or we've developed a few specialized formats for different data types with corresponding visualization. And where possible, we maintain links to the primary data sources. So the specialized formats that we've developed so far that I'll go through in this talk are summaries of imaging data, connectivity data from the MCAC, and human EEG data. And then when I talk about sensory motor DB, I'll talk a bit about how we summarize neurophysiological data currently. So connectivity data is summarized in Bode B at a very high level in terms of region X projects to region Y. And we can use this information to generate these sort of interactive graphs of connectivity in different parts of the brain. So this one's showing for area AIP all the regions, at least in the COCOMAC database that it projects to. So you can get a nice page summarizing this along with the link to COCOMAC to see if you want to view more detailed data about this connection. You can see what experiments support this, what injection, what type of tracers was used, where they were injected, where they saw the labeling, what sort of path it took through the brain if you're interested in those details. So this just shows a little demo. We can search through this summaries of empirical data. Here we're looking for connectivity summaries from area AIP to other regions. You can see all the results here, along with links to COCOMAC. You can generate a clickable graph, and you can navigate around, view these different regions, view the connections. And if you double click on any of the edges in this graph, you'll be taken to the page for that connection, along with a link to COCOMAC, where you can see the details. So brain imaging data is stored in Bode B as coordinates of activation peaks in other Taylor-Ack or MNI space. And we've developed this 3D visualization tool called Brain Surfer to be able to view these along with different brain regions. And you can convert them, for example, from MNI to Taylor-Ack space and navigate around the brain. And each of these pages that describes brain imaging SED has a little description of the experiment, the control and experimental conditions, the method used, the coordinate space, a list of the coordinates. And then a link where you can see more detailed information about the experimental data and the braided database. So this is showing an example SED. This is one for skill learning. So early mirror reading versus late mirror reading. You can see the link to braida. We can select these coordinates. We can launch up Brain Surfer, view them in this sort of navigable 3D space, drag these slices around. And here I've selected two SEDs. One is mirror-reverse text reading versus plain text reading, and then a related one, early mirror reading versus late mirror reading. And we can change the color of these coordinates to see where these coordinates overlap or they don't. And then view different brain regions as three-dimensional meshes and see where these coordinates are located. So EEG data, we allow users to summarize EEG data in terms of ERPs. And these are summarized as groups of ERP components. So this is an example showing an entry for the Breitschaff potential, along with its early and late component. And these are defined by their peak latency and the electrode locations. And then users can view these in standard electrode layouts. So here's showing where the late component of the Breitschaff potential is usually recorded from. So moving on to neurophysiology data. There's currently few resources for organizing and storing this type of data. And for systems-level motor and decision neuroscience, we want to be able to link neural activity to the actual behavior. And so we partnered with several non-human primate labs to fill this gap with sensory motor DB. So this builds on the NeuroData Without Borders data format. So we convert each lab's custom data formats into the NeuroData Without Borders format. And we allow linkage between the firing rates of these neurons and recorded videos of behavior, of the animal's behavior. And we're focusing on reaching and grasping behavior. We allow users to define their own custom analyses in R. And we federate this database with BodeB. So model descriptions can then link to summaries of the analyses that you can run in sensory motor DB. So this is just showing an example of a particular experiment. This is from Sasha Kraskal's lab at UCL. And this is looking at F5 pyramidal track neurons during observation versus execution of grasps. And here you can see for the different conditions, for the various units that were recorded from, what their firing rate was, their average firing rate in these conditions, along with different trial events such as the start of the trial, the go signal, the movement onset, etc. And then you can click on a particular condition and look at a view of that condition and see a video of the actual behavior along with time-stamped events. So this is showing it's a bit difficult to see what's going on. This is showing a monkey reaching and grasping out to a ring and different events pop up in the video. For example, this one is showing the movement onset. So we developed some interactive visualizations for all these data types. So this is showing a particular unit, its activity in a particular condition, over all their trials recorded from. So at the top you see a roster plot of the spikes along with the different events in each trial. We can generate a histogram from these spikes and a firing rate. And this is showing the activity of this neuron aligned to the start event of each trial. You can click on each of these events and realign them to other events. So for example, this is showing the same neurons activity in the same condition aligned to the offset of the hold action. And then you can also change the different ways that the firing rate is calculated. So for example, the bin width of the Gaussian width. So here we're just searching through the database for experiments involving region F5, pulling up that same experiment. And then we can go to the unit view page, see the activity of this particular unit in all the conditions of the experiment, realign its firing rate to different events. You can do this on the roster plots as well. And you can change the way that the firing rate is calculated. So here we're changing the bin width and the Gaussian width. And you get an updated view of the firing rate. So now we can zoom in on one particular condition. So here's one of the videos I showed before. So this is grasping a sphere object. You can see the different events pop up as the video plays. You can slow down the video, go through it frame by frame, and look at this in relation to the events and the neural activity traces. Okay, so we also allow users to run either some standard analyses or implement their own custom analyses in R. And we use libraries pandas and RPi2 libraries to interface with R, run these analyses and retrieve results. And then we use the D3 JavaScript library to generate some of these visualizations. So one of the examples that we have that was developed in collaboration with Sasha Kraskal's lab is a visual motor classification analysis. And so this classifies neurons based on the different conditions in the experiment as visual motor or visual motor neurons. And we allow users to then parameterize and run these analyses on any dataset. So in this example, users can specify different time windows of interest to analyze. So for example, baseline, object view period, grasping period, map different conditions in the experiment onto different factors and levels, and then classify neurons based on a series of, in this case, two-way ANOVA analyses. And then we allow users to view the results of these analysis on this sort of hierarchical donut chart, showing the proportion of neurons with each label. And then on the right here you can see the mean population firing rate for neurons with each type of classification. And at the bottom we show some raw statistical output from R. So we can click on this then and export the results of this analysis to Bode B in summary form. And Bode B will automatically generate sort of text-based description of the analysis results along with this clickable hierarchical donut chart showing the different types of neurons. And we can then link these SCDs to model descriptions. So this is showing an example of one of the datasets from Luca Benini and Lena Arnafagazzi's lab in Parma. So they've got a lot of neurons that they've recorded from a lot of different types of conditions. So we're going to run a visual motor classification analysis on them. So here we can identify different time windows of interest relative to different events in each trial. We can do sort of fixed duration time windows or relative duration, so from one event to another event. And then for each factor, for each level, we can map the different conditions of the experiment to it. So this is mapping all the conditions involving execution of grasping to the grasping level of that factor. So you can run the analysis. It actually takes much more time than that. And view the results of this. So here on the right you can see the mean population firing rates of all the neurons of all the different factors and levels. And then on the left you can see this hierarchical donut chart showing you the proportion of neurons of each type. And you can click on different parts of this chart. It'll zoom in and show you on the right here the population firing rate for all those types of neurons. And then here at the bottom, if you're interested, you can see the raw output from R. So now we can export the results of this analysis to BodeB. And here it's just showing you it generates this text-based description, a summary of the results, along again with this hierarchical donut chart showing you the proportion of neurons of each type. Okay, so now we've got that data summarized in BodeB. We can link it to different model descriptions. And one of the things that BodeB allows you to do then is to compare different models in terms of the data that they're linked to. So for example, this is showing a benchmarking analysis, comparing four different models in terms of the data that they're linked to here. And this is color coded so you can see which pieces of data were used to support the design of each model in purple. And then which pieces of data each model explains in terms of its simulation results in green. And so this allows you to sort of compare models in a qualitative way and as well as identify future targets for modeling. So you can see some data that might be addressed by one model but not another and plan some increment, some next version combining features from both of these models to address that piece of data. So just a bit about how we're deploying this. So currently BodeB and Sensory Motor DB communicate via RESTful APIs. And we're partnering with several labs that are running Sensory Motor DB copies locally so they can organize and analyze their data locally. And then they can either keep that privately on their labs copy or share it publicly on the public version of Sensory Motor DB. And then as I've just shown you can export the results to BodeB as summaries of empirical data. And BodeB will maintain links back to the detailed analysis results. So just to summarize BodeB links model descriptions to experimental data used to build or test them. It stores summaries of experimental data with links to detailed data sets. And it does this through Federation with specialized databases. And it allows models to be compared in terms of the experimental data that they take into account or explain. And as I've said currently this is done in sort of a qualitative way. But we're interested in integrating this with a system like SI unit to do this in a more quantitative fashion in terms of unit tests that can be directly compared against data. And then Sensory Motor DB builds on open data formats for neurophysiology and links neural activity and behavior. And then federates with BodeB to support modeling. So I just want to thank Michael Arbebe who actually just retired yesterday who started this project. And Michael went to our programmer as well as our collaborators at UCL, Parma and the German primate center. Thank you. Thank you very much. Should I say Jimmy? Questions? It's a fantastic report. You look so almost like you're doing the HVP one project, right? But how do you see adoption? How many people are actually putting data, putting models, running banks? Because all those efforts are often isolated and there's a bit of a money for some time and then something else coming up because the funding is... So what's the adoption, the long-term aspect of it and the scalability of it? Yeah, so one thing that we've learned at least in the early days of developing BodeB is that it's difficult to get people to use it unless you're providing them with some service, something that they need to do anyway. And that's sort of the strategy we've taken with Sensory Motor DB is to... And we just came upon this after showing it to some neurophysiologists and they said, oh, that would be good to organize my data. And so then we came up with this plan to have it developed and deployed locally and then feeding into a public repository. And I think that's the way we'd like to go with BodeB as well, to have it be useful locally for developing models. Thank you very much for your talk and I'd like to know about more Sensory Motor DB and how users put their data into the DB. Could you explain a little more? Yeah, so currently we've partnered with three labs and they each have their own custom data formats or ways that they organize their data. And so currently we've been working with each of them to develop some programs that can convert their data formats into the NeuroData Without Borders format. And I envision that each lab that is interested would have somebody that would be responsible for that and that's another reason for running this locally. We can't make tools, universal tools for every lab.