diff --git a/Cargo.lock b/Cargo.lock
index b2586ee..df61a35 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1301,6 +1301,18 @@ dependencies = [
"sha-1 0.8.2",
]
+[[package]]
+name = "pfacts"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "83abebdb324c30f176d449513f0134bafbf976d5279c6554742599e3996d1629"
+dependencies = [
+ "rand 0.7.3",
+ "serde",
+ "serde_derive",
+ "serde_json",
+]
+
[[package]]
name = "pin-project"
version = "0.4.22"
@@ -2507,6 +2519,7 @@ dependencies = [
"color-eyre",
"comrak",
"envy",
+ "eyre",
"glob",
"go_vanity",
"hyper",
@@ -2516,12 +2529,15 @@ dependencies = [
"log",
"mime",
"patreon",
+ "pfacts",
"pretty_env_logger",
"prometheus",
"rand 0.7.3",
+ "reqwest",
"ructe",
"serde",
"serde_dhall",
+ "serde_json",
"serde_yaml",
"sitemap",
"thiserror",
diff --git a/Cargo.toml b/Cargo.toml
index f43230d..eb6cd67 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -40,6 +40,12 @@ patreon = { path = "./lib/patreon" }
[build-dependencies]
ructe = { version = "0.12", features = ["warp02"] }
+[dev-dependencies]
+pfacts = "0"
+serde_json = "1"
+eyre = "0.6"
+reqwest = { version = "0.10", features = ["json"] }
+
[workspace]
members = [
"./lib/go_vanity",
diff --git a/blog/rust-crates-go-stdlib-2020-09-27.markdown b/blog/rust-crates-go-stdlib-2020-09-27.markdown
new file mode 100644
index 0000000..f44b9e7
--- /dev/null
+++ b/blog/rust-crates-go-stdlib-2020-09-27.markdown
@@ -0,0 +1,617 @@
+---
+title: Rust Crates that do What the Go Standard library Does
+date: 2020-09-27
+tags:
+ - rust
+---
+
+# Rust Crates that do What the Go Standard library Does
+
+One of Go's greatest strengths is how batteries-included the standard library
+is. You can do most of what you need to do with only the standard library. On
+the other hand, Rust's standard library is severely lacking by comparison.
+However, the community has capitalized on this and been working on a bunch of
+batteries that you can include in your rust projects. I'm going to cover a bunch
+of them in this post in a few sections.
+
+[A lot of these are actually used to help make this blog site
+work!](conversation://Mara/hacker)
+
+## Logging
+
+Go has logging out of the box with package [`log`](https://godoc.org/log).
+Package `log` is a very uncontroversial logger. It does what it says it does and
+with little fuss. However it does not include a lot of niceties like logging
+levels and context-aware values.
+
+In Rust, we have the [`log`](https://docs.rs/log/) crate which is a very simple
+interface. It uses the `error!`, `warn!`, `info!`, `debug!` and `trace!` macros
+which correlate to the highest and lowest levers. If you want to use `log` in a
+Rust crate, you can add it to your `Cargo.toml` file like this:
+
+```toml
+[dependencies]
+log = "0.4"
+```
+
+Then you can use it in your Rust code like this:
+
+```rust
+use log::{error, warn, info, debug, trace};
+
+fn main() {
+ trace!("starting main");
+ debug!("debug message");
+ info!("this is some information");
+ warn!("oh no something bad is about to happen");
+ error!("oh no it's an error");
+}
+```
+
+[Wait, where does that log to? I ran that example locally but I didn't see any
+of the messages anywhere](conversation://Mara/wat)
+
+This is because the `log` crate doesn't directly log anything anywhere, it is a
+facade that other packages build off of.
+[`pretty_env_logger`](https://docs.rs/pretty_env_logger) is a commonly used
+crate with the `log` facade. Let's add it to the program and work from there:
+
+```toml
+[dependencies]
+log = "0.4"
+pretty_env_logger = "0.4"
+```
+
+Then let's enable it in our code:
+
+```rust
+use log::{error, warn, info, debug, trace};
+
+fn main() {
+ pretty_env_logger::init();
+
+ trace!("starting main");
+ debug!("debug message");
+ info!("this is some information");
+ warn!("oh no something bad is about to happen");
+ error!("oh no it's an error");
+}
+```
+
+And now let's run it with `RUST_LOG=trace`:
+
+```console
+$ env RUST_LOG=trace cargo run --example logger_test
+ Finished dev [unoptimized + debuginfo] target(s) in 0.07s
+ Running `/home/cadey/code/christine.website/target/debug/logger_test`
+ TRACE logger_test > starting main
+ DEBUG logger_test > debug message
+ INFO logger_test > this is some information
+ WARN logger_test > oh no something bad is about to happen
+ ERROR logger_test > oh no it's an error
+```
+
+There are [many
+other](https://docs.rs/log/0.4.11/log/#available-logging-implementations)
+consumers of the log crate and implementing a consumer is easy should you want
+to do more than `pretty_env_logger` can do on its own. However, I have found
+that `pretty_env_logger` does just enough on its own. See its documentation for
+more information.
+
+## Flags
+
+Go's standard library has the [`flag`](https://godoc.org/flag) package out of
+the box. This package is incredibly basic, but is surprisingly capable in terms
+of what you can actually do with it. A common thing to do is use flags for
+configuration or other options, such as
+[here](https://github.com/Xe/hlang/blob/44bb74efa6f124ca05483a527c0e735ce0fca143/main.go#L15-L22):
+
+```go
+package main
+
+import "flag"
+
+var (
+ program = flag.String("p", "", "h program to compile/run")
+ outFname = flag.String("o", "", "if specified, write the webassembly binary created by -p here")
+ watFname = flag.String("o-wat", "", "if specified, write the uncompiled webassembly created by -p here")
+ port = flag.String("port", "", "HTTP port to listen on")
+ writeTao = flag.Bool("koan", false, "if true, print the h koan and then exit")
+ writeVersion = flag.Bool("v", false, "if true, print the version of h and then exit")
+)
+```
+
+This will make a few package-global variables that will contain the values of
+the command-line arguments.
+
+In Rust, a commonly used command line parsing package is
+[`structopt`](https://docs.rs/structopt). It works in a bit of a different way
+than Go's `flag` package does though. `structopt` focuses on loading options into
+a structure rather than into globally mutable variables.
+
+[Something you may notice in Rust-land is that globally mutable state is talked
+about as if it is something to be avoided. It's not inherently bad, but it does
+make things more likely to crash at runtime. In most cases, these global
+variables with package `flag` are fine, but only if they are ever written to
+before the program really starts to do what it needs to do. If they are ever
+written to and read from dynamically at runtime, then you can get into a lot of
+problems such as race
+conditions.](conversation://Mara/hacker)
+
+Here's a quick example copied from [pa'i](https://github.com/Xe/pahi):
+
+```rust
+#[derive(Debug, StructOpt)]
+#[structopt(
+ name = "pa'i",
+ about = "A WebAssembly runtime in Rust meeting the Olin ABI."
+)]
+struct Opt {
+ /// Backend
+ #[structopt(short, long, default_value = "cranelift")]
+ backend: String,
+
+
+ /// Print syscalls on exit
+ #[structopt(short, long)]
+ function_log: bool,
+
+
+ /// Do not cache compiled code?
+ #[structopt(short, long)]
+ no_cache: bool,
+
+
+ /// Binary to run
+ #[structopt()]
+ fname: String,
+
+
+ /// Main function
+ #[structopt(short, long, default_value = "_start")]
+ entrypoint: String,
+
+
+ /// Arguments of the wasm child
+ #[structopt()]
+ args: Vec,
+}
+```
+
+This has the Rust compiler generate the needed argument parsing code for you, so
+you can just use the values as normal:
+
+```rust
+fn main() {
+ let opt = Opt::from_args();
+ debug!("args: {:?}", opt.args);
+}
+```
+
+You can even handle subcommands with this, such as in
+[palisade](https://github.com/lightspeed/palisade/blob/master/src/main.rs). This
+package should handle just about everything you'd do with the `flag` package,
+but will also work for cases where `flag` falls apart.
+
+## Errors
+
+Go's standard library has the [`error`
+interface](https://godoc.org/builtin#error) which lets you create a type that
+describes why functions fail to do what they intend. Rust has the [`Error`
+trait](https://doc.rust-lang.org/std/error/trait.Error.html) which lets you also
+create a type that describes why functions fail to do what they intend.
+
+In [my last post](https://christine.website/blog/TLDR-rust-2020-09-19) I
+described [`eyre`](https://docs.rs/eyre) and the Result type. However, this time
+we're going to dive into [`thiserror`](https://docs.rs/thiserror) for making our
+own error type. Let's add `thiserror` to our crate:
+
+```toml
+[dependencies]
+thiserror = "1"
+```
+
+And then let's re-implement our `DivideByZero` error from the last post:
+
+```rust
+use std::fmt;
+use thiserror::Error;
+
+#[derive(Debug, Error)]
+struct DivideByZero;
+
+impl fmt::Display for DivideByZero {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "cannot divide by zero")
+ }
+}
+```
+
+The compiler made our error instance for us! It can even do that for more
+complicated error types like this one that wraps a lot of other error cases and
+error types in [maj](https://tulpa.dev/cadey/maj):
+
+```rust
+#[derive(thiserror::Error, Debug)]
+pub enum Error {
+ #[error("TLS error: {0:?}")]
+ TLS(#[from] TLSError),
+
+ #[error("URL error: {0:?}")]
+ URL(#[from] url::ParseError),
+
+ #[error("Invalid DNS name: {0:?}")]
+ InvalidDNSName(#[from] webpki::InvalidDNSNameError),
+
+ #[error("IO error: {0:?}")]
+ IO(#[from] std::io::Error),
+
+ #[error("Response parsing error: {0:?}")]
+ ResponseParse(#[from] crate::ResponseError),
+
+ #[error("Invalid URL scheme {0:?}")]
+ InvalidScheme(String),
+}
+```
+
+[These `#[error("whatever")]` annotations will show up when the error message is
+printed. See here for more
+information on what details you can include here.](conversation://Mara/hacker)
+
+## Serialization / Deserialization
+
+Go has JSON encoding/decoding in its standard library via package
+[`encoding/json`](https://godoc.org/encoding/json). This allows you to define
+types that can be read from and write to JSON easily. Let's take this simple
+JSON object representing a comment from some imaginary API as an example:
+
+```json
+{
+ "id": 31337,
+ "author": {
+ "id": 420,
+ "name": "Cadey"
+ },
+ "body": "hahaha its is an laughter image",
+ "in_reply_to": 31335
+}
+```
+
+In Go you could write this as:
+
+```go
+type Author struct {
+ ID int `json:"id"`
+ Name string `json:"name"`
+}
+
+type Comment struct {
+ ID int `json:"id"`
+ Author Author `json:"author"`
+ Body string `json:"body"`
+ InReplyTo int `json:"in_reply_to"`
+}
+```
+
+Rust does not have this capability out of the box, however there is a fantastic
+framework available known as [serde](https://serde.rs/) which works across JSON
+and every other serialization method that you can think of. Let's add serde and
+its JSON support to our crate:
+
+```toml
+[dependencies]
+serde = { version = "1", features = ["derive"] }
+serde_json = "1"
+```
+
+[You might notice that the dependency line for serde is different here. Go's
+JSON package works by using struct
+tags as metadata, but Rust doesn't have these. We need to use Rust's derive
+feature instead.](conversation://Mara/hacker)
+
+So, to use serde for our comment type, we would write Rust that looks like this:
+
+```rust
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct Author {
+ pub id: i32,
+ pub name: String,
+}
+
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct Comment {
+ pub id: i32,
+ pub author: Author,
+ pub body: String,
+ pub in_reply_to: i32,
+}
+```
+
+And then we can load that from JSON using code like this:
+
+```rust
+fn main() {
+ let data = r#"
+ {
+ "id": 31337,
+ "author": {
+ "id": 420,
+ "name": "Cadey"
+ },
+ "body": "hahaha its is an laughter image",
+ "in_reply_to": 31335
+ }
+ "#;
+
+ let c: Comment = serde_json::from_str(data).expect("json to parse");
+ println!("comment: {:#?}", c);
+}
+```
+
+And you can use it like this:
+
+```console
+$ cargo run --example json
+ Compiling xesite v2.0.1 (/home/cadey/code/christine.website)
+ Finished dev [unoptimized + debuginfo] target(s) in 0.43s
+ Running `target/debug/examples/json`
+comment: Comment {
+ id: 31337,
+ author: Author {
+ id: 420,
+ name: "Cadey",
+ },
+ body: "hahaha its is an laughter image",
+ in_reply_to: 31335,
+}
+```
+
+## HTTP
+
+Many APIs expose their data over HTTP. Go has the
+[`net/http`](https://godoc.org/net/http) package that acts as a production-grade
+(Google uses this in production) HTTP client and server. This allows you to get
+going with new projects very easily. The Rust standard library doesn't have this
+out of the box, but there are some very convenient crates that can fill in the
+blanks.
+
+### Client
+
+For an HTTP client, we can use [`reqwest`](https://docs.rs/reqwest). It can also
+seamlessly integrate with serde to allow you to parse JSON from HTTP without any
+issues. Let's add reqwest to our crate as well as [`tokio`](https://tokio.rs) to
+act as an asynchronous runtime:
+
+```toml
+[dependencies]
+reqwest = { version = "0.10", features = ["json"] }
+tokio = { version = "0.2", features = ["full"] }
+```
+
+[We need `tokio` because Rust doesn't ship with an asynchronous runtime by
+default. Go does as a core part of the standard library (and arguably the
+language), but `tokio` is about equivalent to most of the important things that
+the Go runtime handles for you. This omission may seem annoying, but it makes it
+easy for you to create a custom asynchronous runtime should you need
+to.](conversation://Mara/hacker)
+
+And then let's integrate with that imaginary comment api at
+[https://xena.greedo.xeserv.us/files/comment.json](https://xena.greedo.xeserv.us/files/comment.json):
+
+```rust
+use eyre::Result;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct Author {
+ pub id: i32,
+ pub name: String,
+}
+
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct Comment {
+ pub id: i32,
+ pub author: Author,
+ pub body: String,
+ pub in_reply_to: i32,
+}
+
+#[tokio::main]
+async fn main() -> Result<()> {
+ let c: Comment = reqwest::get("https://xena.greedo.xeserv.us/files/comment.json")
+ .await?
+ .json()
+ .await?;
+ println!("comment: {:#?}", c);
+
+ Ok(())
+}
+```
+
+And then let's run this:
+
+```console
+$ cargo run --example http
+ Compiling xesite v2.0.1 (/home/cadey/code/christine.website)
+ Finished dev [unoptimized + debuginfo] target(s) in 2.20s
+ Running `target/debug/examples/http`
+comment: Comment {
+ id: 31337,
+ author: Author {
+ id: 420,
+ name: "Cadey",
+ },
+ body: "hahaha its is an laughter image",
+ in_reply_to: 31335,
+}
+```
+
+[But what if the response status is not 200?](conversation://Mara/hmm)
+
+We can change the code to something like this:
+
+```rust
+let c: Comment = reqwest::get("https://xena.greedo.xeserv.us/files/comment2.json")
+ .await?
+ .error_for_status()?
+ .json()
+ .await?;
+```
+
+And then when we run it we get an error back:
+
+```console
+$ cargo run --example http_fail
+ Compiling xesite v2.0.1 (/home/cadey/code/christine.website)
+ Finished dev [unoptimized + debuginfo] target(s) in 1.84s
+ Running `/home/cadey/code/christine.website/target/debug/examples/http_fail`
+Error: HTTP status client error (404 Not Found) for url (https://xena.greedo.xeserv.us/files/comment2.json)
+```
+
+This combined with the other features in `reqwest` give you an very capable HTTP
+client that does even more than Go's HTTP client does out of the box.
+
+### Server
+
+As for HTTP servers though, let's take a look at [`warp`](https://docs.rs/warp).
+`warp` is a HTTP server framework that builds on top of Rust's type system.
+You can add warp to your dependencies like this:
+
+```toml
+[dependencies]
+warp = "0.2"
+```
+
+Let's take a look at its ["Hello, World" example](https://github.com/seanmonstar/warp/blob/master/examples/hello.rs):
+
+```rust
+use warp::Filter;
+
+#[tokio::main]
+async fn main() {
+ // GET /hello/warp => 200 OK with body "Hello, warp!"
+ let hello = warp::path!("hello" / String)
+ .map(|name| format!("Hello, {}!", name));
+
+ warp::serve(hello)
+ .run(([127, 0, 0, 1], 3030))
+ .await;
+}
+```
+
+We can then build up multiple routes with its `or` pattern:
+
+```
+let hello = warp::path!("hello" / String)
+ .map(|name| format!("Hello, {}!", name));
+let health = warp::path!(".within" / "health")
+ .map(|| "OK");
+let routes = hello.or(health);
+```
+
+And even inject other datatypes into your handlers with filters such as in the
+[printer facts API server](https://tulpa.dev/cadey/printerfacts/src/branch/main/src/main.rs):
+
+```
+let fact = {
+ let facts = pfacts::make();
+ warp::any().map(move || facts.clone())
+};
+
+let fact_handler = warp::get()
+ .and(warp::path("fact"))
+ .and(fact.clone())
+ .and_then(give_fact);
+```
+
+`warp` is an extremely capable HTTP server and can work across everything you
+need for production-grade web apps.
+
+[The blog you are looking at right now is powered by
+warp!](conversation://Mara/hacker)
+
+## Templating
+
+Go's standard library also includes HTML and plain text templating with its
+packages [`html/template`](https://godoc.org/html/template) and
+[`text/template`](https://godoc.org/text/template). There are many solutions for
+templating HTML in Rust, but the one I like the most is
+[`ructe`](https://docs.rs/ructe). `ructe` uses Cargo's
+[build.rs](https://doc.rust-lang.org/cargo/reference/build-scripts.html) feature
+to generate Rust code for its templates at compile time. This allows your HTML
+templates to be compiled into the resulting application binary, allowing them to
+render at ludicrous speeds. To use it, you need to add it to your
+`build-dependencies` section of your `Cargo.toml`:
+
+```toml
+[build-dependencies]
+ructe = { version = "0.12", features = ["warp02"] }
+```
+
+You will also need to add the [`mime`](https://docs.rs/mime) crate to your
+dependencies because the generated template code will require it at runtime.
+
+```toml
+[dependencies]
+mime = "0.3.0"
+```
+
+Once you've done this, create a new folder named `templates` in your current
+working directory. Create a file called `hello.rs.html` and put the following in
+it:
+
+```html
+@(title: String, message: String)
+
+
+
+ @title
+
+
+ @title
+ @message
+
+
+```
+
+Now add the following to the bottom of your `main.rs` file:
+
+```rust
+include!(concat!(env!("OUT_DIR"), "/templates.rs"));
+```
+
+And then use the template like this:
+
+```rust
+use warp::{http::Response, Filter, Rejection, Reply};
+
+async fn hello_html(message: String) -> Result {
+ Response::builder()
+ .html(|o| templates::index_html(o, "Hello".to_string(), message).unwrap().clone()))
+}
+```
+
+And hook it up in your main function:
+
+```rust
+let hello_html_rt = warp::path!("hello" / "html" / String)
+ .and_then(hello_html);
+
+let routes = hello_html_rt.or(health).or(hello);
+```
+
+For a more comprehensive example, check out the [printerfacts
+server](https://tulpa.dev/cadey/printerfacts). It also shows how to handle 404
+responses and other things like that.
+
+---
+
+Wow, this covered a lot. I've included most of the example code in the
+[`examples`](https://github.com/Xe/site/tree/master/examples) folder of [this
+site's GitHub repo](https://github.com/Xe/site). I hope it will help you on your
+journey in Rust. This is documentation that I wish I had when I was learning
+Rust.
diff --git a/examples/http.rs b/examples/http.rs
new file mode 100644
index 0000000..c1533a6
--- /dev/null
+++ b/examples/http.rs
@@ -0,0 +1,27 @@
+use eyre::Result;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct Author {
+ pub id: i32,
+ pub name: String,
+}
+
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct Comment {
+ pub id: i32,
+ pub author: Author,
+ pub body: String,
+ pub in_reply_to: i32,
+}
+
+#[tokio::main]
+async fn main() -> Result<()> {
+ let c: Comment = reqwest::get("https://xena.greedo.xeserv.us/files/comment.json")
+ .await?
+ .json()
+ .await?;
+ println!("comment: {:#?}", c);
+
+ Ok(())
+}
diff --git a/examples/http_fail.rs b/examples/http_fail.rs
new file mode 100644
index 0000000..98e027a
--- /dev/null
+++ b/examples/http_fail.rs
@@ -0,0 +1,28 @@
+use eyre::Result;
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct Author {
+ pub id: i32,
+ pub name: String,
+}
+
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct Comment {
+ pub id: i32,
+ pub author: Author,
+ pub body: String,
+ pub in_reply_to: i32,
+}
+
+#[tokio::main]
+async fn main() -> Result<()> {
+ let c: Comment = reqwest::get("https://xena.greedo.xeserv.us/files/comment2.json")
+ .await?
+ .error_for_status()?
+ .json()
+ .await?;
+ println!("comment: {:#?}", c);
+
+ Ok(())
+}
diff --git a/examples/json.rs b/examples/json.rs
new file mode 100644
index 0000000..bf128ed
--- /dev/null
+++ b/examples/json.rs
@@ -0,0 +1,32 @@
+use serde::{Deserialize, Serialize};
+
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct Author {
+ pub id: i32,
+ pub name: String,
+}
+
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct Comment {
+ pub id: i32,
+ pub author: Author,
+ pub body: String,
+ pub in_reply_to: i32,
+}
+
+fn main() {
+ let data = r#"
+ {
+ "id": 31337,
+ "author": {
+ "id": 420,
+ "name": "Cadey"
+ },
+ "body": "hahaha its is an laughter image",
+ "in_reply_to": 31335
+ }
+ "#;
+
+ let c: Comment = serde_json::from_str(data).expect("json to parse");
+ println!("comment: {:#?}", c);
+}
diff --git a/examples/logger_test.rs b/examples/logger_test.rs
new file mode 100644
index 0000000..f917d66
--- /dev/null
+++ b/examples/logger_test.rs
@@ -0,0 +1,11 @@
+use log::{debug, error, info, trace, warn};
+
+fn main() {
+ pretty_env_logger::init();
+
+ trace!("starting main");
+ debug!("debug message");
+ info!("this is some information");
+ warn!("oh no something bad is about to happen");
+ error!("oh no it's an error");
+}
diff --git a/examples/warp.rs b/examples/warp.rs
new file mode 100644
index 0000000..c705b47
--- /dev/null
+++ b/examples/warp.rs
@@ -0,0 +1,14 @@
+use warp::Filter;
+
+#[tokio::main]
+async fn main() {
+ let hello = warp::path!("hello" / String)
+ .map(|name| format!("Hello, {}!", name));
+ let health = warp::path!(".within" / "health")
+ .map(|| "OK");
+ let routes = hello.or(health);
+
+ warp::serve(routes)
+ .run(([0, 0, 0, 0], 3030))
+ .await;
+}
diff --git a/nix/sources.json b/nix/sources.json
index 8eb271a..8f412c2 100644
--- a/nix/sources.json
+++ b/nix/sources.json
@@ -5,10 +5,10 @@
"homepage": "",
"owner": "justinwoo",
"repo": "easy-dhall-nix",
- "rev": "90957969850a44481c6e150350c56e8b53b29e1e",
- "sha256": "1hsmp3cb0k554kh0jlfzpdzx2b8ndyh2gdykmw9hw41haaw16mmi",
+ "rev": "3e9101c5dfd69a9fc28fe4998aff378f91bfcb64",
+ "sha256": "1nsn1n4sx4za6jipcid1293rdw8lqgj9097s0khiij3fz0bzhrg9",
"type": "tarball",
- "url": "https://github.com/justinwoo/easy-dhall-nix/archive/90957969850a44481c6e150350c56e8b53b29e1e.tar.gz",
+ "url": "https://github.com/justinwoo/easy-dhall-nix/archive/3e9101c5dfd69a9fc28fe4998aff378f91bfcb64.tar.gz",
"url_template": "https://github.com///archive/.tar.gz"
},
"naersk": {
@@ -29,10 +29,10 @@
"homepage": "https://github.com/nmattia/niv",
"owner": "nmattia",
"repo": "niv",
- "rev": "fad2a6cbfb2e7cdebb7cb0ad2f5cc91e2c9bc06b",
- "sha256": "0mghc1j0rd15spdjx81bayjqr0khc062cs25y5dcfzlxk4ynyc6m",
+ "rev": "29ddaaf4e099c3ac0647f5b652469dfc79cd3b53",
+ "sha256": "1va6myp07gkspgxfch8z3rs9nyvys6jmgzkys6a2c4j09qxp1bs0",
"type": "tarball",
- "url": "https://github.com/nmattia/niv/archive/fad2a6cbfb2e7cdebb7cb0ad2f5cc91e2c9bc06b.tar.gz",
+ "url": "https://github.com/nmattia/niv/archive/29ddaaf4e099c3ac0647f5b652469dfc79cd3b53.tar.gz",
"url_template": "https://github.com///archive/.tar.gz"
},
"nixpkgs": {
@@ -41,10 +41,10 @@
"homepage": "https://github.com/NixOS/nixpkgs",
"owner": "NixOS",
"repo": "nixpkgs-channels",
- "rev": "4aa5466cbc741097218a1c494a7b832a17d1967d",
- "sha256": "0w6gg1hxcx83l8s83frxyjm5dwri06a3cy1i4358ny2lcrxq4qap",
+ "rev": "72b9660dc18ba347f7cd41a9504fc181a6d87dc3",
+ "sha256": "1cqgpw263bz261bgz34j6hiawi4hi6smwp6981yz375fx0g6kmss",
"type": "tarball",
- "url": "https://github.com/NixOS/nixpkgs-channels/archive/4aa5466cbc741097218a1c494a7b832a17d1967d.tar.gz",
+ "url": "https://github.com/NixOS/nixpkgs-channels/archive/72b9660dc18ba347f7cd41a9504fc181a6d87dc3.tar.gz",
"url_template": "https://github.com///archive/.tar.gz"
},
"xepkgs": {