diff --git a/ifc/.envrc b/ifc/.envrc new file mode 100644 index 0000000..4a4726a --- /dev/null +++ b/ifc/.envrc @@ -0,0 +1 @@ +use_nix diff --git a/ifc/Cargo.toml b/ifc/Cargo.toml new file mode 100644 index 0000000..0b68985 --- /dev/null +++ b/ifc/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "international-fixed-calendar" +description = "chrono-compatible-ish date objects for the International Fixed Calendar" +version = "0.1.0" +authors = ["Savanni D'Gerinel "] +edition = "2018" +keywords = ["date", "time", "calendar"] +categories = ["date-and-time"] + +[dependencies] +chrono = "0.4" +chrono-tz = "0.4" +iron = "0.6.1" +mustache = "0.9.0" +params = "*" +router = "*" +serde = { version = "1.0", features = ["derive"] } + +[[bin]] +name = "ifc-today" +path = "src/today.rs" + +[[bin]] +name = "ifc-web" +path = "src/web.rs" diff --git a/ifc/readme.md b/ifc/readme.md new file mode 100644 index 0000000..6502e17 --- /dev/null +++ b/ifc/readme.md @@ -0,0 +1,8 @@ +# International Fixed Calendar + +This is a fun project implementing a library for the [International Fixed Calendar](https://en.wikipedia.org/wiki/International_Fixed_Calendar). + +This is at least somewhat compatible with [Chrono](https://github.com/chronotope/chrono), in that I have implemented these traits: + +* `From` +* `Datelike` diff --git a/ifc/shell.nix b/ifc/shell.nix new file mode 100644 index 0000000..12f59f4 --- /dev/null +++ b/ifc/shell.nix @@ -0,0 +1,20 @@ +let + rust_overlay = import (builtins.fetchTarball "https://github.com/oxalica/rust-overlay/archive/master.tar.gz"); + pkgs = import { overlays = [ rust_overlay ]; }; + unstable = import {}; + rust = pkgs.rust-bin.stable."1.55.0".default.override { + extensions = [ "rust-src" ]; + }; + +in pkgs.mkShell { + name = "ifc"; + + buildInputs = [ + rust + unstable.rust-analyzer + ]; + + shellHook = '' + if [ -e ~/.nixpkgs/shellhook.sh ]; then . ~/.nixpkgs/shellhook.sh; fi + ''; +} diff --git a/ifc/src/lib.rs b/ifc/src/lib.rs new file mode 100644 index 0000000..87a6100 --- /dev/null +++ b/ifc/src/lib.rs @@ -0,0 +1,664 @@ +extern crate chrono; +extern crate chrono_tz; + +use chrono::{Datelike, NaiveDate}; + +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum DayOfWeek { + Sunday, + Monday, + Tuesday, + Wednesday, + Thursday, + Friday, + Saturday, + LeapDay, + YearDay, +} + +impl From for String { + fn from(day: DayOfWeek) -> Self { + match day { + DayOfWeek::Sunday => "Sunday", + DayOfWeek::Monday => "Monday", + DayOfWeek::Tuesday => "Tuesday", + DayOfWeek::Wednesday => "Wednesday", + DayOfWeek::Thursday => "Thursday", + DayOfWeek::Friday => "Friday", + DayOfWeek::Saturday => "Saturday", + DayOfWeek::LeapDay => "LeapDay", + DayOfWeek::YearDay => "YearDay", + } + .to_owned() + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum Month { + January, + February, + March, + April, + May, + June, + Sol, + July, + August, + September, + October, + November, + December, +} + +impl From for Month { + fn from(val: u32) -> Month { + match val { + 1 => Month::January, + 2 => Month::February, + 3 => Month::March, + 4 => Month::April, + 5 => Month::May, + 6 => Month::June, + 7 => Month::Sol, + 8 => Month::July, + 9 => Month::August, + 10 => Month::September, + 11 => Month::October, + 12 => Month::November, + 13 => Month::December, + _ => panic!("invalid month number"), + } + } +} + +impl From for String { + fn from(val: Month) -> String { + match val { + Month::January => "January", + Month::February => "February", + Month::March => "March", + Month::April => "April", + Month::May => "May", + Month::June => "June", + Month::Sol => "Sol", + Month::July => "July", + Month::August => "August", + Month::September => "September", + Month::October => "October", + Month::November => "November", + Month::December => "December", + } + .to_owned() + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct IFC { + year: u32, + ordinal: u32, + leap_year: bool, +} + +fn is_leap_year(year: i32) -> bool { + NaiveDate::from_ymd(year, 12, 31).ordinal() == 366 +} + +impl IFC { + pub fn ymd(year: u32, month: u8, day: u8) -> IFC { + let leap_year = is_leap_year(year as i32 - 10000); + + let ordinal = if is_leap_year(year as i32 - 10000) { + if month == 6 && day == 29 { + 168 + } else if month > 6 { + (month as u32 - 1) * 28 + (day as u32) + } else { + (month as u32 - 1) * 28 + (day as u32) - 1 + } + } else { + (month as u32 - 1) * 28 + (day as u32) - 1 + }; + + IFC { + year, + ordinal, + leap_year, + } + } + + pub fn weekday_ifc(&self) -> DayOfWeek { + match self.day() % 7 { + 0 => DayOfWeek::Saturday, + 1 => DayOfWeek::Sunday, + 2 => DayOfWeek::Monday, + 3 => DayOfWeek::Tuesday, + 4 => DayOfWeek::Wednesday, + 5 => DayOfWeek::Thursday, + 6 => DayOfWeek::Friday, + _ => panic!("impossible condition"), + } + } + + pub fn month_ifc(&self) -> Month { + Month::from(self.month()) + } +} + +impl From> for IFC { + fn from(d: chrono::Date) -> IFC { + IFC::from(d.naive_utc()) + } +} + +impl From for IFC { + fn from(d: NaiveDate) -> IFC { + //println!("d: {} [{}]", d.format("%Y-%m-%d"), d.ordinal()); + IFC { + year: (d.year() + 10000) as u32, + ordinal: d.ordinal0(), + leap_year: is_leap_year(d.year()), + } + } +} + +impl Datelike for IFC { + fn year(&self) -> i32 { + self.year as i32 + } + fn month(&self) -> u32 { + self.month0() + 1 + } + fn month0(&self) -> u32 { + if self.leap_year && self.ordinal == 365 { + 12 + } else if self.leap_year && self.ordinal == 168 { + 5 + } else { + self.ordinal / 28 + } + } + fn day(&self) -> u32 { + self.day0() + 1 + } + fn day0(&self) -> u32 { + if self.leap_year { + if self.ordinal == 365 { + 28 + } else if self.ordinal == 168 { + 28 + } else if self.ordinal > 168 { + (self.ordinal - 1).rem_euclid(28) as u32 + } else { + self.ordinal.rem_euclid(28) as u32 + } + } else { + if self.ordinal == 364 { + 28 + } else { + self.ordinal.rem_euclid(28) as u32 + } + } + } + fn ordinal(&self) -> u32 { + self.ordinal + 1 + } + fn ordinal0(&self) -> u32 { + self.ordinal + } + fn weekday(&self) -> chrono::Weekday { + if self.day0() == 28 { + chrono::Weekday::Sat + } else { + match self.day0().rem_euclid(7) { + 0 => chrono::Weekday::Sun, + 1 => chrono::Weekday::Mon, + 2 => chrono::Weekday::Tue, + 3 => chrono::Weekday::Wed, + 4 => chrono::Weekday::Thu, + 5 => chrono::Weekday::Fri, + 6 => chrono::Weekday::Sat, + _ => panic!("rem_euclid should not return anything outside the 0..6 range"), + } + } + } + fn iso_week(&self) -> chrono::IsoWeek { + panic!("iso_week is not implemented because chrono does not expose any constructors for IsoWeek!"); + } + fn with_year(&self, year: i32) -> Option { + Some(IFC { + year: (year as u32) + 10000, + ordinal: self.ordinal, + leap_year: is_leap_year(year), + }) + } + fn with_month(&self, month: u32) -> Option { + Some(IFC::ymd(self.year, month as u8, self.day() as u8)) + } + fn with_month0(&self, month: u32) -> Option { + Some(IFC::ymd(self.year, month as u8 + 1, self.day() as u8)) + } + fn with_day(&self, day: u32) -> Option { + Some(IFC::ymd(self.year, self.month() as u8, day as u8)) + } + fn with_day0(&self, day: u32) -> Option { + Some(IFC::ymd(self.year, self.month() as u8, day as u8 + 1)) + } + fn with_ordinal(&self, ordinal: u32) -> Option { + Some(IFC { + year: self.year, + ordinal, + leap_year: self.leap_year, + }) + } + fn with_ordinal0(&self, ordinal: u32) -> Option { + Some(IFC { + year: self.year, + ordinal: ordinal + 1, + leap_year: self.leap_year, + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use chrono::NaiveDate; + + #[test] + fn check_start_of_month() { + assert_eq!( + IFC::ymd(12019, 1, 1), + IFC { + year: 12019, + ordinal: 0, + leap_year: false + } + ); + assert_eq!( + IFC::ymd(12019, 2, 1), + IFC { + year: 12019, + ordinal: 28, + leap_year: false + } + ); + assert_eq!( + IFC::ymd(12019, 3, 1), + IFC { + year: 12019, + ordinal: 56, + leap_year: false + } + ); + assert_eq!( + IFC::ymd(12019, 4, 1), + IFC { + year: 12019, + ordinal: 84, + leap_year: false + } + ); + assert_eq!( + IFC::ymd(12019, 5, 1), + IFC { + year: 12019, + ordinal: 112, + leap_year: false + } + ); + assert_eq!( + IFC::ymd(12019, 6, 1), + IFC { + year: 12019, + ordinal: 140, + leap_year: false + } + ); + assert_eq!( + IFC::ymd(12019, 7, 1), + IFC { + year: 12019, + ordinal: 168, + leap_year: false + } + ); + assert_eq!( + IFC::ymd(12019, 8, 1), + IFC { + year: 12019, + ordinal: 196, + leap_year: false + } + ); + assert_eq!( + IFC::ymd(12019, 9, 1), + IFC { + year: 12019, + ordinal: 224, + leap_year: false + } + ); + assert_eq!( + IFC::ymd(12019, 10, 1), + IFC { + year: 12019, + ordinal: 252, + leap_year: false + } + ); + assert_eq!( + IFC::ymd(12019, 11, 1), + IFC { + year: 12019, + ordinal: 280, + leap_year: false + } + ); + assert_eq!( + IFC::ymd(12019, 12, 1), + IFC { + year: 12019, + ordinal: 308, + leap_year: false + } + ); + assert_eq!( + IFC::ymd(12019, 13, 1), + IFC { + year: 12019, + ordinal: 336, + leap_year: false + } + ); + } + + #[test] + fn check_start_of_month_leap_year() { + assert_eq!( + IFC::ymd(12020, 1, 1), + IFC { + year: 12020, + ordinal: 0, + leap_year: true + } + ); + assert_eq!( + IFC::ymd(12020, 2, 1), + IFC { + year: 12020, + ordinal: 28, + leap_year: true + } + ); + assert_eq!( + IFC::ymd(12020, 3, 1), + IFC { + year: 12020, + ordinal: 56, + leap_year: true + } + ); + assert_eq!( + IFC::ymd(12020, 4, 1), + IFC { + year: 12020, + ordinal: 84, + leap_year: true + } + ); + assert_eq!( + IFC::ymd(12020, 5, 1), + IFC { + year: 12020, + ordinal: 112, + leap_year: true + } + ); + assert_eq!( + IFC::ymd(12020, 6, 1), + IFC { + year: 12020, + ordinal: 140, + leap_year: true + } + ); + assert_eq!( + IFC::ymd(12020, 6, 29), + IFC { + year: 12020, + ordinal: 168, + leap_year: true + } + ); + assert_eq!( + IFC::ymd(12020, 7, 1), + IFC { + year: 12020, + ordinal: 169, + leap_year: true + } + ); + assert_eq!( + IFC::ymd(12020, 8, 1), + IFC { + year: 12020, + ordinal: 197, + leap_year: true + } + ); + assert_eq!( + IFC::ymd(12020, 9, 1), + IFC { + year: 12020, + ordinal: 225, + leap_year: true + } + ); + assert_eq!( + IFC::ymd(12020, 10, 1), + IFC { + year: 12020, + ordinal: 253, + leap_year: true + } + ); + assert_eq!( + IFC::ymd(12020, 11, 1), + IFC { + year: 12020, + ordinal: 281, + leap_year: true + } + ); + assert_eq!( + IFC::ymd(12020, 12, 1), + IFC { + year: 12020, + ordinal: 309, + leap_year: true + } + ); + assert_eq!( + IFC::ymd(12020, 13, 1), + IFC { + year: 12020, + ordinal: 337, + leap_year: true + } + ); + } + #[test] + fn it_matches_january_1() { + assert_eq!( + IFC::from(NaiveDate::from_ymd(2019, 1, 1)), + IFC::ymd(12019, 1, 1) + ); + } + + #[test] + fn it_matches_february_1() { + assert_eq!( + IFC::from(NaiveDate::from_ymd(2019, 1, 29)), + IFC::ymd(12019, 2, 1) + ); + } + + #[test] + fn it_matches_sol_1() { + assert_eq!( + IFC::from(NaiveDate::from_ymd(2019, 6, 18)), + IFC::ymd(12019, 7, 1) + ); + } + + #[test] + fn it_matches_year_day() { + assert_eq!( + IFC::from(NaiveDate::from_ymd(2019, 12, 31)), + IFC::ymd(12019, 13, 29) + ); + } + + #[test] + fn it_matches_leap_day() { + assert_eq!( + IFC::from(NaiveDate::from_ymd(2019, 6, 18)), + IFC::ymd(12019, 7, 1), + ); + assert_eq!( + IFC::from(NaiveDate::from_ymd(2020, 6, 17)), + IFC::ymd(12020, 6, 29), + ); + assert_eq!( + IFC::from(NaiveDate::from_ymd(2020, 6, 18)), + IFC::ymd(12020, 7, 1), + ); + assert_ne!(IFC::ymd(12020, 6, 29), IFC::ymd(12020, 7, 1)); + } + + #[test] + fn it_handles_gregorian_leap_day() { + assert_eq!( + IFC::from(NaiveDate::from_ymd(2019, 3, 1)), + IFC::ymd(12019, 3, 4) + ); + assert_eq!( + IFC::from(NaiveDate::from_ymd(2020, 2, 29)), + IFC::ymd(12020, 3, 4) + ); + } + + #[test] + fn it_handles_days_between_leap_days() { + assert_eq!( + IFC::from(NaiveDate::from_ymd(2020, 4, 8)), + IFC::ymd(12020, 4, 15), + ); + } + + #[test] + fn it_handles_days_after_ifc_leap_day() { + assert_eq!( + IFC::from(NaiveDate::from_ymd(2020, 10, 8)), + IFC::ymd(12020, 11, 1), + ); + } + + #[test] + fn it_matches_year_day_in_leap_year() { + assert_eq!(NaiveDate::from_ymd(2020, 12, 31).ordinal(), 366); + assert_eq!( + IFC::from(NaiveDate::from_ymd(2020, 12, 31)), + IFC::ymd(12020, 13, 29) + ); + } + + #[test] + fn it_reports_correct_month() { + assert_eq!(IFC::ymd(12019, 1, 1).month(), 1); + assert_eq!(IFC::ymd(12019, 1, 1).month0(), 0); + + assert_eq!(IFC::ymd(12020, 6, 28).month(), 6); + assert_eq!(IFC::ymd(12020, 6, 28).month0(), 5); + + assert_eq!(IFC::ymd(12020, 7, 1).month(), 7); + assert_eq!(IFC::ymd(12020, 7, 1).month0(), 6); + + assert_eq!(IFC::ymd(12019, 13, 1).month(), 13); + assert_eq!(IFC::ymd(12019, 13, 1).month0(), 12); + } + + #[test] + fn it_reports_correct_day() { + assert_eq!(IFC::ymd(12019, 1, 1).day(), 1); + assert_eq!(IFC::ymd(12019, 1, 1).day0(), 0); + + assert_eq!(IFC::ymd(12020, 3, 1).day(), 1); + assert_eq!(IFC::ymd(12020, 3, 1).day0(), 0); + + assert_eq!(IFC::ymd(12020, 6, 28).day(), 28); + assert_eq!(IFC::ymd(12020, 6, 28).day0(), 27); + + assert_eq!(IFC::ymd(12020, 7, 1).day(), 1); + assert_eq!(IFC::ymd(12020, 7, 1).day0(), 0); + + assert_eq!(IFC::ymd(12019, 13, 1).day(), 1); + assert_eq!(IFC::ymd(12019, 13, 1).day0(), 0); + + assert_eq!(IFC::ymd(12019, 13, 29).day(), 29); + assert_eq!(IFC::ymd(12019, 13, 29).day0(), 28); + } + + #[test] + fn it_reports_correct_month_in_leap_year() { + assert_eq!(IFC::ymd(12020, 1, 1).month(), 1); + assert_eq!(IFC::ymd(12020, 1, 1).month0(), 0); + + assert_eq!(IFC::ymd(12020, 3, 1).month(), 3); + assert_eq!(IFC::ymd(12020, 3, 1).month0(), 2); + + assert_eq!(IFC::ymd(12020, 6, 29).month(), 6); + assert_eq!(IFC::ymd(12020, 6, 29).month0(), 5); + + assert_eq!(IFC::ymd(12020, 7, 1).month(), 7); + assert_eq!(IFC::ymd(12020, 7, 1).month0(), 6); + } + + #[test] + fn it_reports_correct_day_in_leap_year() { + assert_eq!(IFC::ymd(12019, 1, 1).day(), 1); + assert_eq!(IFC::ymd(12019, 1, 1).day0(), 0); + + assert_eq!(IFC::ymd(12020, 6, 28).day(), 28); + assert_eq!(IFC::ymd(12020, 6, 28).day0(), 27); + + assert_eq!(IFC::ymd(12020, 6, 29).day(), 29); + assert_eq!(IFC::ymd(12020, 6, 29).day0(), 28); + + assert_eq!(IFC::ymd(12020, 7, 1).day(), 1); + assert_eq!(IFC::ymd(12020, 7, 1).day0(), 0); + + assert_eq!(IFC::ymd(12019, 13, 1).day(), 1); + assert_eq!(IFC::ymd(12019, 13, 1).day0(), 0); + + assert_eq!(IFC::ymd(12019, 13, 29).day(), 29); + assert_eq!(IFC::ymd(12019, 13, 29).day0(), 28); + } + + #[test] + fn it_reports_correct_day_of_week() { + assert_eq!(IFC::ymd(12019, 1, 1).weekday(), chrono::Weekday::Sun); + assert_eq!(IFC::ymd(12019, 6, 1).weekday(), chrono::Weekday::Sun); + assert_eq!(IFC::ymd(12019, 6, 28).weekday(), chrono::Weekday::Sat); + assert_eq!(IFC::ymd(12019, 7, 1).weekday(), chrono::Weekday::Sun); + assert_eq!(IFC::ymd(12019, 13, 28).weekday(), chrono::Weekday::Sat); + assert_eq!(IFC::ymd(12019, 13, 29).weekday(), chrono::Weekday::Sat); + + assert_eq!(IFC::ymd(12020, 6, 28).weekday(), chrono::Weekday::Sat); + assert_eq!(IFC::ymd(12020, 6, 29).weekday(), chrono::Weekday::Sat); + assert_eq!(IFC::ymd(12020, 7, 1).weekday(), chrono::Weekday::Sun); + assert_eq!(IFC::ymd(12020, 13, 28).weekday(), chrono::Weekday::Sat); + assert_eq!(IFC::ymd(12020, 13, 29).weekday(), chrono::Weekday::Sat); + } +} diff --git a/ifc/src/static/index.html b/ifc/src/static/index.html new file mode 100644 index 0000000..6b10716 --- /dev/null +++ b/ifc/src/static/index.html @@ -0,0 +1,34 @@ + + + {{month}} {{year}} + + + + +

IFC Fixed Calendar: {{month}}, {{year}} years after the invention of agriculture

+ + + + + + + + + + + + + + + {{#weeks}} + + {{#days}} + + {{/days}} + + {{/weeks}} + +
Sunday Monday Tuesday Wednesday Thursday Friday Saturday
{{day}}
+ + + diff --git a/ifc/src/static/month.html b/ifc/src/static/month.html new file mode 100644 index 0000000..2544f32 --- /dev/null +++ b/ifc/src/static/month.html @@ -0,0 +1,35 @@ + + + {{month}} {{year}} + + + +

+ IFC Fixed Calendar: {{month}}, {{year}} years after the invention of + agriculture +

+ + + + + + + + + + + + + + + {{#weeks}} + + {{#days}} + + {{/days}} + + {{/weeks}} + +
SundayMondayTuesdayWednesdayThursdayFridaySaturday
{{day}}
+ + diff --git a/ifc/src/static/out_of_time.html b/ifc/src/static/out_of_time.html new file mode 100644 index 0000000..0e5aa93 --- /dev/null +++ b/ifc/src/static/out_of_time.html @@ -0,0 +1,12 @@ + + + {{day_out_of_time}} {{year}} + + + +

+ IFC Fixed Calendar: {{day_out_of_time}}, {{year}} years after the + invention of agriculture +

+ + diff --git a/ifc/src/static/styles.css b/ifc/src/static/styles.css new file mode 100644 index 0000000..8b41587 --- /dev/null +++ b/ifc/src/static/styles.css @@ -0,0 +1,18 @@ + +table { + width: 98%; + border: 1px solid black; + border-collapse: collapse; +} + +th, td { + width: 14%; + font-family: sans-serif; + font-size: larger; + border: 1px solid black; + padding: 1em 0em 5em 1em; +} + +.today { + background-color: rgb(200, 200, 255); +} diff --git a/ifc/src/today.rs b/ifc/src/today.rs new file mode 100644 index 0000000..bdd6dfb --- /dev/null +++ b/ifc/src/today.rs @@ -0,0 +1,10 @@ +extern crate chrono; +extern crate chrono_tz; +extern crate international_fixed_calendar as IFC; + +use chrono::{Datelike, Utc}; + +fn main() { + let d = IFC::IFC::from(Utc::today()); + println!("{} {}, {}", d.month(), d.day(), d.year()); +} diff --git a/ifc/src/web.rs b/ifc/src/web.rs new file mode 100644 index 0000000..cb0119b --- /dev/null +++ b/ifc/src/web.rs @@ -0,0 +1,107 @@ +use chrono::{Datelike, Utc}; +use international_fixed_calendar as IFC; +use iron::headers; +use iron::middleware::Handler; +use iron::modifiers::Header; +use iron::prelude::*; +use iron::status; +use mustache::{compile_str, Template}; +use router::Router; +use serde::Serialize; + +pub const STYLES: &'static str = include_str!("static/styles.css"); +pub const INDEX: &'static str = include_str!("static/index.html"); + +pub struct IndexHandler { + pub template: Template, +} + +#[derive(Serialize)] +pub struct DayEntry { + day: u8, + highlight: String, +} + +#[derive(Serialize)] +pub struct Week { + days: Vec, +} + +impl Week { + fn new(start_day: u8, today: u8) -> Week { + Week { + days: (1..8) + .map(|d| DayEntry { + day: d + start_day, + highlight: if today == (d + start_day) { + String::from("today") + } else { + String::from("") + }, + }) + .collect(), + } + } +} + +#[derive(Serialize)] +pub struct IndexTemplateParams { + month: String, + year: i32, + weeks: Vec, +} + +impl IndexTemplateParams { + fn new(date: IFC::IFC) -> IndexTemplateParams { + let day = date.day() as u8; + IndexTemplateParams { + month: String::from(IFC::Month::from(date.month())), + year: date.year(), + weeks: (0..4).map(|wn| Week::new(wn * 7, day)).collect(), + } + } +} + +impl Handler for IndexHandler { + fn handle(&self, _: &mut Request) -> IronResult { + let d = IFC::IFC::from(Utc::today()); + Ok(Response::with(( + status::Ok, + Header(headers::ContentType(iron::mime::Mime( + iron::mime::TopLevel::Text, + iron::mime::SubLevel::Html, + vec![], + ))), + self.template + .render_to_string(&IndexTemplateParams::new(d)) + .expect("the template to render"), + ))) + } +} + +fn css(_: &mut Request) -> IronResult { + Ok(Response::with(( + status::Ok, + Header(headers::ContentType(iron::mime::Mime( + iron::mime::TopLevel::Text, + iron::mime::SubLevel::Css, + vec![], + ))), + STYLES, + ))) +} + +fn main() { + let mut router = Router::new(); + router.get( + "/", + IndexHandler { + template: compile_str(INDEX).expect("the template to compile"), + }, + "index", + ); + + router.get("/css", css, "styles"); + + Iron::new(router).http("127.0.0.1:3000").unwrap(); +}