The Death and Rebirth of Docs.rs
CC Attribution 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal purpose as long as the work is attributed to the author in the manner specified by the author or licensor.
Mitchell, Gray (Quiet Misdreavus)
Docs.rs is a beloved resource in the Rust community, but it was not long ago that such a resource did not exist. Join QuietMisdreavus as she tells the story of docs.rs, from its humble beginnings as crates.fyi and a Rustacean's learning project; through to its heyday and decline as a single-maintainer project that became a trusted community resource; to its rebirth in the present day as an official Rust Project-maintained endeavor. Along the way, you can also get an insider's view into the service and take a peek at how it ticks.
 All right. Hi. I'm Gray. And we're going to be talking about some of the background and insides of docs.rs. Before we get too far, here's some information about me. If you're in the REST community for long enough, you might recognize me by my alias, quiet mischievous. My GitHub sponsors link is on here. I actually just got approved a week or two ago. So that's fun. I'm at the RecurR center right now as a fellow to actually spend three months working directly on this. So that's fun. I'm the leader of the Rust doc team. I'm also a member of the documentation team. I like music. I like docs. I like Rust. And I like y'all. So I'm not sure how much of an introduction we need, but for completeness and for the video, docs.rs is a little website where anyone who publishes a library on crates.io can. Docs.rs has a scraper that will check crates.io every time something releases and build its documentation and host it up for everyone to see. And so it's a very lovely community resource that I'm sure a lot of people in this room and beyond have depended upon a lot. But I want to talk about where this got started. So back in 2016, someone named owner Aslan, who's named I probably just butchered, wanted to have documentation for everything. At this point, there wasn't really anything, there wasn't really any centralized documentation solution. Everyone either hosted their own docs or didn't have a documentation link in their library information. So he came from the Pearl world and liked how Cpan had documentation for everything. And so he wanted to give this a shot for Rust. It was actually his first Rust program. It started initially as a Pearl script, but it blew up to about 800 megs of member use after a week of trying to build stuff. So he started a project called crates.fyi. As his first Rust program, it took about 10 days to build all of crates.io and even after all of that, I was only using about four megs of memory. So it was actually half a percent of the memory use of the original Pearl script. But after it had all of that initial thing, in February 1st of 2016, crates.fyi launched to the world. It was extremely basic. It didn't have a front page. The idea was that you could look at a crates.io crate page and change the URL to point to crates.fyi instead and you would see the documentation. So this was, you know, this caught on for a while, but someone else in the community had the domain docs.rs and was willing to give it and was just parking it to give it to anyone who wanted to host documentation for Rust stuff. And so after a series of exchanges, this project then landed there where it's been ever since. So in the end of August 2016, August 26th, it relaunched as docs.rs with the front page we all know and love today. And it's kind of been there churning out, slowly improving ever since. So I want to give a note about sort of the internal structure of this because I'm going to harp on one specific thing for the next several slides. Initially docs.rs or crates.fyi was on a server donated by Lease Web. They have a program where they donate servers to open source projects. And so this was kind of going on a donated server for a while. Back when this was created back in 2016, this was before a lot of the web frameworks that we all had that are around today sort of started. So the only thing that was around was this old framework called iron. If you've never used iron, it deals a lot with it. The entire thing is centered around middleware and extending your service using that. And so it's not as popular today. I think it's not as actively maintained as some of the other frameworks out today. But it still works. The builds were run in an LXC container, which if you're familiar with Docker, it's the same kind of solution, but it's a different framework for it. And so all the builds would run in that LXC container to sort of sandbox them a little bit. Because if you think about how a crate can have a build script and that build script and basically do whatever it wants, we'll get to that in a minute. And then whenever it generated documentation, it would take those files and save them into a local Postgres database. And it would just have the entire file contents in the database there ready to serve up. And then for a while, and this is the important part, it used a custom fork of Rustdoc and cargo because there were a few features that it wanted that weren't in the upstream Rustdoc that made hosting the site a lot difficult. Namely, especially when you generate documentation with Rustdoc, there's a lot of static files that are the same for all the docs. There's some CSS and JavaScript and font files that are the same for everyone. Hosting 10,000 copies of that file for everyone is really wasteful. And so one of the features really allowed to sort of consolidate those things. So a custom fork is cool, especially if you have the know how to tinker around with Rustdoc and the compiler build system and building cargo and stuff. But now you have to rebase your changes if you want to use a newer Rustdoc. And Rustdoc is actually tied to the compiler. It lives in the same repo as the compiler uses the compiler's internal libraries. So now you have to rebase the compiler all the time. And if you pay attention to how people release their libraries, people like to use language features as soon as they come out. So if you kind of think about this, some language feature comes out on nightly initially or hits its initial stabilization and some library will immediately upgrade now that the feature flag is not necessary or they want to use this feature in their code, it won't build because our Rustdoc is too old because it's a pain to rebase your compiler all the time. So I just want to give a rough timeline to this. This is a little low resolution on the slide here, but I'll have my slides online. The custom compiler was introduced in 2017 on June 2nd. All those stars on the top was every time a new compiler was rebased. So that's only seven times across 16 months. And this was actually a very important time in the history of the Rust programming language because this was also especially towards the end of that time when some of the 2018 features were coming out. So here's some of the handful of really important stuff that came out. Things like associated consts, the pin struct, the simD structs in the standard library, 128 bit wide integers, prock mac rows, the 2018 edition itself, all of these things came out in this time window. And so there were a lot of people coming in to an issue on DocsRS, GitHub repo saying my crate won't build because your compiler is too old. And to hammer this home, I actually have a little graph here and maybe I can sort of highlight it out. But these spikes here towards the end are where a new compiler was released and a whole bunch of things were queued up. But if you notice, there's these slopes here where the build error rate, which is what this graph is, kind of creeps up over time. And that's because that was just a new compiler that was, or the compiler was so old that the more crates that came in over time couldn't build. So I just thought this was an interesting graph when I pulled the data from the database about the build history to hammer this home. So while this was going on, I know in the IDE talk there was mention about stuff happening at the Rust all hands, but a year earlier in the Rust all hands of 2018 in February, a handful of people got together among the early Rust doc team and the DevTools team saying that we want to make DocsRS official. Because remember all this time it was just a solo maintained project. It was all owners like work and maintenance and operations work keeping this running. But it wasn't really an official Rust project. So but we wanted to kind of work to make it official. And the biggest thing at that time was saying, okay, well, let's at least get using upstream Rust doc. So we worked on the major features, the two biggest things were this resource suffix which kind of lets you pull all of the static files that CSS and JavaScript that I mentioned into the same folder and just name them differently depending on what compiler you're using. And then the other major feature that it was using was this, what was eventually called the extra root URL. So if you looked at Rust doc documentation and there's like those function signatures that say like this function returns a vec of string or a vec of some other type. Those type names are links out to other crates documentation. And on DocsRS those are actually hard coded to link to other DocsRS documentation pages. And that's this feature at work. So we added that in August. And later on, in the next couple months we kind of said, okay, so we have this in place. Let's convert it over. And this was harder than it sounded because setting up a service that tries to build Docs for all of crates.io has this custom server environment that it really expects to be there. It took a while to get off the ground. But I actually did a lot of the work on that. I helped out a lot by a fellow contributor who's alias was John who I forget his human name really helped me out kind of getting the environment set up. And that really helped out a lot. So around this time, Leaseweb said it was going to stop sponsoring the server at the end of 2018. And so we were in October, November around this time. And so we have to go, okay, well, let's migrate this to use the infra teams like AWS account. Let's get the actual server managed by the rest infrastructure team because they manage the servers for crates.io, they manage the file hosting for all the files that you get from Rustup. They were the perfect fit if we're going to make this a project managed thing to get it on infrastructure managed by the project. So we actually switched over about a week before Christmas 2018. We had a couple of weeks where the other server was still up in case we needed to fall back. But it turned out pretty well. There is a bit of a hiccup, but we managed to get everything ironed out. And right at the end of the year, the old server was spun down and now we're happily on AWS. So also along this time, there was a lot of discussion between the infra team and the release team and the rest doc team to say, well, there's a similar thing going on with a tool the release team uses called Crater. If you're not familiar with Crater, it's a thing that the release team uses to test beta compilers by compiling as much code as it can. This includes everything on crates.io. This includes a whole bunch of public GitHub repos that are just tagged with the Rust language that we can just pull down and say, okay, well, let's build this with a new compiler and see if our new compiler is busted. So it uses a standardized Docker container called crates build.v that just has, it's just a standard, we're going to Docker container with a whole bunch of system dependencies installed in it to try and have as many system dependencies as crates can depend on. And so we had this manually synced for a while. Any time we tried to, any time we needed to install something on docs.res because the docs wouldn't build because of a missing system dependency, we would then have to pull requests to this Docker container to say, hey, you need this too so we can build it on Crater. So earlier this year, a bunch of code from Crater was extracted out to this library called Rust wide. And what Rust wide does is it kind of leverages that container to let you build arbitrary code in a more sandbox environment. So not only do you have it inside that Docker container, but you can also say, I'm giving you a memory limit and I'm giving you a time limit and you also can't access the network. And so just a few weeks ago, we actually converted docs.res over. If you read the Rust blog very diligently, you may have seen a post about docs.res changes last month. This was us switching this over so that we could have the same environment between docs.res and Crater. So it was a really good maintenance burden that was lifted. So we didn't have to keep this parallel list of system dependencies in sync, but also it allows us to sandbox the builds a little better. So to draw a parallel, the current structure, whereas the old docs.res and crates.fyi was on a donated server by at least web. Now we're on an AWS server managed by the Rust infrastructure team. The web server is still built in iron, it ain't broke, we didn't fix it. Whereas the old system was running in an LXC built container, which actually was persistent and had all the build artifacts and stuff cached between builds. Now we have a Docker built container that's wiped out every time. So if anyone messes with the built container, we'll just scrap it and start a new one. And this is managed by Rust wide so we can have a bit more of a tighter sandbox there. We no longer store files in the database because as it turns out, when you have a whole bunch of HTML files and source files in a database, that database gets pretty huge when you're storing everything on crates.io. So we pulled all of that out and are saving them on S3 where storage is a lot cheaper and managed to get the database size down and shrink the server some. And now we're using upstream Rust doc and cargo to run the builds, which is now ever since that changed over, now it's updated automatically. Whereas it used to be for a while, we had to manually go in and update the Rust doc inside the container. Basically anytime anyone complained that they were using something that was too new. So I don't like to have big conclusion-y wrap-up slides, but I feel like there are a few good things to call out. I kind of want to reiterate. XRS, crates.io, was that maintainer's first big Rust project. And I feel like it's a huge success story for the language that it didn't fall over, that it's been able to handle the load that it's gotten ever since it became a really trusted community resource. But that first line there, something can become accidentally popular before it's ready. But with a bright preparation, it can handle it. And so that's why I feel like it's a success story for Rust to be able to say, someone who doesn't have a whole lot of experience with the language can still write something that is performant and tolerant to a lot of people accessing it. But despite that, it still decayed after a while because it was a solo project for so long. It took a lot of effort to try and keep it up over time. It took fresh eyes to kind of bring it back, that rebirth that's in the title of this talk. Especially for something 24.7, like this web service, having multiple people in there is really important. And just to hammer it in, part of that decay was burnout. It was a huge pain to rebase the compiler all the time. It was a huge pain to keep up with the build container all the time. It was a huge pain to keep everything running. And so it's really important to sort of not only manage your code in a really clean structured performant way, but also the infrastructure around it as well. It's really helpful to be able to anticipate having to keep things going to three, four, et cetera, years on. And this is all I have. I've got a bunch of links here. All of these projects that I've mentioned are on GitHub. And so if you want to check it out, Docs.RS Development Chat also happens on the Rust Teams Discord and the Pound Docs.RS channel. So if you want to come hang out, check out some stuff about what we're working on, you're welcome to hang out. And then those are my links there as well. I came in well under time, but okay. Thank you so much.
 All right.  Hi.  I'm Gray.  And we're going to be talking about some of the background and insides of docs.rs.  Before we get too far, here's some information about me.  If you're in the REST community for long enough, you might recognize me by my alias, quiet  mischievous.  My GitHub sponsors link is on here.  I actually just got approved a week or two ago.  So that's fun.  I'm at the RecurR center right now as a fellow to actually spend three months working directly  on this.  So that's fun.  I'm the leader of the Rust doc team.  I'm also a member of the documentation team.  I like music.  I like docs.  I like Rust.  And I like y'all.  So I'm not sure how much of an introduction we need, but for completeness and for the  video, docs.rs is a little website where anyone who publishes a library on crates.io  can.  Docs.rs has a scraper that will check crates.io every time something releases and build its  documentation and host it up for everyone to see.  And so it's a very lovely community resource that I'm sure a lot of people in this room  and beyond have depended upon a lot.  But I want to talk about where this got started.  So back in 2016, someone named owner Aslan, who's named I probably just butchered, wanted  to have documentation for everything.  At this point, there wasn't really anything, there wasn't really any centralized documentation  solution.  Everyone either hosted their own docs or didn't have a documentation link in their library  information.  So he came from the Pearl world and liked how Cpan had documentation for everything.  And so he wanted to give this a shot for Rust.  It was actually his first Rust program.  It started initially as a Pearl script, but it blew up to about 800 megs of member use  after a week of trying to build stuff.  So he started a project called crates.fyi.  As his first Rust program, it took about 10 days to build all of crates.io and even after  all of that, I was only using about four megs of memory.  So it was actually half a percent of the memory use of the original Pearl script.  But after it had all of that initial thing, in February 1st of 2016, crates.fyi launched  to the world.  It was extremely basic.  It didn't have a front page.  The idea was that you could look at a crates.io crate page and change the URL to point to  crates.fyi instead and you would see the documentation.  So this was, you know, this caught on for a while, but someone else in the community  had the domain docs.rs and was willing to give it and was just parking it to give it  to anyone who wanted to host documentation for Rust stuff.  And so after a series of exchanges, this project then landed there where it's been ever since.  So in the end of August 2016, August 26th, it relaunched as docs.rs with the front page  we all know and love today.  And it's kind of been there churning out, slowly improving ever since.  So I want to give a note about sort of the internal structure of this because I'm going  to harp on one specific thing for the next several slides.  Initially docs.rs or crates.fyi was on a server donated by Lease Web.  They have a program where they donate servers to open source projects.  And so this was kind of going on a donated server for a while.  Back when this was created back in 2016, this was before a lot of the web frameworks that  we all had that are around today sort of started.  So the only thing that was around was this old framework called iron.  If you've never used iron, it deals a lot with it.  The entire thing is centered around middleware and extending your service using that.  And so it's not as popular today.  I think it's not as actively maintained as some of the other frameworks out today.  But it still works.  The builds were run in an LXC container, which if you're familiar with Docker, it's the same  kind of solution, but it's a different framework for it.  And so all the builds would run in that LXC container to sort of sandbox them a little  bit.  Because if you think about how a crate can have a build script and that build script  and basically do whatever it wants, we'll get to that in a minute.  And then whenever it generated documentation, it would take those files and save them into  a local Postgres database.  And it would just have the entire file contents in the database there ready to serve up.  And then for a while, and this is the important part, it used a custom fork of Rustdoc and  cargo because there were a few features that it wanted that weren't in the upstream Rustdoc  that made hosting the site a lot difficult.  Namely, especially when you generate documentation with Rustdoc, there's a lot of static files  that are the same for all the docs.  There's some CSS and JavaScript and font files that are the same for everyone.  Hosting 10,000 copies of that file for everyone is really wasteful.  And so one of the features really allowed to sort of consolidate those things.  So a custom fork is cool, especially if you have the know how to tinker around with Rustdoc  and the compiler build system and building cargo and stuff.  But now you have to rebase your changes if you want to use a newer Rustdoc.  And Rustdoc is actually tied to the compiler.  It lives in the same repo as the compiler uses the compiler's internal libraries.  So now you have to rebase the compiler all the time.  And if you pay attention to how people release their libraries, people like to use language  features as soon as they come out.  So if you kind of think about this, some language feature comes out on nightly initially or  hits its initial stabilization and some library will immediately upgrade now that the feature  flag is not necessary or they want to use this feature in their code, it won't build  because our Rustdoc is too old because it's a pain to rebase your compiler all the time.  So I just want to give a rough timeline to this.  This is a little low resolution on the slide here, but I'll have my slides online.  The custom compiler was introduced in 2017 on June 2nd.  All those stars on the top was every time a new compiler was rebased.  So that's only seven times across 16 months.  And this was actually a very important time in the history of the Rust programming language  because this was also especially towards the end of that time when some of the 2018 features  were coming out.  So here's some of the handful of really important stuff that came out.  Things like associated consts, the pin struct, the simD structs in the standard library,  128 bit wide integers, prock mac rows, the 2018 edition itself, all of these things came  out in this time window.  And so there were a lot of people coming in to an issue on DocsRS, GitHub repo saying  my crate won't build because your compiler is too old.  And to hammer this home, I actually have a little graph here and maybe I can sort of  highlight it out.  But these spikes here towards the end are where a new compiler was released and a whole  bunch of things were queued up.  But if you notice, there's these slopes here where the build error rate, which is what  this graph is, kind of creeps up over time.  And that's because that was just a new compiler that was, or the compiler was so old that  the more crates that came in over time couldn't build.  So I just thought this was an interesting graph when I pulled the data from the database  about the build history to hammer this home.  So while this was going on, I know in the IDE talk there was mention about stuff happening  at the Rust all hands, but a year earlier in the Rust all hands of 2018 in February,  a handful of people got together among the early Rust doc team and the DevTools team  saying that we want to make DocsRS official.  Because remember all this time it was just a solo maintained project.  It was all owners like work and maintenance and operations work keeping this running.  But it wasn't really an official Rust project.  So but we wanted to kind of work to make it official.  And the biggest thing at that time was saying, okay, well, let's at least get using upstream  Rust doc.  So we worked on the major features, the two biggest things were this resource suffix which  kind of lets you pull all of the static files that CSS and JavaScript that I mentioned into  the same folder and just name them differently depending on what compiler you're using.  And then the other major feature that it was using was this, what was eventually called  the extra root URL.  So if you looked at Rust doc documentation and there's like those function signatures  that say like this function returns a vec of string or a vec of some other type.  Those type names are links out to other crates documentation.  And on DocsRS those are actually hard coded to link to other DocsRS documentation pages.  And that's this feature at work.  So we added that in August.  And later on, in the next couple months we kind of said, okay, so we have this in place.  Let's convert it over.  And this was harder than it sounded because setting up a service that tries to build Docs  for all of crates.io has this custom server environment that it really expects to be there.  It took a while to get off the ground.  But I actually did a lot of the work on that.  I helped out a lot by a fellow contributor who's alias was John who I forget his human  name really helped me out kind of getting the environment set up.  And that really helped out a lot.  So around this time, Leaseweb said it was going to stop sponsoring the server at the  end of 2018.  And so we were in October, November around this time.  And so we have to go, okay, well, let's migrate this to use the infra teams like AWS account.  Let's get the actual server managed by the rest infrastructure team because they manage  the servers for crates.io, they manage the file hosting for all the files that you get  from Rustup.  They were the perfect fit if we're going to make this a project managed thing to get it  on infrastructure managed by the project.  So we actually switched over about a week before Christmas 2018.  We had a couple of weeks where the other server was still up in case we needed to fall back.  But it turned out pretty well.  There is a bit of a hiccup, but we managed to get everything ironed out.  And right at the end of the year, the old server was spun down and now we're happily  on AWS.  So also along this time, there was a lot of discussion between the infra team and the  release team and the rest doc team to say, well, there's a similar thing going on with  a tool the release team uses called Crater.  If you're not familiar with Crater, it's a thing that the release team uses to test beta  compilers by compiling as much code as it can.  This includes everything on crates.io.  This includes a whole bunch of public GitHub repos that are just tagged with the Rust language  that we can just pull down and say, okay, well, let's build this with a new compiler  and see if our new compiler is busted.  So it uses a standardized Docker container called crates build.v that just has, it's  just a standard, we're going to Docker container with a whole bunch of system dependencies  installed in it to try and have as many system dependencies as crates can depend on.  And so we had this manually synced for a while.  Any time we tried to, any time we needed to install something on docs.res because the  docs wouldn't build because of a missing system dependency, we would then have to pull requests  to this Docker container to say, hey, you need this too so we can build it on Crater.  So earlier this year, a bunch of code from Crater was extracted out to this library called  Rust wide.  And what Rust wide does is it kind of leverages that container to let you build arbitrary  code in a more sandbox environment.  So not only do you have it inside that Docker container, but you can also say, I'm giving  you a memory limit and I'm giving you a time limit and you also can't access the network.  And so just a few weeks ago, we actually converted docs.res over.  If you read the Rust blog very diligently, you may have seen a post about docs.res changes  last month.  This was us switching this over so that we could have the same environment between docs.res  and Crater.  So it was a really good maintenance burden that was lifted.  So we didn't have to keep this parallel list of system dependencies in sync, but also it  allows us to sandbox the builds a little better.  So to draw a parallel, the current structure, whereas the old docs.res and crates.fyi was  on a donated server by at least web.  Now we're on an AWS server managed by the Rust infrastructure team.  The web server is still built in iron, it ain't broke, we didn't fix it.  Whereas the old system was running in an LXC built container, which actually was persistent  and had all the build artifacts and stuff cached between builds.  Now we have a Docker built container that's wiped out every time.  So if anyone messes with the built container, we'll just scrap it and start a new one.  And this is managed by Rust wide so we can have a bit more of a tighter sandbox there.  We no longer store files in the database because as it turns out, when you have a whole bunch  of HTML files and source files in a database, that database gets pretty huge when you're  storing everything on crates.io.  So we pulled all of that out and are saving them on S3 where storage is a lot cheaper  and managed to get the database size down and shrink the server some.  And now we're using upstream Rust doc and cargo to run the builds, which is now ever  since that changed over, now it's updated automatically.  Whereas it used to be for a while, we had to manually go in and update the Rust doc  inside the container.  Basically anytime anyone complained that they were using something that was too new.  So I don't like to have big conclusion-y wrap-up slides, but I feel like there are a few good  things to call out.  I kind of want to reiterate.  XRS, crates.io, was that maintainer's first big Rust project.  And I feel like it's a huge success story for the language that it didn't fall over,  that it's been able to handle the load that it's gotten ever since it became a really  trusted community resource.  But that first line there, something can become accidentally popular before it's ready.  But with a bright preparation, it can handle it.  And so that's why I feel like it's a success story for Rust to be able to say, someone  who doesn't have a whole lot of experience with the language can still write something  that is performant and tolerant to a lot of people accessing it.  But despite that, it still decayed after a while because it was a solo project for so  long.  It took a lot of effort to try and keep it up over time.  It took fresh eyes to kind of bring it back, that rebirth that's in the title of this talk.  Especially for something 24.7, like this web service, having multiple people in there  is really important.  And just to hammer it in, part of that decay was burnout.  It was a huge pain to rebase the compiler all the time.  It was a huge pain to keep up with the build container all the time.  It was a huge pain to keep everything running.  And so it's really important to sort of not only manage your code in a really clean structured  performant way, but also the infrastructure around it as well.  It's really helpful to be able to anticipate having to keep things going to three, four,  et cetera, years on.  And this is all I have.  I've got a bunch of links here.  All of these projects that I've mentioned are on GitHub.  And so if you want to check it out, Docs.RS Development Chat also happens on the Rust  Teams Discord and the Pound Docs.RS channel.  So if you want to come hang out, check out some stuff about what we're working on, you're  welcome to hang out.  And then those are my links there as well.  I came in well under time, but okay.  Thank you so much.
The_Death_and_Rebirth_of_Docs_rs_-_Quiet_Misdreavu_jlqMNwVun7Q_0_71.png The_Death_and_Rebirth_of_Docs_rs_-_Quiet_Misdreavu_jlqMNwVun7Q_72_131.png The_Death_and_Rebirth_of_Docs_rs_-_Quiet_Misdreavu_jlqMNwVun7Q_132_179.png The_Death_and_Rebirth_of_Docs_rs_-_Quiet_Misdreavu_jlqMNwVun7Q_180_239.png The_Death_and_Rebirth_of_Docs_rs_-_Quiet_Misdreavu_jlqMNwVun7Q_240_287.png The_Death_and_Rebirth_of_Docs_rs_-_Quiet_Misdreavu_jlqMNwVun7Q_288_359.png The_Death_and_Rebirth_of_Docs_rs_-_Quiet_Misdreavu_jlqMNwVun7Q_360_1127.png The_Death_and_Rebirth_of_Docs_rs_-_Quiet_Misdreavu_jlqMNwVun7Q_1128_2159.png The_Death_and_Rebirth_of_Docs_rs_-_Quiet_Misdreavu_jlqMNwVun7Q_2160_2723.png The_Death_and_Rebirth_of_Docs_rs_-_Quiet_Misdreavu_jlqMNwVun7Q_2724_4667.png The_Death_and_Rebirth_of_Docs_rs_-_Quiet_Misdreavu_jlqMNwVun7Q_4668_5159.png The_Death_and_Rebirth_of_Docs_rs_-_Quiet_Misdreavu_jlqMNwVun7Q_5160_8399.png The_Death_and_Rebirth_of_Docs_rs_-_Quiet_Misdreavu_jlqMNwVun7Q_8400_8639.png The_Death_and_Rebirth_of_Docs_rs_-_Quiet_Misdreavu_jlqMNwVun7Q_8640_9887.png The_Death_and_Rebirth_of_Docs_rs_-_Quiet_Misdreavu_jlqMNwVun7Q_9888_11531.png The_Death_and_Rebirth_of_Docs_rs_-_Quiet_Misdreavu_jlqMNwVun7Q_11532_12563.png The_Death_and_Rebirth_of_Docs_rs_-_Quiet_Misdreavu_jlqMNwVun7Q_12564_12731.png The_Death_and_Rebirth_of_Docs_rs_-_Quiet_Misdreavu_jlqMNwVun7Q_12732_17339.png The_Death_and_Rebirth_of_Docs_rs_-_Quiet_Misdreavu_jlqMNwVun7Q_17340_19283.png The_Death_and_Rebirth_of_Docs_rs_-_Quiet_Misdreavu_jlqMNwVun7Q_19284_20747.png The_Death_and_Rebirth_of_Docs_rs_-_Quiet_Misdreavu_jlqMNwVun7Q_20748_22955.png The_Death_and_Rebirth_of_Docs_rs_-_Quiet_Misdreavu_jlqMNwVun7Q_22956_25919.png The_Death_and_Rebirth_of_Docs_rs_-_Quiet_Misdreavu_jlqMNwVun7Q_25920_26339.png The_Death_and_Rebirth_of_Docs_rs_-_Quiet_Misdreavu_jlqMNwVun7Q_26340_26387.png The_Death_and_Rebirth_of_Docs_rs_-_Quiet_Misdreavu_jlqMNwVun7Q_26388_26747.png The_Death_and_Rebirth_of_Docs_rs_-_Quiet_Misdreavu_jlqMNwVun7Q_26748_26807.png The_Death_and_Rebirth_of_Docs_rs_-_Quiet_Misdreavu_jlqMNwVun7Q_26808_26868.png