 So this is a quick talk about ClosureScript. But specifically, it's more of a case study on this one app that me and a colleague of mine built. So that's why his name is showing there. His name is John Andrews. He's a Closure developer for a while. And he's been, you know, he really loves Closure. And he's contributed to several open source libraries. As a mess for me, my name is Chandu. And I'm in between gigs right now. I'm finishing up working for a software consulting company. We do mostly Ruby and Rails and JavaScript. And now I'm moving to another company that builds learning management systems. It's called Instructure, a really cool company. And their front end is moving from Ember.js to React.js. And it coincides with my interests in React. But specifically, yeah, I've been interested in ClosureScript for a while. I've been working with Closure in ClosureScript for a while. But ClosureScript definitely is the area that I'm most interested in. And then coming to this conference has been interesting with huge contingent of Haskell programmers and Scala programmers. I fully expected something like this. This tweet showed up earlier today at a different talk. And that's why a lot of crappy Ruby developers are now crappy Closure developers. And I'm like, wow. I totally agree with the comment at the bottom. It's like, did they mention me directly or just describe me exactly? Yeah. But yeah, that kind of does describe me. I mean, I've been playing around with Closure. Not a lot of other functional programming, but I really enjoyed the way Closure and ClosureScript has helped me think. And it has informed the way I write Ruby and other languages. So I'd like to talk about this app that I made along with my co-worker. So the motivation for this app. So really quick, is anybody familiar with birding or birdwatching? Sweet. Wow. Awesome. So for those of you who don't know, birdwatching is basically the hobby of going out into nature and just watching birds in silence, watch them in their natural habitat. And it's fascinating. And it's very restful, very peaceful pastime. And then most of the time when you're out there, what you have is your pair of binoculars and a field guide. So it's a really low barrier of entry. So that's one of the things I like to do. And field guides look something like this. You get a page of quick descriptions of birds and then photos that match up with them and then small little maps that show you the rough ranges they're in. And when they're in season, you see all these beautiful markings on them. There's quaint names for them like sublural, whatever, markings or wingbars or roof-asided breasts or whatever. And it turns out that when it's off season, it's really hard to tell those markings because the birds don't wear that plumage all year. And also, you can, and since with field guide you don't have audio, there's quaint little descriptions. I know you can't see from the writing there. And I have audio files, but I won't play them. But it's like the yellow warbler, for example, the one on the left, supposedly goes sweet, sweet, I'm so sweet. Whereas the chestnut-sided warbler, not to be confused with the yellow warbler, says please, please, please, please to meet you. So it's really, it's a tough job out there. But again, it's a very seasonal thing. And when you're in the migration season, the hot time of the year, several of these species are flowing right through that hot spot. Whereas off season, it's like you have to look around and you'll be lucky if you find a crow. And then you're like, oh, wow. But yeah. So I thought part of my interest was with ClotaScript. And I was also interested in D3 and mapping. And so I was like, OK, maybe if I can plot the bird migration across the US region on a map, that would be a cool project. So that's how it started. Basically, this is the app. So I'm going to try and play this video here so that I don't tempt the demo gods. So it's a pretty simple app. There's an autocomplete where you can search for a bird species by name. And then it narrows it down for you. You can pick one. It shows you a picture if it can't find one. You can go from month to month. And if you look at the map, you can see where the bird is kind of, you can see the bird sightings kind of move across the map. Now you can see it, because this is the migration season. And in June, which is the peak, they've already settled in the area that they're going to breed in. So you can zoom in. You can look at the map closely. You can drag the map around. You can then check out the populations of the birds. And then you can keep going. But then also, the way it fetches the photo, is it talks to Flickr. Because I didn't want to store bird images. That's not the purpose of this app. But if it can find a match on Flickr, it links you directly to that so that the photographer can get the credit. And then you can browse other photos that that photographer has taken. So that's the app. So the data for the app. So there's this portal. Those of you who've probably heard of this, it's called eBird.org. And it's this massive crowdsourced warehouse, data warehouse of bird sightings. So people who are out there who are really diligent birders, I'm unfortunately not one of them because it's a lot of work. But what they're doing is noting down what species they've seen, how many of those, what other species are around with it. And this helps eBird kind of make intelligent reports about bird populations in general, and look for trends and such. But they have a huge, huge amount of data. And what's cool is they make some of that data available for free down, or for academic use. And so I reached out to them and that was like, could I have some of the data for maybe, how about one year's data for just the US region? Any ideas how much data that was? So it was about 11 gigs of text. It was just these tabs separated values. It was a huge one big file. They gave it to me after three days. And they generated it and I downloaded it. And then I'm like, wow, what do I do? So there's like over 1700 species. And this is just for the US region. It doesn't even, it's not even North America, right? So it became clear that I needed some kind of API. Because this is not the kind of data that you just throw into your browser and expect it to work. So, but then the API needed to be such that I could quickly import it in, import that something that's not exactly developer friendly format. And then, like I said, too much data. And then also, since the idea of the app is fairly dynamic, I was like, maybe it's a good idea to have an API that gives me data on demand, rather than so-so for specific things. I need to be lazy about it. I need to be, I need to focus it down so that I'm only fetching small bits of data as I need it. And thankfully, there's a very basic JSON request API for D3, the JavaScript library. So with that, I know that I can hit a server somewhere and get some data. So this is where my colleague John was like, yeah, this is perfect for closure. I mean, this API, we can parse this file, Java has got this, and it's been doing it for decades. And so we can import it in a lazy way with closure. So we started out with a schema for the data. And in order to display the values we wanted on the map, we didn't need the entire, all of the attributes on the record because there were all kinds of things on there that like categories and like other species and what the temperature was, how much elevation you were on, statistics like that that were not immediately relevant to what we were trying to show. And then after that, we could parse the data. And that was, so this is an example of a siting function that takes one row of plain text from the file and then builds a map out of it. So that's the int tool line. So it starts with an empty map. And then if you kind of read it from the inside out, it's splitting the plain text row on the very last line on the tab character. And then the fields that we defined earlier, we're mapping that anonymous if function over the fields value and the plain text row. And so what we've essentially done is we're saying, okay, we care about these attributes and the ones that we don't care about, we're just gonna set to nil. And so we end up with two pools of either a schema name and a value or nil and a value. And so then the remove nil will just get rid of all the parts that are nil. And so then what's left is a map of the schema name and the value for it. And so we stick that in a map. So that builds a siting data structure for each row. And then based on that, we can then return a siting sequence. So it's essentially a lazy sequence which wraps the entire file. So with 11 gigs of file, this could get basically impossible in a non-lazy language. But then closure just in a few lines just allows us to get this working. And at that point, once we had the schema, we needed some kind of data storage. So we went to Datomic. There were some features there that we don't really need because this was basically one time right and then just read afterwards. So it was just the import that needed the right. And so transactions and history were not things that we really needed for this app. But then the advantage to using Datomic was the fact that the queries were awesome. They were still closure. So really quickly. So Datomic, we already had the schema and the data import into Datomic is all transactional. So you can basically jump from, so you can go from a transaction to the previous transaction and then you get a database as a value that you can use in your code. And the query language is closure. So we're not using a separate SQL. There's no ORMs. So we're direct and the query itself executes in the application server. And the results, again, are essentially closure maps. So the query in Datomic looks something like this. So for example, this one looks for the tax on order 2881, which happens to be a bald eagle. And it's looking for bald eagle sightings in Sandusky in Ohio. And so the way it does that is it says, if there is a tax on, which matches that number, then store its value in, or get the entity as E, and then make sure that the state is Ohio, the county is Sandusky. And then the count for that one sighting is stored in count. So, and then we do the aggregate query where we actually sum all the counts, which basically tells me that, so it basically takes all the sightings in Sandusky for that species and then sums them all together and then also counts the number of sightings. So then we can normalize based on the number per sighting and then the total number of sightings. So we're basically averaging it out. And so that would return something like 540 and 108. So there've been 108 sightings and then the total birds that were reported seen was 540. Now, it's possible that multiple people went and saw the same birds, right? But by averaging it out like that for all the birds, we get a fairly consistent value. So the next step was to build the web service. And for this, we chose the pedestal framework. And because it has all the features that you would expect from a battle-tested web framework. So it's got a powerful middleware system. It's got its own routing DSL. And then it also allows for HTML templating. So you can specify your HTML as templates and then use other libraries like NLive as one of them, which allows you to transform that HTML and by pulling DOM nodes out as like CSS selectors and then transform values. In this case, we didn't need the templating part because this was gonna be just an API and it's gonna just sort of furnish JSON. But then the middleware system made serving the JSON really easy. So the query that came out of Datomic was closure maps and then we would transform that to JSON and then furnish that. So progress so far, we had the Datomic data store. We had two web, what are called peers. So those are the application servers. And then they would respond to an API request that would look like species slash taxon and then period, which corresponded to the month that we're showing. So the sightings would go from month to month. So then it was time to figure out how to display the data. So this is where D3 came in. And so what is D3? It is a set of libraries that enable DOM manipulation based on data bindings. So when D3 creates SVG, or I think it even supports Canvas, but most applications use SVG and in this case, there's a lot of support for displaying maps as SVG paths. And so the SVG nodes it creates are bound with data inherently. And then, and so in our case, what it allowed us to do is to use like the county information. So this map displays counties and states. And so we could say, this is the county I'm looking for. And from the Datomic query, we said, for this county, this is the statistic that we got, right? And so the data allows us to like look through the, or like the data binding for the county gives us the county name. And so we can look through our JSON data for the frequency for that county, for that species. And quickly, I don't know how much experience folks have had with D3 doing mapping stuff. No, okay, so really quickly, so the way D3 builds a map is by consuming a data format named GeoJSON. And so GeoJSON is a subset of JSON which encodes a lot of geometric information. And so D3 can basically structure that and basically parse that into SVG. And there's another version called TopoJSON, which is way more informationally dense than GeoJSON. And so what it does is like, it's aware of topology of the curves. So it can say, if there's intersecting curves, it knows about like an inside and outside or a left side or right side. And then it represents it but with only one curve. So it like condenses the data by a factor of like on large datasets, it could go up to like 80%. So like TopoJSON is like the fraction of a typical GeoJSON payload. Anyway, so we needed some way for the web service to also send that static GeoJSON over when D3 needed it. So that was not true data omics. So that was just static data. You download it once and it's just served. So, but then displaying that using D3, so this is where we were like, okay, got closure script. And so there were some immediate wins for using closure script. It was easy to integrate into the existing stack because there was, there's already tooling around it for if you're using closure stack, closure stack. It's essentially the same language on both the client and the server. You're describing your front end in the same terms as you're in the same functional way as you're doing the backend. And then interoperability with JavaScript, which is awesome. And in case of D3, that was where it started. But then it always comes down to this. It's like, so what is closure script? And whenever, here it's probably, I don't get this kind of reaction, but like other places when I mentioned closure script, it's like, what? So it's essentially a compiler foreclosure to JavaScript. And so what you're writing is actually still closure, but then the build tools know to compile that down to JavaScript. And not just any JavaScript, it's JavaScript that's optimized for the Google Closure library, which is another set of tools that allows you to do all kinds of magic on the JavaScript that's emitted. So anywhere from minification, but then it can also do something called dead code elimination, where it can, where if you provide, if you tell it exactly which parts of a library you're using, it will make sure to use only those and not concatenate anything else. So your payload is really small. And it has several benefits over vanilla.js because you're writing closure, you get the benefits of using persistent data structures. You can use object keys in your maps, but Jason, you're stuck with strings. You can use, you can, you have laziness. You have macros. You can write functions that write more code. You have function argumenty structuring and JavaScript, it's major pain. So these were some immediate wins. And so for example, this is what JavaScript interop looks like. So if you were in JavaScript, if you were to, can anyone, can everyone see this? Okay, so in JavaScript, if you were to declare a function, you can do the same thing in ClosureScript as a function, then you can use that internally. So if you see in the ClosureScript part, you're calling dot select as a method. And the first argument to it is the receiver. And then the next argument is the arguments that the function actually takes. So that's very similar to how closure interrupts with Java. And you can retrieve properties from an object in a similar way. So like in JavaScript, you would return say d3.event.target. So it's a nested structure. So in this case, you can use the dash syntax to pull out nested data. Or there's also a macro, like a double dot macro that allows you to go in deep and fetch what you need. Fluent APIs. jQuery has fluent APIs. D3 has fluent APIs. So basically it's transforming the result of calling one function that gets fed into another function and so on. So with ClosureScript, you have the threadfirst macro which allows you to do the same thing. So the result of calling jsd3 timescale can then become the first argument to the domain function on the second line. And then the result of evaluating that becomes the first argument to the range function. And if you notice the js slash d3, so the js is the global JavaScript namespace. So any external libraries you use will be available under there. And then you can instantiate, if you look on the second line in the ClosureScript, you can instantiate the new dates by saying js slash date dot. And then that creates a new date object. And then you pass in the arguments just like a regular Closure function. So progress so far, we have a prototype. So we had the back end, we have the topo JSON getting furnished, we have, we're responding to API requests, we have the d3 making JSON requests to the back end to fetch the JSON it needs. So, so far the client side components we have the map, we have the date slider which just all it's doing is like when you go from month to month it just requests the next payload from the back end. And we have the species list which right now is just one long list of allies. So like there's no autocomplete, nothing like that, it's just you had to use the browser find to like look for a particular species. So it was a prototype and it works. We were using the entire Closure stack but it was very basic. So it was very unpolished. There was really no structure to the data because the data was just getting fetched ad hoc. So as you move month to month it would make a JSON request every time. If it happened to be the same month and it got cached in your browser, awesome. But otherwise it would wait until it fetched it every time. There were issues on the back end side. I mean this actually surfaced that our API was definitely really slow because of how we had structured our schema. And then there were internally between my coworker and I that built this. I was like, hey, we have a prototype, it works, great. But he was like, no, no, no, there's more we can do here. And of course it's nowhere responsive. So it was only on the large screen. You made it small, it would just not work because SVG on smaller screens and tablets is really slow. And we were rendering close to 3,000 SVG elements because we were rendering the county level map every time. So this is where React and Ohm came in. And for a quick overview of React and Ohm I did a workshop earlier. So those of you who were in that you've seen this before but I'll quickly go over what it is. So pretend you were in imagination land, right? Pure imagination. So we know that DOM is a pain to work with. And this, however this is an example of an Ohm component. So like this is the autocomplete that we have. So thinking about how we would render this or how we would build this using maybe traditional JavaScript methods. You would probably have a list down there. You have an input field. That part is good. But then how do you match on what we've just typed out? For some reason it's a little out of place. Okay, let me try it one more time. But you get the idea. So if you think about the DOM, what the DOM would look like, you probably have a UL, just a list of the species with allies inside of it. And then links maybe nested in each ally that point to the particular taxon, the species of bird. And building the list would look something like this. You would say that ideally you would have something called a species ally, which would be responsible for building that map, which represented one ally element. And then you would map that species ally over all the list of your species. That way you get a whole bunch of allies, right? And then you would probably apply some kind of UL function over it and then you would have what you need. And then if you were to actually narrow down the species based on what was getting typed, you would need to store that somewhere. The match string, I mean, so the black DHR is how far the user got, but you would kind of hold on to that somewhere and then match that. So we would have a match string function that would take the species, the name of the species, and then match it on that, some kind of regular expression match, and then filter only the ones that return a positive match. And then we would actually map the species ally function over only the ones that came back. So the result of the filter is, again, a vector, but it's a smaller vector, it's a subset. And so we only map the ally over the ones that match the filter, because we don't want to render the whole list at that point. So you would probably have something like a filter list items, which would take the filter text that the user typed and the entire list of species, and then it would return a UL, and internally it would basically create a bunch of allies by mapping the species ally function. So that's theory, right? Unfortunately, we don't live in imagination. So this is where React comes in. So what React will allow you to do is it will let you render the DOM you want, and then it will take care of the details in making it show up in the browser. So what it builds is what's called a virtual DOM, and then it will, anytime you need to make changes to that DOM, it will batch the changes that it needs to make, and then push those into the browser as required. And then it supports, it's really amazing how much, how detailed it is. I mean, it has its own synthetic event system, so any events that originate in the virtual DOM, it will capture and it will give it to you so that you can implement your handlers on it, which are also just changed data, and then your DOM reflects that change. And then OWN is Closure Scripts Library, which builds upon React, but then it takes it one step further because React has a bunch of heuristics that it performs to know which parts of your DOM have changed. And if you think about it, it's working with JavaScript data, which can get arbitrarily changed at any level, and you would never know about it. So React tries to keep tabs on whatever levels of data you have, and then based on that make intelligent guesses on what changed or what needed to, what needs to be rendered in your DOM. But then Closure Script gives you mutable data structures. So what OWN does is it test-chews some of those heuristics and says, I will tell React when something has changed. And internally, the way it handles data is through Closure Script as opposed to JavaScript objects. And then it allows your DOM declaring functions to work with Closure Script data in what's called cursors. And then that allows it to keep tabs on not only what the data is, but where it is in your total application state. And when it does that, it can immediately tell whether something has changed based on a simple equality check. So like, if something has changed way down deep in a cursor, then the resultant cursor is a totally different data object. And so based on an equality check, it can say that this has changed. And so it knows to render all the components in that hierarchy. And so out of the box, oops. Out of the box, in initial tests, OWN is actually faster than React itself, even though it uses React. So in our case, this is what the species list would look like. So it would, so the REFI part returns an instance that knows how to render itself based on some state. In our case, the state is, for example, what the user is typing in the input box because we want to hold on to that, right? But that's transient data, so it's not something that we need to track at a global level like the species list, right? The species list is something that the entire application cares about. What you're typing in that data field is local to just that component. So that is available in the state variable to the render state. And so basically what you're doing is DOM-UL is a, so the UL function is a macro that OWN provides. And so you're literally applying a function to the result of building species item function over the list of species that have been filtered down based on whatever the user has typed in. So this almost matches exactly with our ideal implementation. Handling events, you can have like an on-click handler. So the tax on link that we were talking about is down here nested inside the LI, you can see the DOM slash A, so that's a link. And the href just refers to the tax on's path and then the on-click. Essentially what it does is it uses core async, which is closure scripts and closures way of handling asynchronous events in a way that seems synchronous. And so in this case, what it's doing is it is, so if you click on that link, what it's saying is this is the species that the user selected and it puts it on that channel. And then the app then knows that this was selected and then it knows to render everything according to the species that was selected. So at this point, this was where I was. It was like, okay. But it took me a little while, obviously, to warm up to that. And it's totally a different way of thinking because especially if you're thinking in terms of, oh yeah, my data is just gonna be what I fetch when I need it and then the component that fetches it is gonna be responsible for showing it and then other components that need that data are SOL, but in this case with OM, that's not the case. The data is canonical, it's in one place and then the components are all that are interested in a particular piece of data all get that identical cursor. And then so whenever that changes, they all know that it's changed. And there's a very strict API about how to change that canonical data. So I went ahead and built another component there. This time the one which actually goes and fetches the photos from Flickr. So first, I needed a way to integrate with Flickr. So I wrote a quick little helper, helper module that allowed me to do that. So there's libraries out there, Closure Script libraries that allow you to work with Flickr but they're huge because they talk about signing in, authentication, fetching your photos, sharing photos, uploading stuff, I don't know. Like all kinds of things that the Flickr API exposes. I didn't need all that. All I needed was I had the string that the user entered. That was already part of our data. So all I needed to do was hit the Flickr search endpoint with that string and then retrieve data based on that. And then Flickr for better or for worse, it allows you to specify how many results you want and then it even paginates it for you. So like you can say I only want per page 20 or 30 or whatever. So but then the fallout of that is that you have to make two requests. You have to first hit the search URL and get the URL to one of those results. And then you have to hit that other URL to actually get the image data, but that's it. So two requests. And so, and we already know the base endpoint and then all we needed to do was add this huge query string with all these things that Flickr needed. So part of it is the API key. And then among other things, right? I mean your search terms, what size image you want, the per page, how many results you're looking for, stuff like that. So there's this library by Chas Emmerich who's huge in the Clojure community. He's behind pretty much every third library out there is probably written by him. And he has this tiny little library called URL which all it is is a protocol. It defines a protocol that has these, that basically it wraps a Clojure script map or a Clojure map. You can use this library both in Clojure and Clojure script. So, but what you can do is like you can specify, you can give it a string and then it will return an instance of URL and it will decompose that string into different bits and pieces. So like the protocol, the username, password, the host, the path, all the things that you'd expect in URL. But then what's cool is that it also gives you a query string map. So the query is key value pairs, right? So it really translates really well into a Clojure map. And so the URL query is a map. And then if you wanted to put things on that map, you just call a source. And the source is basically Clojure scripts like a hash merge or like, you know, a way of specifying, adding or overwriting a key in a hash. So we do that. And then if you call string on the result, so the str in the last line, that will give you the URL all put back together. So it's consistent. And if you wanted to do this in JavaScript, it would be a lot of string wrangling around. And, you know, and I tried, you know, really quickly to do that until I found this and I'm like three lines and all I, and it does all I need. And so this is the syntax highlighting is kind of messed up on this one. But so I'm using jsd3.json to make a request to the search URL. And the search URL is a function that returns the search endpoint for Flickr. And then based on that, what I do is the data that comes back. So the second argument to the d3.json function is the callback. That happens when the json comes back. So when the json request is successful. So then we are calling om update. And we basically, the model is the app state and we're storing the first photo in my results in the app state. So, and then secondly, if we needed, if you look, if you remember from the demo, you could actually hover over the picture and then click on a link and it would fetch the attribution for it, right? It would actually tell you who took the photo so that you can again click on it and it'll take you to Flickr. So that's the second example. So where if you clicked on view attribution or whatever, it would actually go and fetch the author name for it. So this is the entire selection image component, right? So there's a DOM image, which is the image tag. And there's some helpers in there, but like there's a default of the loading PNG, which is like a placeholder image. But then it looks in the model for a URL queue property which is what we put in there when we go and fetch the image details from Flickr. And then there's the second part, the div with the attribution, which has again a buy div which has the attribution in it. And again, there's some conditional stuff on whether the user had clicked on it or not, but it's fairly simple. I mean, you can actually scan it quickly and maybe squint a little bit and you can see the DOM declaration right there. So progress so far, we have the same thing, but now we're actually using core async and ohm and our components are now reactive and the data is handled way better, it's more safe. But it's still rendering to the large screen. So now we have not only the first three that we started with, but we have actual push state, which allows us to preserve our links. So if we do some client-side routing based on the tax on that we click, and then we have the photo of the bird, there's a header which also displays the name of the bird that was selected, and then the type of head that we just saw. And so this is some of the things that are stored in the global application state and they all affect how the app is displayed. So the current tax on shows up in the URL, but and it's also in the links on the list. The current name shows up in the header up there, this is what the user has clicked on. The time period is manipulated based on that slider, and then when you go back and forth between the months the push state is updated or the URL is updated. And then the photo and then the taxonomy is like just the entire list of species. So that's all over there. And then the frequencies show up on the map. And all of this data is kind of stored in one canonical place, but then all these other little bits and pieces of the UI are listening to these specific pieces and know exactly how to render that. It's way better. But again, so we've addressed the unpolished UI. We know that the data is better structured. The database query, we worked on it and optimized it. And Datomic lent itself really well to like changing the schema and partitioning the data in specific ways that allowed us to like, we basically separated out by species so that all the sightings for A species were in one partition. And so we could like get that fairly quickly. And that's what is cool about it is like Datomic and enclosure will allow you to munch your data because data is such a first class citizen. It allows you to express your data the way that makes sense for your application. Instead of like being locked into some kind of model or like some kind of object, right? Which hides that with Datomic you can, or with Clojure you can massage that and like express it the way you want. So now we're on the same page, we're rendering home. But then it's still not responsive. So now, I hope this video works. So now this is what it was on the big screen, right? This is what we were seeing. But then if you made it smaller, it would still work. But this is what we want to do. And now if you look, the map is not as granular. It's not, you're on a smaller screen. You don't probably care about county level data. Oh, and it pauses again. That's super annoying. Okay. I could probably do this really quick. Go on doing it live. All right. So when it starts up it like picks a random thing and then goes and fetches the photo. And you can say view attribution and it will like fetch the name, whoever it's by and then you can click on it and go to Flickr. But then for responsiveness, half the screen and then it's rendering something different. This is quicker now because it's, and then you can go smaller and then look what happened with the slider, right? Now we have big buttons that we can tap on. And then you can still drag the snap around but then the layout is different. It's moved to this layout. Some of this you can do with CSS, right? You can change where things go. You can make media queries. You can do that kind of stuff. And those of you who've used Flexbox that makes it even simpler. But then there's other things that are happening though. If you just showed and hid things with CSS, that still doesn't stop you from making queries. For example, the photo, right? When each time you click a bird, it'll still go out to Flickr and fetch a photo even though you're not showing it, right? So CSS doesn't help you there. And then you can move things around but you don't want your app to be making unnecessary requests. And for example, the county data. How does it know with CSS to say, okay, when I'm rendering a smaller map, don't go to counties. Just show me the state level data, right? My map is tiny now. So for that, it is an app level concern. So I came to the realization really quickly that, sorry, that screen size is user input. So when a user pulls up your site on a device, they're telling you how they're, sorry, they're telling you how they're using your site. So that is user input. And so your app needs to know about that. It needs to be intelligent about it. So this is where we were like, okay, let's figure out with JavaScript how to find, or what size the user is viewing our app on. And we made sure that we put our breakpoints where the design actually broke when things were getting crowded or like overlapping. We were like, okay, this is where the layout needs to change. That you can do with CSS. But we still need canonical places or at least application level ideas that reflect the screen size. So we said roughly, there's an excess which is extra small and small, medium and large. Large is just a large screen. And medium is, for example, landscape mode on your iPad. And whereas small is probably portrait mode. And then extra small is the fault. So there's the library, there's JavaScript library, tiny little one called inquire.js which allows you to, it uses the browser's match media API and allows you to have to register handlers when the screen size changes. Or like when it can detect what you're, it can use basically what looks exactly like media queries and let you know with JavaScript when that changes, when that matches or does not match. So in our case, the right side is cut off a little bit but then basically what it is is just the string excess small, larger or medium. So in each case we're saying when the screen width is between these limits, call the size handler and for this size. And what the size handler does is, you guessed it, it will, so it's right there. It's a function that again changes the app level data and stores the screen size on it. That way our components can then look for that string when rendering themselves. So the client changes that we needed were so that the components now have the logic to actually look for the screen size attribute as well. So then the map can be smart about rendering states on smaller size versus counties. The photo does not render. There's no photo component on smaller sizes. If you inspected the DOM on there, you would not see that whole thing. React just does not render it. The slider changes from that big long input range to a little select box and buttons that you can toggle. Actually we can look at that really quick. So when it's on a tiny little screen, you can go pick the month you want or you can go forward or backward and it responds to that. And then the Ajax calls needed to change too because the map data now does not need to fetch the TOPO JSON even though it's small, it's still an order of magnitude too big for rendering county data as opposed to state data. API requests changed because now you only fetch data that makes sense at a state level as opposed to the county level. But then it all turns out to be just the, that if condition right there. It says if my screen size on my model contains larger medium in it, then use the slider. Otherwise use the select. So there are two different components, but only one renders based on the screen size. And again, we're not using CSS to render both of them and hide one of them. We are actually making a logical decision to render the one we want. And server side, we're not passing a query parameter whether I want county level or state level data and then the query needs to handle that. Do you have a question? Oh, okay. And then, right. And then the data log or like interfacing with Datomic to get the right data aggregated. And so now we were at a place where we had the app we wanted and it was responsive. So we were ready to ship. So that's all I have. And at the end of this, we have like three or four pages worth of resources. So there's blog posts that I've written based on my learnings around this. There's birding resources for the three people that were interested. And there's closure, there's tons of material on closure. I mean, these are some of the highlights. Are we there yet is like almost a seminal talk that talks about the ideas behind closure. And then core async is another really interesting concept. It takes, it bottles a lot from go in terms of how it handles asynchronous code. And then for closure script itself, there's some really cool articles and videos. So and on react themselves. And then D3. Mike Bostock has basically flooded the internet with examples. I mean, there's a load of stuff to look through. But then Scott Murray has some really good introductions to D3 itself and how data bindings work. It doesn't talk about mapping though. For that, you would look at Mike Bostock's map example. It gives you a very simple way to build what's called a corocleth, which is what that map is, which shows how a statistic varies based on location. And then there's a really good example by Mike Bostock also that's called building a corocleth in which he goes from scratch and like downloads the shape files from an open repository, parses them using his topo JSON library and creates the topo JSON. And then shows it up in a browser and then uses a statistic to render it. And then there's a site called, I think it's called geojason.io, which allows you to play with it just to look at what that format looks like. And that's it. That's all I have. Go ahead.