[LC74] Working on random plugins and answering questions

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
do [Music] do [Music] [Music] [Music] [Music] [Music] [Music] do [Music] [Music] do [Music] [Music] [Music] do so [Music] okay i think that will have done it let's do one more air chat or one more sound check here all right i think that's good uh apologies for the a little bit of a late start there but uh this is not supposed to be on pardon me there we go that'll make life a little bit better should i spin my chair around um something about this is a little brighter than usual too maybe this one got bumped while i was doing some video work let's see a little better that way a little better that way all right there we go i been too much time with the other part uh it's a little bit warm in here and uh some of the uh some of the fans got moved around uh one of the things that i have been working on recently is that area that's back over my shoulder uh right there still has a bunch of uh work still to do uh with the uh see the curtain covering the closet now but one of the things i did was if i can aim the remote correctly uh is a little bit of uh that type action there's now lights uh ringing around that and i have the standing desk there so as you can see uh they have the piano over there needs to move so that the desk can move to the right and forward then the camera can be somewhere in this area shooting me in that direction and uh hopefully uh videos will have a little bit of a higher quality uh still a bunch of work to do there also i have to uh figure out where my lighting is going to attach because of the normal attachment points for me are up here on shelves that are above me here and on the monitor over there but uh there's guitars on that wall so that's going to be tricky hello ashwin welcome to the stream um just explaining that uh the video section back there and as a result of all the work i was doing to uh set that up a bunch of things got jiggled around in the office and as a result the uh i jumped into the stream tested everything out and realized i was gonna die and all the fan placement was all wonky and playing into the mic but uh i think i have it all sorted out now i guess the last thing to do is remove this bracelet because otherwise it makes an annoying stretchy scratchy sound on the desk we are good to go with some amount of live stream action and i didn't really have too much planned for something like this i've been actually thinking about uh videos for the other channel and the notion such as it is because so many people keep asking for information on what's new in sublime text 4 and and on and on and we always say go check the change log and people want to know what the hot takes are that uh one of the videos i do want to create at least a a series of videos but one for sure is talking about what is new and i need to record stuff for that but i don't want to put it out publicly until there's a public announcement but there's no reason i couldn't record some clips that explain some of those bits and have them in uh an unlisted video on the channel and then when we get closer to an actual release i could polish them up something i have been pondering and as a result i wasn't paying enough attention to how it was in fact tuesday today and uh stream time but uh i have been actually getting some actual use out of sublinet the package we've been working on in the last couple of streams or this is the last one i can't remember i think i think so it was something i was working on during the previous stream day to last week's stream when i wasn't really willing to get on stream because i had had a tooth root canal that same day and that did not go as well as the one that they did on this side uh like a week or two prior um i have been getting some actual use out of it there's just a few more things in here to actually do i'm not sure how many of these we might actually get to because one of them is syntax related and syntax highlighting is spooky but at least what we could do is work out making what goes to the panel make it less ugly for lack of a better term um so there's that and i think uh that might uh take us through uh all the way to the end we'll see what's happening because even with uh the fans blowing in here it's kind of warm which is weird because the air quality here has been absolutely abysmal for the last little while there was a wind change in the uh the smoke uh swung down and the sky was incredibly overcast and it was very cold for a few days but it seems to have recovered nicely unfortunately more fortunately i mean it's good for the environment for those of us that like it a little bit cooler that sit in a room in the nexus of a bunch of computers a little bit more coldness uh would be nice in any case um that is enough rambling i think everything seems to be going good and uh clock's burning so i'm gonna press this button down here and uh we'll see what happens [Music] hello of blind text phonetics oh that nerdy welcome to live stream for september someday after the 12th because that's my birthday i'm gonna say september 15th it's probably what today's date is and uh as usual we're going to be doing some sublime text package development here and i think what we're probably gonna work on is the sublinet package i got a few things down here in the to-do list this one at the top is the scary one so we maybe uh leave that one or maybe not that might be something interesting to uh fiddle with actually so we see what we uh can do with that one um definitely one thing i want to change is these two things are right here um this is actually something that i an idea that i took from the sftp package it has a setting uh that's packaged by will bond by the way it's a pretty great package if you ever find yourself wanting to edit a file remotely and you have ftp or sftp access ridiculously handy i use that more than i use remote subtle which i do use from time to time that's handy to trigger in the other way anyway i digress that that package has the ability to pop up a panel when there's uh information to show you and then it auto closes after a little while if you want so i thought it would be nice to do something similar to that as well because right now that is 100 hard-coded and the other thing there is this one implement the proper token ring in the introduction message as i mentioned at the end of last week's stream i think the introduction message that gets exchanged between machines um both as part of the broadcast out to advertise that we're here as well as for incoming messages have a username and password field inside of them which are currently populated with a hard-coded data just for testing purposes because i took those a little bit of that code from a prior project but the idea that i had why i left that in there is that you could provide instead of a username i'm calling it a token it could be your username it could be something different but the idea is if you could put that in a setting that would go out in the introduction messages and uh to advertise yourself to other people and those other systems could use that information to decide if they want to be able to connect to you or not um so if you had you know for example if my co-worker and i were both working in sublime he doesn't use sublime he's a vim guy and i am too but i prefer sublime for most things but if we both were here and we both wanted to use something like this with our multiple systems then we could make sure that there's not any crosstalk between them by having our own token and then certain things would connect and then if we're going to do that maybe some sort of token password system that you know someone just has to throw a password in there to be able to connect so that someone can't just you know pop in with say the default token and be good to go i don't know uh how far down the line we really want to chase that unless we decide we want to release this but we do have the facility in there and it's easier to use the field than to try to take it out because that requires recalculating offsets of things so we got that going on and one other thing that's actually not in this readme here is something that ash one mentioned in the last stream which is what if it transmitted the entire clipboard history to another host when it connected which i thought was a pretty neat idea as well because if i was working in sublime and then i thought oh i should totally go do something on my linux box i fire up sublime and boop it's got that whole history uh good to go so that's easy enough to do with just using the messages we already have for shipping off clipboard information because we already have a cue mechanism in place to be able to shunt messages out and we can dump a bunch of them in there and let them go but maybe we uh have another message that's like that a clipboard history message that has a boolean or it doesn't even have to be it could be a duplicate of that message that just has a different name the idea being that perhaps on one system you want to disable the ability to of another system to transmit its history one of the things that you know i tend to do if you've watched my streams long enough is if there's something that's relatively easy to add that makes things more configurable and better for the user why not add that in because people do like to use different things in different ways take for example the conversation that was happening in the discord right before we went live where somebody wants ostensibly to do what terminus and other packages are already doing be able to change the foreground color but it's unclear whether they didn't want to use that functionality and wanted the core to do it or if they just don't know that that exists but different people want to do different things well if it's possible why not make it possible so which one of these should we toggle first how about this one configure whether the output panel opens automatically or not when an output is logged to it currently it always opens and that would go hand in hand with this um and let's see if i was to grab a browser window i should switch my chrome to dark mode huh that other monitor is much bigger than this one there we go um all right so what was i just thinking about there packagecontrol.io we look up the sftp package because i can never remember the actual uh page homepage okay well this maybe that might be a better idea one of the items in here is settings um and um we're doing this in the web page and not looking in my actual settings uh because one of the files has my license key in it and uh you know better safe than sorry uh so controls where the output panel is hidden true only shows the output panel on error false always shows it and never hides it number shows it and hides it after a certain number of seconds i think this is kind of the idea that we wanted to have here so you could set it to only on error always show it and never hide it whenever it's displayed or some number that makes it pop and go away in seconds defaults to one right now what the code is actually doing is basically this if this setting was defaulting to a value of two so with that in mind let's move that over there we would need a setting for this one um so these are all the uh network settings and oh and by the way um this code should be pushed up to the github repository um i did some tweaking of the comments in here uh so it'll look different from uh what it looked like previously and we're in a new sublime text build where they fixed the uh the glow so we're back into the glow and things automatically are already look a lot better okay okay um what if we called it auto show panel and set it to default to 2 and then said [Music] should the output panel be automatically displayed valid settings for this r always show the panel on output false only show the up the panel on error and number and again this is probably one of those things that we might tweak between now and when the code actually gets up but i like to this is one of those things sort of treating it somewhat like a comment in code if i write down in here what i'm intending to do it helps clarify in my mind that i'm intending what i mean to be intending so we can always show the panel only show the panel if an error occurs which would be i guess a disconnect of some sort and number is always show the panel but hide it after this many seconds um yeah and if we had that then we probably need to go into the utils uh where the settings file is uh oh and it's up here pardon me so we want a little bit of that we are we're back in glow mode it's exciting isn't it i really missed it i tried so hard to keep using this even though it was broken because for some things it did not it looked wrong but still legible um but for some things the way the glow was offset and muddling it up it made it really too hard to read so that it was some uh some rough action there i got myself habituated to this which is funny because i think i've mentioned i just threw that rule in there because i wanted to test that out and i was like ah glowing who wants things to glow turns out me i do i still haven't taken the plunge into doing it in things that aren't python though um but realistically maybe i should because uh at home and a hobby for hobby purposes pretty much just use python for working with sublime and packages but at work i'm doing web stuff with typescript maybe if parts of that were glowing it would be more interesting to me um all right so we have a setting for this what now i guess uh anywhere we might be displaying stuff we would uh want to know about that so that we know how to how to do it right actually oh this might get a little bit more complicated um the log function for logs where the panel is true this should only automatically open the panel if a configuration item says so there should be an additional config item that indicates if the panel should auto close or not um issues with this involve in order to pop this only if we want to which is essentially this we would need to know if what was being logged is an error or um if we could always log it to the panel and then have another method to call that essentially does this right how would we structure such a code anything that called log with can i scroll that up a little anything that called this with panel set to true that just means it's sending output to the panel because we want it to sometimes always be displayed sometimes only be displayed on error and sometimes always be displayed but auto close itself after some delay which is currently five seconds hard coded here pardon me i thought that was two [Music] i guess we either need to make this log function have an additional auto display panel or an additional panel is error or something i don't want to overload the error parameter that's already here because that one causes it to display an error dialogue and go away and we definitely want the ability to do something like that to draw the user's attention i don't want to get into if error and not panel do this otherwise assume error means something else i guess that would work but it seems kind of messy am i doing this one per i am huh so what would something like this look like if we were doing it it would be a display panel would need a window i guess well this is already pulling it from the active window right so yeah we don't care about that um is error equals false let's say and then we would say display the output panel based on the input parameters and the uh value of the auto show panel setting so this would come down here just for now you do that um we're gonna need to look at to do from utils we need that thing i just did which is this that draws my eye every time over here on this system where's my mouse over here on this system there's a copy of sublime running on the laptop right there uh and every time i copy something it pops over here which is also something i want to tweak but i don't think it was in the readme let's open that up this auto close thing also needs to be a little bit smarter than it currently is oops all right maybe we'll just do it this way because that track pad is awful i'm going to make this real big the console is filled up with lines that say dart thought to dragonland.org org updated the clipboard 15 characters 80 characters 13 characters and so on hello ph uh welcome to the stream we are curious to say that's not going to do anything so what does this actually have to do here uh we definitely don't want to do that and we probably want to fix that too right um uh one of the things that should happen here regardless of anything else uh is we need to know which panel is actually open uh oh sorry i guess i gotta go to the api help for that one returns the name of the currently open panel that is the action that we want for this uh active panel is equal to that well i guess we do that right [Music] and throw in a little bit of that action if active panel is not equal to uh oh put dot sublinet then do this uh the idea there is that uh if the current panel is already the output panel then this doesn't have to do anything and it would just leave actually maybe we do that a different way now we could say this it's equal to then return and we don't even have to do that right so uh i guess we could even refactor that even further because if that's the only thing that's going to use it then we can just do it this way instead oh and that no longer needs to have that so get the active window if the panel active panel in this window is already the output panel you don't need to display it it's already open and in that case it's also not going to try to automatically close it after some number of seconds yes i'm aware google changes their certificates every 15 seconds i feel so secure okay so uh we need to do i guess um let's do over here and say search for [Music] panel equals true it's the only place that this is getting invoked is inside of the net handler what the hell is this doing in here that was probably not strictly necessary so this would also be display panel here and the other one is there because both of those are in that really still seems kind of rough like maybe it should be a little bit smarter about that [Music] let's verify that and will the panel pop do they already miss it let's see copy well that may be mildly bro oh you know what it is it is it is more than mildly broken i forgot uh our usage of enumerations and uh the use of automatic package reloader are a little bit conflicty with each other right okay so that would make sense i guess all things being equal i probably shouldn't call it if i'm not going to import it right that's from here i guess for this one we probably want this we save this the whole plugin will reload in theory well that one's certainly doing something copy well there's a small possibility that this code is actually broken now so maybe we do a little something like that um and restart this to oh we're gonna we're gonna be all happy about it now are we all right i'm gonna do this um i'm gonna open the console in a window sort of leave that sitting there like that oh no maybe i won't because that won't fit on this monitor with my new fancy thing here if we were to open this particular panel and then swap over to this one and copy some text all right that looks like it is working yep that is panel's already open cool uh ph says are you intending that default modules list to persist every call which default modules list is that this one up here in the reload thing there's an interloper in my hallway and the dog wants to make sure that i know about it okay so that is working ironically i spent a bunch of time doing this and i probably didn't need to um this particular list of modules up here in the reload thing uh yes it's actually something that gets called from other places and here as well so for example this call is to reload source which makes sure that it loads the source file and then if we look in the init in that one it's got another sub call for that so i have to remember to add something in here but that makes sure that it always reloads all of the modules now that's just the default so that it works if you don't actually call it with anything that one i intend to always be the same yes or rather once it's called with one of the other ones it will always be a correct thing but i'm aware one of the neat things about using arrays and default arguments is they're only ever initialized once when the thing is compiled and not every time a call is made for the purposes of this thing every time this plug-in loads it effectively recreates a new version of that and the only thing that calls it without a argument is this one right here so in the end it all tends to work out the way that one might expect okay um next if we remembered what our setting was uh tricky a neat feature indeed yeah one of those things that's great 99 of the time and then that one percent of the time you forget and get kicked right in the butt but yeah um we need uh well let's just do this first auto show panel pull that out and this is going to have a value of what it's going to be true for always false for only on error number for always so if that's the case then uh we want to follow through here only if this value is true or a number right the numbers are truthy so [Music] that call's going to make sure we always get a value here i guess not all numbers are truthy 0 is not truthy is it 0 is falsy would what would you expect to happen if you set auto show panel to always show the panel but hide it after zero seconds would you expect it to open and immediately closed or would you expect it to open and close so fast that you never actually get a chance to see it actually doing anything because that's sort of what would happen there right um no uh so show panel is equal to that as we say here true for always false for only on error so if we said if not show panel and not is error return does that do what we want if we expect this value to be either true false or a number then if it was true not true is false so that'll never happen if it was false then not false is true it continues on and if it's a number that's non-zero that's true so it's false so it doesn't go in so that seems like it would do a thing and if that first part ends up being false then we only want this to happen if his error is true and we can always do that and then if ah all right i've been doing so much javascript lately uh i don't trust myself if is is instant show panel ant oops want a little bit a little bit of that and show panel in the world of the purely theoretical uh let's see we don't want that we want you okay um testing testing my coffee's in the way see from sublinet dot oh gosh no it's not source it's utils import uh already forget uh display panel no huh all right oops display panel well that really seems like uh maybe should have shown a panel oh print leaving active panel is already the output panel and i think i don't need to do anything oops do not it's very important that your debug logs have the appropriate thing and then that would actually show the panel um so if i did this is there is false what did i set that default to some number right is it just me or should it uh that must mean it's down here huh showing the panel and hiding after do and show panel back to here save that always remember to re-import the symbol when you do that or you'll be unhappy i'm kind of confused about that one i'm not gonna lie um oh okay oops maybe a little bit of that will make it a little bit nicer huh there we go ah do i hate that yes i do okay uh so if i said this it should be hiding the showing the it says it's showing the panel and hiding after two seconds uh but for some reason it doesn't show the panel which is odd uh but it thought it was doing the right thing if i set this to true then it's doing that okay um i probably shouldn't have closed that file huh let's close that and that and for now that i'm going to need that one in a minute be unhappy open the settings so if we set this to only show the panel on error for example thus then if we did this i don't think i need to do anything uh and it thinks it doesn't need to do anything because of that bit right there it's false and it's not an error but if we passed in true then we get it saying showing the panel hiding after zero i think that tracks with what sftp does theory being if you only want the panel to display on error then you never want it to auto close you probably want something like this and show panel um weird that is very disconcerting uh if you want the panel to only open on error you want it to stay there until you see it but we probably don't want it to automatically pop that up when the value of that is zero actually how is that even working if the value is false shouldn't that not have done anything at all let's double check that this one thinks it doesn't need to do anything and if we said true that this is an error well the panel actually displayed so that's nice um kind of concerned about how there's nothing in it probably make sure that that all works yeah uh it says it's showing the panel but it doesn't necessarily say that it's gonna hide it right which is what we want if we set this to true what happens in that case when we call it with no arguments tightening after one second am i doing that backwards that one uh i'm not gonna lie that one catches me by surprise is this something to do with how ints have a bool method so that they can be considered truthy values checking it that way turns out to be actually a thing because well that's an issue um we don't need this part well i think that's a good idea anyway i'm going to type something over here python is instance of boolean comparing boolean and int using is instance can someone give me an explanation why is instance returns true in the following case i expected false hey i expected false too bull is the subclass of in all right so that's one of those things that you inherently sort of figure as a c programmer for you know an ungodly number of decades right correct way to solve this depends on what you want to be if you want true to stop being an int too bad that's not going to happen you need special handling for that all right i i i like the uh the verbiage there do you want booleans to be an int too bad not being it's too bad not gonna happen um true always shows the panel and never closes it false only shows it on an error but with thus also never close it right so yeah what we really need is we only want to call close after delay if it's a number and if we want to do that oh i'm using javascript is going to be the death of me uh if it's not a boolean and it is an integer and that integer is non-zero do a thing it's got to be a better way to pull that off but that's not the right file pardon me pull the new one in hi so not with an error with the actual value set to true says it's showing the panel because it just always shows the panel it never needs to try to not close it set it to false and it doesn't think it needs to do anything unless you tell it it's an error and then it says it's showing the panel but it doesn't go into that particular value if this was two um i suspect i have a bug in that code uh and i just think i just realized why that panel just disappears uh for no reason so if i did this the panel looks like it's not opening and yeah that's because that's not seconds that's milliseconds so yeah two milliseconds there's not really enough time to actually see that happening um but lastly if this value was zero then it doesn't think it needs to do anything in that case that's weird oh because not show panel huh well first of all let's fix this that'll make that problem go away so if we actually did this we actually get to see the thing for the one two seconds uh theoretically unless i broke that code maybe we need to fix that too one two did it say it was hiding after no it didn't right because i tweaked that thing i want this to be two seconds uh oh right right right reload the plug-in then re-import the symbol then do that that value set to 2 1 2 panel goes away cool so i guess this kind of makes i'm gonna say that that is cool if you actually set that to be always show the panel but hide it after zero seconds the ultimate effect is it never tries to open the panel which is good because as we just saw if it tries to even two milliseconds isn't enough so in that case we don't need that we don't need that we don't need that and we came back over to whoops this one over here save that to reload it um and now we can go back into net handler both of those calls to display panel in theory i have that set to two seconds so if i did this hmm i think we need to quit and restart this that moment when you count up to 10 when the delay is 2 and the panel just stays there yeah fun times huh one if you can't slow enough eventually something will happen okay uh let's try this okay that whole enumeration thing as a class is kind of an unfortunate turn of events so i'm gonna have to do something about that it gets worse if you use uh automatic package reloader but i think that needs to be the very first thing that loads in order to fix this problem kinda connection state so let's say that the default for this temporarily was to only show the panel if an error occurs so i'm going to swap that to that now if we were to open up this panel and there should probably be a key binding for that or something if i copy stuff over here from this system we can see it populating into there and a second ago we just saw that panel pop up and i set this to the setting on this one to only display it on an error that's not an error we're not passing true to this argument so in theory i copy this we don't see anything there if i looked in the console we don't see anything in there but if we look in here we see another one in there so now there's three hit the copy and now there's four so that bit is actually working is apr now capable of running on two plug-in hosts i believe so it does some sort of bootstrapping uh notice there's an automatic package reloader and then it creates an automatic package reloader 33 i think it takes part of its own code out and drops it into a package that doesn't have the appropriate python version so that it'll trigger from both of them now i don't know that there's a cleverer way for that to work short of ditching one of the uh one of the plug-in hosts completely but this is that thing that i was talking about earlier i have a lot of craft in my folder here that i should probably be cleaning up can i don't know that i necessarily you know need uh various of these packages that we were working on throughout november and other things sitting in here per se the one i use for creating the overlay like my camera is in right now there's just oh there's this one sample plug-in in here too i have purple haze installed for reasons i don't fully understand yeah it's uh sample sample help i really need to clean this business up a little bit oh yeah this reminds me i could totally be using sub notify to pop some of this stuff up too if it's actually installed that would be a neat thing to pull off what classifies as an error what's uh are commands now namespaced to the plugin host will the python 3.8 command work in a 3.3 host that's a good question i think a command is just a command and one could invoke the other but i guess that's easy enough to test if i save this as something and call this pie test uh that goes into my user package my user package is in the 3.8 plug-in host by default so if i did view run command pi test it definitely does something but if we swap this to the other plugin host and do the same thing command still runs uh there may or may not be some freaky edge case if both plug-in hosts define the same command but that's not really something that's very uh cleanly delineated uh in just a single plug-in host either generally i think the way that it loads plug-ins and then introspects all of the symbols in the plug-in to see which classes are commands so that it can pull them out it adds them to a list and then creates the commands in the list and registers them in the order they were registered means that whichever plugin loaded last is the one that wins uh and overrides the command for example user oh sorry uh view package file user url.pi there's an open url command that's built into sublime and at some point in the past no matter what it always it fired up uh sea monkey or firefox or so i think it was sea monkey that it always fired up whenever anything would uh be open so for example the uh well i have extra stuff in here but like somewhere in this one if you actually look one of these things will take you you know to i guess probably this documentation link here will be the best thing i added a bunch of other documentation in here as well would always open in the wrong browser and i couldn't figure out why and eventually i just if i put this plug-in in my user package that defines the same command that's also defined in the core the last thing that happens is the user package is loaded this command appears in the table and it replaces the other one and then it uses the appropriate thing i'm not even sure that this is actually even needed because that was probably four years ago if you check on the forum for the number of forum topics where i've asked a question there's only like four and one of them is this um and the rest of my posts are all in response to other people and stuff maybe five i remember this i remember mentioning uh override audit when it launched and i have one other thing about at one point the unofficial documentation mentioned that using variables in commands like trying to run exec from a key binding and using dollar file would work and it actually didn't and i needed a plug-in for that let's go ahead and i nipped that one in bud uh such as it is oh i missed the thing close that so the only places that this are actually happening or here displaying a clipboard the clipboard text is never an error so we wouldn't call it there but we do need some more work for that one and for here connection state is going to be all of those particular states the only one of these that i guess there's is a connection being closed and error i don't think it is connecting as a state uh this one here this means that we have decided to initiate an outgoing connection to someone else so that happens and because all of this all of our sockets are non-blocking because that's the only sane way to work with network i o is to use a non-blocking socket as soon as you call connect on a socket it starts the connection process comes back to you and then the socket will select as writable uh or readable one of the two would have to look in the network code to be able to uh determine whether or not the connection actually worked or not accepting is the same sort of thing uh your if you have a listen socket uh your uh the accepting uh well if you have a listen socket that's non-blocking then it will select as readable or writeable i could never remember which one of those two things i can think of a mental case for both of them to tell you that something's happening so that says we're accepting a thing whether a connection was absolutely absolutely established closed uh i.e the other side just went away that might be an error might not be and that connection failed we tried to talk to something and it didn't work ashman says i've asked plenty of questions but i guess i've helped plenty as well to redeem myself partially i don't know that any redemption is technically needed for something like that i've always been the sort of person that learns best by doing so even if i asked a question and someone had an answer for me i'd still want to play with it a bunch to be able to see if i could to basically get a sense for it in my head i don't know i necessarily know why that always worked best for me i mean i still like to watch tutorial things and read read textbooks and stuff like that to get an idea in my head for what's possible but i don't fully grasp it and all the interactions until i played with it i guess because i know you get that experience with it so by and large if you see me ask a question uh one of two things i've either spent a bunch of time playing with the thing or looking to see if i can solve a problem and nothing has come to mind or i'm in the middle of a 15 mile walk thinking in my head of something i want to do later when i get home and i have an idea and i'm not entirely sure if it'll work and being in the middle of traffic with a cell phone isn't necessarily the greatest time to go into a deep google section session especially on a phone so sometimes you might see me ask a question in the discord that's usually why that happens but asking questions is uh you know absolutely a great thing and certainly you have helped a bunch of people in the forum so it's uh it's good to see i gotta say so congratulations to you i don't think i guess we want to know if a connection is closed so maybe it pops up for that because we kind of intend that the connection to just be established forever connection failed is definitely something you want to know about i'm not entirely sure how to contrive that one personally uh i have to print the event here because i can't quite remember i think it would be the actual value of that thing right i think it would be oops reload that all right well what if i just restarted that shall i i gotta get on that oh great i have some sort of random plugin that's printing stuff in the top level uh i have a vague recollection that sometime this week someone asked a question and i did this to see to help them with something okay network event dot let's say closed network event dot connection failed does that seem like something that would probably work um i think for the purposes of this only show the panel if an error occurs okay so i'm going to quit this i'm going to restart it like so i believe it has established a connection because this one over here just popped up a thing incidentally there's an issue for output panels not scrolling to the bottom and i cannot wait for that to be fixed because this is most definitely broken even though i'm calling append and telling it to move to the end and i'm calling uh a move command to jump to the end of the buffer it still does not scroll to the end and i don't know why and it is annoying as all get out boom so there's something in the panel but it didn't actually pop for us if i copy some text uh we check again it copied it but it did not pop um i might have to do something drastic and quit this copy of sublime which might make me unhappy that one was an error so that one automatically popped up and it's going to stay there until we tell it to go away because i think that's what we want i think if you wanted to display on an error that's what you want to have happen and now i'm going to restart this and oh joy of joys it actually started on the right thing and this one has just connected to it i can see over there it says it's accepting an input put the mouse input back to the correct one check her out and we can see connecting to van term and connected so i think that kinda is doing the thing that we want this is the only two places this is currently being called i don't think uh this is necessarily what we want here um tricky question uh if the theory is that you are working on multiple computers in the same subnet theoretically at the same time you're probably only focused on one so maybe it makes sense to log when another host name another host updates the clipboard so that you can tell it happened and if you had your thing set to like two or whatever to actually see it pop up you can have it set to true and always see it and it would open and just stay open forever which is probably not what anybody would set it to but it's easy enough to do so let's do it set it to false you only see an error in which case this doesn't happen or you set it to some number like two it opens for two seconds and then goes away if that happens and you're the one that's focused on a different editor that probably not that big a deal except for how it keeps happening over here and i'm catching it out of the corner of my eye easy enough to add a setting for that um so we might actually even go ahead and say for the purposes of this one might even say is error equals false just to very clearly point out exactly what it means when it's calling in this particular case and for this we could say is error and we could say is error is that which would more or less do what we want now this needs more working i know one of the things in the readme is that logging is uh spoopy uh and that has everything to do with the crudeness of this log being the name of the event title case uh as opposed to saying connected disconnected and whatnot um but that requires us to come up with a clever idea for how we want this to work uh probably connection.hostname should actually be the first part of the dotted ip it probably doesn't need to be the fully qualified host name uh i know all of my machines are in irc. or on thedragonland.net i don't necessarily need to have that crafting up my log but um i think what we probably want is two like so um so if i copy this we see it popping that up and then i can say pref uh i do not have a thing for that that one i probably don't need that particular thing there that's uh my customized setting for this is just a test that we can broadcast our own discovery packet on a to say that we're listening on a different port than anybody else is and it still works let's set this to yeah false cool um i think that's because that's what the default was when uh package control or when the package have actually loaded that thing it's a fun fact if you use package dev and like me you have sublime text 4 as your primary but you also have sublime text 3 that you fire up from time to time if somebody asks a question you want to verify or look to see something for people in the forum that might not be using the new build um and you're sharing the configuration directory between the two be very careful because as of uh not too long ago there's a new version of package dev that is specifically for sublime text version four uh i think it or some sort of targeted version release anyway i ended myself up in a situation where i started sublime text 3 and it decided uh to upgrade the build of package dev to something else and then when i went back to sublime text 4 it told me that package dev was a package that wasn't supported by my current version probably that means that they tagged a version to they've tagged the uh one of the versions to only require previous versions of sublime because i think he wants to jump into new builds going forward uh as a result package dev ends up uninstalling itself sometimes and you need to fix it then it took me a little bit to figure out what the hell is going on there um so let's see look at this so log to the output panel okay nothing like that configure the output panel opens automatically or not when output is logged to it yes and that is part of this one so those two could go away and then we could open the repository for this and of course you're going to open on the wrong desktop because why wouldn't you tell you hi i'm running 1080p on this monitor that i stream on uh just because it makes for a better output everything else is running at a different resolution boy windows on that monitor over there look ridiculously huge okay so that's those two things new settings new display panel setting probably should have called that something else uh maybe we fixed that in just a second that's the new logging uh is there a new version of this there is isn't there 2033 checking the discord here no there's not all right well that's unfortunate hopefully one is forthcoming because builds prior to the fix that ben just released in the latest build still have broken glow um we want to stage that one as well and yeah stage that thing so say uh new setting to control panel auto display it's good enough for that and now that we've done all of that um i'm kind of unhappy with the name that we chose so we might go ahead and do a little bit of that do that one and this is all in this one file right so there there there all of those and the actual implementation of the thing as well i'm going to quit that and restart it to make sure that it all comes out and [Music] should be okay oh how did nothing appear in there that can't be right oh no i broke it oh here it is weird maybe there was a little bit of a delay i'm kind of slightly confused by the idea that each instance of this broadcasts every 30 seconds thing that says hey i'm here if you want to know about me other instances use that as an impetus to connect over if they're not already connected and one of those discovery messages happens immediately when the plug-in loads but even so when you start a new copy running even though it broadcasts out right away and everything should be getting it right away it sometimes takes a few seconds for it to connect and i'm not sure why because logging in the network thread clearly shows that it's looping and correctly selecting on things um but nevertheless let's just very quickly do a little bit of this business like so and amend that one okay close that that's all good so what was the other thing that we wanted to fiddle in here [Music] detect changes in configuration um that requires setting up a settings change listener and knowing what the last settings were so that you can verify if any of them are different now and any that are different there's there would be only a small number of them would require us to basically tell the network thread to stop and then recreate it i'm going to leave that one for the time being technically not insurmountable but there are weird edge cases with the idea of telling the network thread to quit and then actually verifying that it did that i'm not interested in doing anything with right now um one thing we could do uh let's go ahead and do this uh we open this up how we doing here if we went into our messages let's close all these just for the time being uh we did a little bit of this and then said that uh this is identical to clipboard message but it's a different type so that the receiving end can uh filter them out if it desires the other way to do this would be to have an extra field in this thing um i guess one thing we need to worry about here is that's one that one's nothing clipboards four three file content five uh that one's going to be zero and that one's going to be two so i guess ah this is going to be six and then we're going to need a little bit of this and we will add it in here like so and from dot history import good gravy that um oh did i miss one of those things let's see we'll know soon enough all i have to do is quit this and restart it and we should get kicked right in the bottom if i did that wrong seems to be okay file content is five history is six yes okay we did uh we did correctly handle that if you will so this is something we can use to ship away a clipboard history entry from the global paste from history which is something that our reception of this is already handling in order for well we need to implement this first and then i need to pull that code over to here to have another thing um because otherwise that one's going to get all cranky when it doesn't understand the message that it receives that might actually be an interesting test um so right now we have a new item turn that off a new history thing that's imported there and exported there one new file that implements that uh where we carefully remember to change the name of the class itself uh it's all of its instances and its message id that ought to be good for that i go to net handler uh well that's unfortunate but it'll do the idea is that what when would we transmit our history to the other end uh let's say if we are the one that's connecting to something we ship our history over and is that it or do we also do it when we accept a connection if that copy of sublime is running and i started here theoretically i want that end to give me its history so it'll shoot it over here do i want the history for this one to go there the tricky part of that is there's a limit to the history size so depending on how that all times out it's possible for these two machines to kybosh each other's history so maybe only on connect we pull it down this is also something that we could implement as a user facing command later there's no reason why there couldn't be something in the command palette that said sync history and just have everything shoot every stuff all over everywhere or something for the purposes of testing this i guess let's say uh if event no this isn't where we would do this if we were going to do it in response to connecting to someone we wouldn't do it here we'd only do it here in response to accepting a connection from someone so let's leave this one out for the time being and put that one back to the way it was what we actually want is the transport something down here is in response to this that's accepting a connection uh this is uh theoretically theoretically we could actually do both of those parts in here can this be used to synchronize the console input i don't see myself using clipboard across computers but synchronizing console input history would be nice that might be possible is one of the items for um this the console input yes in theory you could gather the [Music] list of views and use that to pull the console input history over and shoot it you can't really put anything into it though i guess it's probably the problem you could gather it or could ya i'm not sure that there's a way even if you got the view handle for this input and used insert to insert text into it i'm not sure that there's a way to submit it in a way that it would end up into the history theoretically you could modify the session information or the workspace because that information is stored there but i don't think that would work because sublime doesn't it only reads the workspace in session when it's opened it doesn't re-read it if it was modified on disk while it's already running in fact it actively clobbers over it by saving the session information every 30 seconds there might be something to be done with that even if you had a quick panel that had the history from something else that might be something to pull off but um oh i guess we probably want this let's say yeah um the handling in this bit of code here uh i meant to do that but that's okay this is what happens when we receive a discovery message from another host this gathers the whole message and it's guaranteed to gather the whole message because udp datagrams can't be partially read the same way that a socket can be buffered there is an underlying buffer that is associated with udp sockets and when you receive you can take as much out of that buffer as you want but if you don't take all of the data out the rest of it is discarded by the kernel so you won't be you'll never be able to get the other part and if the buffer is like 2k but you get a 4k thing then the kernel registers in overrun and you can't possibly get the whole thing anyway generally speaking buffer sizes for udp are set sanely and that's never really an issue although the thing that we work on at work where we receive 4 billion messages a day on a normal trading day via udp multicast due to over multi-gigabyte links directly connected to stock exchanges uh we have the kernel on those systems uh set up to have ridiculously large udp buffers because when messages are coming in that fast that's the other thing about udp there's a set buffer size that the kernel has for holding udp messages as new messages come in they're slotted into that buffer buffer runs out of space the message over here just gone you don't even get to know that it's missing so that the new one can come in on the end this is why many people refer to udp as the unreliable datagram protocol even though it really stands for user datagram protocol but you know how i like to cheater chatter about networking type stuff so we receive the message if it's our host we don't need to do anything if it's a different version than us we don't need to do anything if we've already have a connection to that ip either one we made or they connected to us we also don't care otherwise we call connect we store the host name into the connection object right away because our reception what we got here is actually an introduction message that has the fully qualified hostname of the other end as it knows it uh so we can store that right away otherwise uh in the other network handler code here um you'll notice uh we have to have something that says uh if there's an introduction message then uh we need to handle that one in a different way which is the one down here which is where we set the host name uh that's entirely because of this we could actually see that happening somewhere else i gather well i guess this thing right here after we connect the first thing we do is transmit the way the same message that we were had we were broadcasting so the other person knows who we are and as a part of this we could also do this although the thought occurs i don't necessarily remember what the method is on this thing get receives the storage okay so um for entry in g clipboard history dot get con.send uh i guess we need to import the thing huh so let's go up here and oh yeah nope i clobbered it away ah clipboard message history message then we can jump back down there and this is safe to do because our connection objects have their own internal cue for messages that we want to transmit out and the network thread down here has code for doing actual selections so while we're running gather the list of all connections that are readable and all connections that are writable and a connection considers itself writable if it has any messages in its outbound queue that it hasn't transmitted yet or it is in the middle of transmitting a message out like if the message was so big it couldn't all be flushed to the socket at once so as long as that's the case this socket ends up in the writable select list and then the select actually happens and if it was writable then its method gets called and it's allowed to try to send as much information out as it wants which spools data out of the queue so theoretically that's all we need um and if i were to start this one up this one over here should get some degree of angry possibly it might just do nothing because it doesn't know what to do with the message unless this failed which it did not seem to um i'm gonna check here something to note here i uh got a 25 amazon gift card for filling out a survey about the software i used to create my youtube videos i assume that means not many many people did it but it was for amazon.com uh and you can't use that on amazon.ca and i'm canadian so i had to get something from the american amazon and the thing that i chose was this little bad boy right here which looks like a usb thumbstick but it's actually an hdmi video capture card i'm not sure if that'll actually focus that thing looks really tiny it cost 25 bucks so basically it was free except i had to pay shipping because they don't ship free to canada you hdmi input there usb 3 output here does 1080p at 30 frames a second it can actually receive 4k input actually works quite well for the price i think i would you know probably recommend it if you need something like that in theory i could use something like this to be able to shoot data from one of the other laptops into the stream or you could watch me play a switch game i don't know that that's necessarily interesting um i'm just looking here to see um well let's go back to this one actually because if we were to receive something we would be getting it as a message and then we might do something like log message let's say any message we receive i'm not entirely sure that that'll work uh let's pretend that it does so let's go ahead and say we'll check that in i'm going to amend this commit later this is going to give us our clipboard history so we can stage that and stage that one right that seems okay i mean this is crunky but we want this one to at least have some ability to do something with it um sync history we would call that one commit that and then push it to origin to make sure that that is yeah the correct thing and if i came over to here and i'm gonna have to quit this thing uh quit and this is where things get tricky because this copy of windows is a gigantic jerk bag about always opening things on this monitor when it doesn't have the active input now that i've set the active input on this monitor to be this computer any windows that it opens will open over here but when it's set to the linux computer it opens on this one and i don't know how to fix that because it definitely it definitely knows the what input it has why it would decide to do it when it's not visible i don't know uh do i have a thing for this i don't know that i do well maybe i do sub lynette get pulled all right things have synced let's go ahead and fire that up yes technically now i can test to see what this one does with that is this one over here that's the input wait just a moment should have theoretically logged some stuff and then we'll know if it actually worked well that can't be good fire that up again that might be unrelated we'll see this one break in some sort of horrible fashion sub notify is ready for messages oh no oh wait that's override audit that doesn't matter no module named crap did i forget to check something in here because it seemed to have loaded just fine here yes i did i hate when that happens you know and we have to get fetch and get reset hard origin master okay let's try that one more time i hate that whole forgetting to check in a new file you quit you restart all right are we happier now okay i think we're happier now now the only error is related to [Music] unrelated packages right yes cool all right so we come over to this one and whoops we don't do that because that's not what we want oh we want that pardon me um the one that initiated the connection so it's only gonna happen for this one this one should be sending it to this one this one does not seem to be receiving it one would assume is that doing anything yes all right so we have that part at least getting stuff i guess i should probably have then something like transmitting history just so we could see it actually doing something uh unless there was an error in there but there wasn't so i think that we'll give that a try so we can at least see what it's doing ah okay and we will force with least that one again yeah i know it diverged two branches diverged in the woods and i took the one on the left because it had the commit that i was interested in okay so let us quit this and restart it this is some exciting business i should remember to swap this around all right not gonna lie was not expecting that wrong one well i mean that really looks like the thing i guess we could check what this is going to manager broadcasts the message and manager broadcast the message just puts it on the connection so i don't need to encode it first so what the hell happened with this code uh connection line 90 in send does this not return what i think it returns that's not going to work hmm i could have sworn that that was a list self dot storage is a list oh but it's inserting display text comma text when you push it all right right right right okay so the first thing in there is the what you see in the panel and the second one his uh i mean just reconstructing the thing at this point is what's actually in there so in that case this should be that i guess right i'm not sure how that one slips past me okay one more time we're gonna amend that we're gonna push it like so and if i could remember to give the input focus to that thing we could get fetch and oops get reset minus hard origin master the joys of get reset all right here's what we're going to do we're going to come over to this thing we're not going to do that we're going to do that and open the console clear it all up and then come over to this thing quit restart shall we see anything does not seem to have had an issue but it also doesn't think it's connected to anything either and if it did i would have imagined that this would have noticed it so that's weird it's just not uh doing anything now because of that it never said it was transmitting history i mean there wouldn't be any so it's got that going for it i guess that means we do need it on the accepting end too because you can never know which way that's going to go right okay that definitely did something okay oops don't do that that does something and that does something all right so i guess we got to do it in two places and i said we could do this in two places right um we could do it here this is when we receive a discovery message and we connect out we make the connection to them we queue up a message to introduce them to us so we know who we they know who we are and then we transmit clipboard histories away if we handle an incoming message we accept an incoming connection that is telling us that this connection is actually done sockets should be ready to go i think we could potentially um not do that because that's unfortunate but a little bit of this two incoming pier and the other one was uh somewhere else apparently oh what did i do no it's right here to outgoing pier okay let's try that and see what we get and then i think we're almost at the end of this thing i'll just stage that and do a little bit of that and then we come over to here oops run yon command quit this the nice thing is it gets a little faster well now now we got other cool issues this one didn't restart so it was sending stuff to that end and i think that end was all cranky about it um but there is an issue here it's saying in that handler in li at line 40. this is uh not doing what we want specifically it says on this line after it goes into the utils text wrap d-dent replacement index zero out of range for positional args toggle top topple um how is this different from the other log call i guess we maybe want a little bit of this let's see what happens when i restart it all right well that one's still unhappy did this one say it did anything no i guess we gotta sync that change over too just to see life is complicated when you join this sort of network-related thing i like the ability to do this with git though a little faster than file shares for this anyway because those are on slightly different network segments in a way that makes that unhappy so whoops that's unfortunate does anybody else have a problem with using their mouse and getting the mouse button a little too close to the keyboard or something else on the desk and then you click down the mouse button and accidentally drag things when you didn't mean to because that happens more than i would care to admit um i'm going to restart this to make sure it starts with its fresh code because i can't remember if i did that or not that and definitely got all cranky on us but i can quit it and i can restart it because that's not the keyboard connected to that computer and quit we see it say it closed thanks for displaying that pop-up there there we go and then we make sure we do this and this okay this one didn't complain and that one didn't complain of course oh connection error it only works if there's something in the clipboard history right by the way there's nothing to transmit so that's something to keep in mind where's my mouse cursor quit that quit that i say that's the control key okay clipboard history text equals so it's angry at that log i'm really confunded by that but you know oh making me finished reading harry potter and now i'm using words like confunded oh it's the end of an era so this log on line 40 is still the sad maker despite the fact that it's one argument is a string that appears to not require any sort of fancy thing i mean why would that have any effect on this i don't know but you got multiple versions of these things running around life can be a little bit confusing okay so we're going to quit that and um we do bad business and then restart this and coming okay there we go that one's happy now that's just weird okay so here's what we're gonna do we're gonna copy that and that and that and that that okay i'm gonna come over here and quit this and restart it and i think that's gonna have it uh doing something or not okay here's the clipboard history which just happens to be from a jwtd code in a window over here on this one which you can't see but now you can kind of see it because it's over there actually this is the file i'm working on this is the sort of thing we can do now it's that big if i came over here this is the file that i'm looking at over in that little laptop window over there so this is totally a useful package so we're receiving the clipboard history we could actually be inserting it into the clipboard history which is something that this already does self.clipboard message is this one and it does that and this so technically it really just needs to do this for that let's implement that lf message.message id is equal to clipboard history message dot message id i thought i mentioned in the previous stream that the reason these classes work the way they do is because they're part of a project i worked on previously where the server end was c-sharp so i couldn't use python pickling for things because they needed it to be cross-compatible so i implemented a class the same as these message classes in c-sharp and in python to make sure that they would work uh self dot clipboard history gonna move that oops i'm gonna move this one up so to do that uh def clipboard history and then we can just say this to push it um what we can't say is and this could be actually tweaked up in the message that we're using when we're actually done with it right kind of an important thing um theory that works in theory um so i think what we want to do is i'm going to quit this go oops go here stage that in amend the previous commit do the ubiquitous push force with lease come over to this one over here where we do no you don't do that i pushed up thank you and then we have to quit here and then restart here here's what we're going to do we're going to copy copy copy so i put three things into the clipboard history over here um it transmitted stuff away which is interesting um is this connected to anybody no i guess it's just counting things that actually put into the thing or my laptop in the other room is still active now we come over here and hit this and whoo boy did that get angry all right let's uh let's actually fix this end shall we oh that's right i took it out of there because i wasn't gonna do anything with it that's my bad start that up one more time all right so we look in the panel doesn't look like anything but here's the stuff from over there and interestingly enough if i copy this to that end and then quit and then start this one on this end wait for it to connect now that one's in the history two because this one pushed it to that one and that one synchronized it back over here that's kind of neat um so yeah we wanted an extra copy of that that totally works i mean all things being equal we probably want to do that just to make sure that this one has the same code as that one does right otherwise we'll be confused in a minute i can actually quit this one to restart it let's see what happens in the other direction here so here that is now closed i'm going to fire it up on this window we can should be able to see it connecting and uh over here [Music] there are a bunch of things in the clipboard history and i totally don't have my override on clipboard history viewer over in this one but uh yeah clipboard history message preferred username last name and that comment so it synchronized it back over here potentially this needs a little bit more jiggering um just pondering the idea that this has a history and that has a history and they each transmit their history across potentially end up with duplicates unless paste from history is smarter about that or we need to de-dupe it somehow but the only thing that we're actually doing with this right now in fact is just putting stuff into the history in one of these two ways probably want something like that this could actually log it um one other thing that this could do and maybe i'll do this after the stream is that the this message could have not just the text but it could also have an integer or two two integers in it that says how many history entries are going out and which one this is so it could say this is one of ten this is two of ten this is three of 10. the other end could get that and it would know that if the indexes are the same then it could output a message that said clipboard history synced or something along those lines one way to pull that off otherwise you got to do something like try to guess when the other one is done or also something that we could uh do here is there are other message types we have that are actually implemented in here this acknowledge message is one you can use to send an ack or a knack to the other side uh which you could use to acknowledge yes or no that something happened so one thing we could do is transmit the history away then transmit and ack and the other end that when it gets the act knows that that's the case or we could transmit actually a message message to say exactly what we did and then the other end could print that message to the console the downside to that is if you wanted to turn off kilter history then you would need to know that this message is related to the history so this is where you start getting into the whole idea of we have the ability to have a network connection a reliable network connection via sockets between all of the different instances of this that are running inside the same local network and we can at will put whatever data we want across we have a structured way to construct a message of some kind and wrap it up in bytes and ship it off we know that the network code has the ability to pull the bytes off into memory and only when it gets exactly enough bytes for one message does it call the decode method to turn this back into a message instance and deliver it for something to happen so we have all the power in the world to transmit messages around the next thing to talk about is what sort of protocol is actually used for this right now the protocol is very simplistic when a connection is established it sends an introduction message to introduce the other side to itself because if we're i'm connecting to you i tell you how who i am the other side uh already knows because it tried to make the connection in response to receiving one of those messages as a broadcast but apart from that the only other thing we're doing is just transmitting a clipboard message to to the other end or now this we could modify this so that every time you receive you send a message you you acknowledge that you received it and then the protocol would allow one side to know that it transmitted a clipboard message and the other side received it and used it or maybe the other side received it and said i don't want it in which case you don't have to send anymore there's all sorts of cool stuff that we could have happening in that particular case but that is something that will happen perhaps in the next stream so i think it's about time to uh caller quits getting a weird sound in the uh headset there but uh i think we did some uh some good work here we managed to get this stuff more or less working there's only a couple of things that are left to do here and you can't see this because i have swapped the screen but the other items in here are changing all of the logging to be nicer and i have some ideas for that you could have an event name at the start and then a host name or it could say host name connected hostname disconnected maybe instead of using the fully qualified hostname we just choose the hostname pad it out to 32 bytes once we have a way to do that the other thing is maybe you syntax highlighting you got to have i like to have a format locked down before implement syntax highlighting one of the other things is replace the message classes something to be done and detecting configuration changes but by and large this is actually doing everything i originally intended it to do so that is pretty cool uh if i do say so myself so we're gonna call the stream here so uh thanks so much for watching uh if you have been thanks for the questions in the console there those are always fun and a nice diversion when things are going wrong remember you can always subscribe to know when live streams happen they should happen every every tuesday at 8 00 p.m pacific time uh follow me on twitter at odatnerd i usually tweet out there if i am going live or not most of the time it's yes occasionally it's no when dental problems or other weird issues get in the way and i have another channel that is linked in the description below that you can subscribe to for weekly sublime text videos we're currently in the midst of some plug-in 101 stuff doing event listener type things and the next video that's coming up is going to have at least an example of a custom key binding context maybe also some autocomplete stuff i haven't decided yet where the edit falls on that if they should be two videos or one we'll see what happens but until those videos or the next live stream thanks for watching and this has been odatnerd asking you to please have a sublime day and then notice that i reach down here so i can push this button do you
Info
Channel: Terence Martin
Views: 48
Rating: 5 out of 5
Keywords:
Id: sFWzzbm5ugw
Channel Id: undefined
Length: 125min 10sec (7510 seconds)
Published: Wed Sep 16 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.